Repository navigation
Version Packages - #1689
Merged
Merged
Version Packages#1689
Conversation
github-actions
Bot
force-pushed
the
changeset-release/main
branch
from
June 6, 2026 10:43
2b16606 to
f887a46
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
from
June 7, 2026 00:06
f887a46 to
2ce627e
Compare
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.
This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.
Releases
agents@0.14.4
Patch Changes
#1693
6496c80Thanks @threepointone! - FixAIChatAgentorphaned-stream recovery merging a new assistant turn into the previous assistant message (#1691).When a stream was interrupted before its final assistant message was persisted (Durable Object hibernation, deploy churn, isolate restart, reconnect), orphan recovery reconstructed the message from stored chunks. If those chunks carried no provider
start.messageId— the common case — recovery fell back to the last assistant message in history. That is correct for a continuation, but wrong for a normal new turn after a later user message: the recovered chunks for the new turn were appended onto the previous assistant message, corrupting both the persisted transcript and future model context.The assistant message id allocated when a stream starts is now persisted in the resumable-stream metadata (
ResumableStream.start()recordsmessage_id). When the reconstructed chunks carry no providerstart.messageId— the common case, and the one that triggered the bug — orphan recovery now uses this stored id instead of the last-assistant fallback, so a new turn becomes its own message and a continuation still merges into the message it was extending (it stored the cloned last-assistant id). A providerstart.messageId, when present, still wins, matching the live path which adopts it for new turns. Stream rows written before this release have no stored id and keep the previous behavior (provider id if present, otherwise the last assistant message). The metadata migration adds a single column, guarded by a schema check so it runs only once.This also fixes two related variants of the same corruption on the durable (
chatRecovery) continuation path:toolCallIdalready exists on the message.onChatRecoveryreturned{ persist: false }— recovery would "continue" it by cloning the previous assistant message, merging the new turn into it. Recovery now detects that the conversation leaf is still the user message (no partial to continue) and re-runs the turn fresh, so it becomes its own message.@cloudflare/thinkis unaffected — its session-tree recovery already allocates a distinct message id per orphan and never falls back to the last assistant message.@cloudflare/ai-chat@0.8.4
Patch Changes
#1690
f6a8bc4Thanks @threepointone! - Surface a terminal chat-recovery outcome to clients that reconnect after it ended (#1645).When a durable chat turn exhausted recovery (e.g. during a deploy/reconnect storm) while no client was connected, the terminal error was only broadcast transiently, so a client that connected afterward never learned the turn failed and the conversation appeared frozen. The outcome is now persisted durably and replayed over the resume handshake on the next reconnect —
STREAM_RESUMING→STREAM_RESUME_ACK→ terminal error frame on the resumed stream — which is the only path that surfaces asuseAgentChat'serroron the real client. (A bare replayed frame is dropped by the client because it never reaches a transport stream reader.) The record is cleared once a later turn supersedes it — on a new client request, and also when any later turn ends in a non-error outcome (completed or aborted, including turns driven server-side viasaveMessages), so a stale exhaustion can never replay after the conversation has recovered. Terminal non-exhaustion errors (e.g. a provider 500) are now durably recorded too, not just transiently broadcast, so they also replay to a reconnecting client.@cloudflare/thinkpreviously recorded the outcome durably but only replayed it as a bare on-connect frame (dropped by the client); it now uses the same resume-handshake delivery.#1693
6496c80Thanks @threepointone! - FixAIChatAgentorphaned-stream recovery merging a new assistant turn into the previous assistant message (#1691).When a stream was interrupted before its final assistant message was persisted (Durable Object hibernation, deploy churn, isolate restart, reconnect), orphan recovery reconstructed the message from stored chunks. If those chunks carried no provider
start.messageId— the common case — recovery fell back to the last assistant message in history. That is correct for a continuation, but wrong for a normal new turn after a later user message: the recovered chunks for the new turn were appended onto the previous assistant message, corrupting both the persisted transcript and future model context.The assistant message id allocated when a stream starts is now persisted in the resumable-stream metadata (
ResumableStream.start()recordsmessage_id). When the reconstructed chunks carry no providerstart.messageId— the common case, and the one that triggered the bug — orphan recovery now uses this stored id instead of the last-assistant fallback, so a new turn becomes its own message and a continuation still merges into the message it was extending (it stored the cloned last-assistant id). A providerstart.messageId, when present, still wins, matching the live path which adopts it for new turns. Stream rows written before this release have no stored id and keep the previous behavior (provider id if present, otherwise the last assistant message). The metadata migration adds a single column, guarded by a schema check so it runs only once.This also fixes two related variants of the same corruption on the durable (
chatRecovery) continuation path:toolCallIdalready exists on the message.onChatRecoveryreturned{ persist: false }— recovery would "continue" it by cloning the previous assistant message, merging the new turn into it. Recovery now detects that the conversation leaf is still the user message (no partial to continue) and re-runs the turn fresh, so it becomes its own message.@cloudflare/thinkis unaffected — its session-tree recovery already allocates a distinct message id per orphan and never falls back to the last assistant message.@cloudflare/think@0.8.5
Patch Changes
#1690
f6a8bc4Thanks @threepointone! - Surface a terminal chat-recovery outcome to clients that reconnect after it ended (#1645).When a durable chat turn exhausted recovery (e.g. during a deploy/reconnect storm) while no client was connected, the terminal error was only broadcast transiently, so a client that connected afterward never learned the turn failed and the conversation appeared frozen. The outcome is now persisted durably and replayed over the resume handshake on the next reconnect —
STREAM_RESUMING→STREAM_RESUME_ACK→ terminal error frame on the resumed stream — which is the only path that surfaces asuseAgentChat'serroron the real client. (A bare replayed frame is dropped by the client because it never reaches a transport stream reader.) The record is cleared once a later turn supersedes it — on a new client request, and also when any later turn ends in a non-error outcome (completed or aborted, including turns driven server-side viasaveMessages), so a stale exhaustion can never replay after the conversation has recovered. Terminal non-exhaustion errors (e.g. a provider 500) are now durably recorded too, not just transiently broadcast, so they also replay to a reconnecting client.@cloudflare/thinkpreviously recorded the outcome durably but only replayed it as a bare on-connect frame (dropped by the client); it now uses the same resume-handshake delivery.#1688
4d050c7Thanks @threepointone! - FixThinkWorkflowstep.prompt({ output })failing on Workers AI withAiError 5023: JSON Schema mode is not supported with stream mode.Structured workflow prompts previously requested output via the AI SDK
Output.objectpath, which streams a JSON Schemaresponse_format— rejected by some providers (notably Workers AI).step.prompt()now runs a full agentic turn that returns its structured result by calling an internalthink_final_answertool whose arguments match the schema. This uses ordinary tool calling, so it works across every provider Think supports (verified on Workers AI, OpenAI, and Anthropic), keeps Think's streaming engine (persistence, recovery, resumable streams), and lets the agent use its own tools across multiple steps before producing the final structured answer.The
think_final_answertool name is reserved; its call and result are stripped from the persisted conversation so the transcript and later turns do not see Think's internal plumbing.