Skip to content

feat(agents-builder): simulated agent runs, status tags, and project-scoped roster - #56

Merged
yyyyaaa merged 2 commits into
mainfrom
feat/agentic-ui-states
Oct 22, 2026
Merged

yyyyaaa merged 2 commits into
mainfrom
feat/agentic-ui-states

Conversation

@yyyyaaa

@yyyyaaa yyyyaaa commented Oct 22, 2026

Copy link
Copy Markdown
Contributor

Makes every agent in the Agents Builder template a realistically simulated thread, gives the roster a status language for what each agent needs, and lets the roster be scoped by project.

Agents Builder

  • Every roster agent opens its own run. agentDetails pairs each agent with a blueprint and a run script; the featured agent/run still work, and agents without a detail still go to the host through open-agent.
  • Runs cover every state: live replay, approval, a question (RunQuestion), a failure at a tool call with a log and retry (RunFailure), queued with "Run now", and a finished run that opens without replaying.
  • Runs keep going off screen. Opened agent views stay mounted, so a run continues while you look elsewhere and finishing marks the row unread.
  • Status tags. Rows end in a tag (Approve, Answer, Failed, Queued); open runs shimmer their border, and the collapsed rail shows the word under the initials. Tags are aria-hidden; each row's accessible name carries the state.
  • Projects. Optional projects group the expanded roster. A folded project shows its most pressing tag, agents that need you are promoted past the per-project limit, and the breadcrumb names the project. Without projects the roster stays flat.
  • Run panel. Approval, question, failure, and queued stop on one card shape: a status line, a title, the body, and actions on the right.
  • New actions: answer-run, retry-run, start-run. NavRow gains tip and railBadge.
stateDiagram-v2
  queued --> running: Run now / schedule
  running --> approval
  running --> input
  running --> failed
  approval --> running: approve or skip
  input --> running: answer or skip
  failed --> running: Retry run
  running --> idle: done (unread if off screen)
Loading
<AgentsBuilder
  data={{
    ...data,
    projects: [{ id: 'revenue', name: 'Revenue' }],
    agents: [{ id: 'revenue-analyst', projectId: 'revenue', name: 'Revenue Analyst', status: 'approval', statusNote: 'Post the summary to #revenue?' }],
    agentDetails: [{ agent: revenueAnalyst, run: revenueRun }],
  }}
  onAction={(action) => {
    // approve-run, answer-run, retry-run, start-run, open-agent, …
  }}
/>

AI kit

  • AskCard shows one question at a time with a pager, radio rows, and Skip/Continue on the right; new eyebrow and icon props. Hosts with several questions now page through them.
  • ApprovalCard takes an eyebrow; its skip button is secondary.
  • ToolTrace hangs its calls from one continuous rail and gains an error status.

Before / after

Before After
Sidebar Flat agent list with no states Projects with agent status tags
Collapsed rail Initials only Initials with status words
Approval Approval card with a separate waiting line Approval card with a status line
AskCard All questions with lettered rows One question with radio rows and a pager

New run states:

Failed Question Queued
Failure card with output and retry Question card in the run Queued card with the upcoming plan

🤖 Generated with Claude Code

https://claude.ai/code/session_01W81pjQJK31ut5W1L7wQavN

…l trace

- AskCard shows one question at a time with a footer pager, radio rows,
  and Skip/Continue on the right; `eyebrow` and `icon` props
- ApprovalCard takes an `eyebrow` and uses a secondary skip button
- ToolTrace hangs its calls from one continuous rail and gains an
  `error` status
- Each roster agent opens its own blueprint and run via `agentDetails`:
  live replay, approval, question, failure with retry, queued, finished
- Opened agents stay mounted, so runs continue off screen and finishing
  marks the row unread
- Agent rows end in a status tag (Approve, Answer, Failed, Queued); the
  collapsed rail shows the word under the initials
- Run panel stops on shared cards for approval, question, failure, queued
- Optional `projects` group the sidebar roster; folded projects carry
  their most pressing tag, and the breadcrumb names the project
@tenki-reviewer

tenki-reviewer Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Review complete. 🟡 4 medium

💬 Inline comments (3)

📍 Findings outside the diff (1) — 🟡 1 medium — defects on lines GitHub can't attach comments to

🟡 Medium — Stopping a run reports it as failed · use-agent-run.ts:161–163 · unchanged line

// packages/ui/src/components/agents-builder/use-agent-run.ts
161	function settledState(script: AgentRunScript): AgentRunState {
162		return buildRunTimeline(script).reduce((state, frame) => frame.apply(state), INITIAL);
163	}

stop() settles by folding the entire buildRunTimeline output, which now includes the failure branch that sets failedStep (use-agent-run.ts:161-163). A user who presses Stop before the run reaches its failing step therefore gets phase = 'failed': the panel renders the FailureBlock with a Retry card and onPhaseChange('failed') writes status: 'failed' plus the failure's statusNote onto the sidebar row. An intentionally stopped run is reported as a failure the run never reached.

🧹 Nitpicks (1) — 🟢 1 low
  • 🟢 Drop direct visibleRoster unit tests (agents-builder.test.tsx:347) — The new describe('visibleRoster') block calls the internal visibleRoster helper directly with hand-built partial AgentSummary objects, asserting its exact output ordering (agents-builder.test.tsx:347-359).

This PR introduces the agents-builder registry module: a run state machine with replay timeline (use-agent-run.ts), run panel and canvas views, sidebar roster, AskCard/ApprovalCard/ToolTrace AI components, API-contract types, registry manifest updates, and a new test suite. The overall structure is sound; the findings below are concentrated in run-lifecycle semantics and stale-state caching.

