All projects

Telephony · Controlled flows · Decision models

Agentic Voice System

LLM voice agents that handle real calls, use your business systems, and follow workflows you can test and control. Callers can ask questions, correct information, and interrupt. The system interprets their meaning, keeps accepted task state, and carries the work forward.

A call that stays on task Link to heading

A question becomes a detour, then the task continues Illustrative call and execution

  1. Ask

    The agent requests the caller's first name.

    collectGivenName(...) waits for an accepted answer.

  2. Explain

    Caller: “Why do you need my name?” The agent explains its declared purpose.

    Navigation visits the explanation goal; collection stays pending.

  3. Resume

    The caller supplies a name. The agent accepts the validated answer and continues the task.

    The collector returns. The parent resumes and invokes inform(...), which checks its remaining requirements.

A child goal can handle several turns while the parent's await remains suspended.

Write the workflow with ordinary awaits Link to heading

defineGoal realizes a controlled state machine through ordinary async functions. The runtime keeps a logical goal stack alongside the language’s async call chain. Each registered goal invocation adds a frame: a child can handle several conversational turns while its parent waits at await. An accepted result lets the parent resume.

Illustrative composition; goal definitions and business schemas are omitted:

const handleCall = defineGoal(callDefinition, async (input, ctx) => {
  await greet(input.introduction, ctx);
  await introduce(input.introduction, ctx);

  if (!ctx.state.values.identity?.givenName) {
    await collectGivenName(input.collection, ctx);
  }

  await inform(input.account, ctx);
  return callEnd({ ending: "achieved" }, ctx);
});

The interface uses control flow developers already know. Calls, if, loops, try/catch, and returns express the workflow; goal frames add input/output validation, requirements, cancellation, and traces. Using the language’s existing constructs reduces onboarding and everyday authoring friction from learning a state library’s separate vocabulary. The graph visualizes goals and recorded transitions.

Test models and control performance Link to heading

Model adapters are replaceable; the workflow stays in application code. Goals, validation rules, and allowed transitions keep their contracts as models and decision formulations change.

  • Test the workflow: supply known decisions and values as fixtures, then check transitions, prerequisites, and interruption handling without live inference.
  • Measure the model: run a fixed corpus of caller evidence and expected decisions through a candidate provider, retaining failures as well as successes.
  • Control the trade-off: compare decision quality and request latency on the same cases before changing a binding. Phase boundaries help locate whether a regression came from routing, interpretation, extraction, or generation.

The architecture behind the behavior Link to heading

Meaning comes before flow control. “Why do you need my name?” calls for an explanation; “I won’t give my name” calls for the declared refusal policy. Both mention the same field. Semantic interpretation establishes which behavior applies, and code controls the allowed transition.

Four phases Route · interpret · extract · respond

  1. NavigationChoose a permitted goal
  2. RegressionSelect a declared semantic case
  3. ReductionExtract a provisional value
  4. GenerationProduce a scoped reply

Code validates candidates and controls acceptance. Branches without data skip reduction; successful collection can skip generation.

Four responsibilities, each with a limited output contract and invoked when needed.

Navigation and regression can use specialised finite-choice decision models. This implementation supports a local H2O model and an OpenAI navigation binding; arbitrary extraction and new free-form replies use a generative LLM. Authored templates can be delivered directly.

Prepared turns remain provisional until accepted; cancellation preserves the suspended task. Speech delivery is tracked separately, so an interrupted message remains pending and changed facts can invalidate stale speech.

Telephony and infrastructure Link to heading

SIP telephony connects inbound and outbound calls to the agent. LiveKit carries the media; isolated call processes coordinate speech providers, decisions, and business services. PostgreSQL and MinIO retain history and traces, with a dashboard for live and recorded execution.

Media path and call execution

  1. Phone networkInbound and outbound SIP / PBX
  2. LiveKit + SIP bridgeRooms, media, and Redis coordination
  3. Call workerIsolated process for each admitted call

Services around the worker

  • Speech providersRecognition and synthesis
  • Decision models + LLMLocal GPU gateway in dev; provider APIs
  • PostgreSQL + MinIOHistory, checkpoints, audio, and traces
  • OperationsNext.js dashboard; Prometheus / Grafana
Two-way media connects the caller and agent; the worker uses models and business services and records execution.

Docker deployments separate dev, stage, and production data while sharing telephony infrastructure. The development decision model can run behind an authenticated GPU gateway and SSH tunnel; Prometheus and Grafana provide host and container monitoring.

RSI: trace-driven improvement Link to heading

RSI turns test calls into reviewable workflow improvements. A larger model exercises the agent, inspects the event trace and defineGoal code, and opens a merge request with a fix and a reproducing regression case.

  1. Make test callsLarger model acts as caller and produces traces
  2. Inspect the traceLarger model diagnoses goals and transitions
  3. Open an MRFlow changes, trace evidence, and a regression case
  4. Retest the candidateCorpus, replay, and further model-driven calls
Corpus and replay checks support review of the candidate. Further calls exercise the revised workflow and feed the next iteration.