Files
agent/docs/web-ui.md
highperfocused 089bd7bd48
All checks were successful
Build and Push Docker Image / build (push) Successful in 1m15s
Add HTTP gateway with streaming chat and multi-client conversation mapping (#1)
Reviewed-on: MoA/agent#1
Co-authored-by: highperfocused <highperfocused@pm.me>
Co-committed-by: highperfocused <highperfocused@pm.me>
2026-03-12 14:47:45 +01:00

158 lines
3.6 KiB
Markdown

# Web UI: how it works
This document explains the built-in browser UI served by the gateway.
Source file:
- `src/gateway/web-ui.ts`
---
## Overview
The Web UI is a single HTML page returned by `GET /` (when enabled).
It is intentionally simple:
- plain HTML/CSS/JS (no framework)
- sends requests to `/v1/chat/stream`
- renders streamed assistant text in real time
- stores and reuses `conversationId` in `localStorage`
---
## Availability
The UI route is controlled by `GATEWAY_ENABLE_WEB_UI`:
- `true` (default): `GET /` returns UI
- `false`: `GET /` returns `404` with `{ "error": "Web UI disabled" }`
If `GATEWAY_AUTH_TOKEN` is enabled, `GET /` also requires an `Authorization` header, because auth is global in the gateway.
---
## UI sections
### 1) Session/header card
- **Conversation ID input** (`#conversationId`)
- if empty, server auto-creates one during first message
- persisted locally under `pi_gateway_conversation_id`
- **Auth token input** (`#token`)
- optional bearer token included in API requests from the page
- this affects `fetch` calls only; it does not add auth headers to the initial page load
### 2) Messages card
- container `#messages`
- each message is appended as a `.msg.user` or `.msg.assistant` block
- text is rendered as plain text (`textContent`), not Markdown/HTML
### 3) Composer card
- textarea `#message`
- status text `#status`
- buttons:
- `Send`
- `New session`
---
## Local state
The page keeps only minimal browser-side state:
- `conversationId` in input + local storage
- rendered message list in DOM
- current request state via button disabled/enabled
Storage key:
- `pi_gateway_conversation_id`
On load, if this key exists, it pre-fills the conversation input.
---
## Send flow
When user presses **Send** (or Cmd/Ctrl + Enter):
1. Trim textarea value; ignore empty input.
2. Disable `Send` and `New session` buttons.
3. Append user message bubble.
4. Append empty assistant bubble.
5. Build payload:
- required: `message`
- optional: `conversationId` (if input non-empty)
6. POST to `/v1/chat/stream` with JSON body.
7. Parse SSE stream incrementally.
8. Update assistant bubble and status based on events.
9. Re-enable buttons when request finishes/fails.
---
## SSE event handling in UI
Handled events:
- `assistant_text_delta`
- appends `data.delta` to assistant message bubble
- `done`
- reads `data.conversationId`
- updates conversation input
- writes `pi_gateway_conversation_id`
- status becomes `Done • conversation <id>`
- `error`
- status becomes error text
- writes fallback error into assistant bubble if empty
Other event types are currently ignored by the UI.
---
## New session button behavior
Clicking **New session**:
- does nothing if a request is currently streaming (`Send` disabled)
- clears conversation ID input
- removes `pi_gateway_conversation_id` from local storage
- clears rendered message list
- sets status to `New session ready`
- focuses the message textarea
This starts a fresh client-side chat thread. The next send will create a new conversation on the server.
---
## Keyboard shortcut
In the message textarea:
- `Cmd + Enter` (macOS) or `Ctrl + Enter` (Windows/Linux)
- triggers the same send flow as the Send button
---
## Limitations
Current UI is intentionally minimal:
- no server-side message history loading
- no cancel/abort button for in-flight response
- no rendering for tool events/thinking events
- no Markdown formatting
- no multi-conversation sidebar
It is best used as a lightweight test/debug interface.
---
## Related API docs
For full gateway/API details, see:
- `docs/gateway.md`