experimental-a2 0.16.1 → 0.18.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/CHANGELOG.md +373 -0
- package/README.md +1 -1
- package/dist/{actor-ohPC-81x.d.ts → actor-Bjce9_5U.d.ts} +21 -11
- package/dist/actor-Bjce9_5U.d.ts.map +1 -0
- package/dist/actor-client.d.ts +2 -5
- package/dist/actor-client.d.ts.map +1 -1
- package/dist/actor-client.js +13 -4
- package/dist/actor-client.js.map +1 -1
- package/dist/actor-react.d.ts +5 -3
- package/dist/actor-react.d.ts.map +1 -1
- package/dist/actor-react.js +20 -10
- package/dist/actor-react.js.map +1 -1
- package/dist/{actor-shared-B5tJfzt-.js → actor-shared-t7w8xIKP.js} +12 -7
- package/dist/actor-shared-t7w8xIKP.js.map +1 -0
- package/dist/actor.d.ts +1 -1
- package/dist/actor.js +42 -23
- package/dist/actor.js.map +1 -1
- package/dist/{ai-DgOBltJ_.js → ai-BpOGm-zB.js} +621 -216
- package/dist/ai-BpOGm-zB.js.map +1 -0
- package/dist/{ai-CrEf6p_W.d.ts → ai-DrUaMyRt.d.ts} +114 -100
- package/dist/ai-DrUaMyRt.d.ts.map +1 -0
- package/dist/ai-client.d.ts +27 -0
- package/dist/ai-client.d.ts.map +1 -0
- package/dist/ai-client.js +29 -0
- package/dist/ai-client.js.map +1 -0
- package/dist/ai-fx.browser.d.ts +1 -0
- package/dist/ai-fx.browser.js +6 -0
- package/dist/ai-fx.browser.js.map +1 -0
- package/dist/ai-fx.d.ts +10 -0
- package/dist/ai-fx.d.ts.map +1 -0
- package/dist/ai-fx.js +634 -0
- package/dist/ai-fx.js.map +1 -0
- package/dist/ai-harness-BuLh_EYi.js +273 -0
- package/dist/ai-harness-BuLh_EYi.js.map +1 -0
- package/dist/ai-harness-DvsPeJeB.d.ts +26 -0
- package/dist/ai-harness-DvsPeJeB.d.ts.map +1 -0
- package/dist/ai-pi.browser.d.ts +1 -0
- package/dist/ai-pi.browser.js +6 -0
- package/dist/ai-pi.browser.js.map +1 -0
- package/dist/ai-pi.d.ts +17 -0
- package/dist/ai-pi.d.ts.map +1 -0
- package/dist/ai-pi.js +904 -0
- package/dist/ai-pi.js.map +1 -0
- package/dist/ai-react.d.ts +96 -0
- package/dist/ai-react.d.ts.map +1 -0
- package/dist/ai-react.js +142 -0
- package/dist/ai-react.js.map +1 -0
- package/dist/ai-server.browser.js +2 -2
- package/dist/ai-server.browser.js.map +1 -1
- package/dist/ai-server.d.ts +109 -43
- package/dist/ai-server.d.ts.map +1 -1
- package/dist/ai-server.js +526 -283
- package/dist/ai-server.js.map +1 -1
- package/dist/ai.d.ts +2 -2
- package/dist/ai.js +2 -2
- package/dist/bounded-cache-CPHWF-8h.js +41 -0
- package/dist/bounded-cache-CPHWF-8h.js.map +1 -0
- package/dist/{client-BYzHjkwU.js → client-BReKqwZC.js} +447 -80
- package/dist/client-BReKqwZC.js.map +1 -0
- package/dist/{client-CzyacQpJ.d.ts → client-h_DKFAjj.d.ts} +14 -13
- package/dist/client-h_DKFAjj.d.ts.map +1 -0
- package/dist/client.d.ts +4 -2
- package/dist/client.js +1 -1
- package/dist/{contract-CKRg_E4q.js → contract-BYKASlCV.js} +12 -21
- package/dist/contract-BYKASlCV.js.map +1 -0
- package/dist/{idempotent-replay-DVOlyYbx.js → idempotent-replay-JdgMQRRm.js} +2 -2
- package/dist/{idempotent-replay-DVOlyYbx.js.map → idempotent-replay-JdgMQRRm.js.map} +1 -1
- package/dist/index.d.ts +6 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/{errors-DvhSXnxk.d.ts → initial-snapshot-Bx-c0pDP.d.ts} +7 -3
- package/dist/initial-snapshot-Bx-c0pDP.d.ts.map +1 -0
- package/dist/{internal-Dq2qYxou.js → internal-B2T3U4Rq.js} +29 -2
- package/dist/internal-B2T3U4Rq.js.map +1 -0
- package/dist/otel.d.ts +1 -1
- package/dist/react-BBXgHWFc.d.ts +86 -0
- package/dist/react-BBXgHWFc.d.ts.map +1 -0
- package/dist/react.d.ts +2 -122
- package/dist/react.js +107 -100
- package/dist/react.js.map +1 -1
- package/dist/reducer-BAXc8JyF.js +87 -0
- package/dist/reducer-BAXc8JyF.js.map +1 -0
- package/dist/{reducer-otzHjuJj.d.ts → reducer-CqA59Q6U.d.ts} +46 -30
- package/dist/reducer-CqA59Q6U.d.ts.map +1 -0
- package/dist/reducer-runtime-DQwz_J59.js +28 -0
- package/dist/reducer-runtime-DQwz_J59.js.map +1 -0
- package/dist/scheduler-qstash.d.ts +3 -3
- package/dist/scheduler-qstash.d.ts.map +1 -1
- package/dist/scheduler-qstash.js +33 -10
- package/dist/scheduler-qstash.js.map +1 -1
- package/dist/{scheduler-task-BpzhPnRS.js → scheduler-task-X1SToDjP.js} +18 -3
- package/dist/scheduler-task-X1SToDjP.js.map +1 -0
- package/dist/scheduler-vercel.d.ts +4 -9
- package/dist/scheduler-vercel.d.ts.map +1 -1
- package/dist/scheduler-vercel.js +25 -44
- package/dist/scheduler-vercel.js.map +1 -1
- package/dist/{server-BD5ckxZb.js → server-Dw_k_7kO.js} +904 -219
- package/dist/server-Dw_k_7kO.js.map +1 -0
- package/dist/{server-DbD7IJVK.d.ts → server-En7cbi3v.d.ts} +116 -26
- package/dist/server-En7cbi3v.d.ts.map +1 -0
- package/dist/server.d.ts +4 -4
- package/dist/server.js +2 -2
- package/dist/session-clear-Bo-XTFEy.d.ts +12 -0
- package/dist/session-clear-Bo-XTFEy.d.ts.map +1 -0
- package/dist/{errors-DCk6ch5n.js → session-clear-DGI4jTQ5.js} +17 -2
- package/dist/session-clear-DGI4jTQ5.js.map +1 -0
- package/dist/{store-DyZM6fS5.d.ts → store-Djdv0bnZ.d.ts} +73 -3
- package/dist/store-Djdv0bnZ.d.ts.map +1 -0
- package/dist/store-N8PXxDAS.js.map +1 -1
- package/dist/store-memory.d.ts +1 -1
- package/dist/store-memory.d.ts.map +1 -1
- package/dist/store-memory.js +205 -66
- package/dist/store-memory.js.map +1 -1
- package/dist/{store-polling-CmxUbV93.js → store-polling-B5FcwJfo.js} +21 -4
- package/dist/store-polling-B5FcwJfo.js.map +1 -0
- package/dist/store-postgres.d.ts +1 -1
- package/dist/store-postgres.d.ts.map +1 -1
- package/dist/store-postgres.js +450 -108
- package/dist/store-postgres.js.map +1 -1
- package/dist/{store-presence-polling-C7-XZyW9.js → store-presence-polling-BAwS8RWn.js} +3 -3
- package/dist/{store-presence-polling-C7-XZyW9.js.map → store-presence-polling-BAwS8RWn.js.map} +1 -1
- package/dist/store-redis-http.d.ts +1 -1
- package/dist/store-redis-http.d.ts.map +1 -1
- package/dist/store-redis-http.js +293 -11
- package/dist/store-redis-http.js.map +1 -1
- package/dist/store-redis-notify-BRITti_o.js +2493 -0
- package/dist/store-redis-notify-BRITti_o.js.map +1 -0
- package/dist/store-redis.d.ts +1 -1
- package/dist/store-redis.d.ts.map +1 -1
- package/dist/store-redis.js +11 -11
- 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 +197 -33
- package/dist/store-sqlite.js.map +1 -1
- package/dist/stream-buffer-Cx7AAPGq.js +23 -0
- package/dist/stream-buffer-Cx7AAPGq.js.map +1 -0
- package/dist/{telemetry-B5jzpy6y.d.ts → telemetry-Cyfqo6Qt.d.ts} +2 -2
- package/dist/telemetry-Cyfqo6Qt.d.ts.map +1 -0
- package/dist/{wire-BO5wWCb1.js → wire-rSUglYo8.js} +132 -10
- package/dist/wire-rSUglYo8.js.map +1 -0
- package/docs/01-quickstart.mdx +50 -84
- package/docs/{guides/07-examples.mdx → 02-examples.mdx} +10 -20
- package/docs/actors/01-introduction.mdx +48 -82
- package/docs/actors/02-concurrency.mdx +43 -70
- package/docs/actors/03-timers.mdx +28 -42
- package/docs/actors/04-routes.mdx +110 -137
- package/docs/actors/meta.ts +1 -1
- package/docs/agents/01-introduction.mdx +257 -0
- package/docs/agents/02-tools.mdx +247 -0
- package/docs/agents/03-conversations.mdx +538 -0
- package/docs/agents/04-harnesses.mdx +136 -0
- package/docs/agents/meta.ts +1 -0
- package/docs/client/01-react.mdx +294 -0
- package/docs/client/02-transports.mdx +86 -0
- package/docs/client/03-presence.mdx +224 -0
- package/docs/client/meta.ts +1 -0
- package/docs/contract/01-events.mdx +57 -0
- package/docs/contract/02-state.mdx +142 -0
- package/docs/contract/03-sessions.mdx +175 -0
- package/docs/index.mdx +112 -156
- package/docs/reference/01-core.mdx +139 -0
- package/docs/reference/02-server.mdx +855 -0
- package/docs/reference/03-client.mdx +301 -0
- package/docs/reference/04-ai.mdx +722 -0
- package/docs/reference/05-adapters.mdx +351 -0
- package/docs/reference/06-errors.mdx +138 -0
- package/docs/reference/meta.ts +1 -1
- package/docs/server/01-handlers.mdx +200 -0
- package/docs/server/02-timers.mdx +130 -0
- package/docs/server/03-cancellation.mdx +141 -0
- package/docs/server/04-routes.mdx +243 -0
- package/docs/server/05-production.mdx +322 -0
- package/docs/server/06-guarantees.mdx +123 -0
- package/examples/playground/DEPLOY.md +53 -7
- package/examples/playground/app/a0/[appId]/loading.tsx +16 -0
- package/examples/playground/app/a0/[appId]/page.tsx +53 -0
- package/examples/playground/app/a0/a0.css +818 -0
- package/examples/playground/app/a0/app-list.tsx +218 -0
- package/examples/playground/app/a0/app-view.tsx +63 -0
- package/examples/playground/app/a0/apps/[appId]/preview/route.ts +27 -0
- package/examples/playground/app/a0/apps/[appId]/route.ts +28 -0
- package/examples/playground/app/a0/apps.test.ts +128 -0
- package/examples/playground/app/a0/apps.ts +102 -0
- package/examples/playground/app/a0/chat.tsx +410 -0
- package/examples/playground/app/a0/columns.tsx +109 -0
- package/examples/playground/app/a0/context-menu.tsx +116 -0
- package/examples/playground/app/a0/cookies.ts +46 -0
- package/examples/playground/app/a0/crash-on-request.ts +72 -0
- package/examples/playground/app/a0/crashes/route.ts +3 -0
- package/examples/playground/app/a0/crashes.test.ts +33 -0
- package/examples/playground/app/a0/crashes.ts +28 -0
- package/examples/playground/app/a0/devtools.tsx +164 -0
- package/examples/playground/app/a0/events/route.ts +6 -0
- package/examples/playground/app/a0/flags.ts +30 -0
- package/examples/playground/app/a0/fx/events/route.ts +9 -0
- package/examples/playground/app/a0/fx/scheduler/route.ts +7 -0
- package/examples/playground/app/a0/fx/short/events/route.ts +11 -0
- package/examples/playground/app/a0/layout.tsx +38 -0
- package/examples/playground/app/a0/list/route.ts +10 -0
- package/examples/playground/app/a0/model.test.ts +73 -0
- package/examples/playground/app/a0/model.ts +95 -0
- package/examples/playground/app/a0/no-photon.cjs +4 -0
- package/examples/playground/app/a0/no-quickjs.cjs +3 -0
- package/examples/playground/app/a0/page.tsx +14 -0
- package/examples/playground/app/a0/pi/events/route.ts +9 -0
- package/examples/playground/app/a0/pi/scheduler/route.ts +7 -0
- package/examples/playground/app/a0/pi/short/events/route.ts +11 -0
- package/examples/playground/app/a0/preview-pane.tsx +145 -0
- package/examples/playground/app/a0/preview.test.ts +53 -0
- package/examples/playground/app/a0/preview.ts +26 -0
- package/examples/playground/app/a0/sandbox-log.ts +75 -0
- package/examples/playground/app/a0/sandbox-session.ts +152 -0
- package/examples/playground/app/a0/sandbox.ts +191 -0
- package/examples/playground/app/a0/sandboxes/scheduler/route.ts +6 -0
- package/examples/playground/app/a0/scheduler/route.ts +7 -0
- package/examples/playground/app/a0/server.ts +213 -0
- package/examples/playground/app/a0/session.ts +59 -0
- package/examples/playground/app/a0/shell.tsx +158 -0
- package/examples/playground/app/a0/short/events/route.ts +9 -0
- package/examples/playground/app/a0/splitter.tsx +120 -0
- package/examples/playground/app/agent/[agentId]/agent-client.tsx +144 -174
- package/examples/playground/app/agent/[agentId]/command-receipt.test.tsx +65 -0
- package/examples/playground/app/agent/[agentId]/command-receipt.tsx +27 -0
- package/examples/playground/app/agent/[agentId]/compaction-event.tsx +25 -24
- package/examples/playground/app/agent/[agentId]/compaction-panel.test.tsx +119 -0
- package/examples/playground/app/agent/[agentId]/compaction-panel.tsx +208 -165
- package/examples/playground/app/agent/[agentId]/page.tsx +2 -16
- package/examples/playground/app/agent/events/route.ts +5 -2
- package/examples/playground/app/agent/ingress.test.ts +101 -0
- package/examples/playground/app/agent/model-input.test.tsx +58 -0
- package/examples/playground/app/agent/model-input.tsx +115 -0
- package/examples/playground/app/agent/model.test.ts +73 -0
- package/examples/playground/app/agent/model.ts +58 -26
- package/examples/playground/app/agent/new-agent-session.tsx +37 -19
- package/examples/playground/app/agent/page.tsx +4 -4
- package/examples/playground/app/agent/server.ts +19 -15
- package/examples/playground/app/agent/session.ts +5 -6
- package/examples/playground/app/agent/telemetry.test.ts +189 -0
- package/examples/playground/app/agent/telemetry.ts +30 -0
- package/examples/playground/app/agent/trace.test.ts +23 -0
- package/examples/playground/app/agent/trace.ts +18 -0
- package/examples/playground/app/canvas/[canvasId]/canvas-client.tsx +12 -12
- package/examples/playground/app/canvas/[canvasId]/page.tsx +1 -2
- package/examples/playground/app/canvas/[canvasId]/session.ts +2 -2
- package/examples/playground/app/canvas/model.ts +53 -53
- package/examples/playground/app/chat/[chatId]/agent-state.test.ts +176 -0
- package/examples/playground/app/chat/[chatId]/agent-stream-drawer.tsx +16 -1
- package/examples/playground/app/chat/[chatId]/chat-client.tsx +55 -77
- package/examples/playground/app/chat/[chatId]/chat-view.ts +37 -3
- package/examples/playground/app/chat/[chatId]/page.tsx +7 -15
- package/examples/playground/app/chat/[chatId]/session.ts +2 -19
- package/examples/playground/app/chat/agent/route.ts +9 -0
- package/examples/playground/app/chat/model.test.ts +46 -119
- package/examples/playground/app/chat/model.ts +82 -128
- package/examples/playground/app/chat/scheduler/route.ts +2 -2
- package/examples/playground/app/chat/server.test.ts +112 -0
- package/examples/playground/app/chat/server.ts +113 -117
- package/examples/playground/app/components/activity-feed.tsx +30 -1
- package/examples/playground/app/components/activity-history.test.tsx +35 -0
- package/examples/playground/app/components/demo-icons.tsx +89 -0
- package/examples/playground/app/components/demos.tsx +33 -0
- package/examples/playground/app/components/fast-link.test.tsx +58 -0
- package/examples/playground/app/components/fast-link.tsx +55 -0
- package/examples/playground/app/components/site-header.tsx +96 -0
- package/examples/playground/app/counter/counter-client.tsx +3 -3
- package/examples/playground/app/counter/model.test.ts +3 -3
- package/examples/playground/app/counter/model.ts +11 -21
- package/examples/playground/app/counter/page.tsx +2 -15
- package/examples/playground/app/counter/session.ts +2 -2
- package/examples/playground/app/documents/[documentId]/code-editor.tsx +12 -1
- package/examples/playground/app/documents/[documentId]/document-client.tsx +10 -11
- package/examples/playground/app/documents/[documentId]/page.tsx +1 -2
- package/examples/playground/app/documents/[documentId]/session.ts +2 -2
- package/examples/playground/app/documents/model.ts +27 -27
- package/examples/playground/app/globals.css +420 -207
- package/examples/playground/app/initial-state.test.tsx +54 -0
- package/examples/playground/app/layout.tsx +7 -23
- package/examples/playground/app/orders/[orderId]/page.tsx +1 -2
- package/examples/playground/app/orders/[orderId]/session.ts +2 -2
- package/examples/playground/app/orders/model.ts +49 -49
- package/examples/playground/app/page.tsx +13 -102
- package/examples/playground/app/recovery/[recoveryId]/page.tsx +1 -2
- package/examples/playground/app/recovery/[recoveryId]/session.ts +2 -2
- package/examples/playground/app/recovery/model.ts +30 -30
- package/examples/playground/instrumentation.ts +5 -0
- package/examples/playground/next.config.ts +17 -5
- package/examples/playground/package.json +13 -2
- package/examples/playground/scripts/a0-template.ts +77 -0
- package/examples/playground/vercel.json +36 -0
- package/package.json +29 -3
- package/src/actor-client.ts +16 -4
- package/src/actor-react.ts +25 -11
- package/src/actor-shared.ts +21 -6
- package/src/actor.ts +76 -31
- package/src/ai-agent-actions.ts +219 -0
- package/src/ai-agent.ts +2517 -0
- package/src/ai-app-state.ts +91 -0
- package/src/ai-client-state.ts +6 -3
- package/src/ai-client.ts +62 -0
- package/src/ai-context-schema.ts +25 -5
- package/src/ai-context.ts +90 -40
- package/src/ai-control-server.ts +92 -72
- package/src/ai-coordinator.ts +23 -22
- package/src/ai-fx.browser.ts +5 -0
- package/src/ai-fx.ts +833 -0
- package/src/ai-harness.ts +518 -0
- package/src/ai-message-base.ts +209 -0
- package/src/ai-message-projection.ts +262 -64
- package/src/ai-model-metadata.ts +11 -6
- package/src/ai-pi.browser.ts +5 -0
- package/src/ai-pi.ts +1263 -0
- package/src/ai-progress-batches.ts +26 -0
- package/src/ai-projector.ts +95 -14
- package/src/ai-react.ts +146 -0
- package/src/ai-sdk-step.ts +2 -2
- package/src/ai-server.browser.ts +2 -2
- package/src/ai-server.ts +23 -1965
- package/src/ai-stored-state.ts +48 -163
- package/src/ai.ts +339 -155
- package/src/bootstrap-stream.ts +72 -0
- package/src/bounded-cache.ts +55 -0
- package/src/client-render-session.ts +49 -0
- package/src/client.ts +688 -151
- package/src/contract.ts +92 -42
- package/src/deterministic-id.ts +37 -0
- package/src/equal-json.ts +32 -0
- package/src/errors.ts +13 -1
- package/src/index.ts +5 -1
- package/src/initial-snapshot.ts +39 -0
- package/src/internal.ts +52 -0
- package/src/libfx.d.ts +34 -0
- package/src/postgres-notification-scope.ts +14 -3
- package/src/react.ts +171 -206
- package/src/redis-http-reply.ts +256 -0
- package/src/redis-http-stream.ts +73 -0
- package/src/redis-http-subscriptions.ts +13 -5
- package/src/reducer-runtime.ts +52 -0
- package/src/reducer.ts +93 -11
- package/src/scheduler-qstash.ts +49 -20
- package/src/scheduler-task.ts +34 -2
- package/src/scheduler-vercel.ts +32 -84
- package/src/server-fetch.ts +139 -35
- package/src/server.ts +1133 -255
- package/src/session-clear.ts +23 -0
- package/src/session-socket.ts +154 -49
- package/src/sse.ts +71 -4
- package/src/store-memory.ts +252 -75
- package/src/store-polling.ts +18 -4
- package/src/store-postgres.ts +541 -114
- package/src/store-redis-core.ts +1450 -493
- package/src/store-redis-http.ts +18 -2
- package/src/store-redis-notify.ts +262 -85
- package/src/store-redis.ts +19 -9
- package/src/store-sqlite.ts +319 -45
- package/src/store.ts +79 -1
- package/src/stream-buffer.ts +43 -0
- package/src/telemetry.ts +14 -1
- package/src/wire.ts +241 -13
- package/dist/actor-ohPC-81x.d.ts.map +0 -1
- package/dist/actor-shared-B5tJfzt-.js.map +0 -1
- package/dist/ai-CrEf6p_W.d.ts.map +0 -1
- package/dist/ai-DgOBltJ_.js.map +0 -1
- package/dist/client-BYzHjkwU.js.map +0 -1
- package/dist/client-CzyacQpJ.d.ts.map +0 -1
- package/dist/contract-CKRg_E4q.js.map +0 -1
- package/dist/errors-DCk6ch5n.js.map +0 -1
- package/dist/errors-DvhSXnxk.d.ts.map +0 -1
- package/dist/internal-Dq2qYxou.js.map +0 -1
- package/dist/react.d.ts.map +0 -1
- package/dist/reducer-DEMjEY_O.js +0 -29
- package/dist/reducer-DEMjEY_O.js.map +0 -1
- package/dist/reducer-otzHjuJj.d.ts.map +0 -1
- package/dist/scheduler-task-BpzhPnRS.js.map +0 -1
- package/dist/server-BD5ckxZb.js.map +0 -1
- package/dist/server-DbD7IJVK.d.ts.map +0 -1
- package/dist/store-DyZM6fS5.d.ts.map +0 -1
- package/dist/store-polling-CmxUbV93.js.map +0 -1
- package/dist/store-redis-notify-BVLUfI3j.js +0 -1583
- package/dist/store-redis-notify-BVLUfI3j.js.map +0 -1
- package/dist/telemetry-B5jzpy6y.d.ts.map +0 -1
- package/dist/validate-XKT4FSNn.js +0 -30
- package/dist/validate-XKT4FSNn.js.map +0 -1
- package/dist/wire-BO5wWCb1.js.map +0 -1
- package/docs/concepts/01-contracts.mdx +0 -142
- package/docs/concepts/02-handlers.mdx +0 -284
- package/docs/concepts/03-durability.mdx +0 -314
- package/docs/concepts/04-state.mdx +0 -209
- package/docs/guides/01-timers.mdx +0 -185
- package/docs/guides/02-cancellation.mdx +0 -161
- package/docs/guides/03-react.mdx +0 -384
- package/docs/guides/04-local-first.mdx +0 -88
- package/docs/guides/05-production.mdx +0 -521
- package/docs/guides/06-ai-agents.mdx +0 -1318
- package/docs/guides/08-application-data.mdx +0 -113
- package/docs/guides/09-presence.mdx +0 -266
- package/docs/guides/10-transports.mdx +0 -221
- package/docs/reference/01-api.mdx +0 -1896
- package/docs/reference/02-errors.mdx +0 -149
- package/examples/playground/app/agent/[agentId]/compaction/route.ts +0 -14
- package/examples/playground/app/agent/compaction-settings.test.ts +0 -144
- package/examples/playground/app/agent/compaction-settings.ts +0 -49
- package/examples/playground/app/agent/compaction-timeline.test.ts +0 -377
- package/examples/playground/app/agent/compaction-timeline.ts +0 -208
- /package/docs/{concepts → contract}/meta.ts +0 -0
- /package/docs/{guides → server}/meta.ts +0 -0
package/src/ai.ts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
|
+
import type { MessageBase } from './ai-message-base.ts'
|
|
2
|
+
import { reducer as makeReducer } from './reducer.ts'
|
|
1
3
|
/**
|
|
2
|
-
* experimental-a2/ai —
|
|
4
|
+
* experimental-a2/ai — the isomorphic AI protocol.
|
|
3
5
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
6
|
+
* Event schemas, the `AIState` reducer, `agentContract()` for extending
|
|
7
|
+
* both, and pure builders for the events applications append. Model calls
|
|
8
|
+
* and tool implementations stay in experimental-a2/ai/server.
|
|
7
9
|
*/
|
|
8
10
|
|
|
9
11
|
import type {
|
|
10
12
|
FinishReason,
|
|
11
13
|
JSONValue,
|
|
14
|
+
LanguageModelCallOptions,
|
|
12
15
|
LanguageModelUsage,
|
|
13
16
|
UIMessage,
|
|
14
17
|
UIMessageChunk,
|
|
@@ -38,35 +41,55 @@ export type {
|
|
|
38
41
|
InboxItem,
|
|
39
42
|
} from './ai-control.ts'
|
|
40
43
|
import { contract as createContract } from './contract.ts'
|
|
41
|
-
import type { Contract, EventDefs } from './contract.ts'
|
|
44
|
+
import type { Contract, ContractEvent, EventDefs } from './contract.ts'
|
|
42
45
|
import {
|
|
43
46
|
interruptUIMessage,
|
|
44
47
|
pauseUIMessage,
|
|
45
48
|
projectUIMessage,
|
|
49
|
+
projectUIMessageStream,
|
|
50
|
+
hasToolCall,
|
|
51
|
+
type ProjectionChunk,
|
|
46
52
|
type UIMessageCursor,
|
|
47
53
|
} from './ai-projector.ts'
|
|
48
54
|
import { ambientToolScopeStorage } from './internal.ts'
|
|
49
55
|
import {
|
|
50
56
|
upsertMessage,
|
|
57
|
+
retainMessageBase,
|
|
58
|
+
findMessage,
|
|
51
59
|
upsertResponse,
|
|
52
60
|
answerApproval,
|
|
53
61
|
approvalRequestedChunk,
|
|
54
62
|
toolResultChunk,
|
|
63
|
+
toolCalledChunk,
|
|
55
64
|
advanceProjection,
|
|
56
65
|
projectedTools,
|
|
57
66
|
restoreGenerationBase,
|
|
58
67
|
stopGenerationTools,
|
|
59
68
|
interruptGenerationProjection,
|
|
60
69
|
projectedMessage,
|
|
70
|
+
projectedMessageStream,
|
|
61
71
|
reduceToolActivity,
|
|
72
|
+
addCompactionPart,
|
|
73
|
+
isCompactionPart,
|
|
74
|
+
settleAbandonedCompaction,
|
|
75
|
+
settleCompactionPart,
|
|
62
76
|
} from './ai-message-projection.ts'
|
|
63
|
-
import {
|
|
64
|
-
import {
|
|
65
|
-
|
|
77
|
+
import type { Reducer } from './reducer.ts'
|
|
78
|
+
import { withReducerRuntime } from './reducer-runtime.ts'
|
|
79
|
+
import { withAIStorage } from './ai-stored-state.ts'
|
|
80
|
+
import {
|
|
81
|
+
appSlice,
|
|
82
|
+
isAIStateKey,
|
|
83
|
+
registerAgentReducer,
|
|
84
|
+
withAppSlice,
|
|
85
|
+
type AppReducer,
|
|
86
|
+
} from './ai-app-state.ts'
|
|
66
87
|
import {
|
|
67
88
|
flattenProgressBatches,
|
|
68
89
|
progressBatches,
|
|
90
|
+
progressOwnedBy,
|
|
69
91
|
type ProgressBatches,
|
|
92
|
+
type StoredProgressPayload,
|
|
70
93
|
} from './ai-progress-batches.ts'
|
|
71
94
|
import type { HandlerContext } from './server.ts'
|
|
72
95
|
import type { StandardSchemaV1 } from './standard-schema.ts'
|
|
@@ -77,6 +100,43 @@ export type AgentStatus =
|
|
|
77
100
|
|
|
78
101
|
export type GenerationReason = 'message' | 'tool' | 'input' | 'retry' | 'resume'
|
|
79
102
|
|
|
103
|
+
export type ReasoningLevel = NonNullable<LanguageModelCallOptions['reasoning']>
|
|
104
|
+
|
|
105
|
+
export const reasoningLevels: readonly ReasoningLevel[] = [
|
|
106
|
+
'provider-default',
|
|
107
|
+
'none',
|
|
108
|
+
'minimal',
|
|
109
|
+
'low',
|
|
110
|
+
'medium',
|
|
111
|
+
'high',
|
|
112
|
+
'xhigh',
|
|
113
|
+
]
|
|
114
|
+
|
|
115
|
+
export type CompactionPartData = {
|
|
116
|
+
status: 'running' | 'completed' | 'failed' | 'interrupted'
|
|
117
|
+
inputTokens?: number
|
|
118
|
+
thresholdTokens?: number
|
|
119
|
+
summary?: string
|
|
120
|
+
usage?: LanguageModelUsage
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** The transcript part A2 adds to a response where its context was compacted. */
|
|
124
|
+
export type CompactionPart = {
|
|
125
|
+
type: 'data-a2-compaction'
|
|
126
|
+
id: string
|
|
127
|
+
data: CompactionPartData
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export { isCompactionPart }
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* A transcript message: `M` plus the compaction part A2 adds, so
|
|
134
|
+
* `isCompactionPart` narrows even when `M` declares its own data parts.
|
|
135
|
+
*/
|
|
136
|
+
export type TranscriptMessage<M extends UIMessage> = Omit<M, 'parts'> & {
|
|
137
|
+
parts: Array<M['parts'][number] | CompactionPart>
|
|
138
|
+
}
|
|
139
|
+
|
|
80
140
|
export type SessionCreatedPayload = { metadata?: JSONValue }
|
|
81
141
|
export type SessionClosedPayload = { reason?: string }
|
|
82
142
|
export type MessageCreatedPayload<M extends UIMessage> = {
|
|
@@ -115,15 +175,13 @@ export type GenerationStartedPayload = {
|
|
|
115
175
|
generationId: string
|
|
116
176
|
responseMessageId: string
|
|
117
177
|
attempt: number
|
|
118
|
-
model
|
|
178
|
+
/** Absent when the attempt failed before its model resolved. */
|
|
179
|
+
model?: string
|
|
119
180
|
promptThroughIndex?: number
|
|
120
181
|
}
|
|
121
182
|
export type GenerationProgressPayload = {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
generationId: string
|
|
125
|
-
responseMessageId: string
|
|
126
|
-
sequence: number
|
|
183
|
+
/** Log index of the generation's `ai.generation.started`. */
|
|
184
|
+
startIndex: number
|
|
127
185
|
chunks: UIMessageChunk[]
|
|
128
186
|
}
|
|
129
187
|
export type GenerationCompletedPayload = {
|
|
@@ -275,17 +333,20 @@ export type AIEventDefs<M extends UIMessage = UIMessage> = {
|
|
|
275
333
|
'ai.model.metadata.resolved': StandardSchemaV1<ModelMetadataResolvedPayload>
|
|
276
334
|
}
|
|
277
335
|
|
|
278
|
-
export type ActiveGeneration = GenerationStartedPayload
|
|
336
|
+
export type ActiveGeneration = GenerationStartedPayload & {
|
|
337
|
+
/** Log index of this generation's `ai.generation.started`. */
|
|
338
|
+
startIndex: number
|
|
339
|
+
}
|
|
279
340
|
|
|
280
|
-
export type ActiveGenerationProjection
|
|
341
|
+
export type ActiveGenerationProjection = {
|
|
281
342
|
generationId: string
|
|
282
343
|
responseMessageId: string
|
|
283
344
|
/** Log index of the completed model step while its response remains interruptible. */
|
|
284
345
|
completionIndex?: number
|
|
285
|
-
|
|
346
|
+
base?: MessageBase
|
|
286
347
|
promptThroughIndex?: number
|
|
287
348
|
cursor?: { throughIndex: number; stream: UIMessageCursor } | null
|
|
288
|
-
baseCompaction?: CompactionState
|
|
349
|
+
baseCompaction?: CompactionState | null
|
|
289
350
|
batches: ProgressBatches
|
|
290
351
|
baseTools: ToolActivity[]
|
|
291
352
|
toolEvents: Array<
|
|
@@ -315,28 +376,20 @@ export type ToolActivity = {
|
|
|
315
376
|
generationId: string
|
|
316
377
|
toolCallId: string
|
|
317
378
|
toolName?: string
|
|
318
|
-
input?: unknown
|
|
319
|
-
rawInput?: unknown
|
|
320
|
-
output?: unknown
|
|
321
379
|
error?: string
|
|
322
380
|
preliminary?: boolean
|
|
323
381
|
phase?: 'input' | 'execution'
|
|
324
382
|
dynamic?: boolean
|
|
325
383
|
providerExecuted?: boolean
|
|
326
|
-
callProviderMetadata?: unknown
|
|
327
|
-
resultProviderMetadata?: unknown
|
|
328
|
-
toolMetadata?: unknown
|
|
329
384
|
title?: string
|
|
330
385
|
status: 'running' | 'completed' | 'failed' | 'denied'
|
|
331
386
|
}
|
|
332
387
|
|
|
333
|
-
export type CompactionState
|
|
388
|
+
export type CompactionState = {
|
|
334
389
|
status: 'running' | 'completed'
|
|
335
390
|
generationId: string
|
|
336
391
|
throughMessageId: string
|
|
337
392
|
throughIndex?: number
|
|
338
|
-
messages?: M[]
|
|
339
|
-
retainedMessageIds?: string[]
|
|
340
393
|
summary?: string
|
|
341
394
|
usage?: LanguageModelUsage
|
|
342
395
|
}
|
|
@@ -354,14 +407,14 @@ export type AIState<M extends UIMessage = UIMessage> = {
|
|
|
354
407
|
receipt: ControlReceipt | null
|
|
355
408
|
pausedGenerationIds?: Record<string, true>
|
|
356
409
|
session: { created: boolean; metadata?: JSONValue }
|
|
357
|
-
messages: M[]
|
|
410
|
+
messages: TranscriptMessage<M>[]
|
|
358
411
|
status: AgentStatus
|
|
359
412
|
activeGeneration: ActiveGeneration | null
|
|
360
413
|
activeRequestId: string | null
|
|
361
414
|
activeRequestReason: GenerationReason | null
|
|
362
415
|
activeRequestSourceGenerationId: string | null
|
|
363
416
|
activeResponseMessageId: string | null
|
|
364
|
-
activeProjection: ActiveGenerationProjection
|
|
417
|
+
activeProjection: ActiveGenerationProjection | null
|
|
365
418
|
responseOwners: Record<
|
|
366
419
|
string,
|
|
367
420
|
Pick<GenerationStartedPayload, 'generationId' | 'requestId' | 'attempt'>
|
|
@@ -374,19 +427,29 @@ export type AIState<M extends UIMessage = UIMessage> = {
|
|
|
374
427
|
pendingApprovals: PendingApproval[]
|
|
375
428
|
pendingInputs: PendingInput[]
|
|
376
429
|
tools: ToolActivity[]
|
|
377
|
-
compaction: CompactionState
|
|
430
|
+
compaction: CompactionState | null
|
|
378
431
|
modelMetadata: Record<string, ModelMetadataState>
|
|
379
432
|
usage: GenerationUsage[]
|
|
380
433
|
error: string | null
|
|
381
434
|
}
|
|
382
435
|
|
|
383
|
-
|
|
436
|
+
/** The `UIMessage` type a contract's `ai.message.created` schema carries. */
|
|
437
|
+
export type AIMessageOf<D> = D extends {
|
|
438
|
+
readonly 'ai.message.created': infer S extends StandardSchemaV1
|
|
439
|
+
}
|
|
440
|
+
? StandardSchemaV1.InferOutput<S> extends MessageCreatedPayload<
|
|
441
|
+
infer M extends UIMessage
|
|
442
|
+
>
|
|
443
|
+
? M
|
|
444
|
+
: UIMessage
|
|
445
|
+
: UIMessage
|
|
446
|
+
|
|
447
|
+
/** What `agentContract()` returns: the AI protocol, with `X` as application state. */
|
|
448
|
+
export type AgentContract<
|
|
384
449
|
M extends UIMessage = UIMessage,
|
|
385
450
|
D extends EventDefs = AIEventDefs<M>,
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
readonly reducer: AIStoredReducer<D, AIState<M>>
|
|
389
|
-
}
|
|
451
|
+
X extends object = Record<never, never>,
|
|
452
|
+
> = Contract<D, Record<never, never>, AgentReducer<M, D, X>>
|
|
390
453
|
|
|
391
454
|
export type AgentToolEventDefs = EventDefs &
|
|
392
455
|
Pick<AIEventDefs, 'ai.tool.execution.requested'>
|
|
@@ -397,24 +460,50 @@ export type AgentToolContext<D extends AgentToolEventDefs> = HandlerContext<
|
|
|
397
460
|
'ai.tool.execution.requested'
|
|
398
461
|
>
|
|
399
462
|
|
|
400
|
-
|
|
463
|
+
/** Application state folded after the AI protocol, on the server and in clients. */
|
|
464
|
+
/** Rejects application state keys that would shadow `AIState`'s. */
|
|
465
|
+
type OwnKeys<X> = { [K in Extract<keyof X, keyof AIState>]: never }
|
|
466
|
+
/** Rejects a stateless application reducer, whose name would not be built in. */
|
|
467
|
+
type NonEmpty<X> = keyof X extends never ? never : unknown
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* The reducer `agentContract()` builds. Without application state it carries
|
|
471
|
+
* the built-in name, which is what lets the contract-free client fold it.
|
|
472
|
+
* `~appState` is type-only, absent at runtime: it carries the application
|
|
473
|
+
* state's type to `agent()`, and marks the reducer as `agentContract()`'s.
|
|
474
|
+
*/
|
|
475
|
+
export type AgentReducer<
|
|
476
|
+
M extends UIMessage,
|
|
477
|
+
D extends EventDefs,
|
|
478
|
+
X extends object,
|
|
479
|
+
> = (keyof X extends never
|
|
480
|
+
? Reducer<D, AIState<M>> & { readonly name: typeof AI_STATE_REDUCER }
|
|
481
|
+
: Reducer<D, AIState<M> & X>) & { readonly '~appState': X }
|
|
482
|
+
|
|
483
|
+
export type AgentContractOptions<
|
|
484
|
+
M extends UIMessage,
|
|
485
|
+
E extends EventDefs,
|
|
486
|
+
X extends object,
|
|
487
|
+
> = {
|
|
401
488
|
name: string
|
|
402
489
|
events?: E
|
|
403
490
|
/** Optional stricter schema for custom UIMessage metadata/data/tool types. */
|
|
404
491
|
messageSchema?: StandardSchemaV1<M>
|
|
405
|
-
/**
|
|
406
|
-
|
|
492
|
+
/**
|
|
493
|
+
* Application state, folded from events beside `AIState` and merged into
|
|
494
|
+
* it. `fold` sees only this state, never the transcript.
|
|
495
|
+
*/
|
|
496
|
+
reducer?: {
|
|
497
|
+
/** Snapshot identity of the application state. Rename it when `fold` changes. */
|
|
498
|
+
name: string
|
|
499
|
+
initialState: X & OwnKeys<X> & NonEmpty<X>
|
|
500
|
+
fold: (
|
|
501
|
+
state: NoInfer<X>,
|
|
502
|
+
event: ContractEvent<AIEventDefs<M> & NoInfer<E>>,
|
|
503
|
+
) => NoInfer<X>
|
|
504
|
+
}
|
|
407
505
|
}
|
|
408
506
|
|
|
409
|
-
type AIMessageFrom<D extends EventDefs> =
|
|
410
|
-
D extends Record<'ai.message.created', infer S extends StandardSchemaV1>
|
|
411
|
-
? StandardSchemaV1.InferOutput<S> extends MessageCreatedPayload<
|
|
412
|
-
infer M extends UIMessage
|
|
413
|
-
>
|
|
414
|
-
? M
|
|
415
|
-
: UIMessage
|
|
416
|
-
: UIMessage
|
|
417
|
-
|
|
418
507
|
type SchemaResult<T> = StandardSchemaV1.Result<T>
|
|
419
508
|
|
|
420
509
|
const issue = <T>(message: string): SchemaResult<T> => ({
|
|
@@ -540,13 +629,8 @@ const progressPayloadSchema: StandardSchemaV1<GenerationProgressPayload> =
|
|
|
540
629
|
if (
|
|
541
630
|
!isRecord(value) ||
|
|
542
631
|
!isJSONCompatible(value) ||
|
|
543
|
-
|
|
544
|
-
!
|
|
545
|
-
!stringField(value, 'generationId') ||
|
|
546
|
-
!stringField(value, 'responseMessageId') ||
|
|
547
|
-
typeof value['sequence'] !== 'number' ||
|
|
548
|
-
!Number.isInteger(value['sequence']) ||
|
|
549
|
-
value['sequence'] < 0 ||
|
|
632
|
+
typeof value['startIndex'] !== 'number' ||
|
|
633
|
+
!optionalIndexField(value, 'startIndex') ||
|
|
550
634
|
!Array.isArray(value['chunks']) ||
|
|
551
635
|
!value['chunks'].every(
|
|
552
636
|
(chunk) => isRecord(chunk) && typeof chunk['type'] === 'string',
|
|
@@ -822,7 +906,7 @@ export function createEvents<M extends UIMessage = UIMessage>(options?: {
|
|
|
822
906
|
typeof value['attempt'] === 'number' &&
|
|
823
907
|
Number.isInteger(value['attempt']) &&
|
|
824
908
|
value['attempt'] > 0 &&
|
|
825
|
-
stringField(value, 'model') &&
|
|
909
|
+
(value['model'] === undefined || stringField(value, 'model')) &&
|
|
826
910
|
optionalIndexField(value, 'promptThroughIndex'),
|
|
827
911
|
),
|
|
828
912
|
'ai.generation.progress': progressPayloadSchema,
|
|
@@ -979,13 +1063,18 @@ const initialState = <M extends UIMessage>(): AIState<M> => ({
|
|
|
979
1063
|
const projectMessageChunks = <M extends UIMessage>(
|
|
980
1064
|
messages: M[],
|
|
981
1065
|
messageId: string,
|
|
982
|
-
chunks:
|
|
983
|
-
): M[] =>
|
|
984
|
-
messages
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
1066
|
+
chunks: ProjectionChunk[],
|
|
1067
|
+
): M[] => {
|
|
1068
|
+
const base = findMessage(messages, messageId)
|
|
1069
|
+
return upsertMessage(
|
|
1070
|
+
messages,
|
|
1071
|
+
projectUIMessage<M>({
|
|
1072
|
+
messageId,
|
|
1073
|
+
...(base === undefined ? {} : { base }),
|
|
1074
|
+
chunks,
|
|
1075
|
+
}),
|
|
988
1076
|
)
|
|
1077
|
+
}
|
|
989
1078
|
|
|
990
1079
|
const waitingStatus = <M extends UIMessage>(state: AIState<M>): AgentStatus => {
|
|
991
1080
|
if (state.pendingApprovals.length > 0 || state.pendingInputs.length > 0) {
|
|
@@ -1018,9 +1107,15 @@ const isStaleGeneration = <M extends UIMessage>(
|
|
|
1018
1107
|
|
|
1019
1108
|
const projectedResponse = <M extends UIMessage>(options: {
|
|
1020
1109
|
state: AIState<M>
|
|
1021
|
-
projection: ActiveGenerationProjection
|
|
1022
|
-
}): M => {
|
|
1023
|
-
const message = projectedMessage(
|
|
1110
|
+
projection: ActiveGenerationProjection
|
|
1111
|
+
}): TranscriptMessage<M> => {
|
|
1112
|
+
const message = projectedMessage({
|
|
1113
|
+
projection: options.projection,
|
|
1114
|
+
current: findMessage(
|
|
1115
|
+
options.state.messages,
|
|
1116
|
+
options.projection.responseMessageId,
|
|
1117
|
+
),
|
|
1118
|
+
})
|
|
1024
1119
|
return options.state.pausedGenerationIds?.[options.projection.generationId]
|
|
1025
1120
|
? pauseUIMessage({
|
|
1026
1121
|
message,
|
|
@@ -1048,6 +1143,19 @@ const terminalGenerationReason = <M extends UIMessage>(
|
|
|
1048
1143
|
export function reduceAIState<M extends UIMessage>(
|
|
1049
1144
|
state: AIState<M>,
|
|
1050
1145
|
event: { type: string; payload: unknown; index: number; id?: string },
|
|
1146
|
+
): AIState<M> {
|
|
1147
|
+
return settleAbandonedCompaction(
|
|
1148
|
+
state,
|
|
1149
|
+
retainMessageBase({
|
|
1150
|
+
before: state,
|
|
1151
|
+
after: reduceAIEvent(state, event),
|
|
1152
|
+
}),
|
|
1153
|
+
)
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
function reduceAIEvent<M extends UIMessage>(
|
|
1157
|
+
state: AIState<M>,
|
|
1158
|
+
event: { type: string; payload: unknown; index: number; id?: string },
|
|
1051
1159
|
): AIState<M> {
|
|
1052
1160
|
if (state.status === 'closed') return state
|
|
1053
1161
|
switch (event.type) {
|
|
@@ -1371,13 +1479,14 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
1371
1479
|
'superseded',
|
|
1372
1480
|
)
|
|
1373
1481
|
: state
|
|
1374
|
-
const baseMessage =
|
|
1375
|
-
|
|
1482
|
+
const baseMessage = findMessage(
|
|
1483
|
+
baseState.messages,
|
|
1484
|
+
payload.responseMessageId,
|
|
1376
1485
|
)
|
|
1377
1486
|
return {
|
|
1378
1487
|
...baseState,
|
|
1379
1488
|
status: 'generating',
|
|
1380
|
-
activeGeneration: payload,
|
|
1489
|
+
activeGeneration: { ...payload, startIndex: event.index },
|
|
1381
1490
|
activeResponseMessageId: null,
|
|
1382
1491
|
responseOwners: {
|
|
1383
1492
|
...baseState.responseOwners,
|
|
@@ -1391,7 +1500,9 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
1391
1500
|
generationId: payload.generationId,
|
|
1392
1501
|
responseMessageId: payload.responseMessageId,
|
|
1393
1502
|
promptThroughIndex: payload.promptThroughIndex ?? event.index - 1,
|
|
1394
|
-
...(baseMessage === undefined
|
|
1503
|
+
...(baseMessage === undefined
|
|
1504
|
+
? {}
|
|
1505
|
+
: { base: { partCount: baseMessage.parts.length } }),
|
|
1395
1506
|
baseCompaction: baseState.compaction,
|
|
1396
1507
|
batches: progressBatches(),
|
|
1397
1508
|
baseTools: baseState.tools,
|
|
@@ -1402,30 +1513,29 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
1402
1513
|
}
|
|
1403
1514
|
}
|
|
1404
1515
|
case 'ai.generation.progress': {
|
|
1405
|
-
const payload = event.payload as
|
|
1406
|
-
|
|
1516
|
+
const payload = event.payload as StoredProgressPayload
|
|
1517
|
+
const generation = state.activeGeneration
|
|
1518
|
+
const activeProjection = state.activeProjection
|
|
1407
1519
|
if (
|
|
1520
|
+
generation === null ||
|
|
1521
|
+
!progressOwnedBy({
|
|
1522
|
+
payload,
|
|
1523
|
+
owner: generation,
|
|
1524
|
+
startIndex: generation.startIndex,
|
|
1525
|
+
}) ||
|
|
1526
|
+
state.pausedGenerationIds?.[generation.generationId] ||
|
|
1408
1527
|
terminalGenerationReason(
|
|
1409
1528
|
state,
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
) !== undefined
|
|
1413
|
-
|
|
1414
|
-
return state
|
|
1415
|
-
}
|
|
1416
|
-
const activeProjection = state.activeProjection
|
|
1417
|
-
if (
|
|
1418
|
-
state.activeGeneration?.generationId !== payload.generationId ||
|
|
1419
|
-
state.activeGeneration.requestId !== payload.requestId ||
|
|
1420
|
-
activeProjection?.generationId !== payload.generationId
|
|
1529
|
+
generation.generationId,
|
|
1530
|
+
generation.requestId,
|
|
1531
|
+
) !== undefined ||
|
|
1532
|
+
activeProjection?.generationId !== generation.generationId
|
|
1421
1533
|
) {
|
|
1422
1534
|
return state
|
|
1423
1535
|
}
|
|
1424
1536
|
const progress = advanceProjection({
|
|
1425
1537
|
projection: activeProjection,
|
|
1426
|
-
base: state.messages.
|
|
1427
|
-
(message) => message.id === activeProjection.responseMessageId,
|
|
1428
|
-
),
|
|
1538
|
+
base: findMessage(state.messages, activeProjection.responseMessageId),
|
|
1429
1539
|
chunks: payload.chunks,
|
|
1430
1540
|
index: event.index,
|
|
1431
1541
|
})
|
|
@@ -1434,7 +1544,7 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
1434
1544
|
messages: upsertResponse({
|
|
1435
1545
|
messages: state.messages,
|
|
1436
1546
|
message: progress.message,
|
|
1437
|
-
inputId:
|
|
1547
|
+
inputId: generation.messageId,
|
|
1438
1548
|
}),
|
|
1439
1549
|
activeProjection: {
|
|
1440
1550
|
...activeProjection,
|
|
@@ -1521,14 +1631,20 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
1521
1631
|
: null
|
|
1522
1632
|
const shouldProject =
|
|
1523
1633
|
projection !== null &&
|
|
1524
|
-
(projection.
|
|
1634
|
+
(projection.base !== undefined || projection.batches.length > 0)
|
|
1525
1635
|
return {
|
|
1526
1636
|
...state,
|
|
1527
1637
|
messages: shouldProject
|
|
1528
1638
|
? upsertMessage(
|
|
1529
1639
|
state.messages,
|
|
1530
1640
|
interruptUIMessage(
|
|
1531
|
-
projectedMessage(
|
|
1641
|
+
projectedMessage({
|
|
1642
|
+
projection,
|
|
1643
|
+
current: findMessage(
|
|
1644
|
+
state.messages,
|
|
1645
|
+
projection.responseMessageId,
|
|
1646
|
+
),
|
|
1647
|
+
}),
|
|
1532
1648
|
`Generation failed before tool completion: ${payload.error}`,
|
|
1533
1649
|
),
|
|
1534
1650
|
)
|
|
@@ -1832,6 +1948,9 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
1832
1948
|
if (projection?.generationId !== payload.generationId) {
|
|
1833
1949
|
const next = {
|
|
1834
1950
|
...state,
|
|
1951
|
+
messages: projectMessageChunks(state.messages, payload.messageId, [
|
|
1952
|
+
toolCalledChunk(payload),
|
|
1953
|
+
]),
|
|
1835
1954
|
tools: reduceToolActivity(state.tools, {
|
|
1836
1955
|
type: 'ai.tool.called',
|
|
1837
1956
|
payload,
|
|
@@ -1839,16 +1958,51 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
1839
1958
|
}
|
|
1840
1959
|
return { ...next, status: lifecycleStatus(state, next) }
|
|
1841
1960
|
}
|
|
1842
|
-
const activeProjection: ActiveGenerationProjection
|
|
1961
|
+
const activeProjection: ActiveGenerationProjection = {
|
|
1843
1962
|
...projection,
|
|
1963
|
+
cursor: null,
|
|
1844
1964
|
toolEvents: [
|
|
1845
1965
|
...projection.toolEvents,
|
|
1846
1966
|
{ index: event.index, type: 'ai.tool.called', payload },
|
|
1847
1967
|
],
|
|
1848
1968
|
}
|
|
1969
|
+
const base = findMessage(state.messages, payload.messageId)
|
|
1970
|
+
const paused = state.pausedGenerationIds?.[payload.generationId]
|
|
1971
|
+
const cursor = projection.cursor
|
|
1972
|
+
const incremental =
|
|
1973
|
+
base && cursor && !paused && event.index > cursor.throughIndex
|
|
1974
|
+
const projected = incremental
|
|
1975
|
+
? {
|
|
1976
|
+
...(hasToolCall({ message: base, call: payload })
|
|
1977
|
+
? { message: base, cursor: cursor.stream }
|
|
1978
|
+
: projectUIMessageStream({
|
|
1979
|
+
messageId: payload.messageId,
|
|
1980
|
+
base,
|
|
1981
|
+
cursor: cursor.stream,
|
|
1982
|
+
chunks: [toolCalledChunk(payload)],
|
|
1983
|
+
})),
|
|
1984
|
+
throughIndex: event.index,
|
|
1985
|
+
}
|
|
1986
|
+
: projectedMessageStream({
|
|
1987
|
+
projection: activeProjection,
|
|
1988
|
+
current: base,
|
|
1989
|
+
})
|
|
1990
|
+
activeProjection.cursor = paused
|
|
1991
|
+
? null
|
|
1992
|
+
: { throughIndex: projected.throughIndex, stream: projected.cursor }
|
|
1849
1993
|
const next = {
|
|
1850
1994
|
...state,
|
|
1851
1995
|
activeProjection,
|
|
1996
|
+
messages: upsertResponse({
|
|
1997
|
+
messages: state.messages,
|
|
1998
|
+
message: paused
|
|
1999
|
+
? projectedResponse({ state, projection: activeProjection })
|
|
2000
|
+
: projected.message,
|
|
2001
|
+
inputId:
|
|
2002
|
+
state.activeGeneration?.messageId ??
|
|
2003
|
+
state.active?.input.id ??
|
|
2004
|
+
payload.messageId,
|
|
2005
|
+
}),
|
|
1852
2006
|
tools: projectedTools(activeProjection),
|
|
1853
2007
|
}
|
|
1854
2008
|
return { ...next, status: lifecycleStatus(state, next) }
|
|
@@ -1903,7 +2057,7 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
1903
2057
|
}
|
|
1904
2058
|
return { ...next, status: lifecycleStatus(state, next) }
|
|
1905
2059
|
}
|
|
1906
|
-
const activeProjection: ActiveGenerationProjection
|
|
2060
|
+
const activeProjection: ActiveGenerationProjection = {
|
|
1907
2061
|
...projection,
|
|
1908
2062
|
cursor: null,
|
|
1909
2063
|
toolEvents: [
|
|
@@ -2136,10 +2290,10 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
2136
2290
|
if (state.activeGeneration?.generationId !== payload.generationId) {
|
|
2137
2291
|
return state
|
|
2138
2292
|
}
|
|
2139
|
-
return
|
|
2140
|
-
...state,
|
|
2141
|
-
|
|
2142
|
-
|
|
2293
|
+
return addCompactionPart(
|
|
2294
|
+
{ ...state, compaction: { status: 'running', ...payload } },
|
|
2295
|
+
payload,
|
|
2296
|
+
)
|
|
2143
2297
|
}
|
|
2144
2298
|
case 'ai.compaction.completed': {
|
|
2145
2299
|
const payload = event.payload as CompactionCompletedPayload<M>
|
|
@@ -2150,20 +2304,41 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
2150
2304
|
) {
|
|
2151
2305
|
return state
|
|
2152
2306
|
}
|
|
2153
|
-
const
|
|
2307
|
+
const {
|
|
2308
|
+
messages: _messages,
|
|
2309
|
+
retainedMessageIds: _retained,
|
|
2310
|
+
...summary
|
|
2311
|
+
} = payload
|
|
2312
|
+
const compaction: CompactionState = {
|
|
2154
2313
|
status: 'completed',
|
|
2155
|
-
...
|
|
2314
|
+
...summary,
|
|
2156
2315
|
throughIndex:
|
|
2157
2316
|
payload.throughIndex ?? state.activeProjection!.promptThroughIndex!,
|
|
2158
2317
|
}
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2318
|
+
const projection = state.activeProjection
|
|
2319
|
+
return settleCompactionPart({
|
|
2320
|
+
state: {
|
|
2321
|
+
...state,
|
|
2322
|
+
compaction,
|
|
2323
|
+
activeProjection: projection && {
|
|
2324
|
+
...projection,
|
|
2325
|
+
baseCompaction: compaction,
|
|
2326
|
+
// A new base identity records the completed part as the step's
|
|
2327
|
+
// starting point, so a later cutoff cannot revert it to running.
|
|
2328
|
+
...(projection.base === undefined
|
|
2329
|
+
? {}
|
|
2330
|
+
: { base: { ...projection.base } }),
|
|
2331
|
+
},
|
|
2165
2332
|
},
|
|
2166
|
-
|
|
2333
|
+
generationId: payload.generationId,
|
|
2334
|
+
data: {
|
|
2335
|
+
status: 'completed',
|
|
2336
|
+
...(summary.summary === undefined
|
|
2337
|
+
? {}
|
|
2338
|
+
: { summary: summary.summary }),
|
|
2339
|
+
...(summary.usage === undefined ? {} : { usage: summary.usage }),
|
|
2340
|
+
},
|
|
2341
|
+
})
|
|
2167
2342
|
}
|
|
2168
2343
|
default:
|
|
2169
2344
|
return state
|
|
@@ -2173,35 +2348,12 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
2173
2348
|
/** Derive AI SDK UI messages directly from an A2 event history. */
|
|
2174
2349
|
export function deriveUIMessages<M extends UIMessage = UIMessage>(
|
|
2175
2350
|
history: readonly { type: string; payload: unknown; index: number }[],
|
|
2176
|
-
): M[] {
|
|
2351
|
+
): TranscriptMessage<M>[] {
|
|
2177
2352
|
let state = initialState<M>()
|
|
2178
2353
|
for (const event of history) state = reduceAIState(state, event)
|
|
2179
2354
|
return state.messages
|
|
2180
2355
|
}
|
|
2181
2356
|
|
|
2182
|
-
/** Build the standard AI state projection for any contract containing the protocol. */
|
|
2183
|
-
export function createReducer<D extends EventDefs>(options: {
|
|
2184
|
-
contract: Contract<D>
|
|
2185
|
-
name?: string
|
|
2186
|
-
fold?: Reducer<D, AIState<AIMessageFrom<D>>>['fold']
|
|
2187
|
-
stateSchema?: StandardSchemaV1<unknown, AIState<AIMessageFrom<D>>>
|
|
2188
|
-
}): AIStoredReducer<D, AIState<AIMessageFrom<D>>> {
|
|
2189
|
-
type M = AIMessageFrom<D>
|
|
2190
|
-
const reducer = options.contract
|
|
2191
|
-
.reducer({
|
|
2192
|
-
name: options.name ?? 'a2.ai.state.v22',
|
|
2193
|
-
initialState: initialState<M>(),
|
|
2194
|
-
...(options.stateSchema === undefined
|
|
2195
|
-
? {}
|
|
2196
|
-
: { stateSchema: options.stateSchema }),
|
|
2197
|
-
})
|
|
2198
|
-
.fold(options.fold ?? ((state, event) => reduceAIState(state, event)))
|
|
2199
|
-
return storedAIReducer({
|
|
2200
|
-
...reducer,
|
|
2201
|
-
[clientStateProjection]: projectAIClientState,
|
|
2202
|
-
})
|
|
2203
|
-
}
|
|
2204
|
-
|
|
2205
2357
|
type CommandInput<C> = { type: 'ai.control.requested'; payload: C; id?: string }
|
|
2206
2358
|
type ControlInput<
|
|
2207
2359
|
M extends UIMessage,
|
|
@@ -2338,22 +2490,24 @@ export const inputs: AIInputs = {
|
|
|
2338
2490
|
* Read the durable handler context ambient to the current AI tool
|
|
2339
2491
|
* execution. A2 runs each local tool's `execute` inside this scope, so
|
|
2340
2492
|
* plain AI SDK `tool()` definitions reach their `event`, `attempt`,
|
|
2341
|
-
* `session`, and `signal` without an A2-specific wrapper.
|
|
2342
|
-
* contract
|
|
2343
|
-
* the executing
|
|
2493
|
+
* `session`, and `signal` without an A2-specific wrapper. Pass the
|
|
2494
|
+
* agent's contract to type application events; it is verified against
|
|
2495
|
+
* the executing agent.
|
|
2344
2496
|
*/
|
|
2345
|
-
export function handlerContext<D extends AgentToolEventDefs>(
|
|
2346
|
-
|
|
2497
|
+
export function handlerContext<D extends AgentToolEventDefs = AIEventDefs>(
|
|
2498
|
+
contract?: Contract<D>,
|
|
2347
2499
|
): AgentToolContext<D> {
|
|
2348
|
-
const contract =
|
|
2349
|
-
'contract' in agentOrContract ? agentOrContract.contract : agentOrContract
|
|
2350
2500
|
const scope = ambientToolScopeStorage()?.getStore()
|
|
2351
2501
|
if (scope === undefined) {
|
|
2352
2502
|
throw new TypeError(
|
|
2353
|
-
|
|
2503
|
+
"handlerContext() requires an ambient A2 tool execution: call it inside a local tool's execute, or wrap direct tool tests with runWithHandlerContext",
|
|
2354
2504
|
)
|
|
2355
2505
|
}
|
|
2356
|
-
if (
|
|
2506
|
+
if (
|
|
2507
|
+
contract !== undefined &&
|
|
2508
|
+
scope.contract !== undefined &&
|
|
2509
|
+
scope.contract.name !== contract.name
|
|
2510
|
+
) {
|
|
2357
2511
|
throw new TypeError(
|
|
2358
2512
|
`handlerContext('${contract.name}') was called during a tool execution for agent '${scope.contract.name}'`,
|
|
2359
2513
|
)
|
|
@@ -2361,14 +2515,23 @@ export function handlerContext<D extends AgentToolEventDefs>(
|
|
|
2361
2515
|
return scope.context as AgentToolContext<D>
|
|
2362
2516
|
}
|
|
2363
2517
|
|
|
2518
|
+
/** The built-in AI reducer's name, and so its checkpoint identity. */
|
|
2519
|
+
export const AI_STATE_REDUCER = 'a2.ai.state.v26'
|
|
2520
|
+
|
|
2364
2521
|
/**
|
|
2365
|
-
*
|
|
2366
|
-
* reducer
|
|
2522
|
+
* The built-in AI protocol plus application events, as a core contract whose
|
|
2523
|
+
* reducer folds `AIState`. Isomorphic: share it when a client needs
|
|
2524
|
+
* application events or extended state; otherwise `agent({ name })` on the
|
|
2525
|
+
* server builds one and clients use the built-in protocol.
|
|
2367
2526
|
*/
|
|
2368
|
-
export function
|
|
2527
|
+
export function agentContract<
|
|
2369
2528
|
M extends UIMessage = UIMessage,
|
|
2370
2529
|
E extends EventDefs = Record<never, never>,
|
|
2371
|
-
|
|
2530
|
+
X extends object = Record<never, never>,
|
|
2531
|
+
>(
|
|
2532
|
+
options: AgentContractOptions<M, E, X>,
|
|
2533
|
+
): AgentContract<M, AIEventDefs<M> & E, X> {
|
|
2534
|
+
type D = AIEventDefs<M> & E
|
|
2372
2535
|
const builtIns = createEvents(
|
|
2373
2536
|
options.messageSchema === undefined
|
|
2374
2537
|
? undefined
|
|
@@ -2382,25 +2545,46 @@ export function agent<
|
|
|
2382
2545
|
)
|
|
2383
2546
|
}
|
|
2384
2547
|
}
|
|
2385
|
-
const
|
|
2548
|
+
const vocabulary = createContract({
|
|
2386
2549
|
name: options.name,
|
|
2387
|
-
events: { ...builtIns, ...extensions },
|
|
2550
|
+
events: { ...builtIns, ...extensions } as D,
|
|
2388
2551
|
})
|
|
2389
|
-
const
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
.fold((state, event) => reduceAIState(state, event))
|
|
2395
|
-
|
|
2396
|
-
const definition = {
|
|
2397
|
-
contract: agentContract,
|
|
2398
|
-
reducer: storedAIReducer({
|
|
2399
|
-
...reducer,
|
|
2400
|
-
[clientStateProjection]: projectAIClientState<M>,
|
|
2401
|
-
}),
|
|
2552
|
+
const app = options.reducer as AppReducer<D, X> | undefined
|
|
2553
|
+
const aiState = initialState<M>()
|
|
2554
|
+
for (const key of Object.keys(app?.initialState ?? {})) {
|
|
2555
|
+
if (isAIStateKey(key))
|
|
2556
|
+
throw new TypeError(`agent state '${key}' conflicts with AIState`)
|
|
2402
2557
|
}
|
|
2403
|
-
|
|
2558
|
+
const reducer = makeReducer({
|
|
2559
|
+
contract: vocabulary,
|
|
2560
|
+
// Application checkpoints embed AI state, so they advance with it.
|
|
2561
|
+
name:
|
|
2562
|
+
app === undefined ? AI_STATE_REDUCER : `${app.name}+${AI_STATE_REDUCER}`,
|
|
2563
|
+
initialState: { ...aiState, ...app?.initialState } as AIState<M> & X,
|
|
2564
|
+
}).fold((state, event) => {
|
|
2565
|
+
const next = reduceAIState(state, event) as AIState<M> & X
|
|
2566
|
+
if (app === undefined) return next
|
|
2567
|
+
const before = appSlice<X>(state)
|
|
2568
|
+
const after = app.fold(before, event as ContractEvent<D>)
|
|
2569
|
+
return after === before ? next : withAppSlice(next, after)
|
|
2570
|
+
})
|
|
2571
|
+
const shared = createContract({
|
|
2572
|
+
name: options.name,
|
|
2573
|
+
events: vocabulary.events,
|
|
2574
|
+
reducer: withAIStorage(
|
|
2575
|
+
withReducerRuntime({
|
|
2576
|
+
reducer,
|
|
2577
|
+
project: projectAIClientState<M> as unknown as (
|
|
2578
|
+
state: AIState<M> & X,
|
|
2579
|
+
) => AIState<M> & X,
|
|
2580
|
+
}),
|
|
2581
|
+
),
|
|
2582
|
+
})
|
|
2583
|
+
registerAgentReducer(
|
|
2584
|
+
shared.reducer,
|
|
2585
|
+
app as unknown as AppReducer<EventDefs, object> | undefined,
|
|
2586
|
+
)
|
|
2587
|
+
return shared as unknown as AgentContract<M, AIEventDefs<M> & E, X>
|
|
2404
2588
|
}
|
|
2405
2589
|
|
|
2406
2590
|
export type {
|