From 5cada3028991943cc2dfd172c521493759e687b4 Mon Sep 17 00:00:00 2001 From: fanghanjun <17737663888@163.com> Date: Wed, 15 Apr 2026 04:00:38 -0700 Subject: [PATCH] fix(core): always use preset baseUrl/api in resolveServiceModel pi-ai's built-in model objects may have different baseUrl (e.g. international endpoint) or api format (e.g. anthropic-messages) than our configured presets. Always construct our own model object using preset values, only inheriting metadata (reasoning, cost, contextWindow) from pi-ai. Co-Authored-By: Claude Opus 4.6 (1M context) --- packages/core/src/llm/service-resolver.ts | 53 ++++++++++++----------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/packages/core/src/llm/service-resolver.ts b/packages/core/src/llm/service-resolver.ts index 3681db28..0142e7c3 100644 --- a/packages/core/src/llm/service-resolver.ts +++ b/packages/core/src/llm/service-resolver.ts @@ -31,33 +31,36 @@ export async function resolveServiceModel( const preset = resolveServicePreset(baseService); const piProvider = SERVICE_TO_PI_PROVIDER[baseService] ?? "openai"; - // Get pi-ai Model — may return undefined for model IDs not in the built-in registry - let model = getModel(piProvider as any, modelId as any) as Model | undefined; + // Resolve baseUrl: prefer custom/configured URL, then preset, then pi-ai's built-in + const apiType = service.startsWith("custom:") + ? (customApiFormat === "responses" ? "openai-responses" : "openai-completions") + : (preset?.api ?? "openai-completions"); + const baseUrl = customBaseUrl ?? preset?.baseUrl ?? ""; - if (!model) { - // Construct a Model object from service preset for models not in pi-ai's registry - const apiType = service.startsWith("custom:") - ? (customApiFormat === "responses" ? "openai-responses" : "openai-completions") - : (preset?.api ?? "openai-completions"); - const baseUrl = customBaseUrl ?? preset?.baseUrl ?? ""; - if (!baseUrl) { - throw new Error( - `Cannot resolve model "${modelId}" for service "${service}": no baseUrl available.`, - ); - } - model = { - id: modelId, - name: modelId, - api: apiType as Api, - provider: piProvider, - baseUrl, - reasoning: false, - input: ["text"] as ("text" | "image")[], - cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, - contextWindow: 0, - maxTokens: 16384, - }; + // Get pi-ai Model — may return undefined for model IDs not in the built-in registry + const piModel = getModel(piProvider as any, modelId as any) as Model | undefined; + + // Always construct our own model object to ensure baseUrl and api format match our presets. + // pi-ai's built-in model may have a different baseUrl (e.g. international endpoint) + // or api format (e.g. anthropic-messages) than what we configure. + const effectiveBaseUrl = baseUrl || piModel?.baseUrl || ""; + if (!effectiveBaseUrl) { + throw new Error( + `Cannot resolve model "${modelId}" for service "${service}": no baseUrl available.`, + ); } + const model: Model = { + id: modelId, + name: piModel?.name ?? modelId, + api: apiType as Api, + provider: piProvider, + baseUrl: effectiveBaseUrl, + reasoning: piModel?.reasoning ?? false, + input: piModel?.input ?? ["text"] as ("text" | "image")[], + cost: piModel?.cost ?? { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + contextWindow: piModel?.contextWindow ?? 0, + maxTokens: piModel?.maxTokens ?? 16384, + }; return { model,