Forge
markdowndeeb25a2
1# ADR 0016: Внешний агент по Agent Client Protocol (stdio, Cursor CLI)
2
3**Статус:** Accepted · Implemented
4**Дата:** 2026-04-05
5## Связанные ADR
6
7| ADR | Роль |
8|-----|------|
9| [0008](0008-mcp-contracts-and-testable-infrastructure.md) | MCP — **другой** контур: сервер инструментов IDE; не путать с ACP |
10
11### Вне ADR
12
13| Документ | Роль |
14|----------|------|
15| [note-acp-cascade-cursor-v1.md](../ui-ux/note-acp-cascade-cursor-v1.md) | терминология и ссылки на спецификацию |
16| [concept-pfd-mfd-cascade-v1.md](../ui-ux/concept-pfd-mfd-cascade-v1.md) | concept pfd mfd cascade v1 |
17
18### Снимок реализации
19
20| Элемент | Значение |
21|---------|----------|
22| — | Cursor ACP / stdio в чате и настройках; ортогонально MCP — см. текст |
23
24---
25## Контекст
26
27Нужна связь встроенного чата CascadeIDE с **внешним** агентом (в первую очередь **Cursor** через официальный CLI и режим ACP), без встраивания UI Cursor и без собственного провода «с нуля».
28
29**Agent Client Protocol (ACP)** — открытый контракт клиент↔агент (JSON-RPC по строкам, типичный транспорт **stdio**). PoC пройден: ответы в чате, русский текст, сессия и обратные вызовы к IDE (fs, terminal) по спецификации.
30
31## Решение
32
331. **Транспорт:** подпроцесс `cursor-agent` (или эквивалент из пакета dist-package) с аргументом **`acp`**, **stdin/stdout** для протокола, без консольного окна (`CreateNoWindow`), перенаправление потоков.
34
352. **Кодировка:** для **Windows** явно задавать **UTF-8** для перенаправленных stdin/stdout/stderr процесса агента (и для дочерних процессов ACP-terminal), иначе ответы на русском декодируются в OEM и дают «кракозябры».
36
373. **Клиентский SDK:** библиотека **AgentClientProtocol** (community, upstream [acp-csharp](https://github.com/nuskey8/acp-csharp)) — **вендор** в `externals/acp-csharp/` как исходники, подключаются через `ProjectReference`. Исходники под `externals/**/*.cs` **не** компилируются в основной сборке IDE (`Compile Remove` в `CascadeIDE.csproj`), чтобы вложенный sandbox с top-level `Main` не перехватывал точку входа приложения.
38
394. **Интеграция в продукт:** отдельный провайдер чата (**Cursor ACP**), настройка пути к `cursor-agent.cmd` или к каталогу с `dist-package`; жизненный цикл сессии ACP и зеркалирование terminal/fs — в `Services/CursorAcp/`.
40
415. **Аутентификация Cursor:** не интерактивно внутри WinExe-чата при первом запуске; пользователь проходит **`agent login` / API key** в обычном терминале или через переменные окружения (как в документации Cursor). Ошибки агента до UI — по мере развития можно дублировать stderr в чат/лог (не часть этого ADR).
42
436. **Границы:** ACP — про **диалог с внешним агентом**. MCP-сервер IDE (`--mcp-stdio`, инструменты для агента) остаётся отдельным контуром ([0008](0008-mcp-contracts-and-testable-infrastructure.md)); объединение сценариев — последующими итерациями.
44
45## Последствия
46
47- Обновления upstream `acp-csharp` — осознанный merge/вендоринг; при смене major спецификации ACP — проверка совместимости с `cursor-agent`.
48- Зависимость от формата CLI Cursor (аргумент `acp`); при изменениях документации Cursor — регрессия вручную или смоук-сценарий.
49- Дублирование типов при ошибочном включении исходников SDK и ссылки на пакет — предотвращается `Compile Remove` для `externals`.
50
51## Отклонённые альтернативы
52
53- **Только Ollama / только локальные LLM без ACP** — остаётся другим провайдером; не покрывает сценарий «тот же агент, что в Cursor».
54- **Свой бинарный протокол поверх stdio** — отклонён в пользу стандарта ACP и готового клиентского SDK.
55- **Встраивание webview Cursor** — вне scope десктопного клиента ACP.
56
57## Обсуждение (не блокирует Accepted)
58
59- Подмодуль вместо вендоринга `externals/acp-csharp` — возможна миграция при стабилизации процесса обновлений.
60- Вывод stderr агента в UI чата при ошибках и «Authentication required».
61
View only · write via MCP/CIDE