experimental-a2 0.16.1 → 0.17.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 +352 -0
- package/dist/{actor-ohPC-81x.d.ts → actor-DBbe5xeE.d.ts} +21 -11
- package/dist/actor-DBbe5xeE.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-UrWfKeuv.js} +621 -216
- package/dist/ai-UrWfKeuv.js.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-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 +80 -36
- package/dist/ai-server.d.ts.map +1 -1
- package/dist/ai-server.js +432 -258
- package/dist/ai-server.js.map +1 -1
- package/dist/{ai-CrEf6p_W.d.ts → ai-vpGtcaCB.d.ts} +114 -100
- package/dist/ai-vpGtcaCB.d.ts.map +1 -0
- package/dist/ai.d.ts +2 -2
- package/dist/ai.js +2 -2
- package/dist/{client-BYzHjkwU.js → client-COaiaDub.js} +447 -80
- package/dist/client-COaiaDub.js.map +1 -0
- package/dist/{client-CzyacQpJ.d.ts → client-qRnRUzBS.d.ts} +14 -13
- package/dist/client-qRnRUzBS.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-BrLso5x_.d.ts} +7 -3
- package/dist/initial-snapshot-BrLso5x_.d.ts.map +1 -0
- package/dist/{internal-Dq2qYxou.js → internal-CbVvEwad.js} +23 -2
- package/dist/internal-CbVvEwad.js.map +1 -0
- package/dist/otel.d.ts +1 -1
- package/dist/react-BbJ-g6Uu.d.ts +86 -0
- package/dist/react-BbJ-g6Uu.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-BYu6DT7h.d.ts} +45 -29
- package/dist/reducer-BYu6DT7h.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-DbD7IJVK.d.ts → server-CGM8WzRG.d.ts} +87 -26
- package/dist/server-CGM8WzRG.d.ts.map +1 -0
- package/dist/{server-BD5ckxZb.js → server-Rj64fNvX.js} +854 -202
- package/dist/server-Rj64fNvX.js.map +1 -0
- package/dist/server.d.ts +4 -4
- package/dist/server.js +2 -2
- package/dist/{errors-DCk6ch5n.js → session-clear-DGI4jTQ5.js} +17 -2
- package/dist/session-clear-DGI4jTQ5.js.map +1 -0
- package/dist/session-clear-Dshpuhff.d.ts +12 -0
- package/dist/session-clear-Dshpuhff.d.ts.map +1 -0
- package/dist/{store-DyZM6fS5.d.ts → store-Gpkq7WBo.d.ts} +44 -3
- package/dist/store-Gpkq7WBo.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 +182 -69
- package/dist/store-memory.js.map +1 -1
- package/dist/{store-polling-CmxUbV93.js → store-polling-4_y8lETm.js} +21 -4
- package/dist/store-polling-4_y8lETm.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 +399 -108
- package/dist/store-postgres.js.map +1 -1
- package/dist/{store-presence-polling-C7-XZyW9.js → store-presence-polling-Q1C-k2dd.js} +3 -3
- package/dist/{store-presence-polling-C7-XZyW9.js.map → store-presence-polling-Q1C-k2dd.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-tqWNnMRu.js +2374 -0
- package/dist/store-redis-notify-tqWNnMRu.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 +166 -32
- 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-cZH-cibj.d.ts} +2 -2
- package/dist/telemetry-cZH-cibj.d.ts.map +1 -0
- package/dist/{wire-BO5wWCb1.js → wire-DjfHOvdW.js} +132 -10
- package/dist/wire-DjfHOvdW.js.map +1 -0
- package/docs/01-quickstart.mdx +2 -2
- package/docs/actors/01-introduction.mdx +4 -0
- package/docs/actors/04-routes.mdx +14 -1
- package/docs/concepts/01-contracts.mdx +95 -0
- package/docs/concepts/04-state.mdx +3 -3
- package/docs/guides/01-timers.mdx +22 -14
- package/docs/guides/02-cancellation.mdx +1 -1
- package/docs/guides/03-react.mdx +268 -328
- package/docs/guides/04-local-first.mdx +32 -73
- package/docs/guides/05-production.mdx +40 -27
- package/docs/guides/06-ai-agents.mdx +671 -581
- package/docs/guides/09-presence.mdx +3 -7
- package/docs/guides/10-transports.mdx +5 -5
- package/docs/index.mdx +10 -18
- package/docs/reference/01-api.mdx +656 -194
- package/docs/reference/02-errors.mdx +2 -1
- package/examples/playground/DEPLOY.md +52 -6
- package/examples/playground/app/a0/[appId]/loading.tsx +16 -0
- package/examples/playground/app/a0/[appId]/page.tsx +48 -0
- package/examples/playground/app/a0/a0.css +818 -0
- package/examples/playground/app/a0/app-list.tsx +211 -0
- package/examples/playground/app/a0/app-view.tsx +55 -0
- package/examples/playground/app/a0/apps/[appId]/preview/route.ts +27 -0
- package/examples/playground/app/a0/apps/[appId]/route.ts +23 -0
- package/examples/playground/app/a0/apps.test.ts +116 -0
- package/examples/playground/app/a0/apps.ts +87 -0
- package/examples/playground/app/a0/chat.tsx +364 -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/layout.tsx +38 -0
- package/examples/playground/app/a0/list/route.ts +10 -0
- package/examples/playground/app/a0/model.test.ts +56 -0
- package/examples/playground/app/a0/model.ts +58 -0
- package/examples/playground/app/a0/page.tsx +14 -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 +69 -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 +158 -0
- package/examples/playground/app/a0/session.ts +47 -0
- package/examples/playground/app/a0/shell.tsx +150 -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 +98 -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 +15 -14
- package/examples/playground/app/agent/session.ts +5 -6
- package/examples/playground/app/agent/telemetry.test.ts +168 -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 +11 -11
- 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 +108 -0
- package/examples/playground/app/chat/server.ts +69 -73
- 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/package.json +10 -2
- package/examples/playground/scripts/a0-template.ts +77 -0
- package/examples/playground/vercel.json +18 -0
- package/package.json +3 -1
- 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 +2343 -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-message-base.ts +209 -0
- package/src/ai-message-projection.ts +262 -64
- 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-server.browser.ts +2 -2
- package/src/ai-server.ts +20 -1964
- 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 +45 -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 +92 -10
- 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 +957 -237
- 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 +220 -78
- package/src/store-polling.ts +18 -4
- package/src/store-postgres.ts +461 -114
- package/src/store-redis-core.ts +1260 -434
- package/src/store-redis-http.ts +18 -2
- package/src/store-redis-notify.ts +260 -85
- package/src/store-redis.ts +19 -9
- package/src/store-sqlite.ts +259 -45
- package/src/store.ts +46 -1
- package/src/stream-buffer.ts +43 -0
- package/src/telemetry.ts +13 -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/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/dist/ai-server.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
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 { m as installAmbientToolScopeStorage, p as consumeSchedulerSendFailure } from "./internal-CbVvEwad.js";
|
|
4
|
+
import { a as CONSOLE_TELEMETRY, l as boundedCache, o as setServerFetchHooks, t as createServer } from "./server-Rj64fNvX.js";
|
|
5
|
+
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-UrWfKeuv.js";
|
|
6
6
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
7
7
|
import { createHash } from "node:crypto";
|
|
8
8
|
import { asSchema, convertToModelMessages, isToolUIPart, stepCountIs, streamText, toUIMessageStream } from "ai";
|
|
@@ -118,7 +118,7 @@ const foldCoordinator = (state, event) => {
|
|
|
118
118
|
}));
|
|
119
119
|
const inputTokens = completion.usage?.inputTokens;
|
|
120
120
|
const estimate = completion.inputTokenEstimate;
|
|
121
|
-
return inputTokens !== void 0 && Number.isFinite(inputTokens) && inputTokens >= 0 && estimate !== void 0 ? {
|
|
121
|
+
return inputTokens !== void 0 && Number.isFinite(inputTokens) && inputTokens >= 0 && estimate !== void 0 && state.response.generation.model !== void 0 ? {
|
|
122
122
|
...uncalibrated,
|
|
123
123
|
calibration: {
|
|
124
124
|
model: state.response.generation.model,
|
|
@@ -218,7 +218,8 @@ const foldCoordinator = (state, event) => {
|
|
|
218
218
|
default: return state;
|
|
219
219
|
}
|
|
220
220
|
};
|
|
221
|
-
const aiCoordinatorReducer = (contract) =>
|
|
221
|
+
const aiCoordinatorReducer = (contract) => reducer({
|
|
222
|
+
contract,
|
|
222
223
|
name: "a2.ai.coordinator.v6",
|
|
223
224
|
initialState: {
|
|
224
225
|
closed: false,
|
|
@@ -238,7 +239,9 @@ var ControlCancelled = class extends Error {};
|
|
|
238
239
|
const callReadyForModel = (call) => call.terminal || call.call.providerExecuted === true && !call.call.supportsDeferredResults && call.response !== void 0;
|
|
239
240
|
const approvalBlocksExecution = (call) => call.approval !== void 0 && call.response?.approved !== true;
|
|
240
241
|
const createControlRuntime = (options) => {
|
|
241
|
-
const
|
|
242
|
+
const telemetry = options.telemetry ?? CONSOLE_TELEMETRY;
|
|
243
|
+
const reducer$2 = reducer({
|
|
244
|
+
contract: options.contract,
|
|
242
245
|
name: "a2.ai.control.v5",
|
|
243
246
|
initialState: initialControlState()
|
|
244
247
|
}).fold((state, event) => {
|
|
@@ -268,9 +271,9 @@ const createControlRuntime = (options) => {
|
|
|
268
271
|
changes: event.payload.changes
|
|
269
272
|
}) : state;
|
|
270
273
|
});
|
|
271
|
-
const coordinator = aiCoordinatorReducer(options.
|
|
274
|
+
const coordinator = aiCoordinatorReducer(options.contract);
|
|
272
275
|
const handler = async (ctx) => {
|
|
273
|
-
const snapshot = await ctx.session.state(reducer, { through: "latest" });
|
|
276
|
+
const snapshot = await ctx.session.state(reducer$2, { through: "latest" });
|
|
274
277
|
const before = structuredClone(snapshot.state);
|
|
275
278
|
const moves = [];
|
|
276
279
|
const state = structuredClone(snapshot.state);
|
|
@@ -502,7 +505,7 @@ const createControlRuntime = (options) => {
|
|
|
502
505
|
responseMessageId: response.responseMessageId,
|
|
503
506
|
reason: "retry"
|
|
504
507
|
},
|
|
505
|
-
id: await aiEventId("a2.ai.request.retry", options.
|
|
508
|
+
id: await aiEventId("a2.ai.request.retry", options.contract.name, ctx.event.sessionId, command.request.retryId)
|
|
506
509
|
});
|
|
507
510
|
} else reason = "stale-turn";
|
|
508
511
|
break;
|
|
@@ -634,7 +637,7 @@ const createControlRuntime = (options) => {
|
|
|
634
637
|
message: item.message,
|
|
635
638
|
generate: item.generate
|
|
636
639
|
},
|
|
637
|
-
id: await aiEventId("a2.ai.admitted", options.
|
|
640
|
+
id: await aiEventId("a2.ai.admitted", options.contract.name, ctx.event.sessionId, item.id)
|
|
638
641
|
});
|
|
639
642
|
if (!item.generate) continue;
|
|
640
643
|
state.active = {
|
|
@@ -645,7 +648,7 @@ const createControlRuntime = (options) => {
|
|
|
645
648
|
suspended: false,
|
|
646
649
|
model: null
|
|
647
650
|
};
|
|
648
|
-
const requestId = await aiEventId("a2.ai.request.message", options.
|
|
651
|
+
const requestId = await aiEventId("a2.ai.request.message", options.contract.name, ctx.event.sessionId, item.id);
|
|
649
652
|
requestModel({
|
|
650
653
|
request: {
|
|
651
654
|
messageId: item.id,
|
|
@@ -685,7 +688,7 @@ const createControlRuntime = (options) => {
|
|
|
685
688
|
const payload = ctx.event.payload;
|
|
686
689
|
const { turnId, version } = "turnId" in payload ? payload : payload.control;
|
|
687
690
|
for (const event of events) {
|
|
688
|
-
const schema = options.
|
|
691
|
+
const schema = options.contract.events[event.type];
|
|
689
692
|
const result = validateSync(schema, event.payload, `AI worker ${event.type}`);
|
|
690
693
|
if (result.issues) throw new TypeError(result.issues.map((issue) => issue.message).join("; "));
|
|
691
694
|
}
|
|
@@ -719,32 +722,39 @@ const createControlRuntime = (options) => {
|
|
|
719
722
|
});
|
|
720
723
|
const persisted = await ctx.session.append(name, ...progress, input);
|
|
721
724
|
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
|
-
|
|
725
|
+
return telemetry.span("a2.ai.ack", {
|
|
726
|
+
"a2.contract": options.contract.name,
|
|
727
|
+
"a2.session_id": ctx.event.sessionId,
|
|
728
|
+
"a2.ai.ack.request_id": ctx.event.id,
|
|
729
|
+
"a2.ai.ack.report_id": input.id
|
|
730
|
+
}, async () => {
|
|
731
|
+
const stream = ctx.session.stream({ startAfter: index })[Symbol.asyncIterator]();
|
|
732
|
+
const canonical = [];
|
|
733
|
+
const wanted = new Set(lifecycle.map((event) => event.id));
|
|
734
|
+
let rejectAbort;
|
|
735
|
+
const aborted = new Promise((_, reject) => {
|
|
736
|
+
rejectAbort = reject;
|
|
737
|
+
});
|
|
738
|
+
const onAbort = () => {
|
|
739
|
+
rejectAbort(ctx.signal.reason);
|
|
740
|
+
};
|
|
741
|
+
ctx.signal.addEventListener("abort", onAbort, { once: true });
|
|
742
|
+
try {
|
|
743
|
+
ctx.signal.throwIfAborted();
|
|
744
|
+
for (;;) {
|
|
745
|
+
const item = await Promise.race([stream.next(), aborted]);
|
|
746
|
+
if (item.done) throw new Error("AI control acknowledgement stream ended");
|
|
747
|
+
if (wanted.has(item.value.id)) canonical.push(item.value);
|
|
748
|
+
if (item.value.type === "ai.control.decided" && item.value.payload.commandId === input.id) {
|
|
749
|
+
if (item.value.payload.outcome === "rejected") throw new ControlCancelled("stale AI work");
|
|
750
|
+
return [...persisted.filter((event) => event.type !== "ai.work.reported"), ...canonical];
|
|
751
|
+
}
|
|
742
752
|
}
|
|
753
|
+
} finally {
|
|
754
|
+
ctx.signal.removeEventListener("abort", onAbort);
|
|
755
|
+
await stream.return?.();
|
|
743
756
|
}
|
|
744
|
-
}
|
|
745
|
-
ctx.signal.removeEventListener("abort", onAbort);
|
|
746
|
-
await stream.return?.();
|
|
747
|
-
}
|
|
757
|
+
});
|
|
748
758
|
};
|
|
749
759
|
const settled = ({ ctx, events }) => report({
|
|
750
760
|
ctx,
|
|
@@ -761,7 +771,7 @@ const createControlRuntime = (options) => {
|
|
|
761
771
|
append,
|
|
762
772
|
settled,
|
|
763
773
|
cancelled,
|
|
764
|
-
reducer,
|
|
774
|
+
reducer: reducer$2,
|
|
765
775
|
coordinator
|
|
766
776
|
};
|
|
767
777
|
};
|
|
@@ -802,19 +812,29 @@ const progress = (value) => {
|
|
|
802
812
|
return count === value["length"];
|
|
803
813
|
};
|
|
804
814
|
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"]));
|
|
815
|
+
const restorableBase = (options) => {
|
|
816
|
+
assertMessageBase(options.base);
|
|
817
|
+
return isMessage(restoreMessageBase({
|
|
818
|
+
current: options.current,
|
|
819
|
+
base: options.base
|
|
820
|
+
}));
|
|
821
|
+
};
|
|
805
822
|
const projection = (value, messages) => {
|
|
806
823
|
if (!record(value) || Object.keys(value).some((key) => ![
|
|
807
824
|
"generationId",
|
|
808
825
|
"responseMessageId",
|
|
809
826
|
"promptThroughIndex",
|
|
810
827
|
"completionIndex",
|
|
811
|
-
"
|
|
828
|
+
"base",
|
|
812
829
|
"baseCompaction",
|
|
813
830
|
"batches",
|
|
814
831
|
"toolEvents",
|
|
815
832
|
"approvalEvents",
|
|
816
833
|
"cursor"
|
|
817
|
-
].includes(key)) || !id(value["generationId"]) || !id(value["responseMessageId"]) || !index(value["promptThroughIndex"]) || value["completionIndex"] !== void 0 && !index(value["completionIndex"]) || value["
|
|
834
|
+
].includes(key)) || !id(value["generationId"]) || !id(value["responseMessageId"]) || !index(value["promptThroughIndex"]) || value["completionIndex"] !== void 0 && !index(value["completionIndex"]) || value["base"] !== void 0 && !restorableBase({
|
|
835
|
+
base: value["base"],
|
|
836
|
+
current: messages.find((message) => message.id === value["responseMessageId"])
|
|
837
|
+
}) || 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
838
|
const cursor = value["cursor"];
|
|
819
839
|
if (cursor === void 0 || cursor === null) return true;
|
|
820
840
|
if (!record(cursor) || !index(cursor["throughIndex"]) || !record(cursor["stream"])) return false;
|
|
@@ -848,7 +868,7 @@ const authority = (value) => value === null || record(value) && Object.keys(valu
|
|
|
848
868
|
"pausing",
|
|
849
869
|
"paused"
|
|
850
870
|
].includes(String(value["phase"])));
|
|
851
|
-
const contextSchema = () => ({ "~standard": {
|
|
871
|
+
const contextSchema = (app) => ({ "~standard": {
|
|
852
872
|
version: 1,
|
|
853
873
|
vendor: "a2-context",
|
|
854
874
|
validate(value) {
|
|
@@ -861,7 +881,8 @@ const contextSchema = () => ({ "~standard": {
|
|
|
861
881
|
"authority",
|
|
862
882
|
"generation",
|
|
863
883
|
"activeProjection",
|
|
864
|
-
"messageIndexes"
|
|
884
|
+
"messageIndexes",
|
|
885
|
+
...app === void 0 ? [] : ["app"]
|
|
865
886
|
];
|
|
866
887
|
try {
|
|
867
888
|
if (!record(value) || keys.some((key) => !Object.hasOwn(value, key)) || Object.keys(value).some((key) => !keys.includes(key))) return invalid;
|
|
@@ -873,7 +894,7 @@ const contextSchema = () => ({ "~standard": {
|
|
|
873
894
|
modelId,
|
|
874
895
|
limits: entry["limits"]
|
|
875
896
|
}))) || !indexes(value["messageIndexes"], messages)) return invalid;
|
|
876
|
-
if (generation !== null && (!record(generation) || !matches(events["ai.generation.started"], generation["owner"]) || ![
|
|
897
|
+
if (generation !== null && (!record(generation) || !matches(events["ai.generation.started"], generation["owner"]) || !index(generation["startIndex"]) || ![
|
|
877
898
|
"streaming",
|
|
878
899
|
"completed",
|
|
879
900
|
"paused",
|
|
@@ -884,6 +905,7 @@ const contextSchema = () => ({ "~standard": {
|
|
|
884
905
|
if (current !== null && (!projection(current, messages) || !record(current) || current["generationId"] !== owner?.["generationId"] || current["responseMessageId"] !== owner?.["responseMessageId"])) return invalid;
|
|
885
906
|
if (generation !== null && generation["phase"] !== "superseded" && current === null) return invalid;
|
|
886
907
|
if (value["closed"] && (generation !== null || current !== null)) return invalid;
|
|
908
|
+
if (app !== void 0 && !record(value["app"])) return invalid;
|
|
887
909
|
return { value };
|
|
888
910
|
} catch {
|
|
889
911
|
return invalid;
|
|
@@ -911,14 +933,24 @@ const replaceResponse = ({ state, message, index }) => {
|
|
|
911
933
|
}
|
|
912
934
|
};
|
|
913
935
|
};
|
|
914
|
-
const calledTools = (projection) => /* @__PURE__ */ new Set([...
|
|
936
|
+
const calledTools = ({ projection, current }) => /* @__PURE__ */ new Set([...restoreMessageBase({
|
|
937
|
+
current,
|
|
938
|
+
base: projection.base
|
|
939
|
+
})?.parts.flatMap((part) => "toolCallId" in part ? [part.toolCallId] : []) ?? [], ...projection.toolEvents.filter((event) => event.type === "ai.tool.called").map((event) => event.payload.toolCallId)]);
|
|
915
940
|
const renderProjection = ({ state, index }) => {
|
|
916
941
|
const projection = state.activeProjection;
|
|
917
|
-
|
|
918
|
-
|
|
942
|
+
const current = findMessage(state.messages, projection.responseMessageId);
|
|
943
|
+
let message = projectedMessage({
|
|
944
|
+
projection,
|
|
945
|
+
current
|
|
946
|
+
});
|
|
947
|
+
if (projection.base === void 0 && projection.batches.length === 0 && message.parts.length === 0) return state;
|
|
919
948
|
if (state.generation?.phase === "paused") message = pauseUIMessage({
|
|
920
949
|
message,
|
|
921
|
-
toolCallIds: calledTools(
|
|
950
|
+
toolCallIds: calledTools({
|
|
951
|
+
projection,
|
|
952
|
+
current
|
|
953
|
+
})
|
|
922
954
|
});
|
|
923
955
|
if (state.generation?.phase === "failed") message = interruptUIMessage(message, `Generation failed before tool completion: ${state.generation.error}`);
|
|
924
956
|
return replaceResponse({
|
|
@@ -936,9 +968,13 @@ const renderProjection = ({ state, index }) => {
|
|
|
936
968
|
const generationBase = (state) => {
|
|
937
969
|
const projection = state.activeProjection;
|
|
938
970
|
if (!projection) return state;
|
|
971
|
+
const base = restoreMessageBase({
|
|
972
|
+
current: findMessage(state.messages, projection.responseMessageId),
|
|
973
|
+
base: projection.base
|
|
974
|
+
});
|
|
939
975
|
return {
|
|
940
976
|
...state,
|
|
941
|
-
messages:
|
|
977
|
+
messages: base === void 0 ? state.messages.filter((message) => message.id !== projection.responseMessageId) : upsertMessage(state.messages, base),
|
|
942
978
|
compaction: projection.baseCompaction ?? null
|
|
943
979
|
};
|
|
944
980
|
};
|
|
@@ -957,22 +993,37 @@ const endGeneration = (state) => ({
|
|
|
957
993
|
activeProjection: null
|
|
958
994
|
});
|
|
959
995
|
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
|
-
|
|
996
|
+
const createContextReducer = ({ contract }) => {
|
|
997
|
+
const app = appReducerOf(contract);
|
|
998
|
+
const initialState = {
|
|
999
|
+
messages: [],
|
|
1000
|
+
compaction: null,
|
|
1001
|
+
modelMetadata: {},
|
|
1002
|
+
closed: false,
|
|
1003
|
+
authority: null,
|
|
1004
|
+
generation: null,
|
|
1005
|
+
activeProjection: null,
|
|
1006
|
+
messageIndexes: {},
|
|
1007
|
+
...app === void 0 ? {} : { app: app.initialState }
|
|
1008
|
+
};
|
|
1009
|
+
const reducer$1 = reducer({
|
|
1010
|
+
contract,
|
|
1011
|
+
name: app === void 0 ? "a2.ai.context.v6" : `${app.name}+a2.ai.context.v6`,
|
|
1012
|
+
initialState,
|
|
1013
|
+
stateSchema: contextSchema(app)
|
|
1014
|
+
}).fold((state, event) => {
|
|
1015
|
+
const after = retainMessageBase({
|
|
1016
|
+
before: state,
|
|
1017
|
+
after: reduceContext(state, event)
|
|
1018
|
+
});
|
|
1019
|
+
if (app === void 0) return after;
|
|
1020
|
+
const next = app.fold(state.app, event);
|
|
1021
|
+
return next === state.app ? after : {
|
|
1022
|
+
...after,
|
|
1023
|
+
app: appSlice(next)
|
|
1024
|
+
};
|
|
1025
|
+
});
|
|
1026
|
+
return withAIStorage(reducer$1);
|
|
976
1027
|
};
|
|
977
1028
|
const reduceContext = (state, event) => {
|
|
978
1029
|
if (state.closed) return state;
|
|
@@ -1029,6 +1080,7 @@ const reduceContext = (state, event) => {
|
|
|
1029
1080
|
...base,
|
|
1030
1081
|
generation: {
|
|
1031
1082
|
owner,
|
|
1083
|
+
startIndex: event.index,
|
|
1032
1084
|
phase: "streaming",
|
|
1033
1085
|
...previous?.owner.responseMessageId === owner.responseMessageId && previous.responseIndex !== void 0 ? { responseIndex: previous.responseIndex } : {}
|
|
1034
1086
|
},
|
|
@@ -1036,7 +1088,7 @@ const reduceContext = (state, event) => {
|
|
|
1036
1088
|
generationId: owner.generationId,
|
|
1037
1089
|
responseMessageId: owner.responseMessageId,
|
|
1038
1090
|
promptThroughIndex: owner.promptThroughIndex ?? event.index - 1,
|
|
1039
|
-
...baseMessage === void 0 ? {} : { baseMessage },
|
|
1091
|
+
...baseMessage === void 0 ? {} : { base: { partCount: baseMessage.parts.length } },
|
|
1040
1092
|
baseCompaction: base.compaction,
|
|
1041
1093
|
batches: progressBatches(),
|
|
1042
1094
|
toolEvents: [],
|
|
@@ -1046,7 +1098,12 @@ const reduceContext = (state, event) => {
|
|
|
1046
1098
|
}
|
|
1047
1099
|
case "ai.generation.progress": {
|
|
1048
1100
|
const payload = event.payload;
|
|
1049
|
-
|
|
1101
|
+
const generation = state.generation;
|
|
1102
|
+
if (generation === null || generation.phase !== "streaming" || !progressOwnedBy({
|
|
1103
|
+
payload,
|
|
1104
|
+
owner: generation.owner,
|
|
1105
|
+
startIndex: generation.startIndex
|
|
1106
|
+
}) || !state.activeProjection) return state;
|
|
1050
1107
|
const projection = state.activeProjection;
|
|
1051
1108
|
const progress = advanceProjection({
|
|
1052
1109
|
projection,
|
|
@@ -1125,9 +1182,12 @@ const reduceContext = (state, event) => {
|
|
|
1125
1182
|
approvalEvents: projection.approvalEvents.filter((item) => item.index <= cutoff)
|
|
1126
1183
|
};
|
|
1127
1184
|
let next = generationBase(state);
|
|
1128
|
-
if (retained.
|
|
1185
|
+
if (retained.base !== void 0 || retained.batches.length > 0) next = replaceResponse({
|
|
1129
1186
|
state: next,
|
|
1130
|
-
message: interruptUIMessage(projectedMessage(
|
|
1187
|
+
message: interruptUIMessage(projectedMessage({
|
|
1188
|
+
projection: retained,
|
|
1189
|
+
current: findMessage(state.messages, retained.responseMessageId)
|
|
1190
|
+
})),
|
|
1131
1191
|
index: event.index
|
|
1132
1192
|
});
|
|
1133
1193
|
return endGeneration(next);
|
|
@@ -1139,7 +1199,10 @@ const reduceContext = (state, event) => {
|
|
|
1139
1199
|
case "ai.generation.paused": {
|
|
1140
1200
|
const { generationId } = event.payload;
|
|
1141
1201
|
if (state.generation?.owner.generationId !== generationId || state.generation.phase === "failed" || state.generation.phase === "superseded" || !state.activeProjection) return state;
|
|
1142
|
-
const toolCallIds = calledTools(
|
|
1202
|
+
const toolCallIds = calledTools({
|
|
1203
|
+
projection: state.activeProjection,
|
|
1204
|
+
current: findMessage(state.messages, state.activeProjection.responseMessageId)
|
|
1205
|
+
});
|
|
1143
1206
|
return renderProjection({
|
|
1144
1207
|
state: {
|
|
1145
1208
|
...state,
|
|
@@ -1242,9 +1305,9 @@ const reduceContext = (state, event) => {
|
|
|
1242
1305
|
...projection,
|
|
1243
1306
|
cursor: null
|
|
1244
1307
|
};
|
|
1245
|
-
delete activeProjection.
|
|
1308
|
+
delete activeProjection.base;
|
|
1246
1309
|
const baseMessage = messages.find((message) => message.id === projection.responseMessageId);
|
|
1247
|
-
if (baseMessage !== void 0) activeProjection.
|
|
1310
|
+
if (baseMessage !== void 0) activeProjection.base = { partCount: baseMessage.parts.length };
|
|
1248
1311
|
const compaction = {
|
|
1249
1312
|
status: "completed",
|
|
1250
1313
|
generationId: payload.generationId,
|
|
@@ -1467,23 +1530,24 @@ const measuredInputTokens = (options) => {
|
|
|
1467
1530
|
return previous !== void 0 && previous.model === options.model && options.estimate >= previous.estimate ? Math.ceil(previous.inputTokens + options.estimate - previous.estimate) : options.estimate;
|
|
1468
1531
|
};
|
|
1469
1532
|
//#endregion
|
|
1470
|
-
//#region src/ai-
|
|
1533
|
+
//#region src/ai-agent.ts
|
|
1471
1534
|
/**
|
|
1472
|
-
*
|
|
1473
|
-
*
|
|
1474
|
-
* `createHandlers()` exposes the ordinary A2 handler table;
|
|
1475
|
-
* `createAgentServer()` is its batteries-included assembly with createServer.
|
|
1535
|
+
* The server-only implementation of the experimental-a2/ai protocol: the
|
|
1536
|
+
* handler table and `agent()`, its assembly as an ordinary A2 server.
|
|
1476
1537
|
*/
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1538
|
+
const isAgentIngressEvent = (event) => {
|
|
1539
|
+
if (event.type !== "ai.control.requested") return false;
|
|
1540
|
+
const command = event.payload;
|
|
1541
|
+
if (typeof command !== "object" || command === null) return false;
|
|
1542
|
+
const action = command.action;
|
|
1543
|
+
if (action === "request-input" || action === "tool-result") return false;
|
|
1544
|
+
if (action === "send" || action === "edit" || action === "steer") return command.message?.role === "user";
|
|
1545
|
+
return true;
|
|
1546
|
+
};
|
|
1547
|
+
const validateAgentIngress = ({ context, applicationEvents }) => {
|
|
1548
|
+
const rejected = context.events.find((event) => Object.hasOwn(events, event.type) ? !isAgentIngressEvent(event) : !applicationEvents);
|
|
1485
1549
|
if (rejected !== void 0) throw new A2Error("INVALID_PAYLOAD", `event '${rejected.type}' is server-only for an AI agent`);
|
|
1486
|
-
}
|
|
1550
|
+
};
|
|
1487
1551
|
const checkAbort = (signal) => {
|
|
1488
1552
|
if (!signal.aborted) return false;
|
|
1489
1553
|
const reason = signal.reason;
|
|
@@ -1501,6 +1565,22 @@ const resolve = async (value, context) => {
|
|
|
1501
1565
|
checkAbort(context.signal);
|
|
1502
1566
|
return result;
|
|
1503
1567
|
};
|
|
1568
|
+
const withModelSettings = (options) => {
|
|
1569
|
+
const { generation, settings } = options;
|
|
1570
|
+
if (settings.reasoning === void 0 && settings.speed === void 0) return generation;
|
|
1571
|
+
const { speed: _speed, ...gateway } = generation.providerOptions?.["gateway"] ?? {};
|
|
1572
|
+
return {
|
|
1573
|
+
...generation,
|
|
1574
|
+
...settings.reasoning === void 0 ? {} : { reasoning: settings.reasoning },
|
|
1575
|
+
...settings.speed === void 0 ? {} : { providerOptions: {
|
|
1576
|
+
...generation.providerOptions,
|
|
1577
|
+
gateway: settings.speed === "fast" ? {
|
|
1578
|
+
...gateway,
|
|
1579
|
+
speed: "fast"
|
|
1580
|
+
} : gateway
|
|
1581
|
+
} }
|
|
1582
|
+
};
|
|
1583
|
+
};
|
|
1504
1584
|
const modelName = (model) => {
|
|
1505
1585
|
if (typeof model === "string") return model;
|
|
1506
1586
|
if ("modelId" in model && typeof model.modelId === "string") return model.modelId;
|
|
@@ -1512,7 +1592,8 @@ const toolScopeStorage = installAmbientToolScopeStorage(() => new AsyncLocalStor
|
|
|
1512
1592
|
function runWithHandlerContext(ctx, fn) {
|
|
1513
1593
|
return toolScopeStorage.run({ context: ctx }, fn);
|
|
1514
1594
|
}
|
|
1515
|
-
|
|
1595
|
+
/** Sessions whose latest step prompt one process keeps for that step's tools. */
|
|
1596
|
+
const PROMPT_SESSIONS = 64;
|
|
1516
1597
|
const asyncIterator = (value) => {
|
|
1517
1598
|
if (typeof value !== "object" || value === null) return void 0;
|
|
1518
1599
|
const factory = Reflect.get(value, Symbol.asyncIterator);
|
|
@@ -1520,6 +1601,49 @@ const asyncIterator = (value) => {
|
|
|
1520
1601
|
return factory.call(value);
|
|
1521
1602
|
};
|
|
1522
1603
|
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");
|
|
1604
|
+
const DELTA_KEYS = {
|
|
1605
|
+
"text-delta": /* @__PURE__ */ new Set([
|
|
1606
|
+
"type",
|
|
1607
|
+
"id",
|
|
1608
|
+
"delta",
|
|
1609
|
+
"providerMetadata"
|
|
1610
|
+
]),
|
|
1611
|
+
"reasoning-delta": /* @__PURE__ */ new Set([
|
|
1612
|
+
"type",
|
|
1613
|
+
"id",
|
|
1614
|
+
"delta",
|
|
1615
|
+
"providerMetadata"
|
|
1616
|
+
]),
|
|
1617
|
+
"tool-input-delta": /* @__PURE__ */ new Set([
|
|
1618
|
+
"type",
|
|
1619
|
+
"toolCallId",
|
|
1620
|
+
"inputTextDelta"
|
|
1621
|
+
])
|
|
1622
|
+
};
|
|
1623
|
+
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";
|
|
1624
|
+
const joinDeltas = (left, right) => {
|
|
1625
|
+
if (left.type === "tool-input-delta") return right.type === "tool-input-delta" && right.toolCallId === left.toolCallId ? {
|
|
1626
|
+
...left,
|
|
1627
|
+
inputTextDelta: left.inputTextDelta + right.inputTextDelta
|
|
1628
|
+
} : void 0;
|
|
1629
|
+
if (right.type === "tool-input-delta" || right.type !== left.type || right.id !== left.id) return void 0;
|
|
1630
|
+
const providerMetadata = right.providerMetadata !== void 0 ? right.providerMetadata : left.providerMetadata;
|
|
1631
|
+
return {
|
|
1632
|
+
...left,
|
|
1633
|
+
delta: left.delta + right.delta,
|
|
1634
|
+
...providerMetadata === void 0 ? {} : { providerMetadata }
|
|
1635
|
+
};
|
|
1636
|
+
};
|
|
1637
|
+
const mergeDeltas = (chunks) => {
|
|
1638
|
+
const merged = [];
|
|
1639
|
+
for (const chunk of chunks) {
|
|
1640
|
+
const previous = merged.at(-1);
|
|
1641
|
+
const joined = previous !== void 0 && isDeltaChunk(previous) && isDeltaChunk(chunk) ? joinDeltas(previous, chunk) : void 0;
|
|
1642
|
+
if (joined === void 0) merged.push(chunk);
|
|
1643
|
+
else merged[merged.length - 1] = joined;
|
|
1644
|
+
}
|
|
1645
|
+
return merged;
|
|
1646
|
+
};
|
|
1523
1647
|
const nextOrTimer = async (next, delayMs) => {
|
|
1524
1648
|
let timer;
|
|
1525
1649
|
try {
|
|
@@ -1541,7 +1665,7 @@ async function generateWithAISDK(options) {
|
|
|
1541
1665
|
...context.generation,
|
|
1542
1666
|
headers: Object.keys(headers).some((key) => key.toLowerCase() === "x-session-affinity") ? headers : {
|
|
1543
1667
|
...headers,
|
|
1544
|
-
"x-session-affinity": createHash("sha256").update(JSON.stringify([agentName, context.
|
|
1668
|
+
"x-session-affinity": createHash("sha256").update(JSON.stringify([agentName, context.event.sessionId])).digest("hex")
|
|
1545
1669
|
},
|
|
1546
1670
|
providerOptions: {
|
|
1547
1671
|
...context.generation.providerOptions,
|
|
@@ -1556,7 +1680,7 @@ async function generateWithAISDK(options) {
|
|
|
1556
1680
|
tools: context.tools,
|
|
1557
1681
|
messages: context.messages,
|
|
1558
1682
|
modelMessages: context.modelMessages,
|
|
1559
|
-
responseMessageId: context.responseMessageId,
|
|
1683
|
+
responseMessageId: context.event.payload.responseMessageId,
|
|
1560
1684
|
abortSignal: context.signal,
|
|
1561
1685
|
...context.instructions === void 0 ? {} : { instructions: context.instructions },
|
|
1562
1686
|
settings: generation,
|
|
@@ -1575,9 +1699,13 @@ async function* consumeGeneration(options) {
|
|
|
1575
1699
|
const pending = [];
|
|
1576
1700
|
let streamedFinishReason;
|
|
1577
1701
|
let streamedError;
|
|
1578
|
-
const maxChunks = options.progress?.maxChunks ??
|
|
1579
|
-
const maxDelayMs = options.progress?.maxDelayMs ??
|
|
1702
|
+
const maxChunks = options.progress?.maxChunks ?? 128;
|
|
1703
|
+
const maxDelayMs = options.progress?.maxDelayMs ?? 0;
|
|
1580
1704
|
let lastFlush = Date.now();
|
|
1705
|
+
const batch = () => ({
|
|
1706
|
+
type: "progress",
|
|
1707
|
+
chunks: mergeDeltas(pending.splice(0))
|
|
1708
|
+
});
|
|
1581
1709
|
const reader = options.source.stream.getReader();
|
|
1582
1710
|
let pendingChunk = reader.read();
|
|
1583
1711
|
try {
|
|
@@ -1587,10 +1715,7 @@ async function* consumeGeneration(options) {
|
|
|
1587
1715
|
const remaining = Math.max(0, maxDelayMs - (Date.now() - lastFlush));
|
|
1588
1716
|
const outcome = await nextOrTimer(pendingChunk, remaining);
|
|
1589
1717
|
if (outcome.type === "timer") {
|
|
1590
|
-
yield
|
|
1591
|
-
type: "progress",
|
|
1592
|
-
chunks: pending.splice(0)
|
|
1593
|
-
};
|
|
1718
|
+
yield batch();
|
|
1594
1719
|
lastFlush = Date.now();
|
|
1595
1720
|
continue;
|
|
1596
1721
|
}
|
|
@@ -1603,18 +1728,12 @@ async function* consumeGeneration(options) {
|
|
|
1603
1728
|
if (chunk.type === "error") streamedError = chunk.errorText;
|
|
1604
1729
|
pendingChunk = reader.read();
|
|
1605
1730
|
if (pending.length >= maxChunks || isBoundaryChunk(pending.at(-1))) {
|
|
1606
|
-
yield
|
|
1607
|
-
type: "progress",
|
|
1608
|
-
chunks: pending.splice(0)
|
|
1609
|
-
};
|
|
1731
|
+
yield batch();
|
|
1610
1732
|
lastFlush = Date.now();
|
|
1611
1733
|
}
|
|
1612
1734
|
}
|
|
1613
1735
|
} catch (error) {
|
|
1614
|
-
if (pending.length > 0) yield
|
|
1615
|
-
type: "progress",
|
|
1616
|
-
chunks: pending.splice(0)
|
|
1617
|
-
};
|
|
1736
|
+
if (pending.length > 0) yield batch();
|
|
1618
1737
|
throw error;
|
|
1619
1738
|
} finally {
|
|
1620
1739
|
pendingChunk.catch(() => {});
|
|
@@ -1628,16 +1747,10 @@ async function* consumeGeneration(options) {
|
|
|
1628
1747
|
try {
|
|
1629
1748
|
completion = options.source.completion?.();
|
|
1630
1749
|
} catch (error) {
|
|
1631
|
-
if (pending.length > 0) yield
|
|
1632
|
-
type: "progress",
|
|
1633
|
-
chunks: pending.splice(0)
|
|
1634
|
-
};
|
|
1750
|
+
if (pending.length > 0) yield batch();
|
|
1635
1751
|
throw error;
|
|
1636
1752
|
}
|
|
1637
|
-
if (pending.length > 0) yield
|
|
1638
|
-
type: "progress",
|
|
1639
|
-
chunks: pending.splice(0)
|
|
1640
|
-
};
|
|
1753
|
+
if (pending.length > 0) yield batch();
|
|
1641
1754
|
if (streamedError !== void 0) throw new Error(streamedError);
|
|
1642
1755
|
const finishReason = completion?.finishReason ?? streamedFinishReason;
|
|
1643
1756
|
yield {
|
|
@@ -1688,8 +1801,7 @@ const summarize = async (options) => {
|
|
|
1688
1801
|
modelMessages: [...options.context.modelMessages, {
|
|
1689
1802
|
role: "user",
|
|
1690
1803
|
content: instruction
|
|
1691
|
-
}]
|
|
1692
|
-
responseMessageId: await aiEventId("a2.ai.summary", options.context.generationId)
|
|
1804
|
+
}]
|
|
1693
1805
|
},
|
|
1694
1806
|
messageMetadata: void 0
|
|
1695
1807
|
});
|
|
@@ -1916,12 +2028,8 @@ const validateCompaction = (options) => {
|
|
|
1916
2028
|
}
|
|
1917
2029
|
return compaction;
|
|
1918
2030
|
};
|
|
1919
|
-
/**
|
|
1920
|
-
* Build the ordinary A2 handler table for the built-in agent protocol.
|
|
1921
|
-
* Application handlers can be spread beside this table.
|
|
1922
|
-
*/
|
|
1923
2031
|
function createHandlers(options) {
|
|
1924
|
-
if (options.model === void 0) throw new TypeError("
|
|
2032
|
+
if (options.model === void 0) throw new TypeError("agent requires model");
|
|
1925
2033
|
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
2034
|
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
2035
|
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");
|
|
@@ -1929,23 +2037,39 @@ function createHandlers(options) {
|
|
|
1929
2037
|
const staticCompaction = typeof configuredCompaction === "function" ? void 0 : validateCompaction({
|
|
1930
2038
|
compaction: configuredCompaction,
|
|
1931
2039
|
explicit: options.compaction !== void 0,
|
|
1932
|
-
generation: options.generation,
|
|
2040
|
+
generation: typeof options.generation === "function" ? void 0 : options.generation,
|
|
1933
2041
|
tools: options.tools
|
|
1934
2042
|
});
|
|
1935
2043
|
const tools = options.tools ?? {};
|
|
1936
|
-
const
|
|
2044
|
+
const telemetry = options.telemetry ?? CONSOLE_TELEMETRY;
|
|
1937
2045
|
const maxSteps = options.maxSteps ?? Number.POSITIVE_INFINITY;
|
|
1938
|
-
const control = createControlRuntime({
|
|
2046
|
+
const control = createControlRuntime({
|
|
2047
|
+
contract: options.contract,
|
|
2048
|
+
telemetry
|
|
2049
|
+
});
|
|
2050
|
+
const controlHandler = (ctx) => telemetry.span("a2.ai.control", {
|
|
2051
|
+
"a2.contract": options.contract.name,
|
|
2052
|
+
"a2.session_id": ctx.event.sessionId,
|
|
2053
|
+
"a2.ai.control.type": ctx.event.type,
|
|
2054
|
+
"a2.ai.control.id": ctx.event.id,
|
|
2055
|
+
"a2.ai.control.attempt": ctx.attempt
|
|
2056
|
+
}, () => control.handler(ctx));
|
|
1939
2057
|
const coordinator = control.coordinator;
|
|
1940
|
-
const contextReducer = createContextReducer({
|
|
2058
|
+
const contextReducer = createContextReducer({ contract: options.contract });
|
|
1941
2059
|
const readContext = async (session, through) => {
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
2060
|
+
return await session.state(contextReducer, { through });
|
|
2061
|
+
};
|
|
2062
|
+
const prompts = boundedCache({
|
|
2063
|
+
maxEntries: PROMPT_SESSIONS,
|
|
2064
|
+
maxBytes: PROMPT_SESSIONS
|
|
2065
|
+
});
|
|
2066
|
+
const cachePrompt = ({ sessionId, generationId, messages }) => prompts.set(sessionId, {
|
|
2067
|
+
generationId,
|
|
2068
|
+
messages
|
|
2069
|
+
}, 1);
|
|
2070
|
+
const forgetPrompt = (sessionId, generationId) => {
|
|
2071
|
+
if (prompts.get(sessionId)?.generationId === generationId) prompts.delete(sessionId);
|
|
1947
2072
|
};
|
|
1948
|
-
const promptCache = /* @__PURE__ */ new Map();
|
|
1949
2073
|
const resultEvent = async (call, suffix, result) => ({
|
|
1950
2074
|
type: "ai.tool.result",
|
|
1951
2075
|
id: await aiEventId("a2.ai.tool.result", call.generationId, call.toolCallId, suffix),
|
|
@@ -1968,25 +2092,32 @@ function createHandlers(options) {
|
|
|
1968
2092
|
});
|
|
1969
2093
|
const promptMessages = (input) => {
|
|
1970
2094
|
const { ctx, call, generation: owner } = input;
|
|
1971
|
-
const
|
|
1972
|
-
const cached =
|
|
1973
|
-
if (cached) return cached;
|
|
2095
|
+
const sessionId = ctx.event.sessionId;
|
|
2096
|
+
const cached = prompts.get(sessionId);
|
|
2097
|
+
if (cached?.generationId === call.generationId) return cached.messages;
|
|
1974
2098
|
const computation = (async () => {
|
|
1975
2099
|
const frontier = owner.promptThroughIndex;
|
|
1976
2100
|
if (frontier === void 0) throw new TypeError("AI work requires a prompt checkpoint");
|
|
1977
2101
|
const snapshot = await readContext(ctx.session, ctx.event.index);
|
|
1978
2102
|
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
2103
|
const state = generationBase(snapshot.state);
|
|
1980
|
-
return
|
|
2104
|
+
return telemetry.span("a2.ai.context", {
|
|
2105
|
+
"a2.contract": options.contract.name,
|
|
2106
|
+
"a2.session_id": ctx.event.sessionId,
|
|
2107
|
+
"a2.ai.context.request_id": call.requestId,
|
|
2108
|
+
"a2.ai.context.phase": "tool"
|
|
2109
|
+
}, () => modelContext({
|
|
1981
2110
|
messages: state.messages.filter((message) => state.messageIndexes[message.id] <= frontier),
|
|
1982
2111
|
state,
|
|
1983
2112
|
tools
|
|
1984
|
-
});
|
|
2113
|
+
}));
|
|
1985
2114
|
})();
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
2115
|
+
cachePrompt({
|
|
2116
|
+
sessionId,
|
|
2117
|
+
generationId: call.generationId,
|
|
2118
|
+
messages: computation
|
|
1989
2119
|
});
|
|
2120
|
+
computation.catch(() => forgetPrompt(sessionId, call.generationId));
|
|
1990
2121
|
return computation;
|
|
1991
2122
|
};
|
|
1992
2123
|
const toolExecutionFailure = async (ctx, call, error) => {
|
|
@@ -2055,7 +2186,7 @@ function createHandlers(options) {
|
|
|
2055
2186
|
const messages = await promptMessages(input);
|
|
2056
2187
|
if (checkAbort(ctx.signal)) return;
|
|
2057
2188
|
const scope = {
|
|
2058
|
-
contract: options.
|
|
2189
|
+
contract: options.contract,
|
|
2059
2190
|
context: ctx
|
|
2060
2191
|
};
|
|
2061
2192
|
return toolScopeStorage.run(scope, () => runToolExecution(ctx, call, execute, messages));
|
|
@@ -2115,109 +2246,124 @@ function createHandlers(options) {
|
|
|
2115
2246
|
state,
|
|
2116
2247
|
coordinator: coordinatorState
|
|
2117
2248
|
}),
|
|
2249
|
+
state: snapshot.state.app ?? {},
|
|
2118
2250
|
session: { state: (reducer, readOptions) => ctx.session.state(reducer, {
|
|
2119
2251
|
...readOptions,
|
|
2120
2252
|
through: readOptions?.through ?? snapshot.index
|
|
2121
2253
|
}) },
|
|
2122
2254
|
signal: ctx.signal
|
|
2123
2255
|
};
|
|
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
|
|
2256
|
+
if (request.reason === "tool" && responseStepCount >= maxSteps) {
|
|
2257
|
+
const source = response.source?.generation;
|
|
2258
|
+
if (source === void 0) return;
|
|
2259
|
+
return {
|
|
2260
|
+
type: "ai.generation.failed",
|
|
2261
|
+
id: await aiEventId("a2.ai.step-limit", requestId),
|
|
2262
|
+
payload: {
|
|
2263
|
+
requestId: source.requestId,
|
|
2264
|
+
messageId: source.messageId,
|
|
2265
|
+
generationId: source.generationId,
|
|
2266
|
+
responseMessageId,
|
|
2267
|
+
error: `agent exceeded the ${maxSteps}-step limit`,
|
|
2268
|
+
stepLimit: true
|
|
2269
|
+
}
|
|
2162
2270
|
};
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
const
|
|
2166
|
-
|
|
2167
|
-
const startEvents = [];
|
|
2168
|
-
if (discoversMetadata && !Object.hasOwn(state.modelMetadata, catalogModelId)) startEvents.push({
|
|
2271
|
+
}
|
|
2272
|
+
const startEvents = async (started, metadataModelId) => {
|
|
2273
|
+
const events = [];
|
|
2274
|
+
if (metadataModelId !== void 0) events.push({
|
|
2169
2275
|
type: "ai.model.metadata.requested",
|
|
2170
|
-
id: await aiEventId("a2.ai.model.metadata", options.
|
|
2171
|
-
payload: { modelId:
|
|
2276
|
+
id: await aiEventId("a2.ai.model.metadata", options.contract.name, ctx.event.sessionId, metadataModelId),
|
|
2277
|
+
payload: { modelId: metadataModelId }
|
|
2172
2278
|
});
|
|
2173
2279
|
if (previous) {
|
|
2174
|
-
const payload = previous;
|
|
2175
2280
|
const superseded = {
|
|
2176
2281
|
requestId,
|
|
2177
|
-
messageId:
|
|
2178
|
-
generationId:
|
|
2179
|
-
responseMessageId:
|
|
2282
|
+
messageId: previous.messageId,
|
|
2283
|
+
generationId: previous.generationId,
|
|
2284
|
+
responseMessageId: previous.responseMessageId,
|
|
2180
2285
|
error: "generation attempt was superseded after an incomplete run",
|
|
2181
2286
|
superseded: true
|
|
2182
2287
|
};
|
|
2183
|
-
|
|
2288
|
+
events.push({
|
|
2184
2289
|
type: "ai.generation.failed",
|
|
2185
|
-
id: await aiEventId("a2.ai.superseded",
|
|
2290
|
+
id: await aiEventId("a2.ai.superseded", previous.generationId),
|
|
2186
2291
|
payload: superseded
|
|
2187
2292
|
});
|
|
2188
2293
|
}
|
|
2189
|
-
|
|
2294
|
+
events.push({
|
|
2190
2295
|
type: "ai.generation.started",
|
|
2191
2296
|
id: generationId,
|
|
2192
2297
|
payload: started
|
|
2193
2298
|
});
|
|
2299
|
+
return events;
|
|
2300
|
+
};
|
|
2301
|
+
const startedPayload = (model) => ({
|
|
2302
|
+
requestId,
|
|
2303
|
+
messageId: request.messageId,
|
|
2304
|
+
generationId,
|
|
2305
|
+
responseMessageId,
|
|
2306
|
+
attempt,
|
|
2307
|
+
...model === void 0 ? {} : { model: modelName(model) },
|
|
2308
|
+
promptThroughIndex: snapshot.index
|
|
2309
|
+
});
|
|
2310
|
+
let resolvedModel;
|
|
2311
|
+
let resolving = true;
|
|
2312
|
+
let generationStarted = false;
|
|
2313
|
+
try {
|
|
2314
|
+
const choice = await resolve(options.model, resolverContext);
|
|
2315
|
+
if (choice === void 0) throw new TypeError("the model resolver returned undefined");
|
|
2316
|
+
const settings = typeof choice === "string" || "specificationVersion" in choice ? { model: choice } : choice;
|
|
2317
|
+
const model = settings.model;
|
|
2318
|
+
if (typeof model !== "string" && (typeof model !== "object" || model === null)) throw new TypeError("the model resolver must return a model");
|
|
2319
|
+
resolvedModel = model;
|
|
2320
|
+
if (checkAbort(ctx.signal)) return;
|
|
2321
|
+
const resolvedInstructions = options.instructions === void 0 ? void 0 : await resolve(options.instructions, resolverContext);
|
|
2322
|
+
if (checkAbort(ctx.signal)) return;
|
|
2323
|
+
const resolvedGeneration = await resolve(options.generation ?? {}, resolverContext);
|
|
2324
|
+
if (checkAbort(ctx.signal)) return;
|
|
2325
|
+
if (resolvedGeneration === null || typeof resolvedGeneration !== "object" || Array.isArray(resolvedGeneration)) throw new TypeError("the generation resolver must return settings");
|
|
2326
|
+
const generation = withModelSettings({
|
|
2327
|
+
generation: resolvedGeneration,
|
|
2328
|
+
settings
|
|
2329
|
+
});
|
|
2330
|
+
const compaction = typeof configuredCompaction === "function" || typeof options.generation === "function" ? validateCompaction({
|
|
2331
|
+
compaction: typeof configuredCompaction === "function" ? await resolve(configuredCompaction, resolverContext) : staticCompaction,
|
|
2332
|
+
explicit: options.compaction !== void 0,
|
|
2333
|
+
generation,
|
|
2334
|
+
tools: options.tools
|
|
2335
|
+
}) : staticCompaction;
|
|
2336
|
+
if (checkAbort(ctx.signal)) return;
|
|
2337
|
+
resolving = false;
|
|
2338
|
+
const catalogModelId = gatewayModelId(model);
|
|
2339
|
+
const gatewayOptions = generation.providerOptions?.["gateway"];
|
|
2340
|
+
const usesFallbackModels = Array.isArray(gatewayOptions?.["models"]) && gatewayOptions["models"].length > 0;
|
|
2341
|
+
const discoversMetadata = compaction !== false && !("shouldCompact" in compaction) && compaction.thresholdTokens === void 0 && !usesFallbackModels && catalogModelId !== void 0;
|
|
2194
2342
|
const generationEvents = await control.append({
|
|
2195
2343
|
ctx,
|
|
2196
2344
|
name: "generation-start",
|
|
2197
|
-
events: startEvents
|
|
2345
|
+
events: await startEvents(startedPayload(model), discoversMetadata && !Object.hasOwn(state.modelMetadata, catalogModelId) ? catalogModelId : void 0)
|
|
2198
2346
|
});
|
|
2347
|
+
const startIndex = generationEvents.find((event) => event.id === generationId).index;
|
|
2199
2348
|
generationStarted = true;
|
|
2200
2349
|
if (checkAbort(ctx.signal)) return;
|
|
2201
2350
|
const promptCoordinatorState = coordinatorState;
|
|
2202
|
-
const messages =
|
|
2203
|
-
state,
|
|
2204
|
-
coordinator: promptCoordinatorState
|
|
2205
|
-
});
|
|
2351
|
+
const { messages } = resolverContext;
|
|
2206
2352
|
let generationMessages = messages;
|
|
2207
|
-
let modelMessages = await
|
|
2353
|
+
let modelMessages = await telemetry.span("a2.ai.context", {
|
|
2354
|
+
"a2.contract": options.contract.name,
|
|
2355
|
+
"a2.session_id": ctx.event.sessionId,
|
|
2356
|
+
"a2.ai.context.request_id": requestId,
|
|
2357
|
+
"a2.ai.context.phase": "generation"
|
|
2358
|
+
}, () => modelContext({
|
|
2208
2359
|
messages,
|
|
2209
2360
|
state,
|
|
2210
2361
|
tools
|
|
2211
|
-
});
|
|
2362
|
+
}));
|
|
2212
2363
|
const baseContext = {
|
|
2213
|
-
|
|
2214
|
-
requestId,
|
|
2364
|
+
...resolverContext,
|
|
2215
2365
|
generationId,
|
|
2216
|
-
responseMessageId,
|
|
2217
|
-
messages,
|
|
2218
2366
|
modelMessages,
|
|
2219
|
-
session: resolverContext.session,
|
|
2220
|
-
signal: ctx.signal,
|
|
2221
2367
|
model: resolvedModel,
|
|
2222
2368
|
tools,
|
|
2223
2369
|
...resolvedInstructions === void 0 ? {} : { instructions: resolvedInstructions },
|
|
@@ -2282,14 +2428,20 @@ function createHandlers(options) {
|
|
|
2282
2428
|
}
|
|
2283
2429
|
}]
|
|
2284
2430
|
}));
|
|
2285
|
-
const result =
|
|
2431
|
+
const result = await telemetry.span("a2.ai.compaction", {
|
|
2432
|
+
"a2.contract": options.contract.name,
|
|
2433
|
+
"a2.session_id": ctx.event.sessionId,
|
|
2434
|
+
"a2.ai.compaction.request_id": requestId,
|
|
2435
|
+
"a2.ai.compaction.generation_id": generationId,
|
|
2436
|
+
"a2.ai.compaction.policy": "shouldCompact" in policy ? "custom" : "automatic"
|
|
2437
|
+
}, async () => !("shouldCompact" in policy) ? {
|
|
2286
2438
|
messages: [],
|
|
2287
2439
|
...await summarize({
|
|
2288
|
-
agentName: options.
|
|
2440
|
+
agentName: options.contract.name,
|
|
2289
2441
|
context: baseContext,
|
|
2290
2442
|
instructions: policy.instructions
|
|
2291
2443
|
})
|
|
2292
|
-
} : { messages: await policy.compact(compactionContext) };
|
|
2444
|
+
} : { messages: await policy.compact(compactionContext) });
|
|
2293
2445
|
if (checkAbort(ctx.signal)) return;
|
|
2294
2446
|
const completed = {
|
|
2295
2447
|
generationId,
|
|
@@ -2313,7 +2465,7 @@ function createHandlers(options) {
|
|
|
2313
2465
|
}
|
|
2314
2466
|
}
|
|
2315
2467
|
const currentState = foldAIEvents({
|
|
2316
|
-
reducer: contextReducer
|
|
2468
|
+
reducer: contextReducer,
|
|
2317
2469
|
events: generationEvents,
|
|
2318
2470
|
state
|
|
2319
2471
|
});
|
|
@@ -2321,12 +2473,21 @@ function createHandlers(options) {
|
|
|
2321
2473
|
state: currentState,
|
|
2322
2474
|
coordinator: promptCoordinatorState
|
|
2323
2475
|
});
|
|
2324
|
-
if (policy && "shouldCompact" in policy || generationMessages !== messages || activeCompaction(currentState)?.summary !== activeCompaction(state)?.summary) modelMessages = await
|
|
2476
|
+
if (policy && "shouldCompact" in policy || generationMessages !== messages || activeCompaction(currentState)?.summary !== activeCompaction(state)?.summary) modelMessages = await telemetry.span("a2.ai.context", {
|
|
2477
|
+
"a2.contract": options.contract.name,
|
|
2478
|
+
"a2.session_id": ctx.event.sessionId,
|
|
2479
|
+
"a2.ai.context.request_id": requestId,
|
|
2480
|
+
"a2.ai.context.phase": "refresh"
|
|
2481
|
+
}, () => modelContext({
|
|
2325
2482
|
messages: generationMessages,
|
|
2326
2483
|
state: currentState,
|
|
2327
2484
|
tools
|
|
2485
|
+
}));
|
|
2486
|
+
cachePrompt({
|
|
2487
|
+
sessionId: ctx.event.sessionId,
|
|
2488
|
+
generationId,
|
|
2489
|
+
messages: Promise.resolve(modelMessages)
|
|
2328
2490
|
});
|
|
2329
|
-
promptCache.set(promptCacheKey(ctx.event.sessionId, generationId), Promise.resolve(modelMessages));
|
|
2330
2491
|
if (tracksInput && (inputTokenEstimate === void 0 || compacted)) inputTokenEstimate = await estimateInputTokens({
|
|
2331
2492
|
messages: modelMessages,
|
|
2332
2493
|
instructions: resolvedInstructions,
|
|
@@ -2335,23 +2496,14 @@ function createHandlers(options) {
|
|
|
2335
2496
|
let pendingToolCalls = [];
|
|
2336
2497
|
if (checkAbort(ctx.signal)) return;
|
|
2337
2498
|
const generateContext = {
|
|
2338
|
-
|
|
2339
|
-
requestId,
|
|
2340
|
-
generationId,
|
|
2341
|
-
responseMessageId,
|
|
2499
|
+
...baseContext,
|
|
2342
2500
|
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 ?? {}
|
|
2501
|
+
modelMessages
|
|
2350
2502
|
};
|
|
2351
2503
|
const custom = options.generate !== void 0;
|
|
2352
2504
|
const updates = consumeGeneration({
|
|
2353
2505
|
source: options.generate === void 0 ? await generateWithAISDK({
|
|
2354
|
-
agentName: options.
|
|
2506
|
+
agentName: options.contract.name,
|
|
2355
2507
|
context: generateContext,
|
|
2356
2508
|
messageMetadata: options.messageMetadata
|
|
2357
2509
|
}) : { stream: await options.generate(generateContext) },
|
|
@@ -2366,11 +2518,7 @@ function createHandlers(options) {
|
|
|
2366
2518
|
continue;
|
|
2367
2519
|
}
|
|
2368
2520
|
const progress = {
|
|
2369
|
-
|
|
2370
|
-
messageId: request.messageId,
|
|
2371
|
-
generationId,
|
|
2372
|
-
responseMessageId,
|
|
2373
|
-
sequence,
|
|
2521
|
+
startIndex,
|
|
2374
2522
|
chunks: update.chunks
|
|
2375
2523
|
};
|
|
2376
2524
|
const lifecycle = await lifecycleEvents({
|
|
@@ -2415,6 +2563,7 @@ function createHandlers(options) {
|
|
|
2415
2563
|
if (unresolved.length > 0) throw new Error(`generation ended with unresolved tool authorization for '${unresolved[0].call.toolName}'`);
|
|
2416
2564
|
const pendingEvents = await Promise.all(pendingToolCalls.filter((pending) => pending.classification === "automatic" || options.generate === void 0 && pending.classification === "unknown").map((pending) => toolCalledEvent(pending.call)));
|
|
2417
2565
|
if (finish.finishReason === "tool-calls") return [...pendingEvents, completionEvent];
|
|
2566
|
+
forgetPrompt(ctx.event.sessionId, generationId);
|
|
2418
2567
|
return [
|
|
2419
2568
|
...pendingEvents,
|
|
2420
2569
|
completionEvent,
|
|
@@ -2431,7 +2580,13 @@ function createHandlers(options) {
|
|
|
2431
2580
|
throw error;
|
|
2432
2581
|
}
|
|
2433
2582
|
if (checkAbort(ctx.signal)) return;
|
|
2434
|
-
if (!generationStarted) throw error;
|
|
2583
|
+
if (!generationStarted && !resolving) throw error;
|
|
2584
|
+
if (!generationStarted) await control.append({
|
|
2585
|
+
ctx,
|
|
2586
|
+
name: "generation-start",
|
|
2587
|
+
events: await startEvents(startedPayload(resolvedModel))
|
|
2588
|
+
});
|
|
2589
|
+
forgetPrompt(ctx.event.sessionId, generationId);
|
|
2435
2590
|
const failed = {
|
|
2436
2591
|
requestId,
|
|
2437
2592
|
messageId: request.messageId,
|
|
@@ -2446,10 +2601,6 @@ function createHandlers(options) {
|
|
|
2446
2601
|
};
|
|
2447
2602
|
}
|
|
2448
2603
|
};
|
|
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
2604
|
return {
|
|
2454
2605
|
"ai.model.metadata.requested": { handler: async (ctx) => {
|
|
2455
2606
|
const limits = await readModelLimits({
|
|
@@ -2474,29 +2625,16 @@ function createHandlers(options) {
|
|
|
2474
2625
|
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
2626
|
return "a2.ai.control";
|
|
2476
2627
|
},
|
|
2477
|
-
handler:
|
|
2628
|
+
handler: controlHandler
|
|
2478
2629
|
},
|
|
2479
2630
|
"ai.work.reported": {
|
|
2480
2631
|
lane: "a2.ai.control",
|
|
2481
|
-
handler:
|
|
2632
|
+
handler: controlHandler
|
|
2482
2633
|
},
|
|
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
2634
|
"ai.session.closed": {
|
|
2490
2635
|
lane: "a2.ai.control",
|
|
2491
|
-
handler:
|
|
2492
|
-
clearPromptCache(ctx.event.sessionId);
|
|
2493
|
-
return control.handler(ctx);
|
|
2494
|
-
}
|
|
2636
|
+
handler: controlHandler
|
|
2495
2637
|
},
|
|
2496
|
-
"ai.generation.failed": { handler: (ctx) => {
|
|
2497
|
-
promptCache.delete(promptCacheKey(ctx.event.sessionId, ctx.event.payload.generationId));
|
|
2498
|
-
return Promise.resolve();
|
|
2499
|
-
} },
|
|
2500
2638
|
"ai.generation.requested": {
|
|
2501
2639
|
lane: "a2.ai.model",
|
|
2502
2640
|
abortOn: {
|
|
@@ -2507,7 +2645,12 @@ function createHandlers(options) {
|
|
|
2507
2645
|
},
|
|
2508
2646
|
"ai.session.closed": true
|
|
2509
2647
|
},
|
|
2510
|
-
handler:
|
|
2648
|
+
handler: (ctx) => telemetry.span("a2.ai.generate", {
|
|
2649
|
+
"a2.contract": options.contract.name,
|
|
2650
|
+
"a2.session_id": ctx.event.sessionId,
|
|
2651
|
+
"a2.ai.generate.request_id": ctx.event.id,
|
|
2652
|
+
"a2.ai.generate.attempt": ctx.attempt
|
|
2653
|
+
}, async () => {
|
|
2511
2654
|
try {
|
|
2512
2655
|
return control.settled({
|
|
2513
2656
|
ctx,
|
|
@@ -2523,9 +2666,10 @@ function createHandlers(options) {
|
|
|
2523
2666
|
});
|
|
2524
2667
|
throw error;
|
|
2525
2668
|
}
|
|
2526
|
-
}
|
|
2669
|
+
})
|
|
2527
2670
|
},
|
|
2528
2671
|
"ai.tool.execution.requested": {
|
|
2672
|
+
...options.toolLane === void 0 ? {} : { lane: options.toolLane },
|
|
2529
2673
|
abortOn: {
|
|
2530
2674
|
"ai.control.requested": (event, trigger) => event.payload.action === "stop" && event.payload.turnId === trigger.payload.turnId,
|
|
2531
2675
|
"ai.generation.failed": (event, trigger) => event.payload.generationId === trigger.payload.call.generationId,
|
|
@@ -2535,16 +2679,40 @@ function createHandlers(options) {
|
|
|
2535
2679
|
},
|
|
2536
2680
|
"ai.session.closed": true
|
|
2537
2681
|
},
|
|
2538
|
-
handler:
|
|
2682
|
+
handler: (ctx) => telemetry.span("a2.ai.tool", {
|
|
2683
|
+
"a2.contract": options.contract.name,
|
|
2684
|
+
"a2.session_id": ctx.event.sessionId,
|
|
2685
|
+
"a2.ai.tool.request_id": ctx.event.payload.call.requestId,
|
|
2686
|
+
"a2.ai.tool.call_id": ctx.event.payload.call.toolCallId,
|
|
2687
|
+
"a2.ai.tool.name": ctx.event.payload.call.toolName,
|
|
2688
|
+
"a2.ai.tool.attempt": ctx.attempt
|
|
2689
|
+
}, () => handleToolExecution(ctx))
|
|
2539
2690
|
}
|
|
2540
2691
|
};
|
|
2541
2692
|
}
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2693
|
+
function agent(options) {
|
|
2694
|
+
const { model, tools, instructions, generation, maxSteps, messageMetadata, generate, compaction, progress, toolLane, handlers, ...rest } = options;
|
|
2695
|
+
let contract;
|
|
2696
|
+
let serverOptions;
|
|
2697
|
+
if ("contract" in rest) {
|
|
2698
|
+
const { contract: shared, ...remaining } = rest;
|
|
2699
|
+
if ("name" in remaining) throw new TypeError("agent takes either name or contract, not both");
|
|
2700
|
+
if (!isAgentContract(shared)) throw new TypeError("agent({ contract }) takes an agentContract()");
|
|
2701
|
+
contract = shared;
|
|
2702
|
+
serverOptions = remaining;
|
|
2703
|
+
} else {
|
|
2704
|
+
const { name, events, messageSchema, ...remaining } = rest;
|
|
2705
|
+
contract = agentContract({
|
|
2706
|
+
name,
|
|
2707
|
+
...events === void 0 ? {} : { events },
|
|
2708
|
+
...messageSchema === void 0 ? {} : { messageSchema }
|
|
2709
|
+
});
|
|
2710
|
+
serverOptions = remaining;
|
|
2711
|
+
}
|
|
2545
2712
|
const builtIns = createHandlers({
|
|
2546
|
-
|
|
2713
|
+
contract,
|
|
2547
2714
|
model,
|
|
2715
|
+
...serverOptions.telemetry === void 0 ? {} : { telemetry: serverOptions.telemetry },
|
|
2548
2716
|
...tools === void 0 ? {} : { tools },
|
|
2549
2717
|
...instructions === void 0 ? {} : { instructions },
|
|
2550
2718
|
...generation === void 0 ? {} : { generation },
|
|
@@ -2552,20 +2720,26 @@ function createAgentServer(options) {
|
|
|
2552
2720
|
...messageMetadata === void 0 ? {} : { messageMetadata },
|
|
2553
2721
|
...generate === void 0 ? {} : { generate },
|
|
2554
2722
|
...compaction === void 0 ? {} : { compaction },
|
|
2555
|
-
...progress === void 0 ? {} : { progress }
|
|
2723
|
+
...progress === void 0 ? {} : { progress },
|
|
2724
|
+
...toolLane === void 0 ? {} : { toolLane }
|
|
2556
2725
|
});
|
|
2726
|
+
for (const type of Object.keys(handlers ?? {})) if (Object.hasOwn(builtIns, type)) throw new TypeError(`agent handles '${type}' itself`);
|
|
2557
2727
|
const server = createServer({
|
|
2558
2728
|
...serverOptions,
|
|
2559
|
-
contract
|
|
2729
|
+
contract,
|
|
2560
2730
|
handlers: {
|
|
2561
2731
|
...builtIns,
|
|
2562
2732
|
...handlers
|
|
2563
2733
|
}
|
|
2564
2734
|
});
|
|
2565
|
-
|
|
2735
|
+
const applicationEvents = "contract" in rest;
|
|
2736
|
+
setServerFetchHooks(server, { validateIngress: (context) => validateAgentIngress({
|
|
2737
|
+
context,
|
|
2738
|
+
applicationEvents
|
|
2739
|
+
}) });
|
|
2566
2740
|
return server;
|
|
2567
2741
|
}
|
|
2568
2742
|
//#endregion
|
|
2569
|
-
export {
|
|
2743
|
+
export { agent, runWithHandlerContext };
|
|
2570
2744
|
|
|
2571
2745
|
//# sourceMappingURL=ai-server.js.map
|