feat: blend title bar, remove menu, add agent activity indicators

- Configure hidden title bar with titleBarOverlay matching dark theme
- Remove native menu bar via Menu.setApplicationMenu(null)
- Fix backgroundColor mismatch (#0f172a -> #09090b)
- Add full-width drag region in AppShell for window dragging
- Adjust sidebar and chat headers with top padding for overlay zone
- Add ThinkingDots component with animated dot sequence
- Show activity indicator in chat when agent is processing
- Replace 'Generating...' spinner with inline blinking cursor
- Refine header status badge to subtle pulsing dot
- Add BACKEND_UI_CHANGES.md documenting future sidecar protocol additions

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
David Kaya
2026-03-21 12:43:44 +01:00
co-authored by Copilot
parent 37a460ed1d
commit b9e9662f6e
6 changed files with 182 additions and 19 deletions
+93
View File
@@ -0,0 +1,93 @@
# Backend UI Changes
This document describes changes to the .NET sidecar / backend protocol that would enable richer agent-activity reporting in the chat UI. These are **not yet implemented** — the current UI infers activity state from existing events. A separate agent should implement these changes.
## Context
The chat UI now shows a "Thinking…" indicator while the agent processes a request (before streaming starts) and a blinking cursor while the response streams in. These states are inferred from the existing `status` and `message-delta` session events.
To display more granular activity (e.g. "Using tool X…", "Agent Y is thinking…", "Handing off to Agent Z…"), the sidecar protocol needs a new event kind.
## Proposed protocol addition
### New event kind: `agent-activity`
Add a new value `'agent-activity'` to `SessionEventKind` in `src/shared/domain/event.ts`:
```typescript
export type SessionEventKind =
| 'status'
| 'message-delta'
| 'message-complete'
| 'agent-activity' // ← new
| 'error';
```
### New fields on `SessionEventRecord`
```typescript
export interface SessionEventRecord {
sessionId: string;
kind: SessionEventKind;
occurredAt: string;
// Existing fields…
status?: 'idle' | 'running' | 'error';
messageId?: string;
authorName?: string;
contentDelta?: string;
error?: string;
// New fields for 'agent-activity' events
activityType?: 'thinking' | 'tool-calling' | 'handoff' | 'completed';
agentName?: string;
toolName?: string;
}
```
### Sidecar event mapping
The .NET sidecar should emit `agent-activity` events at these points:
| MAF lifecycle point | `activityType` | `agentName` | `toolName` |
|---|---|---|---|
| Agent begins processing a turn | `thinking` | agent name | — |
| Agent invokes a tool | `tool-calling` | agent name | tool name |
| Handoff orchestration transfers control | `handoff` | target agent name | — |
| Agent finishes its contribution | `completed` | agent name | — |
### .NET sidecar changes
In the sidecar's turn-execution pipeline, emit a new JSON event type alongside the existing `turn-delta` and `turn-complete`:
```json
{
"type": "agent-activity",
"requestId": "…",
"sessionId": "…",
"activityType": "tool-calling",
"agentName": "Code Reviewer",
"toolName": "read_file"
}
```
The Electron main process (`KopayaAppService`) should map this to a `SessionEventRecord` with `kind: 'agent-activity'` and forward it to the renderer via the existing `sessions:event` channel.
### Renderer consumption (already prepared)
Once these events are available, the `ChatPane` activity indicator can be enhanced to show contextual messages like:
- "Code Reviewer is thinking…"
- "Code Reviewer is using read_file…"
- "Handing off to Summarizer…"
The `ThinkingDots` component and activity indicator section in `ChatPane.tsx` are designed to be extended with this data.
## Files to change
| Layer | File | Change |
|---|---|---|
| Shared | `src/shared/domain/event.ts` | Add `'agent-activity'` to `SessionEventKind`, add optional `activityType` / `agentName` / `toolName` fields |
| Main | `src/main/sidecar/sidecar.ts` | Parse `agent-activity` events from sidecar JSON output |
| Main | `src/main/KopayaAppService.ts` | Map parsed activity events to `SessionEventRecord` and emit via `session-event` |
| Sidecar | `sidecar/src/Kopaya.AgentHost/…` | Emit `agent-activity` JSON events during MAF turn execution |