Skip to content

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.