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/dist/ai-server.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import { i as A2Error } from "./session-clear-DGI4jTQ5.js";
|
|
2
|
+
import { a as reducer, s as validateSync } from "./reducer-BAXc8JyF.js";
|
|
3
|
+
import { h as installAmbientToolScopeStorage, m as failedPreviousAttempt, p as consumeSchedulerSendFailure } from "./internal-B2T3U4Rq.js";
|
|
4
|
+
import { t as boundedCache } from "./bounded-cache-CPHWF-8h.js";
|
|
5
|
+
import { a as CONSOLE_TELEMETRY, o as setServerFetchHooks, t as createServer } from "./server-Dw_k_7kO.js";
|
|
6
|
+
import { A as interruptUIMessage, C as reduceToolActivity, D as flattenProgressBatches, E as upsertResponse, M as assertMessageBase, N as restoreMessageBase, O as progressBatches, S as projectedMessage, T as upsertMessage, _ as applyControlChanges, a as events, b as findMessage, d as appSlice, f as isAgentContract, g as initialControlState, h as aiEventId, j as pauseUIMessage, k as progressOwnedBy, m as AI_EVENT_ID_PREFIX, n as agentContract, p as withAIStorage, u as appReducerOf, v as controlCommit, w as retainMessageBase, y as advanceProjection } from "./ai-BpOGm-zB.js";
|
|
7
|
+
import { a as harnessDriver, o as harnessLog, s as harnessStates, u as registerHarnessStates } from "./ai-harness-BuLh_EYi.js";
|
|
6
8
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
7
9
|
import { createHash } from "node:crypto";
|
|
8
10
|
import { asSchema, convertToModelMessages, isToolUIPart, stepCountIs, streamText, toUIMessageStream } from "ai";
|
|
@@ -118,7 +120,7 @@ const foldCoordinator = (state, event) => {
|
|
|
118
120
|
}));
|
|
119
121
|
const inputTokens = completion.usage?.inputTokens;
|
|
120
122
|
const estimate = completion.inputTokenEstimate;
|
|
121
|
-
return inputTokens !== void 0 && Number.isFinite(inputTokens) && inputTokens >= 0 && estimate !== void 0 ? {
|
|
123
|
+
return inputTokens !== void 0 && Number.isFinite(inputTokens) && inputTokens >= 0 && estimate !== void 0 && state.response.generation.model !== void 0 ? {
|
|
122
124
|
...uncalibrated,
|
|
123
125
|
calibration: {
|
|
124
126
|
model: state.response.generation.model,
|
|
@@ -218,7 +220,8 @@ const foldCoordinator = (state, event) => {
|
|
|
218
220
|
default: return state;
|
|
219
221
|
}
|
|
220
222
|
};
|
|
221
|
-
const aiCoordinatorReducer = (contract) =>
|
|
223
|
+
const aiCoordinatorReducer = (contract) => reducer({
|
|
224
|
+
contract,
|
|
222
225
|
name: "a2.ai.coordinator.v6",
|
|
223
226
|
initialState: {
|
|
224
227
|
closed: false,
|
|
@@ -238,7 +241,9 @@ var ControlCancelled = class extends Error {};
|
|
|
238
241
|
const callReadyForModel = (call) => call.terminal || call.call.providerExecuted === true && !call.call.supportsDeferredResults && call.response !== void 0;
|
|
239
242
|
const approvalBlocksExecution = (call) => call.approval !== void 0 && call.response?.approved !== true;
|
|
240
243
|
const createControlRuntime = (options) => {
|
|
241
|
-
const
|
|
244
|
+
const telemetry = options.telemetry ?? CONSOLE_TELEMETRY;
|
|
245
|
+
const reducer$2 = reducer({
|
|
246
|
+
contract: options.contract,
|
|
242
247
|
name: "a2.ai.control.v5",
|
|
243
248
|
initialState: initialControlState()
|
|
244
249
|
}).fold((state, event) => {
|
|
@@ -268,9 +273,9 @@ const createControlRuntime = (options) => {
|
|
|
268
273
|
changes: event.payload.changes
|
|
269
274
|
}) : state;
|
|
270
275
|
});
|
|
271
|
-
const coordinator = aiCoordinatorReducer(options.
|
|
276
|
+
const coordinator = aiCoordinatorReducer(options.contract);
|
|
272
277
|
const handler = async (ctx) => {
|
|
273
|
-
const snapshot = await ctx.session.state(reducer, { through: "latest" });
|
|
278
|
+
const snapshot = await ctx.session.state(reducer$2, { through: "latest" });
|
|
274
279
|
const before = structuredClone(snapshot.state);
|
|
275
280
|
const moves = [];
|
|
276
281
|
const state = structuredClone(snapshot.state);
|
|
@@ -502,7 +507,7 @@ const createControlRuntime = (options) => {
|
|
|
502
507
|
responseMessageId: response.responseMessageId,
|
|
503
508
|
reason: "retry"
|
|
504
509
|
},
|
|
505
|
-
id: await aiEventId("a2.ai.request.retry", options.
|
|
510
|
+
id: await aiEventId("a2.ai.request.retry", options.contract.name, ctx.event.sessionId, command.request.retryId)
|
|
506
511
|
});
|
|
507
512
|
} else reason = "stale-turn";
|
|
508
513
|
break;
|
|
@@ -634,7 +639,7 @@ const createControlRuntime = (options) => {
|
|
|
634
639
|
message: item.message,
|
|
635
640
|
generate: item.generate
|
|
636
641
|
},
|
|
637
|
-
id: await aiEventId("a2.ai.admitted", options.
|
|
642
|
+
id: await aiEventId("a2.ai.admitted", options.contract.name, ctx.event.sessionId, item.id)
|
|
638
643
|
});
|
|
639
644
|
if (!item.generate) continue;
|
|
640
645
|
state.active = {
|
|
@@ -645,7 +650,7 @@ const createControlRuntime = (options) => {
|
|
|
645
650
|
suspended: false,
|
|
646
651
|
model: null
|
|
647
652
|
};
|
|
648
|
-
const requestId = await aiEventId("a2.ai.request.message", options.
|
|
653
|
+
const requestId = await aiEventId("a2.ai.request.message", options.contract.name, ctx.event.sessionId, item.id);
|
|
649
654
|
requestModel({
|
|
650
655
|
request: {
|
|
651
656
|
messageId: item.id,
|
|
@@ -685,7 +690,7 @@ const createControlRuntime = (options) => {
|
|
|
685
690
|
const payload = ctx.event.payload;
|
|
686
691
|
const { turnId, version } = "turnId" in payload ? payload : payload.control;
|
|
687
692
|
for (const event of events) {
|
|
688
|
-
const schema = options.
|
|
693
|
+
const schema = options.contract.events[event.type];
|
|
689
694
|
const result = validateSync(schema, event.payload, `AI worker ${event.type}`);
|
|
690
695
|
if (result.issues) throw new TypeError(result.issues.map((issue) => issue.message).join("; "));
|
|
691
696
|
}
|
|
@@ -719,32 +724,39 @@ const createControlRuntime = (options) => {
|
|
|
719
724
|
});
|
|
720
725
|
const persisted = await ctx.session.append(name, ...progress, input);
|
|
721
726
|
const index = persisted.at(-1).index;
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
727
|
+
return telemetry.span("a2.ai.ack", {
|
|
728
|
+
"a2.contract": options.contract.name,
|
|
729
|
+
"a2.session_id": ctx.event.sessionId,
|
|
730
|
+
"a2.ai.ack.request_id": ctx.event.id,
|
|
731
|
+
"a2.ai.ack.report_id": input.id
|
|
732
|
+
}, async () => {
|
|
733
|
+
const stream = ctx.session.stream({ startAfter: index })[Symbol.asyncIterator]();
|
|
734
|
+
const canonical = [];
|
|
735
|
+
const wanted = new Set(lifecycle.map((event) => event.id));
|
|
736
|
+
let rejectAbort;
|
|
737
|
+
const aborted = new Promise((_, reject) => {
|
|
738
|
+
rejectAbort = reject;
|
|
739
|
+
});
|
|
740
|
+
const onAbort = () => {
|
|
741
|
+
rejectAbort(ctx.signal.reason);
|
|
742
|
+
};
|
|
743
|
+
ctx.signal.addEventListener("abort", onAbort, { once: true });
|
|
744
|
+
try {
|
|
745
|
+
ctx.signal.throwIfAborted();
|
|
746
|
+
for (;;) {
|
|
747
|
+
const item = await Promise.race([stream.next(), aborted]);
|
|
748
|
+
if (item.done) throw new Error("AI control acknowledgement stream ended");
|
|
749
|
+
if (wanted.has(item.value.id)) canonical.push(item.value);
|
|
750
|
+
if (item.value.type === "ai.control.decided" && item.value.payload.commandId === input.id) {
|
|
751
|
+
if (item.value.payload.outcome === "rejected") throw new ControlCancelled("stale AI work");
|
|
752
|
+
return [...persisted.filter((event) => event.type !== "ai.work.reported"), ...canonical];
|
|
753
|
+
}
|
|
742
754
|
}
|
|
755
|
+
} finally {
|
|
756
|
+
ctx.signal.removeEventListener("abort", onAbort);
|
|
757
|
+
await stream.return?.();
|
|
743
758
|
}
|
|
744
|
-
}
|
|
745
|
-
ctx.signal.removeEventListener("abort", onAbort);
|
|
746
|
-
await stream.return?.();
|
|
747
|
-
}
|
|
759
|
+
});
|
|
748
760
|
};
|
|
749
761
|
const settled = ({ ctx, events }) => report({
|
|
750
762
|
ctx,
|
|
@@ -761,7 +773,7 @@ const createControlRuntime = (options) => {
|
|
|
761
773
|
append,
|
|
762
774
|
settled,
|
|
763
775
|
cancelled,
|
|
764
|
-
reducer,
|
|
776
|
+
reducer: reducer$2,
|
|
765
777
|
coordinator
|
|
766
778
|
};
|
|
767
779
|
};
|
|
@@ -802,19 +814,29 @@ const progress = (value) => {
|
|
|
802
814
|
return count === value["length"];
|
|
803
815
|
};
|
|
804
816
|
const indexedEvents = (value, types) => Array.isArray(value) && value.every((event) => record(event) && index(event["index"]) && types.includes(event["type"]) && matches(events[event["type"]], event["payload"]));
|
|
817
|
+
const restorableBase = (options) => {
|
|
818
|
+
assertMessageBase(options.base);
|
|
819
|
+
return isMessage(restoreMessageBase({
|
|
820
|
+
current: options.current,
|
|
821
|
+
base: options.base
|
|
822
|
+
}));
|
|
823
|
+
};
|
|
805
824
|
const projection = (value, messages) => {
|
|
806
825
|
if (!record(value) || Object.keys(value).some((key) => ![
|
|
807
826
|
"generationId",
|
|
808
827
|
"responseMessageId",
|
|
809
828
|
"promptThroughIndex",
|
|
810
829
|
"completionIndex",
|
|
811
|
-
"
|
|
830
|
+
"base",
|
|
812
831
|
"baseCompaction",
|
|
813
832
|
"batches",
|
|
814
833
|
"toolEvents",
|
|
815
834
|
"approvalEvents",
|
|
816
835
|
"cursor"
|
|
817
|
-
].includes(key)) || !id(value["generationId"]) || !id(value["responseMessageId"]) || !index(value["promptThroughIndex"]) || value["completionIndex"] !== void 0 && !index(value["completionIndex"]) || value["
|
|
836
|
+
].includes(key)) || !id(value["generationId"]) || !id(value["responseMessageId"]) || !index(value["promptThroughIndex"]) || value["completionIndex"] !== void 0 && !index(value["completionIndex"]) || value["base"] !== void 0 && !restorableBase({
|
|
837
|
+
base: value["base"],
|
|
838
|
+
current: messages.find((message) => message.id === value["responseMessageId"])
|
|
839
|
+
}) || value["baseCompaction"] !== void 0 && !compaction(value["baseCompaction"]) || !progress(value["batches"]) || !indexedEvents(value["toolEvents"], ["ai.tool.called", "ai.tool.result"]) || !indexedEvents(value["approvalEvents"], ["ai.approval.requested", "ai.approval.responded"])) return false;
|
|
818
840
|
const cursor = value["cursor"];
|
|
819
841
|
if (cursor === void 0 || cursor === null) return true;
|
|
820
842
|
if (!record(cursor) || !index(cursor["throughIndex"]) || !record(cursor["stream"])) return false;
|
|
@@ -848,7 +870,7 @@ const authority = (value) => value === null || record(value) && Object.keys(valu
|
|
|
848
870
|
"pausing",
|
|
849
871
|
"paused"
|
|
850
872
|
].includes(String(value["phase"])));
|
|
851
|
-
const contextSchema = () => ({ "~standard": {
|
|
873
|
+
const contextSchema = (app) => ({ "~standard": {
|
|
852
874
|
version: 1,
|
|
853
875
|
vendor: "a2-context",
|
|
854
876
|
validate(value) {
|
|
@@ -861,7 +883,8 @@ const contextSchema = () => ({ "~standard": {
|
|
|
861
883
|
"authority",
|
|
862
884
|
"generation",
|
|
863
885
|
"activeProjection",
|
|
864
|
-
"messageIndexes"
|
|
886
|
+
"messageIndexes",
|
|
887
|
+
...app === void 0 ? [] : ["app"]
|
|
865
888
|
];
|
|
866
889
|
try {
|
|
867
890
|
if (!record(value) || keys.some((key) => !Object.hasOwn(value, key)) || Object.keys(value).some((key) => !keys.includes(key))) return invalid;
|
|
@@ -873,7 +896,7 @@ const contextSchema = () => ({ "~standard": {
|
|
|
873
896
|
modelId,
|
|
874
897
|
limits: entry["limits"]
|
|
875
898
|
}))) || !indexes(value["messageIndexes"], messages)) return invalid;
|
|
876
|
-
if (generation !== null && (!record(generation) || !matches(events["ai.generation.started"], generation["owner"]) || ![
|
|
899
|
+
if (generation !== null && (!record(generation) || !matches(events["ai.generation.started"], generation["owner"]) || !index(generation["startIndex"]) || ![
|
|
877
900
|
"streaming",
|
|
878
901
|
"completed",
|
|
879
902
|
"paused",
|
|
@@ -884,6 +907,7 @@ const contextSchema = () => ({ "~standard": {
|
|
|
884
907
|
if (current !== null && (!projection(current, messages) || !record(current) || current["generationId"] !== owner?.["generationId"] || current["responseMessageId"] !== owner?.["responseMessageId"])) return invalid;
|
|
885
908
|
if (generation !== null && generation["phase"] !== "superseded" && current === null) return invalid;
|
|
886
909
|
if (value["closed"] && (generation !== null || current !== null)) return invalid;
|
|
910
|
+
if (app !== void 0 && !record(value["app"])) return invalid;
|
|
887
911
|
return { value };
|
|
888
912
|
} catch {
|
|
889
913
|
return invalid;
|
|
@@ -911,14 +935,24 @@ const replaceResponse = ({ state, message, index }) => {
|
|
|
911
935
|
}
|
|
912
936
|
};
|
|
913
937
|
};
|
|
914
|
-
const calledTools = (projection) => /* @__PURE__ */ new Set([...
|
|
938
|
+
const calledTools = ({ projection, current }) => /* @__PURE__ */ new Set([...restoreMessageBase({
|
|
939
|
+
current,
|
|
940
|
+
base: projection.base
|
|
941
|
+
})?.parts.flatMap((part) => "toolCallId" in part ? [part.toolCallId] : []) ?? [], ...projection.toolEvents.filter((event) => event.type === "ai.tool.called").map((event) => event.payload.toolCallId)]);
|
|
915
942
|
const renderProjection = ({ state, index }) => {
|
|
916
943
|
const projection = state.activeProjection;
|
|
917
|
-
|
|
918
|
-
|
|
944
|
+
const current = findMessage(state.messages, projection.responseMessageId);
|
|
945
|
+
let message = projectedMessage({
|
|
946
|
+
projection,
|
|
947
|
+
current
|
|
948
|
+
});
|
|
949
|
+
if (projection.base === void 0 && projection.batches.length === 0 && message.parts.length === 0) return state;
|
|
919
950
|
if (state.generation?.phase === "paused") message = pauseUIMessage({
|
|
920
951
|
message,
|
|
921
|
-
toolCallIds: calledTools(
|
|
952
|
+
toolCallIds: calledTools({
|
|
953
|
+
projection,
|
|
954
|
+
current
|
|
955
|
+
})
|
|
922
956
|
});
|
|
923
957
|
if (state.generation?.phase === "failed") message = interruptUIMessage(message, `Generation failed before tool completion: ${state.generation.error}`);
|
|
924
958
|
return replaceResponse({
|
|
@@ -936,9 +970,13 @@ const renderProjection = ({ state, index }) => {
|
|
|
936
970
|
const generationBase = (state) => {
|
|
937
971
|
const projection = state.activeProjection;
|
|
938
972
|
if (!projection) return state;
|
|
973
|
+
const base = restoreMessageBase({
|
|
974
|
+
current: findMessage(state.messages, projection.responseMessageId),
|
|
975
|
+
base: projection.base
|
|
976
|
+
});
|
|
939
977
|
return {
|
|
940
978
|
...state,
|
|
941
|
-
messages:
|
|
979
|
+
messages: base === void 0 ? state.messages.filter((message) => message.id !== projection.responseMessageId) : upsertMessage(state.messages, base),
|
|
942
980
|
compaction: projection.baseCompaction ?? null
|
|
943
981
|
};
|
|
944
982
|
};
|
|
@@ -957,22 +995,37 @@ const endGeneration = (state) => ({
|
|
|
957
995
|
activeProjection: null
|
|
958
996
|
});
|
|
959
997
|
const ownsGeneration = (state, owner) => state.generation?.owner.generationId === owner.generationId && state.generation.owner.requestId === owner.requestId && state.generation.phase !== "superseded";
|
|
960
|
-
const createContextReducer = ({
|
|
961
|
-
const
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
998
|
+
const createContextReducer = ({ contract }) => {
|
|
999
|
+
const app = appReducerOf(contract);
|
|
1000
|
+
const initialState = {
|
|
1001
|
+
messages: [],
|
|
1002
|
+
compaction: null,
|
|
1003
|
+
modelMetadata: {},
|
|
1004
|
+
closed: false,
|
|
1005
|
+
authority: null,
|
|
1006
|
+
generation: null,
|
|
1007
|
+
activeProjection: null,
|
|
1008
|
+
messageIndexes: {},
|
|
1009
|
+
...app === void 0 ? {} : { app: app.initialState }
|
|
1010
|
+
};
|
|
1011
|
+
const reducer$1 = reducer({
|
|
1012
|
+
contract,
|
|
1013
|
+
name: app === void 0 ? "a2.ai.context.v6" : `${app.name}+a2.ai.context.v6`,
|
|
1014
|
+
initialState,
|
|
1015
|
+
stateSchema: contextSchema(app)
|
|
1016
|
+
}).fold((state, event) => {
|
|
1017
|
+
const after = retainMessageBase({
|
|
1018
|
+
before: state,
|
|
1019
|
+
after: reduceContext(state, event)
|
|
1020
|
+
});
|
|
1021
|
+
if (app === void 0) return after;
|
|
1022
|
+
const next = app.fold(state.app, event);
|
|
1023
|
+
return next === state.app ? after : {
|
|
1024
|
+
...after,
|
|
1025
|
+
app: appSlice(next)
|
|
1026
|
+
};
|
|
1027
|
+
});
|
|
1028
|
+
return withAIStorage(reducer$1);
|
|
976
1029
|
};
|
|
977
1030
|
const reduceContext = (state, event) => {
|
|
978
1031
|
if (state.closed) return state;
|
|
@@ -1029,6 +1082,7 @@ const reduceContext = (state, event) => {
|
|
|
1029
1082
|
...base,
|
|
1030
1083
|
generation: {
|
|
1031
1084
|
owner,
|
|
1085
|
+
startIndex: event.index,
|
|
1032
1086
|
phase: "streaming",
|
|
1033
1087
|
...previous?.owner.responseMessageId === owner.responseMessageId && previous.responseIndex !== void 0 ? { responseIndex: previous.responseIndex } : {}
|
|
1034
1088
|
},
|
|
@@ -1036,7 +1090,7 @@ const reduceContext = (state, event) => {
|
|
|
1036
1090
|
generationId: owner.generationId,
|
|
1037
1091
|
responseMessageId: owner.responseMessageId,
|
|
1038
1092
|
promptThroughIndex: owner.promptThroughIndex ?? event.index - 1,
|
|
1039
|
-
...baseMessage === void 0 ? {} : { baseMessage },
|
|
1093
|
+
...baseMessage === void 0 ? {} : { base: { partCount: baseMessage.parts.length } },
|
|
1040
1094
|
baseCompaction: base.compaction,
|
|
1041
1095
|
batches: progressBatches(),
|
|
1042
1096
|
toolEvents: [],
|
|
@@ -1046,7 +1100,12 @@ const reduceContext = (state, event) => {
|
|
|
1046
1100
|
}
|
|
1047
1101
|
case "ai.generation.progress": {
|
|
1048
1102
|
const payload = event.payload;
|
|
1049
|
-
|
|
1103
|
+
const generation = state.generation;
|
|
1104
|
+
if (generation === null || generation.phase !== "streaming" || !progressOwnedBy({
|
|
1105
|
+
payload,
|
|
1106
|
+
owner: generation.owner,
|
|
1107
|
+
startIndex: generation.startIndex
|
|
1108
|
+
}) || !state.activeProjection) return state;
|
|
1050
1109
|
const projection = state.activeProjection;
|
|
1051
1110
|
const progress = advanceProjection({
|
|
1052
1111
|
projection,
|
|
@@ -1125,9 +1184,12 @@ const reduceContext = (state, event) => {
|
|
|
1125
1184
|
approvalEvents: projection.approvalEvents.filter((item) => item.index <= cutoff)
|
|
1126
1185
|
};
|
|
1127
1186
|
let next = generationBase(state);
|
|
1128
|
-
if (retained.
|
|
1187
|
+
if (retained.base !== void 0 || retained.batches.length > 0) next = replaceResponse({
|
|
1129
1188
|
state: next,
|
|
1130
|
-
message: interruptUIMessage(projectedMessage(
|
|
1189
|
+
message: interruptUIMessage(projectedMessage({
|
|
1190
|
+
projection: retained,
|
|
1191
|
+
current: findMessage(state.messages, retained.responseMessageId)
|
|
1192
|
+
})),
|
|
1131
1193
|
index: event.index
|
|
1132
1194
|
});
|
|
1133
1195
|
return endGeneration(next);
|
|
@@ -1139,7 +1201,10 @@ const reduceContext = (state, event) => {
|
|
|
1139
1201
|
case "ai.generation.paused": {
|
|
1140
1202
|
const { generationId } = event.payload;
|
|
1141
1203
|
if (state.generation?.owner.generationId !== generationId || state.generation.phase === "failed" || state.generation.phase === "superseded" || !state.activeProjection) return state;
|
|
1142
|
-
const toolCallIds = calledTools(
|
|
1204
|
+
const toolCallIds = calledTools({
|
|
1205
|
+
projection: state.activeProjection,
|
|
1206
|
+
current: findMessage(state.messages, state.activeProjection.responseMessageId)
|
|
1207
|
+
});
|
|
1143
1208
|
return renderProjection({
|
|
1144
1209
|
state: {
|
|
1145
1210
|
...state,
|
|
@@ -1242,9 +1307,9 @@ const reduceContext = (state, event) => {
|
|
|
1242
1307
|
...projection,
|
|
1243
1308
|
cursor: null
|
|
1244
1309
|
};
|
|
1245
|
-
delete activeProjection.
|
|
1310
|
+
delete activeProjection.base;
|
|
1246
1311
|
const baseMessage = messages.find((message) => message.id === projection.responseMessageId);
|
|
1247
|
-
if (baseMessage !== void 0) activeProjection.
|
|
1312
|
+
if (baseMessage !== void 0) activeProjection.base = { partCount: baseMessage.parts.length };
|
|
1248
1313
|
const compaction = {
|
|
1249
1314
|
status: "completed",
|
|
1250
1315
|
generationId: payload.generationId,
|
|
@@ -1378,9 +1443,15 @@ const catalogUrl = "https://ai-gateway.vercel.sh/v1/models";
|
|
|
1378
1443
|
const catalogLifetimeMs = 36e5;
|
|
1379
1444
|
const catalogTimeoutMs = 5e3;
|
|
1380
1445
|
let catalog;
|
|
1446
|
+
/**
|
|
1447
|
+
* The model's AI Gateway ID: the model string, unless an AI SDK global
|
|
1448
|
+
* provider resolves it to a model that is not Gateway's.
|
|
1449
|
+
*/
|
|
1381
1450
|
const gatewayModelId = (model) => {
|
|
1382
|
-
|
|
1383
|
-
|
|
1451
|
+
const provider = globalThis.AI_SDK_DEFAULT_PROVIDER;
|
|
1452
|
+
if (provider === void 0) return model;
|
|
1453
|
+
if (typeof provider.languageModel !== "function") return void 0;
|
|
1454
|
+
return provider.languageModel(model).provider === "gateway" ? model : void 0;
|
|
1384
1455
|
};
|
|
1385
1456
|
const readCatalog = () => {
|
|
1386
1457
|
if (catalog && catalog.expiresAt > Date.now()) return catalog.promise;
|
|
@@ -1467,23 +1538,24 @@ const measuredInputTokens = (options) => {
|
|
|
1467
1538
|
return previous !== void 0 && previous.model === options.model && options.estimate >= previous.estimate ? Math.ceil(previous.inputTokens + options.estimate - previous.estimate) : options.estimate;
|
|
1468
1539
|
};
|
|
1469
1540
|
//#endregion
|
|
1470
|
-
//#region src/ai-
|
|
1541
|
+
//#region src/ai-agent.ts
|
|
1471
1542
|
/**
|
|
1472
|
-
*
|
|
1473
|
-
*
|
|
1474
|
-
* `createHandlers()` exposes the ordinary A2 handler table;
|
|
1475
|
-
* `createAgentServer()` is its batteries-included assembly with createServer.
|
|
1543
|
+
* The server-only implementation of the experimental-a2/ai protocol: the
|
|
1544
|
+
* handler table and `agent()`, its assembly as an ordinary A2 server.
|
|
1476
1545
|
*/
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1546
|
+
const isAgentIngressEvent = (event) => {
|
|
1547
|
+
if (event.type !== "ai.control.requested") return false;
|
|
1548
|
+
const command = event.payload;
|
|
1549
|
+
if (typeof command !== "object" || command === null) return false;
|
|
1550
|
+
const action = command.action;
|
|
1551
|
+
if (action === "request-input" || action === "tool-result") return false;
|
|
1552
|
+
if (action === "send" || action === "edit" || action === "steer") return command.message?.role === "user";
|
|
1553
|
+
return true;
|
|
1554
|
+
};
|
|
1555
|
+
const validateAgentIngress = ({ context, applicationEvents }) => {
|
|
1556
|
+
const rejected = context.events.find((event) => Object.hasOwn(events, event.type) ? !isAgentIngressEvent(event) : !applicationEvents);
|
|
1485
1557
|
if (rejected !== void 0) throw new A2Error("INVALID_PAYLOAD", `event '${rejected.type}' is server-only for an AI agent`);
|
|
1486
|
-
}
|
|
1558
|
+
};
|
|
1487
1559
|
const checkAbort = (signal) => {
|
|
1488
1560
|
if (!signal.aborted) return false;
|
|
1489
1561
|
const reason = signal.reason;
|
|
@@ -1501,18 +1573,31 @@ const resolve = async (value, context) => {
|
|
|
1501
1573
|
checkAbort(context.signal);
|
|
1502
1574
|
return result;
|
|
1503
1575
|
};
|
|
1504
|
-
const
|
|
1505
|
-
|
|
1506
|
-
if (
|
|
1507
|
-
|
|
1576
|
+
const withModelSettings = (options) => {
|
|
1577
|
+
const { generation, settings } = options;
|
|
1578
|
+
if (settings.reasoning === void 0 && settings.speed === void 0) return generation;
|
|
1579
|
+
const { speed: _speed, ...gateway } = generation.providerOptions?.["gateway"] ?? {};
|
|
1580
|
+
return {
|
|
1581
|
+
...generation,
|
|
1582
|
+
...settings.reasoning === void 0 ? {} : { reasoning: settings.reasoning },
|
|
1583
|
+
...settings.speed === void 0 ? {} : { providerOptions: {
|
|
1584
|
+
...generation.providerOptions,
|
|
1585
|
+
gateway: settings.speed === "fast" ? {
|
|
1586
|
+
...gateway,
|
|
1587
|
+
speed: "fast"
|
|
1588
|
+
} : gateway
|
|
1589
|
+
} }
|
|
1590
|
+
};
|
|
1508
1591
|
};
|
|
1592
|
+
const instructionTexts = (instructions) => instructions === void 0 ? [] : typeof instructions === "string" ? [instructions] : (Array.isArray(instructions) ? instructions : [instructions]).map((message) => message.content);
|
|
1509
1593
|
const errorMessage = (error) => error instanceof Error ? error.message : String(error);
|
|
1510
1594
|
const toolScopeStorage = installAmbientToolScopeStorage(() => new AsyncLocalStorage());
|
|
1511
1595
|
/** Run `fn` with `ctx` as the ambient tool handler context, for direct tool tests. */
|
|
1512
1596
|
function runWithHandlerContext(ctx, fn) {
|
|
1513
1597
|
return toolScopeStorage.run({ context: ctx }, fn);
|
|
1514
1598
|
}
|
|
1515
|
-
|
|
1599
|
+
/** Sessions whose latest step prompt one process keeps for that step's tools. */
|
|
1600
|
+
const PROMPT_SESSIONS = 64;
|
|
1516
1601
|
const asyncIterator = (value) => {
|
|
1517
1602
|
if (typeof value !== "object" || value === null) return void 0;
|
|
1518
1603
|
const factory = Reflect.get(value, Symbol.asyncIterator);
|
|
@@ -1520,6 +1605,49 @@ const asyncIterator = (value) => {
|
|
|
1520
1605
|
return factory.call(value);
|
|
1521
1606
|
};
|
|
1522
1607
|
const isBoundaryChunk = (chunk) => chunk !== void 0 && (chunk.type === "text-end" || chunk.type === "reasoning-end" || chunk.type === "tool-input-available" || chunk.type === "tool-input-error" || chunk.type === "tool-output-available" || chunk.type === "tool-output-error" || chunk.type === "tool-output-denied" || chunk.type === "tool-approval-request" || chunk.type === "finish" || chunk.type === "abort" || chunk.type === "error");
|
|
1608
|
+
const DELTA_KEYS = {
|
|
1609
|
+
"text-delta": /* @__PURE__ */ new Set([
|
|
1610
|
+
"type",
|
|
1611
|
+
"id",
|
|
1612
|
+
"delta",
|
|
1613
|
+
"providerMetadata"
|
|
1614
|
+
]),
|
|
1615
|
+
"reasoning-delta": /* @__PURE__ */ new Set([
|
|
1616
|
+
"type",
|
|
1617
|
+
"id",
|
|
1618
|
+
"delta",
|
|
1619
|
+
"providerMetadata"
|
|
1620
|
+
]),
|
|
1621
|
+
"tool-input-delta": /* @__PURE__ */ new Set([
|
|
1622
|
+
"type",
|
|
1623
|
+
"toolCallId",
|
|
1624
|
+
"inputTextDelta"
|
|
1625
|
+
])
|
|
1626
|
+
};
|
|
1627
|
+
const isDeltaChunk = (chunk) => Object.hasOwn(DELTA_KEYS, chunk.type) && Object.keys(chunk).every((key) => DELTA_KEYS[chunk.type].has(key)) && typeof (chunk.type === "tool-input-delta" ? chunk.inputTextDelta : chunk.delta) === "string";
|
|
1628
|
+
const joinDeltas = (left, right) => {
|
|
1629
|
+
if (left.type === "tool-input-delta") return right.type === "tool-input-delta" && right.toolCallId === left.toolCallId ? {
|
|
1630
|
+
...left,
|
|
1631
|
+
inputTextDelta: left.inputTextDelta + right.inputTextDelta
|
|
1632
|
+
} : void 0;
|
|
1633
|
+
if (right.type === "tool-input-delta" || right.type !== left.type || right.id !== left.id) return void 0;
|
|
1634
|
+
const providerMetadata = right.providerMetadata !== void 0 ? right.providerMetadata : left.providerMetadata;
|
|
1635
|
+
return {
|
|
1636
|
+
...left,
|
|
1637
|
+
delta: left.delta + right.delta,
|
|
1638
|
+
...providerMetadata === void 0 ? {} : { providerMetadata }
|
|
1639
|
+
};
|
|
1640
|
+
};
|
|
1641
|
+
const mergeDeltas = (chunks) => {
|
|
1642
|
+
const merged = [];
|
|
1643
|
+
for (const chunk of chunks) {
|
|
1644
|
+
const previous = merged.at(-1);
|
|
1645
|
+
const joined = previous !== void 0 && isDeltaChunk(previous) && isDeltaChunk(chunk) ? joinDeltas(previous, chunk) : void 0;
|
|
1646
|
+
if (joined === void 0) merged.push(chunk);
|
|
1647
|
+
else merged[merged.length - 1] = joined;
|
|
1648
|
+
}
|
|
1649
|
+
return merged;
|
|
1650
|
+
};
|
|
1523
1651
|
const nextOrTimer = async (next, delayMs) => {
|
|
1524
1652
|
let timer;
|
|
1525
1653
|
try {
|
|
@@ -1541,7 +1669,7 @@ async function generateWithAISDK(options) {
|
|
|
1541
1669
|
...context.generation,
|
|
1542
1670
|
headers: Object.keys(headers).some((key) => key.toLowerCase() === "x-session-affinity") ? headers : {
|
|
1543
1671
|
...headers,
|
|
1544
|
-
"x-session-affinity": createHash("sha256").update(JSON.stringify([agentName, context.
|
|
1672
|
+
"x-session-affinity": createHash("sha256").update(JSON.stringify([agentName, context.event.sessionId])).digest("hex")
|
|
1545
1673
|
},
|
|
1546
1674
|
providerOptions: {
|
|
1547
1675
|
...context.generation.providerOptions,
|
|
@@ -1556,7 +1684,7 @@ async function generateWithAISDK(options) {
|
|
|
1556
1684
|
tools: context.tools,
|
|
1557
1685
|
messages: context.messages,
|
|
1558
1686
|
modelMessages: context.modelMessages,
|
|
1559
|
-
responseMessageId: context.responseMessageId,
|
|
1687
|
+
responseMessageId: context.event.payload.responseMessageId,
|
|
1560
1688
|
abortSignal: context.signal,
|
|
1561
1689
|
...context.instructions === void 0 ? {} : { instructions: context.instructions },
|
|
1562
1690
|
settings: generation,
|
|
@@ -1575,9 +1703,13 @@ async function* consumeGeneration(options) {
|
|
|
1575
1703
|
const pending = [];
|
|
1576
1704
|
let streamedFinishReason;
|
|
1577
1705
|
let streamedError;
|
|
1578
|
-
const maxChunks = options.progress?.maxChunks ??
|
|
1579
|
-
const maxDelayMs = options.progress?.maxDelayMs ??
|
|
1706
|
+
const maxChunks = options.progress?.maxChunks ?? 128;
|
|
1707
|
+
const maxDelayMs = options.progress?.maxDelayMs ?? 0;
|
|
1580
1708
|
let lastFlush = Date.now();
|
|
1709
|
+
const batch = () => ({
|
|
1710
|
+
type: "progress",
|
|
1711
|
+
chunks: mergeDeltas(pending.splice(0))
|
|
1712
|
+
});
|
|
1581
1713
|
const reader = options.source.stream.getReader();
|
|
1582
1714
|
let pendingChunk = reader.read();
|
|
1583
1715
|
try {
|
|
@@ -1587,10 +1719,7 @@ async function* consumeGeneration(options) {
|
|
|
1587
1719
|
const remaining = Math.max(0, maxDelayMs - (Date.now() - lastFlush));
|
|
1588
1720
|
const outcome = await nextOrTimer(pendingChunk, remaining);
|
|
1589
1721
|
if (outcome.type === "timer") {
|
|
1590
|
-
yield
|
|
1591
|
-
type: "progress",
|
|
1592
|
-
chunks: pending.splice(0)
|
|
1593
|
-
};
|
|
1722
|
+
yield batch();
|
|
1594
1723
|
lastFlush = Date.now();
|
|
1595
1724
|
continue;
|
|
1596
1725
|
}
|
|
@@ -1603,18 +1732,12 @@ async function* consumeGeneration(options) {
|
|
|
1603
1732
|
if (chunk.type === "error") streamedError = chunk.errorText;
|
|
1604
1733
|
pendingChunk = reader.read();
|
|
1605
1734
|
if (pending.length >= maxChunks || isBoundaryChunk(pending.at(-1))) {
|
|
1606
|
-
yield
|
|
1607
|
-
type: "progress",
|
|
1608
|
-
chunks: pending.splice(0)
|
|
1609
|
-
};
|
|
1735
|
+
yield batch();
|
|
1610
1736
|
lastFlush = Date.now();
|
|
1611
1737
|
}
|
|
1612
1738
|
}
|
|
1613
1739
|
} catch (error) {
|
|
1614
|
-
if (pending.length > 0) yield
|
|
1615
|
-
type: "progress",
|
|
1616
|
-
chunks: pending.splice(0)
|
|
1617
|
-
};
|
|
1740
|
+
if (pending.length > 0) yield batch();
|
|
1618
1741
|
throw error;
|
|
1619
1742
|
} finally {
|
|
1620
1743
|
pendingChunk.catch(() => {});
|
|
@@ -1628,16 +1751,10 @@ async function* consumeGeneration(options) {
|
|
|
1628
1751
|
try {
|
|
1629
1752
|
completion = options.source.completion?.();
|
|
1630
1753
|
} catch (error) {
|
|
1631
|
-
if (pending.length > 0) yield
|
|
1632
|
-
type: "progress",
|
|
1633
|
-
chunks: pending.splice(0)
|
|
1634
|
-
};
|
|
1754
|
+
if (pending.length > 0) yield batch();
|
|
1635
1755
|
throw error;
|
|
1636
1756
|
}
|
|
1637
|
-
if (pending.length > 0) yield
|
|
1638
|
-
type: "progress",
|
|
1639
|
-
chunks: pending.splice(0)
|
|
1640
|
-
};
|
|
1757
|
+
if (pending.length > 0) yield batch();
|
|
1641
1758
|
if (streamedError !== void 0) throw new Error(streamedError);
|
|
1642
1759
|
const finishReason = completion?.finishReason ?? streamedFinishReason;
|
|
1643
1760
|
yield {
|
|
@@ -1688,8 +1805,7 @@ const summarize = async (options) => {
|
|
|
1688
1805
|
modelMessages: [...options.context.modelMessages, {
|
|
1689
1806
|
role: "user",
|
|
1690
1807
|
content: instruction
|
|
1691
|
-
}]
|
|
1692
|
-
responseMessageId: await aiEventId("a2.ai.summary", options.context.generationId)
|
|
1808
|
+
}]
|
|
1693
1809
|
},
|
|
1694
1810
|
messageMetadata: void 0
|
|
1695
1811
|
});
|
|
@@ -1775,7 +1891,7 @@ const lifecycleEvents = async (options) => {
|
|
|
1775
1891
|
...chunk.title === void 0 ? {} : { title: chunk.title }
|
|
1776
1892
|
};
|
|
1777
1893
|
take(payload.toolCallId);
|
|
1778
|
-
const classification = approvalClassification(options.tools, options.generation, chunk.toolName);
|
|
1894
|
+
const classification = options.approvals === false ? "automatic" : approvalClassification(options.tools, options.generation, chunk.toolName);
|
|
1779
1895
|
if (classification === "automatic") result.push(await toolCalledEvent(payload));
|
|
1780
1896
|
else pending.push({
|
|
1781
1897
|
call: payload,
|
|
@@ -1916,36 +2032,79 @@ const validateCompaction = (options) => {
|
|
|
1916
2032
|
}
|
|
1917
2033
|
return compaction;
|
|
1918
2034
|
};
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
2035
|
+
const AI_SDK_HARNESS_OPTIONS = [
|
|
2036
|
+
"generation",
|
|
2037
|
+
"generate",
|
|
2038
|
+
"compaction",
|
|
2039
|
+
"messageMetadata"
|
|
2040
|
+
];
|
|
2041
|
+
const assertNoLoopOptions = (options) => {
|
|
2042
|
+
const harness = options.harness?.type ?? "ai-sdk";
|
|
2043
|
+
for (const key of AI_SDK_HARNESS_OPTIONS) {
|
|
2044
|
+
if (!Object.hasOwn(options, key)) continue;
|
|
2045
|
+
throw new TypeError(harness === "ai-sdk" ? `${key} belongs to the harness: agent({ harness: { type: 'ai-sdk', ${key} } })` : `${key} is an option of the AI SDK harness; ${harness}() runs its own loop`);
|
|
2046
|
+
}
|
|
2047
|
+
};
|
|
1923
2048
|
function createHandlers(options) {
|
|
1924
|
-
if (options.model === void 0) throw new TypeError("
|
|
2049
|
+
if (options.model === void 0) throw new TypeError("agent requires model");
|
|
1925
2050
|
if (options.progress?.maxChunks !== void 0 && (!Number.isInteger(options.progress.maxChunks) || options.progress.maxChunks < 1)) throw new TypeError("progress.maxChunks must be a positive integer");
|
|
1926
2051
|
if (options.progress?.maxDelayMs !== void 0 && (!Number.isFinite(options.progress.maxDelayMs) || options.progress.maxDelayMs < 0)) throw new TypeError("progress.maxDelayMs must be a non-negative number");
|
|
1927
2052
|
if (options.maxSteps !== void 0 && options.maxSteps !== Number.POSITIVE_INFINITY && (!Number.isInteger(options.maxSteps) || options.maxSteps < 1)) throw new TypeError("maxSteps must be a positive integer or Infinity");
|
|
1928
|
-
|
|
2053
|
+
assertNoLoopOptions(options);
|
|
2054
|
+
const configured = options.harness;
|
|
2055
|
+
const loop = configured?.type === "ai-sdk" ? configured : {};
|
|
2056
|
+
const harness = configured === void 0 || configured.type === "ai-sdk" ? void 0 : harnessDriver(configured);
|
|
2057
|
+
const states = options.harnessStates ?? harnessStates();
|
|
2058
|
+
if (harness !== void 0) for (const [name, tool] of Object.entries(options.tools ?? {})) {
|
|
2059
|
+
const needsApproval = tool.needsApproval;
|
|
2060
|
+
if (needsApproval !== void 0 && needsApproval !== false) throw new TypeError(`a harness runs tools without approval; '${name}' sets needsApproval`);
|
|
2061
|
+
}
|
|
2062
|
+
const configuredCompaction = loop.compaction ?? (loop.generate === void 0 && harness === void 0 ? {} : false);
|
|
1929
2063
|
const staticCompaction = typeof configuredCompaction === "function" ? void 0 : validateCompaction({
|
|
1930
2064
|
compaction: configuredCompaction,
|
|
1931
|
-
explicit:
|
|
1932
|
-
generation:
|
|
2065
|
+
explicit: loop.compaction !== void 0,
|
|
2066
|
+
generation: typeof loop.generation === "function" ? void 0 : loop.generation,
|
|
1933
2067
|
tools: options.tools
|
|
1934
2068
|
});
|
|
1935
|
-
const tools = options.tools ?? {}
|
|
1936
|
-
|
|
2069
|
+
const tools = harness === void 0 ? options.tools ?? {} : {
|
|
2070
|
+
...harness.tools,
|
|
2071
|
+
...options.tools
|
|
2072
|
+
};
|
|
2073
|
+
const toolRecovery = options.toolRecovery ?? {};
|
|
2074
|
+
for (const [name, recovery] of Object.entries(toolRecovery)) {
|
|
2075
|
+
if (!Object.hasOwn(tools, name)) throw new TypeError(`toolRecovery names '${name}', which is not one of the agent's tools`);
|
|
2076
|
+
if (typeof tools[name].execute !== "function") throw new TypeError(`toolRecovery names '${name}', which has no execute function`);
|
|
2077
|
+
if (recovery !== "rerun" && recovery !== "report") throw new TypeError(`toolRecovery for '${name}' must be 'rerun' or 'report'`);
|
|
2078
|
+
}
|
|
2079
|
+
const telemetry = options.telemetry ?? CONSOLE_TELEMETRY;
|
|
1937
2080
|
const maxSteps = options.maxSteps ?? Number.POSITIVE_INFINITY;
|
|
1938
|
-
const control = createControlRuntime({
|
|
2081
|
+
const control = createControlRuntime({
|
|
2082
|
+
contract: options.contract,
|
|
2083
|
+
telemetry
|
|
2084
|
+
});
|
|
2085
|
+
const controlHandler = (ctx) => telemetry.span("a2.ai.control", {
|
|
2086
|
+
"a2.contract": options.contract.name,
|
|
2087
|
+
"a2.session_id": ctx.event.sessionId,
|
|
2088
|
+
"a2.ai.control.type": ctx.event.type,
|
|
2089
|
+
"a2.ai.control.id": ctx.event.id,
|
|
2090
|
+
"a2.ai.control.attempt": ctx.attempt
|
|
2091
|
+
}, () => control.handler(ctx));
|
|
1939
2092
|
const coordinator = control.coordinator;
|
|
1940
|
-
const contextReducer = createContextReducer({
|
|
2093
|
+
const contextReducer = createContextReducer({ contract: options.contract });
|
|
1941
2094
|
const readContext = async (session, through) => {
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
2095
|
+
return await session.state(contextReducer, { through });
|
|
2096
|
+
};
|
|
2097
|
+
const prompts = boundedCache({
|
|
2098
|
+
maxEntries: PROMPT_SESSIONS,
|
|
2099
|
+
maxBytes: PROMPT_SESSIONS
|
|
2100
|
+
});
|
|
2101
|
+
const cachePrompt = ({ sessionId, generationId, messages }) => prompts.set(sessionId, {
|
|
2102
|
+
generationId,
|
|
2103
|
+
messages
|
|
2104
|
+
}, 1);
|
|
2105
|
+
const forgetPrompt = (sessionId, generationId) => {
|
|
2106
|
+
if (prompts.get(sessionId)?.generationId === generationId) prompts.delete(sessionId);
|
|
1947
2107
|
};
|
|
1948
|
-
const promptCache = /* @__PURE__ */ new Map();
|
|
1949
2108
|
const resultEvent = async (call, suffix, result) => ({
|
|
1950
2109
|
type: "ai.tool.result",
|
|
1951
2110
|
id: await aiEventId("a2.ai.tool.result", call.generationId, call.toolCallId, suffix),
|
|
@@ -1968,25 +2127,32 @@ function createHandlers(options) {
|
|
|
1968
2127
|
});
|
|
1969
2128
|
const promptMessages = (input) => {
|
|
1970
2129
|
const { ctx, call, generation: owner } = input;
|
|
1971
|
-
const
|
|
1972
|
-
const cached =
|
|
1973
|
-
if (cached) return cached;
|
|
2130
|
+
const sessionId = ctx.event.sessionId;
|
|
2131
|
+
const cached = prompts.get(sessionId);
|
|
2132
|
+
if (cached?.generationId === call.generationId) return cached.messages;
|
|
1974
2133
|
const computation = (async () => {
|
|
1975
2134
|
const frontier = owner.promptThroughIndex;
|
|
1976
2135
|
if (frontier === void 0) throw new TypeError("AI work requires a prompt checkpoint");
|
|
1977
2136
|
const snapshot = await readContext(ctx.session, ctx.event.index);
|
|
1978
2137
|
if (snapshot.state.generation?.owner.generationId !== owner.generationId || snapshot.state.generation.owner.requestId !== owner.requestId || snapshot.state.activeProjection?.generationId !== owner.generationId) throw new TypeError("Tool prompt checkpoint does not own its generation");
|
|
1979
2138
|
const state = generationBase(snapshot.state);
|
|
1980
|
-
return
|
|
2139
|
+
return telemetry.span("a2.ai.context", {
|
|
2140
|
+
"a2.contract": options.contract.name,
|
|
2141
|
+
"a2.session_id": ctx.event.sessionId,
|
|
2142
|
+
"a2.ai.context.request_id": call.requestId,
|
|
2143
|
+
"a2.ai.context.phase": "tool"
|
|
2144
|
+
}, () => modelContext({
|
|
1981
2145
|
messages: state.messages.filter((message) => state.messageIndexes[message.id] <= frontier),
|
|
1982
2146
|
state,
|
|
1983
2147
|
tools
|
|
1984
|
-
});
|
|
2148
|
+
}));
|
|
1985
2149
|
})();
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
2150
|
+
cachePrompt({
|
|
2151
|
+
sessionId,
|
|
2152
|
+
generationId: call.generationId,
|
|
2153
|
+
messages: computation
|
|
1989
2154
|
});
|
|
2155
|
+
computation.catch(() => forgetPrompt(sessionId, call.generationId));
|
|
1990
2156
|
return computation;
|
|
1991
2157
|
};
|
|
1992
2158
|
const toolExecutionFailure = async (ctx, call, error) => {
|
|
@@ -1995,13 +2161,14 @@ function createHandlers(options) {
|
|
|
1995
2161
|
if (schedulerFailure === "retryable") throw error;
|
|
1996
2162
|
return resultEvent(call, `${ctx.event.id}:execution:error`, { error: errorMessage(error) });
|
|
1997
2163
|
};
|
|
1998
|
-
const runToolExecution = async (ctx, call, execute, messages) => {
|
|
2164
|
+
const runToolExecution = async (ctx, call, execute, messages, sandbox) => {
|
|
1999
2165
|
let output;
|
|
2000
2166
|
try {
|
|
2001
2167
|
output = await execute(call.input, {
|
|
2002
2168
|
toolCallId: call.toolCallId,
|
|
2003
2169
|
messages,
|
|
2004
|
-
abortSignal: ctx.signal
|
|
2170
|
+
abortSignal: ctx.signal,
|
|
2171
|
+
...sandbox === void 0 ? {} : { experimental_sandbox: sandbox }
|
|
2005
2172
|
});
|
|
2006
2173
|
} catch (error) {
|
|
2007
2174
|
return toolExecutionFailure(ctx, call, error);
|
|
@@ -2052,13 +2219,27 @@ function createHandlers(options) {
|
|
|
2052
2219
|
const { ctx, call } = input;
|
|
2053
2220
|
const execute = tools[call.toolName]?.execute;
|
|
2054
2221
|
if (execute === void 0) return resultEvent(call, `${ctx.event.id}:execution:error`, { error: `Tool '${call.toolName}' has no server executor` });
|
|
2222
|
+
const report = toolRecovery[call.toolName] === "report";
|
|
2223
|
+
const interrupted = () => resultEvent(call, `${ctx.event.id}:execution:error`, { error: `Tool '${call.toolName}' was interrupted and may have partly run.` });
|
|
2224
|
+
if (report && ctx.attempt > 1 && !failedPreviousAttempt.has(ctx)) return interrupted();
|
|
2055
2225
|
const messages = await promptMessages(input);
|
|
2226
|
+
const sandbox = harness?.sandbox === void 0 ? void 0 : await resolve(harness.sandbox, {
|
|
2227
|
+
session: { id: ctx.session.id },
|
|
2228
|
+
signal: ctx.signal
|
|
2229
|
+
});
|
|
2056
2230
|
if (checkAbort(ctx.signal)) return;
|
|
2057
2231
|
const scope = {
|
|
2058
|
-
contract: options.
|
|
2232
|
+
contract: options.contract,
|
|
2059
2233
|
context: ctx
|
|
2060
2234
|
};
|
|
2061
|
-
|
|
2235
|
+
const run = () => toolScopeStorage.run(scope, () => runToolExecution(ctx, call, execute, messages, sandbox));
|
|
2236
|
+
if (!report) return run();
|
|
2237
|
+
try {
|
|
2238
|
+
return await run() ?? await interrupted();
|
|
2239
|
+
} catch {
|
|
2240
|
+
checkAbort(ctx.signal);
|
|
2241
|
+
return interrupted();
|
|
2242
|
+
}
|
|
2062
2243
|
};
|
|
2063
2244
|
const handleToolExecution = async (ctx) => {
|
|
2064
2245
|
try {
|
|
@@ -2115,109 +2296,124 @@ function createHandlers(options) {
|
|
|
2115
2296
|
state,
|
|
2116
2297
|
coordinator: coordinatorState
|
|
2117
2298
|
}),
|
|
2299
|
+
state: snapshot.state.app ?? {},
|
|
2118
2300
|
session: { state: (reducer, readOptions) => ctx.session.state(reducer, {
|
|
2119
2301
|
...readOptions,
|
|
2120
2302
|
through: readOptions?.through ?? snapshot.index
|
|
2121
2303
|
}) },
|
|
2122
2304
|
signal: ctx.signal
|
|
2123
2305
|
};
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
if (request.reason === "tool" && responseStepCount >= maxSteps) {
|
|
2139
|
-
const source = response.source?.generation;
|
|
2140
|
-
if (source === void 0) return;
|
|
2141
|
-
return {
|
|
2142
|
-
type: "ai.generation.failed",
|
|
2143
|
-
id: await aiEventId("a2.ai.step-limit", requestId),
|
|
2144
|
-
payload: {
|
|
2145
|
-
requestId: source.requestId,
|
|
2146
|
-
messageId: source.messageId,
|
|
2147
|
-
generationId: source.generationId,
|
|
2148
|
-
responseMessageId,
|
|
2149
|
-
error: `agent exceeded the ${maxSteps}-step limit`,
|
|
2150
|
-
stepLimit: true
|
|
2151
|
-
}
|
|
2152
|
-
};
|
|
2153
|
-
}
|
|
2154
|
-
const started = {
|
|
2155
|
-
requestId,
|
|
2156
|
-
messageId: request.messageId,
|
|
2157
|
-
generationId,
|
|
2158
|
-
responseMessageId,
|
|
2159
|
-
attempt,
|
|
2160
|
-
model: modelName(resolvedModel),
|
|
2161
|
-
promptThroughIndex: snapshot.index
|
|
2306
|
+
if (request.reason === "tool" && responseStepCount >= maxSteps) {
|
|
2307
|
+
const source = response.source?.generation;
|
|
2308
|
+
if (source === void 0) return;
|
|
2309
|
+
return {
|
|
2310
|
+
type: "ai.generation.failed",
|
|
2311
|
+
id: await aiEventId("a2.ai.step-limit", requestId),
|
|
2312
|
+
payload: {
|
|
2313
|
+
requestId: source.requestId,
|
|
2314
|
+
messageId: source.messageId,
|
|
2315
|
+
generationId: source.generationId,
|
|
2316
|
+
responseMessageId,
|
|
2317
|
+
error: `agent exceeded the ${maxSteps}-step limit`,
|
|
2318
|
+
stepLimit: true
|
|
2319
|
+
}
|
|
2162
2320
|
};
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
const
|
|
2166
|
-
|
|
2167
|
-
const startEvents = [];
|
|
2168
|
-
if (discoversMetadata && !Object.hasOwn(state.modelMetadata, catalogModelId)) startEvents.push({
|
|
2321
|
+
}
|
|
2322
|
+
const startEvents = async (started, metadataModelId) => {
|
|
2323
|
+
const events = [];
|
|
2324
|
+
if (metadataModelId !== void 0) events.push({
|
|
2169
2325
|
type: "ai.model.metadata.requested",
|
|
2170
|
-
id: await aiEventId("a2.ai.model.metadata", options.
|
|
2171
|
-
payload: { modelId:
|
|
2326
|
+
id: await aiEventId("a2.ai.model.metadata", options.contract.name, ctx.event.sessionId, metadataModelId),
|
|
2327
|
+
payload: { modelId: metadataModelId }
|
|
2172
2328
|
});
|
|
2173
2329
|
if (previous) {
|
|
2174
|
-
const payload = previous;
|
|
2175
2330
|
const superseded = {
|
|
2176
2331
|
requestId,
|
|
2177
|
-
messageId:
|
|
2178
|
-
generationId:
|
|
2179
|
-
responseMessageId:
|
|
2332
|
+
messageId: previous.messageId,
|
|
2333
|
+
generationId: previous.generationId,
|
|
2334
|
+
responseMessageId: previous.responseMessageId,
|
|
2180
2335
|
error: "generation attempt was superseded after an incomplete run",
|
|
2181
2336
|
superseded: true
|
|
2182
2337
|
};
|
|
2183
|
-
|
|
2338
|
+
events.push({
|
|
2184
2339
|
type: "ai.generation.failed",
|
|
2185
|
-
id: await aiEventId("a2.ai.superseded",
|
|
2340
|
+
id: await aiEventId("a2.ai.superseded", previous.generationId),
|
|
2186
2341
|
payload: superseded
|
|
2187
2342
|
});
|
|
2188
2343
|
}
|
|
2189
|
-
|
|
2344
|
+
events.push({
|
|
2190
2345
|
type: "ai.generation.started",
|
|
2191
2346
|
id: generationId,
|
|
2192
2347
|
payload: started
|
|
2193
2348
|
});
|
|
2349
|
+
return events;
|
|
2350
|
+
};
|
|
2351
|
+
const startedPayload = (model) => ({
|
|
2352
|
+
requestId,
|
|
2353
|
+
messageId: request.messageId,
|
|
2354
|
+
generationId,
|
|
2355
|
+
responseMessageId,
|
|
2356
|
+
attempt,
|
|
2357
|
+
...model === void 0 ? {} : { model },
|
|
2358
|
+
promptThroughIndex: snapshot.index
|
|
2359
|
+
});
|
|
2360
|
+
let resolvedModel;
|
|
2361
|
+
let resolving = true;
|
|
2362
|
+
let generationStarted = false;
|
|
2363
|
+
try {
|
|
2364
|
+
const choice = await resolve(options.model, resolverContext);
|
|
2365
|
+
if (choice === void 0) throw new TypeError("the model resolver returned undefined");
|
|
2366
|
+
const settings = typeof choice === "string" ? { model: choice } : choice;
|
|
2367
|
+
const model = settings.model;
|
|
2368
|
+
if (typeof model !== "string" || model === "") throw new TypeError("the model must be an AI Gateway model ID");
|
|
2369
|
+
resolvedModel = model;
|
|
2370
|
+
if (checkAbort(ctx.signal)) return;
|
|
2371
|
+
const resolvedInstructions = options.instructions === void 0 ? void 0 : await resolve(options.instructions, resolverContext);
|
|
2372
|
+
if (checkAbort(ctx.signal)) return;
|
|
2373
|
+
const resolvedGeneration = await resolve(loop.generation ?? {}, resolverContext);
|
|
2374
|
+
if (checkAbort(ctx.signal)) return;
|
|
2375
|
+
if (resolvedGeneration === null || typeof resolvedGeneration !== "object" || Array.isArray(resolvedGeneration)) throw new TypeError("the generation resolver must return settings");
|
|
2376
|
+
const generation = withModelSettings({
|
|
2377
|
+
generation: resolvedGeneration,
|
|
2378
|
+
settings
|
|
2379
|
+
});
|
|
2380
|
+
const compaction = typeof configuredCompaction === "function" || typeof loop.generation === "function" ? validateCompaction({
|
|
2381
|
+
compaction: typeof configuredCompaction === "function" ? await resolve(configuredCompaction, resolverContext) : staticCompaction,
|
|
2382
|
+
explicit: loop.compaction !== void 0,
|
|
2383
|
+
generation,
|
|
2384
|
+
tools: options.tools
|
|
2385
|
+
}) : staticCompaction;
|
|
2386
|
+
if (checkAbort(ctx.signal)) return;
|
|
2387
|
+
resolving = false;
|
|
2388
|
+
const catalogModelId = gatewayModelId(model);
|
|
2389
|
+
const gatewayOptions = generation.providerOptions?.["gateway"];
|
|
2390
|
+
const usesFallbackModels = Array.isArray(gatewayOptions?.["models"]) && gatewayOptions["models"].length > 0;
|
|
2391
|
+
const discoversMetadata = compaction !== false && !("shouldCompact" in compaction) && compaction.thresholdTokens === void 0 && !usesFallbackModels && catalogModelId !== void 0;
|
|
2194
2392
|
const generationEvents = await control.append({
|
|
2195
2393
|
ctx,
|
|
2196
2394
|
name: "generation-start",
|
|
2197
|
-
events: startEvents
|
|
2395
|
+
events: await startEvents(startedPayload(model), discoversMetadata && !Object.hasOwn(state.modelMetadata, catalogModelId) ? catalogModelId : void 0)
|
|
2198
2396
|
});
|
|
2397
|
+
const startIndex = generationEvents.find((event) => event.id === generationId).index;
|
|
2199
2398
|
generationStarted = true;
|
|
2200
2399
|
if (checkAbort(ctx.signal)) return;
|
|
2201
2400
|
const promptCoordinatorState = coordinatorState;
|
|
2202
|
-
const messages =
|
|
2203
|
-
state,
|
|
2204
|
-
coordinator: promptCoordinatorState
|
|
2205
|
-
});
|
|
2401
|
+
const { messages } = resolverContext;
|
|
2206
2402
|
let generationMessages = messages;
|
|
2207
|
-
let modelMessages = await
|
|
2403
|
+
let modelMessages = await telemetry.span("a2.ai.context", {
|
|
2404
|
+
"a2.contract": options.contract.name,
|
|
2405
|
+
"a2.session_id": ctx.event.sessionId,
|
|
2406
|
+
"a2.ai.context.request_id": requestId,
|
|
2407
|
+
"a2.ai.context.phase": "generation"
|
|
2408
|
+
}, () => modelContext({
|
|
2208
2409
|
messages,
|
|
2209
2410
|
state,
|
|
2210
2411
|
tools
|
|
2211
|
-
});
|
|
2412
|
+
}));
|
|
2212
2413
|
const baseContext = {
|
|
2213
|
-
|
|
2214
|
-
requestId,
|
|
2414
|
+
...resolverContext,
|
|
2215
2415
|
generationId,
|
|
2216
|
-
responseMessageId,
|
|
2217
|
-
messages,
|
|
2218
2416
|
modelMessages,
|
|
2219
|
-
session: resolverContext.session,
|
|
2220
|
-
signal: ctx.signal,
|
|
2221
2417
|
model: resolvedModel,
|
|
2222
2418
|
tools,
|
|
2223
2419
|
...resolvedInstructions === void 0 ? {} : { instructions: resolvedInstructions },
|
|
@@ -2247,7 +2443,7 @@ function createHandlers(options) {
|
|
|
2247
2443
|
});
|
|
2248
2444
|
const inputTokens = measuredInputTokens({
|
|
2249
2445
|
estimate: inputTokenEstimate,
|
|
2250
|
-
model:
|
|
2446
|
+
model: resolvedModel,
|
|
2251
2447
|
calibration: coordinatorState.calibration
|
|
2252
2448
|
});
|
|
2253
2449
|
const threshold = policy.thresholdTokens ?? (limits === void 0 ? void 0 : Math.floor(Math.min(limits.contextWindow * .75, limits.contextWindow - (generation.maxOutputTokens ?? 0))));
|
|
@@ -2282,14 +2478,20 @@ function createHandlers(options) {
|
|
|
2282
2478
|
}
|
|
2283
2479
|
}]
|
|
2284
2480
|
}));
|
|
2285
|
-
const result =
|
|
2481
|
+
const result = await telemetry.span("a2.ai.compaction", {
|
|
2482
|
+
"a2.contract": options.contract.name,
|
|
2483
|
+
"a2.session_id": ctx.event.sessionId,
|
|
2484
|
+
"a2.ai.compaction.request_id": requestId,
|
|
2485
|
+
"a2.ai.compaction.generation_id": generationId,
|
|
2486
|
+
"a2.ai.compaction.policy": "shouldCompact" in policy ? "custom" : "automatic"
|
|
2487
|
+
}, async () => !("shouldCompact" in policy) ? {
|
|
2286
2488
|
messages: [],
|
|
2287
2489
|
...await summarize({
|
|
2288
|
-
agentName: options.
|
|
2490
|
+
agentName: options.contract.name,
|
|
2289
2491
|
context: baseContext,
|
|
2290
2492
|
instructions: policy.instructions
|
|
2291
2493
|
})
|
|
2292
|
-
} : { messages: await policy.compact(compactionContext) };
|
|
2494
|
+
} : { messages: await policy.compact(compactionContext) });
|
|
2293
2495
|
if (checkAbort(ctx.signal)) return;
|
|
2294
2496
|
const completed = {
|
|
2295
2497
|
generationId,
|
|
@@ -2313,7 +2515,7 @@ function createHandlers(options) {
|
|
|
2313
2515
|
}
|
|
2314
2516
|
}
|
|
2315
2517
|
const currentState = foldAIEvents({
|
|
2316
|
-
reducer: contextReducer
|
|
2518
|
+
reducer: contextReducer,
|
|
2317
2519
|
events: generationEvents,
|
|
2318
2520
|
state
|
|
2319
2521
|
});
|
|
@@ -2321,12 +2523,21 @@ function createHandlers(options) {
|
|
|
2321
2523
|
state: currentState,
|
|
2322
2524
|
coordinator: promptCoordinatorState
|
|
2323
2525
|
});
|
|
2324
|
-
if (policy && "shouldCompact" in policy || generationMessages !== messages || activeCompaction(currentState)?.summary !== activeCompaction(state)?.summary) modelMessages = await
|
|
2526
|
+
if (policy && "shouldCompact" in policy || generationMessages !== messages || activeCompaction(currentState)?.summary !== activeCompaction(state)?.summary) modelMessages = await telemetry.span("a2.ai.context", {
|
|
2527
|
+
"a2.contract": options.contract.name,
|
|
2528
|
+
"a2.session_id": ctx.event.sessionId,
|
|
2529
|
+
"a2.ai.context.request_id": requestId,
|
|
2530
|
+
"a2.ai.context.phase": "refresh"
|
|
2531
|
+
}, () => modelContext({
|
|
2325
2532
|
messages: generationMessages,
|
|
2326
2533
|
state: currentState,
|
|
2327
2534
|
tools
|
|
2535
|
+
}));
|
|
2536
|
+
cachePrompt({
|
|
2537
|
+
sessionId: ctx.event.sessionId,
|
|
2538
|
+
generationId,
|
|
2539
|
+
messages: Promise.resolve(modelMessages)
|
|
2328
2540
|
});
|
|
2329
|
-
promptCache.set(promptCacheKey(ctx.event.sessionId, generationId), Promise.resolve(modelMessages));
|
|
2330
2541
|
if (tracksInput && (inputTokenEstimate === void 0 || compacted)) inputTokenEstimate = await estimateInputTokens({
|
|
2331
2542
|
messages: modelMessages,
|
|
2332
2543
|
instructions: resolvedInstructions,
|
|
@@ -2335,26 +2546,34 @@ function createHandlers(options) {
|
|
|
2335
2546
|
let pendingToolCalls = [];
|
|
2336
2547
|
if (checkAbort(ctx.signal)) return;
|
|
2337
2548
|
const generateContext = {
|
|
2338
|
-
|
|
2339
|
-
requestId,
|
|
2340
|
-
generationId,
|
|
2341
|
-
responseMessageId,
|
|
2549
|
+
...baseContext,
|
|
2342
2550
|
messages: generationMessages,
|
|
2343
|
-
modelMessages
|
|
2344
|
-
session: resolverContext.session,
|
|
2345
|
-
signal: ctx.signal,
|
|
2346
|
-
model: resolvedModel,
|
|
2347
|
-
tools,
|
|
2348
|
-
...resolvedInstructions === void 0 ? {} : { instructions: resolvedInstructions },
|
|
2349
|
-
generation: options.generation ?? {}
|
|
2551
|
+
modelMessages
|
|
2350
2552
|
};
|
|
2351
|
-
const custom = options.generate !== void 0;
|
|
2352
2553
|
const updates = consumeGeneration({
|
|
2353
|
-
source:
|
|
2354
|
-
agentName: options.
|
|
2554
|
+
source: harness !== void 0 ? await harness.step({
|
|
2555
|
+
agentName: options.contract.name,
|
|
2556
|
+
sessionId: ctx.event.sessionId,
|
|
2557
|
+
requestIndex: ctx.event.index,
|
|
2558
|
+
generationId,
|
|
2559
|
+
responseMessageId,
|
|
2560
|
+
throughIndex: snapshot.index,
|
|
2561
|
+
messages: generationMessages,
|
|
2562
|
+
model,
|
|
2563
|
+
...settings.reasoning === void 0 ? {} : { reasoning: settings.reasoning },
|
|
2564
|
+
...settings.speed === void 0 ? {} : { speed: settings.speed },
|
|
2565
|
+
instructions: instructionTexts(resolvedInstructions),
|
|
2566
|
+
tools,
|
|
2567
|
+
log: harnessLog({
|
|
2568
|
+
states,
|
|
2569
|
+
session: ctx.session
|
|
2570
|
+
}),
|
|
2571
|
+
signal: ctx.signal
|
|
2572
|
+
}) : loop.generate === void 0 ? await generateWithAISDK({
|
|
2573
|
+
agentName: options.contract.name,
|
|
2355
2574
|
context: generateContext,
|
|
2356
|
-
messageMetadata:
|
|
2357
|
-
}) : { stream: await
|
|
2575
|
+
messageMetadata: loop.messageMetadata
|
|
2576
|
+
}) : { stream: await loop.generate(generateContext) },
|
|
2358
2577
|
...options.progress === void 0 ? {} : { progress: options.progress }
|
|
2359
2578
|
});
|
|
2360
2579
|
let sequence = 0;
|
|
@@ -2366,11 +2585,7 @@ function createHandlers(options) {
|
|
|
2366
2585
|
continue;
|
|
2367
2586
|
}
|
|
2368
2587
|
const progress = {
|
|
2369
|
-
|
|
2370
|
-
messageId: request.messageId,
|
|
2371
|
-
generationId,
|
|
2372
|
-
responseMessageId,
|
|
2373
|
-
sequence,
|
|
2588
|
+
startIndex,
|
|
2374
2589
|
chunks: update.chunks
|
|
2375
2590
|
};
|
|
2376
2591
|
const lifecycle = await lifecycleEvents({
|
|
@@ -2382,7 +2597,7 @@ function createHandlers(options) {
|
|
|
2382
2597
|
pending: pendingToolCalls,
|
|
2383
2598
|
tools,
|
|
2384
2599
|
generation,
|
|
2385
|
-
|
|
2600
|
+
approvals: harness === void 0
|
|
2386
2601
|
});
|
|
2387
2602
|
pendingToolCalls = lifecycle.pending;
|
|
2388
2603
|
await control.append({
|
|
@@ -2411,10 +2626,11 @@ function createHandlers(options) {
|
|
|
2411
2626
|
id: await aiEventId("a2.ai.completed", generationId),
|
|
2412
2627
|
payload: completed
|
|
2413
2628
|
};
|
|
2414
|
-
const unresolved =
|
|
2629
|
+
const unresolved = loop.generate ? pendingToolCalls.filter((pending) => pending.classification !== "automatic") : [];
|
|
2415
2630
|
if (unresolved.length > 0) throw new Error(`generation ended with unresolved tool authorization for '${unresolved[0].call.toolName}'`);
|
|
2416
|
-
const pendingEvents = await Promise.all(pendingToolCalls.filter((pending) => pending.classification === "automatic" ||
|
|
2631
|
+
const pendingEvents = await Promise.all(pendingToolCalls.filter((pending) => pending.classification === "automatic" || loop.generate === void 0 && pending.classification === "unknown").map((pending) => toolCalledEvent(pending.call)));
|
|
2417
2632
|
if (finish.finishReason === "tool-calls") return [...pendingEvents, completionEvent];
|
|
2633
|
+
forgetPrompt(ctx.event.sessionId, generationId);
|
|
2418
2634
|
return [
|
|
2419
2635
|
...pendingEvents,
|
|
2420
2636
|
completionEvent,
|
|
@@ -2431,7 +2647,13 @@ function createHandlers(options) {
|
|
|
2431
2647
|
throw error;
|
|
2432
2648
|
}
|
|
2433
2649
|
if (checkAbort(ctx.signal)) return;
|
|
2434
|
-
if (!generationStarted) throw error;
|
|
2650
|
+
if (!generationStarted && !resolving) throw error;
|
|
2651
|
+
if (!generationStarted) await control.append({
|
|
2652
|
+
ctx,
|
|
2653
|
+
name: "generation-start",
|
|
2654
|
+
events: await startEvents(startedPayload(resolvedModel))
|
|
2655
|
+
});
|
|
2656
|
+
forgetPrompt(ctx.event.sessionId, generationId);
|
|
2435
2657
|
const failed = {
|
|
2436
2658
|
requestId,
|
|
2437
2659
|
messageId: request.messageId,
|
|
@@ -2446,10 +2668,6 @@ function createHandlers(options) {
|
|
|
2446
2668
|
};
|
|
2447
2669
|
}
|
|
2448
2670
|
};
|
|
2449
|
-
const clearPromptCache = (sessionId) => {
|
|
2450
|
-
const prefix = `${sessionId}\u001f`;
|
|
2451
|
-
for (const key of promptCache.keys()) if (key.startsWith(prefix)) promptCache.delete(key);
|
|
2452
|
-
};
|
|
2453
2671
|
return {
|
|
2454
2672
|
"ai.model.metadata.requested": { handler: async (ctx) => {
|
|
2455
2673
|
const limits = await readModelLimits({
|
|
@@ -2474,29 +2692,16 @@ function createHandlers(options) {
|
|
|
2474
2692
|
if ((command.action === "send" || command.action === "steer") && event.id !== command.message.id) throw new A2Error("INVALID_PAYLOAD", "AI input event ID must equal message.id");
|
|
2475
2693
|
return "a2.ai.control";
|
|
2476
2694
|
},
|
|
2477
|
-
handler:
|
|
2695
|
+
handler: controlHandler
|
|
2478
2696
|
},
|
|
2479
2697
|
"ai.work.reported": {
|
|
2480
2698
|
lane: "a2.ai.control",
|
|
2481
|
-
handler:
|
|
2699
|
+
handler: controlHandler
|
|
2482
2700
|
},
|
|
2483
|
-
"ai.message.completed": { handler: async (ctx) => {
|
|
2484
|
-
clearPromptCache(ctx.event.sessionId);
|
|
2485
|
-
} },
|
|
2486
|
-
"ai.message.interrupted": { handler: async (ctx) => {
|
|
2487
|
-
clearPromptCache(ctx.event.sessionId);
|
|
2488
|
-
} },
|
|
2489
2701
|
"ai.session.closed": {
|
|
2490
2702
|
lane: "a2.ai.control",
|
|
2491
|
-
handler:
|
|
2492
|
-
clearPromptCache(ctx.event.sessionId);
|
|
2493
|
-
return control.handler(ctx);
|
|
2494
|
-
}
|
|
2703
|
+
handler: controlHandler
|
|
2495
2704
|
},
|
|
2496
|
-
"ai.generation.failed": { handler: (ctx) => {
|
|
2497
|
-
promptCache.delete(promptCacheKey(ctx.event.sessionId, ctx.event.payload.generationId));
|
|
2498
|
-
return Promise.resolve();
|
|
2499
|
-
} },
|
|
2500
2705
|
"ai.generation.requested": {
|
|
2501
2706
|
lane: "a2.ai.model",
|
|
2502
2707
|
abortOn: {
|
|
@@ -2507,7 +2712,12 @@ function createHandlers(options) {
|
|
|
2507
2712
|
},
|
|
2508
2713
|
"ai.session.closed": true
|
|
2509
2714
|
},
|
|
2510
|
-
handler:
|
|
2715
|
+
handler: (ctx) => telemetry.span("a2.ai.generate", {
|
|
2716
|
+
"a2.contract": options.contract.name,
|
|
2717
|
+
"a2.session_id": ctx.event.sessionId,
|
|
2718
|
+
"a2.ai.generate.request_id": ctx.event.id,
|
|
2719
|
+
"a2.ai.generate.attempt": ctx.attempt
|
|
2720
|
+
}, async () => {
|
|
2511
2721
|
try {
|
|
2512
2722
|
return control.settled({
|
|
2513
2723
|
ctx,
|
|
@@ -2523,9 +2733,10 @@ function createHandlers(options) {
|
|
|
2523
2733
|
});
|
|
2524
2734
|
throw error;
|
|
2525
2735
|
}
|
|
2526
|
-
}
|
|
2736
|
+
})
|
|
2527
2737
|
},
|
|
2528
2738
|
"ai.tool.execution.requested": {
|
|
2739
|
+
...options.toolLane === void 0 ? {} : { lane: options.toolLane },
|
|
2529
2740
|
abortOn: {
|
|
2530
2741
|
"ai.control.requested": (event, trigger) => event.payload.action === "stop" && event.payload.turnId === trigger.payload.turnId,
|
|
2531
2742
|
"ai.generation.failed": (event, trigger) => event.payload.generationId === trigger.payload.call.generationId,
|
|
@@ -2535,37 +2746,69 @@ function createHandlers(options) {
|
|
|
2535
2746
|
},
|
|
2536
2747
|
"ai.session.closed": true
|
|
2537
2748
|
},
|
|
2538
|
-
handler:
|
|
2749
|
+
handler: (ctx) => telemetry.span("a2.ai.tool", {
|
|
2750
|
+
"a2.contract": options.contract.name,
|
|
2751
|
+
"a2.session_id": ctx.event.sessionId,
|
|
2752
|
+
"a2.ai.tool.request_id": ctx.event.payload.call.requestId,
|
|
2753
|
+
"a2.ai.tool.call_id": ctx.event.payload.call.toolCallId,
|
|
2754
|
+
"a2.ai.tool.name": ctx.event.payload.call.toolName,
|
|
2755
|
+
"a2.ai.tool.attempt": ctx.attempt
|
|
2756
|
+
}, () => handleToolExecution(ctx))
|
|
2539
2757
|
}
|
|
2540
2758
|
};
|
|
2541
2759
|
}
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
const {
|
|
2760
|
+
function agent(options) {
|
|
2761
|
+
assertNoLoopOptions(options);
|
|
2762
|
+
const { model, tools, instructions, maxSteps, harness, toolRecovery, progress, toolLane, handlers, ...rest } = options;
|
|
2763
|
+
let contract;
|
|
2764
|
+
let serverOptions;
|
|
2765
|
+
if ("contract" in rest) {
|
|
2766
|
+
const { contract: shared, ...remaining } = rest;
|
|
2767
|
+
if ("name" in remaining) throw new TypeError("agent takes either name or contract, not both");
|
|
2768
|
+
if (!isAgentContract(shared)) throw new TypeError("agent({ contract }) takes an agentContract()");
|
|
2769
|
+
contract = shared;
|
|
2770
|
+
serverOptions = remaining;
|
|
2771
|
+
} else {
|
|
2772
|
+
const { name, events, messageSchema, ...remaining } = rest;
|
|
2773
|
+
contract = agentContract({
|
|
2774
|
+
name,
|
|
2775
|
+
...events === void 0 ? {} : { events },
|
|
2776
|
+
...messageSchema === void 0 ? {} : { messageSchema }
|
|
2777
|
+
});
|
|
2778
|
+
serverOptions = remaining;
|
|
2779
|
+
}
|
|
2780
|
+
const states = harnessStates();
|
|
2545
2781
|
const builtIns = createHandlers({
|
|
2546
|
-
|
|
2782
|
+
contract,
|
|
2547
2783
|
model,
|
|
2784
|
+
harnessStates: states,
|
|
2785
|
+
...serverOptions.telemetry === void 0 ? {} : { telemetry: serverOptions.telemetry },
|
|
2548
2786
|
...tools === void 0 ? {} : { tools },
|
|
2549
2787
|
...instructions === void 0 ? {} : { instructions },
|
|
2550
|
-
...generation === void 0 ? {} : { generation },
|
|
2551
2788
|
...maxSteps === void 0 ? {} : { maxSteps },
|
|
2552
|
-
...
|
|
2553
|
-
...
|
|
2554
|
-
...
|
|
2555
|
-
...
|
|
2789
|
+
...harness === void 0 ? {} : { harness },
|
|
2790
|
+
...toolRecovery === void 0 ? {} : { toolRecovery },
|
|
2791
|
+
...progress === void 0 ? {} : { progress },
|
|
2792
|
+
...toolLane === void 0 ? {} : { toolLane }
|
|
2556
2793
|
});
|
|
2794
|
+
for (const type of Object.keys(handlers ?? {})) if (Object.hasOwn(builtIns, type)) throw new TypeError(`agent handles '${type}' itself`);
|
|
2557
2795
|
const server = createServer({
|
|
2558
2796
|
...serverOptions,
|
|
2559
|
-
contract
|
|
2797
|
+
contract,
|
|
2560
2798
|
handlers: {
|
|
2561
2799
|
...builtIns,
|
|
2562
2800
|
...handlers
|
|
2563
2801
|
}
|
|
2564
2802
|
});
|
|
2565
|
-
|
|
2803
|
+
registerHarnessStates(server, states);
|
|
2804
|
+
const applicationEvents = "contract" in rest;
|
|
2805
|
+
setServerFetchHooks(server, { validateIngress: (context) => validateAgentIngress({
|
|
2806
|
+
context,
|
|
2807
|
+
applicationEvents
|
|
2808
|
+
}) });
|
|
2566
2809
|
return server;
|
|
2567
2810
|
}
|
|
2568
2811
|
//#endregion
|
|
2569
|
-
export {
|
|
2812
|
+
export { agent, runWithHandlerContext };
|
|
2570
2813
|
|
|
2571
2814
|
//# sourceMappingURL=ai-server.js.map
|