본문으로 건너뛰기

샌드박스 인스턴스 영속성

에이전트가 둘 이상의 서버 인스턴스 뒤에서 또는 엣지에서 실행됩니다. 실행이 샌드박스를 시작하고, 저장소를 복제하고, 의존성을 설치한 뒤 작업을 수행합니다. 같은 스레드의 다음 실행은 해당 샌드박스를 다시 사용해야 합니다. 하지만 매번 새 샌드박스를 만들어 콜드 스타트 비용을 다시 전부 부담하게 됩니다.

Lifecycle & Snapshots는 이미 재개 방법을 알고 있지만, 관리 정보가 메모리에만 있으므로 하나의 프로세스 안에서만 유지됩니다. 실행이 다른 복제본(또는 새 격리 환경)에 배치되는 순간 해당 인스턴스는 샌드박스를 본 적이 없으므로 샌드박스를 다시 만듭니다.

샌드박스 인스턴스 영속성은 채팅 기록이 아니라 런타임 배치에 관한 것입니다. 이는 @tanstack/ai-persistence(트랜스크립트 / 실행 / 인터럽트)와 독립적으로 @tanstack/ai-sandbox가 소유합니다. 채팅 저장소와 데이터베이스를 공유할 수 있지만, 별도의 미들웨어를 조합합니다.

인스턴스 영속성은 작업 공간을 애플리케이션 저장소로 복사하지 않습니다. 새 샌드박스에서 완료된 파일, 아티팩트, 저장된 대화를 다시 만들어야 할 때는 Keep Files After Reload를 사용합니다.

이는 에이전트의 출력도 아닙니다. 이 페이지에서는 프로세스 간에 샌드박스를 찾을 수 있도록 하고, 프로세스 간에 실행의 이벤트 스트림을 읽을 수 있도록 하는 기능은 The Run Journal에서 다룹니다. 두 기능은 함께 조합됩니다. 재개된 샌드박스에는 해당 샌드박스에서 실행된 모든 영속적 실행의 저널이 /tmp/tanstack-runs 아래에 여전히 보관됩니다. (영속적이라는 것은 withSandboxrunsdurability가 모두 전달되었다는 뜻입니다. 저널링은 선택 사항이며, 이를 사용하지 않은 실행은 해당 위치에 파일을 남기지 않습니다.)

구성 요소는 두 가지입니다.

  • SandboxInstanceStore: 복합 키 → 프로바이더 샌드박스 ID(및 선택적 스냅샷)의 맵입니다. 영속적이며 인스턴스 간에 공유됩니다.
  • LockStore (@tanstack/ai/locks에서 제공): 재개 또는 생성 과정의 상호 배제를 담당합니다. 다중 인스턴스 환경에는 분산 잠금이 필요합니다. Locks를 참조하세요.

연결하기

저장소를 withSandbox에 전달합니다. 다른 미들웨어도 잠금을 공유할 수 있으므로 잠금은 별도의 미들웨어로 구성하며, withSandbox 앞에 와야 합니다.

import { chat } from '@tanstack/ai'
import { InMemoryLockStore, withLocks } from '@tanstack/ai/locks'
import { grokBuildText } from '@tanstack/ai-grok-build'
import {
InMemorySandboxInstanceStore,
defineSandbox,
defineWorkspace,
withSandbox,
} from '@tanstack/ai-sandbox'
import type { ModelMessage } from '@tanstack/ai'

// Single-process: in-memory is fine for local dev.
// Multi-instance: your durable SandboxInstanceStore + distributed LockStore.
const instanceStore = new InMemorySandboxInstanceStore()
const messages: Array<ModelMessage> = [{ role: 'user', content: 'hi' }]

const sandbox = defineSandbox({
id: 'repo',
provider: {
name: 'example',
capabilities: () => ({
fs: true,
exec: true,
env: true,
ports: false,
backgroundProcesses: false,
writableStdin: false,
killableProcesses: false,
snapshots: false,
networkPolicy: false,
durableFilesystem: false,
fork: false,
}),
create: () => {
throw new Error('example provider: wire a real SandboxProvider')
},
resume: () => Promise.resolve(null),
destroy: () => Promise.resolve(),
},
workspace: defineWorkspace({ source: { type: 'none' } }),
})

chat({
adapter: grokBuildText('grok-build'),
messages,
middleware: [
withLocks(new InMemoryLockStore()),
withSandbox(sandbox, { instances: instanceStore }),
],
})

reuse: 'thread'(기본값)을 사용하면 첫 실행에서 인스턴스를 생성하고 기록합니다. 저장소와 잠금이 프로세스 간에 공유될 때 같은 threadId의 이후 실행은 해당 인스턴스를 재개합니다.

단일 샌드박스이고 잠금을 공유하는 다른 대상이 없다면 두 항목을 옵션으로 전달하고 추가 미들웨어를 생략합니다.

import { InMemoryLockStore } from '@tanstack/ai/locks'
import { withSandbox } from '@tanstack/ai-sandbox'
import { instanceStore } from './instance-store'
import { sandbox } from './sandbox'

const middleware = [
withSandbox(sandbox, {
instances: instanceStore,
locks: new InMemoryLockStore(), // multi-replica: a distributed LockStore
}),
]

선택적 채팅 영속성은 독립적입니다.

import { withLocks, InMemoryLockStore } from '@tanstack/ai/locks'
import { withPersistence, memoryPersistence } from '@tanstack/ai-persistence'
import { withSandbox } from '@tanstack/ai-sandbox'
import { instanceStore } from './instance-store'
import { sandbox } from './sandbox'

const middleware = [
withPersistence(memoryPersistence()), // chat state only
withLocks(new InMemoryLockStore()), // multi-replica: distributed LockStore
withSandbox(sandbox, { instances: instanceStore }),
]

SandboxInstanceStore 구현

저장소는 세 메서드(get, upsert, delete)로 구성되며, 각 메서드에는 적합성 테스트 모음이 확인하는 불변 조건이 있습니다. Build a Sandbox Adapter에서는 구현, 표, 테스트 모음과 함께 샌드박스 실행이 남겨야 할 데이터의 범위를 선택하는 방법을 설명합니다.

잠금

분산 잠금이 없는 영속적 인스턴스 맵은 복제본 환경에서도 여전히 잘못 작동합니다. 한 스레드에 대한 두 동시 실행이 모두 레코드를 찾지 못하고 둘 다 생성하기 때문입니다. @tanstack/ai/lockswithLocks 또는 위의 locks 옵션 중 하나를 사용하여 저장소와 잠금을 함께 구성합니다. 전체 가이드는 Locks를 참조하세요.

관련 항목

  • The Run Journal: 샌드박스가 아닌 실행 출력의 영속성
  • Takeover & Detached Runs: 클라이언트 연결 해제 후에도 실행을 유지합니다. 연결이 분리된 실행은 샌드박스를 유지하며, 이후 호스트는 RunStore.sandboxKey / RunStore.detachedSince를 사용하여 샌드박스를 다시 찾습니다.
  • Build a Sandbox Adapter: 이 저장소를 구현하고 샌드박스 실행이 남길 데이터의 범위를 선택합니다.
  • Locks
  • Lifecycle
  • Persistence overview: 채팅 상태만 다룹니다.