Files Change
packages/ui/src/components/agents-builder/use-agent-run.ts New run state machine: timeline building, gate steps, playback clock, failure handling.
packages/ui/src/components/agents-builder/agent-view.tsx, agents-builder.tsx View shell with kept-mounted hidden views and updateAgent patch caching against host data.
packages/ui/src/components/ai/* AskCard paging/answer aggregation, ApprovalCard, ToolTrace error rendering.
packages/ui/src/components/agents-builder/types.ts AgentsBuilderData and action union contract (answer-run, retry-run, start-run).
packages/ui/registry.json, scripts/build-registry.ts Registry manifest and build tooling for the new module.
packages/ui/test/agents-*.test.tsx Integration tests with fake-timer helpers and roster visibility coverage.

Reviewed commit: 9e70347

@yyyyaaa
yyyyaaa merged commit ddbbba2 into main Oct 22, 2026
6 checks passed

@tenki-reviewer tenki-reviewer Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adds an Agents Builder registry module with run lifecycle, AI cards, and tests; five defects center on run-state semantics and stale-session/patch caching.

Key findings

Comment on lines +146 to +149
const [session, setSession] = React.useState(() => {
const summary = agents.find((candidate) => candidate.id === agent.id);
return { attempt: 0, start: runStart(summary ? agentStatus(summary) : 'idle', autoplay), queuedNote: summary?.statusNote };
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 bug · medium

Kept-mounted agent views replay a stale session

AgentViewBody derives its session (start mode and queuedNote) once in a React.useState initializer and never re-derives it (agent-view.tsx:146-149). Because this PR keeps previously opened AgentViews mounted while hidden, a host data refresh that changes the agent's status or replaces data.run is ignored by the kept view: reopening it still shows the old opening mode (e.g. a queued panel stays paused after the host started the run), while the sidebar row reflects the new status. The panel and the roster disagree about the same agent.

📋 Prompt for AI Agents

In packages/ui/src/components/agents-builder/agent-view.tsx around lines 146-149, session.start and session.queuedNote are captured once at mount and never updated, while agent views now stay mounted across host data updates (keptAgentIds in agents-builder.tsx). Add a render-phase adjustment or effect keyed on [currentAgent.run, active]: while the session has not been user-started, when currentAgent.run changes identity (or the agent's host status changes) and the view is not active, reset the session to a freshly derived value (runStart(agentStatus(summary), autoplay) and the latest statusNote). Keep user-initiated transitions (Start/Retry) authoritative once they happen.

const base = { ...data.agents.find((agent) => agent.id === id), ...byId[id] };
// A run reports its phase on every mount; an unchanged patch keeps the state, so nothing re-renders.
if (current.source === data.agents && (Object.keys(patch) as (keyof AgentPatch)[]).every((key) => base[key] === patch[key])) return current;
return { source: data.agents, byId: { ...byId, [id]: { ...byId[id], ...patch } } };

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 bug · medium

updateAgent resurrects patches dropped by a roster refresh

updateAgent's non-no-op branch returns { source: data.agents, byId: { ...byId, ... } } where byId is the previous store's patches even when that store belongs to a stale roster (agents-builder.tsx:140), so patches the host refresh was meant to drop are carried into the new source and re-applied by the agents memo (agents-builder.tsx:127-130). An agent whose template patch said status: 'approval' but whose host roster now says idle flips back to 'approval' the next time any run reports a phase. The sidebar shows a decision request that no longer exists.

📋 Prompt for AI Agents

In packages/ui/src/components/agents-builder/agents-builder.tsx around lines 134-141, updateAgent's setAgentPatches updater returns { source: data.agents, byId: { ...byId, [id]: { ...byId[id], ...patch } } } even when current.source !== data.agents, re-applying patches a host roster refresh dropped. Compute const prev = current.source === data.agents ? current.byId : {} and use prev/prev[id] for both the no-op base and the returned store, so a roster change starts a fresh patch store.

Comment on lines +109 to +115
const failedStep = script.failure ? script.steps.findIndex((step) => step.id === script.failure!.stepId) : -1;
for (const [index] of script.steps.entries()) {
if (index === failedStep) {
at((state) => ({ ...state, failedStep: index, nodes: { ...state.nodes, tools: 'ready' } }), RUN_TIMING.stepMorph);
at((state) => ({ ...state, settled: true }));
return frames;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 bug · medium

Unmatched RunFailure.stepId plays the run as complete

buildRunTimeline resolves script.failure.stepId with findIndex and never validates the result (use-agent-run.ts:109): an id matching no step yields -1, so the failure branch never fires, failedStep stays null, and the phase logic reports done (agent-run-panel.tsx:480-491) while the FailureBlock is never rendered (agent-run-panel.tsx:623). A host authoring a run with a typo'd or stale stepId gets a run that looks fully successful — the opposite of what the data declares, with no diagnostic.

📋 Prompt for AI Agents

In packages/ui/src/components/agents-builder/use-agent-run.ts line 109, after computing failedStep, add a development-mode guard: when script.failure is set and failedStep === -1, log a console.error naming the unmatched stepId and set failedStep to script.steps.length - 1 so the run fails at its final step instead of silently playing to 'Run complete'. This protects hosts authoring RunFailure data with a stale id.

@yyyyaaa
yyyyaaa deleted the feat/agentic-ui-states branch October 22, 2026 03:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant