Documentation / Core concepts / Tools and state
Prompts, tools, business state, and updates¶
VAANI coordinates these values without owning their meaning.
Prompts are complete consumer instructions¶
CallSetup.prompt is the active instruction set. Each LanguageBinding also
contains complete instructions for its language. VAANI does not add a persona,
translate text, or merge business rules.
Use a prompt builder in consumer code:
def build_prompt(customer_name: str) -> str:
return (
"You are a concise product assistant. "
f"The verified caller is {customer_name}. "
"Use lookup_product_catalog before stating pack availability."
)
RuntimeTool is a bounded business seam¶
A tool declares:
- model-facing name and version;
- closed JSON input and output schemas;
- an async handler accepting exactly
(context, arguments); - effect and retry policy;
- safe evidence paths for audit.
async def lookup_handler(context, arguments):
result = await context.consumer_state.catalog.lookup(arguments["query"])
return {"answer": result}
lookup = RuntimeTool(
"lookup_product_catalog",
"1",
{
"type": "object",
"additionalProperties": False,
"required": ["query"],
"properties": {"query": {"type": "string"}},
},
{
"type": "object",
"additionalProperties": False,
"required": ["answer"],
"properties": {"answer": {"type": "string"}},
},
lookup_handler,
ToolExecutionPolicy(ToolEffect.READ_ONLY, ToolRetryPolicy(2)),
ToolAuditPolicy(),
)
This is a public API snippet. Your handler still owns authorization, idempotency, domain validation, and external side effects.
Business state remains outside VAANI¶
Pass per-call state in CallInvocationContext.consumer_state. A tool context
exposes only read-only call_id, tool_call_id, consumer_state, and bounded
requests to end, update, or transfer. It is not a service locator and does not
expose transport or result internals.
Effects determine safe retries¶
ToolEffect |
Meaning |
|---|---|
READ_ONLY |
no external mutation; bounded retries may be safe |
IDEMPOTENT |
repeated calls need the consumer's idempotency guarantee |
NON_IDEMPOTENT |
completion may be unknown; avoid automatic replay |
Never label a write idempotent unless the backing operation uses a durable idempotency key.
CallUpdate changes future behavior atomically¶
An update may replace prompt, language binding, tools, or any cascade profile. Every named part commits together or none does. Unnamed parts remain unchanged. The expected revision prevents last-write-wins races.
Changing a voice alone therefore leaves prompt, language, history, reasoning, and tools untouched. See the live updates guide.
Next: result evidence or write deterministic tests.