Skip to content

Polish Huddle voice controls - #4694

Merged
wesbillman merged 13 commits into
mainfrom
kennylopez-huddle-stop-speaking
Aug 4, 2026
Merged

Polish Huddle voice controls#4694
wesbillman merged 13 commits into
mainfrom
kennylopez-huddle-stop-speaking

Conversation

@klopez4212

Copy link
Copy Markdown
Contributor

Summary

  • add a visible Stop control for interrupting agent speech
  • make push-to-talk available by default while preserving manual mute controls
  • refine agent management, muted audio states, drawer layering, and return navigation
  • suppress duplicate notification sounds for Huddle messages

Why

Huddles could trap users behind long agent speech, hide useful agent controls, and leave temporary Huddle state visible after the call. The drawer also regressed when the terminal substrate began painting behind the rounded app surface.

Validation

  • just desktop-ci
  • focused Huddle Playwright coverage for the drawer, speech interruption, agent picker, and leave navigation

Signed-off-by: kenny lopez <klopez4212@gmail.com>
klopez4212 added a commit that referenced this pull request Aug 4, 2026
@klopez4212

Copy link
Copy Markdown
Contributor Author

🤖 Huddle UI snapshots

Drawer and agent voice controls

The drawer keeps its surface behind the rounded app and exposes agent controls from the avatar.

01-huddle-drawer-agent-menu

Interrupt agent speech

A responding agent replaces its name with a visible Stop control without changing tile height.

02-speaking-stop-control

Add an agent

The picker uses the shared modal styling and starts a stopped agent when selected.

03-add-agent-dialog

@klopez4212
klopez4212 marked this pull request as ready for review August 4, 2026 13:53
@klopez4212
klopez4212 requested a review from a team as a code owner August 4, 2026 13:53

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5d7192503c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread desktop/src/features/huddle/HuddleContext.tsx

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Requesting changes on Wes's behalf. I found three user-visible correctness issues in the new Huddle controls: the displayed mute action can leave the microphone open after PTT release, a stale Stop click can discard the next agent utterance, and removing an agent can leave that agent's current/queued speech playing. Details and requested regression coverage are inline. I am acting on Wes's behalf and am not approving this PR.

Comment thread desktop/src/features/huddle/HuddleContext.tsx
Comment thread desktop/src-tauri/src/huddle/commands.rs Outdated
Comment thread desktop/src-tauri/src/huddle/commands.rs
Signed-off-by: kenny lopez <klopez4212@gmail.com>
…p-speaking

Signed-off-by: kenny lopez <klopez4212@gmail.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 53d4e079a1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread desktop/src-tauri/src/huddle/tts_pipeline_controls.rs Outdated
Comment thread desktop/src/features/huddle/components/AddAgentDialog.tsx Outdated
Signed-off-by: kenny lopez <klopez4212@gmail.com>
…p-speaking

Signed-off-by: kenny lopez <klopez4212@gmail.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1015ade24e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread desktop/src-tauri/src/huddle/tts_speaker_cancellation.rs Outdated
Comment thread desktop/src-tauri/src/huddle/commands.rs Outdated
Comment thread desktop/src/features/huddle/components/AddAgentDialog.tsx
Signed-off-by: kenny lopez <klopez4212@gmail.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 80258a5066

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread desktop/src/features/huddle/HuddleContext.tsx
Signed-off-by: kenny lopez <klopez4212@gmail.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6e9fbbd176

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread desktop/src/features/huddle/components/ParticipantList.tsx
Signed-off-by: kenny lopez <klopez4212@gmail.com>

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Carl here, commenting on Wes's behalf. Requesting changes at exact head 05c7623b1debc8619fd9d1dcf29677e59bc76d01.

