Как HagiCode подключает 13 Agent CLI к одной системе
Как HagiCode подключает 13 Agent CLI к одной системе
На самом деле это дело: сказать, что сложно — не так уж сложно, сказать, что просто — тоже не так уж просто. Расскажем, как мы с помощью слоистой архитектуры объединили такие разные Agent CLI, как Claude Code, Codex, Copilot, Gemini, и можем в любой момент подключить новый.
История началась внезапно,源于 одной довольно головной проблемы.
Agent CLI за последние два года начали появляться как побеги бамбука — Claude Code, OpenAI Codex, GitHub Copilot, Gemini CLI, Kimi, Qoder, Kiro… Каждые несколько месяцев появляется новый. Как проект, который хочет, чтобы пользователи “установили один HagiCode и использовали все Agent”, мы не можем делать ставку только на один CLI, но также не можем писать полный набор логики для каждого CLI — от установки до проверки работоспособности и планирования. Тогда код раздувался бы до состояния, когда его невозможно поддерживать, как запутанный клубок шерсти, который никто не решается трогать.
Что еще хуже, у этих CLI характер очень разный: одни работают через stdio, другие через gRPC, третьи дают только точку входа в shell, формат потокового вывода тоже каждый говорит по-своему. Если прямо в бизнес-коде писать такие проверки, как if (provider == ClaudeCode), то через полгода это превратится в кучу “унаследованного кода”, который никто не смеет трогать. В конце концов, кто захочет трогать кирпич, который выглядит так, будто он вот-вот упадет?
Чтобы собрать все эти боли в кучу, мы приняли решение: между бизнес-слоем и конкретными CLI добавить тонкий абстрактный слой и общую среду выполнения. Это дело выглядит просто, но оно напрямую определяет, может ли HagiCode быстро подключать новые CLI. Позже я подробно расскажу, как это делается.
О HagiCode
Решение, которым мы делимся, пришло из нашей практики в проекте HagiCode. HagiCode — это платформа интеграции AI-помощников для кода, цель очень простая — с помощью одной установки, одной конфигурации подключить все основные Agent CLI для пользователей.
Откуда взялось число “13”
Сначала поговорим о цифре, которую часто спрашивают — почему 13 Agent CLI.
На самом деле ответ спрятан в перечислении AIProviderType, как тень бамбука за окном — если захотите посмотреть, увидите. Исходное определение выглядит так:
public enum AIProviderType{ ClaudeCodeCli = 0, CodexCli = 1, GitHubCopilot = 2, CodebuddyCli = 3, OpenCodeCli = 4, IFlowCli = 5, // Устарело HermesCli = 6, QoderCli = 7, KiroCli = 8, KimiCli = 9, GeminiCli = 10, DeepAgentsCli = 11, ReasonixCli = 12, PiCli = 13,}В перечислении всего 14 значений, но путь IFlowCli=5 уже не работает. В AIProviderFactory он явно закрыт:
if (providerType == AIProviderType.IFlowCli){ throw new NotSupportedException("IFlowCli is no longer supported");}В сочетании с фильтрацией через IsActivelySupportedProviderType(), реально “живых” в системе — 13: Claude Code, Codex, GitHub Copilot, CodeBuddy, OpenCode, Hermes, Qoder, Kiro, Kimi, Gemini, DeepAgents, Reasonix, Pi.
Вот откуда взялось “13”. Это не маркетинговое число, это реальное число из кода. Ведь цифры не врут, врём только мы сами.
Слоистая архитектура: запираем изменения в клетке
Основная идея подключения 13 CLI, по сути, одно предложение: пусть бизнес-код не заботится о том, какой именно CLI он вызывает.
Мы разделили это на шесть слоев, сверху вниз:
1. Слой идентификации — AIProviderType
Перечисление — это “номер ID” каждого CLI. Где бы ни упоминался CLI, он помечается этим значением перечисления. Между строками и перечислением используется преобразование через ToStringValue() / ToAIProviderType(). Просто, но незаменимо.
2. Слой бизнес-контракта — IAIProvider / IAIProviderFactory
На стороне бизнеса признается только интерфейс IAIProvider, в нем определены такие общие действия, как “отправить prompt, получить потоковый ответ”. Что внизу — Claude или Codex — бизнес не заботится — как когда вы пишете письмо, только сдаете письмо, какая фамилия у почтальона, кому это интересно?
3. Слой адаптера — *CliProvider
Каждый CLI соответствует тонкому адаптеру, например PiCliProvider, ReasonixCliProvider, ClaudeCodeCliProvider. Эти адаптеры делают очень мало: переводят общие бизнес-запросы в параметры, которые понимает конкретный CLI, и переводят вывод конкретного CLI обратно. Они намеренно сделаны очень тонкими, чтобы добавить новый CLI — в основном просто копировать готовый и немного поправить.
4. Слой общей среды выполнения — ICliProvider<TOptions>
Этот слой в HagiCode.Libs, это место, где реально делается грязная работа: запуск процессов на разных платформах, обработка передачи stdio, разбор потокового вывода, обработка тайм-аутов и повторов. Все адаптеры используют одну и ту же среду выполнения, поэтому при подключении нового CLI часть управления процессами в основном не нужно переписывать.
К примеру, слой адаптера — это “переводчик”, слой общей среды выполнения — это “курьерская служба”. Переводчик только заботится, чтобы слова были понятными; как отправить посылку, есть ли пробки на дороге — это дело курьерской службы. Каждый занимается своим, мир становится чистым.
5. Слой маршрутизации фабрики — AIProviderFactory
В CreateProvider один switch, по AIProviderType создает соответствующий адаптер, заодно проверяет IsConfigured. Это единственное место, которое “знает конкретный тип”, строго изолированное в фабрике. Изменения разрешены только в одном углу, остальные места чистые.
6. Слой каталога / UI-проекции — main-professions.yaml
Этот слой интересный, это не код, это данные.
Основной список профессий (такие профили, как “я фронтендер”, “я бэкендер”, “я фулстек”) управляется预设-файлом main-professions.yaml, считывается через HeroPrimaryProfessionPresetProvider, проецируется на frontend UI. Добавить новую основную профессию — не нужно менять ни одной строки кода, просто поправить YAML. Данные вместо кода, спокойно.
Кстати, это самое большое место рефакторинга HagiCode. В ранних версиях был кодовый реестр с названием
AgentCliInstallRegistry, потом обнаружили, что стоимость поддержки слишком высока — кода пишут много, человек устает — всё было снесено, заменено на схему на основе данных + проверка работоспособности. Это и причина, почему HagiCode теперь может быстро расширять типы профессий.
Как решается установка
13 CLI все нужно установить, каждый официальный способ установки разный — это еще одна гора.
Наш подход — предустановка Docker Compose + внешнее управление как подстраховка. В образе предварительно установлены основные CLI (Claude Code, Codex, Copilot, CodeBuddy, OpenCode, Qoder, Kiro, Kimi, Gemini, Pi), пользователи могут просто скачать образ и использовать, не нужно сами по одной команде печатать. Установили — настроение хорошее.
Для тех, что нужно устанавливать отдельно в локальной среде, матрица команд установки примерно такая (проверено по официальной документации):
| CLI | Официальный способ установки |
|---|---|
| Claude Code | npm install -g @anthropic-ai/claude-code |
| Codex | npm install -g @openai/codex |
| GitHub Copilot | npm install -g @github/copilot |
| CodeBuddy | npm install -g @tencent-ai/codebuddy-code |
| OpenCode | npm i -g opencode-ai@latest |
| Qoder | npm install -g @qoder-ai/qodercli |
| Kiro | curl -fsSL https://cli.kiro.dev/install | bash |
| Kimi | curl -LsSf https://code.kimi.com/install.sh | bash |
| Gemini | npm |
| Hermes | Официальный скрипт, сохраняем docs-only как подстраховку |
| DeepAgents / Reasonix | См. соответствующие официальные документы |
На frontend PrimaryProfessionCard.tsx тоже изменилось — теперь нет кнопки “установить CLI”, а показывает доступность CLI, результаты определения версии, и подстраховку “этот CLI управляется извне”. То есть, установится или нет — ответственность системного слоя, UI только честно показывает статус. Статус и логика пишутся отдельно, рано или поздно не совпадут, зачем же тогда?
Что нужно сделать, чтобы добавить новый CLI
В практике, чтобы добавить новый CLI в HagiCode, примерно такие шаги:
- Добавить значение перечисления в
AIProviderType - Скопировать готовый
*CliProvider, поправить параметры и разбор вывода нового CLI - Добавить строку маршрутизации в
switchAIProviderFactory - Если нужно включить в основной каталог профессий, настроить в
main-professions.yaml - Добавить команду установки в образ (или использовать внешнее управление как подстраховку)
Весь процесс — основные изменения не более двухсот строк кода — это и есть реальная ценность этой абстракции. Чем больше CLI подключается, тем ниже предельная стоимость, бизнес-код менять не нужно. Все дороги ведут в Рим, только наша дорога — чуть-чуть легче.
Заключение
Если оглянуться назад, “подключить 13 CLI” звучит страшно, а если разобрать, то это всего два уровня работы:
Один уровень — изолировать изменения — через перечисление AIProviderType + контракт IAIProvider + тонкий адаптер + общая среда выполнения, позволить бизнес-коду и конкретным CLI быть независимыми; другой уровень — превратить конфигурацию в данные — использовать预设 YAML, такие как main-professions.yaml, для управления каталогом и UI, избегать необходимости менять код при добавлении каждой вещи.
Это решение стабилизировалось после нескольких итераций и ошибок в реальной разработке HagiCode. Если вы сейчас делаете похожую систему “интеграции нескольких Provider”, надеюсь, эта идея слоев даст вам немного ссылки. Ведь Agent CLI за последние два года продолжат появляться, архитектура, которая может быстро подключать новые CLI, важнее, чем “сколько сейчас поддерживается”…
开始使用 HagiCode
一次安装,几分钟上手
HagiCode for Windows 在 Microsoft Store 免费提供。打开商店即可安装并保持更新;也可以先对比各版本与定价,再决定从哪个渠道开始。