From 4c22d6de769a810e5ac6b25c10b207cba4b37fce Mon Sep 17 00:00:00 2001 From: justsisyphus Date: Thu, 15 Jan 2026 14:30:48 +0900 Subject: [PATCH] fix(todo-continuation): preserve model when injecting continuation prompt --- src/hooks/todo-continuation-enforcer.test.ts | 22 ++++++++++++++++++++ src/hooks/todo-continuation-enforcer.ts | 10 ++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/hooks/todo-continuation-enforcer.test.ts b/src/hooks/todo-continuation-enforcer.test.ts index e680cfd6..2f693b8c 100644 --- a/src/hooks/todo-continuation-enforcer.test.ts +++ b/src/hooks/todo-continuation-enforcer.test.ts @@ -807,4 +807,26 @@ describe("todo-continuation-enforcer", () => { // #then - no continuation (API fallback detected the abort) expect(promptCalls).toHaveLength(0) }) + + test("should pass model property in prompt call (undefined when no message context)", async () => { + // #given - session with incomplete todos, no prior message context available + const sessionID = "main-model-preserve" + setMainSession(sessionID) + + const hook = createTodoContinuationEnforcer(createMockPluginInput(), { + backgroundManager: createMockBackgroundManager(false), + }) + + // #when - session goes idle and continuation is injected + await hook.handler({ + event: { type: "session.idle", properties: { sessionID } }, + }) + + await new Promise(r => setTimeout(r, 2500)) + + // #then - prompt call made, model is undefined when no context (expected behavior) + expect(promptCalls.length).toBe(1) + expect(promptCalls[0].text).toContain("TODO CONTINUATION") + expect("model" in promptCalls[0]).toBe(true) + }) }) diff --git a/src/hooks/todo-continuation-enforcer.ts b/src/hooks/todo-continuation-enforcer.ts index b551a7ca..0c4966ea 100644 --- a/src/hooks/todo-continuation-enforcer.ts +++ b/src/hooks/todo-continuation-enforcer.ts @@ -206,14 +206,18 @@ export function createTodoContinuationEnforcer( const prompt = `${CONTINUATION_PROMPT}\n\n[Status: ${todos.length - freshIncompleteCount}/${todos.length} completed, ${freshIncompleteCount} remaining]` - try { - log(`[${HOOK_NAME}] Injecting continuation`, { sessionID, agent: prevMessage?.agent, incompleteCount: freshIncompleteCount }) + const model = prevMessage?.model?.providerID && prevMessage?.model?.modelID + ? { providerID: prevMessage.model.providerID, modelID: prevMessage.model.modelID } + : undefined + + try { + log(`[${HOOK_NAME}] Injecting continuation`, { sessionID, agent: prevMessage?.agent, model, incompleteCount: freshIncompleteCount }) - // Don't pass model - let OpenCode use session's existing lastModel await ctx.client.session.prompt({ path: { id: sessionID }, body: { agent: prevMessage?.agent, + ...(model !== undefined ? { model } : {}), parts: [{ type: "text", text: prompt }], }, query: { directory: ctx.directory },