Skip to content

FE-1722: Improve Brunch Voice controls - #9747

Merged
kostandinang merged 14 commits into
mainfrom
kostandin/fe-1722-improve-brunch-voice-controls
Sep 15, 2026
Merged

kostandinang merged 14 commits into
mainfrom
kostandin/fe-1722-improve-brunch-voice-controls

Conversation

@kostandinang

@kostandinang kostandinang commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

🌟 What is the purpose of this PR?

This PR makes Brunch Voice controls easier to understand and use. The microphone
button stays in the main dock, while speaker mute and volume sit in a compact,
headerless Audio options popover with an icon toggle, slider, and percentage.
Stop appears only while Brunch is responding and remains separate from End, so
stopping a response does not disconnect a Live session.

The change keeps the existing capture, transcript, and work-ownership rules
intact. Automated tests cover the control behavior; real microphone, speaker,
and headphone behavior still needs a short manual check on physical hardware.

🔗 Related links

🚫 Blocked by

🔍 What does this change?

  • Keeps microphone mute directly available in the Voice dock.
  • Adds speaker mute and volume for Live and Realtime in one compact Audio
    options popover.
  • Keeps Repeat question, Read full response, and Interruption by speaking
    available only for Realtime, below a visual divider.
  • Shows Stop only while Brunch is working and keeps it separate from End.
  • Aligns microphone, Stop, and End as 28 px actions with 16 px line icons;
    Stop remains neutral and End remains red.
  • Renames the display toggle to Show conversation and Hide conversation; it
    changes visibility only.
  • Preserves Speaking status when speaker output is muted or set to zero volume.
  • Adds provider-aware Storybook examples, user documentation, and a Petrinaut
    patch changeset.
🏗️ Agent notes

Status

FE-1722 is based directly on main after foundation PR #9745 merged. It is the
bottom entry in GitHub stack #9750, with follow-up PR #9748 above it.
Deterministic verification is complete. Physical audio routing and quality
remain an owner-held browser check.

Imperative

Make an active Brunch Voice session compact and predictable without changing
who owns capture, canonical work, or playback.

Throughline

  • Live microphone mute changes the existing shared capture track; it does not
    create a second capture or silence playback.
  • Speaker mute and normalized volume are session-local and reset when a new
    Voice session starts.
  • Canonical Stop is shown only for submitted or streaming work. In Live it
    calls LiveBrunchBridge.stopResponse() and keeps media connected.
  • End remains a separate Voice-session teardown and does not cancel canonical
    work.
  • Show/Hide conversation affects presentation only.
  • FE-1712's browser playback recovery, capture preferences, semantic VAD,
    patient listening, and 500 ms output hold remain in place.

Proof

  • Network-denied Petrinaut Voice suites: 160 tests passed.
  • Network-denied website Voice suites: 349 unit tests and 5 preview tests
    passed.
  • Petrinaut and website build, TypeScript, and ESLint checks passed.
  • Architecture documentation, repository formatting, Markdown, and diff checks
    passed.
  • Storybook fixtures were checked at desktop and narrow widths, including
    keyboard activation, Escape dismissal, and focus restoration. Reduced-motion
    handling is implemented, but no per-story emulation is claimed.

These checks prove deterministic control behavior. They do not prove audible
routing, conversational quality, or behavior on every physical device.

Constraints

  • Preserve consent, one-capture ownership, teardown, transcript admission,
    delegation policy, provider pinning, canonical Brunch authority, and Realtime
    response ownership.
  • Speaker controls must not affect microphone input, canonical work, or
    Speaking status.
  • Stop must not tear down Voice; End must not cancel canonical work.
  • Show/Hide conversation must not affect capture, playback, work, session
    state, history, or admission.
  • A provider-finalized partial transcript after muting mid-utterance remains
    admissible.

Fog-line

Physical audio routing, subjective volume behavior, conversational quality,
natural turn boundaries, and real-device narrow-layout usability remain manual
observations.

Stop or reorient

