experimental-a2 0.16.0 → 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 +360 -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-CrLYwNEx.js → ai-UrWfKeuv.js} +966 -541
- 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 +466 -265
- package/dist/ai-server.js.map +1 -1
- package/dist/{ai-HJ9fHfYI.d.ts → ai-vpGtcaCB.d.ts} +115 -101
- 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 +680 -580
- 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 +662 -195
- 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 +39 -2
- 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 +94 -55
- package/src/ai-control.ts +2 -0
- package/src/ai-coordinator.ts +23 -22
- package/src/ai-message-base.ts +209 -0
- package/src/ai-message-projection.ts +382 -58
- 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 -1951
- package/src/ai-stored-state.ts +48 -163
- package/src/ai.ts +343 -276
- 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-CrLYwNEx.js.map +0 -1
- package/dist/ai-HJ9fHfYI.d.ts.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
|
@@ -1,251 +1,135 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as
|
|
3
|
-
import { t as contract } from "./contract-CKRg_E4q.js";
|
|
1
|
+
import { a as reducer, o as assertSyncSchema, s as validateSync } from "./reducer-BAXc8JyF.js";
|
|
2
|
+
import { t as contract } from "./contract-BYKASlCV.js";
|
|
4
3
|
import { t as idempotentId } from "./idempotent-id-BRJVeylj.js";
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
if (
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
return
|
|
4
|
+
import { i as withReducerRuntime } from "./reducer-runtime-DQwz_J59.js";
|
|
5
|
+
import { u as ambientToolScopeStorage } from "./internal-CbVvEwad.js";
|
|
6
|
+
//#region src/equal-json.ts
|
|
7
|
+
const sameValue = (left, right) => {
|
|
8
|
+
if (Object.is(left, right)) return true;
|
|
9
|
+
if (typeof left !== "object" || left === null || typeof right !== "object" || right === null) return false;
|
|
10
|
+
const prototype = Object.getPrototypeOf(left);
|
|
11
|
+
if (prototype !== Object.getPrototypeOf(right) || prototype !== Object.prototype && prototype !== Array.prototype && prototype !== null) return false;
|
|
12
|
+
if (Array.isArray(left) && (!Array.isArray(right) || left.length !== right.length)) return false;
|
|
13
|
+
const keys = Reflect.ownKeys(left);
|
|
14
|
+
return keys.length === Reflect.ownKeys(right).length && keys.every((key) => Object.hasOwn(right, key) && sameValue(Reflect.get(left, key), Reflect.get(right, key)));
|
|
16
15
|
};
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
count += 1;
|
|
39
|
-
show(item.message);
|
|
40
|
-
if (item.generate) {
|
|
41
|
-
turnId = item.id;
|
|
42
|
-
starting = true;
|
|
43
|
-
suspended = false;
|
|
44
|
-
break;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
if (count > 0) items = items.slice(count);
|
|
48
|
-
};
|
|
49
|
-
for (const { command } of pending) {
|
|
50
|
-
switch (command.action) {
|
|
51
|
-
case "send":
|
|
52
|
-
case "steer": {
|
|
53
|
-
if (items.some((item) => item.id === command.message.id) || turnId === command.message.id) break;
|
|
54
|
-
const item = {
|
|
55
|
-
...command.action === "steer" ? { afterStepOf: command.turnId } : {},
|
|
56
|
-
id: command.message.id,
|
|
57
|
-
message: command.message,
|
|
58
|
-
generate: command.message.role === "user" && (command.action === "steer" || command.generate !== false)
|
|
59
|
-
};
|
|
60
|
-
items = command.action === "steer" ? [item, ...items] : [...items, item];
|
|
61
|
-
break;
|
|
62
|
-
}
|
|
63
|
-
case "edit":
|
|
64
|
-
items = items.map((item) => item.id === command.message.id && item.message.role === command.message.role ? {
|
|
65
|
-
...item,
|
|
66
|
-
message: command.message
|
|
67
|
-
} : item);
|
|
68
|
-
break;
|
|
69
|
-
case "move":
|
|
70
|
-
items = moveItem({
|
|
71
|
-
items,
|
|
72
|
-
inputId: command.inputId,
|
|
73
|
-
beforeId: command.beforeId
|
|
74
|
-
});
|
|
75
|
-
break;
|
|
76
|
-
case "remove":
|
|
77
|
-
items = items.filter((item) => item.id !== command.inputId);
|
|
78
|
-
break;
|
|
79
|
-
case "send-now": {
|
|
80
|
-
if (turnId !== command.turnId) break;
|
|
81
|
-
const selected = items.find((item) => item.id === command.inputId);
|
|
82
|
-
if (!selected || selected.message.role !== "user") break;
|
|
83
|
-
items = items.map((item) => item.id === selected.id ? {
|
|
84
|
-
...item,
|
|
85
|
-
generate: true,
|
|
86
|
-
...turnId === null ? {} : { afterStepOf: turnId }
|
|
87
|
-
} : item);
|
|
88
|
-
items = moveItem({
|
|
89
|
-
items,
|
|
90
|
-
inputId: command.inputId,
|
|
91
|
-
beforeId: items[0]?.id ?? null
|
|
92
|
-
});
|
|
93
|
-
break;
|
|
94
|
-
}
|
|
95
|
-
case "pause":
|
|
96
|
-
paused = true;
|
|
97
|
-
if (command.when === "now") suspended = true;
|
|
98
|
-
break;
|
|
99
|
-
case "resume":
|
|
100
|
-
paused = false;
|
|
101
|
-
suspended = false;
|
|
102
|
-
}
|
|
103
|
-
admit();
|
|
16
|
+
//#endregion
|
|
17
|
+
//#region src/ai-message-base.ts
|
|
18
|
+
const record = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
19
|
+
const assertFields = (fields) => {
|
|
20
|
+
if (fields === void 0) return;
|
|
21
|
+
if (!record(fields)) throw new TypeError("invalid AI message base fields");
|
|
22
|
+
for (const [key, undo] of Object.entries(fields)) if (!record(undo) || Object.keys(undo).length > 1 || !(Object.keys(undo).length === 0 || "value" in undo || undo["remove"] === true || key === "text" && Number.isSafeInteger(undo["length"]) && undo["length"] >= 0)) throw new TypeError("invalid AI message base field");
|
|
23
|
+
};
|
|
24
|
+
/** Checks decoded recovery data; `restoreMessageBase` trusts this shape. */
|
|
25
|
+
function assertMessageBase(value) {
|
|
26
|
+
if (!record(value) || !Number.isSafeInteger(value["partCount"]) || value["partCount"] < 0 || value["partCount"] > 4294967294 || Object.keys(value).some((key) => ![
|
|
27
|
+
"partCount",
|
|
28
|
+
"fields",
|
|
29
|
+
"parts"
|
|
30
|
+
].includes(key)) || value["parts"] !== void 0 && !record(value["parts"])) throw new TypeError("invalid AI message base");
|
|
31
|
+
assertFields(value["fields"]);
|
|
32
|
+
const partCount = value["partCount"];
|
|
33
|
+
for (const [key, undo] of Object.entries(value["parts"] ?? {})) {
|
|
34
|
+
const index = Number(key);
|
|
35
|
+
if (!Number.isSafeInteger(index) || String(index) !== key || index < 0 || index >= partCount || !record(undo) || Object.keys(undo).length !== 1 || !("value" in undo && record(undo["value"]) || "fields" in undo)) throw new TypeError("invalid AI message base part");
|
|
36
|
+
if ("fields" in undo) assertFields(undo["fields"]);
|
|
104
37
|
}
|
|
105
|
-
items = items.filter((item) => {
|
|
106
|
-
if (item.afterStepOf === void 0) return true;
|
|
107
|
-
show(item.message);
|
|
108
|
-
return false;
|
|
109
|
-
});
|
|
110
|
-
return {
|
|
111
|
-
...state,
|
|
112
|
-
messages,
|
|
113
|
-
inbox: {
|
|
114
|
-
items,
|
|
115
|
-
paused
|
|
116
|
-
},
|
|
117
|
-
starting: starting && !suspended
|
|
118
|
-
};
|
|
119
38
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
const
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
changes.push({
|
|
147
|
-
path,
|
|
148
|
-
value: right
|
|
149
|
-
});
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
for (const key of Object.keys(left)) if (!Object.hasOwn(right, key)) changes.push({
|
|
153
|
-
path: [...path, key],
|
|
154
|
-
remove: true
|
|
155
|
-
});
|
|
156
|
-
for (const key of Object.keys(right)) visit(Object.hasOwn(left, key) ? left[key] : void 0, right[key], [...path, key]);
|
|
157
|
-
return;
|
|
39
|
+
const restoreFields = (current, fields) => {
|
|
40
|
+
if (fields === void 0) return current;
|
|
41
|
+
const restored = { ...current };
|
|
42
|
+
for (const [key, undo] of Object.entries(fields)) if ("remove" in undo) delete restored[key];
|
|
43
|
+
else if ("length" in undo) {
|
|
44
|
+
const text = current[key];
|
|
45
|
+
if (typeof text !== "string" || undo.length > text.length) return void 0;
|
|
46
|
+
restored[key] = text.slice(0, undo.length);
|
|
47
|
+
} else Object.defineProperty(restored, key, {
|
|
48
|
+
value: undo.value,
|
|
49
|
+
enumerable: true,
|
|
50
|
+
writable: true,
|
|
51
|
+
configurable: true
|
|
52
|
+
});
|
|
53
|
+
return restored;
|
|
54
|
+
};
|
|
55
|
+
/** `undefined` when `base` no longer describes `current`, including a removed message. */
|
|
56
|
+
const restoreMessageBase = (options) => {
|
|
57
|
+
const { current, base } = options;
|
|
58
|
+
if (base === void 0 || current === void 0) return void 0;
|
|
59
|
+
const parts = current.parts.slice(0, base.partCount);
|
|
60
|
+
for (const [key, undo] of Object.entries(base.parts ?? {})) {
|
|
61
|
+
const index = Number(key);
|
|
62
|
+
if ("value" in undo) {
|
|
63
|
+
parts[index] = undo.value;
|
|
64
|
+
continue;
|
|
158
65
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
66
|
+
const part = parts[index];
|
|
67
|
+
const restored = part === void 0 ? void 0 : restoreFields(part, undo.fields);
|
|
68
|
+
if (!restored) return void 0;
|
|
69
|
+
parts[index] = restored;
|
|
70
|
+
}
|
|
71
|
+
if (parts.length !== base.partCount || Object.keys(parts).length !== parts.length) return void 0;
|
|
72
|
+
const { parts: _parts, ...fields } = current;
|
|
73
|
+
const restored = restoreFields(fields, base.fields);
|
|
74
|
+
return restored && {
|
|
75
|
+
...restored,
|
|
76
|
+
parts
|
|
163
77
|
};
|
|
164
|
-
visit(before, after, []);
|
|
165
|
-
return changes;
|
|
166
78
|
};
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
if (
|
|
173
|
-
|
|
79
|
+
const updateFields = (options) => {
|
|
80
|
+
const { before, after, undo } = options;
|
|
81
|
+
const original = restoreFields(before, undo);
|
|
82
|
+
if (!original) return void 0;
|
|
83
|
+
return Object.fromEntries([.../* @__PURE__ */ new Set([...Object.keys(original), ...Object.keys(after)])].flatMap((key) => {
|
|
84
|
+
if (Object.hasOwn(original, key) === Object.hasOwn(after, key) && sameValue(original[key], after[key])) return [];
|
|
85
|
+
const value = original[key];
|
|
86
|
+
const next = after[key];
|
|
87
|
+
return [[key, !Object.hasOwn(original, key) ? { remove: true } : key === "text" && typeof value === "string" && typeof next === "string" && next.startsWith(value) ? { length: value.length } : value === void 0 ? {} : { value }]];
|
|
88
|
+
}));
|
|
89
|
+
};
|
|
90
|
+
/** `undefined` when `before` no longer matches `base`, so the recovery must be dropped. */
|
|
91
|
+
const updateMessageBase = (options) => {
|
|
92
|
+
const { base, before, after } = options;
|
|
93
|
+
if (before === after) return base;
|
|
94
|
+
const { parts: beforeParts, ...beforeFields } = before;
|
|
95
|
+
const { parts: afterParts, ...afterFields } = after;
|
|
96
|
+
const fields = updateFields({
|
|
97
|
+
before: beforeFields,
|
|
98
|
+
after: afterFields,
|
|
99
|
+
...base.fields && { undo: base.fields }
|
|
100
|
+
});
|
|
101
|
+
if (!fields) return void 0;
|
|
102
|
+
const parts = [];
|
|
103
|
+
for (let index = 0; index < base.partCount; index += 1) {
|
|
104
|
+
const previous = beforeParts[index];
|
|
105
|
+
const current = afterParts[index];
|
|
106
|
+
const undo = base.parts?.[index];
|
|
107
|
+
const original = undo && "value" in undo ? undo.value : previous;
|
|
108
|
+
if (!original) return void 0;
|
|
109
|
+
if (previous === current && undo === void 0) continue;
|
|
110
|
+
const originalFields = original;
|
|
111
|
+
const undoFields = undo && "fields" in undo ? undo.fields : void 0;
|
|
112
|
+
if (!current) {
|
|
113
|
+
const value = restoreFields(originalFields, undoFields);
|
|
114
|
+
if (!value) return void 0;
|
|
115
|
+
parts.push([String(index), { value }]);
|
|
174
116
|
continue;
|
|
175
117
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}
|
|
181
|
-
if (!container(target)) throw new TypeError("Invalid AI control change target");
|
|
182
|
-
const parent = target;
|
|
183
|
-
const key = path.at(-1);
|
|
184
|
-
if (change.remove) delete parent[key];
|
|
185
|
-
else if (change.splice) {
|
|
186
|
-
const items = parent[key];
|
|
187
|
-
Object.defineProperty(parent, key, {
|
|
188
|
-
value: [
|
|
189
|
-
...items.slice(0, change.splice.index),
|
|
190
|
-
...structuredClone(change.splice.items),
|
|
191
|
-
...items.slice(change.splice.index + change.splice.deleteCount)
|
|
192
|
-
],
|
|
193
|
-
enumerable: true,
|
|
194
|
-
configurable: true,
|
|
195
|
-
writable: true
|
|
196
|
-
});
|
|
197
|
-
} else if (change.move) {
|
|
198
|
-
const items = parent[key];
|
|
199
|
-
const [item] = items.splice(change.move.from, 1);
|
|
200
|
-
items.splice(change.move.to, 0, item);
|
|
201
|
-
} else Object.defineProperty(parent, key, {
|
|
202
|
-
value: structuredClone(change.value),
|
|
203
|
-
enumerable: true,
|
|
204
|
-
configurable: true,
|
|
205
|
-
writable: true
|
|
118
|
+
const changed = updateFields({
|
|
119
|
+
before: originalFields,
|
|
120
|
+
after: current,
|
|
121
|
+
...undoFields && { undo: undoFields }
|
|
206
122
|
});
|
|
123
|
+
if (!changed) return void 0;
|
|
124
|
+
if (Object.keys(changed).length > 0) parts.push([String(index), { fields: changed }]);
|
|
207
125
|
}
|
|
208
|
-
return next;
|
|
209
|
-
};
|
|
210
|
-
const controlCommit = (options) => {
|
|
211
|
-
const active = options.after.active;
|
|
212
|
-
const response = options.after.coordinator.response;
|
|
213
126
|
return {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
})],
|
|
218
|
-
view: {
|
|
219
|
-
turnId: active?.turnId ?? null,
|
|
220
|
-
version: active?.version ?? null,
|
|
221
|
-
phase: active?.phase ?? null,
|
|
222
|
-
paused: options.after.inbox.paused,
|
|
223
|
-
closed: options.after.coordinator.closed,
|
|
224
|
-
requestId: response?.activeRequestId ?? null,
|
|
225
|
-
requestReason: response?.requestReason ?? null,
|
|
226
|
-
sourceGenerationId: response?.sourceGenerationId ?? null,
|
|
227
|
-
responseMessageId: response?.responseMessageId ?? null
|
|
228
|
-
}
|
|
127
|
+
partCount: base.partCount,
|
|
128
|
+
...Object.keys(fields).length > 0 && { fields },
|
|
129
|
+
...parts.length > 0 && { parts: Object.fromEntries(parts) }
|
|
229
130
|
};
|
|
230
131
|
};
|
|
231
132
|
//#endregion
|
|
232
|
-
//#region src/ai-control.ts
|
|
233
|
-
const initialControlState = () => ({
|
|
234
|
-
inbox: {
|
|
235
|
-
paused: false,
|
|
236
|
-
items: []
|
|
237
|
-
},
|
|
238
|
-
active: null,
|
|
239
|
-
coordinator: {
|
|
240
|
-
closed: false,
|
|
241
|
-
queued: []
|
|
242
|
-
}
|
|
243
|
-
});
|
|
244
|
-
//#endregion
|
|
245
|
-
//#region src/ai-id.ts
|
|
246
|
-
const AI_EVENT_ID_PREFIX = "a2.ai:";
|
|
247
|
-
const aiEventId = async (...parts) => `${AI_EVENT_ID_PREFIX}${await idempotentId(...parts)}`;
|
|
248
|
-
//#endregion
|
|
249
133
|
//#region src/parse-partial-json.ts
|
|
250
134
|
/*!
|
|
251
135
|
* Adapted from AI SDK 7.0.58, packages/ai/src/util/fix-json.ts.
|
|
@@ -527,7 +411,13 @@ const cloneMessage = (messageId, base) => base === void 0 ? {
|
|
|
527
411
|
} : {
|
|
528
412
|
...base,
|
|
529
413
|
id: messageId,
|
|
530
|
-
parts: base.parts
|
|
414
|
+
parts: [...base.parts]
|
|
415
|
+
};
|
|
416
|
+
const editPart = ({ parts, part }) => {
|
|
417
|
+
const index = parts.indexOf(part);
|
|
418
|
+
const next = { ...part };
|
|
419
|
+
parts[index] = next;
|
|
420
|
+
return next;
|
|
531
421
|
};
|
|
532
422
|
const currentStepParts = (parts) => {
|
|
533
423
|
let start = parts.length - 1;
|
|
@@ -540,6 +430,10 @@ const findToolPart = (parts, toolCallId) => {
|
|
|
540
430
|
if (current) return current;
|
|
541
431
|
return parts.findLast((part) => isToolPart(part) && part["toolCallId"] === toolCallId);
|
|
542
432
|
};
|
|
433
|
+
const hasToolCall = ({ message, call }) => {
|
|
434
|
+
const part = findToolPart(message.parts, call.toolCallId);
|
|
435
|
+
return part !== void 0 && part["state"] !== "input-streaming" && sameValue(part["input"], call.input) && (part["callProviderMetadata"] !== void 0 || call.providerMetadata === void 0) && (part["toolMetadata"] !== void 0 || call.toolMetadata === void 0) && (call.providerExecuted === void 0 || part["providerExecuted"] === call.providerExecuted) && (call.title === void 0 || part["title"] === call.title);
|
|
436
|
+
};
|
|
543
437
|
const findApprovalPart = (parts, approvalId) => parts.find((part) => {
|
|
544
438
|
const approval = part["approval"];
|
|
545
439
|
return isToolPart(part) && isRecord$3(approval) && approval["id"] === approvalId;
|
|
@@ -556,7 +450,10 @@ const setToolPart = (options) => {
|
|
|
556
450
|
toolCallId: options.toolCallId
|
|
557
451
|
};
|
|
558
452
|
options.parts.push(part);
|
|
559
|
-
}
|
|
453
|
+
} else part = editPart({
|
|
454
|
+
parts: options.parts,
|
|
455
|
+
part
|
|
456
|
+
});
|
|
560
457
|
part["state"] = options.state;
|
|
561
458
|
part["input"] = options.input;
|
|
562
459
|
delete part["output"];
|
|
@@ -614,13 +511,22 @@ function projectUIMessageStream(options) {
|
|
|
614
511
|
activeText.set(chunk.id, part);
|
|
615
512
|
parts.push(part);
|
|
616
513
|
}
|
|
514
|
+
part = editPart({
|
|
515
|
+
parts,
|
|
516
|
+
part
|
|
517
|
+
});
|
|
518
|
+
activeText.set(chunk.id, part);
|
|
617
519
|
part["text"] = `${typeof part["text"] === "string" ? part["text"] : ""}${chunk.delta}`;
|
|
618
520
|
setOptional(part, "providerMetadata", chunk.providerMetadata);
|
|
619
521
|
break;
|
|
620
522
|
}
|
|
621
523
|
case "text-end": {
|
|
622
|
-
const
|
|
623
|
-
if (
|
|
524
|
+
const current = activeText.get(chunk.id);
|
|
525
|
+
if (current) {
|
|
526
|
+
const part = editPart({
|
|
527
|
+
parts,
|
|
528
|
+
part: current
|
|
529
|
+
});
|
|
624
530
|
part["state"] = "done";
|
|
625
531
|
setOptional(part, "providerMetadata", chunk.providerMetadata);
|
|
626
532
|
activeText.delete(chunk.id);
|
|
@@ -649,13 +555,22 @@ function projectUIMessageStream(options) {
|
|
|
649
555
|
activeReasoning.set(chunk.id, part);
|
|
650
556
|
parts.push(part);
|
|
651
557
|
}
|
|
652
|
-
part
|
|
558
|
+
part = editPart({
|
|
559
|
+
parts,
|
|
560
|
+
part
|
|
561
|
+
});
|
|
562
|
+
activeReasoning.set(chunk.id, part);
|
|
563
|
+
part["text"] = `${typeof part["text"] === "string" ? part["text"] : ""}${chunk.delta}`;
|
|
653
564
|
setOptional(part, "providerMetadata", chunk.providerMetadata);
|
|
654
565
|
break;
|
|
655
566
|
}
|
|
656
567
|
case "reasoning-end": {
|
|
657
|
-
const
|
|
658
|
-
if (
|
|
568
|
+
const current = activeReasoning.get(chunk.id);
|
|
569
|
+
if (current) {
|
|
570
|
+
const part = editPart({
|
|
571
|
+
parts,
|
|
572
|
+
part: current
|
|
573
|
+
});
|
|
659
574
|
part["state"] = "done";
|
|
660
575
|
setOptional(part, "providerMetadata", chunk.providerMetadata);
|
|
661
576
|
activeReasoning.delete(chunk.id);
|
|
@@ -737,6 +652,35 @@ function projectUIMessageStream(options) {
|
|
|
737
652
|
});
|
|
738
653
|
break;
|
|
739
654
|
}
|
|
655
|
+
case "a2-tool-called": {
|
|
656
|
+
const call = chunk.call;
|
|
657
|
+
const current = findToolPart(parts, call.toolCallId);
|
|
658
|
+
if (current) {
|
|
659
|
+
const existing = editPart({
|
|
660
|
+
parts,
|
|
661
|
+
part: current
|
|
662
|
+
});
|
|
663
|
+
existing["input"] = call.input;
|
|
664
|
+
if (existing["state"] === "input-streaming") existing["state"] = "input-available";
|
|
665
|
+
if (existing["callProviderMetadata"] === void 0) setOptional(existing, "callProviderMetadata", call.providerMetadata);
|
|
666
|
+
if (existing["toolMetadata"] === void 0) setOptional(existing, "toolMetadata", call.toolMetadata);
|
|
667
|
+
setOptional(existing, "providerExecuted", call.providerExecuted);
|
|
668
|
+
setOptional(existing, "title", call.title);
|
|
669
|
+
} else setToolPart({
|
|
670
|
+
parts,
|
|
671
|
+
toolCallId: call.toolCallId,
|
|
672
|
+
toolName: call.toolName,
|
|
673
|
+
dynamic: call.dynamic === true,
|
|
674
|
+
state: "input-available",
|
|
675
|
+
input: call.input,
|
|
676
|
+
providerExecuted: call.providerExecuted,
|
|
677
|
+
providerMetadata: call.providerMetadata,
|
|
678
|
+
toolMetadata: call.toolMetadata,
|
|
679
|
+
title: call.title
|
|
680
|
+
});
|
|
681
|
+
partialTools.delete(call.toolCallId);
|
|
682
|
+
break;
|
|
683
|
+
}
|
|
740
684
|
case "tool-input-available":
|
|
741
685
|
setToolPart({
|
|
742
686
|
parts,
|
|
@@ -772,8 +716,12 @@ function projectUIMessageStream(options) {
|
|
|
772
716
|
break;
|
|
773
717
|
}
|
|
774
718
|
case "tool-approval-request": {
|
|
775
|
-
const
|
|
776
|
-
if (!
|
|
719
|
+
const current = findToolPart(parts, chunk.toolCallId);
|
|
720
|
+
if (!current) break;
|
|
721
|
+
const part = editPart({
|
|
722
|
+
parts,
|
|
723
|
+
part: current
|
|
724
|
+
});
|
|
777
725
|
part["state"] = "approval-requested";
|
|
778
726
|
part["approval"] = {
|
|
779
727
|
id: chunk.approvalId,
|
|
@@ -783,8 +731,12 @@ function projectUIMessageStream(options) {
|
|
|
783
731
|
break;
|
|
784
732
|
}
|
|
785
733
|
case "tool-approval-response": {
|
|
786
|
-
const
|
|
787
|
-
if (!
|
|
734
|
+
const current = findApprovalPart(parts, chunk.approvalId);
|
|
735
|
+
if (!current) break;
|
|
736
|
+
const part = editPart({
|
|
737
|
+
parts,
|
|
738
|
+
part: current
|
|
739
|
+
});
|
|
788
740
|
const approval = isRecord$3(part["approval"]) ? part["approval"] : {};
|
|
789
741
|
part["state"] = "approval-responded";
|
|
790
742
|
part["approval"] = {
|
|
@@ -838,7 +790,10 @@ function projectUIMessageStream(options) {
|
|
|
838
790
|
}
|
|
839
791
|
case "tool-output-denied": {
|
|
840
792
|
const part = findToolPart(parts, chunk.toolCallId);
|
|
841
|
-
if (part)
|
|
793
|
+
if (part) editPart({
|
|
794
|
+
parts,
|
|
795
|
+
part
|
|
796
|
+
})["state"] = "output-denied";
|
|
842
797
|
break;
|
|
843
798
|
}
|
|
844
799
|
case "start-step":
|
|
@@ -862,7 +817,10 @@ function projectUIMessageStream(options) {
|
|
|
862
817
|
default: {
|
|
863
818
|
if (!chunk.type.startsWith("data-") || chunk.transient) break;
|
|
864
819
|
const existing = chunk.id === void 0 ? void 0 : parts.find((part) => part["type"] === chunk.type && part["id"] === chunk.id);
|
|
865
|
-
if (existing)
|
|
820
|
+
if (existing) editPart({
|
|
821
|
+
parts,
|
|
822
|
+
part: existing
|
|
823
|
+
})["data"] = chunk.data;
|
|
866
824
|
else parts.push({
|
|
867
825
|
type: chunk.type,
|
|
868
826
|
...chunk.id === void 0 ? {} : { id: chunk.id },
|
|
@@ -923,6 +881,7 @@ function interruptUIMessage(message, toolError = "Tool execution was interrupted
|
|
|
923
881
|
}
|
|
924
882
|
//#endregion
|
|
925
883
|
//#region src/ai-progress-batches.ts
|
|
884
|
+
const progressOwnedBy = ({ payload, owner, startIndex }) => "startIndex" in payload ? payload.startIndex === startIndex : payload.requestId === owner.requestId && payload.generationId === owner.generationId && payload.responseMessageId === owner.responseMessageId;
|
|
926
885
|
const PAGE_SIZE = 64;
|
|
927
886
|
const appendProgressBatch = ({ batches, batch }) => {
|
|
928
887
|
if (batches.tail.length < PAGE_SIZE) return {
|
|
@@ -981,22 +940,22 @@ const flattenProgressBatches = (batches) => {
|
|
|
981
940
|
//#endregion
|
|
982
941
|
//#region src/ai-message-projection.ts
|
|
983
942
|
const isRecord$2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
943
|
+
const positionOf = (messages, id) => messages.findLastIndex((message) => message.id === id);
|
|
944
|
+
const findMessage = (messages, id) => messages.findLast((message) => message.id === id);
|
|
984
945
|
const upsertMessage = (messages, message) => {
|
|
985
|
-
const index = messages
|
|
946
|
+
const index = positionOf(messages, message.id);
|
|
986
947
|
if (index === -1) return [...messages, message];
|
|
987
|
-
|
|
988
|
-
next[index] = message;
|
|
989
|
-
return next;
|
|
948
|
+
return messages[index] === message ? messages : messages.with(index, message);
|
|
990
949
|
};
|
|
991
950
|
const upsertResponse = (options) => {
|
|
992
951
|
const { messages, message, inputId } = options;
|
|
993
|
-
if (messages
|
|
994
|
-
const inputIndex = messages
|
|
995
|
-
|
|
952
|
+
if (positionOf(messages, message.id) !== -1) return upsertMessage(messages, message);
|
|
953
|
+
const inputIndex = positionOf(messages, inputId);
|
|
954
|
+
const position = inputIndex === -1 ? messages.length : inputIndex + 1;
|
|
996
955
|
return [
|
|
997
|
-
...messages.slice(0,
|
|
956
|
+
...messages.slice(0, position),
|
|
998
957
|
message,
|
|
999
|
-
...messages.slice(
|
|
958
|
+
...messages.slice(position)
|
|
1000
959
|
];
|
|
1001
960
|
};
|
|
1002
961
|
const answerApproval = (messages, response) => messages.map((message) => {
|
|
@@ -1034,6 +993,10 @@ const approvalRespondedChunk = (payload) => ({
|
|
|
1034
993
|
approved: payload.approved,
|
|
1035
994
|
...payload.reason === void 0 ? {} : { reason: payload.reason }
|
|
1036
995
|
});
|
|
996
|
+
const toolCalledChunk = (payload) => ({
|
|
997
|
+
type: "a2-tool-called",
|
|
998
|
+
call: payload
|
|
999
|
+
});
|
|
1037
1000
|
const toolResultChunk = (payload) => {
|
|
1038
1001
|
if (payload.phase === "input") return {
|
|
1039
1002
|
type: "tool-input-error",
|
|
@@ -1070,97 +1033,525 @@ const toolResultChunk = (payload) => {
|
|
|
1070
1033
|
...payload.toolMetadata === void 0 ? {} : { toolMetadata: payload.toolMetadata }
|
|
1071
1034
|
};
|
|
1072
1035
|
};
|
|
1073
|
-
const projectedMessageStream = (projection) => {
|
|
1074
|
-
const
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
for (const event of projection.
|
|
1080
|
-
index: event.index,
|
|
1081
|
-
chunks: [event.type === "ai.
|
|
1082
|
-
});
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1036
|
+
const projectedMessageStream = ({ projection, current }) => {
|
|
1037
|
+
const base = restoreMessageBase({
|
|
1038
|
+
current,
|
|
1039
|
+
base: projection.base
|
|
1040
|
+
});
|
|
1041
|
+
const projectionEvents = flattenProgressBatches(projection.batches);
|
|
1042
|
+
for (const event of projection.toolEvents) projectionEvents.push({
|
|
1043
|
+
index: event.index,
|
|
1044
|
+
chunks: [event.type === "ai.tool.called" ? toolCalledChunk(event.payload) : toolResultChunk(event.payload)]
|
|
1045
|
+
});
|
|
1046
|
+
for (const event of projection.approvalEvents) projectionEvents.push({
|
|
1047
|
+
index: event.index,
|
|
1048
|
+
chunks: [event.type === "ai.approval.requested" ? approvalRequestedChunk(event.payload) : approvalRespondedChunk(event.payload)]
|
|
1049
|
+
});
|
|
1050
|
+
const ordered = projectionEvents.toSorted((left, right) => left.index - right.index);
|
|
1051
|
+
return {
|
|
1052
|
+
...projectUIMessageStream({
|
|
1053
|
+
messageId: projection.responseMessageId,
|
|
1054
|
+
...base === void 0 ? {} : { base },
|
|
1055
|
+
chunks: ordered.flatMap((event) => event.chunks)
|
|
1056
|
+
}),
|
|
1057
|
+
throughIndex: ordered.at(-1)?.index ?? 0
|
|
1058
|
+
};
|
|
1059
|
+
};
|
|
1060
|
+
const projectedMessage = (options) => projectedMessageStream(options).message;
|
|
1061
|
+
const reduceToolActivity = (tools, event) => {
|
|
1062
|
+
if (event.type === "ai.tool.called") {
|
|
1063
|
+
const payload = event.payload;
|
|
1064
|
+
const activity = {
|
|
1065
|
+
requestId: payload.requestId,
|
|
1066
|
+
messageId: payload.messageId,
|
|
1067
|
+
generationId: payload.generationId,
|
|
1068
|
+
toolCallId: payload.toolCallId,
|
|
1069
|
+
toolName: payload.toolName,
|
|
1070
|
+
...payload.dynamic === void 0 ? {} : { dynamic: payload.dynamic },
|
|
1071
|
+
...payload.providerExecuted === void 0 ? {} : { providerExecuted: payload.providerExecuted },
|
|
1072
|
+
...payload.title === void 0 ? {} : { title: payload.title },
|
|
1073
|
+
status: "running"
|
|
1074
|
+
};
|
|
1075
|
+
return [...tools.filter((candidate) => candidate.generationId !== payload.generationId || candidate.toolCallId !== payload.toolCallId), activity];
|
|
1076
|
+
}
|
|
1077
|
+
const payload = event.payload;
|
|
1078
|
+
const existing = tools.find((candidate) => candidate.generationId === payload.generationId && candidate.toolCallId === payload.toolCallId);
|
|
1079
|
+
const toolName = payload.toolName ?? existing?.toolName;
|
|
1080
|
+
const dynamic = payload.dynamic ?? existing?.dynamic;
|
|
1081
|
+
const providerExecuted = payload.providerExecuted ?? existing?.providerExecuted;
|
|
1082
|
+
const activity = {
|
|
1083
|
+
requestId: payload.requestId,
|
|
1084
|
+
messageId: payload.messageId,
|
|
1085
|
+
generationId: payload.generationId,
|
|
1086
|
+
toolCallId: payload.toolCallId,
|
|
1087
|
+
...toolName === void 0 ? {} : { toolName },
|
|
1088
|
+
...payload.error === void 0 ? {} : { error: payload.error },
|
|
1089
|
+
...payload.preliminary === void 0 ? {} : { preliminary: payload.preliminary },
|
|
1090
|
+
...payload.phase === void 0 ? {} : { phase: payload.phase },
|
|
1091
|
+
...dynamic === void 0 ? {} : { dynamic },
|
|
1092
|
+
...providerExecuted === void 0 ? {} : { providerExecuted },
|
|
1093
|
+
...existing?.title === void 0 ? {} : { title: existing.title },
|
|
1094
|
+
status: payload.denied ? "denied" : payload.error ? "failed" : payload.preliminary ? "running" : "completed"
|
|
1095
|
+
};
|
|
1096
|
+
return [...tools.filter((candidate) => candidate.generationId !== payload.generationId || candidate.toolCallId !== payload.toolCallId), activity];
|
|
1097
|
+
};
|
|
1098
|
+
const advanceProjection = ({ projection, base, chunks, index }) => {
|
|
1099
|
+
const batches = index > (projection.batches.tail.at(-1)?.index ?? -1) ? appendProgressBatch({
|
|
1100
|
+
batches: projection.batches,
|
|
1101
|
+
batch: {
|
|
1102
|
+
index,
|
|
1103
|
+
chunks
|
|
1104
|
+
}
|
|
1105
|
+
}) : progressBatches([...flattenProgressBatches(projection.batches).filter((batch) => batch.index !== index), {
|
|
1106
|
+
index,
|
|
1107
|
+
chunks
|
|
1108
|
+
}].toSorted((left, right) => left.index - right.index));
|
|
1109
|
+
const incremental = base !== void 0 && projection.cursor != null && index > projection.cursor.throughIndex;
|
|
1110
|
+
const projected = incremental ? projectUIMessageStream({
|
|
1111
|
+
messageId: projection.responseMessageId,
|
|
1112
|
+
base,
|
|
1113
|
+
cursor: projection.cursor.stream,
|
|
1114
|
+
chunks
|
|
1115
|
+
}) : projectedMessageStream({
|
|
1116
|
+
projection: {
|
|
1117
|
+
...projection,
|
|
1118
|
+
batches
|
|
1119
|
+
},
|
|
1120
|
+
current: base
|
|
1121
|
+
});
|
|
1122
|
+
return {
|
|
1123
|
+
message: projected.message,
|
|
1124
|
+
batches,
|
|
1125
|
+
cursor: {
|
|
1126
|
+
throughIndex: incremental ? index : Math.max(index, batches.tail.at(-1)?.index ?? 0, projection.toolEvents.reduce((latest, event) => Math.max(latest, event.index), 0), projection.approvalEvents.reduce((latest, event) => Math.max(latest, event.index), 0)),
|
|
1127
|
+
stream: projected.cursor
|
|
1128
|
+
}
|
|
1129
|
+
};
|
|
1130
|
+
};
|
|
1131
|
+
const projectedTools = (projection) => projection.toolEvents.reduce((tools, event) => reduceToolActivity(tools, event), projection.baseTools);
|
|
1132
|
+
const restoreGenerationBase = (state, generationId, responseMessageId, reason) => {
|
|
1133
|
+
const projection = state.activeProjection?.generationId === generationId ? state.activeProjection : null;
|
|
1134
|
+
const restored = restoreMessageBase({
|
|
1135
|
+
current: findMessage(state.messages, responseMessageId),
|
|
1136
|
+
base: projection?.base
|
|
1137
|
+
});
|
|
1138
|
+
const base = restored !== void 0 && reason === "superseded" ? withoutRunningCompactionPart(restored, generationId) : restored;
|
|
1139
|
+
return {
|
|
1140
|
+
...state,
|
|
1141
|
+
messages: base === void 0 ? state.messages.filter((message) => message.id !== responseMessageId) : upsertMessage(state.messages, base),
|
|
1142
|
+
tools: projection === null ? state.tools.filter((activity) => activity.generationId !== generationId) : projection.baseTools,
|
|
1143
|
+
pendingApprovals: state.pendingApprovals.filter((approval) => approval.generationId !== generationId),
|
|
1144
|
+
pendingInputs: state.pendingInputs.filter((input) => input.generationId !== generationId),
|
|
1145
|
+
activeGeneration: null,
|
|
1146
|
+
activeProjection: null,
|
|
1147
|
+
terminalGenerations: {
|
|
1148
|
+
...state.terminalGenerations,
|
|
1149
|
+
[generationId]: reason
|
|
1150
|
+
},
|
|
1151
|
+
compaction: projection === null ? state.compaction?.generationId === generationId ? null : state.compaction : projection.baseCompaction ?? null
|
|
1152
|
+
};
|
|
1153
|
+
};
|
|
1154
|
+
const stopGenerationTools = (tools, generationId, responseMessageId, error) => tools.map((activity) => activity.status === "running" && (generationId === void 0 ? activity.messageId === responseMessageId : activity.generationId === generationId) ? {
|
|
1155
|
+
...activity,
|
|
1156
|
+
status: "failed",
|
|
1157
|
+
error,
|
|
1158
|
+
preliminary: false
|
|
1159
|
+
} : activity);
|
|
1160
|
+
const interruptGenerationProjection = (state, generationId, responseMessageId, cutoff) => {
|
|
1161
|
+
const projection = state.activeProjection?.generationId === generationId ? state.activeProjection : null;
|
|
1162
|
+
if (projection === null) return null;
|
|
1163
|
+
const retained = {
|
|
1164
|
+
...projection,
|
|
1165
|
+
batches: progressBatches(flattenProgressBatches(projection.batches).filter((batch) => batch.index <= cutoff)),
|
|
1166
|
+
toolEvents: projection.toolEvents.filter((toolEvent) => toolEvent.index <= cutoff),
|
|
1167
|
+
approvalEvents: projection.approvalEvents.filter((approvalEvent) => approvalEvent.index <= cutoff)
|
|
1168
|
+
};
|
|
1169
|
+
const shouldProject = retained.base !== void 0 || retained.batches.length > 0;
|
|
1170
|
+
const restored = restoreGenerationBase(state, generationId, responseMessageId, "interrupted");
|
|
1171
|
+
return {
|
|
1172
|
+
...restored,
|
|
1173
|
+
messages: shouldProject ? upsertMessage(state.messages, interruptUIMessage(projectedMessage({
|
|
1174
|
+
projection: retained,
|
|
1175
|
+
current: findMessage(state.messages, responseMessageId)
|
|
1176
|
+
}))) : restored.messages,
|
|
1177
|
+
tools: stopGenerationTools(projectedTools(retained), generationId, responseMessageId, "Tool execution was interrupted."),
|
|
1178
|
+
usage: projection.completionIndex === void 0 || projection.completionIndex <= cutoff ? restored.usage : restored.usage.filter((entry) => entry.generationId !== generationId)
|
|
1179
|
+
};
|
|
1180
|
+
};
|
|
1181
|
+
const retainMessageBase = (options) => {
|
|
1182
|
+
const { before, after } = options;
|
|
1183
|
+
const projection = after.activeProjection;
|
|
1184
|
+
if (before.messages === after.messages || !projection?.base || projection.base !== before.activeProjection?.base) return after;
|
|
1185
|
+
const previous = findMessage(before.messages, projection.responseMessageId);
|
|
1186
|
+
const current = findMessage(after.messages, projection.responseMessageId);
|
|
1187
|
+
if (previous !== void 0 && previous === current) return after;
|
|
1188
|
+
const base = previous && current && updateMessageBase({
|
|
1189
|
+
base: projection.base,
|
|
1190
|
+
before: previous,
|
|
1191
|
+
after: current
|
|
1192
|
+
});
|
|
1193
|
+
const { base: _stale, ...unrecoverable } = projection;
|
|
1194
|
+
return {
|
|
1195
|
+
...after,
|
|
1196
|
+
activeProjection: base ? {
|
|
1197
|
+
...unrecoverable,
|
|
1198
|
+
base
|
|
1199
|
+
} : unrecoverable
|
|
1200
|
+
};
|
|
1201
|
+
};
|
|
1202
|
+
const isCompactionPart = (part) => part.type === "data-a2-compaction";
|
|
1203
|
+
const compactionPartOf = (message, generationId) => message.parts.findIndex((part) => isCompactionPart(part) && part.id === generationId);
|
|
1204
|
+
const withoutRunningCompactionPart = (message, generationId) => {
|
|
1205
|
+
const index = compactionPartOf(message, generationId);
|
|
1206
|
+
const part = message.parts[index];
|
|
1207
|
+
return part !== void 0 && isCompactionPart(part) && part.data.status === "running" ? {
|
|
1208
|
+
...message,
|
|
1209
|
+
parts: message.parts.toSpliced(index, 1)
|
|
1210
|
+
} : message;
|
|
1211
|
+
};
|
|
1212
|
+
/**
|
|
1213
|
+
* Compaction runs before its model step streams, so the part lands between
|
|
1214
|
+
* the response's earlier steps and this one. Counting it in the step's base
|
|
1215
|
+
* keeps it through Stop cutoffs, failures, and retries of that step.
|
|
1216
|
+
*/
|
|
1217
|
+
const addCompactionPart = (state, payload) => {
|
|
1218
|
+
const projection = state.activeProjection;
|
|
1219
|
+
if (projection?.generationId !== payload.generationId) return state;
|
|
1220
|
+
const current = findMessage(state.messages, projection.responseMessageId);
|
|
1221
|
+
if (current === void 0 ? projection.base !== void 0 : projection.base?.partCount !== current.parts.length) return state;
|
|
1222
|
+
const inputTokens = payload.inputTokens ?? payload.inputTokenEstimate;
|
|
1223
|
+
const part = {
|
|
1224
|
+
type: "data-a2-compaction",
|
|
1225
|
+
id: payload.generationId,
|
|
1226
|
+
data: {
|
|
1227
|
+
status: "running",
|
|
1228
|
+
...inputTokens === void 0 ? {} : { inputTokens },
|
|
1229
|
+
...payload.thresholdTokens === void 0 ? {} : { thresholdTokens: payload.thresholdTokens }
|
|
1230
|
+
}
|
|
1231
|
+
};
|
|
1232
|
+
const message = current === void 0 ? {
|
|
1233
|
+
id: projection.responseMessageId,
|
|
1234
|
+
role: "assistant",
|
|
1235
|
+
parts: [part]
|
|
1236
|
+
} : {
|
|
1237
|
+
...current,
|
|
1238
|
+
parts: [...current.parts, part]
|
|
1239
|
+
};
|
|
1240
|
+
return {
|
|
1241
|
+
...state,
|
|
1242
|
+
messages: upsertResponse({
|
|
1243
|
+
messages: state.messages,
|
|
1244
|
+
message,
|
|
1245
|
+
inputId: state.activeGeneration?.messageId ?? message.id
|
|
1246
|
+
}),
|
|
1247
|
+
activeProjection: {
|
|
1248
|
+
...projection,
|
|
1249
|
+
cursor: null,
|
|
1250
|
+
base: projection.base === void 0 ? { partCount: 1 } : {
|
|
1251
|
+
...projection.base,
|
|
1252
|
+
partCount: projection.base.partCount + 1
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
};
|
|
1256
|
+
};
|
|
1257
|
+
const settleCompactionPart = (options) => {
|
|
1258
|
+
const { state, generationId, data } = options;
|
|
1259
|
+
const position = state.messages.findLastIndex((message) => compactionPartOf(message, generationId) !== -1);
|
|
1260
|
+
if (position === -1) return state;
|
|
1261
|
+
const message = state.messages[position];
|
|
1262
|
+
const index = compactionPartOf(message, generationId);
|
|
1263
|
+
const part = message.parts[index];
|
|
1264
|
+
return {
|
|
1265
|
+
...state,
|
|
1266
|
+
messages: state.messages.with(position, {
|
|
1267
|
+
...message,
|
|
1268
|
+
parts: message.parts.with(index, {
|
|
1269
|
+
...part,
|
|
1270
|
+
data: {
|
|
1271
|
+
...part.data,
|
|
1272
|
+
...data
|
|
1273
|
+
}
|
|
1274
|
+
})
|
|
1275
|
+
})
|
|
1276
|
+
};
|
|
1277
|
+
};
|
|
1278
|
+
/** A running compaction whose state reverted without completing was abandoned. */
|
|
1279
|
+
const settleAbandonedCompaction = (before, after) => {
|
|
1280
|
+
const running = before.compaction;
|
|
1281
|
+
if (running?.status !== "running" || after.compaction === running || after.compaction?.status === "completed" && after.compaction.generationId === running.generationId) return after;
|
|
1282
|
+
const interrupted = after.status === "closed" || after.pausedGenerationIds?.[running.generationId] === true || after.terminalGenerations?.[running.generationId] === "interrupted";
|
|
1283
|
+
return settleCompactionPart({
|
|
1284
|
+
state: after,
|
|
1285
|
+
generationId: running.generationId,
|
|
1286
|
+
data: { status: interrupted ? "interrupted" : "failed" }
|
|
1287
|
+
});
|
|
1288
|
+
};
|
|
1289
|
+
//#endregion
|
|
1290
|
+
//#region src/ai-client-state.ts
|
|
1291
|
+
const isQueueCommand = (command) => command.action === "send" || command.action === "edit" || command.action === "move" || command.action === "remove" || command.action === "send-now" || command.action === "steer" || command.action === "pause" || command.action === "resume" || command.action === "stop";
|
|
1292
|
+
const moveItem = ({ items, inputId, beforeId }) => {
|
|
1293
|
+
const from = items.findIndex((item) => item.id === inputId);
|
|
1294
|
+
if (from < 0 || inputId === beforeId || beforeId !== null && !items.some((item) => item.id === beforeId)) return items;
|
|
1295
|
+
const next = [...items];
|
|
1296
|
+
const [item] = next.splice(from, 1);
|
|
1297
|
+
const to = beforeId === null ? next.length : next.findIndex((entry) => entry.id === beforeId);
|
|
1298
|
+
next.splice(to, 0, item);
|
|
1299
|
+
return next;
|
|
1300
|
+
};
|
|
1301
|
+
function projectAIClientState(state) {
|
|
1302
|
+
const pending = state.pendingQueueCommands ?? [];
|
|
1303
|
+
if (state.status === "closed") return state;
|
|
1304
|
+
if (pending.length === 0 && !state.inbox.items.some((item) => item.afterStepOf !== void 0)) return state;
|
|
1305
|
+
let messages = state.messages;
|
|
1306
|
+
let { items, paused } = state.inbox;
|
|
1307
|
+
let turnId = state.active?.turnId ?? null;
|
|
1308
|
+
let starting = false;
|
|
1309
|
+
let suspended = state.active?.phase === "paused" || state.active?.phase === "pausing";
|
|
1310
|
+
let messageIds;
|
|
1311
|
+
const show = (message) => {
|
|
1312
|
+
messageIds ??= new Set(messages.map((item) => item.id));
|
|
1313
|
+
if (messageIds.has(message.id)) return;
|
|
1314
|
+
if (messages === state.messages) messages = state.messages.slice();
|
|
1315
|
+
messages.push(message);
|
|
1316
|
+
messageIds.add(message.id);
|
|
1317
|
+
};
|
|
1318
|
+
const admit = () => {
|
|
1319
|
+
if (turnId !== null || paused || items.length === 0) return;
|
|
1320
|
+
let count = 0;
|
|
1321
|
+
for (const item of items) {
|
|
1322
|
+
count += 1;
|
|
1323
|
+
show(item.message);
|
|
1324
|
+
if (item.generate) {
|
|
1325
|
+
turnId = item.id;
|
|
1326
|
+
starting = true;
|
|
1327
|
+
suspended = false;
|
|
1328
|
+
break;
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
if (count > 0) items = items.slice(count);
|
|
1332
|
+
};
|
|
1333
|
+
for (const { command } of pending) {
|
|
1334
|
+
switch (command.action) {
|
|
1335
|
+
case "send":
|
|
1336
|
+
case "steer": {
|
|
1337
|
+
if (items.some((item) => item.id === command.message.id) || turnId === command.message.id) break;
|
|
1338
|
+
const item = {
|
|
1339
|
+
...command.action === "steer" ? { afterStepOf: command.turnId } : {},
|
|
1340
|
+
id: command.message.id,
|
|
1341
|
+
message: command.message,
|
|
1342
|
+
generate: command.message.role === "user" && (command.action === "steer" || command.generate !== false)
|
|
1343
|
+
};
|
|
1344
|
+
items = command.action === "steer" ? [item, ...items] : [...items, item];
|
|
1345
|
+
break;
|
|
1346
|
+
}
|
|
1347
|
+
case "edit":
|
|
1348
|
+
items = items.map((item) => item.id === command.message.id && item.message.role === command.message.role ? {
|
|
1349
|
+
...item,
|
|
1350
|
+
message: command.message
|
|
1351
|
+
} : item);
|
|
1352
|
+
break;
|
|
1353
|
+
case "move":
|
|
1354
|
+
items = moveItem({
|
|
1355
|
+
items,
|
|
1356
|
+
inputId: command.inputId,
|
|
1357
|
+
beforeId: command.beforeId
|
|
1358
|
+
});
|
|
1359
|
+
break;
|
|
1360
|
+
case "remove":
|
|
1361
|
+
items = items.filter((item) => item.id !== command.inputId);
|
|
1362
|
+
break;
|
|
1363
|
+
case "send-now": {
|
|
1364
|
+
if (turnId !== command.turnId) break;
|
|
1365
|
+
const selected = items.find((item) => item.id === command.inputId);
|
|
1366
|
+
if (!selected || selected.message.role !== "user") break;
|
|
1367
|
+
items = items.map((item) => item.id === selected.id ? {
|
|
1368
|
+
...item,
|
|
1369
|
+
generate: true,
|
|
1370
|
+
...turnId === null ? {} : { afterStepOf: turnId }
|
|
1371
|
+
} : item);
|
|
1372
|
+
items = moveItem({
|
|
1373
|
+
items,
|
|
1374
|
+
inputId: command.inputId,
|
|
1375
|
+
beforeId: items[0]?.id ?? null
|
|
1376
|
+
});
|
|
1377
|
+
break;
|
|
1378
|
+
}
|
|
1379
|
+
case "pause":
|
|
1380
|
+
paused = true;
|
|
1381
|
+
if (command.when === "now") suspended = true;
|
|
1382
|
+
break;
|
|
1383
|
+
case "resume":
|
|
1384
|
+
paused = false;
|
|
1385
|
+
suspended = false;
|
|
1386
|
+
break;
|
|
1387
|
+
case "stop": continue;
|
|
1388
|
+
}
|
|
1389
|
+
admit();
|
|
1390
|
+
}
|
|
1391
|
+
items = items.filter((item) => {
|
|
1392
|
+
if (item.afterStepOf === void 0) return true;
|
|
1393
|
+
show(item.message);
|
|
1394
|
+
return false;
|
|
1395
|
+
});
|
|
1396
|
+
const displayed = {
|
|
1397
|
+
...state,
|
|
1398
|
+
messages,
|
|
1399
|
+
inbox: {
|
|
1400
|
+
items,
|
|
1401
|
+
paused
|
|
1402
|
+
},
|
|
1403
|
+
starting: starting && !suspended
|
|
1404
|
+
};
|
|
1405
|
+
const stop = pending.find(({ command }) => command.action === "stop" && command.turnId === state.active?.turnId)?.command;
|
|
1406
|
+
if (stop?.action !== "stop") return displayed;
|
|
1407
|
+
const projection = state.activeProjection;
|
|
1408
|
+
const stopped = projection === null ? displayed : interruptGenerationProjection(displayed, projection.generationId, projection.responseMessageId, stop.lastSeenIndex ?? Number.POSITIVE_INFINITY) ?? displayed;
|
|
1409
|
+
return settleAbandonedCompaction(displayed, {
|
|
1410
|
+
...stopped,
|
|
1411
|
+
active: null,
|
|
1412
|
+
status: paused ? "paused" : "idle",
|
|
1413
|
+
starting: false,
|
|
1414
|
+
activeGeneration: null,
|
|
1415
|
+
activeRequestId: null,
|
|
1416
|
+
activeRequestReason: null,
|
|
1417
|
+
activeRequestSourceGenerationId: null,
|
|
1418
|
+
activeResponseMessageId: null,
|
|
1419
|
+
pendingApprovals: [],
|
|
1420
|
+
pendingInputs: [],
|
|
1421
|
+
error: null
|
|
1422
|
+
});
|
|
1423
|
+
}
|
|
1424
|
+
//#endregion
|
|
1425
|
+
//#region src/ai-control-state.ts
|
|
1426
|
+
const container = (value) => typeof value === "object" && value !== null;
|
|
1427
|
+
const same = (left, right) => JSON.stringify(left) === JSON.stringify(right);
|
|
1428
|
+
const controlChanges = ({ before, after }) => {
|
|
1429
|
+
const changes = [];
|
|
1430
|
+
const visit = (left, right, path) => {
|
|
1431
|
+
if (same(left, right)) return;
|
|
1432
|
+
if (Array.isArray(left) && Array.isArray(right)) {
|
|
1433
|
+
let prefix = 0;
|
|
1434
|
+
while (prefix < Math.min(left.length, right.length) && same(left[prefix], right[prefix])) prefix += 1;
|
|
1435
|
+
let suffix = 0;
|
|
1436
|
+
while (suffix < Math.min(left.length, right.length) - prefix && same(left[left.length - 1 - suffix], right[right.length - 1 - suffix])) suffix += 1;
|
|
1437
|
+
if (left.length === right.length) for (let index = prefix; index < left.length - suffix; index += 1) visit(left[index], right[index], [...path, index]);
|
|
1438
|
+
else changes.push({
|
|
1439
|
+
path,
|
|
1440
|
+
splice: {
|
|
1441
|
+
index: prefix,
|
|
1442
|
+
deleteCount: left.length - prefix - suffix,
|
|
1443
|
+
items: right.slice(prefix, right.length - suffix)
|
|
1444
|
+
}
|
|
1445
|
+
});
|
|
1446
|
+
return;
|
|
1447
|
+
}
|
|
1448
|
+
if (container(left) && container(right) && !Array.isArray(left) && !Array.isArray(right)) {
|
|
1449
|
+
if (Object.keys(right).length === 0) {
|
|
1450
|
+
changes.push({
|
|
1451
|
+
path,
|
|
1452
|
+
value: right
|
|
1453
|
+
});
|
|
1454
|
+
return;
|
|
1455
|
+
}
|
|
1456
|
+
for (const key of Object.keys(left)) if (!Object.hasOwn(right, key)) changes.push({
|
|
1457
|
+
path: [...path, key],
|
|
1458
|
+
remove: true
|
|
1459
|
+
});
|
|
1460
|
+
for (const key of Object.keys(right)) visit(Object.hasOwn(left, key) ? left[key] : void 0, right[key], [...path, key]);
|
|
1461
|
+
return;
|
|
1462
|
+
}
|
|
1463
|
+
changes.push({
|
|
1464
|
+
path,
|
|
1465
|
+
value: right
|
|
1466
|
+
});
|
|
1467
|
+
};
|
|
1468
|
+
visit(before, after, []);
|
|
1469
|
+
return changes;
|
|
1470
|
+
};
|
|
1471
|
+
const applyControlChanges = ({ state, changes }) => {
|
|
1472
|
+
if (changes.length === 0) return state;
|
|
1473
|
+
let next = structuredClone(state);
|
|
1474
|
+
for (const change of changes) {
|
|
1475
|
+
const path = change.path;
|
|
1476
|
+
if (path.length === 0) {
|
|
1477
|
+
next = structuredClone(change.value);
|
|
1478
|
+
continue;
|
|
1479
|
+
}
|
|
1480
|
+
let target = next;
|
|
1481
|
+
for (const key of path.slice(0, -1)) {
|
|
1482
|
+
if (!container(target) || !Object.hasOwn(target, key)) throw new TypeError("Invalid AI control change path");
|
|
1483
|
+
target = target[key];
|
|
1484
|
+
}
|
|
1485
|
+
if (!container(target)) throw new TypeError("Invalid AI control change target");
|
|
1486
|
+
const parent = target;
|
|
1487
|
+
const key = path.at(-1);
|
|
1488
|
+
if (change.remove) delete parent[key];
|
|
1489
|
+
else if (change.splice) {
|
|
1490
|
+
const items = parent[key];
|
|
1491
|
+
Object.defineProperty(parent, key, {
|
|
1492
|
+
value: [
|
|
1493
|
+
...items.slice(0, change.splice.index),
|
|
1494
|
+
...structuredClone(change.splice.items),
|
|
1495
|
+
...items.slice(change.splice.index + change.splice.deleteCount)
|
|
1496
|
+
],
|
|
1497
|
+
enumerable: true,
|
|
1498
|
+
configurable: true,
|
|
1499
|
+
writable: true
|
|
1500
|
+
});
|
|
1501
|
+
} else if (change.move) {
|
|
1502
|
+
const items = parent[key];
|
|
1503
|
+
const [item] = items.splice(change.move.from, 1);
|
|
1504
|
+
items.splice(change.move.to, 0, item);
|
|
1505
|
+
} else Object.defineProperty(parent, key, {
|
|
1506
|
+
value: structuredClone(change.value),
|
|
1507
|
+
enumerable: true,
|
|
1508
|
+
configurable: true,
|
|
1509
|
+
writable: true
|
|
1510
|
+
});
|
|
1100
1511
|
}
|
|
1101
|
-
|
|
1102
|
-
const existing = tools.find((candidate) => candidate.generationId === payload.generationId && candidate.toolCallId === payload.toolCallId);
|
|
1103
|
-
const toolName = payload.toolName ?? existing?.toolName;
|
|
1104
|
-
const input = payload.input === void 0 ? existing?.input : payload.input;
|
|
1105
|
-
const dynamic = payload.dynamic ?? existing?.dynamic;
|
|
1106
|
-
const providerExecuted = payload.providerExecuted ?? existing?.providerExecuted;
|
|
1107
|
-
const toolMetadata = payload.toolMetadata ?? existing?.toolMetadata;
|
|
1108
|
-
const resultProviderMetadata = payload.providerMetadata ?? existing?.resultProviderMetadata;
|
|
1109
|
-
const activity = {
|
|
1110
|
-
requestId: payload.requestId,
|
|
1111
|
-
messageId: payload.messageId,
|
|
1112
|
-
generationId: payload.generationId,
|
|
1113
|
-
toolCallId: payload.toolCallId,
|
|
1114
|
-
...toolName === void 0 ? {} : { toolName },
|
|
1115
|
-
...input === void 0 ? {} : { input },
|
|
1116
|
-
...payload.rawInput === void 0 ? {} : { rawInput: payload.rawInput },
|
|
1117
|
-
...payload.output === void 0 ? {} : { output: payload.output },
|
|
1118
|
-
...payload.error === void 0 ? {} : { error: payload.error },
|
|
1119
|
-
...payload.preliminary === void 0 ? {} : { preliminary: payload.preliminary },
|
|
1120
|
-
...payload.phase === void 0 ? {} : { phase: payload.phase },
|
|
1121
|
-
...dynamic === void 0 ? {} : { dynamic },
|
|
1122
|
-
...providerExecuted === void 0 ? {} : { providerExecuted },
|
|
1123
|
-
...existing?.callProviderMetadata === void 0 ? {} : { callProviderMetadata: existing.callProviderMetadata },
|
|
1124
|
-
...resultProviderMetadata === void 0 ? {} : { resultProviderMetadata },
|
|
1125
|
-
...toolMetadata === void 0 ? {} : { toolMetadata },
|
|
1126
|
-
...existing?.title === void 0 ? {} : { title: existing.title },
|
|
1127
|
-
status: payload.denied ? "denied" : payload.error ? "failed" : payload.preliminary ? "running" : "completed"
|
|
1128
|
-
};
|
|
1129
|
-
return [...tools.filter((candidate) => candidate.generationId !== payload.generationId || candidate.toolCallId !== payload.toolCallId), activity];
|
|
1512
|
+
return next;
|
|
1130
1513
|
};
|
|
1131
|
-
const
|
|
1132
|
-
const
|
|
1133
|
-
|
|
1134
|
-
batch: {
|
|
1135
|
-
index,
|
|
1136
|
-
chunks
|
|
1137
|
-
}
|
|
1138
|
-
}) : progressBatches([...flattenProgressBatches(projection.batches).filter((batch) => batch.index !== index), {
|
|
1139
|
-
index,
|
|
1140
|
-
chunks
|
|
1141
|
-
}].toSorted((left, right) => left.index - right.index));
|
|
1142
|
-
const incremental = base !== void 0 && projection.cursor != null && index > projection.cursor.throughIndex;
|
|
1143
|
-
const projected = incremental ? projectUIMessageStream({
|
|
1144
|
-
messageId: projection.responseMessageId,
|
|
1145
|
-
base,
|
|
1146
|
-
cursor: projection.cursor.stream,
|
|
1147
|
-
chunks
|
|
1148
|
-
}) : projectedMessageStream({
|
|
1149
|
-
...projection,
|
|
1150
|
-
batches
|
|
1151
|
-
});
|
|
1514
|
+
const controlCommit = (options) => {
|
|
1515
|
+
const active = options.after.active;
|
|
1516
|
+
const response = options.after.coordinator.response;
|
|
1152
1517
|
return {
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1518
|
+
changes: [...options.moves, ...controlChanges({
|
|
1519
|
+
before: options.before,
|
|
1520
|
+
after: options.after
|
|
1521
|
+
})],
|
|
1522
|
+
view: {
|
|
1523
|
+
turnId: active?.turnId ?? null,
|
|
1524
|
+
version: active?.version ?? null,
|
|
1525
|
+
phase: active?.phase ?? null,
|
|
1526
|
+
paused: options.after.inbox.paused,
|
|
1527
|
+
closed: options.after.coordinator.closed,
|
|
1528
|
+
requestId: response?.activeRequestId ?? null,
|
|
1529
|
+
requestReason: response?.requestReason ?? null,
|
|
1530
|
+
sourceGenerationId: response?.sourceGenerationId ?? null,
|
|
1531
|
+
responseMessageId: response?.responseMessageId ?? null
|
|
1158
1532
|
}
|
|
1159
1533
|
};
|
|
1160
1534
|
};
|
|
1161
1535
|
//#endregion
|
|
1536
|
+
//#region src/ai-control.ts
|
|
1537
|
+
const initialControlState = () => ({
|
|
1538
|
+
pendingStops: {},
|
|
1539
|
+
inbox: {
|
|
1540
|
+
paused: false,
|
|
1541
|
+
items: []
|
|
1542
|
+
},
|
|
1543
|
+
active: null,
|
|
1544
|
+
coordinator: {
|
|
1545
|
+
closed: false,
|
|
1546
|
+
queued: []
|
|
1547
|
+
}
|
|
1548
|
+
});
|
|
1549
|
+
//#endregion
|
|
1550
|
+
//#region src/ai-id.ts
|
|
1551
|
+
const AI_EVENT_ID_PREFIX = "a2.ai:";
|
|
1552
|
+
const aiEventId = async (...parts) => `${AI_EVENT_ID_PREFIX}${await idempotentId(...parts)}`;
|
|
1553
|
+
//#endregion
|
|
1162
1554
|
//#region src/ai-stored-state.ts
|
|
1163
|
-
const aiStateReducer = Symbol("a2.ai.stateReducer");
|
|
1164
1555
|
const isRecord$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1165
1556
|
const hasKeys = (value, { required, optional = [] }) => isRecord$1(value) && required.every((key) => Object.hasOwn(value, key)) && Object.keys(value).every((key) => required.includes(key) || optional.includes(key));
|
|
1166
1557
|
const reference = (value) => {
|
|
@@ -1181,15 +1572,6 @@ const payloadFields = /* @__PURE__ */ new Set([
|
|
|
1181
1572
|
"data"
|
|
1182
1573
|
]);
|
|
1183
1574
|
const keyFor = (value) => value === void 0 ? "undefined" : JSON.stringify(value);
|
|
1184
|
-
const sameValue = (left, right) => {
|
|
1185
|
-
if (Object.is(left, right)) return true;
|
|
1186
|
-
if (typeof left !== "object" || left === null || typeof right !== "object" || right === null) return false;
|
|
1187
|
-
const prototype = Object.getPrototypeOf(left);
|
|
1188
|
-
if (prototype !== Object.getPrototypeOf(right) || prototype !== Object.prototype && prototype !== Array.prototype && prototype !== null) return false;
|
|
1189
|
-
if (Array.isArray(left) && (!Array.isArray(right) || left.length !== right.length)) return false;
|
|
1190
|
-
const keys = Reflect.ownKeys(left);
|
|
1191
|
-
return keys.length === Reflect.ownKeys(right).length && keys.every((key) => Object.hasOwn(right, key) && sameValue(Reflect.get(left, key), Reflect.get(right, key)));
|
|
1192
|
-
};
|
|
1193
1575
|
const restore = (current, undo) => {
|
|
1194
1576
|
if (undo === void 0) return current;
|
|
1195
1577
|
if (!isRecord$1(undo)) throw new TypeError("invalid AI recovery change");
|
|
@@ -1288,22 +1670,18 @@ const storeState = (state) => {
|
|
|
1288
1670
|
packed.set(value, result);
|
|
1289
1671
|
return result;
|
|
1290
1672
|
};
|
|
1291
|
-
const saveProjection = (projection,
|
|
1292
|
-
const {
|
|
1293
|
-
const current = messages.find((message) => message.id === projection.responseMessageId);
|
|
1294
|
-
const message = baseMessage === void 0 ? void 0 : difference(pack(current), pack(baseMessage));
|
|
1673
|
+
const saveProjection = (projection, tools) => {
|
|
1674
|
+
const { baseTools, ...fields } = projection;
|
|
1295
1675
|
const toolPatch = baseTools === void 0 ? void 0 : difference(pack(tools), pack(baseTools));
|
|
1296
1676
|
return {
|
|
1297
1677
|
fields: pack(fields),
|
|
1298
|
-
hasMessage: baseMessage !== void 0,
|
|
1299
|
-
...message === void 0 ? {} : { message },
|
|
1300
1678
|
...toolPatch === void 0 ? {} : { tools: toolPatch }
|
|
1301
1679
|
};
|
|
1302
1680
|
};
|
|
1303
1681
|
const { activeProjection, ...fields } = state;
|
|
1304
|
-
const projection = activeProjection === null ? null : saveProjection(activeProjection, state.
|
|
1682
|
+
const projection = activeProjection === null ? null : saveProjection(activeProjection, state.tools);
|
|
1305
1683
|
return {
|
|
1306
|
-
version:
|
|
1684
|
+
version: 3,
|
|
1307
1685
|
fields: pack(fields),
|
|
1308
1686
|
projection,
|
|
1309
1687
|
values
|
|
@@ -1326,99 +1704,114 @@ const loadState = (stored) => {
|
|
|
1326
1704
|
};
|
|
1327
1705
|
const fields = stored.fields;
|
|
1328
1706
|
const state = unpack(stored.fields);
|
|
1329
|
-
const loadProjection = (saved,
|
|
1707
|
+
const loadProjection = (saved, tools) => {
|
|
1330
1708
|
if (!hasKeys(saved, {
|
|
1331
|
-
required: ["fields"
|
|
1332
|
-
optional: ["
|
|
1333
|
-
}) ||
|
|
1709
|
+
required: ["fields"],
|
|
1710
|
+
optional: ["tools"]
|
|
1711
|
+
}) || !isRecord$1(saved.fields) || "tools" in saved && saved.tools === void 0) throw new TypeError("invalid AI projection recovery");
|
|
1334
1712
|
const projection = unpack(saved.fields);
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
const current =
|
|
1338
|
-
|
|
1713
|
+
if (projection.base !== void 0) {
|
|
1714
|
+
assertMessageBase(projection.base);
|
|
1715
|
+
const current = state.messages.find((message) => message.id === projection.responseMessageId);
|
|
1716
|
+
if (current !== void 0 && restoreMessageBase({
|
|
1717
|
+
current,
|
|
1718
|
+
base: projection.base
|
|
1719
|
+
}) === void 0) throw new TypeError("AI message base does not match its message");
|
|
1339
1720
|
}
|
|
1340
1721
|
if (tools !== void 0) projection.baseTools = unpack(restore(tools, saved.tools));
|
|
1341
1722
|
else if (saved.tools !== void 0) throw new TypeError("missing AI recovery tools");
|
|
1342
1723
|
return projection;
|
|
1343
1724
|
};
|
|
1344
|
-
state.activeProjection = stored.projection === null ? null : loadProjection(stored.projection, fields["
|
|
1725
|
+
state.activeProjection = stored.projection === null ? null : loadProjection(stored.projection, fields["tools"]);
|
|
1345
1726
|
return state;
|
|
1346
1727
|
};
|
|
1347
|
-
const
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
get projection() {
|
|
1366
|
-
return read().projection;
|
|
1367
|
-
},
|
|
1368
|
-
get values() {
|
|
1369
|
-
return read().values;
|
|
1370
|
-
}
|
|
1371
|
-
};
|
|
1372
|
-
views.set(state, next);
|
|
1373
|
-
return state;
|
|
1374
|
-
};
|
|
1375
|
-
return {
|
|
1376
|
-
...source,
|
|
1377
|
-
name: `${source.name}:records-v2`,
|
|
1378
|
-
initialState: storeState(source.initialState),
|
|
1379
|
-
[aiStateReducer]: source,
|
|
1380
|
-
view,
|
|
1381
|
-
fromView: (state) => storeState(state),
|
|
1382
|
-
[clientStateProjection]: (state) => source[clientStateProjection]?.(view(state)) ?? view(state),
|
|
1383
|
-
stateSchema: { "~standard": {
|
|
1384
|
-
version: 1,
|
|
1385
|
-
vendor: "a2-ai",
|
|
1386
|
-
validate(value) {
|
|
1387
|
-
try {
|
|
1388
|
-
if (!hasKeys(value, { required: [
|
|
1389
|
-
"version",
|
|
1390
|
-
"fields",
|
|
1391
|
-
"projection",
|
|
1392
|
-
"values"
|
|
1393
|
-
] }) || value["version"] !== 2 || !Array.isArray(value["values"]) || !isRecord$1(value["fields"]) || value["projection"] !== null && !isRecord$1(value["projection"])) return { issues: [{ message: "invalid AI stored state" }] };
|
|
1394
|
-
const state = value;
|
|
1395
|
-
if (Object.keys(state.values).length !== state.values.length) return { issues: [{ message: "invalid AI payload table" }] };
|
|
1396
|
-
for (const payload of state.values) if (!hasKeys(payload, {
|
|
1397
|
-
required: [],
|
|
1398
|
-
optional: ["value"]
|
|
1399
|
-
})) return { issues: [{ message: "invalid AI payload table" }] };
|
|
1400
|
-
const decoded = loadState(state);
|
|
1401
|
-
if (source.stateSchema) {
|
|
1402
|
-
const result = validateSync(source.stateSchema, decoded, "AI view stateSchema");
|
|
1403
|
-
if (result.issues) return result;
|
|
1404
|
-
return { value: storeState(result.value) };
|
|
1405
|
-
}
|
|
1406
|
-
return { value: state };
|
|
1407
|
-
} catch {
|
|
1408
|
-
return { issues: [{ message: "invalid AI stored state" }] };
|
|
1409
|
-
}
|
|
1410
|
-
}
|
|
1411
|
-
} },
|
|
1412
|
-
fold(state, event) {
|
|
1413
|
-
const current = view(state);
|
|
1414
|
-
const next = source.fold(current, event);
|
|
1415
|
-
if (next === current) return state;
|
|
1416
|
-
return defer(next);
|
|
1728
|
+
const withAIStorage = (source) => withReducerRuntime({
|
|
1729
|
+
reducer: source,
|
|
1730
|
+
storage: {
|
|
1731
|
+
encode: (state) => storeState(state),
|
|
1732
|
+
decode(value) {
|
|
1733
|
+
if (!hasKeys(value, { required: [
|
|
1734
|
+
"version",
|
|
1735
|
+
"fields",
|
|
1736
|
+
"projection",
|
|
1737
|
+
"values"
|
|
1738
|
+
] }) || value["version"] !== 3 || !Array.isArray(value["values"]) || !isRecord$1(value["fields"]) || value["projection"] !== null && !isRecord$1(value["projection"])) throw new TypeError("invalid AI stored state");
|
|
1739
|
+
const state = value;
|
|
1740
|
+
if (Object.keys(state.values).length !== state.values.length) throw new TypeError("invalid AI payload table");
|
|
1741
|
+
for (const payload of state.values) if (!hasKeys(payload, {
|
|
1742
|
+
required: [],
|
|
1743
|
+
optional: ["value"]
|
|
1744
|
+
})) throw new TypeError("invalid AI payload table");
|
|
1745
|
+
return loadState(state);
|
|
1417
1746
|
}
|
|
1418
|
-
}
|
|
1747
|
+
}
|
|
1748
|
+
});
|
|
1749
|
+
//#endregion
|
|
1750
|
+
//#region src/ai-app-state.ts
|
|
1751
|
+
const aiStateKeys = {
|
|
1752
|
+
inbox: true,
|
|
1753
|
+
pendingQueueCommands: true,
|
|
1754
|
+
active: true,
|
|
1755
|
+
starting: true,
|
|
1756
|
+
receipt: true,
|
|
1757
|
+
pausedGenerationIds: true,
|
|
1758
|
+
session: true,
|
|
1759
|
+
messages: true,
|
|
1760
|
+
status: true,
|
|
1761
|
+
activeGeneration: true,
|
|
1762
|
+
activeRequestId: true,
|
|
1763
|
+
activeRequestReason: true,
|
|
1764
|
+
activeRequestSourceGenerationId: true,
|
|
1765
|
+
activeResponseMessageId: true,
|
|
1766
|
+
activeProjection: true,
|
|
1767
|
+
responseOwners: true,
|
|
1768
|
+
terminalRequestIds: true,
|
|
1769
|
+
terminalGenerations: true,
|
|
1770
|
+
pendingApprovals: true,
|
|
1771
|
+
pendingInputs: true,
|
|
1772
|
+
tools: true,
|
|
1773
|
+
compaction: true,
|
|
1774
|
+
modelMetadata: true,
|
|
1775
|
+
usage: true,
|
|
1776
|
+
error: true
|
|
1777
|
+
};
|
|
1778
|
+
const isAIStateKey = (key) => Object.hasOwn(aiStateKeys, key);
|
|
1779
|
+
const keep = (state, ai) => {
|
|
1780
|
+
const kept = {};
|
|
1781
|
+
for (const [key, value] of Object.entries(state)) if (isAIStateKey(key) === ai) kept[key] = value;
|
|
1782
|
+
return kept;
|
|
1783
|
+
};
|
|
1784
|
+
/** The application part of a merged state: every key `AIState` does not own. */
|
|
1785
|
+
const appSlice = (state) => keep(state, false);
|
|
1786
|
+
/** A merged state with its application part replaced. */
|
|
1787
|
+
const withAppSlice = (state, app) => ({
|
|
1788
|
+
...keep(state, true),
|
|
1789
|
+
...keep(app, false)
|
|
1790
|
+
});
|
|
1791
|
+
const agentReducers = /* @__PURE__ */ new WeakMap();
|
|
1792
|
+
const registerAgentReducer = (reducer, app) => {
|
|
1793
|
+
agentReducers.set(reducer, app ?? null);
|
|
1794
|
+
};
|
|
1795
|
+
const reducerOf = (contract) => typeof contract.reducer === "object" && contract.reducer !== null ? contract.reducer : void 0;
|
|
1796
|
+
const isAgentContract = (contract) => {
|
|
1797
|
+
const reducer = reducerOf(contract);
|
|
1798
|
+
return reducer !== void 0 && agentReducers.has(reducer);
|
|
1799
|
+
};
|
|
1800
|
+
const appReducerOf = (contract) => {
|
|
1801
|
+
const reducer = reducerOf(contract);
|
|
1802
|
+
return reducer === void 0 ? void 0 : agentReducers.get(reducer) ?? void 0;
|
|
1419
1803
|
};
|
|
1420
1804
|
//#endregion
|
|
1421
1805
|
//#region src/ai.ts
|
|
1806
|
+
const reasoningLevels = [
|
|
1807
|
+
"provider-default",
|
|
1808
|
+
"none",
|
|
1809
|
+
"minimal",
|
|
1810
|
+
"low",
|
|
1811
|
+
"medium",
|
|
1812
|
+
"high",
|
|
1813
|
+
"xhigh"
|
|
1814
|
+
];
|
|
1422
1815
|
const issue = (message) => ({ issues: [{ message }] });
|
|
1423
1816
|
const schema = (label, parse) => ({ "~standard": {
|
|
1424
1817
|
version: 1,
|
|
@@ -1468,7 +1861,7 @@ const messagePayloadSchema = (messageSchema) => schema("ai.message.created", (va
|
|
|
1468
1861
|
} };
|
|
1469
1862
|
});
|
|
1470
1863
|
const progressPayloadSchema = schema("ai.generation.progress", (value) => {
|
|
1471
|
-
if (!isRecord(value) || !isJSONCompatible(value) ||
|
|
1864
|
+
if (!isRecord(value) || !isJSONCompatible(value) || typeof value["startIndex"] !== "number" || !optionalIndexField(value, "startIndex") || !Array.isArray(value["chunks"]) || !value["chunks"].every((chunk) => isRecord(chunk) && typeof chunk["type"] === "string")) return issue("invalid ai.generation.progress payload");
|
|
1472
1865
|
return { value };
|
|
1473
1866
|
});
|
|
1474
1867
|
const completedPayloadSchema = schema("ai.generation.completed", (value) => {
|
|
@@ -1571,7 +1964,7 @@ function createEvents(options) {
|
|
|
1571
1964
|
"ai.message.interrupted": jsonObject("ai.message.interrupted", (value) => stringField(value, "messageId") && (stringField(value, "generationId") && value["requestId"] === void 0 || stringField(value, "requestId") && value["generationId"] === void 0) && optionalStringField(value, "reason") && (value["lastSeenIndex"] === void 0 || typeof value["lastSeenIndex"] === "number" && Number.isInteger(value["lastSeenIndex"]) && value["lastSeenIndex"] >= 0)),
|
|
1572
1965
|
"ai.generation.requested": jsonObject("ai.generation.requested", (value) => stringField(value, "messageId") && stringField(value, "responseMessageId") && optionalStringField(value, "sourceGenerationId") && (value["reason"] !== "tool" || stringField(value, "sourceGenerationId")) && (value["reason"] === "message" || value["reason"] === "tool" || value["reason"] === "input" || value["reason"] === "retry" || value["reason"] === "resume")),
|
|
1573
1966
|
"ai.retry.requested": jsonObject("ai.retry.requested", (value) => stringField(value, "messageId") && stringField(value, "responseMessageId") && stringField(value, "retryId")),
|
|
1574
|
-
"ai.generation.started": jsonObject("ai.generation.started", (value) => stringField(value, "requestId") && stringField(value, "messageId") && stringField(value, "generationId") && stringField(value, "responseMessageId") && typeof value["attempt"] === "number" && Number.isInteger(value["attempt"]) && value["attempt"] > 0 && stringField(value, "model") && optionalIndexField(value, "promptThroughIndex")),
|
|
1967
|
+
"ai.generation.started": jsonObject("ai.generation.started", (value) => stringField(value, "requestId") && stringField(value, "messageId") && stringField(value, "generationId") && stringField(value, "responseMessageId") && typeof value["attempt"] === "number" && Number.isInteger(value["attempt"]) && value["attempt"] > 0 && (value["model"] === void 0 || stringField(value, "model")) && optionalIndexField(value, "promptThroughIndex")),
|
|
1575
1968
|
"ai.generation.progress": progressPayloadSchema,
|
|
1576
1969
|
"ai.generation.completed": completedPayloadSchema,
|
|
1577
1970
|
"ai.generation.failed": jsonObject("ai.generation.failed", (value) => stringField(value, "requestId") && stringField(value, "messageId") && stringField(value, "generationId") && stringField(value, "responseMessageId") && stringField(value, "error") && (value["superseded"] === void 0 || typeof value["superseded"] === "boolean") && (value["stepLimit"] === void 0 || typeof value["stepLimit"] === "boolean")),
|
|
@@ -1613,11 +2006,14 @@ const initialState = () => ({
|
|
|
1613
2006
|
usage: [],
|
|
1614
2007
|
error: null
|
|
1615
2008
|
});
|
|
1616
|
-
const projectMessageChunks = (messages, messageId, chunks) =>
|
|
1617
|
-
messageId
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
}
|
|
2009
|
+
const projectMessageChunks = (messages, messageId, chunks) => {
|
|
2010
|
+
const base = findMessage(messages, messageId);
|
|
2011
|
+
return upsertMessage(messages, projectUIMessage({
|
|
2012
|
+
messageId,
|
|
2013
|
+
...base === void 0 ? {} : { base },
|
|
2014
|
+
chunks
|
|
2015
|
+
}));
|
|
2016
|
+
};
|
|
1621
2017
|
const waitingStatus = (state) => {
|
|
1622
2018
|
if (state.pendingApprovals.length > 0 || state.pendingInputs.length > 0) return "waiting";
|
|
1623
2019
|
return state.activeGeneration !== null || state.tools.some((activity) => activity.status === "running") ? "generating" : "idle";
|
|
@@ -1628,54 +2024,15 @@ const isStaleGeneration = (state, messageId, owner) => {
|
|
|
1628
2024
|
return current !== void 0 && (current.generationId !== owner.generationId || current.requestId !== owner.requestId);
|
|
1629
2025
|
};
|
|
1630
2026
|
const projectedResponse = (options) => {
|
|
1631
|
-
const message = projectedMessage(
|
|
2027
|
+
const message = projectedMessage({
|
|
2028
|
+
projection: options.projection,
|
|
2029
|
+
current: findMessage(options.state.messages, options.projection.responseMessageId)
|
|
2030
|
+
});
|
|
1632
2031
|
return options.state.pausedGenerationIds?.[options.projection.generationId] ? pauseUIMessage({
|
|
1633
2032
|
message,
|
|
1634
2033
|
toolCallIds: new Set(options.state.tools.map((tool) => tool.toolCallId))
|
|
1635
2034
|
}) : message;
|
|
1636
2035
|
};
|
|
1637
|
-
const projectedTools = (projection) => projection.toolEvents.reduce((tools, event) => reduceToolActivity(tools, event), projection.baseTools);
|
|
1638
|
-
const restoreGenerationBase = (state, generationId, responseMessageId, reason) => {
|
|
1639
|
-
const projection = state.activeProjection?.generationId === generationId ? state.activeProjection : null;
|
|
1640
|
-
return {
|
|
1641
|
-
...state,
|
|
1642
|
-
messages: projection?.baseMessage === void 0 ? state.messages.filter((message) => message.id !== responseMessageId) : upsertMessage(state.messages, projection.baseMessage),
|
|
1643
|
-
tools: projection === null ? state.tools.filter((activity) => activity.generationId !== generationId) : projection.baseTools,
|
|
1644
|
-
pendingApprovals: state.pendingApprovals.filter((approval) => approval.generationId !== generationId),
|
|
1645
|
-
pendingInputs: state.pendingInputs.filter((input) => input.generationId !== generationId),
|
|
1646
|
-
activeGeneration: null,
|
|
1647
|
-
activeProjection: null,
|
|
1648
|
-
terminalGenerations: {
|
|
1649
|
-
...state.terminalGenerations,
|
|
1650
|
-
[generationId]: reason
|
|
1651
|
-
},
|
|
1652
|
-
compaction: projection === null ? state.compaction?.generationId === generationId ? null : state.compaction : projection.baseCompaction ?? null
|
|
1653
|
-
};
|
|
1654
|
-
};
|
|
1655
|
-
const stopGenerationTools = (tools, generationId, responseMessageId, error) => tools.map((activity) => activity.status === "running" && (generationId === void 0 ? activity.messageId === responseMessageId : activity.generationId === generationId) ? {
|
|
1656
|
-
...activity,
|
|
1657
|
-
status: "failed",
|
|
1658
|
-
error,
|
|
1659
|
-
preliminary: false
|
|
1660
|
-
} : activity);
|
|
1661
|
-
const interruptGenerationProjection = (state, generationId, responseMessageId, cutoff) => {
|
|
1662
|
-
const projection = state.activeProjection?.generationId === generationId ? state.activeProjection : null;
|
|
1663
|
-
if (projection === null) return null;
|
|
1664
|
-
const retained = {
|
|
1665
|
-
...projection,
|
|
1666
|
-
batches: progressBatches(flattenProgressBatches(projection.batches).filter((batch) => batch.index <= cutoff)),
|
|
1667
|
-
toolEvents: projection.toolEvents.filter((toolEvent) => toolEvent.index <= cutoff),
|
|
1668
|
-
approvalEvents: projection.approvalEvents.filter((approvalEvent) => approvalEvent.index <= cutoff)
|
|
1669
|
-
};
|
|
1670
|
-
const shouldProject = retained.baseMessage !== void 0 || retained.batches.length > 0;
|
|
1671
|
-
const restored = restoreGenerationBase(state, generationId, responseMessageId, "interrupted");
|
|
1672
|
-
return {
|
|
1673
|
-
...restored,
|
|
1674
|
-
messages: shouldProject ? upsertMessage(state.messages, interruptUIMessage(projectedMessage(retained))) : restored.messages,
|
|
1675
|
-
tools: stopGenerationTools(projectedTools(retained), generationId, responseMessageId, "Tool execution was interrupted."),
|
|
1676
|
-
usage: projection.completionIndex === void 0 || projection.completionIndex <= cutoff ? restored.usage : restored.usage.filter((entry) => entry.generationId !== generationId)
|
|
1677
|
-
};
|
|
1678
|
-
};
|
|
1679
2036
|
const terminalGenerationReason = (state, generationId, requestId) => {
|
|
1680
2037
|
const terminal = state.terminalGenerations?.[generationId];
|
|
1681
2038
|
if (terminal !== void 0) return terminal;
|
|
@@ -1683,6 +2040,12 @@ const terminalGenerationReason = (state, generationId, requestId) => {
|
|
|
1683
2040
|
};
|
|
1684
2041
|
/** Pure projection of the built-in AI protocol. Unknown extension events are ignored. */
|
|
1685
2042
|
function reduceAIState(state, event) {
|
|
2043
|
+
return settleAbandonedCompaction(state, retainMessageBase({
|
|
2044
|
+
before: state,
|
|
2045
|
+
after: reduceAIEvent(state, event)
|
|
2046
|
+
}));
|
|
2047
|
+
}
|
|
2048
|
+
function reduceAIEvent(state, event) {
|
|
1686
2049
|
if (state.status === "closed") return state;
|
|
1687
2050
|
switch (event.type) {
|
|
1688
2051
|
case "ai.control.requested": {
|
|
@@ -1873,11 +2236,14 @@ function reduceAIState(state, event) {
|
|
|
1873
2236
|
if (currentOwner?.requestId === payload.requestId && currentOwner.attempt >= payload.attempt) return state;
|
|
1874
2237
|
const activeGeneration = state.activeGeneration;
|
|
1875
2238
|
const baseState = activeGeneration !== null && activeGeneration.requestId === payload.requestId && activeGeneration.responseMessageId === payload.responseMessageId && activeGeneration.attempt < payload.attempt && state.activeProjection?.generationId === activeGeneration.generationId ? restoreGenerationBase(state, activeGeneration.generationId, activeGeneration.responseMessageId, "superseded") : state;
|
|
1876
|
-
const baseMessage = baseState.messages
|
|
2239
|
+
const baseMessage = findMessage(baseState.messages, payload.responseMessageId);
|
|
1877
2240
|
return {
|
|
1878
2241
|
...baseState,
|
|
1879
2242
|
status: "generating",
|
|
1880
|
-
activeGeneration:
|
|
2243
|
+
activeGeneration: {
|
|
2244
|
+
...payload,
|
|
2245
|
+
startIndex: event.index
|
|
2246
|
+
},
|
|
1881
2247
|
activeResponseMessageId: null,
|
|
1882
2248
|
responseOwners: {
|
|
1883
2249
|
...baseState.responseOwners,
|
|
@@ -1891,7 +2257,7 @@ function reduceAIState(state, event) {
|
|
|
1891
2257
|
generationId: payload.generationId,
|
|
1892
2258
|
responseMessageId: payload.responseMessageId,
|
|
1893
2259
|
promptThroughIndex: payload.promptThroughIndex ?? event.index - 1,
|
|
1894
|
-
...baseMessage === void 0 ? {} : { baseMessage },
|
|
2260
|
+
...baseMessage === void 0 ? {} : { base: { partCount: baseMessage.parts.length } },
|
|
1895
2261
|
baseCompaction: baseState.compaction,
|
|
1896
2262
|
batches: progressBatches(),
|
|
1897
2263
|
baseTools: baseState.tools,
|
|
@@ -1903,13 +2269,16 @@ function reduceAIState(state, event) {
|
|
|
1903
2269
|
}
|
|
1904
2270
|
case "ai.generation.progress": {
|
|
1905
2271
|
const payload = event.payload;
|
|
1906
|
-
|
|
1907
|
-
if (terminalGenerationReason(state, payload.generationId, payload.requestId) !== void 0) return state;
|
|
2272
|
+
const generation = state.activeGeneration;
|
|
1908
2273
|
const activeProjection = state.activeProjection;
|
|
1909
|
-
if (
|
|
2274
|
+
if (generation === null || !progressOwnedBy({
|
|
2275
|
+
payload,
|
|
2276
|
+
owner: generation,
|
|
2277
|
+
startIndex: generation.startIndex
|
|
2278
|
+
}) || state.pausedGenerationIds?.[generation.generationId] || terminalGenerationReason(state, generation.generationId, generation.requestId) !== void 0 || activeProjection?.generationId !== generation.generationId) return state;
|
|
1910
2279
|
const progress = advanceProjection({
|
|
1911
2280
|
projection: activeProjection,
|
|
1912
|
-
base: state.messages
|
|
2281
|
+
base: findMessage(state.messages, activeProjection.responseMessageId),
|
|
1913
2282
|
chunks: payload.chunks,
|
|
1914
2283
|
index: event.index
|
|
1915
2284
|
});
|
|
@@ -1918,7 +2287,7 @@ function reduceAIState(state, event) {
|
|
|
1918
2287
|
messages: upsertResponse({
|
|
1919
2288
|
messages: state.messages,
|
|
1920
2289
|
message: progress.message,
|
|
1921
|
-
inputId:
|
|
2290
|
+
inputId: generation.messageId
|
|
1922
2291
|
}),
|
|
1923
2292
|
activeProjection: {
|
|
1924
2293
|
...activeProjection,
|
|
@@ -1956,10 +2325,13 @@ function reduceAIState(state, event) {
|
|
|
1956
2325
|
if ((state.activeGeneration?.generationId !== payload.generationId || state.activeGeneration.requestId !== payload.requestId) && !(payload.stepLimit === true && state.activeRequestReason === "tool" && state.responseOwners[payload.responseMessageId]?.requestId === payload.requestId && state.responseOwners[payload.responseMessageId]?.generationId === payload.generationId && state.activeRequestSourceGenerationId === payload.generationId && state.activeResponseMessageId === payload.responseMessageId)) return state;
|
|
1957
2326
|
if (payload.superseded === true) return restoreGenerationBase(state, payload.generationId, payload.responseMessageId, "superseded");
|
|
1958
2327
|
const projection = state.activeProjection?.generationId === payload.generationId ? state.activeProjection : null;
|
|
1959
|
-
const shouldProject = projection !== null && (projection.
|
|
2328
|
+
const shouldProject = projection !== null && (projection.base !== void 0 || projection.batches.length > 0);
|
|
1960
2329
|
return {
|
|
1961
2330
|
...state,
|
|
1962
|
-
messages: shouldProject ? upsertMessage(state.messages, interruptUIMessage(projectedMessage(
|
|
2331
|
+
messages: shouldProject ? upsertMessage(state.messages, interruptUIMessage(projectedMessage({
|
|
2332
|
+
projection,
|
|
2333
|
+
current: findMessage(state.messages, projection.responseMessageId)
|
|
2334
|
+
}), `Generation failed before tool completion: ${payload.error}`)) : state.messages,
|
|
1963
2335
|
status: "failed",
|
|
1964
2336
|
activeGeneration: null,
|
|
1965
2337
|
activeResponseMessageId: null,
|
|
@@ -2078,6 +2450,7 @@ function reduceAIState(state, event) {
|
|
|
2078
2450
|
if (projection?.generationId !== payload.generationId) {
|
|
2079
2451
|
const next = {
|
|
2080
2452
|
...state,
|
|
2453
|
+
messages: projectMessageChunks(state.messages, payload.messageId, [toolCalledChunk(payload)]),
|
|
2081
2454
|
tools: reduceToolActivity(state.tools, {
|
|
2082
2455
|
type: "ai.tool.called",
|
|
2083
2456
|
payload
|
|
@@ -2090,15 +2463,49 @@ function reduceAIState(state, event) {
|
|
|
2090
2463
|
}
|
|
2091
2464
|
const activeProjection = {
|
|
2092
2465
|
...projection,
|
|
2466
|
+
cursor: null,
|
|
2093
2467
|
toolEvents: [...projection.toolEvents, {
|
|
2094
2468
|
index: event.index,
|
|
2095
2469
|
type: "ai.tool.called",
|
|
2096
2470
|
payload
|
|
2097
2471
|
}]
|
|
2098
2472
|
};
|
|
2473
|
+
const base = findMessage(state.messages, payload.messageId);
|
|
2474
|
+
const paused = state.pausedGenerationIds?.[payload.generationId];
|
|
2475
|
+
const cursor = projection.cursor;
|
|
2476
|
+
const projected = base && cursor && !paused && event.index > cursor.throughIndex ? {
|
|
2477
|
+
...hasToolCall({
|
|
2478
|
+
message: base,
|
|
2479
|
+
call: payload
|
|
2480
|
+
}) ? {
|
|
2481
|
+
message: base,
|
|
2482
|
+
cursor: cursor.stream
|
|
2483
|
+
} : projectUIMessageStream({
|
|
2484
|
+
messageId: payload.messageId,
|
|
2485
|
+
base,
|
|
2486
|
+
cursor: cursor.stream,
|
|
2487
|
+
chunks: [toolCalledChunk(payload)]
|
|
2488
|
+
}),
|
|
2489
|
+
throughIndex: event.index
|
|
2490
|
+
} : projectedMessageStream({
|
|
2491
|
+
projection: activeProjection,
|
|
2492
|
+
current: base
|
|
2493
|
+
});
|
|
2494
|
+
activeProjection.cursor = paused ? null : {
|
|
2495
|
+
throughIndex: projected.throughIndex,
|
|
2496
|
+
stream: projected.cursor
|
|
2497
|
+
};
|
|
2099
2498
|
const next = {
|
|
2100
2499
|
...state,
|
|
2101
2500
|
activeProjection,
|
|
2501
|
+
messages: upsertResponse({
|
|
2502
|
+
messages: state.messages,
|
|
2503
|
+
message: paused ? projectedResponse({
|
|
2504
|
+
state,
|
|
2505
|
+
projection: activeProjection
|
|
2506
|
+
}) : projected.message,
|
|
2507
|
+
inputId: state.activeGeneration?.messageId ?? state.active?.input.id ?? payload.messageId
|
|
2508
|
+
}),
|
|
2102
2509
|
tools: projectedTools(activeProjection)
|
|
2103
2510
|
};
|
|
2104
2511
|
return {
|
|
@@ -2241,30 +2648,41 @@ function reduceAIState(state, event) {
|
|
|
2241
2648
|
case "ai.compaction.requested": {
|
|
2242
2649
|
const payload = event.payload;
|
|
2243
2650
|
if (state.activeGeneration?.generationId !== payload.generationId) return state;
|
|
2244
|
-
return {
|
|
2651
|
+
return addCompactionPart({
|
|
2245
2652
|
...state,
|
|
2246
2653
|
compaction: {
|
|
2247
2654
|
status: "running",
|
|
2248
2655
|
...payload
|
|
2249
2656
|
}
|
|
2250
|
-
};
|
|
2657
|
+
}, payload);
|
|
2251
2658
|
}
|
|
2252
2659
|
case "ai.compaction.completed": {
|
|
2253
2660
|
const payload = event.payload;
|
|
2254
2661
|
if (state.activeGeneration?.generationId !== payload.generationId || state.compaction?.status !== "running" || state.compaction.generationId !== payload.generationId) return state;
|
|
2662
|
+
const { messages: _messages, retainedMessageIds: _retained, ...summary } = payload;
|
|
2255
2663
|
const compaction = {
|
|
2256
2664
|
status: "completed",
|
|
2257
|
-
...
|
|
2665
|
+
...summary,
|
|
2258
2666
|
throughIndex: payload.throughIndex ?? state.activeProjection.promptThroughIndex
|
|
2259
2667
|
};
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2668
|
+
const projection = state.activeProjection;
|
|
2669
|
+
return settleCompactionPart({
|
|
2670
|
+
state: {
|
|
2671
|
+
...state,
|
|
2672
|
+
compaction,
|
|
2673
|
+
activeProjection: projection && {
|
|
2674
|
+
...projection,
|
|
2675
|
+
baseCompaction: compaction,
|
|
2676
|
+
...projection.base === void 0 ? {} : { base: { ...projection.base } }
|
|
2677
|
+
}
|
|
2678
|
+
},
|
|
2679
|
+
generationId: payload.generationId,
|
|
2680
|
+
data: {
|
|
2681
|
+
status: "completed",
|
|
2682
|
+
...summary.summary === void 0 ? {} : { summary: summary.summary },
|
|
2683
|
+
...summary.usage === void 0 ? {} : { usage: summary.usage }
|
|
2266
2684
|
}
|
|
2267
|
-
};
|
|
2685
|
+
});
|
|
2268
2686
|
}
|
|
2269
2687
|
default: return state;
|
|
2270
2688
|
}
|
|
@@ -2275,18 +2693,6 @@ function deriveUIMessages(history) {
|
|
|
2275
2693
|
for (const event of history) state = reduceAIState(state, event);
|
|
2276
2694
|
return state.messages;
|
|
2277
2695
|
}
|
|
2278
|
-
/** Build the standard AI state projection for any contract containing the protocol. */
|
|
2279
|
-
function createReducer(options) {
|
|
2280
|
-
const reducer = options.contract.reducer({
|
|
2281
|
-
name: options.name ?? "a2.ai.state.v21",
|
|
2282
|
-
initialState: initialState(),
|
|
2283
|
-
...options.stateSchema === void 0 ? {} : { stateSchema: options.stateSchema }
|
|
2284
|
-
}).fold(options.fold ?? ((state, event) => reduceAIState(state, event)));
|
|
2285
|
-
return storedAIReducer({
|
|
2286
|
-
...reducer,
|
|
2287
|
-
[clientStateProjection]: projectAIClientState
|
|
2288
|
-
});
|
|
2289
|
-
}
|
|
2290
2696
|
const commandInput = (payload) => [{
|
|
2291
2697
|
type: "ai.control.requested",
|
|
2292
2698
|
payload
|
|
@@ -2387,45 +2793,64 @@ const inputs = {
|
|
|
2387
2793
|
* Read the durable handler context ambient to the current AI tool
|
|
2388
2794
|
* execution. A2 runs each local tool's `execute` inside this scope, so
|
|
2389
2795
|
* plain AI SDK `tool()` definitions reach their `event`, `attempt`,
|
|
2390
|
-
* `session`, and `signal` without an A2-specific wrapper.
|
|
2391
|
-
* contract
|
|
2392
|
-
* the executing
|
|
2796
|
+
* `session`, and `signal` without an A2-specific wrapper. Pass the
|
|
2797
|
+
* agent's contract to type application events; it is verified against
|
|
2798
|
+
* the executing agent.
|
|
2393
2799
|
*/
|
|
2394
|
-
function handlerContext(
|
|
2395
|
-
const contract = "contract" in agentOrContract ? agentOrContract.contract : agentOrContract;
|
|
2800
|
+
function handlerContext(contract) {
|
|
2396
2801
|
const scope = ambientToolScopeStorage()?.getStore();
|
|
2397
|
-
if (scope === void 0) throw new TypeError(
|
|
2398
|
-
if (scope.contract !== void 0 && scope.contract.name !== contract.name) throw new TypeError(`handlerContext('${contract.name}') was called during a tool execution for agent '${scope.contract.name}'`);
|
|
2802
|
+
if (scope === void 0) throw new TypeError("handlerContext() requires an ambient A2 tool execution: call it inside a local tool's execute, or wrap direct tool tests with runWithHandlerContext");
|
|
2803
|
+
if (contract !== void 0 && scope.contract !== void 0 && scope.contract.name !== contract.name) throw new TypeError(`handlerContext('${contract.name}') was called during a tool execution for agent '${scope.contract.name}'`);
|
|
2399
2804
|
return scope.context;
|
|
2400
2805
|
}
|
|
2806
|
+
/** The built-in AI reducer's name, and so its checkpoint identity. */
|
|
2807
|
+
const AI_STATE_REDUCER = "a2.ai.state.v26";
|
|
2401
2808
|
/**
|
|
2402
|
-
*
|
|
2403
|
-
* reducer
|
|
2809
|
+
* The built-in AI protocol plus application events, as a core contract whose
|
|
2810
|
+
* reducer folds `AIState`. Isomorphic: share it when a client needs
|
|
2811
|
+
* application events or extended state; otherwise `agent({ name })` on the
|
|
2812
|
+
* server builds one and clients use the built-in protocol.
|
|
2404
2813
|
*/
|
|
2405
|
-
function
|
|
2814
|
+
function agentContract(options) {
|
|
2406
2815
|
const builtIns = createEvents(options.messageSchema === void 0 ? void 0 : { messageSchema: options.messageSchema });
|
|
2407
2816
|
const extensions = options.events ?? {};
|
|
2408
2817
|
for (const key of Object.keys(extensions)) if (Object.hasOwn(builtIns, key)) throw new TypeError(`agent event '${key}' conflicts with a built-in event`);
|
|
2409
|
-
const
|
|
2818
|
+
const vocabulary = contract({
|
|
2410
2819
|
name: options.name,
|
|
2411
2820
|
events: {
|
|
2412
2821
|
...builtIns,
|
|
2413
2822
|
...extensions
|
|
2414
2823
|
}
|
|
2415
2824
|
});
|
|
2416
|
-
const
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
...
|
|
2424
|
-
|
|
2425
|
-
}
|
|
2426
|
-
}
|
|
2825
|
+
const app = options.reducer;
|
|
2826
|
+
const aiState = initialState();
|
|
2827
|
+
for (const key of Object.keys(app?.initialState ?? {})) if (isAIStateKey(key)) throw new TypeError(`agent state '${key}' conflicts with AIState`);
|
|
2828
|
+
const reducer$1 = reducer({
|
|
2829
|
+
contract: vocabulary,
|
|
2830
|
+
name: app === void 0 ? AI_STATE_REDUCER : `${app.name}+${AI_STATE_REDUCER}`,
|
|
2831
|
+
initialState: {
|
|
2832
|
+
...aiState,
|
|
2833
|
+
...app?.initialState
|
|
2834
|
+
}
|
|
2835
|
+
}).fold((state, event) => {
|
|
2836
|
+
const next = reduceAIState(state, event);
|
|
2837
|
+
if (app === void 0) return next;
|
|
2838
|
+
const before = appSlice(state);
|
|
2839
|
+
const after = app.fold(before, event);
|
|
2840
|
+
return after === before ? next : withAppSlice(next, after);
|
|
2841
|
+
});
|
|
2842
|
+
const shared = contract({
|
|
2843
|
+
name: options.name,
|
|
2844
|
+
events: vocabulary.events,
|
|
2845
|
+
reducer: withAIStorage(withReducerRuntime({
|
|
2846
|
+
reducer: reducer$1,
|
|
2847
|
+
project: projectAIClientState
|
|
2848
|
+
}))
|
|
2849
|
+
});
|
|
2850
|
+
registerAgentReducer(shared.reducer, app);
|
|
2851
|
+
return shared;
|
|
2427
2852
|
}
|
|
2428
2853
|
//#endregion
|
|
2429
|
-
export {
|
|
2854
|
+
export { interruptUIMessage as A, reduceToolActivity as C, flattenProgressBatches as D, upsertResponse as E, assertMessageBase as M, restoreMessageBase as N, progressBatches as O, projectedMessage as S, upsertMessage as T, applyControlChanges as _, events as a, findMessage as b, reasoningLevels as c, appSlice as d, isAgentContract as f, initialControlState as g, aiEventId as h, deriveUIMessages as i, pauseUIMessage as j, progressOwnedBy as k, reduceAIState as l, AI_EVENT_ID_PREFIX as m, agentContract as n, handlerContext as o, withAIStorage as p, createEvents as r, inputs as s, AI_STATE_REDUCER as t, appReducerOf as u, controlCommit as v, retainMessageBase as w, isCompactionPart as x, advanceProjection as y };
|
|
2430
2855
|
|
|
2431
|
-
//# sourceMappingURL=ai-
|
|
2856
|
+
//# sourceMappingURL=ai-UrWfKeuv.js.map
|