An outbound voice agent for a freight logistics platform. It calls the carrier's dispatcher about a delivery, discloses that the call is recorded, and confirms the license plate of the truck assigned to the shipment, validating every plate it hears against the trucks on file and saving the confirmed one.
Dispatch teams burn hours on exactly this call. A human operator dials a carrier, asks for one field, writes it down, hangs up, dials the next one. This repo is that call as an agent, plus the part that usually goes missing: tests that prove the agent handles the calls before it makes them.
The agent is an OpenAI Realtime
session (gpt-realtime-2.1) defined in src/agent.ts:
instructions, voice, and two tools (validate_license_plate,
save_license_plate). The delivery and the carrier's trucks on file live in
src/dispatch.ts, standing in for the dispatch-system
lookup that would run right before dialing.
tests/plate-confirmation.test.ts uses
LangWatch Scenario to run the agent through
real calls: a simulated dispatcher speaks to it (text-to-speech into the same
realtime session a live call would use), a judge model evaluates the
conversation against criteria, and deterministic checks assert the tool calls
actually happened.
Three scenarios ship today:
- Cooperative dispatcher. Reads the plate when asked. The agent must disclose recording first, name the delivery, validate, save, and close politely.
- Confused dispatcher. Asks "which delivery was this about again?" mid-call. The agent must repeat itself patiently and still collect the plate.
- Wrong plate first. The dispatcher reads a plate that is not on file. The agent must flag the mismatch, ask them to double-check, and accept the corrected plate.
Every run is traced to LangWatch: the full conversation, the simulator and judge turns, and the tool calls, so a failing scenario comes with the trace that explains it.
pnpm install
cp .env.example .env # fill in your keys
pnpm testVoice scenarios hold a live realtime session for the whole conversation, so the suite takes a few minutes. CI runs the same suite on every push with the keys provided as repository secrets.
The delivery, the carrier, and the plates in src/dispatch.ts are fictional.