Сабагенты
Creo поддерживает параллельную многоагентную оркестрацию. Основной агент (parent) порождает независимых под-агентов (children) со своими ролями, моделями и инструментами, координируя их через шину событий.
Инструменты
agent — spawn children
Единая точка входа. Spawn'ит одного или нескольких детей, сразу возвращает список.
agent(agents: [
{role: "reviewer", prompt: "...", model: "mini"},
{role: "tester", prompt: "...", tools: ["read","grep","terminal"]}
])
→ [{child_id: "c1", role: "reviewer", status: "running"},
{child_id: "c2", role: "tester", status: "running"}]
Каждый child:
- Создаётся через
session.Manager.CreateChild(как раньше) - Записывается в таблицу
multiagent_children(task_id, role, model, status) - Получает
MultiAgentStartEventв шину → listener запускает agent loop
agent_manage — блокирующий FSM
Parent вызывает agent_manage для ожидания событий от детей и отправки сообщений.
Без messages — блокируется пока кто-то из детей не закончит turn:
agent_manage()
→ [{child_id: "c1", role: "explorer", status: "running"},
{child_id: "c2", role: "reviewer", status: "idle", message: "Мне нужно уточнение..."},
{child_id: "c3", role: "developer", status: "running"}]
С messages — отправляет указанным детям user-сообщения, затем блокируется:
agent_manage(messages: {"developer": "Для тебя вопрос от Reviewer: ABCD"})
FSM шаги: RESUME (crash recovery) → MESSAGES → CHECK (быстрый возврат если есть idle) → BLOCK (подписка на MultiAgentChildIdleEvent) → COLLECT.
agent_abort — остановка детей
agent_abort(abort: ["reviewer", "c3"])
Публикует AbortRequestEvent для указанных детей, ставит status=done.
Bus события
MultiAgentStartEvent — запуск/resume child
Топик: multiagent.start
Издатель: agent tool, agent_manage (для messages и resume)
Подписчик: StartMultiAgentListener → runMultiAgentChild
1type MultiAgentStartEvent struct {
2 ChildSessionID string
3 ParentSessionID string
4 TaskID string
5 Role string
6 Model string
7 TraceID string
8 Message string // initial prompt или resume message
9}
MultiAgentChildIdleEvent — child закончил turn
Топик: multiagent.child_idle
Издатель: runMultiAgentChild (после возврата Agent.Run)
Подписчик: agent_manage (блокируется в ожидании)
1type MultiAgentChildIdleEvent struct {
2 ChildSessionID string
3 ParentSessionID string
4 TaskID string
5}
Listener
StartMultiAgentListener в internal/agent/multiagent.go — подписывается на
TopicMultiAgentStart и запускает каждого child в отдельной goroutine.
Паттерн: как Dream listener (internal/dream/listener.go).
StartMultiAgentListener
└── for ev := range Subscribe[MultiAgentStartEvent]:
go runMultiAgentChild(ev)
├── store.SetStatus(childID, running)
├── sm.Open(childSessionID)
├── LoadRole(globalDir, cwd, role)
├── resolveModelName(cfg, model)
├── llm.NewFromModel(modelCfg)
├── buildMultiAgentRegistry (BuildRegistry - agent - agent_manage - agent_abort)
├── GenerateSystemMessage + role.Prompt
├── agent.New(...).WithAutoApprove().WithCheckpoints(...)
├── relayChildStream / relayChildToolCalls / relayChildApproval (3 goroutine)
├── agent.Run(ctx, childID, "", userMsg)
├── store.SetStatus(childID, idle)
└── bus.Publish(MultiAgentChildIdleEvent{...})
Relay-горутины
Те же 3 relay-горутины что и в старом SubagentRunner — пересылают события child-сессии на parentSessionID для TUI:
graph LR
subgraph Child Session
CT[StreamingToken]
CTC[ToolCall]
CA2[ApprovalRequest]
end
R1[relayChildStream] --> SSE[SubagentStreamEvent]
R2[relayChildToolCalls] --> SSE
R3[relayChildApproval] --> PA2[ApprovalRequest<br/>с parentSessionID<br/>и subagentSessionID]
CT --> R1
CTC --> R2
CA2 --> R3
Роли
JSON-файлы в директориях ролей (например reviewer.json). Поиск ведётся в
трёх местах в порядке приоритета — project перебивает global при совпадении имени:
./agents/— project (высший приоритет)./.creo/agents/— project local~/.config/creo/agents/— global
1{
2 "prompt": "Ты — ревьюер кода. Анализируй изменения...",
3 "model": "mini",
4 "skills": ["code-review-skill"],
5 "tools": ["read", "grep", "glob"]
6}
Содержимое prompt добавляется к system prompt child'а. Поле model разрешается как
"default" / "mini" / имя модели. Поле tools задаёт инструменты для авто-разрешения.
Persistence & Resume
Состояние в таблице multiagent_children:
1CREATE TABLE multiagent_children (
2 child_id TEXT PRIMARY KEY,
3 task_id TEXT NOT NULL,
4 parent_id TEXT NOT NULL,
5 role TEXT NOT NULL,
6 model TEXT,
7 status TEXT NOT NULL DEFAULT 'running',
8 trace_id TEXT NOT NULL,
9 created_at INTEGER NOT NULL,
10 completed_at INTEGER
11);
Crash recovery: agent_manage проверяет session.running flag. Если status=running
но running=0 (процесс убит) → публикует MultiAgentStartEvent для resume.
После перезапуска Creo: listener стартует автоматически. При «продолжи» parent вызывает
agent_manage → RESUME шаг → незавершённые children перезапускаются.
Вложенность
Максимум 1 уровень. Child-сессия не получает инструменты agent, agent_manage, agent_abort
в своём registry — защищает от рекурсии.