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/contract.ts
CHANGED
|
@@ -1,15 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
*
|
|
8
|
-
* The contract says what can be *said*; the server says how it's
|
|
9
|
-
* *reacted to*; a reducer says how it's *seen*.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { makeReducerBuilder, type ReducerBuilder } from './reducer.ts'
|
|
1
|
+
import {
|
|
2
|
+
makeReducerBuilder,
|
|
3
|
+
type Reducer,
|
|
4
|
+
type RegisteredReducer,
|
|
5
|
+
} from './reducer.ts'
|
|
6
|
+
import { RESERVED_EVENT_PREFIX } from './session-clear.ts'
|
|
13
7
|
import type { StandardSchemaV1 } from './standard-schema.ts'
|
|
14
8
|
import { assertSyncSchema } from './validate.ts'
|
|
15
9
|
|
|
@@ -121,6 +115,7 @@ export type ReducerOptions<Seed, S> = {
|
|
|
121
115
|
export type Contract<
|
|
122
116
|
D extends EventDefs = EventDefs,
|
|
123
117
|
P extends PresenceDefs = Record<never, never>,
|
|
118
|
+
R = RegisteredReducer<D, P> | undefined,
|
|
124
119
|
> = {
|
|
125
120
|
/** Identity — prefixes storage keys and queue messages. */
|
|
126
121
|
readonly name: string
|
|
@@ -130,19 +125,7 @@ export type Contract<
|
|
|
130
125
|
readonly presence: Readonly<P>
|
|
131
126
|
/** Preserve literal types for a handler-returned event batch. */
|
|
132
127
|
readonly batch: EventBatchFactory<D>
|
|
133
|
-
|
|
134
|
-
* Derive a view from this contract. The reducer's `name` is its
|
|
135
|
-
* identity and snapshot cache key: rename it when the fold's logic
|
|
136
|
-
* changes. Two steps by design: this call fixes the state and event
|
|
137
|
-
* types, so `.fold()` receives fully concrete types — literal unions
|
|
138
|
-
* in your state survive, with zero annotations. (A single call can't
|
|
139
|
-
* do this: TypeScript never contextually types the returns of a
|
|
140
|
-
* context-sensitive argument against generics inferred in the same
|
|
141
|
-
* call.)
|
|
142
|
-
*/
|
|
143
|
-
reducer<Seed, S = Seed>(
|
|
144
|
-
options: ReducerOptions<Seed, S>,
|
|
145
|
-
): ReducerBuilder<D, S, P>
|
|
128
|
+
readonly reducer: R
|
|
146
129
|
}
|
|
147
130
|
|
|
148
131
|
/**
|
|
@@ -150,21 +133,77 @@ export type Contract<
|
|
|
150
133
|
* must be synchronous — async ones are rejected here, at definition
|
|
151
134
|
* time. The result is a plain, importable, isomorphic value.
|
|
152
135
|
*/
|
|
153
|
-
|
|
154
|
-
D extends EventDefs,
|
|
155
|
-
P extends PresenceDefs = Record<never, never>,
|
|
156
|
-
>(options: {
|
|
157
|
-
/** Identity — prefixes storage keys and queue messages. */
|
|
136
|
+
type ContractOptions<D extends EventDefs, P extends PresenceDefs> = {
|
|
158
137
|
name: string
|
|
159
|
-
/** The vocabulary: event name → payload schema (Standard Schema). */
|
|
160
138
|
events: D
|
|
161
|
-
/**
|
|
162
|
-
* Optional second vocabulary: presence field → value schema.
|
|
163
|
-
* Per-participant ephemeral state, replicated last-writer-wins and
|
|
164
|
-
* never stored in the log — reducers cannot see it.
|
|
165
|
-
*/
|
|
166
139
|
presence?: P
|
|
167
|
-
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function contract<
|
|
143
|
+
D extends EventDefs,
|
|
144
|
+
P extends PresenceDefs = Record<never, never>,
|
|
145
|
+
Schema extends StandardSchemaV1 = StandardSchemaV1,
|
|
146
|
+
>(
|
|
147
|
+
options: ContractOptions<D, P> & {
|
|
148
|
+
reducer: {
|
|
149
|
+
name: string
|
|
150
|
+
initialState: StandardSchemaV1.InferInput<NoInfer<Schema>>
|
|
151
|
+
stateSchema: Schema
|
|
152
|
+
fold: (
|
|
153
|
+
state: StandardSchemaV1.InferOutput<Schema>,
|
|
154
|
+
event: ContractEvent<NoInfer<D>>,
|
|
155
|
+
) => StandardSchemaV1.InferOutput<Schema>
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
): Contract<D, P, Reducer<D, StandardSchemaV1.InferOutput<Schema>, P>>
|
|
159
|
+
export function contract<
|
|
160
|
+
D extends EventDefs,
|
|
161
|
+
P extends PresenceDefs = Record<never, never>,
|
|
162
|
+
S = unknown,
|
|
163
|
+
>(
|
|
164
|
+
options: ContractOptions<D, P> & {
|
|
165
|
+
reducer: {
|
|
166
|
+
name: string
|
|
167
|
+
initialState: S
|
|
168
|
+
fold: (state: NoInfer<S>, event: ContractEvent<NoInfer<D>>) => NoInfer<S>
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
): Contract<D, P, Reducer<D, S, P>>
|
|
172
|
+
export function contract<
|
|
173
|
+
D extends EventDefs,
|
|
174
|
+
P extends PresenceDefs = Record<never, never>,
|
|
175
|
+
R extends RegisteredReducer<D, P> = RegisteredReducer<D, P>,
|
|
176
|
+
>(options: ContractOptions<D, P> & { reducer: R }): Contract<D, P, R>
|
|
177
|
+
export function contract<
|
|
178
|
+
D extends EventDefs,
|
|
179
|
+
P extends PresenceDefs = Record<never, never>,
|
|
180
|
+
>(
|
|
181
|
+
options: ContractOptions<D, P> & { reducer?: undefined },
|
|
182
|
+
): Contract<D, P, undefined>
|
|
183
|
+
export function contract(options: AnyContractOptions): unknown {
|
|
184
|
+
for (const type of Object.keys(options.events ?? {})) {
|
|
185
|
+
if (type.startsWith(RESERVED_EVENT_PREFIX)) {
|
|
186
|
+
throw new TypeError(
|
|
187
|
+
`contract '${String(options.name)}': event types starting with '${RESERVED_EVENT_PREFIX}' are reserved`,
|
|
188
|
+
)
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return defineContract(options)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/** A2's own contracts, which may declare reserved `a2.` event types. */
|
|
195
|
+
export const internalContract: typeof contract =
|
|
196
|
+
defineContract as typeof contract
|
|
197
|
+
|
|
198
|
+
type AnyContractOptions = ContractOptions<EventDefs, PresenceDefs> & {
|
|
199
|
+
reducer?:
|
|
200
|
+
| (ReducerOptions<unknown, unknown> & {
|
|
201
|
+
fold: (state: never, event: never) => unknown
|
|
202
|
+
})
|
|
203
|
+
| undefined
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function defineContract(options: AnyContractOptions): unknown {
|
|
168
207
|
const { name } = options
|
|
169
208
|
if (typeof name !== 'string' || name.length === 0) {
|
|
170
209
|
throw new TypeError('contract name must be a non-empty string')
|
|
@@ -183,7 +222,7 @@ export function contract<
|
|
|
183
222
|
}
|
|
184
223
|
const events = Object.freeze({ ...defs })
|
|
185
224
|
|
|
186
|
-
const presenceDefs = options.presence ??
|
|
225
|
+
const presenceDefs = options.presence ?? {}
|
|
187
226
|
for (const [field, schema] of Object.entries(presenceDefs)) {
|
|
188
227
|
if (typeof schema?.['~standard']?.validate !== 'function') {
|
|
189
228
|
throw new TypeError(
|
|
@@ -198,9 +237,20 @@ export function contract<
|
|
|
198
237
|
name,
|
|
199
238
|
events,
|
|
200
239
|
presence,
|
|
201
|
-
batch:
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
240
|
+
batch: <const E extends readonly AppendInput<EventDefs>[]>(
|
|
241
|
+
...items: E
|
|
242
|
+
): E => items,
|
|
243
|
+
reducer:
|
|
244
|
+
options.reducer === undefined
|
|
245
|
+
? undefined
|
|
246
|
+
: {
|
|
247
|
+
...options.reducer,
|
|
248
|
+
...makeReducerBuilder(events, presence, options.reducer).fold(
|
|
249
|
+
options.reducer.fold as (
|
|
250
|
+
state: unknown,
|
|
251
|
+
event: ContractEvent<EventDefs>,
|
|
252
|
+
) => unknown,
|
|
253
|
+
),
|
|
254
|
+
},
|
|
205
255
|
}
|
|
206
256
|
}
|
package/src/deterministic-id.ts
CHANGED
|
@@ -14,6 +14,7 @@ const APPEND_NAMESPACE = 'a2:handler-append:v2'
|
|
|
14
14
|
const RETURN_NAMESPACE = 'a2:handler-return:v1'
|
|
15
15
|
const SCHEDULE_NAMESPACE = 'a2:schedule:v1'
|
|
16
16
|
const SCHEDULED_EVENT_NAMESPACE = 'a2:scheduled-event:v1'
|
|
17
|
+
const SCHEDULE_CLEAR_NAMESPACE = 'a2:schedule-clear:v1'
|
|
17
18
|
|
|
18
19
|
async function deterministicIdFromInput(input: string): Promise<string> {
|
|
19
20
|
const digest = await crypto.subtle.digest(
|
|
@@ -47,11 +48,18 @@ export async function deterministicReturnedEventId(
|
|
|
47
48
|
return deterministicId([RETURN_NAMESPACE, triggerEventId, itemOrdinal])
|
|
48
49
|
}
|
|
49
50
|
|
|
51
|
+
/**
|
|
52
|
+
* The id of a scheduled append. `clearIndex` is the lifetime the trigger was
|
|
53
|
+
* claimed in; it joins the input only when positive, so a trigger id reused
|
|
54
|
+
* after a clear schedules a distinct task while sessions never cleared keep
|
|
55
|
+
* the ids they always had.
|
|
56
|
+
*/
|
|
50
57
|
export async function deterministicScheduleId(
|
|
51
58
|
contract: string,
|
|
52
59
|
sessionId: string,
|
|
53
60
|
triggerEventId: string | null,
|
|
54
61
|
name: string,
|
|
62
|
+
clearIndex = 0,
|
|
55
63
|
): Promise<string> {
|
|
56
64
|
return deterministicIdFromInput(
|
|
57
65
|
JSON.stringify([
|
|
@@ -60,6 +68,35 @@ export async function deterministicScheduleId(
|
|
|
60
68
|
sessionId,
|
|
61
69
|
triggerEventId,
|
|
62
70
|
name,
|
|
71
|
+
...(clearIndex > 0 ? [clearIndex] : []),
|
|
72
|
+
]),
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export async function deterministicScheduleClearId({
|
|
77
|
+
contract,
|
|
78
|
+
sessionId,
|
|
79
|
+
triggerEventId,
|
|
80
|
+
clearIndex,
|
|
81
|
+
name,
|
|
82
|
+
ifLastIndex,
|
|
83
|
+
}: {
|
|
84
|
+
contract: string
|
|
85
|
+
sessionId: string
|
|
86
|
+
triggerEventId: string | null
|
|
87
|
+
clearIndex: number
|
|
88
|
+
name: string
|
|
89
|
+
ifLastIndex: number
|
|
90
|
+
}): Promise<string> {
|
|
91
|
+
return deterministicIdFromInput(
|
|
92
|
+
JSON.stringify([
|
|
93
|
+
SCHEDULE_CLEAR_NAMESPACE,
|
|
94
|
+
contract,
|
|
95
|
+
sessionId,
|
|
96
|
+
triggerEventId,
|
|
97
|
+
clearIndex,
|
|
98
|
+
name,
|
|
99
|
+
ifLastIndex,
|
|
63
100
|
]),
|
|
64
101
|
)
|
|
65
102
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export const sameValue = (left: unknown, right: unknown): boolean => {
|
|
2
|
+
if (Object.is(left, right)) return true
|
|
3
|
+
if (
|
|
4
|
+
typeof left !== 'object' ||
|
|
5
|
+
left === null ||
|
|
6
|
+
typeof right !== 'object' ||
|
|
7
|
+
right === null
|
|
8
|
+
)
|
|
9
|
+
return false
|
|
10
|
+
const prototype = Object.getPrototypeOf(left)
|
|
11
|
+
if (
|
|
12
|
+
prototype !== Object.getPrototypeOf(right) ||
|
|
13
|
+
(prototype !== Object.prototype &&
|
|
14
|
+
prototype !== Array.prototype &&
|
|
15
|
+
prototype !== null)
|
|
16
|
+
)
|
|
17
|
+
return false
|
|
18
|
+
if (
|
|
19
|
+
Array.isArray(left) &&
|
|
20
|
+
(!Array.isArray(right) || left.length !== right.length)
|
|
21
|
+
)
|
|
22
|
+
return false
|
|
23
|
+
const keys = Reflect.ownKeys(left)
|
|
24
|
+
return (
|
|
25
|
+
keys.length === Reflect.ownKeys(right).length &&
|
|
26
|
+
keys.every(
|
|
27
|
+
(key) =>
|
|
28
|
+
Object.hasOwn(right, key) &&
|
|
29
|
+
sameValue(Reflect.get(left, key), Reflect.get(right, key)),
|
|
30
|
+
)
|
|
31
|
+
)
|
|
32
|
+
}
|
package/src/errors.ts
CHANGED
|
@@ -3,7 +3,8 @@ export type A2ServerErrorCode =
|
|
|
3
3
|
| 'FORBIDDEN' // external ingress was denied by server.fetch authorization
|
|
4
4
|
| 'UNKNOWN_EVENT_TYPE' // event type not in the machine's `events` map
|
|
5
5
|
| 'PARTIAL_DUPLICATE_BATCH' // batch mixed already-appended and fresh events
|
|
6
|
-
| 'SUPERSEDED_ATTEMPT' // handler append from an attempt a recovery claim replaced
|
|
6
|
+
| 'SUPERSEDED_ATTEMPT' // handler append from an attempt a recovery claim or a clear replaced
|
|
7
|
+
| 'SESSION_CLEARED' // a read or call reached across the session's latest clear
|
|
7
8
|
| 'CLAIM_EXPIRED' // ctx.signal abort reason: the attempt's lease lapsed without renewal
|
|
8
9
|
| 'STORE_UNAVAILABLE' // store backend failure — retryable, nothing was written
|
|
9
10
|
| 'STORE_NOT_CONFIGURED' // production boot with no `store` passed
|
|
@@ -33,6 +34,17 @@ export class A2Error extends Error {
|
|
|
33
34
|
}
|
|
34
35
|
}
|
|
35
36
|
|
|
37
|
+
/** A handler write whose attempt no longer owns its triggering event. */
|
|
38
|
+
export function supersededAttemptError(
|
|
39
|
+
sessionId: string,
|
|
40
|
+
cause: { index: number; attempt: number },
|
|
41
|
+
): A2Error {
|
|
42
|
+
return new A2Error(
|
|
43
|
+
'SUPERSEDED_ATTEMPT',
|
|
44
|
+
`attempt ${cause.attempt} no longer owns event ${cause.index} in session '${sessionId}'`,
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
|
|
36
48
|
/**
|
|
37
49
|
* Wrap an arbitrary thrown value as STORE_UNAVAILABLE, preserving the
|
|
38
50
|
* original as `cause`. A2Errors pass through untouched — they already
|
package/src/index.ts
CHANGED
|
@@ -22,9 +22,11 @@ export type {
|
|
|
22
22
|
ReducerOptions,
|
|
23
23
|
} from './contract.ts'
|
|
24
24
|
|
|
25
|
-
export
|
|
25
|
+
export { reducer } from './reducer.ts'
|
|
26
|
+
export type { Reducer, ReducerBuilder, StateSnapshot } from './reducer.ts'
|
|
26
27
|
|
|
27
28
|
export { A2Error, NonRetriableError } from './errors.ts'
|
|
29
|
+
export type { SessionCleared } from './session-clear.ts'
|
|
28
30
|
export type { A2ErrorCode, A2ServerErrorCode } from './errors.ts'
|
|
29
31
|
|
|
30
32
|
export type {
|
|
@@ -36,3 +38,5 @@ export type {
|
|
|
36
38
|
|
|
37
39
|
export type { Event } from './store.ts'
|
|
38
40
|
export type { StandardSchemaV1 } from './standard-schema.ts'
|
|
41
|
+
|
|
42
|
+
export type { InitialSnapshot } from './initial-snapshot.ts'
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { StateSnapshot } from './reducer.ts'
|
|
2
|
+
|
|
3
|
+
export type InitialSnapshot<S> =
|
|
4
|
+
| StateSnapshot<S>
|
|
5
|
+
| null
|
|
6
|
+
| undefined
|
|
7
|
+
| Promise<StateSnapshot<S> | null | undefined>
|
|
8
|
+
|
|
9
|
+
export function isInitialPromise<S>(
|
|
10
|
+
initial: InitialSnapshot<S>,
|
|
11
|
+
): initial is Promise<StateSnapshot<S> | null | undefined> {
|
|
12
|
+
return (
|
|
13
|
+
initial !== null &&
|
|
14
|
+
typeof initial === 'object' &&
|
|
15
|
+
'then' in initial &&
|
|
16
|
+
typeof initial.then === 'function'
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function observeInitial<S>(options: {
|
|
21
|
+
promise: Promise<StateSnapshot<S> | null | undefined>
|
|
22
|
+
settled(
|
|
23
|
+
result: { value: StateSnapshot<S> | null | undefined } | { error: unknown },
|
|
24
|
+
): void
|
|
25
|
+
}): () => void {
|
|
26
|
+
let listener: typeof options.settled | undefined = options.settled
|
|
27
|
+
const deliver = (result: Parameters<typeof options.settled>[0]): void => {
|
|
28
|
+
const current = listener
|
|
29
|
+
listener = undefined
|
|
30
|
+
current?.(result)
|
|
31
|
+
}
|
|
32
|
+
void Promise.resolve(options.promise).then(
|
|
33
|
+
(value) => deliver({ value }),
|
|
34
|
+
(error: unknown) => deliver({ error }),
|
|
35
|
+
)
|
|
36
|
+
return () => {
|
|
37
|
+
listener = undefined
|
|
38
|
+
}
|
|
39
|
+
}
|
package/src/internal.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import type { ScheduledEvent } from './scheduler-task.ts'
|
|
7
7
|
import type { DrainableServer } from './server.ts'
|
|
8
|
+
import type { Event } from './store.ts'
|
|
8
9
|
|
|
9
10
|
export type DrainOutcome = 'busy' | 'stalled' | 'settled'
|
|
10
11
|
|
|
@@ -62,11 +63,23 @@ export type ServerInternals = {
|
|
|
62
63
|
schedulerAppend(
|
|
63
64
|
sessionId: string,
|
|
64
65
|
events: readonly ScheduledEvent[],
|
|
66
|
+
originIndex?: number,
|
|
65
67
|
): Promise<void>
|
|
68
|
+
/** Deliver a scheduler-owned conditional clear, deletion included. */
|
|
69
|
+
schedulerClear(sessionId: string, ifLastIndex: number): Promise<void>
|
|
70
|
+
/** `session.history` with clear markers kept; reads start at the latest one. */
|
|
71
|
+
historyWithMarkers(sessionId: string, gte: number): Promise<Event[]>
|
|
66
72
|
}
|
|
67
73
|
|
|
68
74
|
export const serverInternals: WeakMap<object, ServerInternals> = new WeakMap()
|
|
69
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Handler contexts whose previous attempt ended in a failure the handler
|
|
78
|
+
* threw, as opposed to a claim that lapsed (a crash, a timeout, a frozen
|
|
79
|
+
* process). Only the attempt's own outcome is known, not how far it got.
|
|
80
|
+
*/
|
|
81
|
+
export const failedPreviousAttempt: WeakSet<object> = new WeakSet()
|
|
82
|
+
|
|
70
83
|
const objectLike = (value: unknown): value is object =>
|
|
71
84
|
(typeof value === 'object' && value !== null) || typeof value === 'function'
|
|
72
85
|
|
|
@@ -305,6 +318,45 @@ export const NOTIFY_TIMINGS: {
|
|
|
305
318
|
safetyReadMs: 10_000,
|
|
306
319
|
}
|
|
307
320
|
|
|
321
|
+
/**
|
|
322
|
+
* Bounds for each server instance's in-memory reducer-state cache. Sizes are
|
|
323
|
+
* encoded JSON lengths, re-measured every `measureEvery` folded events, so
|
|
324
|
+
* the byte budget is approximate. Mutable only as a white-box test seam.
|
|
325
|
+
*/
|
|
326
|
+
export const STATE_CACHE: {
|
|
327
|
+
maxEntries: number
|
|
328
|
+
maxBytes: number
|
|
329
|
+
/** Events a cached state may advance before it writes a snapshot. */
|
|
330
|
+
snapshotEvery: number
|
|
331
|
+
/** Events a warm read may fold; longer tails read the stored snapshot. */
|
|
332
|
+
maxTail: number
|
|
333
|
+
/** Events folded between re-measuring a cached state's encoded size. */
|
|
334
|
+
measureEvery: number
|
|
335
|
+
} = {
|
|
336
|
+
maxEntries: 1_000,
|
|
337
|
+
maxBytes: 32 * 1024 * 1024,
|
|
338
|
+
snapshotEvery: 128,
|
|
339
|
+
maxTail: 255,
|
|
340
|
+
measureEvery: 16,
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Warm state-read tails for stores that can serve one in a single request:
|
|
345
|
+
* events from `fromIndex` (inclusive) through `throughIndex` or the newest
|
|
346
|
+
* event, or null when that needs more than one request. Like every store
|
|
347
|
+
* read, a tail starts no lower than the latest clear marker. Keyed by the exact
|
|
348
|
+
* store object, so a wrapper built by spreading or proxying a store reads
|
|
349
|
+
* through its own `readHistory` instead.
|
|
350
|
+
*/
|
|
351
|
+
export const stateTailReaders: WeakMap<
|
|
352
|
+
object,
|
|
353
|
+
(
|
|
354
|
+
sessionId: string,
|
|
355
|
+
fromIndex: number,
|
|
356
|
+
throughIndex?: number,
|
|
357
|
+
) => Promise<Event[] | null>
|
|
358
|
+
> = new WeakMap()
|
|
359
|
+
|
|
308
360
|
export const STREAM_TIMINGS: {
|
|
309
361
|
/** Cadence of `: ping` comment frames from `sseResponse`. */
|
|
310
362
|
sseHeartbeatMs: number
|
package/src/libfx.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// The subset of libfx's agent API that experimental-a2/ai/fx uses; libfx
|
|
2
|
+
// ships no type declarations.
|
|
3
|
+
declare module 'libfx' {
|
|
4
|
+
export type FxHostTool = {
|
|
5
|
+
name: string
|
|
6
|
+
description: string
|
|
7
|
+
inputSchema: object
|
|
8
|
+
execute(input: unknown, context: { signal: AbortSignal }): unknown
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export type FxTurn = AsyncIterable<{ type: string }> & {
|
|
12
|
+
result: Promise<{ stopReason: string }>
|
|
13
|
+
steer(input: string): Promise<void>
|
|
14
|
+
cancel(): void
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type FxAgent = {
|
|
18
|
+
prompt(input: string, options?: { signal?: AbortSignal }): FxTurn
|
|
19
|
+
checkpoint(): Promise<Uint8Array>
|
|
20
|
+
close(): Promise<void>
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function createFxAgent(options: {
|
|
24
|
+
apiKey: string
|
|
25
|
+
model?: string | { id: string; effort?: string; fast?: boolean }
|
|
26
|
+
instructions?: string | string[]
|
|
27
|
+
tools?: FxHostTool[]
|
|
28
|
+
checkpoint?: Uint8Array
|
|
29
|
+
fetch?: (
|
|
30
|
+
input: string | URL | Request,
|
|
31
|
+
init?: RequestInit,
|
|
32
|
+
) => Promise<Response>
|
|
33
|
+
}): Promise<FxAgent>
|
|
34
|
+
}
|
|
@@ -65,12 +65,15 @@ export function postgresNotificationScope(
|
|
|
65
65
|
[Symbol.asyncIterator]() {
|
|
66
66
|
let stopped = false
|
|
67
67
|
let after = startAfter
|
|
68
|
-
let buffer: Event
|
|
68
|
+
let buffer: Array<Event | undefined> = []
|
|
69
|
+
let position = 0
|
|
69
70
|
let version = 0
|
|
70
71
|
let waiting: Sleeper | undefined
|
|
71
72
|
let lease: ReturnType<PostgresNotifications['watch']> | undefined
|
|
72
73
|
const stop = (): void => {
|
|
73
74
|
stopped = true
|
|
75
|
+
buffer = []
|
|
76
|
+
position = 0
|
|
74
77
|
waiting?.cancel()
|
|
75
78
|
lease?.stop()
|
|
76
79
|
state.stops.delete(stop)
|
|
@@ -92,16 +95,24 @@ export function postgresNotificationScope(
|
|
|
92
95
|
for (;;) {
|
|
93
96
|
if (stopped || state.closed)
|
|
94
97
|
return { done: true, value: undefined }
|
|
95
|
-
const row = buffer
|
|
98
|
+
const row = buffer[position]
|
|
96
99
|
if (row) {
|
|
97
100
|
after = row.index
|
|
101
|
+
buffer[position] = undefined
|
|
102
|
+
position += 1
|
|
103
|
+
if (position === buffer.length) {
|
|
104
|
+
buffer = []
|
|
105
|
+
position = 0
|
|
106
|
+
}
|
|
98
107
|
return { done: false, value: row }
|
|
99
108
|
}
|
|
100
109
|
const before = version
|
|
101
110
|
// oxlint-disable-next-line no-await-in-loop -- cursor catch-up
|
|
102
|
-
|
|
111
|
+
const rows = await read(after)
|
|
103
112
|
if (stopped || state.closed)
|
|
104
113
|
return { done: true, value: undefined }
|
|
114
|
+
buffer = rows
|
|
115
|
+
position = 0
|
|
105
116
|
if (buffer.length || before !== version) continue
|
|
106
117
|
waiting = defaultSleep(NOTIFY_TIMINGS.safetyReadMs)
|
|
107
118
|
// oxlint-disable-next-line no-await-in-loop -- wait for a hint or the safety read
|