A complete drive-thru ordering system demonstrating interactive voice agents for food ordering with database integration and order management.
For setup instructions and more details, see the main examples README.
This example simulates a fast food drive-thru. It is split across three files: database.py contains the menu and formats it as system prompt text, order.py holds Pydantic models for the three order types, and agent.py defines DriveThruAgent with dynamically built ordering tools.
The full menu is loaded once per session and injected directly into the agent's instructions, so the LLM has menu context without needing to call a tool.
At the start of each session, new_userdata() queries FakeDB for all item categories (drinks, combos, Happy Meals, regulars, sauces) and stores them in the Userdata dataclass alongside a fresh OrderState.
agents/examples/drive-thru/agent.py
Lines 382 to 399 in 8283a5a
DriveThruAgent.__init__ then formats each category using menu_instructions() and concatenates the results with COMMON_INSTRUCTIONS to build the full system prompt. This means the LLM sees the entire menu from the first turn and can answer questions or suggest items without any tool calls.
agents/examples/drive-thru/agent.py
Lines 55 to 83 in 8283a5a
The three ordering tools are constructed by build_combo_order_tool, build_happy_order_tool, and build_regular_order_tool. Each method closes over the relevant item lists and injects their IDs as the enum constraint in the tool's JSON schema.
agents/examples/drive-thru/agent.py
Lines 85 to 119 in 8283a5a
This restricts the LLM to known IDs at the schema layer before any runtime logic runs. ToolError handles the cases that can't be caught statically β for example, when a drink has multiple available sizes and the customer hasn't specified one yet, the tool raises a ToolError prompting the agent to ask for clarification before retrying.
order.py defines three Pydantic models: OrderedCombo, OrderedHappy, and OrderedRegular . A discriminated union OrderedItem is also defined. Each ordered item receives a random short order_id on creation via order_uid().
OrderState stores the current cart as a dict[str, OrderedItem] keyed by order_id, which the remove_order_item and list_order_items tools use to look up or modify existing items.
agents/examples/drive-thru/order.py
Lines 45 to 56 in 8283a5a
Two tools handle cart management:
list_order_itemsreturns all current cart items with theirorder_ids. The agent is instructed to call this first when modifying or removing an item whoseorder_idis unknown.remove_order_itemremoves one or more items byorder_id. Modifications (e.g., upsizing fries) are done by removing the old item and re-adding it with the new parameters.
max_tool_steps=10 is set on the session to give the agent enough budget to call list_order_items followed by remove_order_item in a single turn when needed.
BackgroundAudioPlayer plays an ambient drive-thru noise track (bg_noise.mp3) throughout the session to set the scene.
agents/examples/drive-thru/agent.py
Lines 438 to 443 in 8283a5a
The STT model is also initialized with keyterm hints for McDonald's brand names (e.g., "Big Mac", "McFlurry", "McCrispy") to improve transcription accuracy.
agents/examples/drive-thru/agent.py
Lines 415 to 430 in 8283a5a
scenarios.yaml holds scenarios that run the agent against a simulated customer, covering ordering, removal, combos, sizes, quantities, unavailable items and tool failures. Run them from the repo root:
lk agent simulate text examples/drive_thru/agent.py --scenarios examples/drive_thru/scenarios.yamlAll simulation glue lives in simulation.py. Each scenario's userdata can set:
expected_order: the items the order must hold when the run ends (order ids are ignored).on_simulation_endfails the run on a mismatch, even if the simulator passed it.unavailable_items: menu item ids marked unavailable before the agent starts.failing_tools: tools that raise instead of running, mocked on the live session withmock_tools(..., session=session).