experimental-a2 0.15.0 → 0.16.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.
Files changed (101) hide show
  1. package/CHANGELOG.md +73 -0
  2. package/dist/actor-client.d.ts +1 -1
  3. package/dist/{actor-BfQSE0KC.d.ts → actor-ohPC-81x.d.ts} +5 -5
  4. package/dist/{actor-BfQSE0KC.d.ts.map → actor-ohPC-81x.d.ts.map} +1 -1
  5. package/dist/actor-react.d.ts +3 -3
  6. package/dist/actor.d.ts +1 -1
  7. package/dist/actor.js +1 -1
  8. package/dist/ai-CrLYwNEx.js +2431 -0
  9. package/dist/ai-CrLYwNEx.js.map +1 -0
  10. package/dist/{ai-Cai-lCbj.d.ts → ai-HJ9fHfYI.d.ts} +72 -13
  11. package/dist/ai-HJ9fHfYI.d.ts.map +1 -0
  12. package/dist/ai-server.d.ts +4 -5
  13. package/dist/ai-server.d.ts.map +1 -1
  14. package/dist/ai-server.js +755 -290
  15. package/dist/ai-server.js.map +1 -1
  16. package/dist/ai.d.ts +2 -2
  17. package/dist/ai.js +1 -1999
  18. package/dist/client-BYzHjkwU.js.map +1 -1
  19. package/dist/{client-BAEABRZB.d.ts → client-CzyacQpJ.d.ts} +9 -9
  20. package/dist/client-CzyacQpJ.d.ts.map +1 -0
  21. package/dist/client.d.ts +1 -1
  22. package/dist/idempotent-id-BRJVeylj.js +13 -0
  23. package/dist/idempotent-id-BRJVeylj.js.map +1 -0
  24. package/dist/index.d.ts +3 -3
  25. package/dist/index.js +1 -12
  26. package/dist/otel.d.ts +1 -1
  27. package/dist/react.d.ts +13 -13
  28. package/dist/react.d.ts.map +1 -1
  29. package/dist/react.js.map +1 -1
  30. package/dist/reducer-DEMjEY_O.js.map +1 -1
  31. package/dist/{reducer-BcS9VDKC.d.ts → reducer-otzHjuJj.d.ts} +3 -3
  32. package/dist/{reducer-BcS9VDKC.d.ts.map → reducer-otzHjuJj.d.ts.map} +1 -1
  33. package/dist/scheduler-qstash.d.ts +2 -2
  34. package/dist/scheduler-qstash.js +1 -1
  35. package/dist/scheduler-vercel.d.ts +2 -2
  36. package/dist/scheduler-vercel.js +1 -1
  37. package/dist/{server-CjJSGcF7.js → server-BD5ckxZb.js} +39 -26
  38. package/dist/server-BD5ckxZb.js.map +1 -0
  39. package/dist/{server-Bp5Nd1pF.d.ts → server-DbD7IJVK.d.ts} +5 -5
  40. package/dist/{server-Bp5Nd1pF.d.ts.map → server-DbD7IJVK.d.ts.map} +1 -1
  41. package/dist/server.d.ts +3 -3
  42. package/dist/server.js +1 -1
  43. package/dist/{store-D_yhNdPz.d.ts → store-DyZM6fS5.d.ts} +3 -2
  44. package/dist/{store-D_yhNdPz.d.ts.map → store-DyZM6fS5.d.ts.map} +1 -1
  45. package/dist/store-N8PXxDAS.js.map +1 -1
  46. package/dist/store-memory.d.ts +1 -1
  47. package/dist/store-postgres.d.ts +1 -1
  48. package/dist/store-redis-http.d.ts +1 -1
  49. package/dist/store-redis-http.js +1 -1
  50. package/dist/{store-redis-notify-D2EI6gwX.js → store-redis-notify-BVLUfI3j.js} +14 -13
  51. package/dist/store-redis-notify-BVLUfI3j.js.map +1 -0
  52. package/dist/store-redis.d.ts +1 -1
  53. package/dist/store-redis.js +1 -1
  54. package/dist/store-sqlite.d.ts +1 -1
  55. package/dist/{telemetry-CpeclqB2.d.ts → telemetry-B5jzpy6y.d.ts} +2 -2
  56. package/dist/telemetry-B5jzpy6y.d.ts.map +1 -0
  57. package/docs/concepts/04-state.mdx +9 -4
  58. package/docs/guides/06-ai-agents.mdx +134 -43
  59. package/docs/reference/01-api.mdx +104 -27
  60. package/examples/playground/app/agent/[agentId]/agent-client.tsx +20 -28
  61. package/examples/playground/app/agent/[agentId]/agent-queue.test.tsx +123 -0
  62. package/examples/playground/app/agent/[agentId]/agent-queue.tsx +37 -43
  63. package/examples/playground/app/agent/[agentId]/compaction-panel.tsx +44 -24
  64. package/examples/playground/app/agent/compaction-timeline.test.ts +47 -7
  65. package/examples/playground/app/agent/compaction-timeline.ts +13 -3
  66. package/examples/playground/app/chat/[chatId]/chat-client.tsx +1 -5
  67. package/examples/playground/app/chat/[chatId]/session.ts +17 -2
  68. package/examples/playground/app/chat/model.test.ts +4 -4
  69. package/examples/playground/app/chat/model.ts +18 -6
  70. package/examples/playground/app/chat/server.ts +6 -3
  71. package/examples/playground/package.json +3 -1
  72. package/package.json +1 -1
  73. package/src/ai-client-state.ts +0 -2
  74. package/src/ai-context-schema.ts +296 -0
  75. package/src/ai-context.ts +680 -0
  76. package/src/ai-control-server.ts +160 -131
  77. package/src/ai-control-state.ts +6 -0
  78. package/src/ai-control.ts +6 -7
  79. package/src/ai-coordinator.ts +92 -38
  80. package/src/ai-id.ts +6 -0
  81. package/src/ai-input-tokens.ts +75 -0
  82. package/src/ai-message-projection.ts +348 -0
  83. package/src/ai-server.ts +232 -334
  84. package/src/ai-stored-state.ts +484 -0
  85. package/src/ai.ts +252 -418
  86. package/src/client.ts +21 -15
  87. package/src/react.ts +25 -19
  88. package/src/reducer.ts +2 -1
  89. package/src/server.ts +73 -56
  90. package/src/store-redis-core.ts +15 -17
  91. package/src/store.ts +1 -0
  92. package/src/telemetry.ts +2 -1
  93. package/dist/ai-Cai-lCbj.d.ts.map +0 -1
  94. package/dist/ai-control-CcD4hh3y.js +0 -119
  95. package/dist/ai-control-CcD4hh3y.js.map +0 -1
  96. package/dist/ai.js.map +0 -1
  97. package/dist/client-BAEABRZB.d.ts.map +0 -1
  98. package/dist/index.js.map +0 -1
  99. package/dist/server-CjJSGcF7.js.map +0 -1
  100. package/dist/store-redis-notify-D2EI6gwX.js.map +0 -1
  101. package/dist/telemetry-CpeclqB2.d.ts.map +0 -1
