AkurAI Build
Menu

popagent

public

Latest change ac1b32888da9db0a129d0e91ff5cb4dac22c12f0 - Add workspace documentation RAG by AkurAI Build

# Chat UI

Library: **assistant-ui** (`@assistant-ui/react` primitives). Docs: https://www.assistant-ui.com/

## Architecture

- `useChatRuntime` + `AssistantChatTransport` (`@assistant-ui/react-ai-sdk`)
  targets `/api/chat`; the selected model, persistent session ID, and repository
  workspace ID ride in the request. Backend history reconstruction and
  newest-message policy are defined in [AGENTS_AGENT.md](AGENTS_AGENT.md).
- Composed from primitives (`ThreadPrimitive`, `MessagePrimitive`,
  `ComposerPrimitive`) with our own markup — not the styled `Thread` bundle.
- Markdown: `MarkdownTextPrimitive` (`@assistant-ui/react-markdown`) +
  `remark-gfm`, styled under `.md-content` in `globals.css`.
- Tool calls use `MessagePrimitive.Parts` `tools.Fallback`. The global display
  preference selects compact chips, expanded argument/result details, or
  timeline-accented cards; each card exposes its current execution status.
- Styling: **Tailwind v4** at serve time (`bun-plugin-tailwind`, `bunfig.toml`
  `[serve.static]`). Semantic theme tokens in `globals.css` support explicit light
  and dark modes; the Appearance setting persists the selection in browser local
  storage and initially follows the operating system. Icons come from `lucide-react`.
- Shared server/UI wire shapes come from `src/api-types.ts`. Large independent
  surfaces are split into `ModelPicker.tsx`, `MemoryDrawer.tsx`,
  `WorkspaceOverview.tsx`, `DocumentationPage.tsx`, and `AgentSettingsPage.tsx`;
  `Chat.tsx` owns repository-workspace and session orchestration.
- Native browser-history routing keeps major locations reloadable and shareable:
  `/` is the overview, `/workspaces/:workspaceId` is a repository workspace,
  `/workspaces/:workspaceId/docs/*` is its Markdown documentation workspace,
  `/chats/:sessionId` is a conversation, and `/settings/:section` is a settings
  section. Bun serves the application shell for browser routes while unmatched
  `/api/*` requests remain JSON 404 responses.
- `src/ui/api.ts` provides `apiFetch`, attaching the optional localStorage API key and dispatching `popagent:unauthorized` on 401; all UI API calls use it.
- Session saves include the current `revision`; a 409 conflict is retried once with the server session revision while retaining local messages.
- Tool cards mask `recall-secret` results as `[redacted]` at render time.
- Failure surfacing: transient errors show in the module-level toast host
  (`src/ui/toast.ts` + `<Toasts/>` in the Chat root); a failed initial session
  load renders a retry card instead of a blank screen; a 401 renders an access
  key gate that stores the key in `localStorage["popagent:api-key"]`.
- Message actions use `ActionBarPrimitive`: copy on all messages, regenerate on
  assistant messages, and trace-linked thumbs up/down plus trace-ID copy when a
  traced assistant response is available. Actions appear on hover/focus and hide
  while running. Feedback is recorded once per rendered response through the
  protected observability API.
- Accessibility: an `aria-live=polite` region announces run start/completion;
  `useFocusTrap` (`src/ui/use-focus-trap.ts`) traps Tab and restores prior
  focus in MemoryDrawer, AgentSettingsPage, WorkspaceDialog, DeleteDialog, and
  the ModelPicker popover.
- The context meter renders nothing when the catalog has no context window for
  the selected model, rather than showing a zero denominator.

## Workspace layout

Sidebar: branding, a master overview link, repository workspace switcher, one
primary `Create new chat` control, title search, active/archived views, and the
selected workspace's sessions ordered by activity. Each session can be renamed,
archived/restored, or permanently deleted. Permanent deletion confirms that
transcript and Mastra thread data are removed while independent long-term
memories remain.
Main header: a searchable, provider-grouped model picker fed by
`GET /api/models`, long-term-memory control, and tool-display settings. Tool
display mode (`compact`, `expanded`, or `timeline`) is global and persisted in
browser local storage.
Main: the default master overview shows repository cards with chat counts, active
task counts, and recent activity. The documentation workspace provides a Markdown
page tree, editor, GFM preview, semantic search, and index status; its durable
contracts live in [AGENTS_DOCUMENTATION.md](AGENTS_DOCUMENTATION.md). A chat view contains its thread viewport,
empty-state suggestions, composer with send/stop toggle, thinking indicator,
collapsible hook activity, and context-window meter. Specialist
`data-agentActivity` parts render inline as live iteration cards beside the
supervisor's final response. The meter uses provider `inputTokens` from
`message.metadata.custom.usage`; its denominator comes from live 9Router
context-window metadata.
Desktop keeps session navigation visible. Mobile uses an isolated modal session
drawer, a single-row workspace header, 44px touch targets, safe-area-aware
composer spacing, and a horizontal settings-section bar above full-width
settings content.

