DeepSeek (V3/R1, V3.1, V3.2 DSML, V4 DSML, V4.1 DSML) on vllm 0.30.0
fail 51% strict pass 43 pass · 9 soft pass · 33 fail
Run
Checks
| Check | Pass | Soft | Fail | Error | Strict pass rate |
|---|---|---|---|---|---|
expected_match |
43 | 9 | 26 | 0 | 55% |
expected_error |
1 | 0 | 6 | 0 | 14% |
stream_equals_nonstream |
56 | 0 | 29 | 0 | 66% |
split_invariance |
60 | 0 | 25 | 0 | 71% |
no_leakage |
83 | 0 | 2 | 0 | 98% |
arguments_json |
54 | 0 | 18 | 0 | 75% |
arguments_schema |
50 | 0 | 22 | 0 | 69% |
parallel_order |
8 | 0 | 3 | 0 | 73% |
Fixtures needing attention
fail deepseek/sglang-v4-self-closing-invoke
expected_match, no_leakage, arguments_schema
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_match | nonstream | fail | tool_calls: expected ['submit'], got ['submit"/>\n</|DSML|tool_calls>'] |
expected_match | one | fail | tool_calls: expected ['submit'], got ['submit"/>\n</|DSML|tool_calls>'] |
expected_match | special | fail | tool_calls: expected ['submit'], got ['submit"/>\n</|DSML|tool_calls>'] |
expected_match | token | fail | tool_calls: expected ['submit'], got ['submit"/>\n</|DSML|tool_calls>'] |
expected_match | rand:1:8 | fail | tool_calls: expected ['submit'], got ['submit"/>\n</|DSML|tool_calls>'] |
expected_match | rand:2:8 | fail | tool_calls: expected ['submit'], got ['submit"/>\n</|DSML|tool_calls>'] |
expected_match | rand:3:8 | fail | tool_calls: expected ['submit'], got ['submit"/>\n</|DSML|tool_calls>'] |
expected_match | rand:4:8 | fail | tool_calls: expected ['submit'], got ['submit"/>\n</|DSML|tool_calls>'] |
expected_match | rand:5:8 | fail | tool_calls: expected ['submit'], got ['submit"/>\n</|DSML|tool_calls>'] |
no_leakage | nonstream | fail | tool_calls[0].name contains '|DSML|' |
no_leakage | one | fail | tool_calls[0].name contains '|DSML|' |
no_leakage | special | fail | tool_calls[0].name contains '|DSML|' |
no_leakage | token | fail | tool_calls[0].name contains '|DSML|' |
no_leakage | rand:1:8 | fail | tool_calls[0].name contains '|DSML|' |
no_leakage | rand:2:8 | fail | tool_calls[0].name contains '|DSML|' |
no_leakage | rand:3:8 | fail | tool_calls[0].name contains '|DSML|' |
no_leakage | rand:4:8 | fail | tool_calls[0].name contains '|DSML|' |
no_leakage | rand:5:8 | fail | tool_calls[0].name contains '|DSML|' |
arguments_schema | nonstream | fail | [0] 'submit"/>\n</|DSML|tool_calls>' is not an offered tool |
arguments_schema | one | fail | [0] 'submit"/>\n</|DSML|tool_calls>' is not an offered tool |
arguments_schema | special | fail | [0] 'submit"/>\n</|DSML|tool_calls>' is not an offered tool |
arguments_schema | token | fail | [0] 'submit"/>\n</|DSML|tool_calls>' is not an offered tool |
arguments_schema | rand:1:8 | fail | [0] 'submit"/>\n</|DSML|tool_calls>' is not an offered tool |
arguments_schema | rand:2:8 | fail | [0] 'submit"/>\n</|DSML|tool_calls>' is not an offered tool |
arguments_schema | rand:3:8 | fail | [0] 'submit"/>\n</|DSML|tool_calls>' is not an offered tool |
arguments_schema | rand:4:8 | fail | [0] 'submit"/>\n</|DSML|tool_calls>' is not an offered tool |
arguments_schema | rand:5:8 | fail | [0] 'submit"/>\n</|DSML|tool_calls>' is not an offered tool |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/engine-tests.jsonl --id deepseek/sglang-v4-self-closing-invoke --strategy one --strategy rand:1:8 --strategy rand:2:8 --strategy rand:3:8 --strategy rand:4:8 --strategy rand:5:8 --strategy special --strategy token --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 10 of fixtures/deepseek/engine-tests.jsonl.
Observed vs expected
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: nonstream, one, special, token, rand:1:8, rand:2:8, rand:3:8, rand:4:8, rand:5:8
@@ -5,5 +5,5 @@ { "arguments": {}, - "name": "submit" + "name": "submit\"/>\n</|DSML|tool_calls>" } ]
Fixture
Provenance: engine_test, https://github.com/sgl-project/sglang/blob/94602c9c2b7cbdb8efd5c52802dac6a1c180089e/test/registered/unit/function_call/test_function_call_parser.py#L2258.
Tags: single-call, empty-arguments, x-self-closing-invoke, x-deepseek-v4.
Raw output
<|DSML|tool_calls> <|DSML|invoke name="submit"/> </|DSML|tool_calls>
Expected parse
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {},
"name": "submit"
}
]
}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/sglang-v4-self-closing-invoke", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V4-Flash", "deepseek-ai/DeepSeek-V4-Pro"], "spec_version": "0.1", "provenance": {"kind": "engine_test", "source_url": "https://github.com/sgl-project/sglang/blob/94602c9c2b7cbdb8efd5c52802dac6a1c180089e/test/registered/unit/function_call/test_function_call_parser.py#L2258", "revision": "94602c9c2b7cbdb8efd5c52802dac6a1c180089e", "license": "Apache-2.0", "attribution": "Copyright SGLang Team"}, "tools": [{"type": "function", "function": {"name": "submit", "parameters": {"type": "object", "properties": {}}}}], "raw_output": "<|DSML|tool_calls>\n<|DSML|invoke name=\"submit\"/>\n</|DSML|tool_calls>", "output_token_ids": [30, 128825, 72461, 4941, 12548, 1018, 30, 128825, 40148, 5406, 2329, 1281, 35380, 39278, 1718, 128825, 72461, 4941, 12548, 32], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V4-Flash", "revision": "60d8d70770c6776ff598c94bb586a859a38244f1", "mode": "hf"}, "generation_prompt": "<|Assistant|></think>", "thinking": false, "expected": {"content": null, "reasoning_content": null, "tool_calls": [{"name": "submit", "arguments": {}}]}, "tags": ["single-call", "empty-arguments", "x-self-closing-invoke", "x-deepseek-v4"], "notes": "SGLang's test states 'V4 emits <|DSML|invoke name=\"x\"/> for zero-arg tools'. The official V4 encoder renders an open/close pair instead, and DeepSeek's reference parser rejects this form; kept because the engine reports the model generating it. output_token_ids: tokenizer.encode(raw_output)."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|></think>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V4-Flash",
"model_rule": "DeepSeek-V4",
"model_type": "deepseek_v4",
"parser_source": "docs/formats/deepseek.md (vLLM v0.30.0 row)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "emas to invoke tool calls.\n<|User|>Use the tools to answer.<|Assistant|></think>",
"reasoning_parser": "deepseek_v4",
"stop_token_in_final_delta": false,
"template": {
"sha256": "bfbb51e563b89c7d3581864cd0ea4d975b96e14fed034a222caf9d50c549b99d",
"source": "vLLM tokenizer_mode=deepseek_v4 encoder (vllm.tokenizers.deepseek_v4_encoding)"
},
"tokenizer": {
"mode": "deepseek_v4",
"repo": "deepseek-ai/DeepSeek-V4-Flash",
"requested_mode": "auto",
"resolved_revision": "60d8d70770c6776ff598c94bb586a859a38244f1",
"revision": "60d8d70770c6776ff598c94bb586a859a38244f1",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v4",
"units_source": "fixture.output_token_ids"
}
fail deepseek/v3-empty-arguments
expected_match, stream_equals_nonstream, split_invariance, arguments_json, arguments_schema
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_match | one | fail | tool_calls: expected ['get_time'], got [] |
expected_match | special | fail | tool_calls: expected ['get_time'], got [] |
expected_match | rand:2:8 | fail | tool_calls[0].arguments: expected '{}', got '' |
expected_match | rand:3:8 | fail | tool_calls[0].arguments: expected '{}', got '' |
stream_equals_nonstream | one | fail | tool_calls: nonstream ['get_time'], got [] |
stream_equals_nonstream | special | fail | tool_calls: nonstream ['get_time'], got [] |
stream_equals_nonstream | rand:2:8 | fail | tool_calls[0].arguments: nonstream '{}', got '' |
stream_equals_nonstream | rand:3:8 | fail | tool_calls[0].arguments: nonstream '{}', got '' |
split_invariance | * | fail | vs one: token (fail): tool_calls: one [], got ['get_time'] | rand:1:8 (fail): tool_calls: one [], got ['get_time'] | rand:2:8 (fail): tool_calls: one [], got ['get_time'] | rand:3:8 (fail): tool_calls: one [], got ['get_time'] | rand:4:8 (fail): tool_calls: one [], got ['get_time'] | rand:5:8 (fail): tool_calls: one [], got ['get_time'] |
arguments_json | rand:2:8 | fail | [0] get_time: arguments are not valid JSON text ('': Expecting value: line 1 column 1 (char 0)) |
arguments_json | rand:3:8 | fail | [0] get_time: arguments are not valid JSON text ('': Expecting value: line 1 column 1 (char 0)) |
arguments_schema | rand:2:8 | fail | [0] get_time: arguments are not a JSON object; not validated |
arguments_schema | rand:3:8 | fail | [0] get_time: arguments are not a JSON object; not validated |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/v3.jsonl --id deepseek/v3-empty-arguments --strategy one --strategy rand:2:8 --strategy rand:3:8 --strategy special --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 5 of fixtures/deepseek/v3.jsonl.
Observed vs expected
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: one, special
@@ -2,9 +2,4 @@ "content": null, "reasoning_content": null, - "tool_calls": [ - { - "arguments": {}, - "name": "get_time" - } - ] + "tool_calls": [] }
Strategies: rand:2:8, rand:3:8
@@ -4,5 +4,7 @@ "tool_calls": [ { - "arguments": {}, + "arguments": { + "<arguments_raw, not valid JSON>": "" + }, "name": "get_time" }
Strategies: nonstream, token, rand:1:8, rand:4:8, rand:5:8
Matches the expected parse.
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {},
"name": "get_time"
}
]
}
Fixture
Provenance: template_render, https://huggingface.co/deepseek-ai/DeepSeek-V3-0324/blob/e9b33add76883f293d6bf61f6bd89b497e80e335/tokenizer_config.json.
Tags: single-call, empty-arguments, x-deepseek-v3.
Raw output
<|tool▁calls▁begin|><|tool▁call▁begin|>function<|tool▁sep|>get_time
```json
{}
```<|tool▁call▁end|><|tool▁calls▁end|>
Expected parse
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {},
"name": "get_time"
}
]
}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/v3-empty-arguments", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V3-0324"], "spec_version": "0.1", "provenance": {"kind": "template_render", "source_url": "https://huggingface.co/deepseek-ai/DeepSeek-V3-0324/blob/e9b33add76883f293d6bf61f6bd89b497e80e335/tokenizer_config.json", "revision": "e9b33add76883f293d6bf61f6bd89b497e80e335", "license": "MIT", "generator": "scripts/fixtures/deepseek/build.py", "template_sha256": "22e97ba043dacf9df1f071a9de9d2bb6b0757491f16e96e810834b86e1641286", "attribution": "Copyright (c) 2023 DeepSeek"}, "tools": [{"type": "function", "function": {"name": "get_time", "description": "Get the current UTC time. Takes no arguments.", "parameters": {"type": "object", "properties": {}}}}], "raw_output": "<|tool▁calls▁begin|><|tool▁call▁begin|>function<|tool▁sep|>get_time\n```json\n{}\n```<|tool▁call▁end|><|tool▁calls▁end|>", "output_token_ids": [128806, 128808, 8701, 128814, 1133, 20035, 201, 9854, 14479, 201, 76188, 9854, 128809, 128807], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V3-0324", "revision": "e9b33add76883f293d6bf61f6bd89b497e80e335", "mode": "hf"}, "generation_prompt": "<|Assistant|>", "thinking": false, "expected": {"content": null, "reasoning_content": null, "tool_calls": [{"name": "get_time", "arguments": {}}]}, "tags": ["single-call", "empty-arguments", "x-deepseek-v3"], "notes": "Sub-format deepseek-v3; history render of the official chat template."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V3-0324",
"model_rule": "DeepSeek-V3",
"model_type": "deepseek_v3",
"parser_source": "docs/formats/deepseek.md (V3: no reasoning)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "<|begin▁of▁sentence|><|User|>Use the tools to answer.<|Assistant|>",
"reasoning_parser": null,
"stop_token_in_final_delta": false,
"template": {
"sha256": "22e97ba043dacf9df1f071a9de9d2bb6b0757491f16e96e810834b86e1641286",
"source": "tokenizer chat template (HF repo)"
},
"tokenizer": {
"mode": "hf",
"repo": "deepseek-ai/DeepSeek-V3-0324",
"requested_mode": "auto",
"resolved_revision": "e9b33add76883f293d6bf61f6bd89b497e80e335",
"revision": "e9b33add76883f293d6bf61f6bd89b497e80e335",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v3",
"units_source": "fixture.output_token_ids"
}
fail deepseek/v3-marker-in-arguments
expected_match, stream_equals_nonstream, split_invariance
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_match | one | fail | tool_calls: expected ['echo'], got [] |
expected_match | special | fail | tool_calls: expected ['echo'], got [] |
stream_equals_nonstream | one | fail | tool_calls: nonstream ['echo'], got [] |
stream_equals_nonstream | special | fail | tool_calls: nonstream ['echo'], got [] |
split_invariance | * | fail | vs one: token (fail): tool_calls: one [], got ['echo'] | rand:1:8 (fail): tool_calls: one [], got ['echo'] | rand:2:8 (fail): tool_calls: one [], got ['echo'] | rand:3:8 (fail): tool_calls: one [], got ['echo'] | rand:4:8 (fail): tool_calls: one [], got ['echo'] | rand:5:8 (fail): tool_calls: one [], got ['echo'] |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/v3.jsonl --id deepseek/v3-marker-in-arguments --strategy one --strategy special --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 8 of fixtures/deepseek/v3.jsonl.
Observed vs expected
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: one, special
@@ -2,11 +2,4 @@ "content": null, "reasoning_content": null, - "tool_calls": [ - { - "arguments": { - "text": "Reply as ```json\n{\"a\": 1}\n``` or use <|tool▁sep|> tokens." - }, - "name": "echo" - } - ] + "tool_calls": [] }
Strategies: nonstream, token, rand:1:8, rand:2:8, rand:3:8, rand:4:8, rand:5:8
Matches the expected parse.
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"text": "Reply as ```json\n{\"a\": 1}\n``` or use <|tool▁sep|> tokens."
},
"name": "echo"
}
]
}
Fixture
Provenance: template_render, https://huggingface.co/deepseek-ai/DeepSeek-V3-0324/blob/e9b33add76883f293d6bf61f6bd89b497e80e335/tokenizer_config.json.
Tags: single-call, marker-in-arguments, x-deepseek-v3.
Raw output
<|tool▁calls▁begin|><|tool▁call▁begin|>function<|tool▁sep|>echo
```json
{"text": "Reply as ```json\n{\"a\": 1}\n``` or use <|tool▁sep|> tokens."}
```<|tool▁call▁end|><|tool▁calls▁end|>
Expected parse
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"text": "Reply as ```json\n{\"a\": 1}\n``` or use <|tool▁sep|> tokens."
},
"name": "echo"
}
]
}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/v3-marker-in-arguments", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V3-0324"], "spec_version": "0.1", "provenance": {"kind": "template_render", "source_url": "https://huggingface.co/deepseek-ai/DeepSeek-V3-0324/blob/e9b33add76883f293d6bf61f6bd89b497e80e335/tokenizer_config.json", "revision": "e9b33add76883f293d6bf61f6bd89b497e80e335", "license": "MIT", "generator": "scripts/fixtures/deepseek/build.py", "template_sha256": "22e97ba043dacf9df1f071a9de9d2bb6b0757491f16e96e810834b86e1641286", "attribution": "Copyright (c) 2023 DeepSeek"}, "tools": [{"type": "function", "function": {"name": "echo", "description": "Echo a string back verbatim.", "parameters": {"type": "object", "properties": {"text": {"type": "string"}}, "required": ["text"]}}}], "raw_output": "<|tool▁calls▁begin|><|tool▁call▁begin|>function<|tool▁sep|>echo\n```json\n{\"text\": \"Reply as ```json\\n{\\\"a\\\": 1}\\n``` or use <|tool▁sep|> tokens.\"}\n```<|tool▁call▁end|><|tool▁calls▁end|>", "output_token_ids": [128806, 128808, 8701, 128814, 18843, 201, 9854, 14479, 201, 24313, 2067, 3362, 582, 19905, 412, 35739, 14479, 5809, 3757, 4, 67, 55550, 223, 19, 1464, 80, 9854, 469, 1347, 223, 128814, 35977, 2148, 1778, 9854, 128809, 128807], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V3-0324", "revision": "e9b33add76883f293d6bf61f6bd89b497e80e335", "mode": "hf"}, "generation_prompt": "<|Assistant|>", "thinking": false, "expected": {"content": null, "reasoning_content": null, "tool_calls": [{"name": "echo", "arguments": {"text": "Reply as ```json\n{\"a\": 1}\n``` or use <|tool▁sep|> tokens."}}]}, "tags": ["single-call", "marker-in-arguments", "x-deepseek-v3"], "notes": "The argument contains format-marker text, which the official tokenizer maps to special-token ids. Sub-format deepseek-v3; history render of the official chat template."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V3-0324",
"model_rule": "DeepSeek-V3",
"model_type": "deepseek_v3",
"parser_source": "docs/formats/deepseek.md (V3: no reasoning)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "<|begin▁of▁sentence|><|User|>Use the tools to answer.<|Assistant|>",
"reasoning_parser": null,
"stop_token_in_final_delta": false,
"template": {
"sha256": "22e97ba043dacf9df1f071a9de9d2bb6b0757491f16e96e810834b86e1641286",
"source": "tokenizer chat template (HF repo)"
},
"tokenizer": {
"mode": "hf",
"repo": "deepseek-ai/DeepSeek-V3-0324",
"requested_mode": "auto",
"resolved_revision": "e9b33add76883f293d6bf61f6bd89b497e80e335",
"revision": "e9b33add76883f293d6bf61f6bd89b497e80e335",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v3",
"units_source": "fixture.output_token_ids"
}
fail deepseek/v3-nested-json
expected_match, stream_equals_nonstream, split_invariance, arguments_json, arguments_schema
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_match | one | fail | tool_calls: expected ['create_event'], got [] |
expected_match | special | fail | tool_calls: expected ['create_event'], got [] |
expected_match | rand:2:8 | fail | tool_calls[0].arguments: expected '{"title": "Design review", "when": {"start": "2026-10-01T09:00:00Z", "end": "2026-10-01T10:00:00Z"}, "attendees": [{"name": "Ana", "optional": false}, {"nam..., got '{"title": "Design review", "when": {"start": "2026-10-01T09:00:00Z", "end": "2026-10-01T10:00:00Z"}, "attendees": [{"name": "Ana", "optional": false}, {"nam... |
stream_equals_nonstream | one | fail | tool_calls: nonstream ['create_event'], got [] |
stream_equals_nonstream | special | fail | tool_calls: nonstream ['create_event'], got [] |
stream_equals_nonstream | rand:2:8 | fail | tool_calls[0].arguments: nonstream '{"title": "Design review", "when": {"start": "2026-10-01T09:00:00Z", "end": "2026-10-01T10:00:00Z"}, "attendees": [{"name": "Ana", "optional": false}, {"nam..., got '{"title": "Design review", "when": {"start": "2026-10-01T09:00:00Z", "end": "2026-10-01T10:00:00Z"}, "attendees": [{"name": "Ana", "optional": false}, {"nam... |
split_invariance | * | fail | vs one: token (fail): tool_calls: one [], got ['create_event'] | rand:1:8 (fail): tool_calls: one [], got ['create_event'] | rand:2:8 (fail): tool_calls: one [], got ['create_event'] | rand:3:8 (fail): tool_calls: one [], got ['create_event'] | rand:4:8 (fail): tool_calls: one [], got ['create_event'] | rand:5:8 (fail): tool_calls: one [], got ['create_event'] |
arguments_json | rand:2:8 | fail | [0] create_event: arguments are not valid JSON text ('{"title": "Design review", "when": {"start": "2026-10-01T09:00:00Z", "end": "2026-10-01T10:00:00Z"}, "attendees": [{"name": "Ana", "optional": false}, {"nam...: Unterminated string starting at: line 1 column 195 (char 194)) |
arguments_schema | rand:2:8 | fail | [0] create_event: arguments are not a JSON object; not validated |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/v3.jsonl --id deepseek/v3-nested-json --strategy one --strategy rand:2:8 --strategy special --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 10 of fixtures/deepseek/v3.jsonl.
Observed vs expected
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: one, special
@@ -2,28 +2,4 @@ "content": null, "reasoning_content": null, - "tool_calls": [ - { - "arguments": { - "attendees": [ - { - "name": "Ana", - "optional": false - }, - { - "name": "Bo", - "optional": true, - "roles": [ - "notes" - ] - } - ], - "title": "Design review", - "when": { - "end": "2026-10-01T10:00:00Z", - "start": "2026-10-01T09:00:00Z" - } - }, - "name": "create_event" - } - ] + "tool_calls": [] }
Strategies: rand:2:8
@@ -5,22 +5,5 @@ { "arguments": { - "attendees": [ - { - "name": "Ana", - "optional": false - }, - { - "name": "Bo", - "optional": true, - "roles": [ - "notes" - ] - } - ], - "title": "Design review", - "when": { - "end": "2026-10-01T10:00:00Z", - "start": "2026-10-01T09:00:00Z" - } + "<arguments_raw, not valid JSON>": "{\"title\": \"Design review\", \"when\": {\"start\": \"2026-10-01T09:00:00Z\", \"end\": \"2026-10-01T10:00:00Z\"}, \"attendees\": [{\"name\": \"Ana\", \"optional\": false}, {\"name\": \"Bo\", \"optional\": true, \"roles\": [\"" }, "name": "create_event"
Strategies: nonstream, token, rand:1:8, rand:3:8, rand:4:8, rand:5:8
Matches the expected parse.
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"attendees": [
{
"name": "Ana",
"optional": false
},
{
"name": "Bo",
"optional": true,
"roles": [
"notes"
]
}
],
"title": "Design review",
"when": {
"end": "2026-10-01T10:00:00Z",
"start": "2026-10-01T09:00:00Z"
}
},
"name": "create_event"
}
]
}
Fixture
Provenance: template_render, https://huggingface.co/deepseek-ai/DeepSeek-V3-0324/blob/e9b33add76883f293d6bf61f6bd89b497e80e335/tokenizer_config.json.
Tags: single-call, nested-json, x-deepseek-v3.
Raw output
<|tool▁calls▁begin|><|tool▁call▁begin|>function<|tool▁sep|>create_event
```json
{"title": "Design review", "when": {"start": "2026-10-01T09:00:00Z", "end": "2026-10-01T10:00:00Z"}, "attendees": [{"name": "Ana", "optional": false}, {"name": "Bo", "optional": true, "roles": ["notes"]}]}
```<|tool▁call▁end|><|tool▁calls▁end|>
Expected parse
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"attendees": [
{
"name": "Ana",
"optional": false
},
{
"name": "Bo",
"optional": true,
"roles": [
"notes"
]
}
],
"title": "Design review",
"when": {
"end": "2026-10-01T10:00:00Z",
"start": "2026-10-01T09:00:00Z"
}
},
"name": "create_event"
}
]
}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/v3-nested-json", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V3-0324"], "spec_version": "0.1", "provenance": {"kind": "template_render", "source_url": "https://huggingface.co/deepseek-ai/DeepSeek-V3-0324/blob/e9b33add76883f293d6bf61f6bd89b497e80e335/tokenizer_config.json", "revision": "e9b33add76883f293d6bf61f6bd89b497e80e335", "license": "MIT", "generator": "scripts/fixtures/deepseek/build.py", "template_sha256": "22e97ba043dacf9df1f071a9de9d2bb6b0757491f16e96e810834b86e1641286", "attribution": "Copyright (c) 2023 DeepSeek"}, "tools": [{"type": "function", "function": {"name": "create_event", "description": "Create a calendar event.", "parameters": {"type": "object", "properties": {"title": {"type": "string"}, "when": {"type": "object"}, "attendees": {"type": "array", "items": {"type": "object"}}}, "required": ["title", "when"]}}}], "raw_output": "<|tool▁calls▁begin|><|tool▁call▁begin|>function<|tool▁sep|>create_event\n```json\n{\"title\": \"Design review\", \"when\": {\"start\": \"2026-10-01T09:00:00Z\", \"end\": \"2026-10-01T10:00:00Z\"}, \"attendees\": [{\"name\": \"Ana\", \"optional\": false}, {\"name\": \"Bo\", \"optional\": true, \"roles\": [\"notes\"]}]}\n```<|tool▁call▁end|><|tool▁calls▁end|>", "output_token_ids": [128806, 128808, 8701, 128814, 10028, 76740, 201, 9854, 14479, 201, 24313, 10212, 3362, 582, 31151, 3862, 1760, 582, 21123, 3362, 28612, 10513, 3362, 582, 939, 24, 15, 553, 15, 2616, 54, 3130, 28, 504, 28, 504, 60, 1760, 582, 523, 3362, 582, 939, 24, 15, 553, 15, 2616, 54, 553, 28, 504, 28, 504, 60, 87928, 582, 112191, 5993, 3362, 764, 24313, 2852, 3362, 582, 114991, 1760, 582, 41401, 3362, 5062, 6989, 28612, 2852, 3362, 582, 18056, 1760, 582, 41401, 3362, 3292, 14, 582, 81345, 3362, 20584, 33955, 13747, 37236, 1778, 9854, 128809, 128807], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V3-0324", "revision": "e9b33add76883f293d6bf61f6bd89b497e80e335", "mode": "hf"}, "generation_prompt": "<|Assistant|>", "thinking": false, "expected": {"content": null, "reasoning_content": null, "tool_calls": [{"name": "create_event", "arguments": {"title": "Design review", "when": {"start": "2026-10-01T09:00:00Z", "end": "2026-10-01T10:00:00Z"}, "attendees": [{"name": "Ana", "optional": false}, {"name": "Bo", "optional": true, "roles": ["notes"]}]}}]}, "tags": ["single-call", "nested-json", "x-deepseek-v3"], "notes": "Sub-format deepseek-v3; history render of the official chat template."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V3-0324",
"model_rule": "DeepSeek-V3",
"model_type": "deepseek_v3",
"parser_source": "docs/formats/deepseek.md (V3: no reasoning)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "<|begin▁of▁sentence|><|User|>Use the tools to answer.<|Assistant|>",
"reasoning_parser": null,
"stop_token_in_final_delta": false,
"template": {
"sha256": "22e97ba043dacf9df1f071a9de9d2bb6b0757491f16e96e810834b86e1641286",
"source": "tokenizer chat template (HF repo)"
},
"tokenizer": {
"mode": "hf",
"repo": "deepseek-ai/DeepSeek-V3-0324",
"requested_mode": "auto",
"resolved_revision": "e9b33add76883f293d6bf61f6bd89b497e80e335",
"revision": "e9b33add76883f293d6bf61f6bd89b497e80e335",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v3",
"units_source": "fixture.output_token_ids"
}
fail deepseek/v3-numeric-arguments
expected_match, stream_equals_nonstream, split_invariance
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_match | one | fail | tool_calls: expected ['calculate'], got [] |
expected_match | special | fail | tool_calls: expected ['calculate'], got [] |
stream_equals_nonstream | one | fail | tool_calls: nonstream ['calculate'], got [] |
stream_equals_nonstream | special | fail | tool_calls: nonstream ['calculate'], got [] |
split_invariance | * | fail | vs one: token (fail): tool_calls: one [], got ['calculate'] | rand:1:8 (fail): tool_calls: one [], got ['calculate'] | rand:2:8 (fail): tool_calls: one [], got ['calculate'] | rand:3:8 (fail): tool_calls: one [], got ['calculate'] | rand:4:8 (fail): tool_calls: one [], got ['calculate'] | rand:5:8 (fail): tool_calls: one [], got ['calculate'] |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/v3.jsonl --id deepseek/v3-numeric-arguments --strategy one --strategy special --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 6 of fixtures/deepseek/v3.jsonl.
Observed vs expected
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: one, special
@@ -2,21 +2,4 @@ "content": null, "reasoning_content": null, - "tool_calls": [ - { - "arguments": { - "code": "007", - "exact": true, - "limit": null, - "tolerance": 1e-05, - "values": [ - 0, - -0.5, - 1e+21 - ], - "x": -3, - "y": 2.5 - }, - "name": "calculate" - } - ] + "tool_calls": [] }
Strategies: nonstream, token, rand:1:8, rand:2:8, rand:3:8, rand:4:8, rand:5:8
Matches the expected parse.
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"code": "007",
"exact": true,
"limit": null,
"tolerance": 1e-05,
"values": [
0,
-0.5,
1e+21
],
"x": -3,
"y": 2.5
},
"name": "calculate"
}
]
}
Fixture
Provenance: template_render, https://huggingface.co/deepseek-ai/DeepSeek-V3-0324/blob/e9b33add76883f293d6bf61f6bd89b497e80e335/tokenizer_config.json.
Tags: single-call, numeric-arguments, x-deepseek-v3.
Raw output
<|tool▁calls▁begin|><|tool▁call▁begin|>function<|tool▁sep|>calculate
```json
{"x": -3, "y": 2.5, "tolerance": 1e-05, "exact": true, "limit": null, "values": [0, -0.5, 1e+21], "code": "007"}
```<|tool▁call▁end|><|tool▁calls▁end|>
Expected parse
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"code": "007",
"exact": true,
"limit": null,
"tolerance": 1e-05,
"values": [
0,
-0.5,
1e+21
],
"x": -3,
"y": 2.5
},
"name": "calculate"
}
]
}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/v3-numeric-arguments", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V3-0324"], "spec_version": "0.1", "provenance": {"kind": "template_render", "source_url": "https://huggingface.co/deepseek-ai/DeepSeek-V3-0324/blob/e9b33add76883f293d6bf61f6bd89b497e80e335/tokenizer_config.json", "revision": "e9b33add76883f293d6bf61f6bd89b497e80e335", "license": "MIT", "generator": "scripts/fixtures/deepseek/build.py", "template_sha256": "22e97ba043dacf9df1f071a9de9d2bb6b0757491f16e96e810834b86e1641286", "attribution": "Copyright (c) 2023 DeepSeek"}, "tools": [{"type": "function", "function": {"name": "calculate", "description": "Evaluate numbers.", "parameters": {"type": "object", "properties": {"x": {"type": "integer"}, "y": {"type": "number"}, "tolerance": {"type": "number"}, "exact": {"type": "boolean"}, "limit": {"type": ["integer", "null"]}, "values": {"type": "array", "items": {"type": "number"}}, "code": {"type": "string"}}, "required": ["x", "y"]}}}], "raw_output": "<|tool▁calls▁begin|><|tool▁call▁begin|>function<|tool▁sep|>calculate\n```json\n{\"x\": -3, \"y\": 2.5, \"tolerance\": 1e-05, \"exact\": true, \"limit\": null, \"values\": [0, -0.5, 1e+21], \"code\": \"007\"}\n```<|tool▁call▁end|><|tool▁calls▁end|>", "output_token_ids": [128806, 128808, 8701, 128814, 93801, 201, 9854, 14479, 201, 24313, 90, 3362, 565, 21, 14, 582, 91, 3362, 223, 20, 16, 23, 14, 582, 86, 44016, 3362, 223, 19, 71, 15, 2642, 14, 582, 1289, 651, 3362, 3292, 14, 582, 39673, 3362, 5100, 14, 582, 15737, 3362, 764, 18, 14, 565, 18, 16, 23, 14, 223, 19, 71, 13, 1602, 3031, 582, 8308, 3362, 582, 17065, 60676, 9854, 128809, 128807], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V3-0324", "revision": "e9b33add76883f293d6bf61f6bd89b497e80e335", "mode": "hf"}, "generation_prompt": "<|Assistant|>", "thinking": false, "expected": {"content": null, "reasoning_content": null, "tool_calls": [{"name": "calculate", "arguments": {"x": -3, "y": 2.5, "tolerance": 1e-05, "exact": true, "limit": null, "values": [0, -0.5, 1e+21], "code": "007"}}]}, "tags": ["single-call", "numeric-arguments", "x-deepseek-v3"], "notes": "'code' is the STRING \"007\"; numbers, booleans and null must keep their JSON types. Sub-format deepseek-v3; history render of the official chat template."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V3-0324",
"model_rule": "DeepSeek-V3",
"model_type": "deepseek_v3",
"parser_source": "docs/formats/deepseek.md (V3: no reasoning)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "<|begin▁of▁sentence|><|User|>Use the tools to answer.<|Assistant|>",
"reasoning_parser": null,
"stop_token_in_final_delta": false,
"template": {
"sha256": "22e97ba043dacf9df1f071a9de9d2bb6b0757491f16e96e810834b86e1641286",
"source": "tokenizer chat template (HF repo)"
},
"tokenizer": {
"mode": "hf",
"repo": "deepseek-ai/DeepSeek-V3-0324",
"requested_mode": "auto",
"resolved_revision": "e9b33add76883f293d6bf61f6bd89b497e80e335",
"revision": "e9b33add76883f293d6bf61f6bd89b497e80e335",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v3",
"units_source": "fixture.output_token_ids"
}
fail deepseek/v3-parallel-two-calls
expected_match, stream_equals_nonstream, split_invariance, arguments_json, arguments_schema, parallel_order
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_match | one | fail | tool_calls: expected ['get_weather', 'search'], got [] |
expected_match | special | fail | tool_calls: expected ['get_weather', 'search'], got [] |
expected_match | token | soft pass | content (whitespace only): expected None, got '\n' |
expected_match | rand:1:8 | fail | tool_calls[1].arguments: expected '{"query": "café \\"best\\"", "filters": {"tags": ["a", "b"], "max": 3}}', got '{"query": "café \\"best\\"", "filters": {"tags": ["a", "b"], "max": 3' |
expected_match | rand:3:8 | fail | tool_calls[0].arguments: expected '{"city": "Zürich", "unit": "c"}', got '{"city": "Zürich", "unit": "c'; tool_calls[1].arguments: expected '{"query": "café \\"best\\"", "filters": {"tags": ["a", "b"], "max": 3}}', got '{"query": "café \\"best\\"", "filters": {"tags": ["a", "b"], "' |
stream_equals_nonstream | one | fail | tool_calls: nonstream ['get_weather', 'search'], got [] |
stream_equals_nonstream | special | fail | tool_calls: nonstream ['get_weather', 'search'], got [] |
stream_equals_nonstream | token | soft pass | content (whitespace only): nonstream None, got '\n' |
stream_equals_nonstream | rand:1:8 | fail | tool_calls[1].arguments: nonstream '{"query": "café \\"best\\"", "filters": {"tags": ["a", "b"], "max": 3}}', got '{"query": "café \\"best\\"", "filters": {"tags": ["a", "b"], "max": 3' |
stream_equals_nonstream | rand:3:8 | fail | tool_calls[0].arguments: nonstream '{"city": "Zürich", "unit": "c"}', got '{"city": "Zürich", "unit": "c'; tool_calls[1].arguments: nonstream '{"query": "café \\"best\\"", "filters": {"tags": ["a", "b"], "max": 3}}', got '{"query": "café \\"best\\"", "filters": {"tags": ["a", "b"], "' |
split_invariance | * | fail | vs one: token (fail): content (whitespace only): one None, got '\n'; tool_calls: one [], got ['get_weather', 'search'] | rand:1:8 (fail): tool_calls: one [], got ['get_weather', 'search'] | rand:2:8 (fail): tool_calls: one [], got ['get_weather', 'search'] | rand:3:8 (fail): tool_calls: one [], got ['get_weather', 'search'] | rand:4:8 (fail): tool_calls: one [], got ['get_weather', 'search'] | rand:5:8 (fail): tool_calls: one [], got ['get_weather', 'search'] |
arguments_json | rand:1:8 | fail | [1] search: arguments are not valid JSON text ('{"query": "café \\"best\\"", "filters": {"tags": ["a", "b"], "max": 3': Expecting ',' delimiter: line 1 column 68 (char 67)) |
arguments_json | rand:3:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "Zürich", "unit": "c': Unterminated string starting at: line 1 column 28 (char 27)); [1] search: arguments are not valid JSON text ('{"query": "café \\"best\\"", "filters": {"tags": ["a", "b"], "': Unterminated string starting at: line 1 column 60 (char 59)) |
arguments_schema | rand:1:8 | fail | [1] search: arguments are not a JSON object; not validated |
arguments_schema | rand:3:8 | fail | [0] get_weather: arguments are not a JSON object; not validated; [1] search: arguments are not a JSON object; not validated |
parallel_order | one | fail | expected 2 calls ['get_weather', 'search'], got 0 [] |
parallel_order | special | fail | expected 2 calls ['get_weather', 'search'], got 0 [] |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/v3.jsonl --id deepseek/v3-parallel-two-calls --strategy one --strategy rand:1:8 --strategy rand:3:8 --strategy special --strategy token --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 2 of fixtures/deepseek/v3.jsonl.
Observed vs expected
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: one, special
@@ -2,25 +2,4 @@ "content": null, "reasoning_content": null, - "tool_calls": [ - { - "arguments": { - "city": "Zürich", - "unit": "c" - }, - "name": "get_weather" - }, - { - "arguments": { - "filters": { - "max": 3, - "tags": [ - "a", - "b" - ] - }, - "query": "café \"best\"" - }, - "name": "search" - } - ] + "tool_calls": [] }
Strategies: rand:1:8
@@ -12,12 +12,5 @@ { "arguments": { - "filters": { - "max": 3, - "tags": [ - "a", - "b" - ] - }, - "query": "café \"best\"" + "<arguments_raw, not valid JSON>": "{\"query\": \"café \\\"best\\\"\", \"filters\": {\"tags\": [\"a\", \"b\"], \"max\": 3" }, "name": "search"
Strategies: rand:3:8
@@ -5,6 +5,5 @@ { "arguments": { - "city": "Zürich", - "unit": "c" + "<arguments_raw, not valid JSON>": "{\"city\": \"Zürich\", \"unit\": \"c" }, "name": "get_weather" @@ -12,12 +11,5 @@ { "arguments": { - "filters": { - "max": 3, - "tags": [ - "a", - "b" - ] - }, - "query": "café \"best\"" + "<arguments_raw, not valid JSON>": "{\"query\": \"café \\\"best\\\"\", \"filters\": {\"tags\": [\"a\", \"b\"], \"" }, "name": "search"
Strategies: nonstream, rand:2:8, rand:4:8, rand:5:8
Matches the expected parse.
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"city": "Zürich",
"unit": "c"
},
"name": "get_weather"
},
{
"arguments": {
"filters": {
"max": 3,
"tags": [
"a",
"b"
]
},
"query": "café \"best\""
},
"name": "search"
}
]
}
Strategies: token
@@ -1,4 +1,4 @@ { - "content": null, + "content": "\n", "reasoning_content": null, "tool_calls": [
Fixture
Provenance: template_render, https://huggingface.co/deepseek-ai/DeepSeek-V3-0324/blob/e9b33add76883f293d6bf61f6bd89b497e80e335/tokenizer_config.json.
Tags: parallel-calls, unicode, nested-json, string-escapes, x-deepseek-v3.
Raw output
<|tool▁calls▁begin|><|tool▁call▁begin|>function<|tool▁sep|>get_weather
```json
{"city": "Zürich", "unit": "c"}
```<|tool▁call▁end|>
<|tool▁call▁begin|>function<|tool▁sep|>search
```json
{"query": "café \"best\"", "filters": {"tags": ["a", "b"], "max": 3}}
```<|tool▁call▁end|><|tool▁calls▁end|>
Expected parse
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"city": "Zürich",
"unit": "c"
},
"name": "get_weather"
},
{
"arguments": {
"filters": {
"max": 3,
"tags": [
"a",
"b"
]
},
"query": "café \"best\""
},
"name": "search"
}
]
}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/v3-parallel-two-calls", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V3-0324"], "spec_version": "0.1", "provenance": {"kind": "template_render", "source_url": "https://huggingface.co/deepseek-ai/DeepSeek-V3-0324/blob/e9b33add76883f293d6bf61f6bd89b497e80e335/tokenizer_config.json", "revision": "e9b33add76883f293d6bf61f6bd89b497e80e335", "license": "MIT", "generator": "scripts/fixtures/deepseek/build.py", "template_sha256": "22e97ba043dacf9df1f071a9de9d2bb6b0757491f16e96e810834b86e1641286", "attribution": "Copyright (c) 2023 DeepSeek"}, "tools": [{"type": "function", "function": {"name": "get_weather", "description": "Get the current weather for a city.", "parameters": {"type": "object", "properties": {"city": {"type": "string"}, "unit": {"type": "string", "enum": ["c", "f"]}}, "required": ["city"]}}}, {"type": "function", "function": {"name": "search", "description": "Search the web.", "parameters": {"type": "object", "properties": {"query": {"type": "string"}, "filters": {"type": "object"}}, "required": ["query"]}}}], "raw_output": "<|tool▁calls▁begin|><|tool▁call▁begin|>function<|tool▁sep|>get_weather\n```json\n{\"city\": \"Zürich\", \"unit\": \"c\"}\n```<|tool▁call▁end|>\n<|tool▁call▁begin|>function<|tool▁sep|>search\n```json\n{\"query\": \"café \\\"best\\\"\", \"filters\": {\"tags\": [\"a\", \"b\"], \"max\": 3}}\n```<|tool▁call▁end|><|tool▁calls▁end|>", "output_token_ids": [128806, 128808, 8701, 128814, 1133, 65, 50219, 201, 9854, 14479, 201, 24313, 37399, 3362, 582, 60, 5421, 616, 1760, 582, 15165, 3362, 582, 69, 60676, 9854, 128809, 201, 128808, 8701, 128814, 14346, 201, 9854, 14479, 201, 24313, 12066, 3362, 582, 69, 2797, 619, 36952, 21910, 28609, 1760, 582, 72, 40332, 3362, 28612, 44175, 3362, 20584, 67, 1760, 582, 68, 45390, 582, 9047, 3362, 223, 21, 30316, 9854, 128809, 128807], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V3-0324", "revision": "e9b33add76883f293d6bf61f6bd89b497e80e335", "mode": "hf"}, "generation_prompt": "<|Assistant|>", "thinking": false, "expected": {"content": null, "reasoning_content": null, "tool_calls": [{"name": "get_weather", "arguments": {"city": "Zürich", "unit": "c"}}, {"name": "search", "arguments": {"query": "café \"best\"", "filters": {"tags": ["a", "b"], "max": 3}}}]}, "tags": ["parallel-calls", "unicode", "nested-json", "string-escapes", "x-deepseek-v3"], "notes": "Sub-format deepseek-v3; history render of the official chat template."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V3-0324",
"model_rule": "DeepSeek-V3",
"model_type": "deepseek_v3",
"parser_source": "docs/formats/deepseek.md (V3: no reasoning)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "<|begin▁of▁sentence|><|User|>Use the tools to answer.<|Assistant|>",
"reasoning_parser": null,
"stop_token_in_final_delta": false,
"template": {
"sha256": "22e97ba043dacf9df1f071a9de9d2bb6b0757491f16e96e810834b86e1641286",
"source": "tokenizer chat template (HF repo)"
},
"tokenizer": {
"mode": "hf",
"repo": "deepseek-ai/DeepSeek-V3-0324",
"requested_mode": "auto",
"resolved_revision": "e9b33add76883f293d6bf61f6bd89b497e80e335",
"revision": "e9b33add76883f293d6bf61f6bd89b497e80e335",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v3",
"units_source": "fixture.output_token_ids"
}
fail deepseek/v3-single-call
expected_match, stream_equals_nonstream, split_invariance
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_match | one | fail | tool_calls: expected ['get_weather'], got [] |
expected_match | special | fail | tool_calls: expected ['get_weather'], got [] |
stream_equals_nonstream | one | fail | tool_calls: nonstream ['get_weather'], got [] |
stream_equals_nonstream | special | fail | tool_calls: nonstream ['get_weather'], got [] |
split_invariance | * | fail | vs one: token (fail): tool_calls: one [], got ['get_weather'] | rand:1:8 (fail): tool_calls: one [], got ['get_weather'] | rand:2:8 (fail): tool_calls: one [], got ['get_weather'] | rand:3:8 (fail): tool_calls: one [], got ['get_weather'] | rand:4:8 (fail): tool_calls: one [], got ['get_weather'] | rand:5:8 (fail): tool_calls: one [], got ['get_weather'] |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/v3.jsonl --id deepseek/v3-single-call --strategy one --strategy special --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 1 of fixtures/deepseek/v3.jsonl.
Observed vs expected
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: one, special
@@ -2,12 +2,4 @@ "content": null, "reasoning_content": null, - "tool_calls": [ - { - "arguments": { - "city": "Paris", - "unit": "c" - }, - "name": "get_weather" - } - ] + "tool_calls": [] }
Strategies: nonstream, token, rand:1:8, rand:2:8, rand:3:8, rand:4:8, rand:5:8
Matches the expected parse.
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"city": "Paris",
"unit": "c"
},
"name": "get_weather"
}
]
}
Fixture
Provenance: template_render, https://huggingface.co/deepseek-ai/DeepSeek-V3-0324/blob/e9b33add76883f293d6bf61f6bd89b497e80e335/tokenizer_config.json.
Tags: single-call, x-deepseek-v3.
Raw output
<|tool▁calls▁begin|><|tool▁call▁begin|>function<|tool▁sep|>get_weather
```json
{"city": "Paris", "unit": "c"}
```<|tool▁call▁end|><|tool▁calls▁end|>
Expected parse
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"city": "Paris",
"unit": "c"
},
"name": "get_weather"
}
]
}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/v3-single-call", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V3-0324"], "spec_version": "0.1", "provenance": {"kind": "template_render", "source_url": "https://huggingface.co/deepseek-ai/DeepSeek-V3-0324/blob/e9b33add76883f293d6bf61f6bd89b497e80e335/tokenizer_config.json", "revision": "e9b33add76883f293d6bf61f6bd89b497e80e335", "license": "MIT", "generator": "scripts/fixtures/deepseek/build.py", "template_sha256": "22e97ba043dacf9df1f071a9de9d2bb6b0757491f16e96e810834b86e1641286", "attribution": "Copyright (c) 2023 DeepSeek"}, "tools": [{"type": "function", "function": {"name": "get_weather", "description": "Get the current weather for a city.", "parameters": {"type": "object", "properties": {"city": {"type": "string"}, "unit": {"type": "string", "enum": ["c", "f"]}}, "required": ["city"]}}}], "raw_output": "<|tool▁calls▁begin|><|tool▁call▁begin|>function<|tool▁sep|>get_weather\n```json\n{\"city\": \"Paris\", \"unit\": \"c\"}\n```<|tool▁call▁end|><|tool▁calls▁end|>", "output_token_ids": [128806, 128808, 8701, 128814, 1133, 65, 50219, 201, 9854, 14479, 201, 24313, 37399, 3362, 582, 51119, 1760, 582, 15165, 3362, 582, 69, 60676, 9854, 128809, 128807], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V3-0324", "revision": "e9b33add76883f293d6bf61f6bd89b497e80e335", "mode": "hf"}, "generation_prompt": "<|Assistant|>", "thinking": false, "expected": {"content": null, "reasoning_content": null, "tool_calls": [{"name": "get_weather", "arguments": {"city": "Paris", "unit": "c"}}]}, "tags": ["single-call", "x-deepseek-v3"], "notes": "Sub-format deepseek-v3; history render of the official chat template."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V3-0324",
"model_rule": "DeepSeek-V3",
"model_type": "deepseek_v3",
"parser_source": "docs/formats/deepseek.md (V3: no reasoning)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "<|begin▁of▁sentence|><|User|>Use the tools to answer.<|Assistant|>",
"reasoning_parser": null,
"stop_token_in_final_delta": false,
"template": {
"sha256": "22e97ba043dacf9df1f071a9de9d2bb6b0757491f16e96e810834b86e1641286",
"source": "tokenizer chat template (HF repo)"
},
"tokenizer": {
"mode": "hf",
"repo": "deepseek-ai/DeepSeek-V3-0324",
"requested_mode": "auto",
"resolved_revision": "e9b33add76883f293d6bf61f6bd89b497e80e335",
"revision": "e9b33add76883f293d6bf61f6bd89b497e80e335",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v3",
"units_source": "fixture.output_token_ids"
}
fail deepseek/v3-text-before-call
expected_match, stream_equals_nonstream, split_invariance, arguments_json, arguments_schema
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_match | one | fail | content: expected 'Let me check the current conditions in London.', got None; tool_calls: expected ['get_weather'], got [] |
expected_match | special | fail | content: expected 'Let me check the current conditions in London.', got None; tool_calls: expected ['get_weather'], got [] |
expected_match | rand:1:8 | fail | tool_calls[0].arguments: expected '{"city": "London"}', got '' |
expected_match | rand:2:8 | fail | content: expected 'Let me check the current conditions in London.', got 'Let me check the current' |
expected_match | rand:3:8 | fail | content: expected 'Let me check the current conditions in London.', got 'Let me check the current conditions in' |
expected_match | rand:5:8 | fail | content: expected 'Let me check the current conditions in London.', got 'Let me check the current' |
stream_equals_nonstream | one | fail | content: nonstream 'Let me check the current conditions in London.', got None; tool_calls: nonstream ['get_weather'], got [] |
stream_equals_nonstream | special | fail | content: nonstream 'Let me check the current conditions in London.', got None; tool_calls: nonstream ['get_weather'], got [] |
stream_equals_nonstream | rand:1:8 | fail | tool_calls[0].arguments: nonstream '{"city": "London"}', got '' |
stream_equals_nonstream | rand:2:8 | fail | content: nonstream 'Let me check the current conditions in London.', got 'Let me check the current' |
stream_equals_nonstream | rand:3:8 | fail | content: nonstream 'Let me check the current conditions in London.', got 'Let me check the current conditions in' |
stream_equals_nonstream | rand:5:8 | fail | content: nonstream 'Let me check the current conditions in London.', got 'Let me check the current' |
split_invariance | * | fail | vs one: token (fail): content: one None, got 'Let me check the current conditions in London.'; tool_calls: one [], got ['get_weather'] | rand:1:8 (fail): content: one None, got 'Let me check the current conditions in London.'; tool_calls: one [], got ['get_weather'] | rand:2:8 (fail): content: one None, got 'Let me check the current'; tool_calls: one [], got ['get_weather'] | rand:3:8 (fail): content: one None, got 'Let me check the current conditions in'; tool_calls: one [], got ['get_weather'] | rand:4:8 (fail): content: one None, got 'Let me check the current conditions in London.'; tool_calls: one [], got ['get_weather'] | rand:5:8 (fail): content: one None, got 'Let me check the current'; tool_calls: one [], got ['get_weather'] |
arguments_json | rand:1:8 | fail | [0] get_weather: arguments are not valid JSON text ('': Expecting value: line 1 column 1 (char 0)) |
arguments_schema | rand:1:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/v3.jsonl --id deepseek/v3-text-before-call --strategy one --strategy rand:1:8 --strategy rand:2:8 --strategy rand:3:8 --strategy rand:5:8 --strategy special --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 4 of fixtures/deepseek/v3.jsonl.
Observed vs expected
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: one, special
@@ -1,12 +1,5 @@ { - "content": "Let me check the current conditions in London.", + "content": null, "reasoning_content": null, - "tool_calls": [ - { - "arguments": { - "city": "London" - }, - "name": "get_weather" - } - ] + "tool_calls": [] }
Strategies: rand:1:8
@@ -5,5 +5,5 @@ { "arguments": { - "city": "London" + "<arguments_raw, not valid JSON>": "" }, "name": "get_weather"
Strategies: rand:2:8, rand:5:8
@@ -1,4 +1,4 @@ { - "content": "Let me check the current conditions in London.", + "content": "Let me check the current", "reasoning_content": null, "tool_calls": [
Strategies: rand:3:8
@@ -1,4 +1,4 @@ { - "content": "Let me check the current conditions in London.", + "content": "Let me check the current conditions in", "reasoning_content": null, "tool_calls": [
Strategies: nonstream, token, rand:4:8
Matches the expected parse.
{
"content": "Let me check the current conditions in London.",
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"city": "London"
},
"name": "get_weather"
}
]
}
Fixture
Provenance: template_render, https://huggingface.co/deepseek-ai/DeepSeek-V3-0324/blob/e9b33add76883f293d6bf61f6bd89b497e80e335/tokenizer_config.json.
Tags: single-call, text-before-call, x-deepseek-v3.
Raw output
Let me check the current conditions in London.<|tool▁calls▁begin|><|tool▁call▁begin|>function<|tool▁sep|>get_weather
```json
{"city": "London"}
```<|tool▁call▁end|><|tool▁calls▁end|>
Expected parse
{
"content": "Let me check the current conditions in London.",
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"city": "London"
},
"name": "get_weather"
}
]
}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/v3-text-before-call", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V3-0324"], "spec_version": "0.1", "provenance": {"kind": "template_render", "source_url": "https://huggingface.co/deepseek-ai/DeepSeek-V3-0324/blob/e9b33add76883f293d6bf61f6bd89b497e80e335/tokenizer_config.json", "revision": "e9b33add76883f293d6bf61f6bd89b497e80e335", "license": "MIT", "generator": "scripts/fixtures/deepseek/build.py", "template_sha256": "22e97ba043dacf9df1f071a9de9d2bb6b0757491f16e96e810834b86e1641286", "attribution": "Copyright (c) 2023 DeepSeek"}, "tools": [{"type": "function", "function": {"name": "get_weather", "description": "Get the current weather for a city.", "parameters": {"type": "object", "properties": {"city": {"type": "string"}, "unit": {"type": "string", "enum": ["c", "f"]}}, "required": ["city"]}}}], "raw_output": "Let me check the current conditions in London.<|tool▁calls▁begin|><|tool▁call▁begin|>function<|tool▁sep|>get_weather\n```json\n{\"city\": \"London\"}\n```<|tool▁call▁end|><|tool▁calls▁end|>", "output_token_ids": [5718, 678, 4085, 270, 2573, 4132, 295, 6693, 16, 128806, 128808, 8701, 128814, 1133, 65, 50219, 201, 9854, 14479, 201, 24313, 37399, 3362, 582, 27571, 60676, 9854, 128809, 128807], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V3-0324", "revision": "e9b33add76883f293d6bf61f6bd89b497e80e335", "mode": "hf"}, "generation_prompt": "<|Assistant|>", "thinking": false, "expected": {"content": "Let me check the current conditions in London.", "reasoning_content": null, "tool_calls": [{"name": "get_weather", "arguments": {"city": "London"}}]}, "tags": ["single-call", "text-before-call", "x-deepseek-v3"], "notes": "Sub-format deepseek-v3; history render of the official chat template."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V3-0324",
"model_rule": "DeepSeek-V3",
"model_type": "deepseek_v3",
"parser_source": "docs/formats/deepseek.md (V3: no reasoning)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "<|begin▁of▁sentence|><|User|>Use the tools to answer.<|Assistant|>",
"reasoning_parser": null,
"stop_token_in_final_delta": false,
"template": {
"sha256": "22e97ba043dacf9df1f071a9de9d2bb6b0757491f16e96e810834b86e1641286",
"source": "tokenizer chat template (HF repo)"
},
"tokenizer": {
"mode": "hf",
"repo": "deepseek-ai/DeepSeek-V3-0324",
"requested_mode": "auto",
"resolved_revision": "e9b33add76883f293d6bf61f6bd89b497e80e335",
"revision": "e9b33add76883f293d6bf61f6bd89b497e80e335",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v3",
"units_source": "fixture.output_token_ids"
}
fail deepseek/v3-truncated-mid-arguments
expected_error, stream_equals_nonstream, split_invariance, arguments_json, arguments_schema
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_error | one | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | special | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | token | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | rand:1:8 | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | rand:2:8 | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | rand:3:8 | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | rand:4:8 | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | rand:5:8 | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
stream_equals_nonstream | one | fail | tool_calls: nonstream [], got ['get_weather'] |
stream_equals_nonstream | special | fail | tool_calls: nonstream [], got ['get_weather'] |
stream_equals_nonstream | token | fail | tool_calls: nonstream [], got ['get_weather'] |
stream_equals_nonstream | rand:1:8 | fail | tool_calls: nonstream [], got ['get_weather'] |
stream_equals_nonstream | rand:2:8 | fail | tool_calls: nonstream [], got ['get_weather'] |
stream_equals_nonstream | rand:3:8 | fail | tool_calls: nonstream [], got ['get_weather'] |
stream_equals_nonstream | rand:4:8 | fail | tool_calls: nonstream [], got ['get_weather'] |
stream_equals_nonstream | rand:5:8 | fail | tool_calls: nonstream [], got ['get_weather'] |
split_invariance | * | fail | vs one: token (fail): tool_calls[0].arguments: one '', got '{"city": "Zür' | rand:1:8 (fail): tool_calls[0].arguments: one '', got '{"city": "Zür' | rand:2:8 (fail): tool_calls[0].arguments: one '', got '{"city": "Zür' | rand:3:8 (fail): tool_calls[0].arguments: one '', got '{"city": "Zür' | rand:4:8 (fail): tool_calls[0].arguments: one '', got '{"city": "Zür' | rand:5:8 (fail): tool_calls[0].arguments: one '', got '{"city": "Zür' |
arguments_json | one | fail | [0] get_weather: arguments are not valid JSON text ('': Expecting value: line 1 column 1 (char 0)) |
arguments_json | special | fail | [0] get_weather: arguments are not valid JSON text ('': Expecting value: line 1 column 1 (char 0)) |
arguments_json | token | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "Zür': Unterminated string starting at: line 1 column 10 (char 9)) |
arguments_json | rand:1:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "Zür': Unterminated string starting at: line 1 column 10 (char 9)) |
arguments_json | rand:2:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "Zür': Unterminated string starting at: line 1 column 10 (char 9)) |
arguments_json | rand:3:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "Zür': Unterminated string starting at: line 1 column 10 (char 9)) |
arguments_json | rand:4:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "Zür': Unterminated string starting at: line 1 column 10 (char 9)) |
arguments_json | rand:5:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "Zür': Unterminated string starting at: line 1 column 10 (char 9)) |
arguments_schema | one | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | special | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | token | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | rand:1:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | rand:2:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | rand:3:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | rand:4:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | rand:5:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/v3.jsonl --id deepseek/v3-truncated-mid-arguments --strategy one --strategy rand:1:8 --strategy rand:2:8 --strategy rand:3:8 --strategy rand:4:8 --strategy rand:5:8 --strategy special --strategy token --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 9 of fixtures/deepseek/v3.jsonl.
Observed
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: one, special
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"<arguments_raw, not valid JSON>": ""
},
"name": "get_weather"
}
]
}
Strategies: token, rand:1:8, rand:2:8, rand:3:8, rand:4:8, rand:5:8
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"<arguments_raw, not valid JSON>": "{\"city\": \"Zür"
},
"name": "get_weather"
}
]
}
Strategies: nonstream
{
"content": null,
"reasoning_content": null,
"tool_calls": []
}
Fixture
Provenance: template_render, https://huggingface.co/deepseek-ai/DeepSeek-V3-0324/blob/e9b33add76883f293d6bf61f6bd89b497e80e335/tokenizer_config.json.
Tags: truncated, x-deepseek-v3.
Expected graceful failure: Output cut by max_tokens inside the first call's arguments: no complete call exists. (accept: no_tool_calls, content_passthrough, exception).
Raw output
<|tool▁calls▁begin|><|tool▁call▁begin|>function<|tool▁sep|>get_weather
```json
{"city": "Zür
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/v3-truncated-mid-arguments", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V3-0324"], "spec_version": "0.1", "provenance": {"kind": "template_render", "source_url": "https://huggingface.co/deepseek-ai/DeepSeek-V3-0324/blob/e9b33add76883f293d6bf61f6bd89b497e80e335/tokenizer_config.json", "revision": "e9b33add76883f293d6bf61f6bd89b497e80e335", "license": "MIT", "generator": "scripts/fixtures/deepseek/build.py", "template_sha256": "22e97ba043dacf9df1f071a9de9d2bb6b0757491f16e96e810834b86e1641286", "attribution": "Copyright (c) 2023 DeepSeek"}, "tools": [{"type": "function", "function": {"name": "get_weather", "description": "Get the current weather for a city.", "parameters": {"type": "object", "properties": {"city": {"type": "string"}, "unit": {"type": "string", "enum": ["c", "f"]}}, "required": ["city"]}}}, {"type": "function", "function": {"name": "search", "description": "Search the web.", "parameters": {"type": "object", "properties": {"query": {"type": "string"}, "filters": {"type": "object"}}, "required": ["query"]}}}], "raw_output": "<|tool▁calls▁begin|><|tool▁call▁begin|>function<|tool▁sep|>get_weather\n```json\n{\"city\": \"Zür", "output_token_ids": [128806, 128808, 8701, 128814, 1133, 65, 50219, 201, 9854, 14479, 201, 24313, 37399, 3362, 582, 60, 5421], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V3-0324", "revision": "e9b33add76883f293d6bf61f6bd89b497e80e335", "mode": "hf"}, "generation_prompt": "<|Assistant|>", "thinking": false, "expected_error": {"reason": "Output cut by max_tokens inside the first call's arguments: no complete call exists.", "accept": ["no_tool_calls", "content_passthrough", "exception"]}, "tags": ["truncated", "x-deepseek-v3"], "notes": "Token prefix of the full render, cut right after 'Zür' appears. Sub-format deepseek-v3; history render of the official chat template."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V3-0324",
"model_rule": "DeepSeek-V3",
"model_type": "deepseek_v3",
"parser_source": "docs/formats/deepseek.md (V3: no reasoning)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "<|begin▁of▁sentence|><|User|>Use the tools to answer.<|Assistant|>",
"reasoning_parser": null,
"stop_token_in_final_delta": false,
"template": {
"sha256": "22e97ba043dacf9df1f071a9de9d2bb6b0757491f16e96e810834b86e1641286",
"source": "tokenizer chat template (HF repo)"
},
"tokenizer": {
"mode": "hf",
"repo": "deepseek-ai/DeepSeek-V3-0324",
"requested_mode": "auto",
"resolved_revision": "e9b33add76883f293d6bf61f6bd89b497e80e335",
"revision": "e9b33add76883f293d6bf61f6bd89b497e80e335",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v3",
"units_source": "fixture.output_token_ids"
}
fail deepseek/v3-unicode-emoji
expected_match, stream_equals_nonstream, split_invariance
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_match | one | fail | tool_calls: expected ['translate'], got [] |
expected_match | special | fail | tool_calls: expected ['translate'], got [] |
stream_equals_nonstream | one | fail | tool_calls: nonstream ['translate'], got [] |
stream_equals_nonstream | special | fail | tool_calls: nonstream ['translate'], got [] |
split_invariance | * | fail | vs one: token (fail): tool_calls: one [], got ['translate'] | rand:1:8 (fail): tool_calls: one [], got ['translate'] | rand:2:8 (fail): tool_calls: one [], got ['translate'] | rand:3:8 (fail): tool_calls: one [], got ['translate'] | rand:4:8 (fail): tool_calls: one [], got ['translate'] | rand:5:8 (fail): tool_calls: one [], got ['translate'] |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/v3.jsonl --id deepseek/v3-unicode-emoji --strategy one --strategy special --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 7 of fixtures/deepseek/v3.jsonl.
Observed vs expected
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: one, special
@@ -2,12 +2,4 @@ "content": null, "reasoning_content": null, - "tool_calls": [ - { - "arguments": { - "target": "de", - "text": "こんにちは 🌸 مرحبا — naïve café 👩💻" - }, - "name": "translate" - } - ] + "tool_calls": [] }
Strategies: nonstream, token, rand:1:8, rand:2:8, rand:3:8, rand:4:8, rand:5:8
Matches the expected parse.
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"target": "de",
"text": "こんにちは 🌸 مرحبا — naïve café 👩💻"
},
"name": "translate"
}
]
}
Fixture
Provenance: template_render, https://huggingface.co/deepseek-ai/DeepSeek-V3-0324/blob/e9b33add76883f293d6bf61f6bd89b497e80e335/tokenizer_config.json.
Tags: single-call, unicode, x-deepseek-v3.
Raw output
<|tool▁calls▁begin|><|tool▁call▁begin|>function<|tool▁sep|>translate
```json
{"text": "こんにちは 🌸 مرحبا — naïve café 👩💻", "target": "de"}
```<|tool▁call▁end|><|tool▁calls▁end|>
Expected parse
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"target": "de",
"text": "こんにちは 🌸 مرحبا — naïve café 👩💻"
},
"name": "translate"
}
]
}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/v3-unicode-emoji", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V3-0324"], "spec_version": "0.1", "provenance": {"kind": "template_render", "source_url": "https://huggingface.co/deepseek-ai/DeepSeek-V3-0324/blob/e9b33add76883f293d6bf61f6bd89b497e80e335/tokenizer_config.json", "revision": "e9b33add76883f293d6bf61f6bd89b497e80e335", "license": "MIT", "generator": "scripts/fixtures/deepseek/build.py", "template_sha256": "22e97ba043dacf9df1f071a9de9d2bb6b0757491f16e96e810834b86e1641286", "attribution": "Copyright (c) 2023 DeepSeek"}, "tools": [{"type": "function", "function": {"name": "translate", "description": "Translate text.", "parameters": {"type": "object", "properties": {"text": {"type": "string"}, "target": {"type": "string"}}, "required": ["text"]}}}], "raw_output": "<|tool▁calls▁begin|><|tool▁call▁begin|>function<|tool▁sep|>translate\n```json\n{\"text\": \"こんにちは 🌸 مرحبا — naïve café 👩💻\", \"target\": \"de\"}\n```<|tool▁call▁end|><|tool▁calls▁end|>", "output_token_ids": [128806, 128808, 8701, 128814, 77296, 201, 9854, 14479, 201, 24313, 2067, 3362, 582, 4549, 7245, 2298, 12457, 2841, 73369, 119, 112125, 53067, 2136, 112752, 57664, 52780, 105, 46088, 23903, 122, 1760, 582, 28292, 3362, 582, 928, 60676, 9854, 128809, 128807], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V3-0324", "revision": "e9b33add76883f293d6bf61f6bd89b497e80e335", "mode": "hf"}, "generation_prompt": "<|Assistant|>", "thinking": false, "expected": {"content": null, "reasoning_content": null, "tool_calls": [{"name": "translate", "arguments": {"text": "こんにちは 🌸 مرحبا — naïve café 👩💻", "target": "de"}}]}, "tags": ["single-call", "unicode", "x-deepseek-v3"], "notes": "Sub-format deepseek-v3; history render of the official chat template."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V3-0324",
"model_rule": "DeepSeek-V3",
"model_type": "deepseek_v3",
"parser_source": "docs/formats/deepseek.md (V3: no reasoning)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "<|begin▁of▁sentence|><|User|>Use the tools to answer.<|Assistant|>",
"reasoning_parser": null,
"stop_token_in_final_delta": false,
"template": {
"sha256": "22e97ba043dacf9df1f071a9de9d2bb6b0757491f16e96e810834b86e1641286",
"source": "tokenizer chat template (HF repo)"
},
"tokenizer": {
"mode": "hf",
"repo": "deepseek-ai/DeepSeek-V3-0324",
"requested_mode": "auto",
"resolved_revision": "e9b33add76883f293d6bf61f6bd89b497e80e335",
"revision": "e9b33add76883f293d6bf61f6bd89b497e80e335",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v3",
"units_source": "fixture.output_token_ids"
}
fail deepseek/v31-empty-arguments
expected_match, stream_equals_nonstream, split_invariance, arguments_json, arguments_schema
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_match | one | fail | tool_calls: expected ['get_time'], got [] |
expected_match | special | fail | tool_calls: expected ['get_time'], got [] |
expected_match | rand:1:8 | fail | tool_calls[0].arguments: expected '{}', got '' |
expected_match | rand:2:8 | fail | tool_calls[0].arguments: expected '{}', got '' |
expected_match | rand:3:8 | fail | tool_calls: expected ['get_time'], got [] |
expected_match | rand:4:8 | fail | tool_calls: expected ['get_time'], got [] |
expected_match | rand:5:8 | fail | tool_calls[0].arguments: expected '{}', got '' |
stream_equals_nonstream | one | fail | tool_calls: nonstream ['get_time'], got [] |
stream_equals_nonstream | special | fail | tool_calls: nonstream ['get_time'], got [] |
stream_equals_nonstream | rand:1:8 | fail | tool_calls[0].arguments: nonstream '{}', got '' |
stream_equals_nonstream | rand:2:8 | fail | tool_calls[0].arguments: nonstream '{}', got '' |
stream_equals_nonstream | rand:3:8 | fail | tool_calls: nonstream ['get_time'], got [] |
stream_equals_nonstream | rand:4:8 | fail | tool_calls: nonstream ['get_time'], got [] |
stream_equals_nonstream | rand:5:8 | fail | tool_calls[0].arguments: nonstream '{}', got '' |
split_invariance | * | fail | vs one: token (fail): tool_calls: one [], got ['get_time'] | rand:1:8 (fail): tool_calls: one [], got ['get_time'] | rand:2:8 (fail): tool_calls: one [], got ['get_time'] | rand:5:8 (fail): tool_calls: one [], got ['get_time'] |
arguments_json | rand:1:8 | fail | [0] get_time: arguments are not valid JSON text ('': Expecting value: line 1 column 1 (char 0)) |
arguments_json | rand:2:8 | fail | [0] get_time: arguments are not valid JSON text ('': Expecting value: line 1 column 1 (char 0)) |
arguments_json | rand:5:8 | fail | [0] get_time: arguments are not valid JSON text ('': Expecting value: line 1 column 1 (char 0)) |
arguments_schema | rand:1:8 | fail | [0] get_time: arguments are not a JSON object; not validated |
arguments_schema | rand:2:8 | fail | [0] get_time: arguments are not a JSON object; not validated |
arguments_schema | rand:5:8 | fail | [0] get_time: arguments are not a JSON object; not validated |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/v31.jsonl --id deepseek/v31-empty-arguments --strategy one --strategy rand:1:8 --strategy rand:2:8 --strategy rand:3:8 --strategy rand:4:8 --strategy rand:5:8 --strategy special --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 5 of fixtures/deepseek/v31.jsonl.
Observed vs expected
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: one, special, rand:3:8, rand:4:8
@@ -2,9 +2,4 @@ "content": null, "reasoning_content": null, - "tool_calls": [ - { - "arguments": {}, - "name": "get_time" - } - ] + "tool_calls": [] }
Strategies: rand:1:8, rand:2:8, rand:5:8
@@ -4,5 +4,7 @@ "tool_calls": [ { - "arguments": {}, + "arguments": { + "<arguments_raw, not valid JSON>": "" + }, "name": "get_time" }
Strategies: nonstream, token
Matches the expected parse.
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {},
"name": "get_time"
}
]
}
Fixture
Provenance: template_render, https://huggingface.co/deepseek-ai/DeepSeek-V3.1/blob/c0781d039fb7a1ba2abc4add0bdc293e92d2b8db/tokenizer_config.json.
Tags: single-call, empty-arguments, x-deepseek-v31.
Raw output
<|tool▁calls▁begin|><|tool▁call▁begin|>get_time<|tool▁sep|>{}<|tool▁call▁end|><|tool▁calls▁end|>
Expected parse
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {},
"name": "get_time"
}
]
}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/v31-empty-arguments", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V3.1", "deepseek-ai/DeepSeek-V3.1-Terminus"], "spec_version": "0.1", "provenance": {"kind": "template_render", "source_url": "https://huggingface.co/deepseek-ai/DeepSeek-V3.1/blob/c0781d039fb7a1ba2abc4add0bdc293e92d2b8db/tokenizer_config.json", "revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db", "license": "MIT", "generator": "scripts/fixtures/deepseek/build.py", "template_sha256": "45690185067ea25c073bff2d3e425a45ee2564d2bbf6cdf7d885e139d460b8e0", "attribution": "Copyright (c) 2023 DeepSeek"}, "tools": [{"type": "function", "function": {"name": "get_time", "description": "Get the current UTC time. Takes no arguments.", "parameters": {"type": "object", "properties": {}}}}], "raw_output": "<|tool▁calls▁begin|><|tool▁call▁begin|>get_time<|tool▁sep|>{}<|tool▁call▁end|><|tool▁calls▁end|>", "output_token_ids": [128806, 128808, 1133, 20035, 128814, 25902, 128809, 128807], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V3.1", "revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db", "mode": "hf"}, "generation_prompt": "<|Assistant|></think>", "thinking": false, "expected": {"content": null, "reasoning_content": null, "tool_calls": [{"name": "get_time", "arguments": {}}]}, "tags": ["single-call", "empty-arguments", "x-deepseek-v31"], "notes": "Sub-format deepseek-v31; history render of the official chat template."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|></think>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V3.1",
"model_rule": "DeepSeek-V3\\.1",
"model_type": "deepseek_v3",
"parser_source": "docs/formats/deepseek.md (vLLM v0.30.0 row)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "<|begin▁of▁sentence|><|User|>Use the tools to answer.<|Assistant|></think>",
"reasoning_parser": "deepseek_v3",
"stop_token_in_final_delta": false,
"template": {
"sha256": "45690185067ea25c073bff2d3e425a45ee2564d2bbf6cdf7d885e139d460b8e0",
"source": "tokenizer chat template (HF repo)"
},
"tokenizer": {
"mode": "hf",
"repo": "deepseek-ai/DeepSeek-V3.1",
"requested_mode": "auto",
"resolved_revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db",
"revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v31",
"units_source": "fixture.output_token_ids"
}
fail deepseek/v31-marker-in-arguments
expected_match, stream_equals_nonstream, split_invariance, no_leakage, arguments_json, arguments_schema
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_match | one | fail | tool_calls: expected ['echo'], got ['f'] |
expected_match | special | fail | tool_calls: expected ['echo'], got ['f'] |
expected_match | token | fail | tool_calls: expected ['echo'], got ['echo', 'f'] |
expected_match | rand:1:8 | fail | tool_calls: expected ['echo'], got ['echo', 'f'] |
expected_match | rand:2:8 | fail | tool_calls: expected ['echo'], got ['echo', 'f'] |
expected_match | rand:3:8 | fail | tool_calls: expected ['echo'], got ['echo', 'f'] |
expected_match | rand:4:8 | fail | tool_calls: expected ['echo'], got ['echo', 'f'] |
expected_match | rand:5:8 | fail | tool_calls: expected ['echo'], got ['echo', 'f'] |
stream_equals_nonstream | one | fail | tool_calls: nonstream ['echo'], got ['f'] |
stream_equals_nonstream | special | fail | tool_calls: nonstream ['echo'], got ['f'] |
stream_equals_nonstream | token | fail | tool_calls: nonstream ['echo'], got ['echo', 'f'] |
stream_equals_nonstream | rand:1:8 | fail | tool_calls: nonstream ['echo'], got ['echo', 'f'] |
stream_equals_nonstream | rand:2:8 | fail | tool_calls: nonstream ['echo'], got ['echo', 'f'] |
stream_equals_nonstream | rand:3:8 | fail | tool_calls: nonstream ['echo'], got ['echo', 'f'] |
stream_equals_nonstream | rand:4:8 | fail | tool_calls: nonstream ['echo'], got ['echo', 'f'] |
stream_equals_nonstream | rand:5:8 | fail | tool_calls: nonstream ['echo'], got ['echo', 'f'] |
split_invariance | * | fail | vs one: token (fail): tool_calls: one ['f'], got ['echo', 'f'] | rand:1:8 (fail): tool_calls: one ['f'], got ['echo', 'f'] | rand:2:8 (fail): tool_calls: one ['f'], got ['echo', 'f'] | rand:3:8 (fail): tool_calls: one ['f'], got ['echo', 'f'] | rand:4:8 (fail): tool_calls: one ['f'], got ['echo', 'f'] | rand:5:8 (fail): tool_calls: one ['f'], got ['echo', 'f'] |
no_leakage | token | fail | tool_calls[1].arguments contains '<|tool▁calls▁end|>'; tool_calls[1].arguments contains '<|tool▁call▁end|>' |
no_leakage | rand:1:8 | fail | tool_calls[1].arguments contains '<|tool▁calls▁end|>'; tool_calls[1].arguments contains '<|tool▁call▁end|>' |
no_leakage | rand:2:8 | fail | tool_calls[1].arguments contains '<|tool▁calls▁end|>'; tool_calls[1].arguments contains '<|tool▁call▁end|>' |
no_leakage | rand:4:8 | fail | tool_calls[1].arguments contains '<|tool▁calls▁end|>'; tool_calls[1].arguments contains '<|tool▁call▁end|>' |
no_leakage | rand:5:8 | fail | tool_calls[1].arguments contains '<|tool▁calls▁end|>'; tool_calls[1].arguments contains '<|tool▁call▁end|>' |
arguments_json | one | fail | [0] f: arguments are not valid JSON text ('': Expecting value: line 1 column 1 (char 0)) |
arguments_json | special | fail | [0] f: arguments are not valid JSON text ('': Expecting value: line 1 column 1 (char 0)) |
arguments_json | token | fail | [0] echo: arguments are not valid JSON text ('{"text": "Tokens like ': Unterminated string starting at: line 1 column 10 (char 9)); [1] f: arguments are not valid JSON text ('{} are markup."}<|tool▁call▁end|><|tool▁calls▁end|>': Extra data: line 1 column 4 (char 3)) |
arguments_json | rand:1:8 | fail | [0] echo: arguments are not valid JSON text ('{"text": "Tokens like': Unterminated string starting at: line 1 column 10 (char 9)); [1] f: arguments are not valid JSON text ('{} are markup."}<|tool▁call▁end|><|tool▁calls▁end|>': Extra data: line 1 column 4 (char 3)) |
arguments_json | rand:2:8 | fail | [0] echo: arguments are not valid JSON text ('{"text": "Tokens like ': Unterminated string starting at: line 1 column 10 (char 9)); [1] f: arguments are not valid JSON text ('{} are markup."}<|tool▁call▁end|><|tool▁calls▁end|>': Extra data: line 1 column 4 (char 3)) |
arguments_json | rand:3:8 | fail | [0] echo: arguments are not valid JSON text ('{"text":': Expecting value: line 1 column 9 (char 8)); [1] f: arguments are not valid JSON text ('': Expecting value: line 1 column 1 (char 0)) |
arguments_json | rand:4:8 | fail | [0] echo: arguments are not valid JSON text ('{"text": "Tokens like ': Unterminated string starting at: line 1 column 10 (char 9)); [1] f: arguments are not valid JSON text ('{} are markup."}<|tool▁call▁end|><|tool▁calls▁end|>': Extra data: line 1 column 4 (char 3)) |
arguments_json | rand:5:8 | fail | [0] echo: arguments are not valid JSON text ('{"text": "Tokens like ': Unterminated string starting at: line 1 column 10 (char 9)); [1] f: arguments are not valid JSON text ('{} are markup."}<|tool▁call▁end|><|tool▁calls▁end|>': Extra data: line 1 column 4 (char 3)) |
arguments_schema | one | fail | [0] 'f' is not an offered tool |
arguments_schema | special | fail | [0] 'f' is not an offered tool |
arguments_schema | token | fail | [0] echo: arguments are not a JSON object; not validated; [1] 'f' is not an offered tool |
arguments_schema | rand:1:8 | fail | [0] echo: arguments are not a JSON object; not validated; [1] 'f' is not an offered tool |
arguments_schema | rand:2:8 | fail | [0] echo: arguments are not a JSON object; not validated; [1] 'f' is not an offered tool |
arguments_schema | rand:3:8 | fail | [0] echo: arguments are not a JSON object; not validated; [1] 'f' is not an offered tool |
arguments_schema | rand:4:8 | fail | [0] echo: arguments are not a JSON object; not validated; [1] 'f' is not an offered tool |
arguments_schema | rand:5:8 | fail | [0] echo: arguments are not a JSON object; not validated; [1] 'f' is not an offered tool |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/v31.jsonl --id deepseek/v31-marker-in-arguments --strategy one --strategy rand:1:8 --strategy rand:2:8 --strategy rand:3:8 --strategy rand:4:8 --strategy rand:5:8 --strategy special --strategy token --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 8 of fixtures/deepseek/v31.jsonl.
Observed vs expected
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: one, special
@@ -5,7 +5,7 @@ { "arguments": { - "text": "Tokens like <|tool▁call▁begin|>f<|tool▁sep|>{} are markup." + "<arguments_raw, not valid JSON>": "" }, - "name": "echo" + "name": "f" } ]
Strategies: token, rand:2:8, rand:4:8, rand:5:8
@@ -5,7 +5,13 @@ { "arguments": { - "text": "Tokens like <|tool▁call▁begin|>f<|tool▁sep|>{} are markup." + "<arguments_raw, not valid JSON>": "{\"text\": \"Tokens like " }, "name": "echo" + }, + { + "arguments": { + "<arguments_raw, not valid JSON>": "{} are markup.\"}<|tool▁call▁end|><|tool▁calls▁end|>" + }, + "name": "f" } ]
Strategies: rand:1:8
@@ -5,7 +5,13 @@ { "arguments": { - "text": "Tokens like <|tool▁call▁begin|>f<|tool▁sep|>{} are markup." + "<arguments_raw, not valid JSON>": "{\"text\": \"Tokens like" }, "name": "echo" + }, + { + "arguments": { + "<arguments_raw, not valid JSON>": "{} are markup.\"}<|tool▁call▁end|><|tool▁calls▁end|>" + }, + "name": "f" } ]
Strategies: rand:3:8
@@ -5,7 +5,13 @@ { "arguments": { - "text": "Tokens like <|tool▁call▁begin|>f<|tool▁sep|>{} are markup." + "<arguments_raw, not valid JSON>": "{\"text\":" }, "name": "echo" + }, + { + "arguments": { + "<arguments_raw, not valid JSON>": "" + }, + "name": "f" } ]
Strategies: nonstream
Matches the expected parse.
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"text": "Tokens like <|tool▁call▁begin|>f<|tool▁sep|>{} are markup."
},
"name": "echo"
}
]
}
Fixture
Provenance: template_render, https://huggingface.co/deepseek-ai/DeepSeek-V3.1/blob/c0781d039fb7a1ba2abc4add0bdc293e92d2b8db/tokenizer_config.json.
Tags: single-call, marker-in-arguments, x-deepseek-v31.
Raw output
<|tool▁calls▁begin|><|tool▁call▁begin|>echo<|tool▁sep|>{"text": "Tokens like <|tool▁call▁begin|>f<|tool▁sep|>{} are markup."}<|tool▁call▁end|><|tool▁calls▁end|>
Expected parse
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"text": "Tokens like <|tool▁call▁begin|>f<|tool▁sep|>{} are markup."
},
"name": "echo"
}
]
}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/v31-marker-in-arguments", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V3.1", "deepseek-ai/DeepSeek-V3.1-Terminus"], "spec_version": "0.1", "provenance": {"kind": "template_render", "source_url": "https://huggingface.co/deepseek-ai/DeepSeek-V3.1/blob/c0781d039fb7a1ba2abc4add0bdc293e92d2b8db/tokenizer_config.json", "revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db", "license": "MIT", "generator": "scripts/fixtures/deepseek/build.py", "template_sha256": "45690185067ea25c073bff2d3e425a45ee2564d2bbf6cdf7d885e139d460b8e0", "attribution": "Copyright (c) 2023 DeepSeek"}, "tools": [{"type": "function", "function": {"name": "echo", "description": "Echo a string back verbatim.", "parameters": {"type": "object", "properties": {"text": {"type": "string"}}, "required": ["text"]}}}], "raw_output": "<|tool▁calls▁begin|><|tool▁call▁begin|>echo<|tool▁sep|>{\"text\": \"Tokens like <|tool▁call▁begin|>f<|tool▁sep|>{} are markup.\"}<|tool▁call▁end|><|tool▁calls▁end|>", "output_token_ids": [128806, 128808, 18843, 128814, 24313, 2067, 3362, 582, 105119, 1277, 223, 128808, 72, 128814, 25902, 477, 92637, 2148, 95, 128809, 128807], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V3.1", "revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db", "mode": "hf"}, "generation_prompt": "<|Assistant|></think>", "thinking": false, "expected": {"content": null, "reasoning_content": null, "tool_calls": [{"name": "echo", "arguments": {"text": "Tokens like <|tool▁call▁begin|>f<|tool▁sep|>{} are markup."}}]}, "tags": ["single-call", "marker-in-arguments", "x-deepseek-v31"], "notes": "The argument contains format-marker text, which the official tokenizer maps to special-token ids. Sub-format deepseek-v31; history render of the official chat template."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|></think>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V3.1",
"model_rule": "DeepSeek-V3\\.1",
"model_type": "deepseek_v3",
"parser_source": "docs/formats/deepseek.md (vLLM v0.30.0 row)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "<|begin▁of▁sentence|><|User|>Use the tools to answer.<|Assistant|></think>",
"reasoning_parser": "deepseek_v3",
"stop_token_in_final_delta": false,
"template": {
"sha256": "45690185067ea25c073bff2d3e425a45ee2564d2bbf6cdf7d885e139d460b8e0",
"source": "tokenizer chat template (HF repo)"
},
"tokenizer": {
"mode": "hf",
"repo": "deepseek-ai/DeepSeek-V3.1",
"requested_mode": "auto",
"resolved_revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db",
"revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v31",
"units_source": "fixture.output_token_ids"
}
fail deepseek/v31-multi-turn-after-tool-result
expected_match, stream_equals_nonstream, split_invariance
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_match | one | fail | tool_calls: expected ['search'], got [] |
expected_match | special | fail | tool_calls: expected ['search'], got [] |
stream_equals_nonstream | one | fail | tool_calls: nonstream ['search'], got [] |
stream_equals_nonstream | special | fail | tool_calls: nonstream ['search'], got [] |
split_invariance | * | fail | vs one: token (fail): tool_calls: one [], got ['search'] | rand:1:8 (fail): tool_calls: one [], got ['search'] | rand:2:8 (fail): tool_calls: one [], got ['search'] | rand:3:8 (fail): tool_calls: one [], got ['search'] | rand:4:8 (fail): tool_calls: one [], got ['search'] | rand:5:8 (fail): tool_calls: one [], got ['search'] |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/v31.jsonl --id deepseek/v31-multi-turn-after-tool-result --strategy one --strategy special --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 10 of fixtures/deepseek/v31.jsonl.
Observed vs expected
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: one, special
@@ -2,11 +2,4 @@ "content": null, "reasoning_content": null, - "tool_calls": [ - { - "arguments": { - "query": "café Zürich" - }, - "name": "search" - } - ] + "tool_calls": [] }
Strategies: nonstream, token, rand:1:8, rand:2:8, rand:3:8, rand:4:8, rand:5:8
Matches the expected parse.
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"query": "café Zürich"
},
"name": "search"
}
]
}
Fixture
Provenance: template_render, https://huggingface.co/deepseek-ai/DeepSeek-V3.1/blob/c0781d039fb7a1ba2abc4add0bdc293e92d2b8db/tokenizer_config.json.
Tags: single-call, multi-turn, unicode, x-deepseek-v31.
Raw output
<|tool▁calls▁begin|><|tool▁call▁begin|>search<|tool▁sep|>{"query": "café Zürich"}<|tool▁call▁end|><|tool▁calls▁end|>
Expected parse
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"query": "café Zürich"
},
"name": "search"
}
]
}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/v31-multi-turn-after-tool-result", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V3.1", "deepseek-ai/DeepSeek-V3.1-Terminus"], "spec_version": "0.1", "provenance": {"kind": "template_render", "source_url": "https://huggingface.co/deepseek-ai/DeepSeek-V3.1/blob/c0781d039fb7a1ba2abc4add0bdc293e92d2b8db/tokenizer_config.json", "revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db", "license": "MIT", "generator": "scripts/fixtures/deepseek/build.py", "template_sha256": "45690185067ea25c073bff2d3e425a45ee2564d2bbf6cdf7d885e139d460b8e0", "attribution": "Copyright (c) 2023 DeepSeek"}, "tools": [{"type": "function", "function": {"name": "get_weather", "description": "Get the current weather for a city.", "parameters": {"type": "object", "properties": {"city": {"type": "string"}, "unit": {"type": "string", "enum": ["c", "f"]}}, "required": ["city"]}}}, {"type": "function", "function": {"name": "search", "description": "Search the web.", "parameters": {"type": "object", "properties": {"query": {"type": "string"}, "filters": {"type": "object"}}, "required": ["query"]}}}], "raw_output": "<|tool▁calls▁begin|><|tool▁call▁begin|>search<|tool▁sep|>{\"query\": \"café Zürich\"}<|tool▁call▁end|><|tool▁calls▁end|>", "output_token_ids": [128806, 128808, 14346, 128814, 24313, 12066, 3362, 582, 69, 2797, 619, 125388, 616, 62773, 128809, 128807], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V3.1", "revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db", "mode": "hf"}, "generation_prompt": "", "thinking": false, "expected": {"content": null, "reasoning_content": null, "tool_calls": [{"name": "search", "arguments": {"query": "café Zürich"}}]}, "tags": ["single-call", "multi-turn", "unicode", "x-deepseek-v31"], "notes": "Sub-format deepseek-v31; history render of the official chat template."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V3.1",
"model_rule": "DeepSeek-V3\\.1",
"model_type": "deepseek_v3",
"parser_source": "docs/formats/deepseek.md (vLLM v0.30.0 row)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "<|begin▁of▁sentence|><|User|>Use the tools to answer.<|Assistant|></think>",
"reasoning_parser": "deepseek_v3",
"stop_token_in_final_delta": false,
"template": {
"sha256": "45690185067ea25c073bff2d3e425a45ee2564d2bbf6cdf7d885e139d460b8e0",
"source": "tokenizer chat template (HF repo)"
},
"tokenizer": {
"mode": "hf",
"repo": "deepseek-ai/DeepSeek-V3.1",
"requested_mode": "auto",
"resolved_revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db",
"revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v31",
"units_source": "fixture.output_token_ids"
}
fail deepseek/v31-nested-json
expected_match, stream_equals_nonstream, split_invariance, arguments_json, arguments_schema
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_match | one | fail | tool_calls: expected ['create_event'], got [] |
expected_match | special | fail | tool_calls: expected ['create_event'], got [] |
expected_match | rand:2:8 | fail | tool_calls[0].arguments: expected '{"title": "Design review", "when": {"start": "2026-10-01T09:00:00Z", "end": "2026-10-01T10:00:00Z"}, "attendees": [{"name": "Ana", "optional": false}, {"nam..., got '{"title": "Design review", "when": {"start": "2026-10-01T09:00:00Z", "end": "2026-10-01T10:00:00Z"}, "attendees": [{"name": "Ana", "optional": false}, {"nam... |
expected_match | rand:4:8 | fail | tool_calls[0].arguments: expected '{"title": "Design review", "when": {"start": "2026-10-01T09:00:00Z", "end": "2026-10-01T10:00:00Z"}, "attendees": [{"name": "Ana", "optional": false}, {"nam..., got '{"title": "Design review", "when": {"start": "2026-10-01T09:00:00Z", "end": "2026-10-01T10:00:00Z"}, "attendees": [{"name": "Ana", "optional": false}, {"nam... |
expected_match | rand:5:8 | fail | tool_calls[0].arguments: expected '{"title": "Design review", "when": {"start": "2026-10-01T09:00:00Z", "end": "2026-10-01T10:00:00Z"}, "attendees": [{"name": "Ana", "optional": false}, {"nam..., got '{"title": "Design review", "when": {"start": "2026-10-01T09:00:00Z", "end": "2026-10-01T10:00:00Z"}, "attendees": [{"name": "Ana", "optional": false}, {"nam... |
stream_equals_nonstream | one | fail | tool_calls: nonstream ['create_event'], got [] |
stream_equals_nonstream | special | fail | tool_calls: nonstream ['create_event'], got [] |
stream_equals_nonstream | rand:2:8 | fail | tool_calls[0].arguments: nonstream '{"title": "Design review", "when": {"start": "2026-10-01T09:00:00Z", "end": "2026-10-01T10:00:00Z"}, "attendees": [{"name": "Ana", "optional": false}, {"nam..., got '{"title": "Design review", "when": {"start": "2026-10-01T09:00:00Z", "end": "2026-10-01T10:00:00Z"}, "attendees": [{"name": "Ana", "optional": false}, {"nam... |
stream_equals_nonstream | rand:4:8 | fail | tool_calls[0].arguments: nonstream '{"title": "Design review", "when": {"start": "2026-10-01T09:00:00Z", "end": "2026-10-01T10:00:00Z"}, "attendees": [{"name": "Ana", "optional": false}, {"nam..., got '{"title": "Design review", "when": {"start": "2026-10-01T09:00:00Z", "end": "2026-10-01T10:00:00Z"}, "attendees": [{"name": "Ana", "optional": false}, {"nam... |
stream_equals_nonstream | rand:5:8 | fail | tool_calls[0].arguments: nonstream '{"title": "Design review", "when": {"start": "2026-10-01T09:00:00Z", "end": "2026-10-01T10:00:00Z"}, "attendees": [{"name": "Ana", "optional": false}, {"nam..., got '{"title": "Design review", "when": {"start": "2026-10-01T09:00:00Z", "end": "2026-10-01T10:00:00Z"}, "attendees": [{"name": "Ana", "optional": false}, {"nam... |
split_invariance | * | fail | vs one: token (fail): tool_calls: one [], got ['create_event'] | rand:1:8 (fail): tool_calls: one [], got ['create_event'] | rand:2:8 (fail): tool_calls: one [], got ['create_event'] | rand:3:8 (fail): tool_calls: one [], got ['create_event'] | rand:4:8 (fail): tool_calls: one [], got ['create_event'] | rand:5:8 (fail): tool_calls: one [], got ['create_event'] |
arguments_json | rand:2:8 | fail | [0] create_event: arguments are not valid JSON text ('{"title": "Design review", "when": {"start": "2026-10-01T09:00:00Z", "end": "2026-10-01T10:00:00Z"}, "attendees": [{"name": "Ana", "optional": false}, {"nam...: Expecting value: line 1 column 193 (char 192)) |
arguments_json | rand:4:8 | fail | [0] create_event: arguments are not valid JSON text ('{"title": "Design review", "when": {"start": "2026-10-01T09:00:00Z", "end": "2026-10-01T10:00:00Z"}, "attendees": [{"name": "Ana", "optional": false}, {"nam...: Unterminated string starting at: line 1 column 195 (char 194)) |
arguments_json | rand:5:8 | fail | [0] create_event: arguments are not valid JSON text ('{"title": "Design review", "when": {"start": "2026-10-01T09:00:00Z", "end": "2026-10-01T10:00:00Z"}, "attendees": [{"name": "Ana", "optional": false}, {"nam...: Expecting value: line 1 column 193 (char 192)) |
arguments_schema | rand:2:8 | fail | [0] create_event: arguments are not a JSON object; not validated |
arguments_schema | rand:4:8 | fail | [0] create_event: arguments are not a JSON object; not validated |
arguments_schema | rand:5:8 | fail | [0] create_event: arguments are not a JSON object; not validated |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/v31.jsonl --id deepseek/v31-nested-json --strategy one --strategy rand:2:8 --strategy rand:4:8 --strategy rand:5:8 --strategy special --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 11 of fixtures/deepseek/v31.jsonl.
Observed vs expected
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: one, special
@@ -2,28 +2,4 @@ "content": null, "reasoning_content": null, - "tool_calls": [ - { - "arguments": { - "attendees": [ - { - "name": "Ana", - "optional": false - }, - { - "name": "Bo", - "optional": true, - "roles": [ - "notes" - ] - } - ], - "title": "Design review", - "when": { - "end": "2026-10-01T10:00:00Z", - "start": "2026-10-01T09:00:00Z" - } - }, - "name": "create_event" - } - ] + "tool_calls": [] }
Strategies: rand:2:8, rand:5:8
@@ -5,22 +5,5 @@ { "arguments": { - "attendees": [ - { - "name": "Ana", - "optional": false - }, - { - "name": "Bo", - "optional": true, - "roles": [ - "notes" - ] - } - ], - "title": "Design review", - "when": { - "end": "2026-10-01T10:00:00Z", - "start": "2026-10-01T09:00:00Z" - } + "<arguments_raw, not valid JSON>": "{\"title\": \"Design review\", \"when\": {\"start\": \"2026-10-01T09:00:00Z\", \"end\": \"2026-10-01T10:00:00Z\"}, \"attendees\": [{\"name\": \"Ana\", \"optional\": false}, {\"name\": \"Bo\", \"optional\": true, \"roles\":" }, "name": "create_event"
Strategies: rand:4:8
@@ -5,22 +5,5 @@ { "arguments": { - "attendees": [ - { - "name": "Ana", - "optional": false - }, - { - "name": "Bo", - "optional": true, - "roles": [ - "notes" - ] - } - ], - "title": "Design review", - "when": { - "end": "2026-10-01T10:00:00Z", - "start": "2026-10-01T09:00:00Z" - } + "<arguments_raw, not valid JSON>": "{\"title\": \"Design review\", \"when\": {\"start\": \"2026-10-01T09:00:00Z\", \"end\": \"2026-10-01T10:00:00Z\"}, \"attendees\": [{\"name\": \"Ana\", \"optional\": false}, {\"name\": \"Bo\", \"optional\": true, \"roles\": [\"" }, "name": "create_event"
Strategies: nonstream, token, rand:1:8, rand:3:8
Matches the expected parse.
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"attendees": [
{
"name": "Ana",
"optional": false
},
{
"name": "Bo",
"optional": true,
"roles": [
"notes"
]
}
],
"title": "Design review",
"when": {
"end": "2026-10-01T10:00:00Z",
"start": "2026-10-01T09:00:00Z"
}
},
"name": "create_event"
}
]
}
Fixture
Provenance: template_render, https://huggingface.co/deepseek-ai/DeepSeek-V3.1/blob/c0781d039fb7a1ba2abc4add0bdc293e92d2b8db/tokenizer_config.json.
Tags: single-call, nested-json, x-deepseek-v31.
Raw output
<|tool▁calls▁begin|><|tool▁call▁begin|>create_event<|tool▁sep|>{"title": "Design review", "when": {"start": "2026-10-01T09:00:00Z", "end": "2026-10-01T10:00:00Z"}, "attendees": [{"name": "Ana", "optional": false}, {"name": "Bo", "optional": true, "roles": ["notes"]}]}<|tool▁call▁end|><|tool▁calls▁end|>
Expected parse
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"attendees": [
{
"name": "Ana",
"optional": false
},
{
"name": "Bo",
"optional": true,
"roles": [
"notes"
]
}
],
"title": "Design review",
"when": {
"end": "2026-10-01T10:00:00Z",
"start": "2026-10-01T09:00:00Z"
}
},
"name": "create_event"
}
]
}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/v31-nested-json", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V3.1", "deepseek-ai/DeepSeek-V3.1-Terminus"], "spec_version": "0.1", "provenance": {"kind": "template_render", "source_url": "https://huggingface.co/deepseek-ai/DeepSeek-V3.1/blob/c0781d039fb7a1ba2abc4add0bdc293e92d2b8db/tokenizer_config.json", "revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db", "license": "MIT", "generator": "scripts/fixtures/deepseek/build.py", "template_sha256": "45690185067ea25c073bff2d3e425a45ee2564d2bbf6cdf7d885e139d460b8e0", "attribution": "Copyright (c) 2023 DeepSeek"}, "tools": [{"type": "function", "function": {"name": "create_event", "description": "Create a calendar event.", "parameters": {"type": "object", "properties": {"title": {"type": "string"}, "when": {"type": "object"}, "attendees": {"type": "array", "items": {"type": "object"}}}, "required": ["title", "when"]}}}], "raw_output": "<|tool▁calls▁begin|><|tool▁call▁begin|>create_event<|tool▁sep|>{\"title\": \"Design review\", \"when\": {\"start\": \"2026-10-01T09:00:00Z\", \"end\": \"2026-10-01T10:00:00Z\"}, \"attendees\": [{\"name\": \"Ana\", \"optional\": false}, {\"name\": \"Bo\", \"optional\": true, \"roles\": [\"notes\"]}]}<|tool▁call▁end|><|tool▁calls▁end|>", "output_token_ids": [128806, 128808, 10028, 76740, 128814, 24313, 10212, 3362, 582, 31151, 3862, 1760, 582, 21123, 3362, 28612, 10513, 3362, 582, 939, 24, 15, 553, 15, 2616, 54, 3130, 28, 504, 28, 504, 60, 1760, 582, 523, 3362, 582, 939, 24, 15, 553, 15, 2616, 54, 553, 28, 504, 28, 504, 60, 87928, 582, 112191, 5993, 3362, 764, 24313, 2852, 3362, 582, 114991, 1760, 582, 41401, 3362, 5062, 6989, 28612, 2852, 3362, 582, 18056, 1760, 582, 41401, 3362, 3292, 14, 582, 81345, 3362, 20584, 33955, 13747, 37236, 95, 128809, 128807], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V3.1", "revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db", "mode": "hf"}, "generation_prompt": "<|Assistant|></think>", "thinking": false, "expected": {"content": null, "reasoning_content": null, "tool_calls": [{"name": "create_event", "arguments": {"title": "Design review", "when": {"start": "2026-10-01T09:00:00Z", "end": "2026-10-01T10:00:00Z"}, "attendees": [{"name": "Ana", "optional": false}, {"name": "Bo", "optional": true, "roles": ["notes"]}]}}]}, "tags": ["single-call", "nested-json", "x-deepseek-v31"], "notes": "Sub-format deepseek-v31; history render of the official chat template."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|></think>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V3.1",
"model_rule": "DeepSeek-V3\\.1",
"model_type": "deepseek_v3",
"parser_source": "docs/formats/deepseek.md (vLLM v0.30.0 row)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "<|begin▁of▁sentence|><|User|>Use the tools to answer.<|Assistant|></think>",
"reasoning_parser": "deepseek_v3",
"stop_token_in_final_delta": false,
"template": {
"sha256": "45690185067ea25c073bff2d3e425a45ee2564d2bbf6cdf7d885e139d460b8e0",
"source": "tokenizer chat template (HF repo)"
},
"tokenizer": {
"mode": "hf",
"repo": "deepseek-ai/DeepSeek-V3.1",
"requested_mode": "auto",
"resolved_revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db",
"revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v31",
"units_source": "fixture.output_token_ids"
}
fail deepseek/v31-numeric-arguments
expected_match, stream_equals_nonstream, split_invariance
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_match | one | fail | tool_calls: expected ['calculate'], got [] |
expected_match | special | fail | tool_calls: expected ['calculate'], got [] |
stream_equals_nonstream | one | fail | tool_calls: nonstream ['calculate'], got [] |
stream_equals_nonstream | special | fail | tool_calls: nonstream ['calculate'], got [] |
split_invariance | * | fail | vs one: token (fail): tool_calls: one [], got ['calculate'] | rand:1:8 (fail): tool_calls: one [], got ['calculate'] | rand:2:8 (fail): tool_calls: one [], got ['calculate'] | rand:3:8 (fail): tool_calls: one [], got ['calculate'] | rand:4:8 (fail): tool_calls: one [], got ['calculate'] | rand:5:8 (fail): tool_calls: one [], got ['calculate'] |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/v31.jsonl --id deepseek/v31-numeric-arguments --strategy one --strategy special --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 6 of fixtures/deepseek/v31.jsonl.
Observed vs expected
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: one, special
@@ -2,21 +2,4 @@ "content": null, "reasoning_content": null, - "tool_calls": [ - { - "arguments": { - "code": "007", - "exact": true, - "limit": null, - "tolerance": 1e-05, - "values": [ - 0, - -0.5, - 1e+21 - ], - "x": -3, - "y": 2.5 - }, - "name": "calculate" - } - ] + "tool_calls": [] }
Strategies: nonstream, token, rand:1:8, rand:2:8, rand:3:8, rand:4:8, rand:5:8
Matches the expected parse.
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"code": "007",
"exact": true,
"limit": null,
"tolerance": 1e-05,
"values": [
0,
-0.5,
1e+21
],
"x": -3,
"y": 2.5
},
"name": "calculate"
}
]
}
Fixture
Provenance: template_render, https://huggingface.co/deepseek-ai/DeepSeek-V3.1/blob/c0781d039fb7a1ba2abc4add0bdc293e92d2b8db/tokenizer_config.json.
Tags: single-call, numeric-arguments, x-deepseek-v31.
Raw output
<|tool▁calls▁begin|><|tool▁call▁begin|>calculate<|tool▁sep|>{"x": -3, "y": 2.5, "tolerance": 1e-05, "exact": true, "limit": null, "values": [0, -0.5, 1e+21], "code": "007"}<|tool▁call▁end|><|tool▁calls▁end|>
Expected parse
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"code": "007",
"exact": true,
"limit": null,
"tolerance": 1e-05,
"values": [
0,
-0.5,
1e+21
],
"x": -3,
"y": 2.5
},
"name": "calculate"
}
]
}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/v31-numeric-arguments", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V3.1", "deepseek-ai/DeepSeek-V3.1-Terminus"], "spec_version": "0.1", "provenance": {"kind": "template_render", "source_url": "https://huggingface.co/deepseek-ai/DeepSeek-V3.1/blob/c0781d039fb7a1ba2abc4add0bdc293e92d2b8db/tokenizer_config.json", "revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db", "license": "MIT", "generator": "scripts/fixtures/deepseek/build.py", "template_sha256": "45690185067ea25c073bff2d3e425a45ee2564d2bbf6cdf7d885e139d460b8e0", "attribution": "Copyright (c) 2023 DeepSeek"}, "tools": [{"type": "function", "function": {"name": "calculate", "description": "Evaluate numbers.", "parameters": {"type": "object", "properties": {"x": {"type": "integer"}, "y": {"type": "number"}, "tolerance": {"type": "number"}, "exact": {"type": "boolean"}, "limit": {"type": ["integer", "null"]}, "values": {"type": "array", "items": {"type": "number"}}, "code": {"type": "string"}}, "required": ["x", "y"]}}}], "raw_output": "<|tool▁calls▁begin|><|tool▁call▁begin|>calculate<|tool▁sep|>{\"x\": -3, \"y\": 2.5, \"tolerance\": 1e-05, \"exact\": true, \"limit\": null, \"values\": [0, -0.5, 1e+21], \"code\": \"007\"}<|tool▁call▁end|><|tool▁calls▁end|>", "output_token_ids": [128806, 128808, 93801, 128814, 24313, 90, 3362, 565, 21, 14, 582, 91, 3362, 223, 20, 16, 23, 14, 582, 86, 44016, 3362, 223, 19, 71, 15, 2642, 14, 582, 1289, 651, 3362, 3292, 14, 582, 39673, 3362, 5100, 14, 582, 15737, 3362, 764, 18, 14, 565, 18, 16, 23, 14, 223, 19, 71, 13, 1602, 3031, 582, 8308, 3362, 582, 17065, 62773, 128809, 128807], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V3.1", "revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db", "mode": "hf"}, "generation_prompt": "<|Assistant|></think>", "thinking": false, "expected": {"content": null, "reasoning_content": null, "tool_calls": [{"name": "calculate", "arguments": {"x": -3, "y": 2.5, "tolerance": 1e-05, "exact": true, "limit": null, "values": [0, -0.5, 1e+21], "code": "007"}}]}, "tags": ["single-call", "numeric-arguments", "x-deepseek-v31"], "notes": "'code' is the STRING \"007\"; numbers, booleans and null must keep their JSON types. Sub-format deepseek-v31; history render of the official chat template."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|></think>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V3.1",
"model_rule": "DeepSeek-V3\\.1",
"model_type": "deepseek_v3",
"parser_source": "docs/formats/deepseek.md (vLLM v0.30.0 row)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "<|begin▁of▁sentence|><|User|>Use the tools to answer.<|Assistant|></think>",
"reasoning_parser": "deepseek_v3",
"stop_token_in_final_delta": false,
"template": {
"sha256": "45690185067ea25c073bff2d3e425a45ee2564d2bbf6cdf7d885e139d460b8e0",
"source": "tokenizer chat template (HF repo)"
},
"tokenizer": {
"mode": "hf",
"repo": "deepseek-ai/DeepSeek-V3.1",
"requested_mode": "auto",
"resolved_revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db",
"revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v31",
"units_source": "fixture.output_token_ids"
}
fail deepseek/v31-parallel-two-calls
expected_match, stream_equals_nonstream, split_invariance, arguments_json, arguments_schema, parallel_order
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_match | one | fail | tool_calls: expected ['get_weather', 'search'], got [] |
expected_match | special | fail | tool_calls: expected ['get_weather', 'search'], got [] |
expected_match | rand:1:8 | fail | tool_calls[1].arguments: expected '{"query": "café \\"best\\"", "filters": {"tags": ["a", "b"], "max": 3}}', got '{"query": "café \\"best\\"", "filters": {"tags": ["a", "b"], "' |
expected_match | rand:2:8 | fail | tool_calls[0].arguments: expected '{"city": "Zürich", "unit": "c"}', got '{"city": "Zürich", "unit": "c'; tool_calls[1].arguments: expected '{"query": "café \\"best\\"", "filters": {"tags": ["a", "b"], "max": 3}}', got '{"query": "café \\"best\\"", "filters": {"tags": ["a", "b"], "max": ' |
expected_match | rand:3:8 | fail | tool_calls[1].arguments: expected '{"query": "café \\"best\\"", "filters": {"tags": ["a", "b"], "max": 3}}', got '{"query": "café \\"best\\"", "filters": {"tags": ["a", "b"], "max": 3' |
expected_match | rand:4:8 | fail | tool_calls[0].arguments: expected '{"city": "Zürich", "unit": "c"}', got '{"city": "Zürich", "unit": "'; tool_calls[1].arguments: expected '{"query": "café \\"best\\"", "filters": {"tags": ["a", "b"], "max": 3}}', got '{"query": "café \\"best\\"", "filters": {"tags": ["a", "b"], "max":' |
expected_match | rand:5:8 | fail | tool_calls[1].arguments: expected '{"query": "café \\"best\\"", "filters": {"tags": ["a", "b"], "max": 3}}', got '{"query": "café \\"best\\"", "filters": {"tags": ["a", "b"],' |
stream_equals_nonstream | one | fail | tool_calls: nonstream ['get_weather', 'search'], got [] |
stream_equals_nonstream | special | fail | tool_calls: nonstream ['get_weather', 'search'], got [] |
stream_equals_nonstream | rand:1:8 | fail | tool_calls[1].arguments: nonstream '{"query": "café \\"best\\"", "filters": {"tags": ["a", "b"], "max": 3}}', got '{"query": "café \\"best\\"", "filters": {"tags": ["a", "b"], "' |
stream_equals_nonstream | rand:2:8 | fail | tool_calls[0].arguments: nonstream '{"city": "Zürich", "unit": "c"}', got '{"city": "Zürich", "unit": "c'; tool_calls[1].arguments: nonstream '{"query": "café \\"best\\"", "filters": {"tags": ["a", "b"], "max": 3}}', got '{"query": "café \\"best\\"", "filters": {"tags": ["a", "b"], "max": ' |
stream_equals_nonstream | rand:3:8 | fail | tool_calls[1].arguments: nonstream '{"query": "café \\"best\\"", "filters": {"tags": ["a", "b"], "max": 3}}', got '{"query": "café \\"best\\"", "filters": {"tags": ["a", "b"], "max": 3' |
stream_equals_nonstream | rand:4:8 | fail | tool_calls[0].arguments: nonstream '{"city": "Zürich", "unit": "c"}', got '{"city": "Zürich", "unit": "'; tool_calls[1].arguments: nonstream '{"query": "café \\"best\\"", "filters": {"tags": ["a", "b"], "max": 3}}', got '{"query": "café \\"best\\"", "filters": {"tags": ["a", "b"], "max":' |
stream_equals_nonstream | rand:5:8 | fail | tool_calls[1].arguments: nonstream '{"query": "café \\"best\\"", "filters": {"tags": ["a", "b"], "max": 3}}', got '{"query": "café \\"best\\"", "filters": {"tags": ["a", "b"],' |
split_invariance | * | fail | vs one: token (fail): tool_calls: one [], got ['get_weather', 'search'] | rand:1:8 (fail): tool_calls: one [], got ['get_weather', 'search'] | rand:2:8 (fail): tool_calls: one [], got ['get_weather', 'search'] | rand:3:8 (fail): tool_calls: one [], got ['get_weather', 'search'] | rand:4:8 (fail): tool_calls: one [], got ['get_weather', 'search'] | rand:5:8 (fail): tool_calls: one [], got ['get_weather', 'search'] |
arguments_json | rand:1:8 | fail | [1] search: arguments are not valid JSON text ('{"query": "café \\"best\\"", "filters": {"tags": ["a", "b"], "': Unterminated string starting at: line 1 column 60 (char 59)) |
arguments_json | rand:2:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "Zürich", "unit": "c': Unterminated string starting at: line 1 column 28 (char 27)); [1] search: arguments are not valid JSON text ('{"query": "café \\"best\\"", "filters": {"tags": ["a", "b"], "max": ': Expecting value: line 1 column 67 (char 66)) |
arguments_json | rand:3:8 | fail | [1] search: arguments are not valid JSON text ('{"query": "café \\"best\\"", "filters": {"tags": ["a", "b"], "max": 3': Expecting ',' delimiter: line 1 column 68 (char 67)) |
arguments_json | rand:4:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "Zürich", "unit": "': Unterminated string starting at: line 1 column 28 (char 27)); [1] search: arguments are not valid JSON text ('{"query": "café \\"best\\"", "filters": {"tags": ["a", "b"], "max":': Expecting value: line 1 column 66 (char 65)) |
arguments_json | rand:5:8 | fail | [1] search: arguments are not valid JSON text ('{"query": "café \\"best\\"", "filters": {"tags": ["a", "b"],': Expecting property name enclosed in double quotes: line 1 column 59 (char 58)) |
arguments_schema | rand:1:8 | fail | [1] search: arguments are not a JSON object; not validated |
arguments_schema | rand:2:8 | fail | [0] get_weather: arguments are not a JSON object; not validated; [1] search: arguments are not a JSON object; not validated |
arguments_schema | rand:3:8 | fail | [1] search: arguments are not a JSON object; not validated |
arguments_schema | rand:4:8 | fail | [0] get_weather: arguments are not a JSON object; not validated; [1] search: arguments are not a JSON object; not validated |
arguments_schema | rand:5:8 | fail | [1] search: arguments are not a JSON object; not validated |
parallel_order | one | fail | expected 2 calls ['get_weather', 'search'], got 0 [] |
parallel_order | special | fail | expected 2 calls ['get_weather', 'search'], got 0 [] |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/v31.jsonl --id deepseek/v31-parallel-two-calls --strategy one --strategy rand:1:8 --strategy rand:2:8 --strategy rand:3:8 --strategy rand:4:8 --strategy rand:5:8 --strategy special --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 2 of fixtures/deepseek/v31.jsonl.
Observed vs expected
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: one, special
@@ -2,25 +2,4 @@ "content": null, "reasoning_content": null, - "tool_calls": [ - { - "arguments": { - "city": "Zürich", - "unit": "c" - }, - "name": "get_weather" - }, - { - "arguments": { - "filters": { - "max": 3, - "tags": [ - "a", - "b" - ] - }, - "query": "café \"best\"" - }, - "name": "search" - } - ] + "tool_calls": [] }
Strategies: rand:1:8
@@ -12,12 +12,5 @@ { "arguments": { - "filters": { - "max": 3, - "tags": [ - "a", - "b" - ] - }, - "query": "café \"best\"" + "<arguments_raw, not valid JSON>": "{\"query\": \"café \\\"best\\\"\", \"filters\": {\"tags\": [\"a\", \"b\"], \"" }, "name": "search"
Strategies: rand:2:8
@@ -5,6 +5,5 @@ { "arguments": { - "city": "Zürich", - "unit": "c" + "<arguments_raw, not valid JSON>": "{\"city\": \"Zürich\", \"unit\": \"c" }, "name": "get_weather" @@ -12,12 +11,5 @@ { "arguments": { - "filters": { - "max": 3, - "tags": [ - "a", - "b" - ] - }, - "query": "café \"best\"" + "<arguments_raw, not valid JSON>": "{\"query\": \"café \\\"best\\\"\", \"filters\": {\"tags\": [\"a\", \"b\"], \"max\": " }, "name": "search"
Strategies: rand:3:8
@@ -12,12 +12,5 @@ { "arguments": { - "filters": { - "max": 3, - "tags": [ - "a", - "b" - ] - }, - "query": "café \"best\"" + "<arguments_raw, not valid JSON>": "{\"query\": \"café \\\"best\\\"\", \"filters\": {\"tags\": [\"a\", \"b\"], \"max\": 3" }, "name": "search"
Strategies: rand:4:8
@@ -5,6 +5,5 @@ { "arguments": { - "city": "Zürich", - "unit": "c" + "<arguments_raw, not valid JSON>": "{\"city\": \"Zürich\", \"unit\": \"" }, "name": "get_weather" @@ -12,12 +11,5 @@ { "arguments": { - "filters": { - "max": 3, - "tags": [ - "a", - "b" - ] - }, - "query": "café \"best\"" + "<arguments_raw, not valid JSON>": "{\"query\": \"café \\\"best\\\"\", \"filters\": {\"tags\": [\"a\", \"b\"], \"max\":" }, "name": "search"
Strategies: rand:5:8
@@ -12,12 +12,5 @@ { "arguments": { - "filters": { - "max": 3, - "tags": [ - "a", - "b" - ] - }, - "query": "café \"best\"" + "<arguments_raw, not valid JSON>": "{\"query\": \"café \\\"best\\\"\", \"filters\": {\"tags\": [\"a\", \"b\"]," }, "name": "search"
Strategies: nonstream, token
Matches the expected parse.
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"city": "Zürich",
"unit": "c"
},
"name": "get_weather"
},
{
"arguments": {
"filters": {
"max": 3,
"tags": [
"a",
"b"
]
},
"query": "café \"best\""
},
"name": "search"
}
]
}
Fixture
Provenance: template_render, https://huggingface.co/deepseek-ai/DeepSeek-V3.1/blob/c0781d039fb7a1ba2abc4add0bdc293e92d2b8db/tokenizer_config.json.
Tags: parallel-calls, unicode, nested-json, string-escapes, x-deepseek-v31.
Raw output
<|tool▁calls▁begin|><|tool▁call▁begin|>get_weather<|tool▁sep|>{"city": "Zürich", "unit": "c"}<|tool▁call▁end|><|tool▁call▁begin|>search<|tool▁sep|>{"query": "café \"best\"", "filters": {"tags": ["a", "b"], "max": 3}}<|tool▁call▁end|><|tool▁calls▁end|>
Expected parse
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"city": "Zürich",
"unit": "c"
},
"name": "get_weather"
},
{
"arguments": {
"filters": {
"max": 3,
"tags": [
"a",
"b"
]
},
"query": "café \"best\""
},
"name": "search"
}
]
}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/v31-parallel-two-calls", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V3.1", "deepseek-ai/DeepSeek-V3.1-Terminus"], "spec_version": "0.1", "provenance": {"kind": "template_render", "source_url": "https://huggingface.co/deepseek-ai/DeepSeek-V3.1/blob/c0781d039fb7a1ba2abc4add0bdc293e92d2b8db/tokenizer_config.json", "revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db", "license": "MIT", "generator": "scripts/fixtures/deepseek/build.py", "template_sha256": "45690185067ea25c073bff2d3e425a45ee2564d2bbf6cdf7d885e139d460b8e0", "attribution": "Copyright (c) 2023 DeepSeek"}, "tools": [{"type": "function", "function": {"name": "get_weather", "description": "Get the current weather for a city.", "parameters": {"type": "object", "properties": {"city": {"type": "string"}, "unit": {"type": "string", "enum": ["c", "f"]}}, "required": ["city"]}}}, {"type": "function", "function": {"name": "search", "description": "Search the web.", "parameters": {"type": "object", "properties": {"query": {"type": "string"}, "filters": {"type": "object"}}, "required": ["query"]}}}], "raw_output": "<|tool▁calls▁begin|><|tool▁call▁begin|>get_weather<|tool▁sep|>{\"city\": \"Zürich\", \"unit\": \"c\"}<|tool▁call▁end|><|tool▁call▁begin|>search<|tool▁sep|>{\"query\": \"café \\\"best\\\"\", \"filters\": {\"tags\": [\"a\", \"b\"], \"max\": 3}}<|tool▁call▁end|><|tool▁calls▁end|>", "output_token_ids": [128806, 128808, 1133, 65, 50219, 128814, 24313, 37399, 3362, 582, 60, 5421, 616, 1760, 582, 15165, 3362, 582, 69, 62773, 128809, 128808, 14346, 128814, 24313, 12066, 3362, 582, 69, 2797, 619, 36952, 21910, 28609, 1760, 582, 72, 40332, 3362, 28612, 44175, 3362, 20584, 67, 1760, 582, 68, 45390, 582, 9047, 3362, 223, 21, 3831, 128809, 128807], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V3.1", "revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db", "mode": "hf"}, "generation_prompt": "<|Assistant|></think>", "thinking": false, "expected": {"content": null, "reasoning_content": null, "tool_calls": [{"name": "get_weather", "arguments": {"city": "Zürich", "unit": "c"}}, {"name": "search", "arguments": {"query": "café \"best\"", "filters": {"tags": ["a", "b"], "max": 3}}}]}, "tags": ["parallel-calls", "unicode", "nested-json", "string-escapes", "x-deepseek-v31"], "notes": "Sub-format deepseek-v31; history render of the official chat template."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|></think>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V3.1",
"model_rule": "DeepSeek-V3\\.1",
"model_type": "deepseek_v3",
"parser_source": "docs/formats/deepseek.md (vLLM v0.30.0 row)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "<|begin▁of▁sentence|><|User|>Use the tools to answer.<|Assistant|></think>",
"reasoning_parser": "deepseek_v3",
"stop_token_in_final_delta": false,
"template": {
"sha256": "45690185067ea25c073bff2d3e425a45ee2564d2bbf6cdf7d885e139d460b8e0",
"source": "tokenizer chat template (HF repo)"
},
"tokenizer": {
"mode": "hf",
"repo": "deepseek-ai/DeepSeek-V3.1",
"requested_mode": "auto",
"resolved_revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db",
"revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v31",
"units_source": "fixture.output_token_ids"
}
fail deepseek/v31-single-call
expected_match, stream_equals_nonstream, split_invariance
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_match | one | fail | tool_calls: expected ['get_weather'], got [] |
expected_match | special | fail | tool_calls: expected ['get_weather'], got [] |
stream_equals_nonstream | one | fail | tool_calls: nonstream ['get_weather'], got [] |
stream_equals_nonstream | special | fail | tool_calls: nonstream ['get_weather'], got [] |
split_invariance | * | fail | vs one: token (fail): tool_calls: one [], got ['get_weather'] | rand:1:8 (fail): tool_calls: one [], got ['get_weather'] | rand:2:8 (fail): tool_calls: one [], got ['get_weather'] | rand:3:8 (fail): tool_calls: one [], got ['get_weather'] | rand:4:8 (fail): tool_calls: one [], got ['get_weather'] | rand:5:8 (fail): tool_calls: one [], got ['get_weather'] |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/v31.jsonl --id deepseek/v31-single-call --strategy one --strategy special --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 1 of fixtures/deepseek/v31.jsonl.
Observed vs expected
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: one, special
@@ -2,12 +2,4 @@ "content": null, "reasoning_content": null, - "tool_calls": [ - { - "arguments": { - "city": "Paris", - "unit": "c" - }, - "name": "get_weather" - } - ] + "tool_calls": [] }
Strategies: nonstream, token, rand:1:8, rand:2:8, rand:3:8, rand:4:8, rand:5:8
Matches the expected parse.
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"city": "Paris",
"unit": "c"
},
"name": "get_weather"
}
]
}
Fixture
Provenance: template_render, https://huggingface.co/deepseek-ai/DeepSeek-V3.1/blob/c0781d039fb7a1ba2abc4add0bdc293e92d2b8db/tokenizer_config.json.
Tags: single-call, x-deepseek-v31.
Raw output
<|tool▁calls▁begin|><|tool▁call▁begin|>get_weather<|tool▁sep|>{"city": "Paris", "unit": "c"}<|tool▁call▁end|><|tool▁calls▁end|>
Expected parse
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"city": "Paris",
"unit": "c"
},
"name": "get_weather"
}
]
}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/v31-single-call", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V3.1", "deepseek-ai/DeepSeek-V3.1-Terminus"], "spec_version": "0.1", "provenance": {"kind": "template_render", "source_url": "https://huggingface.co/deepseek-ai/DeepSeek-V3.1/blob/c0781d039fb7a1ba2abc4add0bdc293e92d2b8db/tokenizer_config.json", "revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db", "license": "MIT", "generator": "scripts/fixtures/deepseek/build.py", "template_sha256": "45690185067ea25c073bff2d3e425a45ee2564d2bbf6cdf7d885e139d460b8e0", "attribution": "Copyright (c) 2023 DeepSeek"}, "tools": [{"type": "function", "function": {"name": "get_weather", "description": "Get the current weather for a city.", "parameters": {"type": "object", "properties": {"city": {"type": "string"}, "unit": {"type": "string", "enum": ["c", "f"]}}, "required": ["city"]}}}], "raw_output": "<|tool▁calls▁begin|><|tool▁call▁begin|>get_weather<|tool▁sep|>{\"city\": \"Paris\", \"unit\": \"c\"}<|tool▁call▁end|><|tool▁calls▁end|>", "output_token_ids": [128806, 128808, 1133, 65, 50219, 128814, 24313, 37399, 3362, 582, 51119, 1760, 582, 15165, 3362, 582, 69, 62773, 128809, 128807], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V3.1", "revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db", "mode": "hf"}, "generation_prompt": "<|Assistant|></think>", "thinking": false, "expected": {"content": null, "reasoning_content": null, "tool_calls": [{"name": "get_weather", "arguments": {"city": "Paris", "unit": "c"}}]}, "tags": ["single-call", "x-deepseek-v31"], "notes": "Sub-format deepseek-v31; history render of the official chat template."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|></think>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V3.1",
"model_rule": "DeepSeek-V3\\.1",
"model_type": "deepseek_v3",
"parser_source": "docs/formats/deepseek.md (vLLM v0.30.0 row)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "<|begin▁of▁sentence|><|User|>Use the tools to answer.<|Assistant|></think>",
"reasoning_parser": "deepseek_v3",
"stop_token_in_final_delta": false,
"template": {
"sha256": "45690185067ea25c073bff2d3e425a45ee2564d2bbf6cdf7d885e139d460b8e0",
"source": "tokenizer chat template (HF repo)"
},
"tokenizer": {
"mode": "hf",
"repo": "deepseek-ai/DeepSeek-V3.1",
"requested_mode": "auto",
"resolved_revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db",
"revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v31",
"units_source": "fixture.output_token_ids"
}
fail deepseek/v31-text-before-call
expected_match, stream_equals_nonstream, split_invariance, arguments_json, arguments_schema
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_match | one | fail | content: expected 'Let me check the current conditions in London.', got None; tool_calls: expected ['get_weather'], got [] |
expected_match | special | fail | content: expected 'Let me check the current conditions in London.', got None; tool_calls: expected ['get_weather'], got [] |
expected_match | rand:1:8 | fail | tool_calls[0].arguments: expected '{"city": "London"}', got '' |
expected_match | rand:2:8 | fail | content: expected 'Let me check the current conditions in London.', got 'Let me check the current'; tool_calls[0].arguments: expected '{"city": "London"}', got '' |
expected_match | rand:3:8 | fail | content: expected 'Let me check the current conditions in London.', got 'Let me check the current conditions in'; tool_calls[0].arguments: expected '{"city": "London"}', got '' |
expected_match | rand:4:8 | fail | tool_calls[0].arguments: expected '{"city": "London"}', got '' |
expected_match | rand:5:8 | fail | content: expected 'Let me check the current conditions in London.', got 'Let me check the current'; tool_calls[0].arguments: expected '{"city": "London"}', got '' |
stream_equals_nonstream | one | fail | content: nonstream 'Let me check the current conditions in London.', got None; tool_calls: nonstream ['get_weather'], got [] |
stream_equals_nonstream | special | fail | content: nonstream 'Let me check the current conditions in London.', got None; tool_calls: nonstream ['get_weather'], got [] |
stream_equals_nonstream | rand:1:8 | fail | tool_calls[0].arguments: nonstream '{"city": "London"}', got '' |
stream_equals_nonstream | rand:2:8 | fail | content: nonstream 'Let me check the current conditions in London.', got 'Let me check the current'; tool_calls[0].arguments: nonstream '{"city": "London"}', got '' |
stream_equals_nonstream | rand:3:8 | fail | content: nonstream 'Let me check the current conditions in London.', got 'Let me check the current conditions in'; tool_calls[0].arguments: nonstream '{"city": "London"}', got '' |
stream_equals_nonstream | rand:4:8 | fail | tool_calls[0].arguments: nonstream '{"city": "London"}', got '' |
stream_equals_nonstream | rand:5:8 | fail | content: nonstream 'Let me check the current conditions in London.', got 'Let me check the current'; tool_calls[0].arguments: nonstream '{"city": "London"}', got '' |
split_invariance | * | fail | vs one: token (fail): content: one None, got 'Let me check the current conditions in London.'; tool_calls: one [], got ['get_weather'] | rand:1:8 (fail): content: one None, got 'Let me check the current conditions in London.'; tool_calls: one [], got ['get_weather'] | rand:2:8 (fail): content: one None, got 'Let me check the current'; tool_calls: one [], got ['get_weather'] | rand:3:8 (fail): content: one None, got 'Let me check the current conditions in'; tool_calls: one [], got ['get_weather'] | rand:4:8 (fail): content: one None, got 'Let me check the current conditions in London.'; tool_calls: one [], got ['get_weather'] | rand:5:8 (fail): content: one None, got 'Let me check the current'; tool_calls: one [], got ['get_weather'] |
arguments_json | rand:1:8 | fail | [0] get_weather: arguments are not valid JSON text ('': Expecting value: line 1 column 1 (char 0)) |
arguments_json | rand:2:8 | fail | [0] get_weather: arguments are not valid JSON text ('': Expecting value: line 1 column 1 (char 0)) |
arguments_json | rand:3:8 | fail | [0] get_weather: arguments are not valid JSON text ('': Expecting value: line 1 column 1 (char 0)) |
arguments_json | rand:4:8 | fail | [0] get_weather: arguments are not valid JSON text ('': Expecting value: line 1 column 1 (char 0)) |
arguments_json | rand:5:8 | fail | [0] get_weather: arguments are not valid JSON text ('': Expecting value: line 1 column 1 (char 0)) |
arguments_schema | rand:1:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | rand:2:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | rand:3:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | rand:4:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | rand:5:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/v31.jsonl --id deepseek/v31-text-before-call --strategy one --strategy rand:1:8 --strategy rand:2:8 --strategy rand:3:8 --strategy rand:4:8 --strategy rand:5:8 --strategy special --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 4 of fixtures/deepseek/v31.jsonl.
Observed vs expected
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: one, special
@@ -1,12 +1,5 @@ { - "content": "Let me check the current conditions in London.", + "content": null, "reasoning_content": null, - "tool_calls": [ - { - "arguments": { - "city": "London" - }, - "name": "get_weather" - } - ] + "tool_calls": [] }
Strategies: rand:1:8, rand:4:8
@@ -5,5 +5,5 @@ { "arguments": { - "city": "London" + "<arguments_raw, not valid JSON>": "" }, "name": "get_weather"
Strategies: rand:2:8, rand:5:8
@@ -1,9 +1,9 @@ { - "content": "Let me check the current conditions in London.", + "content": "Let me check the current", "reasoning_content": null, "tool_calls": [ { "arguments": { - "city": "London" + "<arguments_raw, not valid JSON>": "" }, "name": "get_weather"
Strategies: rand:3:8
@@ -1,9 +1,9 @@ { - "content": "Let me check the current conditions in London.", + "content": "Let me check the current conditions in", "reasoning_content": null, "tool_calls": [ { "arguments": { - "city": "London" + "<arguments_raw, not valid JSON>": "" }, "name": "get_weather"
Strategies: nonstream, token
Matches the expected parse.
{
"content": "Let me check the current conditions in London.",
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"city": "London"
},
"name": "get_weather"
}
]
}
Fixture
Provenance: template_render, https://huggingface.co/deepseek-ai/DeepSeek-V3.1/blob/c0781d039fb7a1ba2abc4add0bdc293e92d2b8db/tokenizer_config.json.
Tags: single-call, text-before-call, x-deepseek-v31.
Raw output
Let me check the current conditions in London.<|tool▁calls▁begin|><|tool▁call▁begin|>get_weather<|tool▁sep|>{"city": "London"}<|tool▁call▁end|><|tool▁calls▁end|>
Expected parse
{
"content": "Let me check the current conditions in London.",
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"city": "London"
},
"name": "get_weather"
}
]
}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/v31-text-before-call", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V3.1", "deepseek-ai/DeepSeek-V3.1-Terminus"], "spec_version": "0.1", "provenance": {"kind": "template_render", "source_url": "https://huggingface.co/deepseek-ai/DeepSeek-V3.1/blob/c0781d039fb7a1ba2abc4add0bdc293e92d2b8db/tokenizer_config.json", "revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db", "license": "MIT", "generator": "scripts/fixtures/deepseek/build.py", "template_sha256": "45690185067ea25c073bff2d3e425a45ee2564d2bbf6cdf7d885e139d460b8e0", "attribution": "Copyright (c) 2023 DeepSeek"}, "tools": [{"type": "function", "function": {"name": "get_weather", "description": "Get the current weather for a city.", "parameters": {"type": "object", "properties": {"city": {"type": "string"}, "unit": {"type": "string", "enum": ["c", "f"]}}, "required": ["city"]}}}], "raw_output": "Let me check the current conditions in London.<|tool▁calls▁begin|><|tool▁call▁begin|>get_weather<|tool▁sep|>{\"city\": \"London\"}<|tool▁call▁end|><|tool▁calls▁end|>", "output_token_ids": [5718, 678, 4085, 270, 2573, 4132, 295, 6693, 16, 128806, 128808, 1133, 65, 50219, 128814, 24313, 37399, 3362, 582, 27571, 62773, 128809, 128807], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V3.1", "revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db", "mode": "hf"}, "generation_prompt": "<|Assistant|></think>", "thinking": false, "expected": {"content": "Let me check the current conditions in London.", "reasoning_content": null, "tool_calls": [{"name": "get_weather", "arguments": {"city": "London"}}]}, "tags": ["single-call", "text-before-call", "x-deepseek-v31"], "notes": "Sub-format deepseek-v31; history render of the official chat template."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|></think>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V3.1",
"model_rule": "DeepSeek-V3\\.1",
"model_type": "deepseek_v3",
"parser_source": "docs/formats/deepseek.md (vLLM v0.30.0 row)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "<|begin▁of▁sentence|><|User|>Use the tools to answer.<|Assistant|></think>",
"reasoning_parser": "deepseek_v3",
"stop_token_in_final_delta": false,
"template": {
"sha256": "45690185067ea25c073bff2d3e425a45ee2564d2bbf6cdf7d885e139d460b8e0",
"source": "tokenizer chat template (HF repo)"
},
"tokenizer": {
"mode": "hf",
"repo": "deepseek-ai/DeepSeek-V3.1",
"requested_mode": "auto",
"resolved_revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db",
"revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v31",
"units_source": "fixture.output_token_ids"
}
fail deepseek/v31-truncated-mid-arguments
expected_error, stream_equals_nonstream, split_invariance, arguments_json, arguments_schema
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_error | one | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | special | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | token | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | rand:1:8 | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | rand:2:8 | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | rand:3:8 | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | rand:4:8 | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | rand:5:8 | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
stream_equals_nonstream | one | fail | tool_calls: nonstream [], got ['get_weather'] |
stream_equals_nonstream | special | fail | tool_calls: nonstream [], got ['get_weather'] |
stream_equals_nonstream | token | fail | tool_calls: nonstream [], got ['get_weather'] |
stream_equals_nonstream | rand:1:8 | fail | tool_calls: nonstream [], got ['get_weather'] |
stream_equals_nonstream | rand:2:8 | fail | tool_calls: nonstream [], got ['get_weather'] |
stream_equals_nonstream | rand:3:8 | fail | tool_calls: nonstream [], got ['get_weather'] |
stream_equals_nonstream | rand:4:8 | fail | tool_calls: nonstream [], got ['get_weather'] |
stream_equals_nonstream | rand:5:8 | fail | tool_calls: nonstream [], got ['get_weather'] |
split_invariance | * | fail | vs one: token (fail): tool_calls[0].arguments: one '', got '{"city": "Zür' | rand:1:8 (fail): tool_calls[0].arguments: one '', got '{"city": "Zür' | rand:2:8 (fail): tool_calls[0].arguments: one '', got '{"city": "Zür' | rand:3:8 (fail): tool_calls[0].arguments: one '', got '{"city": "Zür' | rand:4:8 (fail): tool_calls[0].arguments: one '', got '{"city": "Zür' | rand:5:8 (fail): tool_calls[0].arguments: one '', got '{"city": "Zür' |
arguments_json | one | fail | [0] get_weather: arguments are not valid JSON text ('': Expecting value: line 1 column 1 (char 0)) |
arguments_json | special | fail | [0] get_weather: arguments are not valid JSON text ('': Expecting value: line 1 column 1 (char 0)) |
arguments_json | token | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "Zür': Unterminated string starting at: line 1 column 10 (char 9)) |
arguments_json | rand:1:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "Zür': Unterminated string starting at: line 1 column 10 (char 9)) |
arguments_json | rand:2:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "Zür': Unterminated string starting at: line 1 column 10 (char 9)) |
arguments_json | rand:3:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "Zür': Unterminated string starting at: line 1 column 10 (char 9)) |
arguments_json | rand:4:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "Zür': Unterminated string starting at: line 1 column 10 (char 9)) |
arguments_json | rand:5:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "Zür': Unterminated string starting at: line 1 column 10 (char 9)) |
arguments_schema | one | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | special | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | token | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | rand:1:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | rand:2:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | rand:3:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | rand:4:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | rand:5:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/v31.jsonl --id deepseek/v31-truncated-mid-arguments --strategy one --strategy rand:1:8 --strategy rand:2:8 --strategy rand:3:8 --strategy rand:4:8 --strategy rand:5:8 --strategy special --strategy token --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 9 of fixtures/deepseek/v31.jsonl.
Observed
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: one, special
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"<arguments_raw, not valid JSON>": ""
},
"name": "get_weather"
}
]
}
Strategies: token, rand:1:8, rand:2:8, rand:3:8, rand:4:8, rand:5:8
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"<arguments_raw, not valid JSON>": "{\"city\": \"Zür"
},
"name": "get_weather"
}
]
}
Strategies: nonstream
{
"content": null,
"reasoning_content": null,
"tool_calls": []
}
Fixture
Provenance: template_render, https://huggingface.co/deepseek-ai/DeepSeek-V3.1/blob/c0781d039fb7a1ba2abc4add0bdc293e92d2b8db/tokenizer_config.json.
Tags: truncated, x-deepseek-v31.
Expected graceful failure: Output cut by max_tokens inside the first call's arguments: no complete call exists. (accept: no_tool_calls, content_passthrough, exception).
Raw output
<|tool▁calls▁begin|><|tool▁call▁begin|>get_weather<|tool▁sep|>{"city": "Zür
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/v31-truncated-mid-arguments", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V3.1", "deepseek-ai/DeepSeek-V3.1-Terminus"], "spec_version": "0.1", "provenance": {"kind": "template_render", "source_url": "https://huggingface.co/deepseek-ai/DeepSeek-V3.1/blob/c0781d039fb7a1ba2abc4add0bdc293e92d2b8db/tokenizer_config.json", "revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db", "license": "MIT", "generator": "scripts/fixtures/deepseek/build.py", "template_sha256": "45690185067ea25c073bff2d3e425a45ee2564d2bbf6cdf7d885e139d460b8e0", "attribution": "Copyright (c) 2023 DeepSeek"}, "tools": [{"type": "function", "function": {"name": "get_weather", "description": "Get the current weather for a city.", "parameters": {"type": "object", "properties": {"city": {"type": "string"}, "unit": {"type": "string", "enum": ["c", "f"]}}, "required": ["city"]}}}, {"type": "function", "function": {"name": "search", "description": "Search the web.", "parameters": {"type": "object", "properties": {"query": {"type": "string"}, "filters": {"type": "object"}}, "required": ["query"]}}}], "raw_output": "<|tool▁calls▁begin|><|tool▁call▁begin|>get_weather<|tool▁sep|>{\"city\": \"Zür", "output_token_ids": [128806, 128808, 1133, 65, 50219, 128814, 24313, 37399, 3362, 582, 60, 5421], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V3.1", "revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db", "mode": "hf"}, "generation_prompt": "<|Assistant|></think>", "thinking": false, "expected_error": {"reason": "Output cut by max_tokens inside the first call's arguments: no complete call exists.", "accept": ["no_tool_calls", "content_passthrough", "exception"]}, "tags": ["truncated", "x-deepseek-v31"], "notes": "Token prefix of the full render, cut right after 'Zür' appears. Sub-format deepseek-v31; history render of the official chat template."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|></think>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V3.1",
"model_rule": "DeepSeek-V3\\.1",
"model_type": "deepseek_v3",
"parser_source": "docs/formats/deepseek.md (vLLM v0.30.0 row)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "<|begin▁of▁sentence|><|User|>Use the tools to answer.<|Assistant|></think>",
"reasoning_parser": "deepseek_v3",
"stop_token_in_final_delta": false,
"template": {
"sha256": "45690185067ea25c073bff2d3e425a45ee2564d2bbf6cdf7d885e139d460b8e0",
"source": "tokenizer chat template (HF repo)"
},
"tokenizer": {
"mode": "hf",
"repo": "deepseek-ai/DeepSeek-V3.1",
"requested_mode": "auto",
"resolved_revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db",
"revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v31",
"units_source": "fixture.output_token_ids"
}
fail deepseek/v31-unicode-emoji
expected_match, stream_equals_nonstream, split_invariance
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_match | one | fail | tool_calls: expected ['translate'], got [] |
expected_match | special | fail | tool_calls: expected ['translate'], got [] |
stream_equals_nonstream | one | fail | tool_calls: nonstream ['translate'], got [] |
stream_equals_nonstream | special | fail | tool_calls: nonstream ['translate'], got [] |
split_invariance | * | fail | vs one: token (fail): tool_calls: one [], got ['translate'] | rand:1:8 (fail): tool_calls: one [], got ['translate'] | rand:2:8 (fail): tool_calls: one [], got ['translate'] | rand:3:8 (fail): tool_calls: one [], got ['translate'] | rand:4:8 (fail): tool_calls: one [], got ['translate'] | rand:5:8 (fail): tool_calls: one [], got ['translate'] |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/v31.jsonl --id deepseek/v31-unicode-emoji --strategy one --strategy special --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 7 of fixtures/deepseek/v31.jsonl.
Observed vs expected
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: one, special
@@ -2,12 +2,4 @@ "content": null, "reasoning_content": null, - "tool_calls": [ - { - "arguments": { - "target": "de", - "text": "こんにちは 🌸 مرحبا — naïve café 👩💻" - }, - "name": "translate" - } - ] + "tool_calls": [] }
Strategies: nonstream, token, rand:1:8, rand:2:8, rand:3:8, rand:4:8, rand:5:8
Matches the expected parse.
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"target": "de",
"text": "こんにちは 🌸 مرحبا — naïve café 👩💻"
},
"name": "translate"
}
]
}
Fixture
Provenance: template_render, https://huggingface.co/deepseek-ai/DeepSeek-V3.1/blob/c0781d039fb7a1ba2abc4add0bdc293e92d2b8db/tokenizer_config.json.
Tags: single-call, unicode, x-deepseek-v31.
Raw output
<|tool▁calls▁begin|><|tool▁call▁begin|>translate<|tool▁sep|>{"text": "こんにちは 🌸 مرحبا — naïve café 👩💻", "target": "de"}<|tool▁call▁end|><|tool▁calls▁end|>
Expected parse
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"target": "de",
"text": "こんにちは 🌸 مرحبا — naïve café 👩💻"
},
"name": "translate"
}
]
}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/v31-unicode-emoji", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V3.1", "deepseek-ai/DeepSeek-V3.1-Terminus"], "spec_version": "0.1", "provenance": {"kind": "template_render", "source_url": "https://huggingface.co/deepseek-ai/DeepSeek-V3.1/blob/c0781d039fb7a1ba2abc4add0bdc293e92d2b8db/tokenizer_config.json", "revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db", "license": "MIT", "generator": "scripts/fixtures/deepseek/build.py", "template_sha256": "45690185067ea25c073bff2d3e425a45ee2564d2bbf6cdf7d885e139d460b8e0", "attribution": "Copyright (c) 2023 DeepSeek"}, "tools": [{"type": "function", "function": {"name": "translate", "description": "Translate text.", "parameters": {"type": "object", "properties": {"text": {"type": "string"}, "target": {"type": "string"}}, "required": ["text"]}}}], "raw_output": "<|tool▁calls▁begin|><|tool▁call▁begin|>translate<|tool▁sep|>{\"text\": \"こんにちは 🌸 مرحبا — naïve café 👩💻\", \"target\": \"de\"}<|tool▁call▁end|><|tool▁calls▁end|>", "output_token_ids": [128806, 128808, 77296, 128814, 24313, 2067, 3362, 582, 4549, 7245, 2298, 12457, 2841, 73369, 119, 112125, 53067, 2136, 112752, 57664, 52780, 105, 46088, 23903, 122, 1760, 582, 28292, 3362, 582, 928, 62773, 128809, 128807], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V3.1", "revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db", "mode": "hf"}, "generation_prompt": "<|Assistant|></think>", "thinking": false, "expected": {"content": null, "reasoning_content": null, "tool_calls": [{"name": "translate", "arguments": {"text": "こんにちは 🌸 مرحبا — naïve café 👩💻", "target": "de"}}]}, "tags": ["single-call", "unicode", "x-deepseek-v31"], "notes": "Sub-format deepseek-v31; history render of the official chat template."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|></think>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V3.1",
"model_rule": "DeepSeek-V3\\.1",
"model_type": "deepseek_v3",
"parser_source": "docs/formats/deepseek.md (vLLM v0.30.0 row)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "<|begin▁of▁sentence|><|User|>Use the tools to answer.<|Assistant|></think>",
"reasoning_parser": "deepseek_v3",
"stop_token_in_final_delta": false,
"template": {
"sha256": "45690185067ea25c073bff2d3e425a45ee2564d2bbf6cdf7d885e139d460b8e0",
"source": "tokenizer chat template (HF repo)"
},
"tokenizer": {
"mode": "hf",
"repo": "deepseek-ai/DeepSeek-V3.1",
"requested_mode": "auto",
"resolved_revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db",
"revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v31",
"units_source": "fixture.output_token_ids"
}
fail deepseek/v32-truncated-mid-arguments
expected_error, stream_equals_nonstream, arguments_json, arguments_schema
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_error | nonstream | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | one | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | special | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | token | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | rand:1:8 | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | rand:2:8 | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | rand:3:8 | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | rand:4:8 | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | rand:5:8 | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
stream_equals_nonstream | one | fail | tool_calls[0].arguments: nonstream '{}', got '{"city": "' |
stream_equals_nonstream | special | fail | tool_calls[0].arguments: nonstream '{}', got '{"city": "' |
stream_equals_nonstream | token | fail | tool_calls[0].arguments: nonstream '{}', got '{"city": "' |
stream_equals_nonstream | rand:1:8 | fail | tool_calls[0].arguments: nonstream '{}', got '{"city": "' |
stream_equals_nonstream | rand:2:8 | fail | tool_calls[0].arguments: nonstream '{}', got '{"city": "' |
stream_equals_nonstream | rand:3:8 | fail | tool_calls[0].arguments: nonstream '{}', got '{"city": "' |
stream_equals_nonstream | rand:4:8 | fail | tool_calls[0].arguments: nonstream '{}', got '{"city": "' |
stream_equals_nonstream | rand:5:8 | fail | tool_calls[0].arguments: nonstream '{}', got '{"city": "' |
arguments_json | one | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "': Unterminated string starting at: line 1 column 10 (char 9)) |
arguments_json | special | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "': Unterminated string starting at: line 1 column 10 (char 9)) |
arguments_json | token | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "': Unterminated string starting at: line 1 column 10 (char 9)) |
arguments_json | rand:1:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "': Unterminated string starting at: line 1 column 10 (char 9)) |
arguments_json | rand:2:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "': Unterminated string starting at: line 1 column 10 (char 9)) |
arguments_json | rand:3:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "': Unterminated string starting at: line 1 column 10 (char 9)) |
arguments_json | rand:4:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "': Unterminated string starting at: line 1 column 10 (char 9)) |
arguments_json | rand:5:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "': Unterminated string starting at: line 1 column 10 (char 9)) |
arguments_schema | nonstream | fail | [0] get_weather: $: 'city' is a required property |
arguments_schema | one | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | special | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | token | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | rand:1:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | rand:2:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | rand:3:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | rand:4:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | rand:5:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/v32.jsonl --id deepseek/v32-truncated-mid-arguments --strategy one --strategy rand:1:8 --strategy rand:2:8 --strategy rand:3:8 --strategy rand:4:8 --strategy rand:5:8 --strategy special --strategy token --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 9 of fixtures/deepseek/v32.jsonl.
Observed
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: nonstream
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {},
"name": "get_weather"
}
]
}
Strategies: one, special, token, rand:1:8, rand:2:8, rand:3:8, rand:4:8, rand:5:8
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"<arguments_raw, not valid JSON>": "{\"city\": \""
},
"name": "get_weather"
}
]
}
Fixture
Provenance: template_render, https://huggingface.co/deepseek-ai/DeepSeek-V3.2/blob/a7e62ac04ecb2c0a54d736dc46601c5606cf10a6/encoding/encoding_dsv32.py.
Tags: truncated, x-deepseek-v32.
Expected graceful failure: Output cut by max_tokens inside the first call's arguments: no complete call exists. (accept: no_tool_calls, content_passthrough, exception).
Raw output
<|DSML|function_calls> <|DSML|invoke name="get_weather"> <|DSML|parameter name="city" string="true">Zür
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/v32-truncated-mid-arguments", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V3.2"], "spec_version": "0.1", "provenance": {"kind": "template_render", "source_url": "https://huggingface.co/deepseek-ai/DeepSeek-V3.2/blob/a7e62ac04ecb2c0a54d736dc46601c5606cf10a6/encoding/encoding_dsv32.py", "revision": "a7e62ac04ecb2c0a54d736dc46601c5606cf10a6", "license": "MIT", "generator": "scripts/fixtures/deepseek/build.py", "template_sha256": "5e068c2ba2a6e5ebe37a49bb005650c507e7935d77a32f3f7c11ee071498b370", "attribution": "Copyright (c) 2023 DeepSeek"}, "tools": [{"type": "function", "function": {"name": "get_weather", "description": "Get the current weather for a city.", "parameters": {"type": "object", "properties": {"city": {"type": "string"}, "unit": {"type": "string", "enum": ["c", "f"]}}, "required": ["city"]}}}, {"type": "function", "function": {"name": "search", "description": "Search the web.", "parameters": {"type": "object", "properties": {"query": {"type": "string"}, "filters": {"type": "object"}}, "required": ["query"]}}}], "raw_output": "\n\n<|DSML|function_calls>\n<|DSML|invoke name=\"get_weather\">\n<|DSML|parameter name=\"city\" string=\"true\">Zür", "output_token_ids": [271, 30, 128793, 8701, 4941, 12548, 1018, 30, 128793, 40148, 5406, 2329, 1281, 1133, 65, 50219, 3816, 30, 128793, 41523, 2329, 1281, 37399, 4, 3418, 1281, 11476, 3320, 60, 5421], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V3.2", "revision": "a7e62ac04ecb2c0a54d736dc46601c5606cf10a6", "mode": "hf"}, "generation_prompt": "<|Assistant|></think>", "thinking": false, "expected_error": {"reason": "Output cut by max_tokens inside the first call's arguments: no complete call exists.", "accept": ["no_tool_calls", "content_passthrough", "exception"]}, "tags": ["truncated", "x-deepseek-v32"], "notes": "Token prefix of the full render, cut right after 'Zür' appears. Sub-format deepseek-v32; history render of the official encoder."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|></think>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V3.2",
"model_rule": "DeepSeek-V3\\.2",
"model_type": "deepseek_v32",
"parser_source": "docs/formats/deepseek.md (vLLM v0.30.0 row)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "\": [\"text\"]}}\n</functions>\n<|User|>Use the tools to answer.<|Assistant|></think>",
"reasoning_parser": "deepseek_v3",
"stop_token_in_final_delta": false,
"template": {
"sha256": "1bade67606d54952ae652a4f71f44065041ef0842ad1b5420ed82f8159502bc8",
"source": "vLLM tokenizer_mode=deepseek_v32 encoder (vllm.tokenizers.deepseek_v32_encoding)"
},
"tokenizer": {
"mode": "deepseek_v32",
"repo": "deepseek-ai/DeepSeek-V3.2",
"requested_mode": "auto",
"resolved_revision": "a7e62ac04ecb2c0a54d736dc46601c5606cf10a6",
"revision": "a7e62ac04ecb2c0a54d736dc46601c5606cf10a6",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v32",
"units_source": "fixture.output_token_ids"
}
fail deepseek/v32-truncated-second-parallel-call
expected_match, arguments_schema
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_match | nonstream | fail | tool_calls: expected ['get_weather'], got ['get_weather', 'search'] |
expected_match | one | fail | tool_calls: expected ['get_weather'], got ['get_weather', 'search'] |
expected_match | special | fail | tool_calls: expected ['get_weather'], got ['get_weather', 'search'] |
expected_match | token | fail | tool_calls: expected ['get_weather'], got ['get_weather', 'search'] |
expected_match | rand:1:8 | fail | tool_calls: expected ['get_weather'], got ['get_weather', 'search'] |
expected_match | rand:2:8 | fail | tool_calls: expected ['get_weather'], got ['get_weather', 'search'] |
expected_match | rand:3:8 | fail | tool_calls: expected ['get_weather'], got ['get_weather', 'search'] |
expected_match | rand:4:8 | fail | tool_calls: expected ['get_weather'], got ['get_weather', 'search'] |
expected_match | rand:5:8 | fail | tool_calls: expected ['get_weather'], got ['get_weather', 'search'] |
arguments_schema | nonstream | fail | [1] search: $: 'query' is a required property |
arguments_schema | one | fail | [1] search: $: 'query' is a required property |
arguments_schema | special | fail | [1] search: $: 'query' is a required property |
arguments_schema | token | fail | [1] search: $: 'query' is a required property |
arguments_schema | rand:1:8 | fail | [1] search: $: 'query' is a required property |
arguments_schema | rand:2:8 | fail | [1] search: $: 'query' is a required property |
arguments_schema | rand:3:8 | fail | [1] search: $: 'query' is a required property |
arguments_schema | rand:4:8 | fail | [1] search: $: 'query' is a required property |
arguments_schema | rand:5:8 | fail | [1] search: $: 'query' is a required property |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/v32.jsonl --id deepseek/v32-truncated-second-parallel-call --strategy one --strategy rand:1:8 --strategy rand:2:8 --strategy rand:3:8 --strategy rand:4:8 --strategy rand:5:8 --strategy special --strategy token --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 16 of fixtures/deepseek/v32.jsonl.
Observed vs expected
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: nonstream, one, special, token, rand:1:8, rand:2:8, rand:3:8, rand:4:8, rand:5:8
@@ -9,4 +9,8 @@ }, "name": "get_weather" + }, + { + "arguments": {}, + "name": "search" } ]
Fixture
Provenance: template_render, https://huggingface.co/deepseek-ai/DeepSeek-V3.2/blob/a7e62ac04ecb2c0a54d736dc46601c5606cf10a6/encoding/encoding_dsv32.py.
Tags: truncated, parallel-calls, unicode, x-deepseek-v32.
Raw output
<|DSML|function_calls> <|DSML|invoke name="get_weather"> <|DSML|parameter name="city" string="true">Zürich</|DSML|parameter> <|DSML|parameter name="unit" string="true">c</|DSML|parameter> </|DSML|invoke> <|DSML|invoke name="search"> <|DSML|parameter name="query"
Expected parse
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"city": "Zürich",
"unit": "c"
},
"name": "get_weather"
}
]
}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/v32-truncated-second-parallel-call", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V3.2"], "spec_version": "0.1", "provenance": {"kind": "template_render", "source_url": "https://huggingface.co/deepseek-ai/DeepSeek-V3.2/blob/a7e62ac04ecb2c0a54d736dc46601c5606cf10a6/encoding/encoding_dsv32.py", "revision": "a7e62ac04ecb2c0a54d736dc46601c5606cf10a6", "license": "MIT", "generator": "scripts/fixtures/deepseek/build.py", "template_sha256": "5e068c2ba2a6e5ebe37a49bb005650c507e7935d77a32f3f7c11ee071498b370", "attribution": "Copyright (c) 2023 DeepSeek"}, "tools": [{"type": "function", "function": {"name": "get_weather", "description": "Get the current weather for a city.", "parameters": {"type": "object", "properties": {"city": {"type": "string"}, "unit": {"type": "string", "enum": ["c", "f"]}}, "required": ["city"]}}}, {"type": "function", "function": {"name": "search", "description": "Search the web.", "parameters": {"type": "object", "properties": {"query": {"type": "string"}, "filters": {"type": "object"}}, "required": ["query"]}}}], "raw_output": "\n\n<|DSML|function_calls>\n<|DSML|invoke name=\"get_weather\">\n<|DSML|parameter name=\"city\" string=\"true\">Zürich</|DSML|parameter>\n<|DSML|parameter name=\"unit\" string=\"true\">c</|DSML|parameter>\n</|DSML|invoke>\n<|DSML|invoke name=\"search\">\n<|DSML|parameter name=\"query\"", "output_token_ids": [271, 30, 128793, 8701, 4941, 12548, 1018, 30, 128793, 40148, 5406, 2329, 1281, 1133, 65, 50219, 3816, 30, 128793, 41523, 2329, 1281, 37399, 4, 3418, 1281, 11476, 3320, 60, 5421, 616, 1718, 128793, 41523, 1018, 30, 128793, 41523, 2329, 1281, 15165, 4, 3418, 1281, 11476, 3320, 69, 1718, 128793, 41523, 1018, 1718, 128793, 40148, 5406, 1018, 30, 128793, 40148, 5406, 2329, 1281, 14346, 3816, 30, 128793, 41523, 2329, 1281, 12066, 4], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V3.2", "revision": "a7e62ac04ecb2c0a54d736dc46601c5606cf10a6", "mode": "hf"}, "generation_prompt": "<|Assistant|></think>", "thinking": false, "expected": {"content": null, "reasoning_content": null, "tool_calls": [{"name": "get_weather", "arguments": {"city": "Zürich", "unit": "c"}}]}, "tags": ["truncated", "parallel-calls", "unicode", "x-deepseek-v32"], "notes": "The first invoke is complete, the second is cut: a correct parser keeps only the first call. Token prefix of the full render, cut right after 'name=\"query\"' appears. Sub-format deepseek-v32; history render of the official encoder."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|></think>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V3.2",
"model_rule": "DeepSeek-V3\\.2",
"model_type": "deepseek_v32",
"parser_source": "docs/formats/deepseek.md (vLLM v0.30.0 row)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": " \"content\"]}}\n</functions>\n<|User|>Use the tools to answer.<|Assistant|></think>",
"reasoning_parser": "deepseek_v3",
"stop_token_in_final_delta": false,
"template": {
"sha256": "1bade67606d54952ae652a4f71f44065041ef0842ad1b5420ed82f8159502bc8",
"source": "vLLM tokenizer_mode=deepseek_v32 encoder (vllm.tokenizers.deepseek_v32_encoding)"
},
"tokenizer": {
"mode": "deepseek_v32",
"repo": "deepseek-ai/DeepSeek-V3.2",
"requested_mode": "auto",
"resolved_revision": "a7e62ac04ecb2c0a54d736dc46601c5606cf10a6",
"revision": "a7e62ac04ecb2c0a54d736dc46601c5606cf10a6",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v32",
"units_source": "fixture.output_token_ids"
}
fail deepseek/v4-truncated-mid-arguments
expected_error, stream_equals_nonstream, arguments_json, arguments_schema
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_error | nonstream | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | one | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | special | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | token | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | rand:1:8 | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | rand:2:8 | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | rand:3:8 | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | rand:4:8 | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | rand:5:8 | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
stream_equals_nonstream | one | fail | tool_calls[0].arguments: nonstream '{}', got '{"city": "' |
stream_equals_nonstream | special | fail | tool_calls[0].arguments: nonstream '{}', got '{"city": "' |
stream_equals_nonstream | token | fail | tool_calls[0].arguments: nonstream '{}', got '{"city": "' |
stream_equals_nonstream | rand:1:8 | fail | tool_calls[0].arguments: nonstream '{}', got '{"city": "' |
stream_equals_nonstream | rand:2:8 | fail | tool_calls[0].arguments: nonstream '{}', got '{"city": "' |
stream_equals_nonstream | rand:3:8 | fail | tool_calls[0].arguments: nonstream '{}', got '{"city": "' |
stream_equals_nonstream | rand:4:8 | fail | tool_calls[0].arguments: nonstream '{}', got '{"city": "' |
stream_equals_nonstream | rand:5:8 | fail | tool_calls[0].arguments: nonstream '{}', got '{"city": "' |
arguments_json | one | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "': Unterminated string starting at: line 1 column 10 (char 9)) |
arguments_json | special | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "': Unterminated string starting at: line 1 column 10 (char 9)) |
arguments_json | token | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "': Unterminated string starting at: line 1 column 10 (char 9)) |
arguments_json | rand:1:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "': Unterminated string starting at: line 1 column 10 (char 9)) |
arguments_json | rand:2:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "': Unterminated string starting at: line 1 column 10 (char 9)) |
arguments_json | rand:3:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "': Unterminated string starting at: line 1 column 10 (char 9)) |
arguments_json | rand:4:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "': Unterminated string starting at: line 1 column 10 (char 9)) |
arguments_json | rand:5:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "': Unterminated string starting at: line 1 column 10 (char 9)) |
arguments_schema | nonstream | fail | [0] get_weather: $: 'city' is a required property |
arguments_schema | one | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | special | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | token | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | rand:1:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | rand:2:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | rand:3:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | rand:4:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | rand:5:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/v4.jsonl --id deepseek/v4-truncated-mid-arguments --strategy one --strategy rand:1:8 --strategy rand:2:8 --strategy rand:3:8 --strategy rand:4:8 --strategy rand:5:8 --strategy special --strategy token --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 9 of fixtures/deepseek/v4.jsonl.
Observed
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: nonstream
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {},
"name": "get_weather"
}
]
}
Strategies: one, special, token, rand:1:8, rand:2:8, rand:3:8, rand:4:8, rand:5:8
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"<arguments_raw, not valid JSON>": "{\"city\": \""
},
"name": "get_weather"
}
]
}
Fixture
Provenance: template_render, https://huggingface.co/deepseek-ai/DeepSeek-V4-Flash/blob/60d8d70770c6776ff598c94bb586a859a38244f1/encoding/encoding_dsv4.py.
Tags: truncated, x-deepseek-v4.
Expected graceful failure: Output cut by max_tokens inside the first call's arguments: no complete call exists. (accept: no_tool_calls, content_passthrough, exception).
Raw output
<|DSML|tool_calls> <|DSML|invoke name="get_weather"> <|DSML|parameter name="city" string="true">Zür
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/v4-truncated-mid-arguments", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V4-Flash", "deepseek-ai/DeepSeek-V4-Pro"], "spec_version": "0.1", "provenance": {"kind": "template_render", "source_url": "https://huggingface.co/deepseek-ai/DeepSeek-V4-Flash/blob/60d8d70770c6776ff598c94bb586a859a38244f1/encoding/encoding_dsv4.py", "revision": "60d8d70770c6776ff598c94bb586a859a38244f1", "license": "MIT", "generator": "scripts/fixtures/deepseek/build.py", "template_sha256": "bdbd57c132a1b3725042323d02b98b9d1df28e5f388f134399555d041f5055e0", "attribution": "Copyright (c) 2023 DeepSeek"}, "tools": [{"type": "function", "function": {"name": "get_weather", "description": "Get the current weather for a city.", "parameters": {"type": "object", "properties": {"city": {"type": "string"}, "unit": {"type": "string", "enum": ["c", "f"]}}, "required": ["city"]}}}, {"type": "function", "function": {"name": "search", "description": "Search the web.", "parameters": {"type": "object", "properties": {"query": {"type": "string"}, "filters": {"type": "object"}}, "required": ["query"]}}}], "raw_output": "\n\n<|DSML|tool_calls>\n<|DSML|invoke name=\"get_weather\">\n<|DSML|parameter name=\"city\" string=\"true\">Zür", "output_token_ids": [271, 30, 128825, 72461, 4941, 12548, 1018, 30, 128825, 40148, 5406, 2329, 1281, 1133, 65, 50219, 3816, 30, 128825, 41523, 2329, 1281, 37399, 4, 3418, 1281, 11476, 3320, 60, 5421], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V4-Flash", "revision": "60d8d70770c6776ff598c94bb586a859a38244f1", "mode": "hf"}, "generation_prompt": "<|Assistant|></think>", "thinking": false, "expected_error": {"reason": "Output cut by max_tokens inside the first call's arguments: no complete call exists.", "accept": ["no_tool_calls", "content_passthrough", "exception"]}, "tags": ["truncated", "x-deepseek-v4"], "notes": "Token prefix of the full render, cut right after 'Zür' appears. Sub-format deepseek-v4; history render of the official encoder."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|></think>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V4-Flash",
"model_rule": "DeepSeek-V4",
"model_type": "deepseek_v4",
"parser_source": "docs/formats/deepseek.md (vLLM v0.30.0 row)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "emas to invoke tool calls.\n<|User|>Use the tools to answer.<|Assistant|></think>",
"reasoning_parser": "deepseek_v4",
"stop_token_in_final_delta": false,
"template": {
"sha256": "bfbb51e563b89c7d3581864cd0ea4d975b96e14fed034a222caf9d50c549b99d",
"source": "vLLM tokenizer_mode=deepseek_v4 encoder (vllm.tokenizers.deepseek_v4_encoding)"
},
"tokenizer": {
"mode": "deepseek_v4",
"repo": "deepseek-ai/DeepSeek-V4-Flash",
"requested_mode": "auto",
"resolved_revision": "60d8d70770c6776ff598c94bb586a859a38244f1",
"revision": "60d8d70770c6776ff598c94bb586a859a38244f1",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v4",
"units_source": "fixture.output_token_ids"
}
fail deepseek/v4-truncated-second-parallel-call
expected_match, arguments_schema
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_match | nonstream | fail | tool_calls: expected ['get_weather'], got ['get_weather', 'search'] |
expected_match | one | fail | tool_calls: expected ['get_weather'], got ['get_weather', 'search'] |
expected_match | special | fail | tool_calls: expected ['get_weather'], got ['get_weather', 'search'] |
expected_match | token | fail | tool_calls: expected ['get_weather'], got ['get_weather', 'search'] |
expected_match | rand:1:8 | fail | tool_calls: expected ['get_weather'], got ['get_weather', 'search'] |
expected_match | rand:2:8 | fail | tool_calls: expected ['get_weather'], got ['get_weather', 'search'] |
expected_match | rand:3:8 | fail | tool_calls: expected ['get_weather'], got ['get_weather', 'search'] |
expected_match | rand:4:8 | fail | tool_calls: expected ['get_weather'], got ['get_weather', 'search'] |
expected_match | rand:5:8 | fail | tool_calls: expected ['get_weather'], got ['get_weather', 'search'] |
arguments_schema | nonstream | fail | [1] search: $: 'query' is a required property |
arguments_schema | one | fail | [1] search: $: 'query' is a required property |
arguments_schema | special | fail | [1] search: $: 'query' is a required property |
arguments_schema | token | fail | [1] search: $: 'query' is a required property |
arguments_schema | rand:1:8 | fail | [1] search: $: 'query' is a required property |
arguments_schema | rand:2:8 | fail | [1] search: $: 'query' is a required property |
arguments_schema | rand:3:8 | fail | [1] search: $: 'query' is a required property |
arguments_schema | rand:4:8 | fail | [1] search: $: 'query' is a required property |
arguments_schema | rand:5:8 | fail | [1] search: $: 'query' is a required property |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/v4.jsonl --id deepseek/v4-truncated-second-parallel-call --strategy one --strategy rand:1:8 --strategy rand:2:8 --strategy rand:3:8 --strategy rand:4:8 --strategy rand:5:8 --strategy special --strategy token --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 17 of fixtures/deepseek/v4.jsonl.
Observed vs expected
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: nonstream, one, special, token, rand:1:8, rand:2:8, rand:3:8, rand:4:8, rand:5:8
@@ -9,4 +9,8 @@ }, "name": "get_weather" + }, + { + "arguments": {}, + "name": "search" } ]
Fixture
Provenance: template_render, https://huggingface.co/deepseek-ai/DeepSeek-V4-Flash/blob/60d8d70770c6776ff598c94bb586a859a38244f1/encoding/encoding_dsv4.py.
Tags: truncated, parallel-calls, unicode, x-deepseek-v4.
Raw output
<|DSML|tool_calls> <|DSML|invoke name="get_weather"> <|DSML|parameter name="city" string="true">Zürich</|DSML|parameter> <|DSML|parameter name="unit" string="true">c</|DSML|parameter> </|DSML|invoke> <|DSML|invoke name="search"> <|DSML|parameter name="query"
Expected parse
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"city": "Zürich",
"unit": "c"
},
"name": "get_weather"
}
]
}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/v4-truncated-second-parallel-call", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V4-Flash", "deepseek-ai/DeepSeek-V4-Pro"], "spec_version": "0.1", "provenance": {"kind": "template_render", "source_url": "https://huggingface.co/deepseek-ai/DeepSeek-V4-Flash/blob/60d8d70770c6776ff598c94bb586a859a38244f1/encoding/encoding_dsv4.py", "revision": "60d8d70770c6776ff598c94bb586a859a38244f1", "license": "MIT", "generator": "scripts/fixtures/deepseek/build.py", "template_sha256": "bdbd57c132a1b3725042323d02b98b9d1df28e5f388f134399555d041f5055e0", "attribution": "Copyright (c) 2023 DeepSeek"}, "tools": [{"type": "function", "function": {"name": "get_weather", "description": "Get the current weather for a city.", "parameters": {"type": "object", "properties": {"city": {"type": "string"}, "unit": {"type": "string", "enum": ["c", "f"]}}, "required": ["city"]}}}, {"type": "function", "function": {"name": "search", "description": "Search the web.", "parameters": {"type": "object", "properties": {"query": {"type": "string"}, "filters": {"type": "object"}}, "required": ["query"]}}}], "raw_output": "\n\n<|DSML|tool_calls>\n<|DSML|invoke name=\"get_weather\">\n<|DSML|parameter name=\"city\" string=\"true\">Zürich</|DSML|parameter>\n<|DSML|parameter name=\"unit\" string=\"true\">c</|DSML|parameter>\n</|DSML|invoke>\n<|DSML|invoke name=\"search\">\n<|DSML|parameter name=\"query\"", "output_token_ids": [271, 30, 128825, 72461, 4941, 12548, 1018, 30, 128825, 40148, 5406, 2329, 1281, 1133, 65, 50219, 3816, 30, 128825, 41523, 2329, 1281, 37399, 4, 3418, 1281, 11476, 3320, 60, 5421, 616, 1718, 128825, 41523, 1018, 30, 128825, 41523, 2329, 1281, 15165, 4, 3418, 1281, 11476, 3320, 69, 1718, 128825, 41523, 1018, 1718, 128825, 40148, 5406, 1018, 30, 128825, 40148, 5406, 2329, 1281, 14346, 3816, 30, 128825, 41523, 2329, 1281, 12066, 4], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V4-Flash", "revision": "60d8d70770c6776ff598c94bb586a859a38244f1", "mode": "hf"}, "generation_prompt": "<|Assistant|></think>", "thinking": false, "expected": {"content": null, "reasoning_content": null, "tool_calls": [{"name": "get_weather", "arguments": {"city": "Zürich", "unit": "c"}}]}, "tags": ["truncated", "parallel-calls", "unicode", "x-deepseek-v4"], "notes": "The first invoke is complete, the second is cut: a correct parser keeps only the first call. Token prefix of the full render, cut right after 'name=\"query\"' appears. Sub-format deepseek-v4; history render of the official encoder."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|></think>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V4-Flash",
"model_rule": "DeepSeek-V4",
"model_type": "deepseek_v4",
"parser_source": "docs/formats/deepseek.md (vLLM v0.30.0 row)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "emas to invoke tool calls.\n<|User|>Use the tools to answer.<|Assistant|></think>",
"reasoning_parser": "deepseek_v4",
"stop_token_in_final_delta": false,
"template": {
"sha256": "bfbb51e563b89c7d3581864cd0ea4d975b96e14fed034a222caf9d50c549b99d",
"source": "vLLM tokenizer_mode=deepseek_v4 encoder (vllm.tokenizers.deepseek_v4_encoding)"
},
"tokenizer": {
"mode": "deepseek_v4",
"repo": "deepseek-ai/DeepSeek-V4-Flash",
"requested_mode": "auto",
"resolved_revision": "60d8d70770c6776ff598c94bb586a859a38244f1",
"revision": "60d8d70770c6776ff598c94bb586a859a38244f1",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v4",
"units_source": "fixture.output_token_ids"
}
fail deepseek/v41-truncated-mid-arguments
expected_error, stream_equals_nonstream, arguments_json, arguments_schema
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_error | nonstream | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | one | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | special | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | token | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | rand:1:8 | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | rand:2:8 | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | rand:3:8 | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | rand:4:8 | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
expected_error | rand:5:8 | fail | returned 1 tool call(s) ['get_weather'] for Output cut by max_tokens inside the first call's arguments: no complete call exists. |
stream_equals_nonstream | one | fail | tool_calls[0].arguments: nonstream '{}', got '{"city": "' |
stream_equals_nonstream | special | fail | tool_calls[0].arguments: nonstream '{}', got '{"city": "' |
stream_equals_nonstream | token | fail | tool_calls[0].arguments: nonstream '{}', got '{"city": "' |
stream_equals_nonstream | rand:1:8 | fail | tool_calls[0].arguments: nonstream '{}', got '{"city": "' |
stream_equals_nonstream | rand:2:8 | fail | tool_calls[0].arguments: nonstream '{}', got '{"city": "' |
stream_equals_nonstream | rand:3:8 | fail | tool_calls[0].arguments: nonstream '{}', got '{"city": "' |
stream_equals_nonstream | rand:4:8 | fail | tool_calls[0].arguments: nonstream '{}', got '{"city": "' |
stream_equals_nonstream | rand:5:8 | fail | tool_calls[0].arguments: nonstream '{}', got '{"city": "' |
arguments_json | one | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "': Unterminated string starting at: line 1 column 10 (char 9)) |
arguments_json | special | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "': Unterminated string starting at: line 1 column 10 (char 9)) |
arguments_json | token | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "': Unterminated string starting at: line 1 column 10 (char 9)) |
arguments_json | rand:1:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "': Unterminated string starting at: line 1 column 10 (char 9)) |
arguments_json | rand:2:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "': Unterminated string starting at: line 1 column 10 (char 9)) |
arguments_json | rand:3:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "': Unterminated string starting at: line 1 column 10 (char 9)) |
arguments_json | rand:4:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "': Unterminated string starting at: line 1 column 10 (char 9)) |
arguments_json | rand:5:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "': Unterminated string starting at: line 1 column 10 (char 9)) |
arguments_schema | nonstream | fail | [0] get_weather: $: 'city' is a required property |
arguments_schema | one | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | special | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | token | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | rand:1:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | rand:2:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | rand:3:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | rand:4:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | rand:5:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/v41.jsonl --id deepseek/v41-truncated-mid-arguments --strategy one --strategy rand:1:8 --strategy rand:2:8 --strategy rand:3:8 --strategy rand:4:8 --strategy rand:5:8 --strategy special --strategy token --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 9 of fixtures/deepseek/v41.jsonl.
Observed
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: nonstream
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {},
"name": "get_weather"
}
]
}
Strategies: one, special, token, rand:1:8, rand:2:8, rand:3:8, rand:4:8, rand:5:8
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"<arguments_raw, not valid JSON>": "{\"city\": \""
},
"name": "get_weather"
}
]
}
Fixture
Provenance: template_render, https://huggingface.co/deepseek-ai/DeepSeek-V4.1-Flash/blob/dba1be0a40aa45a94ad051997016db3960a90277/encoding/encoding.py.
Tags: truncated, x-deepseek-v41.
Expected graceful failure: Output cut by max_tokens inside the first call's arguments: no complete call exists. (accept: no_tool_calls, content_passthrough, exception).
Raw output
<|DSML| calls> <|DSML| invoke name="get_weather"> <|DSML| parameter name="city" string="true">Zür
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/v41-truncated-mid-arguments", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V4.1-Flash"], "spec_version": "0.1", "provenance": {"kind": "template_render", "source_url": "https://huggingface.co/deepseek-ai/DeepSeek-V4.1-Flash/blob/dba1be0a40aa45a94ad051997016db3960a90277/encoding/encoding.py", "revision": "dba1be0a40aa45a94ad051997016db3960a90277", "license": "MIT", "generator": "scripts/fixtures/deepseek/build.py", "template_sha256": "502bdaec8a3fd88ebc24c4721a7038fbe42f2063c664638127056107920035c1", "attribution": "Copyright (c) 2023 DeepSeek"}, "tools": [{"type": "function", "function": {"name": "get_weather", "description": "Get the current weather for a city.", "parameters": {"type": "object", "properties": {"city": {"type": "string"}, "unit": {"type": "string", "enum": ["c", "f"]}}, "required": ["city"]}}}, {"type": "function", "function": {"name": "search", "description": "Search the web.", "parameters": {"type": "object", "properties": {"query": {"type": "string"}, "filters": {"type": "object"}}, "required": ["query"]}}}], "raw_output": "\n\n<|DSML| calls>\n<|DSML| invoke name=\"get_weather\">\n<|DSML| parameter name=\"city\" string=\"true\">Zür", "output_token_ids": [271, 30, 128825, 10699, 1018, 30, 128825, 34756, 2329, 1281, 1133, 65, 50219, 3816, 30, 128825, 10767, 2329, 1281, 37399, 4, 3418, 1281, 11476, 3320, 60, 5421], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V4.1-Flash", "revision": "dba1be0a40aa45a94ad051997016db3960a90277", "mode": "hf"}, "generation_prompt": "<|Assistant|></think>", "thinking": false, "expected_error": {"reason": "Output cut by max_tokens inside the first call's arguments: no complete call exists.", "accept": ["no_tool_calls", "content_passthrough", "exception"]}, "tags": ["truncated", "x-deepseek-v41"], "notes": "Token prefix of the full render, cut right after 'Zür' appears. Sub-format deepseek-v41; history render of the official encoder."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|></think>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V4.1-Flash",
"model_rule": "DeepSeek-V4\\.1",
"model_type": "deepseek_v41",
"parser_source": "docs/formats/deepseek.md (vLLM v0.30.0 row)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "emas to invoke tool calls.\n<|User|>Use the tools to answer.<|Assistant|></think>",
"reasoning_parser": "deepseek_v41",
"stop_token_in_final_delta": false,
"template": {
"sha256": "081382cb953a1c8041fdfc82a6001cf0c932553171436625c89fe5b9fbcda464",
"source": "vLLM tokenizer_mode=deepseek_v41 encoder (vllm.tokenizers.deepseek_v41_encoding)"
},
"tokenizer": {
"mode": "deepseek_v41",
"repo": "deepseek-ai/DeepSeek-V4.1-Flash",
"requested_mode": "auto",
"resolved_revision": "dba1be0a40aa45a94ad051997016db3960a90277",
"revision": "dba1be0a40aa45a94ad051997016db3960a90277",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v41",
"units_source": "fixture.output_token_ids"
}
fail deepseek/v41-truncated-second-parallel-call
expected_match, arguments_schema
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_match | nonstream | fail | tool_calls: expected ['get_weather'], got ['get_weather', 'search'] |
expected_match | one | fail | tool_calls: expected ['get_weather'], got ['get_weather', 'search'] |
expected_match | special | fail | tool_calls: expected ['get_weather'], got ['get_weather', 'search'] |
expected_match | token | fail | tool_calls: expected ['get_weather'], got ['get_weather', 'search'] |
expected_match | rand:1:8 | fail | tool_calls: expected ['get_weather'], got ['get_weather', 'search'] |
expected_match | rand:2:8 | fail | tool_calls: expected ['get_weather'], got ['get_weather', 'search'] |
expected_match | rand:3:8 | fail | tool_calls: expected ['get_weather'], got ['get_weather', 'search'] |
expected_match | rand:4:8 | fail | tool_calls: expected ['get_weather'], got ['get_weather', 'search'] |
expected_match | rand:5:8 | fail | tool_calls: expected ['get_weather'], got ['get_weather', 'search'] |
arguments_schema | nonstream | fail | [1] search: $: 'query' is a required property |
arguments_schema | one | fail | [1] search: $: 'query' is a required property |
arguments_schema | special | fail | [1] search: $: 'query' is a required property |
arguments_schema | token | fail | [1] search: $: 'query' is a required property |
arguments_schema | rand:1:8 | fail | [1] search: $: 'query' is a required property |
arguments_schema | rand:2:8 | fail | [1] search: $: 'query' is a required property |
arguments_schema | rand:3:8 | fail | [1] search: $: 'query' is a required property |
arguments_schema | rand:4:8 | fail | [1] search: $: 'query' is a required property |
arguments_schema | rand:5:8 | fail | [1] search: $: 'query' is a required property |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/v41.jsonl --id deepseek/v41-truncated-second-parallel-call --strategy one --strategy rand:1:8 --strategy rand:2:8 --strategy rand:3:8 --strategy rand:4:8 --strategy rand:5:8 --strategy special --strategy token --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 17 of fixtures/deepseek/v41.jsonl.
Observed vs expected
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: nonstream, one, special, token, rand:1:8, rand:2:8, rand:3:8, rand:4:8, rand:5:8
@@ -9,4 +9,8 @@ }, "name": "get_weather" + }, + { + "arguments": {}, + "name": "search" } ]
Fixture
Provenance: template_render, https://huggingface.co/deepseek-ai/DeepSeek-V4.1-Flash/blob/dba1be0a40aa45a94ad051997016db3960a90277/encoding/encoding.py.
Tags: truncated, parallel-calls, unicode, x-deepseek-v41.
Raw output
<|DSML| calls> <|DSML| invoke name="get_weather"> <|DSML| parameter name="city" string="true">Zürich</|DSML| parameter> <|DSML| parameter name="unit" string="true">c</|DSML| parameter> </|DSML| invoke> <|DSML| invoke name="search"> <|DSML| parameter name="query"
Expected parse
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"city": "Zürich",
"unit": "c"
},
"name": "get_weather"
}
]
}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/v41-truncated-second-parallel-call", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V4.1-Flash"], "spec_version": "0.1", "provenance": {"kind": "template_render", "source_url": "https://huggingface.co/deepseek-ai/DeepSeek-V4.1-Flash/blob/dba1be0a40aa45a94ad051997016db3960a90277/encoding/encoding.py", "revision": "dba1be0a40aa45a94ad051997016db3960a90277", "license": "MIT", "generator": "scripts/fixtures/deepseek/build.py", "template_sha256": "502bdaec8a3fd88ebc24c4721a7038fbe42f2063c664638127056107920035c1", "attribution": "Copyright (c) 2023 DeepSeek"}, "tools": [{"type": "function", "function": {"name": "get_weather", "description": "Get the current weather for a city.", "parameters": {"type": "object", "properties": {"city": {"type": "string"}, "unit": {"type": "string", "enum": ["c", "f"]}}, "required": ["city"]}}}, {"type": "function", "function": {"name": "search", "description": "Search the web.", "parameters": {"type": "object", "properties": {"query": {"type": "string"}, "filters": {"type": "object"}}, "required": ["query"]}}}], "raw_output": "\n\n<|DSML| calls>\n<|DSML| invoke name=\"get_weather\">\n<|DSML| parameter name=\"city\" string=\"true\">Zürich</|DSML| parameter>\n<|DSML| parameter name=\"unit\" string=\"true\">c</|DSML| parameter>\n</|DSML| invoke>\n<|DSML| invoke name=\"search\">\n<|DSML| parameter name=\"query\"", "output_token_ids": [271, 30, 128825, 10699, 1018, 30, 128825, 34756, 2329, 1281, 1133, 65, 50219, 3816, 30, 128825, 10767, 2329, 1281, 37399, 4, 3418, 1281, 11476, 3320, 60, 5421, 616, 1718, 128825, 10767, 1018, 30, 128825, 10767, 2329, 1281, 15165, 4, 3418, 1281, 11476, 3320, 69, 1718, 128825, 10767, 1018, 1718, 128825, 34756, 1018, 30, 128825, 34756, 2329, 1281, 14346, 3816, 30, 128825, 10767, 2329, 1281, 12066, 4], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V4.1-Flash", "revision": "dba1be0a40aa45a94ad051997016db3960a90277", "mode": "hf"}, "generation_prompt": "<|Assistant|></think>", "thinking": false, "expected": {"content": null, "reasoning_content": null, "tool_calls": [{"name": "get_weather", "arguments": {"city": "Zürich", "unit": "c"}}]}, "tags": ["truncated", "parallel-calls", "unicode", "x-deepseek-v41"], "notes": "The first invoke is complete, the second is cut: a correct parser keeps only the first call. Token prefix of the full render, cut right after 'name=\"query\"' appears. Sub-format deepseek-v41; history render of the official encoder."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|></think>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V4.1-Flash",
"model_rule": "DeepSeek-V4\\.1",
"model_type": "deepseek_v41",
"parser_source": "docs/formats/deepseek.md (vLLM v0.30.0 row)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "emas to invoke tool calls.\n<|User|>Use the tools to answer.<|Assistant|></think>",
"reasoning_parser": "deepseek_v41",
"stop_token_in_final_delta": false,
"template": {
"sha256": "081382cb953a1c8041fdfc82a6001cf0c932553171436625c89fe5b9fbcda464",
"source": "vLLM tokenizer_mode=deepseek_v41 encoder (vllm.tokenizers.deepseek_v41_encoding)"
},
"tokenizer": {
"mode": "deepseek_v41",
"repo": "deepseek-ai/DeepSeek-V4.1-Flash",
"requested_mode": "auto",
"resolved_revision": "dba1be0a40aa45a94ad051997016db3960a90277",
"revision": "dba1be0a40aa45a94ad051997016db3960a90277",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v41",
"units_source": "fixture.output_token_ids"
}
fail deepseek/vllm-v3-escaped-strings
expected_match, stream_equals_nonstream, split_invariance
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_match | one | fail | tool_calls: expected ['send_message'], got [] |
expected_match | special | fail | tool_calls: expected ['send_message'], got [] |
stream_equals_nonstream | one | fail | tool_calls: nonstream ['send_message'], got [] |
stream_equals_nonstream | special | fail | tool_calls: nonstream ['send_message'], got [] |
split_invariance | * | fail | vs one: token (fail): tool_calls: one [], got ['send_message'] | rand:1:8 (fail): tool_calls: one [], got ['send_message'] | rand:2:8 (fail): tool_calls: one [], got ['send_message'] | rand:3:8 (fail): tool_calls: one [], got ['send_message'] | rand:4:8 (fail): tool_calls: one [], got ['send_message'] | rand:5:8 (fail): tool_calls: one [], got ['send_message'] |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/engine-tests.jsonl --id deepseek/vllm-v3-escaped-strings --strategy one --strategy special --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 5 of fixtures/deepseek/engine-tests.jsonl.
Observed vs expected
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: one, special
@@ -2,13 +2,4 @@ "content": null, "reasoning_content": null, - "tool_calls": [ - { - "arguments": { - "newline": "line1\nline2", - "path": "C:\\Users\\file", - "text": "He said \"hello\"" - }, - "name": "send_message" - } - ] + "tool_calls": [] }
Strategies: nonstream, token, rand:1:8, rand:2:8, rand:3:8, rand:4:8, rand:5:8
Matches the expected parse.
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"newline": "line1\nline2",
"path": "C:\\Users\\file",
"text": "He said \"hello\""
},
"name": "send_message"
}
]
}
Fixture
Provenance: engine_test, https://github.com/vllm-project/vllm/blob/ced6857afa0ea7b2e3f0846a62e1394e90f15607/tests/tool_parsers/test_deepseekv3_tool_parser.py#L61.
Tags: single-call, string-escapes, x-deepseek-v3.
Raw output
<|tool▁calls▁begin|><|tool▁call▁begin|>function<|tool▁sep|>send_message
```json
{"text": "He said \"hello\"", "path": "C:\\Users\\file", "newline": "line1\nline2"}
```<|tool▁call▁end|><|tool▁calls▁end|>
Expected parse
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"newline": "line1\nline2",
"path": "C:\\Users\\file",
"text": "He said \"hello\""
},
"name": "send_message"
}
]
}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/vllm-v3-escaped-strings", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V3-0324"], "spec_version": "0.1", "provenance": {"kind": "engine_test", "source_url": "https://github.com/vllm-project/vllm/blob/ced6857afa0ea7b2e3f0846a62e1394e90f15607/tests/tool_parsers/test_deepseekv3_tool_parser.py#L61", "revision": "ced6857afa0ea7b2e3f0846a62e1394e90f15607", "license": "Apache-2.0", "attribution": "Copyright contributors to the vLLM project"}, "tools": [{"type": "function", "function": {"name": "send_message", "parameters": {"type": "object", "properties": {"text": {"type": "string"}, "path": {"type": "string"}, "newline": {"type": "string"}}}}}], "raw_output": "<|tool▁calls▁begin|><|tool▁call▁begin|>function<|tool▁sep|>send_message\n```json\n{\"text\": \"He said \\\"hello\\\"\", \"path\": \"C:\\\\Users\\\\file\", \"newline\": \"line1\\nline2\"}\n```<|tool▁call▁end|><|tool▁calls▁end|>", "output_token_ids": [128806, 128808, 8701, 128814, 35397, 53735, 201, 9854, 14479, 201, 24313, 2067, 3362, 582, 3158, 1359, 36952, 33310, 28609, 1760, 582, 9860, 3362, 582, 37, 111396, 24979, 7387, 8104, 1760, 582, 2839, 1836, 3362, 582, 1836, 19, 5809, 1836, 20, 60676, 9854, 128809, 128807], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V3-0324", "revision": "e9b33add76883f293d6bf61f6bd89b497e80e335", "mode": "hf"}, "generation_prompt": "<|Assistant|>", "thinking": false, "expected": {"content": null, "reasoning_content": null, "tool_calls": [{"name": "send_message", "arguments": {"text": "He said \"hello\"", "path": "C:\\Users\\file", "newline": "line1\nline2"}}]}, "tags": ["single-call", "string-escapes", "x-deepseek-v3"], "notes": "output_token_ids: tokenizer.encode(raw_output)."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V3-0324",
"model_rule": "DeepSeek-V3",
"model_type": "deepseek_v3",
"parser_source": "docs/formats/deepseek.md (V3: no reasoning)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "<|begin▁of▁sentence|><|User|>Use the tools to answer.<|Assistant|>",
"reasoning_parser": null,
"stop_token_in_final_delta": false,
"template": {
"sha256": "22e97ba043dacf9df1f071a9de9d2bb6b0757491f16e96e810834b86e1641286",
"source": "tokenizer chat template (HF repo)"
},
"tokenizer": {
"mode": "hf",
"repo": "deepseek-ai/DeepSeek-V3-0324",
"requested_mode": "auto",
"resolved_revision": "e9b33add76883f293d6bf61f6bd89b497e80e335",
"revision": "e9b33add76883f293d6bf61f6bd89b497e80e335",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v3",
"units_source": "fixture.output_token_ids"
}
fail deepseek/vllm-v3-malformed-missing-brace
expected_error, stream_equals_nonstream, split_invariance, arguments_json, arguments_schema
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_error | nonstream | fail | returned 1 tool call(s) ['get_weather'] for The arguments JSON is missing its closing brace; no valid call exists. |
expected_error | token | fail | returned 1 tool call(s) ['get_weather'] for The arguments JSON is missing its closing brace; no valid call exists. |
expected_error | rand:1:8 | fail | returned 1 tool call(s) ['get_weather'] for The arguments JSON is missing its closing brace; no valid call exists. |
expected_error | rand:2:8 | fail | returned 1 tool call(s) ['get_weather'] for The arguments JSON is missing its closing brace; no valid call exists. |
expected_error | rand:3:8 | fail | returned 1 tool call(s) ['get_weather'] for The arguments JSON is missing its closing brace; no valid call exists. |
expected_error | rand:4:8 | fail | returned 1 tool call(s) ['get_weather'] for The arguments JSON is missing its closing brace; no valid call exists. |
expected_error | rand:5:8 | fail | returned 1 tool call(s) ['get_weather'] for The arguments JSON is missing its closing brace; no valid call exists. |
stream_equals_nonstream | one | fail | tool_calls: nonstream ['get_weather'], got [] |
stream_equals_nonstream | special | fail | tool_calls: nonstream ['get_weather'], got [] |
stream_equals_nonstream | rand:1:8 | fail | tool_calls[0].arguments: nonstream '{"city": "Tokyo"', got '{"' |
stream_equals_nonstream | rand:2:8 | fail | tool_calls[0].arguments: nonstream '{"city": "Tokyo"', got '{"city":' |
stream_equals_nonstream | rand:3:8 | fail | tool_calls[0].arguments: nonstream '{"city": "Tokyo"', got '' |
stream_equals_nonstream | rand:5:8 | fail | tool_calls[0].arguments: nonstream '{"city": "Tokyo"', got '{"' |
split_invariance | * | fail | vs one: token (fail): tool_calls: one [], got ['get_weather'] | rand:1:8 (fail): tool_calls: one [], got ['get_weather'] | rand:2:8 (fail): tool_calls: one [], got ['get_weather'] | rand:3:8 (fail): tool_calls: one [], got ['get_weather'] | rand:4:8 (fail): tool_calls: one [], got ['get_weather'] | rand:5:8 (fail): tool_calls: one [], got ['get_weather'] |
arguments_json | nonstream | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "Tokyo"': Expecting ',' delimiter: line 1 column 17 (char 16)) |
arguments_json | token | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "Tokyo"': Expecting ',' delimiter: line 1 column 17 (char 16)) |
arguments_json | rand:1:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"': Unterminated string starting at: line 1 column 2 (char 1)) |
arguments_json | rand:2:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"city":': Expecting value: line 1 column 9 (char 8)) |
arguments_json | rand:3:8 | fail | [0] get_weather: arguments are not valid JSON text ('': Expecting value: line 1 column 1 (char 0)) |
arguments_json | rand:4:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "Tokyo"': Expecting ',' delimiter: line 1 column 17 (char 16)) |
arguments_json | rand:5:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"': Unterminated string starting at: line 1 column 2 (char 1)) |
arguments_schema | nonstream | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | token | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | rand:1:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | rand:2:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | rand:3:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | rand:4:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
arguments_schema | rand:5:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/malformed.jsonl --id deepseek/vllm-v3-malformed-missing-brace --strategy one --strategy rand:1:8 --strategy rand:2:8 --strategy rand:3:8 --strategy rand:4:8 --strategy rand:5:8 --strategy special --strategy token --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 1 of fixtures/deepseek/malformed.jsonl.
Observed
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: nonstream, token, rand:4:8
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"<arguments_raw, not valid JSON>": "{\"city\": \"Tokyo\""
},
"name": "get_weather"
}
]
}
Strategies: one, special
{
"content": null,
"reasoning_content": null,
"tool_calls": []
}
Strategies: rand:1:8, rand:5:8
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"<arguments_raw, not valid JSON>": "{\""
},
"name": "get_weather"
}
]
}
Strategies: rand:2:8
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"<arguments_raw, not valid JSON>": "{\"city\":"
},
"name": "get_weather"
}
]
}
Strategies: rand:3:8
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"<arguments_raw, not valid JSON>": ""
},
"name": "get_weather"
}
]
}
Fixture
Provenance: engine_test, https://github.com/vllm-project/vllm/blob/ced6857afa0ea7b2e3f0846a62e1394e90f15607/tests/tool_parsers/test_deepseekv3_tool_parser.py#L68.
Tags: malformed, x-deepseek-v3.
Expected graceful failure: The arguments JSON is missing its closing brace; no valid call exists. (accept: no_tool_calls, content_passthrough).
Raw output
<|tool▁calls▁begin|><|tool▁call▁begin|>function<|tool▁sep|>get_weather
```json
{"city": "Tokyo"
```<|tool▁call▁end|><|tool▁calls▁end|>
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/vllm-v3-malformed-missing-brace", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V3-0324"], "spec_version": "0.1", "provenance": {"kind": "engine_test", "source_url": "https://github.com/vllm-project/vllm/blob/ced6857afa0ea7b2e3f0846a62e1394e90f15607/tests/tool_parsers/test_deepseekv3_tool_parser.py#L68", "revision": "ced6857afa0ea7b2e3f0846a62e1394e90f15607", "license": "Apache-2.0", "attribution": "Copyright contributors to the vLLM project"}, "tools": [{"type": "function", "function": {"name": "get_weather", "parameters": {"type": "object", "properties": {"city": {"type": "string"}, "unit": {"type": "string"}, "count": {"type": "integer"}}}}}], "raw_output": "<|tool▁calls▁begin|><|tool▁call▁begin|>function<|tool▁sep|>get_weather\n```json\n{\"city\": \"Tokyo\"\n```<|tool▁call▁end|><|tool▁calls▁end|>", "output_token_ids": [128806, 128808, 8701, 128814, 1133, 65, 50219, 201, 9854, 14479, 201, 24313, 37399, 3362, 582, 106239, 2701, 9854, 128809, 128807], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V3-0324", "revision": "e9b33add76883f293d6bf61f6bd89b497e80e335", "mode": "hf"}, "generation_prompt": "<|Assistant|>", "thinking": false, "expected_error": {"reason": "The arguments JSON is missing its closing brace; no valid call exists.", "accept": ["no_tool_calls", "content_passthrough"]}, "tags": ["malformed", "x-deepseek-v3"], "notes": "malformed_input_outputs[0] of the test. output_token_ids: tokenizer.encode(raw_output)."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V3-0324",
"model_rule": "DeepSeek-V3",
"model_type": "deepseek_v3",
"parser_source": "docs/formats/deepseek.md (V3: no reasoning)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "<|begin▁of▁sentence|><|User|>Use the tools to answer.<|Assistant|>",
"reasoning_parser": null,
"stop_token_in_final_delta": false,
"template": {
"sha256": "22e97ba043dacf9df1f071a9de9d2bb6b0757491f16e96e810834b86e1641286",
"source": "tokenizer chat template (HF repo)"
},
"tokenizer": {
"mode": "hf",
"repo": "deepseek-ai/DeepSeek-V3-0324",
"requested_mode": "auto",
"resolved_revision": "e9b33add76883f293d6bf61f6bd89b497e80e335",
"revision": "e9b33add76883f293d6bf61f6bd89b497e80e335",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v3",
"units_source": "fixture.output_token_ids"
}
fail deepseek/vllm-v3-malformed-missing-call-tokens
stream_equals_nonstream
| Check | Strategy | Result | Detail |
|---|---|---|---|
stream_equals_nonstream | one | fail | content: nonstream None, got 'function<|tool▁sep|>get_weather\n```json\n{"city": "Tokyo"}\n```' |
stream_equals_nonstream | special | fail | content: nonstream None, got 'function<|tool▁sep|>get_weather\n```json\n{"city": "Tokyo"}\n```' |
stream_equals_nonstream | token | fail | content: nonstream None, got 'function<|tool▁sep|>get_weather\n```json\n{"city": "Tokyo"}\n```' |
stream_equals_nonstream | rand:1:8 | fail | content: nonstream None, got 'function<|tool▁sep|>get_weather\n```json\n{"city": "Tokyo"}\n```' |
stream_equals_nonstream | rand:2:8 | fail | content: nonstream None, got 'function<|tool▁sep|>get_weather\n```json\n{"city": "Tokyo"}\n```' |
stream_equals_nonstream | rand:3:8 | fail | content: nonstream None, got 'function<|tool▁sep|>get_weather\n```json\n{"city": "Tokyo"}\n```' |
stream_equals_nonstream | rand:4:8 | fail | content: nonstream None, got 'function<|tool▁sep|>get_weather\n```json\n{"city": "Tokyo"}\n```' |
stream_equals_nonstream | rand:5:8 | fail | content: nonstream None, got 'function<|tool▁sep|>get_weather\n```json\n{"city": "Tokyo"}\n```' |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/malformed.jsonl --id deepseek/vllm-v3-malformed-missing-call-tokens --strategy one --strategy rand:1:8 --strategy rand:2:8 --strategy rand:3:8 --strategy rand:4:8 --strategy rand:5:8 --strategy special --strategy token --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 2 of fixtures/deepseek/malformed.jsonl.
Observed
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: one, special, token, rand:1:8, rand:2:8, rand:3:8, rand:4:8, rand:5:8
{
"content": "function<|tool▁sep|>get_weather\n```json\n{\"city\": \"Tokyo\"}\n```",
"reasoning_content": null,
"tool_calls": []
}
Strategies: nonstream
{
"content": null,
"reasoning_content": null,
"tool_calls": []
}
Fixture
Provenance: engine_test, https://github.com/vllm-project/vllm/blob/ced6857afa0ea7b2e3f0846a62e1394e90f15607/tests/tool_parsers/test_deepseekv3_tool_parser.py#L68.
Tags: malformed, x-deepseek-v3.
Expected graceful failure: <|tool▁call▁begin|>/<|tool▁call▁end|> are missing inside the calls section; no well-formed call exists. (accept: no_tool_calls, content_passthrough).
Raw output
<|tool▁calls▁begin|>function<|tool▁sep|>get_weather
```json
{"city": "Tokyo"}
```<|tool▁calls▁end|>
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/vllm-v3-malformed-missing-call-tokens", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V3-0324"], "spec_version": "0.1", "provenance": {"kind": "engine_test", "source_url": "https://github.com/vllm-project/vllm/blob/ced6857afa0ea7b2e3f0846a62e1394e90f15607/tests/tool_parsers/test_deepseekv3_tool_parser.py#L68", "revision": "ced6857afa0ea7b2e3f0846a62e1394e90f15607", "license": "Apache-2.0", "attribution": "Copyright contributors to the vLLM project"}, "tools": [{"type": "function", "function": {"name": "get_weather", "parameters": {"type": "object", "properties": {"city": {"type": "string"}, "unit": {"type": "string"}, "count": {"type": "integer"}}}}}], "raw_output": "<|tool▁calls▁begin|>function<|tool▁sep|>get_weather\n```json\n{\"city\": \"Tokyo\"}\n```<|tool▁calls▁end|>", "output_token_ids": [128806, 8701, 128814, 1133, 65, 50219, 201, 9854, 14479, 201, 24313, 37399, 3362, 582, 106239, 60676, 9854, 128807], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V3-0324", "revision": "e9b33add76883f293d6bf61f6bd89b497e80e335", "mode": "hf"}, "generation_prompt": "<|Assistant|>", "thinking": false, "expected_error": {"reason": "<|tool▁call▁begin|>/<|tool▁call▁end|> are missing inside the calls section; no well-formed call exists.", "accept": ["no_tool_calls", "content_passthrough"]}, "tags": ["malformed", "x-deepseek-v3"], "notes": "malformed_input_outputs[1] of the test. output_token_ids: tokenizer.encode(raw_output)."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V3-0324",
"model_rule": "DeepSeek-V3",
"model_type": "deepseek_v3",
"parser_source": "docs/formats/deepseek.md (V3: no reasoning)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "<|begin▁of▁sentence|><|User|>Use the tools to answer.<|Assistant|>",
"reasoning_parser": null,
"stop_token_in_final_delta": false,
"template": {
"sha256": "22e97ba043dacf9df1f071a9de9d2bb6b0757491f16e96e810834b86e1641286",
"source": "tokenizer chat template (HF repo)"
},
"tokenizer": {
"mode": "hf",
"repo": "deepseek-ai/DeepSeek-V3-0324",
"requested_mode": "auto",
"resolved_revision": "e9b33add76883f293d6bf61f6bd89b497e80e335",
"revision": "e9b33add76883f293d6bf61f6bd89b497e80e335",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v3",
"units_source": "fixture.output_token_ids"
}
fail deepseek/vllm-v3-parallel-no-newline
expected_match, stream_equals_nonstream, split_invariance, arguments_json, arguments_schema, parallel_order
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_match | one | fail | tool_calls: expected ['get_weather', 'search_hotels'], got [] |
expected_match | special | fail | tool_calls: expected ['get_weather', 'search_hotels'], got [] |
expected_match | rand:1:8 | fail | tool_calls[0].arguments: expected '{"city": "Tokyo", "unit": "celsius"}', got '{"city": "Tokyo", "unit":' |
stream_equals_nonstream | one | fail | tool_calls: nonstream ['get_weather', 'search_hotels'], got [] |
stream_equals_nonstream | special | fail | tool_calls: nonstream ['get_weather', 'search_hotels'], got [] |
stream_equals_nonstream | rand:1:8 | fail | tool_calls[0].arguments: nonstream '{"city": "Tokyo", "unit": "celsius"}', got '{"city": "Tokyo", "unit":' |
split_invariance | * | fail | vs one: token (fail): tool_calls: one [], got ['get_weather', 'search_hotels'] | rand:1:8 (fail): tool_calls: one [], got ['get_weather', 'search_hotels'] | rand:2:8 (fail): tool_calls: one [], got ['get_weather', 'search_hotels'] | rand:3:8 (fail): tool_calls: one [], got ['get_weather', 'search_hotels'] | rand:4:8 (fail): tool_calls: one [], got ['get_weather', 'search_hotels'] | rand:5:8 (fail): tool_calls: one [], got ['get_weather', 'search_hotels'] |
arguments_json | rand:1:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "Tokyo", "unit":': Expecting value: line 1 column 26 (char 25)) |
arguments_schema | rand:1:8 | fail | [0] get_weather: arguments are not a JSON object; not validated |
parallel_order | one | fail | expected 2 calls ['get_weather', 'search_hotels'], got 0 [] |
parallel_order | special | fail | expected 2 calls ['get_weather', 'search_hotels'], got 0 [] |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/engine-tests.jsonl --id deepseek/vllm-v3-parallel-no-newline --strategy one --strategy rand:1:8 --strategy special --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 3 of fixtures/deepseek/engine-tests.jsonl.
Observed vs expected
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: one, special
@@ -2,19 +2,4 @@ "content": null, "reasoning_content": null, - "tool_calls": [ - { - "arguments": { - "city": "Tokyo", - "unit": "celsius" - }, - "name": "get_weather" - }, - { - "arguments": { - "check_in": "2025-01-15", - "location": "Tokyo" - }, - "name": "search_hotels" - } - ] + "tool_calls": [] }
Strategies: rand:1:8
@@ -5,6 +5,5 @@ { "arguments": { - "city": "Tokyo", - "unit": "celsius" + "<arguments_raw, not valid JSON>": "{\"city\": \"Tokyo\", \"unit\":" }, "name": "get_weather"
Strategies: nonstream, token, rand:2:8, rand:3:8, rand:4:8, rand:5:8
Matches the expected parse.
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"city": "Tokyo",
"unit": "celsius"
},
"name": "get_weather"
},
{
"arguments": {
"check_in": "2025-01-15",
"location": "Tokyo"
},
"name": "search_hotels"
}
]
}
Fixture
Provenance: engine_test, https://github.com/vllm-project/vllm/blob/ced6857afa0ea7b2e3f0846a62e1394e90f15607/tests/tool_parsers/test_deepseekv3_tool_parser.py#L31.
Tags: parallel-calls, x-deepseek-v3.
Raw output
<|tool▁calls▁begin|><|tool▁call▁begin|>function<|tool▁sep|>get_weather
```json
{"city": "Tokyo", "unit": "celsius"}
```<|tool▁call▁end|><|tool▁call▁begin|>function<|tool▁sep|>search_hotels
```json
{"location": "Tokyo", "check_in": "2025-01-15"}
```<|tool▁call▁end|><|tool▁calls▁end|>
Expected parse
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"city": "Tokyo",
"unit": "celsius"
},
"name": "get_weather"
},
{
"arguments": {
"check_in": "2025-01-15",
"location": "Tokyo"
},
"name": "search_hotels"
}
]
}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/vllm-v3-parallel-no-newline", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V3-0324"], "spec_version": "0.1", "provenance": {"kind": "engine_test", "source_url": "https://github.com/vllm-project/vllm/blob/ced6857afa0ea7b2e3f0846a62e1394e90f15607/tests/tool_parsers/test_deepseekv3_tool_parser.py#L31", "revision": "ced6857afa0ea7b2e3f0846a62e1394e90f15607", "license": "Apache-2.0", "attribution": "Copyright contributors to the vLLM project"}, "tools": [{"type": "function", "function": {"name": "get_weather", "parameters": {"type": "object", "properties": {"city": {"type": "string"}, "unit": {"type": "string"}, "count": {"type": "integer"}}}}}, {"type": "function", "function": {"name": "search_hotels", "parameters": {"type": "object", "properties": {"location": {"type": "string"}, "check_in": {"type": "string"}}}}}], "raw_output": "<|tool▁calls▁begin|><|tool▁call▁begin|>function<|tool▁sep|>get_weather\n```json\n{\"city\": \"Tokyo\", \"unit\": \"celsius\"}\n```<|tool▁call▁end|><|tool▁call▁begin|>function<|tool▁sep|>search_hotels\n```json\n{\"location\": \"Tokyo\", \"check_in\": \"2025-01-15\"}\n```<|tool▁call▁end|><|tool▁calls▁end|>", "output_token_ids": [128806, 128808, 8701, 128814, 1133, 65, 50219, 201, 9854, 14479, 201, 24313, 37399, 3362, 582, 106239, 1760, 582, 15165, 3362, 582, 69, 33030, 60676, 9854, 128809, 128808, 8701, 128814, 14346, 17462, 347, 1713, 201, 9854, 14479, 201, 24313, 33182, 3362, 582, 106239, 1760, 582, 9547, 12743, 3362, 582, 939, 23, 15, 2616, 15, 856, 60676, 9854, 128809, 128807], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V3-0324", "revision": "e9b33add76883f293d6bf61f6bd89b497e80e335", "mode": "hf"}, "generation_prompt": "<|Assistant|>", "thinking": false, "expected": {"content": null, "reasoning_content": null, "tool_calls": [{"name": "get_weather", "arguments": {"city": "Tokyo", "unit": "celsius"}}, {"name": "search_hotels", "arguments": {"location": "Tokyo", "check_in": "2025-01-15"}}]}, "tags": ["parallel-calls", "x-deepseek-v3"], "notes": "Calls are adjacent here; the official template separates them with '\\n'. output_token_ids: tokenizer.encode(raw_output)."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V3-0324",
"model_rule": "DeepSeek-V3",
"model_type": "deepseek_v3",
"parser_source": "docs/formats/deepseek.md (V3: no reasoning)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "<|begin▁of▁sentence|><|User|>Use the tools to answer.<|Assistant|>",
"reasoning_parser": null,
"stop_token_in_final_delta": false,
"template": {
"sha256": "22e97ba043dacf9df1f071a9de9d2bb6b0757491f16e96e810834b86e1641286",
"source": "tokenizer chat template (HF repo)"
},
"tokenizer": {
"mode": "hf",
"repo": "deepseek-ai/DeepSeek-V3-0324",
"requested_mode": "auto",
"resolved_revision": "e9b33add76883f293d6bf61f6bd89b497e80e335",
"revision": "e9b33add76883f293d6bf61f6bd89b497e80e335",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v3",
"units_source": "fixture.output_token_ids"
}
fail deepseek/vllm-v3-single-call
expected_match, stream_equals_nonstream, split_invariance
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_match | one | fail | tool_calls: expected ['get_weather'], got [] |
expected_match | special | fail | tool_calls: expected ['get_weather'], got [] |
stream_equals_nonstream | one | fail | tool_calls: nonstream ['get_weather'], got [] |
stream_equals_nonstream | special | fail | tool_calls: nonstream ['get_weather'], got [] |
split_invariance | * | fail | vs one: token (fail): tool_calls: one [], got ['get_weather'] | rand:1:8 (fail): tool_calls: one [], got ['get_weather'] | rand:2:8 (fail): tool_calls: one [], got ['get_weather'] | rand:3:8 (fail): tool_calls: one [], got ['get_weather'] | rand:4:8 (fail): tool_calls: one [], got ['get_weather'] | rand:5:8 (fail): tool_calls: one [], got ['get_weather'] |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/engine-tests.jsonl --id deepseek/vllm-v3-single-call --strategy one --strategy special --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 2 of fixtures/deepseek/engine-tests.jsonl.
Observed vs expected
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: one, special
@@ -2,12 +2,4 @@ "content": null, "reasoning_content": null, - "tool_calls": [ - { - "arguments": { - "city": "Tokyo", - "unit": "celsius" - }, - "name": "get_weather" - } - ] + "tool_calls": [] }
Strategies: nonstream, token, rand:1:8, rand:2:8, rand:3:8, rand:4:8, rand:5:8
Matches the expected parse.
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"city": "Tokyo",
"unit": "celsius"
},
"name": "get_weather"
}
]
}
Fixture
Provenance: engine_test, https://github.com/vllm-project/vllm/blob/ced6857afa0ea7b2e3f0846a62e1394e90f15607/tests/tool_parsers/test_deepseekv3_tool_parser.py#L27.
Tags: single-call, x-deepseek-v3.
Raw output
<|tool▁calls▁begin|><|tool▁call▁begin|>function<|tool▁sep|>get_weather
```json
{"city": "Tokyo", "unit": "celsius"}
```<|tool▁call▁end|><|tool▁calls▁end|>
Expected parse
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"city": "Tokyo",
"unit": "celsius"
},
"name": "get_weather"
}
]
}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/vllm-v3-single-call", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V3-0324"], "spec_version": "0.1", "provenance": {"kind": "engine_test", "source_url": "https://github.com/vllm-project/vllm/blob/ced6857afa0ea7b2e3f0846a62e1394e90f15607/tests/tool_parsers/test_deepseekv3_tool_parser.py#L27", "revision": "ced6857afa0ea7b2e3f0846a62e1394e90f15607", "license": "Apache-2.0", "attribution": "Copyright contributors to the vLLM project"}, "tools": [{"type": "function", "function": {"name": "get_weather", "parameters": {"type": "object", "properties": {"city": {"type": "string"}, "unit": {"type": "string"}, "count": {"type": "integer"}}}}}], "raw_output": "<|tool▁calls▁begin|><|tool▁call▁begin|>function<|tool▁sep|>get_weather\n```json\n{\"city\": \"Tokyo\", \"unit\": \"celsius\"}\n```<|tool▁call▁end|><|tool▁calls▁end|>", "output_token_ids": [128806, 128808, 8701, 128814, 1133, 65, 50219, 201, 9854, 14479, 201, 24313, 37399, 3362, 582, 106239, 1760, 582, 15165, 3362, 582, 69, 33030, 60676, 9854, 128809, 128807], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V3-0324", "revision": "e9b33add76883f293d6bf61f6bd89b497e80e335", "mode": "hf"}, "generation_prompt": "<|Assistant|>", "thinking": false, "expected": {"content": null, "reasoning_content": null, "tool_calls": [{"name": "get_weather", "arguments": {"city": "Tokyo", "unit": "celsius"}}]}, "tags": ["single-call", "x-deepseek-v3"], "notes": "output_token_ids: tokenizer.encode(raw_output)."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V3-0324",
"model_rule": "DeepSeek-V3",
"model_type": "deepseek_v3",
"parser_source": "docs/formats/deepseek.md (V3: no reasoning)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "<|begin▁of▁sentence|><|User|>Use the tools to answer.<|Assistant|>",
"reasoning_parser": null,
"stop_token_in_final_delta": false,
"template": {
"sha256": "22e97ba043dacf9df1f071a9de9d2bb6b0757491f16e96e810834b86e1641286",
"source": "tokenizer chat template (HF repo)"
},
"tokenizer": {
"mode": "hf",
"repo": "deepseek-ai/DeepSeek-V3-0324",
"requested_mode": "auto",
"resolved_revision": "e9b33add76883f293d6bf61f6bd89b497e80e335",
"revision": "e9b33add76883f293d6bf61f6bd89b497e80e335",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v3",
"units_source": "fixture.output_token_ids"
}
fail deepseek/vllm-v3-various-data-types
expected_match, stream_equals_nonstream, split_invariance, arguments_json, arguments_schema
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_match | one | fail | tool_calls: expected ['test_function'], got [] |
expected_match | special | fail | tool_calls: expected ['test_function'], got [] |
expected_match | rand:3:8 | fail | tool_calls[0].arguments: expected '{"string_field": "hello", "int_field": 42, "float_field": 3.14, "bool_field": true, "null_field": null, "array_field": ["a", "b", "c"], "object_field": {"ne..., got '{"string_field": "hello", "int_field": 42, "float_field": 3.14, "bool_field": true, "null_field": null, "array_field": ["a", "b", "c"], "object_field": {"ne... |
expected_match | rand:4:8 | fail | tool_calls[0].arguments: expected '{"string_field": "hello", "int_field": 42, "float_field": 3.14, "bool_field": true, "null_field": null, "array_field": ["a", "b", "c"], "object_field": {"ne..., got '{"string_field": "hello", "int_field": 42, "float_field": 3.14, "bool_field": true, "null_field": null, "array_field": ["a", "b", "c"], "object_field": {"ne... |
stream_equals_nonstream | one | fail | tool_calls: nonstream ['test_function'], got [] |
stream_equals_nonstream | special | fail | tool_calls: nonstream ['test_function'], got [] |
stream_equals_nonstream | rand:3:8 | fail | tool_calls[0].arguments: nonstream '{"string_field": "hello", "int_field": 42, "float_field": 3.14, "bool_field": true, "null_field": null, "array_field": ["a", "b", "c"], "object_field": {"ne..., got '{"string_field": "hello", "int_field": 42, "float_field": 3.14, "bool_field": true, "null_field": null, "array_field": ["a", "b", "c"], "object_field": {"ne... |
stream_equals_nonstream | rand:4:8 | fail | tool_calls[0].arguments: nonstream '{"string_field": "hello", "int_field": 42, "float_field": 3.14, "bool_field": true, "null_field": null, "array_field": ["a", "b", "c"], "object_field": {"ne..., got '{"string_field": "hello", "int_field": 42, "float_field": 3.14, "bool_field": true, "null_field": null, "array_field": ["a", "b", "c"], "object_field": {"ne... |
split_invariance | * | fail | vs one: token (fail): tool_calls: one [], got ['test_function'] | rand:1:8 (fail): tool_calls: one [], got ['test_function'] | rand:2:8 (fail): tool_calls: one [], got ['test_function'] | rand:3:8 (fail): tool_calls: one [], got ['test_function'] | rand:4:8 (fail): tool_calls: one [], got ['test_function'] | rand:5:8 (fail): tool_calls: one [], got ['test_function'] |
arguments_json | rand:3:8 | fail | [0] test_function: arguments are not valid JSON text ('{"string_field": "hello", "int_field": 42, "float_field": 3.14, "bool_field": true, "null_field": null, "array_field": ["a", "b", "c"], "object_field": {"ne...: Expecting value: line 1 column 208 (char 207)) |
arguments_json | rand:4:8 | fail | [0] test_function: arguments are not valid JSON text ('{"string_field": "hello", "int_field": 42, "float_field": 3.14, "bool_field": true, "null_field": null, "array_field": ["a", "b", "c"], "object_field": {"ne...: Unterminated string starting at: line 1 column 193 (char 192)) |
arguments_schema | rand:3:8 | fail | [0] test_function: arguments are not a JSON object; not validated |
arguments_schema | rand:4:8 | fail | [0] test_function: arguments are not a JSON object; not validated |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/engine-tests.jsonl --id deepseek/vllm-v3-various-data-types --strategy one --strategy rand:3:8 --strategy rand:4:8 --strategy special --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 4 of fixtures/deepseek/engine-tests.jsonl.
Observed vs expected
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: one, special
@@ -2,25 +2,4 @@ "content": null, "reasoning_content": null, - "tool_calls": [ - { - "arguments": { - "array_field": [ - "a", - "b", - "c" - ], - "bool_field": true, - "empty_array": [], - "empty_object": {}, - "float_field": 3.14, - "int_field": 42, - "null_field": null, - "object_field": { - "nested": "value" - }, - "string_field": "hello" - }, - "name": "test_function" - } - ] + "tool_calls": [] }
Strategies: rand:3:8
@@ -5,19 +5,5 @@ { "arguments": { - "array_field": [ - "a", - "b", - "c" - ], - "bool_field": true, - "empty_array": [], - "empty_object": {}, - "float_field": 3.14, - "int_field": 42, - "null_field": null, - "object_field": { - "nested": "value" - }, - "string_field": "hello" + "<arguments_raw, not valid JSON>": "{\"string_field\": \"hello\", \"int_field\": 42, \"float_field\": 3.14, \"bool_field\": true, \"null_field\": null, \"array_field\": [\"a\", \"b\", \"c\"], \"object_field\": {\"nested\": \"value\"}, \"empty_array\": [], \"empty_object\":" }, "name": "test_function"
Strategies: rand:4:8
@@ -5,19 +5,5 @@ { "arguments": { - "array_field": [ - "a", - "b", - "c" - ], - "bool_field": true, - "empty_array": [], - "empty_object": {}, - "float_field": 3.14, - "int_field": 42, - "null_field": null, - "object_field": { - "nested": "value" - }, - "string_field": "hello" + "<arguments_raw, not valid JSON>": "{\"string_field\": \"hello\", \"int_field\": 42, \"float_field\": 3.14, \"bool_field\": true, \"null_field\": null, \"array_field\": [\"a\", \"b\", \"c\"], \"object_field\": {\"nested\": \"value\"}, \"empty_array\": [], \"empty_object" }, "name": "test_function"
Strategies: nonstream, token, rand:1:8, rand:2:8, rand:5:8
Matches the expected parse.
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"array_field": [
"a",
"b",
"c"
],
"bool_field": true,
"empty_array": [],
"empty_object": {},
"float_field": 3.14,
"int_field": 42,
"null_field": null,
"object_field": {
"nested": "value"
},
"string_field": "hello"
},
"name": "test_function"
}
]
}
Fixture
Provenance: engine_test, https://github.com/vllm-project/vllm/blob/ced6857afa0ea7b2e3f0846a62e1394e90f15607/tests/tool_parsers/test_deepseekv3_tool_parser.py#L39.
Tags: single-call, numeric-arguments, nested-json, x-deepseek-v3.
Raw output
<|tool▁calls▁begin|><|tool▁call▁begin|>function<|tool▁sep|>test_function
```json
{"string_field": "hello", "int_field": 42, "float_field": 3.14, "bool_field": true, "null_field": null, "array_field": ["a", "b", "c"], "object_field": {"nested": "value"}, "empty_array": [], "empty_object": {}}
```<|tool▁call▁end|><|tool▁calls▁end|>
Expected parse
{
"content": null,
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"array_field": [
"a",
"b",
"c"
],
"bool_field": true,
"empty_array": [],
"empty_object": {},
"float_field": 3.14,
"int_field": 42,
"null_field": null,
"object_field": {
"nested": "value"
},
"string_field": "hello"
},
"name": "test_function"
}
]
}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/vllm-v3-various-data-types", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V3-0324"], "spec_version": "0.1", "provenance": {"kind": "engine_test", "source_url": "https://github.com/vllm-project/vllm/blob/ced6857afa0ea7b2e3f0846a62e1394e90f15607/tests/tool_parsers/test_deepseekv3_tool_parser.py#L39", "revision": "ced6857afa0ea7b2e3f0846a62e1394e90f15607", "license": "Apache-2.0", "attribution": "Copyright contributors to the vLLM project"}, "tools": [{"type": "function", "function": {"name": "test_function", "parameters": {"type": "object", "properties": {"string_field": {"type": "string"}, "int_field": {"type": "integer"}, "float_field": {"type": "number"}, "bool_field": {"type": "boolean"}, "null_field": {"type": "null"}, "array_field": {"type": "array"}, "object_field": {"type": "object"}, "empty_array": {"type": "array"}, "empty_object": {"type": "object"}}}}}], "raw_output": "<|tool▁calls▁begin|><|tool▁call▁begin|>function<|tool▁sep|>test_function\n```json\n{\"string_field\": \"hello\", \"int_field\": 42, \"float_field\": 3.14, \"bool_field\": true, \"null_field\": null, \"array_field\": [\"a\", \"b\", \"c\"], \"object_field\": {\"nested\": \"value\"}, \"empty_array\": [], \"empty_object\": {}}\n```<|tool▁call▁end|><|tool▁calls▁end|>", "output_token_ids": [128806, 128808, 8701, 128814, 7958, 64334, 201, 9854, 14479, 201, 24313, 4463, 55291, 3362, 582, 33310, 1760, 582, 650, 55291, 3362, 223, 3180, 14, 582, 15891, 55291, 3362, 223, 21, 16, 929, 14, 582, 20600, 55291, 3362, 3292, 14, 582, 16042, 55291, 3362, 5100, 14, 582, 7386, 55291, 3362, 20584, 67, 1760, 582, 68, 1760, 582, 69, 45390, 582, 10325, 55291, 3362, 28612, 80, 12904, 3362, 582, 5197, 87928, 582, 15566, 30549, 3362, 66517, 582, 15566, 55774, 3362, 26102, 1778, 9854, 128809, 128807], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V3-0324", "revision": "e9b33add76883f293d6bf61f6bd89b497e80e335", "mode": "hf"}, "generation_prompt": "<|Assistant|>", "thinking": false, "expected": {"content": null, "reasoning_content": null, "tool_calls": [{"name": "test_function", "arguments": {"string_field": "hello", "int_field": 42, "float_field": 3.14, "bool_field": true, "null_field": null, "array_field": ["a", "b", "c"], "object_field": {"nested": "value"}, "empty_array": [], "empty_object": {}}}]}, "tags": ["single-call", "numeric-arguments", "nested-json", "x-deepseek-v3"], "notes": "output_token_ids: tokenizer.encode(raw_output)."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V3-0324",
"model_rule": "DeepSeek-V3",
"model_type": "deepseek_v3",
"parser_source": "docs/formats/deepseek.md (V3: no reasoning)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "<|begin▁of▁sentence|><|User|>Use the tools to answer.<|Assistant|>",
"reasoning_parser": null,
"stop_token_in_final_delta": false,
"template": {
"sha256": "22e97ba043dacf9df1f071a9de9d2bb6b0757491f16e96e810834b86e1641286",
"source": "tokenizer chat template (HF repo)"
},
"tokenizer": {
"mode": "hf",
"repo": "deepseek-ai/DeepSeek-V3-0324",
"requested_mode": "auto",
"resolved_revision": "e9b33add76883f293d6bf61f6bd89b497e80e335",
"revision": "e9b33add76883f293d6bf61f6bd89b497e80e335",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v3",
"units_source": "fixture.output_token_ids"
}
fail deepseek/vllm-v31-text-before-call
expected_match, stream_equals_nonstream, split_invariance, arguments_json, arguments_schema
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_match | one | fail | content: expected 'normal text', got None; tool_calls: expected ['foo'], got [] |
expected_match | special | fail | content: expected 'normal text', got None; tool_calls: expected ['foo'], got [] |
expected_match | rand:1:8 | fail | tool_calls[0].arguments: expected '{"x": 1}', got '' |
expected_match | rand:2:8 | fail | tool_calls[0].arguments: expected '{"x": 1}', got '' |
expected_match | rand:3:8 | fail | content: expected 'normal text', got None; tool_calls[0].arguments: expected '{"x": 1}', got '' |
expected_match | rand:4:8 | fail | content: expected 'normal text', got None |
expected_match | rand:5:8 | fail | content: expected 'normal text', got None; tool_calls[0].arguments: expected '{"x": 1}', got '' |
stream_equals_nonstream | one | fail | content: nonstream 'normal text', got None; tool_calls: nonstream ['foo'], got [] |
stream_equals_nonstream | special | fail | content: nonstream 'normal text', got None; tool_calls: nonstream ['foo'], got [] |
stream_equals_nonstream | rand:1:8 | fail | tool_calls[0].arguments: nonstream '{"x":1}', got '' |
stream_equals_nonstream | rand:2:8 | fail | tool_calls[0].arguments: nonstream '{"x":1}', got '' |
stream_equals_nonstream | rand:3:8 | fail | content: nonstream 'normal text', got None; tool_calls[0].arguments: nonstream '{"x":1}', got '' |
stream_equals_nonstream | rand:4:8 | fail | content: nonstream 'normal text', got None |
stream_equals_nonstream | rand:5:8 | fail | content: nonstream 'normal text', got None; tool_calls[0].arguments: nonstream '{"x":1}', got '' |
split_invariance | * | fail | vs one: token (fail): content: one None, got 'normal text'; tool_calls: one [], got ['foo'] | rand:1:8 (fail): content: one None, got 'normal text'; tool_calls: one [], got ['foo'] | rand:2:8 (fail): content: one None, got 'normal text'; tool_calls: one [], got ['foo'] | rand:3:8 (fail): tool_calls: one [], got ['foo'] | rand:4:8 (fail): tool_calls: one [], got ['foo'] | rand:5:8 (fail): tool_calls: one [], got ['foo'] |
arguments_json | rand:1:8 | fail | [0] foo: arguments are not valid JSON text ('': Expecting value: line 1 column 1 (char 0)) |
arguments_json | rand:2:8 | fail | [0] foo: arguments are not valid JSON text ('': Expecting value: line 1 column 1 (char 0)) |
arguments_json | rand:3:8 | fail | [0] foo: arguments are not valid JSON text ('': Expecting value: line 1 column 1 (char 0)) |
arguments_json | rand:5:8 | fail | [0] foo: arguments are not valid JSON text ('': Expecting value: line 1 column 1 (char 0)) |
arguments_schema | rand:1:8 | fail | [0] foo: arguments are not a JSON object; not validated |
arguments_schema | rand:2:8 | fail | [0] foo: arguments are not a JSON object; not validated |
arguments_schema | rand:3:8 | fail | [0] foo: arguments are not a JSON object; not validated |
arguments_schema | rand:5:8 | fail | [0] foo: arguments are not a JSON object; not validated |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/engine-tests.jsonl --id deepseek/vllm-v31-text-before-call --strategy one --strategy rand:1:8 --strategy rand:2:8 --strategy rand:3:8 --strategy rand:4:8 --strategy rand:5:8 --strategy special --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 6 of fixtures/deepseek/engine-tests.jsonl.
Observed vs expected
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: one, special
@@ -1,12 +1,5 @@ { - "content": "normal text", + "content": null, "reasoning_content": null, - "tool_calls": [ - { - "arguments": { - "x": 1 - }, - "name": "foo" - } - ] + "tool_calls": [] }
Strategies: rand:1:8, rand:2:8
@@ -5,5 +5,5 @@ { "arguments": { - "x": 1 + "<arguments_raw, not valid JSON>": "" }, "name": "foo"
Strategies: rand:3:8, rand:5:8
@@ -1,9 +1,9 @@ { - "content": "normal text", + "content": null, "reasoning_content": null, "tool_calls": [ { "arguments": { - "x": 1 + "<arguments_raw, not valid JSON>": "" }, "name": "foo"
Strategies: rand:4:8
@@ -1,4 +1,4 @@ { - "content": "normal text", + "content": null, "reasoning_content": null, "tool_calls": [
Strategies: nonstream, token
Matches the expected parse.
{
"content": "normal text",
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"x": 1
},
"name": "foo"
}
]
}
Fixture
Provenance: engine_test, https://github.com/vllm-project/vllm/blob/ced6857afa0ea7b2e3f0846a62e1394e90f15607/tests/tool_parsers/test_deepseekv31_tool_parser.py#L25.
Tags: single-call, text-before-call, x-deepseek-v31.
Raw output
normal text<|tool▁calls▁begin|><|tool▁call▁begin|>foo<|tool▁sep|>{"x":1}<|tool▁call▁end|><|tool▁calls▁end|>
Expected parse
{
"content": "normal text",
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"x": 1
},
"name": "foo"
}
]
}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/vllm-v31-text-before-call", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V3.1", "deepseek-ai/DeepSeek-V3.1-Terminus"], "spec_version": "0.1", "provenance": {"kind": "engine_test", "source_url": "https://github.com/vllm-project/vllm/blob/ced6857afa0ea7b2e3f0846a62e1394e90f15607/tests/tool_parsers/test_deepseekv31_tool_parser.py#L25", "revision": "ced6857afa0ea7b2e3f0846a62e1394e90f15607", "license": "Apache-2.0", "attribution": "Copyright contributors to the vLLM project"}, "tools": [{"type": "function", "function": {"name": "foo", "parameters": {"type": "object", "properties": {"x": {"type": "integer"}}}}}], "raw_output": "normal text<|tool▁calls▁begin|><|tool▁call▁begin|>foo<|tool▁sep|>{\"x\":1}<|tool▁call▁end|><|tool▁calls▁end|>", "output_token_ids": [13644, 3051, 128806, 128808, 40897, 128814, 24313, 90, 3362, 19, 95, 128809, 128807], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V3.1", "revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db", "mode": "hf"}, "generation_prompt": "<|Assistant|></think>", "thinking": false, "expected": {"content": "normal text", "reasoning_content": null, "tool_calls": [{"name": "foo", "arguments": {"x": 1}}]}, "tags": ["single-call", "text-before-call", "x-deepseek-v31"], "notes": "output_token_ids: tokenizer.encode(raw_output)."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|></think>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V3.1",
"model_rule": "DeepSeek-V3\\.1",
"model_type": "deepseek_v3",
"parser_source": "docs/formats/deepseek.md (vLLM v0.30.0 row)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "<|begin▁of▁sentence|><|User|>Use the tools to answer.<|Assistant|></think>",
"reasoning_parser": "deepseek_v3",
"stop_token_in_final_delta": false,
"template": {
"sha256": "45690185067ea25c073bff2d3e425a45ee2564d2bbf6cdf7d885e139d460b8e0",
"source": "tokenizer chat template (HF repo)"
},
"tokenizer": {
"mode": "hf",
"repo": "deepseek-ai/DeepSeek-V3.1",
"requested_mode": "auto",
"resolved_revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db",
"revision": "c0781d039fb7a1ba2abc4add0bdc293e92d2b8db",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v31",
"units_source": "fixture.output_token_ids"
}
soft pass deepseek/sglang-v32-text-before-empty-invoke
expected_match
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_match | nonstream | soft pass | content (whitespace only): expected 'Let me get the current date for you.', got 'Let me get the current date for you.\n\n' |
expected_match | one | soft pass | content (whitespace only): expected 'Let me get the current date for you.', got 'Let me get the current date for you.\n\n' |
expected_match | special | soft pass | content (whitespace only): expected 'Let me get the current date for you.', got 'Let me get the current date for you.\n\n' |
expected_match | token | soft pass | content (whitespace only): expected 'Let me get the current date for you.', got 'Let me get the current date for you.\n\n' |
expected_match | rand:1:8 | soft pass | content (whitespace only): expected 'Let me get the current date for you.', got 'Let me get the current date for you.\n\n' |
expected_match | rand:2:8 | soft pass | content (whitespace only): expected 'Let me get the current date for you.', got 'Let me get the current date for you.\n\n' |
expected_match | rand:3:8 | soft pass | content (whitespace only): expected 'Let me get the current date for you.', got 'Let me get the current date for you.\n\n' |
expected_match | rand:4:8 | soft pass | content (whitespace only): expected 'Let me get the current date for you.', got 'Let me get the current date for you.\n\n' |
expected_match | rand:5:8 | soft pass | content (whitespace only): expected 'Let me get the current date for you.', got 'Let me get the current date for you.\n\n' |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/engine-tests.jsonl --id deepseek/sglang-v32-text-before-empty-invoke --strategy one --strategy rand:1:8 --strategy rand:2:8 --strategy rand:3:8 --strategy rand:4:8 --strategy rand:5:8 --strategy special --strategy token --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 9 of fixtures/deepseek/engine-tests.jsonl.
Observed vs expected
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: nonstream, one, special, token, rand:1:8, rand:2:8, rand:3:8, rand:4:8, rand:5:8
@@ -1,4 +1,4 @@ { - "content": "Let me get the current date for you.", + "content": "Let me get the current date for you.\n\n", "reasoning_content": null, "tool_calls": [
Fixture
Provenance: engine_test, https://github.com/sgl-project/sglang/blob/94602c9c2b7cbdb8efd5c52802dac6a1c180089e/test/registered/unit/function_call/test_function_call_parser.py#L1802.
Tags: single-call, text-before-call, empty-arguments, x-deepseek-v32.
Raw output
Let me get the current date for you. <|DSML|function_calls> <|DSML|invoke name="get_date"> </|DSML|invoke> </|DSML|function_calls>
Expected parse
{
"content": "Let me get the current date for you.",
"reasoning_content": null,
"tool_calls": [
{
"arguments": {},
"name": "get_date"
}
]
}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/sglang-v32-text-before-empty-invoke", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V3.2"], "spec_version": "0.1", "provenance": {"kind": "engine_test", "source_url": "https://github.com/sgl-project/sglang/blob/94602c9c2b7cbdb8efd5c52802dac6a1c180089e/test/registered/unit/function_call/test_function_call_parser.py#L1802", "revision": "94602c9c2b7cbdb8efd5c52802dac6a1c180089e", "license": "Apache-2.0", "attribution": "Copyright SGLang Team"}, "tools": [{"type": "function", "function": {"name": "get_date", "parameters": {"type": "object", "properties": {}}}}], "raw_output": "Let me get the current date for you.\n\n<|DSML|function_calls>\n<|DSML|invoke name=\"get_date\">\n</|DSML|invoke>\n</|DSML|function_calls>", "output_token_ids": [5718, 678, 1178, 270, 2573, 5045, 362, 440, 339, 30, 128793, 8701, 4941, 12548, 1018, 30, 128793, 40148, 5406, 2329, 1281, 1133, 22993, 3816, 1718, 128793, 40148, 5406, 1018, 1718, 128793, 8701, 4941, 12548, 32], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V3.2", "revision": "a7e62ac04ecb2c0a54d736dc46601c5606cf10a6", "mode": "hf"}, "generation_prompt": "<|Assistant|></think>", "thinking": false, "expected": {"content": "Let me get the current date for you.", "reasoning_content": null, "tool_calls": [{"name": "get_date", "arguments": {}}]}, "tags": ["single-call", "text-before-call", "empty-arguments", "x-deepseek-v32"], "notes": "An invoke with no parameter lines (the encoder itself renders an empty line between the tags). output_token_ids: tokenizer.encode(raw_output)."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|></think>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V3.2",
"model_rule": "DeepSeek-V3\\.2",
"model_type": "deepseek_v32",
"parser_source": "docs/formats/deepseek.md (vLLM v0.30.0 row)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "erties\": {}}}\n</functions>\n<|User|>Use the tools to answer.<|Assistant|></think>",
"reasoning_parser": "deepseek_v3",
"stop_token_in_final_delta": false,
"template": {
"sha256": "1bade67606d54952ae652a4f71f44065041ef0842ad1b5420ed82f8159502bc8",
"source": "vLLM tokenizer_mode=deepseek_v32 encoder (vllm.tokenizers.deepseek_v32_encoding)"
},
"tokenizer": {
"mode": "deepseek_v32",
"repo": "deepseek-ai/DeepSeek-V3.2",
"requested_mode": "auto",
"resolved_revision": "a7e62ac04ecb2c0a54d736dc46601c5606cf10a6",
"revision": "a7e62ac04ecb2c0a54d736dc46601c5606cf10a6",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v32",
"units_source": "fixture.output_token_ids"
}
soft pass deepseek/v32-reasoning-parallel-text-before
expected_match
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_match | nonstream | soft pass | content (whitespace only): expected "I'll look both up.", got "I'll look both up.\n\n" |
expected_match | one | soft pass | content (whitespace only): expected "I'll look both up.", got "I'll look both up.\n\n" |
expected_match | special | soft pass | content (whitespace only): expected "I'll look both up.", got "I'll look both up.\n\n" |
expected_match | token | soft pass | content (whitespace only): expected "I'll look both up.", got "I'll look both up.\n\n" |
expected_match | rand:1:8 | soft pass | content (whitespace only): expected "I'll look both up.", got "I'll look both up.\n\n" |
expected_match | rand:2:8 | soft pass | content (whitespace only): expected "I'll look both up.", got "I'll look both up.\n\n" |
expected_match | rand:3:8 | soft pass | content (whitespace only): expected "I'll look both up.", got "I'll look both up.\n\n" |
expected_match | rand:4:8 | soft pass | content (whitespace only): expected "I'll look both up.", got "I'll look both up.\n\n" |
expected_match | rand:5:8 | soft pass | content (whitespace only): expected "I'll look both up.", got "I'll look both up.\n\n" |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/v32.jsonl --id deepseek/v32-reasoning-parallel-text-before --strategy one --strategy rand:1:8 --strategy rand:2:8 --strategy rand:3:8 --strategy rand:4:8 --strategy rand:5:8 --strategy special --strategy token --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 11 of fixtures/deepseek/v32.jsonl.
Observed vs expected
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: nonstream, one, special, token, rand:1:8, rand:2:8, rand:3:8, rand:4:8, rand:5:8
@@ -1,4 +1,4 @@ { - "content": "I'll look both up.", + "content": "I'll look both up.\n\n", "reasoning_content": "Two independent lookups: weather and search.", "tool_calls": [
Fixture
Provenance: template_render, https://huggingface.co/deepseek-ai/DeepSeek-V3.2/blob/a7e62ac04ecb2c0a54d736dc46601c5606cf10a6/encoding/encoding_dsv32.py.
Tags: parallel-calls, reasoning, reasoning-prefilled, text-before-call, unicode, nested-json, string-escapes, x-deepseek-v32.
Raw output
Two independent lookups: weather and search.</think>I'll look both up.
<|DSML|function_calls>
<|DSML|invoke name="get_weather">
<|DSML|parameter name="city" string="true">Zürich</|DSML|parameter>
<|DSML|parameter name="unit" string="true">c</|DSML|parameter>
</|DSML|invoke>
<|DSML|invoke name="search">
<|DSML|parameter name="query" string="true">café "best"</|DSML|parameter>
<|DSML|parameter name="filters" string="false">{"tags": ["a", "b"], "max": 3}</|DSML|parameter>
</|DSML|invoke>
</|DSML|function_calls>
Expected parse
{
"content": "I'll look both up.",
"reasoning_content": "Two independent lookups: weather and search.",
"tool_calls": [
{
"arguments": {
"city": "Zürich",
"unit": "c"
},
"name": "get_weather"
},
{
"arguments": {
"filters": {
"max": 3,
"tags": [
"a",
"b"
]
},
"query": "café \"best\""
},
"name": "search"
}
]
}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/v32-reasoning-parallel-text-before", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V3.2"], "spec_version": "0.1", "provenance": {"kind": "template_render", "source_url": "https://huggingface.co/deepseek-ai/DeepSeek-V3.2/blob/a7e62ac04ecb2c0a54d736dc46601c5606cf10a6/encoding/encoding_dsv32.py", "revision": "a7e62ac04ecb2c0a54d736dc46601c5606cf10a6", "license": "MIT", "generator": "scripts/fixtures/deepseek/build.py", "template_sha256": "5e068c2ba2a6e5ebe37a49bb005650c507e7935d77a32f3f7c11ee071498b370", "attribution": "Copyright (c) 2023 DeepSeek"}, "tools": [{"type": "function", "function": {"name": "get_weather", "description": "Get the current weather for a city.", "parameters": {"type": "object", "properties": {"city": {"type": "string"}, "unit": {"type": "string", "enum": ["c", "f"]}}, "required": ["city"]}}}, {"type": "function", "function": {"name": "search", "description": "Search the web.", "parameters": {"type": "object", "properties": {"query": {"type": "string"}, "filters": {"type": "object"}}, "required": ["query"]}}}], "raw_output": "Two independent lookups: weather and search.</think>I'll look both up.\n\n<|DSML|function_calls>\n<|DSML|invoke name=\"get_weather\">\n<|DSML|parameter name=\"city\" string=\"true\">Zürich</|DSML|parameter>\n<|DSML|parameter name=\"unit\" string=\"true\">c</|DSML|parameter>\n</|DSML|invoke>\n<|DSML|invoke name=\"search\">\n<|DSML|parameter name=\"query\" string=\"true\">café \"best\"</|DSML|parameter>\n<|DSML|parameter name=\"filters\" string=\"false\">{\"tags\": [\"a\", \"b\"], \"max\": 3}</|DSML|parameter>\n</|DSML|invoke>\n</|DSML|function_calls>", "output_token_ids": [14959, 8181, 1747, 13953, 28, 9670, 305, 5351, 16, 128799, 43, 5922, 1747, 1952, 890, 339, 30, 128793, 8701, 4941, 12548, 1018, 30, 128793, 40148, 5406, 2329, 1281, 1133, 65, 50219, 3816, 30, 128793, 41523, 2329, 1281, 37399, 4, 3418, 1281, 11476, 3320, 60, 5421, 616, 1718, 128793, 41523, 1018, 30, 128793, 41523, 2329, 1281, 15165, 4, 3418, 1281, 11476, 3320, 69, 1718, 128793, 41523, 1018, 1718, 128793, 40148, 5406, 1018, 30, 128793, 40148, 5406, 2329, 1281, 14346, 3816, 30, 128793, 41523, 2329, 1281, 12066, 4, 3418, 1281, 11476, 3320, 69, 2797, 619, 582, 21910, 4, 1718, 128793, 41523, 1018, 30, 128793, 41523, 2329, 1281, 72, 40332, 4, 3418, 1281, 19836, 3320, 24313, 44175, 3362, 20584, 67, 1760, 582, 68, 45390, 582, 9047, 3362, 223, 21, 24568, 128793, 41523, 1018, 1718, 128793, 40148, 5406, 1018, 1718, 128793, 8701, 4941, 12548, 32], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V3.2", "revision": "a7e62ac04ecb2c0a54d736dc46601c5606cf10a6", "mode": "hf"}, "generation_prompt": "<|Assistant|><think>", "thinking": true, "expected": {"content": "I'll look both up.", "reasoning_content": "Two independent lookups: weather and search.", "tool_calls": [{"name": "get_weather", "arguments": {"city": "Zürich", "unit": "c"}}, {"name": "search", "arguments": {"query": "café \"best\"", "filters": {"tags": ["a", "b"], "max": 3}}}]}, "tags": ["parallel-calls", "reasoning", "reasoning-prefilled", "text-before-call", "unicode", "nested-json", "string-escapes", "x-deepseek-v32"], "notes": "expected == DeepSeek's reference parse_message_from_completion_text on this output. Sub-format deepseek-v32; history render of the official encoder."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": true,
"thinking": true
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|><think>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V3.2",
"model_rule": "DeepSeek-V3\\.2",
"model_type": "deepseek_v32",
"parser_source": "docs/formats/deepseek.md (vLLM v0.30.0 row)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "\": [\"query\"]}}\n</functions>\n<|User|>Use the tools to answer.<|Assistant|><think>",
"reasoning_parser": "deepseek_v3",
"stop_token_in_final_delta": false,
"template": {
"sha256": "1bade67606d54952ae652a4f71f44065041ef0842ad1b5420ed82f8159502bc8",
"source": "vLLM tokenizer_mode=deepseek_v32 encoder (vllm.tokenizers.deepseek_v32_encoding)"
},
"tokenizer": {
"mode": "deepseek_v32",
"repo": "deepseek-ai/DeepSeek-V3.2",
"requested_mode": "auto",
"resolved_revision": "a7e62ac04ecb2c0a54d736dc46601c5606cf10a6",
"revision": "a7e62ac04ecb2c0a54d736dc46601c5606cf10a6",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v32",
"units_source": "fixture.output_token_ids"
}
soft pass deepseek/v32-text-before-call
expected_match
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_match | nonstream | soft pass | content (whitespace only): expected 'Let me check the current conditions in London.', got 'Let me check the current conditions in London.\n\n' |
expected_match | one | soft pass | content (whitespace only): expected 'Let me check the current conditions in London.', got 'Let me check the current conditions in London.\n\n' |
expected_match | special | soft pass | content (whitespace only): expected 'Let me check the current conditions in London.', got 'Let me check the current conditions in London.\n\n' |
expected_match | token | soft pass | content (whitespace only): expected 'Let me check the current conditions in London.', got 'Let me check the current conditions in London.\n\n' |
expected_match | rand:1:8 | soft pass | content (whitespace only): expected 'Let me check the current conditions in London.', got 'Let me check the current conditions in London.\n\n' |
expected_match | rand:2:8 | soft pass | content (whitespace only): expected 'Let me check the current conditions in London.', got 'Let me check the current conditions in London.\n\n' |
expected_match | rand:3:8 | soft pass | content (whitespace only): expected 'Let me check the current conditions in London.', got 'Let me check the current conditions in London.\n\n' |
expected_match | rand:4:8 | soft pass | content (whitespace only): expected 'Let me check the current conditions in London.', got 'Let me check the current conditions in London.\n\n' |
expected_match | rand:5:8 | soft pass | content (whitespace only): expected 'Let me check the current conditions in London.', got 'Let me check the current conditions in London.\n\n' |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/v32.jsonl --id deepseek/v32-text-before-call --strategy one --strategy rand:1:8 --strategy rand:2:8 --strategy rand:3:8 --strategy rand:4:8 --strategy rand:5:8 --strategy special --strategy token --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 4 of fixtures/deepseek/v32.jsonl.
Observed vs expected
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: nonstream, one, special, token, rand:1:8, rand:2:8, rand:3:8, rand:4:8, rand:5:8
@@ -1,4 +1,4 @@ { - "content": "Let me check the current conditions in London.", + "content": "Let me check the current conditions in London.\n\n", "reasoning_content": null, "tool_calls": [
Fixture
Provenance: template_render, https://huggingface.co/deepseek-ai/DeepSeek-V3.2/blob/a7e62ac04ecb2c0a54d736dc46601c5606cf10a6/encoding/encoding_dsv32.py.
Tags: single-call, text-before-call, x-deepseek-v32.
Raw output
Let me check the current conditions in London. <|DSML|function_calls> <|DSML|invoke name="get_weather"> <|DSML|parameter name="city" string="true">London</|DSML|parameter> </|DSML|invoke> </|DSML|function_calls>
Expected parse
{
"content": "Let me check the current conditions in London.",
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"city": "London"
},
"name": "get_weather"
}
]
}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/v32-text-before-call", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V3.2"], "spec_version": "0.1", "provenance": {"kind": "template_render", "source_url": "https://huggingface.co/deepseek-ai/DeepSeek-V3.2/blob/a7e62ac04ecb2c0a54d736dc46601c5606cf10a6/encoding/encoding_dsv32.py", "revision": "a7e62ac04ecb2c0a54d736dc46601c5606cf10a6", "license": "MIT", "generator": "scripts/fixtures/deepseek/build.py", "template_sha256": "5e068c2ba2a6e5ebe37a49bb005650c507e7935d77a32f3f7c11ee071498b370", "attribution": "Copyright (c) 2023 DeepSeek"}, "tools": [{"type": "function", "function": {"name": "get_weather", "description": "Get the current weather for a city.", "parameters": {"type": "object", "properties": {"city": {"type": "string"}, "unit": {"type": "string", "enum": ["c", "f"]}}, "required": ["city"]}}}], "raw_output": "Let me check the current conditions in London.\n\n<|DSML|function_calls>\n<|DSML|invoke name=\"get_weather\">\n<|DSML|parameter name=\"city\" string=\"true\">London</|DSML|parameter>\n</|DSML|invoke>\n</|DSML|function_calls>", "output_token_ids": [5718, 678, 4085, 270, 2573, 4132, 295, 6693, 339, 30, 128793, 8701, 4941, 12548, 1018, 30, 128793, 40148, 5406, 2329, 1281, 1133, 65, 50219, 3816, 30, 128793, 41523, 2329, 1281, 37399, 4, 3418, 1281, 11476, 3320, 27571, 1718, 128793, 41523, 1018, 1718, 128793, 40148, 5406, 1018, 1718, 128793, 8701, 4941, 12548, 32], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V3.2", "revision": "a7e62ac04ecb2c0a54d736dc46601c5606cf10a6", "mode": "hf"}, "generation_prompt": "<|Assistant|></think>", "thinking": false, "expected": {"content": "Let me check the current conditions in London.", "reasoning_content": null, "tool_calls": [{"name": "get_weather", "arguments": {"city": "London"}}]}, "tags": ["single-call", "text-before-call", "x-deepseek-v32"], "notes": "expected == DeepSeek's reference parse_message_from_completion_text on this output. Sub-format deepseek-v32; history render of the official encoder."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|></think>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V3.2",
"model_rule": "DeepSeek-V3\\.2",
"model_type": "deepseek_v32",
"parser_source": "docs/formats/deepseek.md (vLLM v0.30.0 row)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": ": [\"query\"]}}\n</functions>\n<|User|>Use the tools to answer.<|Assistant|></think>",
"reasoning_parser": "deepseek_v3",
"stop_token_in_final_delta": false,
"template": {
"sha256": "1bade67606d54952ae652a4f71f44065041ef0842ad1b5420ed82f8159502bc8",
"source": "vLLM tokenizer_mode=deepseek_v32 encoder (vllm.tokenizers.deepseek_v32_encoding)"
},
"tokenizer": {
"mode": "deepseek_v32",
"repo": "deepseek-ai/DeepSeek-V3.2",
"requested_mode": "auto",
"resolved_revision": "a7e62ac04ecb2c0a54d736dc46601c5606cf10a6",
"revision": "a7e62ac04ecb2c0a54d736dc46601c5606cf10a6",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v32",
"units_source": "fixture.output_token_ids"
}
soft pass deepseek/v4-reasoning-parallel-text-before
expected_match
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_match | nonstream | soft pass | content (whitespace only): expected "I'll look both up.", got "I'll look both up.\n\n" |
expected_match | one | soft pass | content (whitespace only): expected "I'll look both up.", got "I'll look both up.\n\n" |
expected_match | special | soft pass | content (whitespace only): expected "I'll look both up.", got "I'll look both up.\n\n" |
expected_match | token | soft pass | content (whitespace only): expected "I'll look both up.", got "I'll look both up.\n\n" |
expected_match | rand:1:8 | soft pass | content (whitespace only): expected "I'll look both up.", got "I'll look both up.\n\n" |
expected_match | rand:2:8 | soft pass | content (whitespace only): expected "I'll look both up.", got "I'll look both up.\n\n" |
expected_match | rand:3:8 | soft pass | content (whitespace only): expected "I'll look both up.", got "I'll look both up.\n\n" |
expected_match | rand:4:8 | soft pass | content (whitespace only): expected "I'll look both up.", got "I'll look both up.\n\n" |
expected_match | rand:5:8 | soft pass | content (whitespace only): expected "I'll look both up.", got "I'll look both up.\n\n" |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/v4.jsonl --id deepseek/v4-reasoning-parallel-text-before --strategy one --strategy rand:1:8 --strategy rand:2:8 --strategy rand:3:8 --strategy rand:4:8 --strategy rand:5:8 --strategy special --strategy token --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 12 of fixtures/deepseek/v4.jsonl.
Observed vs expected
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: nonstream, one, special, token, rand:1:8, rand:2:8, rand:3:8, rand:4:8, rand:5:8
@@ -1,4 +1,4 @@ { - "content": "I'll look both up.", + "content": "I'll look both up.\n\n", "reasoning_content": "Two independent lookups: weather and search.", "tool_calls": [
Fixture
Provenance: template_render, https://huggingface.co/deepseek-ai/DeepSeek-V4-Flash/blob/60d8d70770c6776ff598c94bb586a859a38244f1/encoding/encoding_dsv4.py.
Tags: parallel-calls, reasoning, reasoning-prefilled, text-before-call, unicode, nested-json, string-escapes, x-deepseek-v4.
Raw output
Two independent lookups: weather and search.</think>I'll look both up.
<|DSML|tool_calls>
<|DSML|invoke name="get_weather">
<|DSML|parameter name="city" string="true">Zürich</|DSML|parameter>
<|DSML|parameter name="unit" string="true">c</|DSML|parameter>
</|DSML|invoke>
<|DSML|invoke name="search">
<|DSML|parameter name="query" string="true">café "best"</|DSML|parameter>
<|DSML|parameter name="filters" string="false">{"tags": ["a", "b"], "max": 3}</|DSML|parameter>
</|DSML|invoke>
</|DSML|tool_calls>
Expected parse
{
"content": "I'll look both up.",
"reasoning_content": "Two independent lookups: weather and search.",
"tool_calls": [
{
"arguments": {
"city": "Zürich",
"unit": "c"
},
"name": "get_weather"
},
{
"arguments": {
"filters": {
"max": 3,
"tags": [
"a",
"b"
]
},
"query": "café \"best\""
},
"name": "search"
}
]
}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/v4-reasoning-parallel-text-before", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V4-Flash", "deepseek-ai/DeepSeek-V4-Pro"], "spec_version": "0.1", "provenance": {"kind": "template_render", "source_url": "https://huggingface.co/deepseek-ai/DeepSeek-V4-Flash/blob/60d8d70770c6776ff598c94bb586a859a38244f1/encoding/encoding_dsv4.py", "revision": "60d8d70770c6776ff598c94bb586a859a38244f1", "license": "MIT", "generator": "scripts/fixtures/deepseek/build.py", "template_sha256": "bdbd57c132a1b3725042323d02b98b9d1df28e5f388f134399555d041f5055e0", "attribution": "Copyright (c) 2023 DeepSeek"}, "tools": [{"type": "function", "function": {"name": "get_weather", "description": "Get the current weather for a city.", "parameters": {"type": "object", "properties": {"city": {"type": "string"}, "unit": {"type": "string", "enum": ["c", "f"]}}, "required": ["city"]}}}, {"type": "function", "function": {"name": "search", "description": "Search the web.", "parameters": {"type": "object", "properties": {"query": {"type": "string"}, "filters": {"type": "object"}}, "required": ["query"]}}}], "raw_output": "Two independent lookups: weather and search.</think>I'll look both up.\n\n<|DSML|tool_calls>\n<|DSML|invoke name=\"get_weather\">\n<|DSML|parameter name=\"city\" string=\"true\">Zürich</|DSML|parameter>\n<|DSML|parameter name=\"unit\" string=\"true\">c</|DSML|parameter>\n</|DSML|invoke>\n<|DSML|invoke name=\"search\">\n<|DSML|parameter name=\"query\" string=\"true\">café \"best\"</|DSML|parameter>\n<|DSML|parameter name=\"filters\" string=\"false\">{\"tags\": [\"a\", \"b\"], \"max\": 3}</|DSML|parameter>\n</|DSML|invoke>\n</|DSML|tool_calls>", "output_token_ids": [14959, 8181, 1747, 13953, 28, 9670, 305, 5351, 16, 128822, 43, 5922, 1747, 1952, 890, 339, 30, 128825, 72461, 4941, 12548, 1018, 30, 128825, 40148, 5406, 2329, 1281, 1133, 65, 50219, 3816, 30, 128825, 41523, 2329, 1281, 37399, 4, 3418, 1281, 11476, 3320, 60, 5421, 616, 1718, 128825, 41523, 1018, 30, 128825, 41523, 2329, 1281, 15165, 4, 3418, 1281, 11476, 3320, 69, 1718, 128825, 41523, 1018, 1718, 128825, 40148, 5406, 1018, 30, 128825, 40148, 5406, 2329, 1281, 14346, 3816, 30, 128825, 41523, 2329, 1281, 12066, 4, 3418, 1281, 11476, 3320, 69, 2797, 619, 582, 21910, 4, 1718, 128825, 41523, 1018, 30, 128825, 41523, 2329, 1281, 72, 40332, 4, 3418, 1281, 19836, 3320, 24313, 44175, 3362, 20584, 67, 1760, 582, 68, 45390, 582, 9047, 3362, 223, 21, 24568, 128825, 41523, 1018, 1718, 128825, 40148, 5406, 1018, 1718, 128825, 72461, 4941, 12548, 32], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V4-Flash", "revision": "60d8d70770c6776ff598c94bb586a859a38244f1", "mode": "hf"}, "generation_prompt": "<|Assistant|><think>", "thinking": true, "expected": {"content": "I'll look both up.", "reasoning_content": "Two independent lookups: weather and search.", "tool_calls": [{"name": "get_weather", "arguments": {"city": "Zürich", "unit": "c"}}, {"name": "search", "arguments": {"query": "café \"best\"", "filters": {"tags": ["a", "b"], "max": 3}}}]}, "tags": ["parallel-calls", "reasoning", "reasoning-prefilled", "text-before-call", "unicode", "nested-json", "string-escapes", "x-deepseek-v4"], "notes": "expected == DeepSeek's reference parse_message_from_completion_text on this output. Sub-format deepseek-v4; history render of the official encoder."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": true,
"thinking": true
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|><think>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V4-Flash",
"model_rule": "DeepSeek-V4",
"model_type": "deepseek_v4",
"parser_source": "docs/formats/deepseek.md (vLLM v0.30.0 row)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "hemas to invoke tool calls.\n<|User|>Use the tools to answer.<|Assistant|><think>",
"reasoning_parser": "deepseek_v4",
"stop_token_in_final_delta": false,
"template": {
"sha256": "bfbb51e563b89c7d3581864cd0ea4d975b96e14fed034a222caf9d50c549b99d",
"source": "vLLM tokenizer_mode=deepseek_v4 encoder (vllm.tokenizers.deepseek_v4_encoding)"
},
"tokenizer": {
"mode": "deepseek_v4",
"repo": "deepseek-ai/DeepSeek-V4-Flash",
"requested_mode": "auto",
"resolved_revision": "60d8d70770c6776ff598c94bb586a859a38244f1",
"revision": "60d8d70770c6776ff598c94bb586a859a38244f1",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v4",
"units_source": "fixture.output_token_ids"
}
soft pass deepseek/v4-text-before-call
expected_match
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_match | nonstream | soft pass | content (whitespace only): expected 'Let me check the current conditions in London.', got 'Let me check the current conditions in London.\n\n' |
expected_match | one | soft pass | content (whitespace only): expected 'Let me check the current conditions in London.', got 'Let me check the current conditions in London.\n\n' |
expected_match | special | soft pass | content (whitespace only): expected 'Let me check the current conditions in London.', got 'Let me check the current conditions in London.\n\n' |
expected_match | token | soft pass | content (whitespace only): expected 'Let me check the current conditions in London.', got 'Let me check the current conditions in London.\n\n' |
expected_match | rand:1:8 | soft pass | content (whitespace only): expected 'Let me check the current conditions in London.', got 'Let me check the current conditions in London.\n\n' |
expected_match | rand:2:8 | soft pass | content (whitespace only): expected 'Let me check the current conditions in London.', got 'Let me check the current conditions in London.\n\n' |
expected_match | rand:3:8 | soft pass | content (whitespace only): expected 'Let me check the current conditions in London.', got 'Let me check the current conditions in London.\n\n' |
expected_match | rand:4:8 | soft pass | content (whitespace only): expected 'Let me check the current conditions in London.', got 'Let me check the current conditions in London.\n\n' |
expected_match | rand:5:8 | soft pass | content (whitespace only): expected 'Let me check the current conditions in London.', got 'Let me check the current conditions in London.\n\n' |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/v4.jsonl --id deepseek/v4-text-before-call --strategy one --strategy rand:1:8 --strategy rand:2:8 --strategy rand:3:8 --strategy rand:4:8 --strategy rand:5:8 --strategy special --strategy token --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 4 of fixtures/deepseek/v4.jsonl.
Observed vs expected
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: nonstream, one, special, token, rand:1:8, rand:2:8, rand:3:8, rand:4:8, rand:5:8
@@ -1,4 +1,4 @@ { - "content": "Let me check the current conditions in London.", + "content": "Let me check the current conditions in London.\n\n", "reasoning_content": null, "tool_calls": [
Fixture
Provenance: template_render, https://huggingface.co/deepseek-ai/DeepSeek-V4-Flash/blob/60d8d70770c6776ff598c94bb586a859a38244f1/encoding/encoding_dsv4.py.
Tags: single-call, text-before-call, x-deepseek-v4.
Raw output
Let me check the current conditions in London. <|DSML|tool_calls> <|DSML|invoke name="get_weather"> <|DSML|parameter name="city" string="true">London</|DSML|parameter> </|DSML|invoke> </|DSML|tool_calls>
Expected parse
{
"content": "Let me check the current conditions in London.",
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"city": "London"
},
"name": "get_weather"
}
]
}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/v4-text-before-call", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V4-Flash", "deepseek-ai/DeepSeek-V4-Pro"], "spec_version": "0.1", "provenance": {"kind": "template_render", "source_url": "https://huggingface.co/deepseek-ai/DeepSeek-V4-Flash/blob/60d8d70770c6776ff598c94bb586a859a38244f1/encoding/encoding_dsv4.py", "revision": "60d8d70770c6776ff598c94bb586a859a38244f1", "license": "MIT", "generator": "scripts/fixtures/deepseek/build.py", "template_sha256": "bdbd57c132a1b3725042323d02b98b9d1df28e5f388f134399555d041f5055e0", "attribution": "Copyright (c) 2023 DeepSeek"}, "tools": [{"type": "function", "function": {"name": "get_weather", "description": "Get the current weather for a city.", "parameters": {"type": "object", "properties": {"city": {"type": "string"}, "unit": {"type": "string", "enum": ["c", "f"]}}, "required": ["city"]}}}], "raw_output": "Let me check the current conditions in London.\n\n<|DSML|tool_calls>\n<|DSML|invoke name=\"get_weather\">\n<|DSML|parameter name=\"city\" string=\"true\">London</|DSML|parameter>\n</|DSML|invoke>\n</|DSML|tool_calls>", "output_token_ids": [5718, 678, 4085, 270, 2573, 4132, 295, 6693, 339, 30, 128825, 72461, 4941, 12548, 1018, 30, 128825, 40148, 5406, 2329, 1281, 1133, 65, 50219, 3816, 30, 128825, 41523, 2329, 1281, 37399, 4, 3418, 1281, 11476, 3320, 27571, 1718, 128825, 41523, 1018, 1718, 128825, 40148, 5406, 1018, 1718, 128825, 72461, 4941, 12548, 32], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V4-Flash", "revision": "60d8d70770c6776ff598c94bb586a859a38244f1", "mode": "hf"}, "generation_prompt": "<|Assistant|></think>", "thinking": false, "expected": {"content": "Let me check the current conditions in London.", "reasoning_content": null, "tool_calls": [{"name": "get_weather", "arguments": {"city": "London"}}]}, "tags": ["single-call", "text-before-call", "x-deepseek-v4"], "notes": "expected == DeepSeek's reference parse_message_from_completion_text on this output. Sub-format deepseek-v4; history render of the official encoder."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|></think>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V4-Flash",
"model_rule": "DeepSeek-V4",
"model_type": "deepseek_v4",
"parser_source": "docs/formats/deepseek.md (vLLM v0.30.0 row)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "emas to invoke tool calls.\n<|User|>Use the tools to answer.<|Assistant|></think>",
"reasoning_parser": "deepseek_v4",
"stop_token_in_final_delta": false,
"template": {
"sha256": "bfbb51e563b89c7d3581864cd0ea4d975b96e14fed034a222caf9d50c549b99d",
"source": "vLLM tokenizer_mode=deepseek_v4 encoder (vllm.tokenizers.deepseek_v4_encoding)"
},
"tokenizer": {
"mode": "deepseek_v4",
"repo": "deepseek-ai/DeepSeek-V4-Flash",
"requested_mode": "auto",
"resolved_revision": "60d8d70770c6776ff598c94bb586a859a38244f1",
"revision": "60d8d70770c6776ff598c94bb586a859a38244f1",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v4",
"units_source": "fixture.output_token_ids"
}
soft pass deepseek/v41-reasoning-parallel-text-before
expected_match
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_match | nonstream | soft pass | content (whitespace only): expected "I'll look both up.", got "I'll look both up.\n\n" |
expected_match | one | soft pass | content (whitespace only): expected "I'll look both up.", got "I'll look both up.\n\n" |
expected_match | special | soft pass | content (whitespace only): expected "I'll look both up.", got "I'll look both up.\n\n" |
expected_match | token | soft pass | content (whitespace only): expected "I'll look both up.", got "I'll look both up.\n\n" |
expected_match | rand:1:8 | soft pass | content (whitespace only): expected "I'll look both up.", got "I'll look both up.\n\n" |
expected_match | rand:2:8 | soft pass | content (whitespace only): expected "I'll look both up.", got "I'll look both up.\n\n" |
expected_match | rand:3:8 | soft pass | content (whitespace only): expected "I'll look both up.", got "I'll look both up.\n\n" |
expected_match | rand:4:8 | soft pass | content (whitespace only): expected "I'll look both up.", got "I'll look both up.\n\n" |
expected_match | rand:5:8 | soft pass | content (whitespace only): expected "I'll look both up.", got "I'll look both up.\n\n" |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/v41.jsonl --id deepseek/v41-reasoning-parallel-text-before --strategy one --strategy rand:1:8 --strategy rand:2:8 --strategy rand:3:8 --strategy rand:4:8 --strategy rand:5:8 --strategy special --strategy token --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 12 of fixtures/deepseek/v41.jsonl.
Observed vs expected
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: nonstream, one, special, token, rand:1:8, rand:2:8, rand:3:8, rand:4:8, rand:5:8
@@ -1,4 +1,4 @@ { - "content": "I'll look both up.", + "content": "I'll look both up.\n\n", "reasoning_content": "Two independent lookups: weather and search.", "tool_calls": [
Fixture
Provenance: template_render, https://huggingface.co/deepseek-ai/DeepSeek-V4.1-Flash/blob/dba1be0a40aa45a94ad051997016db3960a90277/encoding/encoding.py.
Tags: parallel-calls, reasoning, reasoning-prefilled, text-before-call, unicode, nested-json, string-escapes, x-deepseek-v41.
Raw output
Two independent lookups: weather and search.</think>I'll look both up.
<|DSML| calls>
<|DSML| invoke name="get_weather">
<|DSML| parameter name="city" string="true">Zürich</|DSML| parameter>
<|DSML| parameter name="unit" string="true">c</|DSML| parameter>
</|DSML| invoke>
<|DSML| invoke name="search">
<|DSML| parameter name="query" string="true">café "best"</|DSML| parameter>
<|DSML| parameter name="filters" string="false">{"tags": ["a", "b"], "max": 3}</|DSML| parameter>
</|DSML| invoke>
</|DSML| calls>
Expected parse
{
"content": "I'll look both up.",
"reasoning_content": "Two independent lookups: weather and search.",
"tool_calls": [
{
"arguments": {
"city": "Zürich",
"unit": "c"
},
"name": "get_weather"
},
{
"arguments": {
"filters": {
"max": 3,
"tags": [
"a",
"b"
]
},
"query": "café \"best\""
},
"name": "search"
}
]
}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/v41-reasoning-parallel-text-before", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V4.1-Flash"], "spec_version": "0.1", "provenance": {"kind": "template_render", "source_url": "https://huggingface.co/deepseek-ai/DeepSeek-V4.1-Flash/blob/dba1be0a40aa45a94ad051997016db3960a90277/encoding/encoding.py", "revision": "dba1be0a40aa45a94ad051997016db3960a90277", "license": "MIT", "generator": "scripts/fixtures/deepseek/build.py", "template_sha256": "502bdaec8a3fd88ebc24c4721a7038fbe42f2063c664638127056107920035c1", "attribution": "Copyright (c) 2023 DeepSeek"}, "tools": [{"type": "function", "function": {"name": "get_weather", "description": "Get the current weather for a city.", "parameters": {"type": "object", "properties": {"city": {"type": "string"}, "unit": {"type": "string", "enum": ["c", "f"]}}, "required": ["city"]}}}, {"type": "function", "function": {"name": "search", "description": "Search the web.", "parameters": {"type": "object", "properties": {"query": {"type": "string"}, "filters": {"type": "object"}}, "required": ["query"]}}}], "raw_output": "Two independent lookups: weather and search.</think>I'll look both up.\n\n<|DSML| calls>\n<|DSML| invoke name=\"get_weather\">\n<|DSML| parameter name=\"city\" string=\"true\">Zürich</|DSML| parameter>\n<|DSML| parameter name=\"unit\" string=\"true\">c</|DSML| parameter>\n</|DSML| invoke>\n<|DSML| invoke name=\"search\">\n<|DSML| parameter name=\"query\" string=\"true\">café \"best\"</|DSML| parameter>\n<|DSML| parameter name=\"filters\" string=\"false\">{\"tags\": [\"a\", \"b\"], \"max\": 3}</|DSML| parameter>\n</|DSML| invoke>\n</|DSML| calls>", "output_token_ids": [14959, 8181, 1747, 13953, 28, 9670, 305, 5351, 16, 128822, 43, 5922, 1747, 1952, 890, 339, 30, 128825, 10699, 1018, 30, 128825, 34756, 2329, 1281, 1133, 65, 50219, 3816, 30, 128825, 10767, 2329, 1281, 37399, 4, 3418, 1281, 11476, 3320, 60, 5421, 616, 1718, 128825, 10767, 1018, 30, 128825, 10767, 2329, 1281, 15165, 4, 3418, 1281, 11476, 3320, 69, 1718, 128825, 10767, 1018, 1718, 128825, 34756, 1018, 30, 128825, 34756, 2329, 1281, 14346, 3816, 30, 128825, 10767, 2329, 1281, 12066, 4, 3418, 1281, 11476, 3320, 69, 2797, 619, 582, 21910, 4, 1718, 128825, 10767, 1018, 30, 128825, 10767, 2329, 1281, 72, 40332, 4, 3418, 1281, 19836, 3320, 24313, 44175, 3362, 20584, 67, 1760, 582, 68, 45390, 582, 9047, 3362, 223, 21, 24568, 128825, 10767, 1018, 1718, 128825, 34756, 1018, 1718, 128825, 10699, 32], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V4.1-Flash", "revision": "dba1be0a40aa45a94ad051997016db3960a90277", "mode": "hf"}, "generation_prompt": "<|Assistant|><think>", "thinking": true, "expected": {"content": "I'll look both up.", "reasoning_content": "Two independent lookups: weather and search.", "tool_calls": [{"name": "get_weather", "arguments": {"city": "Zürich", "unit": "c"}}, {"name": "search", "arguments": {"query": "café \"best\"", "filters": {"tags": ["a", "b"], "max": 3}}}]}, "tags": ["parallel-calls", "reasoning", "reasoning-prefilled", "text-before-call", "unicode", "nested-json", "string-escapes", "x-deepseek-v41"], "notes": "expected == DeepSeek's reference parse_message_from_completion_text on this output. Sub-format deepseek-v41; history render of the official encoder."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": true,
"thinking": true
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|><think>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V4.1-Flash",
"model_rule": "DeepSeek-V4\\.1",
"model_type": "deepseek_v41",
"parser_source": "docs/formats/deepseek.md (vLLM v0.30.0 row)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "hemas to invoke tool calls.\n<|User|>Use the tools to answer.<|Assistant|><think>",
"reasoning_parser": "deepseek_v41",
"stop_token_in_final_delta": false,
"template": {
"sha256": "081382cb953a1c8041fdfc82a6001cf0c932553171436625c89fe5b9fbcda464",
"source": "vLLM tokenizer_mode=deepseek_v41 encoder (vllm.tokenizers.deepseek_v41_encoding)"
},
"tokenizer": {
"mode": "deepseek_v41",
"repo": "deepseek-ai/DeepSeek-V4.1-Flash",
"requested_mode": "auto",
"resolved_revision": "dba1be0a40aa45a94ad051997016db3960a90277",
"revision": "dba1be0a40aa45a94ad051997016db3960a90277",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v41",
"units_source": "fixture.output_token_ids"
}
soft pass deepseek/v41-text-before-call
expected_match
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_match | nonstream | soft pass | content (whitespace only): expected 'Let me check the current conditions in London.', got 'Let me check the current conditions in London.\n\n' |
expected_match | one | soft pass | content (whitespace only): expected 'Let me check the current conditions in London.', got 'Let me check the current conditions in London.\n\n' |
expected_match | special | soft pass | content (whitespace only): expected 'Let me check the current conditions in London.', got 'Let me check the current conditions in London.\n\n' |
expected_match | token | soft pass | content (whitespace only): expected 'Let me check the current conditions in London.', got 'Let me check the current conditions in London.\n\n' |
expected_match | rand:1:8 | soft pass | content (whitespace only): expected 'Let me check the current conditions in London.', got 'Let me check the current conditions in London.\n\n' |
expected_match | rand:2:8 | soft pass | content (whitespace only): expected 'Let me check the current conditions in London.', got 'Let me check the current conditions in London.\n\n' |
expected_match | rand:3:8 | soft pass | content (whitespace only): expected 'Let me check the current conditions in London.', got 'Let me check the current conditions in London.\n\n' |
expected_match | rand:4:8 | soft pass | content (whitespace only): expected 'Let me check the current conditions in London.', got 'Let me check the current conditions in London.\n\n' |
expected_match | rand:5:8 | soft pass | content (whitespace only): expected 'Let me check the current conditions in London.', got 'Let me check the current conditions in London.\n\n' |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/v41.jsonl --id deepseek/v41-text-before-call --strategy one --strategy rand:1:8 --strategy rand:2:8 --strategy rand:3:8 --strategy rand:4:8 --strategy rand:5:8 --strategy special --strategy token --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 4 of fixtures/deepseek/v41.jsonl.
Observed vs expected
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: nonstream, one, special, token, rand:1:8, rand:2:8, rand:3:8, rand:4:8, rand:5:8
@@ -1,4 +1,4 @@ { - "content": "Let me check the current conditions in London.", + "content": "Let me check the current conditions in London.\n\n", "reasoning_content": null, "tool_calls": [
Fixture
Provenance: template_render, https://huggingface.co/deepseek-ai/DeepSeek-V4.1-Flash/blob/dba1be0a40aa45a94ad051997016db3960a90277/encoding/encoding.py.
Tags: single-call, text-before-call, x-deepseek-v41.
Raw output
Let me check the current conditions in London. <|DSML| calls> <|DSML| invoke name="get_weather"> <|DSML| parameter name="city" string="true">London</|DSML| parameter> </|DSML| invoke> </|DSML| calls>
Expected parse
{
"content": "Let me check the current conditions in London.",
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"city": "London"
},
"name": "get_weather"
}
]
}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/v41-text-before-call", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V4.1-Flash"], "spec_version": "0.1", "provenance": {"kind": "template_render", "source_url": "https://huggingface.co/deepseek-ai/DeepSeek-V4.1-Flash/blob/dba1be0a40aa45a94ad051997016db3960a90277/encoding/encoding.py", "revision": "dba1be0a40aa45a94ad051997016db3960a90277", "license": "MIT", "generator": "scripts/fixtures/deepseek/build.py", "template_sha256": "502bdaec8a3fd88ebc24c4721a7038fbe42f2063c664638127056107920035c1", "attribution": "Copyright (c) 2023 DeepSeek"}, "tools": [{"type": "function", "function": {"name": "get_weather", "description": "Get the current weather for a city.", "parameters": {"type": "object", "properties": {"city": {"type": "string"}, "unit": {"type": "string", "enum": ["c", "f"]}}, "required": ["city"]}}}], "raw_output": "Let me check the current conditions in London.\n\n<|DSML| calls>\n<|DSML| invoke name=\"get_weather\">\n<|DSML| parameter name=\"city\" string=\"true\">London</|DSML| parameter>\n</|DSML| invoke>\n</|DSML| calls>", "output_token_ids": [5718, 678, 4085, 270, 2573, 4132, 295, 6693, 339, 30, 128825, 10699, 1018, 30, 128825, 34756, 2329, 1281, 1133, 65, 50219, 3816, 30, 128825, 10767, 2329, 1281, 37399, 4, 3418, 1281, 11476, 3320, 27571, 1718, 128825, 10767, 1018, 1718, 128825, 34756, 1018, 1718, 128825, 10699, 32], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V4.1-Flash", "revision": "dba1be0a40aa45a94ad051997016db3960a90277", "mode": "hf"}, "generation_prompt": "<|Assistant|></think>", "thinking": false, "expected": {"content": "Let me check the current conditions in London.", "reasoning_content": null, "tool_calls": [{"name": "get_weather", "arguments": {"city": "London"}}]}, "tags": ["single-call", "text-before-call", "x-deepseek-v41"], "notes": "expected == DeepSeek's reference parse_message_from_completion_text on this output. Sub-format deepseek-v41; history render of the official encoder."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|></think>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V4.1-Flash",
"model_rule": "DeepSeek-V4\\.1",
"model_type": "deepseek_v41",
"parser_source": "docs/formats/deepseek.md (vLLM v0.30.0 row)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "emas to invoke tool calls.\n<|User|>Use the tools to answer.<|Assistant|></think>",
"reasoning_parser": "deepseek_v41",
"stop_token_in_final_delta": false,
"template": {
"sha256": "081382cb953a1c8041fdfc82a6001cf0c932553171436625c89fe5b9fbcda464",
"source": "vLLM tokenizer_mode=deepseek_v41 encoder (vllm.tokenizers.deepseek_v41_encoding)"
},
"tokenizer": {
"mode": "deepseek_v41",
"repo": "deepseek-ai/DeepSeek-V4.1-Flash",
"requested_mode": "auto",
"resolved_revision": "dba1be0a40aa45a94ad051997016db3960a90277",
"revision": "dba1be0a40aa45a94ad051997016db3960a90277",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v41",
"units_source": "fixture.output_token_ids"
}
soft pass deepseek/vllm-v41-reasoning-text-before-parallel-calls
expected_match
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_match | nonstream | soft pass | content (whitespace only): expected 'Checking.', got 'Checking.\n\n' |
expected_match | one | soft pass | content (whitespace only): expected 'Checking.', got 'Checking.\n\n' |
expected_match | special | soft pass | content (whitespace only): expected 'Checking.', got 'Checking.\n\n' |
expected_match | token | soft pass | content (whitespace only): expected 'Checking.', got 'Checking.\n\n' |
expected_match | rand:1:8 | soft pass | content (whitespace only): expected 'Checking.', got 'Checking.\n\n' |
expected_match | rand:2:8 | soft pass | content (whitespace only): expected 'Checking.', got 'Checking.\n\n' |
expected_match | rand:3:8 | soft pass | content (whitespace only): expected 'Checking.', got 'Checking.\n\n' |
expected_match | rand:4:8 | soft pass | content (whitespace only): expected 'Checking.', got 'Checking.\n\n' |
expected_match | rand:5:8 | soft pass | content (whitespace only): expected 'Checking.', got 'Checking.\n\n' |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/engine-tests.jsonl --id deepseek/vllm-v41-reasoning-text-before-parallel-calls --strategy one --strategy rand:1:8 --strategy rand:2:8 --strategy rand:3:8 --strategy rand:4:8 --strategy rand:5:8 --strategy special --strategy token --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 8 of fixtures/deepseek/engine-tests.jsonl.
Observed vs expected
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: nonstream, one, special, token, rand:1:8, rand:2:8, rand:3:8, rand:4:8, rand:5:8
@@ -1,4 +1,4 @@ { - "content": "Checking.", + "content": "Checking.\n\n", "reasoning_content": "Plan.", "tool_calls": [
Fixture
Provenance: engine_test, https://github.com/vllm-project/vllm/blob/ced6857afa0ea7b2e3f0846a62e1394e90f15607/tests/parser/engine/test_deepseek_v41.py#L59.
Tags: parallel-calls, text-before-call, reasoning, reasoning-prefilled, unicode, numeric-arguments, x-deepseek-v41.
Raw output
Plan.</think>Checking. <|DSML| calls> <|DSML| invoke name="get_weather"> <|DSML| parameter name="city" string="true">杭州</|DSML| parameter> <|DSML| parameter name="count" string="false">42</|DSML| parameter> </|DSML| invoke> <|DSML| invoke name="add"> <|DSML| parameter name="x" string="false">1.5</|DSML| parameter> <|DSML| parameter name="y" string="false">2.25</|DSML| parameter> </|DSML| invoke> </|DSML| calls>
Expected parse
{
"content": "Checking.",
"reasoning_content": "Plan.",
"tool_calls": [
{
"arguments": {
"city": "杭州",
"count": 42
},
"name": "get_weather"
},
{
"arguments": {
"x": 1.5,
"y": 2.25
},
"name": "add"
}
]
}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/vllm-v41-reasoning-text-before-parallel-calls", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V4.1-Flash"], "spec_version": "0.1", "provenance": {"kind": "engine_test", "source_url": "https://github.com/vllm-project/vllm/blob/ced6857afa0ea7b2e3f0846a62e1394e90f15607/tests/parser/engine/test_deepseek_v41.py#L59", "revision": "ced6857afa0ea7b2e3f0846a62e1394e90f15607", "license": "Apache-2.0", "attribution": "Copyright contributors to the vLLM project"}, "tools": [{"type": "function", "function": {"name": "get_weather", "parameters": {"type": "object", "properties": {"city": {"type": "string"}, "unit": {"type": "string"}, "count": {"type": "integer"}}}}}, {"type": "function", "function": {"name": "add", "parameters": {"type": "object", "properties": {"x": {"type": "number"}, "y": {"type": "number"}}}}}], "raw_output": "Plan.</think>Checking.\n\n<|DSML| calls>\n<|DSML| invoke name=\"get_weather\">\n<|DSML| parameter name=\"city\" string=\"true\">杭州</|DSML| parameter>\n<|DSML| parameter name=\"count\" string=\"false\">42</|DSML| parameter>\n</|DSML| invoke>\n<|DSML| invoke name=\"add\">\n<|DSML| parameter name=\"x\" string=\"false\">1.5</|DSML| parameter>\n<|DSML| parameter name=\"y\" string=\"false\">2.25</|DSML| parameter>\n</|DSML| invoke>\n</|DSML| calls>", "output_token_ids": [31002, 16, 128822, 123452, 339, 30, 128825, 10699, 1018, 30, 128825, 34756, 2329, 1281, 1133, 65, 50219, 3816, 30, 128825, 10767, 2329, 1281, 37399, 4, 3418, 1281, 11476, 3320, 24463, 1718, 128825, 10767, 1018, 30, 128825, 10767, 2329, 1281, 10499, 4, 3418, 1281, 19836, 3320, 3180, 1718, 128825, 10767, 1018, 1718, 128825, 34756, 1018, 30, 128825, 34756, 2329, 1281, 3327, 3816, 30, 128825, 10767, 2329, 1281, 90, 4, 3418, 1281, 19836, 3320, 19, 16, 23, 1718, 128825, 10767, 1018, 30, 128825, 10767, 2329, 1281, 91, 4, 3418, 1281, 19836, 3320, 20, 16, 1069, 1718, 128825, 10767, 1018, 1718, 128825, 34756, 1018, 1718, 128825, 10699, 32], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V4.1-Flash", "revision": "dba1be0a40aa45a94ad051997016db3960a90277", "mode": "hf"}, "generation_prompt": "<|Assistant|><think>", "thinking": true, "expected": {"content": "Checking.", "reasoning_content": "Plan.", "tool_calls": [{"name": "get_weather", "arguments": {"city": "杭州", "count": 42}}, {"name": "add", "arguments": {"x": 1.5, "y": 2.25}}]}, "tags": ["parallel-calls", "text-before-call", "reasoning", "reasoning-prefilled", "unicode", "numeric-arguments", "x-deepseek-v41"], "notes": "text = 'Plan.</think>' + 'Checking.' + CALLS (CALLS defined at line 18), thinking=True. output_token_ids: tokenizer.encode(raw_output)."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": true,
"thinking": true
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|><think>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V4.1-Flash",
"model_rule": "DeepSeek-V4\\.1",
"model_type": "deepseek_v41",
"parser_source": "docs/formats/deepseek.md (vLLM v0.30.0 row)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "hemas to invoke tool calls.\n<|User|>Use the tools to answer.<|Assistant|><think>",
"reasoning_parser": "deepseek_v41",
"stop_token_in_final_delta": false,
"template": {
"sha256": "081382cb953a1c8041fdfc82a6001cf0c932553171436625c89fe5b9fbcda464",
"source": "vLLM tokenizer_mode=deepseek_v41 encoder (vllm.tokenizers.deepseek_v41_encoding)"
},
"tokenizer": {
"mode": "deepseek_v41",
"repo": "deepseek-ai/DeepSeek-V4.1-Flash",
"requested_mode": "auto",
"resolved_revision": "dba1be0a40aa45a94ad051997016db3960a90277",
"revision": "dba1be0a40aa45a94ad051997016db3960a90277",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v41",
"units_source": "fixture.output_token_ids"
}
soft pass deepseek/vllm-v41-text-before-parallel-calls
expected_match
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_match | nonstream | soft pass | content (whitespace only): expected 'Checking.', got 'Checking.\n\n' |
expected_match | one | soft pass | content (whitespace only): expected 'Checking.', got 'Checking.\n\n' |
expected_match | special | soft pass | content (whitespace only): expected 'Checking.', got 'Checking.\n\n' |
expected_match | token | soft pass | content (whitespace only): expected 'Checking.', got 'Checking.\n\n' |
expected_match | rand:1:8 | soft pass | content (whitespace only): expected 'Checking.', got 'Checking.\n\n' |
expected_match | rand:2:8 | soft pass | content (whitespace only): expected 'Checking.', got 'Checking.\n\n' |
expected_match | rand:3:8 | soft pass | content (whitespace only): expected 'Checking.', got 'Checking.\n\n' |
expected_match | rand:4:8 | soft pass | content (whitespace only): expected 'Checking.', got 'Checking.\n\n' |
expected_match | rand:5:8 | soft pass | content (whitespace only): expected 'Checking.', got 'Checking.\n\n' |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/deepseek/engine-tests.jsonl --id deepseek/vllm-v41-text-before-parallel-calls --strategy one --strategy rand:1:8 --strategy rand:2:8 --strategy rand:3:8 --strategy rand:4:8 --strategy rand:5:8 --strategy special --strategy token --observed all
Set up the engine first with scripts/engines/vllm.sh; this run used vllm 0.30.0.
The fixture is line 7 of fixtures/deepseek/engine-tests.jsonl.
Observed vs expected
Identical parses are grouped. Empty strings are shown as null, as in strict comparison.
Strategies: nonstream, one, special, token, rand:1:8, rand:2:8, rand:3:8, rand:4:8, rand:5:8
@@ -1,4 +1,4 @@ { - "content": "Checking.", + "content": "Checking.\n\n", "reasoning_content": null, "tool_calls": [
Fixture
Provenance: engine_test, https://github.com/vllm-project/vllm/blob/ced6857afa0ea7b2e3f0846a62e1394e90f15607/tests/parser/engine/test_deepseek_v41.py#L59.
Tags: parallel-calls, text-before-call, unicode, numeric-arguments, x-deepseek-v41.
Raw output
Checking. <|DSML| calls> <|DSML| invoke name="get_weather"> <|DSML| parameter name="city" string="true">杭州</|DSML| parameter> <|DSML| parameter name="count" string="false">42</|DSML| parameter> </|DSML| invoke> <|DSML| invoke name="add"> <|DSML| parameter name="x" string="false">1.5</|DSML| parameter> <|DSML| parameter name="y" string="false">2.25</|DSML| parameter> </|DSML| invoke> </|DSML| calls>
Expected parse
{
"content": "Checking.",
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"city": "杭州",
"count": 42
},
"name": "get_weather"
},
{
"arguments": {
"x": 1.5,
"y": 2.25
},
"name": "add"
}
]
}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "deepseek/vllm-v41-text-before-parallel-calls", "family": "deepseek", "models": ["deepseek-ai/DeepSeek-V4.1-Flash"], "spec_version": "0.1", "provenance": {"kind": "engine_test", "source_url": "https://github.com/vllm-project/vllm/blob/ced6857afa0ea7b2e3f0846a62e1394e90f15607/tests/parser/engine/test_deepseek_v41.py#L59", "revision": "ced6857afa0ea7b2e3f0846a62e1394e90f15607", "license": "Apache-2.0", "attribution": "Copyright contributors to the vLLM project"}, "tools": [{"type": "function", "function": {"name": "get_weather", "parameters": {"type": "object", "properties": {"city": {"type": "string"}, "unit": {"type": "string"}, "count": {"type": "integer"}}}}}, {"type": "function", "function": {"name": "add", "parameters": {"type": "object", "properties": {"x": {"type": "number"}, "y": {"type": "number"}}}}}], "raw_output": "Checking.\n\n<|DSML| calls>\n<|DSML| invoke name=\"get_weather\">\n<|DSML| parameter name=\"city\" string=\"true\">杭州</|DSML| parameter>\n<|DSML| parameter name=\"count\" string=\"false\">42</|DSML| parameter>\n</|DSML| invoke>\n<|DSML| invoke name=\"add\">\n<|DSML| parameter name=\"x\" string=\"false\">1.5</|DSML| parameter>\n<|DSML| parameter name=\"y\" string=\"false\">2.25</|DSML| parameter>\n</|DSML| invoke>\n</|DSML| calls>", "output_token_ids": [123452, 339, 30, 128825, 10699, 1018, 30, 128825, 34756, 2329, 1281, 1133, 65, 50219, 3816, 30, 128825, 10767, 2329, 1281, 37399, 4, 3418, 1281, 11476, 3320, 24463, 1718, 128825, 10767, 1018, 30, 128825, 10767, 2329, 1281, 10499, 4, 3418, 1281, 19836, 3320, 3180, 1718, 128825, 10767, 1018, 1718, 128825, 34756, 1018, 30, 128825, 34756, 2329, 1281, 3327, 3816, 30, 128825, 10767, 2329, 1281, 90, 4, 3418, 1281, 19836, 3320, 19, 16, 23, 1718, 128825, 10767, 1018, 30, 128825, 10767, 2329, 1281, 91, 4, 3418, 1281, 19836, 3320, 20, 16, 1069, 1718, 128825, 10767, 1018, 1718, 128825, 34756, 1018, 1718, 128825, 10699, 32], "tokenizer": {"repo": "deepseek-ai/DeepSeek-V4.1-Flash", "revision": "dba1be0a40aa45a94ad051997016db3960a90277", "mode": "hf"}, "generation_prompt": "<|Assistant|></think>", "thinking": false, "expected": {"content": "Checking.", "reasoning_content": null, "tool_calls": [{"name": "get_weather", "arguments": {"city": "杭州", "count": 42}}, {"name": "add", "arguments": {"x": 1.5, "y": 2.25}}]}, "tags": ["parallel-calls", "text-before-call", "unicode", "numeric-arguments", "x-deepseek-v41"], "notes": "text = 'Checking.' + CALLS (CALLS defined at line 18), thinking=False. output_token_ids: tokenizer.encode(raw_output)."}
Parser configuration
{
"chat_template_kwargs": {
"enable_thinking": false,
"thinking": false
},
"detokenizer": "vllm.v1.engine.detokenizer.IncrementalDetokenizer.from_new_request",
"detokenizer_class": "vllm.v1.engine.detokenizer.FastIncrementalDetokenizer",
"enable_auto_tools": true,
"engine": "vllm",
"entrypoint": "vllm.parser.parser_manager.ParserManager.get_parser",
"generation_prompt": "<|Assistant|></think>",
"generation_prompt_match": true,
"is_harmony": false,
"model": "deepseek-ai/DeepSeek-V4.1-Flash",
"model_rule": "DeepSeek-V4\\.1",
"model_type": "deepseek_v41",
"parser_source": "docs/formats/deepseek.md (vLLM v0.30.0 row)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "emas to invoke tool calls.\n<|User|>Use the tools to answer.<|Assistant|></think>",
"reasoning_parser": "deepseek_v41",
"stop_token_in_final_delta": false,
"template": {
"sha256": "081382cb953a1c8041fdfc82a6001cf0c932553171436625c89fe5b9fbcda464",
"source": "vLLM tokenizer_mode=deepseek_v41 encoder (vllm.tokenizers.deepseek_v41_encoding)"
},
"tokenizer": {
"mode": "deepseek_v41",
"repo": "deepseek-ai/DeepSeek-V4.1-Flash",
"requested_mode": "auto",
"resolved_revision": "dba1be0a40aa45a94ad051997016db3960a90277",
"revision": "dba1be0a40aa45a94ad051997016db3960a90277",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "deepseek_v41",
"units_source": "fixture.output_token_ids"
}
- pass strict match on every realistic strategy
- soft pass only whitespace differs (normalization
soft-v1) - fail a check failed
- error the harness failed, not the engine's parser
- unsupported the engine has no parser for this family or model