diff --git a/src/agents/model-selection.ts b/src/agents/model-selection.ts index 09a9ca90547..238b8276504 100644 --- a/src/agents/model-selection.ts +++ b/src/agents/model-selection.ts @@ -14,7 +14,7 @@ export type ModelRef = { model: string; }; -export type ThinkLevel = "off" | "minimal" | "low" | "medium" | "high" | "xhigh"; +export type ThinkLevel = "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "adaptive"; export type ModelAliasIndex = { byAlias: Map; diff --git a/src/agents/openclaw-tools.plugin-context.test.ts b/src/agents/openclaw-tools.plugin-context.test.ts index 45c30bf7ece..3609c0a7940 100644 --- a/src/agents/openclaw-tools.plugin-context.test.ts +++ b/src/agents/openclaw-tools.plugin-context.test.ts @@ -1,6 +1,9 @@ import { describe, expect, it, vi } from "vitest"; -const resolvePluginToolsMock = vi.fn(() => []); +const resolvePluginToolsMock = vi.fn((params?: unknown) => { + void params; + return []; +}); vi.mock("../plugins/tools.js", () => ({ resolvePluginTools: (params: unknown) => resolvePluginToolsMock(params), diff --git a/src/agents/pi-embedded-runner/extra-params.ts b/src/agents/pi-embedded-runner/extra-params.ts index dd7bad46453..75dc4e85324 100644 --- a/src/agents/pi-embedded-runner/extra-params.ts +++ b/src/agents/pi-embedded-runner/extra-params.ts @@ -518,6 +518,9 @@ function mapThinkingLevelToOpenRouterReasoningEffort( if (thinkingLevel === "off") { return "none"; } + if (thinkingLevel === "adaptive") { + return "medium"; + } return thinkingLevel; } @@ -631,6 +634,7 @@ function mapThinkLevelToGoogleThinkingLevel( case "low": return "LOW"; case "medium": + case "adaptive": return "MEDIUM"; case "high": case "xhigh": diff --git a/src/agents/pi-embedded-runner/utils.ts b/src/agents/pi-embedded-runner/utils.ts index 07fba6458c3..9bac18ee7b4 100644 --- a/src/agents/pi-embedded-runner/utils.ts +++ b/src/agents/pi-embedded-runner/utils.ts @@ -6,6 +6,13 @@ export function mapThinkingLevel(level?: ThinkLevel): ThinkingLevel { if (!level) { return "off"; } + // "adaptive" maps to "medium" at the pi-agent-core layer. The Pi SDK + // provider then translates this to `thinking.type: "adaptive"` with + // `output_config.effort: "medium"` for models that support it (Opus 4.6, + // Sonnet 4.6). + if (level === "adaptive") { + return "medium"; + } return level; } diff --git a/src/auto-reply/thinking.test.ts b/src/auto-reply/thinking.test.ts index 4588eee791e..90aede76047 100644 --- a/src/auto-reply/thinking.test.ts +++ b/src/auto-reply/thinking.test.ts @@ -33,6 +33,12 @@ describe("normalizeThinkLevel", () => { it("accepts on as low", () => { expect(normalizeThinkLevel("on")).toBe("low"); }); + + it("accepts adaptive and auto aliases", () => { + expect(normalizeThinkLevel("adaptive")).toBe("adaptive"); + expect(normalizeThinkLevel("auto")).toBe("adaptive"); + expect(normalizeThinkLevel("Adaptive")).toBe("adaptive"); + }); }); describe("listThinkingLevels", () => { @@ -54,6 +60,11 @@ describe("listThinkingLevels", () => { it("excludes xhigh for non-codex models", () => { expect(listThinkingLevels(undefined, "gpt-4.1-mini")).not.toContain("xhigh"); }); + + it("always includes adaptive", () => { + expect(listThinkingLevels(undefined, "gpt-4.1-mini")).toContain("adaptive"); + expect(listThinkingLevels("anthropic", "claude-opus-4-6")).toContain("adaptive"); + }); }); describe("listThinkingLevelLabels", () => { diff --git a/src/auto-reply/thinking.ts b/src/auto-reply/thinking.ts index 5a13c5a0920..0342e6fe7b2 100644 --- a/src/auto-reply/thinking.ts +++ b/src/auto-reply/thinking.ts @@ -1,4 +1,4 @@ -export type ThinkLevel = "off" | "minimal" | "low" | "medium" | "high" | "xhigh"; +export type ThinkLevel = "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "adaptive"; export type VerboseLevel = "off" | "on" | "full"; export type NoticeLevel = "off" | "on" | "full"; export type ElevatedLevel = "off" | "on" | "ask" | "full"; @@ -45,6 +45,9 @@ export function normalizeThinkLevel(raw?: string | null): ThinkLevel | undefined } const key = raw.trim().toLowerCase(); const collapsed = key.replace(/[\s_-]+/g, ""); + if (collapsed === "adaptive" || collapsed === "auto") { + return "adaptive"; + } if (collapsed === "xhigh" || collapsed === "extrahigh") { return "xhigh"; } @@ -91,6 +94,7 @@ export function listThinkingLevels(provider?: string | null, model?: string | nu if (supportsXHighThinking(provider, model)) { levels.push("xhigh"); } + levels.push("adaptive"); return levels; } diff --git a/src/config/types.agent-defaults.ts b/src/config/types.agent-defaults.ts index 5444f9e9950..7a7526948cc 100644 --- a/src/config/types.agent-defaults.ts +++ b/src/config/types.agent-defaults.ts @@ -171,7 +171,7 @@ export type AgentDefaultsConfig = { /** Vector memory search configuration (per-agent overrides supported). */ memorySearch?: MemorySearchConfig; /** Default thinking level when no /think directive is present. */ - thinkingDefault?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh"; + thinkingDefault?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "adaptive"; /** Default verbose level when no /verbose directive is present. */ verboseDefault?: "off" | "on" | "full"; /** Default elevated level when no /elevated directive is present. */ diff --git a/src/config/zod-schema.agent-defaults.ts b/src/config/zod-schema.agent-defaults.ts index 0f60ab980f4..e2381093492 100644 --- a/src/config/zod-schema.agent-defaults.ts +++ b/src/config/zod-schema.agent-defaults.ts @@ -125,6 +125,7 @@ export const AgentDefaultsSchema = z z.literal("medium"), z.literal("high"), z.literal("xhigh"), + z.literal("adaptive"), ]) .optional(), verboseDefault: z.union([z.literal("off"), z.literal("on"), z.literal("full")]).optional(), diff --git a/src/secrets/runtime.test.ts b/src/secrets/runtime.test.ts index 113b1807cd6..e569dc24d65 100644 --- a/src/secrets/runtime.test.ts +++ b/src/secrets/runtime.test.ts @@ -169,7 +169,7 @@ describe("secrets runtime snapshot", () => { key: { source: "env", provider: "default", id: "SHADOW_KEY" }, }, }, - }) as AuthProfileStore, + }) as unknown as AuthProfileStore, }); const profile = snapshot.authStores[0]?.store.profiles["custom:explicit-keyref"] as Record<