Skip to content

[Frontend] DeepSeek-V4 native OpenAI/Anthropic/Responses API + DSML tool parser - #1563

Draft
yhl-amd wants to merge 15 commits into
ROCm:mainfrom
yhl-amd:feat/dsv4-pro-openai-anthropic-responses-api
Draft

[Frontend] DeepSeek-V4 native OpenAI/Anthropic/Responses API + DSML tool parser#1563
yhl-amd wants to merge 15 commits into
ROCm:mainfrom
yhl-amd:feat/dsv4-pro-openai-anthropic-responses-api

Conversation

@yhl-amd

@yhl-amd yhl-amd commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Serve DeepSeek-V4 (Pro/Flash) so Claude Code (Anthropic /v1/messages) and Codex CLI (OpenAI Responses /v1/responses) can talk to ATOM directly, with DSML tool-call parsing shared across /v1/chat/completions, /v1/messages and /v1/responses.

Stacked on #1562 (uses the abort_request disconnect path). Review/merge that first; until then this PR's diff includes that commit.

Changes

  • tool_parser: DeepSeek-V4 DSML tool-call format (<|DSML|invoke ...>) with marker-less / self-closing / direct-JSON recovery, schema-driven type coercion and key aliases; streaming + non-streaming (alongside existing Qwen/GLM/MiniMax).
  • serving_chat: reasoning-filter + tool-call streaming for /v1/chat/completions (reasoning_content deltas during think phase, tool_calls deltas).
  • serving_responses (new) + /v1/responses endpoint: OpenAI Responses translation (input/tools ↔ chat, SSE emitter, reasoning/function_call items). Codex compat: inject a mandatory DSML tool-format instruction; normalize shell tool name/param aliases (exec/shell_exec/… → registered exec tool; command/scriptcmd) so Codex tool calls execute instead of erroring.
  • /v1/messages: pass the tool schema to the parser so tool args are typed correctly (fixes Claude Code "Invalid tool parameters"); streaming UTF-8 incremental detokenization (vLLM-style sliding window) so multi-byte chars (CJK, box-drawing) aren't split into U+FFFD.
  • reasoning / chat_encoders: DeepSeek-V4 message encoding + reasoning tags.

Test plan

  • claude-local (Claude Code → /v1/messages): multi-tool agentic session, tools execute, no "Invalid tool parameters", CJK/box-drawing render cleanly.
  • codex-local (Codex → /v1/responses): tool calls execute (no "unsupported call"/"missing field cmd"), multi-step task completes.
  • /v1/chat/completions streaming: reasoning + tool_calls deltas.

🤖 Generated with Claude Code

@github-actions

Copy link
Copy Markdown
Contributor

🏷️ CI Guide

Runs automatically on every eligible PR before approval:

  • ✅ Pre Checkin: Black, Ruff, catalog schema validation, non-GPU unit tests

Heavy model tests:

  • ✅ Run after the PR is approved and Pre Checkin passes
  • ✅ Run immediately when an approval review is submitted
  • ✅ Can be requested before approval with labels
Label Tests
ci:full Run all heavy PR model tests: native ATOM, vLLM, and SGLang
ci:atom Run native ATOM model accuracy tests
ci:vllm Run ATOM vLLM OOT model accuracy tests
ci:sglang Run ATOM SGLang model accuracy tests

Heavy jobs are skipped when the PR is not approved and no matching ci:* label is present.
Add labels via the sidebar or gh pr edit 1563 --add-label <label>

@yhl-amd
yhl-amd force-pushed the feat/dsv4-pro-openai-anthropic-responses-api branch 2 times, most recently from e884e5c to aea46ad Compare July 10, 2026 23:36
@zufayu
zufayu requested review from valarLip and removed request for valarLip July 13, 2026 01:37
@yhl-amd
yhl-amd force-pushed the feat/dsv4-pro-openai-anthropic-responses-api branch 3 times, most recently from 8abadef to 999168e Compare July 13, 2026 03:24
yhl-amd added a commit to yhl-amd/ATOM that referenced this pull request Jul 27, 2026
…mpletions streaming drains

