nemo_voice_agent.evaluation.runner
nemo_voice_agent.evaluation.runner
Dynamic Voice Agent Evaluation Runner
Runs evaluation scenarios with dynamic system prompt updates. Accepts structured Scenario objects instead of raw dicts.
Module Contents
Classes
Functions
API
Bases: enum.Enum
Policies used to decide whether a scenario reached a valid end state.
Run-level metric accumulator.
Holds per-signal pass-rate buckets + per-domain breakdowns + per-side
token totals across all scenarios in a run. add_scenario(metrics, domain)
folds a per-scenario metrics dict into all buckets uniformly — used by
both the freshly-run path (after computing metrics) and the resume-skip
path (after loading metrics.json from disk for an already-completed
scenario). Centralizing this logic guarantees the final all_summary.txt
aggregate is identical regardless of whether a scenario ran live or was
loaded from a prior session.
Bucket lists are kept as flat List[bool|float] (not keyed by
SuccessSignal) so the existing downstream consumers in
run_dynamic_evaluation (summary writer, per-domain rollups) can
reference them by name without changing 100+ call sites. Dict-key
lookups on incoming metrics use SuccessSignal.* members directly
(StrEnum makes them str-equal to their JSON-key values).
Append one scenario’s metrics into all run-level + per-domain buckets.
Idempotent against incomplete metrics dicts — each signal is only
appended when its corresponding key is present and well-typed in
metrics. Signals not opted into by the scenario (no
expected_scenario_db, no NL assertions, etc.) simply don’t
contribute to their bucket.
SuccessSignal enum members are used as the dict keys when
looking up signal values in metrics — StrEnum members compare
equal to their string values, so this preserves byte-stability of
the on-disk metrics.json format while pinning the lookup to a
typo-resistant symbol.
When min_agent_turns > 0, scenarios with fewer agent LLM responses
(stalled agent) are counted as failures in the composite success/task
buckets, skipped in the per-signal buckets (those measurements are
meaningless for a run that stalled), and recorded in
insufficient_turns_skipped for the resume warning. Token usage is
still rolled up so cost accounting stays accurate.
Decide whether a just-finished scenario attempt should be re-run.
Returns a short reason string when the attempt should be retried, or
None to accept it.
Two triggers, deliberately separated by how certain the failure is:
- Hard failure (
turn_count == 0): not a single conversation turn was exchanged, so the bots never talked and no measurement exists. Re-running cannot bias the score because there is no score to bias. This mirrors the"0 turns (bot crashed before audio)"case inclassify_scenario_resume_state. Governed byon_stale(default True). - Soft heuristic (
0 < agent_llm_count < min_agent_turns): the agent responded, but fewer times than the floor. This is only a proxy for a stalled backend — legitimately short scenarios (refusals, quick lookups) sit right on the floor. Becauseinsufficient_turnsforcesis_successful=False, retrying converts a guaranteed failure into a fresh draw, which inflates scores whenever the heuristic fires on a scenario that would have passed. Governed byon_insufficient_turns, which defaults to False for that reason.
Turn count, not token_usage, gates the hard trigger on purpose.
token_usage.agent.n_calls only increments when the agent emits an RTVI
token-usage message, so a backend that does not report usage would read as
zero on a perfectly healthy run — and with on_stale defaulting to True
that would silently re-run every scenario. Turn count comes from the
bridge’s own conversation record and does not depend on backend reporting.
A None count means the signal was unavailable; never retry on a guess.
Return the policy verdict and the concrete evidence that produced it.
Run evaluation with dynamic scenario switching and latency measurement.
Parameters:
WebSocket URL of user (simulated user)
WebSocket URL of agent being tested
Output directory for results
List of Scenario objects defining each evaluation scenario
Audio chunk in seconds for the audio stream (default: 0.016)
Maximum duration per scenario in seconds, which overrides the scenario’s own max_duration if set.
Seconds to pause between scenarios
User TTS output sample rate (default: 24000)
Agent TTS output sample rate (default: 24000)
User STT input sample rate (default: 16000)
Agent STT input sample rate (default: 16000)
Output sample rate for recorded audio (default: 24000)
Timestamp string for output file naming
FileLogger instance for logging
LLMJudge instance for judging the scenario
Threshold for judging the scenario if binary result is desired, None for score based result
If True, include bridge transcript turns in the judge input. Disabled by default because interrupted/cross-talk segments can make these turns noisy.
If True, force disallow_extra_items=True on every scenario for this run,
overriding each scenario’s own setting. Default False respects per-scenario flags.
scenarios with agent turns less than this number will be treated as incomplete
If True (default), immediately re-run a scenario that recorded zero
conversation turns — an unambiguous infrastructure failure with no measurement to bias.
Keyed on the bridge’s turn record rather than token_usage, which reads zero on a
healthy run against a backend that does not report usage.
If True, also re-run scenarios that merely fall below
min_agent_turns. Default False: that floor is a heuristic, legitimately short
scenarios sit on it, and retrying a forced failure biases the score upward.
Maximum automatic re-runs per scenario (default 1). Bounds the loop when the backend is persistently down.
Seconds to wait before an automatic re-run (default 5.0). An immediate retry against a hung backend is the least likely moment to succeed.
Policy for the CLEAN_EXIT gate. tool-only requires the agent’s
EndConversationTool. valid-terminal-state also accepts a simulator-reported end or an inactivity
timeout after the user’s final turn.
Seconds without conversational activity before the bridge stops the scenario.