OpenCode

Open-source агентный CLI через AITUNNEL: тот же OpenCode, ключ в рублях, VPN не нужен.

OpenCode построен на AI SDK и говорит на OpenAI Chat Completions — отдельный прокси не ставится. AITUNNEL подключается как custom provider: один ключ, модели из каталога.

Зачем через AITUNNEL

  • Из России без VPN. Запросы идут на api.aitunnel.ru. Зарубежный аккаунт не нужен.
  • Оплата в рублях, бюджет на ключе, расход в панели.
  • Любая модель из каталога. Claude, GPT, Gemini, Kimi, Qwen, DeepSeek — id как на странице моделей. Слаг со слешем уходит в OpenRouter.
  • Запасные модели и провайдер. Если апстрим не ответил — fallback и выбор провайдера.

Быстрый старт

  1. Установка

    Инструкция OpenCode. Через npm нужен Node.js 18+.

    curl -fsSL https://opencode.ai/install | bash
    Проверка
    opencode --version
  2. Ключ AITUNNEL

    Создайте ключ в панели ключей — он начинается с sk-aitunnel-.

    Через /connect (рекомендуется). Запустите opencode, в TUI введите:

    TUI
    /connect
    /connect — Connect provider

    Прокрутите список и выберите Other Custom provider.

    Connect a provider → Other

    Id провайдера — aitunnel. OpenCode напишет, что это только сохранение ключа — провайдер настраивается в opencode.jsonc на следующем шаге.

    Id провайдера — aitunnel

    Вставьте ключ AITUNNEL.

    API key — ключ из панели

    OpenCode сохранит его в ~/.local/share/opencode/auth.json.

    Прямо в конфиге. Пропустите /connect и укажите options.apiKey — лучше через {env:…} или {file:…}.

  3. Файл opencode.jsonc

    Глобально — ~/.config/opencode/opencode.jsonc. Или opencode.jsonc в корне проекта. Подойдёт и .json.

    opencode.jsonc
    {
      "$schema": "https://opencode.ai/config.json",
      "provider": {
        "aitunnel": {
          "npm": "@openrouter/ai-sdk-provider",
          "name": "AITUNNEL",
          "options": {
            "baseURL": "https://api.aitunnel.ru/v1"
          },
          "models": {
            "claude-sonnet-4.6": {
              "name": "Claude Sonnet 4.6",
              "limit": { "context": 1000000, "output": 128000 }
            },
            "gpt-6-astra": {
              "name": "GPT-5.6 Sol",
              "limit": { "context": 1050000, "output": 128000 }
            },
            "gemini-3.7-flash": {
              "name": "Gemini 3.7 Flash",
              "limit": { "context": 1048576, "output": 65535 }
            }
          }
        }
      },
      "model": "aitunnel/claude-sonnet-4.6",
      "small_model": "aitunnel/gemini-3.7-flash"
    }
    ПолеСмысл
    provider.aitunnelId провайдера — тот же, что в /connect
    npm@openrouter/ai-sdk-provider для /v1/chat/completions — наш формат ответа совпадает с OpenRouter. Для /v1/responses @ai-sdk/openai
    options.baseURLhttps://api.aitunnel.ru/v1/v1, без слеша в конце)
    modelsКлюч — id из каталога, name — подпись в UI
    limit.context / limit.outputОкно контекста и ответа: OpenCode считает по ним остаток
    modelМодель по умолчанию: providerID/modelID
    small_modelДешёвая модель для заголовков сессии и суммаризации
    reasoningДля моделей с рассуждениями — см. токены рассуждений
  4. Запуск

    Терминал
    cd /path/to/your/project
    opencode

    В TUI — /models, выберите модель AITUNNEL. Запросы появятся в панели.

Ключ отдельно от конфига

Если не используете /connect, не кладите sk-aitunnel-… в JSON.

Переменная окружения

