mudler / mudler/vllm.cpp

OpenAI multi-turn tool history reaches chat templates with string-valued arguments

Open
#526 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C++
Stars
423
Forks
53
Avg merge
20h 26m
Merged PRs (30d)
310

Description

Row: SERVE-TOOL-HISTORY-ARGS

Bug

The OpenAI Chat Completions protocol carries assistant.tool_calls[].function.arguments as a JSON-encoded string. vllm.cpp preserves that string through ChatMessage and BuildMessages() and hands it directly to Jinja. This diverges from pinned vLLM vllm/entrypoints/chat_utils.py::_postprocess_messages, which json.loads() each historical argument string before chat-template rendering (empty/null becomes {}).

Gemma 4 exposes the failure because its canonical DSL requires an arguments mapping. A valid first call such as {"command":"date"} is rendered into history as <|tool_call>call:terminal{"command":"date"}<tool_call|> rather than canonical <|tool_call>call:terminal{command:<|"|>date<|"|>}<tool_call|>. On the next turn Gemma imitates the quoted form; the parser faithfully returns a literal quote-wrapped key such as {"\"command\"":"\"ls\""}, and clients cannot find command. Retries recursively escape it.

Reproduction evidence

  • ~/llms/logs/agentic_tool_loop_20260811-212603.json: turns 1-2 have valid arguments; turn 3 is the first completed-history turn and emits the literal quote-wrapped key/value.
  • The same pattern repeats in agentic_tool_loop_20260811-202653.json.
  • Fresh-context controls emit valid {command: ...}-derived JSON.
  • Current vllm.cpp src/vllm/entrypoints/chat_template.cpp stores fn["arguments"] = tc.function.arguments.
  • Pinned vLLM converts strings to objects in vllm/entrypoints/chat_utils.py:1915-1951.
  • Google/vLLM Gemma 4 canonical templates now fail closed unless historical arguments are mappings.

Expected behavior

Before rendering any chat template, vllm.cpp should mirror vLLM message post-processing:

  1. Decode valid JSON argument strings to JSON values.
  2. Normalize empty/null arguments to {}.
  3. Reject invalid JSON instead of teaching the model malformed history.
  4. Preserve already-structured arguments internally.
  5. Gate a complete user → assistant tool call → tool result → next-generation Gemma render, plus non-Gemma template compatibility.

This must be fixed in vllm.cpp, not in Hermes or another client.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in src/vllm/entrypoints/chat_template.cpp, where fn["arguments"] is currently stored, and compare the pinned vLLM handling in vllm/entrypoints/chat_utils.py:1915-1951. Trace BuildMessages() through chat-template rendering, then add coverage for a complete tool-call history with Gemma 4 and a non-Gemma template, including valid, empty/null, structured, and invalid arguments.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
backend-api-design
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.