项目文件夹

文件
2026-07-13 13:39:12 +08:00

80 行
3.3 KiB
TypeScript

/**
* Issue #2900 — OpenCode `big-pickle` fails DeepSeek thinking-mode
* reasoning_content replay.
*
* `big-pickle` (OpenCode free / Zen, endpoint https://opencode.ai/zen/v1) is
* backed by DeepSeek thinking mode upstream, so follow-up/tool-use turns must
* replay `reasoning_content` or DeepSeek returns:
* [400]: The reasoning_content in the thinking mode must be passed back to the API.
*
* Unlike `deepseek-v4-flash-free`, the model id `big-pickle` gives no signal to
* the replay detector, and `requiresReasoningReplay` (with allowLegacyFallback:false,
* as the translator calls it) only triggers on:
* - interleavedField === "reasoning_content" (models.dev signal), or
* - isDeepSeekReasoningModel() pattern match.
*
* Note: `supportsReasoning` is NOT consumed by `requiresReasoningReplay`, so
* marking the model `supportsReasoning: true` alone does NOT enable replay.
* The real trigger is an explicit `interleavedField: "reasoning_content"` on the
* registry entry, surfaced by getResolvedModelCapabilities.
*
* This test asserts the end-to-end wiring for both OpenCode registrations
* (`opencode`/alias `oc` and `opencode-zen`).
*/
import test from "node:test";
import assert from "node:assert/strict";
const { REGISTRY } = await import("../../open-sse/config/providerRegistry.ts");
const { getResolvedModelCapabilities } = await import("../../src/lib/modelCapabilities.ts");
const { requiresReasoningReplay } = await import("../../open-sse/services/reasoningCache.ts");
type ModelEntry = {
id: string;
supportsReasoning?: boolean;
interleavedField?: string;
[key: string]: unknown;
};
function getModel(providerId: string, modelId: string): ModelEntry | undefined {
const provider = (REGISTRY as Record<string, { models?: ModelEntry[] }>)[providerId];
return provider?.models?.find((m) => m.id === modelId);
}
for (const providerId of ["opencode", "opencode-zen"]) {
test(`#2900 ${providerId}/big-pickle registry declares interleavedField reasoning_content`, () => {
const model = getModel(providerId, "big-pickle");
assert.ok(model, `big-pickle must be registered in ${providerId}`);
assert.strictEqual(
model.interleavedField,
"reasoning_content",
`${providerId}/big-pickle must declare interleavedField:"reasoning_content" to trigger replay`
);
});
test(`#2900 ${providerId}/big-pickle resolves interleavedField via capabilities`, () => {
const caps = getResolvedModelCapabilities({ provider: providerId, model: "big-pickle" });
assert.strictEqual(
caps.interleavedField,
"reasoning_content",
`getResolvedModelCapabilities must surface the registry interleavedField for ${providerId}/big-pickle`
);
});
test(`#2900 ${providerId}/big-pickle triggers reasoning replay`, () => {
const caps = getResolvedModelCapabilities({ provider: providerId, model: "big-pickle" });
const isReasoner = requiresReasoningReplay({
provider: providerId,
model: "big-pickle",
thinkingEnabled: false,
supportsReasoning: caps.reasoning,
interleavedField: caps.interleavedField,
allowLegacyFallback: false,
});
assert.strictEqual(
isReasoner,
true,
`${providerId}/big-pickle must require reasoning replay (matching deepseek-v4-flash-free behavior)`
);
});
}