|
|
@@ -238,6 +238,8 @@ def test_benchmark_result_models_are_strict_and_allow_nullable_metrics():
|
|
|
fallback_count=None,
|
|
|
tool_count=None,
|
|
|
event_names=[],
|
|
|
+ batch_event_names=[],
|
|
|
+ tool_event_names=[],
|
|
|
event_sources=[],
|
|
|
tool_statuses=[],
|
|
|
tool_latencies_ms=[],
|
|
|
@@ -510,6 +512,12 @@ async def test_mock_runner_is_ordered_ignores_factory_and_reports_event_ledgers(
|
|
|
assert {tuple(item.event_names) for item in search_results} == {
|
|
|
("knowledge.web.search",)
|
|
|
}
|
|
|
+ assert {tuple(item.batch_event_names) for item in search_results} == {
|
|
|
+ ("knowledge.web.search",)
|
|
|
+ }
|
|
|
+ assert {tuple(item.tool_event_names) for item in search_results} == {
|
|
|
+ ("knowledge.web.search",)
|
|
|
+ }
|
|
|
assert {tuple(item.tool_statuses) for item in search_results} == {("success",)}
|
|
|
assert {
|
|
|
tuple(item.event_sources) for item in search_results
|
|
|
@@ -526,6 +534,8 @@ async def test_mock_runner_is_ordered_ignores_factory_and_reports_event_ledgers(
|
|
|
if item.case_id is benchmark.BenchmarkCaseId.ORDINARY_CHAT
|
|
|
]
|
|
|
assert all(item.event_names == [] for item in ordinary_results)
|
|
|
+ assert all(item.batch_event_names == [] for item in ordinary_results)
|
|
|
+ assert all(item.tool_event_names == [] for item in ordinary_results)
|
|
|
assert all(item.tool_count == 0 for item in ordinary_results)
|
|
|
|
|
|
|
|
|
@@ -630,6 +640,12 @@ async def test_runner_continues_after_one_factory_failure():
|
|
|
|
|
|
assert [result.status for result in results] == ["failed", "passed"]
|
|
|
assert results[0].error == "first factory failed"
|
|
|
+ assert results[0].model_call_count == 0
|
|
|
+ assert results[0].fallback_count == 0
|
|
|
+ assert results[0].prompt_tokens is None
|
|
|
+ assert results[0].completion_tokens is None
|
|
|
+ assert results[0].total_tokens is None
|
|
|
+ assert results[0].cached_tokens is None
|
|
|
assert results[1].error is None
|
|
|
assert clients[0].closed is True
|
|
|
|
|
|
@@ -802,6 +818,8 @@ def _semantic_failures_for_counts(
|
|
|
outputs=[{"type": "message_delta", "content": "Ordinary answer."}],
|
|
|
audits=[],
|
|
|
event_names=[],
|
|
|
+ batch_event_names=[],
|
|
|
+ tool_event_names=[],
|
|
|
event_sources=[],
|
|
|
tool_statuses=[],
|
|
|
model_call_count=ledger_model_count,
|
|
|
@@ -851,3 +869,228 @@ def test_semantics_keep_timing_vs_ledger_consistency_failure():
|
|
|
"model_call_count expected 1, timing got 2",
|
|
|
"model_call_count ledger=1, timing=2",
|
|
|
]
|
|
|
+
|
|
|
+
|
|
|
+def test_build_result_rejects_wrong_event_identity_in_all_ledgers_and_pairs_status():
|
|
|
+ config = benchmark.BenchmarkConfig(
|
|
|
+ schema_version=1,
|
|
|
+ base_url="https://provider.example/v1",
|
|
|
+ model="benchmark-model",
|
|
|
+ cases=[benchmark.BenchmarkCaseId.DEVICE_VOLUME_SILENT],
|
|
|
+ modes=[benchmark.BenchmarkMode.DUAL_AGENT],
|
|
|
+ )
|
|
|
+ runner = benchmark.BenchmarkRunner(config, api_key=None, mock=True)
|
|
|
+ timing = benchmark.BenchmarkModelCallTiming(
|
|
|
+ call_index=1,
|
|
|
+ call_kind="chat_completion",
|
|
|
+ first_item_kind="raw_chunk",
|
|
|
+ provider_ttft_ms=1,
|
|
|
+ visible_ttft_ms=2,
|
|
|
+ elapsed_ms=3,
|
|
|
+ usage=TokenUsage(total_tokens=5),
|
|
|
+ )
|
|
|
+
|
|
|
+ result = runner._build_result(
|
|
|
+ case=benchmark.BENCHMARK_CASE_CATALOG[
|
|
|
+ benchmark.BenchmarkCaseId.DEVICE_VOLUME_SILENT
|
|
|
+ ],
|
|
|
+ mode=benchmark.BenchmarkMode.DUAL_AGENT,
|
|
|
+ iteration=1,
|
|
|
+ outputs=[
|
|
|
+ {
|
|
|
+ "type": "message_delta",
|
|
|
+ "content": "I will set the volume to 30.",
|
|
|
+ },
|
|
|
+ {"type": "tool_result", "message": {}},
|
|
|
+ ],
|
|
|
+ audits=[
|
|
|
+ {
|
|
|
+ "event": "chat_event_detected",
|
|
|
+ "details": {
|
|
|
+ "event_name": "wrong.detected",
|
|
|
+ "event_source": "text_event",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "event": "event_batch_results",
|
|
|
+ "details": {
|
|
|
+ "results": [
|
|
|
+ {"event_name": "wrong.batch", "status": "success"}
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ usage={
|
|
|
+ "calls": [
|
|
|
+ {
|
|
|
+ "call_kind": "chat_completion",
|
|
|
+ "event_name": None,
|
|
|
+ "tool_latency_ms": None,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "call_kind": "tool_execution",
|
|
|
+ "event_name": "wrong.tool",
|
|
|
+ "tool_latency_ms": 4,
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ "session": {
|
|
|
+ "prompt_tokens": 2,
|
|
|
+ "completion_tokens": 3,
|
|
|
+ "total_tokens": 5,
|
|
|
+ "cached_tokens": 0,
|
|
|
+ "fallback_count": 0,
|
|
|
+ "tool_count": 1,
|
|
|
+ "turn_wall_time_ms": 10,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ timings=[timing],
|
|
|
+ visible_ttft_ms=2,
|
|
|
+ runtime_error=None,
|
|
|
+ )
|
|
|
+
|
|
|
+ assert result.status == "failed"
|
|
|
+ assert result.event_names == ["wrong.detected"]
|
|
|
+ assert result.batch_event_names == ["wrong.batch"]
|
|
|
+ assert result.tool_event_names == ["wrong.tool"]
|
|
|
+ assert result.tool_statuses == ["success"]
|
|
|
+ assert result.semantic_failures == [
|
|
|
+ "event names expected ('device.volume.adjust',), got ('wrong.detected',)",
|
|
|
+ "batch event names expected ('device.volume.adjust',), got ('wrong.batch',)",
|
|
|
+ "tool event names expected ('device.volume.adjust',), got ('wrong.tool',)",
|
|
|
+ "event batch statuses expected "
|
|
|
+ "(('device.volume.adjust', 'success'),), got (('wrong.batch', 'success'),)",
|
|
|
+ ]
|
|
|
+
|
|
|
+
|
|
|
+def test_build_result_reports_timing_attempt_counts_and_flags_ledger_mismatch():
|
|
|
+ config = benchmark.BenchmarkConfig(
|
|
|
+ schema_version=1,
|
|
|
+ base_url="https://provider.example/v1",
|
|
|
+ model="benchmark-model",
|
|
|
+ cases=[benchmark.BenchmarkCaseId.ORDINARY_CHAT],
|
|
|
+ modes=[benchmark.BenchmarkMode.DUAL_AGENT],
|
|
|
+ )
|
|
|
+ runner = benchmark.BenchmarkRunner(config, api_key=None, mock=True)
|
|
|
+ timing = benchmark.BenchmarkModelCallTiming(
|
|
|
+ call_index=1,
|
|
|
+ call_kind="chat_completion",
|
|
|
+ first_item_kind="raw_chunk",
|
|
|
+ provider_ttft_ms=1,
|
|
|
+ visible_ttft_ms=2,
|
|
|
+ elapsed_ms=3,
|
|
|
+ usage=TokenUsage(total_tokens=5),
|
|
|
+ )
|
|
|
+
|
|
|
+ result = runner._build_result(
|
|
|
+ case=benchmark.BENCHMARK_CASE_CATALOG[
|
|
|
+ benchmark.BenchmarkCaseId.ORDINARY_CHAT
|
|
|
+ ],
|
|
|
+ mode=benchmark.BenchmarkMode.DUAL_AGENT,
|
|
|
+ iteration=1,
|
|
|
+ outputs=[{"type": "message_delta", "content": "Ordinary answer."}],
|
|
|
+ audits=[],
|
|
|
+ usage={
|
|
|
+ "calls": [],
|
|
|
+ "session": {
|
|
|
+ "prompt_tokens": 0,
|
|
|
+ "completion_tokens": 0,
|
|
|
+ "total_tokens": 0,
|
|
|
+ "cached_tokens": 0,
|
|
|
+ "fallback_count": 0,
|
|
|
+ "tool_count": 0,
|
|
|
+ "turn_wall_time_ms": 3,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ timings=[timing],
|
|
|
+ visible_ttft_ms=2,
|
|
|
+ runtime_error=None,
|
|
|
+ )
|
|
|
+
|
|
|
+ assert result.status == "failed"
|
|
|
+ assert result.model_call_count == 1
|
|
|
+ assert result.fallback_count == 0
|
|
|
+ assert result.semantic_failures == [
|
|
|
+ "model_call_count expected 1, ledger got 0",
|
|
|
+ "model_call_count ledger=0, timing=1",
|
|
|
+ ]
|
|
|
+
|
|
|
+
|
|
|
+def test_failed_result_uses_timing_attempt_counts_and_returned_usage():
|
|
|
+ timings = [
|
|
|
+ benchmark.BenchmarkModelCallTiming(
|
|
|
+ call_index=1,
|
|
|
+ call_kind="chat_completion",
|
|
|
+ first_item_kind="raw_chunk",
|
|
|
+ provider_ttft_ms=1,
|
|
|
+ visible_ttft_ms=2,
|
|
|
+ elapsed_ms=3,
|
|
|
+ usage=TokenUsage(
|
|
|
+ prompt_tokens=2,
|
|
|
+ completion_tokens=3,
|
|
|
+ total_tokens=5,
|
|
|
+ cached_tokens=1,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ benchmark.BenchmarkModelCallTiming(
|
|
|
+ call_index=2,
|
|
|
+ call_kind="argument_fallback",
|
|
|
+ first_item_kind="raw_chunk",
|
|
|
+ provider_ttft_ms=4,
|
|
|
+ visible_ttft_ms=None,
|
|
|
+ elapsed_ms=6,
|
|
|
+ usage=TokenUsage(
|
|
|
+ prompt_tokens=7,
|
|
|
+ completion_tokens=11,
|
|
|
+ total_tokens=18,
|
|
|
+ cached_tokens=2,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ]
|
|
|
+
|
|
|
+ result = benchmark.BenchmarkRunner._failed_result(
|
|
|
+ benchmark.BenchmarkCaseId.ORDINARY_CHAT,
|
|
|
+ benchmark.BenchmarkMode.DUAL_AGENT,
|
|
|
+ 1,
|
|
|
+ error="failed before persistence",
|
|
|
+ timings=timings,
|
|
|
+ )
|
|
|
+
|
|
|
+ assert result.model_call_count == 1
|
|
|
+ assert result.fallback_count == 1
|
|
|
+ assert (
|
|
|
+ result.prompt_tokens,
|
|
|
+ result.completion_tokens,
|
|
|
+ result.total_tokens,
|
|
|
+ result.cached_tokens,
|
|
|
+ ) == (9, 14, 23, 3)
|
|
|
+ assert result.batch_event_names == []
|
|
|
+ assert result.tool_event_names == []
|
|
|
+
|
|
|
+
|
|
|
+def test_failed_result_keeps_tokens_nullable_when_no_timing_usage_returned():
|
|
|
+ timing = benchmark.BenchmarkModelCallTiming(
|
|
|
+ call_index=1,
|
|
|
+ call_kind="chat_completion",
|
|
|
+ first_item_kind="raw_chunk",
|
|
|
+ provider_ttft_ms=1,
|
|
|
+ visible_ttft_ms=None,
|
|
|
+ elapsed_ms=2,
|
|
|
+ usage=None,
|
|
|
+ )
|
|
|
+
|
|
|
+ result = benchmark.BenchmarkRunner._failed_result(
|
|
|
+ benchmark.BenchmarkCaseId.ORDINARY_CHAT,
|
|
|
+ benchmark.BenchmarkMode.DUAL_AGENT,
|
|
|
+ 1,
|
|
|
+ error="failed without usage",
|
|
|
+ timings=[timing],
|
|
|
+ )
|
|
|
+
|
|
|
+ assert result.model_call_count == 1
|
|
|
+ assert result.fallback_count == 0
|
|
|
+ assert (
|
|
|
+ result.prompt_tokens,
|
|
|
+ result.completion_tokens,
|
|
|
+ result.total_tokens,
|
|
|
+ result.cached_tokens,
|
|
|
+ ) == (None, None, None, None)
|