Skip to content

Fix stop() for tool continuation streams; fix orphaned continuation hibernation#1234

Merged
threepointone merged 2 commits intomainfrom
fix/issue-1233-stop-tool-continuation
Mar 31, 2026
Merged

Fix stop() for tool continuation streams; fix orphaned continuation hibernation#1234
threepointone merged 2 commits intomainfrom
fix/issue-1233-stop-tool-continuation

Conversation

@whoiskatrin
Copy link
Copy Markdown
Contributor

@whoiskatrin whoiskatrin commented Mar 30, 2026

Summary

  • fix useAgentChat().stop() for client-side tool continuations by cancelling the active server continuation request id instead of only aborting the local AI SDK response
  • teach WebSocketChatTransport to track and cancel an active tool continuation stream after the resume handshake attaches it to the server request id
  • handle stop during the handshake window (before STREAM_RESUMING arrives) by closing the stream and clearing resolvers so late resumes are ignored
  • use try/finally in the stop wrapper so the server-side cancel fires even if the AI SDK's stop() throws
  • fix _persistOrphanedStream to handle continuation streams where messageId was stripped (ai-chat: tool continuation sends new messageId in start chunk, causing duplicate assistant message #1229) — fall back to the last assistant message and merge parts/metadata instead of creating a duplicate
  • add React, transport, and server-side tests plus a patch changeset for @cloudflare/ai-chat

Closes #1233

Testing

  • npm run test (392 worker tests including new transport abort + orphaned continuation tests)
  • npm run test:react (77 React tests including new stop-during-continuation test)
  • npx tsc --noEmit -p packages/ai-chat/src/tests/tsconfig.json

Reviewer Notes

  • the root problem is the tool-continuation path, not normal sendMessage(): continuations go through resumeStream() / reconnectToStream(), and AI SDK does not provide an abort signal to that transport path. That means stop() aborted local client state but never sent CF_AGENT_CHAT_REQUEST_CANCEL for the server continuation request.
  • the server request id is only known after CF_AGENT_STREAM_RESUMING, so the transport now captures that id and exposes a narrow abortActiveToolContinuation() helper. useAgentChat.stop() calls the normal AI SDK stop first, then invokes that transport helper.
  • pre-handshake abort: if stop is called before STREAM_RESUMING arrives (requestId is still null), the stream is closed immediately and resolvers are cleared so late resumes become no-ops.
  • this intentionally keeps the stop fix in @cloudflare/ai-chat client code. There is no server-side protocol change and no change to the standard request-cancel path for normal submits.
  • the _persistOrphanedStream fix is a separate hibernation-safety issue found during review: ai-chat: tool continuation sends new messageId in start chunk, causing duplicate assistant message #1229's messageId stripping broke orphaned stream recovery for continuations, causing duplicate assistant messages after hibernation. The fix falls back to the last assistant message ID and merges existing parts with stream parts.

Open with Devin

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 30, 2026

🦋 Changeset detected

Latest commit: 8320dd1

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 Patch

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
Copy Markdown

pkg-pr-new bot commented Mar 30, 2026

Open in StackBlitz

agents

npm i https://pkg.pr.new/agents@1234

@cloudflare/ai-chat

npm i https://pkg.pr.new/@cloudflare/ai-chat@1234

@cloudflare/codemode

npm i https://pkg.pr.new/@cloudflare/codemode@1234

hono-agents

npm i https://pkg.pr.new/hono-agents@1234

@cloudflare/shell

npm i https://pkg.pr.new/@cloudflare/shell@1234

@cloudflare/think

npm i https://pkg.pr.new/@cloudflare/think@1234

@cloudflare/voice

npm i https://pkg.pr.new/@cloudflare/voice@1234

@cloudflare/worker-bundler

npm i https://pkg.pr.new/@cloudflare/worker-bundler@1234

commit: 8320dd1

whoiskatrin and others added 2 commits March 31, 2026 15:00
Always call transport.abortActiveToolContinuation when stopping (wrap stop() in finally) and enhance WebSocket transport abort logic to handle pre-handshake aborts and keep request IDs for server cleanup. Adds an abortRequested flag and closes the stream if the handshake hasn't completed so late STREAM_RESUMING is ignored, and keeps the requestId in activeIds until server signals done. Also adds tests covering: keeping requestId for cleanup, abort semantics when no continuation or already completed, and abort-before-handshake behavior to prevent late resumes.
@threepointone threepointone force-pushed the fix/issue-1233-stop-tool-continuation branch from dca7901 to 8320dd1 Compare March 31, 2026 15:11
@threepointone threepointone changed the title Fix stop() for tool continuation streams Fix stop() for tool continuation streams; fix orphaned continuation hibernation Mar 31, 2026
@threepointone threepointone marked this pull request as ready for review March 31, 2026 15:15
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 5 additional findings.

Open in Devin Review

@threepointone threepointone merged commit 809f4dd into main Mar 31, 2026
2 checks passed
@threepointone threepointone deleted the fix/issue-1233-stop-tool-continuation branch March 31, 2026 15:25
@github-actions github-actions bot mentioned this pull request Mar 31, 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.

sdkStop() doesn't cancel tool continuation stream — request ID mismatch

2 participants