Menu
popagent
publicLatest change 6726bbcb1e8a68b297a0e59825c4d913d4b9aab8 - Run autonomous improvements continuously by Ólafur Búi Ólafsson
# 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 Light, Dark, Dracula, Nord, Tokyo Night, Catppuccin, Gruvbox, and Solarized Light palettes; 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`, `AgentSettingsPage.tsx`, and `AutonomySettingsPanel.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 centrally mask arguments and results for retired plaintext secret tools as `[redacted]`. - 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, credential edit/delete dialogs, 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 command center is the operational root. Its hierarchy is: explicit queued/running/attention/completed totals, live work, then repository workspaces. `Start task` opens a focus-trapped modal for repository and outcome selection instead of leaving a large composer in the dashboard. The live agile board groups queued, in-progress/cancelling, attention-required (failed, cancelled, or dead-letter), and done work without inventing review or artifact-readiness state. Cards show workspace, latest agent activity, bounded step progress, attempts, retries, recovery, errors, source lineage, timestamps, and collapsible request/output evidence. Terminal cards expose removal through a focus-trapped destructive confirmation that explains task history/evidence is deleted without undoing repository changes. Active tasks remain cancellable but cannot be removed. Each lane bounds its card stack and scrolls independently so completed history cannot push repository navigation out of reach. Root task state refreshes every two seconds; mobile uses horizontal snap lanes instead of compressing four columns. Repository cards follow the board and show chat counts, active work, and recent activity. Each repository workspace landing page can permanently delete all of its active and archived chats through a focus-trapped confirmation modal; transcripts and Mastra threads are removed while independent long-term memories remain. The documentation workspace provides a PostgreSQL-backed project-folder tree, Markdown editor, GFM preview, semantic search with local-model reranking, 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** provides a structured AgentBrowser overview plus persisted runtime; security and API boundaries are canonical in [AGENTS_BROWSER.md](AGENTS_BROWSER.md). It includes viewport, isolation, session/idle limits, screencast, recording, capability, host-policy, active-session, and encrypted Playwright storage-profile controls. It lists and closes live sessions and downloads/deletes retained recordings. Headless operation and read-only tool exclusions remain fixed server safety boundaries. - **Secrets** manages write-only credentials through the authenticated metadata-only API. Operators can create, rotate, bind, and delete a credential; values are never rendered or returned. Each usable credential requires one exact HTTPS origin. Create/edit and destructive confirmation use focus-trapped, theme-matched dialogs with explicit loading, empty, error, and busy states. - **Memory** explains Mastra's recent-message → observation → reflection model with an accessible, settings-aware connection graph and exposes persisted operating presets, token thresholds, retention, asynchronous buffering and safety controls, idle/provider-change activation, shared budgets, exact-history recall scope, temporal markers, attachment policy, Observer context optimization, and custom Observer/Reflector guidance. It links to the current Mastra Observational Memory documentation and previews the effective token intervals calculated from the persisted values. - **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. - Terminal task review can mark failed, cancelled, or dead-lettered work completed with inline evidence through the one-shot CLI/API; active and already-completed tasks cannot be relabeled. - Browser, Secrets, Memory, Runtime, and Autonomy controls render only after their API values load; the client has no substitute settings defaults. - **Autonomy** configures persisted learning and continuous repository improvement: selected workspaces, cycle cadence, local Titan model execution, and optional server-owned publication/deployment. `GET /api/autonomy/status` exposes paused, active, and improving state; `POST /api/autonomy/run` requests one immediate enabled-workspace cycle and rejects concurrent work. The overview displays current autonomous state, and schedule rows expose latest task status and heartbeat. - Protected signal and revision APIs retain bounded history, retries, and focus-trapped reversion. Reversion never changes user-managed base instructions, capability membership, workspace/browser access, secrets, hooks, authentication, or execution bounds. - **Observability** follows [AGENTS_OBSERVABILITY.md](AGENTS_OBSERVABILITY.md) and shows last-24-hour run/error/token/latency KPIs, current Popagent process RSS and heap usage, 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. - **Schedules** selects a repository workspace before creating recurring work. The 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. Self-update schedules are managed in Autonomy and cannot be paused or deleted from Schedules; user-created schedules retain those controls. Schedule rows show explicit source lineage, a human-readable recurrence, and the local next-run timestamp. Live one-off tasks are intentionally absent from Settings and belong to the master overview. - When a Mastra browser becomes active for the current chat, an authenticated SSE screencast workspace slides in from the right. Desktop keeps transcript and browser side by side; mobile uses a focus-trapped full-screen dialog. The panel shows URL, tabs, access and stream state, remains view-only by default, and requires explicit interactive-session takeover before bounded pointer or keyboard events are accepted. Hiding the panel disables takeover. ## 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. - UI verification follows the TDD, browser-lifecycle, console, network, and reporting gates in [AGENTS_RULES.md](AGENTS_RULES.md).