Documentation / Guides / Port an existing voicebot
Port an existing voicebot¶
Port behavior first and mechanics second. The goal is a smaller consumer that still owns every product decision while VAANI replaces duplicated runtime work.
This approach is based on the proven standalone Product Catalog consumer and the
approved prod-v4.2 Vertex migration at 05a5c42b.
Map files by responsibility¶
| Existing voicebot area | Consumer destination | VAANI replacement |
|---|---|---|
| root/persona instructions | prompts.py |
none |
| call-flow prompt builders | feature modules beside prompts.py |
none |
| tools and domain providers | tools.py and domain/ |
RuntimeTool admission/execution |
| product/reference data | packaged consumer data | none |
| language/model/voice config | reviewed consumer config | typed profiles and bindings |
| accepted-call/session plumbing | vaani_setup.py |
VoiceRuntime and adapters |
| LiveKit entrypoint | thin deployment adapter | LiveKitCallHandoff |
| frontend choices | existing frontend | validated CallSetup |
| logging/GCS/Postgres | result consumers | immutable result and optional adapters/publisher |
Port one vertical slice¶
Start with one representative call flow:
- Freeze an expected prompt, participant utterance, business tool request, business result, reply, and terminal outcome.
- Move the prompt builder without changing its wording.
- Wrap one existing domain function in a
RuntimeTool. Keep its underlying data and state in the consumer. - Build one
LanguageBindingandCallSetup. - Script STT → LLM → tool → TTS offline.
- Assert transcript, tool evidence, one Closure, and no resources.
- Only then assemble live adapters and a non-connecting credential preflight.
The Vertex Product Catalog example shows this slice in repository form.
For a greenfield shell around migrated prompts and tools, the companion Starter CLI generates a consumer-owned LiveKit bridge, backend, and browser console. Treat it as scaffolding: move existing behavior into the generated consumer modules and repeat the same offline proof before considering live traffic.
Adapt tools deliberately¶
Do not expose arbitrary Python callables directly. Give each tool a stable model-facing name, closed JSON schemas, a declared effect, and a handler that uses only approved consumer state.
During a broad port, classify tools:
get_,check_,lookup_: oftenREAD_ONLY;- durable upserts with idempotency keys: potentially
IDEMPOTENT; - transfers, notifications, payments, or unkeyed writes: usually
NON_IDEMPOTENT.
Confirm each classification with the domain owner.
Preserve deployment choices¶
The reference Vertex bot retains Deepgram STT, Vertex reasoning, Google speech, Google STT and AI Studio fallbacks, language-specific prompts/voices, named transfer routes, and frontend persona composition. Those values belong in the consumer setup. VAANI does not choose a "better" route during migration.
Keep the entrypoint thin¶
The final entrypoint should:
- validate deployment/caller data;
- construct
TelephonyIdentityand the LiveKit handoff; - build consumer state and
CallSetup; - call the runtime;
- send the terminal result to post-Closure consumers.
It should not reimplement silence timers, provider retries, teardown races, or mutable result assembly.
Roll out by composition¶
Deploy the VAANI entrypoint behind a consumer-owned feature flag. Keep the previous entrypoint deployable. New calls take the selected composition; already-running calls remain pinned to the runtime/adapters they started with. Rollback routes only new calls back to the previous entrypoint and drains running calls.
Next: prove the port offline and prepare production.