Stop if microphone mute creates or replaces capture, silences output, or
changes admission; if speaker controls affect capture or canonical work; if
Stop disconnects Voice; if End cancels canonical work; if Show/Hide changes
anything beyond visibility; or if Realtime-only controls appear in Live.

Deferred

Device switching, voice and speed selection, helmet animation, and persistent
speaker settings remain out of scope. Follow-up work is recorded in
MISSION.next.md.

Pre-Merge Checklist 🚀

🚢 Has this modified a publishable library?

This PR:

  • modifies an npm-publishable library and I have added a changeset file(s)

📜 Does this require a change to the docs?

The changes in this PR:

  • require changes to docs which are made as part of this PR

🕸️ Does this require a change to the Turbo Graph?

The changes in this PR:

  • do not affect the execution graph

⚠️ Known issues

  • Real microphone, speaker, and headphone behavior has not been checked on
    physical hardware yet.
  • The existing static Storybook build still encounters its CSS minification
    issue; the development Storybook and interaction checks pass.

🐾 Next steps

  • Complete the manual Live and Realtime audio check on physical hardware.
  • Handle device selection, voice and speed controls, animation, and persisted
    speaker settings separately.

🛡 What tests cover this?

  • 160 Petrinaut Voice tests.
  • 349 website Voice unit tests and 5 preview tests.
  • Petrinaut and website build, TypeScript, and ESLint checks.
  • Architecture-doc, formatting, Markdown, and diff checks.

❓ How to test this?

  1. Run yarn workspace @hashintel/petrinaut dev and open Storybook at
    http://localhost:6006.
  2. Under Editor / AI Assistant, open the Live and Realtime Audio options
    stories. Confirm Live uses the compact speaker row, while Realtime places
    its provider-specific actions below a divider.
  3. Open the submitted or streaming story. Confirm microphone, Stop, and End
    have consistent visual weight, and that Stop remains separate from End.
  4. Check the microphone-muted and speaker-muted Speaking stories. Speaking
    should remain visible in both.
  5. Open the narrow-width story and confirm the dock and popover stay inside the
    frame. Use Escape to close the popover and confirm focus returns to Audio
    options.

📹 Demo

A typical Voice control flow:

  1. Open Audio options. Live presents speaker mute, volume, and the current
    percentage in one compact row.

Compact Live Audio options with speaker toggle, volume slider, and percentage

  1. Use provider-specific actions when available. Realtime keeps its
    existing actions below a subtle divider.

Realtime Audio options with provider-specific actions below a divider

  1. Stop a response without disconnecting. During active work, Stop appears
    beside the consistently sized microphone and End controls.

Aligned microphone, Stop, and End controls in the active Voice dock

Try the provider-specific and narrow-width variants under
Editor / AI Assistant in Storybook.

@vercel

vercel Bot commented Sep 15, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
hash Ready Ready Preview Sep 15, 2026 5:56pm UTC
petrinaut Ready Ready Preview Sep 15, 2026 5:56pm UTC
petrinaut-docs Ready Ready Preview Sep 15, 2026 5:56pm UTC
1 Skipped Deployment
Project Deployment Actions Updated
hashdotdesign-tokens Ignored Ignored Preview Sep 15, 2026 5:56pm UTC

Request Review

@github-actions github-actions Bot added area/infra Relates to version control, CI, CD or IaC (area) area/libs Relates to first-party libraries/crates/packages (area) type/eng > frontend Owned by the @frontend team area/apps area/apps > hash.design Affects the `hash.design` design site (app) labels Sep 15, 2026
@kostandinang kostandinang self-assigned this Sep 15, 2026
@kostandinang
kostandinang added this pull request to stack #9749 September 15, 2026 16:26
@kostandinang
kostandinang marked this pull request as ready for review September 15, 2026 16:29
An error occurred while trying to automatically change base from kostandin/fe-1664-land-voice-stack to main September 15, 2026 16:29
@cursor

cursor Bot commented Sep 15, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Changes real-time voice media and canonical Stop/End semantics on Live and Realtime paths; regressions would affect capture, playback, or Brunch cancellation without obvious UI breakage.

