diff --git a/src/features/background-agent/manager.test.ts b/src/features/background-agent/manager.test.ts index 304cf99dd4..b4cc496f24 100644 --- a/src/features/background-agent/manager.test.ts +++ b/src/features/background-agent/manager.test.ts @@ -1036,6 +1036,93 @@ describe("BackgroundManager.resume concurrency key", () => { }) }) +describe("BackgroundManager.resume model persistence", () => { + let manager: BackgroundManager + let promptCalls: Array<{ path: { id: string }; body: Record }> + + beforeEach(() => { + // #given + promptCalls = [] + const client = { + session: { + prompt: async (args: { path: { id: string }; body: Record }) => { + promptCalls.push(args) + return {} + }, + }, + } + manager = new BackgroundManager({ client, directory: tmpdir() } as unknown as PluginInput) + stubNotifyParentSession(manager) + }) + + afterEach(() => { + manager.shutdown() + }) + + test("should pass model when task has a configured model", async () => { + // #given - task with model from category config + const taskWithModel: BackgroundTask = { + id: "task-with-model", + sessionID: "session-1", + parentSessionID: "parent-session", + parentMessageID: "msg-1", + description: "task with model override", + prompt: "original prompt", + agent: "explore", + status: "completed", + startedAt: new Date(), + completedAt: new Date(), + model: { providerID: "anthropic", modelID: "claude-sonnet-4-20250514" }, + concurrencyGroup: "explore", + } + getTaskMap(manager).set(taskWithModel.id, taskWithModel) + + // #when + await manager.resume({ + sessionId: "session-1", + prompt: "continue the work", + parentSessionID: "parent-session-2", + parentMessageID: "msg-2", + }) + + // #then - model should be passed in prompt body + expect(promptCalls).toHaveLength(1) + expect(promptCalls[0].body.model).toEqual({ providerID: "anthropic", modelID: "claude-sonnet-4-20250514" }) + expect(promptCalls[0].body.agent).toBe("explore") + }) + + test("should NOT pass model when task has no model (backward compatibility)", async () => { + // #given - task without model (default behavior) + const taskWithoutModel: BackgroundTask = { + id: "task-no-model", + sessionID: "session-2", + parentSessionID: "parent-session", + parentMessageID: "msg-1", + description: "task without model", + prompt: "original prompt", + agent: "explore", + status: "completed", + startedAt: new Date(), + completedAt: new Date(), + concurrencyGroup: "explore", + } + getTaskMap(manager).set(taskWithoutModel.id, taskWithoutModel) + + // #when + await manager.resume({ + sessionId: "session-2", + prompt: "continue the work", + parentSessionID: "parent-session-2", + parentMessageID: "msg-2", + }) + + // #then - model should NOT be in prompt body + expect(promptCalls).toHaveLength(1) + expect("model" in promptCalls[0].body).toBe(false) + expect(promptCalls[0].body.agent).toBe("explore") + }) +}) + describe("BackgroundManager process cleanup", () => { test("should remove listeners after last shutdown", () => { // #given diff --git a/src/features/background-agent/manager.ts b/src/features/background-agent/manager.ts index 39ead85ee8..184302ad32 100644 --- a/src/features/background-agent/manager.ts +++ b/src/features/background-agent/manager.ts @@ -397,15 +397,17 @@ export class BackgroundManager { log("[background-agent] Resuming task - calling prompt (fire-and-forget) with:", { sessionID: existingTask.sessionID, agent: existingTask.agent, + model: existingTask.model, promptLength: input.prompt.length, }) - // Note: Don't pass model in body - use agent's configured model instead // Use prompt() instead of promptAsync() to properly initialize agent loop + // Include model if task has one (preserved from original launch with category config) this.client.session.prompt({ path: { id: existingTask.sessionID }, body: { agent: existingTask.agent, + ...(existingTask.model ? { model: existingTask.model } : {}), tools: { ...getAgentToolRestrictions(existingTask.agent), task: false,