Travel Booking Agent
A user says the last Friday of June and the following Sunday.
The second date is relative to the first, not to today. Biruni lets you
chain calls — pass the first result as reference_date for the second.
User says
extract()Your LLM
→
resolve_time()Biruni — depart
→
resolve_time()Biruni — return
→
search_flights()Your flight API
→
reply()Your chat
The agent
travel_agent.py
import httpx, os
from datetime import date
BIRUNI_URL = "https://biruni.dev/v1/resolve"
# ── Stubs: replace with your integrations ────────────────────
async def search_flights(origin: str, dest: str, depart: str, ret: str):
"""Search flights. (Amadeus, Duffel, Skyscanner ...)"""
...
async def reply(text: str):
"""Send a response back to the user. (Slack, chat UI, email ...)"""
...
def extract(message: str) -> dict:
"""
Use your LLM to pull structured fields from the raw message.
Returns: {
"origin": str, "dest": str, "tz": str,
"depart_phrase": str, "return_phrase": str,
}
"""
...
# ── Biruni integration ──────────────────────────────────────
async def resolve_time(phrase: str, tz: str, ref: str | None = None) -> dict:
async with httpx.AsyncClient() as client:
r = await client.post(
BIRUNI_URL,
headers={"Authorization": f"Bearer {os.environ['BIRUNI_API_KEY']}"},
json={
"expression": phrase,
"reference_date": ref or date.today().isoformat(),
"timezone": tz,
},
)
r.raise_for_status()
return r.json()
# ── Agent entry point ────────────────────────────────────────
async def handle(message: str):
fields = extract(message)
departure = await resolve_time(fields["depart_phrase"], fields["tz"])
if departure["status"] != "resolved":
await reply("Couldn't pin down the departure date — could you rephrase?")
return
# Chain: use the departure date as the anchor for the return phrase
ret = await resolve_time(
fields["return_phrase"], fields["tz"],
ref=departure["resolved"][:10],
)
if ret["status"] != "resolved":
await reply("Got the departure, but the return date is unclear.")
return
await search_flights(
fields["origin"], fields["dest"],
departure["resolved"], ret["resolved"],
)
await reply(
f"Searching {fields['origin']} → {fields['dest']}: "
f"depart {departure['resolved'][:10]}, "
f"return {ret['resolved'][:10]}."
)