mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-19 06:54:46 +00:00
fix(config): normalize Gemini provider catalog writes
This commit is contained in:
@@ -76,6 +76,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Google/Gemini: normalize retired nested Gemini 3 Pro Preview ids while converting manifest catalog rows into emitted provider config, so `google/gemini-3.1-pro-preview` is used for testing instead of `google/gemini-3-pro-preview`.
|
||||
- Google/Gemini: normalize retired nested Gemini 3 Pro Preview ids in configured proxy/provider-auth model catalogs, so regenerated config keeps testing `google/gemini-3.1-pro-preview` instead of `google/gemini-3-pro-preview`.
|
||||
- Google/Gemini: normalize retired nested Gemini 3 Pro Preview ids while onboarding provider catalog presets, so setup-emitted proxy configs test `google/gemini-3.1-pro-preview` instead of `google/gemini-3-pro-preview`.
|
||||
- Google/Gemini: normalize retired Gemini 3 Pro Preview ids in provider catalog rows during generic config writes, so unrelated config changes keep testing `google/gemini-3.1-pro-preview`.
|
||||
- Models: keep configured fallback chains ahead of configured primary models for override selections with duplicate model ids, preventing fallback jumps to the wrong provider. Fixes #80562.
|
||||
- Native apps: advertise the Gateway protocol compatibility range so chat and node sessions can connect to v3 gateways after additive v4 client updates.
|
||||
- Gateway/agents: keep stale `sessions_send` ACP manager and `web_fetch` runtime chunks importable after package updates, preventing live gateways from breaking before restart. Fixes #78804. Thanks @Gomesy72.
|
||||
|
||||
@@ -223,6 +223,64 @@ describe("config io write prepare", () => {
|
||||
expect(persisted.gateway?.port).toBe(18888);
|
||||
});
|
||||
|
||||
it("normalizes retired Google provider catalog refs during unrelated config writes", () => {
|
||||
const makeModel = (id: string, name: string) => ({
|
||||
id,
|
||||
name,
|
||||
reasoning: true,
|
||||
input: ["text" as const],
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: 1_048_576,
|
||||
maxTokens: 65_536,
|
||||
});
|
||||
const sourceConfig: OpenClawConfig = {
|
||||
models: {
|
||||
providers: {
|
||||
google: {
|
||||
baseUrl: "https://generativelanguage.googleapis.com/v1beta",
|
||||
models: [makeModel("google/gemini-3-pro-preview", "Gemini 3 Pro")],
|
||||
},
|
||||
kilocode: {
|
||||
baseUrl: "https://kilocode.test/v1",
|
||||
models: [makeModel("google/gemini-3-pro-preview", "Gemini via Kilo")],
|
||||
},
|
||||
},
|
||||
},
|
||||
gateway: { port: 18789 },
|
||||
};
|
||||
const runtimeConfig: OpenClawConfig = {
|
||||
models: {
|
||||
providers: {
|
||||
google: {
|
||||
baseUrl: "https://generativelanguage.googleapis.com/v1beta",
|
||||
models: [makeModel("google/gemini-3.1-pro-preview", "Gemini 3 Pro")],
|
||||
},
|
||||
kilocode: {
|
||||
baseUrl: "https://kilocode.test/v1",
|
||||
models: [makeModel("google/gemini-3.1-pro-preview", "Gemini via Kilo")],
|
||||
},
|
||||
},
|
||||
},
|
||||
gateway: { port: 18789 },
|
||||
};
|
||||
const persisted = resolvePersistCandidateForWrite({
|
||||
runtimeConfig,
|
||||
sourceConfig,
|
||||
nextConfig: {
|
||||
...runtimeConfig,
|
||||
gateway: { port: 18888 },
|
||||
},
|
||||
}) as OpenClawConfig;
|
||||
|
||||
expect(persisted.models?.providers?.google?.models).toEqual([
|
||||
makeModel("google/gemini-3.1-pro-preview", "Gemini 3 Pro"),
|
||||
]);
|
||||
expect(persisted.models?.providers?.kilocode?.models).toEqual([
|
||||
makeModel("google/gemini-3.1-pro-preview", "Gemini via Kilo"),
|
||||
]);
|
||||
expect(persisted.gateway?.port).toBe(18888);
|
||||
});
|
||||
|
||||
it("allows explicit unsets to remove authored agent provider params", () => {
|
||||
const sourceConfig: OpenClawConfig = {
|
||||
agents: {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { isDeepStrictEqual } from "node:util";
|
||||
import { normalizeConfiguredProviderCatalogModelId } from "../agents/model-ref-shared.js";
|
||||
import { isRecord } from "../utils.js";
|
||||
import { applyMergePatch } from "./merge-patch.js";
|
||||
import { normalizeAgentModelMapForConfig, normalizeAgentModelRefForConfig } from "./model-input.js";
|
||||
@@ -354,6 +355,49 @@ function normalizeAgentDefaultModelRefsForWrite(config: unknown): unknown {
|
||||
return next;
|
||||
}
|
||||
|
||||
function normalizeModelProviderCatalogRefsForWrite(config: unknown): unknown {
|
||||
const providers = getPathValue(config, ["models", "providers"]);
|
||||
if (!isRecord(providers)) {
|
||||
return config;
|
||||
}
|
||||
|
||||
let mutated = false;
|
||||
const nextProviders: Record<string, unknown> = { ...providers };
|
||||
for (const [provider, providerConfig] of Object.entries(providers)) {
|
||||
if (!isRecord(providerConfig) || !Array.isArray(providerConfig.models)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let providerMutated = false;
|
||||
const models = providerConfig.models.map((model) => {
|
||||
if (!isRecord(model) || typeof model.id !== "string") {
|
||||
return model;
|
||||
}
|
||||
const trimmed = model.id.trim();
|
||||
if (!trimmed) {
|
||||
return model;
|
||||
}
|
||||
const id = normalizeConfiguredProviderCatalogModelId(provider, trimmed);
|
||||
if (id === model.id) {
|
||||
return model;
|
||||
}
|
||||
providerMutated = true;
|
||||
return { ...model, id };
|
||||
});
|
||||
|
||||
if (providerMutated) {
|
||||
nextProviders[provider] = { ...providerConfig, models };
|
||||
mutated = true;
|
||||
}
|
||||
}
|
||||
|
||||
return mutated ? setPathValue(config, ["models", "providers"], nextProviders) : config;
|
||||
}
|
||||
|
||||
function normalizeModelRefsForWrite(config: unknown): unknown {
|
||||
return normalizeModelProviderCatalogRefsForWrite(normalizeAgentDefaultModelRefsForWrite(config));
|
||||
}
|
||||
|
||||
function preserveUntouchedIncludes(params: {
|
||||
patch: unknown;
|
||||
rootAuthoredConfig: unknown;
|
||||
@@ -524,7 +568,7 @@ export function resolvePersistCandidateForWrite(params: {
|
||||
persistedCandidate: withSchema,
|
||||
unsetPaths: params.unsetPaths,
|
||||
});
|
||||
return normalizeAgentDefaultModelRefsForWrite(withAuthoredParams);
|
||||
return normalizeModelRefsForWrite(withAuthoredParams);
|
||||
}
|
||||
|
||||
function readRootSchemaUri(value: unknown): string | undefined {
|
||||
|
||||
Reference in New Issue
Block a user