Documentation / Reference / Configuration and policy
Configuration, deadlines, and policies¶
Most applications select a complete closed-schema TOML preset through
Assistant; they do not construct the values below. Use
Define an Assistant for the normal path.
This page documents the advanced compatibility interface.
One preset declares the provider-policy identities, exact models and routes, language/voice choices, operation and lifecycle deadlines, measurement requirements, standard tools, Judge slot, price book, extras, and logical credential sources. Every field is explicit. Unknown fields, partial deadline tables, unsafe durations, and route/policy mismatches fail locally.
Environment bootstrap¶
Backend and worker startup must set VAANI_ENVIRONMENT to exactly
development or production. Missing, blank, differently-cased, and unknown
values fail locally; there is no default.
from vaani import Assistant, bootstrap_environment
configuration = bootstrap_environment()
assistant = Assistant(
name="Reception",
prompt="Help the caller briefly.",
environment=configuration,
)
bootstrap_environment() reads only the selected versioned TOML document and
then resolves its exact preset profile. Development and production documents
are complete alternatives: VAANI never merges them and neither document has
precedence over the other. The resolved environment document and preset are
immutable, and their identities and SHA-256 digests are retained in
CallResult.provenance.preset_versions.
Tests can avoid process-environment state by passing an explicit environment mapping and can inject the returned configuration directly:
Pass EnvironmentDocuments(development=..., production=...) to select
deployment-owned manifests. Both use the closed vaani.environment.v1 schema:
schema = "vaani.environment.v1"
environment = "development"
revision = "1"
profile = "basic-monolingual@1"
# Explicit immutable deployment capability: none, cloud, or self-host.
noise_cancellation_mode = "none"
digest = "<sha256 of the other canonical fields>"
noise_cancellation_mode is optional for legacy documents and defaults to
none; new documents should declare it. A preset noise profile is
Cloud-only, so a worker in self-host or none mode rejects that profile
before LiveKit job admission. VAANI never infers this capability from a URL or
hostname. Use cloud only when the deployment has explicitly approved the
Cloud noise plugin; use none when self-hosted audio should remain unfiltered.
Unknown keys, an environment/file mismatch, a non-exact profile, or digest drift fail before provider access. Frontends should receive only derived read-only status; they must never edit these files or reconfigure the running Assistant.
Development Evaluation Catalog¶
The Starter loads a backend-owned development Route Catalog:
catalog = DevelopmentEvaluationCatalog.from_environment(
configuration,
route_catalog=load_production_deployment(
"development-options@1.toml"
),
)
Despite the loader name, this document is an allow-list for local testing; it
does not make development production-locked. public_summary() exposes only
safe target IDs, provider/model labels, supported languages and voices, fixed
settings for display, and readiness reasons. Credentials and secret values are
never included.
The browser submits IDs from that exact response:
{
"language": "en-IN",
"selection": {
"speech_recognition": "stt-deepgram-nova-3",
"reasoning": "llm-vertex-gemini-3-flash-preview",
"speech_generation": "tts-smallest-lightning-v3-1-pro",
"voice": "meher"
}
}
catalog.bind_session(...) rejects unknown, unavailable, or
language/voice-incompatible targets and returns an immutable
EvaluationSession. The token server serializes the validated request as
private job metadata; one worker binds it to that call. Installed plugins never
add targets automatically.
The older complete-profile allow-list remains supported when no
route_catalog is supplied: the browser then sends one exact
evaluation_profile_identity. New Starter applications use route selection.
Production creates neither catalog and rejects both forms.
Production Deployment Profile¶
A production document instead names one production_deployment and its
production_lock. The profile fixes one primary plus ordered fallbacks for
speech recognition, reasoning, and speech generation. Generate the secret-free
review bytes with the production-only API, write them as JSON, review them, and
commit them:
import json
from pathlib import Path
from vaani import (
create_production_deployment_lock,
load_production_deployment,
)
profile = load_production_deployment("production-deployment@1.toml")
lock = create_production_deployment_lock(
profile,
"production@1#sha256:<production-environment-digest>",
)
Path("production-deployment@1.lock.json").write_text(
json.dumps(dict(lock), indent=2, sort_keys=True) + "\n",
encoding="utf-8",
)
The lock binds the environment, preset, complete Route Target fingerprints, fallback order, Provider Failure Domains, and Resilience Policy values. Startup verifies it before worker readiness. Configuration changes require new documents, a regenerated lock, and a restart.
Use this page to find the right public value. In the matching source release,
contracts/public/v1/vectors/construction.json and src/vaani/_model.py
define exact fields and defaults.
CallSetup map¶
| Field | Type | Owner |
|---|---|---|
prompt |
str |
consumer |
mode |
CascadeMode |
consumer route/fallback selection |
greeting |
GreetingPolicy |
consumer wording/failure choice |
language |
LanguagePolicy |
consumer enabled languages |
conversation |
ConversationPolicy |
consumer behavior/profile |
ending |
EndingPolicy |
consumer terminal media + lifecycle budgets |
measurement |
MeasurementPolicy |
consumer capture/usage requirements |
recording |
RecordingPolicy |
consumer legal/business choice |
transfer |
TransferPolicy |
consumer allowed routes |
tools |
tuple of RuntimeTool |
consumer business capabilities |
judge |
optional JudgeSetup |
consumer evaluation definition |
All are immutable once supplied. Build a new setup with
dataclasses.replace or use CallUpdate for a running call.
Lifecycle deadlines¶
LifecycleDeadlinePolicy covers connection, readiness, greeting preparation and
playout, terminal media, work drain, teardown, base finalization, Judge, and
total startup/closure.
These are absolute phase budgets, not per-retry waits. Assistant compiles the
values declared by the selected preset; it does not substitute dataclass
defaults.
Operation deadlines¶
OperationDeadlinePolicy covers provider operations, tools, update preparation,
retired resources, blind transfer, recording start/stop, and result publication.
Keep the total consistent with lifecycle budgets. For example, a terminal-media provider retry must still finish within the terminal-media phase cutoff.
Conversation policy¶
Choose either:
or explicit ConversationPolicyValues. Explicit values include both
agent_response_progress_seconds and agent_response_total_seconds; VAANI does
not insert hidden watchdog limits. Compatibility profiles are revisioned behavior
bundles, not global defaults and never include business wording.
Assistant presets use the same exclusive choice. Keep a revisioned profile:
Or declare every value explicitly:
[conversation]
maximum_endpoint_seconds = "1.5"
minimum_consecutive_speech_seconds = "0.1"
silence_seconds = "13"
mechanical_repetition_enabled = true
agent_response_progress_seconds = "10"
agent_response_total_seconds = "60"
vad = "silero"
Do not mix profile with explicit values. Write durations as quoted canonical
Decimal strings so TOML parsing cannot lose precision. All durations must be
positive except minimum_consecutive_speech_seconds, which may be "0" for
profiles equivalent to collection@1.
When an Agent-response watch expires, VAANI preserves that timeout as CallResult
failure evidence before it attempts any recovery media. The first configured
recovery receives one independent absolute budget equal to
provider_operation_seconds for synthesis and confirmed playout; it does not
extend the original response total or restart expired LLM/Tool work. Missing,
failed, cancelled, or timed-out playout is a terminal failure with immutable
evidence. A participant turn observed during recovery waits until recovery
playout finishes.
A second unresolved watch expiry performs the configured typed terminal action
instead of opening another recovery loop.
Measurement and privacy¶
TranscriptCapturePolicy is FULL, REDACTED, or OMITTED.
MeasurementPolicy can require usage dimensions and known estimated cost.
Unmet required evidence affects validated behavior/failure rather than being
silently guessed.
Assistant definition lock¶
Judge evidence policy¶
Preset schema v2 makes Judge evidence choices explicit:
[judge]
enabled = true
transcript = "REDACTED" # FULL, REDACTED, or OMITTED
include_tool_activity = true
include_consumer_evidence = false
on_empty = "EVIDENCE_EMPTY"
on_oversize = "EVIDENCE_TOO_LARGE"
Judge transcript modes do not change the terminal CallResult capture policy:
FULLsends the captured text and audible-prefix evidence unchanged.REDACTEDkeeps each item's speaker, order, language, disposition, revision, and provider-segment references. It sends text with email addresses, phone-like values containing 8 to 15 actual digits, labelled OTP/PIN, credential, token, account/customer/member/loyalty identifiers, and obvious long credential-like tokens replaced by[REDACTED]. Audible-prefix evidence is omitted. Dates, semantic versions, and separator-heavy non-phone facts remain unchanged. Each text value is at most 2,048 Unicode characters, including a final…[TRUNCATED]marker when needed.OMITTEDsends no transcript items.
The runtime applies this projection and the existing 256 KiB total Judge
evidence limit before invoking a Judge provider. REDACTED is intended to
retain conversational meaning, not to make arbitrary sensitive prose safe;
consumer business evidence must still use its separate allow-list.
Rubric instructions and output schemas remain business-owned Python, never
preset content. If include_consumer_evidence is true, pass a per-call provider
as consumer_evidence= to Assistant.configure_judge(...). It is invoked only
when the preset permits it; the result must be JSON-safe and at most 16 KiB.
Return only allow-listed business facts, never credentials, tokens, arbitrary
objects, or unfiltered provider payloads.
A minimal consumer definition is:
from vaani import Call
JUDGE_SCHEMA = {
"type": "object",
"additionalProperties": False,
"required": ["resolved", "reason"],
"properties": {
"resolved": {"type": "boolean"},
"reason": {"type": ["string", "null"]},
},
}
async def judge_evidence(call: Call) -> object:
# Project reviewed facts; do not return all of call.state.
return {
"requested_action": call.state.get("requested_action"),
"action_completed": call.state.get("action_completed"),
}
assistant.configure_judge(
rubric_id="support-resolution",
revision="1",
instructions="Judge resolution only from the supplied evidence.",
output_schema_id="support-resolution-result",
output_schema_revision="1",
output_schema=JUDGE_SCHEMA,
consumer_evidence=judge_evidence,
)
This requires include_consumer_evidence = true in the selected v2 preset.
When it is false, omit the provider; VAANI does not silently widen the preset's
evidence boundary.
Legacy v1 identities retain the previous redacted-transcript, included-tool, no-consumer-evidence behavior. Policy changes use a new v2 preset revision and therefore contribute to the production lock and call provenance identity.
vaani preset lock PRESET --output production-lock.json records the exact
deployment identities without secret values. Pass that file as
Assistant(..., production_lock="production-lock.json"). Assistant.check()
then compares every identity—including the installed VAANI version and enabled
Judge rubric/schema identities—before lifecycle ownership. The lock also binds
each constructed official Adapter manifest to its exact installed distribution
version, including LiveKit transport and any enabled transfer or recording
Adapter. Enabled recording adds its preset requirement and secret-free storage
binding digest; raw bucket, prefix, credential, and audio values remain absent.
The CLI form targets an Assistant without named prompts, transfer routes, or a
recording binding. After configuring those capabilities, tool disables, or
language/voice overrides, use Assistant.create_production_lock() so the lock
binds the exact tool revisions, allowed choices, language profiles,
transfer-route digests, and recording identity.
This lock is separate from the environment's Production Deployment Profile
lock; production verifies both applicable contracts.
Updates¶
CallUpdate always requires:
expected_revision;reason;boundary;- interrupted-reply handling when required.
The six optional change fields default to UNCHANGED: prompt, language, tools,
STT, reasoning, and TTS.
Next: public API map or Assistant update boundaries.