feat(ai-chat): support addToolOutput for approval states and custom denial messages#967
Open
threepointone wants to merge 5 commits intomainfrom
Open
feat(ai-chat): support addToolOutput for approval states and custom denial messages#967threepointone wants to merge 5 commits intomainfrom
threepointone wants to merge 5 commits intomainfrom
Conversation
Allow client-side tool outputs to signal denials/errors and work for approval flows. addToolOutput now supports a state override ("output-error") and errorText, and can be used for tools in approval-requested/approval-responded states (not just input-available). The agent core applies output-error state and propagates errorText, and tool approval rejections (approved: false) now auto-continue when autoContinue is set so the LLM can react to the denial. Updated hooks/types/react logic to send and handle the new fields, updated UI examples/docs to render denied/error states, and added tests covering the new behaviors and edge cases.
🦋 Changeset detectedLatest commit: 7575a4f The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Contributor
Author
|
/bonk review this PR |
commit: |
Include an explicit approval.id ("approval-denied-guard") in the approval object within client-tool-duplicate-message.test.ts. This aligns the test data with the expected shape (approval id required) and prevents schema/guard-related failures during test assertions.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
Contributor
Author
|
/bonk try reviewing again |
Co-authored-by: threepointone <threepointone@users.noreply.github.com>
This comment was marked as resolved.
This comment was marked as resolved.
Treat tool results with state "output-error" as deliberate client denials: set autoContinue to false for these cases and avoid storing them in clientToolResults. A comment clarifies that addToolApprovalResponse still performs the standard approve/reject auto-continue flow, and users can call sendMessage() if they want the LLM to respond to an output-error denial. This prevents unintended automatic continuation after explicit rejections.
Contributor
Author
|
/bonk please review again |
Contributor
Author
|
/bonk hey buddy, please review my PR |
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
Update documentation and code comments to make auto-continue semantics explicit: addToolApprovalResponse (including rejections) auto-continues when autoContinueAfterToolResult is enabled, while addToolOutput with state:"output-error" does not auto-continue and requires calling sendMessage() to proceed. Aligns react.tsx comments with the docs for clearer developer guidance.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Follow-up to #956 (which fixed #955). This PR addresses the remaining two issues from #955:
addToolOutputnow works for tools in approval states —_applyToolResultacceptsapproval-requestedandapproval-respondedstates, not justinput-available. Users can provide custom tool results forneedsApprovaltools.Custom denial messages via
output-error—addToolOutputnow acceptsstate: "output-error"anderrorText, enabling the Vercel AI SDK recommended pattern for client-side tool denial with a custom message (instead of the generic "Tool execution denied.").Rejections auto-continue — Tool approval rejections now auto-continue the conversation (when
autoContinueAfterToolResultis enabled), so the LLM sees thetool_resultand responds naturally.Example
What changed
SDK (
packages/ai-chat/)src/index.ts_applyToolResult()— expandedmatchStatesto includeapproval-requestedandapproval-responded; addedoverrideStateanderrorTextparams foroutput-errorCF_AGENT_TOOL_RESULThandler — extracts and forwardsstate/errorTextfrom the wire messageCF_AGENT_TOOL_APPROVALhandler — removedapprovedguard from auto-continue; rejections now continue the conversation_resolveMessageForToolMerge()— addedoutput-errorto dedup state checksrc/types.ts— added optionalstateanderrorTextfields toCF_AGENT_TOOL_RESULTwire messagesrc/react.tsxAddToolOutputOptions— moved beforeOnToolCallCallbackas single source of truth; addedstateanderrorTextfields;outputmade optionalOnToolCallCallback— referencesAddToolOutputOptionsviaOmit<..., "toolName">sendToolOutputToServer— forwardsstate/errorText; suppressesautoContinueforoutput-erroraddToolOutputimplementations updated to use shared type and pass through new fieldsTests (
packages/ai-chat/src/tests/)convertToModelMessagesintegrationDocs
docs/human-in-the-loop.md— addedoutput-deniedUI handling in client example; new "Custom denial messages withaddToolOutput" section; documented auto-continue behavior for rejectionsdocs/chat-agents.md— fixed 4 pre-existing bugs:approval-required→approval-requested,part.type === "tool"→isToolUIPart(),part.toolName→getToolName(),id: part.toolCallId→id: part.approval?.iddocs/client-tools-continuation.md— addedoutput-errordenial snippetExamples
examples/playground/src/demos/ai/ToolsDemo.tsx— "Denied" and "Error" badges foroutput-denied/output-errorstatesexamples/ai-chat/src/client.tsx—output-deniedrendering with "Denied" badgeNotes for reviewers
Start with
_applyToolResultinsrc/index.ts— the core change is wideningmatchStatesand adding theoutput-errorcode path.Auto-continue for rejections (
src/index.tsline ~634) — the guard changed fromapplied && approved && autoContinuetoapplied && autoContinue. This is intentional: now thatoutput-deniedproduces a propertool_result(from fix(ai-chat): emit output-denied state for rejected tool approvals #956), the LLM should see the denial and respond. Without this, rejections silently dead-end the conversation.sendToolOutputToServersuppressesautoContinueforoutput-error(react.tsxline ~805) — when the client explicitly sendsoutput-error, we setautoContinue: falseso the server does not auto-continue. This is the opposite of the approval flow auto-continue change above. The difference:output-errorviaaddToolOutputis a deliberate client action where the client controls the flow, whileaddToolApprovalResponseis the standard approve/reject path where auto-continue is expected.Not a breaking change — all new fields are optional; existing callers get identical behavior. The auto-continue change for rejections is a behavior change but was previously a bug (rejections dead-ended).
Doc fix in
chat-agents.mdis unrelated to this PR but fixes real bugs (wrong state nameapproval-required, wrong field for approval ID) that would confuse users copy-pasting the example.Test plan
Made with Cursor