diff --git a/CHANGELOG.md b/CHANGELOG.md index 56c971afd14..2b4b3f53611 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ Docs: https://docs.openclaw.ai ### Changes +- Agents/Subagents: add an accepted response note for `sessions_spawn` explaining polling subagents are disabled for one-off calls. +- Agents/Subagents: prefix spawned subagent task messages with context to preserve source information in downstream handling. - iOS/Talk: add a `Background Listening` toggle that keeps Talk Mode active while the app is backgrounded (off by default for battery safety). Thanks @zeulewan. - iOS/Talk: harden barge-in behavior by disabling interrupt-on-speech when output route is built-in speaker/receiver, reducing false interruptions from local TTS bleed-through. Thanks @zeulewan. - iOS/Talk: add a `Voice Directive Hint` toggle for Talk Mode prompts so users can disable ElevenLabs voice-switching instructions to save tokens when not needed. (#18250) Thanks @zeulewan. diff --git a/src/agents/openclaw-tools.subagents.sessions-spawn.model.e2e.test.ts b/src/agents/openclaw-tools.subagents.sessions-spawn.model.e2e.test.ts index 2b9df1b5a1c..e81719c5720 100644 --- a/src/agents/openclaw-tools.subagents.sessions-spawn.model.e2e.test.ts +++ b/src/agents/openclaw-tools.subagents.sessions-spawn.model.e2e.test.ts @@ -83,6 +83,7 @@ describe("openclaw-tools: subagents (sessions_spawn model + thinking)", () => { }); expect(result.details).toMatchObject({ status: "accepted", + note: "auto-announces on completion, do not poll", modelApplied: true, }); diff --git a/src/agents/subagent-spawn.ts b/src/agents/subagent-spawn.ts index 189347de9d1..79f802dfeff 100644 --- a/src/agents/subagent-spawn.ts +++ b/src/agents/subagent-spawn.ts @@ -39,10 +39,13 @@ export type SpawnSubagentContext = { requesterAgentIdOverride?: string; }; +export const SUBAGENT_SPAWN_ACCEPTED_NOTE = "auto-announces on completion, do not poll"; + export type SpawnSubagentResult = { status: "accepted" | "forbidden" | "error"; childSessionKey?: string; runId?: string; + note?: string; modelApplied?: boolean; warning?: string; error?: string; @@ -258,6 +261,10 @@ export async function spawnSubagentDirect( childDepth, maxSpawnDepth, }); + const childTaskMessage = [ + `[Subagent Context] You are running as a subagent (depth ${childDepth}/${maxSpawnDepth}). Results auto-announce to your requester; do not busy-poll for status.`, + `[Subagent Task]: ${task}`, + ].join("\n\n"); const childIdem = crypto.randomUUID(); let childRunId: string = childIdem; @@ -265,7 +272,7 @@ export async function spawnSubagentDirect( const response = await callGateway<{ runId: string }>({ method: "agent", params: { - message: task, + message: childTaskMessage, sessionKey: childSessionKey, channel: requesterOrigin?.channel, to: requesterOrigin?.to ?? undefined, @@ -316,6 +323,7 @@ export async function spawnSubagentDirect( status: "accepted", childSessionKey, runId: childRunId, + note: SUBAGENT_SPAWN_ACCEPTED_NOTE, modelApplied: resolvedModel ? modelApplied : undefined, warning: modelWarning, };