experimental-agent 0.2.1 → 0.3.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.
Files changed (71) hide show
  1. package/README.md +55 -254
  2. package/dist/adapter-BigchkkI.d.mts +201 -0
  3. package/dist/adapter-BigchkkI.d.ts +201 -0
  4. package/dist/chunk-BFFNCESS.mjs +302 -0
  5. package/dist/chunk-C4VSUEY2.mjs +72 -0
  6. package/dist/chunk-DOD4MC5D.mjs +196 -0
  7. package/dist/chunk-ELWIUJUK.mjs +96 -0
  8. package/dist/chunk-GKASMIBR.mjs +50 -0
  9. package/dist/chunk-JO3JDCH5.mjs +107 -0
  10. package/dist/chunk-MSWINCCM.mjs +128 -0
  11. package/dist/chunk-RT72C52I.mjs +324 -0
  12. package/dist/chunk-ZUFJJYC4.mjs +150 -0
  13. package/dist/{handler-FRUPZ4LX.mjs → docker-QPCLWLYR.mjs} +3 -4
  14. package/dist/entry-BmQ8FO-5.d.ts +36 -0
  15. package/dist/entry-CZd9aAwn.d.mts +36 -0
  16. package/dist/index.d.mts +415 -18
  17. package/dist/index.d.ts +415 -18
  18. package/dist/index.js +3036 -5494
  19. package/dist/index.mjs +3264 -1142
  20. package/dist/lifecycle-workflow-steps.d.mts +5 -0
  21. package/dist/lifecycle-workflow-steps.d.ts +5 -0
  22. package/dist/lifecycle-workflow-steps.js +263 -0
  23. package/dist/lifecycle-workflow-steps.mjs +9 -0
  24. package/dist/lifecycle-workflow.d.mts +6 -6
  25. package/dist/lifecycle-workflow.d.ts +6 -6
  26. package/dist/lifecycle-workflow.js +192 -905
  27. package/dist/lifecycle-workflow.mjs +3 -1
  28. package/dist/local-KJ3BSIFJ.mjs +8 -0
  29. package/dist/next/loader.d.mts +1 -0
  30. package/dist/next/loader.d.ts +1 -0
  31. package/dist/next/loader.js +44 -18
  32. package/dist/next/loader.mjs +18 -13
  33. package/dist/next.js +32 -9
  34. package/dist/next.mjs +6 -4
  35. package/dist/{process-manager-JDUJDYGU.mjs → process-manager-WQHAIVRB.mjs} +1 -1
  36. package/dist/sandbox.d.mts +6 -0
  37. package/dist/sandbox.d.ts +6 -0
  38. package/dist/sandbox.js +1070 -0
  39. package/dist/sandbox.mjs +19 -0
  40. package/dist/steps-BnkRQKlc.d.ts +173 -0
  41. package/dist/steps-u-mGDbP_.d.mts +173 -0
  42. package/dist/storage.d.mts +11 -0
  43. package/dist/storage.d.ts +11 -0
  44. package/dist/storage.js +234 -0
  45. package/dist/storage.mjs +12 -0
  46. package/dist/vercel-QZ6INPMV.mjs +11 -0
  47. package/package.json +26 -5
  48. package/dist/agent-workflow.d.mts +0 -30
  49. package/dist/agent-workflow.d.ts +0 -30
  50. package/dist/agent-workflow.js +0 -5433
  51. package/dist/agent-workflow.mjs +0 -14
  52. package/dist/chunk-AML2VCQS.mjs +0 -1287
  53. package/dist/chunk-FQ67QZOI.mjs +0 -75
  54. package/dist/chunk-NO7RHGTH.mjs +0 -2367
  55. package/dist/chunk-NXDVNJRS.mjs +0 -106
  56. package/dist/chunk-OZZVS6L5.mjs +0 -139
  57. package/dist/chunk-QRWGDFFY.mjs +0 -75
  58. package/dist/chunk-SJVFFE5D.mjs +0 -402
  59. package/dist/chunk-TAXLUVIC.mjs +0 -1
  60. package/dist/chunk-TGNVXSMX.mjs +0 -399
  61. package/dist/chunk-YRYXN7W4.mjs +0 -48
  62. package/dist/chunk-ZIAHPXOJ.mjs +0 -595
  63. package/dist/client-BKA7XBGW.mjs +0 -15
  64. package/dist/client-CEeSFGva.d.mts +0 -2376
  65. package/dist/client-CEeSFGva.d.ts +0 -2376
  66. package/dist/docker-FB2MJTHJ.mjs +0 -12
  67. package/dist/local-fs-handlers-SYOCKTPN.mjs +0 -447
  68. package/dist/sandbox-UENKQV3T.mjs +0 -21
  69. package/dist/storage-LSDMRW73.mjs +0 -20
  70. package/dist/vercel-SD3JTECG.mjs +0 -20
  71. package/dist/vercel-sdk-I6A4MVAN.mjs +0 -8
