Skip to content

feat(ai-chat): tool approval continuation + autoContinue default true#919

Merged
threepointone merged 3 commits intomainfrom
autocontinue
Feb 16, 2026
Merged

feat(ai-chat): tool approval continuation + autoContinue default true#919
threepointone merged 3 commits intomainfrom
autocontinue

Conversation

@threepointone
Copy link
Contributor

@threepointone threepointone commented Feb 16, 2026

Summary

Two related changes to @cloudflare/ai-chat that improve the tool approval (needsApproval) and auto-continuation experience:

1. Tool approval auto-continuation (patch)

Ref: #918

The original issue reported a crash ("Tool invocation not found") that was already fixed in main — the applyChunkToParts handler no longer throws. However, the bonk analysis identified two real remaining gaps:

Missing continuation plumbing for CF_AGENT_TOOL_APPROVAL. When a tool with needsApproval: true is approved, _applyToolApproval updates the tool state to approval-responded and returns — but nothing triggers the LLM to continue. Compare this to CF_AGENT_TOOL_RESULT which has full autoContinue support (waits for active stream, calls onChatMessage, merges continuation into last assistant message). This PR adds the same continuation logic to CF_AGENT_TOOL_APPROVAL, gated behind autoContinue: true and approved: true.

Silent data loss for cross-message tool outputs. When a continuation stream emits tool-output-available for a tool call that lives in a previous assistant message (common in the approval flow), applyChunkToParts only searches the current streaming message's parts — the update is silently dropped. This PR adds a fallback in _streamSSEReply that uses _findAndUpdateToolPart (which searches across all messages with retry logic) when the tool part isn't found in the current message.

2. autoContinueAfterToolResult default falsetrue (minor)

Server-executed tools already auto-continue via streamText's multi-step. Client tools and approvals defaulting to false creates an asymmetry where the same conceptual flow (LLM calls tool → tool runs → LLM responds) behaves differently depending on where the tool executes. This made every developer using client tools or needsApproval discover and enable the option to get expected behavior.

Now autoContinueAfterToolResult defaults to true. The escape hatch is autoContinueAfterToolResult: false.

Changes

File What
src/types.ts Added optional autoContinue to CF_AGENT_TOOL_APPROVAL message type
src/index.ts Added continuation logic to approval handler + cross-message tool output fallback in _streamSSEReply
src/react.tsx Default flipped to true, sendToolApprovalToServer now passes autoContinue
src/tests/client-tool-duplicate-message.test.ts 4 new unit tests for approval continuation
src/react-tests/use-agent-chat.test.tsx 3 new React hook tests verifying default true sends correct wire values
e2e/client-tools.spec.ts 1 new e2e test for approval + autoContinue flow
README.md, docs/chat-agents.md, docs/client-tools-continuation.md Updated defaults and examples

Notes for reviewers

  • Wire protocol is backwards-compatible. autoContinue is optional on CF_AGENT_TOOL_APPROVAL. Clients that don't send it get the same behavior as before (no continuation). Existing server-side unit tests pass unchanged since they explicitly set autoContinue in WebSocket messages.
  • The approval continuation only fires when approved: true. Rejections (approved: false) never trigger continuation, even with autoContinue: true. This is intentional — a rejected tool shouldn't cause the LLM to continue as if the tool succeeded.
  • The cross-message fallback matches states broadly (input-available, input-streaming, approval-responded, approval-requested) to handle tool outputs arriving for tools in various lifecycle stages.
  • The default flip is a minor because it changes behavior for existing consumers who didn't set the option. The escape hatch is a single boolean. No examples or sites in the repo explicitly set autoContinueAfterToolResult, so they all silently pick up the better default.

Test plan

  • All 17 ai-chat unit tests pass (including 4 new approval continuation tests)
  • 3 new React hook tests verify default true sends autoContinue: true on tool results and approvals
  • 1 new e2e test verifies approval + autoContinue triggers continuation stream
  • Build passes
  • Typecheck passes
  • Lint clean

Made with Cursor

Add auto-continuation for tool approvals: CF_AGENT_TOOL_APPROVAL now accepts an optional autoContinue flag and, when approved and requested, triggers the agent to continue the conversation. The client hook forwards autoContinue when autoContinueAfterToolResult is enabled. Also add a cross-message fallback to handle tool-output-available / tool-output-error events that refer to tool calls in previous assistant messages (fixes silent data loss during continuation streams). Updates include type additions and multiple tests (e2e and unit) to cover approval/no-approval/autoContinue behaviors and a new changeset note.
Change the default behavior so autoContinueAfterToolResult is true. Updated useAgentChat implementation and JSDoc/default param, refreshed docs and README to reflect the new default, and added React tests verifying default=true, explicit false, and approvals behavior. Also added a changeset describing the minor version change. To restore previous behavior set autoContinueAfterToolResult: false in useAgentChat.
@changeset-bot
Copy link

changeset-bot bot commented Feb 16, 2026

🦋 Changeset detected

Latest commit: 0e4ad43

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@cloudflare/ai-chat Minor

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

@pkg-pr-new
Copy link

pkg-pr-new bot commented Feb 16, 2026

Open in StackBlitz

npm i https://pkg.pr.new/cloudflare/agents@919

commit: 0e4ad43

@threepointone
Copy link
Contributor Author

/bonk review this pr

@ask-bonk

This comment was marked as resolved.

The fallback now checks `foundInCurrentMessage` independently of
applyChunkToParts' return value, since it returns true for recognized
chunk types even when the target part isn't found.

Co-authored-by: Cursor <cursoragent@cursor.com>
@threepointone threepointone merged commit 6b6497c into main Feb 16, 2026
4 checks passed
@threepointone threepointone deleted the autocontinue branch February 16, 2026 08:12
@github-actions github-actions bot mentioned this pull request Feb 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant