Skip to content

Commit f2d1345

Browse files
TEST-273 docs: document transcriber and endpointing simulation latency limits and the unmeasured flag (#1382)
Linear: [TEST-273 Sims: add transcriber and endpointing latency limits by marking unmeasured turns in Lasensor](https://linear.app/vapi/issue/TEST-273/sims-add-transcriber-and-endpointing-latency-limits-by-marking). Stacked on #1381. **Hold: merge after [VapiAI/vapi#25252](VapiAI/vapi#25252) deploys.** That PR adds the two metrics; it is itself held until [VapiAI/vapi#25251](VapiAI/vapi#25251) (the `unmeasured` flag) has been live for a week. ## Description - **Simulation latency limits:** add `transcriber` and `endpointing` to the dashboard metric list, the cURL example and the metrics table. Replace "turns that recorded 0 for model or voice are left out" with the general rule: a turn counts toward a metric unless its `unmeasured` list names that metric, a real 0 ms counts, and `turn` counts every turn. Troubleshooting now points at each turn's `unmeasured` list. - **Per-turn latency on a call:** document `TurnLatency.unmeasured`: what it means, that it's omitted when everything was measured, that older entries lack it, and when each component is listed (wording from the field's API description in #25251). The averages bullet now says sims skip flagged turns. ## Testing Steps - [x] Pinned Fern 5.151.1 check: 0 errors and the same 15 existing warnings. - [x] `git diff --check` passes. - [ ] In the preview, check the nested list under **Understanding latency → Per-turn latency on a call** renders, and the new rows in **Simulations → Advanced → Metrics and aggregations**. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
1 parent 995ce39 commit f2d1345

2 files changed

Lines changed: 15 additions & 6 deletions

File tree

‎fern/assistants/model-intelligence/understanding-latency.mdx‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,14 @@ Keep these points in mind when you read the numbers:
3737
- **Model and voice latency include more than the provider.** The `modelLatency` field includes knowledge base retrieval and request routing before the provider request. The `voiceLatency` field includes the time spent collecting enough of the reply to send the first voice request. The `minCharacters` and `punctuationBoundaries` settings in `voice.chunkPlan` control that wait. The field also includes any sample-rate conversion after the provider returns audio.
3838
- **Vapi measures on its servers.** None of the fields include network time to or from the caller, or playback on the caller's device.
3939
- **Only replies to the caller are recorded.** Turns where the assistant didn't speak, for example because the caller interrupted first, have no entry. When the assistant speaks first, its first message has no entry either. When it waits for the caller (`firstMessageMode` set to `assistant-waits-for-user`), the first message is recorded as a reply, with `endpointingLatency` as `0`.
40-
- **A value of `0` can mean "not measured".** A stage that didn't run or wasn't measured on a turn is recorded as `0` rather than left out. For example, when a turn's first audio is a static tool message rather than model output, `modelLatency` and `voiceLatency` are `0`. When `transcriberLatency` is `0` because it wasn't measured, `turnLatency` leaves that interval out too.
41-
- **Averages count every turn.** The call's `modelLatencyAverage`, `voiceLatencyAverage`, and other averages divide by every entry, including those zeros. Simulation latency limits ignore a `0` for `modelLatency` and `voiceLatency`, so a simulation's model or voice result can be higher than the call's average for the same call.
40+
- **The `unmeasured` list tells a missing value from a real `0`.** A stage that didn't run or wasn't measured on a turn is recorded as `0`, and the entry's `unmeasured` array names it. A `0` for a component that isn't listed is a real 0 ms. The array is left out when every component was measured. Entries recorded before `unmeasured` existed don't have it, so a `0` there can mean either. A component is listed when:
41+
- `transcriber`: voice activity detection saw no speech for the turn, more than 10 seconds passed between the caller's last detected speech and the transcript, or the speech that detection last saw had already been answered by an earlier turn. Those last two usually mean detection missed this speech. It's also listed when the transcript's text was first seen before the caller started this speech, or when detection still hadn't confirmed the end of speech when the reply started. That last case includes a caller who kept talking after a short pause. In that case, `transcriberLatency` is measured from when the speech started or from the pause they talked through, so it can be above `0`.
42+
- `endpointing`: no caller transcript was sent to the model that turn, for example the first message or a reply to a tool result, or the transcript's text was first seen before the caller started this speech.
43+
- `model`: the model sent no output token that turn, for example when the first audio is a static tool message or a guardrail held the reply.
44+
- `voice`: there was no model output to time the voice from.
45+
46+
When `transcriberLatency` is unmeasured, `turnLatency` isn't a real measurement either: it leaves that interval out, or counts it from when the speech started.
47+
- **Averages count every turn.** The call's `modelLatencyAverage`, `voiceLatencyAverage`, and other averages divide by every entry, including those zeros. Simulation latency limits leave out turns that list the metric in `unmeasured`, so a simulation's result can be higher than the call's average for the same call. The `artifact.performanceMetrics.turnLatencyUnmeasuredTracked` field is `true` on calls recorded with `unmeasured`. On those calls, an entry without the `unmeasured` list had every component measured. On older calls, which don't have `turnLatencyUnmeasuredTracked`, simulation latency limits drop a `0` for `modelLatency` or `voiceLatency` and take no `transcriberLatency` or `endpointingLatency` values at all.
4248

4349
## What the displayed latency measures
4450

‎fern/observability/simulations-advanced.mdx‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ Latency limits work alongside structured-output evaluations. A scenario still ne
293293
On the **Success criteria** tab, under **Latency expectations**, select **Add latency expectation**. Configure each limit with four fields:
294294

295295
- **Aggregation**: How the call's turns are combined: **Median**, **Mean**, **P95**, or **Max**.
296-
- **Metric**: **Turn latency**, **Model latency**, or **Voice latency**.
296+
- **Metric**: **Turn latency**, **Model latency**, **Voice latency**, **Transcriber latency**, or **Endpointing latency**.
297297
- **Limit**: The maximum in milliseconds, as a whole number from 1 to 60,000.
298298
- **Required**: Turn off to make the limit informational. An optional limit is reported but never fails the simulation.
299299

@@ -311,7 +311,8 @@ curl -X PATCH "https://api.vapi.ai/eval/simulation/scenario/<scenario-id>" \
311311
-d '{
312312
"latencyExpectations": [
313313
{ "metric": "turn", "aggregation": "median", "thresholdMs": 1200 },
314-
{ "metric": "model", "aggregation": "p95", "thresholdMs": 800, "required": false }
314+
{ "metric": "model", "aggregation": "p95", "thresholdMs": 800, "required": false },
315+
{ "metric": "endpointing", "aggregation": "median", "thresholdMs": 600 }
315316
]
316317
}'
317318
```
@@ -330,8 +331,10 @@ Each metric reads one field of the call's per-turn latency, measured the same wa
330331
| `turn` | `turnLatency` | Time from the end of the AI tester's speech to the assistant starting its reply |
331332
| `model` | `modelLatency` | Time from the start of the turn's model stage, including knowledge base retrieval, to the model's first output token |
332333
| `voice` | `voiceLatency` | Time from the model's first output token to the first reply audio being ready, including the voice provider and any sample-rate conversion |
334+
| `transcriber` | `transcriberLatency` | Time from the AI tester's last voice activity, normally the end of its speech, to the transcriber returning the words |
335+
| `endpointing` | `endpointingLatency` | Time from the transcriber returning the words to Vapi deciding the AI tester's turn is over |
333336

334-
Model and voice latency happen inside turn latency, so the `model` and `voice` metrics don't add up to `turn`. A turn that recorded `0` for `model` or `voice` didn't measure that stage, so the metric leaves it out.
337+
Turn latency is transcriber latency plus endpointing latency plus the time until the reply starts, and model and voice latency happen inside that last part, so the metrics don't add up to `turn`. A turn counts toward a metric unless its per-turn `unmeasured` list names that metric: a real 0 ms counts, and a turn that didn't measure the component is left out. The `turn` metric leaves out turns that list `transcriber`, because turn latency includes that interval. On calls recorded before the list existed (no `turnLatencyUnmeasuredTracked` in the call's performance metrics), a `0` for `model` or `voice` is left out, `transcriber` and `endpointing` take no turns, and `turn` counts every turn. See [`unmeasured`](/assistants/model-intelligence/understanding-latency#per-turn-latency-on-a-call) for when each component is listed.
335338

336339
The AI tester speaks with clean synthetic audio, so transcription, endpointing, and turn latency can run faster than with real callers.
337340

@@ -403,7 +406,7 @@ For a transient scenario, set the same `targetOverrides` on the inline `scenario
403406
| The assistant never asks whether the AI tester is still there | Simulations remove `customer.speech.timeout` hooks. To test them, set `targetOverrides.hooks` on the scenario. See [**Hooks and call endings**](#hooks-and-call-endings). |
404407
| A voice simulation's assistant call ends as `customer-ended-call` | The AI tester hung up first, which matches a real caller hanging up. |
405408
| A tool looks up the wrong caller | Set `customer.number` in the scenario's variable values. See [**Simulate a call from a specific phone number**](#simulate-a-call-from-a-specific-phone-number). |
406-
| A latency limit fails without a measured value | No turn in the call measured that metric. Confirm the run used voice mode and that the conversation completed at least one exchange. |
409+
| A latency limit fails without a measured value | No turn in the call measured that metric. Confirm the run used voice mode and that the conversation completed at least one exchange. For `transcriber` and `endpointing`, check each turn's `unmeasured` list in the assistant call's `artifact.performanceMetrics.turnLatencies`. These two limits always fail this way on calls recorded before `unmeasured` existed, which have no `turnLatencyUnmeasuredTracked`. |
407410
| Latency limits show as skipped | Check whether the run used chat mode or the assistant under test uses GPT-Live. Both skip latency limits. |
408411

409412
## Next steps

0 commit comments

Comments
 (0)