ORI Utter: E2E audio runtime that turns any text agent into a world-class conversational agent, deployed anywhere.
A systems note on ORI Utter — the speech runtime under every Waterr meeting, now opening as a deployment surface for agents that already exist. Your agent keeps its loop, its tools, and its state on your infrastructure; Utter runs the room: transport, turn-taking, recognition, synthesis, pacing, and the paper trail.
Today we're publishing a systems note on ORI Utter, the speech runtime that carries every Waterr meeting, and opening early access to its endpoint connector — the seam that lets a text agent you already run become the brain of a live, face-to-face meeting. The agent stays on your infrastructure, in your language, behind your endpoint. Utter runs everything a spoken conversation needs that a chat loop does not have: the WebRTC room, turn detection, interruption handling, streaming recognition, speech synthesis, pacing, transcripts, analysis, and the clock.
We think giving an agent a voice should be a deployment decision, not an engineering quarter. A chat reply can be late; a speaking turn cannot — and that difference is infrastructure, not intelligence. Utter is available in Studio and over the REST API today; the connector's wire contract is published below.
The last mile of every text agent is a mouth
The agents that work in production today are text agents: a loop over streaming chat completions, tools that reach into internal systems, state the team can inspect, and an eval harness the team trusts. Companies have spent one to two years making these loops reliable. The reasoning is done. What the agent cannot do is be in the room — take a live turn in a meeting, with a person, on a clock.
The current routes into voice both move the brain. Route one is porting: rewrite the agent inside a voice vendor's SDK and run it on their managed runtime — Cartesia's Line, for example, requires exactly this. Route two is rebuilding: re-implement the agent's behavior against a realtime speech API, at which point state splits across two systems, tools get re-wired, and the eval harness no longer covers what users actually hear. Either way, the thing your team spent two years hardening is now a second, diverging copy. It is the difference between hiring an interpreter and hiring a replacement: the interpreter gives your expert a voice in the room; the replacement asks your expert to leave.
Note what is not on the list of problems: the agent. Nothing about its loop, its tools, or its state needed to change. What is missing is everything around it — the transport, the turn-taking, the recognition, the synthesis, the pacing, the record — and none of that is agent-specific. It is a runtime.
Our approach
The runtime: everything a conversation needs except the brain
ORI Utter is not a new stack built for this note; it is the production speech runtime that has carried Waterr's AI meetings — interviews, discovery calls, training sessions — and we are documenting the seam that makes it general. One instance of the runtime hosts one meeting, end to end:
- The room. A multiparty WebRTC meeting — video, audio, screen share, participant files, chat — not a phone line. The agent is a participant with a seat, a name, and a face-free voice.
- The clock. Voice-activity detection (Silero), turn-boundary detection, barge-in and interruption handling. Deciding when the user has finished speaking is half the difficulty of voice AI, and it never reaches your code.
- Ears. Streaming speech recognition (Deepgram) that finalizes the user's turn as it ends, so the next hop starts with text, not audio.
- Voice. A synthesis roster across vendors (Cartesia, ElevenLabs, Deepgram, Azure) with per-persona voice selection, streamed sentence by sentence as tokens arrive.
- Pacing. Filler audio that holds the floor when a turn runs long, and spoken fallback lines when it fails outright. Silence is the one thing the runtime never emits.
- The paper trail. Live transcripts streamed to clients as RTVI events, post-meeting analysis, recordings, and 8 HMAC-signed webhook events back to your systems.
The result is a runtime that feels less like a telephony stack and more like a meeting that happens to have an empty seat. Monologue, our reasoning harness, lives in the same runtime — the between-turn reasoning it adds composes with whatever brain occupies the seat.
The seam: a schema, not an SDK
The brain is an endpoint. Most voice platforms attach your agent by absorbing it: an SDK to adopt, a framework to inherit, a managed runtime to deploy into — your loop becomes their process. Rather than a hosted runtime, we opt for a wire contract. A scenario (or a single meeting request) names an OpenAI-compatible streaming chat-completions URL — the custom_agent block — and from the runtime's point of view your agent is just a model. From your side, a live meeting is one more client of an API you already serve. No SDK, no port, no second deployment of the thing you already deploy.
Turns arrive clean. At meeting time, the hard realtime work — voice-activity detection inside a ~200–500 ms turn-taking window, barge-in, interruption recovery — happens before your endpoint is ever called. You receive a messages array: the scenario's instructions, the conversation so far, the user's finished turn. You return deltas. Your agent never touches audio in either direction.
The deadline is enforced, then masked. To keep conversational pacing, the contract publishes a budget rather than assuming one: first token in 1.5 s (target), hard timeout at 10 s (configurable to 30). Past the target, the runtime's filler machinery holds the floor; past the timeout, the agent speaks a fallback line and the turn ends; three consecutive failures put the meeting into listen-and-transcribe mode instead of crashing it, so the recording, transcript, and duration survive your outage. The failure modes are designed, not discovered.
Tools pass through both ways. The runtime's built-in functions — ending the call, web search, the custom functions attached to a scenario — travel to your endpoint as standard tools, and honored calls come back as standard tool_calls. Your own tools never appear on the wire at all: they run inside your loop, behind your endpoint, invisible to us — which is the point. Note that customer logic already runs in production this way today: a custom function attached to a scenario is delivered to your webhook mid-meeting and its answer is spoken seconds later.
Your credentials never mix with ours. The request to your endpoint carries the API key you configured and nothing else — no internal service credentials attach to that wire, ever. HTTPS is required; hosts that resolve to private, link-local, or cloud-metadata address ranges are rejected before a connection is attempted; header overrides that could impersonate internal traffic are dropped. The connector was specified with its SSRF policy first and its features second.
POST https://agent.yourco.com/v1/chat/completions Authorization: Bearer sk-your-key // your key — and nothing else { "model": "support-bot-v3", "stream": true, "messages": [ { "role": "system", "content": "<scenario instructions>" }, … the conversation so far … { "role": "user", "content": "Can you pull up my last order?" } ], "tools": [ { "type": "function", "function": { "name": "end_call", … } }, … scenario custom functions … ] }
HTTP/1.1 200 Content-Type: text/event-stream data: {"choices":[{"delta": {"role":"assistant"}}]} data: {"choices":[{"delta": {"content":"Sure — "}}]} data: {"choices":[{"delta": {"content":"pulling that up now."}}]} data: [DONE] // first token ≤ 1.5 s target // synthesis starts on the first // complete sentence, not on [DONE]
model field is an opaque string your endpoint routes on.Three ways in today
Utter is not waiting on the connector to be useful. In Studio, you define the agent in place — scenario, persona, goals, participant files, custom functions — and the runtime gives it the seat; no code. Over the REST API — 46 documented operations with an OpenAPI spec — you create scenarios and meetings programmatically and read back transcripts and analyses. As an embed, the meeting drops into your own product behind signed tokens and origin allowlists. And the loop closes in both directions: 8 webhook events (HMAC-signed, with delivery logs, redelivery, and key rotation with a 24 h grace window) push transcripts and analyses back into your systems the moment a meeting ends, and a local tunnel in the CLI (waterr listen) brings those events to your laptop during development.
| Surface | What it is | Status |
|---|---|---|
| Studioscenario-defined agents | Define instructions, persona, goals, files, and tools in the browser; the runtime runs the meeting. | Available |
REST APIapi.waterr.ai |
46 documented operations: meetings, scenarios, personas, transcripts, analyses, recordings, webhooks. | Available |
| Webhook toolscustom functions | Your logic, called mid-meeting: the agent invokes a function, your webhook answers, the answer is spoken. | Available |
| Embedssigned tokens | The meeting inside your product — token-scoped, origin-allowlisted iframe variants. | Available |
| Events outwebhooks | 8 events incl. transcript.ready and session.analysis_complete; HMAC-signed, redeliverable. |
Available |
Endpoint connectorcustom_agent |
Your OpenAI-compatible endpoint as the meeting's brain — the contract in Figures 1–3. | Early access |
ORI Realtime/v1/realtime |
Speech-native sibling: an OpenAI-Realtime-shaped WebSocket onto our realtime model. | Research preview |
Status labels are honest by policy: Available means running in production for customers today; Early access means the contract is locked and integrations are onboarding; Research preview means waitlist-gated. Docs at docs.waterr.ai. |
||
Figure 5 · The deployment surfaces of the Utter runtime, and where the endpoint connector sits among them.
What this doesn't show yet
We hold ourselves to the same standard here as in the Monologue note: status labels over adjectives. Four honest edges, stated plainly:
- The connector is the youngest seam. The runtime is production — it carries every Waterr meeting. The endpoint connector is early access: the contract above is locked, and integrations onboard in cohorts. General availability follows the first cohort, not this note.
- Cascaded pipeline only, for now. The connector applies to the turn-based pipeline (recognition → your endpoint → synthesis). Our speech-native pipeline — ORI Realtime, where the model hears audio directly — does not take an external brain yet. A scenario configured with both gets the connector, on the cascaded path.
- Latency is shared custody. The runtime masks misses and bounds failures, but it cannot make a slow agent fast: your time-to-first-token is your responsibility, and the documentation says so plainly rather than pretending the budget is ours alone to keep.
- Meetings, not telephony. The unit of work is a meeting room — video, screen, files, multiparty — not a phone number. If your channel is PSTN, Utter is not your runtime today.
The road ahead, ordered by expected value: a richer event tier that exposes meeting actions as tool calls (end_meeting, present_file, switch_persona) and notifies your endpoint on interruption; endpoint fallbacks, so a backup model catches what your primary drops; a speech-native connector over an OpenAI-Realtime-shaped WebSocket for agents that want audio in-band; and thin SDKs for teams that prefer a library over a schema.
Try it, test it, or challenge it
Every meeting at waterr.ai already runs on Utter — the fastest way to evaluate the runtime is to sit in a meeting with it. The API surface is documented at docs.waterr.ai. For early access to the endpoint connector, write to [email protected] with one thing: the URL where your agent speaks chat completions. That is the whole integration, and we mean to keep it that way.
Citation
Please cite this work as:
Sharma, H. and Waterr Research, "ORI Utter: A Speech Runtime for Text Agents", Waterr Research: Research Notes, July 2026.
BibTeX:
@article{waterr2026utter,
author = {Sharma, Harshit and {Waterr Research}},
title = {ORI Utter: A Speech Runtime for Text Agents},
journal = {Waterr Research: Research Notes},
year = {2026},
month = {July},
note = {https://waterr.ai/research/utter}
}