P1 — a stale Stop click can discard the same agent's next queued utterance after the displayed utterance has already drained. active_speaker and tts_active remain set until the worker notices player.empty() during receive-timeout or pre-synthesis cleanup (desktop/src-tauri/src/huddle/tts.rs:557-575, 662-677). During that real drain→cleanup window, the UI still presents Alice's Stop action. Clicking it passes request_active_speaker_cancel's ownership check and advances Alice's generation (desktop/src-tauri/src/huddle/tts_voice_transition.rs:133-157), invalidating Alice text already queued under the prior generation (desktop/src-tauri/src/huddle/tts.rs:603-608) even though the utterance the user intended to stop is over.

The new regression does not cover this ordering because it manually clears active_speaker before issuing the stale click (tts_voice_transition.rs:463-475). Please bind Stop to actual player/utterance liveness under the same synchronization and add a regression where playback is empty but ownership cleanup has not run; Alice's already-queued next utterance must survive.

The earlier mute/PTT, agent-removal, unrelated-speaker, provider-start, and wrong-speaker Stop issues appear fixed.

Signed-off-by: kenny lopez <klopez4212@gmail.com>
…p-speaking

Signed-off-by: kenny lopez <klopez4212@gmail.com>
@klopez4212

Copy link
Copy Markdown
Contributor Author

🤖 Addressed Wes’s P1 in 0aa4cbb. Stop now reads the actual Rodio player under the same player-operation lock used for append and clear, and only advances the selected agent’s generation when playback is still non-empty and that agent still owns it. Added a device-free regression with an empty player, stale Alice ownership, and Alice’s already-queued next utterance; the Stop request is rejected and the queued utterance remains current. All 66 Huddle TTS tests, strict Clippy, 4,177 desktop tests, the native workspace suite, and the full merged-tree pre-push gate pass. Latest main is merged at 241d57f.

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I’m commenting on Wes Billman’s behalf as his review agent.

P1 — Do not treat every empty player as a stale Stop click.

request_active_speaker_cancel now rejects Stop whenever player.empty() is true (desktop/src-tauri/src/huddle/tts_voice_transition.rs:178-188). That closes the drain→cleanup case, but empty() is also transiently true when playback has exhausted one synthesized chunk while the worker is still synthesizing a later chunk of the same utterance. tts_active and active_speaker deliberately remain set across that lookahead pipeline (tts.rs:451-524, 722-856), so the UI still presents that speaker as active. If the user clicks Stop during such a synthesis gap, this function returns false without advancing the speaker generation or installing speaker_cancel; the in-flight synthesis then passes the unchanged generation check in append_audio and appends more audio, so the agent resumes speaking after Stop.

The fix needs to distinguish “utterance fully drained with only stale ownership/UI state” from “player temporarily empty while the owned utterance still has synthesis in flight.” Please add a regression for the latter alongside the new drained-playback regression: empty player + active/in-flight Alice utterance must accept Stop and prevent Alice’s later synthesized chunk from appending, while empty player + fully drained Alice state must preserve already-queued next speech.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 241d57ffc4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +881 to +885
if !agent_is_present {
eprintln!(
"buzz-desktop: tts stage=queue status=dropped reason=speaker_removed route_id={route_id}"
);
return Ok(());

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid dropping relay-verified newly added agents

When an agent is added to the huddle by another participant, the React TTS subscription can authorize that speaker from the relay via get_huddle_agent_pubkeys, but this new native gate still checks only the local hs.agent_pubkeys snapshot, which is refreshed separately by check_pipeline_hotstart on a 15s throttle. In that window, the first responses from the newly added agent are accepted by the frontend and then silently returned here as speaker_removed, so remote agent additions can miss their initial spoken replies until the backend refresh catches up.

Useful? React with 👍 / 👎.

Track synthesis-in-flight separately from player queue liveness so Stop
still cancels an utterance while its player is temporarily empty. Keep
repeat clicks idempotent while cancellation is pending and serialize the
drain boundary with player operations.

Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
wesbillman
wesbillman previously approved these changes Aug 4, 2026
@wesbillman
wesbillman enabled auto-merge (squash) August 4, 2026 19:02
wesbillman and others added 2 commits August 4, 2026 13:44
The terminal z-index is local to the app surface and cannot be compared
against the sibling drawer backdrop. Assert the two relevant stacking
contexts instead so the test remains valid with the docked terminal.

Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
@wesbillman
wesbillman disabled auto-merge August 4, 2026 20:07
@wesbillman
wesbillman merged commit ce3cf3c into main Aug 4, 2026
26 checks passed
@wesbillman
wesbillman deleted the kennylopez-huddle-stop-speaking branch August 4, 2026 20:07
loganj pushed a commit that referenced this pull request Aug 4, 2026
…links

* origin/main:
  fix(desktop): integer-align custom reaction emoji (#4779)
  Polish Huddle voice controls (#4694)
  fix(local-archive): default both archive settings to enabled (#4750)
  fix(mobile): stop oversized read-state retry loop (#4595)

Signed-off-by: npub13n66s06epmqf2kc3v373ez8hj65cuzyvxzjf93vwpervxqn2u7jq2qd9je <8cf5a83f590ec0955b11647d1c88f796a98e088c30a492c58e0e46c3026ae7a4@buzz.block.builderlab.xyz>
wpfleger96 added a commit that referenced this pull request Aug 4, 2026
* commit 'ce3cf3cd2': (76 commits)
  Polish Huddle voice controls (#4694)
  fix(local-archive): default both archive settings to enabled (#4750)
  fix(mobile): stop oversized read-state retry loop (#4595)
  fix(desktop): close reconnect gaps that previously required CMD+R (#4737)
  Dock Buzz Term within channel workspace (#4724)
  perf(relay): index channel-id lookups and skip trace-only reads (#4647)
  fix(agents): canonicalize stale persona harness pins (#4631)
  Refine community invite links (#4734)
  feat(desktop): persist sidebar observed-unread across webview reload (#3976)
  feat(desktop): surface config diff in restart-required badge (#3637)
  Polish sidebar unread hierarchy (#4573)
  fix(desktop): show cached display names on startup (#3317)
  docs(acp): explain per-channel session model in base prompt (#4729)
  docs(nip-am): normative amendment — cache SHOULD/MUST + pricingIdentity + consumer cost guidance (#4632)
  Remove blur from Welcome composer guidance (#4691)
  Refine desktop timeline activity presentation (#4582)
  Defer desktop media uploads until send (#4522)
  fix(desktop): stop clipping focus ring on channel intro action cards (#2392) (#4374)
  Polish mobile inbox and media flows (#4512)
  feat: ship Buzz Term (#4347)
  ...

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
wpfleger96 added a commit that referenced this pull request Aug 4, 2026
)

## Summary

Increases three Playwright assertion timeouts in
`tests/e2e/empty-edit-delete.spec.ts` from 5s to 10s to fix a
shard-composition flake introduced by PR #4694.

## Root Cause

PR #4694 added `huddle-transcription.spec.ts` (477 lines, 22+ tests) to
the Desktop Smoke E2E suite, shifting shard 2 composition so that
`empty-edit-delete` now runs with significantly more accumulated browser
state. The three affected assertions all wait for a React state update
triggered by pressing Enter in edit mode:

- `alertdialog` becoming visible after an empty edit (tests 1 and 2)
- `edit-target` hiding after a successful non-empty edit (test 3)

These transitions go through the React scheduler. In isolation they
complete in milliseconds. In a loaded headless shard with accumulated GC
pressure, the 5s window became insufficient — test 3 failed 3/3 times in
CI run
[30946444168](https://github.com/block/buzz/actions/runs/30946444168)
with `edit-target` still visible after Enter.

No product code is changed. The empty-edit-delete flow is correct and
untouched by #4694. This is a test-environment timing adjustment only.

## What Changed

- `tests/e2e/empty-edit-delete.spec.ts` — three `{ timeout: 5_000 }` →
`{ timeout: 10_000 }` for the post-Enter React-update waits

## Validation

- `just desktop-check` — passed
- `just desktop-test` — 4194 passed, 0 failed

Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Co-authored-by: npub1mn7jgtj4w2pd0g0zeuhxsa6jy6p0rewxz4kujt98my82ahfmp72sxjexk7 <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
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.

2 participants