Skip to content

Add hotel receptionist example#1727

Open
rosetta-livekit-bot[bot] wants to merge 1 commit into
mainfrom
port-hotel-receptionist-example-5983
Open

Add hotel receptionist example#1727
rosetta-livekit-bot[bot] wants to merge 1 commit into
mainfrom
port-hotel-receptionist-example-5983

Conversation

@rosetta-livekit-bot
Copy link
Copy Markdown
Contributor

@rosetta-livekit-bot rosetta-livekit-bot Bot commented Jun 7, 2026

Summary

  • port the Hotel Receptionist example from livekit/agents to agents-js
  • include seeded hotel, restaurant, invoice, cancellation, and dispute flows as an in-memory TypeScript example
  • adapt Python AgentTask workflows to TypeScript AgentTask tools without adding tests

Testing

  • pnpm eslint examples/src/hotel_receptionist.ts
  • pnpm build

Ported from livekit/agents#5983

Original PR description

No description.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Jun 7, 2026

⚠️ No Changeset found

Latest commit: 4104afa

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@rosetta-livekit-bot rosetta-livekit-bot Bot requested a review from theomonnom June 7, 2026 02:23
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 3 potential issues.

View 4 additional findings in Devin Review.

Open in Devin Review

Comment on lines +1826 to +1832
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}.`;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 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:

  1. updated === booking is always true, so the tool always returns "Booking left unchanged." even when changes were applied.
  2. Even if that guard were removed, updated.total - booking.total is always 0 (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 }.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +2098 to +2100
function speakCode(code: string): string {
return code.replace('-', ' dash ').toUpperCase().split('').join(', ');
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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.

Suggested change
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 ');
}
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +2262 to +2264
voiceOptions: {
maxToolSteps: 5,
},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 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 maxToolStepsreport.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.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants