Repository navigation
fix(ai-sandbox): keep the first host's transcript on takeover #2108
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| --- | ||
| '@tanstack/ai-sandbox': patch | ||
| '@tanstack/ai-claude-code': patch | ||
| '@tanstack/ai-codex': patch | ||
| '@tanstack/ai-grok-build': patch | ||
| --- | ||
|
|
||
| Keep text and tool calls the first host already delivered in the saved transcript after a sandbox takeover. The event log still stores that prefix once. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -44,6 +44,7 @@ import { computeWorkspaceHash } from './key' | |
| import { buildFileHookEvent, resolveFileEvents } from './file-diff' | ||
| import { ProjectionCapability, provideWorkspaceProjection } from './projection' | ||
| import { resolveAllSecrets, resolveSecret } from './secrets' | ||
| import { isStoredReplayChunk } from './align' | ||
| import { | ||
| createToolHistoryRecorder, | ||
| stripObservedToolCalls, | ||
|
|
@@ -1027,11 +1028,12 @@ export function withSandbox<TOffset extends string = string>( | |
| runState.get(ctx)?.toolHistory.reconcile(ctx) | ||
| }, | ||
|
|
||
| // Record the harness's own tool calls as transcript messages. Observe only: | ||
| // returning nothing passes every chunk through untouched. | ||
| // Record the harness's own tool calls as transcript messages. A stored | ||
| // replay chunk is recorded, then dropped: the event log already has it. | ||
| async onChunk(ctx, chunk) { | ||
| const state = runState.get(ctx) | ||
| state?.toolHistory.observe(chunk, ctx) | ||
| if (isStoredReplayChunk(chunk)) return null | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| if ( | ||
| state && | ||
| chunk.type === 'RUN_FINISHED' && | ||
|
|
@@ -1041,6 +1043,7 @@ export function withSandbox<TOffset extends string = string>( | |
| await drainWatcher(state, 'pause') | ||
| await stopSnapshotLease(state, { closePortable: true }) | ||
| } | ||
| return undefined | ||
| }, | ||
|
|
||
| async onFinish(ctx) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Script executed:
Repository: TanStack/ai
Length of output: 14497
Script executed:
Repository: TanStack/ai
Length of output: 12916
Script executed:
Repository: TanStack/ai
Length of output: 42565
Script executed:
Repository: TanStack/ai
Length of output: 21114
Script executed:
Repository: TanStack/ai
Length of output: 29062
Script executed:
Repository: TanStack/ai
Length of output: 4737
Script executed:
Repository: TanStack/ai
Length of output: 11890
Script executed:
Repository: TanStack/ai
Length of output: 6527
Preserve prefix suppression for direct attach streams.
When an attach consumer forwards
chatStream()withoutwithSandboxorpipeToRunLog, it receives the stored prefix again. An SSE client can therefore receive duplicate text or tool calls. Make transcript replay opt-in for the chat engine while keeping direct attach streams prefix-free.