Inspiration

The US flight cancellation rate reached 1.4% in 2024 (up from 1.3% the year before), and at hub airports like Washington Reagan National, over a quarter of flights are delayed and nearly 4% are cancelled outright. Every one of those disruptions currently gets discovered by the traveler — a gate announcement, a push notification — who then has to open an app or call the airline themselves. Trip Rescue flips who does the noticing.

What it does

Trip Rescue watches a traveler's booking, and when it's disrupted, it doesn't wait for them to notice. It asks Duffel for real, live rebooking options on the spot, then has a CALL-E voice agent call the traveler directly, read out up to three real alternatives with actual prices and departure times, and ask which one they'd like — or whether none of them work, or they'd rather talk to a person. If the traveler accepts an option, it's confirmed on their real booking before the call ends. No option is ever invented, and the booking is never changed without the traveler's explicit, on-call confirmation.

How we built it

  • Duffel for real flight search, instant booking, and the order-change/confirm flow that actually moves a passenger to a new flight. Every one of these calls was proven against Duffel's live sandbox before being written into the codebase — twice, independently (booking references LQKYWD and UUEGXU) — which caught a real validation bug (Duffel rejects fictional +1555...-range phone numbers) before it could surprise us on demo day.
  • CALL-E (calle-ai Python SDK) for the actual phone call, using calls.create_and_wait with a closed, enum-driven result_schema so the call can only report one of five defined outcomes (accepted option 1/2/3, declined all, asked for a human) — never a free-text decision the rest of the system has to interpret.
  • A plain-code orchestrator that owns every decision about whether to touch the booking — the voice model reports what happened, the orchestrator decides what happens next, and it only ever confirms a change after a reachable call with an explicit accepted-option decision.
  • A SQLite persistence layer (store.py) so every disruption, call, and outcome is recorded instead of living only in process memory, and a wider rebooking search that automatically checks nearby dates when the traveler's original date has no good options.

Challenges we ran into

The two paid dependencies a "real" version of this would need — a live flight-status feed and a production airline/GDS relationship — were both out of reach in a multi-day build. Rather than fake it silently, the disruption trigger is explicitly a stand-in (documented loudly in the README and the CLI's own --help text), while the rebooking mechanic itself is fully real against Duffel's sandbox.

Accomplishments that we're proud of

Every rebooking path is tested against Duffel's live sandbox, not mocked — including a real validation bug we caught before demo day. The voice agent's decision space is a closed enum, not free text, so it can never drift into an unconfirmed booking change. The test suite grew from 17 to 28 tests as we added nearby-date search widening and SQLite persistence.

What we learned

Test against the real thing, not a mock of it — mocking Duffel would have hidden the phone-number validation bug entirely, and that's exactly the kind of surprise you don't want live on demo day. We also learned to keep the voice agent's job narrow: the moment we tried letting it interpret free-text intent, edge cases multiplied; collapsing its output to a closed, five-value enum made the whole system easier to reason about and impossible to accidentally over-trust. That pushed us toward a broader principle — keep the model as a reporter of what happened on the call, and keep every decision that touches money or a real booking in plain, auditable code. Finally, building the SQLite layer after the fact made clear how much we'd been relying on the process simply not crashing; persisting state from the start would have saved us a rewrite.

What's next

Since the initial build, the rebooking search now widens to nearby dates automatically and every disruption/call/outcome is persisted to SQLite instead of living only in process memory — both were on this list and are now in the codebase (28 tests, up from 17). What's still ahead: widening the search further to nearby airports and other cabin classes, a real crash-recovery sweep over unresolved rows in the store, and — if this moves past a hackathon build — a real disruption feed and a partnership with an OTA or travel management company that already holds PNRs across multiple airlines, rather than going airline-by-airline.

Built with

Python, CALL-E (CALL-E Python SDK), the Duffel API, httpx, pytest, SQLite.

PR: https://github.com/CALLE-AI/awesome-phone-call-agents/pull/423 Demo video: https://youtu.be/UOf0mkBbaTI

Built With

Share this project:

Updates

Submission history