Skip to content

[BUG] V4 Flash with thinking disabled emits agent planning in content on an unsupported tool task #1594

Description

@eddyxu81

Important

AI-generated bug report: This issue was investigated, written, and
submitted by OpenAI Codex, acting under human direction. The reproduction
runs and result counts below were collected automatically by the agent and
reviewed for secrets and local-path disclosure before submission. The
diagnosis is an AI-generated hypothesis and has not been independently
verified by the DeepSeek maintainers.

Summary

deepseek-v4-flash can emit internal agent planning and workspace-search
deliberation in the ordinary content field when thinking is explicitly
disabled and a user request does not match the available Skill/tool context.

This is not a client merge of reasoning_content: the affected responses have
no reasoning_content. Some turns correctly return structured tool calls, but
the text preceding them contains phrases such as The user is asking...,
I need to..., Let me think..., and a detailed description of the model's
own search strategy. One sample ended with finish_reason: "stop" after only
emitting its plan, without answering the user.

This looks related to #1244, where V4 Pro falls from the structured tool-call
path into plain content, but this reproduction does not require a large tool
set or a long conversation.

Environment

  • API: official DeepSeek OpenAI-compatible endpoint
  • Model: deepseek-v4-flash
  • Harness: @mariozechner/pi-coding-agent 0.73.1
  • API adapter: Pi's built-in deepseek provider
  • Thinking: --thinking off, serialized as
    {"thinking":{"type":"disabled"}}
  • Output mode: JSON
  • Streaming: Pi/OpenAI-compatible streaming
  • Runs: five independent sequential runs
  • Workspace: fresh temporary directory
  • Available tools: only Pi's read tool
  • Available Skills: only the official Agent Skills Quickstart roll-dice
    Skill (under 20 lines)
  • Context files, prompt templates, unrelated extensions, and sessions: disabled

How thinking is actually disabled in Pi

--thinking off is not only a Pi display setting and it does not merely hide
reasoning blocks. In Pi 0.73.1 the setting follows this request path:

  1. The CLI parser accepts off as the explicit --thinking level and gives
    the explicit CLI value precedence over saved/default settings:
    https://github.com/earendil-works/pi/blob/v0.73.1/packages/coding-agent/src/cli/args.ts
  2. Pi stores that value as thinkingLevel = "off". The agent core converts
    off to an absent reasoningEffort when it builds the provider options:
    https://github.com/earendil-works/pi/blob/v0.73.1/packages/agent/src/agent.ts#L1976-L1986
  3. Pi's built-in deepseek-v4-flash model is marked as a reasoning model with
    DeepSeek's native thinking format and the official
    https://api.deepseek.com base URL.
  4. The DeepSeek provider adapter deliberately converts the absent
    reasoningEffort into the following explicit API request field (it does
    not omit the setting):
{
  "model": "deepseek-v4-flash",
  "thinking": { "type": "disabled" }
}

The exact provider branch is here:
https://github.com/earendil-works/pi/blob/v0.73.1/packages/ai/src/providers/openai-completions.ts#L3176-L3186

In other words, the reproduction command's --thinking off reaches the
official DeepSeek request as thinking.type = "disabled"; it is not a
client-side attempt to remove reasoning after the response arrives.

Pi's JSON event output also keeps provider reasoning separate as thinking
content blocks. Across the five recorded runs there were zero such
blocks, while the affected English planning sentences arrived as ordinary
text blocks. A local run can check that distinction with:

pi ... --thinking off --mode json --print '我还有些什么公司' > run.jsonl

# Expected to print nothing for the affected runs:
grep '"type":"thinking"' run.jsonl

# The reported planning is instead present in ordinary text events:
grep -E 'I need to|Let me|The user is asking' run.jsonl

If capturing the outgoing HTTPS payload, please verify this fragment before
classifying a run as a reproduction:

"thinking":{"type":"disabled"}

Minimal Skill

Source:
https://github.com/agentskills/agentskills/blob/main/docs/skill-creation/quickstart.mdx

---
name: roll-dice
description: Roll dice using a random number generator. Use when asked to roll a die (d6, d20, etc.), roll dice, or generate a random dice roll.
---

To roll a die, use the following command that generates a random number from 1
to the given number of sides:

```bash
echo $((RANDOM % <sides> + 1))
```

Replace `<sides>` with the number of sides on the die.

Reproduction

From a fresh directory containing only skills/roll-dice/SKILL.md:

export DEEPSEEK_API_KEY=REDACTED

pi \
  --provider deepseek \
  --model deepseek-v4-flash \
  --thinking off \
  --no-extensions \
  --no-context-files \
  --no-prompt-templates \
  --no-session \
  --tools read \
  --skill ./skills \
  --mode json \
  --print '我还有些什么公司'

Repeat from independent sessions.

The input means “What other companies do I have?” It intentionally does not
match the only available Skill and there is no company data in the workspace.
A concise clarification is expected.

Results

Five sequential independent runs:

Observation Count
Provider reasoning_content present 0/5
Planning/metacognitive text in ordinary content 4/5
Long search/capability self-analysis in content 2/5
Clean concise clarification 1/5
Structured read tool use despite no grounded file 3/5

Example: plan returned as the whole answer

{
  "finish_reason": "stop",
  "message": {
    "content": "I need to look at the context to understand what this question is about. Let me explore the workspace first.",
    "reasoning_content": null,
    "tool_calls": null
  }
}

Example: planning mixed with a structured tool turn

The assistant emitted ordinary content along these lines before structured
read calls:

The user is asking "...". Let me look for relevant files in the workspace.
...
I can't list directories directly with the read tool. Let me search for files
that might contain company information. ... Let me think about where company
information might be stored.

It then read the unrelated roll-dice/SKILL.md and produced a long explanation
of its own workspace/tool limitations before the actual clarification.

Control observations

  1. With the same model/provider-level disabled configuration but the matching
    input Roll a d20, the same minimal Skill completed
    read Skill -> execute -> final in 5/5 runs. No long self-analysis appeared;
    only brief user-facing tool progress appeared in 3/5.
  2. A direct minimal Chat Completions request with one small ToolSpec and a short
    system prompt mostly returned normal clarifications (4/5) and one ungrounded
    tool call. The stronger symptom therefore appears sensitive to a real agent
    harness/context, even with only one small Skill and one read tool.
  3. In a separate control where provider reasoning was not actually disabled,
    planning was returned in the typed reasoning_content channel and the final
    text remained clean. This report is specifically about the explicit
    thinking-disabled response shape.

Expected behavior

When thinking is disabled:

  • content should contain a user-facing answer or concise progress narration,
    not the model's internal task interpretation and search plan;
  • tool invocations should remain in tool_calls;
  • an unsupported/ungrounded request should produce a concise clarification;
  • the model should not end the turn with only I need to... / Let me... prose.

Actual behavior

For unsupported tool-using turns, V4 Flash intermittently enters a plain-text
planning mode. Since reasoning_content is absent, the client cannot safely
separate this text from the final answer without heuristic content filtering.

Why this matters

Agent frameworks normally treat content as user-visible. Filtering phrases
such as I need to or Let me is unsafe because they can also occur in valid
answers. The response protocol needs to keep internal planning out of ordinary
content, or provide a typed channel even when the model performs lightweight
internal planning with thinking disabled.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions