

























@@ -110,6 +110,102 @@ describe("normalizeProviders", () => {
110110await fs.rm(agentDir, { recursive: true, force: true });
111111}
112112});
113+114+it("normalizes retired Google Gemini model ids before emitting provider config", async () => {
115+const agentDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-agent-"));
116+try {
117+const providers: NonNullable<NonNullable<OpenClawConfig["models"]>["providers"]> = {
118+google: {
119+baseUrl: "https://generativelanguage.googleapis.com/v1beta",
120+api: "google-generative-ai",
121+apiKey: "GOOGLE_API_KEY", // pragma: allowlist secret
122+models: [
123+createModel({
124+id: "gemini-3-pro-preview",
125+name: "Gemini 3 Pro",
126+}),
127+],
128+},
129+"google-gemini-cli": {
130+baseUrl: "openclaw://google-gemini-cli",
131+models: [
132+createModel({
133+id: "gemini-3-pro-preview",
134+name: "Gemini CLI 3 Pro",
135+}),
136+],
137+},
138+openrouter: {
139+baseUrl: "https://openrouter.ai/api/v1",
140+api: "openai-completions",
141+apiKey: "OPENROUTER_API_KEY", // pragma: allowlist secret
142+models: [
143+createModel({
144+id: "google/gemini-3-pro-preview",
145+name: "Gemini 3 Pro via OpenRouter",
146+}),
147+],
148+},
149+};
150+151+const normalized = normalizeProviders({ providers, agentDir });
152+153+expect(normalized?.google?.models?.map((model) => model.id)).toEqual([
154+"gemini-3.1-pro-preview",
155+]);
156+expect(normalized?.["google-gemini-cli"]?.models?.map((model) => model.id)).toEqual([
157+"gemini-3.1-pro-preview",
158+]);
159+expect(normalized?.openrouter?.models?.map((model) => model.id)).toEqual([
160+"google/gemini-3-pro-preview",
161+]);
162+} finally {
163+await fs.rm(agentDir, { recursive: true, force: true });
164+}
165+});
166+167+it("deduplicates Google Gemini provider rows after model id normalization", async () => {
168+const agentDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-agent-"));
169+try {
170+const providers: NonNullable<NonNullable<OpenClawConfig["models"]>["providers"]> = {
171+google: {
172+baseUrl: "https://generativelanguage.googleapis.com/v1beta",
173+api: "google-generative-ai",
174+apiKey: "GOOGLE_API_KEY", // pragma: allowlist secret
175+models: [
176+createModel({
177+id: "gemini-3-pro-preview",
178+name: "Pinned Gemini",
179+contextWindow: 12345,
180+cost: { input: 1, output: 2, cacheRead: 3, cacheWrite: 4 },
181+}),
182+createModel({
183+id: "gemini-3.1-pro-preview",
184+name: "Discovered Gemini",
185+contextWindow: 1_048_576,
186+maxTokens: 65536,
187+reasoning: true,
188+}),
189+],
190+},
191+};
192+193+const normalized = normalizeProviders({ providers, agentDir });
194+195+expect(normalized?.google?.models).toHaveLength(1);
196+expect(normalized?.google?.models?.[0]).toMatchObject({
197+id: "gemini-3.1-pro-preview",
198+name: "Pinned Gemini",
199+contextWindow: 12345,
200+maxTokens: 2048,
201+reasoning: false,
202+cost: { input: 1, output: 2, cacheRead: 3, cacheWrite: 4 },
203+});
204+} finally {
205+await fs.rm(agentDir, { recursive: true, force: true });
206+}
207+});
208+113209it("replaces resolved env var value with env var name to prevent plaintext persistence", async () => {
114210const agentDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-agent-"));
115211const env = {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。