Repository navigation
feat(ui): agent header — repo, tags and a context chart back; Talk and Workspace doors out (abilityai/trinity-enterprise#950) - #3823
Merged
Conversation
…d Workspace doors out (Abilityai/trinity-enterprise#950) Amends the ent#887 header (#3798) per product review: - Repo line: the bound GitHub repo from the live git status (linked via utils/gitRemote.js — http(s)/ssh on a dotted host only, built from host + path), branch, "N changed" / "N ahead" / "N behind" or "in sync". Pull/Push stay on the Git tab. - Tags: two BaseBadge chips + a counted "+N"; owners edit in a BaseModal around the existing TagsEditor, same update/add/remove-tag handlers. - Context ring (AgentHeaderContext.vue) for a running agent, fed by stores/network.js contextStats through useAgentContextStats (15 s, visibility-gated, no stacked requests). Started/stopped in AgentDetail's start/stopAllPolling and status watcher, since the page is KeepAlive-cached. A 0 / offline reading shows "—", never a 0% ring. - Talk and Workspace doors removed from the header; the call lives in the Workspace composer. armVoiceAutoStart now has no in-app caller (docs say so). - AgentDetail clears gitStatus on agent switch and on stop, and useGitSync drops a git-status answer that lands for a previous agent or after a stop. - The meta line reserves its height (two lines below sm) so late git/tag data never moves the tab strip. Specs: header mount spec, gitRemote, useAgentContextStats, useGitSync stale answer; door specs flipped to absence; e2e Talk-door spec split into a hermetic agent-header spec (worst-case repo/tags at 375/768/1440) and workspace-voice-query (the ?voice= one-shot cases). source-text baseline lowered for portalVoiceMode (10 -> 9). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…oad (Abilityai/trinity-enterprise#950) The first CI run of the new e2e specs caught two defects: - agent-detail-request-dedupe: /api/agents/context-stats was fetched twice on one page load. AgentDetail starts its polls from onMounted, onActivated (both fire on a KeepAlive view's first mount) and the running-status watcher; useAgentContextStats.start() restarted and re-fetched for each. start() is now a no-op while the poll runs. - agent-header @ 375px: the body scrolled 33px and the repo name was crushed to zero width — the header has ~184px of content width and the worded count badges alone need ~218px. The repo row now has two inner groups so the counts wrap under the name; below `sm` the branch hides and the counts read ±N / ↑N / ↓N (words at `sm` and in the tooltip); the name keeps a 4rem minimum. The e2e case now also asserts the name stays legible and every badge stays inside the header. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s the overflow offender (Abilityai/trinity-enterprise#950) The second CI run of e2e/agent-header.spec.js measured the page 5px too wide at 375px with the header itself fitting. The offender is OverviewPanel's "Activity trends" title row — title + live running/queued counts + the 7d/14d/30d toggle on one rigid non-wrapping row (the #2197 class). It predates this PR; this spec is the first CI check that measures Agent Detail at phone width with a running agent. The row now wraps. The overflow assertion now reports the widest unclipped element, as body-horizontal-overflow.spec.js does, so the next failure names its cause. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
vybe
approved these changes
Oct 20, 2026
vybe
left a comment
Contributor
There was a problem hiding this comment.
Validated (/validate-pr, lane B): Tier 1 green incl. e2e (agent-header + workspace-voice-query specs ran), pytest head + regression diff; security greps and enterprise-docs guard clean; dev green.
vybe
pushed a commit
that referenced
this pull request
Oct 20, 2026
…ing switcher, toggles, live sparklines, 7-day spend, GitHub line, capacity bars (Abilityai/trinity-enterprise#955) (#3826) * feat(ui): edit the display name and change the avatar in place on the agent header again (Abilityai/trinity-enterprise#955) ent#887 (#3798) moved the label edit and the avatar prompt into Settings › General and ent#950 (#3823) kept the header slim. The operator asked for the quick path back: a pencil beside the name edits the display label inline (editor inside the h1 so it inherits the heading's type and ink; pre-filled with the label, never the slug; Enter/blur save, Esc cancels, empty clears), and hovering — or focusing into — the avatar shows the camera (no avatar) or change-prompt + next-emotion (avatar with an identity prompt). Owners only, never a system agent — the same predicate the General pane uses. The header emits the SAME three events the General pane's Identity rows emit (`set-label`, `open-avatar-modal`, `cycle-emotion`), and AgentDetail wires them to the handlers it already owned, so the two surfaces cannot drift. Settings › General keeps its rows; the id rename stays there only (it stops the agent and re-keys ~20 tables, #1664). No new raw palette classes: the header's gray count stays at its baseline (9), the overlay's scrim and ink are `bg-black/40` / `text-white` on a photograph, the pencil uses action-primary tokens, and the inline editor inherits the h1's colour. Keyboard reaches the overlay via `group-focus-within`. Tests: `tests/unit/agentHeaderIdentityEdit.mount.spec.js` mounts the header (pencil visibility per principal, label-not-slug prefill, Enter/blur/Esc/ unchanged/empty, overlay per avatar state and principal) and shallow-mounts the page (set-label reaches PUT /label and the heading follows; the modal opens from the header; `hasAvatarPrompt` is passed). Full frontend unit suite green (386 files, 6122 tests, ratchets included); `check:tokens` OK. Docs: requirements core-agent (§ Settings home), feature flows agent-settings-home + agent-avatars, architecture frontend.md, user-docs managing-agents. Closes Abilityai/trinity-enterprise#955 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(ui): the header's inline label editor gets a definite width and swallows its underline (Abilityai/trinity-enterprise#955) Seen in the browser on the first build: the identity block is content-sized, so the editor's `w-full` resolved against the input's intrinsic ~20ch and a long name scrolled its first letters out on select-all; the 2px underline also dropped the badge rows by 2px while editing. The block and the h1 take `flex-1` only while editing (at rest nothing moves), and the input carries `-mb-0.5`. Also drops a `font-inherit` class that is not a Tailwind utility — preflight already gives the input the heading's font. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(ui): the live strip — CPU/memory and the 7-day spend row — is back in the agent header (Abilityai/trinity-enterprise#955) ent#887 moved the header's second and third rows (live CPU/memory, and the 7-day cost sparkline with today, trend and lifetime) to the top of Overview as `AgentLiveStrip`. The operator wants them on the header, where they were. The header gains a `strip` slot at the card's bottom; AgentDetail slots the same `AgentLiveStrip` there with a new `embedded` prop (a top rule instead of card chrome — mutually exclusive class arms, #2662) and no longer renders it on Overview, so the strip stays one component with one data path and is shown once. No new raw palette classes in either file. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(ui): the agent header is the pre-#3798 header again — funding switcher, toggles, live sparklines, 7-day spend, GitHub line (Abilityai/trinity-enterprise#955) Operator ruling on the release build: the header goes almost back to the way it was before the Settings home (#3798). Four rows now: 1 identity — the ent#955 in-place label pencil and avatar overlay stay; the badges regain the funding badge with the overlaid native subscription select (owners), which emits the same `change-subscription` the General pane does; right: Brain door, context ring, Start/Stop 2 the Autonomy and Read-only toggles (`toggle-read-only` → the page's existing handler), the ent#950 tag chips (AgentHeaderMeta, tags only), and the live CPU / MEM / uptime sparklines against the configured limits (skeleton before the first sample, allocation when stopped) with a gear that opens Settings › General for memory / CPU (`open-resources`) 3 the 7-day spend row (sparkline, today, trend vs avg, lifetime · runs) 4 the GitHub line — repo, branch, last commit, changed / ahead / behind — only when the live status says a repository is connected, and WITHOUT Pull / Push / Refresh: the Git tab keeps the verbs (the one exclusion) AgentHeaderMeta gains `show-repo` / `show-tags` so the header renders its two halves in two rows, plus the last-commit sha the old git row showed. AgentLiveStrip is deleted and Overview no longer shows a strip. The identity spec pins the restored rows (funding select → change-subscription, viewer gets no switcher, read-only + gear events, live stats running vs stopped, spend row gated on a first run); the ent#950 spec pins the commit sha and the absence of Pull / Push on the GitHub row, and stubs `matchMedia` hoisted, which the sparklines' module-level theme read needs under jsdom. The raw-colour baseline is re-frozen in the next commit, on its own. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * chore(ui): re-freeze the raw-colour baseline for the restored agent header (Abilityai/trinity-enterprise#955) Deliberate growth, named: AgentHeader.vue raw_gray 9 → 53 (the pre-#3798 rows came back with their chrome ink: toggles divider, live-stats meta, spend row, gear); AgentHeaderMeta.vue gets its first entry at raw_gray 19 (it was created after the last freeze; adding the last-commit sha made it worth pinning). No raw non-gray anywhere in either file; no hex. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * test(ui): stub the sparkline in the header identity spec — jsdom has no canvas 2D context, and its async clearRect failed the run as an unhandled error (Abilityai/trinity-enterprise#955) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(ui): the agent header keeps one footprint while its data lands (Abilityai/trinity-enterprise#955) Measured on an in-app agent switch: the tab strip moved twice while the header filled in. Now every late-arriving piece has a reserved home: - the slug / description line is always one line tall; - the funding badge shows a same-size skeleton until the auth status lands; - the 7-day spend row is always rendered — skeleton in flight, "No spend yet" after a first fetch that found no runs — at a fixed min-height; - the GitHub row is reserved up front for a `github:` template (skeleton while running and the status is in flight, a sentence while stopped) and otherwise appears only when the live status names a remote; - row 2's tag block and live-stats cluster have fixed widths from `sm` up, so whether the row wraps no longer depends on which data has arrived (the skeleton, the stopped allocation and the running cluster were three different widths — a 32px jump a beat after paint). Pinned by the identity spec (reserved spend row, reserved GitHub row per template, funding skeleton). Raw-colour baseline: header raw_gray 53 → 63 for the three skeleton fills, named here rather than re-frozen apart since it is the same change. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(ui): no spinner above a still-rendered agent on an in-app switch (Abilityai/trinity-enterprise#955) Agent Detail is KeepAlive-cached: on a switch the previous agent stays on screen for the ~100ms the new one takes to land, and the page's loading spinner stacked ABOVE it, pushing the header and the tab strip down 112px and back. The spinner now renders only when there is no agent on screen at all; a switch is stale-while-loading, like a refresh. Measured: header top, header height and tab-strip top are constant across a round-trip switch. Loading-gate baseline regenerated (the gate was narrowed, not added). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(ui): one-line settings row, and an activity + capacity indicator on the agent header (Abilityai/trinity-enterprise#955) Two operator notes on the restored header. (1) Row 2 broke into two lines: the live cluster's fixed width was a hair under its running content, so uptime and the gear dropped under CPU / MEM, and the tags block's fixed width pushed the cluster itself to a second line. The cluster is now `flex-nowrap` at a min-width that fits its widest state, and the tags block is `flex-1` with truncating chips — one line wherever toggles + cluster fit, and the wrap point no longer moves when data lands. (2) "Is something showing when the agent is actively working?" — now yes, the dashboard's capacity meter with a word: a `Working` badge on a pulsing green dot plus the slot bars and `active/max`, or a quiet `Idle`, beside the context ring for running agents. "Working" is the WS `workingState` first (instant), else the polled activity state; the slot count never reads below it, so the bars and the word cannot disagree. `useAgentContextStats` now also refreshes `fetchSlotStats` on its 15 s tick, so the header and the fleet tile read one map. Pinned by the identity spec (Idle / Working / WS-before-poll / hidden when stopped). Raw-colour baseline: header raw_gray 63 → 65 (the `active/max` meta text), named here. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(ui): drop the uptime label and the gear from the header's live cluster (Abilityai/trinity-enterprise#955) Operator: the CPU / MEM line carries the sparklines and their limits only. The `open-resources` emit goes with the gear (memory / CPU are in Settings › General, one click away on the tab strip). Raw-colour baseline: header raw_gray 65 → 59, named here. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(ui): the header's right cluster is Brain, capacity bars, Start/Stop — no Idle/Working word, no slot count, no context ring (Abilityai/trinity-enterprise#955) Operator: just the capacity indicator. The dashboard's CapacityMeter stands alone (its own tooltip names the slots); the Working / Idle badge, the `active/max` text and the ent#950 context ring are gone, and `AgentHeaderContext.vue` is deleted with its unit and e2e assertions. The page no longer passes `contextStats` / `working` to the header; the composable keeps the slot map fresh on its tick. Raw-colour baseline: header raw_gray 59 → 57, named here. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * test(ui): the context-stats composable spec's fake store gains the slot fetch the tick now makes (Abilityai/trinity-enterprise#955) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(ui): a short run lights the header's capacity bars at once (Abilityai/trinity-enterprise#955) The bars read the slot map, refreshed every 15 s; a task or message that finishes between two polls never reached them. The WS activity event lands the moment an execution starts (`stores/network.js::workingState`), so the composable now exposes it, the header fills one bar on it immediately (the bars never read below the WS signal), and the slot map is re-read on that event so the real count follows without waiting for the tick. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(ui): the agent page sees executions start — activity events reach the working map over the app-wide socket (Abilityai/trinity-enterprise#955) Root cause of "a 10-second task never lights the capacity bars": the fleet store's WS-driven `workingState` updated only through the store's OWN socket, which the Dashboard opens on mount and closes on unmount — on the agent page nothing fed it, so the header's instant signal was dead and the bars waited for the 15 s slot poll, which a short run slips between. The app-wide `/ws` (App.vue, `utils/websocket.js`) carries the same `agent_activity` events; its handler now feeds the store's `handleActivityStatusChange` for operator roles. The dashboard "working" chip benefits the same way when the Dashboard is not the page that opened the socket. Pinned in websocketWorkspaceOnly.spec.js through the real connect path: an operator's start/terminal events light and clear the state; a Workspace-only member's do not touch it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(ui): the capacity bars clear as soon as the run ends (Abilityai/trinity-enterprise#955) Measured on a 5 s turn: the start event lit the bar at once and re-read the slot map, but the end event only cleared the WS flag — the map still said one slot taken until the next 15 s tick, so the bar stayed lit for up to 15 s after the run. The map is now re-read on both edges; measured again: lit within a second of the start, cleared half a second after the end. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(ui): the header's loading skeletons never widen a 375px page, and each AgentHeaderMeta half carries its own test id (Abilityai/trinity-enterprise#955) The PR-side e2e run caught two things the mounted specs cannot see: - At 375px the live cluster's "Loading live usage…" skeleton (`w-64`) pushed the page 25px wide. The cluster is now `min-w-0 max-w-full` and all three skeletons (live usage, spend, repository) are `max-w-full`, so a fixed-width placeholder is bounded by its row. - `AgentHeaderMeta` is rendered twice (tags half in row 2, repo half in row 4) and both carried `data-testid="agent-header-meta"`: Playwright's strict mode refused the locator, and the 768px fit check measured the badges against the TAGS card's right edge. The repo half keeps `agent-header-meta`; the tags half is `agent-header-meta-tags`. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: trinity-ability <309458136+trinity-ability@users.noreply.github.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
N changed/N ahead/N behindorin sync), the tags (two chips, a counted+N, owners edit in a dialog reusingTagsEditor), and a small context-window ring for a running agent.Changes
components/AgentHeader.vue— doors out; context ring in the right cluster; new meta line under the badges. New props default safely (gitStatus, counts, tags, allTags, contextStats).components/AgentHeaderMeta.vue(new) — repo + tags line with a reserved height (two lines belowsm) so late git/tag data never moves the tab strip.components/AgentHeaderContext.vue(new) — ring + percent;—until a real reading (the backend's0/offlineprobe is treated as no reading, never a 0% ring).composables/useAgentContextStats.js(new) — keepsstores/network.js::contextStatsfresh for this agent: 15 s, visibility-gated, no stacked requests. Does not use the Dashboard-ownedstartContextPolling.views/AgentDetail.vue— passes the props and tag events; starts/stops the context poll insidestartAllPolling/stopAllPollingand the status watcher (the page is KeepAlive-cached, soonUnmountednever fires on navigation); clearsgitStatuson agent switch and on stop.composables/useGitSync.js— drops a git-status answer that lands for a previous agent or after the agent stopped (the header now shows git state on every tab).utils/gitRemote.js(new) —remote_urltoowner/repo+ href; http(s)/ssh on a dotted host only, rebuilt from host + path, so no credentials, query,javascript:orfile:origin can become a link.architecture/frontend.md,feature-flows/agent-settings-home.md(new header section), requirements (core-agent, public-access, runtimes), voice flow docs and 11 user-doc pages no longer describe a Talk/Workspace header door.Test Plan
cd src/frontend && npx vitest run), including the raw-colour, loading-gate and source-text ratchets.npm run check:tokenspasses.agentHeader950.mount.spec.js(jsdom mount: repo shown/hidden/unlinked, separate counts, tag chips ++N, owner dialog emitsremove-tag, viewer read-only, context hidden when stopped,—for null and offline-0, level colour),gitRemote.spec.js,useAgentContextStats.spec.js(fake timers: stop really stops, no stacking, hidden tab skips),useGitSyncStaleStatus.spec.js.agentDetailTalkDoor.spec.js,portalVoiceMode.spec.js(source-text baseline 10 → 9).e2e/agent-header.spec.js(hermetic@smoke: content, tag dialog Esc, no body overflow at 375/768/1440 with a worst-case repo/branch/10 tags) ande2e/workspace-voice-query.spec.js(the?voice=cases moved out of the deletedagent-detail-talk-door.spec.js) were only listed withplaywright --list. They need a real run infrontend-e2e.Notes for review
armVoiceAutoStart()now has no in-app caller, so?voice=1is always inert. The Workspace strip-and-disarm stays; removing the one-shot machinery is a separate cleanup.GET /api/agents/context-stats, which for a non-admin fans out across their running agents (as the Dashboard already does).remote_urlinto an href, covered by the parser tests.Fixes abilityai/trinity-enterprise#950 (cross-repo: close the private issue manually at release)
🤖 Generated with Claude Code