diff --git a/src/agents/tools/sessions-spawn-tool.test.ts b/src/agents/tools/sessions-spawn-tool.test.ts index 4fe106a7ebd..ab9c94a1693 100644 --- a/src/agents/tools/sessions-spawn-tool.test.ts +++ b/src/agents/tools/sessions-spawn-tool.test.ts @@ -224,24 +224,22 @@ describe("sessions_spawn tool", () => { expect(hoisted.spawnSubagentDirectMock).not.toHaveBeenCalled(); }); - it('rejects streamTo when runtime is not "acp"', async () => { + it('ignores streamTo when runtime is not "acp" (schema-following models may include it)', async () => { const tool = createSessionsSpawnTool({ agentSessionKey: "agent:main:main", }); - const result = await tool.execute("call-3b", { + const result = await tool.execute("call-streamto-ignore", { runtime: "subagent", task: "analyze file", streamTo: "parent", }); expect(result.details).toMatchObject({ - status: "error", + status: "accepted", }); - const details = result.details as { error?: string }; - expect(details.error).toContain("streamTo is only supported for runtime=acp"); + expect(hoisted.spawnSubagentDirectMock).toHaveBeenCalled(); expect(hoisted.spawnAcpDirectMock).not.toHaveBeenCalled(); - expect(hoisted.spawnSubagentDirectMock).not.toHaveBeenCalled(); }); it("keeps attachment content schema unconstrained for llama.cpp grammar safety", () => { diff --git a/src/agents/tools/sessions-spawn-tool.ts b/src/agents/tools/sessions-spawn-tool.ts index b735084d2b0..833e2bf0249 100644 --- a/src/agents/tools/sessions-spawn-tool.ts +++ b/src/agents/tools/sessions-spawn-tool.ts @@ -41,7 +41,9 @@ const SessionsSpawnToolSchema = Type.Object({ mode: optionalStringEnum(SUBAGENT_SPAWN_MODES), cleanup: optionalStringEnum(["delete", "keep"] as const), sandbox: optionalStringEnum(SESSIONS_SPAWN_SANDBOX_MODES), - streamTo: optionalStringEnum(ACP_SPAWN_STREAM_TARGETS), + streamTo: optionalStringEnum(ACP_SPAWN_STREAM_TARGETS, { + description: 'ACP-only. Ignored when runtime != "acp".', + }), // Inline attachments (snapshot-by-value). // NOTE: Attachment contents are redacted from transcript persistence by sanitizeToolCallInputs. @@ -105,7 +107,8 @@ export function createSessionsSpawnTool( const cleanup = params.cleanup === "keep" || params.cleanup === "delete" ? params.cleanup : "keep"; const sandbox = params.sandbox === "require" ? "require" : "inherit"; - const streamTo = params.streamTo === "parent" ? "parent" : undefined; + // Only relevant for ACP. For runtime=subagent, ignore it (schema-following models may still send it). + const streamTo = runtime === "acp" && params.streamTo === "parent" ? "parent" : undefined; // Back-compat: older callers used timeoutSeconds for this tool. const timeoutSecondsCandidate = typeof params.runTimeoutSeconds === "number" @@ -127,12 +130,8 @@ export function createSessionsSpawnTool( }>) : undefined; - if (streamTo && runtime !== "acp") { - return jsonResult({ - status: "error", - error: `streamTo is only supported for runtime=acp; got runtime=${runtime}`, - }); - } + // NOTE: streamTo is ACP-only. For runtime=subagent we intentionally ignore it, + // because schema-following models may include it if it is present in the tool schema. if (resumeSessionId && runtime !== "acp") { return jsonResult({