Skip to content

feat(agent): big-agents-work — turn inspector, HITL hardening, tool catalog, playground UX - #5058

Merged
ardaerzin merged 57 commits into
big-agentsfrom
big-agents-work-clean
Jul 3, 2026
Merged

ardaerzin merged 57 commits into
big-agentsfrom
big-agents-work-clean

Conversation

@ardaerzin

Copy link
Copy Markdown
Contributor

What

Clean, complete snapshot of big-agents-work (the agent integration branch) as a single PR into big-agents. It carries the full accumulated agent feature set — 57 commits, 73 files.

This branch exists because origin/big-agents-work was force-pushed back to an earlier merge (8ab3070), which dropped all of the work below from the remote. big-agents-work-clean is the intact superset (it contains everything in 8ab3070 plus the 57 commits here), cut from the last good local state so nothing is lost.

Highlights

Agent tool catalog

  • Connection health now reflects authentication (is_valid), not mere existence (is_active) — pending/abandoned connections read amber "Pending", not green "Connected".
  • Distinguishable multi-account switcher (labels by slug; selected highlighted).
  • Reconnect action for pending connections (reuses /connections/{id}/refresh → reopens OAuth popup).

Turn Inspector (Build-mode tooling)

  • Timeline / Context / Raw tabs, per-turn request capture, session-scoped turn store, inline side panel.

HITL (human-in-the-loop) hardening

  • Approval keyed on stable recorded tool name (survives arg-refresh), non-converging loop-breaker, persistent approval dock, stop re-sending after approval resolves. Spans frontend + SDK + runner.

Agent chat + playground UX

  • Rich chat input (links, code blocks), empty states, scroll fixes, composer polish.
  • Playground build-kit rebuilt on ConfigAccordionSection; scoped-draft section drawers; revision selector in title row; resize-handle affordance.
  • Dark-mode surface/elevation refinements.

Base / context

  • Base: big-agents. origin/big-agents is fully contained here (this branch is strictly ahead).
  • The upstream big-agents-work remote is intentionally bypassed after the force-push; this branch supersedes it.

ardaerzin added 30 commits July 2, 2026 09:57
…ssion button

Add min-w-0 to the agent playground Tabs so the session tab strip clamps to
the available width and scrolls internally instead of pushing the search and
history controls off-screen. Move the New session (+) button out of the scroll
container into the fixed right-hand actions cluster so it no longer scrolls
away with the tabs.
…overable

The agent playground disables the splitter's collapse pills (Build/Chat lives
in the header), so the drag handle was the only resize affordance and read as
a bare hairline. Add a persistent centered grip on the divider — neutral at
rest, accent-tinted (colorPrimary at reduced opacity, so it stays visible in
dark without shouting) and taller on hover/drag — scoped to a new
playground-splitter-agent class so prompt playgrounds keep antd's defaults.
…title row

Extract the agent revision selector (variant picker + version/status chip)
into a self-contained AgentRevisionSelector and render it next to the agent
name in the page header. The config-panel header (ROW B) now shows a
'Configuration' title instead. Scoped to agent mode; prompt/evaluator and
embedded surfaces are unchanged.
Add a railInfoLabel helper to RailField (label + inline info tooltip, so a
field keeps its help text without a separate description line) and a disabled
prop to SectionRail (for read-only revisions). Both back the config-drawer
refactors that follow.
…Field rows

Convert SandboxPermissionControl, ClaudePermissionsControl and McpServerFormView
from stacked label-above LabeledField groups to flat [label | control] RailField
rows using railInfoLabel for per-field help. Drops the redundant nested headers
and inner borders (the 'form inside a form' look) so each knob is a peer row that
shares the section rail.
…gAccordionSection

Replace the hand-rolled collapsible card with the shared ConfigAccordionSection
(toggle as the header extra, 'Removed on commit' as the status), and render the
overlay groups as RailField rows. Add an optional enabledOverride so the Advanced
drawer can buffer the build-kit toggle in its draft and only write the persisted
atom on Save.
…nced UX

