Skip to content

[fix] Wait for a request's arguments before calling it malformed [AGE-4095] - #6064

Draft
ashrafchowdury wants to merge 1 commit into
mainfrom
fix/age-4095-elicitation-input-not-final
Draft

[fix] Wait for a request's arguments before calling it malformed [AGE-4095]#6064
ashrafchowdury wants to merge 1 commit into
mainfrom
fix/age-4095-elicitation-input-not-final

Conversation

@ashrafchowdury

Copy link
Copy Markdown
Contributor

Context

When an agent asked a question mid-run, the card sometimes rendered as an amber "Couldn't render this request." chip instead of the form. The question was lost, the agent carried on as if it had been answered, and a reload replayed the same chip because the failure was already saved.

The recorded error said payload is not an object, yet the saved input held a perfectly good payload. Both were true because the parse ran before the arguments arrived.

The runner surfaces a tool call before its arguments exist and fills them in afterwards, and it does so on purpose (services/runner/src/tracing/otel.ts: the call "MUST surface before any approval/result for this id", so the args are refreshed later, "never by delaying this"). The args then land incrementally, as a growing partial parse. So a live request_input part passes through a sequence of shapes:

null                                     -> "payload is not an object"
{}                                       -> "missing message"
{message: "Which repository should I re"} -> "missing requestedSchema"
{message, requestedSchema: {...}}         -> the real payload

ElicitationWidget validated whichever shape it happened to mount on and auto-settled a permanent error. Whether it caught a placeholder depended on where useChat's 50ms throttle boundary fell against the stream, which is why the same session could fail once and render fine the next time.

Changes

The widget now judges the payload only once the turn stops streaming, which is the point at which the args are final. Both the degradation settle and the parked "needs attention" notice wait for it.

A narrower check does not work. Testing input != null misses the {} announce, and testing state === "input-available" misses every partial, because the part is already input-available from the first frame onward.

turnStreaming threads from AgentMessage (which already held isStreaming) through ClientToolPart to the widget, matching how the sibling degradedEarlierInTurn flag is already passed. The default is safe: a caller that omits it degrades exactly as before, so nothing can hang.

This also brings elicitation in line with a rule the codebase already had. UnhandledClientTool can only mount when the turn is not streaming, so it never auto-settles mid-stream. Elicitation was the exception.

A genuinely malformed payload still degrades the moment the turn parks.

Tests / notes

  • New ElicitationWidget.degradation.test.tsx drives the real frame sequence above through the real parser (only the chrome is mocked) and pins that the widget waits. I confirmed it is not vacuous: with the gate disabled, the three cases covering the fix fail and the two covering unchanged behaviour still pass.
  • pnpm vitest run src/components/AgentChatSlice: 490 passed, 1 skipped. pnpm lint-fix clean.
  • No runner or SDK change. The late arguments are deliberate, the tracing layer cannot know a call is a client tool when it announces it, and both client_tool emit sites already carry complete args. The bug was the frontend reading "not finished" as "malformed".
  • This stops new occurrences only. Sessions that already degraded have the error saved in their interaction row, so they replay the same chip.
  • Known gap, not fixed here: if two genuinely malformed elicitations park in the same commit, both settle instead of one settling and one parking, because degradedEarlierInTurn only flips once a part carries the error text. That is two error settles, not a resume loop, and fixing it properly would pull payload validation up into AgentMessage.
  • ConnectToolWidget reads meta.input under the same assumption and does not take this flag. It degrades gracefully (a briefly wrong label, no auto-settle), so it is not broken today. It is the second widget that would want this, which is when moving inputFinal onto ClientToolMeta starts to pay off.

What to QA

  • Open the templates gallery, pick the PR reviewer template, and let the builder agent run its first turn without typing anything. The card after discover_tools shows the stepper form ("1. GitHub repository", "Review posture", "Risk focus"), never an amber "Couldn't render this request." chip.
  • Repeat that on a few fresh sessions. The bug was timing dependent, so one clean run is not proof.
  • Answer the form and continue. The agent receives the answers and the card collapses to a single line showing what you submitted.
  • Click Decline on a question, then Dismiss on another. Each settles to its own chip and the run resumes.
  • Regression: a connect request (an agent asking for a GitHub connection) still renders its Connect / Not now row and completes.

…rmed

