diff --git a/.changeset/empty-hoops-tie.md b/.changeset/empty-hoops-tie.md new file mode 100644 index 0000000..93c3abe --- /dev/null +++ b/.changeset/empty-hoops-tie.md @@ -0,0 +1,5 @@ +--- +"opencode-adaptive-thinking": patch +--- + +Preserve the active agent when synthetic prompts adjust reasoning effort and when temporary overrides reset after a session becomes idle. This prevents OpenCode from routing follow-up work to the default agent instead of the agent that initiated the change. diff --git a/src/index.test.ts b/src/index.test.ts index a059845..7c13359 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -117,6 +117,21 @@ describe("AdaptiveThinkingPlugin", () => { expect(system[0]).toContain("set_reasoning_effort"); }); + test("preserves the calling agent when setting reasoning effort", async () => { + const sessionID = "preserve-agent"; + const { client, toolContext } = createClient(sessionID, [createMessage("medium")]); + toolContext.agent = "custom-worker"; + const plugin = await AdaptiveThinkingPlugin({ client } as never); + + await setReasoningEffort(plugin, { level: "high", persist: true }, toolContext); + + expect(client.session.promptAsync).toHaveBeenCalledWith( + expect.objectContaining({ + body: expect.objectContaining({ agent: "custom-worker", variant: "high" }), + }), + ); + }); + test("returns no hooks when disabled", async () => { const { client } = createClient("disabled-plugin"); const plugin = await AdaptiveThinkingPlugin({ client } as never, { enabled: false }); @@ -298,6 +313,7 @@ describe("AdaptiveThinkingPlugin", () => { const secondPrompt = promptCalls[1]?.[0]; expect(secondPrompt).toMatchObject({ body: { + agent: "agent", variant: "medium", parts: [{ ignored: true, synthetic: true }], }, diff --git a/src/index.ts b/src/index.ts index ec6cc14..48ae69b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,6 +11,7 @@ type SessionState = { currentVariant?: string; persistedVariant?: string; temporaryResetVariant?: string; + temporaryResetAgent?: string; }; class SessionStateCache { @@ -83,6 +84,7 @@ export const AdaptiveThinkingPlugin: Plugin = async ({ client }, options) => { sessionID: string, variant: string, text: string, + agent: string, ignored = true, ) => { const body: PromptAsyncBody = { @@ -95,6 +97,7 @@ export const AdaptiveThinkingPlugin: Plugin = async ({ client }, options) => { ignored, }, ], + agent, variant, }; @@ -212,7 +215,7 @@ export const AdaptiveThinkingPlugin: Plugin = async ({ client }, options) => { "Whether to persist the setting for this session, otherwise it will only apply for the remainder of the current turn", ), }, - execute: async ({ level, persist }, { sessionID }) => { + execute: async ({ level, persist }, { sessionID, agent }) => { const validVariants = await resolveValidVariants(sessionID); if (validVariants.length === 0) { return "Failed to set reasoning effort: no valid reasoning effort levels are available for this session"; @@ -230,6 +233,7 @@ export const AdaptiveThinkingPlugin: Plugin = async ({ client }, options) => { sessionID, level, `Reasoning effort set to ${level}`, + agent, ); if (promptResponse.error) { return `Failed to set reasoning effort: ${JSON.stringify(promptResponse.error.data)}`; @@ -240,10 +244,13 @@ export const AdaptiveThinkingPlugin: Plugin = async ({ client }, options) => { if (persist) { entry.persistedVariant = level; delete entry.temporaryResetVariant; + delete entry.temporaryResetAgent; } else if (resetVariant && resetVariant !== level) { entry.temporaryResetVariant = resetVariant; + entry.temporaryResetAgent = agent; } else { delete entry.temporaryResetVariant; + delete entry.temporaryResetAgent; } }); @@ -256,12 +263,14 @@ export const AdaptiveThinkingPlugin: Plugin = async ({ client }, options) => { const sessionID = event.properties.sessionID; const sessionState = state.get(sessionID); const resetVariant = sessionState?.temporaryResetVariant; - if (!resetVariant) return; + const resetAgent = sessionState?.temporaryResetAgent; + if (!resetVariant || !resetAgent) return; const promptResponse = await sendVariantPrompt( sessionID, resetVariant, `Reasoning effort reset to ${resetVariant}.`, + resetAgent, ); if (promptResponse.error) { client.app.log({ @@ -277,6 +286,7 @@ export const AdaptiveThinkingPlugin: Plugin = async ({ client }, options) => { state.update(sessionID, (entry) => { entry.currentVariant = resetVariant; delete entry.temporaryResetVariant; + delete entry.temporaryResetAgent; }); return; }