apiKey из env
{
  "$schema": "https://opencode.ai/config.json",
  "provider": {
    "aitunnel": {
      "npm": "@openrouter/ai-sdk-provider",
      "name": "AITUNNEL",
      "options": {
        "baseURL": "https://api.aitunnel.ru/v1",
        "apiKey": "{env:AITUNNEL_API_KEY}"
      },
      "models": {
        "claude-sonnet-4.6": { "name": "Claude Sonnet 4.6" }
      }
    }
  },
  "model": "aitunnel/claude-sonnet-4.6"
}
Профиль оболочки
# ~/.zshrc, ~/.bashrc или ~/.config/fish/config.fish
export AITUNNEL_API_KEY="sk-aitunnel-xxx"

Файл с ключом

{file:…}
{
  "provider": {
    "aitunnel": {
      "options": {
        "apiKey": "{file:~/.secrets/aitunnel-key}"
      }
    }
  }
}

~/.secrets/aitunnel-key — одна строка, без перевода строки.

Приоритет конфигов

OpenCode сливает слои (поздние перекрывают ранние):

  1. Удалённый .well-known/opencode у провайдера
  2. Глобальный ~/.config/opencode/opencode.jsonc
  3. OPENCODE_CONFIG=/path/to/config.jsonc
  4. opencode.jsonc в корне проекта
  5. Каталоги .opencode/ — агенты, команды, плагины
  6. OPENCODE_CONFIG_CONTENT

Держите провайдер AITUNNEL в глобальном файле, а в проекте переопределяйте только model.

small_model

OpenCode гоняет small_model на заголовки сессии и суммаризацию. Ставьте туда быструю дешёвую модель:

small_model
{
  "model": "aitunnel/gpt-6-astra",
  "small_model": "aitunnel/gemini-3.7-flash"
}

Это особенно заметно, если основная — Opus или GPT Pro.

Токены рассуждений

AITUNNEL отдаёт цепочку мыслей в формате OpenRouter: строкой в reasoning и массивом в reasoning_details (в стриме — в delta). Подробнее — токены рассуждений.

Пакет @openrouter/ai-sdk-provider из конфига выше читает оба поля и сам возвращает цепочку модели на следующем ходу. Осталось объявить, что модель рассуждает — тогда OpenCode покажет блок мыслей и варианты усилия в /models:

reasoning-модель
{
  "provider": {
    "aitunnel": {
      "models": {
        "glm-5.3-flash": {
          "name": "GLM 5.3 Flash",
          "reasoning": true,
          "limit": { "context": 1048576, "output": 131072 }
        }
      }
    }
  }
}

Выбранный вариант усилия OpenCode отдаёт как reasoning.effort, бюджет — как reasoning.max_tokens; наш API принимает оба поля напрямую. Задать вручную:

усилие
{
  "provider": {
    "aitunnel": {
      "models": {
        "glm-5.3-flash": {
          "options": { "reasoning": { "effort": "max" } }
        }
      }
    }
  }
}

На @ai-sdk/openai-compatible мыслей не будет: он читает только reasoning_content и отбрасывает reasoning с reasoning_details при разборе ответа. Поле interleaved тут не помогает — им задаётся имя поля, под которым OpenCode возвращает цепочку обратно в следующем запросе, к отображению оно отношения не имеет.

Картинки и вложения

Модели из своего конфига OpenCode по умолчанию считает текстовыми, даже если модель мультимодальная. Картинка в такой запрос не уходит: вместо неё модель получает текст «this model does not support image input». Объявите модальности:

modalities
{
  "provider": {
    "aitunnel": {
      "models": {
        "glm-5.3-flash": {
          "name": "GLM 5.3 Flash",
          "attachment": true,
          "modalities": { "input": ["text", "image", "video"], "output": ["text"] }
        }
      }
    }
  }
}
ПолеСмысл
modalities.inputЧто модель принимает на вход. Ровно это поле решает, отправится картинка или нет
attachmentПометка, что модель работает с вложениями

