feat(voice): per-restaurant voice_agent_name#23
Merged
ByteStreams-AI merged 2 commits intomainfrom May 4, 2026
Merged
Conversation
Adds a nullable `voice_agent_name` column on `restaurants` and threads it through `RestaurantLookup` → `PromptContext` → `PROMPT_TEMPLATE`. When set, the LLM introduces itself by this name verbatim if the caller asks; when null it picks a name on its own (current behavior, where it had been answering "Ruth"). Pronunciation is handled by storing what the agent should *say*: operators spell phonetically (e.g. "My-tay" instead of "Maite") or embed inline SSML phoneme tags for exact IPA control. ElevenLabs honors both. Single-column design — promote to two columns later if we ever add a non-voice display surface that needs the real spelling. - Migration 0014_voice_agent_name.sql - Seed: Sui's Sushi → "Maya" - Updates canonical schema doc to also list voice_id (added in 0013 but missing from the doc until now). - Three new prompt-template tests: name set, phonetic respelling, whitespace-only treated as null. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2cebf79 to
8f600c7
Compare
- Seed: voice_agent_name "Maya" → "MeSee" (matches the operator's ElevenLabs pronunciation-dictionary entry for "Mici"). - Promote agent_name guidance to a top-level # Identity block (was a single conditional line). Explicit override of the catch-all "automated assistant" canned reply when asked your name — that disclosure now stays scoped to the "are you a real person?" path. - Thread agent_name into the "are you a real person?" canned line: becomes "I'm MeSee, an automated assistant taking the order — is that okay?" when set; falls back to the original wording when null. Two new prompt-template tests cover both branches; whitespace-only treated as null. 281/281 unit. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ByteStreams-AI
added a commit
that referenced
this pull request
May 4, 2026
Adds open follow-up #6 capturing the flake observed on PR #24's full lane. Same test passed on PR #23's run an hour earlier; the failing PR #24 diff is prompt text only — zero impact on the reservation availability path. The flake is real and worth tracking, but not caused by the prompt change. Captures: where it lives, what triggers it, the proposed real fix (deterministic slot anchor instead of `now + 5h`).
ByteStreams-AI
added a commit
that referenced
this pull request
May 4, 2026
PR #24's full lane started failing on vapi_check_availability > returns alternative slots when the requested time is unavailable even though the diff is prompt text only. Same code paths passed on PR #23 an hour earlier. Two compounding test-setup bugs: 1. Sub-minute drift between iso and date+time. `localDateTimeFromNow` returned a millisecond-precision iso but minute-precision date+time. The blocked reservation was inserted with iso (e.g., 00:14:35.123Z) while the availability call used date+time (00:14:00). The 35-sec offset turned the +90-min candidate (which exactly abuts the reservation's end) into an apparent overlap, killing the only candidate that should have been a valid alternative. 2. UTC midnight boundary. When CI runs late in Chicago afternoon, now+5h crosses the UTC date boundary. The DB function's alternatives walk constrains candidates to the same UTC day as the requested slot, so the negative offsets (-90/-60/-30) all skip, leaving only +30/+60/+90 — and with bug #1, none of those produce an alternative. Fix: - Round localDateTimeFromNow down to the minute so iso/date/time align; eliminates bug #1 for every caller of this helper. - Add tomorrowAtHour(12) helper for tests that need a deterministic slot fully inside one UTC day and well inside operating hours. Switch the alternatives test to use it. The DB function is correct; the test setup was the bug. Marks the AGENTS.md follow-up as fixed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ByteStreams-AI
added a commit
that referenced
this pull request
May 4, 2026
* fix(voice): mandate "anything else?" + broaden finalize trigger
M11 ramp surfaced a wedge: caller orders two items, both land in cart
correctly via add_item_to_order, but finalize_order is never called.
Cart sits at $16.98 untouched, the call goes silent.
Root cause: the prompt told the LLM to call finalize_order "when the
customer says they're done" but never instructed it to ASK if they
were done. The model confirmed each item, called add_item_to_order,
then waited indefinitely for the caller to volunteer "that's it" —
which most callers don't say.
Two prompt fixes (no code path changes):
- Step 4f: ALWAYS ask "Anything else?" after each add_item_to_order.
Not optional, not tone-dependent. Going silent wedges the call.
- Step 5: broaden the done-signal recognizer from explicit "that's
it" / "I'm done" to also include implicit no-answers ("no thanks",
"nope", "no that's all"). Treats any "no" answer to "anything
else?" as a done signal.
Two new prompt-template tests lock both behaviors so a future prompt
edit can't silently regress.
Captured live during a Sui's call where call_id
019df454-3639-7000-8ed1-acce72d91492 had Cucumber Roll +
California Roll w/ white rice in raw_payload.cart but tool_log ended
at the second add_item_to_order.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs: log reservation alternative-slot test as time-of-day flaky
Adds open follow-up #6 capturing the flake observed on PR #24's full
lane. Same test passed on PR #23's run an hour earlier; the failing
PR #24 diff is prompt text only — zero impact on the reservation
availability path. The flake is real and worth tracking, but not
caused by the prompt change.
Captures: where it lives, what triggers it, the proposed real fix
(deterministic slot anchor instead of `now + 5h`).
* test(reservations): pin alternative-slot test to deterministic slot
PR #24's full lane started failing on
vapi_check_availability > returns alternative slots when the
requested time is unavailable
even though the diff is prompt text only. Same code paths passed on
PR #23 an hour earlier. Two compounding test-setup bugs:
1. Sub-minute drift between iso and date+time. `localDateTimeFromNow`
returned a millisecond-precision iso but minute-precision date+time.
The blocked reservation was inserted with iso (e.g., 00:14:35.123Z)
while the availability call used date+time (00:14:00). The 35-sec
offset turned the +90-min candidate (which exactly abuts the
reservation's end) into an apparent overlap, killing the only
candidate that should have been a valid alternative.
2. UTC midnight boundary. When CI runs late in Chicago afternoon,
now+5h crosses the UTC date boundary. The DB function's
alternatives walk constrains candidates to the same UTC day as the
requested slot, so the negative offsets (-90/-60/-30) all skip,
leaving only +30/+60/+90 — and with bug #1, none of those produce
an alternative.
Fix:
- Round localDateTimeFromNow down to the minute so iso/date/time
align; eliminates bug #1 for every caller of this helper.
- Add tomorrowAtHour(12) helper for tests that need a deterministic
slot fully inside one UTC day and well inside operating hours.
Switch the alternatives test to use it.
The DB function is correct; the test setup was the bug. Marks the
AGENTS.md follow-up as fixed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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
voice_agent_namecolumn onrestaurants(migration 0014). When set, the prompt instructs the LLM to introduce itself by this name verbatim if asked; null falls through to whatever the model invents (currently "Ruth" on Sui's calls).RestaurantLookup→buildPromptContext→PromptContext→PROMPT_TEMPLATE(one new conditional line at the top of the persona section)."Maya"so local + cloud test calls answer with a stable name.voice_id(was added in 0013 but never reflected) so the doc stays the source of truth it claims to be.Test plan
pnpm ci:fast— 280/280 (one new prompt-template test covering set / phonetic-respelling / whitespace-only-treated-as-null)db push:update restaurants set voice_agent_name = 'Maya' where slug = 'suis-sushi', place call, ask "what's your name?", confirm "Maya"voice_agent_name = 'My-tay'on a test restaurant, confirm ElevenLabs pronounces it that wayOperational note
The cloud deploy workflow does NOT push migrations (known gap, tracked in PR #16). After this merges, run
pnpm supabase db push --linkedagainst the cloud project before relying on the new column —select voice_agent_name from restaurants limit 1to verify.🤖 Generated with Claude Code
Greptile Summary
Adds a nullable
voice_agent_namecolumn onrestaurantsand threads it end-to-end — migration → DB types →RestaurantLookup→buildPromptContext→PromptContext→PROMPT_TEMPLATE— so operators can give the voice agent a stable, pronounceable name. The custom Mustache renderer's existingisTruthyguard correctly treatsnulland whitespace-only values as falsy, preventing the Identity section from rendering when no name is configured.Confidence Score: 5/5
Clean, well-scoped feature addition — safe to merge after the manual cloud migration step noted in the PR.
No P0 or P1 findings. The rendering logic is correct (non-greedy section regex + interpolate pass handles two
{{#agent_name}}sections cleanly), the migration is idempotent, types are in sync, and all branching paths are covered by tests.No files require special attention.
Important Files Changed
{{#agent_name}}Identity section and threads the name into the "are you a real person?" disclosure; rendering logic is correct givenrenderSectionsnon-greedy regex and subsequentinterpolatepass.voice_agent_namefrom DB, threads it throughRestaurantLookupintoPromptContext; straightforward plumbing with no logic issues.voice_agent_namecolumn withadd column if not existsguard; clean and idempotent.voice_agent_name = 'MeSee'; code and tests are internally consistent.voice_id(added in 0013 but missed here) and addsvoice_agent_name; keeps the canonical schema doc in sync.Reviews (3): Last reviewed commit: "feat(voice): swap seed to MeSee + streng..." | Re-trigger Greptile