Skip to content

Commit 20fa772

Browse files
committed
fix: prefer exact provider config match
1 parent c109fda commit 20fa772

File tree

3 files changed

+70
-1
lines changed

3 files changed

+70
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,7 @@ Docs: https://docs.openclaw.ai
483483

484484
### Fixes
485485

486+
- Models/provider config precedence: prefer exact `models.providers.<name>` matches before normalized provider aliases in embedded model resolution, preventing alias/canonical key collisions from applying the wrong provider `api`, `baseUrl`, or headers. (#35934) thanks @RealKai42.
486487
- Logging/Subsystem console timestamps: route subsystem console timestamp rendering through `formatConsoleTimestamp(...)` so `pretty` and timestamp-prefix output use local timezone formatting consistently instead of inline UTC `toISOString()` paths. (#25970) Thanks @openperf.
487488
- Feishu/Multi-account + reply reliability: add `channels.feishu.defaultAccount` outbound routing support with schema validation, prevent inbound preview text from leaking into prompt system events, keep quoted-message extraction text-first (post/interactive/file placeholders instead of raw JSON), route Feishu video sends as `msg_type: "file"`, and avoid websocket event blocking by using non-blocking event handling in monitor dispatch. Landed from contributor PRs #31209, #29610, #30432, #30331, and #29501. Thanks @stakeswky, @hclsys, @bmendonca3, @patrick-yingxi-pan, and @zwffff.
488489
- Feishu/Target routing + replies + dedupe: normalize provider-prefixed targets (`feishu:`/`lark:`), prefer configured `channels.feishu.defaultAccount` for tool execution, honor Feishu outbound `renderMode` in adapter text/caption sends, fall back to normal send when reply targets are withdrawn/deleted, and add synchronous in-memory dedupe guard for concurrent duplicate inbound events. Landed from contributor PRs #30428, #30438, #29958, #30444, and #29463. Thanks @bmendonca3 and @Yaxuan42.

src/agents/pi-embedded-runner/model.test.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,66 @@ describe("resolveModel", () => {
330330
});
331331
});
332332

333+
it("prefers exact provider config over normalized alias match when both keys exist", () => {
334+
mockDiscoveredModel({
335+
provider: "qwen",
336+
modelId: "qwen3-coder-plus",
337+
templateModel: {
338+
id: "qwen3-coder-plus",
339+
name: "Qwen3 Coder Plus",
340+
provider: "qwen",
341+
api: "openai-completions",
342+
baseUrl: "https://default-provider.example.com/v1",
343+
reasoning: false,
344+
input: ["text"],
345+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
346+
contextWindow: 8192,
347+
maxTokens: 2048,
348+
},
349+
});
350+
351+
const cfg = {
352+
models: {
353+
providers: {
354+
"qwen-portal": {
355+
baseUrl: "https://canonical-provider.example.com/v1",
356+
api: "openai-completions",
357+
headers: { "X-Provider": "canonical" },
358+
models: [{ ...makeModel("qwen3-coder-plus"), reasoning: false }],
359+
},
360+
qwen: {
361+
baseUrl: "https://alias-provider.example.com/v1",
362+
api: "anthropic-messages",
363+
headers: { "X-Provider": "alias" },
364+
models: [
365+
{
366+
...makeModel("qwen3-coder-plus"),
367+
api: "anthropic-messages",
368+
reasoning: true,
369+
contextWindow: 262144,
370+
maxTokens: 32768,
371+
},
372+
],
373+
},
374+
},
375+
},
376+
} as OpenClawConfig;
377+
378+
const result = resolveModel("qwen", "qwen3-coder-plus", "/tmp/agent", cfg);
379+
380+
expect(result.error).toBeUndefined();
381+
expect(result.model).toMatchObject({
382+
provider: "qwen",
383+
id: "qwen3-coder-plus",
384+
api: "anthropic-messages",
385+
baseUrl: "https://alias-provider.example.com",
386+
reasoning: true,
387+
contextWindow: 262144,
388+
maxTokens: 32768,
389+
headers: { "X-Provider": "alias" },
390+
});
391+
});
392+
333393
it("builds an openai-codex fallback for gpt-5.3-codex", () => {
334394
mockOpenAICodexTemplateModel();
335395

src/agents/pi-embedded-runner/model.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,15 @@ function resolveConfiguredProviderConfig(
2828
cfg: OpenClawConfig | undefined,
2929
provider: string,
3030
): InlineProviderConfig | undefined {
31-
return findNormalizedProviderValue(cfg?.models?.providers, provider);
31+
const configuredProviders = cfg?.models?.providers;
32+
if (!configuredProviders) {
33+
return undefined;
34+
}
35+
const exactProviderConfig = configuredProviders[provider];
36+
if (exactProviderConfig) {
37+
return exactProviderConfig;
38+
}
39+
return findNormalizedProviderValue(configuredProviders, provider);
3240
}
3341

3442
function applyConfiguredProviderOverrides(params: {

0 commit comments

Comments
 (0)