PR ROCm#1563 added the batched stream-dispatch (per-seq stream callbacks buffer
their chunks into a thread-local; flush_stream_batch() drains the whole step's
buffer into the per-request asyncio queues via one call_soon_threadsafe per
event loop) but left the hook unwired: engine_core_mgr._flush_stream_batch_fn
was only initialized to None, never resolved, and never called in the output
thread. The result: streaming /v1/chat/completions and /v1/messages emitted
only the initial synthetic role:assistant chunk, then hung indefinitely as
the model's content chunks piled up in the thread-local buffer and never
reached the per-request queue (the client timed out and the abort-on-disconnect
fired). Non-streaming requests were unaffected.

Fix: (a) engine_core_mgr's output thread calls self._flush_stream_batch_fn()
(if set) after each step's per-seq callback dispatch; (b) the api server
resolves the hook to flush_stream_batch lazily after engine init (avoids the
api_server <-> engine_core_mgr import cycle).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: yihonglie <hyi@amd.com>
(cherry picked from commit 7c2a88a07a807a7d055cef2a60351107bcd7b917)
yhl-amd added a commit to yhl-amd/ATOM that referenced this pull request Jul 27, 2026
PR ROCm#1563 only injected the mandatory DSML tool-call format instruction on the
/v1/responses path (Codex), not /v1/messages (Claude Code / Anthropic). Without
it, DSV4 running under Claude Code (which speaks the Anthropic /v1/messages
API) does not receive the 'output ONLY a DSML tool-call block' instruction, so
it emits ad-hoc/mixed tool calls instead of its native DSML format — weaker
agentic behavior. Add the same inject_tool_format_instruction(openai_messages)
call (gated on request.tools) that /v1/responses uses, right after
anthropic_to_openai_messages.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: yihonglie <hyi@amd.com>
(cherry picked from commit 83984016fc141f14982d60cd3d0fb1637d169e4b)
yhl-amd added a commit to yhl-amd/ATOM that referenced this pull request Jul 27, 2026
…essages

DSV4 (sparse indexer, index_topk=1024) cannot reliably verbatim-recall a path
buried in a ~20-40k-token system prompt. Claude Code (Anthropic /v1/messages)
puts the working directory in the system message but NOT in the Bash tool
description, so DSV4 blind-cd's to whatever path the user named (e.g.
'cd /app/vllm-rocm && ls' on a non-existent path) instead of using the
absolute path or pwd'ing first. Codex (/v1/responses) sends <cwd>...</cwd>
environment_context which extract_cwd rewrites against; Claude Code has no
such field (Anthropic-incompatible).

Empirical A/B on the same DSV4 server (temp 0, 2 runs/condition): with the
cwd in the Bash tool description DSV4 ls's the absolute path / pwd's first
(0/2 blind-cd); without it DSV4 blind-cd's to the user-named path (2/2). The
endpoint and the ROCm#1563 DSML-format inject are NOT the discriminating variable
(held constant in the A/B); wording + cwd-presence is.

Add extract_cwd_from_system (pulls 'Working directory: <path>' from the Claude
Code system message) + inject_cwd_into_bash_tool (appends
'The current working directory is <path>' to the Bash tool description), and
wire them on the /v1/messages path. This is a prompt-content mitigation of a
model-level recall cliff, not a fix to a serving bug — the /v1/messages prompt
is otherwise correctly constructed (cwd is in the system message).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: yihonglie <hyi@amd.com>
(cherry picked from commit 6e0b326e5bbd88559f385973305fda40efb2ac63)
@yhl-amd

yhl-amd commented Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

Pushed 7 follow-up commits (append-only fast-forward) making the DSV4 native agentic path actually work end-to-end and hardening it:

Makes tool-calling work / native agentic:

  • [Bugfix] Wire batched stream-flush hook — the batched stream-dispatch hook was left unwired (_flush_stream_batch_fn = None, never resolved/called), so streaming /v1/messages + /v1/chat/completions emitted only the synthetic role chunk then hung. Now resolved lazily after engine init.
  • [Bugfix] Inject DSML tool-format instruction on /v1/messages too
  • [Frontend] Inject Claude Code cwd into Bash tool description on /v1/messages — mitigates the long-context cwd recall cliff.

