Hermes 284313f908
Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

172 lines
9.5 KiB
Markdown

# Spotlight Quick Ask Overlay (AI Chat)
## Summary
Add a **Spotlight-style “Quick Ask” overlay** that opens centered over the app and lets users ask a question fast. When an answer begins returning, the UI **expands into a chat-style dialog** with the response streaming in. The user can then optionally **move the in-progress chat into the existing chat sidebar** (right sidebar), continuing with the normal chat UI.
Quick Ask and the sidebar chat are **the same underlying chat session** (same persistence, same chat id, same messages). The difference is primarily UX: Quick Ask is optimized for “one quick question”, while the sidebar is optimized for extended interaction.
## Problem Statement
Today, AI chat lives in the right sidebar and requires a more deliberate UI mode switch. Users often want to ask a fast question without opening/committing to the sidebar. We need a lightweight, global entry point that feels like macOS Spotlight: a focused input that can quickly expand to show results.
## Goals
- A global keyboard shortcut opens a centered overlay:
- macOS: `⌘` + `↑` (hardcoded initially)
- Windows/Linux: `Ctrl` + `↑` (hardcoded initially)
- Quick Ask starts as a minimal input UI; upon sending a prompt and receiving the first response bytes/chunks, it transitions to an expanded dialog showing:
- user prompt
- assistant response streaming in (token/chunk streaming supported)
- follow-up prompts supported (multi-turn)
- Quick Ask shares as much logic as possible with the existing sidebar chat:
- message persistence (create chat + save messages)
- request/response handling (including “function proposed” / approval flows if enabled)
- stop/cancel
- error handling
- In “expanded dialog” state, provide an action to **move/open the chat in the right sidebar**:
- The right sidebar should open and display the same session seamlessly.
- Quick Ask should close (or optionally remain open in minimized state; see Open Questions).
- Messages asked via Quick Ask must persist exactly as messages asked via the sidebar chat do today.
## Non-Goals
- A configurable shortcut UI (future enhancement; we will hardcode initially).
- A full “command palette” that searches app entities (assets/tickets/etc).
- A chat history list UI (the current sidebar chat does not expose prior chats).
- New analytics/telemetry, observability, or rollout flags beyond existing AI gating (unless requested).
## Users / Personas
- **Technician**: wants a fast answer while working in tickets/projects without changing context.
- **Dispatcher/Coordinator**: uses quick prompts for “how do I…” and procedural guidance.
- **Admin**: may use AI to understand settings/integrations quickly.
## Primary User Flows
### Flow A: Quick One-Off Answer
1. User presses `⌘↑` / `Ctrl↑`.
2. Overlay opens centered and focuses the input.
3. User types question and hits `Enter`.
4. Overlay expands; assistant response streams in.
5. User hits `Esc` to close overlay.
### Flow B: Follow-Ups in Overlay
1. User opens overlay and asks question.
2. While response is shown, user asks a follow-up in the same overlay.
3. Chat continues as a single persisted chat session.
### Flow C: Move to Sidebar
1. User opens overlay, asks question, sees response.
2. User clicks “Open in sidebar”.
3. Right sidebar opens showing the same session.
4. User continues in the normal sidebar chat UI.
## UX / UI Notes
### Overlay look & feel (“Spotlight style”)
- Centered on screen horizontally + vertically.
- Rounded container, subtle border/shadow; darkened translucent backdrop.
- Collapsed state:
- single prominent input (optionally with “Ask Alga…” placeholder)
- small hint row (e.g., `Esc` to close, `Enter` to ask)
- Expanded dialog state:
- input remains available at bottom for follow-ups
- transcript area above (user + assistant)
- streaming indicator while generating
- “Open in sidebar” control (only in expanded state)
- Accessibility:
- focus trap while open
- `Esc` closes
- reasonable ARIA labeling via existing `Dialog` component patterns
### Transition (“seamless switch”)
- Use a single Dialog container; animate height/width between collapsed and expanded states.
- Expansion should trigger when:
- user submits a prompt, and
- the response begins (first SSE chunk / first tokens received), OR
- immediately after submit if non-streaming response is used.
### Keyboard behaviors
- Global shortcut toggles open/close when appropriate.
- Inside overlay:
- `Enter` submits prompt (single-line mode).
- `Shift+Enter` inserts a newline (multiline input supported).
- `Esc` closes overlay.
- Shortcut should still work even when focus is inside a text input/textarea/contentEditable in the main app.
- If the right sidebar chat is already open, the shortcut should focus the sidebar chat (instead of opening Quick Ask).
## Technical Design Notes
### Current-State Notes (as observed in repo)
- Right sidebar is toggled in `server/src/components/layout/DefaultLayout.tsx` via `⌘/Ctrl + L`.
- EE sidebar chat uses `ee/server/src/components/layout/RightSidebarContent.tsx`, which renders `ee/server/src/components/chat/Chat.tsx`.
- Chat persistence is handled via server actions in `ee/server/src/lib/chat-actions/chatActions.tsx` (`createNewChatAction`, `addMessageToChatAction`, `updateMessageAction`).
- Chat requests are currently sent to `POST /api/chat/v1/completions` (delegates to `ee/server/src/services/chatCompletionsService.ts`).
- Streaming endpoints exist at `POST /api/chat/stream/*` (delegates to `ee/server/src/services/chatStreamService.ts`), and there is a client-side SSE parser in `ee/server/src/services/streaming.ts`.
### Proposed Architecture
#### 1) Extract shared chat “session” logic
Create a headless hook/service (EE-only) that encapsulates:
- conversation state (model messages + UI messages)
- `chatId` lifecycle (create on first send)
- persistence for user + assistant messages
- request execution (completions today; optional SSE streaming)
- abort/stop
- function proposal/approval flow state (if applicable)
This logic becomes the single source of truth for both:
- sidebar chat UI
- Quick Ask overlay UI
#### 2) Add an EE “Quick Ask Overlay” component
Implement `QuickAskOverlay` as an EE component that:
- is controlled from `DefaultLayout` (open state + close handler)
- uses the shared chat session hook for sending and rendering
- supports “collapsed” and “expanded” UI states
- exposes an “Open in sidebar” action to hand off the active session
In CE builds (or when AI is disabled), the overlay should either:
- do nothing on shortcut, or
- show a small “EE required / AI unavailable” message consistent with existing patterns (decision).
#### 3) Enable handoff (“Open in sidebar”)
Introduce a minimal shared state channel between overlay and sidebar:
- Option A (preferred): a `ChatSessionProvider` at layout/root that stores the active session and exposes:
- `activeSessionId` / `activeSession`
- `setActiveSession(...)`
- `openInSidebar(sessionId)` helper
- Sidebar chat reads from this provider; if a session is active, it renders that session (instead of creating a new one).
- The overlay calls `openInSidebar()` and closes itself.
This avoids brittle prop drilling and ensures both UIs show the same in-memory stream while also persisting to the DB.
### Streaming vs non-streaming
- The Quick Ask overlay UI must support streamed updates.
- Implementation can start by:
- using the existing `POST /api/chat/stream/...` SSE endpoint and progressively appending chunks, OR
- extending the completions service to provide an SSE mode.
- Even if the backend currently emits a single SSE chunk, the UI should be built to handle true token streaming later without rewrites.
### Persistence requirements
- On first user message in a session:
- create chat row (title defaults to first user message)
- persist user message
- On assistant completion:
- persist assistant message
- When using streaming:
- persist assistant message once final (or update incrementally if/when supported by server actions; optional).
### Gating / Feature Availability
- The existing `AI-stuff` feature flag check in `ee/server/src/components/layout/RightSidebarContent.tsx` should be reused for Quick Ask.
- If AI is disabled, opening Quick Ask should present a clear disabled state and not call the API.
## Risks / Edge Cases
- Global shortcut conflicts with OS/browser navigation or app keybindings.
- Focus stealing: opening Quick Ask while typing in a form could be disruptive.
- Session handoff consistency: ensuring the sidebar renders the exact in-memory state (esp. during streaming) without duplicating sends.
- SSE parsing and abort behavior across browsers.
## Open Questions
1. Where should “chat history” live for revisiting past sessions (if not already present in the product)?
## Acceptance Criteria / Definition of Done
- Pressing `⌘↑` on macOS or `Ctrl↑` on Windows opens a centered Spotlight-like overlay with focused input.
- If the right sidebar chat is already open, pressing `⌘↑` / `Ctrl↑` focuses the sidebar chat instead of opening Quick Ask.
- Submitting a question causes the overlay to expand and display the assistant response streaming in.
- Messages asked in Quick Ask persist using the same storage path as the sidebar chat.
- Clicking “Open in sidebar” opens the right sidebar and shows the same session, allowing continued conversation.
- The right sidebar continues to work as before for starting a new chat; the new shared logic does not regress existing chat behavior.