fix(hotel_receptionist): room and dispute tool-flow fixes - #6807
Open
u9g wants to merge 9 commits into
Open
Conversation
…sition An escalation reply that opens with "I have escalated this to the manager" skips the stance the caller is owed from the record - a card-guaranteed no-show charge that stands, say - and reads as a brush-off. Put the policy explanation first, and record a callback number so the manager can reach them instead of offering an unasked-for live transfer.
Telling the agent to give the walk "in short pieces" let it spread the four parts across turns, and an angry guest hangs up before the later ones land - so the guest never hears that the taxi is covered or that their own room is theirs again. Require all four parts in one reply, and say the walk itself is the resolution so the agent stops offering a manager on top of it.
A caller booking two rooms can get the model to call start_room_booking twice in one turn. Inline AgentTasks cannot run in parallel - the second activation supplants the first, whose function call then never resolves, and the session wedges. Track the in-flight flow and raise a ToolError on re-entry so the model finishes one room before starting the next.
When card capture ends with no usable card, GetCardTask raises and the bare ToolError reaches the model as a dead end - it apologizes and leaves the caller thinking the reservation is at risk. Nothing was lost: the existing card stays on file and a working one is not needed until check-in. Say that, and make the callback offer the turn's question.
The model sometimes re-invokes start_booking_modification with no new caller input instead of relaying the result, re-opening the flow on the booking it just updated and walking the caller through the same changes again while the confirmation and any refund never get spoken. Mirror the cancel guard: with no caller turn since the last modification, re-surface that outcome.
…field
The progressive-disclosure rule ("surface results progressively, don't recite
the whole list") bleeds into lookup_booking, so a caller who asks to confirm
their reservation hears only the field they named and never gets the chance to
catch a wrong room type or smoking status before arrival. Scope that rule to
option lists explicitly.
…unambiguous lookup_invoice rendered a line as "Room (2 nights) 560 dollars", so the model copied the merged label-plus-amount string into dispute_charge, the exact-label match failed, and the error told it to read the lines back - which produced the same merged string again, looping until the caller gave up. Quote the labels at the source, and have the no-match error list the exact labels and say what to do when the charge is genuinely not on the invoice.
dispute_charge took a bool for whether the caller had accepted the offer, but the agent has to call the tool to learn what the policy offer even is - so the first call filed the dispute and applied the waiver or credit before the caller had been told anything, and a "declined" second call could not undo it. Split the argument into pending/accepted/declined. A pending call resolves the policy and hands back the offer to present, persisting nothing; only an explicit accepted or declined call files. Policies whose two outcomes are identical are automatic and still resolve on the first call.
"I thought I cancelled" reads as a cancellation to the model, so it picked cancellation_fee and the caller got the wrong policy - that category is only for a fee from an actual recorded cancellation. Draw the line at the call site; the system prompt already draws it, but the choice is made here.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Nine independent room- and dispute-tool fixes from #6567, split one per commit. Everything here is scoped to
examples/hotel_receptionist/tools_rooms.pyplus theUserdatafields two of the guards need.Dispute flow
dispute_chargetook a bool for whether the caller had accepted the offer, but the agent has to call the tool to learn what the policy offer even is — so the first call filed the dispute and applied the waiver or credit before the caller had been told anything, and adeclinedsecond call could not undo it. The argument is nowpending/accepted/declined: a pending call resolves the policy and hands back the offer to present, persisting nothing. Policies whose accepted and declined outcomes are identical are automatic and still resolve on the first call.lookup_invoicerendered a line asRoom (2 nights) 560 dollars, so the model copied the merged label-plus-amount string intodispute_charge, the exact-label match failed, and the error told it to read the lines back — producing the same merged string again, looping until the caller gave up. Labels are quoted at the source, and the no-match error lists the exact labels and says what to do when the charge genuinely isn't on the invoice.cancellation_fee; that category is only for a fee from an actual recorded cancellation. Theno_showline is now drawn in the arg docstring, where the choice is made.Room tools
start_room_bookingtwice in one turn. InlineAgentTasks cannot run in parallel — the second activation supplants the first, whose function call then never resolves, and the session wedges. A second call now raises instead of running.ToolErrorreached the model as a dead end and it left the caller thinking the reservation was at risk. Nothing was lost: the existing card stays on file and a working one isn't needed until check-in. The callback offer becomes the turn's question.start_booking_modificationwith no new caller input instead of relaying the result, re-opening the flow on the booking it just updated while the confirmation and any refund never got spoken. Same guard the cancel path already has.lookup_booking, so a caller confirming their reservation heard only the field they named and never got the chance to catch a wrong room type or smoking status before arrival. That rule is now scoped to option lists.Not carried over from #6567
describe_room_optionsincheck_room_availability— fix(hotel_receptionist): hotel_db stored-state and read-back fixes #6805 already carries it.load_capability("guest_services")becamerecord_followup (kind="other");capabilities.pyisn't on main, so the original wording would name a nonexistent tool.Testing
ruff format --checkandruff checkclean acrossexamples/hotel_receptionist/.DISPUTE_POLICIESactions: the two automatic actions (sub-threshold minibar, duplicate-charge ticket) still resolve on the first call; every other action returns an unfiled offer while pending, then the matching outcome onaccepted/declined.mypyon the two changed files goes 13 -> 15 errors, allRoomToolsMixin has no attribute "session"— the pre-existing mixin pattern the cancel guard already trips, andexamples/is outsidescripts/check_types.py's scope.