# 04 — Sub-agents + A2A между агентами Точки 2 и 3 из планов. Orchestrator-агент spawn'ит sub-агентов с изолированным контекстом. Независимые агенты общаются через A2A. ![Sub-agents + A2A](./04-sub-agents.svg) PlantUML source (для редактирования; требует Graphviz `dot` для рендеринга): ```plantuml @startuml sub-agents-and-a2a skinparam componentStyle rectangle title Sub-agents + A2A между агентами (точка 2+3 из планов) ' --- Orchestrator --- rectangle "OrchestratorAgent\n(BaseAgent + tools)" as Orch { rectangle "ConversationLoop\n(main user)" as MainConv } ' --- Sub-agent spawn --- rectangle "subAgent(\n task: String,\n config: AgentConfig\n): Flow" as SpawnAPI note right of SpawnAPI Spawn API — НЕ отдельный модуль, а convenience поверх BaseAgent: val sub = agent.spawnChild(config) { systemPrompt = "..." tools = [ReadTool, WriteTool] memory = EmptyMemory // изолированно } sub.events.collect { ... } end note ' --- Дочерний агент (изолированный контекст) --- rectangle "SubAgent\n(изолированный scope)" as Sub { rectangle "ConversationLoop\n(child)" as SubConv rectangle "backgroundScope\n(lifecycle scoped)" as SubBg } ' --- A2A между независимыми агентами --- rectangle "Agent A\n(BaseAgent)" as AgentA rectangle "Agent B\n(BaseAgent)" as AgentB rectangle "A2A Server\n(:a2a-server)" as A2ASrv AgentA -> A2ASrv : POST /\n(application/json) A2ASrv -> AgentB : dispatch(message) AgentB --> A2ASrv : response A2ASrv --> AgentA : SSE / JSON-RPC ' --- Стрелки --- Orch -> SpawnAPI : calls SpawnAPI -> Sub : creates with custom config Sub -> SubBg : has its own Orch -> Orch : main flow continues Sub --> Orch : Flow emits\n(Started / ToolCalled / ToolResult /\nAssistantMessage / Done / Failed) Orch -> A2ASrv : can also delegate to remote agent @enduml ``` ## Sub-agents API ```kotlin sealed interface SubAgentEvent { data class Started(val taskId: String) : SubAgentEvent data class AssistantMessage(val text: String) : SubAgentEvent data class ToolCalled(val toolName: String, val args: JsonObject) : SubAgentEvent data class ToolResult(val toolName: String, val result: String) : SubAgentEvent data class Done(val taskId: String, val finalResult: String) : SubAgentEvent data class Failed(val taskId: String, val error: String) : SubAgentEvent } interface BaseAgent { // ... existing methods ... /** * Spawn дочерний агент с изолированным контекстом (memory, system prompt, * tools). Возвращает Flow событий жизненного цикла + результата. * Cancellation родителя НЕ отменяет sub-agent — sub-agent живёт до Done/Failed. */ fun spawnChild(config: SubAgentConfig): Flow } data class SubAgentConfig( val systemPrompt: String, val tools: List = emptyList(), val memory: MemorySystem = EmptyMemory(), val model: LiteLlm? = null, // если null — делит LLM родителя val maxTurns: Int = 10, val timeoutMs: Long = 60_000, ) ``` ## Зачем изолированный scope Sub-agent получает **свою копию контекста**, не делит memory с родителем. Это критично: - `research_subagent` — должен исследовать тему, не отвечать на основные сообщения пользователя - `summarize_subagent` — суммаризировать документ, не трогать основной диалог - `code_review_subagent` — ревьюить PR, не видеть разговор Если нужно расшарить контекст — это explicit через `sharedMemory: SharedMemoryHandle` параметр, не default. ## A2A между независимыми агентами Уже есть `:a2a-server` модуль (см. `standalone/build.gradle.kts` — `implementation(libs.a2a.server)`). Использовался для AG-UI/A2A протокола в `:standalone`. Можно переиспользовать для межагентного общения. Сценарий: orchestrator-agent не может сам решить задачу → делегирует remote-агенту через A2A → получает response → продолжает. Это уже работающая инфраструктура. ## Текущее состояние vs целевое ✅ Уже есть: - `:a2a-server` подключён - `BaseAgent.spawnChild` — **не существует**, но `ConversationLoop` уже умеет создавать изолированный scope через свой `agentScope` — нужна только обёртка ⏳ Не сделано: - `SubAgentConfig` + `Flow` API - `EmptyMemory` (null-object для изолированного scope) - Lifecycle management (parent dies → child должен complete or be cancelled?) - Сериализация sub-agent state для отладки (event log)