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.
Files changed (150) hide show
  1. package/AGENTS.md +11 -0
  2. package/CHANGELOG.md +27 -0
  3. package/README.md +29 -0
  4. package/dist/ai-server.d.ts +1 -1
  5. package/dist/ai-server.d.ts.map +1 -1
  6. package/dist/ai-server.js +13 -11
  7. package/dist/ai-server.js.map +1 -1
  8. package/dist/ai.d.ts +1 -1
  9. package/dist/index.d.ts +1 -1
  10. package/dist/scheduler-qstash.d.ts +2 -2
  11. package/dist/scheduler-qstash.js +1 -1
  12. package/dist/scheduler-vercel.d.ts +2 -2
  13. package/dist/scheduler-vercel.js +1 -1
  14. package/dist/{server-286j79Mt.js → server-B2XNevQA.js} +123 -53
  15. package/dist/server-B2XNevQA.js.map +1 -0
  16. package/dist/{server-DgXmORIq.d.ts → server-DjPhHnbI.d.ts} +7 -4
  17. package/dist/server-DjPhHnbI.d.ts.map +1 -0
  18. package/dist/server.d.ts +3 -3
  19. package/dist/server.js +1 -1
  20. package/dist/store-N8PXxDAS.js.map +1 -1
  21. package/dist/{store-flRz1OWh.d.ts → store-RJO35BMj.d.ts} +25 -8
  22. package/dist/store-RJO35BMj.d.ts.map +1 -0
  23. package/dist/store-memory.d.ts +1 -1
  24. package/dist/store-memory.d.ts.map +1 -1
  25. package/dist/store-memory.js +79 -19
  26. package/dist/store-memory.js.map +1 -1
  27. package/dist/store-postgres.d.ts +1 -1
  28. package/dist/store-postgres.d.ts.map +1 -1
  29. package/dist/store-postgres.js +230 -101
  30. package/dist/store-postgres.js.map +1 -1
  31. package/dist/{store-redis-core-DEYO8Ryv.js → store-redis-core-DT01r4GZ.js} +167 -29
  32. package/dist/store-redis-core-DT01r4GZ.js.map +1 -0
  33. package/dist/store-redis-http.d.ts +1 -1
  34. package/dist/store-redis-http.js +2 -2
  35. package/dist/store-redis-http.js.map +1 -1
  36. package/dist/store-redis.d.ts +1 -1
  37. package/dist/store-redis.js +2 -2
  38. package/dist/store-redis.js.map +1 -1
  39. package/dist/store-sqlite.d.ts +1 -1
  40. package/dist/store-sqlite.d.ts.map +1 -1
  41. package/dist/store-sqlite.js +103 -19
  42. package/dist/store-sqlite.js.map +1 -1
  43. package/docs/concepts/02-handlers.mdx +4 -0
  44. package/docs/concepts/04-state.mdx +57 -9
  45. package/docs/guides/06-ai-agents.mdx +2 -1
  46. package/docs/guides/07-examples.mdx +56 -0
  47. package/docs/index.mdx +13 -0
  48. package/docs/reference/01-api.mdx +39 -16
  49. package/examples/README.md +15 -0
  50. package/examples/playground/AGENTS.md +11 -0
  51. package/examples/playground/DEPLOY.md +106 -0
  52. package/examples/playground/README.md +19 -0
  53. package/examples/playground/activity-feed.test.ts +10 -0
  54. package/examples/playground/app/agent/[agentId]/agent-client.tsx +376 -0
  55. package/examples/playground/app/agent/[agentId]/page.tsx +29 -0
  56. package/examples/playground/app/agent/events/route.ts +4 -0
  57. package/examples/playground/app/agent/model.ts +3 -0
  58. package/examples/playground/app/agent/new-agent-session.tsx +98 -0
  59. package/examples/playground/app/agent/page.tsx +25 -0
  60. package/examples/playground/app/agent/scheduler/route.ts +5 -0
  61. package/examples/playground/app/agent/server.ts +153 -0
  62. package/examples/playground/app/agent/session.ts +13 -0
  63. package/examples/playground/app/canvas/[canvasId]/canvas-client.tsx +682 -0
  64. package/examples/playground/app/canvas/[canvasId]/canvas-replay.test.ts +68 -0
  65. package/examples/playground/app/canvas/[canvasId]/canvas-replay.ts +19 -0
  66. package/examples/playground/app/canvas/[canvasId]/page.tsx +22 -0
  67. package/examples/playground/app/canvas/[canvasId]/session.ts +19 -0
  68. package/examples/playground/app/canvas/events/route.ts +13 -0
  69. package/examples/playground/app/canvas/model.ts +94 -0
  70. package/examples/playground/app/canvas/open-canvas.tsx +40 -0
  71. package/examples/playground/app/canvas/page.tsx +20 -0
  72. package/examples/playground/app/canvas/server.ts +9 -0
  73. package/examples/playground/app/chat/[chatId]/agent-stream-drawer.test.tsx +118 -0
  74. package/examples/playground/app/chat/[chatId]/agent-stream-drawer.tsx +316 -0
  75. package/examples/playground/app/chat/[chatId]/chat-client.tsx +922 -0
  76. package/examples/playground/app/chat/[chatId]/chat-view.test.ts +152 -0
  77. package/examples/playground/app/chat/[chatId]/chat-view.ts +101 -0
  78. package/examples/playground/app/chat/[chatId]/composer.test.ts +44 -0
  79. package/examples/playground/app/chat/[chatId]/composer.ts +30 -0
  80. package/examples/playground/app/chat/[chatId]/page.tsx +30 -0
  81. package/examples/playground/app/chat/[chatId]/session.ts +7 -0
  82. package/examples/playground/app/chat/events/route.ts +7 -0
  83. package/examples/playground/app/chat/model.test.ts +155 -0
  84. package/examples/playground/app/chat/model.ts +310 -0
  85. package/examples/playground/app/chat/new-conversation.tsx +16 -0
  86. package/examples/playground/app/chat/page.tsx +25 -0
  87. package/examples/playground/app/chat/scheduler/route.ts +5 -0
  88. package/examples/playground/app/chat/server.ts +184 -0
  89. package/examples/playground/app/components/activity-feed.tsx +54 -0
  90. package/examples/playground/app/components/connection-pill.tsx +29 -0
  91. package/examples/playground/app/counter/counter-client.tsx +72 -0
  92. package/examples/playground/app/counter/events/route.ts +4 -0
  93. package/examples/playground/app/counter/model.test.ts +36 -0
  94. package/examples/playground/app/counter/model.ts +31 -0
  95. package/examples/playground/app/counter/page.tsx +24 -0
  96. package/examples/playground/app/counter/server.ts +9 -0
  97. package/examples/playground/app/counter/session.ts +13 -0
  98. package/examples/playground/app/documents/[documentId]/code-editor.tsx +80 -0
  99. package/examples/playground/app/documents/[documentId]/document-client.tsx +525 -0
  100. package/examples/playground/app/documents/[documentId]/page.tsx +23 -0
  101. package/examples/playground/app/documents/[documentId]/session.ts +7 -0
  102. package/examples/playground/app/documents/events/route.ts +4 -0
  103. package/examples/playground/app/documents/model.ts +55 -0
  104. package/examples/playground/app/documents/open-document.tsx +40 -0
  105. package/examples/playground/app/documents/page.tsx +22 -0
  106. package/examples/playground/app/documents/server.ts +9 -0
  107. package/examples/playground/app/globals.css +2078 -0
  108. package/examples/playground/app/layout.tsx +44 -0
  109. package/examples/playground/app/orders/[orderId]/order-client.tsx +140 -0
  110. package/examples/playground/app/orders/[orderId]/page.tsx +29 -0
  111. package/examples/playground/app/orders/[orderId]/session.ts +11 -0
  112. package/examples/playground/app/orders/create/route.ts +30 -0
  113. package/examples/playground/app/orders/events/route.ts +4 -0
  114. package/examples/playground/app/orders/model.ts +79 -0
  115. package/examples/playground/app/orders/new-order-form.tsx +98 -0
  116. package/examples/playground/app/orders/page.tsx +22 -0
  117. package/examples/playground/app/orders/scheduler/route.ts +5 -0
  118. package/examples/playground/app/orders/server.ts +50 -0
  119. package/examples/playground/app/page.tsx +102 -0
  120. package/examples/playground/app/recovery/[recoveryId]/page.tsx +31 -0
  121. package/examples/playground/app/recovery/[recoveryId]/recovery-client.tsx +144 -0
  122. package/examples/playground/app/recovery/[recoveryId]/session.ts +7 -0
  123. package/examples/playground/app/recovery/events/route.ts +3 -0
  124. package/examples/playground/app/recovery/model.ts +55 -0
  125. package/examples/playground/app/recovery/new-recovery-session.tsx +20 -0
  126. package/examples/playground/app/recovery/page.tsx +22 -0
  127. package/examples/playground/app/recovery/scheduler/route.ts +7 -0
  128. package/examples/playground/app/recovery/server.ts +53 -0
  129. package/examples/playground/app/recovery/start/route.ts +41 -0
  130. package/examples/playground/css.d.ts +4 -0
  131. package/examples/playground/lib/store.ts +15 -0
  132. package/examples/playground/next-env.d.ts +5 -0
  133. package/examples/playground/next.config.ts +10 -0
  134. package/examples/playground/package.json +46 -0
  135. package/examples/playground/tsconfig.json +37 -0
  136. package/examples/playground/vercel.json +40 -0
  137. package/package.json +5 -2
  138. package/src/ai-server.ts +27 -10
  139. package/src/server.ts +242 -87
  140. package/src/store-memory.ts +138 -20
  141. package/src/store-postgres.ts +355 -138
  142. package/src/store-redis-core.ts +201 -27
  143. package/src/store-redis-http.ts +1 -1
  144. package/src/store-redis.ts +1 -1
  145. package/src/store-sqlite.ts +191 -34
  146. package/src/store.ts +27 -9
  147. package/dist/server-286j79Mt.js.map +0 -1
  148. package/dist/server-DgXmORIq.d.ts.map +0 -1
  149. package/dist/store-flRz1OWh.d.ts.map +0 -1
  150. 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
+ })