The loop
A voice turn runs a streaming pipeline:The stack
The Phase 0 spike measured every stage on real calls from India and picked the vendors from the numbers:- Orchestration: Pipecat. Transport-swappable, good observability.
- Telephony: Exotel. India-native and DLT-ready. Handles inbound and
outbound on the same handler; the call’s
startevent tags it inbound or outbound and carries the caller number. - STT: Sarvam. Accurate Hindi and Hinglish transcription, and it finalizes before the end of the turn, so it adds no perceived latency.
- TTS: Smallest Lightning. 5 to 140ms to first byte.
- LLM: governed by cruq. The pipeline drives a real cruq agent through
agent-servicerather than calling a provider directly, so the call inherits the agent’s prompt, tools, KB, tracing, and metering.
Latency, honestly
The loop, telephony, STT, TTS, and Hinglish quality all validated end to end on real calls. One thing sits above target:
With gemini-2.5-flash-lite, perceived p50 landed around 1130ms, with the LLM’s
first token being almost all of it. Everything else is already within budget.
The next lever is a low-time-to-first-token model (a Groq or Cerebras served
Llama), which should cut first token to a few hundred milliseconds and bring
perceived latency toward 550 to 650ms, at a possible cost to Hinglish quality
worth A/B testing.
Language
Forcing Hinglish in the system prompt produces a natural romanized Hinglish greeting and qualification, with no drift back to English. Sarvam transcribes the caller’s Hindi and Hinglish accurately in both directions.Every call is recorded
A call persists three things, all tenant-scoped:- A recording (WAV, caller and agent mixed) in object storage.
- A transcript (the conversation, timestamped) as JSON.
- A
voice_callsrow in Postgres with the vendors used, turn count, duration, and perceived-latency p50, under row-level security like every other tenant table.
Pausing on a call
The Ask a Human tool works over voice. When the agent hits something it should not decide alone, it speaks the question, parks the run as paused, and resumes on the caller’s next turn using the same thread. The call does not drop while it waits.Status
Phase 0 (the throwaway spike,apps/voice-spike) validated the loop, vendors,
and Hinglish quality on real phone calls. Phase 1 shipped the governed
cruq-agent backend, call recording and transcript persistence to object storage
and Postgres, the Voice Calls page, and the Kubernetes deploy scaffolding.
Bulk or commercial calling in India still requires DLT registration before it
goes wide.
backchannel (in the sibling hf-voice repo) is a separate, open experiment in
a full-duplex voice framework with first-class barge-in and turn detection. It
is not part of the product runtime described here.
