agent-ecosystem/docs/research/model-agnostic-proxy.md
iliya 9368e7639d feat: enhance tool summary integration in messaging services and UI components
- Added tool summary generation in TeamDataService and TeamProvisioningService to capture tool usage details in messages.
- Updated InboxMessage type to include toolSummary for better tracking of tool usage in assistant messages.
- Enhanced LeadThoughtsGroupRow to aggregate and display total tool usage across thoughts, improving visibility of tool interactions.
- Refactored TeamModelSelector to incorporate provider icons and improve user interface for model selection.
- Updated README and CLAUDE.md to reflect new command usage and features related to tool summaries.
2026-03-06 13:51:37 +02:00

23 KiB
Raw Blame History

Model-Agnostic Proxy для Claude Code Agent Teams

Дата исследования: 2026-03-06

Цель

Сделать Claude Code Agent Teams model-agnostic: lead остаётся на Claude, а teammates могут работать на GPT-4o, Gemini, DeepSeek, Kimi K2.5 и других моделях через прокси, который транслирует Anthropic Messages API в формат целевого провайдера.

Ключевой механизм

Claude Code обращается к Anthropic Messages API (/v1/messages). Переменная ANTHROPIC_BASE_URL позволяет перенаправить запросы на локальный прокси. Прокси:

  1. Принимает запрос в формате Anthropic Messages API
  2. Транслирует в формат целевого провайдера (OpenAI Chat Completions и др.)
  3. Пересылает провайдеру
  4. Получает SSE-стрим ответа
  5. Транслирует обратно в формат Anthropic SSE-событий
  6. Отдаёт Claude Code CLI как будто это ответ от Claude

Team tools (TeamCreate, TaskCreate, SendMessage, TaskGet, TaskList, TaskUpdate, TeamDelete) исполняются локально Claude Code CLI. LLM только генерирует tool_use блоки. Значит прокси не нужно знать о team-семантике — достаточно корректно транслировать tool_use формат.


Исследованные проекты

1. HydraTeams

  • URL: https://github.com/Pickle-Pixel/HydraTeams
  • Назначение: Прокси-переводчик API специально для Agent Teams
  • Язык: TypeScript (~580 строк, 8 файлов)
  • Зависимости: Zero runtime dependencies (только Node.js builtins)
  • Лицензия: Не указана явно
  • Stars: 33 | Forks: 9 | Commits: 4 | Создан: 2026-02-08

Архитектура

src/
  index.ts              (35)   — точка входа, banner, graceful shutdown
  proxy.ts              (280)  — HTTP-сервер, маршрутизация, retry
  config.ts             (95)   — CLI-аргументы, env vars, Codex JWT
  logger.ts             (190)  — логирование, идентификация сессий
  translators/
    types.ts            (120)  — интерфейсы Anthropic + OpenAI
    messages.ts         (85)   — конвертация истории сообщений
    request.ts          (65)   — Anthropic req -> OpenAI Chat Completions req
    request-responses.ts (145) — Anthropic req -> ChatGPT Responses API req
    response.ts         (185)  — OpenAI SSE -> Anthropic SSE
    response-responses.ts (235) — Responses API SSE -> Anthropic SSE

Два конвейера трансляции

  1. OpenAI Chat Completions API (--provider openai) — для GPT-4o, GPT-4o-mini, o3-mini
  2. ChatGPT Responses API (--provider chatgpt) — для ChatGPT Subscription ($0 дополнительных затрат)

Lead vs Teammate детекция

  • Lead: маркер <!-- hydra:lead --> в CLAUDE.md (попадает в system prompt)
  • Teammate: фраза "the user interacts primarily with the team lead" в system prompt
  • Lead-запросы passthrough на настоящий Anthropic API
  • Teammate-запросы транслируются на целевую модель

