Skip to content

fix(frontend): denied and cold-resumed approvals render and resolve correctly - #5630

Merged
mmabrouk merged 4 commits into
release/v0.107.0from
fix/denied-tool-not-handled
Aug 1, 2026
Merged

fix(frontend): denied and cold-resumed approvals render and resolve correctly#5630
mmabrouk merged 4 commits into
release/v0.107.0from
fix/denied-tool-not-handled

Conversation

@mmabrouk

@mmabrouk mmabrouk commented Aug 1, 2026

Copy link
Copy Markdown
Member

What was broken

Three defects in the approval flow, all found during multi-modality QA, all in code that predates the train:

  1. A denial was erased before the model saw it. Answering a gate with Deny came back to the model as {"status":"not_handled"}, so it kept retrying the same command (reported on fix(services): resume a run when its approval is answered outside the playground (#5593) #5598).
  2. After a page reload, a resolved approval came back as a live card, locked the composer, and answering the stale card fired a bogus new run.
  3. A hidden, permanently disabled "Deny & send" button sat in the DOM whenever an approval was pending, confusing tooling and tab order, because the flag-gated steer panel was collapsed instead of unmounted.

Causes and fixes

  1. A denied part lands in state output-denied, which was missing from the client-tool dispatcher's settled set, so UnhandledClientTool auto-settled it and the AI SDK rewrote the part, erasing the {approved: false} envelope. Fix: output-denied joins SETTLED, and any part carrying approval metadata is never a client-tool fallback candidate (clientTools/meta.ts); isSettledToolPart learns the state too.
  2. A cold approval resume re-raises the approved call under a new tool-call id. Reconstruction resolved the answer by tool-call id first, found the re-raised part, bailed, and left the original part approval-requested forever. Fix: settle by the interaction id first (the wire contract guarantees it matches), re-point the tool index at the gate part, and splice the duplicate re-raised part, carrying its executed result. Both arrival orders covered (transcriptToMessages.ts).
  3. The steer panel now unmounts entirely while NEXT_PUBLIC_AGENT_CHAT_STEER is off, and the sibling collapses gained inert (ApprovalDock.tsx).

Tests

The dispatch decision, both cold-resume arrival orders plus a deny variant, the composer-unlock predicate, and the resume seam are all pinned (meta.test.ts, transcriptToMessages.test.ts, agentMessageQueue.test.ts). Verified live on the dev stack: the denial envelope reaches the runner and the model changes course; reload renders each resolved call exactly once.

Notes for review

  • All three are base bugs, not train regressions; they ride this train because its QA exposed them and the release should not ship approvals in this state.
  • No user-facing strings added or removed.
  • A future "deny with feedback" seam exists (the AI SDK approval response supports reason); the steer feature remains behind its flag, untouched.

https://claude.ai/code/session_01McMogkcDRV7UpSAjfd8VKG

@dosubot dosubot Bot added the size:XS This PR changes 0-9 lines, ignoring generated files. label Aug 1, 2026
@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes

    • Improved handling of denied tool approvals so completed denials no longer block agent execution from resuming.
    • Prevented approval-related tool results from being incorrectly treated as regular client tools.
  • Tests

    • Added coverage for denied approvals, approval states, streaming behavior, unknown tools, and resumed execution scenarios.

Walkthrough

The change updates client-tool detection and approval-resume settlement logic. Denied tool outputs are settled, approval-bearing parts are excluded from client-tool detection, and unit tests cover both behaviors.

Changes

Approval tool handling

Layer / File(s) Summary
Client-tool classification
web/oss/src/components/AgentChatSlice/components/clientTools/meta.ts, web/oss/src/components/AgentChatSlice/components/clientTools/meta.test.ts, web/oss/vitest.config.ts
isClientToolPart excludes approval-bearing parts and recognizes output-denied as settled. Tests cover approval states, parked unknown tools, streaming behavior, and known client tools.
Approval resume settlement
web/packages/agenta-playground/src/state/execution/agentApprovalResume.ts, web/packages/agenta-playground/tests/unit/agentApprovalResume.test.ts
isSettledToolPart recognizes output-denied. Tests verify resumption after a denied approval result and a resolved sibling approval.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

🚥 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 describes the denied approval fix and related approval behavior covered by the changeset.
Description check ✅ Passed The description explains the denied approval issue and directly matches the implemented changes and tests.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/denied-tool-not-handled

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.

@vercel

vercel Bot commented Aug 1, 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 Aug 1, 2026 6:00pm

Request Review

@mmabrouk

mmabrouk commented Aug 1, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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

🧹 Nitpick comments (2)
web/oss/src/components/AgentChatSlice/components/clientTools/meta.test.ts (2)

24-38: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cover the new SETTLED branch directly.

Both denied cases include approval. Therefore, isClientToolPart returns at Line 63 of web/oss/src/components/AgentChatSlice/components/clientTools/meta.ts before it evaluates clientToolMeta(...).settled. These tests pass even if output-denied is removed from SETTLED.

Add a parked unknown tool with state: "output-denied" and no approval metadata.

Proposed test
+    it("does NOT claim a parked unknown tool after output-denied", () => {
+        const part = toolPart({
+            type: "tool-mysteryTool",
+            state: "output-denied",
+        })
+        expect(isClientToolPart(part, settledCtx)).toBe(false)
+    })

50-58: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Align the test name with its coverage.

The test claims coverage for every state, but it checks only output-available. isClientToolPart deliberately rejects approval-requested and approval-responded. Rename the test or parameterize the supported non-approval states.

Proposed rename
-    it("claims a known client tool in every state", () => {
+    it("claims a known client tool with a settled output", () => {

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 1639d527-5130-4a63-8f8f-ab47a692f67a

📥 Commits

Reviewing files that changed from the base of the PR and between 927cb78 and 9f1b25f.

📒 Files selected for processing (5)
  • web/oss/src/components/AgentChatSlice/components/clientTools/meta.test.ts
  • web/oss/src/components/AgentChatSlice/components/clientTools/meta.ts
  • web/oss/vitest.config.ts
  • web/packages/agenta-playground/src/state/execution/agentApprovalResume.ts
  • web/packages/agenta-playground/tests/unit/agentApprovalResume.test.ts

@mmabrouk
mmabrouk force-pushed the wp4-frontend-transport branch from 927cb78 to 9e02eef Compare August 1, 2026 16:35
@mmabrouk
mmabrouk force-pushed the fix/denied-tool-not-handled branch from 9f1b25f to 0ae32d2 Compare August 1, 2026 16:35
@mmabrouk
mmabrouk force-pushed the fix/denied-tool-not-handled branch from 0ae32d2 to 84b0e24 Compare August 1, 2026 16:50
@dosubot dosubot Bot added size:M This PR changes 30-99 lines, ignoring generated files. and removed size:XS This PR changes 0-9 lines, ignoring generated files. labels Aug 1, 2026
@dosubot dosubot Bot added size:L This PR changes 100-499 lines, ignoring generated files. and removed size:M This PR changes 30-99 lines, ignoring generated files. labels Aug 1, 2026
@mmabrouk mmabrouk changed the title fix(frontend): a denied tool call is no longer auto-settled as an unhandled client tool fix(frontend): denied and cold-resumed approvals render and resolve correctly Aug 1, 2026
@mmabrouk
mmabrouk force-pushed the wp4-frontend-transport branch from 92797ad to c7ac4f6 Compare August 1, 2026 17:59
@mmabrouk
mmabrouk force-pushed the fix/denied-tool-not-handled branch from 1d7e4b1 to 70b611b Compare August 1, 2026 17:59
@mmabrouk
mmabrouk changed the base branch from wp4-frontend-transport to release/v0.107.0 August 1, 2026 18:15
@mmabrouk
mmabrouk merged commit c8a1479 into release/v0.107.0 Aug 1, 2026
38 of 39 checks passed
@mmabrouk
mmabrouk deleted the fix/denied-tool-not-handled branch August 1, 2026 18:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Bug Report Something isn't working Frontend size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant