fix(forwarder): preserve Cursor fork context

Store checkpoint turns as validated blobs and restore prefetched parent turns so forked conversations retain their replay history and rewind prefix.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
DedSecer
2026-08-01 10:51:23 +08:00
co-authored by Cursor
parent 00f52166b2
commit 14b286a466
14 changed files with 1979 additions and 304 deletions
+7
View File
@@ -23,6 +23,7 @@ const (
TurnPhaseWaitingExternal TurnPhase = "waiting_external"
TurnPhaseAwaitingUser TurnPhase = "awaiting_user"
TurnPhaseCompacting TurnPhase = "compacting"
TurnPhaseCheckpointing TurnPhase = "checkpointing"
TurnPhaseCompleted TurnPhase = "completed"
TurnPhaseFailed TurnPhase = "failed"
TurnPhaseCanceled TurnPhase = "canceled"
@@ -66,6 +67,7 @@ const (
streamTimerNonStreamingRecovery streamTimerKind = "non_streaming_recovery"
streamTimerShellForeground streamTimerKind = "shell_foreground"
streamTimerShellTransportClose streamTimerKind = "shell_transport_close"
streamTimerCheckpointBlobs streamTimerKind = "checkpoint_blobs"
streamTimerOrphanCancel streamTimerKind = "orphan_cancel"
)
@@ -318,6 +320,9 @@ func (service *Service) handleStreamCommand(stream *ActiveStream, command stream
case streamCommandCancel:
return service.handleCancelIntent(command.Intent)
case streamCommandMetadata:
if strings.TrimSpace(command.Intent.Kind) == "kv_result" {
return service.handleCheckpointBlobResult(stream, command.Intent.KVClientMessage)
}
return service.handleMetadataIntent(command.Intent)
case streamCommandExecResult:
return service.handleExecResult(command.Intent)
@@ -1003,6 +1008,8 @@ func (service *Service) handleTimerEvent(stream *ActiveStream, payload *streamTi
return nil
}
return service.recoverShellWithoutTerminal(stream, current, shellRecoveryReasonTransportClosed)
case streamTimerCheckpointBlobs:
return service.handleCheckpointBlobTimeout(stream)
case streamTimerOrphanCancel:
stream.mu.Lock()
subscriberCount := len(stream.Subscribers)