mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 21:54:32 +00:00
fix(models): land #38947 from @davidemanuelDEV
Co-authored-by: davidemanuelDEV <davidemanuelDEV@users.noreply.github.com>
This commit is contained in:
@@ -248,6 +248,7 @@ Docs: https://docs.openclaw.ai
|
|||||||
- Outbound/message target normalization: ignore empty legacy `to`/`channelId` fields when explicit `target` is provided so valid target-based sends no longer fail legacy-param validation; includes regression coverage. (#38944) Thanks @Narcooo.
|
- Outbound/message target normalization: ignore empty legacy `to`/`channelId` fields when explicit `target` is provided so valid target-based sends no longer fail legacy-param validation; includes regression coverage. (#38944) Thanks @Narcooo.
|
||||||
- Models/auth token prompts: guard cancelled manual token prompts so `Symbol(clack:cancel)` values cannot be persisted into auth profiles; adds regression coverage for cancelled `models auth paste-token`. (#38951) Thanks @MumuTW.
|
- Models/auth token prompts: guard cancelled manual token prompts so `Symbol(clack:cancel)` values cannot be persisted into auth profiles; adds regression coverage for cancelled `models auth paste-token`. (#38951) Thanks @MumuTW.
|
||||||
- Gateway/loopback announce URLs: treat `http://` and `https://` aliases with the same loopback/private-network policy as websocket URLs so loopback cron announce delivery no longer fails secure URL validation. (#39064) Thanks @Narcooo.
|
- Gateway/loopback announce URLs: treat `http://` and `https://` aliases with the same loopback/private-network policy as websocket URLs so loopback cron announce delivery no longer fails secure URL validation. (#39064) Thanks @Narcooo.
|
||||||
|
- Models/default provider fallback: when the hardcoded default provider is removed from `models.providers`, resolve defaults from configured providers instead of reporting stale removed-provider defaults in status output. (#38947) Thanks @davidemanuelDEV.
|
||||||
|
|
||||||
## 2026.3.2
|
## 2026.3.2
|
||||||
|
|
||||||
|
|||||||
@@ -481,6 +481,83 @@ describe("model-selection", () => {
|
|||||||
});
|
});
|
||||||
expect(result).toEqual({ provider: "openai", model: "gpt-4" });
|
expect(result).toEqual({ provider: "openai", model: "gpt-4" });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should prefer configured custom provider when default provider is not in models.providers", () => {
|
||||||
|
const cfg: Partial<OpenClawConfig> = {
|
||||||
|
models: {
|
||||||
|
providers: {
|
||||||
|
n1n: {
|
||||||
|
baseUrl: "https://n1n.example.com",
|
||||||
|
models: [
|
||||||
|
{
|
||||||
|
id: "gpt-5.4",
|
||||||
|
name: "GPT 5.4",
|
||||||
|
reasoning: false,
|
||||||
|
input: ["text"],
|
||||||
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||||
|
contextWindow: 128000,
|
||||||
|
maxTokens: 4096,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const result = resolveConfiguredModelRef({
|
||||||
|
cfg: cfg as OpenClawConfig,
|
||||||
|
defaultProvider: "anthropic",
|
||||||
|
defaultModel: "claude-opus-4-6",
|
||||||
|
});
|
||||||
|
expect(result).toEqual({ provider: "n1n", model: "gpt-5.4" });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should keep default provider when it is in models.providers", () => {
|
||||||
|
const cfg: Partial<OpenClawConfig> = {
|
||||||
|
models: {
|
||||||
|
providers: {
|
||||||
|
anthropic: {
|
||||||
|
baseUrl: "https://api.anthropic.com",
|
||||||
|
models: [
|
||||||
|
{
|
||||||
|
id: "claude-opus-4-6",
|
||||||
|
name: "Claude Opus 4.6",
|
||||||
|
reasoning: true,
|
||||||
|
input: ["text", "image"],
|
||||||
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||||
|
contextWindow: 200000,
|
||||||
|
maxTokens: 4096,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const result = resolveConfiguredModelRef({
|
||||||
|
cfg: cfg as OpenClawConfig,
|
||||||
|
defaultProvider: "anthropic",
|
||||||
|
defaultModel: "claude-opus-4-6",
|
||||||
|
});
|
||||||
|
expect(result).toEqual({ provider: "anthropic", model: "claude-opus-4-6" });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should fall back to hardcoded default when no custom providers have models", () => {
|
||||||
|
const cfg: Partial<OpenClawConfig> = {
|
||||||
|
models: {
|
||||||
|
providers: {
|
||||||
|
"empty-provider": {
|
||||||
|
baseUrl: "https://example.com",
|
||||||
|
models: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const result = resolveConfiguredModelRef({
|
||||||
|
cfg: cfg as OpenClawConfig,
|
||||||
|
defaultProvider: "anthropic",
|
||||||
|
defaultModel: "claude-opus-4-6",
|
||||||
|
});
|
||||||
|
expect(result).toEqual({ provider: "anthropic", model: "claude-opus-4-6" });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("resolveThinkingDefault", () => {
|
describe("resolveThinkingDefault", () => {
|
||||||
|
|||||||
@@ -317,6 +317,28 @@ export function resolveConfiguredModelRef(params: {
|
|||||||
return resolved.ref;
|
return resolved.ref;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Before falling back to the hardcoded default, check if the default provider
|
||||||
|
// is actually available. If it isn't but other providers are configured, prefer
|
||||||
|
// the first configured provider's first model to avoid reporting a stale default
|
||||||
|
// from a removed provider. (See #38880)
|
||||||
|
const configuredProviders = params.cfg.models?.providers;
|
||||||
|
if (configuredProviders && typeof configuredProviders === "object") {
|
||||||
|
const hasDefaultProvider = Boolean(configuredProviders[params.defaultProvider]);
|
||||||
|
if (!hasDefaultProvider) {
|
||||||
|
const availableProvider = Object.entries(configuredProviders).find(
|
||||||
|
([, providerCfg]) =>
|
||||||
|
providerCfg &&
|
||||||
|
Array.isArray(providerCfg.models) &&
|
||||||
|
providerCfg.models.length > 0 &&
|
||||||
|
providerCfg.models[0]?.id,
|
||||||
|
);
|
||||||
|
if (availableProvider) {
|
||||||
|
const [providerName, providerCfg] = availableProvider;
|
||||||
|
const firstModel = providerCfg.models[0];
|
||||||
|
return { provider: providerName, model: firstModel.id };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return { provider: params.defaultProvider, model: params.defaultModel };
|
return { provider: params.defaultProvider, model: params.defaultModel };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user