Skip to content

feat(frontend): Surface parked connect prompts in an interaction dock - #5521

Open
ashrafchowdury wants to merge 4 commits into
release/v0.106.1from
feat/agent-interaction-dock
Open

feat(frontend): Surface parked connect prompts in an interaction dock#5521
ashrafchowdury wants to merge 4 commits into
release/v0.106.1from
feat/agent-interaction-dock

Conversation

@ashrafchowdury

@ashrafchowdury ashrafchowdury commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Context

When the runner parks a request_connection call, the stream genuinely ends. useChat reports ready, so nothing busy-derived (working dots, the stop button) signals that the run is paused on you. Meanwhile the message queue quietly holds every send.

The result: the turn looked finished, anything you typed disappeared into a queue with no explanation, and a parked connection had no way to say no, so the conversation stayed frozen.

Changes

InteractionDock sits in the composer region, between the transcript and the input, so a paused run cannot scroll out of reach. It follows the same contract as ApprovalDock. The dock owns the actions and the inline transcript row is only a marker. It also adds the escape hatch a parked connection lacked: "Not now" settles the call as a structured decline, so the run resumes and the conversation unfreezes.

Three smaller pieces make the pause legible:

  • A "Waiting for your input" chip on the paused turn. WorkingDots animates because the agent is working. This one is deliberately static, because here it is your move.
  • The composer placeholder now says new messages will be queued.
  • The queue popover explains itself. Before it read "Queued, sent one by one". Now it reads "Held until you answer the agent", with a "waiting on you" tag on the trigger and in the aria-label.

ConnectToolWidget drops about 280 lines. The OAuth flow moved into a new useConnectFlow hook so the dock and the inline chip share one implementation instead of two that could both settle the same call. The hook settles on every terminal path, so a run cannot hang:

success  -> {connected: true,  integration, slug}
decline  -> {connected: false, reason: "declined"}
cancel   -> {connected: false, reason: "cancelled"}
timeout  -> {connected: false, reason: "timeout"}

It settles with a reference, never a secret. The runner re-resolves the credential from the project vault on resume.

Scope is the connect interaction only. Elicitation stays inline, since it is a form the user fills in the transcript and it already carries its own decline and dismiss actions. The composer waiting state covers its visibility.

Tests / notes

What to QA

  • Ask the agent for something needing a connection (a GitHub tool). The dock appears above the composer with a Connect button, and the turn shows "Waiting for your input" rather than looking finished.
  • Type while the dock is up. The message goes to the queue and the popover says "Held until you answer the agent".
  • Click "Not now". The dock clears, the run resumes, and the queued messages send.
  • Click Connect and complete the OAuth in the popup. The dock clears and the agent continues with the connection available.
  • Close the OAuth popup without finishing it. The call settles as cancelled and the run resumes instead of hanging.
  • Regression: an approval-gated turn still shows ApprovalDock as before, and an ordinary tool-using turn shows no interaction dock and does not auto-resend.

Previews

Before:
image.png
After:
image.png

- Added InteractionDock component to manage parked client-tool interactions, mirroring ApprovalDock's functionality.
- Introduced WaitingForInput component to indicate when the agent is waiting for user input.
- Updated AgentConversation to integrate InteractionDock and display waiting states appropriately.
- Enhanced QueuedMessages to reflect held messages when the interaction is pending.
- Refactored ConnectToolWidget to utilize useConnectFlow for managing connection states and actions.
- Added useConnectFlow hook to centralize connection logic for both InteractionDock and inline components.
- Updated state management to include isPendingClientToolInteraction for better handling of client-tool interactions.
@dosubot dosubot Bot added size:XL This PR changes 500-999 lines, ignoring generated files. Feature Request New feature or request Frontend labels Jul 26, 2026
@vercel

vercel Bot commented Jul 26, 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 28, 2026 9:58pm

Request Review

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Review Change Stack

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: f181d65b-0078-4c19-b665-311b3aec6ef4

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
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main UI change: showing parked connect prompts in an interaction dock.
Description check ✅ Passed The description matches the changeset, covering the dock, queue state, shared connect flow, and decline/resume behavior.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/agent-interaction-dock

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.

@ashrafchowdury
ashrafchowdury force-pushed the feat/agent-interaction-dock branch from 10bb97f to 4b9e0e4 Compare July 26, 2026 14:23
@ashrafchowdury ashrafchowdury changed the title feat(frontend): interaction dock for parked client-tool interactions feat(frontend): Surface parked connect prompts in an interaction dock Jul 26, 2026
@github-actions

github-actions Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Railway Preview Environment

Preview URL https://gateway-production-d917.up.railway.app/w
Project agenta-oss-pr-5521
Image tag pr-5521-d53d392
Status Deployed
Railway logs Open logs
Workflow logs View workflow run
Updated at 2026-07-28T22:07:50.429Z

@ashrafchowdury
ashrafchowdury requested a review from mmabrouk July 27, 2026 07:01
…n-dock

