gpt-oss (Harmony response format) on vllm 0.30.0
fail 90% strict pass 46 pass · 5 fail
Run
Checks
| Check | Pass | Soft | Fail | Error | Strict pass rate |
|---|---|---|---|---|---|
expected_match |
44 | 0 | 1 | 0 | 98% |
expected_error |
3 | 0 | 3 | 0 | 50% |
stream_equals_nonstream |
50 | 0 | 1 | 0 | 98% |
split_invariance |
51 | 0 | 0 | 0 | 100% |
no_leakage |
49 | 0 | 2 | 0 | 96% |
arguments_json |
35 | 0 | 2 | 0 | 95% |
arguments_schema |
35 | 0 | 2 | 0 | 95% |
parallel_order |
1 | 0 | 0 | 0 | 100% |
Fixtures needing attention
fail gpt-oss/bug-garbled-channel-commentary-question
expected_error
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_error | nonstream | fail | outcome exception 'HarmonyError: unexpected tokens remaining in message header: Some("need temperature difference. Also need outside temperature. Get")'; accepted: ['content_passthrough', 'no_tool_calls'] |
expected_error | one | fail | outcome exception 'HarmonyError: unexpected tokens remaining in message header: Some("need temperature difference. Also need outside temperature. Get")'; accepted: ['content_passthrough', 'no_tool_calls'] |
expected_error | special | fail | outcome exception 'HarmonyError: unexpected tokens remaining in message header: Some("need temperature difference. Also need outside temperature. Get")'; accepted: ['content_passthrough', 'no_tool_calls'] |
expected_error | token | fail | outcome exception 'HarmonyError: unexpected tokens remaining in message header: Some("need temperature difference. Also need outside temperature. Get")'; accepted: ['content_passthrough', 'no_tool_calls'] |
expected_error | rand:1:8 | fail | outcome exception 'HarmonyError: unexpected tokens remaining in message header: Some("need temperature difference. Also need outside temperature. Get")'; accepted: ['content_passthrough', 'no_tool_calls'] |
expected_error | rand:2:8 | fail | outcome exception 'HarmonyError: unexpected tokens remaining in message header: Some("need temperature difference. Also need outside temperature. Get")'; accepted: ['content_passthrough', 'no_tool_calls'] |
expected_error | rand:3:8 | fail | outcome exception 'HarmonyError: unexpected tokens remaining in message header: Some("need temperature difference. Also need outside temperature. Get")'; accepted: ['content_passthrough', 'no_tool_calls'] |
expected_error | rand:4:8 | fail | outcome exception 'HarmonyError: unexpected tokens remaining in message header: Some("need temperature difference. Also need outside temperature. Get")'; accepted: ['content_passthrough', 'no_tool_calls'] |
expected_error | rand:5:8 | fail | outcome exception 'HarmonyError: unexpected tokens remaining in message header: Some("need temperature difference. Also need outside temperature. Get")'; accepted: ['content_passthrough', 'no_tool_calls'] |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/gpt-oss/imported.jsonl --id gpt-oss/bug-garbled-channel-commentary-question --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 24 of fixtures/gpt-oss/imported.jsonl.
Observed
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
{
"content": null,
"exception": "HarmonyError: unexpected tokens remaining in message header: Some(\"need temperature difference. Also need outside temperature. Get\")",
"reasoning_content": null,
"tool_calls": []
}
Fixture
Provenance: bug_report, https://github.com/ggml-org/llama.cpp/issues/27720.
Tags: malformed, truncated, no-call, regression, x-malformed-channel.
Expected graceful failure: Malformed channel header ('commentary?commentary?' with no <|message|>) followed by a well-formed analysis message. There is no tool call; the turn must not error. (accept: no_tool_calls, content_passthrough).
Raw output
<|channel|>commentary?commentary?We need temperature difference. Also need outside temperature. Get outdoor temperature.<|end|><|start|>assistant<|channel|>analysis<|message|>Need GetLiveContext for Outdoor Temperature.
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "gpt-oss/bug-garbled-channel-commentary-question", "family": "gpt-oss", "models": ["openai/gpt-oss-20b", "openai/gpt-oss-120b"], "spec_version": "0.1", "provenance": {"kind": "bug_report", "source_url": "https://github.com/ggml-org/llama.cpp/issues/27720", "revision": "issue-27720", "license": "NOASSERTION", "generator": "scripts/fixtures/gpt-oss/import_gpt_oss.py"}, "tools": [{"type": "function", "function": {"name": "get_weather", "parameters": {"type": "object", "properties": {"location": {"type": "string"}}}}}], "raw_output": "<|channel|>commentary?commentary?We need temperature difference. Also need outside temperature. Get outdoor temperature.<|end|><|start|>assistant<|channel|>analysis<|message|>Need GetLiveContext for Outdoor Temperature.", "output_token_ids": [200005, 12606, 815, 30, 12606, 815, 30, 2167, 1309, 12088, 9809, 13, 8820, 1309, 7539, 12088, 13, 2942, 16332, 12088, 13, 200007, 200006, 173781, 200005, 35644, 200008, 23483, 2942, 20770, 2522, 395, 40767, 64495, 13], "tokenizer": {"repo": "openai/gpt-oss-20b", "revision": "6cee5e81ee83917806bbde320786a8fb61efebee", "mode": "hf"}, "expected_error": {"reason": "Malformed channel header ('commentary?commentary?' with no <|message|>) followed by a well-formed analysis message. There is no tool call; the turn must not error.", "accept": ["no_tool_calls", "content_passthrough"]}, "tags": ["malformed", "truncated", "no-call", "regression", "x-malformed-channel"], "notes": "Quoted from the issue's log line at 179.42 s, which is cut at '<|end|' by the log; this fixture stops before that partial token."}
Parser configuration
{
"chat_template_kwargs": {},
"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": "<|start|>assistant",
"generation_prompt_match": true,
"is_harmony": true,
"model": "openai/gpt-oss-20b",
"model_rule": "gpt-oss",
"model_type": "gpt_oss",
"parser_source": "vLLM gpt-oss recipe; HarmonyParser (is_harmony)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "<|end|><|start|>user<|message|>Use the tools to answer.<|end|><|start|>assistant",
"reasoning_parser": "openai_gptoss",
"stop_token_in_final_delta": false,
"template": {
"openai_harmony": "0.0.8",
"source": "openai_harmony via vLLM OnlineRenderer._make_request_with_harmony (no Jinja template)"
},
"tokenizer": {
"mode": "hf",
"repo": "openai/gpt-oss-20b",
"requested_mode": "auto",
"resolved_revision": "6cee5e81ee83917806bbde320786a8fb61efebee",
"revision": "6cee5e81ee83917806bbde320786a8fb61efebee",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "openai",
"units_source": "fixture.output_token_ids"
}
fail gpt-oss/harmony-truncated-in-arguments
expected_error, arguments_json, arguments_schema
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_error | nonstream | fail | returned 1 tool call(s) ['get_weather'] for Output stopped (max_tokens) inside the tool-call JSON; there is no complete call. |
expected_error | one | fail | returned 1 tool call(s) ['get_weather'] for Output stopped (max_tokens) inside the tool-call JSON; there is no complete call. |
expected_error | special | fail | returned 1 tool call(s) ['get_weather'] for Output stopped (max_tokens) inside the tool-call JSON; there is no complete call. |
expected_error | token | fail | returned 1 tool call(s) ['get_weather'] for Output stopped (max_tokens) inside the tool-call JSON; there is no complete call. |
expected_error | rand:1:8 | fail | returned 1 tool call(s) ['get_weather'] for Output stopped (max_tokens) inside the tool-call JSON; there is no complete call. |
expected_error | rand:2:8 | fail | returned 1 tool call(s) ['get_weather'] for Output stopped (max_tokens) inside the tool-call JSON; there is no complete call. |
expected_error | rand:3:8 | fail | returned 1 tool call(s) ['get_weather'] for Output stopped (max_tokens) inside the tool-call JSON; there is no complete call. |
expected_error | rand:4:8 | fail | returned 1 tool call(s) ['get_weather'] for Output stopped (max_tokens) inside the tool-call JSON; there is no complete call. |
expected_error | rand:5:8 | fail | returned 1 tool call(s) ['get_weather'] for Output stopped (max_tokens) inside the tool-call JSON; there is no complete call. |
arguments_json | nonstream | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "Paris", "unit': Unterminated string starting at: line 1 column 19 (char 18)) |
arguments_json | one | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "Paris", "unit': Unterminated string starting at: line 1 column 19 (char 18)) |
arguments_json | special | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "Paris", "unit': Unterminated string starting at: line 1 column 19 (char 18)) |
arguments_json | token | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "Paris", "unit': Unterminated string starting at: line 1 column 19 (char 18)) |
arguments_json | rand:1:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "Paris", "unit': Unterminated string starting at: line 1 column 19 (char 18)) |
arguments_json | rand:2:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "Paris", "unit': Unterminated string starting at: line 1 column 19 (char 18)) |
arguments_json | rand:3:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "Paris", "unit': Unterminated string starting at: line 1 column 19 (char 18)) |
arguments_json | rand:4:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "Paris", "unit': Unterminated string starting at: line 1 column 19 (char 18)) |
arguments_json | rand:5:8 | fail | [0] get_weather: arguments are not valid JSON text ('{"city": "Paris", "unit': Unterminated string starting at: line 1 column 19 (char 18)) |
arguments_schema | nonstream | fail | [0] get_weather: arguments are not a JSON object; not validated |
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/gpt-oss/rendered.jsonl --id gpt-oss/harmony-truncated-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 20 of fixtures/gpt-oss/rendered.jsonl.
Observed
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
{
"content": null,
"reasoning_content": "The user asks for the weather in Paris. I should call get_weather.",
"tool_calls": [
{
"arguments": {
"<arguments_raw, not valid JSON>": "{\"city\": \"Paris\", \"unit"
},
"name": "get_weather"
}
]
}
Fixture
Provenance: template_render, https://github.com/openai/harmony/blob/ec7606df9e87e3d0a1fec9f50928c1e407f0c438/src/encoding.rs.
Tags: truncated, reasoning, x-recipient-in-role.
Expected graceful failure: Output stopped (max_tokens) inside the tool-call JSON; there is no complete call. (accept: no_tool_calls, content_passthrough, exception).
Raw output
<|channel|>analysis<|message|>The user asks for the weather in Paris. I should call get_weather.<|end|><|start|>assistant to=functions.get_weather<|channel|>commentary <|constrain|>json<|message|>{"city": "Paris", "unit
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "gpt-oss/harmony-truncated-in-arguments", "family": "gpt-oss", "models": ["openai/gpt-oss-20b", "openai/gpt-oss-120b"], "spec_version": "0.1", "provenance": {"kind": "template_render", "source_url": "https://github.com/openai/harmony/blob/ec7606df9e87e3d0a1fec9f50928c1e407f0c438/src/encoding.rs", "revision": "ec7606df9e87e3d0a1fec9f50928c1e407f0c438", "license": "Apache-2.0", "generator": "scripts/fixtures/gpt-oss/render_gpt_oss.py", "template_sha256": "788675d601fe782e0c9aa7b1111166498a3ab380ca885b7d164e27f7438184ed", "attribution": "Rendered with openai-harmony 0.0.8 (Copyright OpenAI, Apache-2.0)."}, "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"]}}}, {"type": "function", "function": {"name": "get_time", "description": "Get the current UTC time.", "parameters": {"type": "object", "properties": {}, "required": []}}}, {"type": "function", "function": {"name": "write_file", "description": "Write text to a file.", "parameters": {"type": "object", "properties": {"path": {"type": "string"}, "content": {"type": "string"}}, "required": ["path", "content"]}}}, {"type": "function", "function": {"name": "set_alarm", "description": "Set an alarm.", "parameters": {"type": "object", "properties": {"hour": {"type": "integer"}, "minute": {"type": "integer"}, "volume": {"type": "number"}, "repeat": {"type": "boolean"}, "label": {"type": ["string", "null"]}}, "required": ["hour", "minute"]}}}], "raw_output": "<|channel|>analysis<|message|>The user asks for the weather in Paris. I should call get_weather.<|end|><|start|>assistant to=functions.get_weather<|channel|>commentary <|constrain|>json<|message|>{\"city\": \"Paris\", \"unit", "output_token_ids": [200005, 35644, 200008, 976, 1825, 31064, 395, 290, 11122, 306, 12650, 13, 357, 1757, 2421, 717, 170154, 13, 200007, 200006, 173781, 316, 28, 44580, 775, 170154, 200005, 12606, 815, 220, 200003, 4108, 200008, 10848, 17500, 1243, 392, 72782, 672, 392, 5400], "tokenizer": {"repo": "openai/gpt-oss-20b", "revision": "6cee5e81ee83917806bbde320786a8fb61efebee", "mode": "hf"}, "expected_error": {"reason": "Output stopped (max_tokens) inside the tool-call JSON; there is no complete call.", "accept": ["no_tool_calls", "content_passthrough", "exception"]}, "tags": ["truncated", "reasoning", "x-recipient-in-role"], "notes": "History render by openai-harmony 0.0.8 (recipient in the role header)."}
Parser configuration
{
"chat_template_kwargs": {},
"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": "<|start|>assistant",
"generation_prompt_match": true,
"is_harmony": true,
"model": "openai/gpt-oss-20b",
"model_rule": "gpt-oss",
"model_type": "gpt_oss",
"parser_source": "vLLM gpt-oss recipe; HarmonyParser (is_harmony)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "<|end|><|start|>user<|message|>Use the tools to answer.<|end|><|start|>assistant",
"reasoning_parser": "openai_gptoss",
"stop_token_in_final_delta": false,
"template": {
"openai_harmony": "0.0.8",
"source": "openai_harmony via vLLM OnlineRenderer._make_request_with_harmony (no Jinja template)"
},
"tokenizer": {
"mode": "hf",
"repo": "openai/gpt-oss-20b",
"requested_mode": "auto",
"resolved_revision": "6cee5e81ee83917806bbde320786a8fb61efebee",
"revision": "6cee5e81ee83917806bbde320786a8fb61efebee",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "openai",
"units_source": "fixture.output_token_ids"
}
fail gpt-oss/harmony-truncated-in-header
expected_match, no_leakage
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_match | nonstream | fail | content: expected None, got '<|start|>assistant to=functions.get_weather<|channel|>commentary <|constrain|>json' |
expected_match | one | fail | content: expected None, got '<|start|>assistant to=functions.get_weather<|channel|>commentary <|constrain|>json' |
expected_match | special | fail | content: expected None, got '<|start|>assistant to=functions.get_weather<|channel|>commentary <|constrain|>json' |
expected_match | token | fail | content: expected None, got '<|start|>assistant to=functions.get_weather<|channel|>commentary <|constrain|>json' |
expected_match | rand:1:8 | fail | content: expected None, got '<|start|>assistant to=functions.get_weather<|channel|>commentary <|constrain|>json' |
expected_match | rand:2:8 | fail | content: expected None, got '<|start|>assistant to=functions.get_weather<|channel|>commentary <|constrain|>json' |
expected_match | rand:3:8 | fail | content: expected None, got '<|start|>assistant to=functions.get_weather<|channel|>commentary <|constrain|>json' |
expected_match | rand:4:8 | fail | content: expected None, got '<|start|>assistant to=functions.get_weather<|channel|>commentary <|constrain|>json' |
expected_match | rand:5:8 | fail | content: expected None, got '<|start|>assistant to=functions.get_weather<|channel|>commentary <|constrain|>json' |
no_leakage | nonstream | fail | content contains '<|start|>'; content contains '<|channel|>'; content contains '<|constrain|>' |
no_leakage | one | fail | content contains '<|start|>'; content contains '<|channel|>'; content contains '<|constrain|>' |
no_leakage | special | fail | content contains '<|start|>'; content contains '<|channel|>'; content contains '<|constrain|>' |
no_leakage | token | fail | content contains '<|start|>'; content contains '<|channel|>'; content contains '<|constrain|>' |
no_leakage | rand:1:8 | fail | content contains '<|start|>'; content contains '<|channel|>'; content contains '<|constrain|>' |
no_leakage | rand:2:8 | fail | content contains '<|start|>'; content contains '<|channel|>'; content contains '<|constrain|>' |
no_leakage | rand:3:8 | fail | content contains '<|start|>'; content contains '<|channel|>'; content contains '<|constrain|>' |
no_leakage | rand:4:8 | fail | content contains '<|start|>'; content contains '<|channel|>'; content contains '<|constrain|>' |
no_leakage | rand:5:8 | fail | content contains '<|start|>'; content contains '<|channel|>'; content contains '<|constrain|>' |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/gpt-oss/rendered.jsonl --id gpt-oss/harmony-truncated-in-header --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 22 of fixtures/gpt-oss/rendered.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": null, + "content": "<|start|>assistant to=functions.get_weather<|channel|>commentary <|constrain|>json", "reasoning_content": "The user asks for the weather in Paris. I should call get_weather.", "tool_calls": []
Fixture
Provenance: template_render, https://github.com/openai/harmony/blob/ec7606df9e87e3d0a1fec9f50928c1e407f0c438/src/encoding.rs.
Tags: truncated, reasoning, x-recipient-in-role.
Raw output
<|channel|>analysis<|message|>The user asks for the weather in Paris. I should call get_weather.<|end|><|start|>assistant to=functions.get_weather<|channel|>commentary <|constrain|>json
Expected parse
{
"content": null,
"reasoning_content": "The user asks for the weather in Paris. I should call get_weather.",
"tool_calls": []
}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "gpt-oss/harmony-truncated-in-header", "family": "gpt-oss", "models": ["openai/gpt-oss-20b", "openai/gpt-oss-120b"], "spec_version": "0.1", "provenance": {"kind": "template_render", "source_url": "https://github.com/openai/harmony/blob/ec7606df9e87e3d0a1fec9f50928c1e407f0c438/src/encoding.rs", "revision": "ec7606df9e87e3d0a1fec9f50928c1e407f0c438", "license": "Apache-2.0", "generator": "scripts/fixtures/gpt-oss/render_gpt_oss.py", "template_sha256": "788675d601fe782e0c9aa7b1111166498a3ab380ca885b7d164e27f7438184ed", "attribution": "Rendered with openai-harmony 0.0.8 (Copyright OpenAI, Apache-2.0)."}, "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"]}}}, {"type": "function", "function": {"name": "get_time", "description": "Get the current UTC time.", "parameters": {"type": "object", "properties": {}, "required": []}}}, {"type": "function", "function": {"name": "write_file", "description": "Write text to a file.", "parameters": {"type": "object", "properties": {"path": {"type": "string"}, "content": {"type": "string"}}, "required": ["path", "content"]}}}, {"type": "function", "function": {"name": "set_alarm", "description": "Set an alarm.", "parameters": {"type": "object", "properties": {"hour": {"type": "integer"}, "minute": {"type": "integer"}, "volume": {"type": "number"}, "repeat": {"type": "boolean"}, "label": {"type": ["string", "null"]}}, "required": ["hour", "minute"]}}}], "raw_output": "<|channel|>analysis<|message|>The user asks for the weather in Paris. I should call get_weather.<|end|><|start|>assistant to=functions.get_weather<|channel|>commentary <|constrain|>json", "output_token_ids": [200005, 35644, 200008, 976, 1825, 31064, 395, 290, 11122, 306, 12650, 13, 357, 1757, 2421, 717, 170154, 13, 200007, 200006, 173781, 316, 28, 44580, 775, 170154, 200005, 12606, 815, 220, 200003, 4108], "tokenizer": {"repo": "openai/gpt-oss-20b", "revision": "6cee5e81ee83917806bbde320786a8fb61efebee", "mode": "hf"}, "expected": {"content": null, "reasoning_content": "The user asks for the weather in Paris. I should call get_weather.", "tool_calls": []}, "tags": ["truncated", "reasoning", "x-recipient-in-role"], "notes": "History render by openai-harmony 0.0.8 (recipient in the role header). Output stopped inside the tool-call header, before <|message|>: the analysis is complete reasoning and there is no call yet."}
Parser configuration
{
"chat_template_kwargs": {},
"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": "<|start|>assistant",
"generation_prompt_match": true,
"is_harmony": true,
"model": "openai/gpt-oss-20b",
"model_rule": "gpt-oss",
"model_type": "gpt_oss",
"parser_source": "vLLM gpt-oss recipe; HarmonyParser (is_harmony)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "<|end|><|start|>user<|message|>Use the tools to answer.<|end|><|start|>assistant",
"reasoning_parser": "openai_gptoss",
"stop_token_in_final_delta": false,
"template": {
"openai_harmony": "0.0.8",
"source": "openai_harmony via vLLM OnlineRenderer._make_request_with_harmony (no Jinja template)"
},
"tokenizer": {
"mode": "hf",
"repo": "openai/gpt-oss-20b",
"requested_mode": "auto",
"resolved_revision": "6cee5e81ee83917806bbde320786a8fb61efebee",
"revision": "6cee5e81ee83917806bbde320786a8fb61efebee",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "openai",
"units_source": "fixture.output_token_ids"
}
fail gpt-oss/llamacpp-stray-commentary-header
expected_error, no_leakage, arguments_json, arguments_schema
| Check | Strategy | Result | Detail |
|---|---|---|---|
expected_error | nonstream | fail | returned 1 tool call(s) ['assistant<|channel|>analysis'] for Stray '<|channel|>commentary to=assistant' header before the analysis channel. llama.cpp recovers reasoning 'I'm\nthinking' and content 'Hello, world!\nWhat's up?'; openai-harmony's non-strict parser keeps the content but drops the reasoning. Either way there is no tool call and the turn must not error. |
expected_error | one | fail | returned 1 tool call(s) ['assistant<|channel|>analysis'] for Stray '<|channel|>commentary to=assistant' header before the analysis channel. llama.cpp recovers reasoning 'I'm\nthinking' and content 'Hello, world!\nWhat's up?'; openai-harmony's non-strict parser keeps the content but drops the reasoning. Either way there is no tool call and the turn must not error. |
expected_error | special | fail | returned 1 tool call(s) ['assistant<|channel|>analysis'] for Stray '<|channel|>commentary to=assistant' header before the analysis channel. llama.cpp recovers reasoning 'I'm\nthinking' and content 'Hello, world!\nWhat's up?'; openai-harmony's non-strict parser keeps the content but drops the reasoning. Either way there is no tool call and the turn must not error. |
expected_error | token | fail | returned 1 tool call(s) ['assistant<|channel|>analysis'] for Stray '<|channel|>commentary to=assistant' header before the analysis channel. llama.cpp recovers reasoning 'I'm\nthinking' and content 'Hello, world!\nWhat's up?'; openai-harmony's non-strict parser keeps the content but drops the reasoning. Either way there is no tool call and the turn must not error. |
expected_error | rand:1:8 | fail | returned 1 tool call(s) ['assistant<|channel|>analysis'] for Stray '<|channel|>commentary to=assistant' header before the analysis channel. llama.cpp recovers reasoning 'I'm\nthinking' and content 'Hello, world!\nWhat's up?'; openai-harmony's non-strict parser keeps the content but drops the reasoning. Either way there is no tool call and the turn must not error. |
expected_error | rand:2:8 | fail | returned 1 tool call(s) ['assistant<|channel|>analysis'] for Stray '<|channel|>commentary to=assistant' header before the analysis channel. llama.cpp recovers reasoning 'I'm\nthinking' and content 'Hello, world!\nWhat's up?'; openai-harmony's non-strict parser keeps the content but drops the reasoning. Either way there is no tool call and the turn must not error. |
expected_error | rand:3:8 | fail | returned 1 tool call(s) ['assistant<|channel|>analysis'] for Stray '<|channel|>commentary to=assistant' header before the analysis channel. llama.cpp recovers reasoning 'I'm\nthinking' and content 'Hello, world!\nWhat's up?'; openai-harmony's non-strict parser keeps the content but drops the reasoning. Either way there is no tool call and the turn must not error. |
expected_error | rand:4:8 | fail | returned 1 tool call(s) ['assistant<|channel|>analysis'] for Stray '<|channel|>commentary to=assistant' header before the analysis channel. llama.cpp recovers reasoning 'I'm\nthinking' and content 'Hello, world!\nWhat's up?'; openai-harmony's non-strict parser keeps the content but drops the reasoning. Either way there is no tool call and the turn must not error. |
expected_error | rand:5:8 | fail | returned 1 tool call(s) ['assistant<|channel|>analysis'] for Stray '<|channel|>commentary to=assistant' header before the analysis channel. llama.cpp recovers reasoning 'I'm\nthinking' and content 'Hello, world!\nWhat's up?'; openai-harmony's non-strict parser keeps the content but drops the reasoning. Either way there is no tool call and the turn must not error. |
no_leakage | nonstream | fail | tool_calls[0].name contains '<|channel|>' |
no_leakage | one | fail | tool_calls[0].name contains '<|channel|>' |
no_leakage | special | fail | tool_calls[0].name contains '<|channel|>' |
no_leakage | token | fail | tool_calls[0].name contains '<|channel|>' |
no_leakage | rand:1:8 | fail | tool_calls[0].name contains '<|channel|>' |
no_leakage | rand:2:8 | fail | tool_calls[0].name contains '<|channel|>' |
no_leakage | rand:3:8 | fail | tool_calls[0].name contains '<|channel|>' |
no_leakage | rand:4:8 | fail | tool_calls[0].name contains '<|channel|>' |
no_leakage | rand:5:8 | fail | tool_calls[0].name contains '<|channel|>' |
arguments_json | nonstream | fail | [0] assistant<|channel|>analysis: arguments are not valid JSON text ("I'm\nthinking": Expecting value: line 1 column 1 (char 0)) |
arguments_json | one | fail | [0] assistant<|channel|>analysis: arguments are not valid JSON text ("I'm\nthinking": Expecting value: line 1 column 1 (char 0)) |
arguments_json | special | fail | [0] assistant<|channel|>analysis: arguments are not valid JSON text ("I'm\nthinking": Expecting value: line 1 column 1 (char 0)) |
arguments_json | token | fail | [0] assistant<|channel|>analysis: arguments are not valid JSON text ("I'm\nthinking": Expecting value: line 1 column 1 (char 0)) |
arguments_json | rand:1:8 | fail | [0] assistant<|channel|>analysis: arguments are not valid JSON text ("I'm\nthinking": Expecting value: line 1 column 1 (char 0)) |
arguments_json | rand:2:8 | fail | [0] assistant<|channel|>analysis: arguments are not valid JSON text ("I'm\nthinking": Expecting value: line 1 column 1 (char 0)) |
arguments_json | rand:3:8 | fail | [0] assistant<|channel|>analysis: arguments are not valid JSON text ("I'm\nthinking": Expecting value: line 1 column 1 (char 0)) |
arguments_json | rand:4:8 | fail | [0] assistant<|channel|>analysis: arguments are not valid JSON text ("I'm\nthinking": Expecting value: line 1 column 1 (char 0)) |
arguments_json | rand:5:8 | fail | [0] assistant<|channel|>analysis: arguments are not valid JSON text ("I'm\nthinking": Expecting value: line 1 column 1 (char 0)) |
arguments_schema | nonstream | fail | [0] 'assistant<|channel|>analysis' is not an offered tool |
arguments_schema | one | fail | [0] 'assistant<|channel|>analysis' is not an offered tool |
arguments_schema | special | fail | [0] 'assistant<|channel|>analysis' is not an offered tool |
arguments_schema | token | fail | [0] 'assistant<|channel|>analysis' is not an offered tool |
arguments_schema | rand:1:8 | fail | [0] 'assistant<|channel|>analysis' is not an offered tool |
arguments_schema | rand:2:8 | fail | [0] 'assistant<|channel|>analysis' is not an offered tool |
arguments_schema | rand:3:8 | fail | [0] 'assistant<|channel|>analysis' is not an offered tool |
arguments_schema | rand:4:8 | fail | [0] 'assistant<|channel|>analysis' is not an offered tool |
arguments_schema | rand:5:8 | fail | [0] 'assistant<|channel|>analysis' is not an offered tool |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/gpt-oss/imported.jsonl --id gpt-oss/llamacpp-stray-commentary-header --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/gpt-oss/imported.jsonl.
Observed
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
{
"content": "Hello, world!\nWhat's up?",
"reasoning_content": null,
"tool_calls": [
{
"arguments": {
"<arguments_raw, not valid JSON>": "I'm\nthinking"
},
"name": "assistant<|channel|>analysis"
}
]
}
Fixture
Provenance: engine_test, https://github.com/ggml-org/llama.cpp/blob/7fe450e19305b828c199d602c23a8337aaa1f03b/tests/test-chat.cpp#L6540-L6546.
Tags: no-call, reasoning, malformed, x-malformed-channel.
Expected graceful failure: Stray '<|channel|>commentary to=assistant' header before the analysis channel. llama.cpp recovers reasoning 'I'm\nthinking' and content 'Hello, world!\nWhat's up?'; openai-harmony's non-strict parser keeps the content but drops the reasoning. Either way there is no tool call and the turn must not error. (accept: no_tool_calls).
Raw output
<|channel|>commentary to=assistant<|channel|>analysis<|message|>I'm thinking<|end|><|start|>assistant<|channel|>final<|message|>Hello, world! What's up?
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "gpt-oss/llamacpp-stray-commentary-header", "family": "gpt-oss", "models": ["openai/gpt-oss-20b", "openai/gpt-oss-120b"], "spec_version": "0.1", "provenance": {"kind": "engine_test", "source_url": "https://github.com/ggml-org/llama.cpp/blob/7fe450e19305b828c199d602c23a8337aaa1f03b/tests/test-chat.cpp#L6540-L6546", "revision": "7fe450e19305b828c199d602c23a8337aaa1f03b", "license": "MIT", "generator": "scripts/fixtures/gpt-oss/import_gpt_oss.py", "attribution": "Copyright (c) 2023-2026 The ggml authors (MIT)."}, "tools": [{"type": "function", "function": {"name": "special_function", "parameters": {"type": "object", "properties": {"arg1": {"type": "integer", "description": "The arg."}}, "required": ["arg1"]}, "description": "I'm special"}}], "raw_output": "<|channel|>commentary to=assistant<|channel|>analysis<|message|>I'm\nthinking<|end|><|start|>assistant<|channel|>final<|message|>Hello, world!\nWhat's up?", "output_token_ids": [200005, 12606, 815, 316, 28, 173781, 200005, 35644, 200008, 15390, 198, 149404, 200007, 200006, 173781, 200005, 17196, 200008, 13225, 11, 2375, 4175, 45350, 869, 30], "tokenizer": {"repo": "openai/gpt-oss-20b", "revision": "6cee5e81ee83917806bbde320786a8fb61efebee", "mode": "hf"}, "expected_error": {"reason": "Stray '<|channel|>commentary to=assistant' header before the analysis channel. llama.cpp recovers reasoning 'I'm\\nthinking' and content 'Hello, world!\\nWhat's up?'; openai-harmony's non-strict parser keeps the content but drops the reasoning. Either way there is no tool call and the turn must not error.", "accept": ["no_tool_calls"]}, "tags": ["no-call", "reasoning", "malformed", "x-malformed-channel"], "notes": "Edge case '<|channel|>commentary to=assistant' before reasoning (the stray header llama.cpp #21286 tolerates)."}
Parser configuration
{
"chat_template_kwargs": {},
"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": "<|start|>assistant",
"generation_prompt_match": true,
"is_harmony": true,
"model": "openai/gpt-oss-20b",
"model_rule": "gpt-oss",
"model_type": "gpt_oss",
"parser_source": "vLLM gpt-oss recipe; HarmonyParser (is_harmony)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "<|end|><|start|>user<|message|>Use the tools to answer.<|end|><|start|>assistant",
"reasoning_parser": "openai_gptoss",
"stop_token_in_final_delta": false,
"template": {
"openai_harmony": "0.0.8",
"source": "openai_harmony via vLLM OnlineRenderer._make_request_with_harmony (no Jinja template)"
},
"tokenizer": {
"mode": "hf",
"repo": "openai/gpt-oss-20b",
"requested_mode": "auto",
"resolved_revision": "6cee5e81ee83917806bbde320786a8fb61efebee",
"revision": "6cee5e81ee83917806bbde320786a8fb61efebee",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "openai",
"units_source": "fixture.output_token_ids"
}
fail gpt-oss/vllm-malformed-headers
stream_equals_nonstream
| Check | Strategy | Result | Detail |
|---|---|---|---|
stream_equals_nonstream | one | fail | content: nonstream 'thinking\n<|start|>assistant<|channel|>final {"answer": "hi"}', got 'thinking<|start|>assistant<|channel|>final {"answer": "hi"}' |
stream_equals_nonstream | special | fail | content: nonstream 'thinking\n<|start|>assistant<|channel|>final {"answer": "hi"}', got 'thinking<|start|>assistant<|channel|>final {"answer": "hi"}' |
stream_equals_nonstream | token | fail | content: nonstream 'thinking\n<|start|>assistant<|channel|>final {"answer": "hi"}', got 'thinking<|start|>assistant<|channel|>final {"answer": "hi"}' |
stream_equals_nonstream | rand:1:8 | fail | content: nonstream 'thinking\n<|start|>assistant<|channel|>final {"answer": "hi"}', got 'thinking<|start|>assistant<|channel|>final {"answer": "hi"}' |
stream_equals_nonstream | rand:2:8 | fail | content: nonstream 'thinking\n<|start|>assistant<|channel|>final {"answer": "hi"}', got 'thinking<|start|>assistant<|channel|>final {"answer": "hi"}' |
stream_equals_nonstream | rand:3:8 | fail | content: nonstream 'thinking\n<|start|>assistant<|channel|>final {"answer": "hi"}', got 'thinking<|start|>assistant<|channel|>final {"answer": "hi"}' |
stream_equals_nonstream | rand:4:8 | fail | content: nonstream 'thinking\n<|start|>assistant<|channel|>final {"answer": "hi"}', got 'thinking<|start|>assistant<|channel|>final {"answer": "hi"}' |
stream_equals_nonstream | rand:5:8 | fail | content: nonstream 'thinking\n<|start|>assistant<|channel|>final {"answer": "hi"}', got 'thinking<|start|>assistant<|channel|>final {"answer": "hi"}' |
Minimal repro
uv run canitoolcall run --engine vllm --fixtures fixtures/gpt-oss/imported.jsonl --id gpt-oss/vllm-malformed-headers --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/gpt-oss/imported.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": "thinking<|start|>assistant<|channel|>final {\"answer\": \"hi\"}",
"reasoning_content": "thinking",
"tool_calls": []
}
Strategies: nonstream
{
"content": "thinking\n<|start|>assistant<|channel|>final {\"answer\": \"hi\"}",
"reasoning_content": "thinking",
"tool_calls": []
}
Fixture
Provenance: engine_test, https://github.com/vllm-project/vllm/blob/ced6857afa0ea7b2e3f0846a62e1394e90f15607/tests/parser/test_harmony.py#L79-L85.
Tags: malformed, no-call, reasoning.
Expected graceful failure: The last message header has no <|message|> token (malformed). There is no tool call; a parser must not crash (vLLM recovers the raw text as content). (accept: no_tool_calls, content_passthrough).
Raw output
<|channel|>analysis<|message|>thinking<|end|><|start|>assistant<|channel|>commentary<|message|>thinking<|end|><|start|>assistant<|channel|>final {"answer": "hi"}
Fixture record (JSONL, ready to vendor into an engine's tests)
{"id": "gpt-oss/vllm-malformed-headers", "family": "gpt-oss", "models": ["openai/gpt-oss-20b", "openai/gpt-oss-120b"], "spec_version": "0.1", "provenance": {"kind": "engine_test", "source_url": "https://github.com/vllm-project/vllm/blob/ced6857afa0ea7b2e3f0846a62e1394e90f15607/tests/parser/test_harmony.py#L79-L85", "revision": "ced6857afa0ea7b2e3f0846a62e1394e90f15607", "license": "Apache-2.0", "generator": "scripts/fixtures/gpt-oss/import_gpt_oss.py", "attribution": "Copyright contributors to the vLLM project (Apache-2.0)."}, "tools": [{"type": "function", "function": {"name": "get_weather", "parameters": {"type": "object", "properties": {"location": {"type": "string"}}}}}], "raw_output": "<|channel|>analysis<|message|>thinking<|end|><|start|>assistant<|channel|>commentary<|message|>thinking<|end|><|start|>assistant<|channel|>final {\"answer\": \"hi\"}", "output_token_ids": [200005, 35644, 200008, 149404, 200007, 200006, 173781, 200005, 12606, 815, 200008, 149404, 200007, 200006, 173781, 200005, 17196, 10494, 17021, 1243, 392, 3686, 18583], "tokenizer": {"repo": "openai/gpt-oss-20b", "revision": "6cee5e81ee83917806bbde320786a8fb61efebee", "mode": "hf"}, "expected_error": {"reason": "The last message header has no <|message|> token (malformed). There is no tool call; a parser must not crash (vLLM recovers the raw text as content).", "accept": ["no_tool_calls", "content_passthrough"]}, "tags": ["malformed", "no-call", "reasoning"], "notes": "malformed_msgs_str fixture, joined as in test_malformed_msgs_recovers_raw_content. The trailing stop token <|return|> was removed (raw_output ends before the stop token)."}
Parser configuration
{
"chat_template_kwargs": {},
"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": "<|start|>assistant",
"generation_prompt_match": true,
"is_harmony": true,
"model": "openai/gpt-oss-20b",
"model_rule": "gpt-oss",
"model_type": "gpt_oss",
"parser_source": "vLLM gpt-oss recipe; HarmonyParser (is_harmony)",
"pinned_version": "0.30.0",
"prompt_messages": [
{
"content": "Use the tools to answer.",
"role": "user"
}
],
"prompt_tail": "<|end|><|start|>user<|message|>Use the tools to answer.<|end|><|start|>assistant",
"reasoning_parser": "openai_gptoss",
"stop_token_in_final_delta": false,
"template": {
"openai_harmony": "0.0.8",
"source": "openai_harmony via vLLM OnlineRenderer._make_request_with_harmony (no Jinja template)"
},
"tokenizer": {
"mode": "hf",
"repo": "openai/gpt-oss-20b",
"requested_mode": "auto",
"resolved_revision": "6cee5e81ee83917806bbde320786a8fb61efebee",
"revision": "6cee5e81ee83917806bbde320786a8fb61efebee",
"tokenizer_class": "transformers.tokenization_utils_tokenizers.TokenizersBackend"
},
"tool_choice": "auto (tools and tool_choice omitted when the fixture offers no tools)",
"tool_parser": "openai",
"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