Что работает правильно

  • Tool definitions: input_schema -> parameters, tool_choice маппинг корректен
  • tool_use блоки ассистанта -> tool_calls формат OpenAI
  • tool_result -> role: "tool" сообщения
  • Streaming: StreamState отслеживает blockIndex, activeToolCalls, textBlockStarted
  • Правильная SSE-последовательность: message_start -> content_block_start -> content_block_delta -> content_block_stop -> message_delta -> message_stop
  • Retry с exponential backoff на 429 (до 5 попыток)

Найденные баги (code review)

# Баг Серьёзность
1 response-responses.ts: content_index используется вместо Anthropic blockIndex в response.output_text.done — content_block_stop уйдёт с неправильным index Высокая
2 proxy.ts: shouldPassthrough() получает parsed.system (может быть массив AnthropicSystemBlock[]) как string — count_tokens passthrough для lead не сработает Средняя
3 proxy.ts: Non-streaming JSON.parse(tc.function.arguments) — если OpenAI вернёт невалидный JSON, exception убьёт весь запрос Средняя
4 proxy.ts: shouldPassthrough("*") означает "все Claude модели", а не "всё" — контринтуитивно Низкая
5 logger.ts: Warmup-запросы определяются по toolCount === 0 — может ложно классифицировать обычные запросы Низкая

Критические проблемы

Проблема Серьёзность
0 тестов Критично
Нет таймаутов на upstream — fetch() без AbortController, зависнет навсегда Критично
Слушает на 0.0.0.0 — доступен в сети, релеит auth headers Критично
Teammate детекция по строке "the user interacts primarily with the team lead" — сломается при обновлении Claude Code Высокая
Spoofed model hardcoded claude-sonnet-4-5-20250929 — устареет Средняя
Token counting = JSON.length / 4 — грубая заглушка Средняя
Нет extended thinking — thinking блоки игнорируются Средняя
Нет image/multimodal — молча теряются Низкая

Безопасность

  • Сервер слушает на 0.0.0.0 (все интерфейсы) — в сети это дыра
  • Passthrough релеит auth headers (x-api-key, authorization, cookie) к api.anthropic.com
  • JWT парсинг без валидации подписи
  • Нет rate limiting на входящие запросы
  • Логи могут содержать API-ключи в ответах об ошибках

Итоговые оценки

Аспект Оценка
Архитектура 7/10
API трансляция 6/10
Lead/Teammate детекция 5/10
Обработка ошибок 4/10
Streaming 7/10
Безопасность 3/10
Production readiness 3/10
Общая 5/10

2. free-claude-code

  • URL: https://github.com/Alishahryar1/free-claude-code
  • Назначение: Прокси для использования Claude Code с бесплатными моделями
  • Язык: Python (FastAPI + uvicorn)
  • Stars: 814 | Forks: 95 | Issues: 4 | Создан: 2026-01-28
  • Лицензия: MIT
  • Тесты: 85+ файлов, pytest, GitHub Actions CI

Архитектура

server.py                    — точка входа (uvicorn)
api/
  app.py                     — FastAPI factory + lifespan
  routes.py                  — POST /v1/messages, GET /health
  detection.py               — эвристики определения типа запроса
  optimization_handlers.py   — 5 fast-path перехватчиков
  request_utils.py           — подсчёт токенов (tiktoken cl100k_base)
  models/anthropic.py        — Pydantic модели Anthropic request
providers/
  base.py                    — BaseProvider (ABC)
  openai_compat.py           — OpenAICompatibleProvider (основная логика)
  common/
    message_converter.py     — Anthropic <-> OpenAI конвертер (~200 строк)
    sse_builder.py           — SSE event builder Anthropic формат (~300 строк)
    think_parser.py          — парсер <think> тегов (~80 строк)
    heuristic_tool_parser.py — парсер tool calls из текста
  nvidia_nim/, open_router/, lmstudio/ — конкретные провайдеры

Провайдеры и модели

NVIDIA NIM (бесплатно, 40 req/min)

Tier S (флагманы):

