experimental-a2 0.7.0 → 0.8.1
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/AGENTS.md +11 -0
- package/CHANGELOG.md +27 -0
- package/README.md +29 -0
- package/dist/ai-server.d.ts +1 -1
- package/dist/ai-server.d.ts.map +1 -1
- package/dist/ai-server.js +13 -11
- package/dist/ai-server.js.map +1 -1
- package/dist/ai.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/scheduler-qstash.d.ts +2 -2
- package/dist/scheduler-qstash.js +1 -1
- package/dist/scheduler-vercel.d.ts +2 -2
- package/dist/scheduler-vercel.js +1 -1
- package/dist/{server-286j79Mt.js → server-B2XNevQA.js} +123 -53
- package/dist/server-B2XNevQA.js.map +1 -0
- package/dist/{server-DgXmORIq.d.ts → server-DjPhHnbI.d.ts} +7 -4
- package/dist/server-DjPhHnbI.d.ts.map +1 -0
- package/dist/server.d.ts +3 -3
- package/dist/server.js +1 -1
- package/dist/store-N8PXxDAS.js.map +1 -1
- package/dist/{store-flRz1OWh.d.ts → store-RJO35BMj.d.ts} +25 -8
- package/dist/store-RJO35BMj.d.ts.map +1 -0
- package/dist/store-memory.d.ts +1 -1
- package/dist/store-memory.d.ts.map +1 -1
- package/dist/store-memory.js +79 -19
- package/dist/store-memory.js.map +1 -1
- package/dist/store-postgres.d.ts +1 -1
- package/dist/store-postgres.d.ts.map +1 -1
- package/dist/store-postgres.js +230 -101
- package/dist/store-postgres.js.map +1 -1
- package/dist/{store-redis-core-DEYO8Ryv.js → store-redis-core-DT01r4GZ.js} +167 -29
- package/dist/store-redis-core-DT01r4GZ.js.map +1 -0
- package/dist/store-redis-http.d.ts +1 -1
- package/dist/store-redis-http.js +2 -2
- package/dist/store-redis-http.js.map +1 -1
- package/dist/store-redis.d.ts +1 -1
- package/dist/store-redis.js +2 -2
- package/dist/store-redis.js.map +1 -1
- package/dist/store-sqlite.d.ts +1 -1
- package/dist/store-sqlite.d.ts.map +1 -1
- package/dist/store-sqlite.js +103 -19
- package/dist/store-sqlite.js.map +1 -1
- package/docs/concepts/02-handlers.mdx +4 -0
- package/docs/concepts/04-state.mdx +57 -9
- package/docs/guides/06-ai-agents.mdx +2 -1
- package/docs/guides/07-examples.mdx +56 -0
- package/docs/index.mdx +13 -0
- package/docs/reference/01-api.mdx +39 -16
- package/examples/README.md +15 -0
- package/examples/playground/AGENTS.md +11 -0
- package/examples/playground/DEPLOY.md +106 -0
- package/examples/playground/README.md +19 -0
- package/examples/playground/activity-feed.test.ts +10 -0
- package/examples/playground/app/agent/[agentId]/agent-client.tsx +376 -0
- package/examples/playground/app/agent/[agentId]/page.tsx +29 -0
- package/examples/playground/app/agent/events/route.ts +4 -0
- package/examples/playground/app/agent/model.ts +3 -0
- package/examples/playground/app/agent/new-agent-session.tsx +98 -0
- package/examples/playground/app/agent/page.tsx +25 -0
- package/examples/playground/app/agent/scheduler/route.ts +5 -0
- package/examples/playground/app/agent/server.ts +153 -0
- package/examples/playground/app/agent/session.ts +13 -0
- package/examples/playground/app/canvas/[canvasId]/canvas-client.tsx +682 -0
- package/examples/playground/app/canvas/[canvasId]/canvas-replay.test.ts +68 -0
- package/examples/playground/app/canvas/[canvasId]/canvas-replay.ts +19 -0
- package/examples/playground/app/canvas/[canvasId]/page.tsx +22 -0
- package/examples/playground/app/canvas/[canvasId]/session.ts +19 -0
- package/examples/playground/app/canvas/events/route.ts +13 -0
- package/examples/playground/app/canvas/model.ts +94 -0
- package/examples/playground/app/canvas/open-canvas.tsx +40 -0
- package/examples/playground/app/canvas/page.tsx +20 -0
- package/examples/playground/app/canvas/server.ts +9 -0
- package/examples/playground/app/chat/[chatId]/agent-stream-drawer.test.tsx +118 -0
- package/examples/playground/app/chat/[chatId]/agent-stream-drawer.tsx +316 -0
- package/examples/playground/app/chat/[chatId]/chat-client.tsx +922 -0
- package/examples/playground/app/chat/[chatId]/chat-view.test.ts +152 -0
- package/examples/playground/app/chat/[chatId]/chat-view.ts +101 -0
- package/examples/playground/app/chat/[chatId]/composer.test.ts +44 -0
- package/examples/playground/app/chat/[chatId]/composer.ts +30 -0
- package/examples/playground/app/chat/[chatId]/page.tsx +30 -0
- package/examples/playground/app/chat/[chatId]/session.ts +7 -0
- package/examples/playground/app/chat/events/route.ts +7 -0
- package/examples/playground/app/chat/model.test.ts +155 -0
- package/examples/playground/app/chat/model.ts +310 -0
- package/examples/playground/app/chat/new-conversation.tsx +16 -0
- package/examples/playground/app/chat/page.tsx +25 -0
- package/examples/playground/app/chat/scheduler/route.ts +5 -0
- package/examples/playground/app/chat/server.ts +184 -0
- package/examples/playground/app/components/activity-feed.tsx +54 -0
- package/examples/playground/app/components/connection-pill.tsx +29 -0
- package/examples/playground/app/counter/counter-client.tsx +72 -0
- package/examples/playground/app/counter/events/route.ts +4 -0
- package/examples/playground/app/counter/model.test.ts +36 -0
- package/examples/playground/app/counter/model.ts +31 -0
- package/examples/playground/app/counter/page.tsx +24 -0
- package/examples/playground/app/counter/server.ts +9 -0
- package/examples/playground/app/counter/session.ts +13 -0
- package/examples/playground/app/documents/[documentId]/code-editor.tsx +80 -0
- package/examples/playground/app/documents/[documentId]/document-client.tsx +525 -0
- package/examples/playground/app/documents/[documentId]/page.tsx +23 -0
- package/examples/playground/app/documents/[documentId]/session.ts +7 -0
- package/examples/playground/app/documents/events/route.ts +4 -0
- package/examples/playground/app/documents/model.ts +55 -0
- package/examples/playground/app/documents/open-document.tsx +40 -0
- package/examples/playground/app/documents/page.tsx +22 -0
- package/examples/playground/app/documents/server.ts +9 -0
- package/examples/playground/app/globals.css +2078 -0
- package/examples/playground/app/layout.tsx +44 -0
- package/examples/playground/app/orders/[orderId]/order-client.tsx +140 -0
- package/examples/playground/app/orders/[orderId]/page.tsx +29 -0
- package/examples/playground/app/orders/[orderId]/session.ts +11 -0
- package/examples/playground/app/orders/create/route.ts +30 -0
- package/examples/playground/app/orders/events/route.ts +4 -0
- package/examples/playground/app/orders/model.ts +79 -0
- package/examples/playground/app/orders/new-order-form.tsx +98 -0
- package/examples/playground/app/orders/page.tsx +22 -0
- package/examples/playground/app/orders/scheduler/route.ts +5 -0
- package/examples/playground/app/orders/server.ts +50 -0
- package/examples/playground/app/page.tsx +102 -0
- package/examples/playground/app/recovery/[recoveryId]/page.tsx +31 -0
- package/examples/playground/app/recovery/[recoveryId]/recovery-client.tsx +144 -0
- package/examples/playground/app/recovery/[recoveryId]/session.ts +7 -0
- package/examples/playground/app/recovery/events/route.ts +3 -0
- package/examples/playground/app/recovery/model.ts +55 -0
- package/examples/playground/app/recovery/new-recovery-session.tsx +20 -0
- package/examples/playground/app/recovery/page.tsx +22 -0
- package/examples/playground/app/recovery/scheduler/route.ts +7 -0
- package/examples/playground/app/recovery/server.ts +53 -0
- package/examples/playground/app/recovery/start/route.ts +41 -0
- package/examples/playground/css.d.ts +4 -0
- package/examples/playground/lib/store.ts +15 -0
- package/examples/playground/next-env.d.ts +5 -0
- package/examples/playground/next.config.ts +10 -0
- package/examples/playground/package.json +46 -0
- package/examples/playground/tsconfig.json +37 -0
- package/examples/playground/vercel.json +40 -0
- package/package.json +5 -2
- package/src/ai-server.ts +27 -10
- package/src/server.ts +242 -87
- package/src/store-memory.ts +138 -20
- package/src/store-postgres.ts +355 -138
- package/src/store-redis-core.ts +201 -27
- package/src/store-redis-http.ts +1 -1
- package/src/store-redis.ts +1 -1
- package/src/store-sqlite.ts +191 -34
- package/src/store.ts +27 -9
- package/dist/server-286j79Mt.js.map +0 -1
- package/dist/server-DgXmORIq.d.ts.map +0 -1
- package/dist/store-flRz1OWh.d.ts.map +0 -1
- package/dist/store-redis-core-DEYO8Ryv.js.map +0 -1
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import 'server-only'
|
|
2
|
+
import { Buffer } from 'node:buffer'
|
|
3
|
+
import { createHash } from 'node:crypto'
|
|
4
|
+
import { Sandbox } from '@vercel/sandbox'
|
|
5
|
+
import { tool } from 'ai'
|
|
6
|
+
import { handlerContext, inputs } from 'experimental-a2/ai'
|
|
7
|
+
import { createAgentServer } from 'experimental-a2/ai/server'
|
|
8
|
+
import { vercelQueues } from 'experimental-a2/scheduler-vercel'
|
|
9
|
+
import { z } from 'zod'
|
|
10
|
+
import { store } from '@/lib/store'
|
|
11
|
+
import { demoAgent } from './model'
|
|
12
|
+
|
|
13
|
+
const maxReminderDelaySeconds = 6 * 24 * 60 * 60
|
|
14
|
+
const bashTimeoutMs = 120_000
|
|
15
|
+
const maxBashOutputBytes = 64 * 1024
|
|
16
|
+
|
|
17
|
+
const sandboxName = (sessionId: string): string =>
|
|
18
|
+
`a2-playground-agent-${createHash('sha256').update(sessionId).digest('hex').slice(0, 32)}`
|
|
19
|
+
|
|
20
|
+
const tools = {
|
|
21
|
+
inspectService: tool({
|
|
22
|
+
description: 'Inspect the current health and runbook for a service.',
|
|
23
|
+
inputSchema: z.object({ service: z.string() }),
|
|
24
|
+
execute: ({ service }) => ({
|
|
25
|
+
service,
|
|
26
|
+
errorRate: '12.4%',
|
|
27
|
+
runbook: 'restart after sustained 10%',
|
|
28
|
+
}),
|
|
29
|
+
}),
|
|
30
|
+
restartService: tool({
|
|
31
|
+
description: 'Restart every instance of a service.',
|
|
32
|
+
inputSchema: z.object({ service: z.string() }),
|
|
33
|
+
execute: ({ service }) => ({
|
|
34
|
+
service,
|
|
35
|
+
status: 'restarted',
|
|
36
|
+
instances: 3,
|
|
37
|
+
}),
|
|
38
|
+
}),
|
|
39
|
+
bash: tool({
|
|
40
|
+
description:
|
|
41
|
+
"Execute a Bash command in this session's persistent Vercel Sandbox. Files created by one command are available to later commands in the same session.",
|
|
42
|
+
inputSchema: z.object({
|
|
43
|
+
command: z.string().min(1).describe('The Bash command to execute.'),
|
|
44
|
+
}),
|
|
45
|
+
execute: async ({ command }) => {
|
|
46
|
+
const context = handlerContext(demoAgent)
|
|
47
|
+
const sandbox = await Sandbox.getOrCreate({
|
|
48
|
+
name: sandboxName(context.session.id),
|
|
49
|
+
persistent: true,
|
|
50
|
+
signal: context.signal,
|
|
51
|
+
})
|
|
52
|
+
const running = await sandbox.runCommand({
|
|
53
|
+
cmd: '/bin/bash',
|
|
54
|
+
args: ['-lc', command],
|
|
55
|
+
detached: true,
|
|
56
|
+
signal: context.signal,
|
|
57
|
+
timeoutMs: bashTimeoutMs,
|
|
58
|
+
})
|
|
59
|
+
const logs = running.logs({ signal: context.signal })
|
|
60
|
+
let stdout = ''
|
|
61
|
+
let stderr = ''
|
|
62
|
+
let remainingBytes = maxBashOutputBytes
|
|
63
|
+
let truncated = false
|
|
64
|
+
try {
|
|
65
|
+
for await (const log of logs) {
|
|
66
|
+
const bytes = Buffer.from(log.data)
|
|
67
|
+
const retained = bytes.subarray(0, remainingBytes)
|
|
68
|
+
const text =
|
|
69
|
+
retained.byteLength === bytes.byteLength
|
|
70
|
+
? log.data
|
|
71
|
+
: new TextDecoder().decode(retained, { stream: true })
|
|
72
|
+
if (log.stream === 'stdout') stdout += text
|
|
73
|
+
else stderr += text
|
|
74
|
+
remainingBytes -= retained.byteLength
|
|
75
|
+
if (retained.byteLength < bytes.byteLength) {
|
|
76
|
+
truncated = true
|
|
77
|
+
break
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
} catch (error) {
|
|
81
|
+
try {
|
|
82
|
+
await running.kill('SIGKILL')
|
|
83
|
+
} catch {}
|
|
84
|
+
throw error
|
|
85
|
+
} finally {
|
|
86
|
+
logs.close()
|
|
87
|
+
}
|
|
88
|
+
if (truncated) {
|
|
89
|
+
try {
|
|
90
|
+
await running.kill('SIGKILL')
|
|
91
|
+
} catch {}
|
|
92
|
+
}
|
|
93
|
+
const result = await running.wait({ signal: context.signal })
|
|
94
|
+
return { exitCode: result.exitCode, stdout, stderr, truncated }
|
|
95
|
+
},
|
|
96
|
+
}),
|
|
97
|
+
setReminder: tool({
|
|
98
|
+
description:
|
|
99
|
+
'Set a reminder for yourself after any delay up to six days. When it is due, it arrives as a new user message.',
|
|
100
|
+
inputSchema: z.object({
|
|
101
|
+
delaySeconds: z
|
|
102
|
+
.number()
|
|
103
|
+
.int()
|
|
104
|
+
.min(1)
|
|
105
|
+
.max(maxReminderDelaySeconds)
|
|
106
|
+
.describe('Seconds from now, from 1 through 518400'),
|
|
107
|
+
reminder: z.string().min(1).max(500),
|
|
108
|
+
}),
|
|
109
|
+
execute: async ({ delaySeconds, reminder }, { toolCallId }) => {
|
|
110
|
+
const context = handlerContext(demoAgent)
|
|
111
|
+
await context.session.schedule(
|
|
112
|
+
`reminder:${toolCallId}`,
|
|
113
|
+
{ delay: `${delaySeconds}s` },
|
|
114
|
+
...inputs.message({
|
|
115
|
+
id: `reminder:${context.event.id}`,
|
|
116
|
+
role: 'user',
|
|
117
|
+
parts: [{ type: 'text', text: `Reminder: ${reminder}` }],
|
|
118
|
+
}),
|
|
119
|
+
)
|
|
120
|
+
return { scheduled: true, delaySeconds, reminder }
|
|
121
|
+
},
|
|
122
|
+
}),
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export const agentScheduler =
|
|
126
|
+
process.env.VERCEL || process.env.A2_QUEUES
|
|
127
|
+
? vercelQueues({ topic: 'a2-agent' })
|
|
128
|
+
: undefined
|
|
129
|
+
|
|
130
|
+
export const agentServer = createAgentServer({
|
|
131
|
+
...(store ? { store } : {}),
|
|
132
|
+
...(agentScheduler ? { scheduler: agentScheduler } : {}),
|
|
133
|
+
agent: demoAgent,
|
|
134
|
+
model: 'openai/gpt-5.6-luna',
|
|
135
|
+
tools,
|
|
136
|
+
instructions: `You are an incident-response agent for the playground.
|
|
137
|
+
When responding to an incident, inspect checkout-api before taking action. Its
|
|
138
|
+
runbook says to restart when the error rate remains above 10%. If it does,
|
|
139
|
+
immediately call restartService. Do not ask for approval in prose: that tool
|
|
140
|
+
automatically creates the built-in approval. After the operator responds,
|
|
141
|
+
continue and report the result.
|
|
142
|
+
|
|
143
|
+
When the operator asks for a reminder, always call setReminder and only say it
|
|
144
|
+
was scheduled after the tool succeeds. A user message beginning with
|
|
145
|
+
"Reminder:" is a reminder that is now due: respond to it, and do not schedule
|
|
146
|
+
it again.
|
|
147
|
+
|
|
148
|
+
When the operator asks you to run a shell command, call bash. Make one bash call
|
|
149
|
+
at a time and wait for its result before calling it again. Be concise.`,
|
|
150
|
+
generation: {
|
|
151
|
+
toolApproval: { restartService: 'user-approval' },
|
|
152
|
+
},
|
|
153
|
+
})
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
import { createClient } from 'experimental-a2/client'
|
|
3
|
+
import { createReact } from 'experimental-a2/react'
|
|
4
|
+
import { demoAgent } from './model'
|
|
5
|
+
|
|
6
|
+
export const agentClient = createClient({
|
|
7
|
+
reducer: demoAgent.reducer,
|
|
8
|
+
api: '/agent/events',
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
export const { SessionProvider, useSession } = createReact({
|
|
12
|
+
client: agentClient,
|
|
13
|
+
})
|