Accuracy (DeepSeek-V4 #1507):

  • [Bugfix] DeepSeek-V4: drop Hadamard on indexer Q to match un-rotated K (#1507) — the lightning-indexer scored (Hq)·k instead of q·k (Q was Hadamard-rotated, the compressor's K was not), flattening sparse top-k so long-context needles couldn't be recalled. Apply RoPE-only to Q. Verified 13/13 needle recall on DSV4-Pro TP8 fp8 at default index_topk=1024, incl. ~40k-token prompts in the sparse regime. (Note: this is a model-path fix living in this frontend PR for convenience — happy to split it out to a standalone PR against [DeepSeek-V4] index_topk=1024 sparse indexer can't recall verbatim lines from ~18k+ prompts (breaks agentic cwd/env recall) #1507 if preferred.)

Robustness (from a 10-angle review of this PR):

  • [Bugfix] Abort leaked seq on streaming client disconnect (chat + responses) — three stream generators cleaned up with aborted=False, so client disconnect never aborted the engine seq (ran to max_tokens, wasting KV/GPU). Restored the aborted tracking pattern from serving_completion.py.
  • [Bugfix] Guard Responses tool translation against malformed inputs — null function field (AttributeError) + non-numeric offset/limit (ValueError mid-stream).
  • [Bugfix] Preserve cwd paths containing spaces in Codex <cwd> extraction.

yhl-amd added a commit to yhl-amd/ATOM that referenced this pull request Jul 28, 2026
…mpletions streaming drains

PR ROCm#1563 added the batched stream-dispatch (per-seq stream callbacks buffer
their chunks into a thread-local; flush_stream_batch() drains the whole step's
buffer into the per-request asyncio queues via one call_soon_threadsafe per
event loop) but left the hook unwired: engine_core_mgr._flush_stream_batch_fn
was only initialized to None, never resolved, and never called in the output
thread. The result: streaming /v1/chat/completions and /v1/messages emitted
only the initial synthetic role:assistant chunk, then hung indefinitely as
the model's content chunks piled up in the thread-local buffer and never
reached the per-request queue (the client timed out and the abort-on-disconnect
fired). Non-streaming requests were unaffected.

Fix: (a) engine_core_mgr's output thread calls self._flush_stream_batch_fn()
(if set) after each step's per-seq callback dispatch; (b) the api server
resolves the hook to flush_stream_batch lazily after engine init (avoids the
api_server <-> engine_core_mgr import cycle).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: yihonglie <hyi@amd.com>
(cherry picked from commit 7c2a88a07a807a7d055cef2a60351107bcd7b917)
yhl-amd added a commit to yhl-amd/ATOM that referenced this pull request Jul 28, 2026
PR ROCm#1563 only injected the mandatory DSML tool-call format instruction on the
/v1/responses path (Codex), not /v1/messages (Claude Code / Anthropic). Without
it, DSV4 running under Claude Code (which speaks the Anthropic /v1/messages
API) does not receive the 'output ONLY a DSML tool-call block' instruction, so
it emits ad-hoc/mixed tool calls instead of its native DSML format — weaker
agentic behavior. Add the same inject_tool_format_instruction(openai_messages)
call (gated on request.tools) that /v1/responses uses, right after
anthropic_to_openai_messages.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: yihonglie <hyi@amd.com>
(cherry picked from commit 83984016fc141f14982d60cd3d0fb1637d169e4b)
yhl-amd added a commit to yhl-amd/ATOM that referenced this pull request Jul 28, 2026
…essages

DSV4 (sparse indexer, index_topk=1024) cannot reliably verbatim-recall a path
buried in a ~20-40k-token system prompt. Claude Code (Anthropic /v1/messages)
puts the working directory in the system message but NOT in the Bash tool
description, so DSV4 blind-cd's to whatever path the user named (e.g.
'cd /app/vllm-rocm && ls' on a non-existent path) instead of using the
absolute path or pwd'ing first. Codex (/v1/responses) sends <cwd>...</cwd>
environment_context which extract_cwd rewrites against; Claude Code has no
such field (Anthropic-incompatible).

Empirical A/B on the same DSV4 server (temp 0, 2 runs/condition): with the
cwd in the Bash tool description DSV4 ls's the absolute path / pwd's first
(0/2 blind-cd); without it DSV4 blind-cd's to the user-named path (2/2). The
endpoint and the ROCm#1563 DSML-format inject are NOT the discriminating variable
(held constant in the A/B); wording + cwd-presence is.

Add extract_cwd_from_system (pulls 'Working directory: <path>' from the Claude
Code system message) + inject_cwd_into_bash_tool (appends
'The current working directory is <path>' to the Bash tool description), and
wire them on the /v1/messages path. This is a prompt-content mitigation of a
model-level recall cliff, not a fix to a serving bug — the /v1/messages prompt
is otherwise correctly constructed (cwd is in the system message).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: yihonglie <hyi@amd.com>
(cherry picked from commit 6e0b326e5bbd88559f385973305fda40efb2ac63)
@yhl-amd
yhl-amd force-pushed the feat/dsv4-pro-openai-anthropic-responses-api branch from 8516bab to 23f5e67 Compare July 28, 2026 06:43
yhl-amd and others added 14 commits July 28, 2026 19:38
…ool parser

Serve DeepSeek-V4 (Pro/Flash) so Claude Code (Anthropic /v1/messages) and Codex
CLI (OpenAI Responses /v1/responses) talk to ATOM directly, with DSML tool-call
parsing shared across /v1/chat/completions, /v1/messages and /v1/responses.

- tool_parser: DeepSeek-V4 DSML tool-call format (<|DSML|invoke ...>) with
  marker-less / self-closing / direct-JSON recovery, schema-driven type coercion
  and key aliases; streaming + non-streaming (alongside Qwen/GLM/MiniMax).
- serving_chat: reasoning-filter + tool-call streaming for /v1/chat/completions.
- serving_responses (new) + /v1/responses: OpenAI Responses translation
  (input/tools<->chat, SSE emitter, reasoning/function_call items). Codex compat:
  inject a mandatory DSML tool-format instruction and normalize shell tool
  name/param aliases (exec/shell_exec/... -> registered exec tool; command/script
  -> cmd) so Codex tool calls execute instead of erroring.
- /v1/messages: pass the tool schema to the parser so tool args are typed
  correctly (fixes "Invalid tool parameters"); streaming UTF-8 incremental
  detokenization (vLLM-style sliding window) so multi-byte chars (CJK,
  box-drawing) aren't split into U+FFFD.
- reasoning / chat_encoders: DeepSeek-V4 message encoding + reasoning tags.

Builds on the abort-on-disconnect path from the previous commit.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fixes "Check Code Style with Black" CI on the DSV4 API + DSML tool parser
changes (serving_responses.py, tool_parser.py, api_server.py).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: yihonglie <hyi@amd.com>
…mpletions streaming drains

PR ROCm#1563 added the batched stream-dispatch (per-seq stream callbacks buffer
their chunks into a thread-local; flush_stream_batch() drains the whole step's
buffer into the per-request asyncio queues via one call_soon_threadsafe per
event loop) but left the hook unwired: engine_core_mgr._flush_stream_batch_fn
was only initialized to None, never resolved, and never called in the output
thread. The result: streaming /v1/chat/completions and /v1/messages emitted
only the initial synthetic role:assistant chunk, then hung indefinitely as
the model's content chunks piled up in the thread-local buffer and never
reached the per-request queue (the client timed out and the abort-on-disconnect
fired). Non-streaming requests were unaffected.

Fix: (a) engine_core_mgr's output thread calls self._flush_stream_batch_fn()
(if set) after each step's per-seq callback dispatch; (b) the api server
resolves the hook to flush_stream_batch lazily after engine init (avoids the
api_server <-> engine_core_mgr import cycle).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: yihonglie <hyi@amd.com>
(cherry picked from commit 7c2a88a07a807a7d055cef2a60351107bcd7b917)
PR ROCm#1563 only injected the mandatory DSML tool-call format instruction on the
/v1/responses path (Codex), not /v1/messages (Claude Code / Anthropic). Without
it, DSV4 running under Claude Code (which speaks the Anthropic /v1/messages
API) does not receive the 'output ONLY a DSML tool-call block' instruction, so
it emits ad-hoc/mixed tool calls instead of its native DSML format — weaker
agentic behavior. Add the same inject_tool_format_instruction(openai_messages)
call (gated on request.tools) that /v1/responses uses, right after
anthropic_to_openai_messages.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: yihonglie <hyi@amd.com>
(cherry picked from commit 83984016fc141f14982d60cd3d0fb1637d169e4b)
…essages

DSV4 (sparse indexer, index_topk=1024) cannot reliably verbatim-recall a path
buried in a ~20-40k-token system prompt. Claude Code (Anthropic /v1/messages)
puts the working directory in the system message but NOT in the Bash tool
description, so DSV4 blind-cd's to whatever path the user named (e.g.
'cd /app/vllm-rocm && ls' on a non-existent path) instead of using the
absolute path or pwd'ing first. Codex (/v1/responses) sends <cwd>...</cwd>
environment_context which extract_cwd rewrites against; Claude Code has no
such field (Anthropic-incompatible).

Empirical A/B on the same DSV4 server (temp 0, 2 runs/condition): with the
cwd in the Bash tool description DSV4 ls's the absolute path / pwd's first
(0/2 blind-cd); without it DSV4 blind-cd's to the user-named path (2/2). The
endpoint and the ROCm#1563 DSML-format inject are NOT the discriminating variable
(held constant in the A/B); wording + cwd-presence is.

Add extract_cwd_from_system (pulls 'Working directory: <path>' from the Claude
Code system message) + inject_cwd_into_bash_tool (appends
'The current working directory is <path>' to the Bash tool description), and
wire them on the /v1/messages path. This is a prompt-content mitigation of a
model-level recall cliff, not a fix to a serving bug — the /v1/messages prompt
is otherwise correctly constructed (cwd is in the system message).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: yihonglie <hyi@amd.com>
(cherry picked from commit 6e0b326e5bbd88559f385973305fda40efb2ac63)
…onses)

Three streaming generators called cleanup_streaming_request() in their finally
with the default aborted=False. On client disconnect (GeneratorExit) the engine
sequence was never aborted — it kept decoding to max_tokens with no consumer,
wasting GPU cycles and KV-cache blocks. cleanup_streaming_request() only calls
engine.core_mgr.abort_request() when aborted=True.

Restore the aborted-tracking pattern already used by serving_completion.py:
assume aborted=True before the stream, flip to False only after the stream
reaches its normal end, and pass aborted to cleanup in the finally. Affected:
stream_chat_response, stream_chat_response_fanout (serving_chat.py) and
generate_responses_stream (api_server.py). Normal completion is unchanged
(aborted=False -> abort is a no-op, no extra control-path broadcast).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: yihonglie <hyi@amd.com>
(cherry picked from commit a35fbf3c7f6daf6816b9e91a96a9ae688aa881f2)
Two crash sites in serving_responses.py, both reachable from model/client input
and fatal mid-stream (500 or truncated SSE):

- responses_tools_to_openai(): `tl.get("function", tl)` returns None when the
  key is present with value null, so the following `fn.get("name")` raised
  AttributeError. Use `tl.get("function") or tl`.
- _claude_tool_to_shell(): `int(off or 0)` / `int(lim or 200)` raised
  ValueError on non-numeric offset/limit (e.g. the model emits {"offset":"top"}),
  crashing the streaming handler. Wrap in try/except -> fall back to (1, 400).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: yihonglie <hyi@amd.com>
(cherry picked from commit ddc2897fcc830634824d838ca8b2464318ae220f)
extract_cwd()'s regex `<cwd>\s*([^<\s]+)\s*</cwd>` stopped at the first
whitespace, truncating paths like "/home/user/My Projects/foo" to
"/home/user/My" and corrupting all downstream path fix-ups. Use `[^<]+?`
(keeps internal spaces/newlines, never spans a stray '<', non-greedy so it
stops at the first </cwd>) and strip() the captured group.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: yihonglie <hyi@amd.com>
(cherry picked from commit 2be8dcb46b514b70974decd2b927f6e5661c765b)
Remove extract_cwd_from_system() and inject_cwd_into_bash_tool() and their
/v1/messages call site. They parsed the `Working directory: <path>` line out
of Claude Code's system prompt and appended it to the Bash tool description,
as a prompt-content mitigation for DSV4's recall cliff on long system prompts.

Also drops the private _text_of() helper, added by the same commit and left
with no callers once the two functions above are gone.

