openclaw - 💡(How to fix) Fix Bug: Foundry DeepSeek V4 tool turns surface DSML text instead of executable tool calls

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

microsoft-foundry/deepseek-v4-pro now works for plain chat in OpenClaw, but tool-using/operator turns remain unreliable because DeepSeek/Foundry sometimes emits DSML tool markup as plain assistant text instead of native tool_calls, and the current openai-completions stream path does not recover that text into executable tool calls.

Root Cause

Summary

microsoft-foundry/deepseek-v4-pro now works for plain chat in OpenClaw, but tool-using/operator turns remain unreliable because DeepSeek/Foundry sometimes emits DSML tool markup as plain assistant text instead of native tool_calls, and the current openai-completions stream path does not recover that text into executable tool calls.

Fix Action

Fix / Workaround

Tested patch candidate

I added a conservative local patch in src/agents/openai-transport-stream.ts plus regression tests in src/agents/openai-transport-stream.test.ts that recover the observed DSML form into synthetic toolCall blocks when:

  • the DSML block is complete
  • the invoke name exists
  • parameters or JSON body parse into valid object arguments

Important caveat

This is currently a source-tree patch candidate, not a fully validated installed-runtime fix yet. The local openclaw CLI I reproed with is still the installed build and did not automatically pick up the edited source tree, so I have not yet re-validated the runtime end-to-end on a build containing the patch.

Suggested next step

Take this as a bug + patch candidate:

  • add a conservative DSML-text-to-toolCall recovery layer in processOpenAICompletionsStream(...) (or a provider-specific wrapper)
  • only synthesize a tool call when the DSML block is complete and arguments parse cleanly
  • leave malformed/incomplete DSML as plain text
  • then validate from an actual build path using the patched source rather than the currently installed binary

Code Example

openclaw agent --local --agent main --model microsoft-foundry/deepseek-v4-pro --thinking minimal --message 'Call the session_status tool exactly once with sessionKey current and then stop.' --json

---

<DSML|tool_calls>
<DSML|invoke name="session_status">
<DSML|parameter name="sessionKey" string="true">current</DSML|parameter>
</DSML|invoke>
</DSML|tool_calls>

---

<DSML|tool_calls>
<DSML|invoke name="session_status">
</DSML|invoke>
</DSML|tool_calls>

---

npx vitest run src/agents/openai-transport-stream.test.ts -t "recovers observed DeepSeek DSML parameter tool call|filters DeepSeek DSML content without disturbing native tool calls|keeps DeepSeek DSML state across native tool-call chunks"
RAW_BUFFERClick to expand / collapse

Summary

microsoft-foundry/deepseek-v4-pro now works for plain chat in OpenClaw, but tool-using/operator turns remain unreliable because DeepSeek/Foundry sometimes emits DSML tool markup as plain assistant text instead of native tool_calls, and the current openai-completions stream path does not recover that text into executable tool calls.

What changed

A prior fix already addressed the earlier request-shaping failure where Foundry rejected DeepSeek-style thinking payloads (400 Unrecognized request argument supplied: thinking). Plain chat/reasoning calls now succeed.

The remaining failure is later in the pipeline: tool intent is sometimes surfaced as text instead of becoming toolCall blocks.

Live evidence

Installed runtime checked locally:

  • openclaw --version -> OpenClaw 2026.5.20 (e510042)

Plain response smoke tests succeeded:

  • openclaw agent --local --agent main --model microsoft-foundry/deepseek-v4-pro --thinking minimal --message 'Reply with exactly DEEPSEEK_SMOKE_OK' --json
  • openclaw agent --local --agent main --model microsoft-foundry/deepseek-v4-pro --thinking medium --message 'Reply with exactly DEEPSEEK_MEDIUM_OK' --json

Tool-use repro against the real CLI/runtime:

openclaw agent --local --agent main --model microsoft-foundry/deepseek-v4-pro --thinking minimal --message 'Call the session_status tool exactly once with sessionKey current and then stop.' --json

Observed assistant payload returned as visible text instead of an executed tool call:

<|DSML|tool_calls>
<|DSML|invoke name="session_status">
<|DSML|parameter name="sessionKey" string="true">current</|DSML|parameter>
</|DSML|invoke>
</|DSML|tool_calls>

A second live variant was malformed/incomplete and omitted the parameter body entirely:

<|DSML|tool_calls>
<|DSML|invoke name="session_status">
</|DSML|invoke>
</|DSML|tool_calls>

Subagent/history verification also showed that the tool was not actually executed; the markup was emitted as assistant text.

Source diagnosis

Relevant repo inspected locally at /Users/manos/Code/openclaw.

What the current code does

src/agents/deepseek-text-filter.ts contains createDeepSeekTextFilter() which strips DSML wrapper text from visible output.

src/agents/openai-transport-stream.ts uses that filter in processOpenAICompletionsStream(...), but real tool calls are still created only from native choiceDelta.tool_calls.

So today the behavior is:

  • if DeepSeek/Foundry emits native tool_calls, OpenClaw can handle them
  • if DeepSeek/Foundry emits DSML tool markup as plain text, OpenClaw currently strips/streams text but does not promote it to toolCall

Why this is likely not just expected model behavior

DeepSeek's own tool-calls docs describe OpenAI-compatible native message.tool_calls as the intended path:

There is also upstream evidence that DeepSeek V4 Pro can intermittently emit tool calls as plain text with tool_calls: null:

So the remaining problem looks like a combination of:

  1. upstream/provider instability in DeepSeek tool emission
  2. missing defensive recovery in OpenClaw for DSML/textual tool intent on the openai-completions stream path

Tested patch candidate

I added a conservative local patch in src/agents/openai-transport-stream.ts plus regression tests in src/agents/openai-transport-stream.test.ts that recover the observed DSML form into synthetic toolCall blocks when:

  • the DSML block is complete
  • the invoke name exists
  • parameters or JSON body parse into valid object arguments

Added test coverage for:

  • one-chunk observed DSML tool text
  • split-chunk observed DSML tool text
  • coexistence with existing DeepSeek DSML filtering/native-tool-call tests

Targeted validation passed:

npx vitest run src/agents/openai-transport-stream.test.ts -t "recovers observed DeepSeek DSML parameter tool call|filters DeepSeek DSML content without disturbing native tool calls|keeps DeepSeek DSML state across native tool-call chunks"

Result:

  • 2 test files passed
  • 8 tests passed
  • 0 failures in that targeted set

Important caveat

This is currently a source-tree patch candidate, not a fully validated installed-runtime fix yet. The local openclaw CLI I reproed with is still the installed build and did not automatically pick up the edited source tree, so I have not yet re-validated the runtime end-to-end on a build containing the patch.

Suggested next step

Take this as a bug + patch candidate:

  • add a conservative DSML-text-to-toolCall recovery layer in processOpenAICompletionsStream(...) (or a provider-specific wrapper)
  • only synthesize a tool call when the DSML block is complete and arguments parse cleanly
  • leave malformed/incomplete DSML as plain text
  • then validate from an actual build path using the patched source rather than the currently installed binary

Labels / framing suggestion

  • bug
  • providers
  • microsoft-foundry
  • deepseek
  • streaming
  • tool-calls

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - 💡(How to fix) Fix Bug: Foundry DeepSeek V4 tool turns surface DSML text instead of executable tool calls