Model ID Thinking Tool Calling
moonshotai/kimi-k2.5 Да Native
qwen/qwen3-coder-480b-a35b-instruct Да Native
z-ai/glm5 Да Native
deepseek-ai/deepseek-v3.2 Да Native
mistralai/mistral-large-3-675b-instruct Да Native
minimaxai/minimax-m2.5 Да Native

Tier A:

Model ID Thinking Tool Calling
z-ai/glm4.7 Да Native
mistralai/devstral-2-123b-instruct Да Native
openai/gpt-oss-120b Да Native
meta/llama-3.1-405b-instruct Нет Native

Tier B (быстрые):

Model ID Thinking Tool Calling
qwen/qwen2.5-coder-32b-instruct Нет Native
stepfun-ai/step-3.5-flash Да Native
meta/llama-3.3-70b-instruct Нет Native

Всего в каталоге NIM 185 моделей, все бесплатные. max_tokens: 81920.

OpenRouter (free модели с суффиксом :free)

С Tool Calling + Thinking:

Model ID Context Max Output
openai/gpt-oss-120b:free 131K 131K
stepfun/step-3.5-flash:free 256K 256K
qwen/qwen3-coder:free 262K 262K
qwen/qwen3-235b-a22b-thinking-2507:free 131K
z-ai/glm-4.5-air:free 131K 96K

С Tool Calling, без Thinking:

Model ID Context
meta-llama/llama-3.3-70b-instruct:free 128K
mistralai/mistral-small-3.1-24b-instruct:free 128K
google/gemma-3-27b-it:free 131K

Всего 28 бесплатных моделей + мета-роутер openrouter/free.

LM Studio (полностью локально, без лимитов)
Модель VRAM Качество кода
unsloth/MiniMax-M2.5-GGUF 48GB+ 7/10
unsloth/Qwen3-Coder-480B-A35B-Instruct-GGUF 48GB+ 8/10
unsloth/Qwen3.5-35B-A3B-GGUF 24GB 6/10
unsloth/GLM-4.7-Flash-GGUF 24GB 6/10
unsloth/Qwen2.5-Coder-32B-Instruct-GGUF 24GB 6/10

Что лучше чем HydraTeams

Аспект free-claude-code HydraTeams
Тесты 85+ файлов, CI 0
Thinking blocks Два пути (native + <think> парсер) Нет
Token counting tiktoken (реальный подсчёт) JSON.length / 4
Provider abstraction ABC + наследование Hardcoded if/else
Error handling Graceful shutdown, rate limiter Базовый try/catch
Heuristic tool parser Есть (для моделей без native tool use) Нет

Проблемы для Agent Teams

  1. Task tool patching — принудительно ставит run_in_background=False в трёх местах. Опасная мина для team coordination
  2. Optimization interceptors — 5 эвристик могут ложно сработать на teammate messages
  3. Общий rate limiter — singleton GlobalRateLimiter (40 req/min, max_concurrency=5). 5 teammates = мгновенный bottleneck. Один 429 блокирует ВСЕХ
  4. Python 3.14 requirement — ещё в beta, проблема для bundling
  5. tiktoken требует Rust-скомпилированный .so — кросс-платформенная сборка сложная
  6. Нет lead/teammate разделения — все запросы на один провайдер

Bundling с Electron

Критерий free-claude-code (Python) HydraTeams (TypeScript)
Bundling в Electron PyInstaller ~100-150MB, Python 3.14, Rust deps Прямо в main process, 0 deps
Размер ~50MB минимум ~580 строк, КБ
Кросс-платформа tiktoken .so для каждой платформы Нативный Node.js
Запуск Child process + Python runtime Просто import

Переиспользуемое ядро (~900 строк Python)

  • message_converter.py (~200 строк) — полностью независим
  • sse_builder.py (~300 строк) — почти независим (убрать Task patching)
  • think_parser.py (~80 строк) — полностью независим
  • openai_compat.py (~250 строк) — stream_response логика

Итоговые оценки

Критерий Оценка
Качество кода 7/10
Тесты 8/10
Bundling с Electron 2/10
Agent Teams совместимость 3/10
Адаптация под наш стек 3/10

3. LiteLLM Proxy

  • URL: https://github.com/BerriAI/litellm
  • Лицензия: MIT (enterprise-фичи проприетарные)
  • Stars: ~38,000 | Forks: ~6,200
  • Язык: Python
  • Провайдеры: 100+ (OpenAI, Gemini, Bedrock, Azure, Groq, DeepSeek...)

Как работает с Claude Code

export ANTHROPIC_BASE_URL="http://0.0.0.0:4000"
export ANTHROPIC_AUTH_TOKEN="$LITELLM_MASTER_KEY"
claude --model gpt-4o

Нативный Anthropic SDK-совместимый endpoint /messages. Полная трансляция tool_use, streaming SSE.

Почему НЕ подходит для Electron

Проблема Детали
Python 70+ зависимостей, Prisma с Node binaries, grpcio
Размер ~2 ГБ (Docker-образ)
RAM Рекомендация 8 ГБ для production
Bundling Никто никогда не бандлил с desktop app

Известные баги с Claude Code

  • #21446 — Gemini не работает через LiteLLM
  • #14194 — Bedrock thinking + tools конфликтуют
  • #12222 — Gemini падает на tools с optional args
  • #18730 — Concurrent requests обходят rate limits

Вердикт: enterprise-серверный gateway, не для десктопа. 1/10 для нашего кейса.


4. Bifrost (Maxim AI)

  • URL: https://github.com/maximhq/bifrost
  • Лицензия: Apache 2.0
  • Stars: ~2,700 | Commits: 3,341
  • Язык: Go (11 мкс overhead при 5000 RPS)
  • Провайдеры: 20+ (OpenAI, Gemini, Bedrock, Azure, Mistral, Ollama...)

Bundling с Electron

Bifrost компилируется в единый статический Go-бинарник. npm-пакет @maximhq/bifrost скачивает prebuilt binary с CDN под нужную платформу.

https://downloads.getmaxim.ai/bifrost/{version}/{platform}/{arch}/bifrost-http

Поддерживаемые платформы:

  • darwin/arm64 (macOS Apple Silicon)
  • darwin/amd64 (macOS Intel)
  • linux/amd64, linux/386
  • windows/amd64, windows/arm64

Размер: ~30-60 MB. Запуск: child_process.spawn(bifrostBinaryPath).

Bundling: 9/10 — скачать бинарник, положить рядом, запустить как child process.

Проблемы для Agent Teams

Issue Описание Статус
#1164 Parallel tool calls через Bedrock не работают Открыт
#1829 Streaming tool call deltas мёрджатся Закрыт
#1804 Streaming tool calls с агентскими клиентами не работают Открыт
#828 Goroutine leak при context cancellation Открыт
#1613 SSE streaming от Gemini ломается Открыт

