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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,378 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.18.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- ba50c3e: `agent()` takes its loop as `harness`. The AI SDK's loop, one `streamText()` step per durable generation, is the default, `harness: { type: 'ai-sdk' }`, and its options move into it: `generation`, `generate`, `compaction`, and `messageMetadata` are no longer top-level `agent()` options, and passing one there throws a `TypeError`.
|
|
8
|
+
|
|
9
|
+
`model` is an AI Gateway model ID, or `ModelSettings` with one, under every harness: `agent()` no longer takes AI SDK provider model objects, and `HarnessModelSettings` is gone.
|
|
10
|
+
|
|
11
|
+
Run FX or Pi as the loop instead with `harness: fx()` from `experimental-a2/ai/fx` or `harness: pi({ sandbox })` from `experimental-a2/ai/pi`. Each model call the harness makes is one durable step, and each tool call an A2 tool call, so a crash resumes at the interrupted step without repeating finished model calls or tools.
|
|
12
|
+
|
|
13
|
+
A0 can run the AI SDK's, FX's, or Pi's loop: pick the harness in the composer before an app's first message.
|
|
14
|
+
|
|
15
|
+
- f3762ef: Add `toolRecovery` to `agent()`, which per tool answers a call that a crash, a timeout, Stop, or Pause now may have cut short with an error result instead of running it again.
|
|
16
|
+
- 2b409f0: Add `session.deadLetters()` and `session.redrive(index, { action })` to server sessions. List a session's dead-lettered events with their last error, then retry one with a fresh failure budget or skip it so its lane continues, in one atomic store operation that wakes the session like an append. Custom stores opt in with the optional `A2Store.deadLetters` and `A2Store.redrive` methods; every built-in store implements them. Redrives emit an `a2.redrive` span.
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- 0df2721: Docs: the introduction now walks through a shared contract, the server, and the client, then links to handlers, state, history, and AI.
|
|
21
|
+
- 3fc2253: Docs: the bundled `docs/` folder is reorganized into `contract/`, `server/`, `client/`, `agents/`, `actors/`, and `reference/`, and every page is shorter. The API reference is now one page per entry point group. Old paths such as `docs/guides/05-production.mdx` now live at their new homes, for example `docs/server/05-production.mdx`.
|
|
22
|
+
- 90ffa58: The package description and README now say what A2 does: it syncs your immutable event log, from server to browser.
|
|
23
|
+
|
|
24
|
+
## 0.17.0
|
|
25
|
+
|
|
26
|
+
### Minor Changes
|
|
27
|
+
|
|
28
|
+
- 7308a33: Serve an agent with `agent()` from `experimental-a2/ai/server` and use it in
|
|
29
|
+
React with `useAgent()` from the new `experimental-a2/ai/react`. Browsers no
|
|
30
|
+
longer need a contract: the AI protocol and `AIState` reducer are library code,
|
|
31
|
+
and `useAgent<typeof assistant>({ api, id, initial })` takes the agent's types
|
|
32
|
+
through a type-only import. `createAgentClient()` from the new
|
|
33
|
+
`experimental-a2/ai/client` covers pushes outside React.
|
|
34
|
+
|
|
35
|
+
`useAgent()` returns the session plus `messages`, `status`, an `indicator`
|
|
36
|
+
(`starting`, `thinking`, `compacting`, or `null`), and actions that fill in
|
|
37
|
+
protocol identities: `sendMessage`, `steer`, `stop`, `approve`, `deny`,
|
|
38
|
+
`respond`, `retry`, `pause`, `resume`, and `queue.edit`/`move`/`remove`/`sendNow`.
|
|
39
|
+
Actions return the same `PushResult` as `push()`.
|
|
40
|
+
|
|
41
|
+
`model` also accepts `ModelSettings`, `{ model, reasoning?, speed? }`, statically
|
|
42
|
+
or from a resolver, to choose the reasoning level and AI Gateway speed with the
|
|
43
|
+
model; both override `generation`. `reasoningLevels` lists the levels.
|
|
44
|
+
|
|
45
|
+
Compaction now appears in the transcript: the response gains a
|
|
46
|
+
`data-a2-compaction` part where its context was compacted, with its status,
|
|
47
|
+
summary, and usage. Render it with `isCompactionPart()`; `AIState` messages are
|
|
48
|
+
typed as `TranscriptMessage<M>`, so it narrows even with custom data parts. AI
|
|
49
|
+
SDK model conversion skips it.
|
|
50
|
+
|
|
51
|
+
`agent({ toolLane })` runs local tool executions one at a time on a lane.
|
|
52
|
+
|
|
53
|
+
Migration:
|
|
54
|
+
|
|
55
|
+
- `createAgentServer({ agent: definition, ... })` becomes
|
|
56
|
+
`agent({ name, ... })`, or `agent({ contract, ... })` with a shared contract.
|
|
57
|
+
- The isomorphic `agent()` becomes `agentContract()`, which returns a core
|
|
58
|
+
contract. Its `reducer` option folds application state beside the AI
|
|
59
|
+
protocol; it replaces `createReducer()` and `reducerName`.
|
|
60
|
+
- `createHandlers()` and `authorizeAgentIngress` are removed. Pass `handlers`
|
|
61
|
+
and `events` to `agent()`. Browsers push application events like any A2
|
|
62
|
+
client, narrowed by the route's `authorize`. Handlers for events `agent()`
|
|
63
|
+
already handles are rejected.
|
|
64
|
+
- `handlerContext(agent)` becomes `handlerContext()`, optionally
|
|
65
|
+
`handlerContext(contract)` to type application events.
|
|
66
|
+
|
|
67
|
+
The AI reducer identity advances to `a2.ai.state.v26`; with application state it
|
|
68
|
+
is `<name>+a2.ai.state.v26`.
|
|
69
|
+
Existing event logs remain the source for rebuilding those checkpoints.
|
|
70
|
+
|
|
71
|
+
- 5ba57e5: Give agents your own events and state, and let them decide the model from it.
|
|
72
|
+
`agentContract({ events, reducer })` takes a core `contract()` reducer's
|
|
73
|
+
`name`, `initialState`, and `fold`; `fold` sees your state and every event,
|
|
74
|
+
never the transcript, and the session state is `AIState` merged with yours.
|
|
75
|
+
|
|
76
|
+
Every `agent({ contract })` resolver, and the compaction, metadata, and
|
|
77
|
+
custom-generation callbacks, receive that state as `state`. It rides in the
|
|
78
|
+
model-context checkpoint each model step already reads, so it adds no reads;
|
|
79
|
+
agents without application state keep their existing checkpoints. A `model`
|
|
80
|
+
resolver can return `{ model, reasoning, speed }` from it.
|
|
81
|
+
|
|
82
|
+
A resolver that throws, or returns an invalid value, now fails the turn once
|
|
83
|
+
with its message, like a provider error, instead of retrying the handler; the
|
|
84
|
+
attempt's `ai.generation.started` omits `model` when the model never resolved,
|
|
85
|
+
so `GenerationStartedPayload.model` is optional. `retry()` runs it again. Store
|
|
86
|
+
failures still retry durably.
|
|
87
|
+
|
|
88
|
+
`useAgent({ api, id, contract })`, or `useAgent({ client, id })` with that
|
|
89
|
+
contract's `createClient()`, folds a shared contract's state in the browser.
|
|
90
|
+
`agent({ contract })` takes only an `agentContract()`, so every agent's
|
|
91
|
+
resolvers receive `state`; any other contract throws. A fully custom contract
|
|
92
|
+
is core A2, served by `createServer()`.
|
|
93
|
+
|
|
94
|
+
A shared contract's application events follow core A2: browsers may push them,
|
|
95
|
+
and the route's `authorize` narrows who may push what. The agent still refuses
|
|
96
|
+
its own server-authored `ai.*` events, and events passed to
|
|
97
|
+
`agent({ name, events })` stay server-only.
|
|
98
|
+
|
|
99
|
+
Agents no longer handle `ai.message.completed`, `ai.message.interrupted`, or
|
|
100
|
+
`ai.generation.failed`, so apps can react to them with ordinary `handlers`.
|
|
101
|
+
The prompt cache those handlers evicted now keeps each session's latest step
|
|
102
|
+
in a bounded in-process cache, dropped when the step ends without tool calls.
|
|
103
|
+
A plain turn runs one fewer durable handler.
|
|
104
|
+
|
|
105
|
+
- e779c74: Allow per-attempt generation settings resolvers for model calls, compaction, and tool approvals.
|
|
106
|
+
|
|
107
|
+
Add Thinking and Prefer fast controls to the Agent playground. Per-message preferences persist through queued turns, compaction, tool continuations, and reminders.
|
|
108
|
+
|
|
109
|
+
- 707315a: `generate` and `messageMetadata` now receive the resolver context,
|
|
110
|
+
`{ event, messages, state, session, signal }`, plus what the step resolves:
|
|
111
|
+
`generationId`, `modelMessages`, and the resolved `model`, `instructions`,
|
|
112
|
+
`tools`, and `generation`. The triggering `ai.generation.requested` event is
|
|
113
|
+
`event`, as in every resolver, handler, and `handlerContext()`.
|
|
114
|
+
|
|
115
|
+
Migration: rename `request` to `event`, replace `requestId` with `event.id`, and
|
|
116
|
+
replace `responseMessageId` with `event.payload.responseMessageId`.
|
|
117
|
+
|
|
118
|
+
- 862dfdb: Use `AIState` directly for AI reducers, server reads, hydration, and React.
|
|
119
|
+
Remove the public stored-state types and `view`/`fromView` conversion methods.
|
|
120
|
+
Checkpoint and subscription encoding remain internal. Reducer and client types
|
|
121
|
+
no longer distinguish stored state from view state.
|
|
122
|
+
|
|
123
|
+
Keep tool payloads in message parts and retain only identity and status in the
|
|
124
|
+
tool activity ledger. Current compaction metadata no longer repeats the model
|
|
125
|
+
context.
|
|
126
|
+
|
|
127
|
+
The AI and context reducer cache identities advance; existing event logs remain
|
|
128
|
+
the source for rebuilding those checkpoints.
|
|
129
|
+
|
|
130
|
+
Active-step recovery retains the original part count, text lengths, and
|
|
131
|
+
overwritten fields instead of another complete copy of the response. The step's
|
|
132
|
+
events remain available for exact interruption cutoffs and cold retries, and
|
|
133
|
+
recovery is released when the response closes. An extension that removes or
|
|
134
|
+
rewrites the streaming response releases that recovery instead of failing the
|
|
135
|
+
fold. Streaming updates copy only the
|
|
136
|
+
parts they change. The benchmark reports streaming, tool waiting, and completed
|
|
137
|
+
responses separately.
|
|
138
|
+
|
|
139
|
+
Export `authorizeAgentIngress` from `experimental-a2/ai/server`. Custom
|
|
140
|
+
`createServer()` assemblies pass it as `server.fetch(request, { authorize })`
|
|
141
|
+
to apply the same browser allowlist `createAgentServer()` installs.
|
|
142
|
+
|
|
143
|
+
- 1987df0: Actors follow session clearing. After `handle.session.clear()`, snapshots,
|
|
144
|
+
call answers, and state commits carry `clearIndex`, and the live stream sends
|
|
145
|
+
the actor's initial state through the route's `view` as a reset, so
|
|
146
|
+
`useActor` drops older history. A delayed reset never replaces a newer
|
|
147
|
+
snapshot. A call whose message is cleared before it is answered rejects with
|
|
148
|
+
`SESSION_CLEARED`, which the route answers with `410` and the actor client
|
|
149
|
+
raises as an `ActorRequestError` with the `A2Error` as its `cause`. A message
|
|
150
|
+
that reuses the cleared call's id can't answer it.
|
|
151
|
+
|
|
152
|
+
`ActorCallResult` and `ActorSnapshot` gain an optional `clearIndex`; actors
|
|
153
|
+
that are never cleared return the same shapes as before.
|
|
154
|
+
|
|
155
|
+
- 92de099: Support `session.clear()` in both Redis stores. A clear moves the session's log
|
|
156
|
+
aside in one step, drops its pending work, and writes the marker into a fresh
|
|
157
|
+
log, so every read, live feed, and cached state tail starts at the marker at
|
|
158
|
+
once. Deletion then drains the moved log in batches: event metadata, pins, lane
|
|
159
|
+
pointers, and the id keys that still name a deleted event, so an id reused after
|
|
160
|
+
a clear keeps its new owner.
|
|
161
|
+
|
|
162
|
+
Sessions that are never cleared send the same number of commands as before,
|
|
163
|
+
apart from one: a reducer's first snapshot write-back in a session records its
|
|
164
|
+
name in a `{prefix}:{session}:snap-reducers` set, so clearing can delete every
|
|
165
|
+
reducer's cached state without a key scan. This relies on the fresh `keyPrefix`
|
|
166
|
+
this release already requires; on a reused prefix, snapshots written by an
|
|
167
|
+
earlier version are left behind by a clear until their reducer writes again.
|
|
168
|
+
|
|
169
|
+
Upgrade every instance before clearing any session: an earlier version ignores
|
|
170
|
+
the clear boundary and can dispatch cleared events into the new lifetime.
|
|
171
|
+
|
|
172
|
+
- eb3d6b6: Support `session.clear()` in the SQLite and Postgres stores. Both add an
|
|
173
|
+
`a2_clears` table (one row per cleared session) on their next schema setup; no
|
|
174
|
+
index is built over existing events. Clearing deletes old history in batches
|
|
175
|
+
that skip rows other transactions hold, so deletion never waits on or
|
|
176
|
+
deadlocks with foreground work. In Postgres, reusing an event id whose cleared
|
|
177
|
+
row another transaction still holds fails with the retryable
|
|
178
|
+
`STORE_UNAVAILABLE` instead of waiting, and snapshot write-back locks its head
|
|
179
|
+
row before the events it pins.
|
|
180
|
+
|
|
181
|
+
Upgrade every instance before clearing any session: an earlier version ignores
|
|
182
|
+
the clear boundary and can dispatch cleared events into the new lifetime.
|
|
183
|
+
|
|
184
|
+
- 08de5d6: Add `session.clear({ ifLastIndex })`, which ends a session's current lifetime
|
|
185
|
+
without restarting its indexes. A clear appends a reserved marker in one atomic
|
|
186
|
+
step, supersedes every piece of work from the old lifetime, then deletes the old
|
|
187
|
+
history in bounded batches before it resolves. Pushes and appends after the
|
|
188
|
+
marker start the new lifetime. Every built-in store supports clearing.
|
|
189
|
+
|
|
190
|
+
`session.stream()` yields the marker as `SessionCleared`, whose `type` is
|
|
191
|
+
`'a2.cleared'`. `session.state()` returns
|
|
192
|
+
`clearIndex` once a session has been cleared, and the snapshot types, the
|
|
193
|
+
automatic subscription snapshot, and the HTTP history lane
|
|
194
|
+
(`a2-clear-index`) carry it, so clients reset and drop older history. A
|
|
195
|
+
handler whose event was cleared never folds the new lifetime: `state()`
|
|
196
|
+
throws `SESSION_CLEARED` once it reads past the clear.
|
|
197
|
+
|
|
198
|
+
Event types starting with `a2.` are now reserved for A2 and rejected by
|
|
199
|
+
`contract()`. Actors already reserved the prefix for their own events.
|
|
200
|
+
|
|
201
|
+
- 1579995: Add `session.schedule.clear(name, { delay | at, ifLastIndex })`, a durable
|
|
202
|
+
conditional clear. Delivery runs `clear({ ifLastIndex })` and acknowledges
|
|
203
|
+
only after the old history is deleted, so a provider retry finishes an
|
|
204
|
+
interrupted deletion. A delivery whose condition no longer holds changes
|
|
205
|
+
nothing, and no event is appended. `deliverSchedulerClear` and the
|
|
206
|
+
`SchedulerClearTask` type are exported from `experimental-a2/server` for custom
|
|
207
|
+
scheduler adapters, and both built-in schedulers route clear tasks.
|
|
208
|
+
|
|
209
|
+
Appends scheduled by a handler now carry their triggering event's index as
|
|
210
|
+
`originIndex`. If the session is cleared before delivery, the task is
|
|
211
|
+
acknowledged without appending. Once a session has been cleared, handler task
|
|
212
|
+
ids include the clear, so a trigger id reused in the new lifetime schedules a
|
|
213
|
+
new task. Sessions that were never cleared derive the same task ids as before.
|
|
214
|
+
|
|
215
|
+
Upgrade every scheduler route before scheduling clears, and don't roll back
|
|
216
|
+
while clear tasks are pending. An earlier Vercel Queues route keeps failing a
|
|
217
|
+
clear task until retention ends; an earlier QStash route rejects it as
|
|
218
|
+
non-retryable, so QStash moves it to its dead-letter queue.
|
|
219
|
+
|
|
220
|
+
- c2dd95f: Store AI generation progress in fewer bytes: 2.7 times fewer on a measured
|
|
221
|
+
tool-heavy agent session. `ai.generation.progress` payloads are
|
|
222
|
+
`{ startIndex, chunks }`: `startIndex` is the log index of the
|
|
223
|
+
generation's `ai.generation.started`, which replaces the request, input,
|
|
224
|
+
generation, and response ids and the `sequence` each batch used to repeat.
|
|
225
|
+
Adjacent text, reasoning, and tool-input deltas of one part are joined into a
|
|
226
|
+
single chunk before they are stored, and the joined batch projects exactly as
|
|
227
|
+
the separate chunks did.
|
|
228
|
+
|
|
229
|
+
`ActiveGeneration` gains `startIndex`. Reducers still read progress already in
|
|
230
|
+
a log, and history returns it in its original id-carrying shape. Upgrade
|
|
231
|
+
clients with the server: a client reducer from before this release ignores new
|
|
232
|
+
progress, so streamed output doesn't appear in that client until it reloads.
|
|
233
|
+
The AI reducer advances to `a2.ai.state.v26` and the model-context reducer to
|
|
234
|
+
`a2.ai.context.v6`, so their checkpoints rebuild from the log. No storage
|
|
235
|
+
operations, subscriptions, or timers are added.
|
|
236
|
+
|
|
237
|
+
- fa5b816: Publish one optional reducer in a contract and bootstrap unseeded clients
|
|
238
|
+
with a snapshot on their existing SSE or WebSocket subscription. Keep
|
|
239
|
+
server-side reducers through `reducer({ contract, ... }).fold(...)`, the React
|
|
240
|
+
factory, raw events, and history access.
|
|
241
|
+
|
|
242
|
+
Clients bind the contract directly. Client sessions, React providers, and
|
|
243
|
+
hooks accept one optional initial state/index snapshot or its Promise. Cold
|
|
244
|
+
sessions wait for a supplied Promise before connecting; null results use
|
|
245
|
+
subscription bootstrap. React hooks can opt into Suspense for that Promise
|
|
246
|
+
with `suspend: true` without suspending automatic subscription bootstrap.
|
|
247
|
+
State starts from a supplied snapshot or the reducer's initial state, then
|
|
248
|
+
adopts the loaded snapshot atomically. Pending initial Promises show the
|
|
249
|
+
reducer seed unless the hook opts into Suspense. Pushes never wait for the
|
|
250
|
+
snapshot, and HTTP pushes do not wait for a pending initial Promise either;
|
|
251
|
+
WebSocket pushes wait for their connection, which opens once that Promise
|
|
252
|
+
settles. A push sent before the snapshot arrives stays out of the optimistic
|
|
253
|
+
view, along with pushes queued behind it, until its acknowledgement shows
|
|
254
|
+
whether the snapshot already contains it.
|
|
255
|
+
|
|
256
|
+
Multiplexed WebSocket subscribe entries carry a client `attempt` that the
|
|
257
|
+
server echoes on `subscribed` and `unsubscribed`, so a quick release and
|
|
258
|
+
re-subscribe (such as a StrictMode remount) ignores answers to the earlier
|
|
259
|
+
entry.
|
|
260
|
+
|
|
261
|
+
Preserve root `undefined` snapshots over SSE and WebSocket bootstrap without
|
|
262
|
+
conflating them with `null`.
|
|
263
|
+
|
|
264
|
+
Expose `hydrated` on client snapshots and React hook results. It distinguishes
|
|
265
|
+
the reducer seed from a known state/index baseline and remains true while that
|
|
266
|
+
baseline is retained during reconnects. It adds no I/O or connection ownership.
|
|
267
|
+
|
|
268
|
+
- e779c74: Add Core claim/commit and `a2.ai.*` spans. `createAgentServer` shares telemetry
|
|
269
|
+
with its AI handlers; custom assemblies can pass it to `createHandlers`.
|
|
270
|
+
Custom recorders must support the new span names. Durations include nested work.
|
|
271
|
+
- fb721f8: Fix Vercel scheduler callbacks without inline payloads by using one configured
|
|
272
|
+
QueueClient for sends, payload fetches, acknowledgements, and visibility changes.
|
|
273
|
+
Callback routing no longer depends on metadata inside the payload.
|
|
274
|
+
|
|
275
|
+
Replace `scheduledAppends` with `deploymentId?: string | null`, matching the Queue
|
|
276
|
+
SDK: omit it to use the current deployment, pass a deployment ID to target it,
|
|
277
|
+
or pass `null` for deploymentless delivery. The setting applies to all tasks,
|
|
278
|
+
including recovery drains. Publishing and consuming clients must use the same
|
|
279
|
+
deployment scope. Remove the fourth `QueueTransport.send` routing argument;
|
|
280
|
+
injected transports own their provider configuration.
|
|
281
|
+
|
|
282
|
+
Changing the setting does not move already queued tasks. Keep consumers in their
|
|
283
|
+
original scope until they finish. Unlike the former timer-only opt-out,
|
|
284
|
+
`deploymentId: null` also makes recovery deploymentless. Every eligible consumer
|
|
285
|
+
must use the same null setting and remain compatible with pending tasks and
|
|
286
|
+
session work; deploymentless delivery does not mean latest production.
|
|
287
|
+
|
|
288
|
+
### Patch Changes
|
|
289
|
+
|
|
290
|
+
- 3885f5e: Bound Redis append and completion retry reads to the retried batch. Retrying old
|
|
291
|
+
events no longer rereads the session's later history. Applies to both Redis
|
|
292
|
+
transports; existing idempotency and conflict checks are unchanged.
|
|
293
|
+
- 05dbd13: Live events take about 80 fewer bytes each on the wire (18% for 256-byte payloads), and the client applies them in batches. The client asks for wire version 2 (`wire=2`) on SSE and WebSocket streams. In version 2, events the server's stream already holds, such as a Redis catch-up page, travel together in one frame, and the client folds each batch with one notification to listeners. Each event drops the `sessionId` its connection already names and sends `createdAt` as epoch milliseconds; a multiplexed socket names each batch's session once. Events reach application code unchanged, and older clients and servers keep working with version 1.
|
|
294
|
+
- 430d1e3: Contracts with presence now get batched catch-up too. Their streams forward the events a Redis store already holds, so a replay goes out in batched frames with one client notification each, instead of one frame per event. Presence patches still arrive after the snapshot and stay reconciled by `seen`; a patch that arrives during a batch follows it.
|
|
295
|
+
- a7e7491: Drain SQL streaming replay buffers in linear time, and let the memory adapter stream directly from its retained log without copying or spreading large histories. This fixes memory replay failures on large sessions and releases stream subscriptions if copying an event fails. Event ordering, resume positions, live delivery, and database query counts are unchanged.
|
|
296
|
+
|
|
297
|
+
Consumed payloads are released as they are delivered, and the buffer allocation is released with its final event, without waiting for another read or close. SQL still fetches the full unread backlog in each catch-up query.
|
|
298
|
+
|
|
299
|
+
- 3f2a056: Fix Redis HTTP replay stalls when the provider returns only part of a backlog. Stream catch-up now requests bounded batches and continues immediately after nonempty replies, preserving incremental decoding and direct provider errors.
|
|
300
|
+
- b55415a: Make Redis appends and completions one command cheaper by no longer reading the
|
|
301
|
+
shared event-id hash that releases before per-id ownership keys used; a streamed
|
|
302
|
+
AI progress batch now costs 7 billed commands instead of 8. A completion that
|
|
303
|
+
returns an event in its own lane also no longer rewrites that lane's pointers.
|
|
304
|
+
Use a fresh `keyPrefix` when upgrading.
|
|
305
|
+
- 5c1317c: Cut the Redis commands each store operation issues. Upstash bills every call a
|
|
306
|
+
Lua script makes, so the scripts now read the counter, split, and event ids in
|
|
307
|
+
one request, batch metadata reads and writes, and skip calls that change
|
|
308
|
+
nothing. Appending a handled event and running its handler now costs 24 billed
|
|
309
|
+
commands instead of 52. Live streams no longer refresh a watched marker every
|
|
310
|
+
10 seconds, which halves an idle viewer's commands; every write now publishes
|
|
311
|
+
its wake-up instead of first checking for the marker. Applies to both Redis
|
|
312
|
+
transports.
|
|
313
|
+
|
|
314
|
+
During a rollout, writes from earlier deployments still check for the marker,
|
|
315
|
+
which new viewers no longer set, so those events reach new viewers on the
|
|
316
|
+
10-second safety read instead of immediately. Nothing is lost.
|
|
317
|
+
|
|
318
|
+
- faaaff7: Store Redis event-id ownership in one key per id instead of one shared hash, so
|
|
319
|
+
long-lived deployments no longer hit provider per-key size limits as sessions
|
|
320
|
+
accumulate. Applies to both Redis transports.
|
|
321
|
+
|
|
322
|
+
This is a breaking storage change: the shared hash is no longer read, so switch
|
|
323
|
+
to a fresh `keyPrefix` when upgrading. On an existing prefix, ids recorded only
|
|
324
|
+
in the shared hash lose their ownership, and earlier versions cannot see ids
|
|
325
|
+
recorded after the upgrade, so a retry on either side can append a duplicate
|
|
326
|
+
event. Vercel Queues keeps running recovery and scheduled work on the deployment
|
|
327
|
+
that published it for up to 7 days, so do not roll back to an earlier version on
|
|
328
|
+
an upgraded prefix.
|
|
329
|
+
|
|
330
|
+
- 8b5afc6: Replay Redis backlogs with much less CPU. Redis HTTP catch-up decodes the entries that complete in each response chunk with one `JSON.parse`, instead of scanning and parsing them one at a time, and hands them to the stream without an await per event. `server.fetch` writes the frames of events a Redis stream already holds together, in chunks of about 64 Ki characters plus the frame that crosses that size. Redis commands, SSE frames, event order, resume positions, and memory bounds are unchanged.
|
|
331
|
+
- 8174d0d: Stream AI tokens as they arrive and stop re-reading the log on every wake-up.
|
|
332
|
+
Redis wake-up messages now carry the appended events, so live streams, including
|
|
333
|
+
the server's own stop watcher, apply them without reading; gaps, reconnects,
|
|
334
|
+
oversized batches, and the safety read still catch up from the log. A handler
|
|
335
|
+
appending only settled events no longer triggers a drain or a pending check. AI
|
|
336
|
+
progress batches now flush as soon as the previous write finishes
|
|
337
|
+
(`progress.maxDelayMs` defaults to 0 and `progress.maxChunks` to 128), so each
|
|
338
|
+
chunk is written as it arrives and chunks that arrive while a write is in flight
|
|
339
|
+
share the next one. In a measured agent turn, writing every token cost 3,737
|
|
340
|
+
Redis commands against 4,549 for the previous 30 ms batches, and a watching
|
|
341
|
+
browser added no reads.
|
|
342
|
+
- cfeafec: Store Redis per-event metadata in hashes of 1,000 consecutive events instead of
|
|
343
|
+
one hash per session, so a long session's metadata no longer approaches
|
|
344
|
+
provider per-key size limits. Metadata recorded before the upgrade stays where
|
|
345
|
+
it is, and existing data needs no migration. Applies to both Redis transports.
|
|
346
|
+
|
|
347
|
+
The upgrade is one-way for a key prefix. Earlier versions read only the single
|
|
348
|
+
hash, so they cannot see metadata for events recorded after the upgrade and
|
|
349
|
+
could re-run handlers for in-flight events or stall lanes. Vercel Queues keeps
|
|
350
|
+
running recovery and scheduled work on the deployment that published it for up
|
|
351
|
+
to 7 days, so earlier deployments keep touching sessions after an upgrade.
|
|
352
|
+
Switch to a fresh `keyPrefix` when upgrading, or keep earlier deployments' work
|
|
353
|
+
away from upgraded sessions until it drains. Do not roll back to an earlier
|
|
354
|
+
version on an upgraded prefix.
|
|
355
|
+
|
|
356
|
+
- 6fe0154: Write SSE frames for a Redis HTTP backlog around each event's stored payload JSON, without parsing and re-serializing it. `session.stream()` still yields parsed events, and the SSE bytes are unchanged.
|
|
357
|
+
- 94b33b3: A TCP Redis store created from `url` decodes live feed catch-up pages with less work: it reads each `XRANGE` page as raw bytes and turns only the five values a row needs into strings, instead of all thirteen per event. Rows and SSE bytes are unchanged, and so are injected clients.
|
|
358
|
+
- a55272b: TCP Redis live feeds catch up in pages of 1,000 events instead of 256, which cuts the billed `XRANGE` commands for a long backlog by about four. Their SSE frames also reuse each event's stored payload JSON. A catching-up TCP feed can hold up to 1,000 events in memory at once, up from 256.
|
|
359
|
+
- 46fee5f: Stream Redis HTTP catch-up in one request by default, decoding events as the consumer pulls instead of materializing a full page. Closing the stream aborts its active catch-up request.
|
|
360
|
+
|
|
361
|
+
A delayed subscription-capability check cannot interrupt a channel that has already connected.
|
|
362
|
+
|
|
363
|
+
There is no new configuration or automatic fallback to smaller reads. Provider rejections, including response-size limits, surface as `STORE_UNAVAILABLE` with the provider's error message. Callers can consume bounded `history({ gte, lte })` ranges before opening `stream({ startAfter: lastIndex })` to reduce the unread range. Provider buffering remains outside A2's memory bound. An in-flight read can finish its captured pre-clear history before reaching the clear marker. History, state reads, TCP Redis, and subscription-free polling are unchanged.
|
|
364
|
+
|
|
365
|
+
- e5c52b8: Keep reducer state in server memory between reads. Each server instance keeps
|
|
366
|
+
the latest state it folded per session and reducer, bounded to 1,000 entries and
|
|
367
|
+
roughly 32 MB. A handler read at its own trigger needs no store request. Other
|
|
368
|
+
reads fetch only the events after the cached one and check that event's id, so a
|
|
369
|
+
missing or rewritten log falls back to the store; on Redis that is one command
|
|
370
|
+
for up to 255 events, and longer tails read the stored snapshot. Snapshots are
|
|
371
|
+
written on cold reads, for handler retries, and every 128 events instead of
|
|
372
|
+
after nearly every read. On stores without the Redis fast path, warm reads call
|
|
373
|
+
`readHistory` (or `read`) instead of `readState`, and `a2.state` spans report
|
|
374
|
+
`a2.state.snapshot` as `memory`.
|
|
375
|
+
|
|
3
376
|
## 0.16.1
|
|
4
377
|
|
|
5
378
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as A2Store } from "./store-
|
|
3
|
-
import {
|
|
4
|
-
import { i as A2Telemetry } from "./telemetry-
|
|
1
|
+
import { s as Contract, t as Reducer, u as EventDefs, v as StandardSchemaV1 } from "./reducer-CqA59Q6U.js";
|
|
2
|
+
import { t as A2Store } from "./store-Djdv0bnZ.js";
|
|
3
|
+
import { h as Session, n as A2Server, p as ScheduleTiming, t as A2Scheduler } from "./server-En7cbi3v.js";
|
|
4
|
+
import { i as A2Telemetry } from "./telemetry-Cyfqo6Qt.js";
|
|
5
5
|
//#region src/actor-shared.d.ts
|
|
6
6
|
/**
|
|
7
7
|
* A handler answered by throwing `NonRetriableError`: the event
|
|
@@ -128,6 +128,8 @@ type ActorStatePayload<S> = {
|
|
|
128
128
|
event: string;
|
|
129
129
|
/** The message (invocation event) id this state answers. */
|
|
130
130
|
message: string;
|
|
131
|
+
/** The session's latest clear marker when this state was read. */
|
|
132
|
+
clearIndex?: number;
|
|
131
133
|
};
|
|
132
134
|
/** The event vocabulary a client needs to follow an actor's state. */
|
|
133
135
|
type ActorClientEventDefs<S> = {
|
|
@@ -248,6 +250,11 @@ type ActorCallResult<S> = {
|
|
|
248
250
|
state: S;
|
|
249
251
|
/** Log index of the state commit that answered this message. */
|
|
250
252
|
index: number;
|
|
253
|
+
/**
|
|
254
|
+
* The clear marker this state's lifetime began at, once the actor has been
|
|
255
|
+
* cleared. For a call answer it is the lifetime the handler read.
|
|
256
|
+
*/
|
|
257
|
+
clearIndex?: number;
|
|
251
258
|
};
|
|
252
259
|
type CallMethod<D extends ActorProtocol, K extends keyof D["events"]> = {} extends D["events"][K] ? (input?: D["events"][K], options?: ActorCallOptions) => Promise<ActorCallResult<D["state"]>> : (input: D["events"][K], options?: ActorCallOptions) => Promise<ActorCallResult<D["state"]>>;
|
|
253
260
|
type SendMethod<D extends ActorProtocol, K extends keyof D["events"]> = {} extends D["events"][K] ? (input?: D["events"][K], options?: ActorSendOptions) => Promise<{
|
|
@@ -262,8 +269,10 @@ type ActorHandle<D extends ActorProtocol> = {
|
|
|
262
269
|
readonly id: string;
|
|
263
270
|
/**
|
|
264
271
|
* Send the event and await its answer: the state after the handler
|
|
265
|
-
* ran, or a rejection with `ActorRefusedError`.
|
|
266
|
-
*
|
|
272
|
+
* ran, or a rejection with `ActorRefusedError`. A clear before the call
|
|
273
|
+
* receives its answer rejects with `A2Error('SESSION_CLEARED')`. Serial
|
|
274
|
+
* events only — concurrent handlers produce no answer to await; `send`
|
|
275
|
+
* them.
|
|
267
276
|
*/
|
|
268
277
|
readonly call: { readonly [K in keyof D["events"]]: CallMethod<D, K>; };
|
|
269
278
|
/** Cast: validate, append the event durably, return without waiting. */
|
|
@@ -273,9 +282,10 @@ type ActorHandle<D extends ActorProtocol> = {
|
|
|
273
282
|
/**
|
|
274
283
|
* The managed door — the actor mirror of `server.fetch`, bound to
|
|
275
284
|
* this instance. GET streams the state plane (`a2.actor.state`
|
|
276
|
-
* commits
|
|
277
|
-
* POST is the call lane `createActorClient` speaks
|
|
278
|
-
* input, messageId? }` → the answer, 409 for a refusal
|
|
285
|
+
* commits and clear resets, `?index` resume, heartbeat, deadline
|
|
286
|
+
* rotation); POST is the call lane `createActorClient` speaks
|
|
287
|
+
* (`{ event, input, messageId? }` → the answer, 409 for a refusal,
|
|
288
|
+
* 410 for a call cleared before its answer). Your route
|
|
279
289
|
* authenticates and picks the instance; `authorize` sees every
|
|
280
290
|
* operation. Custom endpoints are route code around this call.
|
|
281
291
|
*/
|
|
@@ -295,7 +305,7 @@ type ActorDefinition<D extends ActorProtocol> = {
|
|
|
295
305
|
readonly contract: Contract<EventDefs>;
|
|
296
306
|
/** The underlying A2 server — `server.fetch` mounts the full session wire. */
|
|
297
307
|
readonly server: A2Server<EventDefs>;
|
|
298
|
-
/** The state fold
|
|
308
|
+
/** The state fold over commits; a clear resets it to the initial state. */
|
|
299
309
|
readonly reducer: Reducer<ActorClientEventDefs<D["state"]>, D["state"]>;
|
|
300
310
|
actor(id: string): ActorHandle<D>;
|
|
301
311
|
};
|
|
@@ -307,4 +317,4 @@ type ActorDefinition<D extends ActorProtocol> = {
|
|
|
307
317
|
declare function actor<D extends ActorProtocol>(options: ActorOptions<D>): ActorDefinition<D>;
|
|
308
318
|
//#endregion
|
|
309
319
|
export { ActorProtocol as _, ActorHandle as a, ActorScheduleSend as b, ActorOptions as c, concurrent as d, ActorConcurrentContext as f, ActorPresenceValues as g, ActorPresenceOf as h, ActorFetchOptions as i, ActorSendOptions as l, ActorPresenceMap as m, ActorCallResult as n, ActorHandler as o, ActorContext as p, ActorDefinition as r, ActorOperation as s, ActorCallOptions as t, actor as u, ActorRefusedError as v, ActorSend as x, ActorScheduleOptions as y };
|
|
310
|
-
//# sourceMappingURL=actor-
|
|
320
|
+
//# sourceMappingURL=actor-Bjce9_5U.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"actor-Bjce9_5U.d.ts","names":[],"sources":["../src/actor-shared.ts","../src/actor.ts"],"mappings":";;;;;;;;;;;cAiCa,0BAA0B;;WAE5B;;WAEA;EACT,YAAY,eAAe,mBAAmB;;;;;;;;;KAepC;EACV;EACA;;;;;;;EAOA;;;KAIU,gBAAgB,UAAU,iBAAiB;EACrD,gBAAgB;IAEd;;KAIQ,oBAAoB,QAC7B,WAAW,cAAc,EAAE;;;;;;KAQlB,iBAAiB;GAExB,yBAAA,WAAW;IAAgB,OAAO,EAAE;IAAI;IAAc,IAAI;;;;;;;;;;;;KAanD,UAAU,iBACV,WAAW,eAAe,EAAE,MACjC,QAAQ,EAAE,eACV,OAAO,EAAE;;;;;;;;;KAWJ,uBAAuB;EAAmB;;;;;;;;;;;;KAY1C,kBAAkB,iBAClB,WAAW,eAAe,EAAE,MACjC,OAAO,EAAE,gBAAgB,SAAS,yBAAyB,iBAC3D,OAAO,EAAE,IAAI,SAAS,yBAAyB;;KAI1C,aAAa,UAAU;;EAEjC,OAAO;;EAEP;;EAEA;;EAEA,QAAQ;;EAER,MAAM,UAAU;;EAEhB,UAAU,kBAAkB;;;;;;;;KASlB,uBAAuB,UAAU;;EAE3C;;EAEA;;EAEA,QAAQ;;EAER,SAAS;IAAU,OAAO;IAAY;;;EAEtC,MAAM,UAAU;;EAEhB,UAAU,kBAAkB;;KAGlB,kBAAkB;EAC5B,OAAO;;EAEP;;EAEA;;EAEA;;;KAWU,qBAAqB;EAC/B,kBAAkB,iBAAiB,kBAAkB;;;;;;;;;;;;;;KCzE3C,aAAa,UAAU,eAAe,gBAAgB,iBAC5D,KAAK,aAAa,IAAI,OAAO,YAAY,cAAc;EAEvD;EACA,SACE,KAAK,uBAAuB,IAC5B,OAAO,YAAY,cACT;;;;;;;;;;;;;;;;iBAiBF,WAAW,KAAK,GAC9B,SAAS,KAAK,KAAK,OAAO,aAAa;EACpC;EAAkB,SAAS,KAAK,KAAK,OAAO,aAAa;;KAIlD,aAAa,UAAU;;EAEjC;;EAEA,OAAO;;;;;EAKP,aAAa,WAAW,cAAc,aAAa,GAAG;EACtD,QAAQ;EACR,YAAY;EACZ,YAAY;MACR,gBAAgB;EAChB;;;;;;;;;;;;EAYA;;;;;;;KAQM;WACG;WAAwB;;WAExB;WACA;WACA;;WAGA;WACA;WACA;WACA;WACA;;WAGA;WACA;WACA;WACA,QAAQ,SAAS;;KAGpB,kBAAkB,UAAU;;EAEtC,aAAa,WAAW,6BAA6B;;;;;;;;;;;;EAYrD,QAAQ,OAAO;;KAGL;;EAEV;;KAGU,mBAAmB;;EAE7B;;KAGU,gBAAgB;;EAE1B,OAAO;;EAEP;;;;;EAKA;;KAGG,WACH,UAAU,eACV,gBAAgB,0BACH,YAAY,MAErB,QAAQ,YAAY,IACpB,UAAU,qBACP,QAAQ,gBAAgB,gBAE3B,OAAO,YAAY,IACnB,UAAU,qBACP,QAAQ,gBAAgB;KAE5B,WACH,UAAU,eACV,gBAAgB,0BACH,YAAY,MAErB,QAAQ,YAAY,IACpB,UAAU,qBACP;EAAU;EAAY;MAEzB,OAAO,YAAY,IACnB,UAAU,qBACP;EAAU;EAAY;;;KAGnB,YAAY,UAAU;WACvB;;;;;;;;WAQA,kBAAkB,WAAW,cAAc,WAAW,GAAG;;WAEzD,kBAAkB,WAAW,cAAc,WAAW,GAAG;;WAEzD,aAAa,QAAQ,gBAAgB;;;;;;;;;;;WAWrC,QACP,SAAS,SACT,UAAU,kBAAkB,OACzB,QAAQ;;WAEJ,SAAS,QAAQ;;KAGhB,gBAAgB,UAAU;WAC3B;;;;;;WAMA,WAAW;;WAEX,UAAU,SAAS;;WAEnB,QAAQ,SAAS;;WAEjB,SAAS,QAAQ,qBAAqB,aAAa;EAC5D,MAAM,aAAa,YAAY;;;;;;;iBAsDjB,MAAM,UAAU,eAC9B,SAAS,aAAa,KACrB,gBAAgB"}
|
package/dist/actor-client.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as ActorCallResult, v as ActorRefusedError } from "./actor-
|
|
1
|
+
import { n as ActorCallResult, v as ActorRefusedError } from "./actor-Bjce9_5U.js";
|
|
2
2
|
//#region src/actor-client.d.ts
|
|
3
3
|
declare class ActorRequestError extends Error {
|
|
4
4
|
readonly status: number | undefined;
|
|
@@ -27,10 +27,7 @@ type ActorStateOf<D extends AnyActorDefinition> = Awaited<ReturnType<HandleOf<D>
|
|
|
27
27
|
type ActorClientCall<D extends AnyActorDefinition, View = ActorStateOf<D>> = { readonly [K in keyof HandleOf<D>["call"]]: HandleOf<D>["call"][K] extends ((...args: infer P) => Promise<{
|
|
28
28
|
state: unknown;
|
|
29
29
|
index: number;
|
|
30
|
-
}>) ? (...args: P) => Promise<
|
|
31
|
-
state: View;
|
|
32
|
-
index: number;
|
|
33
|
-
}> : never; };
|
|
30
|
+
}>) ? (...args: P) => Promise<ActorCallResult<View>> : never; };
|
|
34
31
|
type ActorClient<D extends AnyActorDefinition, View = ActorStateOf<D>> = {
|
|
35
32
|
/** Typed calls over POST — the response is the answer. */
|
|
36
33
|
readonly call: ActorClientCall<D, View>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actor-client.d.ts","names":[],"sources":["../src/actor-client.ts"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"actor-client.d.ts","names":[],"sources":["../src/actor-client.ts"],"mappings":";;cA0Ba,0BAA0B;WAC5B;EAET,YAAY,iBAAiB;IAAY;IAAiB;;;;KAQhD;EACV,MAAM;IACJ,SAAS;MAAU;MAAgB;;IACnC;;;KAIC,SAAS,UAAU,sBAAsB,WAAW;KAE7C,aAAa,UAAU,sBAAsB,QACvD,WAAW,SAAS;;;;;;KAQV,gBACV,UAAU,oBACV,OAAO,aAAa,kBAEV,WAAW,SAAS,aAAa,SAAS,WAAW,gBAC1D,YAAY,MACZ;EAAU;EAAgB;UACvB,MAAM,MAAM,QAAQ,gBAAgB;KAIlC,YACV,UAAU,oBACV,OAAO,aAAa;;WAGX,MAAM,gBAAgB,GAAG;WACzB,aAAa,QAAQ,gBAAgB;;KAGpC,yBAAyB;;EAEnC;;EAEA,eAAe,WAAW;EAC1B,cAAc,UAAU,gBAAgB;;;;;;;;iBAsG1B,kBACd,UAAU,oBACV,OAAO,aAAa,IACpB,SAAS,yBAAyB,QAAQ,YAAY,GAAG"}
|
package/dist/actor-client.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { i as
|
|
1
|
+
import { i as A2Error } from "./session-clear-DGI4jTQ5.js";
|
|
2
|
+
import { i as ActorRefusedError } from "./actor-shared-t7w8xIKP.js";
|
|
2
3
|
//#region src/actor-client.ts
|
|
3
4
|
/**
|
|
4
5
|
* experimental-a2/actor/client — typed calls to an actor over HTTP.
|
|
@@ -8,7 +9,8 @@ import { i as ActorRefusedError } from "./actor-shared-B5tJfzt-.js";
|
|
|
8
9
|
* `client.call` mirrors the server handle's `call` record over the
|
|
9
10
|
* call lane `handle.fetch` serves — POST `{ event, input, messageId? }`
|
|
10
11
|
* → the answer (post-state), a 409 refusal (revived as
|
|
11
|
-
* `ActorRefusedError`),
|
|
12
|
+
* `ActorRefusedError`), a 410 for a call cleared before its answer
|
|
13
|
+
* (an `ActorRequestError` whose `cause` is the `A2Error`), or a 400. Both ends of that wire are library
|
|
12
14
|
* code: the types here are backed by `handle.fetch`, not by a
|
|
13
15
|
* hand-written convention.
|
|
14
16
|
*
|
|
@@ -40,7 +42,13 @@ const callOverWire = async (fetchImpl, api, event, input, options) => {
|
|
|
40
42
|
});
|
|
41
43
|
const body = await responseBody(response);
|
|
42
44
|
if (response.status === 409 && typeof body["error"] === "string") throw new ActorRefusedError(typeof body["event"] === "string" ? body["event"] : event, typeof body["messageId"] === "string" ? body["messageId"] : "", body["error"]);
|
|
43
|
-
if (!response.ok)
|
|
45
|
+
if (!response.ok) {
|
|
46
|
+
const message = typeof body["error"] === "string" ? body["error"] : `actor call failed (${response.status})`;
|
|
47
|
+
throw new ActorRequestError(message, {
|
|
48
|
+
status: response.status,
|
|
49
|
+
...response.status === 410 && body["code"] === "SESSION_CLEARED" ? { cause: new A2Error("SESSION_CLEARED", message) } : {}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
44
52
|
return snapshotBody(body, response.status);
|
|
45
53
|
};
|
|
46
54
|
const requestOverWire = async (fetchImpl, api, init) => {
|
|
@@ -63,7 +71,8 @@ const responseBody = async (response) => {
|
|
|
63
71
|
}
|
|
64
72
|
};
|
|
65
73
|
const snapshotBody = (body, status) => {
|
|
66
|
-
|
|
74
|
+
const clearIndex = body["clearIndex"];
|
|
75
|
+
if (!("state" in body) || !Number.isSafeInteger(body["index"]) || body["index"] < 0 || clearIndex !== void 0 && (!Number.isSafeInteger(clearIndex) || clearIndex < 1 || clearIndex > body["index"])) throw new ActorRequestError("actor request returned an invalid snapshot", { status });
|
|
67
76
|
return body;
|
|
68
77
|
};
|
|
69
78
|
/**
|
package/dist/actor-client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actor-client.js","names":[],"sources":["../src/actor-client.ts"],"sourcesContent":["/**\n * experimental-a2/actor/client — typed calls to an actor over HTTP.\n * Framework-agnostic: no React, no framework machinery; works in any\n * browser code and server-to-server.\n *\n * `client.call` mirrors the server handle's `call` record over the\n * call lane `handle.fetch` serves — POST `{ event, input, messageId? }`\n * → the answer (post-state), a 409 refusal (revived as\n * `ActorRefusedError`), or a 400. Both ends of that wire are library\n * code: the types here are backed by `handle.fetch`, not by a\n * hand-written convention.\n *\n * ```ts\n * import type { vault } from '@/app/vault/server' // type-only, erased\n * const client = createActorClient<typeof vault>({ api: `/vault/${id}` })\n * await client.call.withdraw({ amount: 60 }) // ActorRefusedError on refusal\n * ```\n */\n\nimport { ActorRefusedError } from './actor-shared.ts'\nimport type { ActorCallOptions, ActorCallResult } from './actor.ts'\n\nexport { ActorRefusedError }\n\nexport class ActorRequestError extends Error {\n readonly status: number | undefined\n\n constructor(message: string, options?: { status?: number; cause?: unknown }) {\n super(message, { cause: options?.cause })\n this.name = 'ActorRequestError'\n this.status = options?.status\n }\n}\n\n/** The loose shape of an `actor()` definition — carried type-only. */\nexport type AnyActorDefinition = {\n actor(id: string): {\n state(): Promise<{ state: unknown; index: number }>\n call: object\n }\n}\n\ntype HandleOf<D extends AnyActorDefinition> = ReturnType<D['actor']>\n\nexport type ActorStateOf<D extends AnyActorDefinition> = Awaited<\n ReturnType<HandleOf<D>['state']>\n>['state']\n\n/**\n * The server handle's `call` record mirrored to the client, with\n * answers carrying `View` — the projected shape when the route mounts\n * `fetch(req, { view })`, the full state otherwise (the default).\n */\nexport type ActorClientCall<\n D extends AnyActorDefinition,\n View = ActorStateOf<D>,\n> = {\n readonly [K in keyof HandleOf<D>['call']]: HandleOf<D>['call'][K] extends (\n ...args: infer P\n ) => Promise<{ state: unknown; index: number }>\n ? (...args: P) => Promise<{ state: View; index: number }>\n : never\n}\n\nexport type ActorClient<\n D extends AnyActorDefinition,\n View = ActorStateOf<D>,\n> = {\n /** Typed calls over POST — the response is the answer. */\n readonly call: ActorClientCall<D, View>\n readonly state: () => Promise<ActorCallResult<View>>\n}\n\nexport type CreateActorClientOptions<View = unknown> = {\n /** The route whose handler delegates to `handle.fetch` for this instance. */\n api: string\n /** Injectable transport (tests, custom auth headers). */\n fetch?: typeof globalThis.fetch\n onSnapshot?: (snapshot: ActorCallResult<View>) => void\n}\n\nconst CALL_TIMEOUT_MS = 30_000\n\nconst callOverWire = async (\n fetchImpl: typeof globalThis.fetch,\n api: string,\n event: string,\n input: unknown,\n options?: ActorCallOptions,\n): Promise<ActorCallResult<unknown>> => {\n const response = await requestOverWire(fetchImpl, api, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n event,\n ...(input === undefined ? {} : { input }),\n ...(options?.id === undefined ? {} : { messageId: options.id }),\n }),\n signal: AbortSignal.timeout(options?.timeoutMs ?? CALL_TIMEOUT_MS),\n })\n const body = await responseBody(response)\n if (response.status === 409 && typeof body['error'] === 'string') {\n throw new ActorRefusedError(\n typeof body['event'] === 'string' ? body['event'] : event,\n typeof body['messageId'] === 'string' ? body['messageId'] : '',\n body['error'],\n )\n }\n if (!response.ok) {\n const message =\n typeof body['error'] === 'string'\n ? body['error']\n : `actor call failed (${response.status})`\n throw new ActorRequestError(message, { status: response.status })\n }\n return snapshotBody(body, response.status)\n}\n\nconst requestOverWire = async (\n fetchImpl: typeof globalThis.fetch,\n api: string,\n init: RequestInit,\n): Promise<Response> => {\n try {\n return await fetchImpl(api, init)\n } catch (cause) {\n throw new ActorRequestError('actor request did not receive a response', {\n cause,\n })\n }\n}\n\nconst responseBody = async (\n response: Response,\n): Promise<Record<string, unknown>> => {\n try {\n const body: unknown = await response.json()\n if (!body || typeof body !== 'object' || Array.isArray(body))\n throw new Error('invalid response')\n return body as Record<string, unknown>\n } catch (cause) {\n throw new ActorRequestError('actor request returned an invalid response', {\n status: response.status,\n cause,\n })\n }\n}\n\nconst snapshotBody = (\n body: Record<string, unknown>,\n status: number,\n): ActorCallResult<unknown> => {\n if (\n !('state' in body) ||\n !Number.isSafeInteger(body['index']) ||\n (body['index'] as number) < 0\n ) {\n throw new ActorRequestError('actor request returned an invalid snapshot', {\n status,\n })\n }\n return body as ActorCallResult<unknown>\n}\n\n/**\n * A typed call surface for one actor instance's route. When the route\n * mounts a `view`, pass its shape as the second type argument so call\n * answers carry the projected state:\n * `createActorClient<typeof vault, PublicVault>({ api })`.\n */\nexport function createActorClient<\n D extends AnyActorDefinition,\n View = ActorStateOf<D>,\n>(options: CreateActorClientOptions<View>): ActorClient<D, View> {\n const fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis)\n const adopt = (snapshot: ActorCallResult<unknown>): ActorCallResult<View> => {\n const result = snapshot as ActorCallResult<View>\n options.onSnapshot?.(result)\n return result\n }\n const state = async (): Promise<ActorCallResult<View>> => {\n const api = options.api.split('#')[0]!\n const separator = api.includes('?') ? '&' : '?'\n const response = await requestOverWire(\n fetchImpl,\n `${api}${separator}snapshot=1`,\n {\n cache: 'no-store',\n signal: AbortSignal.timeout(CALL_TIMEOUT_MS),\n },\n )\n const body = await responseBody(response)\n if (!response.ok) {\n throw new ActorRequestError(\n typeof body['error'] === 'string'\n ? body['error']\n : `actor state read failed (${response.status})`,\n { status: response.status },\n )\n }\n return adopt(snapshotBody(body, response.status))\n }\n const methods = new Map<\n string,\n (\n input?: unknown,\n callOptions?: ActorCallOptions,\n ) => Promise<ActorCallResult<View>>\n >()\n const call = new Proxy(\n {},\n {\n get: (_target, event) => {\n if (typeof event !== 'string') return undefined\n let method = methods.get(event)\n if (!method) {\n method = (input, callOptions) =>\n callOverWire(\n fetchImpl,\n options.api,\n event,\n input,\n callOptions,\n ).then(adopt)\n methods.set(event, method)\n }\n return method\n },\n },\n ) as ActorClientCall<D, View>\n return { call, state }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"actor-client.js","names":[],"sources":["../src/actor-client.ts"],"sourcesContent":["/**\n * experimental-a2/actor/client — typed calls to an actor over HTTP.\n * Framework-agnostic: no React, no framework machinery; works in any\n * browser code and server-to-server.\n *\n * `client.call` mirrors the server handle's `call` record over the\n * call lane `handle.fetch` serves — POST `{ event, input, messageId? }`\n * → the answer (post-state), a 409 refusal (revived as\n * `ActorRefusedError`), a 410 for a call cleared before its answer\n * (an `ActorRequestError` whose `cause` is the `A2Error`), or a 400. Both ends of that wire are library\n * code: the types here are backed by `handle.fetch`, not by a\n * hand-written convention.\n *\n * ```ts\n * import type { vault } from '@/app/vault/server' // type-only, erased\n * const client = createActorClient<typeof vault>({ api: `/vault/${id}` })\n * await client.call.withdraw({ amount: 60 }) // ActorRefusedError on refusal\n * ```\n */\n\nimport { ActorRefusedError } from './actor-shared.ts'\nimport type { ActorCallOptions, ActorCallResult } from './actor.ts'\nimport { A2Error } from './errors.ts'\n\nexport { ActorRefusedError }\n\nexport class ActorRequestError extends Error {\n readonly status: number | undefined\n\n constructor(message: string, options?: { status?: number; cause?: unknown }) {\n super(message, { cause: options?.cause })\n this.name = 'ActorRequestError'\n this.status = options?.status\n }\n}\n\n/** The loose shape of an `actor()` definition — carried type-only. */\nexport type AnyActorDefinition = {\n actor(id: string): {\n state(): Promise<{ state: unknown; index: number }>\n call: object\n }\n}\n\ntype HandleOf<D extends AnyActorDefinition> = ReturnType<D['actor']>\n\nexport type ActorStateOf<D extends AnyActorDefinition> = Awaited<\n ReturnType<HandleOf<D>['state']>\n>['state']\n\n/**\n * The server handle's `call` record mirrored to the client, with\n * answers carrying `View` — the projected shape when the route mounts\n * `fetch(req, { view })`, the full state otherwise (the default).\n */\nexport type ActorClientCall<\n D extends AnyActorDefinition,\n View = ActorStateOf<D>,\n> = {\n readonly [K in keyof HandleOf<D>['call']]: HandleOf<D>['call'][K] extends (\n ...args: infer P\n ) => Promise<{ state: unknown; index: number }>\n ? (...args: P) => Promise<ActorCallResult<View>>\n : never\n}\n\nexport type ActorClient<\n D extends AnyActorDefinition,\n View = ActorStateOf<D>,\n> = {\n /** Typed calls over POST — the response is the answer. */\n readonly call: ActorClientCall<D, View>\n readonly state: () => Promise<ActorCallResult<View>>\n}\n\nexport type CreateActorClientOptions<View = unknown> = {\n /** The route whose handler delegates to `handle.fetch` for this instance. */\n api: string\n /** Injectable transport (tests, custom auth headers). */\n fetch?: typeof globalThis.fetch\n onSnapshot?: (snapshot: ActorCallResult<View>) => void\n}\n\nconst CALL_TIMEOUT_MS = 30_000\n\nconst callOverWire = async (\n fetchImpl: typeof globalThis.fetch,\n api: string,\n event: string,\n input: unknown,\n options?: ActorCallOptions,\n): Promise<ActorCallResult<unknown>> => {\n const response = await requestOverWire(fetchImpl, api, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n event,\n ...(input === undefined ? {} : { input }),\n ...(options?.id === undefined ? {} : { messageId: options.id }),\n }),\n signal: AbortSignal.timeout(options?.timeoutMs ?? CALL_TIMEOUT_MS),\n })\n const body = await responseBody(response)\n if (response.status === 409 && typeof body['error'] === 'string') {\n throw new ActorRefusedError(\n typeof body['event'] === 'string' ? body['event'] : event,\n typeof body['messageId'] === 'string' ? body['messageId'] : '',\n body['error'],\n )\n }\n if (!response.ok) {\n const message =\n typeof body['error'] === 'string'\n ? body['error']\n : `actor call failed (${response.status})`\n throw new ActorRequestError(message, {\n status: response.status,\n ...(response.status === 410 && body['code'] === 'SESSION_CLEARED'\n ? { cause: new A2Error('SESSION_CLEARED', message) }\n : {}),\n })\n }\n return snapshotBody(body, response.status)\n}\n\nconst requestOverWire = async (\n fetchImpl: typeof globalThis.fetch,\n api: string,\n init: RequestInit,\n): Promise<Response> => {\n try {\n return await fetchImpl(api, init)\n } catch (cause) {\n throw new ActorRequestError('actor request did not receive a response', {\n cause,\n })\n }\n}\n\nconst responseBody = async (\n response: Response,\n): Promise<Record<string, unknown>> => {\n try {\n const body: unknown = await response.json()\n if (!body || typeof body !== 'object' || Array.isArray(body))\n throw new Error('invalid response')\n return body as Record<string, unknown>\n } catch (cause) {\n throw new ActorRequestError('actor request returned an invalid response', {\n status: response.status,\n cause,\n })\n }\n}\n\nconst snapshotBody = (\n body: Record<string, unknown>,\n status: number,\n): ActorCallResult<unknown> => {\n const clearIndex = body['clearIndex']\n if (\n !('state' in body) ||\n !Number.isSafeInteger(body['index']) ||\n (body['index'] as number) < 0 ||\n (clearIndex !== undefined &&\n (!Number.isSafeInteger(clearIndex) ||\n (clearIndex as number) < 1 ||\n (clearIndex as number) > (body['index'] as number)))\n ) {\n throw new ActorRequestError('actor request returned an invalid snapshot', {\n status,\n })\n }\n return body as ActorCallResult<unknown>\n}\n\n/**\n * A typed call surface for one actor instance's route. When the route\n * mounts a `view`, pass its shape as the second type argument so call\n * answers carry the projected state:\n * `createActorClient<typeof vault, PublicVault>({ api })`.\n */\nexport function createActorClient<\n D extends AnyActorDefinition,\n View = ActorStateOf<D>,\n>(options: CreateActorClientOptions<View>): ActorClient<D, View> {\n const fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis)\n const adopt = (snapshot: ActorCallResult<unknown>): ActorCallResult<View> => {\n const result = snapshot as ActorCallResult<View>\n options.onSnapshot?.(result)\n return result\n }\n const state = async (): Promise<ActorCallResult<View>> => {\n const api = options.api.split('#')[0]!\n const separator = api.includes('?') ? '&' : '?'\n const response = await requestOverWire(\n fetchImpl,\n `${api}${separator}snapshot=1`,\n {\n cache: 'no-store',\n signal: AbortSignal.timeout(CALL_TIMEOUT_MS),\n },\n )\n const body = await responseBody(response)\n if (!response.ok) {\n throw new ActorRequestError(\n typeof body['error'] === 'string'\n ? body['error']\n : `actor state read failed (${response.status})`,\n { status: response.status },\n )\n }\n return adopt(snapshotBody(body, response.status))\n }\n const methods = new Map<\n string,\n (\n input?: unknown,\n callOptions?: ActorCallOptions,\n ) => Promise<ActorCallResult<View>>\n >()\n const call = new Proxy(\n {},\n {\n get: (_target, event) => {\n if (typeof event !== 'string') return undefined\n let method = methods.get(event)\n if (!method) {\n method = (input, callOptions) =>\n callOverWire(\n fetchImpl,\n options.api,\n event,\n input,\n callOptions,\n ).then(adopt)\n methods.set(event, method)\n }\n return method\n },\n },\n ) as ActorClientCall<D, View>\n return { call, state }\n}\n"],"mappings":"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"}
|
package/dist/actor-react.d.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { g as ActorPresenceValues, m as ActorPresenceMap } from "./actor-
|
|
1
|
+
import { c as ContractEvent, u as EventDefs } from "./reducer-CqA59Q6U.js";
|
|
2
|
+
import { g as ActorPresenceValues, m as ActorPresenceMap } from "./actor-Bjce9_5U.js";
|
|
3
3
|
import { ActorClientCall, ActorStateOf, AnyActorDefinition } from "./actor-client.js";
|
|
4
|
-
import { a as Connection } from "./client-
|
|
4
|
+
import { a as Connection } from "./client-h_DKFAjj.js";
|
|
5
5
|
//#region src/actor-react.d.ts
|
|
6
6
|
/** The server-to-client handoff: `await def.actor(id).state()`. */
|
|
7
7
|
type ActorSnapshot<S> = {
|
|
8
8
|
state: S;
|
|
9
9
|
index: number;
|
|
10
|
+
/** The latest clear marker, once the actor has been cleared. */
|
|
11
|
+
clearIndex?: number;
|
|
10
12
|
};
|
|
11
13
|
type UseActorOptions<View> = {
|
|
12
14
|
/** The route whose handler delegates to `handle.fetch` for this instance. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actor-react.d.ts","names":[],"sources":["../src/actor-react.ts"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"actor-react.d.ts","names":[],"sources":["../src/actor-react.ts"],"mappings":";;;;;;KAiDY,cAAc;EACxB,OAAO;EACP;;EAEA;;KAGU,gBAAgB;;EAE1B;;EAEA;;EAEA,SAAS,cAAc;;EAEvB;;;KAIG,WAAW,UAAU,sBAAsB;EAC9C,iBAAiB;IAEf,YAAY;EAAa,gBAAgB;IACvC;KAIM,eAAe,UAAU,oBAAoB;;EAEvD,OAAO;;EAEP;EACA,YAAY;;EAEZ,MAAM,gBAAgB,GAAG;EACzB,eAAe,QAAQ,cAAc;;EAErC,QAAQ,cAAc;;;;;;;EAOtB,UAAU,iBAAiB,WAAW;;;;;EAKtC,cAAc,QAAQ,oBAAoB,WAAW;;;iBAoCvC,SAAS,UAAU,oBAAoB,OAAO,aAAa,IACzE,SAAS,gBAAgB,QACxB,eAAe,GAAG"}
|