Skip to content

Commit 9c1b60d

Browse files
author
OpenClaw Contributor
committed
fix(agents): add missing DeepSeek V4 proxy models to reasoning_content replay set
When DeepSeek V4 models (deepseek-v4-flash-free, big-pickle) are accessed through proxy providers like OpenCode Zen, the reasoning_content field is stripped from assistant message replay, causing the API to return 500 errors because these models require reasoning_content to be echoed back. The root cause is that `isDeepSeek` detection only checks endpoint class (deepseek-native) which doesn't match proxy endpoints (opencode-native). The model ID fallback set REASONING_CONTENT_REPLAY_MODEL_IDS also didn't include these model variants. Fix: - Add deepseek-v4-flash-free and big-pickle to REASONING_CONTENT_REPLAY_MODEL_IDS in both openai-transport-stream.ts and transcript-policy.ts - Add regression tests for DeepSeek V4 Flash Free and Big Pickle via proxy Fixes #86521
1 parent 6f695c1 commit 9c1b60d

4 files changed

Lines changed: 58 additions & 0 deletions

File tree

src/agents/openai-transport-stream.test.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7680,6 +7680,32 @@ describe("buildOpenAICompletionsParams sanitizes reasoning replay fields", () =>
76807680
baseUrl: "https://api.kimi.com/coding/v1",
76817681
} satisfies Model<"openai-completions">;
76827682

7683+
const customDeepSeekProxyModel = {
7684+
id: "deepseek-v4-flash-free",
7685+
name: "DeepSeek V4 Flash Free",
7686+
api: "openai-completions",
7687+
provider: "opencode-go-extras",
7688+
baseUrl: "https://proxy.example.com/v1",
7689+
reasoning: true,
7690+
input: ["text"],
7691+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
7692+
contextWindow: 64_000,
7693+
maxTokens: 8000,
7694+
} satisfies Model<"openai-completions">;
7695+
7696+
const customBigPickleProxyModel = {
7697+
id: "big-pickle",
7698+
name: "Big Pickle",
7699+
api: "openai-completions",
7700+
provider: "custom-openai-proxy",
7701+
baseUrl: "https://another-proxy.example.com/v1",
7702+
reasoning: true,
7703+
input: ["text"],
7704+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
7705+
contextWindow: 128_000,
7706+
maxTokens: 16_000,
7707+
} satisfies Model<"openai-completions">;
7708+
76837709
function getAssistantMessage(params: { messages: unknown }) {
76847710
expect(Array.isArray(params.messages)).toBe(true);
76857711
const list = params.messages as Array<Record<string, unknown>>;
@@ -7901,6 +7927,28 @@ describe("buildOpenAICompletionsParams sanitizes reasoning replay fields", () =>
79017927
expect(assistant).not.toHaveProperty("reasoning_text");
79027928
});
79037929

7930+
it("preserves reasoning_content replay for DeepSeek V4 Flash Free via proxy", () => {
7931+
const assistant = getAssistantMessage(
7932+
buildReplayParams(customDeepSeekProxyModel, "reasoning_content"),
7933+
);
7934+
7935+
expect(assistant.reasoning_content).toBe("Need to answer politely.");
7936+
expect(assistant).not.toHaveProperty("reasoning_details");
7937+
expect(assistant).not.toHaveProperty("reasoning");
7938+
expect(assistant).not.toHaveProperty("reasoning_text");
7939+
});
7940+
7941+
it("preserves reasoning_content replay for Big Pickle via proxy", () => {
7942+
const assistant = getAssistantMessage(
7943+
buildReplayParams(customBigPickleProxyModel, "reasoning_content"),
7944+
);
7945+
7946+
expect(assistant.reasoning_content).toBe("Need to answer politely.");
7947+
expect(assistant).not.toHaveProperty("reasoning_details");
7948+
expect(assistant).not.toHaveProperty("reasoning");
7949+
expect(assistant).not.toHaveProperty("reasoning_text");
7950+
});
7951+
79047952
it("preserves reasoning_content replay for suffixed reasoning model ids", () => {
79057953
const assistant = getAssistantMessage(
79067954
buildReplayParams(

src/agents/openai-transport-stream.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3372,7 +3372,9 @@ function sanitizeReasoningContentReplayFields(record: Record<string, unknown>):
33723372

33733373
const REASONING_CONTENT_REPLAY_MODEL_IDS = new Set([
33743374
"deepseek-v4-flash",
3375+
"deepseek-v4-flash-free",
33753376
"deepseek-v4-pro",
3377+
"big-pickle",
33763378
"kimi-for-coding",
33773379
"kimi-k2.5",
33783380
"kimi-k2.6",

src/agents/transcript-policy.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,10 @@ describe("resolveTranscriptPolicy", () => {
369369
"hf:moonshotai/kimi-k2-thinking",
370370
"xiaomi/mimo-v2.6-pro",
371371
"xiaomi/mimo-v2.6-pro:cloud",
372+
"deepseek-v4-flash",
373+
"deepseek-v4-flash-free",
374+
"deepseek-v4-pro",
375+
"big-pickle",
372376
])(
373377
"preserves historical reasoning for %s replay-required OpenAI-compatible models",
374378
(modelId) => {

src/agents/transcript-policy.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,10 @@ function buildUnownedProviderTransportReplayFallback(params: {
167167
}
168168

169169
const REASONING_CONTENT_REPLAY_MODEL_IDS = new Set([
170+
"deepseek-v4-flash",
171+
"deepseek-v4-flash-free",
172+
"deepseek-v4-pro",
173+
"big-pickle",
170174
"kimi-for-coding",
171175
"kimi-k2.5",
172176
"kimi-k2.6",

0 commit comments

Comments
 (0)