Repository navigation
fix(think,agents): keep a restart-interrupted regeneration on its own branch - #2417
Merged
Merged
Conversation
… branch After a restart, orphan recovery appended a regeneration's partial answer under the latest leaf, the response it was replacing, and the continuation then extended it with that response still in the prompt. Record the turn's parent message on the resumable stream and append the recovered partial under it. Co-authored-by: Cursor <cursoragent@cursor.com>
🦋 Changeset detectedLatest commit: e382893 The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
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
|
✅ agents import sizes: no significant changes ( |
agents
@cloudflare/ai-chat
@cloudflare/codemode
hono-agents
@cloudflare/shell
@cloudflare/think
@cloudflare/voice
@cloudflare/worker-bundler
commit: |
Merged
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.
Follow-up to #2413 (#2028). That PR noted one gap: a regeneration interrupted after partial output takes the "continue" recovery path. We had described that as continuing on the right branch instead of restarting. Writing a test for it showed a real bug instead.
Problem
When a restart (Durable Object eviction or a deploy) interrupts a regeneration that has already streamed part of its answer:
persistReconstructedOrphanthenappendMessage(message)), so it lands under the latest leaf, which is the response being replaced. The tree becomesuser, old answer, new partialinstead of the new partial sitting beside the old answer.user,assistant: <old answer>,assistant: <new partial>, followed by "continue". The replaced answer is back in the context, which is exactly what Think regeneration includes the previous response in the model prompt #2028 fixed for live turns.The live interruption path (stall or transient error) already passes
branchParentIdintopersistPartial(#2413). Only the restart paths went wrong: fiber recovery, and a client's resume ACK after hibernation. Neither has the turn's fiber snapshot where the orphan is persisted.Fix
ResumableStream.start()accepts an optionalparentMessageId, stored in the stream row's chat metadata next tomessageIdandoriginMessageIds.getStreamParentMessageId(streamId)reads it back._streamResultrecords the turn'sparentId(set for regenerations) when it opens the stream._persistOrphanedStreamappends the reconstructed message under that parent. Both orphan paths go through it. On anagentsrelease without the getter it falls back to the current behavior.Kept the continue behavior rather than restarting the answer: the user has already watched the partial answer stream, and every other interrupted turn keeps and continues its partial.
Tests
continues a regeneration interrupted after partial output on its new branch (#2028): a restored streaming row with a recorded parent. It asserts the partial lands besidea-previous, the old answer is untouched, and the continuation prompt isuserthenassistant: New partial, without the old answer. Mutation check: disabling the parent lookup fails it.keeps a recovered partial with no recorded parent on the latest leaf: turns that do not branch are unchanged.agents: the parent survivesrestore(), and it is null for a non-branching stream or a missing row.pnpm run check.