Overview
FE-1722 reshapes Brunch Voice into a compact dock: microphone mute stays on the bar, Audio options (popover) holds speaker mute/volume for Live and Realtime, and Realtime-only replay/interruption controls stay behind a divider. Stop AI response appears only while Brunch is submitted or streaming and stays separate from End voice mode; Hide/Show conversation toggles transcript visibility only.

The host contract and website sessions now thread session-local speaker state (not persisted; reset each new session). Live mutes the shared capture track without stopping playback or tearing down media on Stop; Realtime keeps existing mic gating and adds the same speaker APIs on remote audio. Status precedence is unchanged—Speaking still reflects provider output when the speaker is muted or volume is zero.

Docs, mission pointers, Storybook scenarios, and broad unit tests cover dock behavior, lifecycle guards (no controls after session end), and the existing Live Stop → stopResponse() path.

Reviewed by Cursor Bugbot for commit 5746995. Bugbot is set up for automated code reviews on this repo. Configure here.

kostandinang and others added 6 commits September 15, 2026 19:20
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
kostandinang and others added 7 commits September 15, 2026 19:20
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@kostandinang
kostandinang force-pushed the kostandin/fe-1722-improve-brunch-voice-controls branch from c860d30 to 089a4fb Compare September 15, 2026 17:20
@kostandinang
kostandinang removed this pull request from stack #9749 September 15, 2026 17:22
@kostandinang
kostandinang changed the base branch from kostandin/fe-1664-land-voice-stack to main September 15, 2026 17:22
@kostandinang
kostandinang added this pull request to stack #9750 September 15, 2026 17:22
@semgrep-code-hashintel

Copy link
Copy Markdown

Semgrep found 1 node_api_key finding:

  • apps/petrinaut-website/src/server/voice/openai-transcription-session.ts

A hardcoded API Key is identified. Store it properly in an environment variable.

@lunelson lunelson left a comment

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.

Two non-blocking follow-ups:

  1. FE-1722 asks for Storybook coverage of keyboard focus, Escape dismissal, and reduced motion. The new stories cover pointer interaction and narrow layout, while focus/Escape are covered only by the unit test and reduced motion has no Storybook scenario. Please consider adding those Storybook interactions so the stated verification remains reproducible.

  2. libs/@hashintel/brunch-agent/MISSION.md lines 16–18 cite 49ffd6836a..bdc699c923, but neither commit is an ancestor of this PR head after the rebase. Please replace the range with current commits or remove the volatile hashes.

Co-authored-by: Cursor <cursoragent@cursor.com>
@kostandinang

Copy link
Copy Markdown
Contributor Author

Addressed the pragmatic review follow-ups in 5746995:

  • The Live Audio options story now opens from the keyboard, verifies focus enters the popover, closes with Escape, and verifies focus returns to the trigger.
  • MISSION.md now describes the current main base and PR stack without volatile commit hashes or stale pre-push authorization text.
  • The PR description no longer claims reduced-motion Storybook coverage. The production reduced-motion handling remains, but no per-story emulation is claimed in this PR.

@lunelson lunelson left a comment

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.

Re-reviewed the follow-up. The stale mission references are fixed, and Storybook now covers keyboard opening, focus placement, Escape dismissal, and focus return. The remaining reduced-motion coverage suggestion is non-blocking.

@kostandinang
kostandinang added this pull request to the merge queue Sep 15, 2026
Merged via the queue into main with commit 36d777c Sep 15, 2026
67 checks passed
@kostandinang
kostandinang deleted the kostandin/fe-1722-improve-brunch-voice-controls branch September 15, 2026 19:06
@hash-release hash-release Bot mentioned this pull request Sep 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/apps > hash.design Affects the `hash.design` design site (app) area/apps area/infra Relates to version control, CI, CD or IaC (area) area/libs Relates to first-party libraries/crates/packages (area) type/eng > frontend Owned by the @frontend team

Development

Successfully merging this pull request may close these issues.

2 participants