LangGraph

View as Markdown

This guide shows how to integrate the AgentDuet SDK with LangGraph for durable agent workflows, including checkpointed state, human-in-the-loop interrupts, and policy-gated tools.

What this integration provides

A voice agent that:

  • Answers inbound calls and bridges 24 kHz PCM to Gemini Live
  • Authenticates demo orders against a local mock database (no live store APIs)
  • Speaks shipping status in one or two short sentences
  • Allows address changes or cancellations only when fulfillment is unfulfilled

How the pieces fit

LayerOwns
AgentDuetConnector, inbound calls, PCM
Gemini LiveSpeech-to-speech dialogue + tool calls
LangGraphCall-scoped order state, tools, fulfillment policy
Your appPrompts, mock orders, tool side effects

PCM stays on the AgentDuet ↔ Gemini bridge. Graph checkpoints store compact business state only (order id, auth, fulfillment) — not audio.

Prerequisites

Step 1: Clone the sample

$git clone https://github.com/AgentDuet/agentduet-samples.git
$cd agentduet-samples/integrations/langgraph/order-tracking

Layout:

order-tracking/
├── main.py # SessionManager + Gemini Live bridge
├── graph.py # LangGraph OrderSession + tools
├── orders.py # Mock DB helpers
├── prompts.py # System prompt + greeting
├── data/orders.json # Seed orders #1001 / #1002
├── requirements.txt
└── .env.example

Step 2: Install dependencies

$python3.12 -m venv .venv
$source .venv/bin/activate # Windows: .venv\Scripts\activate
$pip install -r requirements.txt

The sample pins agentduet==1.0.0.

Step 3: Configure .env

$cp .env.example .env
$AGENTDUET_API_KEY=your-connector-api-key
$AGENTDUET_CONNECTOR_UUID=your-connector-uuid
$GEMINI_API_KEY=your-gemini-api-key

Step 4: Run locally

$python main.py

Call your agent. It should answer and walk order status or a change/cancel.

Demo orders

OrderZipFulfillmentTry
#100194107unfulfilledSpoken status; change address or cancel
#100210001fulfilledSpoken status; modifications declined

Example scripts:

  1. “Order 1001, zip 94107.” → short spoken status.
  2. “Change my address to 88 Folsom Street, San Francisco, California, 94105.” → succeeds on #1001.
  3. “Order 1002, zip 10001. Please cancel.” → status OK; cancel politely declined.

Step 5: How LangGraph and AgentDuet connect

SessionManager answers the call

From main.py:

1@sm.on_incoming_call
2async def on_call(noti: IncomingCallNotification) -> None:
3 session = await sm.open_session(new_session_id(), noti.subscriber)
4 call = await session.process_call(noti)
5 await handle_call(call)

LangGraph owns tools and call state

From graph.py, each call builds an OrderSession with checkpointed OrderState (thread id = call id) and LangChain tools:

  • authenticate_order — mock DB lookup by order id + zip
  • check_fulfillment_status — policy gate before modifications
  • change_shipping_address / cancel_order — allowed only when unfulfilled
  • hang_up — end the call after the caller says goodbye

Gemini Live receives the tool declarations and dispatches through OrderSession.ainvoke_tool.

Voice prompt rules

The system prompt in prompts.py instructs the agent to:

  • Greet inbound callers and collect a test order id (#1001 / #1002) plus zip
  • Authenticate via the mock database tool (never invent status)
  • Speak shipping status in one or two concise sentences
  • Check fulfillment before modifications; decline politely when fulfilled
  • Say a short goodbye and call hang_up when the caller is done
  • Keep spoken replies short

Notes

  • Keep call control and PCM buffering on the AgentDuet path; put order policy in LangGraph tools.
  • Map graph thread ids to stable conversation keys (this sample uses call.id).
  • Restarting the process reloads seed orders from data/orders.json.
  • This sample uses 24 kHz audio (CallAudioConfig(sample_rate=24000)).