# Conflicts:
#	web/packages/agenta-playground/src/index.ts
#	web/packages/agenta-playground/src/state/execution/index.ts
#	web/packages/agenta-playground/src/state/index.ts
@ashrafchowdury
ashrafchowdury changed the base branch from release/v0.106.0 to main July 28, 2026 16:25
@ashrafchowdury
ashrafchowdury changed the base branch from main to release/v0.106.1 July 28, 2026 16:27

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
web/oss/src/components/AgentChatSlice/components/clientTools/ConnectToolWidget.tsx (1)

63-108: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

phase === "error" branch is unreachable — retry failures never show the specific reason.

Every reachable runConnect(false) call comes from the Retry button at line 93, which only renders once meta.settled || outcome is already true (that's the whole premise of "retry after settle"). So when that retry fails and sets phase = "error" + errorText, the render still hits the meta.settled || outcome check at line 64 first and returns the generic "Connection not completed" chip (line 88-95) — the new phase === "error" block at line 98 can never execute. The specific failure reason from a failed retry is silently dropped.

Move the phase === "error" check ahead of the settled check (same pattern already used for phase === "connecting").

🐛 Proposed fix: reorder the branches
-    // ── Settled: the result chip (U1). `outcome` covers the render before `meta.settled` flips. ──
-    if (meta.settled || outcome) {
+    // ── Error on a manual retry (create failed, popup blocked): show reason + Retry ──────────────
+    if (phase === "error") {
+        return (
+            <ChipRow icon={<Warning size={13} weight="fill" className="text-colorError" />}>
+                <Text type="danger" className="!text-xs truncate" title={errorText ?? undefined}>
+                    {errorText ?? "Connection failed."}
+                </Text>
+                <RetryButton onClick={() => runConnect(false)} />
+            </ChipRow>
+        )
+    }
+
+    // ── Settled: the result chip (U1). `outcome` covers the render before `meta.settled` flips. ──
+    if (meta.settled || outcome) {
         const output = (meta.output ?? {}) as ConnectOutput
         ...
         return (
             <ChipRow icon={<Warning size={13} weight="fill" className="text-colorWarning" />}>
                 <Text type="secondary" className="!text-xs">
                     Connection not completed
                 </Text>
                 <RetryButton onClick={() => runConnect(false)} />
             </ChipRow>
         )
     }
-
-    // ── Error on a manual retry (create failed, popup blocked): show reason + Retry ──────────────
-    if (phase === "error") {
-        return (
-            <ChipRow icon={<Warning size={13} weight="fill" className="text-colorError" />}>
-                <Text type="danger" className="!text-xs truncate" title={errorText ?? undefined}>
-                    {errorText ?? "Connection failed."}
-                </Text>
-                <RetryButton onClick={() => runConnect(false)} />
-            </ChipRow>
-        )
-    }
🧹 Nitpick comments (2)
web/oss/src/components/AgentChatSlice/components/clientTools/useConnectFlow.ts (2)

174-190: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Consider validating redirectUrl's scheme before opening it.

redirectUrl comes straight from result.connection?.data?.redirect_url and is passed to window.open unchecked. It's backend-controlled today, but a cheap http(s):-only guard adds defense-in-depth against a misbehaving/compromised response opening a javascript:/data: URL in the opener's context.

🛡️ Proposed guard
                 if (!redirectUrl) {
                     // No OAuth step (e.g. api_key created inline): the connection already exists.
                     onSuccess()
                     return
                 }
+                if (!/^https?:\/\//i.test(redirectUrl)) {
+                    setPhase("error")
+                    setErrorText("Received an unexpected connection URL.")
+                    return
+                }
 
                 const popup = window.open(

70-304: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

No unit tests for this race-prone state machine.

useConnectFlow coordinates popup lifecycle, postMessage origin validation, polling, and a timeout backstop with a one-shot settle guard — exactly the kind of logic where a small ordering mistake (as found in ConnectToolWidget.tsx's render branches) goes unnoticed without tests. Consider adding unit tests around finish/runConnect/cancel/decline (mocking window.open, postMessage, timers).


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 55573f52-cd9d-412e-ab59-654c60dae71d

📥 Commits

Reviewing files that changed from the base of the PR and between a3e7fdf and 1d8ab6c.

📒 Files selected for processing (8)
  • web/oss/src/components/AgentChatSlice/AgentConversation.tsx
  • web/oss/src/components/AgentChatSlice/components/InteractionDock.tsx
  • web/oss/src/components/AgentChatSlice/components/QueuedMessages.tsx
  • web/oss/src/components/AgentChatSlice/components/clientTools/ConnectToolWidget.tsx
  • web/oss/src/components/AgentChatSlice/components/clientTools/useConnectFlow.ts
  • web/packages/agenta-playground/src/index.ts
  • web/packages/agenta-playground/src/state/execution/index.ts
  • web/packages/agenta-playground/src/state/index.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Feature Request New feature or request Frontend size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants