@tanstack/ai-sandbox 0.3.4 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -0
- package/dist/esm/approvals.js +5 -4
- package/dist/esm/approvals.js.map +1 -1
- package/dist/esm/bridge-events.js +7 -6
- package/dist/esm/bridge-events.js.map +1 -1
- package/dist/esm/checkpoint-store.d.ts +147 -0
- package/dist/esm/checkpoint-store.js +267 -0
- package/dist/esm/checkpoint-store.js.map +1 -0
- package/dist/esm/chunk-identity.d.ts +0 -17
- package/dist/esm/chunk-identity.js +28 -5
- package/dist/esm/chunk-identity.js.map +1 -1
- package/dist/esm/contracts.d.ts +19 -0
- package/dist/esm/index.d.ts +11 -1
- package/dist/esm/index.js +12 -7
- package/dist/esm/memory-snapshot-types.d.ts +129 -0
- package/dist/esm/memory-snapshots.d.ts +6 -0
- package/dist/esm/memory-snapshots.js +490 -0
- package/dist/esm/memory-snapshots.js.map +1 -0
- package/dist/esm/middleware.d.ts +33 -1
- package/dist/esm/middleware.js +339 -94
- package/dist/esm/middleware.js.map +1 -1
- package/dist/esm/ngrok.d.ts +1 -1
- package/dist/esm/sandbox.d.ts +16 -0
- package/dist/esm/sandbox.js +62 -9
- package/dist/esm/sandbox.js.map +1 -1
- package/dist/esm/snapshot-operations.d.ts +65 -0
- package/dist/esm/snapshot-operations.js +317 -0
- package/dist/esm/snapshot-operations.js.map +1 -0
- package/dist/esm/snapshot-tools.d.ts +185 -0
- package/dist/esm/snapshot-tools.js +160 -0
- package/dist/esm/snapshot-tools.js.map +1 -0
- package/dist/esm/snapshots.d.ts +51 -0
- package/dist/esm/snapshots.js +350 -0
- package/dist/esm/snapshots.js.map +1 -0
- package/dist/esm/testkit/checkpoint-conformance.d.ts +2 -0
- package/dist/esm/testkit/checkpoint-conformance.js +453 -0
- package/dist/esm/testkit/checkpoint-conformance.js.map +1 -0
- package/dist/esm/testkit/checkpoint-fork-conformance.d.ts +18 -0
- package/dist/esm/testkit/checkpoint-fork-conformance.js +191 -0
- package/dist/esm/testkit/checkpoint-fork-conformance.js.map +1 -0
- package/dist/esm/testkit/conformance.d.ts +4 -0
- package/dist/esm/testkit/conformance.js +3 -1
- package/dist/esm/testkit/conformance.js.map +1 -1
- package/dist/esm/tool-history.js +4 -5
- package/dist/esm/tool-history.js.map +1 -1
- package/package.json +8 -3
- package/skills/ai-sandbox/SKILL.md +96 -8
- package/src/approvals.ts +13 -12
- package/src/bridge-events.ts +16 -10
- package/src/checkpoint-store.ts +652 -0
- package/src/chunk-identity.ts +36 -5
- package/src/contracts.ts +12 -0
- package/src/index.ts +56 -0
- package/src/memory-snapshot-types.ts +167 -0
- package/src/memory-snapshots.ts +936 -0
- package/src/middleware.ts +610 -160
- package/src/sandbox.ts +107 -6
- package/src/snapshot-operations.ts +540 -0
- package/src/snapshot-tools.ts +208 -0
- package/src/snapshots.ts +711 -0
- package/src/testkit/checkpoint-conformance.ts +472 -0
- package/src/testkit/checkpoint-fork-conformance.ts +299 -0
- package/src/testkit/conformance.ts +7 -0
- package/src/tool-history.ts +9 -13
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { toolDefinition } from '@tanstack/ai'
|
|
2
|
+
import { SandboxSnapshotError } from './snapshots'
|
|
3
|
+
import type { SandboxSnapshots } from './snapshot-operations'
|
|
4
|
+
|
|
5
|
+
export interface CreateSnapshotToolsOptions {
|
|
6
|
+
threadId: string
|
|
7
|
+
runId: string
|
|
8
|
+
createThreadId: () => string
|
|
9
|
+
tenant?: { userId?: string; orgId?: string }
|
|
10
|
+
onForked?: (input: {
|
|
11
|
+
destinationThreadId: string
|
|
12
|
+
checkpointId: string
|
|
13
|
+
}) => void | Promise<void>
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function field(value: unknown, key: string): unknown {
|
|
17
|
+
if (value === null || typeof value !== 'object') return undefined
|
|
18
|
+
return Reflect.get(value, key)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function requiredString(value: unknown, key: string): string {
|
|
22
|
+
const candidate = field(value, key)
|
|
23
|
+
if (typeof candidate !== 'string' || candidate.length === 0) {
|
|
24
|
+
throw new SandboxSnapshotError(
|
|
25
|
+
'SANDBOX_SNAPSHOT_INVALID_TOOL_INPUT',
|
|
26
|
+
`Snapshot tool requires a non-empty ${key}`,
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
return candidate
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function optionalString(value: unknown, key: string): string | undefined {
|
|
33
|
+
const candidate = field(value, key)
|
|
34
|
+
if (candidate === undefined) return undefined
|
|
35
|
+
if (typeof candidate !== 'string' || candidate.length === 0) {
|
|
36
|
+
throw new SandboxSnapshotError(
|
|
37
|
+
'SANDBOX_SNAPSHOT_INVALID_TOOL_INPUT',
|
|
38
|
+
`Snapshot tool ${key} must be a non-empty string when provided`,
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
return candidate
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function requireIdentifier(value: string, label: string): string {
|
|
45
|
+
if (value.length === 0) {
|
|
46
|
+
throw new SandboxSnapshotError(
|
|
47
|
+
'SANDBOX_SNAPSHOT_INVALID_TOOL_INPUT',
|
|
48
|
+
`${label} must be a non-empty string`,
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
return value
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function createSnapshotTools(
|
|
55
|
+
snapshots: SandboxSnapshots,
|
|
56
|
+
options: CreateSnapshotToolsOptions,
|
|
57
|
+
) {
|
|
58
|
+
const threadId = requireIdentifier(options.threadId, 'threadId')
|
|
59
|
+
const runId = requireIdentifier(options.runId, 'runId')
|
|
60
|
+
const createThreadId = options.createThreadId
|
|
61
|
+
const tenant = options.tenant
|
|
62
|
+
const onForked = options.onForked
|
|
63
|
+
if (typeof createThreadId !== 'function') {
|
|
64
|
+
throw new SandboxSnapshotError(
|
|
65
|
+
'SANDBOX_SNAPSHOT_INVALID_TOOL_INPUT',
|
|
66
|
+
'createSnapshotTools requires createThreadId',
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const save = toolDefinition({
|
|
71
|
+
name: 'save_sandbox_snapshot',
|
|
72
|
+
description:
|
|
73
|
+
'Save a named checkpoint of the current live sandbox for this thread. Do not pass a thread id.',
|
|
74
|
+
inputSchema: {
|
|
75
|
+
type: 'object',
|
|
76
|
+
properties: {
|
|
77
|
+
label: {
|
|
78
|
+
type: 'string',
|
|
79
|
+
description: 'A short name for this version, such as release-1.',
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
required: ['label'],
|
|
83
|
+
additionalProperties: false,
|
|
84
|
+
},
|
|
85
|
+
outputSchema: {
|
|
86
|
+
type: 'object',
|
|
87
|
+
properties: {
|
|
88
|
+
checkpointId: { type: 'string' },
|
|
89
|
+
label: { type: 'string' },
|
|
90
|
+
threadId: { type: 'string' },
|
|
91
|
+
},
|
|
92
|
+
required: ['checkpointId', 'label', 'threadId'],
|
|
93
|
+
additionalProperties: false,
|
|
94
|
+
},
|
|
95
|
+
}).server(async (input) => {
|
|
96
|
+
const label = requiredString(input, 'label')
|
|
97
|
+
const checkpoint = await snapshots.save({
|
|
98
|
+
threadId,
|
|
99
|
+
runId,
|
|
100
|
+
label,
|
|
101
|
+
...(tenant === undefined ? {} : { tenant }),
|
|
102
|
+
})
|
|
103
|
+
return {
|
|
104
|
+
checkpointId: checkpoint.id,
|
|
105
|
+
label: checkpoint.label ?? label,
|
|
106
|
+
threadId,
|
|
107
|
+
}
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
const fork = toolDefinition({
|
|
111
|
+
name: 'fork_sandbox_snapshot',
|
|
112
|
+
description:
|
|
113
|
+
'Copy one checkpoint from this thread into a new empty thread. Omit checkpointId to copy the latest checkpoint. Do not pass thread ids.',
|
|
114
|
+
inputSchema: {
|
|
115
|
+
type: 'object',
|
|
116
|
+
properties: {
|
|
117
|
+
checkpointId: {
|
|
118
|
+
type: 'string',
|
|
119
|
+
description:
|
|
120
|
+
'The checkpoint to copy. When omitted, the latest checkpoint is copied.',
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
additionalProperties: false,
|
|
124
|
+
},
|
|
125
|
+
outputSchema: {
|
|
126
|
+
type: 'object',
|
|
127
|
+
properties: {
|
|
128
|
+
checkpointId: { type: 'string' },
|
|
129
|
+
destinationThreadId: { type: 'string' },
|
|
130
|
+
},
|
|
131
|
+
required: ['checkpointId', 'destinationThreadId'],
|
|
132
|
+
additionalProperties: false,
|
|
133
|
+
},
|
|
134
|
+
}).server(async (input) => {
|
|
135
|
+
const suppliedCheckpointId = optionalString(input, 'checkpointId')
|
|
136
|
+
const checkpointId =
|
|
137
|
+
suppliedCheckpointId ?? (await snapshots.checkpoints.getHead(threadId))
|
|
138
|
+
if (checkpointId === null) {
|
|
139
|
+
throw new SandboxSnapshotError(
|
|
140
|
+
'SANDBOX_SNAPSHOT_MISSING_CHECKPOINT',
|
|
141
|
+
'This thread has no checkpoint to fork',
|
|
142
|
+
)
|
|
143
|
+
}
|
|
144
|
+
const destinationThreadId = requireIdentifier(
|
|
145
|
+
createThreadId(),
|
|
146
|
+
'destinationThreadId',
|
|
147
|
+
)
|
|
148
|
+
const checkpoint = await snapshots.fork({
|
|
149
|
+
threadId,
|
|
150
|
+
checkpointId,
|
|
151
|
+
destinationThreadId,
|
|
152
|
+
})
|
|
153
|
+
if (onForked !== undefined) {
|
|
154
|
+
await onForked({
|
|
155
|
+
destinationThreadId,
|
|
156
|
+
checkpointId: checkpoint.id,
|
|
157
|
+
})
|
|
158
|
+
}
|
|
159
|
+
return {
|
|
160
|
+
checkpointId: checkpoint.id,
|
|
161
|
+
destinationThreadId,
|
|
162
|
+
}
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
const readArtifact = toolDefinition({
|
|
166
|
+
name: 'read_sandbox_snapshot_artifact',
|
|
167
|
+
description:
|
|
168
|
+
'Read metadata for one artifact on a checkpoint in this thread. Do not pass a thread id.',
|
|
169
|
+
inputSchema: {
|
|
170
|
+
type: 'object',
|
|
171
|
+
properties: {
|
|
172
|
+
checkpointId: { type: 'string' },
|
|
173
|
+
artifactId: { type: 'string' },
|
|
174
|
+
},
|
|
175
|
+
required: ['checkpointId', 'artifactId'],
|
|
176
|
+
additionalProperties: false,
|
|
177
|
+
},
|
|
178
|
+
outputSchema: {
|
|
179
|
+
type: 'object',
|
|
180
|
+
properties: {
|
|
181
|
+
artifactId: { type: 'string' },
|
|
182
|
+
name: { type: 'string' },
|
|
183
|
+
mimeType: { type: 'string' },
|
|
184
|
+
size: { type: 'number' },
|
|
185
|
+
createdAt: { type: 'number' },
|
|
186
|
+
},
|
|
187
|
+
required: ['artifactId', 'name', 'mimeType', 'size', 'createdAt'],
|
|
188
|
+
additionalProperties: false,
|
|
189
|
+
},
|
|
190
|
+
}).server(async (input) => {
|
|
191
|
+
const checkpointId = requiredString(input, 'checkpointId')
|
|
192
|
+
const artifactId = requiredString(input, 'artifactId')
|
|
193
|
+
const resolved = await snapshots.readArtifact({
|
|
194
|
+
threadId,
|
|
195
|
+
checkpointId,
|
|
196
|
+
artifactId,
|
|
197
|
+
})
|
|
198
|
+
return {
|
|
199
|
+
artifactId: resolved.artifact.artifactId,
|
|
200
|
+
name: resolved.artifact.name,
|
|
201
|
+
mimeType: resolved.artifact.mimeType,
|
|
202
|
+
size: resolved.artifact.size,
|
|
203
|
+
createdAt: resolved.artifact.createdAt,
|
|
204
|
+
}
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
return [save, fork, readArtifact] as const
|
|
208
|
+
}
|