mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-27 21:07:01 -06:00
fix: normalize merged gemini model config
This commit is contained in:
@@ -65,6 +65,7 @@ Docs: https://docs.openclaw.ai
|
||||
- OpenAI/Codex: point gateway missing-key recovery and wizard docs at the canonical `openai/gpt-5.5` plus Codex OAuth route, and fix trajectory export errors so they suggest the valid `openclaw sessions` command.
|
||||
- Google/Gemini: normalize retired `google/gemini-3-pro-preview` primary, fallback, and model-map refs during config load and unrelated config writes so saved config keeps targeting Gemini 3.1 Pro Preview.
|
||||
- Google/Gemini: normalize retired Gemini 3 Pro Preview ids inside emitted Google provider model config, so regenerated models.json rows test `google/gemini-3.1-pro-preview`.
|
||||
- Google/Gemini: normalize retired Gemini 3 Pro Preview ids preserved from existing merged models.json providers so config emission keeps targeting `google/gemini-3.1-pro-preview`.
|
||||
- GitHub Copilot: mint short-lived Copilot API tokens with the same `vscode-chat` integration identity used by runtime requests, and refresh legacy cached tokens missing that identity so image-capable Copilot models no longer inherit the `copilot-language-server` scope. Fixes #79946, #80074. Thanks @TurboTheTurtle.
|
||||
- Plugins/doctor: drop stale managed npm install records when `openclaw doctor --fix` removes npm packages that shadow bundled plugins, so the rebuilt registry no longer resurrects the removed package metadata.
|
||||
- Discord/voice: reuse or suppress late realtime consult tool calls without stealing newer speaker context or speaking forced fallback answers twice.
|
||||
|
||||
@@ -188,6 +188,64 @@ describe("models-config", () => {
|
||||
expect(observedSnapshot).toBe(pluginMetadataSnapshot);
|
||||
});
|
||||
|
||||
it("normalizes retired Gemini ids preserved from existing models.json rows", async () => {
|
||||
const plan = await planOpenClawModelsJsonWithDeps(
|
||||
{
|
||||
cfg: { models: { mode: "merge", providers: {} } },
|
||||
agentDir: "/tmp/openclaw-models-config-env-vars-test",
|
||||
env: {},
|
||||
existingRaw: "",
|
||||
existingParsed: {
|
||||
providers: {
|
||||
google: {
|
||||
baseUrl: "https://generativelanguage.googleapis.com/v1beta",
|
||||
api: "google-generative-ai",
|
||||
apiKey: "GOOGLE_API_KEY", // pragma: allowlist secret
|
||||
models: [
|
||||
{
|
||||
id: "gemini-3-pro-preview",
|
||||
name: "Gemini 3 Pro",
|
||||
input: ["text"],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
resolveImplicitProviders: async () => ({
|
||||
openai: {
|
||||
baseUrl: "https://api.openai.com/v1",
|
||||
api: "openai-responses",
|
||||
apiKey: "OPENAI_API_KEY", // pragma: allowlist secret
|
||||
models: [
|
||||
{
|
||||
id: "gpt-5.5",
|
||||
name: "GPT-5.5",
|
||||
input: ["text"],
|
||||
reasoning: true,
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: 400000,
|
||||
maxTokens: 128000,
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
expect(plan.action).toBe("write");
|
||||
if (plan.action !== "write") {
|
||||
throw new Error("Expected models.json write plan");
|
||||
}
|
||||
const parsed = JSON.parse(plan.contents) as {
|
||||
providers?: Record<string, { models?: Array<{ id?: string }> }>;
|
||||
};
|
||||
expect(parsed.providers?.google?.models?.map((model) => model.id)).toEqual([
|
||||
"gemini-3.1-pro-preview",
|
||||
]);
|
||||
});
|
||||
|
||||
it("uses config env.vars entries for implicit provider discovery without mutating process.env", async () => {
|
||||
await withTempEnv(["OPENROUTER_API_KEY", TEST_ENV_VAR], async () => {
|
||||
unsetEnv(["OPENROUTER_API_KEY", TEST_ENV_VAR]);
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
import {
|
||||
applyNativeStreamingUsageCompat,
|
||||
enforceSourceManagedProviderSecrets,
|
||||
normalizeProviderCatalogModelsForConfig,
|
||||
normalizeProviders,
|
||||
resolveImplicitProviders,
|
||||
type ProviderConfig,
|
||||
@@ -167,13 +168,15 @@ export async function planOpenClawModelsJsonWithDeps(
|
||||
providers: normalizedProviders,
|
||||
secretRefManagedProviders,
|
||||
});
|
||||
const normalizedMergedProviders =
|
||||
normalizeProviderCatalogModelsForConfig(mergedProviders) ?? mergedProviders;
|
||||
const secretEnforcedProviders =
|
||||
enforceSourceManagedProviderSecrets({
|
||||
providers: mergedProviders,
|
||||
providers: normalizedMergedProviders,
|
||||
sourceProviders: params.sourceConfigForSecrets?.models?.providers,
|
||||
sourceSecretDefaults: params.sourceConfigForSecrets?.secrets?.defaults,
|
||||
secretRefManagedProviders,
|
||||
}) ?? mergedProviders;
|
||||
}) ?? normalizedMergedProviders;
|
||||
const finalProviders = applyNativeStreamingUsageCompat(secretEnforcedProviders);
|
||||
const nextContents = `${JSON.stringify({ providers: finalProviders }, null, 2)}\n`;
|
||||
|
||||
|
||||
@@ -84,6 +84,26 @@ function normalizeProviderModelsForConfig(
|
||||
: { provider, mutated };
|
||||
}
|
||||
|
||||
export function normalizeProviderCatalogModelsForConfig(
|
||||
providers: ModelsConfig["providers"],
|
||||
): ModelsConfig["providers"] {
|
||||
if (!providers) {
|
||||
return providers;
|
||||
}
|
||||
|
||||
let mutated = false;
|
||||
const next: Record<string, ProviderConfig> = {};
|
||||
for (const [providerKey, provider] of Object.entries(providers)) {
|
||||
const normalized = normalizeProviderModelsForConfig(providerKey, provider);
|
||||
if (normalized.mutated) {
|
||||
mutated = true;
|
||||
}
|
||||
next[providerKey] = normalized.provider;
|
||||
}
|
||||
|
||||
return mutated ? next : providers;
|
||||
}
|
||||
|
||||
export function normalizeProviders(params: {
|
||||
providers: ModelsConfig["providers"];
|
||||
agentDir: string;
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
export { resolveImplicitProviders } from "./models-config.providers.implicit.js";
|
||||
export { normalizeProviders } from "./models-config.providers.normalize.js";
|
||||
export {
|
||||
normalizeProviderCatalogModelsForConfig,
|
||||
normalizeProviders,
|
||||
} from "./models-config.providers.normalize.js";
|
||||
export type { ProviderConfig } from "./models-config.providers.secrets.js";
|
||||
export { applyNativeStreamingUsageCompat } from "./models-config.providers.policy.js";
|
||||
export { enforceSourceManagedProviderSecrets } from "./models-config.providers.source-managed.js";
|
||||
|
||||
Reference in New Issue
Block a user