# Changing the model, end to end

Changing the model changes three things at once — latency, cost and which features exist — and only the first is obvious. The default, Gemini 3.1 Flash Live, reaches first audio in 0.6 s against 1.2–2.2 s for 2.5 native audio, and pays for it by refusing affective dialog and holding an immutable session, so no mid-call note or supervisor guidance can reach it.

- **Status:** Available
- **Audience:** both
- **Channels:** phone
- **In the app:** #/calls, #/engine-advanced
- **Last verified:** 2026-09-10
- **Canonical:** https://connectbyjbrh.com/docs/workflows/model-change/

## What you are trading

A realtime model is not a component that can be chosen on price alone. Each one refuses a different set of things, and the refusals arrive as error codes on live calls rather than as a feature matrix. The two the Voice Lab offers differ like this.

|  | Gemini 3.1 Flash Live (default) | 2.5 native audio |
|---|---|---|
| First audio | 0.6 s, measured on the host | 1.2–2.2 s |
| Affective dialog | Refused — error 1007 | Available |
| Session | Immutable: the SDK will not accept a changed session | Mutable |
| Mid-call notes | Not delivered; a stalled reply is recorded as `nudge {via: none}` and notes as undelivered | Delivered through `agent.update_chat_ctx` |
| Supervisor guidance | Recorded as `guidance_undeliverable` | Reaches the system prompt |
| Check-in and goodbye lines | Never spoken — the TTS has the live voice's name, not its sound | Available |

> **Note** Pick 2.5 when a colleague steering a call mid-conversation matters more than a second per reply. Pick the default when time to first word is what customers notice. No configuration gives both, and a page that implied otherwise would be describing a model that does not exist.

## Before you switch

1. Check the model id itself. A Vertex-style path or a malformed id is refused as `bad_model` before any call row is created — the fifth Lab call rang the owner and then died with a 1008 because the id was a Vertex path.
2. Check what the line depends on. If the supervisor panel is part of how that line is run, an immutable session takes it away.
3. Check the budget. Live calls are billed on audio tokens — roughly 4× the same model's text rate on input and 2.7× on output — so a model with a lower text rate is not automatically cheaper on the phone.
4. Note today's numbers: reply median, the first-token share of the wait, and cost per call from the profiler. A switch with no baseline cannot be judged, only defended.

## The chain a switch runs through

1. TRIGGER — the model is changed in the Voice Lab, at the workspace or on one profile.
2. USER / EXTERNAL EVENT — a person makes the change; the first affected caller is an ordinary inbound or outbound call.
3. AUTH / WORKSPACE RESOLUTION — the setting is written inside the owning workspace; both audiences reach the Lab through `/api/voice/realtime/lab*`.
4. INGEST / REQUEST — the next call's `ring` validates the model id and refuses `bad_model` before a `Call` row exists, so a malformed id costs nothing.
5. CANONICAL RECORD — the call is created and the resolved settings, the model among them, are snapshotted on `call.quality`.
6. CLASSIFICATION / RESEARCH / REASONING — the model now does the listening and the answering; the worker holds no business logic of its own.
7. KNOWLEDGE + MEMORY + RULES — the same brief is rendered as before. Only the model reading it has changed.
8. AUTONOMY / APPROVAL — unchanged. Outbound still runs through `comms_providers.dispatch_call`, so memory blocks, consent, autonomy and budget gate the call exactly as before.
9. ACTION / PROVIDER — the session opens against the new model. One that refuses to start is opened once more on the same model and once on the fallback before the call is given up.
10. RESULT — `model_session_restarted` goes on the record when a restart happened, so a call that sounded fine but restarted twice is visible afterwards.
11. RELATIONSHIP / TIMELINE / MEMORY — summary, lead, memory and follow-up run through the same `voice.end_call` whichever model held the call.
12. AUDIT / USAGE / NEEDS YOU — model usage is booked into `costs` split by modality; sessions the model refused escalate into Needs You as `engine_error`.
13. NEXT — compare reply median and cost per call against the baseline, over calls rather than over one call.

## Afterwards: what proves it

Three numbers, all of them already recorded. Reply median comes from the `turn_timing` events rather than from transcripts. Cost comes from `GET /api/usage/voice`, the per-call profiler, which reports what was measured and says what was not rather than estimating the gap — that matters because the SDK reports `input_audio_tokens` and `session_duration` but no `input_audio_duration`, and code that looked for one recorded 0.0 seconds for every call ever metered.

The third is the share of the wait that belongs to the model. When the first token is 60% of it, the review says so and offers no control to turn; that share moving is the clearest single signal that a model change was the right one.

> **Careful** `merge_usage` adds every session a call held, because a restart used to bill only the survivor. When you compare a new model on calls that restarted, read the merged figure — the per-session one flatters whichever model restarted more.

## What can fail

**Calls die shortly after ringing** — The model id is wrong for this stack: refused as `bad_model` where the check runs, a 1008 on the wire where it does not.
**The supervisor panel stopped working** — The new model holds an immutable session. Guidance is recorded as `guidance_undeliverable` rather than silently dropped.
**Cost rose while replies got shorter** — Audio tokens, not words. A Live session is re-billed for its whole context every turn, so a long conversation costs more per reply than a short one on the same model.
**A call reports no tokens** — It is still charged from its own duration at the published per-minute rate. Zero is not an outcome the ledger accepts.
**The first call after the switch was slow** — Greeting warm-up is per process, and a newly started process has an empty `LineCache` until `prewarm` fills it.

## Questions

### Is there a fallback if the new model will not start a session?

Yes, and it is bounded. The session is attempted once more on the chosen model and once on the mutable 2.5 before the call is given up, with `model_session_restarted` recorded. It is a safety net for one bad session, not a reason to leave a broken model configured.

### Does changing the model change what Connect is allowed to do?

No. Autonomy modes, suppression, consent and budget are checked outside the model, in the same services a carrier call goes through. A different model changes how the call sounds and what it costs, never what it may do.

### Can different lines run different models?

Yes — the model is one of the engine knobs a voice profile carries, and profiles resolve by purpose, by line number and by contact. Running a new model on one purpose first is the least disruptive way to try it.

## Related

- [What a setting cannot change](https://connectbyjbrh.com/docs/phone/model-limits/)
- [The realtime voice engine](https://connectbyjbrh.com/docs/phone/realtime-engine/)
- [What a call costs](https://connectbyjbrh.com/docs/phone/voice-cost/)
- [The voice model refused the session](https://connectbyjbrh.com/docs/troubleshooting/model-session-failed/)
- [Findings a setting cannot fix](https://connectbyjbrh.com/research/model-limited-findings/)
- [Changing what the agent is told](https://connectbyjbrh.com/docs/workflows/prompt-change/)
- [Changing a provider, end to end](https://connectbyjbrh.com/docs/workflows/provider-change/)

## What this page is based on

- `docs-source/sources/PHONE.md` §4, §7, §9 — cost, models, refusals
- `backend/app/voice_engine.py` — `ring`, `meter_call`, `merge_usage`
- `backend/app/voice_style.py` — the default model and session options
- Connect capability registry (docs-source/facts.py)