Codex's <cwd>...</cwd> handling (serving_responses.extract_cwd and its
_resolve_dir / _read_cmd consumers) is a separate mechanism and is unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: yihonglie <hyi@amd.com>
tool_parser.py had grown to 1048 lines holding five formats, and the streaming
half was largely copy-paste: _process_/_flush_ for qwen, dsml, glm and minimax
were 57 lines each differing in exactly two — the marker lookup and which
_parse_* to call. A stale `# -- Qwen3 XML --` header left above _process_glm
recorded where the last paste happened. All five also shared one mutable
`state`/`buf` on a single dataclass, with `state`'s meaning documented for Kimi
only.

Split into a package, one module per format, named after vLLM's
tool_parsers/ layout:

    tool_parser/
      tool_parser.py             ToolCall, ToolCallParser, BufferedMarkerParser
      schema.py                  build_param_types / coerce_param_value /
                                 coerce_json_or_raw
      registry.py                detection order + stream sniff + parse_tool_calls
      stream.py                  ToolCallStreamParser facade
      kimi_tool_parser.py
      qwen3_tool_parser.py
      deepseekv4_tool_parser.py
      glm_tool_parser.py
      minimax_tool_parser.py

Four of the five formats stream identically (buffer from a start marker, parse
the block at flush), so that strategy is written once in BufferedMarkerParser
and each format declares only START_MARKERS, HOLDBACK_CHARS and parse().
Kimi keeps its own process/flush: its token format is self-delimiting, so it
emits calls incrementally rather than buffering. GLM's and MiniMax's identical
value coercion is now one shared helper; DeepSeek-V4's is deliberately NOT
merged with it, because on a JSON-decode miss it falls back to value.strip()
where the shared one falls back to value.strip("\n").

Behavior is unchanged, including the parts that are only accidentally correct:
the detection order (documented in one place in registry.py instead of scattered
across if-branches), the streaming sniff being stricter than the non-streaming
detect, the `len(buf) > 8` heuristic, and parse_tool_calls returning unstripped
text when no format matches while every matching path strips.

Public API is unchanged — parse_tool_calls, ToolCallStreamParser and ToolCall
are re-exported from the package, so all five call sites, atomesh and the
existing tests import exactly as before. Net +59 lines: ~150 lines of duplicated
streaming logic removed, offset by per-file headers and the parser interface.

Verified: existing 13 tool-parser tests pass, plus a differential harness
comparing old vs new across 33 inputs (all five formats, malformed DSML
variants, unclosed blocks) — 226 comparisons covering parse_tool_calls and
streaming under six chunkings including one character at a time — byte-identical
after normalizing random tool-call ids.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: yihonglie <hyi@amd.com>
Remove inject_tool_format_instruction() and its _DSML_TOOL_INSTRUCTION prompt
block, plus both call sites: /v1/messages (anthropic_messages) and
/v1/responses (responses_endpoint).

It appended a "MANDATORY tool-call format" section to the system message
spelling out the DSML syntax, so a non-tuned model would emit parseable DSML
instead of ad-hoc <command>/```json text. Requested removed along with the
other prompt-content injections on these paths.

Note this is a behavior change, not dead-code cleanup: the tool parser's DSML
branch only fires on output that already looks like DSML, so models that
needed the instruction to produce it may now emit tool calls the parser cannot
recover. Worth re-checking DSV4-Pro tool calling on both paths.

Also fixes a comment left stale by the tool_parser package split: the
key-alias note referenced _parse_dsml, now DsmlParser.parse.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: yihonglie <hyi@amd.com>
Keep the shared reasoning parser focused on the supported standard think tags now that MiniMax M3 compatibility is out of scope.

Co-authored-by: Cursor <cursoragent@cursor.com>
Keep the shared chat-template dispatcher model-agnostic while giving DeepSeek-V4 the same synthetic tool-system message flow used by vLLM.

Co-authored-by: Cursor <cursoragent@cursor.com>
Extract incremental UTF-8 detokenization and queue batching so direct and fan-out streams share one lifecycle-safe dispatch path.

Co-authored-by: Cursor <cursoragent@cursor.com>
Remove the standalone Codex Responses endpoint and its tool adaptation layer so the frontend remains focused on chat and Anthropic protocols.

Co-authored-by: Cursor <cursoragent@cursor.com>
@yhl-amd
yhl-amd force-pushed the feat/dsv4-pro-openai-anthropic-responses-api branch from dcef850 to 4721c02 Compare July 28, 2026 12:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant