Skip to content

docs(agent): plan the HITL approval fix (F-024) - #4845

Merged
mmabrouk merged 1 commit into
big-agentsfrom
docs/hitl-fix
Jun 25, 2026
Merged

docs(agent): plan the HITL approval fix (F-024)#4845
mmabrouk merged 1 commit into
big-agentsfrom
docs/hitl-fix

Conversation

@mmabrouk

Copy link
Copy Markdown
Member

What

Design-only workspace for fixing the broken human-in-the-loop (HITL) tool approval flow, QA finding F-024. No code change.

Adds docs/design/agent-workflows/projects/hitl-fix/ (README, context, research, plan, status).

The bug (F-024)

Claude harness + an Ask permission rule + a gateway tool: the permission gate fires, but the playground shows no "Run this tool? Approve / Deny" prompt. The tool-call card resolves straight to ERROR: "User refused permission to run tool" and the run auto-denies. Park → approve → resume never triggers. Separately, Pi's "Permission policy" field offers only auto/deny — no ask — so HITL is not configurable for Pi at all.

Root cause (across layers)

The renderer (ToolPart.tsx), the AI-SDK egress (stream.py emits tool-approval-request), and the cross-turn resume (HITLResponder + extractApprovalDecisions) are all correct. The break is one conflicting reply in the runner:

  • On an ask gate with a human surface, HITLResponder.onPermission returns deny to "park", and attachPermissionResponder maps that to session.respondPermission(id, "reject").
  • For Claude, reject produces a failed tool call ("User refused permission to run tool"), which maybeCloseTool (tracing/otel.ts) records as a tool_result {isError:true}.
  • The egress projects that as tool-output-error on the same toolCallId as the approval-requested part, so the AI SDK merges and the error overwrites the approval prompt.

Park (the surface signal) and reject (the harness reply) contradict each other on the wire.

Proposed fix (smallest-correct)

  • Runner: add a runner-internal park outcome; on park, do not send reject (end the turn with the tool pending), so the approval-requested part is the last word. No wire change. (Fallback B: suppress the park-induced failed tool_result in the otel layer.)
  • Egress / FE: no change for the Claude path once the runner stops poisoning the wire (assertion-only tests).
  • Pi: hide ask for Pi in the form now (honest, tiny); track real Pi HITL via relay enforcement (open-issues S5.2) as a follow-up.

Test plan covers runner unit + SDK egress/ingest contract + golden wire (unchanged) + live FE e2e (park → approve → resume) + a replay-test pin.

Decisions needed

See the pinned "Decision needed" comment.

https://claude.ai/code/session_01GYo3UEfvsZpncagqb28Mbc

Root-cause and design workspace for the broken human-in-the-loop tool
approval flow. The Claude permission gate fires but the playground shows
no Approve/Deny prompt: the runner parks an 'ask' gate by replying reject
to the harness, which makes Claude emit a failed tool call that the egress
projects as tool-output-error, overwriting the approval-requested part.

Adds docs/design/agent-workflows/projects/hitl-fix/ (README, context,
research, plan, status) with the smallest-correct fix across the runner,
egress, FE, and Pi permission model, plus an FE+SDK+live test plan.

Design only; no code change.

Claude-Session: https://claude.ai/code/session_01GYo3UEfvsZpncagqb28Mbc
@dosubot dosubot Bot added the size:XL This PR changes 500-999 lines, ignoring generated files. label Jun 25, 2026
@vercel

vercel Bot commented Jun 25, 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 Jun 25, 2026 2:07pm

Request Review

@dosubot dosubot Bot added Bug Report Something isn't working documentation Improvements or additions to documentation labels Jun 25, 2026
@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

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: f7c18493-90a6-4b27-b535-795ceb8cd0c0

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 docs/hitl-fix

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.

@mmabrouk

Copy link
Copy Markdown
Member Author

🔸 Decision needed — HITL approval fix (F-024)

The bug. Claude + an Ask rule + a tool: the gate fires but the playground shows no Approve/Deny prompt — the tool resolves to ERROR "User refused permission to run tool" and the run auto-denies. Pi can't do HITL at all (only auto/deny, no ask).

Root cause (one line). The runner parks an ask gate by replying reject to the harness AND emitting the approval-request event; for Claude, reject produces a failed tool call that the egress projects as tool-output-error on the same toolCallId, overwriting the approval-requested part. The FE renderer, the egress, and the cross-turn resume are all already correct — only the runner's park reply poisons the wire.

Proposed fix. Runner: park WITHOUT sending reject (add an internal park outcome; end the turn with the tool pending), so the approval part survives to the FE. No wire change. The existing FE + egress + resume machinery then works as built.

Decision 1 — park mechanism.

  • A (recommended): add a runner-internal park outcome; on park, do not reply reject (or reply the harness's cancel/defer, never reject). Clean, no wire change.
  • B (fallback): keep reject, but suppress the resulting failed tool_result in the otel layer. Pattern-matchy; couples otel to the responder. Use only if A can't end the turn cleanly.

Decision 2 — Pi HITL.

  • Pi-1 (recommended now): hide/grey-out ask for Pi in the form. Pi declares permissions:false and never raises a gate, so offering ask would be a lie. Honest, tiny, ships with the Claude fix.
  • Pi-2 (follow-up): enforce ask for Pi's resolved tools via the relay (open-issues S5.2 — needs a turn-boundary park/resume in the relay). The only way Pi can actually gate tools. Larger; tracked separately.

The one real fork: how Pi HITL should behave (Pi-1 now vs commit to building Pi-2). The Claude fix is unambiguous (Approach A).

My recommendation: Approach A + Option Pi-1 now, with Pi-2 tracked as the real Pi HITL path.

One empirical unknown (settled by the live test in the plan): whether ending the parked turn without reject leaves Claude cleanly stopped, and whether a cold-replayed turn 2 re-raises the gate so the stored approval applies. If it doesn't, resume falls back to the runner replaying the approved tool result into the transcript.

Full design: docs/design/agent-workflows/projects/hitl-fix/ (research.md = the layer-by-layer trace; plan.md = the fix + test plan).

@mmabrouk mmabrouk added the needs-review Agent updated; awaiting Mahmoud's review label Jun 25, 2026

@mmabrouk mmabrouk left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

lgtm

@mmabrouk mmabrouk added lgtm This PR has been approved by a maintainer implementing Design approved; implementation queued/in progress (not awaiting review) and removed needs-review Agent updated; awaiting Mahmoud's review labels Jun 25, 2026
@mmabrouk
mmabrouk merged commit 1f7b6ac into big-agents Jun 25, 2026
5 checks passed
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 documentation Improvements or additions to documentation implementing Design approved; implementation queued/in progress (not awaiting review) lgtm This PR has been approved by a maintainer size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant