From 68ec783e74b59b672dbe14585e892d887adb2bfb Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Thu, 11 Jun 2026 21:03:36 +0900 Subject: [PATCH] fix(agents): project thinking catalog compat --- src/agents/sessions/sdk.test.ts | 22 ++++++++++++-- src/agents/sessions/sdk.ts | 53 ++++++++++++++++++++++++++++----- 2 files changed, 64 insertions(+), 11 deletions(-) diff --git a/src/agents/sessions/sdk.test.ts b/src/agents/sessions/sdk.test.ts index e2da2ebb40cb..d2fef1ed7b44 100644 --- a/src/agents/sessions/sdk.test.ts +++ b/src/agents/sessions/sdk.test.ts @@ -339,7 +339,7 @@ describe("createAgentSession thinking level defaults", () => { provider: "ollama", reasoning: true, params: { canonicalModelId: "qwen3:8b" }, - compat: { thinkingFormat: "ollama" }, + compat: { thinkingFormat: "qwen" }, } satisfies Model; const { session } = await createAgentSession({ model: ollamaModel, @@ -353,7 +353,16 @@ describe("createAgentSession thinking level defaults", () => { expect(thinkingMocks.resolveThinkingDefaultForModel).toHaveBeenCalledWith({ provider: "ollama", model: testModel.id, - catalog: [ollamaModel], + catalog: [ + { + provider: "ollama", + id: testModel.id, + api: ollamaModel.api, + reasoning: true, + params: { canonicalModelId: "qwen3:8b" }, + compat: { thinkingFormat: "qwen" }, + }, + ], }); }); @@ -393,7 +402,14 @@ describe("createAgentSession thinking level defaults", () => { expect(thinkingMocks.resolveThinkingDefaultForModel).toHaveBeenCalledWith({ provider: "ollama", model: testModel.id, - catalog: [customOllamaModel], + catalog: [ + { + provider: "ollama", + id: testModel.id, + api: "ollama", + reasoning: true, + }, + ], }); }); diff --git a/src/agents/sessions/sdk.ts b/src/agents/sessions/sdk.ts index 3033f713de6c..835d337a885f 100644 --- a/src/agents/sessions/sdk.ts +++ b/src/agents/sessions/sdk.ts @@ -4,7 +4,10 @@ * Selects models, wires built-in/custom tools, loads resources, and creates AgentSession instances. */ import { join } from "node:path"; -import { resolveThinkingDefaultForModel } from "../../auto-reply/thinking.js"; +import { + resolveThinkingDefaultForModel, + type ThinkingCatalogEntry, +} from "../../auto-reply/thinking.js"; import { clampThinkingLevel } from "../../llm/model-utils.js"; import { streamSimple } from "../../llm/stream.js"; import type { Message, Model } from "../../llm/types.js"; @@ -42,6 +45,28 @@ import { withFileMutationQueue, } from "./tools/index.js"; +type ThinkingCatalogCompat = NonNullable; + +function projectThinkingCatalogCompat(compat: Model["compat"]) { + if (!compat || typeof compat !== "object") { + return undefined; + } + const record = compat as Record; + const projected: ThinkingCatalogCompat = {}; + if (typeof record.thinkingFormat === "string") { + projected.thinkingFormat = record.thinkingFormat; + } + if (record.supportedReasoningEfforts === null) { + projected.supportedReasoningEfforts = null; + } else if ( + Array.isArray(record.supportedReasoningEfforts) && + record.supportedReasoningEfforts.every((effort) => typeof effort === "string") + ) { + projected.supportedReasoningEfforts = record.supportedReasoningEfforts; + } + return Object.keys(projected).length > 0 ? projected : undefined; +} + export interface CreateAgentSessionOptions { /** Working directory for project-local discovery. Default: process.cwd() */ cwd?: string; @@ -272,13 +297,25 @@ export async function createAgentSession( // Use "off" when a provider explicitly opts out of thinking (e.g. Ollama). Non-off // provider defaults (high, low, adaptive) fall back to DEFAULT_THINKING_LEVEL to avoid // silent cost changes for DeepSeek, OpenRouter, xAI, and other providers. - const resolvedProviderDefault = model - ? resolveThinkingDefaultForModel({ - provider: model.api === "ollama" ? "ollama" : model.provider, - model: model.id, - catalog: [model], - }) - : undefined; + const modelThinkingProvider = model?.api === "ollama" ? "ollama" : model?.provider; + const modelThinkingCompat = model ? projectThinkingCatalogCompat(model.compat) : undefined; + const resolvedProviderDefault = + model && modelThinkingProvider + ? resolveThinkingDefaultForModel({ + provider: modelThinkingProvider, + model: model.id, + catalog: [ + { + provider: modelThinkingProvider, + id: model.id, + api: model.api, + reasoning: model.reasoning, + ...(model.params ? { params: model.params } : {}), + ...(modelThinkingCompat ? { compat: modelThinkingCompat } : {}), + }, + ], + }) + : undefined; const modelThinkingDefault: ThinkingLevel = resolvedProviderDefault === "off" ? "off" : DEFAULT_THINKING_LEVEL;