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 и выбор провайдера.
Быстрый старт
Установка
Инструкция OpenCode. Через npm нужен Node.js 18+.
curl -fsSL https://opencode.ai/install | bashПроверкаopencode --versionКлюч 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:…}.Файл 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 провайдера — тот же, что в /connectnpm@openrouter/ai-sdk-providerдля/v1/chat/completions— наш формат ответа совпадает с OpenRouter. Для/v1/responses—@ai-sdk/openaioptions.baseURLhttps://api.aitunnel.ru/v1(с/v1, без слеша в конце)modelsКлюч — id из каталога, name— подпись в UIlimit.context/limit.outputОкно контекста и ответа: OpenCode считает по ним остаток modelМодель по умолчанию: providerID/modelIDsmall_modelДешёвая модель для заголовков сессии и суммаризации reasoningДля моделей с рассуждениями — см. токены рассуждений Запуск
Терминалcd /path/to/your/project opencodeВ TUI —
/models, выберите модель AITUNNEL. Запросы появятся в панели.
Ключ отдельно от конфига
Если не используете /connect, не кладите sk-aitunnel-… в JSON.
Переменная окружения
{
"$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"Файл с ключом
{
"provider": {
"aitunnel": {
"options": {
"apiKey": "{file:~/.secrets/aitunnel-key}"
}
}
}
}~/.secrets/aitunnel-key — одна строка, без перевода строки.
Приоритет конфигов
OpenCode сливает слои (поздние перекрывают ранние):
- Удалённый
.well-known/opencodeу провайдера - Глобальный
~/.config/opencode/opencode.jsonc OPENCODE_CONFIG=/path/to/config.jsoncopencode.jsoncв корне проекта- Каталоги
.opencode/— агенты, команды, плагины OPENCODE_CONFIG_CONTENT
Держите провайдер AITUNNEL в глобальном файле, а в проекте переопределяйте только model.
small_model
OpenCode гоняет 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:
{
"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». Объявите модальности:
{
"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.
# AITUNNEL API CF
## Стек
- Cloudflare Workers + Hono
- TypeScript, деплой через Wrangler
## Правила
- Все обращения к провайдерам идут через единый failover-слой
- Писать тесты для новых route handlers
- Не коммитить секреты и `.dev.vars`Рекомендуемые модели
Id — как в каталоге, без префикса провайдера.
claude-sonnet-4.6— баланс качества и tool callinggpt-6-astra— флагман OpenAI для кода и агентовgpt-5.6-sol— заточена под кодkimi-k2.7-code— дешевле Claude/GPT, сильна в tool useqwen3-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:
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. Ключ живой в панели ключей, баланс положительный,
baseURL—https://api.aitunnel.ru/v1. Устаревшийauth.json—opencode 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'а.