Skip to content

Documentation / Core concepts / Lifecycle

From ActiveCall to Closure

After setup passes preflight, VAANI owns the call attempt. That owned attempt produces exactly one immutable CallResult, even when providers fail, the participant disconnects, teardown times out, or the owner is cancelled.

stateDiagram-v2
  [*] --> ACCEPTED
  ACCEPTED --> VALIDATING
  VALIDATING --> STARTING
  STARTING --> CONNECTING
  CONNECTING --> WAITING_FOR_PARTICIPANT
  WAITING_FOR_PARTICIPANT --> GREETING
  GREETING --> CONVERSING
  CONVERSING --> ENDING: graceful EndRequest
  CONVERSING --> TEARING_DOWN: forced terminal signal
  ENDING --> TEARING_DOWN
  TEARING_DOWN --> FINALIZING
  FINALIZING --> CLOSED: publish CallResult
  CLOSED --> [*]

Some failures skip phases. Progress is always forward; a late signal cannot reopen or reverse a committed transition.

Start and run

Use run() when the owner only needs the terminal result:

result = await runtime.run(invocation, setup)

Use start() when consumer code needs the call handle:

active = await runtime.start(invocation, setup)
print(active.call_id, active.revision)
receipt = await active.update(update)
await active.end(EndRequest(EndRequestSource.ACTIVE_CALL, "complete"))
result = await active.wait()

ActiveCall.update(), end(), and wait() are the public operations. The async context manager is also an ownership boundary: normal exit requests a graceful end; exceptional exit forces cancellation if the call is still active.

Exactly one result

Closure is the atomic publication point. All successful waiters receive the same frozen result. Cancelling a result observer does not end the call; cancelling the lifecycle owner does.

Before ownership, configuration/controller-installation problems raise a typed startup error and produce no result. After ownership, terminal failures appear inside the result's normalized failure evidence.

Deadlines do not reset on retry

Each bounded phase receives an absolute monotonic cutoff. A retry spends the remaining budget; it cannot create a new full timeout. Completion observed by the cutoff wins, and later completion is quarantined rather than mutating the result.

Separate budgets exist for:

  • connection, participant readiness, greeting, terminal media, drain, teardown, and finalization;
  • provider operations, tools, updates, transfer, recording, and result publication.

Graceful and forced endings

All healthy completion sources submit an EndRequest. The first accepted request is canonical; later requests join the same ending and remain as suppressed evidence. A forced terminal signal can pre-empt terminal media but cannot erase that canonical request.

Next: tools and state or result evidence.