Move the Model & harness and Advanced section drawers to a true scoped draft:
edits are buffered and relayed to the entity only on Save, with Save gated on a
real diff (a second useModelHarness instance holds the draft so the background
accordion summaries keep reflecting the saved entity). Advanced is rebuilt on
ConfigAccordionSection + RailField (auth as a SectionRail; sandbox/permissions
flattened), and the 'Edit as JSON' escape hatch is removed. Model & harness uses
the rail rhythm too; compatibility is now self-contained on the harness cards
(the current card owns its own model-availability, and availability also matches
on the model's provider family to avoid cross-harness id-namespace false
negatives), the 'Current' badge tracks the saved harness (not the draft pick),
and the redundant compatibility side panel is dropped in favour of version
history — matching the Advanced drawer's shape.
…arity

Add paste-a-link-over-selection and a plain code-block fence to the RichChatInput (new LinkPastePlugin + CodeFencePlugin, LinkNode/CodeNode registered), and harmonize link/code/blockquote styling between the composer theme and the message-bubble markdown so a block looks identical while typing and after sending.
…ease

Move the tool-approval action out of the scrolling transcript into a persistent ApprovalDock pinned above the composer (neutral surface, tool + payload context, animated show/hide, inert while collapsed); the inline tool row now just marks 'Awaiting approval'. Harden the queue: a user stop voids the pending gate so a new message sends immediately instead of queuing, narrow isHitlPending to approval-requested (lockstep with the dock, avoids a queue-freeze trap), and release on a settled 'error' turn.
…ubble

The hover toolbar (metrics + copy/rewind/trace) is anchored to the bottom of a reserved lane below each message. The lane was pb-7 (28px) and the toolbar is ~28px tall, so it filled the lane and hugged the bubble text. Bump to pb-10 (40px) so the extra space falls between the bubble and the toolbar.
In Build mode the agent transcript renders each tool call as a full step — per-tool input and output/error as monospace blocks, expanded reasoning — gated on chatPanelMaximizedAtom; Chat mode keeps the calm collapsed summary.
… to target session

The inspector read the settle-only sessionMessagesAtom, so it showed a stale/wrong turn and never updated while streaming; and being mounted per session it popped a drawer per tab. Feed it the live useChat messages + sessionId as props, open only when it's the target session, and drop the AI SDK step-start/step-end boundary noise from the Timeline.
Each detailed tool step in Build mode now has its own caret toggle — click a step header to collapse/expand its input/output blocks (HeightCollapse), independent of the others. Default expanded.
…inimal in Chat

Replace the bare 'Ask a question…' text with a mode-adaptive empty state: Chat mode shows a warm welcome (robot mark + prompt); Build mode shows an agent-aware card (name, model, tool/skill counts, a one-line summary from the instructions) plus curated starter prompts that send on click.
…hange and tool collapse

Two reported jump-to-top bugs in the agent playground chat, plus perf hardening
of the scroll handler:

- onScroll only re-arms follow on a real scroll-DOWN-to-edge. A content shrink
  (tool gutter collapsing to "Used N tools", reasoning folding) clamps scrollTop
  to the new bottom and fires a non-gesture scroll event; a clamp only decreases
  scrollTop, so `> prevTop` rejects it. Previously that silently re-enabled follow
  and the next token snapped the min-h-full active turn to the top.
- Coalesce the costly jump-pill measurement (querySelectorAll + getBoundingClientRect)
  to one rAF/frame; keep the follow decision and SC-3 anchor synchronous. Removes
  per-scroll-event and per-render forced reflows during streaming.
- Dedup the follow-pin: guarded scrollToBottom so the ResizeObserver and the follow
  effect don't both write scrollTop for the same growth.
The Vercel adapter keyed a parked approval on the ACP display fields
(name -> title -> kind). A Claude tool has no ACP `name`, so the key was a
drift-prone display string: between the park turn and the re-raise the harness
could vary it, the cross-turn resume key silently stopped matching, and the gate
re-parked every turn (the HITL resume loop).

- _approval_tool_name / _tool_spec_of: prefer the resolved spec's canonical
  `name` (stable across cold-replay turns), falling back to the old chain when no
  spec is resolved. Mirrors the runner's permissionToolName precedence so the
  persisted key and the live re-raised key agree.
- tool-input-available now prefers `rawInput` over the often-empty `input`, so
  every tool-call path shows the real args (approve-empty-input bug).
- [HITL] ingress/egress info logs to diff the persisted key against the runner's
  live gate identity.

Covered by test_vercel_stream_park.py.
Runner side of the approval re-park loop, matched to the SDK egress fix.

- permissionToolName / specOf: resolve the gated tool's key from the resolved
  spec's canonical `name` first (stable across cold-replay turns), then the ACP
  display fields. This is the same precedence the SDK egress persists, so the
  stored decision key and the live re-raised key agree instead of drifting apart.
- nonConvergingToolNames + loop-breaker: when a tool's {approved:true} envelopes
  outnumber its real executions by a threshold, the resume key never matched;
  DENY the next gate for it (a clean terminal failure the model stops re-issuing)
  instead of parking forever. Fail-safe under the key fix above.
- [HITL] ground-truth logging across permissions.ts / responder.ts /
  sandbox_agent.ts (ACP permission, gate hit/miss/park, stored resume state) to
  diff the persisted keys against the live gate identity field-by-field.

Covered by responder.test.ts.
ardaerzin and others added 21 commits July 3, 2026 00:49
… not deferral

The previous rawInput fix deferred the tool_call run-event until args
arrived. That broke the emit-first invariant the HITL approval path and
loop-breaker depend on: for a gated tool whose ACP call carries no args,
the tool_call no longer surfaced before the approval, so the egress took
the synthesize branch and my late second emission re-injected
tool-input-start for an already-approved part — the FE re-rendered the
tool as if it re-ran (the "looping" regression), and non-gated inputs
were still empty.

Restore the shipped contract instead (see test_vercel_stream_park
test_parked_tool_call_refreshes_real_args_on_approval): emit the
tool_call up front (empty input is fine), then REFRESH its input by
re-emitting the tool_call once the real args land on a later
tool_call_update. This mirrors the gated approval-refresh for the
non-gated path (query_workflows, list_connections).

The egress now treats a repeat tool_call for a seen id as an input
refresh: it re-emits tool-input-available but skips a second
tool-input-start (which would reset the FE part), exactly like
_interaction_parts. No wire-shape change.

Tests: otel scenarios for emit-first + refresh, empty-stays-empty, and
args-up-front-no-refresh; an egress test that a repeat tool_call yields
one start and two inputs (empty then real), refresh before output.
Claude-over-ACP names the same gated call differently across frames: the
session/update tool_call titles it by category ("Terminal"), the permission
request titles it by the specific invocation ("cat ..."). Neither carries a
stable name/spec, so the cross-turn key drifted (stored "Terminal#args" vs live
"cat ...#args") and every approval re-parked — the HITL resume loop.

Recover the recorded tool_call name for the gate's id and stamp it as
resolvedName; permissionToolName prefers it, so the live re-raised key equals the
stored key and the gate resolves. Keep the non-converging loop-breaker and the
[HITL] diagnostics (gate identity, decisions, gate miss) as a fail-safe.
…arg-refresh

Mirror the runner's resolvedName anchor in the vercel egress: _approval_tool_name
prefers resolvedName (then spec.name) over the drift-prone ACP title/kind, so the
FE part the transcript folds back keys the same as the live gate.

Also stop a late arg-refresh from downgrading it: Pi fills args in on a later
tool_call_update replayed as a repeat tool_call carrying only the ACP title; the
egress now preserves the best-known (approval-upgraded) name per id instead of
clobbering it. Add [HITL] egress/ingress logging for the round-trip.
The cold-replay runner re-issues the approved tool under a fresh id, so its output
attaches to a new part and the original approval-responded part LINGERS in the
same assistant message. agentShouldResumeAfterApproval only checked that a resolved
approval exists and all parts settled, which stays true forever, so
sendAutomaticallyWhen re-sent after every completion and re-ran the whole turn.

Guard on already-resumed: once the model continues past the approval a new step
begins (a step-start part follows it), so don't resume again. Chained second
approvals still resume (the last resolved part is the tail).
…utput fences

A HITL-approved tool's part lingers in approval-responded (cold-replay attaches the
execution output to a fresh-id sibling), which rendered as a perpetual spinner with
no output. AgentMessage now drops the answered gate once its executed sibling
exists (same tool + input), so the turn shows the single completed call with its
output; ToolActivity treats approval-responded as resolved (approved, not running)
as a safety net.

Also strip the markdown code fence backends wrap tool output in (the IOBlock is
already a monospace pre), matching the existing error-display behavior.
…treatment with semantic elevation tokens

Introduce a surface ladder (app/gutter/raised/canvas/card/inset/chat) that separates the Build view's two workspaces (Configuration authoring panel vs Chat observing canvas) via elevation and containment instead of flat hue. The relationship inverts by theme: raised surfaces are lighter than the canvas in dark mode, white over soft-grey in light. Define semantic CSS classes (ag-panel-raised
# Conflicts:
#	web/oss/src/components/AgentChatSlice/components/AgentMessage.tsx
#	web/packages/agenta-ui/src/RichChatInput/assets/theme.ts
Address PR review on the runner/SDK HITL path:

- SDK vercel stream: pick tool input with `rawInput is not None` instead of
  truthiness, so a legitimately empty `{}` counts as real args rather than
  falling through to `input` (the same empty-vs-missing ambiguity this stream
  otherwise fixes). Applied to all four read sites.
- Runner HITL resume log: dump decision KEYS only, not the stored values —
  those values can carry client-tool outputs (connection/auth data) and this
  line fires on every browser-driven turn. Matches every other [HITL] log.
- Single-source the tool-spec alias chain: export `specOf` from responder.ts
  and drop the duplicate `clientToolSpecOf` in permissions.ts. That alias list
  is the crux of the tool-identity-drift fix, so keeping one copy prevents the
  two sides from silently diverging and re-opening the resume loop.
Turn inspector + tool rendering pass, plus PR review fixes on the agent chat FE:

- Turn Inspector: horizontal Timeline/Context/Raw tab bar (vertical rail ate a
  third of the panel, squeezing tool-I/O JSON); click any assistant turn to
  re-point the inspector, with the target turn tinted; dismiss on leaving Build.
- Shared `toolFormat` (strip a whole-string markdown fence, pretty-print real
  JSON/JSON-strings) so the inline step log and the inspector render payloads
  identically. Reasoning now auto-collapses in both modes.
- Tool rows: track input/output/error presence explicitly so a legit `null`
  output renders and `output-available` with no output can't open an empty
  expander.
- Timeline: drop step-boundary and data-carrier/unknown parts instead of
  emitting empty rows.
- Approval dock: show the exact string payload (no trim) — the user approves
  what the tool receives; the one-line preview still normalizes.
- Raw tab: await the clipboard write and only toast on success/failure.
- Queue: gate `hitlPending` on `!stopped` so a stopped-and-settled turn no
  longer reports "awaiting" while sends go through immediately.
Give right-hand drawers a distinct top elevation tier in dark mode so a drawer
opened over the (already elevated) config panels reads as a separate sheet.

- New `--ag-drawer-*` tokens (theme-variables.css) + a `.ag-drawer-elevated`
  scope (globals.css) that restyles the sheet, fields, segmented, switches, and
  the semantic drawer parts (`ag-drawer-rail`/`-card`/`-row`/`-tag`) — dark only,
  light unchanged.
- Opt the drawers in via `rootClassName="ag-drawer-elevated"` (config item,
  instructions, section, agent integration, workflow reference, trigger
  schedule/subscription) and tag their rails/cards/rows with the semantic
  classes (CatalogChooser, WorkflowReferenceSelector, SkillFormView,
  ParameterTree, AgentTemplateControl).
- Type badges get `ag-type-{completion,chat,agent}` classes; MainLayout splitter
  tweaks for the agent surface.
…t cards

Revert the accordion layout's per-section card treatment (surface-card box +
inter-section gaps) back to flat accordions with dividers between sections. The
explicit Cards layout and the surface color tokens are untouched.
…ile list

Follow-ons to the drawer elevation tier:

- Tag the agent chat scroll container `ag-canvas` so the transcript surface is
  addressable for dark-mode treatment.
- Skill Files list: give it `ag-rail-filelist` and drop its light panel fill in
  dark mode — on the already-recessed drawer rail the fill read as a redundant
  box, so the rows now sit directly on the rail.
The shared CatalogChooser drove its status dots off a connection's is_active
flag, but is_active only means "not soft-deleted" — it defaults to true the
moment a connection record is created, before OAuth completes. So a pending or
abandoned connection showed a green "Active" dot even though it was never
authenticated (the reported case: start a connect flow, close the OAuth popup,
and the connection still appears green).

Key the health signal off is_valid instead (set true only on a successful auth
callback): the grid tile, rail rows, in-detail account switcher and the detail
header now show green "Connected" only when authenticated, amber "Pending"
otherwise. Rename the CatalogChooser prop isConnectionActive -> isConnectionReady
to name the real semantic, and pass isConnectionValid from both the agent tools
and trigger subscription consumers.

Also improves multi-account support: rail rows fall back to the connection slug
so two accounts of one app are distinguishable, and an in-detail account
switcher appears when an integration has more than one connection.
…d tab polish

Introduce a distinct visual identity for user turns and strengthen the chat composer
as the primary input:

- User bubbles: soft accent-tinted card (`--ag-user-bubble-bg/border`) vs the agent's
  borderless turn, making "mine" unmistakable on the canvas.
- Composer: visible border + subtle shadow (`--ag-composer-border`, `--ag-surface-chat-shadow`)
  so it reads as a defined, slightly-lifted field; accent border on focus instead
# Conflicts:
#	web/oss/src/components/Sidebar/Sidebar.tsx
…apps

When an integration had more than one connection, the detail view showed a big
card and a chip row that carried the same label — display names default to the
integration name, so every account read as "Gmail". Replace the card+chips with
a single ConnectionSwitcher: the integration shown once as a header, then one
selectable card per account labelled by its slug (the per-account identifier the
user chose), with a per-account health dot and the selected account highlighted.
Single-connection view is unchanged.
A pending connection (record created, OAuth never completed) had no way to
resume auth from the catalog. Surface a Reconnect button on the selected
connection while it isn't ready: it calls the existing /connections/{id}/refresh
(backend re-initiates OAuth and updates the same row — no duplicate), reopens
the returned redirect_url in a popup, and refetches on completion so the dot
flips to Connected. Extracted the popup/listen flow into a reusable
useReconnectToolConnection hook (mirrors ConnectDrawer). Wired into the agent
tools catalog via optional onReconnect/isReconnecting props on CatalogChooser.
…e placeholder, soft focus

Corrections to the agent chat composer surface:
- Border softened to a quiet edge (light #e7e8eb, dark #2a2c30) — the shadow
  (light) / fill (dark) carries the lift instead of a hard outline.
- Focus edge is now theme-aware (--ag-composer-focus): the full accent on white,
  a soft olive tint on the near-black composer where full lime shouted.
- Composer-specific placeholder token (light #767b82, dark #7e828a) so the
  placeholder is readable without darkening every antd input's placeholder.
@dosubot dosubot Bot added the size:XXL This PR changes 1000+ lines, ignoring generated files. label Jul 3, 2026
@vercel

vercel Bot commented Jul 3, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agenta-documentation Ready Ready Preview, Comment Jul 3, 2026 2:55pm

Request Review

@dosubot dosubot Bot added enhancement New feature or request frontend labels Jul 3, 2026
@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d9eeab02-53ac-4607-8847-009e49c7c73e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch big-agents-work-clean

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

This branch was successfully deployed

1 active deployment
Preview — a11b58ce Deployed Jul 3, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request frontend size:XXL This PR changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants