feat(desktop): add Quick Copilot summon and Full Chat handoff #100

Merged
lost-rob0t merged 18 commits from feature/quick-copilot into master 2026-08-12 21:10:34 +00:00
lost-rob0t commented 2026-08-12 20:46:44 +00:00 (Migrated from github.com)

Closes #86

Architecture

  • Adds one process-owned native PySide6 QuickCopilotWindow alongside the existing FullChatWindow.
  • Quick and Full Chat share the exact same ConversationService, ConversationStore, DatabaseManager, QtRuntimeBridge, and RuntimeHost; no second assistant/runtime/provider/database path is created.
  • In desktop-hosted mode, DesktopController is the single reducer for runtime events and command receipts into shared conversation state. Both windows are projections over that reduced state, preventing duplicate AssistantDelta, buffered ResponseText, tool, failure, and cancellation persistence.
  • FullChatWindow retains its standalone reducer mode for existing isolated tests/embedders.

Conversation and handoff semantics

  • Quick owns an independent bound conversation ID. Reopening Quick preserves it.
  • Quick New Chat creates exactly one durable conversation and binds Quick to it.
  • Browsing Full Chat history does not retarget Quick.
  • DesktopController.expand_quick_to_full_chat() opens the exact Quick conversation through FullChatWindow.open_conversation() and hides Quick.
  • Handoff never creates/copies a conversation, duplicates messages, resubmits the prompt, restarts generation, or cancels an active turn. Partial streamed state and the canonical active turn remain in the shared service.

Interaction

  • Enter submits once; Shift+Enter inserts a newline; Escape hides Quick.
  • Every summon restores composer focus and reuses the one existing Quick window.
  • Close hides instead of exiting Zara.
  • Stop sends canonical CancelTurn(turn_id=state.active_turn_id) through QtRuntimeBridge.
  • Compact provider/model, runtime state/error, recent messages/tool placeholders, New Chat, and Open in Chat controls are included.

Tray

  • Extends the one canonical tray with Ask Zara and Open Full Chat.
  • Tray summon reuses the existing Quick instance; no second tray or QApplication is introduced.

Geometry recovery

  • Persists Quick geometry with QSettings.
  • Keeps valid remembered geometry, clamps partially visible windows, recenters fully-offscreen/disconnected-monitor windows on the cursor/primary screen, and clamps oversized geometry after resolution changes.

Tests

Adds deterministic coverage for:

  • one Quick instance, summon/hide/focus/close, Enter/Shift+Enter/Escape, no double submit
  • shared service/state and exact-ID handoff during active partial generation
  • no message/delta/tool duplication and durable persistence
  • independent Full Chat history selection
  • buffered ResponseText, failures, ProviderUnavailable
  • canonical cancellation and stale-turn recovery across restart events
  • durable Quick New Chat/reopen binding
  • interrupted persisted turn recovery
  • valid/partial/offscreen/disconnected/preferred-screen/resolution-change geometry

The repository-wide nix develop -c bash scripts/test-all.sh gate and shared-microphone matrix are required before merge.

Follow-ups remain intentionally out of scope: #87 global Wayland/X11 shortcuts and #88 explicit context attachments/permission UI.

Closes #86 ## Architecture - Adds one process-owned native PySide6 `QuickCopilotWindow` alongside the existing `FullChatWindow`. - Quick and Full Chat share the exact same `ConversationService`, `ConversationStore`, `DatabaseManager`, `QtRuntimeBridge`, and `RuntimeHost`; no second assistant/runtime/provider/database path is created. - In desktop-hosted mode, `DesktopController` is the single reducer for runtime events and command receipts into shared conversation state. Both windows are projections over that reduced state, preventing duplicate `AssistantDelta`, buffered `ResponseText`, tool, failure, and cancellation persistence. - `FullChatWindow` retains its standalone reducer mode for existing isolated tests/embedders. ## Conversation and handoff semantics - Quick owns an independent bound conversation ID. Reopening Quick preserves it. - Quick `New Chat` creates exactly one durable conversation and binds Quick to it. - Browsing Full Chat history does not retarget Quick. - `DesktopController.expand_quick_to_full_chat()` opens the exact Quick conversation through `FullChatWindow.open_conversation()` and hides Quick. - Handoff never creates/copies a conversation, duplicates messages, resubmits the prompt, restarts generation, or cancels an active turn. Partial streamed state and the canonical active turn remain in the shared service. ## Interaction - Enter submits once; Shift+Enter inserts a newline; Escape hides Quick. - Every summon restores composer focus and reuses the one existing Quick window. - Close hides instead of exiting Zara. - Stop sends canonical `CancelTurn(turn_id=state.active_turn_id)` through `QtRuntimeBridge`. - Compact provider/model, runtime state/error, recent messages/tool placeholders, New Chat, and Open in Chat controls are included. ## Tray - Extends the one canonical tray with `Ask Zara` and `Open Full Chat`. - Tray summon reuses the existing Quick instance; no second tray or QApplication is introduced. ## Geometry recovery - Persists Quick geometry with `QSettings`. - Keeps valid remembered geometry, clamps partially visible windows, recenters fully-offscreen/disconnected-monitor windows on the cursor/primary screen, and clamps oversized geometry after resolution changes. ## Tests Adds deterministic coverage for: - one Quick instance, summon/hide/focus/close, Enter/Shift+Enter/Escape, no double submit - shared service/state and exact-ID handoff during active partial generation - no message/delta/tool duplication and durable persistence - independent Full Chat history selection - buffered `ResponseText`, failures, `ProviderUnavailable` - canonical cancellation and stale-turn recovery across restart events - durable Quick New Chat/reopen binding - interrupted persisted turn recovery - valid/partial/offscreen/disconnected/preferred-screen/resolution-change geometry The repository-wide `nix develop -c bash scripts/test-all.sh` gate and shared-microphone matrix are required before merge. Follow-ups remain intentionally out of scope: #87 global Wayland/X11 shortcuts and #88 explicit context attachments/permission UI.
Sign in to join this conversation.
No description provided.