Repository navigation
feat(agent): big-agents-work — turn inspector, HITL hardening, tool catalog, playground UX - #5058
Conversation
…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.
…width instead of overlay drawer
… 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.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
What
Clean, complete snapshot of
big-agents-work(the agent integration branch) as a single PR intobig-agents. It carries the full accumulated agent feature set — 57 commits, 73 files.This branch exists because
origin/big-agents-workwas force-pushed back to an earlier merge (8ab3070), which dropped all of the work below from the remote.big-agents-work-cleanis the intact superset (it contains everything in8ab3070plus the 57 commits here), cut from the last good local state so nothing is lost.Highlights
Agent tool catalog
is_valid), not mere existence (is_active) — pending/abandoned connections read amber "Pending", not green "Connected"./connections/{id}/refresh→ reopens OAuth popup).Turn Inspector (Build-mode tooling)
HITL (human-in-the-loop) hardening
Agent chat + playground UX
ConfigAccordionSection; scoped-draft section drawers; revision selector in title row; resize-handle affordance.Base / context
big-agents.origin/big-agentsis fully contained here (this branch is strictly ahead).big-agents-workremote is intentionally bypassed after the force-push; this branch supersedes it.