The runner surfaces a tool call before its args exist and refreshes them
incrementally, so a request_input part passes through null, {} and partial
payloads before the real one arrives. ElicitationWidget validated whatever it
saw at mount and auto-settled a permanent degradation error, so a valid
question rendered as "Couldn't render this request." and was lost (#5949).

Gate the degradation settle and the parked notice on the turn having stopped
streaming, which is the point at which the args are final. A genuinely
malformed payload still degrades as soon as the turn parks, so nothing hangs.
This matches UnhandledClientTool, which already refuses to auto-settle while
the turn is streaming.
@vercel

vercel Bot commented Aug 16, 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 16, 2026 2:50pm

Request Review

@linear-code

linear-code Bot commented Aug 16, 2026

Copy link
Copy Markdown

AGE-4095

@dosubot dosubot Bot added size:S This PR changes 10-29 lines, ignoring generated files. bug frontend tests labels Aug 16, 2026
@coderabbitai

coderabbitai Bot commented Aug 16, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 19fb4cf7-a8a6-46de-9f4f-e9053bcc9d8d

📥 Commits

Reviewing files that changed from the base of the PR and between 0af145e and fe6c4d5.

📒 Files selected for processing (5)
  • web/oss/src/components/AgentChatSlice/components/AgentMessage.tsx
  • web/oss/src/components/AgentChatSlice/components/clientTools/ClientToolPart.tsx
  • web/oss/src/components/AgentChatSlice/components/clientTools/ElicitationWidget.degradation.test.tsx
  • web/oss/src/components/AgentChatSlice/components/clientTools/ElicitationWidget.tsx
  • web/oss/src/components/AgentChatSlice/components/clientTools/types.ts

Included review availability: Your plan includes up to 8 reviews per rolling hour; 7 remain after this review.


📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of streamed input in interactive elicitation prompts.
    • Incomplete or malformed requests now wait until streaming finishes before showing errors or settling.
    • Prevented previously degraded prompts from retrying unnecessarily.
    • Added clearer handling for incomplete payloads and parked prompt states.

Walkthrough

turnStreaming now flows from AgentMessage to client-tool handlers. ElicitationWidget defers malformed-input degradation and settlement until streamed input is final. Tests cover incremental, complete, malformed, incomplete, and parked states.

Changes

Streaming elicitation handling

Layer / File(s) Summary
Streaming state propagation
web/oss/src/components/AgentChatSlice/components/AgentMessage.tsx, web/oss/src/components/AgentChatSlice/components/clientTools/ClientToolPart.tsx, web/oss/src/components/AgentChatSlice/components/clientTools/types.ts
The client-tool handler contract accepts optional turnStreaming. AgentMessage passes the state to ClientToolPart, which forwards it to the resolved handler.
Deferred elicitation degradation
web/oss/src/components/AgentChatSlice/components/clientTools/ElicitationWidget.tsx, web/oss/src/components/AgentChatSlice/components/clientTools/ElicitationWidget.degradation.test.tsx
ElicitationWidget waits for final input before degrading malformed payloads or settling errors. Tests cover streamed, complete, malformed, incomplete, and parked payloads.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to fe6c4

This localized change defers malformed-request handling until request arguments are complete, preventing valid forms from being replaced by error chips while preserving existing malformed-request behavior; no actionable merge-blocking risk remains after normal checks and review.

Sequence Diagram(s)

sequenceDiagram
  participant AgentMessage
  participant ClientToolPart
  participant ElicitationWidget
  participant Settlement
  AgentMessage->>ClientToolPart: Pass turnStreaming
  ClientToolPart->>ElicitationWidget: Forward streaming state and input
  ElicitationWidget->>ElicitationWidget: Wait for final input
  ElicitationWidget->>Settlement: Settle degradation after streaming ends
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the fix: waiting for request arguments before marking them malformed.
Description check ✅ Passed The description directly explains the streaming-argument bug, implementation, tests, and expected behavior.
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.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/age-4095-elicitation-input-not-final

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.

@github-actions

github-actions Bot commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Railway Preview Environment

Status Destroyed (PR converted to draft)

Updated at 2026-08-16T16:00:45.620Z

@ashrafchowdury
ashrafchowdury marked this pull request as draft August 16, 2026 16:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug frontend size:S This PR changes 10-29 lines, ignoring generated files. tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant