Skip to content

Commit a1b8931

Browse files
committed
fix(ollama): keep DeepSeek cloud thinking enabled
1 parent 877eae9 commit a1b8931

4 files changed

Lines changed: 39 additions & 15 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Docs: https://docs.openclaw.ai
1212

1313
### Fixes
1414

15+
- Ollama: keep DeepSeek V4 cloud models thinking-capable even when Ollama Cloud `/api/show` omits the `thinking` capability, so `/think high` no longer rejects `ollama/deepseek-v4-*:cloud`.
1516
- ACP sessions: map canonical runtime options to backend-advertised ACP config keys like Claude's `effort` while keeping persisted OpenClaw state canonical. (#79926) Thanks @InTheCloudDan.
1617
- Gateway/watch: rebuild or restage missing bundled-plugin dist and runtime-postbuild outputs before launching the Gateway from a source checkout, preventing incomplete watch-mode runtime trees. (#70805) Thanks @rubencu.
1718
- CLI/update: allow restart health probes from the previous gateway protocol during self-update, and make plugin dry-runs report exact npm target versions instead of `unknown` while preserving unchanged status.

extensions/ollama/index.test.ts

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,22 @@ const ensureOllamaModelPulledMock = vi.hoisted(() => vi.fn(async () => {}));
2727
const buildOllamaProviderMock = vi.hoisted(() => vi.fn());
2828
const queryOllamaModelShowInfoMock = vi.hoisted(() => vi.fn());
2929
const buildOllamaModelDefinitionMock = vi.hoisted(() =>
30-
vi.fn((modelId: string, contextWindow?: number, capabilities?: string[]) => ({
31-
id: modelId,
32-
name: modelId,
33-
reasoning: capabilities?.includes("thinking") ?? false,
34-
input: capabilities?.includes("vision") ? ["text", "image"] : ["text"],
35-
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
36-
contextWindow: contextWindow ?? 8192,
37-
maxTokens: 8192,
38-
compat: capabilities
39-
? { supportsTools: capabilities.includes("tools"), supportsUsageInStreaming: true }
40-
: { supportsUsageInStreaming: true },
41-
})),
30+
vi.fn((modelId: string, contextWindow?: number, capabilities?: string[]) => {
31+
const normalized = modelId.trim().toLowerCase();
32+
const isKnownCloudReasoningModel = /^deepseek-v4-(?:flash|pro):cloud$/.test(normalized);
33+
return {
34+
id: modelId,
35+
name: modelId,
36+
reasoning: isKnownCloudReasoningModel || (capabilities?.includes("thinking") ?? false),
37+
input: capabilities?.includes("vision") ? ["text", "image"] : ["text"],
38+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
39+
contextWindow: contextWindow ?? 8192,
40+
maxTokens: 8192,
41+
compat: capabilities
42+
? { supportsTools: capabilities.includes("tools"), supportsUsageInStreaming: true }
43+
: { supportsUsageInStreaming: true },
44+
};
45+
}),
4246
);
4347
const createConfiguredOllamaStreamFnMock = vi.hoisted(() =>
4448
vi.fn((_params: { model: unknown; providerBaseUrl?: string }) => ({}) as never),
@@ -468,7 +472,7 @@ describe("ollama plugin", () => {
468472
});
469473
queryOllamaModelShowInfoMock.mockResolvedValueOnce({
470474
contextWindow: 1048576,
471-
capabilities: ["completion", "tools", "thinking"],
475+
capabilities: ["completion", "tools"],
472476
});
473477

474478
try {

extensions/ollama/src/provider-models.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,19 @@ describe("ollama provider models", () => {
269269
expect(textModel.compat?.supportsTools).toBe(true);
270270
expect(textModel.compat?.supportsUsageInStreaming).toBe(true);
271271

272+
const deepseekCloudModel = buildOllamaModelDefinition("deepseek-v4-pro:cloud", 1048576, [
273+
"completion",
274+
"tools",
275+
]);
276+
expect(deepseekCloudModel.reasoning).toBe(true);
277+
expect(deepseekCloudModel.compat?.supportsTools).toBe(true);
278+
279+
const deepseekCloudModelWithoutCapabilities = buildOllamaModelDefinition(
280+
"deepseek-v4-flash:cloud",
281+
1048576,
282+
);
283+
expect(deepseekCloudModelWithoutCapabilities.reasoning).toBe(true);
284+
272285
const noCapabilities = buildOllamaModelDefinition("unknown-model", 65536);
273286
expect(noCapabilities.input).toEqual(["text"]);
274287
expect(noCapabilities.compat?.supportsUsageInStreaming).toBe(true);

extensions/ollama/src/provider-models.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,11 @@ export function isReasoningModelHeuristic(modelId: string): boolean {
236236
return /r1|reasoning|think|reason/i.test(modelId);
237237
}
238238

239+
function isKnownOllamaCloudReasoningModel(modelId: string): boolean {
240+
const normalized = modelId.trim().toLowerCase();
241+
return /^deepseek-v4-(?:flash|pro):cloud$/.test(normalized);
242+
}
243+
239244
export function buildOllamaModelDefinition(
240245
modelId: string,
241246
contextWindow?: number,
@@ -244,9 +249,10 @@ export function buildOllamaModelDefinition(
244249
const hasVision = capabilities?.includes("vision") ?? false;
245250
const input: ("text" | "image")[] = hasVision ? ["text", "image"] : ["text"];
246251
const reasoning =
247-
capabilities === undefined
252+
isKnownOllamaCloudReasoningModel(modelId) ||
253+
(capabilities === undefined
248254
? isReasoningModelHeuristic(modelId)
249-
: capabilities.includes("thinking");
255+
: capabilities.includes("thinking"));
250256
const compat =
251257
capabilities === undefined
252258
? { supportsUsageInStreaming: true }

0 commit comments

Comments
 (0)