From 5788359cdb9e21ef0940f5fea6349f9bf5a7b802 Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 30 Apr 2026 16:22:30 -0500 Subject: [PATCH] fix: route child session events to parent ACP session ACPSessionManager only tracked sessions created via session/new or session/load. Child sessions spawned by the Task tool via Session.create({ parentID: ... }) were never registered, causing handleEvent() to silently drop all sub-agent events (tool calls, text streaming, permission requests). Added childToRoot map in ACPSessionManager to resolve child session IDs to their root ACP session. Added session.created handler in agent.ts to register child sessions when the Task tool spawns them, and session.deleted handler for cleanup. Closes #21802 --- packages/opencode/src/acp/agent.ts | 13 +++++++++++++ packages/opencode/src/acp/session.ts | 21 ++++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/packages/opencode/src/acp/agent.ts b/packages/opencode/src/acp/agent.ts index af16cba114fe..1732251f9d16 100644 --- a/packages/opencode/src/acp/agent.ts +++ b/packages/opencode/src/acp/agent.ts @@ -189,6 +189,19 @@ export class Agent implements ACPAgent { private async handleEvent(event: Event) { switch (event.type) { + case "session.created": { + const info = event.properties.info + if (info.parentID) { + this.sessionManager.registerChild(event.properties.sessionID, info.parentID) + } + return + } + + case "session.deleted": { + this.sessionManager.unregisterChild(event.properties.sessionID) + return + } + case "permission.asked": { const permission = event.properties const session = this.sessionManager.tryGet(permission.sessionID) diff --git a/packages/opencode/src/acp/session.ts b/packages/opencode/src/acp/session.ts index d932b65701a4..8840ef00ccff 100644 --- a/packages/opencode/src/acp/session.ts +++ b/packages/opencode/src/acp/session.ts @@ -8,13 +8,32 @@ const log = Log.create({ service: "acp-session-manager" }) export class ACPSessionManager { private sessions = new Map() private sdk: OpencodeClient + private childToRoot = new Map() constructor(sdk: OpencodeClient) { this.sdk = sdk } tryGet(sessionId: string): ACPSessionState | undefined { - return this.sessions.get(sessionId) + const direct = this.sessions.get(sessionId) + if (direct) return direct + const rootId = this.childToRoot.get(sessionId) + if (rootId) return this.sessions.get(rootId) + return undefined + } + + registerChild(childSessionID: string, parentSessionID: string) { + const rootId = + this.childToRoot.get(parentSessionID) ?? + (this.sessions.has(parentSessionID) ? parentSessionID : undefined) + if (rootId) { + this.childToRoot.set(childSessionID, rootId) + log.info("registered child session", { child: childSessionID, root: rootId }) + } + } + + unregisterChild(childSessionID: string) { + this.childToRoot.delete(childSessionID) } async create(cwd: string, mcpServers: McpServer[], model?: ACPSessionState["model"]): Promise {