diff --git a/packages/coding-agent/src/modes/rpc/rpc-client.ts b/packages/coding-agent/src/modes/rpc/rpc-client.ts index f401d3922..3fa485aa7 100644 --- a/packages/coding-agent/src/modes/rpc/rpc-client.ts +++ b/packages/coding-agent/src/modes/rpc/rpc-client.ts @@ -4,7 +4,7 @@ * Spawns the agent in RPC mode and provides a typed API for all operations. */ import type { AgentEvent, AgentMessage, ThinkingLevel } from "@oh-my-pi/pi-agent-core"; -import type { Effort, ImageContent, Model } from "@oh-my-pi/pi-ai"; +import type { ImageContent, Model } from "@oh-my-pi/pi-ai"; import { isRecord, ptree, readJsonl } from "@oh-my-pi/pi-utils"; import type { BashResult } from "../../exec/bash-executor"; import type { SessionStats } from "../../session/agent-session"; @@ -304,7 +304,7 @@ export class RpcClient { /** * Cycle thinking level. */ - async cycleThinkingLevel(): Promise<{ level: Effort } | null> { + async cycleThinkingLevel(): Promise<{ level: ThinkingLevel } | null> { const response = await this.#send({ type: "cycle_thinking_level" }); return this.#getData(response); } diff --git a/packages/coding-agent/src/session/agent-session.ts b/packages/coding-agent/src/session/agent-session.ts index c5d120285..434f16871 100644 --- a/packages/coding-agent/src/session/agent-session.ts +++ b/packages/coding-agent/src/session/agent-session.ts @@ -2905,14 +2905,12 @@ export class AgentSession { * Cycle to next thinking level. * @returns New level, or undefined if model doesn't support thinking */ - cycleThinkingLevel(): Effort | undefined { + cycleThinkingLevel(): ThinkingLevel | undefined { if (!this.model?.reasoning) return undefined; - const levels = this.getAvailableThinkingLevels(); - const currentIndex = - this.thinkingLevel && this.thinkingLevel !== ThinkingLevel.Off && this.thinkingLevel !== ThinkingLevel.Inherit - ? levels.indexOf(this.thinkingLevel) - : -1; + const levels = [ThinkingLevel.Off, ...this.getAvailableThinkingLevels()]; + const currentLevel = this.thinkingLevel === ThinkingLevel.Inherit ? ThinkingLevel.Off : this.thinkingLevel; + const currentIndex = currentLevel ? levels.indexOf(currentLevel) : -1; const nextIndex = (currentIndex + 1) % levels.length; const nextLevel = levels[nextIndex]; if (!nextLevel) return undefined; diff --git a/packages/coding-agent/test/agent-session-role-thinking.test.ts b/packages/coding-agent/test/agent-session-role-thinking.test.ts index f99bcb6d2..81a7221a3 100644 --- a/packages/coding-agent/test/agent-session-role-thinking.test.ts +++ b/packages/coding-agent/test/agent-session-role-thinking.test.ts @@ -196,4 +196,34 @@ describe("AgentSession role model thinking behavior", () => { expect(session.thinkingLevel).toBe(Effort.High); expect(session.getAvailableThinkingLevels()).not.toContain("xhigh"); }); + + it("cycles through off before returning to effort levels", async () => { + const model = getAnthropicModelOrThrow("claude-sonnet-4-5"); + + const agent = new Agent({ + initialState: { + model, + systemPrompt: "Test", + tools: [], + messages: [], + thinkingLevel: Effort.High, + }, + }); + const authStorage = await AuthStorage.create(path.join(tempDir.path(), "testauth-cycle-thinking.db")); + authStorage.setRuntimeApiKey("anthropic", "test-key"); + const modelRegistry = new ModelRegistry(authStorage, path.join(tempDir.path(), "models-cycle-thinking.yml")); + + sessionSettings = Settings.isolated(); + session = new AgentSession({ + agent, + sessionManager: SessionManager.inMemory(), + settings: sessionSettings, + modelRegistry, + }); + + expect(session.cycleThinkingLevel()).toBe("off"); + expect(session.thinkingLevel).toBe("off"); + expect(session.cycleThinkingLevel()).toBe(Effort.Minimal); + expect(session.thinkingLevel).toBe(Effort.Minimal); + }); });