Slot fields and status transitions

A conversation is a slot-filling exercise. The user walks in with an unstructured sentence. By the end of the turn you want filled fields: intent, specialty, chosen slot, confirmed record. The job of each node is to own a specific slot and fill it. Nobody else writes that slot.

booking_graph.py
python
# Slot ownership by node:
#
#   intent_router    -> state["intent"]
#   collect_symptoms -> state["symptom"]
#   match_specialty  -> state["specialty"]
#   find_doctor      -> state["doctor"]
#   propose_slots    -> state["slot_options"], state["status"] = "ready_to_confirm"
#   confirm_booking  -> state["slot"], state["status"] = "confirmed"
#
# status is the routing pivot. The next turn reads it to decide
# whether to enter the router or jump straight to confirm_booking.

One writer per slot. When debugging, you always know which node produced which value. Status is the exception: multiple nodes write it because it drives routing for the next turn.

booking_graph.py
python
async def run_turn(thread_id, user_message, patient_id=None):
    state = get_thread_state(thread_id)
    state["user_message"] = user_message
    state["patient_id"] = patient_id
    state["events"] = []
    state["assistant_reply"] = ""

    graph = get_graph()

    # The status field from the previous turn decides entry point
    if state.get("status") == "ready_to_confirm":
        result = await confirm_booking(state)
    else:
        result = await graph.ainvoke(state)

    _THREADS[thread_id] = dict(result)
    ...

The status field written on turn N decides the entry point for turn N+1. ready_to_confirm means "a slot was proposed, interpret the next user message as a choice". Any other status means "run the full router again".

Matching exercise: Match each slot to the node that owns it

Loading practice…

Quiz: Quiz

Loading practice…