Settings is a routed full-screen modal workspace reached from session
navigation or a direct `/settings/:section` URL. It uses dialog semantics,
focuses its close control on open, closes on Escape to the originating route,
and restores focus to the opener:

- **Agents** presents a compact selectable handoff sequence—Orchestrator →
  Researcher → Implementer → Reviewer—then edits each agent's PostgreSQL-backed
  display identity, delegation description, complete role instructions,
  workspace/browser access, delegation eligibility, and tool membership. Instructions are capped at 32,000
  characters and link to their agency-agents source provenance. It also manages
  database-backed Agent Skills including instructions, references, source
  provenance, enablement, user invocation, creation, and deletion. Empty
  identity or instruction fields are rejected.
- **Browser** toggles global persisted browser-tool enablement. Headless
  operation and read-only tool exclusions are fixed server safety boundaries.
- **Memory** exposes persisted compaction controls: automatic compaction,
  observation/reflection thresholds, recent raw-history retention, and idle
  buffering.
- **Runtime** edits the database-backed default model, supervisor/specialist
  execution limits, delegation bounds and feedback, and background-task
  concurrency/timing. Changes apply to new turns and tasks; active tasks retain
  the timeout captured when they started.
- Browser, Memory, and Runtime controls render only after their API values load;
  the client has no substitute settings defaults.
- **Observability** shows last-24-hour run/error/token/latency KPIs, recent
  traces with expandable span timelines, and correlated warnings/errors. Reads
  use the server's bounded observability APIs and expose explicit loading, empty,
  and failure states.
- **Tasks** selects a repository workspace before creating background prompts or
  recurring schedules. The schedule editor offers every day, weekdays, or every
  week; weekly schedules add a day selector, and every option uses a native time
  input. It does not expose a timezone because schedules use the server
  computer's configured timezone. Schedule rows show a human-readable recurrence
  and local next-run timestamp. The section also shows running
  specialist/supervisor iteration progress, restart-recovery counts, final
  output/errors, and queued, cancelling, or cancelled state for active work.

## Decisions

- No shadcn/ui — Tailwind + primitives cover current needs.
- No AI Elements — overlaps with assistant-ui; one chat layer, not two.
- Gotcha: `useThread` is not exported by this `@assistant-ui/react` version —
  use `ThreadPrimitive.If running` for run state and `useAuiState` for message
  metadata/state selectors.
- Visual direction: Mastra Docs density and hierarchy interpreted as a
  macOS-forward liquid-glass workspace. Use near-black/soft-white neutral
  fields, restrained green status/accent color, translucent navigation and
  controls with real backdrop context, fine inner highlights, and compact
  workhorse typography. Glass is reserved for navigation, controls, overlays,
  the composer, and user messages; reading content remains visually quiet.
- Session creation is single-flight (`src/ui/single-flight.ts`): rapid clicks
  share one pending `POST /api/sessions`, then creation becomes available again.
  Keep the primary creation and session-selection accessible names distinct;
  duplicate `New chat` names make automation and assistive navigation ambiguous.
- Initial loading honors the current browser route; `/` opens the master
  workspace overview and never creates a chat implicitly. A chat is created only
  after the user selects a repository workspace and activates `New chat`. With
  no active model selection, creation omits the model so the server uses the
  current persisted default.
- Active and archived lists are disjoint API views. Every session response
  includes `archivedAt` (`null` while active); verify both views after lifecycle
  or cleanup changes rather than inferring state from the visible list alone.
- Initial session and workspace loading is independent of the live model catalog.
  If 9Router catalog discovery fails, existing sessions and the master overview
  still open; the model picker remains empty until a reload.

## Contract checks

- UI helper contracts live beside their helpers.
- Visual changes require exercising the affected desktop and mobile paths in a
  real browser.