После перезапуска картинку можно перетащить в окно терминала, вставить из буфера обмена (Ctrl+V) или указать путь через @. Поддерживаются png, jpeg, gif, webp, avif, svg и pdf. Перед отправкой OpenCode сам ужимает изображения до 2000×2000 и 5 МБ — пороги меняются в attachment.image в конфиге.

Мультимодальные модели видны в каталоге по значку модальностей; glm-5.3-flash принимает текст, изображения и видео.

AGENTS.md

OpenCode читает AGENTS.md в корне проекта как системные инструкции — аналог CLAUDE.md. Есть и глобальный ~/.config/opencode/AGENTS.md.

AGENTS.md
# AITUNNEL API CF

## Стек
- Cloudflare Workers + Hono
- TypeScript, деплой через Wrangler

## Правила
- Все обращения к провайдерам идут через единый failover-слой
- Писать тесты для новых route handlers
- Не коммитить секреты и `.dev.vars`

Рекомендуемые модели

Id — как в каталоге, без префикса провайдера.

  • claude-sonnet-4.6 — баланс качества и tool calling
  • gpt-6-astra — флагман OpenAI для кода и агентов
  • gpt-5.6-sol — заточена под код
  • kimi-k2.7-code — дешевле Claude/GPT, сильна в tool use
  • qwen3-coder-next — open-source, хорошая агентность
  • gemini-3.7-flash — быстрая и дешёвая, удобна как small_model

Команды

В TUI: /help, /connect, /models, /agents, /share.

В терминале: opencode auth list, opencode run "промпт", opencode serve, opencode web, opencode --help.

Headless для CI:

opencode run
export AITUNNEL_API_KEY="sk-aitunnel-xxx"

opencode run "Напиши unit-тесты для src/utils.ts и положи их в src/utils.test.ts"

Читает глобальный opencode.jsonc, один прогон, результат в stdout.

Устранение неполадок

  • Провайдер не в /models. Id в provider.<ID> совпадает с /connect (aitunnel). opencode auth list показывает сохранённый ключ. Если ключ в options.apiKey, /connect не нужен. После правки opencode.jsonc перезапустите OpenCode.
  • 401 / 403. Ключ живой в панели ключей, баланс положительный, baseURLhttps://api.aitunnel.ru/v1. Устаревший auth.jsonopencode auth list, затем снова /connect.
  • Model not found / 404. Id как в каталоге: claude-sonnet-4.6, не anthropic/claude-sonnet-4.6. Слаг со слешем уходит в OpenRouter. name в конфиге на запрос не влияет.
  • Ошибка AI SDK. Для /v1/chat/completions "npm": "@openrouter/ai-sdk-provider" (оба пакета встроены в OpenCode, ставить их отдельно не нужно). Для /v1/responses@ai-sdk/openai. Можно переопределить npm на конкретной модели: provider.<id>.models.<model>.provider.npm.
  • Модель не показывает рассуждения. Проверьте, что npm@openrouter/ai-sdk-provider, и добавьте на модель "reasoning": true — см. токены рассуждений. На @ai-sdk/openai-compatible мыслей не будет: он читает только reasoning_content. Если цепочка стала короче после явного усилия — уберите его.
  • Модель не видит картинку. В ответе — «this model does not support image input». Добавьте на модель "modalities": { "input": ["text", "image"] } — см. картинки и вложения.
  • Лимит контекста. Поднимите limit.context. Для больших репозиториев — модели с окном ≥ 128k (claude-sonnet-4.6 — 1M). small_model тоже ест контекст на суммаризацию.
  • Приватность. AITUNNEL не логирует исходный код промптов. Не коммитьте opencode.jsonc с ключом — {env:AITUNNEL_API_KEY} или {file:~/.secrets/…}. Ключ из /connect лежит в ~/.local/share/opencode/auth.json. В CI — только переменные окружения runner'а.

Смотрите также