Skip to main content
A LiveKit voice agent that splits a mortgage servicing call into two agents. MortgageRetrievalAgent answers complex loan questions grounded in a Moss knowledge base. When the customer is ready to pay, a single @function_tool hands the call to PaymentFlowAgent, which walks through a structured payment flow — with no repeated questions, because both agents share the same session state.
Full example — see the Mortgage Lending cookbook for the complete agent, 41-document knowledge base, and index builder.

Architecture

Handoff is one line. LiveKit preserves the full chat history across the switch so the conversation feels continuous to the caller.

What this demonstrates

Required tools

Integration guide

1

Installation

2

Environment setup

.env
3

Define shared session state

Both agents read from and write to a single dataclass stored on session.userdata. The moss_client field carries the already-loaded client so handoffs reuse the warm in-process index — constructing a new client after handoff would silently fall back to the slower cloud query path.
4

Build the retrieval agent

MortgageRetrievalAgent answers loan questions and calls transfer_to_payment_flow when the customer is ready to pay.
5

Build the payment flow agent

PaymentFlowAgent reads the session state the retrieval agent already populated, so the customer never has to repeat their loan number.
6

Wire up the entrypoint

Load the Moss index once at startup and store the client on userdata so both agents can reuse it across the handoff.
Run in console mode to test without a LiveKit server:

How the handoff works

LiveKit Agents 1.0+ supports first-class handoff: a @function_tool can return (NextAgent, "transition message") instead of a string. LiveKit runs the transition utterance through TTS, tears down the current agent’s tools and instructions, and starts the new agent with the same chat history and session.userdata. Both agents share MortgageSessionData — no re-asking, no lost context.