diff --git a/src/features/background-agent/spawner.test.ts b/src/features/background-agent/spawner.test.ts index d3896e55f..0d996ec19 100644 --- a/src/features/background-agent/spawner.test.ts +++ b/src/features/background-agent/spawner.test.ts @@ -466,4 +466,58 @@ describe("background-agent spawner fallback model promotion", () => { }) expect(promptCalls[0]?.body?.variant).toBe("medium") }) + + test("strips leading zwsp from prompt body agent before promptAsync", async () => { + //#given + const promptCalls: Array<{ body?: { agent?: string } }> = [] + + const client = { + session: { + get: async () => ({ data: { directory: "/parent/dir" } }), + create: async () => ({ data: { id: "ses_child_clean_agent" } }), + promptAsync: async (args?: { body?: { agent?: string } }) => { + promptCalls.push(args ?? {}) + return {} + }, + }, + } + + const task = createTask({ + description: "Test task", + prompt: "Do work", + agent: "\u200Bsisyphus-junior", + parentSessionID: "ses_parent", + parentMessageID: "msg_parent", + }) + + const item = { + task, + input: { + description: task.description, + prompt: task.prompt, + agent: task.agent, + parentSessionID: task.parentSessionID, + parentMessageID: task.parentMessageID, + parentModel: task.parentModel, + parentAgent: task.parentAgent, + model: task.model, + }, + } + + const ctx = { + client, + directory: "/fallback", + concurrencyManager: { release: () => {} }, + tmuxEnabled: false, + onTaskError: () => {}, + } + + //#when + await startTask(item as any, ctx as any) + await new Promise((resolve) => setTimeout(resolve, 0)) + + //#then + expect(promptCalls).toHaveLength(1) + expect(promptCalls[0]?.body?.agent).toBe("sisyphus-junior") + }) }) diff --git a/src/features/background-agent/spawner.ts b/src/features/background-agent/spawner.ts index 3c2fd7e73..b549c706b 100644 --- a/src/features/background-agent/spawner.ts +++ b/src/features/background-agent/spawner.ts @@ -6,6 +6,7 @@ import { applySessionPromptParams } from "../../shared/session-prompt-params-hel import { subagentSessions } from "../claude-code-session-state" import { getTaskToastManager } from "../task-toast-manager" import { isInsideTmux } from "../../shared/tmux" +import { stripAgentListSortPrefix } from "../../shared/agent-display-names" import type { ConcurrencyManager } from "./concurrency" export const FALLBACK_AGENT = "general" @@ -168,11 +169,12 @@ export async function startTask( } : undefined const launchVariant = input.model?.variant + const normalizedAgent = stripAgentListSortPrefix(input.agent) applySessionPromptParams(sessionID, input.model) const promptBody = { - agent: input.agent, + agent: normalizedAgent, ...(launchModel ? { model: launchModel } : {}), ...(launchVariant ? { variant: launchVariant } : {}), system: input.skillContent, @@ -180,7 +182,7 @@ export async function startTask( task: false, call_omo_agent: true, question: false, - ...getAgentToolRestrictions(input.agent), + ...getAgentToolRestrictions(normalizedAgent), }, parts: [createInternalAgentTextPart(input.prompt)], } diff --git a/src/tools/delegate-task/background-task.test.ts b/src/tools/delegate-task/background-task.test.ts index 0d95dd1dd..84a7bc644 100644 --- a/src/tools/delegate-task/background-task.test.ts +++ b/src/tools/delegate-task/background-task.test.ts @@ -204,6 +204,50 @@ describeFn("executeBackgroundTask output/session metadata compatibility", () => ]) }) + testFn("strips leading zwsp from agent name before launching background task", async () => { + //#given - display-sorted agent names should be normalized before manager launch + const launchCalls: unknown[] = [] + const manager = { + launch: async (input: unknown) => { + launchCalls.push(input) + return { + id: "bg_clean_agent", + sessionID: "ses_clean_agent", + description: "Clean agent", + agent: "sisyphus-junior", + status: "running", + } + }, + getTask: () => ({ sessionID: "ses_clean_agent" }), + } + + //#when + await executeBackgroundTask( + { + description: "Clean agent", + prompt: "check", + run_in_background: true, + load_skills: [], + }, + { + sessionID: "ses_parent", + callID: "call_clean_agent", + metadata: async () => {}, + abort: new AbortController().signal, + }, + { manager }, + { sessionID: "ses_parent", messageID: "msg_clean_agent" }, + "\u200Bsisyphus-junior", + undefined, + undefined, + undefined, + ) + + //#then + expectFn(launchCalls).toHaveLength(1) + expectFn((launchCalls[0] as { agent: string }).agent).toBe("sisyphus-junior") + }) + testFn("keeps launched background task alive when parent aborts before session id resolves", async () => { //#given - parallel tool execution can abort the parent call after launch succeeds const metadataCalls: any[] = [] diff --git a/src/tools/delegate-task/background-task.ts b/src/tools/delegate-task/background-task.ts index 0dbb042ab..184325ec9 100644 --- a/src/tools/delegate-task/background-task.ts +++ b/src/tools/delegate-task/background-task.ts @@ -10,6 +10,7 @@ import { getSessionTools } from "../../shared/session-tools-store" import { SessionCategoryRegistry } from "../../shared/session-category-registry" import { QUESTION_DENIED_SESSION_PERMISSION } from "../../shared/question-denied-session-permission" import { setSessionFallbackChain } from "../../hooks/model-fallback/hook" +import { stripAgentListSortPrefix } from "../../shared/agent-display-names" function continueSessionSetup(args: { taskID: string @@ -62,11 +63,12 @@ export async function executeBackgroundTask( try { const tddEnabled = executorCtx.sisyphusAgentConfig?.tdd - const effectivePrompt = buildTaskPrompt(args.prompt, agentToUse, tddEnabled) + const normalizedAgent = stripAgentListSortPrefix(agentToUse) + const effectivePrompt = buildTaskPrompt(args.prompt, normalizedAgent, tddEnabled) const task = await manager.launch({ description: args.description, prompt: effectivePrompt, - agent: agentToUse, + agent: normalizedAgent, parentSessionID: parentContext.sessionID, parentMessageID: parentContext.messageID, parentModel: parentContext.model, @@ -156,7 +158,7 @@ Do NOT call background_output now. Wait for notification first return formatDetailedError(error, { operation: "Launch background task", args, - agent: agentToUse, + agent: stripAgentListSortPrefix(agentToUse), category: args.category, }) }