Slot validation
The LLM is flexible, which also means it is inconsistent. "lhr", "LHR", and "London" might all refer to the same airport. Before a slot enters state, we normalize it. That way the catalog lookup, option proposal, and confirmation nodes never have to guess what the value means.
# Inside intent_router, after merging slots from the LLM response:
# Uppercase IATA codes when they look like codes.
for key in ("origin", "destination"):
v = state.get(key)
if isinstance(v, str) and len(v) == 3:
state[key] = v.upper()A tiny normalization step right after extraction. Three-character strings look like IATA codes, so we uppercase them. Everything downstream can now assume LHR, not lhr.
async def search_flights_node(state: BookingState) -> BookingState:
origin = state.get("origin") or ""
dest = state.get("destination") or ""
depart = state.get("depart_date") or ""
candidates = search_flights(origin, dest, depart, limit=3)
state["candidates"] = candidates
if not candidates:
state["assistant_reply"] = (
f"I couldn't find flights from {origin} to {dest}. "
"Would you like to try a different route?"
)
state["stage"] = "collecting"
# Reset route so the user can retry
state["origin"] = None
state["destination"] = None
return stateValidation also means handling the empty case. If the catalog returned nothing, the agent resets origin and destination, sets stage back to collecting, and invites the user to try again.
Fill in the blanks: Fill in the normalization guard
Loading practice…