Merge PR #7561: fix(catalog): honor disabled DeepSeek thinking (@roboomp)

This commit is contained in:
can1357
2026-08-04 01:03:07 +02:00
3 changed files with 54 additions and 10 deletions
+28 -7
View File
@@ -25,16 +25,22 @@ function abortedSignal(): AbortSignal {
return controller.signal;
}
interface CaptureOptions {
tools?: Tool[];
reasoning?: Effort;
disableReasoning?: boolean;
}
async function capturePayload(
model: Model<"openai-completions">,
tools?: Tool[],
reasoning: "high" | "max" = "high",
options: CaptureOptions = {},
): Promise<Record<string, unknown>> {
const { promise, resolve } = Promise.withResolvers<unknown>();
streamOpenAICompletions(model, contextWithTools(tools), {
streamOpenAICompletions(model, contextWithTools(options.tools), {
apiKey: "test-key",
signal: abortedSignal(),
reasoning,
reasoning: options.disableReasoning ? undefined : (options.reasoning ?? Effort.High),
disableReasoning: options.disableReasoning,
toolChoice: "auto",
maxTokens: 123,
onPayload: payload => resolve(payload),
@@ -42,7 +48,7 @@ async function capturePayload(
return (await promise) as Record<string, unknown>;
}
function customDeepseekFlash(): Model<"openai-completions"> {
function customDeepseekFlash(legacyThinkingExtraBody = false): Model<"openai-completions"> {
return buildModel({
...getBundledModel("openai", "gpt-4o-mini"),
api: "openai-completions",
@@ -54,6 +60,7 @@ function customDeepseekFlash(): Model<"openai-completions"> {
compat: {
supportsReasoningEffort: true,
reasoningEffortMap: { xhigh: "max" },
...(legacyThinkingExtraBody ? { extraBody: { thinking: { type: "enabled" } } } : {}),
},
} as ModelSpec<"openai-completions">);
}
@@ -65,7 +72,9 @@ describe("issue #1207 — DeepSeek V4 keeps reasoning with tools", () => {
expect(compat.supportsToolChoice).toBe(false);
expect(compat.maxTokensField).toBe("max_tokens");
expect(compat.extraBody).toEqual({ thinking: { type: "enabled" } });
expect(compat.extraBody).toBeUndefined();
expect(compat.reasoningDisableMode).toBe("zai-thinking-disabled");
expect(compat.whenThinking?.extraBody).toEqual({ thinking: { type: "enabled" } });
// DeepSeek's reasoning_effort is the honest wire-exact high/max pair;
// no synthetic lower tiers, no alias map.
expect(model.thinking?.efforts).toEqual([Effort.High, Effort.Max]);
@@ -93,6 +102,18 @@ describe("issue #1207 — DeepSeek V4 keeps reasoning with tools", () => {
expect(body.max_completion_tokens).toBeUndefined();
});
it("disables thinking for bundled and legacy cached model definitions", async () => {
const bundled = getBundledModel("deepseek", "deepseek-v4-flash") as Model<"openai-completions">;
const legacyCached = customDeepseekFlash(true);
for (const model of [bundled, legacyCached]) {
const body = await capturePayload(model, { disableReasoning: true });
expect(model.compat.extraBody).toBeUndefined();
expect(body.reasoning_effort).toBeUndefined();
expect(body.thinking).toEqual({ type: "disabled" });
}
});
it("does not mix Fireworks DeepSeek effort with the native thinking toggle", async () => {
const model = getBundledModel("fireworks", "deepseek-v4-pro") as Model<"openai-completions">;
const compat = model.compat;
@@ -127,7 +148,7 @@ describe("issue #1207 — DeepSeek V4 keeps reasoning with tools", () => {
paths: "(string | string[])?",
}),
};
const body = await capturePayload(model, [unionTool]);
const body = await capturePayload(model, { tools: [unionTool] });
const tools = body.tools as Array<{ function: { parameters: Record<string, unknown> } }>;
const properties = tools[0].function.parameters.properties as Record<string, Record<string, unknown>>;
const branches = properties.paths.anyOf as Array<Record<string, unknown>>;
+4
View File
@@ -6,6 +6,10 @@
- Replaced arktype with `@oh-my-pi/omptype` for discovery payload schemas (same definition DSL, lazy JIT validation).
### Fixed
- Fixed `thinking-level: off` still enabling reasoning on direct DeepSeek V4 requests by emitting the provider's disabled thinking toggle and migrating stale cached model metadata ([#7559](https://github.com/can1357/oh-my-pi/issues/7559)).
## [17.2.6] - 2026-08-03
### Added
+22 -3
View File
@@ -583,7 +583,7 @@ export function buildOpenAICompat(spec: ModelSpec<"openai-completions">): Resolv
wireModelIdMode,
isVercelGatewayHost: isVercelGateway,
supportsStrictMode: detectStrictModeSupport(provider, baseUrl),
extraBody: isDirectDeepseekReasoning ? { thinking: { type: "enabled" } } : undefined,
extraBody: undefined,
toolStrictMode: isCerebras ? "all_strict" : "mixed",
// Kimi-family ids trigger MFJS on any host, not just native base URLs:
// proxies (OpenRouter, custom gateways) forward `tools.function.parameters`
@@ -604,10 +604,24 @@ export function buildOpenAICompat(spec: ModelSpec<"openai-completions">): Resolv
};
applyCompatOverrides(compat, spec.compat);
const deepseekThinking = compat.extraBody?.thinking;
if (
isDirectDeepseekReasoning &&
typeof deepseekThinking === "object" &&
deepseekThinking !== null &&
"type" in deepseekThinking &&
deepseekThinking.type === "enabled"
) {
const extraBody = { ...compat.extraBody };
delete extraBody.thinking;
compat.extraBody = Object.keys(extraBody).length > 0 ? extraBody : undefined;
}
if (spec.compat?.reasoningDisableMode === undefined) {
compat.reasoningDisableMode = requiresEnabledThinking
? "omit"
: resolveReasoningDisableMode(compat.thinkingFormat);
: isDirectDeepseekReasoning
? "zai-thinking-disabled"
: resolveReasoningDisableMode(compat.thinkingFormat);
}
if (spec.compat?.omitReasoningEffort === undefined && !compat.supportsReasoningEffort) {
compat.omitReasoningEffort = true;
@@ -615,7 +629,12 @@ export function buildOpenAICompat(spec: ModelSpec<"openai-completions">): Resolv
mergeModelReasoningEffortMap(compat, spec.id, isMimoReasoningEffortModel);
const whenThinkingPolicy =
spec.compat?.whenThinking ?? (isOpenCodeProvider && spec.reasoning ? OPENCODE_WHEN_THINKING : undefined);
spec.compat?.whenThinking ??
(isDirectDeepseekReasoning
? { extraBody: { ...compat.extraBody, thinking: { type: "enabled" } } }
: isOpenCodeProvider && spec.reasoning
? OPENCODE_WHEN_THINKING
: undefined);
if (whenThinkingPolicy) {
const variant: ResolvedOpenAICompat = { ...compat };
applyCompatOverrides(variant, whenThinkingPolicy);