experimental-agent 0.0.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 +243 -0
- package/dist/agent-workflow.d.mts +21 -0
- package/dist/agent-workflow.d.ts +21 -0
- package/dist/agent-workflow.js +2659 -0
- package/dist/agent-workflow.mjs +9 -0
- package/dist/chunk-2YI7MQGZ.mjs +261 -0
- package/dist/chunk-36X6L7SK.mjs +1 -0
- package/dist/chunk-DPPQO7DA.mjs +343 -0
- package/dist/chunk-JQPR6M7D.mjs +649 -0
- package/dist/chunk-MR4UWCJT.mjs +878 -0
- package/dist/client-FCFZYOOB.mjs +9 -0
- package/dist/client-RRX3GDQD.mjs +9 -0
- package/dist/index.d.mts +128 -0
- package/dist/index.d.ts +128 -0
- package/dist/index.js +3078 -0
- package/dist/index.mjs +421 -0
- package/dist/lifecycle-workflow-steps-6BLGTYVB.mjs +20 -0
- package/dist/lifecycle-workflow.d.mts +17 -0
- package/dist/lifecycle-workflow.d.ts +17 -0
- package/dist/lifecycle-workflow.js +1690 -0
- package/dist/lifecycle-workflow.mjs +44 -0
- package/dist/local-J6QFWSWB.mjs +244 -0
- package/dist/process-manager-H2HF6G4G.mjs +153 -0
- package/dist/sandbox-Y3ENCNUA.mjs +10 -0
- package/dist/storage-QSTSE2ZB.mjs +27 -0
- package/dist/types-Lwut_0_u.d.mts +80 -0
- package/dist/types-ctZeJ3iQ.d.ts +80 -0
- package/dist/types-vRxN1Qz1.d.mts +805 -0
- package/dist/types-vRxN1Qz1.d.ts +805 -0
- package/dist/vercel-2CFDMEHB.mjs +18 -0
- package/package.json +59 -0
package/README.md
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
# Agent
|
|
2
|
+
|
|
3
|
+
An LLM running in a loop, with access to a sandbox, tools, and session management. Nothing more.
|
|
4
|
+
|
|
5
|
+
## Why
|
|
6
|
+
|
|
7
|
+
- **AI SDK compatible** — Built on `ai`. Uses `UIMessage`, `GatewayModelId`, streams the same way. If you know AI SDK, you know this.
|
|
8
|
+
- **Managed workflow** — Runs inside Vercel Workflow. Retries, timeouts, resumption handled for you.
|
|
9
|
+
- **Managed sandbox** — Auto-provisions on first use, auto-snapshots when idle, auto-resumes. You don't manage the VM.
|
|
10
|
+
- **Built-in tools** — Read, Grep, List, Bash. No setup.
|
|
11
|
+
|
|
12
|
+
## Quick Start
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
// lib/agent.ts
|
|
16
|
+
import { agent } from "experimental-agent";
|
|
17
|
+
|
|
18
|
+
export const myAgent = agent({
|
|
19
|
+
model: "anthropic/claude-sonnet-4",
|
|
20
|
+
instructions: "You are a helpful coding assistant.",
|
|
21
|
+
});
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
// app/api/chat/[chatId]/route.ts
|
|
26
|
+
import { myAgent } from "@/lib/agent";
|
|
27
|
+
|
|
28
|
+
export async function POST(req: Request, { params }: { params: { chatId: string } }) {
|
|
29
|
+
const { chatId } = await params;
|
|
30
|
+
const { message } = await req.json();
|
|
31
|
+
|
|
32
|
+
const session = await myAgent.session(chatId);
|
|
33
|
+
await session.send({ input: message });
|
|
34
|
+
const stream = await session.stream();
|
|
35
|
+
|
|
36
|
+
return new Response(stream);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export async function GET(req: Request, { params }: { params: { chatId: string } }) {
|
|
40
|
+
const { chatId } = await params;
|
|
41
|
+
const session = await myAgent.session(chatId);
|
|
42
|
+
const { messages, streamingMessageId } = await session.ui();
|
|
43
|
+
|
|
44
|
+
return Response.json({ messages, streamingMessageId });
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Tools
|
|
49
|
+
|
|
50
|
+
| Tool | Description |
|
|
51
|
+
|------|-------------|
|
|
52
|
+
| **Read** | Read files. Large files (>200 lines) paginate automatically. |
|
|
53
|
+
| **Grep** | ripgrep-powered search. Regex, file types, context lines. |
|
|
54
|
+
| **List** | Directory listing with depth control and glob filtering. |
|
|
55
|
+
| **Bash** | Shell commands. Background processes via `waitUntil: 0`. Persistent CWD. |
|
|
56
|
+
|
|
57
|
+
## Configuration
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
agent({
|
|
61
|
+
model: "anthropic/claude-sonnet-4", // Required
|
|
62
|
+
instructions: "...", // System prompt
|
|
63
|
+
sandbox: { type: "vercel" }, // or "local"
|
|
64
|
+
storage: { type: "vercel" }, // or "local" or "custom"
|
|
65
|
+
skillsDir: ".agent/skills", // Skills location
|
|
66
|
+
mcp: { ... }, // Custom tools
|
|
67
|
+
})
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Sessions
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
const session = await myAgent.session(sessionId);
|
|
74
|
+
|
|
75
|
+
await session.send({ input: "Hello" });
|
|
76
|
+
const stream = await session.stream();
|
|
77
|
+
|
|
78
|
+
// Tags for your app's metadata
|
|
79
|
+
await session.tag.set("category", "support");
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Rendering Messages
|
|
83
|
+
|
|
84
|
+
`session.ui()` returns `UIMessage[]` — the same format `useChat` uses.
|
|
85
|
+
|
|
86
|
+
### RSC Pattern
|
|
87
|
+
|
|
88
|
+
Server component fetches initial state, client component handles streaming:
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
// app/chat/[chatId]/page.tsx (server component)
|
|
92
|
+
import { myAgent } from "@/lib/agent";
|
|
93
|
+
import { Chat } from "./chat-client";
|
|
94
|
+
|
|
95
|
+
export default async function ChatPage({ params }) {
|
|
96
|
+
const { chatId } = await params;
|
|
97
|
+
const session = await myAgent.session(chatId);
|
|
98
|
+
const { messages, streamingMessageId } = await session.ui();
|
|
99
|
+
|
|
100
|
+
return (
|
|
101
|
+
<>
|
|
102
|
+
{messages.map((m) => (
|
|
103
|
+
<MessageView key={m.id} message={m} />
|
|
104
|
+
))}
|
|
105
|
+
<Chat chatId={chatId} streamingMessageId={streamingMessageId} />
|
|
106
|
+
</>
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
```tsx
|
|
112
|
+
// chat-client.tsx
|
|
113
|
+
"use client";
|
|
114
|
+
|
|
115
|
+
import { useChat } from "@ai-sdk/react";
|
|
116
|
+
|
|
117
|
+
export function Chat({ chatId, streamingMessageId }) {
|
|
118
|
+
const { messages, input, handleInputChange, handleSubmit, status } = useChat({
|
|
119
|
+
id: chatId,
|
|
120
|
+
api: `/api/chat/${chatId}`,
|
|
121
|
+
initialMessages: [], // hydrate from server if needed
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
return (
|
|
125
|
+
<>
|
|
126
|
+
{messages.map((m) => (
|
|
127
|
+
<MessageView key={m.id} message={m} />
|
|
128
|
+
))}
|
|
129
|
+
<form onSubmit={handleSubmit}>
|
|
130
|
+
<input value={input} onChange={handleInputChange} />
|
|
131
|
+
<button type="submit" disabled={status !== "ready"}>Send</button>
|
|
132
|
+
</form>
|
|
133
|
+
</>
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Durable UI
|
|
139
|
+
|
|
140
|
+
Unlike `useChat` alone, messages survive refresh. They're persisted to storage.
|
|
141
|
+
|
|
142
|
+
- Close laptop, open tomorrow — conversation is there
|
|
143
|
+
- Browser crashes mid-stream — reload, partial response preserved
|
|
144
|
+
- Share a session URL — another user sees the same conversation
|
|
145
|
+
|
|
146
|
+
The server component renders completed messages from `session.ui()`. The client component handles new input and streaming. State lives in storage, not browser memory.
|
|
147
|
+
|
|
148
|
+
## Sandbox
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
// Local (dev)
|
|
152
|
+
agent({ sandbox: { type: "local" } })
|
|
153
|
+
|
|
154
|
+
// Vercel (prod)
|
|
155
|
+
agent({ sandbox: { type: "vercel", resources: { vcpus: 2 }, ports: [3000] } })
|
|
156
|
+
|
|
157
|
+
// Direct access
|
|
158
|
+
await session.sandbox.exec({ command: "npm", args: ["install"] });
|
|
159
|
+
|
|
160
|
+
// Share across sessions
|
|
161
|
+
await myAgent.session("s1", { sandbox: "shared_id" });
|
|
162
|
+
await myAgent.session("s2", { sandbox: "shared_id" });
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Skills
|
|
166
|
+
|
|
167
|
+
Skills are `SKILL.md` files discovered from the sandbox:
|
|
168
|
+
|
|
169
|
+
```yaml
|
|
170
|
+
---
|
|
171
|
+
name: deploy
|
|
172
|
+
description: Deploy to Vercel
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
Run `vercel deploy` in the project root.
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
agent({ skillsDir: ".agent/skills" })
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## MCP (this api will change soon)
|
|
183
|
+
|
|
184
|
+
Custom tools with type-safe schemas:
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
import { agent, mcp } from "experimental-agent";
|
|
188
|
+
import { z } from "zod";
|
|
189
|
+
|
|
190
|
+
const myAgent = agent({
|
|
191
|
+
mcp: {
|
|
192
|
+
vercel: mcp({
|
|
193
|
+
url: "/api/mcp",
|
|
194
|
+
headersSchema: z.object({ authorization: z.string() }),
|
|
195
|
+
tools: {
|
|
196
|
+
listProjects: {
|
|
197
|
+
description: "List Vercel projects",
|
|
198
|
+
inputSchema: z.object({ teamId: z.string().optional() }),
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
}),
|
|
202
|
+
},
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
// Send with auth
|
|
206
|
+
await session.send({
|
|
207
|
+
input: "List my projects",
|
|
208
|
+
mcpContext: { vercel: { headers: { authorization: `Bearer ${token}` } } },
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
// Handle in your API
|
|
212
|
+
await myAgent.handleMcpToolCall(body, {
|
|
213
|
+
"vercel/listProjects": async ({ input, headers }) => {
|
|
214
|
+
return fetchProjects(input.teamId, headers.authorization);
|
|
215
|
+
},
|
|
216
|
+
});
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Storage
|
|
220
|
+
|
|
221
|
+
HTTP-based (workflow inputs must be serializable).
|
|
222
|
+
|
|
223
|
+
```ts
|
|
224
|
+
agent({ storage: { type: "vercel" } }) // default — hosted service
|
|
225
|
+
agent({ storage: { type: "local" } }) // dev — filesystem
|
|
226
|
+
agent({ storage: { type: "custom", url: "https://...", headers: {} } })
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
The SDK stores: `Session`, `Message`, `Part`, `SandboxRecord`.
|
|
230
|
+
|
|
231
|
+
Everything else—users, titles, access control—belongs in your database. Session ID is your join key.
|
|
232
|
+
|
|
233
|
+
### Vercel Agent Storage
|
|
234
|
+
|
|
235
|
+
The default `{ type: "vercel" }` uses the hosted Vercel Agent Storage service:
|
|
236
|
+
|
|
237
|
+
- **Zero config** — authenticates via Vercel OIDC, no API keys needed
|
|
238
|
+
- **Multi-tenant** — data isolated by owner, project, and environment
|
|
239
|
+
- **Postgres-backed** — reliable, queryable, scales with you
|
|
240
|
+
|
|
241
|
+
Just deploy to Vercel and it works. No database setup, no connection strings.
|
|
242
|
+
|
|
243
|
+
For self-hosting or custom backends, see [apps/storage](../../apps/storage/) for a reference implementation using `handleStorageRpc`.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as workflow from 'workflow';
|
|
2
|
+
import { a as StorageConfig } from './types-vRxN1Qz1.mjs';
|
|
3
|
+
import 'ai';
|
|
4
|
+
import 'zod';
|
|
5
|
+
import 'errore';
|
|
6
|
+
|
|
7
|
+
type AgentInput = {
|
|
8
|
+
sessionId: string;
|
|
9
|
+
storageConfig: StorageConfig;
|
|
10
|
+
};
|
|
11
|
+
type AgentMessageInput = {
|
|
12
|
+
assistantMessageId: string;
|
|
13
|
+
hookToken: string;
|
|
14
|
+
};
|
|
15
|
+
declare const agentMessageHook: workflow.TypedHook<AgentMessageInput, AgentMessageInput>;
|
|
16
|
+
declare function agentWorkflow({ input, event, }: {
|
|
17
|
+
input: AgentInput;
|
|
18
|
+
event: AgentMessageInput;
|
|
19
|
+
}): Promise<void>;
|
|
20
|
+
|
|
21
|
+
export { type AgentInput, type AgentMessageInput, agentMessageHook, agentWorkflow };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as workflow from 'workflow';
|
|
2
|
+
import { a as StorageConfig } from './types-vRxN1Qz1.js';
|
|
3
|
+
import 'ai';
|
|
4
|
+
import 'zod';
|
|
5
|
+
import 'errore';
|
|
6
|
+
|
|
7
|
+
type AgentInput = {
|
|
8
|
+
sessionId: string;
|
|
9
|
+
storageConfig: StorageConfig;
|
|
10
|
+
};
|
|
11
|
+
type AgentMessageInput = {
|
|
12
|
+
assistantMessageId: string;
|
|
13
|
+
hookToken: string;
|
|
14
|
+
};
|
|
15
|
+
declare const agentMessageHook: workflow.TypedHook<AgentMessageInput, AgentMessageInput>;
|
|
16
|
+
declare function agentWorkflow({ input, event, }: {
|
|
17
|
+
input: AgentInput;
|
|
18
|
+
event: AgentMessageInput;
|
|
19
|
+
}): Promise<void>;
|
|
20
|
+
|
|
21
|
+
export { type AgentInput, type AgentMessageInput, agentMessageHook, agentWorkflow };
|