Skip to content

[defer] fix(deepseek-web): support native DSML tool calls - #13345

Merged
diegosouzapw merged 3 commits into
cheaper-inference:release/v3.8.52from
espokaos-ops:fix/deepseek-web-dsml-tool-calling
Oct 1, 2026
Merged

diegosouzapw merged 3 commits into
cheaper-inference:release/v3.8.52from
espokaos-ops:fix/deepseek-web-dsml-tool-calling

Conversation

@espokaos-ops

Copy link
Copy Markdown
Contributor

Summary

DeepSeek Web can emit native DSML tool calls even when OmniRoute requests the canonical <tool>{JSON}</tool> format.

Previously, the DeepSeek Web translator only recognized <tool> / <tool_call> markers. Native DSML was therefore returned as normal text, causing the executor to emit finish_reason: stop instead of tool_calls. Agent clients such as OpenCode could then hang after the model indicated that it wanted to use a tool.

This patch adds native DSML parsing to the DeepSeek Web translator.

Changes

  • Recognize native DeepSeek DSML <calls> / <invoke> / <parameter> markers.
  • Support root-level <invoke> calls as well as the <calls> envelope.
  • Support multiple tool calls and multiple parameters.
  • Reuse the existing tool-name resolution and argument helpers.
  • Preserve tool-call ordering.
  • Preserve normal surrounding content.
  • Fail safely on malformed, empty, or incomplete invokes.
  • Prevent an unclosed invoke from consuming legitimate trailing text.
  • Strip consumed DSML ranges while preserving unrelated response content.
  • Update the DeepSeek Web prompt to explicitly request OmniRoute's expected tool-call format.

Root cause

The previous parser contained a fail-fast check equivalent to:

if (
  typeof text !== "string" ||
  (!text.includes("<tool>") && !text.includes("<tool_call"))
) {
  return { content: text ?? "", toolCalls: null };
}

Native DSML therefore never reached the tool parser.

The executor subsequently observed:

toolCalls = null
finishReason = "stop"

instead of emitting OpenAI-compatible tool_calls.

Validation

The implementation was validated against real DeepSeek Web traffic containing native DSML.

  • 20/20 dedicated DSML unit tests pass.

  • 34/34 adversarial regression checks pass.

  • 3/3 executor split checks pass.

  • 6/6 byte-equivalence checks pass.

  • Existing non-DSML behavior remains equivalent.

  • Full live tool loop validated after rebuilding the patched bundle:

    • echo HOLA
    • free -h
    • uname -a
    • tool call -> execution -> tool result -> second model turn -> final response
  • A real captured native DSML call was successfully converted to an OpenAI-compatible function call and executed through Bash.

Scope / limitations

This is intentionally a focused DSML translator rather than a general XML/DSML parser.

Known edge cases include literal DSML markers embedded inside parameter values. The implementation is fail-safe for malformed or incomplete tool calls and does not execute invalid tool invocations.

No unrelated files, generated bundles, backups, logs, or temporary PoC artifacts are included in the commit.

@bagusandrewijaya

Copy link
Copy Markdown

are you already solve and can use deepseek web for coding copilot

@espokaos-ops

Copy link
Copy Markdown
Contributor Author

Yes, I tested it end-to-end with real DeepSeek Web traffic and the tool-calling issue is solved.

I can use DeepSeek Web as a coding copilot with this patch. The full tool loop works correctly, including tool calls, execution, tool results, and the following model turn.

I tested it with real commands like echo HOLA, free -h, and uname -a, and the DSML and regression tests are passing as well.

One thing worth mentioning is that DeepSeek can ban the account when using it this way. This actually happened to me during testing, and I had to create a new account. Other than that account-related risk, everything worked correctly for me.

@diegosouzapw

Copy link
Copy Markdown
Collaborator

Thorough, well-tested fix for the native DSML dialect — the stack-based tokenizer and the L2
fail-safe (no call without at least one non-empty argument) are the right call given how sloppy
the upstream closers are in the wild. Ran deepseekWebTools.dsml.test.ts at your head — all
green, and your live end-to-end confirmation in the comments is great extra evidence. Heads up
for context: #13226 touches the same file (different functions, verified conflict-free) and
#12905 handles a related-but-distinct DSML dialect on the non-web DeepSeek path — no action
needed on your end, just flagging for the maintainer. Only ask: add a changelog.d/fixes/
fragment.

@diegosouzapw diegosouzapw changed the title fix(deepseek-web): support native DSML tool calls [defer] fix(deepseek-web): support native DSML tool calls Sep 29, 2026
@diegosouzapw diegosouzapw added the deferred-v3.8.52 Grande demais / suspeito para o lote atual; precisa de sessão dedicada no ciclo v3.8.52 label Sep 29, 2026
Reconciles the native DSML parser with the tip's cheaper-inference#13930/cheaper-inference#14446 handling in
deepseekWebTools.ts: the sloppy-closer DSML parser runs on the original text
first; when it yields no calls the tip's normalizing path runs unchanged
(extracted into normalizeDeepSeekMarkup).

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
@diegosouzapw
diegosouzapw changed the base branch from release/v3.8.51 to release/v3.8.52 September 29, 2026 11:25
@diegosouzapw

Copy link
Copy Markdown
Collaborator

Re-homed to release/v3.8.52: v3.8.51 entered its release freeze, so the branch now belongs to the release captain and development continues on the next cycle. Nothing is wrong with this PR — it just needed a live base. No action needed from you; CI will re-run against the new base.

@diegosouzapw
diegosouzapw merged commit 3fd15a7 into cheaper-inference:release/v3.8.52 Oct 1, 2026
3 checks passed
@diegosouzapw

Copy link
Copy Markdown
Collaborator

Thanks @espokaos-ops — merged into release/v3.8.52; it ships in the next release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

deferred-v3.8.52 Grande demais / suspeito para o lote atual; precisa de sessão dedicada no ciclo v3.8.52

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants