Repository navigation
fix(live-voice): give the docked widget its own state, not a store it lacks - #1274
Merged
Merged
Conversation
… lacks The docked widget window boots no app store and renders no toast surface, yet the call bar derived the work-decision hint from that store and sent one-shot failures to that toast. In the widget window both were invisible. - the owner frame computes the waiting decision and reports it together with its own failure code (voice/live/widget/ownerState replaces widget/issue) - the bar takes the flag as a prop and draws every issue in place, so nothing the user must see depends on a surface the widget window does not have - rename the widget ADR to 0315: it collided with the spoken-answer ADR 0314 and failed the ADR catalog check on main - fixture: assert the waiting hint arrives from the owner store and clears again
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
The renamed channel remains stale in ADR documentation, validation records are outdated, and the fixture contains unreachable legacy code.
Review effort: Balanced
Findings: 4
Open (4)
What changed in this PR
Moves widget-only state derivation to the main window owner and forwards it through validated IPC, while fixing the duplicate ADR identifier.
Changes:
- Reports failure codes and pending decisions through
widget/ownerState. - Makes the docked call bar fully presentational with inline errors.
- Extends widget tests and renumbers the widget ADR to 0315.
| File | Description |
|---|---|
packages/shared/src/protocol.ts |
Renames the widget owner-state IPC channel. |
docs/spec/03-runtime/01-ipc-protocol.md |
Documents the expanded IPC payload. |
docs/spec/04-ux/08-component-spec.md |
Documents owner-derived decision state. |
docs/zh-CN/spec/03-runtime/01-ipc-protocol.md |
Updates Chinese IPC documentation. |
docs/zh-CN/spec/04-ux/08-component-spec.md |
Updates Chinese component behavior. |
docs/adr/README.md |
Registers ADR 0315. |
docs/adr/0315-live-voice-docked-widget.md |
Renumbers the widget ADR. |
apps/desktop/src/features/voice/live/LiveVoiceStatusHost.tsx |
Derives and reports owner-only state. |
apps/desktop/src/features/voice/live/LiveVoiceCallBar.tsx |
Accepts decision state as a prop and renders errors inline. |
apps/desktop/src/features/voice/live/LiveVoiceWidget.tsx |
Passes reported decision state to the bar. |
apps/desktop/src/features/voice/live/live-voice-api.ts |
Exposes the renamed owner-state IPC API. |
apps/desktop/electron/main/ipc/live-voice-ipc.ts |
Validates and handles owner-state reports. |
apps/desktop/electron/main/live-voice/widget-window.ts |
Caches and publishes owner-only widget state. |
apps/desktop/test/live-work-decision.test.mjs |
Supplies derived decision state to component tests. |
apps/desktop/test/live-voice-widget.test.mjs |
Tests authorization and payload validation. |
apps/desktop/test/live-voice-controls.test.mjs |
Updates owner-state source assertions. |
apps/desktop/test/fixtures/live-voice-interaction.jsx |
Models owner-state forwarding in the fixture. |
apps/desktop/test/fixtures/live-voice-interaction-runner.cjs |
Tests showing and clearing the waiting hint. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+230
to
+234
| await check("a decision the bound session waits on reaches the widget bar", | ||
| `document.querySelector('.live-voice-call-bar')?.textContent.includes('waiting for your answer or approval') === true`); | ||
| await evaluate("window.liveVoiceFixture.clearPendingAsks()"); | ||
| await check("the waiting hint clears with the decision", | ||
| `document.querySelector('.live-voice-call-bar')?.textContent.includes('waiting for your answer or approval') === false`); |
Comment on lines
162
to
164
| widgetReports.errorCode = request.code ?? undefined; | ||
| pushWidgetState(); | ||
| return { ok: true }; |
| liveVoiceCancelQueuedOperation: "pi-desktop/voice/live/work/cancelQueuedOperation", | ||
| liveVoiceWidgetAction: "pi-desktop/voice/live/widget/action", | ||
| liveVoiceWidgetIssue: "pi-desktop/voice/live/widget/issue", | ||
| liveVoiceWidgetOwnerState: "pi-desktop/voice/live/widget/ownerState", |
Keep the owner-state boundary while preserving the latest ADR numbering and main-branch Live Voice changes. Remove the duplicate stylesheet import introduced by the conflict resolution.
jiangchuanso
added a commit
to jiangchuanso/PI-Desktop
that referenced
this pull request
Oct 1, 2026
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.

Why
The docked widget window boots no app store and renders no toast surface, but after the #1271 merge the call bar still
main is also red:
27fda481dfails Docs checks and JS build/typecheck/lint/architecture/test becausedocs/adrcarries two ADR 0314 files (live-voice-docked-widget+live-voice-spoken-asktool-answers), and the ADR catalog requires unique decision ids.What
voice/live/widget/ownerStatereplacesvoice/live/widget/issue({ callId, errorCode, decisionWaiting }). Main caches both per call and pushes them with the authoritative view.decisionWaitingarrives as a prop and every issue is drawn in place next to its verbatimLIVE_*code, so nothing the user must see depends on a surface the widget window does not have. The owner-frame playback gesture from feat(live-voice): dock the call bar as a global desktop widget #1271 is untouched.Verification (on this branch)
apps/desktoptypecheck; biome; style-token guard;check-architecture;check-agent-policy-sync.docs:check: 543 pages + 83 EN/zh pairs + ADR catalog ✓.apps/desktopsuite 3346/3346; Live Voice / Live Work sets incl. the spoken-answer and pending-interactive tests 97/97.pnpm test:e2e:live-voice5/5 journeys against the real app.