# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
"""On-demand trace builder for parser engine testing and benchmarks.
Generates token sequences programmatically from model-agnostic scenario
definitions. Each model format handler knows how to render scenarios
into the model's output format, tokenize them with correct special token
IDs, and compute expected parse outputs.
Every generated sample is self-validated by replaying it through the
real parser before being returned.
"""
from __future__ import annotations
import functools
import json
from dataclasses import dataclass
from typing import Any
from tests.parser.engine.replay_harness import (
MockTokenizer,
Sample,
assert_parse_output,
collect_output,
replay_streaming,
)
from vllm.entrypoints.openai.chat_completion.protocol import (
ChatCompletionToolsParam,
)
from vllm.parser.engine.registered_adapters import (
DeepSeekV4Parser,
DeepSeekV32Parser,
Gemma4Parser,
Glm47MoeParser,
KimiK2Parser,
MinimaxM2Parser,
NemotronV3Parser,
Qwen3Parser,
SeedOssParser,
)
# ── Data structures ──────────────────────────────────────────────────
@dataclass
class ToolCallSpec:
name: str
arguments: dict[str, Any]
@dataclass
class Scenario:
id: str
description: str
reasoning: str | None = None
content: str | None = None
tool_calls: list[ToolCallSpec] | None = None
after_tool_response: bool = False
# ── Scenarios ────────────────────────────────────────────────────────
_READ_TOOL = ToolCallSpec("read_file", {"path": "/tmp/test.txt"})
_BASH_TOOL = ToolCallSpec(
"bash", {"command": "hostname", "description": "Get hostname"}
)
_WEATHER_TOOL = ToolCallSpec(
"get_weather",
{"city": "Dallas", "state": "TX", "unit": "fahrenheit"},
)
_COMPLEX_TOOL = ToolCallSpec(
"search",
{
"query": "vllm parser",
"filters": {"language": "python", "min_stars": 100},
"tags": ["ml", "inference"],
"limit": 10,
"verbose": True,
},
)
SCENARIOS: list[Scenario] = [
Scenario(
id="think-then-tool",
description="Reasoning then single tool call",
reasoning="Let me check the file.",
tool_calls=[_READ_TOOL],
),
Scenario(
id="think-then-parallel-tools",
description="Reasoning then two parallel tool calls",
reasoning="I need to run both commands.",
tool_calls=[_BASH_TOOL, _WEATHER_TOOL],
),
Scenario(
id="think-then-content",
description="Reasoning then content response",
reasoning="Let me think about this carefully.",
content="The answer is 42.",
),
Scenario(
id="content-only",
description="Plain content response without reasoning",
content="Hello! How can I help you today?",
),
Scenario(
id="tool-only",
description="Tool call without reasoning",
tool_calls=[_READ_TOOL],
),
Scenario(
id="complex-json-args",
description="Tool call with nested objects, arrays, numbers, booleans",
reasoning="This needs a complex query.",
tool_calls=[_COMPLEX_TOOL],
),
Scenario(
id="whitespace-before-tool",
description="Whitespace-only content before tool call",
content="\n\n",
tool_calls=[_WEATHER_TOOL],
),
Scenario(
id="think-content-tool",
description="Reasoning, content, then tool call",
reasoning="Let me analyze and then fetch data.",
content="Checking the weather now.",
tool_calls=[_WEATHER_TOOL],
),
Scenario(
id="think-whitespace-tool",
description="Reasoning, whitespace-only gap, then tool call",
reasoning="Let me check the file contents.",
content="\n\n",
tool_calls=[_READ_TOOL],
),
Scenario(
id="empty-reasoning-content",
description="Empty reasoning section followed by content",
reasoning="",
content="The epoch timestamp is 1779111346.",
),
Scenario(
id="tool-after-tool-response",
description="Tool call immediately after tool response (agentic flow)",
tool_calls=[_READ_TOOL],
after_tool_response=True,
),
Scenario(
id="empty-tool-block",
description="Empty tool block followed by content (edge case recovery)",
content="Content after empty tools.",
tool_calls=[],
),
]
# ── Tokenization ─────────────────────────────────────────────────────
def _word_split(text: str) -> list[str]:
"""Split text into word-like tokens, preserving all characters."""
if not text:
return []
parts: list[str] = []
current = ""
for ch in text:
if ch in " \t\n\r" and current and current[-1] not in " \t\n\r":
parts.append(current)
current = ch
else:
current += ch
if current:
parts.append(current)
return parts
def _tokenize(
segments: list[tuple[str, bool]],
vocab: dict[str, int],
start_id: int = 100,
) -> list[tuple[int, str]]:
"""Build token list from segments.
Each segment is ``(text, is_special)``. Special segments use vocab
IDs; content segments are word-split with sequential IDs.
"""
tokens: list[tuple[int, str]] = []
next_id = start_id
for text, is_special in segments:
if not text:
continue
if is_special:
tid = vocab.get(text)
if tid is None:
raise ValueError(f"Special token {text!r} not in vocab")
tokens.append((tid, text))
else:
for word in _word_split(text):
tokens.append((next_id, word))
next_id += 1
return tokens
# ── Tool definitions ─────────────────────────────────────────────────
def _infer_schema(value: object) -> dict:
"""Infer a JSON Schema from a Python value, recursing into dicts/lists."""
if isinstance(value, bool):
return {"type": "boolean"}
if isinstance(value, int):
return {"type": "integer"}
if isinstance(value, float):
return {"type": "number"}
if isinstance(value, str):
return {"type": "string"}
if isinstance(value, dict):
return {
"type": "object",
"properties": {k: _infer_schema(v) for k, v in value.items()},
}
if isinstance(value, list) and value:
return {"type": "array", "items": _infer_schema(value[0])}
if isinstance(value, list):
return {"type": "array"}
return {}
def _tool_defs(tool_calls: list[ToolCallSpec]) -> list[dict]:
"""Generate OpenAI-style tool definitions from tool call specs."""
seen: set[str] = set()
tools: list[dict] = []
for tc in tool_calls:
if tc.name in seen:
continue
seen.add(tc.name)
properties = {k: _infer_schema(v) for k, v in tc.arguments.items()}
tools.append(
{
"type": "function",
"function": {
"name": tc.name,
"parameters": {
"type": "object",
"properties": properties,
},
},
}
)
return tools
# ── Format handlers ──────────────────────────────────────────────────
def _expected_tc(scenario: Scenario) -> list[dict] | None:
if not scenario.tool_calls:
return None
return [{"name": tc.name, "arguments": tc.arguments} for tc in scenario.tool_calls]
def _expected_tools(scenario: Scenario) -> list[dict] | None:
return _tool_defs(scenario.tool_calls) if scenario.tool_calls else None
def _validate_sample(sample: Sample, parser_cls: type, **kwargs) -> None:
"""Replay sample through the real parser and assert correctness."""
tokenizer = MockTokenizer(vocab=dict(sample.vocab), tokens=sample.tokens)
parser = parser_cls(tokenizer, sample.tools, **kwargs)
deltas = replay_streaming(
parser,
sample.tokens,
chunk_size=1,
tools=sample.tools,
prompt_token_ids=sample.prompt_token_ids,
)
output = collect_output(deltas)
assert_parse_output(output, sample)
def _validate_tools(
tools: list[dict] | None,
) -> list[ChatCompletionToolsParam] | None:
if not tools:
return None
return [ChatCompletionToolsParam.model_validate(t) for t in tools]
def _make_sample(
sample_id: str,
description: str,
vocab: dict[str, int],
segments: list[tuple[str, bool]],
expected_reasoning: str | None,
expected_content: str | None,
expected_tool_calls: list[dict] | None,
tools: list[dict] | None,
chat_template_kwargs: dict | None = None,
prompt_token_ids: list[int] | None = None,
) -> Sample:
tokens = _tokenize(segments, vocab)
return Sample(
id=sample_id,
description=description,
source="trace-builder",
vocab=dict(vocab),
tokens=tokens,
expected_reasoning=expected_reasoning,
expected_content=expected_content,
expected_tool_calls=expected_tool_calls,
tools=_validate_tools(tools),
chat_template_kwargs=chat_template_kwargs,
prompt_token_ids=prompt_token_ids,
)
# ── Qwen3 (XML tool format, starts in REASONING) ────────────────────
_QWEN3_VOCAB: dict[str, int] = {
"": 50,
"": 51,
"": 60,
"": 61,
}
def _qwen3_arg_value(value: Any) -> str:
if isinstance(value, bool):
return "true" if value else "false"
if isinstance(value, (int, float)):
return str(value)
if isinstance(value, str):
return value
return json.dumps(value, ensure_ascii=False)
def _qwen3_tool_segments(tc: ToolCallSpec) -> list[tuple[str, bool]]:
parts = [f"\n"]
for key, value in tc.arguments.items():
parts.append(f"\n{_qwen3_arg_value(value)}")
parts.append("\n\n")
return [
("", True),
("".join(parts), False),
("", True),
]
def _qwen3_segments(scenario: Scenario) -> list[tuple[str, bool]]:
segs: list[tuple[str, bool]] = []
if scenario.reasoning is not None:
segs.append((scenario.reasoning, False))
if scenario.content is not None or scenario.tool_calls is not None:
segs.append(("", True))
if scenario.tool_calls is not None and not scenario.tool_calls:
segs.append(("", True))
segs.append(("", True))
if scenario.content is not None:
segs.append((scenario.content, False))
if scenario.tool_calls:
for tc in scenario.tool_calls:
segs.extend(_qwen3_tool_segments(tc))
return segs
def _qwen3_expected_content(scenario: Scenario) -> str | None:
if (
scenario.content is not None
and scenario.tool_calls
and not scenario.content.strip()
):
return ""
return scenario.content
def _build_qwen3(
scenario: Scenario,
name: str = "qwen3",
parser_cls: type = Qwen3Parser,
strip_trailing_ws: bool = False,
validate: bool = True,
) -> Sample:
expected_reasoning: str | None
if scenario.reasoning is not None:
r = scenario.reasoning
if strip_trailing_ws:
r = r.rstrip()
expected_reasoning = r
else:
expected_reasoning = ""
sample = _make_sample(
sample_id=f"{name}-{scenario.id}",
description=scenario.description,
vocab=_QWEN3_VOCAB,
segments=_qwen3_segments(scenario),
expected_reasoning=expected_reasoning,
expected_content=_qwen3_expected_content(scenario),
expected_tool_calls=_expected_tc(scenario),
tools=_expected_tools(scenario),
)
if validate:
_validate_sample(sample, parser_cls)
return sample
# ── MiniMax M2 (XML invoke format, starts in REASONING) ──────────────
_MINIMAX_M2_VOCAB: dict[str, int] = {
"": 50,
"": 51,
"": 60,
"": 61,
}
def _minimax_m2_arg_value(value: Any) -> str:
if isinstance(value, bool):
return "true" if value else "false"
if isinstance(value, (int, float)):
return str(value)
if isinstance(value, str):
return value
return json.dumps(value, ensure_ascii=False)
def _minimax_m2_tool_segments(tool_calls: list[ToolCallSpec]) -> list[tuple[str, bool]]:
segs: list[tuple[str, bool]] = [("", True)]
for tc in tool_calls:
segs.append((f'', False))
for key, value in tc.arguments.items():
segs.append(
(
f''
f"{_minimax_m2_arg_value(value)}"
"",
False,
)
)
segs.append(("", False))
segs.append(("", True))
return segs
def _minimax_m2_segments(scenario: Scenario) -> list[tuple[str, bool]]:
segs: list[tuple[str, bool]] = []
if scenario.reasoning is not None:
segs.append((scenario.reasoning, False))
if scenario.content is not None or scenario.tool_calls is not None:
segs.append(("", True))
if scenario.tool_calls is not None and not scenario.tool_calls:
segs.append(("", True))
segs.append(("", True))
if scenario.content is not None:
segs.append((scenario.content, False))
if scenario.tool_calls:
segs.extend(_minimax_m2_tool_segments(scenario.tool_calls))
return segs
def _build_minimax_m2(scenario: Scenario, validate: bool = True) -> Sample:
expected_reasoning: str | None
if scenario.reasoning is not None:
expected_reasoning = scenario.reasoning.rstrip()
else:
expected_reasoning = ""
sample = _make_sample(
sample_id=f"minimax_m2-{scenario.id}",
description=scenario.description,
vocab=_MINIMAX_M2_VOCAB,
segments=_minimax_m2_segments(scenario),
expected_reasoning=expected_reasoning,
expected_content=_qwen3_expected_content(scenario),
expected_tool_calls=_expected_tc(scenario),
tools=_expected_tools(scenario),
)
if validate:
_validate_sample(sample, MinimaxM2Parser)
return sample
# ── Gemma4 (channel reasoning, custom arg format) ────────────────────
_GEMMA4_VOCAB: dict[str, int] = {
"<|channel>": 50,
"": 51,
"<|tool_call>": 48,
"": 49,
'<|"|>': 52,
"<|turn>": 53,
"<|tool_response>": 54,
}
_GEMMA4_THOUGHT_PREFIX = "thought\n"
_GEMMA4_QUOTE = '<|"|>'
def _gemma4_value_segments(value: Any) -> list[tuple[str, bool]]:
"""Render a value in Gemma4 arg format as segments."""
if isinstance(value, str):
return [(_GEMMA4_QUOTE, True), (value, False), (_GEMMA4_QUOTE, True)]
if isinstance(value, bool):
return [("true" if value else "false", False)]
if isinstance(value, (int, float)):
return [(str(value), False)]
if isinstance(value, dict):
segs: list[tuple[str, bool]] = [("{", False)]
for i, (k, v) in enumerate(value.items()):
if i > 0:
segs.append((",", False))
segs.append((f"{k}:", False))
segs.extend(_gemma4_value_segments(v))
segs.append(("}", False))
return segs
if isinstance(value, list):
segs = [("[", False)]
for i, item in enumerate(value):
if i > 0:
segs.append((",", False))
segs.extend(_gemma4_value_segments(item))
segs.append(("]", False))
return segs
return [(json.dumps(value, ensure_ascii=False), False)]
def _gemma4_tool_segments(tc: ToolCallSpec) -> list[tuple[str, bool]]:
segs: list[tuple[str, bool]] = [
("<|tool_call>", True),
(f"call:{tc.name}", False),
("{", False),
]
for i, (key, value) in enumerate(tc.arguments.items()):
if i > 0:
segs.append((",", False))
segs.append((f"{key}:", False))
segs.extend(_gemma4_value_segments(value))
segs.append(("}", False))
segs.append(("", True))
return segs
def _gemma4_segments(scenario: Scenario) -> list[tuple[str, bool]]:
segs: list[tuple[str, bool]] = []
if scenario.reasoning is not None:
segs.append(("<|channel>", True))
segs.append((_GEMMA4_THOUGHT_PREFIX, False))
segs.append((scenario.reasoning, False))
segs.append(("", True))
if scenario.tool_calls is not None and not scenario.tool_calls:
segs.append(("<|tool_call>", True))
segs.append(("", True))
if scenario.content is not None:
segs.append((scenario.content, False))
if scenario.tool_calls:
for tc in scenario.tool_calls:
segs.extend(_gemma4_tool_segments(tc))
return segs
def _build_gemma4(scenario: Scenario, validate: bool = True) -> Sample:
prompt_token_ids = None
if scenario.after_tool_response:
prompt_token_ids = [_GEMMA4_VOCAB["<|tool_response>"]]
sample = _make_sample(
sample_id=f"gemma4-{scenario.id}",
description=scenario.description,
vocab=_GEMMA4_VOCAB,
segments=_gemma4_segments(scenario),
expected_reasoning=scenario.reasoning,
expected_content=_qwen3_expected_content(scenario),
expected_tool_calls=_expected_tc(scenario),
tools=_expected_tools(scenario),
prompt_token_ids=prompt_token_ids,
)
if validate:
_validate_sample(sample, Gemma4Parser)
return sample
def _build_nemotron_v3(scenario: Scenario, validate: bool = True) -> Sample:
return _build_qwen3(
scenario,
name="nemotron_v3",
parser_cls=NemotronV3Parser,
strip_trailing_ws=True,
validate=validate,
)
# ── Seed-OSS (Qwen3 XML grammar with Seed wrapper tokens) ────────────
_SEED_OSS_VOCAB: dict[str, int] = {
"": 50,
"": 51,
"": 60,
"": 61,
}
def _seed_oss_tool_segments(tc: ToolCallSpec) -> list[tuple[str, bool]]:
parts = [f"\n"]
for key, value in tc.arguments.items():
parts.append(f"\n{_qwen3_arg_value(value)}")
parts.append("\n\n")
return [
("", True),
("".join(parts), False),
("", True),
]
def _seed_oss_segments(scenario: Scenario) -> list[tuple[str, bool]]:
segs: list[tuple[str, bool]] = []
if scenario.reasoning is not None:
segs.append((scenario.reasoning, False))
if scenario.content is not None or scenario.tool_calls is not None:
segs.append(("", True))
if scenario.tool_calls is not None and not scenario.tool_calls:
segs.append(("", True))
segs.append(("", True))
if scenario.content is not None:
segs.append((scenario.content, False))
if scenario.tool_calls:
for tc in scenario.tool_calls:
segs.extend(_seed_oss_tool_segments(tc))
return segs
def _build_seed_oss(scenario: Scenario, validate: bool = True) -> Sample:
sample = _make_sample(
sample_id=f"seed_oss-{scenario.id}",
description=scenario.description,
vocab=_SEED_OSS_VOCAB,
segments=_seed_oss_segments(scenario),
expected_reasoning=scenario.reasoning if scenario.reasoning is not None else "",
expected_content=_qwen3_expected_content(scenario),
expected_tool_calls=_expected_tc(scenario),
tools=_expected_tools(scenario),
)
if validate:
_validate_sample(sample, SeedOssParser)
return sample
# ── DeepSeek V4 (DSML tool format) ──────────────────────────────────
_DSML = "|DSML|"
_DSV4_VOCAB: dict[str, int] = {
"": 128821,
"": 128822,
f"<{_DSML}tool_calls>": 128823,
f"{_DSML}tool_calls>": 128824,
}
def _dsv4_param_text(key: str, value: Any) -> str:
is_string = isinstance(value, str)
if is_string:
val_str = value
elif isinstance(value, bool):
val_str = "true" if value else "false"
elif isinstance(value, (int, float)):
val_str = str(value)
else:
val_str = json.dumps(value, ensure_ascii=False)
string_attr = "true" if is_string else "false"
return (
f'<{_DSML}parameter name="{key}" string="{string_attr}">'
f"{val_str}{_DSML}parameter>\n"
)
def _dsv4_tool_text(tc: ToolCallSpec) -> str:
parts = [f'<{_DSML}invoke name="{tc.name}">\n']
for key, value in tc.arguments.items():
parts.append(_dsv4_param_text(key, value))
parts.append(f"{_DSML}invoke>\n")
return "".join(parts)
def _dsml_tool_segs(
scenario: Scenario,
tag: str,
) -> list[tuple[str, bool]]:
if not scenario.tool_calls:
return []
parts = ["\n"]
for tc in scenario.tool_calls:
parts.append(_dsv4_tool_text(tc))
return [
(f"<{_DSML}{tag}>", True),
("".join(parts), False),
(f"{_DSML}{tag}>", True),
]
def _dsv4_segments(scenario: Scenario, thinking: bool) -> list[tuple[str, bool]]:
segs: list[tuple[str, bool]] = []
if thinking:
if scenario.reasoning is not None:
segs.append((scenario.reasoning, False))
if scenario.content is not None or scenario.tool_calls:
segs.append(("", True))
else:
if scenario.reasoning is not None:
segs.append(("", True))
segs.append((scenario.reasoning, False))
segs.append(("", True))
if scenario.content is not None:
segs.append((scenario.content, False))
segs.extend(_dsml_tool_segs(scenario, "tool_calls"))
return segs
def _build_deepseek_v4(scenario: Scenario, validate: bool = True) -> Sample:
thinking = scenario.reasoning is not None
chat_kwargs = {"thinking": True} if thinking else None
if thinking:
expected_reasoning: str | None = scenario.reasoning or ""
else:
expected_reasoning = None
sample = _make_sample(
sample_id=f"deepseek_v4-{scenario.id}",
description=scenario.description,
vocab=_DSV4_VOCAB,
segments=_dsv4_segments(scenario, thinking),
expected_reasoning=expected_reasoning,
expected_content=_qwen3_expected_content(scenario),
expected_tool_calls=_expected_tc(scenario),
tools=_expected_tools(scenario),
chat_template_kwargs=chat_kwargs,
)
if validate:
kwargs = {}
if chat_kwargs:
kwargs["chat_template_kwargs"] = chat_kwargs
_validate_sample(sample, DeepSeekV4Parser, **kwargs)
return sample
# ── DeepSeek V3.2 (DSML tool format, no reasoning) ──────────────────
_DSV32_VOCAB: dict[str, int] = {
f"<{_DSML}function_calls>": 128830,
f"{_DSML}function_calls>": 128831,
}
def _dsv32_segments(scenario: Scenario) -> list[tuple[str, bool]]:
segs: list[tuple[str, bool]] = []
if scenario.content is not None:
segs.append((scenario.content, False))
segs.extend(_dsml_tool_segs(scenario, "function_calls"))
return segs
def _build_deepseek_v32(scenario: Scenario, validate: bool = True) -> Sample | None:
if scenario.reasoning is not None:
return None
sample = _make_sample(
sample_id=f"deepseek_v32-{scenario.id}",
description=scenario.description,
vocab=_DSV32_VOCAB,
segments=_dsv32_segments(scenario),
expected_reasoning=None,
expected_content=_qwen3_expected_content(scenario),
expected_tool_calls=_expected_tc(scenario),
tools=_expected_tools(scenario),
)
if validate:
_validate_sample(sample, DeepSeekV32Parser)
return sample
# ── GLM-4.7 MoE (XML tool format, starts in REASONING) ──────────────
_GLM47_MOE_VOCAB: dict[str, int] = {
"": 50,
"": 51,
"": 60,
"": 61,
"": 62,
"": 63,
"": 64,
"": 65,
}
def _glm47_moe_arg_value(value: Any) -> str:
if isinstance(value, bool):
return "true" if value else "false"
if isinstance(value, (int, float)):
return str(value)
if isinstance(value, str):
return value
return json.dumps(value, ensure_ascii=False)
def _glm47_moe_tool_segments(tc: ToolCallSpec) -> list[tuple[str, bool]]:
segs: list[tuple[str, bool]] = [
("", True),
(tc.name, False),
]
for key, value in tc.arguments.items():
segs.extend(
[
("", True),
(key, False),
("", True),
("", True),
(_glm47_moe_arg_value(value), False),
("", True),
]
)
segs.append(("", True))
return segs
def _glm47_moe_segments(scenario: Scenario) -> list[tuple[str, bool]]:
segs: list[tuple[str, bool]] = []
if scenario.reasoning is not None:
segs.append((scenario.reasoning, False))
if scenario.content is not None or scenario.tool_calls:
segs.append(("", True))
if scenario.content is not None:
segs.append((scenario.content, False))
if scenario.tool_calls:
for tc in scenario.tool_calls:
segs.extend(_glm47_moe_tool_segments(tc))
return segs
def _build_glm47_moe(scenario: Scenario, validate: bool = True) -> Sample:
sample = _make_sample(
sample_id=f"glm47_moe-{scenario.id}",
description=scenario.description,
vocab=_GLM47_MOE_VOCAB,
segments=_glm47_moe_segments(scenario),
expected_reasoning=scenario.reasoning if scenario.reasoning is not None else "",
expected_content=_qwen3_expected_content(scenario),
expected_tool_calls=_expected_tc(scenario),
tools=_expected_tools(scenario),
)
if validate:
_validate_sample(sample, Glm47MoeParser)
return sample
# ── Kimi K2 (native tool-call section, starts in REASONING) ──────────
_KIMI_K2_VOCAB: dict[str, int] = {
"": 50,
"": 51,
"<|tool_calls_section_begin|>": 60,
"<|tool_calls_section_end|>": 61,
"<|tool_call_begin|>": 62,
"<|tool_call_end|>": 63,
"<|tool_call_argument_begin|>": 64,
}
def _kimi_k2_tool_segments(
tool_calls: list[ToolCallSpec],
) -> list[tuple[str, bool]]:
segs: list[tuple[str, bool]] = [("<|tool_calls_section_begin|>", True)]
for index, tc in enumerate(tool_calls):
args = json.dumps(tc.arguments, ensure_ascii=False, separators=(",", ":"))
segs.extend(
[
("<|tool_call_begin|>", True),
(f"functions.{tc.name}:{index}\n", False),
("<|tool_call_argument_begin|>", True),
(args, False),
("<|tool_call_end|>", True),
]
)
segs.append(("<|tool_calls_section_end|>", True))
return segs
def _kimi_k2_segments(scenario: Scenario) -> list[tuple[str, bool]]:
segs: list[tuple[str, bool]] = []
if scenario.reasoning is not None:
segs.append(("", True))
segs.append((scenario.reasoning, False))
if scenario.content is not None or scenario.tool_calls is not None:
segs.append(("", True))
if scenario.content is not None:
segs.append((scenario.content, False))
if scenario.tool_calls is not None:
segs.extend(_kimi_k2_tool_segments(scenario.tool_calls))
return segs
def _build_kimi_k2(
scenario: Scenario,
validate: bool = True,
thinking: bool = True,
) -> Sample:
expected_reasoning = (
scenario.reasoning.rstrip()
if (thinking and scenario.reasoning is not None)
else None
)
if thinking and scenario.reasoning is None:
expected_reasoning = ""
sample = _make_sample(
sample_id=f"kimi_k2-{scenario.id}",
description=scenario.description,
vocab=_KIMI_K2_VOCAB,
segments=_kimi_k2_segments(scenario),
expected_reasoning=expected_reasoning,
expected_content=_qwen3_expected_content(scenario),
expected_tool_calls=_expected_tc(scenario),
tools=_expected_tools(scenario),
chat_template_kwargs=None if thinking else {"thinking": False},
)
if validate:
_validate_sample(
sample,
KimiK2Parser,
chat_template_kwargs=sample.chat_template_kwargs,
)
return sample
_KIMI_K2_SCENARIOS = [
*SCENARIOS,
Scenario(
id="trailing-reasoning-whitespace",
description="Reasoning trailing whitespace is stripped",
reasoning="Reasoning with trailing whitespace. \n\t",
content="Done.",
),
]
# ── Registry and public API ──────────────────────────────────────────
_BUILDERS: dict[str, Any] = {
"deepseek_v32": _build_deepseek_v32,
"deepseek_v4": _build_deepseek_v4,
"gemma4": _build_gemma4,
"minimax_m2": _build_minimax_m2,
"nemotron_v3": _build_nemotron_v3,
"seed_oss": _build_seed_oss,
"glm47_moe": _build_glm47_moe,
"kimi_k2": _build_kimi_k2,
"qwen3": _build_qwen3,
}
@functools.cache
def build_samples(model: str) -> tuple[Sample, ...]:
"""Build all scenario samples for a model, self-validated."""
builder = _BUILDERS[model]
scenarios = _KIMI_K2_SCENARIOS if model == "kimi_k2" else SCENARIOS
return tuple(s for s in (builder(sc) for sc in scenarios) if s is not None)
def build_sample(model: str, scenario: Scenario) -> Sample | None:
"""Build a single sample for one model + scenario."""
return _BUILDERS[model](scenario)
def build_scaling_sample(
model: str, token_count: int, validate: bool = False
) -> Sample:
"""Build a sample with approximately *token_count* tokens."""
sentence = "The quick brown fox jumps over the lazy dog. "
text = sentence * (token_count // 10 + 1)
scenario = Scenario(
id=f"scaling-{token_count}",
description=f"Scaling test with ~{token_count} tokens",
reasoning=text,
tool_calls=[_READ_TOOL],
)
return _BUILDERS[model](scenario, validate=validate)