Не использует anthropic-go-sdk, дублирует типы вручную (Discussion #1259).

Никто не тестировал Bifrost с Agent Teams.

Итоговые оценки

Критерий Оценка
Bundling с Electron 9/10
Agent Teams (passthrough) 8/10
Agent Teams (трансляция) 4/10
Зрелость 7/10

Сравнение качества моделей vs Claude

Модель Кодинг vs Sonnet vs Opus
Kimi K2.5 (NIM) 8/10 ~80% ~60%
Qwen3 Coder 480B (NIM) 8/10 ~80% ~60%
GLM-5 (NIM) 7/10 ~70% ~50%
GPT-OSS 120B (NIM/OR) 7/10 ~70% ~50%
GLM-4.7 (NIM) 7/10 ~65% ~45%
Step 3.5 Flash (OR) 6/10 ~55% ~35%
Llama 3.3 70B (OR) 5/10 ~45% ~30%

Ни одна бесплатная модель не дотягивает до Claude по качеству агентного кодинга.


Юридические аспекты

Что разрешено Anthropic

  • ANTHROPIC_BASE_URLофициально поддерживается для LLM Gateway
  • Использование прокси с собственными API-ключами других провайдеров — легально
  • Документация описывает LLM Gateway конфигурацию: endpoint должен реализовывать Anthropic Messages API

Что запрещено

  • Использование OAuth-токенов от Claude Free/Pro/Max подписок в сторонних продуктах
  • Anthropic активно блокирует несанкционированное использование подписочных токенов
  • Использование Claude для обучения конкурирующих моделей (Section D.4 Commercial Terms)

ChatGPT backend API (HydraTeams)

  • chatgpt.com/backend-api/codex/responses — недокументированный API
  • Нарушение ToS ChatGPT при автоматизации через backend API
  • Может быть заблокирован в любой момент

Влияние на наш проект (Claude DevTools)

JSONL формат сессий не меняется — Claude Code CLI генерирует одинаковую структуру независимо от backend-модели. TeamCreate, TaskCreate, SendMessage и прочие team tools остаются теми же. Парсинг и chunk building будет работать без изменений.

Единственное потенциальное отличие — metadata о модели в сообщениях (model field).


Рекомендация по реализации

Лучший путь: форк HydraTeams + hardening

HydraTeams — единственный проект заточенный под Agent Teams, на TypeScript (наш стек), zero deps, встраивается в Electron main process.

Что нужно починить обязательно:

  1. Localhost-only binding (127.0.0.1)
  2. AbortController + таймауты на upstream fetch
  3. Баги с indices в response-responses.ts
  4. Тесты на трансляцию (unit-тесты на каждый translator)
  5. Убрать hardcoded spoofModel -> сделать конфигурируемым

Что заимствовать из free-claude-code:

  1. ThinkTagParser — переписать на TS (~50 строк)
  2. Provider abstraction — интерфейс TranslationProvider
  3. Структуру тестов
  4. Heuristic tool parser для моделей без native tool calling

Что переосмыслить:

  • Lead/teammate детекция — маркер по строке хрупкий. Мы знаем роли из TeamDataService, можно передавать через env var HYDRA_ROLE=lead|teammate

Оценка трудозатрат

~2-3 дня на hardening + тесты. Итого: TypeScript-пакет ~800-1000 строк с тестами, встраиваемый в Electron main process.

Альтернативы

Вариант Надёжность Уверенность
Форк HydraTeams + hardening 7/10 8/10
Свой proxy с нуля на TS (вдохновлённый обоими) 8/10 7/10
Bifrost binary + thin TS translator 5/10 6/10
LiteLLM как Docker sidecar 6/10 7/10
free-claude-code (Python child process) 3/10 8/10

Другие найденные проекты

Проект Описание Применимость
1rgs/claude-code-proxy На базе LiteLLM, BIG/SMALL model маппинг 5/10
fuergaosi233/claude-code-proxy Anthropic -> OpenAI конвертер 4/10
nielspeter/claude-code-proxy Легковесный бинарник, OpenRouter 4/10
9router Smart router с fallback-каскадом 5/10
claude-code-teams-mcp MCP-сервер, реимплементация Agent Teams 3/10

Архитектурная схема целевого решения

[Lead Agent Process]
  ANTHROPIC_BASE_URL=http://127.0.0.1:{port}
  HYDRA_ROLE=lead
       |
       v
[Proxy (TypeScript, в Electron main process)]
  if role=lead  --> passthrough к api.anthropic.com
  if role=teammate --> трансляция к целевому провайдеру
       |
       v
[Teammate 1] --> OpenAI API (GPT-4o)
[Teammate 2] --> NVIDIA NIM (Kimi K2.5)
[Teammate 3] --> Local (LM Studio)

Stream-json протокол (stdin/stdout между lead и teammates) не затрагивается — прокси работает на уровне HTTP API запросов к LLM.