From 0295b8898109b941ea85c75e39f8d469d1571831 Mon Sep 17 00:00:00 2001 From: Semih Date: Wed, 13 May 2026 23:11:09 +0000 Subject: [PATCH] fix(phase6b): DeepSeek V4 disable thinking by default + parse text block (not first content) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - thinking={type:disabled} skips reasoning trace → output_tokens drop 10x - find first content block of type='text' (V4 may emit thinking before text) - DEEPSEEK_THINKING=true env to re-enable if needed for hard problems Co-Authored-By: Claude Opus 4.7 --- apps/worker/src/lib/deepseek.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/apps/worker/src/lib/deepseek.ts b/apps/worker/src/lib/deepseek.ts index b1045b6..123c480 100644 --- a/apps/worker/src/lib/deepseek.ts +++ b/apps/worker/src/lib/deepseek.ts @@ -64,13 +64,15 @@ export async function callDeepSeek(opts: { const model = modelForTier(opts.tier); const url = `${BASE}/v1/messages`; - const body = { + const enableThinking = (process.env.DEEPSEEK_THINKING ?? "false") === "true"; + const body: Record = { model, max_tokens: opts.maxOutputTokens, temperature: opts.temperature ?? 0.3, system: opts.systemPrompt, messages: [{ role: "user" as const, content: opts.userPrompt }], }; + if (!enableThinking) body.thinking = { type: "disabled" }; const start = Date.now(); let res: Response; @@ -97,9 +99,13 @@ export async function callDeepSeek(opts: { } catch { throw new DeepSeekError(res.status, `non-json: ${text.slice(0, 200)}`); } - const content = parsed?.content?.[0]?.text; + // V4 models may emit a "thinking" block before the final "text" block. + // Find the first text block; thinking blocks are not billed as output_tokens. + const blocks = Array.isArray(parsed?.content) ? parsed.content : []; + const textBlock = blocks.find((b: any) => b && b.type === "text" && typeof b.text === "string"); + const content = textBlock?.text; if (typeof content !== "string") { - throw new DeepSeekError(res.status, `no content text: ${text.slice(0, 200)}`); + throw new DeepSeekError(res.status, `no text block (got types: ${blocks.map((b: any) => b?.type).join(",")})`); } const usage = parsed.usage ?? {};