- MCP Server ToolsUpdated
- Managed MCP with chat()Updated
- Manual MCPUpdated
- MCP Type GenerationUpdated
- MCP Client InputUpdated
- MCP Server Tools: AdvancedNew
- MCP EventsNew
- MCP AppsUpdated
- Serve Tools over HTTPUpdated
- Serve Resources and PromptsUpdated
- Ask for InputUpdated
- Draft Text from a ToolUpdated
- MCP Server TasksUpdated
- MCP Server AuthUpdated
- MCP Server SessionsUpdated
- MCP Server on stdioUpdated
Persistence (Advanced)
- GenerationsUpdated
- Realtime Voice ChatUpdated
- Text-to-SpeechUpdated
- TranscriptionUpdated
- Transcription: AdvancedNew
- Voice CreationUpdated
- Audio RecordingUpdated
- Audio GenerationUpdated
- Image GenerationUpdated
- Image Generation: AdvancedNew
- Video GenerationUpdated
- Video Generation: AdvancedNew
- Live GenerationUpdated
- World GenerationUpdated
- Generation HooksUpdated
- OverviewUpdated
- Quick StartUpdated
- ProvidersUpdated
- HarnessesUpdated
- Harness AuthUpdated
- WorkspaceUpdated
- ToolsUpdated
- PolicyUpdated
- Lifecycle & SnapshotsUpdated
- Portable SnapshotsUpdated
- Keep Files After ReloadUpdated
- Save a Named VersionUpdated
- Branch From a VersionUpdated
- Send a Frozen FileUpdated
- Let the Agent Save and ForkUpdated
- Pick Which Files to KeepUpdated
- What a Snapshot StoresUpdated
- Instance DurabilityUpdated
- Durable RunsUpdated
- EventsUpdated
Sandboxes (Advanced)
- Runtime ContextUpdated
- Bring Your Own KeyUpdated
- Debug LoggingUpdated
- Multimodal ContentUpdated
- Files APIUpdated
- Per-Model Type SafetyUpdated
- Runtime Adapter SwitchingUpdated
- Tree-ShakingUpdated
- Extend AdapterUpdated
- Extend Adapter: AdvancedNew
- Typed Pre-Configured OptionsUpdated
- Test with a Fake ModelUpdated
- Prompt CachingUpdated
- Mid-Conversation ChangesUpdated
- Approval Flow ProcessingUpdated
Let the Agent Save and Fork
You want the agent to mark a version or open a new direction. The route already knows threadId and runId. createSnapshotTools turns those values into host tools that you spread into chat().
The model can pass a label or a checkpoint id on this thread. It cannot pass a thread id. Your factory mints every new thread id.
import { chat } from '@tanstack/ai'
import { grokBuildText } from '@tanstack/ai-grok-build'
import { withPersistence } from '@tanstack/ai-persistence'
import { createSnapshotTools, withSandbox } from '@tanstack/ai-sandbox'
import { instances, sandbox, snapshots } from './sandbox-server'
export function POST(threadId: string, runId: string) {
return chat({
threadId,
runId,
adapter: grokBuildText('composer-2.5'),
messages: [{ role: 'user', content: 'Save this, then try a dark theme.' }],
tools: [
...createSnapshotTools(snapshots, {
threadId,
runId,
createThreadId: () => crypto.randomUUID(),
onForked({ destinationThreadId }) {
void destinationThreadId
},
}),
],
middleware: [
withPersistence(snapshots.persistence),
withSandbox(sandbox, { instances, snapshots }),
],
})
}The tools run on the server. In a sandbox chat they are bridged back to the host. See Tools.
What each tool does#
- save_sandbox_snapshot: saves the live sandbox for the bound thread. The model passes label only.
- fork_sandbox_snapshot: copies one checkpoint into a new empty thread. The model can pass checkpointId. When it omits that id, the tool copies the latest checkpoint. createThreadId() sets the destination thread id.
- read_sandbox_snapshot_artifact: returns artifact metadata for a checkpoint on this thread. It does not return file bytes. Serve bytes from Send a Frozen File.
onForked runs after a successful fork. If you want the new branch to work right away, start chat() on destinationThreadId in that callback.
When save and fork run#
save_sandbox_snapshot takes the writer lease for this thread. If this chat() already holds that lease through portable snapshots, the save fails with SANDBOX_SNAPSHOT_WRITER_CONFLICT. Save from a planner thread, or after this run ends.
fork_sandbox_snapshot takes the writer lease on the new thread. A fork during this run can succeed. It copies a saved checkpoint. It does not copy files the agent is still writing.
See Keep Files After Reload to create the snapshots object. See Save a Named Version and Branch From a Version for routes that you call yourself.