Add hotel receptionist example#1727
Conversation
|
| if (updated === booking) return 'Booking left unchanged.'; | ||
| const delta = updated.total - booking.total; | ||
| const money = | ||
| delta === 0 | ||
| ? `total stays at ${speakUsd(updated.total)}` | ||
| : `new total is ${speakUsd(updated.total)}; ${speakUsd(Math.abs(delta))} ${delta > 0 ? 'added to' : 'refunded to'} the card ending in ${updated.cardLast4}`; | ||
| return `Your booking is updated; ${money}.`; |
There was a problem hiding this comment.
🔴 startBookingModification always says "Booking left unchanged" because updateBooking mutates and returns the same object reference
After a successful booking modification, db.updateBooking() at examples/src/hotel_receptionist.ts:457 uses Object.assign(booking, {...}) to mutate the found booking in-place and returns the same object reference. Since verifiedBooking (line 1960-1966) caches a reference to the same object from the db.bookings array, updated returned by ModifyBookingTask.run() is always the identical JS object as booking in startBookingModification. This causes two problems on lines 1826-1831:
updated === bookingis alwaystrue, so the tool always returns "Booking left unchanged." even when changes were applied.- Even if that guard were removed,
updated.total - booking.totalis always0(same object), so the price delta is never communicated.
The database IS correctly modified, but the caller is incorrectly told nothing changed and never hears the updated total or price difference.
Prompt for agents
The bug is that db.updateBooking() mutates the booking object in-place and returns the same reference. The startBookingModification handler then compares updated === booking (same object → always true) and updated.total - booking.total (same object → always 0). To fix this, either: (1) snapshot the old total before calling ModifyBookingTask.run() (e.g. const oldTotal = booking.total) and use that for the delta comparison, and use ModifyBookingTask's changed set (or a similar mechanism) to determine if changes were made; or (2) have db.updateBooking() return a shallow copy of the booking instead of the same reference; or (3) have ModifyBookingTask.run() return a result object that includes a 'changed' boolean alongside the booking. The simplest fix is approach (1): save const oldTotal = booking.total before the run() call, then after it, check if the task made changes (e.g. check if updated.total !== oldTotal or if key fields differ from what you snapshot). The ModifyBookingTask already tracks changes in its 'changed' set but doesn't expose it. You could also make the giveUp handler return a sentinel (like wrapping in { booking, changed: false }) vs confirm returning { booking, changed: true }.
Was this helpful? React with 👍 or 👎 to provide feedback.
| function speakCode(code: string): string { | ||
| return code.replace('-', ' dash ').toUpperCase().split('').join(', '); | ||
| } |
There was a problem hiding this comment.
🟡 speakCode spells out the word "dash" as individual letters D-A-S-H, making confirmation codes unintelligible
speakCode replaces '-' with ' dash ' but then immediately calls .split('').join(', '), which splits every character including the expanded word "dash" and the surrounding spaces. For a code like "HTL-EF56", the output is "H, T, L, , D, A, S, H, , E, F, 5, 6" — the TTS reads "D, A, S, H" as individual letters instead of the word "dash", making the confirmation code difficult for callers to understand.
| function speakCode(code: string): string { | |
| return code.replace('-', ' dash ').toUpperCase().split('').join(', '); | |
| } | |
| function speakCode(code: string): string { | |
| return code | |
| .toUpperCase() | |
| .split('-') | |
| .map((part) => part.split('').join(', ')) | |
| .join(' dash '); | |
| } |
Was this helpful? React with 👍 or 👎 to provide feedback.
| voiceOptions: { | ||
| maxToolSteps: 5, | ||
| }, |
There was a problem hiding this comment.
🚩 voiceOptions is deprecated — maxToolSteps should be a top-level option
The session is configured with voiceOptions: { maxToolSteps: 5 } at line 2262-2264, but voiceOptions is marked deprecated in the framework (agents/src/voice/agent_session.ts:231). The top-level maxToolSteps field on AgentSessionOptions (line 233 of the same file) is the current API. The deprecated voiceOptions path may or may not still propagate maxToolSteps — report.ts only reads interruption/endpointing fields from it, and I could not confirm that maxToolSteps is merged. If it isn't, the agent would silently fall back to the default of 3 tool steps instead of the intended 5, which could cause complex multi-tool flows (booking, verification, modification) to be truncated.
Was this helpful? React with 👍 or 👎 to provide feedback.
Summary
Testing
Ported from livekit/agents#5983
Original PR description
No description.