package/dist/ai.js CHANGED
@@ -1,2000 +1,2 @@
1
- import { n as validateSync, t as assertSyncSchema } from "./validate-XKT4FSNn.js";
2
- import { t as clientStateProjection } from "./reducer-DEMjEY_O.js";
3
- import { t as contract } from "./contract-CKRg_E4q.js";
4
- import { l as ambientToolScopeStorage } from "./internal-Dq2qYxou.js";
5
- import { n as applyControlChanges, t as initialControlState } from "./ai-control-CcD4hh3y.js";
6
- //#region src/ai-client-state.ts
7
- 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";
8
- const moveItem = ({ items, inputId, beforeId }) => {
9
- const from = items.findIndex((item) => item.id === inputId);
10
- if (from < 0 || inputId === beforeId || beforeId !== null && !items.some((item) => item.id === beforeId)) return items;
11
- const next = [...items];
12
- const [item] = next.splice(from, 1);
13
- const to = beforeId === null ? next.length : next.findIndex((entry) => entry.id === beforeId);
14
- next.splice(to, 0, item);
15
- return next;
16
- };
17
- function projectAIClientState(state) {
18
- const pending = state.pendingQueueCommands ?? [];
19
- if (state.status === "closed") return state;
20
- if (pending.length === 0 && !state.inbox.items.some((item) => item.afterStepOf !== void 0)) return state;
21
- let messages = state.messages;
22
- let { items, paused } = state.inbox;
23
- let turnId = state.active?.turnId ?? null;
24
- let starting = false;
25
- let suspended = state.active?.phase === "paused" || state.active?.phase === "pausing";
26
- let messageIds;
27
- const show = (message) => {
28
- messageIds ??= new Set(messages.map((item) => item.id));
29
- if (messageIds.has(message.id)) return;
30
- if (messages === state.messages) messages = state.messages.slice();
31
- messages.push(message);
32
- messageIds.add(message.id);
33
- };
34
- const admit = () => {
35
- if (turnId !== null || paused || items.length === 0) return;
36
- let count = 0;
37
- for (const item of items) {
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
- revision: 0,
58
- message: command.message,
59
- generate: command.message.role === "user" && (command.action === "steer" || command.generate !== false)
60
- };
61
- items = command.action === "steer" ? [item, ...items] : [...items, item];
62
- break;
63
- }
64
- case "edit":
65
- items = items.map((item) => item.id === command.message.id && item.revision === command.expectedRevision && item.message.role === command.message.role ? {
66
- ...item,
67
- message: command.message
68
- } : item);
69
- break;
70
- case "move":
71
- items = moveItem({
72
- items,
73
- inputId: command.inputId,
74
- beforeId: command.beforeId
75
- });
76
- break;
77
- case "remove":
78
- items = items.filter((item) => item.id !== command.inputId);
79
- break;
80
- case "send-now": {
81
- if (turnId !== command.turnId) break;
82
- const selected = items.find((item) => item.id === command.inputId);
83
- if (!selected || selected.message.role !== "user") break;
84
- items = items.map((item) => item.id === selected.id ? {
85
- ...item,
86
- generate: true,
87
- ...turnId === null ? {} : { afterStepOf: turnId }
88
- } : item);
89
- items = moveItem({
90
- items,
91
- inputId: command.inputId,
92
- beforeId: items[0]?.id ?? null
93
- });
94
- break;
95
- }
96
- case "pause":
97
- paused = true;
98
- if (command.when === "now") suspended = true;
99
- break;
100
- case "resume":
101
- paused = false;
102
- suspended = false;
103
- }
104
- admit();
105
- }
106
- items = items.filter((item) => {
107
- if (item.afterStepOf === void 0) return true;
108
- show(item.message);
109
- return false;
110
- });
111
- return {
112
- ...state,
113
- messages,
114
- inbox: {
115
- items,
116
- paused
117
- },
118
- starting: starting && !suspended
119
- };
120
- }
121
- //#endregion
122
- //#region src/parse-partial-json.ts
123
- /*!
124
- * Adapted from AI SDK 7.0.58, packages/ai/src/util/fix-json.ts.
125
- * Source: https://github.com/vercel/ai, packages/ai/src/util/fix-json.ts.
126
- * Modified to expose a synchronous partial parser with strict TypeScript types.
127
- * Also preserves positive exponents in unfinished containers.
128
- * Copyright 2023 Vercel, Inc.
129
- * @license Apache-2.0. See src/licenses/Apache-2.0.txt.
130
- */
131
- function parsePartialJSON(text) {
132
- if (text === void 0 || text.trim() === "") return void 0;
133
- try {
134
- return JSON.parse(text);
135
- } catch {
136
- try {
137
- return JSON.parse(repairPartialJSON(text));
138
- } catch {
139
- return;
140
- }
141
- }
142
- }
143
- const isHexDigit = (char) => char >= "0" && char <= "9" || char >= "A" && char <= "F" || char >= "a" && char <= "f";
144
- function repairPartialJSON(input) {
145
- const stack = ["ROOT"];
146
- let lastValidIndex = -1;
147
- let literalStart = null;
148
- let unicodeEscapeDigits = 0;
149
- function processValueStart(char, i, swapState) {
150
- switch (char) {
151
- case "\"":
152
- lastValidIndex = i;
153
- stack.pop();
154
- stack.push(swapState);
155
- stack.push("INSIDE_STRING");
156
- break;
157
- case "f":
158
- case "t":
159
- case "n":
160
- lastValidIndex = i;
161
- literalStart = i;
162
- stack.pop();
163
- stack.push(swapState);
164
- stack.push("INSIDE_LITERAL");
165
- break;
166
- case "-":
167
- stack.pop();
168
- stack.push(swapState);
169
- stack.push("INSIDE_NUMBER");
170
- break;
171
- case "0":
172
- case "1":
173
- case "2":
174
- case "3":
175
- case "4":
176
- case "5":
177
- case "6":
178
- case "7":
179
- case "8":
180
- case "9":
181
- lastValidIndex = i;
182
- stack.pop();
183
- stack.push(swapState);
184
- stack.push("INSIDE_NUMBER");
185
- break;
186
- case "{":
187
- lastValidIndex = i;
188
- stack.pop();
189
- stack.push(swapState);
190
- stack.push("INSIDE_OBJECT_START");
191
- break;
192
- case "[":
193
- lastValidIndex = i;
194
- stack.pop();
195
- stack.push(swapState);
196
- stack.push("INSIDE_ARRAY_START");
197
- }
198
- }
199
- function processAfterObjectValue(char, i) {
200
- switch (char) {
201
- case ",":
202
- stack.pop();
203
- stack.push("INSIDE_OBJECT_AFTER_COMMA");
204
- break;
205
- case "}":
206
- lastValidIndex = i;
207
- stack.pop();
208
- }
209
- }
210
- function processAfterArrayValue(char, i) {
211
- switch (char) {
212
- case ",":
213
- stack.pop();
214
- stack.push("INSIDE_ARRAY_AFTER_COMMA");
215
- break;
216
- case "]":
217
- lastValidIndex = i;
218
- stack.pop();
219
- }
220
- }
221
- for (let i = 0; i < input.length; i++) {
222
- const char = input[i];
223
- switch (stack[stack.length - 1]) {
224
- case "ROOT":
225
- processValueStart(char, i, "FINISH");
226
- break;
227
- case "INSIDE_OBJECT_START":
228
- switch (char) {
229
- case "\"":
230
- stack.pop();
231
- stack.push("INSIDE_OBJECT_KEY");
232
- break;
233
- case "}":
234
- lastValidIndex = i;
235
- stack.pop();
236
- }
237
- break;
238
- case "INSIDE_OBJECT_AFTER_COMMA":
239
- switch (char) {
240
- case "\"":
241
- stack.pop();
242
- stack.push("INSIDE_OBJECT_KEY");
243
- }
244
- break;
245
- case "INSIDE_OBJECT_KEY":
246
- switch (char) {
247
- case "\"":
248
- stack.pop();
249
- stack.push("INSIDE_OBJECT_AFTER_KEY");
250
- }
251
- break;
252
- case "INSIDE_OBJECT_AFTER_KEY":
253
- switch (char) {
254
- case ":":
255
- stack.pop();
256
- stack.push("INSIDE_OBJECT_BEFORE_VALUE");
257
- }
258
- break;
259
- case "INSIDE_OBJECT_BEFORE_VALUE":
260
- processValueStart(char, i, "INSIDE_OBJECT_AFTER_VALUE");
261
- break;
262
- case "INSIDE_OBJECT_AFTER_VALUE":
263
- processAfterObjectValue(char, i);
264
- break;
265
- case "INSIDE_STRING":
266
- switch (char) {
267
- case "\"":
268
- stack.pop();
269
- lastValidIndex = i;
270
- break;
271
- case "\\":
272
- stack.push("INSIDE_STRING_ESCAPE");
273
- break;
274
- default: lastValidIndex = i;
275
- }
276
- break;
277
- case "INSIDE_ARRAY_START":
278
- switch (char) {
279
- case "]":
280
- lastValidIndex = i;
281
- stack.pop();
282
- break;
283
- default:
284
- lastValidIndex = i;
285
- processValueStart(char, i, "INSIDE_ARRAY_AFTER_VALUE");
286
- }
287
- break;
288
- case "INSIDE_ARRAY_AFTER_VALUE":
289
- switch (char) {
290
- case ",":
291
- stack.pop();
292
- stack.push("INSIDE_ARRAY_AFTER_COMMA");
293
- break;
294
- case "]":
295
- lastValidIndex = i;
296
- stack.pop();
297
- break;
298
- default: lastValidIndex = i;
299
- }
300
- break;
301
- case "INSIDE_ARRAY_AFTER_COMMA":
302
- processValueStart(char, i, "INSIDE_ARRAY_AFTER_VALUE");
303
- break;
304
- case "INSIDE_STRING_ESCAPE":
305
- stack.pop();
306
- if (char === "u") {
307
- unicodeEscapeDigits = 0;
308
- stack.push("INSIDE_STRING_UNICODE_ESCAPE");
309
- } else lastValidIndex = i;
310
- break;
311
- case "INSIDE_STRING_UNICODE_ESCAPE":
312
- if (isHexDigit(char)) {
313
- unicodeEscapeDigits++;
314
- if (unicodeEscapeDigits === 4) {
315
- stack.pop();
316
- lastValidIndex = i;
317
- }
318
- }
319
- break;
320
- case "INSIDE_NUMBER":
321
- switch (char) {
322
- case "0":
323
- case "1":
324
- case "2":
325
- case "3":
326
- case "4":
327
- case "5":
328
- case "6":
329
- case "7":
330
- case "8":
331
- case "9":
332
- lastValidIndex = i;
333
- break;
334
- case "e":
335
- case "E":
336
- case "-":
337
- case "+":
338
- case ".": break;
339
- case ",":
340
- stack.pop();
341
- if (stack[stack.length - 1] === "INSIDE_ARRAY_AFTER_VALUE") processAfterArrayValue(char, i);
342
- if (stack[stack.length - 1] === "INSIDE_OBJECT_AFTER_VALUE") processAfterObjectValue(char, i);
343
- break;
344
- case "}":
345
- stack.pop();
346
- if (stack[stack.length - 1] === "INSIDE_OBJECT_AFTER_VALUE") processAfterObjectValue(char, i);
347
- break;
348
- case "]":
349
- stack.pop();
350
- if (stack[stack.length - 1] === "INSIDE_ARRAY_AFTER_VALUE") processAfterArrayValue(char, i);
351
- break;
352
- default: stack.pop();
353
- }
354
- break;
355
- case "INSIDE_LITERAL": {
356
- const partialLiteral = input.substring(literalStart, i + 1);
357
- if (!"false".startsWith(partialLiteral) && !"true".startsWith(partialLiteral) && !"null".startsWith(partialLiteral)) {
358
- stack.pop();
359
- if (stack[stack.length - 1] === "INSIDE_OBJECT_AFTER_VALUE") processAfterObjectValue(char, i);
360
- else if (stack[stack.length - 1] === "INSIDE_ARRAY_AFTER_VALUE") processAfterArrayValue(char, i);
361
- } else lastValidIndex = i;
362
- break;
363
- }
364
- }
365
- }
366
- let result = input.slice(0, lastValidIndex + 1);
367
- for (let i = stack.length - 1; i >= 0; i--) switch (stack[i]) {
368
- case "INSIDE_STRING":
369
- result += "\"";
370
- break;
371
- case "INSIDE_OBJECT_KEY":
372
- case "INSIDE_OBJECT_AFTER_KEY":
373
- case "INSIDE_OBJECT_AFTER_COMMA":
374
- case "INSIDE_OBJECT_START":
375
- case "INSIDE_OBJECT_BEFORE_VALUE":
376
- case "INSIDE_OBJECT_AFTER_VALUE":
377
- result += "}";
378
- break;
379
- case "INSIDE_ARRAY_START":
380
- case "INSIDE_ARRAY_AFTER_COMMA":
381
- case "INSIDE_ARRAY_AFTER_VALUE":
382
- result += "]";
383
- break;
384
- case "INSIDE_LITERAL": {
385
- const partialLiteral = input.substring(literalStart, input.length);
386
- if ("true".startsWith(partialLiteral)) result += "true".slice(partialLiteral.length);
387
- else if ("false".startsWith(partialLiteral)) result += "false".slice(partialLiteral.length);
388
- else if ("null".startsWith(partialLiteral)) result += "null".slice(partialLiteral.length);
389
- }
390
- }
391
- return result;
392
- }
393
- //#endregion
394
- //#region src/ai-projector.ts
395
- const isRecord$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
396
- const cloneMessage = (messageId, base) => base === void 0 ? {
397
- id: messageId,
398
- role: "assistant",
399
- parts: []
400
- } : {
401
- ...base,
402
- id: messageId,
403
- parts: base.parts.map((part) => ({ ...part }))
404
- };
405
- const currentStepParts = (parts) => {
406
- let start = parts.length - 1;
407
- while (start >= 0 && parts[start]?.["type"] !== "step-start") start -= 1;
408
- return parts.slice(start + 1);
409
- };
410
- const isToolPart = (part) => typeof part["toolCallId"] === "string" && (part["type"] === "dynamic-tool" || typeof part["type"] === "string" && part["type"].startsWith("tool-"));
411
- const findToolPart = (parts, toolCallId) => {
412
- const current = currentStepParts(parts).find((part) => isToolPart(part) && part["toolCallId"] === toolCallId);
413
- if (current) return current;
414
- return parts.findLast((part) => isToolPart(part) && part["toolCallId"] === toolCallId);
415
- };
416
- const findApprovalPart = (parts, approvalId) => parts.find((part) => {
417
- const approval = part["approval"];
418
- return isToolPart(part) && isRecord$1(approval) && approval["id"] === approvalId;
419
- });
420
- const setOptional = (target, key, value) => {
421
- if (value !== void 0) target[key] = value;
422
- };
423
- const setToolPart = (options) => {
424
- let part = findToolPart(options.parts, options.toolCallId);
425
- if (!part) {
426
- part = {
427
- type: options.dynamic ? "dynamic-tool" : `tool-${options.toolName}`,
428
- ...options.dynamic ? { toolName: options.toolName } : {},
429
- toolCallId: options.toolCallId
430
- };
431
- options.parts.push(part);
432
- }
433
- part["state"] = options.state;
434
- part["input"] = options.input;
435
- delete part["output"];
436
- delete part["rawInput"];
437
- delete part["errorText"];
438
- delete part["preliminary"];
439
- setOptional(part, "rawInput", options.rawInput);
440
- setOptional(part, "output", options.output);
441
- setOptional(part, "errorText", options.errorText);
442
- setOptional(part, "preliminary", options.preliminary);
443
- setOptional(part, "providerExecuted", options.providerExecuted);
444
- setOptional(part, "title", options.title);
445
- setOptional(part, "toolMetadata", options.toolMetadata);
446
- if (options.dynamic) part["toolName"] = options.toolName;
447
- if (options.providerMetadata !== void 0) part[options.state === "output-available" || options.state === "output-error" ? "resultProviderMetadata" : "callProviderMetadata"] = options.providerMetadata;
448
- return part;
449
- };
450
- const mergeMetadata = (current, update) => {
451
- if (update === void 0 || update === null) return current;
452
- return isRecord$1(current) && isRecord$1(update) ? {
453
- ...current,
454
- ...update
455
- } : update;
456
- };
457
- function projectUIMessage(options) {
458
- return projectUIMessageStream(options).message;
459
- }
460
- function projectUIMessageStream(options) {
461
- const message = cloneMessage(options.messageId, options.base);
462
- const record = message;
463
- const parts = message.parts;
464
- const activeText = new Map(Object.entries(options.cursor?.text ?? {}).map(([id, index]) => [id, parts[index]]));
465
- const activeReasoning = new Map(Object.entries(options.cursor?.reasoning ?? {}).map(([id, index]) => [id, parts[index]]));
466
- const partialTools = new Map(Object.entries(options.cursor?.tools ?? {}).map(([id, partial]) => [id, { ...partial }]));
467
- for (const chunk of options.chunks) switch (chunk.type) {
468
- case "text-start": {
469
- const part = {
470
- type: "text",
471
- text: "",
472
- state: "streaming",
473
- ...chunk.providerMetadata === void 0 ? {} : { providerMetadata: chunk.providerMetadata }
474
- };
475
- activeText.set(chunk.id, part);
476
- parts.push(part);
477
- break;
478
- }
479
- case "text-delta": {
480
- let part = activeText.get(chunk.id);
481
- if (!part) {
482
- part = {
483
- type: "text",
484
- text: "",
485
- state: "streaming"
486
- };
487
- activeText.set(chunk.id, part);
488
- parts.push(part);
489
- }
490
- part["text"] = `${typeof part["text"] === "string" ? part["text"] : ""}${chunk.delta}`;
491
- setOptional(part, "providerMetadata", chunk.providerMetadata);
492
- break;
493
- }
494
- case "text-end": {
495
- const part = activeText.get(chunk.id);
496
- if (part) {
497
- part["state"] = "done";
498
- setOptional(part, "providerMetadata", chunk.providerMetadata);
499
- activeText.delete(chunk.id);
500
- }
501
- break;
502
- }
503
- case "reasoning-start": {
504
- const part = {
505
- type: "reasoning",
506
- text: "",
507
- state: "streaming",
508
- ...chunk.providerMetadata === void 0 ? {} : { providerMetadata: chunk.providerMetadata }
509
- };
510
- activeReasoning.set(chunk.id, part);
511
- parts.push(part);
512
- break;
513
- }
514
- case "reasoning-delta": {
515
- let part = activeReasoning.get(chunk.id);
516
- if (!part) {
517
- part = {
518
- type: "reasoning",
519
- text: "",
520
- state: "streaming"
521
- };
522
- activeReasoning.set(chunk.id, part);
523
- parts.push(part);
524
- }
525
- part["text"] = `${typeof part["text"] === "string" ? part["text"] : ""}${chunk.delta}`;
526
- setOptional(part, "providerMetadata", chunk.providerMetadata);
527
- break;
528
- }
529
- case "reasoning-end": {
530
- const part = activeReasoning.get(chunk.id);
531
- if (part) {
532
- part["state"] = "done";
533
- setOptional(part, "providerMetadata", chunk.providerMetadata);
534
- activeReasoning.delete(chunk.id);
535
- }
536
- break;
537
- }
538
- case "custom":
539
- parts.push({
540
- type: "custom",
541
- kind: chunk.kind,
542
- ...chunk.providerMetadata === void 0 ? {} : { providerMetadata: chunk.providerMetadata }
543
- });
544
- break;
545
- case "file":
546
- case "reasoning-file":
547
- parts.push({
548
- type: chunk.type,
549
- mediaType: chunk.mediaType,
550
- url: chunk.url,
551
- ...chunk.providerMetadata === void 0 ? {} : { providerMetadata: chunk.providerMetadata }
552
- });
553
- break;
554
- case "source-url":
555
- parts.push({
556
- type: chunk.type,
557
- sourceId: chunk.sourceId,
558
- url: chunk.url,
559
- ...chunk.title === void 0 ? {} : { title: chunk.title },
560
- ...chunk.providerMetadata === void 0 ? {} : { providerMetadata: chunk.providerMetadata }
561
- });
562
- break;
563
- case "source-document":
564
- parts.push({
565
- type: chunk.type,
566
- sourceId: chunk.sourceId,
567
- mediaType: chunk.mediaType,
568
- title: chunk.title,
569
- ...chunk.filename === void 0 ? {} : { filename: chunk.filename },
570
- ...chunk.providerMetadata === void 0 ? {} : { providerMetadata: chunk.providerMetadata }
571
- });
572
- break;
573
- case "tool-input-start":
574
- partialTools.set(chunk.toolCallId, {
575
- text: "",
576
- toolName: chunk.toolName,
577
- dynamic: chunk.dynamic === true,
578
- ...chunk.providerExecuted === void 0 ? {} : { providerExecuted: chunk.providerExecuted },
579
- ...chunk.providerMetadata === void 0 ? {} : { providerMetadata: chunk.providerMetadata },
580
- ...chunk.toolMetadata === void 0 ? {} : { toolMetadata: chunk.toolMetadata },
581
- ...chunk.title === void 0 ? {} : { title: chunk.title }
582
- });
583
- setToolPart({
584
- parts,
585
- toolCallId: chunk.toolCallId,
586
- toolName: chunk.toolName,
587
- dynamic: chunk.dynamic === true,
588
- state: "input-streaming",
589
- providerExecuted: chunk.providerExecuted,
590
- providerMetadata: chunk.providerMetadata,
591
- toolMetadata: chunk.toolMetadata,
592
- title: chunk.title
593
- });
594
- break;
595
- case "tool-input-delta": {
596
- const partial = partialTools.get(chunk.toolCallId);
597
- if (!partial) break;
598
- partial.text += chunk.inputTextDelta;
599
- setToolPart({
600
- parts,
601
- toolCallId: chunk.toolCallId,
602
- toolName: partial.toolName,
603
- dynamic: partial.dynamic,
604
- state: "input-streaming",
605
- input: parsePartialJSON(partial.text),
606
- providerExecuted: partial.providerExecuted,
607
- providerMetadata: partial.providerMetadata,
608
- toolMetadata: partial.toolMetadata,
609
- title: partial.title
610
- });
611
- break;
612
- }
613
- case "tool-input-available":
614
- setToolPart({
615
- parts,
616
- toolCallId: chunk.toolCallId,
617
- toolName: chunk.toolName,
618
- dynamic: chunk.dynamic === true,
619
- state: "input-available",
620
- input: chunk.input,
621
- providerExecuted: chunk.providerExecuted,
622
- providerMetadata: chunk.providerMetadata,
623
- toolMetadata: chunk.toolMetadata,
624
- title: chunk.title
625
- });
626
- partialTools.delete(chunk.toolCallId);
627
- break;
628
- case "tool-input-error": {
629
- const dynamic = findToolPart(parts, chunk.toolCallId)?.["type"] === "dynamic-tool" || chunk.dynamic;
630
- setToolPart({
631
- parts,
632
- toolCallId: chunk.toolCallId,
633
- toolName: chunk.toolName,
634
- dynamic: dynamic === true,
635
- state: "output-error",
636
- input: dynamic ? chunk.input : void 0,
637
- rawInput: dynamic ? void 0 : chunk.input,
638
- errorText: chunk.errorText,
639
- providerExecuted: chunk.providerExecuted,
640
- providerMetadata: chunk.providerMetadata,
641
- toolMetadata: chunk.toolMetadata,
642
- title: chunk.title
643
- });
644
- partialTools.delete(chunk.toolCallId);
645
- break;
646
- }
647
- case "tool-approval-request": {
648
- const part = findToolPart(parts, chunk.toolCallId);
649
- if (!part) break;
650
- part["state"] = "approval-requested";
651
- part["approval"] = {
652
- id: chunk.approvalId,
653
- ...chunk.isAutomatic === true ? { isAutomatic: true } : {},
654
- ...chunk.signature === void 0 ? {} : { signature: chunk.signature }
655
- };
656
- break;
657
- }
658
- case "tool-approval-response": {
659
- const part = findApprovalPart(parts, chunk.approvalId);
660
- if (!part) break;
661
- const approval = isRecord$1(part["approval"]) ? part["approval"] : {};
662
- part["state"] = "approval-responded";
663
- part["approval"] = {
664
- id: chunk.approvalId,
665
- approved: chunk.approved,
666
- ...chunk.reason === void 0 ? {} : { reason: chunk.reason },
667
- ...approval["isAutomatic"] === true ? { isAutomatic: true } : {},
668
- ...typeof approval["signature"] === "string" ? { signature: approval["signature"] } : {}
669
- };
670
- setOptional(part, "providerExecuted", chunk.providerExecuted);
671
- setOptional(part, "callProviderMetadata", chunk.providerMetadata);
672
- break;
673
- }
674
- case "tool-output-available": {
675
- const part = findToolPart(parts, chunk.toolCallId);
676
- if (!part) break;
677
- setToolPart({
678
- parts,
679
- toolCallId: chunk.toolCallId,
680
- toolName: part["type"] === "dynamic-tool" && typeof part["toolName"] === "string" ? part["toolName"] : String(part["type"]).slice(5),
681
- dynamic: part["type"] === "dynamic-tool",
682
- state: "output-available",
683
- input: part["input"],
684
- output: chunk.output,
685
- preliminary: chunk.preliminary,
686
- providerExecuted: chunk.providerExecuted,
687
- providerMetadata: chunk.providerMetadata,
688
- toolMetadata: chunk.toolMetadata ?? part["toolMetadata"],
689
- title: typeof part["title"] === "string" ? part["title"] : void 0
690
- });
691
- break;
692
- }
693
- case "tool-output-error": {
694
- const part = findToolPart(parts, chunk.toolCallId);
695
- if (!part) break;
696
- setToolPart({
697
- parts,
698
- toolCallId: chunk.toolCallId,
699
- toolName: part["type"] === "dynamic-tool" && typeof part["toolName"] === "string" ? part["toolName"] : String(part["type"]).slice(5),
700
- dynamic: part["type"] === "dynamic-tool",
701
- state: "output-error",
702
- input: part["input"],
703
- rawInput: part["rawInput"],
704
- errorText: chunk.errorText,
705
- providerExecuted: chunk.providerExecuted,
706
- providerMetadata: chunk.providerMetadata,
707
- toolMetadata: chunk.toolMetadata ?? part["toolMetadata"],
708
- title: typeof part["title"] === "string" ? part["title"] : void 0
709
- });
710
- break;
711
- }
712
- case "tool-output-denied": {
713
- const part = findToolPart(parts, chunk.toolCallId);
714
- if (part) part["state"] = "output-denied";
715
- break;
716
- }
717
- case "start-step":
718
- parts.push({ type: "step-start" });
719
- break;
720
- case "finish-step":
721
- activeText.clear();
722
- activeReasoning.clear();
723
- break;
724
- case "start":
725
- if (chunk.messageMetadata !== void 0 && chunk.messageMetadata !== null) record["metadata"] = mergeMetadata(record["metadata"], chunk.messageMetadata);
726
- break;
727
- case "finish":
728
- if (chunk.messageMetadata !== void 0 && chunk.messageMetadata !== null) record["metadata"] = mergeMetadata(record["metadata"], chunk.messageMetadata);
729
- break;
730
- case "message-metadata":
731
- if (chunk.messageMetadata !== void 0 && chunk.messageMetadata !== null) record["metadata"] = mergeMetadata(record["metadata"], chunk.messageMetadata);
732
- break;
733
- case "abort":
734
- case "error": break;
735
- default: {
736
- if (!chunk.type.startsWith("data-") || chunk.transient) break;
737
- const existing = chunk.id === void 0 ? void 0 : parts.find((part) => part["type"] === chunk.type && part["id"] === chunk.id);
738
- if (existing) existing["data"] = chunk.data;
739
- else parts.push({
740
- type: chunk.type,
741
- ...chunk.id === void 0 ? {} : { id: chunk.id },
742
- data: chunk.data
743
- });
744
- }
745
- }
746
- const indexes = new Map(parts.map((part, index) => [part, index]));
747
- return {
748
- message,
749
- cursor: {
750
- text: Object.fromEntries([...activeText].map(([id, part]) => [id, indexes.get(part)])),
751
- reasoning: Object.fromEntries([...activeReasoning].map(([id, part]) => [id, indexes.get(part)])),
752
- tools: Object.fromEntries(partialTools)
753
- }
754
- };
755
- }
756
- function pauseUIMessage(options) {
757
- const next = structuredClone(options.message);
758
- next.parts = next.parts.filter((part) => !("toolCallId" in part && !options.toolCallIds.has(part.toolCallId)));
759
- for (const part of next.parts) if ((part.type === "text" || part.type === "reasoning") && part.state === "streaming") part.state = "done";
760
- return next;
761
- }
762
- function interruptUIMessage(message, toolError = "Tool execution was interrupted.") {
763
- const next = structuredClone(message);
764
- next.parts = next.parts.filter((value) => {
765
- const part = value;
766
- return !isToolPart(part) || part["state"] !== "input-streaming";
767
- });
768
- for (const value of next.parts) {
769
- if (value["type"] === "text" || value["type"] === "reasoning") {
770
- if (value["state"] === "streaming") value["state"] = "done";
771
- continue;
772
- }
773
- if (!isToolPart(value)) continue;
774
- const state = value["state"];
775
- if (state === "approval-responded") {
776
- const approval = value["approval"];
777
- if (isRecord$1(approval) && approval["approved"] === false) {
778
- value["state"] = "output-denied";
779
- continue;
780
- }
781
- }
782
- if (state === "output-available" && value["preliminary"] === true) {
783
- delete value["output"];
784
- delete value["preliminary"];
785
- value["state"] = "output-error";
786
- value["errorText"] = toolError;
787
- continue;
788
- }
789
- if (state === "input-available" || state === "approval-requested" || state === "approval-responded") {
790
- if (state === "approval-requested") delete value["approval"];
791
- value["state"] = "output-error";
792
- value["errorText"] = toolError;
793
- }
794
- }
795
- return next;
796
- }
797
- //#endregion
798
- //#region src/ai-progress-batches.ts
799
- const PAGE_SIZE = 64;
800
- const appendProgressBatch = ({ batches, batch }) => {
801
- if (batches.tail.length < PAGE_SIZE) return {
802
- ...batches,
803
- length: batches.length + 1,
804
- tail: [...batches.tail, batch]
805
- };
806
- const blocks = [...batches.blocks];
807
- let block = batches.tail;
808
- let level = 0;
809
- for (;;) {
810
- const left = blocks[level];
811
- if (left == null) break;
812
- block = {
813
- left,
814
- right: block
815
- };
816
- blocks[level] = null;
817
- level += 1;
818
- }
819
- blocks[level] = block;
820
- return {
821
- length: batches.length + 1,
822
- tail: [batch],
823
- blocks
824
- };
825
- };
826
- const progressBatches = (items = []) => {
827
- let batches = {
828
- length: 0,
829
- tail: [],
830
- blocks: []
831
- };
832
- for (const batch of items) batches = appendProgressBatch({
833
- batches,
834
- batch
835
- });
836
- return batches;
837
- };
838
- const flattenProgressBatches = (batches) => {
839
- const items = [];
840
- const visit = (block) => {
841
- if (Array.isArray(block)) items.push(...block);
842
- else {
843
- visit(block.left);
844
- visit(block.right);
845
- }
846
- };
847
- for (let level = batches.blocks.length - 1; level >= 0; level -= 1) {
848
- const block = batches.blocks[level];
849
- if (block) visit(block);
850
- }
851
- items.push(...batches.tail);
852
- return items;
853
- };
854
- //#endregion
855
- //#region src/ai.ts
856
- const issue = (message) => ({ issues: [{ message }] });
857
- const schema = (label, parse) => ({ "~standard": {
858
- version: 1,
859
- vendor: "a2",
860
- validate(value) {
861
- try {
862
- return parse(value);
863
- } catch (error) {
864
- return issue(`${label}: ${error instanceof Error ? error.message : String(error)}`);
865
- }
866
- }
867
- } });
868
- const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
869
- const isJSONCompatible = (value, seen = /* @__PURE__ */ new Set()) => {
870
- if (value === null || typeof value === "string" || typeof value === "boolean") return true;
871
- if (typeof value === "number") return Number.isFinite(value);
872
- if (typeof value === "undefined") return true;
873
- if (typeof value !== "object") return false;
874
- if (seen.has(value)) return false;
875
- seen.add(value);
876
- const valid = Array.isArray(value) ? value.every((item) => isJSONCompatible(item, seen)) : Object.getPrototypeOf(value) === Object.prototype && Object.values(value).every((item) => isJSONCompatible(item, seen));
877
- seen.delete(value);
878
- return valid;
879
- };
880
- const jsonObject = (label, check) => schema(label, (value) => {
881
- if (!isRecord(value) || !isJSONCompatible(value) || !check(value)) return issue(`invalid ${label}`);
882
- return { value };
883
- });
884
- const stringField = (value, key) => typeof value[key] === "string" && value[key].length > 0;
885
- const optionalIndexField = (value, key) => value[key] === void 0 || typeof value[key] === "number" && Number.isSafeInteger(value[key]) && value[key] >= 0;
886
- const optionalStringField = (value, key) => value[key] === void 0 || typeof value[key] === "string";
887
- const messageValue = (value) => isRecord(value) && typeof value["id"] === "string" && (value["role"] === "user" || value["role"] === "assistant" || value["role"] === "system") && Array.isArray(value["parts"]) && value["parts"].every((part) => isRecord(part) && typeof part["type"] === "string") && isJSONCompatible(value);
888
- const validateMessage = (value, messageSchema) => {
889
- if (!messageValue(value)) return issue("invalid AI SDK UIMessage");
890
- if (!messageSchema) return { value };
891
- return validateSync(messageSchema, value, "the AI message");
892
- };
893
- const messagePayloadSchema = (messageSchema) => schema("ai.message.created", (value) => {
894
- if (!isRecord(value)) return issue("invalid ai.message.created payload");
895
- const message = validateMessage(value["message"], messageSchema);
896
- if (message.issues) return { issues: message.issues };
897
- const generate = value["generate"];
898
- if (generate !== void 0 && typeof generate !== "boolean") return issue("invalid ai.message.created generate flag");
899
- return { value: {
900
- message: message.value,
901
- ...generate === false ? { generate: false } : {}
902
- } };
903
- });
904
- const progressPayloadSchema = schema("ai.generation.progress", (value) => {
905
- if (!isRecord(value) || !isJSONCompatible(value) || !stringField(value, "requestId") || !stringField(value, "messageId") || !stringField(value, "generationId") || !stringField(value, "responseMessageId") || typeof value["sequence"] !== "number" || !Number.isInteger(value["sequence"]) || value["sequence"] < 0 || !Array.isArray(value["chunks"]) || !value["chunks"].every((chunk) => isRecord(chunk) && typeof chunk["type"] === "string")) return issue("invalid ai.generation.progress payload");
906
- return { value };
907
- });
908
- const completedPayloadSchema = schema("ai.generation.completed", (value) => {
909
- if (!isRecord(value) || !isJSONCompatible(value) || !stringField(value, "requestId") || !stringField(value, "messageId") || !stringField(value, "generationId") || !stringField(value, "responseMessageId") || !optionalIndexField(value, "inputTokenEstimate") || !optionalStringField(value, "finishReason")) return issue("invalid ai.generation.completed payload");
910
- return { value };
911
- });
912
- const compactionPayloadSchema = (messageSchema) => schema("ai.compaction.completed", (value) => {
913
- if (!isRecord(value) || !isJSONCompatible(value) || !stringField(value, "generationId") || !stringField(value, "throughMessageId") || !optionalIndexField(value, "throughIndex") || !optionalStringField(value, "summary") || !Array.isArray(value["messages"]) || value["retainedMessageIds"] !== void 0 && (!Array.isArray(value["retainedMessageIds"]) || !value["retainedMessageIds"].every((candidate) => typeof candidate === "string"))) return issue("invalid ai.compaction.completed payload");
914
- const messages = [];
915
- for (const candidate of value["messages"]) {
916
- const result = validateMessage(candidate, messageSchema);
917
- if (result.issues) return { issues: result.issues };
918
- messages.push(result.value);
919
- }
920
- return { value: {
921
- generationId: value["generationId"],
922
- throughMessageId: value["throughMessageId"],
923
- ...value["throughIndex"] === void 0 ? {} : { throughIndex: value["throughIndex"] },
924
- messages,
925
- ...value["summary"] === void 0 ? {} : { summary: value["summary"] },
926
- ...value["usage"] === void 0 ? {} : { usage: value["usage"] },
927
- ...value["retainedMessageIds"] === void 0 ? {} : { retainedMessageIds: value["retainedMessageIds"] }
928
- } };
929
- });
930
- function createEvents(options) {
931
- const messageSchema = options?.messageSchema;
932
- if (messageSchema) assertSyncSchema(messageSchema, "the AI message schema");
933
- const definition = {
934
- "ai.control.requested": schema("ai.control.requested", (value) => {
935
- if (!isRecord(value) || !isJSONCompatible(value)) return issue("invalid AI command");
936
- const action = value["action"];
937
- const forwarded = {
938
- approval: ["ai.approval.responded", "response"],
939
- "tool-result": ["ai.tool.result", "result"],
940
- input: ["ai.input.responded", "response"],
941
- "request-input": ["ai.input.requested", "request"],
942
- retry: ["ai.retry.requested", "request"],
943
- interrupt: ["ai.message.interrupted", "request"]
944
- };
945
- if (typeof action === "string" && Object.hasOwn(forwarded, action)) {
946
- const [type, key] = forwarded[action];
947
- const payload = validateSync(definition[type], value[key], "AI command");
948
- if (payload.issues) return { issues: payload.issues };
949
- return { value: {
950
- action,
951
- [key]: payload.value
952
- } };
953
- }
954
- if (action === "send" || action === "edit" || action === "steer") {
955
- const parsed = validateMessage(value["message"], messageSchema);
956
- if (parsed.issues) return parsed;
957
- if (action === "edit" && (!Number.isSafeInteger(value["expectedRevision"]) || Number(value["expectedRevision"]) < 0) || action === "steer" && (!stringField(value, "turnId") || !optionalIndexField(value, "lastSeenIndex")) || action === "send" && value["generate"] !== void 0 && typeof value["generate"] !== "boolean") return issue("invalid AI command");
958
- return { value: {
959
- ...value,
960
- message: parsed.value
961
- } };
962
- }
963
- if (action === "remove" && stringField(value, "inputId") || action === "send-now" && stringField(value, "inputId") && (value["turnId"] === null || stringField(value, "turnId")) && optionalIndexField(value, "lastSeenIndex") || action === "move" && stringField(value, "inputId") && (value["beforeId"] === null || stringField(value, "beforeId")) || action === "stop" && stringField(value, "turnId") && optionalIndexField(value, "lastSeenIndex") || action === "pause" && (value["when"] === "now" || value["when"] === "after-turn") || action === "resume") return { value };
964
- return issue("invalid AI command");
965
- }),
966
- "ai.control.committed": jsonObject("ai.control.committed", (value) => Array.isArray(value["changes"]) && isRecord(value["view"])),
967
- "ai.control.decided": jsonObject("ai.control.decided", (value) => stringField(value, "commandId") && (value["outcome"] === "applied" || value["outcome"] === "rejected")),
968
- "ai.work.reported": schema("ai.work.reported", (value) => {
969
- if (!isRecord(value) || !isJSONCompatible(value) || !stringField(value, "workId") || !stringField(value, "turnId") || typeof value["version"] !== "number" || !optionalIndexField(value, "version") || typeof value["attempt"] !== "number" || !Number.isSafeInteger(value["attempt"]) || value["attempt"] < 1 || typeof value["settled"] !== "boolean" || value["kind"] !== "model" && value["kind"] !== "tool" || !Array.isArray(value["events"])) return issue("invalid AI work report");
970
- const allowed = /* @__PURE__ */ new Set([
971
- "ai.generation.started",
972
- "ai.generation.completed",
973
- "ai.generation.failed",
974
- "ai.tool.called",
975
- "ai.tool.result",
976
- "ai.approval.requested",
977
- "ai.approval.responded",
978
- "ai.compaction.requested",
979
- "ai.compaction.completed",
980
- "ai.model.metadata.requested"
981
- ]);
982
- const events = [];
983
- for (const event of value["events"]) {
984
- if (!isRecord(event) || !stringField(event, "id") || typeof event["type"] !== "string" || !allowed.has(event["type"]) || value["kind"] === "tool" && event["type"] !== "ai.tool.result") return issue("invalid AI work fact");
985
- const parsed = validateSync(definition[event["type"]], event["payload"], "AI work fact");
986
- if (parsed.issues) return { issues: parsed.issues };
987
- events.push({
988
- id: event["id"],
989
- type: event["type"],
990
- payload: parsed.value
991
- });
992
- }
993
- return { value: {
994
- ...value,
995
- events
996
- } };
997
- }),
998
- "ai.tool.execution.requested": jsonObject("ai.tool.execution.requested", (value) => stringField(value, "turnId") && optionalIndexField(value, "version") && isRecord(value["call"]) && isRecord(value["generation"])),
999
- "ai.generation.paused": jsonObject("ai.generation.paused", (value) => stringField(value, "generationId") && stringField(value, "messageId")),
1000
- "ai.session.created": jsonObject("ai.session.created", () => true),
1001
- "ai.session.closed": jsonObject("ai.session.closed", (value) => optionalStringField(value, "reason")),
1002
- "ai.message.created": messagePayloadSchema(messageSchema),
1003
- "ai.message.completed": jsonObject("ai.message.completed", (value) => stringField(value, "messageId")),
1004
- "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)),
1005
- "ai.generation.requested": jsonObject("ai.generation.requested", (value) => stringField(value, "messageId") && optionalStringField(value, "responseMessageId") && (value["reason"] === "message" || value["reason"] === "tool" || value["reason"] === "input" || value["reason"] === "retry" || value["reason"] === "resume")),
1006
- "ai.retry.requested": jsonObject("ai.retry.requested", (value) => stringField(value, "messageId") && stringField(value, "responseMessageId") && stringField(value, "retryId")),
1007
- "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")),
1008
- "ai.generation.progress": progressPayloadSchema,
1009
- "ai.generation.completed": completedPayloadSchema,
1010
- "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")),
1011
- "ai.tool.called": jsonObject("ai.tool.called", (value) => stringField(value, "requestId") && stringField(value, "messageId") && stringField(value, "generationId") && stringField(value, "toolCallId") && stringField(value, "toolName") && (value["dynamic"] === void 0 || typeof value["dynamic"] === "boolean") && (value["providerExecuted"] === void 0 || typeof value["providerExecuted"] === "boolean") && (value["supportsDeferredResults"] === void 0 || typeof value["supportsDeferredResults"] === "boolean") && optionalStringField(value, "title")),
1012
- "ai.tool.result": jsonObject("ai.tool.result", (value) => stringField(value, "requestId") && stringField(value, "messageId") && stringField(value, "generationId") && stringField(value, "toolCallId") && optionalStringField(value, "toolName") && optionalStringField(value, "error") && (value["denied"] === void 0 || typeof value["denied"] === "boolean") && (value["preliminary"] === void 0 || typeof value["preliminary"] === "boolean") && (value["phase"] === void 0 || value["phase"] === "input" || value["phase"] === "execution") && (value["dynamic"] === void 0 || typeof value["dynamic"] === "boolean") && (value["providerExecuted"] === void 0 || typeof value["providerExecuted"] === "boolean")),
1013
- "ai.approval.requested": jsonObject("ai.approval.requested", (value) => stringField(value, "messageId") && stringField(value, "generationId") && stringField(value, "approvalId") && stringField(value, "toolCallId") && (value["isAutomatic"] === void 0 || typeof value["isAutomatic"] === "boolean") && optionalStringField(value, "signature")),
1014
- "ai.approval.responded": jsonObject("ai.approval.responded", (value) => stringField(value, "messageId") && stringField(value, "generationId") && stringField(value, "approvalId") && typeof value["approved"] === "boolean" && optionalStringField(value, "reason")),
1015
- "ai.input.requested": jsonObject("ai.input.requested", (value) => stringField(value, "messageId") && stringField(value, "generationId") && stringField(value, "inputId") && stringField(value, "name")),
1016
- "ai.input.responded": jsonObject("ai.input.responded", (value) => stringField(value, "messageId") && stringField(value, "generationId") && stringField(value, "inputId") && stringField(value, "name")),
1017
- "ai.compaction.requested": jsonObject("ai.compaction.requested", (value) => stringField(value, "generationId") && stringField(value, "throughMessageId") && optionalIndexField(value, "throughIndex")),
1018
- "ai.compaction.completed": compactionPayloadSchema(messageSchema),
1019
- "ai.model.metadata.requested": jsonObject("ai.model.metadata.requested", (value) => stringField(value, "modelId")),
1020
- "ai.model.metadata.resolved": jsonObject("ai.model.metadata.resolved", (value) => stringField(value, "modelId") && (value["limits"] === null || isRecord(value["limits"]) && typeof value["limits"]["contextWindow"] === "number" && Number.isSafeInteger(value["limits"]["contextWindow"]) && value["limits"]["contextWindow"] > 0 && typeof value["limits"]["maxOutputTokens"] === "number" && Number.isSafeInteger(value["limits"]["maxOutputTokens"]) && value["limits"]["maxOutputTokens"] > 0))
1021
- };
1022
- return definition;
1023
- }
1024
- const events = createEvents();
1025
- const initialState = () => ({
1026
- inbox: initialControlState().inbox,
1027
- pendingQueueCommands: [],
1028
- active: null,
1029
- starting: false,
1030
- receipt: null,
1031
- session: { created: false },
1032
- messages: [],
1033
- status: "idle",
1034
- activeGeneration: null,
1035
- activeRequestId: null,
1036
- activeResponseMessageId: null,
1037
- activeProjection: null,
1038
- responseGenerationIds: {},
1039
- pendingApprovals: [],
1040
- pendingInputs: [],
1041
- tools: [],
1042
- compaction: null,
1043
- modelMetadata: {},
1044
- usage: [],
1045
- error: null
1046
- });
1047
- const upsertMessage = (messages, message) => {
1048
- const index = messages.findIndex((candidate) => candidate.id === message.id);
1049
- if (index === -1) return [...messages, message];
1050
- const next = [...messages];
1051
- next[index] = message;
1052
- return next;
1053
- };
1054
- const upsertResponse = (options) => {
1055
- const { messages, message, inputId } = options;
1056
- if (messages.some((item) => item.id === message.id)) return upsertMessage(messages, message);
1057
- const inputIndex = messages.findIndex((item) => item.id === inputId);
1058
- if (inputIndex === -1) return [...messages, message];
1059
- return [
1060
- ...messages.slice(0, inputIndex + 1),
1061
- message,
1062
- ...messages.slice(inputIndex + 1)
1063
- ];
1064
- };
1065
- const answerApproval = (messages, response) => messages.map((message) => {
1066
- if (message.id !== response.messageId) return message;
1067
- let changed = false;
1068
- const parts = message.parts.map((part) => {
1069
- const candidate = part;
1070
- if (!isRecord(candidate) || candidate["state"] !== "approval-requested" || !isRecord(candidate["approval"]) || candidate["approval"]["id"] !== response.approvalId) return part;
1071
- changed = true;
1072
- return {
1073
- ...part,
1074
- state: "approval-responded",
1075
- approval: {
1076
- ...candidate["approval"],
1077
- approved: response.approved,
1078
- ...response.reason === void 0 ? {} : { reason: response.reason }
1079
- }
1080
- };
1081
- });
1082
- return changed ? {
1083
- ...message,
1084
- parts
1085
- } : message;
1086
- });
1087
- const projectMessageChunks = (messages, messageId, chunks) => messages.map((message) => message.id === messageId ? projectUIMessage({
1088
- messageId,
1089
- base: message,
1090
- chunks
1091
- }) : message);
1092
- const approvalRequestedChunk = (payload) => ({
1093
- type: "tool-approval-request",
1094
- approvalId: payload.approvalId,
1095
- toolCallId: payload.toolCallId,
1096
- ...payload.isAutomatic === void 0 ? {} : { isAutomatic: payload.isAutomatic },
1097
- ...payload.signature === void 0 ? {} : { signature: payload.signature }
1098
- });
1099
- const approvalRespondedChunk = (payload) => ({
1100
- type: "tool-approval-response",
1101
- approvalId: payload.approvalId,
1102
- approved: payload.approved,
1103
- ...payload.reason === void 0 ? {} : { reason: payload.reason }
1104
- });
1105
- const toolResultChunk = (payload) => {
1106
- if (payload.phase === "input") return {
1107
- type: "tool-input-error",
1108
- toolCallId: payload.toolCallId,
1109
- toolName: payload.toolName ?? "unknown",
1110
- input: payload.rawInput ?? payload.input,
1111
- errorText: payload.error ?? "Invalid tool input",
1112
- ...payload.dynamic === void 0 ? {} : { dynamic: payload.dynamic },
1113
- ...payload.providerExecuted === void 0 ? {} : { providerExecuted: payload.providerExecuted },
1114
- ...payload.providerMetadata === void 0 ? {} : { providerMetadata: payload.providerMetadata },
1115
- ...payload.toolMetadata === void 0 ? {} : { toolMetadata: payload.toolMetadata }
1116
- };
1117
- if (payload.denied === true) return {
1118
- type: "tool-output-denied",
1119
- toolCallId: payload.toolCallId
1120
- };
1121
- if (payload.error !== void 0) return {
1122
- type: "tool-output-error",
1123
- toolCallId: payload.toolCallId,
1124
- errorText: payload.error,
1125
- ...payload.dynamic === void 0 ? {} : { dynamic: payload.dynamic },
1126
- ...payload.providerExecuted === void 0 ? {} : { providerExecuted: payload.providerExecuted },
1127
- ...payload.providerMetadata === void 0 ? {} : { providerMetadata: payload.providerMetadata },
1128
- ...payload.toolMetadata === void 0 ? {} : { toolMetadata: payload.toolMetadata }
1129
- };
1130
- return {
1131
- type: "tool-output-available",
1132
- toolCallId: payload.toolCallId,
1133
- output: payload.output,
1134
- ...payload.preliminary === void 0 ? {} : { preliminary: payload.preliminary },
1135
- ...payload.dynamic === void 0 ? {} : { dynamic: payload.dynamic },
1136
- ...payload.providerExecuted === void 0 ? {} : { providerExecuted: payload.providerExecuted },
1137
- ...payload.providerMetadata === void 0 ? {} : { providerMetadata: payload.providerMetadata },
1138
- ...payload.toolMetadata === void 0 ? {} : { toolMetadata: payload.toolMetadata }
1139
- };
1140
- };
1141
- const waitingStatus = (state) => {
1142
- if (state.pendingApprovals.length > 0 || state.pendingInputs.length > 0) return "waiting";
1143
- return state.activeGeneration !== null || state.tools.some((activity) => activity.status === "running") ? "generating" : "idle";
1144
- };
1145
- const lifecycleStatus = (previous, next) => previous.status === "failed" ? "failed" : waitingStatus(next);
1146
- const isStaleGeneration = (state, messageId, generationId) => {
1147
- const current = state.responseGenerationIds[messageId];
1148
- return current !== void 0 && current !== generationId;
1149
- };
1150
- const projectedMessageStream = (projection) => {
1151
- const projectionEvents = flattenProgressBatches(projection.batches);
1152
- for (const event of projection.toolEvents) if (event.type === "ai.tool.result") projectionEvents.push({
1153
- index: event.index,
1154
- chunks: [toolResultChunk(event.payload)]
1155
- });
1156
- for (const event of projection.approvalEvents) projectionEvents.push({
1157
- index: event.index,
1158
- chunks: [event.type === "ai.approval.requested" ? approvalRequestedChunk(event.payload) : approvalRespondedChunk(event.payload)]
1159
- });
1160
- return projectUIMessageStream({
1161
- messageId: projection.responseMessageId,
1162
- ...projection.baseMessage === void 0 ? {} : { base: projection.baseMessage },
1163
- chunks: projectionEvents.toSorted((left, right) => left.index - right.index).flatMap((event) => event.chunks)
1164
- });
1165
- };
1166
- const projectedMessage = (projection) => projectedMessageStream(projection).message;
1167
- const projectedResponse = (options) => {
1168
- const message = projectedMessage(options.projection);
1169
- return options.state.pausedGenerationIds?.[options.projection.generationId] ? pauseUIMessage({
1170
- message,
1171
- toolCallIds: new Set(options.state.tools.map((tool) => tool.toolCallId))
1172
- }) : message;
1173
- };
1174
- const reduceToolActivity = (tools, event) => {
1175
- if (event.type === "ai.tool.called") {
1176
- const payload = event.payload;
1177
- const { providerMetadata, ...called } = payload;
1178
- const activity = {
1179
- ...called,
1180
- ...providerMetadata === void 0 ? {} : { callProviderMetadata: providerMetadata },
1181
- status: "running"
1182
- };
1183
- return [...tools.filter((candidate) => candidate.generationId !== payload.generationId || candidate.toolCallId !== payload.toolCallId), activity];
1184
- }
1185
- const payload = event.payload;
1186
- const existing = tools.find((candidate) => candidate.generationId === payload.generationId && candidate.toolCallId === payload.toolCallId);
1187
- const toolName = payload.toolName ?? existing?.toolName;
1188
- const input = payload.input === void 0 ? existing?.input : payload.input;
1189
- const dynamic = payload.dynamic ?? existing?.dynamic;
1190
- const providerExecuted = payload.providerExecuted ?? existing?.providerExecuted;
1191
- const toolMetadata = payload.toolMetadata ?? existing?.toolMetadata;
1192
- const resultProviderMetadata = payload.providerMetadata ?? existing?.resultProviderMetadata;
1193
- const activity = {
1194
- requestId: payload.requestId,
1195
- messageId: payload.messageId,
1196
- generationId: payload.generationId,
1197
- toolCallId: payload.toolCallId,
1198
- ...toolName === void 0 ? {} : { toolName },
1199
- ...input === void 0 ? {} : { input },
1200
- ...payload.rawInput === void 0 ? {} : { rawInput: payload.rawInput },
1201
- ...payload.output === void 0 ? {} : { output: payload.output },
1202
- ...payload.error === void 0 ? {} : { error: payload.error },
1203
- ...payload.preliminary === void 0 ? {} : { preliminary: payload.preliminary },
1204
- ...payload.phase === void 0 ? {} : { phase: payload.phase },
1205
- ...dynamic === void 0 ? {} : { dynamic },
1206
- ...providerExecuted === void 0 ? {} : { providerExecuted },
1207
- ...existing?.callProviderMetadata === void 0 ? {} : { callProviderMetadata: existing.callProviderMetadata },
1208
- ...resultProviderMetadata === void 0 ? {} : { resultProviderMetadata },
1209
- ...toolMetadata === void 0 ? {} : { toolMetadata },
1210
- ...existing?.title === void 0 ? {} : { title: existing.title },
1211
- status: payload.denied ? "denied" : payload.error ? "failed" : payload.preliminary ? "running" : "completed"
1212
- };
1213
- return [...tools.filter((candidate) => candidate.generationId !== payload.generationId || candidate.toolCallId !== payload.toolCallId), activity];
1214
- };
1215
- const projectedTools = (projection) => projection.toolEvents.reduce((tools, event) => reduceToolActivity(tools, event), projection.baseTools);
1216
- const restoreGenerationBase = (state, generationId, responseMessageId, reason) => {
1217
- const projection = state.activeProjection?.generationId === generationId ? state.activeProjection : null;
1218
- return {
1219
- ...state,
1220
- messages: projection?.baseMessage === void 0 ? state.messages.filter((message) => message.id !== responseMessageId) : upsertMessage(state.messages, projection.baseMessage),
1221
- tools: projection === null ? state.tools.filter((activity) => activity.generationId !== generationId) : projection.baseTools,
1222
- pendingApprovals: state.pendingApprovals.filter((approval) => approval.generationId !== generationId),
1223
- pendingInputs: state.pendingInputs.filter((input) => input.generationId !== generationId),
1224
- activeGeneration: null,
1225
- activeProjection: null,
1226
- terminalGenerations: {
1227
- ...state.terminalGenerations,
1228
- [generationId]: reason
1229
- },
1230
- compaction: projection === null ? state.compaction?.generationId === generationId ? null : state.compaction : projection.baseCompaction ?? null
1231
- };
1232
- };
1233
- const stopGenerationTools = (tools, generationId, responseMessageId, error) => tools.map((activity) => activity.status === "running" && (generationId === void 0 ? activity.messageId === responseMessageId : activity.generationId === generationId) ? {
1234
- ...activity,
1235
- status: "failed",
1236
- error,
1237
- preliminary: false
1238
- } : activity);
1239
- const interruptGenerationProjection = (state, generationId, responseMessageId, cutoff) => {
1240
- const projection = state.activeProjection?.generationId === generationId ? state.activeProjection : null;
1241
- if (projection === null) return null;
1242
- const retained = {
1243
- ...projection,
1244
- batches: progressBatches(flattenProgressBatches(projection.batches).filter((batch) => batch.index <= cutoff)),
1245
- toolEvents: projection.toolEvents.filter((toolEvent) => toolEvent.index <= cutoff),
1246
- approvalEvents: projection.approvalEvents.filter((approvalEvent) => approvalEvent.index <= cutoff)
1247
- };
1248
- const shouldProject = retained.baseMessage !== void 0 || retained.batches.length > 0;
1249
- const restored = restoreGenerationBase(state, generationId, responseMessageId, "interrupted");
1250
- return {
1251
- ...restored,
1252
- messages: shouldProject ? upsertMessage(state.messages, interruptUIMessage(projectedMessage(retained))) : restored.messages,
1253
- tools: stopGenerationTools(projectedTools(retained), generationId, responseMessageId, "Tool execution was interrupted."),
1254
- usage: projection.completionIndex === void 0 || projection.completionIndex <= cutoff ? restored.usage : restored.usage.filter((entry) => entry.generationId !== generationId)
1255
- };
1256
- };
1257
- const generationRequestId = (generationId) => {
1258
- const markerIndex = generationId.lastIndexOf(":generation:");
1259
- return markerIndex === -1 ? void 0 : generationId.slice(0, markerIndex);
1260
- };
1261
- const terminalGenerationReason = (state, generationId) => {
1262
- const terminal = state.terminalGenerations?.[generationId];
1263
- if (terminal !== void 0) return terminal;
1264
- const requestId = generationRequestId(generationId);
1265
- return requestId !== void 0 && state.terminalRequestIds?.[requestId] === true ? "interrupted" : void 0;
1266
- };
1267
- /** Pure projection of the built-in AI protocol. Unknown extension events are ignored. */
1268
- function reduceAIState(state, event) {
1269
- if (state.status === "closed") return state;
1270
- switch (event.type) {
1271
- case "ai.control.requested": {
1272
- const command = event.payload;
1273
- if (!event.id || !isQueueCommand(command)) return state;
1274
- const pending = state.pendingQueueCommands ?? [];
1275
- if (pending.some((item) => item.commandId === event.id)) return state;
1276
- if ((command.action === "send" || command.action === "steer") && (state.messages.some((message) => message.id === command.message.id) || state.inbox.items.some((item) => item.id === command.message.id))) return state;
1277
- return {
1278
- ...state,
1279
- pendingQueueCommands: [...pending, {
1280
- commandId: event.id,
1281
- command
1282
- }]
1283
- };
1284
- }
1285
- case "ai.control.committed": {
1286
- const commit = event.payload;
1287
- const visible = applyControlChanges({
1288
- state: {
1289
- inbox: state.inbox,
1290
- active: state.active
1291
- },
1292
- changes: commit.changes.filter((change) => change.path[0] === "inbox" || change.path[0] === "active")
1293
- });
1294
- const { phase } = commit.view;
1295
- const status = commit.view.closed ? "closed" : phase === "paused" || phase === "pausing" || commit.view.paused && phase === null ? "paused" : phase === "failed" ? "failed" : phase === "starting" || phase === "generating" ? "generating" : phase ? "waiting" : "idle";
1296
- return {
1297
- ...state,
1298
- ...visible,
1299
- status,
1300
- activeRequestId: commit.view.requestId,
1301
- activeResponseMessageId: commit.view.responseMessageId
1302
- };
1303
- }
1304
- case "ai.control.decided": {
1305
- const receipt = event.payload;
1306
- if (receipt.work) return state;
1307
- const pending = state.pendingQueueCommands ?? [];
1308
- const settled = pending.find((item) => item.commandId === receipt.commandId);
1309
- return {
1310
- ...state,
1311
- receipt,
1312
- ...settled === void 0 ? {} : { pendingQueueCommands: pending.filter((item) => item.commandId !== receipt.commandId) }
1313
- };
1314
- }
1315
- case "ai.generation.paused": {
1316
- const payload = event.payload;
1317
- const toolCallIds = new Set(state.tools.filter((tool) => tool.messageId === payload.messageId).map((tool) => tool.toolCallId));
1318
- const projection = state.activeProjection;
1319
- return {
1320
- ...state,
1321
- activeGeneration: null,
1322
- activeProjection: projection?.generationId === payload.generationId ? {
1323
- ...projection,
1324
- cursor: null,
1325
- batches: progressBatches(flattenProgressBatches(projection.batches).map((batch) => ({
1326
- index: batch.index,
1327
- chunks: batch.chunks.filter((chunk) => !("toolCallId" in chunk) || toolCallIds.has(chunk.toolCallId))
1328
- })))
1329
- } : projection,
1330
- compaction: state.compaction?.status === "running" ? projection?.baseCompaction ?? null : state.compaction,
1331
- messages: state.messages.map((message) => message.id === payload.messageId ? pauseUIMessage({
1332
- message,
1333
- toolCallIds
1334
- }) : message),
1335
- pausedGenerationIds: {
1336
- ...state.pausedGenerationIds,
1337
- [payload.generationId]: true
1338
- }
1339
- };
1340
- }
1341
- case "ai.model.metadata.requested": {
1342
- const { modelId } = event.payload;
1343
- if (Object.hasOwn(state.modelMetadata, modelId)) return state;
1344
- return {
1345
- ...state,
1346
- modelMetadata: {
1347
- ...state.modelMetadata,
1348
- [modelId]: { status: "pending" }
1349
- }
1350
- };
1351
- }
1352
- case "ai.model.metadata.resolved": {
1353
- const { modelId, limits } = event.payload;
1354
- return {
1355
- ...state,
1356
- modelMetadata: {
1357
- ...state.modelMetadata,
1358
- [modelId]: limits === null ? { status: "unavailable" } : {
1359
- status: "resolved",
1360
- limits
1361
- }
1362
- }
1363
- };
1364
- }
1365
- case "ai.session.created": {
1366
- const payload = event.payload;
1367
- return {
1368
- ...state,
1369
- session: {
1370
- created: true,
1371
- ...payload.metadata === void 0 ? state.session.metadata === void 0 ? {} : { metadata: state.session.metadata } : { metadata: payload.metadata }
1372
- }
1373
- };
1374
- }
1375
- case "ai.session.closed": return {
1376
- ...state,
1377
- active: null,
1378
- inbox: {
1379
- paused: true,
1380
- items: []
1381
- },
1382
- pendingQueueCommands: [],
1383
- status: "closed",
1384
- compaction: state.compaction?.status === "running" ? state.activeProjection?.baseCompaction ?? null : state.compaction,
1385
- activeGeneration: null,
1386
- activeRequestId: null,
1387
- activeResponseMessageId: null,
1388
- activeProjection: null
1389
- };
1390
- case "ai.message.created": {
1391
- const { message } = event.payload;
1392
- return {
1393
- ...state,
1394
- messages: upsertMessage(state.messages, message),
1395
- activeProjection: state.activeProjection?.responseMessageId === message.id ? {
1396
- ...state.activeProjection,
1397
- cursor: null
1398
- } : state.activeProjection
1399
- };
1400
- }
1401
- case "ai.message.completed": {
1402
- const { messageId } = event.payload;
1403
- const generationId = state.responseGenerationIds[messageId];
1404
- if (generationId === void 0 || terminalGenerationReason(state, generationId) !== void 0) return state;
1405
- const requestId = generationRequestId(generationId);
1406
- return {
1407
- ...state,
1408
- activeRequestId: null,
1409
- activeResponseMessageId: null,
1410
- activeProjection: state.activeProjection?.generationId === generationId ? null : state.activeProjection,
1411
- terminalGenerations: {
1412
- ...state.terminalGenerations,
1413
- [generationId]: "completed"
1414
- },
1415
- ...requestId === void 0 ? {} : { terminalRequestIds: {
1416
- ...state.terminalRequestIds,
1417
- [requestId]: true
1418
- } }
1419
- };
1420
- }
1421
- case "ai.generation.requested": {
1422
- const payload = event.payload;
1423
- const schedulesToolContinuation = payload.reason === "tool";
1424
- const responseMessageId = payload.responseMessageId ?? (payload.reason === "message" ? `${payload.messageId}:assistant` : payload.messageId);
1425
- const ownerGenerationId = state.responseGenerationIds[responseMessageId] ?? state.activeGeneration?.generationId;
1426
- const ownerRequestId = ownerGenerationId === void 0 ? void 0 : generationRequestId(ownerGenerationId);
1427
- const requestId = event.id;
1428
- if (requestId !== void 0 && state.terminalRequestIds?.[requestId] === true) return state;
1429
- if (!(payload.control !== void 0 && state.activeRequestId === event.id || payload.reason === "message" || (payload.reason === "tool" ? ownerGenerationId !== void 0 && requestId === `ai.generate:tools:${ownerGenerationId}` && state.activeRequestId === ownerRequestId && state.status !== "failed" : payload.reason === "retry" ? state.status === "failed" : ownerGenerationId !== void 0 && requestId?.startsWith(`ai.generate:input:${encodeURIComponent(responseMessageId)}:${encodeURIComponent(ownerGenerationId)}:`) === true && state.activeRequestId === ownerRequestId && state.status !== "failed"))) return state;
1430
- return {
1431
- ...state,
1432
- messages: payload.reason === "retry" && payload.responseMessageId !== void 0 ? state.messages.filter((message) => message.id !== payload.responseMessageId) : state.messages,
1433
- activeProjection: payload.reason === "retry" ? null : state.activeProjection,
1434
- status: schedulesToolContinuation ? state.status : "generating",
1435
- activeRequestId: requestId ?? null,
1436
- activeResponseMessageId: responseMessageId,
1437
- error: schedulesToolContinuation ? state.error : null
1438
- };
1439
- }
1440
- case "ai.generation.started": {
1441
- const payload = event.payload;
1442
- if (state.terminalRequestIds?.[payload.requestId] === true || terminalGenerationReason(state, payload.generationId) !== void 0) return state;
1443
- if (state.activeRequestId !== null && state.activeRequestId !== payload.requestId) return state;
1444
- const currentOwner = state.responseGenerationIds[payload.responseMessageId];
1445
- const currentTerminal = currentOwner === void 0 ? void 0 : terminalGenerationReason(state, currentOwner);
1446
- if (currentTerminal === "completed" || currentTerminal === "interrupted") return state;
1447
- const marker = ":generation:";
1448
- const currentAttempt = currentOwner?.startsWith(`${payload.requestId}${marker}`) ? Number(currentOwner.slice(`${payload.requestId}${marker}`.length)) : void 0;
1449
- if (currentAttempt !== void 0 && Number.isFinite(currentAttempt) && currentAttempt >= payload.attempt) return state;
1450
- const activeGeneration = state.activeGeneration;
1451
- 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;
1452
- const baseMessage = baseState.messages.find((message) => message.id === payload.responseMessageId);
1453
- return {
1454
- ...baseState,
1455
- status: "generating",
1456
- activeGeneration: payload,
1457
- activeResponseMessageId: null,
1458
- responseGenerationIds: {
1459
- ...baseState.responseGenerationIds,
1460
- [payload.responseMessageId]: payload.generationId
1461
- },
1462
- activeProjection: {
1463
- generationId: payload.generationId,
1464
- responseMessageId: payload.responseMessageId,
1465
- promptThroughIndex: payload.promptThroughIndex ?? event.index - 1,
1466
- ...baseMessage === void 0 ? {} : { baseMessage },
1467
- baseCompaction: baseState.compaction,
1468
- batches: progressBatches(),
1469
- baseTools: baseState.tools,
1470
- toolEvents: [],
1471
- approvalEvents: []
1472
- },
1473
- error: null
1474
- };
1475
- }
1476
- case "ai.generation.progress": {
1477
- const payload = event.payload;
1478
- if (state.pausedGenerationIds?.[payload.generationId]) return state;
1479
- if (terminalGenerationReason(state, payload.generationId) !== void 0) return state;
1480
- const activeProjection = state.activeProjection;
1481
- if (state.activeGeneration?.generationId !== payload.generationId || activeProjection?.generationId !== payload.generationId) return state;
1482
- const ordered = event.index > (activeProjection.batches.tail.at(-1)?.index ?? -1);
1483
- const projection = {
1484
- ...activeProjection,
1485
- batches: ordered ? appendProgressBatch({
1486
- batches: activeProjection.batches,
1487
- batch: {
1488
- index: event.index,
1489
- chunks: payload.chunks
1490
- }
1491
- }) : progressBatches([...flattenProgressBatches(activeProjection.batches).filter((batch) => batch.index !== event.index), {
1492
- index: event.index,
1493
- chunks: payload.chunks
1494
- }].toSorted((left, right) => left.index - right.index))
1495
- };
1496
- const base = state.messages.find((message) => message.id === projection.responseMessageId);
1497
- const incremental = base !== void 0 && activeProjection.cursor != null && event.index > activeProjection.cursor.throughIndex;
1498
- const projected = incremental ? projectUIMessageStream({
1499
- messageId: projection.responseMessageId,
1500
- base,
1501
- cursor: activeProjection.cursor.stream,
1502
- chunks: payload.chunks
1503
- }) : projectedMessageStream(projection);
1504
- projection.cursor = {
1505
- throughIndex: incremental ? event.index : Math.max(event.index, projection.batches.tail.at(-1)?.index ?? 0, projection.toolEvents.reduce((index, entry) => Math.max(index, entry.index), 0), projection.approvalEvents.reduce((index, entry) => Math.max(index, entry.index), 0)),
1506
- stream: projected.cursor
1507
- };
1508
- return {
1509
- ...state,
1510
- messages: upsertResponse({
1511
- messages: state.messages,
1512
- message: projected.message,
1513
- inputId: state.activeGeneration.messageId
1514
- }),
1515
- activeProjection: projection,
1516
- status: "generating"
1517
- };
1518
- }
1519
- case "ai.generation.completed": {
1520
- const payload = event.payload;
1521
- if (terminalGenerationReason(state, payload.generationId) !== void 0) return state;
1522
- if (state.activeGeneration?.generationId !== payload.generationId) return state;
1523
- const usage = payload.usage ? [...state.usage.filter((entry) => entry.generationId !== payload.generationId), {
1524
- generationId: payload.generationId,
1525
- usage: payload.usage
1526
- }] : state.usage;
1527
- const next = {
1528
- ...state,
1529
- activeGeneration: null,
1530
- activeProjection: state.activeProjection?.generationId === payload.generationId ? {
1531
- ...state.activeProjection,
1532
- completionIndex: event.index
1533
- } : state.activeProjection,
1534
- usage
1535
- };
1536
- return {
1537
- ...next,
1538
- status: waitingStatus(next)
1539
- };
1540
- }
1541
- case "ai.generation.failed": {
1542
- const payload = event.payload;
1543
- if (terminalGenerationReason(state, payload.generationId) !== void 0) return state;
1544
- if (state.activeGeneration?.generationId !== payload.generationId && !(payload.stepLimit === true && state.responseGenerationIds[payload.responseMessageId] === payload.generationId && state.activeRequestId === `ai.generate:tools:${payload.generationId}` && state.activeResponseMessageId === payload.responseMessageId)) return state;
1545
- if (payload.superseded === true) return restoreGenerationBase(state, payload.generationId, payload.responseMessageId, "superseded");
1546
- const projection = state.activeProjection?.generationId === payload.generationId ? state.activeProjection : null;
1547
- const shouldProject = projection !== null && (projection.baseMessage !== void 0 || projection.batches.length > 0);
1548
- return {
1549
- ...state,
1550
- messages: shouldProject ? upsertMessage(state.messages, interruptUIMessage(projectedMessage(projection), `Generation failed before tool completion: ${payload.error}`)) : state.messages,
1551
- status: "failed",
1552
- activeGeneration: null,
1553
- activeResponseMessageId: null,
1554
- activeProjection: projection,
1555
- terminalGenerations: {
1556
- ...state.terminalGenerations,
1557
- [payload.generationId]: "failed"
1558
- },
1559
- terminalRequestIds: {
1560
- ...state.terminalRequestIds,
1561
- [payload.requestId]: true,
1562
- ...state.activeRequestId === null ? {} : { [state.activeRequestId]: true }
1563
- },
1564
- compaction: projection?.generationId === payload.generationId ? projection.baseCompaction ?? null : state.compaction?.generationId === payload.generationId ? null : state.compaction,
1565
- pendingApprovals: state.pendingApprovals.filter((approval) => approval.generationId !== payload.generationId),
1566
- pendingInputs: state.pendingInputs.filter((input) => input.generationId !== payload.generationId),
1567
- tools: stopGenerationTools(state.tools, payload.generationId, payload.responseMessageId, payload.error),
1568
- error: payload.error
1569
- };
1570
- }
1571
- case "ai.message.interrupted": {
1572
- const payload = event.payload;
1573
- const currentGenerationId = state.responseGenerationIds[payload.messageId];
1574
- const targetRequestId = payload.requestId ?? generationRequestId(payload.generationId);
1575
- const ownsRequestPhase = payload.requestId !== void 0 && state.activeGeneration === null && state.activeRequestId === payload.requestId && state.activeResponseMessageId === payload.messageId;
1576
- if (currentGenerationId !== void 0 && !ownsRequestPhase && (payload.generationId !== void 0 ? currentGenerationId !== payload.generationId : generationRequestId(currentGenerationId) !== payload.requestId)) return state;
1577
- if (state.activeGeneration === null && state.activeRequestId !== null && state.activeResponseMessageId === payload.messageId && targetRequestId !== state.activeRequestId) return state;
1578
- const currentTerminal = currentGenerationId === void 0 ? void 0 : terminalGenerationReason(state, currentGenerationId);
1579
- if (currentTerminal === "completed" || currentTerminal === "interrupted" || currentTerminal === "superseded") return state;
1580
- const active = state.activeGeneration;
1581
- if (active === null) {
1582
- if (payload.requestId !== void 0 && state.activeRequestId !== null && state.activeRequestId === payload.requestId && state.activeResponseMessageId === payload.messageId) {
1583
- const baseState = (currentGenerationId === void 0 ? null : interruptGenerationProjection(state, currentGenerationId, payload.messageId, payload.lastSeenIndex ?? Number.POSITIVE_INFINITY)) ?? state;
1584
- return {
1585
- ...baseState,
1586
- status: "idle",
1587
- activeRequestId: null,
1588
- activeResponseMessageId: null,
1589
- activeProjection: null,
1590
- terminalRequestIds: {
1591
- ...baseState.terminalRequestIds,
1592
- [payload.requestId]: true
1593
- },
1594
- ...currentGenerationId === void 0 ? {} : { terminalGenerations: {
1595
- ...baseState.terminalGenerations,
1596
- [currentGenerationId]: "interrupted"
1597
- } },
1598
- error: null
1599
- };
1600
- }
1601
- const targetGenerationId = payload.generationId ?? (currentGenerationId !== void 0 && generationRequestId(currentGenerationId) === payload.requestId ? currentGenerationId : void 0);
1602
- if (targetGenerationId === void 0) return state;
1603
- if (currentGenerationId !== targetGenerationId) return state;
1604
- const matchesGeneration = (generationId) => targetGenerationId === generationId;
1605
- const hasMessageWork = state.pendingApprovals.some((approval) => approval.messageId === payload.messageId && matchesGeneration(approval.generationId)) || state.pendingInputs.some((input) => input.messageId === payload.messageId && matchesGeneration(input.generationId)) || state.tools.some((activity) => activity.messageId === payload.messageId && activity.status === "running" && matchesGeneration(activity.generationId));
1606
- const resolvesFailedGeneration = state.status === "failed" && currentGenerationId === targetGenerationId && (state.activeRequestId === null || state.activeRequestId === targetRequestId || state.activeRequestId === `ai.generate:tools:${targetGenerationId}`);
1607
- if (!hasMessageWork && !resolvesFailedGeneration && !(currentGenerationId === targetGenerationId && currentTerminal === void 0)) return state;
1608
- const pendingRequestId = state.activeRequestId;
1609
- const projectedState = interruptGenerationProjection(state, targetGenerationId, payload.messageId, payload.lastSeenIndex ?? Number.POSITIVE_INFINITY);
1610
- const baseState = projectedState ?? state;
1611
- const next = {
1612
- ...baseState,
1613
- activeRequestId: null,
1614
- activeResponseMessageId: null,
1615
- activeProjection: null,
1616
- messages: projectedState === null ? state.messages.map((message) => message.id === payload.messageId ? interruptUIMessage(message) : message) : baseState.messages,
1617
- pendingApprovals: baseState.pendingApprovals.filter((approval) => approval.messageId !== payload.messageId || !matchesGeneration(approval.generationId)),
1618
- pendingInputs: baseState.pendingInputs.filter((input) => input.messageId !== payload.messageId || !matchesGeneration(input.generationId)),
1619
- tools: projectedState === null ? stopGenerationTools(state.tools, targetGenerationId, payload.messageId, "Tool execution was interrupted.") : baseState.tools,
1620
- terminalGenerations: {
1621
- ...baseState.terminalGenerations,
1622
- [targetGenerationId]: "interrupted"
1623
- },
1624
- ...pendingRequestId === null ? {} : { terminalRequestIds: {
1625
- ...baseState.terminalRequestIds,
1626
- [pendingRequestId]: true
1627
- } },
1628
- error: resolvesFailedGeneration ? null : state.error
1629
- };
1630
- return {
1631
- ...next,
1632
- status: waitingStatus(next)
1633
- };
1634
- }
1635
- if (payload.messageId !== active.responseMessageId || payload.generationId !== active.generationId && payload.requestId !== active.requestId) return state;
1636
- const cutoff = payload.lastSeenIndex ?? Number.POSITIVE_INFINITY;
1637
- const projectedState = interruptGenerationProjection(state, active.generationId, active.responseMessageId, cutoff);
1638
- const baseState = projectedState ?? restoreGenerationBase(state, active.generationId, active.responseMessageId, "interrupted");
1639
- const next = {
1640
- ...baseState,
1641
- activeRequestId: null,
1642
- activeResponseMessageId: null,
1643
- terminalRequestIds: {
1644
- ...baseState.terminalRequestIds,
1645
- [active.requestId]: true
1646
- },
1647
- tools: projectedState === null ? stopGenerationTools(baseState.tools, active.generationId, active.responseMessageId, "Tool execution was interrupted.") : baseState.tools
1648
- };
1649
- return {
1650
- ...next,
1651
- status: lifecycleStatus(state, next)
1652
- };
1653
- }
1654
- case "ai.tool.called": {
1655
- const payload = event.payload;
1656
- const projection = state.activeProjection;
1657
- if (isStaleGeneration(state, payload.messageId, payload.generationId) || terminalGenerationReason(state, payload.generationId) !== void 0) return state;
1658
- if (state.tools.some((activity) => activity.generationId === payload.generationId && activity.toolCallId === payload.toolCallId && activity.status === "failed" && state.activeGeneration?.generationId !== payload.generationId)) return state;
1659
- if (projection?.generationId !== payload.generationId) {
1660
- const next = {
1661
- ...state,
1662
- tools: reduceToolActivity(state.tools, {
1663
- type: "ai.tool.called",
1664
- payload
1665
- })
1666
- };
1667
- return {
1668
- ...next,
1669
- status: lifecycleStatus(state, next)
1670
- };
1671
- }
1672
- const activeProjection = {
1673
- ...projection,
1674
- toolEvents: [...projection.toolEvents, {
1675
- index: event.index,
1676
- type: "ai.tool.called",
1677
- payload
1678
- }]
1679
- };
1680
- const next = {
1681
- ...state,
1682
- activeProjection,
1683
- tools: projectedTools(activeProjection)
1684
- };
1685
- return {
1686
- ...next,
1687
- status: lifecycleStatus(state, next)
1688
- };
1689
- }
1690
- case "ai.tool.result": {
1691
- const payload = event.payload;
1692
- const projection = state.activeProjection;
1693
- const terminalReason = terminalGenerationReason(state, payload.generationId);
1694
- const completesFailedTool = terminalReason === "failed" && state.status === "failed" && payload.preliminary !== true && projection?.generationId === payload.generationId && projectedTools(projection).some((activity) => activity.generationId === payload.generationId && activity.toolCallId === payload.toolCallId && activity.status === "running");
1695
- if (isStaleGeneration(state, payload.messageId, payload.generationId) || terminalReason !== void 0 && !completesFailedTool) return state;
1696
- if (state.tools.some((activity) => activity.generationId === payload.generationId && activity.toolCallId === payload.toolCallId && activity.status === "failed" && state.activeGeneration?.generationId !== payload.generationId && !completesFailedTool)) return state;
1697
- if (projection?.generationId !== payload.generationId) {
1698
- const next = {
1699
- ...state,
1700
- messages: projectMessageChunks(state.messages, payload.messageId, [toolResultChunk(payload)]),
1701
- tools: reduceToolActivity(state.tools, {
1702
- type: "ai.tool.result",
1703
- payload
1704
- })
1705
- };
1706
- return {
1707
- ...next,
1708
- status: lifecycleStatus(state, next)
1709
- };
1710
- }
1711
- const activeProjection = {
1712
- ...projection,
1713
- cursor: null,
1714
- toolEvents: [...projection.toolEvents, {
1715
- index: event.index,
1716
- type: "ai.tool.result",
1717
- payload
1718
- }]
1719
- };
1720
- const projected = projectedResponse({
1721
- state,
1722
- projection: activeProjection
1723
- });
1724
- const tools = projectedTools(activeProjection);
1725
- const failureError = state.error ?? "Generation failed.";
1726
- const next = {
1727
- ...state,
1728
- messages: upsertMessage(state.messages, terminalReason === "failed" ? interruptUIMessage(projected, `Generation failed before tool completion: ${failureError}`) : projected),
1729
- activeProjection,
1730
- tools: terminalReason === "failed" ? stopGenerationTools(tools, payload.generationId, payload.messageId, failureError) : tools
1731
- };
1732
- return {
1733
- ...next,
1734
- status: lifecycleStatus(state, next)
1735
- };
1736
- }
1737
- case "ai.approval.requested": {
1738
- const payload = event.payload;
1739
- const projection = state.activeProjection;
1740
- if (isStaleGeneration(state, payload.messageId, payload.generationId) || terminalGenerationReason(state, payload.generationId) !== void 0) return state;
1741
- if (state.tools.some((activity) => activity.generationId === payload.generationId && activity.toolCallId === payload.toolCallId && activity.status === "failed" && state.activeGeneration?.generationId !== payload.generationId)) return state;
1742
- const activeProjection = projection?.generationId === payload.generationId ? {
1743
- ...projection,
1744
- cursor: null,
1745
- approvalEvents: [...projection.approvalEvents, {
1746
- index: event.index,
1747
- type: "ai.approval.requested",
1748
- payload
1749
- }]
1750
- } : projection;
1751
- const next = {
1752
- ...state,
1753
- messages: activeProjection === null || activeProjection === projection ? projectMessageChunks(state.messages, payload.messageId, [approvalRequestedChunk(payload)]) : upsertMessage(state.messages, projectedResponse({
1754
- state,
1755
- projection: activeProjection
1756
- })),
1757
- activeProjection,
1758
- pendingApprovals: payload.isAutomatic === true ? state.pendingApprovals : [...state.pendingApprovals.filter((approval) => approval.approvalId !== payload.approvalId || approval.messageId !== payload.messageId), payload]
1759
- };
1760
- return {
1761
- ...next,
1762
- status: lifecycleStatus(state, next)
1763
- };
1764
- }
1765
- case "ai.approval.responded": {
1766
- const payload = event.payload;
1767
- if (isStaleGeneration(state, payload.messageId, payload.generationId) || terminalGenerationReason(state, payload.generationId) !== void 0) return state;
1768
- const projection = state.activeProjection;
1769
- const pendingRequest = state.pendingApprovals.find((candidate) => candidate.approvalId === payload.approvalId && candidate.messageId === payload.messageId && candidate.generationId === payload.generationId);
1770
- const activeRequest = projection?.approvalEvents.findLast((candidate) => candidate.type === "ai.approval.requested" && candidate.payload.approvalId === payload.approvalId && candidate.payload.messageId === payload.messageId && candidate.payload.generationId === payload.generationId);
1771
- if (state.status === "failed" && pendingRequest === void 0 && activeRequest === void 0) return state;
1772
- const activeProjection = projection !== null && activeRequest !== void 0 ? {
1773
- ...projection,
1774
- cursor: null,
1775
- approvalEvents: [...projection.approvalEvents, {
1776
- index: event.index,
1777
- type: "ai.approval.responded",
1778
- payload
1779
- }]
1780
- } : projection;
1781
- const next = {
1782
- ...state,
1783
- messages: activeProjection === null || activeProjection === projection ? answerApproval(state.messages, payload) : upsertMessage(state.messages, projectedResponse({
1784
- state,
1785
- projection: activeProjection
1786
- })),
1787
- activeProjection: activeProjection === null ? null : {
1788
- ...activeProjection,
1789
- cursor: null
1790
- },
1791
- pendingApprovals: state.pendingApprovals.filter((approval) => approval.approvalId !== payload.approvalId || approval.messageId !== payload.messageId || approval.generationId !== payload.generationId)
1792
- };
1793
- return {
1794
- ...next,
1795
- status: lifecycleStatus(state, next)
1796
- };
1797
- }
1798
- case "ai.input.requested": {
1799
- const payload = event.payload;
1800
- if (isStaleGeneration(state, payload.messageId, payload.generationId) || terminalGenerationReason(state, payload.generationId) !== void 0) return state;
1801
- const next = {
1802
- ...state,
1803
- pendingInputs: [...state.pendingInputs.filter((input) => input.messageId !== payload.messageId || input.generationId !== payload.generationId || input.inputId !== payload.inputId), payload]
1804
- };
1805
- return {
1806
- ...next,
1807
- status: lifecycleStatus(state, next)
1808
- };
1809
- }
1810
- case "ai.input.responded": {
1811
- const payload = event.payload;
1812
- if (isStaleGeneration(state, payload.messageId, payload.generationId) || terminalGenerationReason(state, payload.generationId) !== void 0) return state;
1813
- const next = {
1814
- ...state,
1815
- pendingInputs: state.pendingInputs.filter((input) => input.inputId !== payload.inputId || input.messageId !== payload.messageId || input.generationId !== payload.generationId)
1816
- };
1817
- return {
1818
- ...next,
1819
- status: lifecycleStatus(state, next)
1820
- };
1821
- }
1822
- case "ai.compaction.requested": {
1823
- const payload = event.payload;
1824
- if (state.activeGeneration?.generationId !== payload.generationId) return state;
1825
- return {
1826
- ...state,
1827
- compaction: {
1828
- status: "running",
1829
- ...payload
1830
- }
1831
- };
1832
- }
1833
- case "ai.compaction.completed": {
1834
- const payload = event.payload;
1835
- if (state.activeGeneration?.generationId !== payload.generationId || state.compaction?.status !== "running" || state.compaction.generationId !== payload.generationId) return state;
1836
- return {
1837
- ...state,
1838
- compaction: {
1839
- status: "completed",
1840
- ...payload,
1841
- throughIndex: payload.throughIndex ?? state.activeProjection.promptThroughIndex
1842
- }
1843
- };
1844
- }
1845
- default: return state;
1846
- }
1847
- }
1848
- /** Derive AI SDK UI messages directly from an A2 event history. */
1849
- function deriveUIMessages(history) {
1850
- let state = initialState();
1851
- for (const event of history) state = reduceAIState(state, event);
1852
- return state.messages;
1853
- }
1854
- /** Build the standard AI state projection for any contract containing the protocol. */
1855
- function createReducer(options) {
1856
- return {
1857
- ...options.contract.reducer({
1858
- name: options.name ?? "a2.ai.state.v17",
1859
- initialState: initialState()
1860
- }).fold((state, event) => reduceAIState(state, event)),
1861
- [clientStateProjection]: projectAIClientState
1862
- };
1863
- }
1864
- const commandInput = (payload) => [{
1865
- type: "ai.control.requested",
1866
- payload
1867
- }];
1868
- const messageInput = (message, generate) => [{
1869
- type: "ai.control.requested",
1870
- id: `ai.message:${message.id}`,
1871
- payload: {
1872
- action: "send",
1873
- message,
1874
- ...generate === false ? { generate: false } : {}
1875
- }
1876
- }];
1877
- /** Pure append inputs for the built-in AI protocol. */
1878
- const inputs = {
1879
- toolResult: (result) => commandInput({
1880
- action: "tool-result",
1881
- result
1882
- }),
1883
- queue: {
1884
- remove: (options) => commandInput({
1885
- action: "remove",
1886
- ...options
1887
- }),
1888
- sendNow: (options) => commandInput({
1889
- action: "send-now",
1890
- ...options
1891
- }),
1892
- edit: (options) => commandInput({
1893
- action: "edit",
1894
- ...options
1895
- }),
1896
- move: (options) => commandInput({
1897
- action: "move",
1898
- ...options
1899
- })
1900
- },
1901
- stop: (options) => commandInput({
1902
- action: "stop",
1903
- ...options
1904
- }),
1905
- steer: (options) => commandInput({
1906
- action: "steer",
1907
- ...options
1908
- }),
1909
- pause: (options) => commandInput({
1910
- action: "pause",
1911
- ...options
1912
- }),
1913
- resume: () => commandInput({ action: "resume" }),
1914
- message(message, options) {
1915
- return messageInput(message, options?.generate);
1916
- },
1917
- seed(message) {
1918
- return messageInput(message, false);
1919
- },
1920
- approval: (response) => [{
1921
- ...commandInput({
1922
- action: "approval",
1923
- response
1924
- })[0],
1925
- id: `ai.approval:${encodeURIComponent(response.messageId)}:${encodeURIComponent(response.generationId)}:${encodeURIComponent(response.approvalId)}:response`
1926
- }],
1927
- input: (response) => [{
1928
- ...commandInput({
1929
- action: "input",
1930
- response
1931
- })[0],
1932
- id: `ai.input:${encodeURIComponent(response.messageId)}:${encodeURIComponent(response.generationId)}:${encodeURIComponent(response.inputId)}:response`
1933
- }],
1934
- requestInput: (request) => [{
1935
- ...commandInput({
1936
- action: "request-input",
1937
- request
1938
- })[0],
1939
- id: `ai.input:${encodeURIComponent(request.messageId)}:${encodeURIComponent(request.generationId)}:${encodeURIComponent(request.inputId)}:request`
1940
- }],
1941
- retry: (request) => [{
1942
- ...commandInput({
1943
- action: "retry",
1944
- request
1945
- })[0],
1946
- id: `ai.retry:${request.retryId}`
1947
- }],
1948
- interrupt: (request) => [{
1949
- ...commandInput({
1950
- action: "interrupt",
1951
- request
1952
- })[0],
1953
- id: `ai.interrupt:${request.generationId ?? request.requestId}`
1954
- }]
1955
- };
1956
- /**
1957
- * Read the durable handler context ambient to the current AI tool
1958
- * execution. A2 runs each local tool's `execute` inside this scope, so
1959
- * plain AI SDK `tool()` definitions reach their `event`, `attempt`,
1960
- * `session`, and `signal` without an A2-specific wrapper. The agent (or
1961
- * contract) argument carries the event types and is verified against
1962
- * the executing server's contract.
1963
- */
1964
- function handlerContext(agentOrContract) {
1965
- const contract = "contract" in agentOrContract ? agentOrContract.contract : agentOrContract;
1966
- const scope = ambientToolScopeStorage()?.getStore();
1967
- if (scope === void 0) throw new TypeError(`handlerContext('${contract.name}') requires an ambient A2 tool execution: call it inside a local tool's execute, or wrap direct tool tests with runWithHandlerContext`);
1968
- 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}'`);
1969
- return scope.context;
1970
- }
1971
- /**
1972
- * Define an agent: built-in AI protocol + application events and one state
1973
- * reducer. The result is isomorphic.
1974
- */
1975
- function agent(options) {
1976
- const builtIns = createEvents(options.messageSchema === void 0 ? void 0 : { messageSchema: options.messageSchema });
1977
- const extensions = options.events ?? {};
1978
- for (const key of Object.keys(extensions)) if (Object.hasOwn(builtIns, key)) throw new TypeError(`agent event '${key}' conflicts with a built-in event`);
1979
- const agentContract = contract({
1980
- name: options.name,
1981
- events: {
1982
- ...builtIns,
1983
- ...extensions
1984
- }
1985
- });
1986
- return {
1987
- contract: agentContract,
1988
- reducer: {
1989
- ...agentContract.reducer({
1990
- name: options.reducerName ?? "a2.ai.state.v17",
1991
- initialState: initialState()
1992
- }).fold((state, event) => reduceAIState(state, event)),
1993
- [clientStateProjection]: projectAIClientState
1994
- }
1995
- };
1996
- }
1997
- //#endregion
1
+ import { a as events, c as reduceAIState, i as deriveUIMessages, n as createEvents, o as handlerContext, r as createReducer, s as inputs, t as agent } from "./ai-CrLYwNEx.js";
1998
2
  export { agent, createEvents, createReducer, deriveUIMessages, events, handlerContext, inputs, reduceAIState };
1999
-
2000
- //# sourceMappingURL=ai.js.map