package/README.md CHANGED
@@ -9,10 +9,10 @@ pnpm i experimental-agent
9
9
  ## Why
10
10
 
11
11
  - **AI SDK compatible** — Built on `ai`. Uses `UIMessage`, `GatewayModelId`, streams the same way. If you know AI SDK, you know this.
12
- - **Managed workflow** — Runs inside Vercel Workflow. Retries, timeouts, resumption handled for you.
12
+ - **Opt-in durability** — Works in-process by default. Add a `"use workflow"` wrapper for full durability that survives crashes, timeouts, and deploys.
13
+ - **Bring your own storage** — Implement a flat handler map backed by any database. Built-in `localStorage()` for dev.
13
14
  - **Managed sandbox** — Auto-starts on first use, auto-snapshots when idle, auto-resumes. You don't manage the VM.
14
- - **Built-in storage** — Messages, tool calls, and sandbox state persisted automatically. Survives refreshes, crashes, reconnects.
15
- - **Built-in tools** — Read, Grep, List, Bash. No setup.
15
+ - **Built-in tools** — Read, Grep, List, Bash, Write, Edit, Skill, JavaScript. No setup.
16
16
 
17
17
  ## Quick Start
18
18
 
@@ -20,8 +20,8 @@ pnpm i experimental-agent
20
20
  // lib/agent.ts
21
21
  import { agent } from "experimental-agent";
22
22
 
23
- export const myAgent = agent({
24
- model: "anthropic/claude-opus-4.5",
23
+ export const myAgent = agent("my-agent", {
24
+ model: "anthropic/claude-opus-4.6",
25
25
  system: "You are a helpful coding assistant.",
26
26
  });
27
27
  ```
@@ -33,10 +33,10 @@ import { createUIMessageStreamResponse } from "ai";
33
33
 
34
34
  export async function POST(req: Request, { params }: { params: { chatId: string } }) {
35
35
  const { chatId } = await params;
36
- const { message } = await req.json(); // string or UIMessage
36
+ const { message } = await req.json();
37
37
 
38
- const session = await myAgent.session(chatId);
39
- await session.send({ input: message }); // accepts string, UIMessage, or parts array
38
+ const session = myAgent.session(chatId);
39
+ await session.send(message);
40
40
  const stream = await session.stream();
41
41
 
42
42
  return createUIMessageStreamResponse({ stream });
@@ -44,275 +44,76 @@ export async function POST(req: Request, { params }: { params: { chatId: string
44
44
 
45
45
  export async function GET(req: Request, { params }: { params: { chatId: string } }) {
46
46
  const { chatId } = await params;
47
- const session = await myAgent.session(chatId);
48
- const stream = await session.stream();
49
- if (stream instanceof Error) {
50
- console.error(stream);
51
- if (stream instanceof SessionNotFoundError) {
52
- return new Response("Session not found", { status: 404 });
53
- }
54
- return new Response("Internal server error", { status: 500 });
47
+ const session = myAgent.session(chatId);
48
+ try {
49
+ const stream = await session.stream();
50
+ return createUIMessageStreamResponse({ stream });
51
+ } catch {
52
+ return Response.json(await session.history());
55
53
  }
56
-
57
- return createUIMessageStreamResponse({ stream });
58
54
  }
59
55
  ```
60
56
 
57
+ ## Adding Workflow
61
58
 
59
+ Everything works without workflow. To add durability:
62
60
 
63
- ## Rendering Messages
64
-
65
- `session.ui()` returns `UIMessage[]` — the same format `useChat` uses.
66
-
67
- ### RSC Pattern
68
-
69
- Server component fetches initial state, client component handles streaming:
70
-
71
- ```tsx
72
- // app/chat/[chatId]/page.tsx (server component)
61
+ ```ts
62
+ // workflow.ts
73
63
  import { myAgent } from "@/lib/agent";
74
- import { Chat } from "./chat-client";
75
-
76
- export default async function ChatPage({ params }) {
77
- const { chatId } = await params;
78
- const session = await myAgent.session(chatId);
79
- const ui = await session.ui();
80
- if (ui instanceof Error) {
81
- console.error(ui);
82
- throw new Error("Failed to get messages");
83
- }
84
-
85
- return (
86
- <>
87
- {ui.messages.map((m) => (
88
- <MessageView key={m.id} message={m} />
89
- ))}
90
- <Chat chatId={chatId} streamingMessageId={ui.streamingMessageId} />
91
- </>
92
- );
93
- }
94
- ```
95
-
96
- ```tsx
97
- // chat-client.tsx
98
- "use client";
99
-
100
- import { useEffect } from "react";
101
- import { useChat, DefaultChatTransport } from "@ai-sdk/react";
102
-
103
- export function Chat({ chatId, streamingMessageId }) {
104
- const { messages, resumeStream, sendMessage, status } = useChat({
105
- id: chatId,
106
- transport: new DefaultChatTransport({
107
- api: `/api/chat/${chatId}`,
108
- prepareSendMessagesRequest: ({ messages }) => ({
109
- body: { message: messages.at(-1) },
110
- }),
111
- prepareReconnectToStreamRequest: (request) => ({
112
- ...request,
113
- api: `/api/chat/${chatId}`,
114
- }),
115
- }),
116
- });
117
-
118
- useEffect(() => {
119
- if (streamingMessageId) {
120
- resumeStream();
121
- }
122
- }, [streamingMessageId, resumeStream]);
123
-
124
- return (
125
- <>
126
- {messages.map((m) => (
127
- <MessageView key={m.id} message={m} />
128
- ))}
129
- <form
130
- onSubmit={async (e) => {
131
- e.preventDefault();
132
- const form = e.currentTarget;
133
- const textarea = form.elements.namedItem("composer") as HTMLTextAreaElement | null;
134
- const text = textarea ? textarea.value : "";
135
- if (text.trim()) {
136
- await sendMessage({ parts: [{ type: "text", text }] });
137
- textarea.value = "";
138
- }
139
- }}
140
- >
141
- <textarea name="composer" />
142
- <button type="submit" disabled={status !== "ready"}>
143
- Send
144
- </button>
145
- </form>
146
- </>
147
- );
64
+ import type { SessionSendArgs } from "experimental-agent";
65
+
66
+ export async function agentWorkflow(
67
+ sessionId: string,
68
+ ...args: SessionSendArgs<typeof myAgent>
69
+ ) {
70
+ "use workflow";
71
+ return await myAgent.session(sessionId).send(...args);
148
72
  }
149
73
  ```
150
74
 
151
-
152
- ## Tools
153
-
154
- | Tool | Description |
155
- |------|-------------|
156
- | **Read** | Read files. Large files (>200 lines) paginate automatically. |
157
- | **Grep** | ripgrep-powered search. Regex, file types, context lines. |
158
- | **List** | Directory listing with depth control and glob filtering. |
159
- | **Bash** | Shell commands. Background processes via `waitUntil: 0`. Persistent CWD. |
160
-
161
- ## Configuration
162
-
163
- ```ts
164
- const myAgent = agent({
165
- model: "anthropic/claude-haiku-4.5", // Required
166
- system: "...", // System prompt
167
- sandbox: { type: "vercel" }, // or "local"
168
- storage: { type: "vercel" }, // or "local" or "custom"
169
- skillsDir: ".agent/skills", // Skills location
170
- mcp: { ... }, // Custom tools
171
- })
172
-
173
- // overrides per session
174
- myAgent.session("<session-id>", {
175
- model: "anthropic/claude-opus-4.5"
176
- })
177
- ```
178
-
179
- ## Sessions
180
-
181
- ```ts
182
- const session = await myAgent.session(sessionId);
183
-
184
- // input can be a string, UIMessage, or parts array
185
- await session.send({ input: "Hello" });
186
- await session.send({ input: { role: "user", parts: [{ type: "text", text: "Hello" }] } });
187
-
188
- const stream = await session.stream();
189
-
190
- // Tags for your app's metadata
191
- await session.tag.set("category", "support");
192
- ```
193
-
194
- ### Handles vs Records
195
-
196
- - `myAgent.session(id)` and `myAgent.sandbox(id)` return orchestration handles.
197
- - Handles are use-case APIs (send, stream, run tools, resume sandbox lifecycle).
198
- - `myAgent.storage.*` is the raw record API (`Session`, `SandboxRecord`, `Message`, `Part`, `Command`, `SetupSnapshot`).
199
- - Use `storage` for record lookups and filters (for example existence checks and list queries).
200
-
201
- ### Durable UI
202
-
203
- Unlike `useChat` alone, messages survive refresh. They're persisted to storage.
204
-
205
- - Close laptop, open tomorrow — conversation is there
206
- - Browser crashes mid-stream — reload, partial response preserved
207
- - Share a session URL — another user sees the same conversation
208
-
209
- The server component renders completed messages from `session.ui()`. The client component handles new input and streaming. State lives in storage, not browser memory.
210
-
211
- ## Sandbox
212
-
213
- ```ts
214
- // Local (dev)
215
- const myAgent = agent({ sandbox: { type: "local" } })
216
-
217
- // Vercel (prod)
218
- const myAgent = agent({ sandbox: { type: "vercel", resources: { vcpus: 2 }, ports: [3000] } })
219
-
220
- const session = await myAgent.session("some-session")
221
-
222
- // Direct access
223
- await session.sandbox.exec({ command: "npm", args: ["install"] });
224
- ```
225
-
226
- ### Share a sandbox
227
-
228
75
  ```ts
229
- const sharedBox = await myAgent.sandbox("some-sandbox")
230
-
231
- await myAgent.session("s1", { sandbox: sharedBox.id });
232
- await myAgent.session("s2", { sandbox: sharedBox.id });
233
- ```
234
-
235
- ## Skills
236
-
237
- Skills are `SKILL.md` files discovered from the sandbox:
76
+ // route.ts
77
+ import { start } from "workflow/api";
78
+ import { agentWorkflow } from "./workflow";
238
79
 
239
- ```yaml
240
- ---
241
- name: deploy
242
- description: Deploy to Vercel
243
- ---
244
-
245
- Run `vercel deploy` in the project root.
80
+ const result = await start(agentWorkflow, [chatId, message, opts]);
81
+ const stream = await session.stream(result);
82
+ return createUIMessageStreamResponse({ stream });
246
83
  ```
247
84
 
248
- ```ts
249
- agent({ skillsDir: ".agent/skills" })
250
- ```
251
-
252
- ## MCP (this api will change soon)
253
-
254
- Custom tools with type-safe schemas:
85
+ ## Storage
255
86
 
256
87
  ```ts
257
- import { agent, mcp } from "experimental-agent";
258
- import { z } from "zod";
259
-
260
- const myAgent = agent({
261
- mcp: {
262
- vercel: mcp({
263
- url: "/api/mcp",
264
- headersSchema: z.object({ authorization: z.string() }),
265
- tools: {
266
- listProjects: {
267
- description: "List Vercel projects",
268
- inputSchema: z.object({ teamId: z.string().optional() }),
269
- },
270
- },
271
- }),
88
+ // Dev built-in filesystem storage
89
+ import { localStorage } from "experimental-agent/storage";
90
+ agent("my-agent", { storage: localStorage() })
91
+
92
+ // Prod — your own database
93
+ agent("my-agent", {
94
+ async storage(store) {
95
+ return await store.on({
96
+ "session.get": async ({ id }) => await db.sessions.findById(id),
97
+ "session.set": async ({ id, value }) => await db.sessions.upsert(id, value),
98
+ // ... all handlers
99
+ });
272
100
  },
273
- });
274
-
275
- // Send with auth
276
- await session.send({
277
- input: "List my projects",
278
- mcpContext: { vercel: { headers: { authorization: `Bearer ${token}` } } },
279
- });
101
+ })
280
102
 
281
- // Handle in your API
282
- await myAgent.handleMcpToolCall(body, {
283
- "vercel/listProjects": async ({ input, headers }) => {
284
- return fetchProjects(input.teamId, headers.authorization);
103
+ // To add workflow durability, just add "use step" at the top:
104
+ agent("my-agent", {
105
+ async storage(store) {
106
+ "use step";
107
+ return await store.on({ /* same handlers */ });
285
108
  },
286
- });
287
- ```
288
-
289
- ## Storage
290
-
291
- HTTP-based (workflow inputs must be serializable).
292
-
293
- ```ts
294
- agent({ storage: { type: "vercel" } }) // default — hosted service
295
- agent({ storage: { type: "local" } }) // dev — filesystem
296
- agent({ storage: { type: "custom", url: "https://...", headers: {} } })
109
+ })
297
110
  ```
298
111
 
299
- The SDK stores: `Session`, `Message`, `Part`, `SandboxRecord`.
300
-
301
- Everything else—users, titles, access control—belongs in your database. Session ID is your join key.
302
-
303
- For session queries scoped to a sandbox, use `storage.session.listBySandbox({ sandboxId, ... })`.
304
-
305
- ### Vercel Agent Storage
306
-
307
- The default `{ type: "vercel" }` uses the hosted Vercel Agent Storage service:
308
-
309
- - **Zero config** — authenticates via Vercel OIDC, no API keys needed
310
- - **Multi-tenant** — data isolated by owner, project, and environment
311
- - **Postgres-backed** — reliable, queryable, scales with you
112
+ The SDK stores `Session`, `Message`, `Part`, `Sandbox`. Everything else — users, titles, access control — belongs in your database. Session ID is your join key.
312
113
 
313
- Just deploy to Vercel and it works. No database setup, no connection strings.
114
+ ## Documentation
314
115
 
315
- For self-hosting or custom backends, see [apps/storage](../../apps/storage/) for a reference implementation using `handleStorageRpc`.
116
+ Full docs at [packages/agent/docs](./docs/).
316
117
 
317
118
  ## Development
318
119
 
@@ -0,0 +1,201 @@
1
+ import { WORKFLOW_SERIALIZE, WORKFLOW_DESERIALIZE } from '@workflow/serde';
2
+ import { NetworkPolicy } from '@vercel/sandbox';
3
+ import { UIMessage } from 'ai';
4
+
5
+ type Session = {
6
+ id: string;
7
+ createdAt: number;
8
+ updatedAt: number;
9
+ model: string | null;
10
+ system: string | null;
11
+ sandboxId: string | null;
12
+ lastMessageId: string | null;
13
+ activeTools: string[] | null;
14
+ skillsDir: string[] | null;
15
+ generation: {
16
+ maxSteps?: number;
17
+ temperature?: number;
18
+ topK?: number;
19
+ topP?: number;
20
+ frequencyPenalty?: number;
21
+ presencePenalty?: number;
22
+ maxOutputTokens?: number;
23
+ headers?: Record<string, string>;
24
+ } | null;
25
+ };
26
+ type Message = {
27
+ id: string;
28
+ sessionId: string;
29
+ role: "user" | "assistant" | "system";
30
+ createdAt: number;
31
+ startedAt: number | null;
32
+ completedAt: number | null;
33
+ interruptedAt: number | null;
34
+ interruptedLastPart: {
35
+ index: number;
36
+ part: unknown;
37
+ } | null;
38
+ usage: {
39
+ steps: {
40
+ stepIndex: number;
41
+ model: string;
42
+ inputTokens: number;
43
+ outputTokens: number;
44
+ totalTokens: number;
45
+ cacheReadTokens: number;
46
+ cacheWriteTokens: number;
47
+ reasoningTokens: number;
48
+ }[];
49
+ summary: {
50
+ model: string;
51
+ inputTokens: number;
52
+ outputTokens: number;
53
+ totalTokens: number;
54
+ cacheReadTokens: number;
55
+ cacheWriteTokens: number;
56
+ reasoningTokens: number;
57
+ stepCount: number;
58
+ };
59
+ } | null;
60
+ workflowRunId?: string | null;
61
+ };
62
+ type Part = {
63
+ id: string;
64
+ messageId: string;
65
+ sessionId: string;
66
+ index: number;
67
+ part: UIMessage["parts"][number];
68
+ };
69
+ type Sandbox = {
70
+ id: string;
71
+ setup: {
72
+ binding: string;
73
+ version: string | null;
74
+ completedAt: number | null;
75
+ metadata: Record<string, unknown> | null;
76
+ networkPolicy: NetworkPolicy | null;
77
+ };
78
+ createdAt: number | null;
79
+ lastActiveAt: number | null;
80
+ };
81
+ type Setup = {
82
+ version: string;
83
+ snapshotId: string | null;
84
+ createdAt: number;
85
+ lastUsedAt: number | null;
86
+ };
87
+ type SetupSnapshot = Setup;
88
+
89
+ type StorageHandlers = {
90
+ "session.get"(p: {
91
+ id: string;
92
+ }): Promise<Session | null>;
93
+ "session.set"(p: {
94
+ id: string;
95
+ value: Session;
96
+ }): Promise<void>;
97
+ "session.update"(p: {
98
+ id: string;
99
+ updates: Partial<Session>;
100
+ }): Promise<Session>;
101
+ "message.get"(p: {
102
+ id: string;
103
+ }): Promise<Message | null>;
104
+ "message.set"(p: {
105
+ id: string;
106
+ value: Message;
107
+ }): Promise<void>;
108
+ "message.update"(p: {
109
+ id: string;
110
+ updates: Partial<Message>;
111
+ }): Promise<Message>;
112
+ "message.listBySession"(p: {
113
+ sessionId: string;
114
+ }): Promise<Message[]>;
115
+ "part.get"(p: {
116
+ id: string;
117
+ }): Promise<Part | null>;
118
+ "part.set"(p: {
119
+ id: string;
120
+ value: Part;
121
+ }): Promise<void>;
122
+ "part.listBySession"(p: {
123
+ sessionId: string;
124
+ }): Promise<Part[]>;
125
+ "sandbox.get"(p: {
126
+ id: string;
127
+ }): Promise<Sandbox | null>;
128
+ "sandbox.set"(p: {
129
+ id: string;
130
+ value: Sandbox;
131
+ }): Promise<void>;
132
+ "sandbox.update"(p: {
133
+ id: string;
134
+ updates: Partial<Sandbox>;
135
+ }): Promise<Sandbox>;
136
+ "setup.get"(p: {
137
+ id: string;
138
+ }): Promise<Setup | null>;
139
+ "setup.set"(p: {
140
+ id: string;
141
+ value: Setup;
142
+ }): Promise<void>;
143
+ };
144
+ type StorageCall = {
145
+ [K in keyof StorageHandlers]: {
146
+ method: K;
147
+ } & Parameters<StorageHandlers[K]>[0];
148
+ }[keyof StorageHandlers];
149
+ declare class StorageStep {
150
+ event: StorageCall;
151
+ constructor(event: StorageCall);
152
+ static [WORKFLOW_SERIALIZE](instance: StorageStep): {
153
+ event: StorageCall;
154
+ };
155
+ static [WORKFLOW_DESERIALIZE](data: {
156
+ event: StorageCall;
157
+ }): StorageStep;
158
+ on(handlers: StorageHandlers): Promise<any>;
159
+ }
160
+ /**
161
+ * A single function that handles all storage operations. Intended to be
162
+ * marked with `"use step"` so that its body (and Node.js-dependent
163
+ * imports like database clients) is extracted by the workflow bundler
164
+ * and runs server-side.
165
+ *
166
+ * The step receives a `StorageStep` instance (serializable via
167
+ * `@workflow/serde`) and should call `step.handle({ ... })` with a
168
+ * `StorageHandlers` map.
169
+ */
170
+ type StorageStepFunction = (store: StorageStep) => Promise<any>;
171
+ interface Storage {
172
+ session: {
173
+ get(key: string): Promise<Session | null>;
174
+ set(key: string, value: Session): Promise<void>;
175
+ update(key: string, updates: Partial<Session>): Promise<Session>;
176
+ };
177
+ message: {
178
+ get(key: string): Promise<Message | null>;
179
+ set(key: string, value: Message): Promise<void>;
180
+ update(key: string, updates: Partial<Message>): Promise<Message>;
181
+ listBySession(sessionId: string): Promise<Message[]>;
182
+ };
183
+ part: {
184
+ get(key: string): Promise<Part | null>;
185
+ set(key: string, value: Part): Promise<void>;
186
+ listBySession(sessionId: string): Promise<Part[]>;
187
+ };
188
+ sandbox: {
189
+ get(key: string): Promise<Sandbox | null>;
190
+ set(key: string, value: Sandbox): Promise<void>;
191
+ update(key: string, updates: Partial<Sandbox>): Promise<Sandbox>;
192
+ };
193
+ setup: {
194
+ get(key: string): Promise<Setup | null>;
195
+ set(key: string, value: Setup): Promise<void>;
196
+ };
197
+ }
198
+ type StorageInput = StorageHandlers | StorageStepFunction;
199
+ declare function toStorage(h: StorageInput): Storage;
200
+
201
+ export { type Message as M, type Part as P, type StorageHandlers as S, type Sandbox as a, type Session as b, type Setup as c, type SetupSnapshot as d, type Storage as e, type StorageCall as f, StorageStep as g, type StorageStepFunction as h, type StorageInput as i, toStorage as t };