

























1+// Ollama tests cover doctor contract config compatibility.
2+import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";
3+import { describe, expect, it } from "vitest";
4+import { legacyConfigRules, normalizeCompatibilityConfig } from "./doctor-contract-api.js";
5+6+type ModelDefinition = NonNullable<
7+NonNullable<OpenClawConfig["models"]>["providers"]
8+>[string]["models"][number];
9+10+const cloudModel: ModelDefinition = {
11+id: "kimi-k2.5:cloud",
12+name: "Kimi K2.5 Cloud",
13+reasoning: false,
14+input: ["text"],
15+cost: {
16+input: 0,
17+output: 0,
18+cacheRead: 0,
19+cacheWrite: 0,
20+},
21+contextWindow: 131072,
22+maxTokens: 8192,
23+};
24+25+function readOllamaCloudProvider(config: OpenClawConfig): Record<string, unknown> | undefined {
26+return config.models?.providers?.["ollama-cloud"] as Record<string, unknown> | undefined;
27+}
28+29+describe("ollama doctor contract", () => {
30+it("detects retired Ollama Cloud provider endpoints", () => {
31+expect(legacyConfigRules[0]?.match({ baseUrl: "https://ai.ollama.com" })).toBe(true);
32+expect(legacyConfigRules[0]?.match({ baseUrl: "https://ollama.com" })).toBe(false);
33+});
34+35+it("migrates retired Ollama Cloud provider baseUrl to the canonical endpoint", () => {
36+const config = {
37+models: {
38+providers: {
39+"ollama-cloud": {
40+baseUrl: "https://ai.ollama.com",
41+api: "ollama",
42+models: [cloudModel],
43+},
44+ollama: {
45+baseUrl: "http://127.0.0.1:11434",
46+api: "ollama",
47+models: [],
48+},
49+},
50+},
51+} as OpenClawConfig;
52+53+const result = normalizeCompatibilityConfig({ cfg: config });
54+55+expect(result.changes).toEqual([
56+"Updated models.providers.ollama-cloud.baseUrl from the retired Ollama Cloud endpoint to https://ollama.com.",
57+]);
58+expect(readOllamaCloudProvider(result.config)).toEqual({
59+baseUrl: "https://ollama.com",
60+api: "ollama",
61+models: [cloudModel],
62+});
63+expect(readOllamaCloudProvider(config)?.baseUrl).toBe("https://ai.ollama.com");
64+});
65+66+it("removes retired Ollama Cloud provider baseURL aliases when canonical baseUrl is present", () => {
67+const config = {
68+models: {
69+providers: {
70+"ollama-cloud": {
71+baseUrl: "https://ollama.com",
72+baseURL: "https://ai.ollama.com/",
73+api: "ollama",
74+models: [],
75+},
76+},
77+},
78+} as OpenClawConfig;
79+80+const result = normalizeCompatibilityConfig({ cfg: config });
81+82+expect(result.changes).toEqual([
83+"Removed retired models.providers.ollama-cloud.baseURL while preserving models.providers.ollama-cloud.baseUrl.",
84+]);
85+expect(readOllamaCloudProvider(result.config)).toEqual({
86+baseUrl: "https://ollama.com",
87+api: "ollama",
88+models: [],
89+});
90+expect(readOllamaCloudProvider(config)).toEqual({
91+baseUrl: "https://ollama.com",
92+baseURL: "https://ai.ollama.com/",
93+api: "ollama",
94+models: [],
95+});
96+});
97+98+it("migrates retired Ollama Cloud provider baseURL aliases when canonical baseUrl is blank", () => {
99+const config = {
100+models: {
101+providers: {
102+"ollama-cloud": {
103+baseUrl: " ",
104+baseURL: "https://ai.ollama.com/",
105+api: "ollama",
106+models: [],
107+},
108+},
109+},
110+} as OpenClawConfig;
111+112+const result = normalizeCompatibilityConfig({ cfg: config });
113+114+expect(result.changes).toEqual([
115+"Updated models.providers.ollama-cloud.baseURL from the retired Ollama Cloud endpoint to https://ollama.com.",
116+]);
117+expect(readOllamaCloudProvider(result.config)).toEqual({
118+baseUrl: "https://ollama.com",
119+api: "ollama",
120+models: [],
121+});
122+expect(readOllamaCloudProvider(config)).toEqual({
123+baseUrl: " ",
124+baseURL: "https://ai.ollama.com/",
125+api: "ollama",
126+models: [],
127+});
128+});
129+130+it("preserves custom canonical baseUrl when removing retired baseURL aliases", () => {
131+const config = {
132+models: {
133+providers: {
134+"ollama-cloud": {
135+baseUrl: "https://custom-ollama-cloud.example.test",
136+baseURL: "https://ai.ollama.com/",
137+api: "ollama",
138+models: [],
139+},
140+},
141+},
142+} as OpenClawConfig;
143+144+const result = normalizeCompatibilityConfig({ cfg: config });
145+146+expect(result.changes).toEqual([
147+"Removed retired models.providers.ollama-cloud.baseURL while preserving models.providers.ollama-cloud.baseUrl.",
148+]);
149+expect(readOllamaCloudProvider(result.config)).toEqual({
150+baseUrl: "https://custom-ollama-cloud.example.test",
151+api: "ollama",
152+models: [],
153+});
154+expect(readOllamaCloudProvider(config)).toEqual({
155+baseUrl: "https://custom-ollama-cloud.example.test",
156+baseURL: "https://ai.ollama.com/",
157+api: "ollama",
158+models: [],
159+});
160+});
161+162+it("does not expose credentials or query parameters from the retired URL", () => {
163+const config = {
164+models: {
165+providers: {
166+"ollama-cloud": {
167+baseUrl: "https://user:password@ai.ollama.com/?token=secret",
168+api: "ollama",
169+models: [],
170+},
171+},
172+},
173+} as OpenClawConfig;
174+175+const result = normalizeCompatibilityConfig({ cfg: config });
176+177+expect(result.changes.join("\n")).not.toContain("user");
178+expect(result.changes.join("\n")).not.toContain("password");
179+expect(result.changes.join("\n")).not.toContain("secret");
180+expect(readOllamaCloudProvider(result.config)?.baseUrl).toBe("https://ollama.com");
181+});
182+});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。