experimental-a2 0.13.0 → 0.14.1

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 (99) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/dist/{actor-DJi3RsNu.d.ts → actor-BfQSE0KC.d.ts} +4 -4
  3. package/dist/{actor-DJi3RsNu.d.ts.map → actor-BfQSE0KC.d.ts.map} +1 -1
  4. package/dist/actor-client.d.ts +1 -1
  5. package/dist/actor-client.js +1 -1
  6. package/dist/actor-react.d.ts +3 -3
  7. package/dist/actor-react.js +2 -2
  8. package/dist/{actor-shared-DI7J5upy.js → actor-shared-B5tJfzt-.js} +2 -2
  9. package/dist/{actor-shared-DI7J5upy.js.map → actor-shared-B5tJfzt-.js.map} +1 -1
  10. package/dist/actor.d.ts +1 -1
  11. package/dist/actor.js +3 -3
  12. package/dist/ai-Cai-lCbj.d.ts +580 -0
  13. package/dist/ai-Cai-lCbj.d.ts.map +1 -0
  14. package/dist/ai-control-CcD4hh3y.js +119 -0
  15. package/dist/ai-control-CcD4hh3y.js.map +1 -0
  16. package/dist/ai-server.d.ts +6 -6
  17. package/dist/ai-server.d.ts.map +1 -1
  18. package/dist/ai-server.js +1053 -513
  19. package/dist/ai-server.js.map +1 -1
  20. package/dist/ai.d.ts +2 -365
  21. package/dist/ai.js +801 -80
  22. package/dist/ai.js.map +1 -1
  23. package/dist/{client-P_NNNRM-.d.ts → client-BAEABRZB.d.ts} +2 -2
  24. package/dist/{client-P_NNNRM-.d.ts.map → client-BAEABRZB.d.ts.map} +1 -1
  25. package/dist/{client-Bf6uSEAk.js → client-BYzHjkwU.js} +21 -6
  26. package/dist/client-BYzHjkwU.js.map +1 -0
  27. package/dist/client.d.ts +1 -1
  28. package/dist/client.js +1 -1
  29. package/dist/{contract-48bUMgcL.js → contract-CKRg_E4q.js} +3 -26
  30. package/dist/contract-CKRg_E4q.js.map +1 -0
  31. package/dist/index.d.ts +2 -2
  32. package/dist/index.js +1 -1
  33. package/dist/react.d.ts +2 -2
  34. package/dist/react.js +1 -1
  35. package/dist/{reducer-DJKWm3cp.d.ts → reducer-BcS9VDKC.d.ts} +4 -1
  36. package/dist/{reducer-DJKWm3cp.d.ts.map → reducer-BcS9VDKC.d.ts.map} +1 -1
  37. package/dist/reducer-DEMjEY_O.js +29 -0
  38. package/dist/reducer-DEMjEY_O.js.map +1 -0
  39. package/dist/scheduler-qstash.d.ts +2 -2
  40. package/dist/scheduler-qstash.js +1 -1
  41. package/dist/scheduler-vercel.d.ts +2 -2
  42. package/dist/scheduler-vercel.js +1 -1
  43. package/dist/{server-DjZZa1wr.d.ts → server-Bp5Nd1pF.d.ts} +3 -3
  44. package/dist/{server-DjZZa1wr.d.ts.map → server-Bp5Nd1pF.d.ts.map} +1 -1
  45. package/dist/{server-BeNADlCI.js → server-CjJSGcF7.js} +4 -3
  46. package/dist/server-CjJSGcF7.js.map +1 -0
  47. package/dist/server.d.ts +3 -3
  48. package/dist/server.js +1 -1
  49. package/dist/{store-DtDOWLSn.d.ts → store-D_yhNdPz.d.ts} +7 -2
  50. package/dist/{store-DtDOWLSn.d.ts.map → store-D_yhNdPz.d.ts.map} +1 -1
  51. package/dist/store-N8PXxDAS.js.map +1 -1
  52. package/dist/store-memory.d.ts +1 -1
  53. package/dist/store-postgres.d.ts +1 -1
  54. package/dist/store-postgres.js +19 -0
  55. package/dist/store-postgres.js.map +1 -1
  56. package/dist/store-redis-http.d.ts +1 -1
  57. package/dist/store-redis-http.js +1 -1
  58. package/dist/{store-redis-notify-BUCyXOn0.js → store-redis-notify-D2EI6gwX.js} +27 -2
  59. package/dist/store-redis-notify-D2EI6gwX.js.map +1 -0
  60. package/dist/store-redis.d.ts +1 -1
  61. package/dist/store-redis.js +1 -1
  62. package/dist/store-sqlite.d.ts +1 -1
  63. package/docs/guides/06-ai-agents.mdx +287 -65
  64. package/docs/reference/01-api.mdx +122 -27
  65. package/examples/playground/app/agent/[agentId]/agent-client.tsx +118 -21
  66. package/examples/playground/app/agent/[agentId]/agent-queue.tsx +289 -0
  67. package/examples/playground/app/agent/compaction-settings.test.ts +22 -6
  68. package/examples/playground/app/agent/model.ts +11 -2
  69. package/examples/playground/app/agent/server.ts +8 -2
  70. package/examples/playground/app/chat/[chatId]/chat-client.tsx +3 -13
  71. package/examples/playground/app/chat/model.ts +2 -2
  72. package/examples/playground/app/chat/server.ts +24 -17
  73. package/examples/playground/app/globals.css +179 -0
  74. package/examples/playground/package.json +1 -1
  75. package/package.json +1 -1
  76. package/src/ai-client-state.ts +185 -0
  77. package/src/ai-control-server.ts +829 -0
  78. package/src/ai-control-state.ts +152 -0
  79. package/src/ai-control.ts +139 -0
  80. package/src/ai-coordinator.ts +99 -32
  81. package/src/ai-progress-batches.ts +68 -0
  82. package/src/ai-projector.ts +76 -15
  83. package/src/ai-sdk-step.ts +0 -1
  84. package/src/ai-server.ts +429 -619
  85. package/src/ai.ts +553 -108
  86. package/src/client.ts +31 -9
  87. package/src/licenses/Apache-2.0.txt +55 -0
  88. package/src/parse-partial-json.ts +441 -0
  89. package/src/reducer.ts +6 -0
  90. package/src/server.ts +8 -4
  91. package/src/store-postgres.ts +27 -0
  92. package/src/store-redis-core.ts +53 -1
  93. package/src/store-redis-notify.ts +1 -0
  94. package/src/store.ts +6 -0
  95. package/dist/ai.d.ts.map +0 -1
  96. package/dist/client-Bf6uSEAk.js.map +0 -1
  97. package/dist/contract-48bUMgcL.js.map +0 -1
  98. package/dist/server-BeNADlCI.js.map +0 -1
  99. package/dist/store-redis-notify-BUCyXOn0.js.map +0 -1
@@ -1,4 +1,5 @@
1
1
  import type { UIMessage, UIMessageChunk } from 'ai'
2
+ import { parsePartialJSON } from './parse-partial-json.ts'
2
3
 
3
4
  type MutablePart = Record<string, unknown>
4
5
 
@@ -16,7 +17,13 @@ const isRecord = (value: unknown): value is Record<string, unknown> =>
16
17
  typeof value === 'object' && value !== null && !Array.isArray(value)
17
18
 
18
19
  const cloneMessage = <M extends UIMessage>(messageId: string, base?: M): M =>
19
- structuredClone(base ?? { id: messageId, role: 'assistant', parts: [] }) as M
20
+ (base === undefined
21
+ ? { id: messageId, role: 'assistant', parts: [] }
22
+ : {
23
+ ...base,
24
+ id: messageId,
25
+ parts: base.parts.map((part) => ({ ...part })),
26
+ }) as M
20
27
 
21
28
  const currentStepParts = (parts: MutablePart[]): MutablePart[] => {
22
29
  let start = parts.length - 1
@@ -118,26 +125,47 @@ const mergeMetadata = (current: unknown, update: unknown): unknown => {
118
125
  : update
119
126
  }
120
127
 
121
- const parseCompleteJSON = (value: string): unknown => {
122
- try {
123
- return JSON.parse(value) as unknown
124
- } catch {
125
- return undefined
126
- }
128
+ export type UIMessageCursor = {
129
+ text: Record<string, number>
130
+ reasoning: Record<string, number>
131
+ tools: Record<string, PartialToolCall>
127
132
  }
128
133
 
129
- /** Internal synchronous counterpart of the AI SDK UI message stream fold. */
130
134
  export function projectUIMessage<M extends UIMessage>(options: {
131
135
  messageId: string
132
136
  base?: M
133
137
  chunks: readonly UIMessageChunk[]
134
138
  }): M {
139
+ return projectUIMessageStream(options).message
140
+ }
141
+
142
+ export function projectUIMessageStream<M extends UIMessage>(options: {
143
+ messageId: string
144
+ base?: M
145
+ cursor?: UIMessageCursor
146
+ chunks: readonly UIMessageChunk[]
147
+ }): { message: M; cursor: UIMessageCursor } {
135
148
  const message = cloneMessage(options.messageId, options.base)
136
149
  const record = message as unknown as Record<string, unknown>
137
150
  const parts = message.parts as unknown as MutablePart[]
138
- const activeText = new Map<string, MutablePart>()
139
- const activeReasoning = new Map<string, MutablePart>()
140
- const partialTools = new Map<string, PartialToolCall>()
151
+ const activeText = new Map(
152
+ Object.entries(options.cursor?.text ?? {}).map(([id, index]) => [
153
+ id,
154
+ parts[index]!,
155
+ ]),
156
+ )
157
+ const activeReasoning = new Map(
158
+ Object.entries(options.cursor?.reasoning ?? {}).map(([id, index]) => [
159
+ id,
160
+ parts[index]!,
161
+ ]),
162
+ )
163
+ const partialTools = new Map(
164
+ Object.entries(options.cursor?.tools ?? {}).map(([id, partial]) => [
165
+ id,
166
+ { ...partial },
167
+ ]),
168
+ )
141
169
 
142
170
  for (const chunk of options.chunks) {
143
171
  switch (chunk.type) {
@@ -291,7 +319,7 @@ export function projectUIMessage<M extends UIMessage>(options: {
291
319
  toolName: partial.toolName,
292
320
  dynamic: partial.dynamic,
293
321
  state: 'input-streaming',
294
- input: parseCompleteJSON(partial.text),
322
+ input: parsePartialJSON(partial.text),
295
323
  providerExecuted: partial.providerExecuted,
296
324
  providerMetadata: partial.providerMetadata,
297
325
  toolMetadata: partial.toolMetadata,
@@ -424,7 +452,6 @@ export function projectUIMessage<M extends UIMessage>(options: {
424
452
  activeReasoning.clear()
425
453
  break
426
454
  case 'start':
427
- if (chunk.messageId !== undefined) record['id'] = chunk.messageId
428
455
  if (
429
456
  chunk.messageMetadata !== undefined &&
430
457
  chunk.messageMetadata !== null
@@ -480,7 +507,38 @@ export function projectUIMessage<M extends UIMessage>(options: {
480
507
  }
481
508
  }
482
509
 
483
- return message
510
+ const indexes = new Map(parts.map((part, index) => [part, index]))
511
+ return {
512
+ message,
513
+ cursor: {
514
+ text: Object.fromEntries(
515
+ [...activeText].map(([id, part]) => [id, indexes.get(part)!]),
516
+ ),
517
+ reasoning: Object.fromEntries(
518
+ [...activeReasoning].map(([id, part]) => [id, indexes.get(part)!]),
519
+ ),
520
+ tools: Object.fromEntries(partialTools),
521
+ },
522
+ }
523
+ }
524
+
525
+ export function pauseUIMessage<M extends UIMessage>(options: {
526
+ message: M
527
+ toolCallIds: ReadonlySet<string>
528
+ }): M {
529
+ const next = structuredClone(options.message)
530
+ next.parts = next.parts.filter(
531
+ (part) =>
532
+ !('toolCallId' in part && !options.toolCallIds.has(part.toolCallId)),
533
+ )
534
+ for (const part of next.parts) {
535
+ if (
536
+ (part.type === 'text' || part.type === 'reasoning') &&
537
+ part.state === 'streaming'
538
+ )
539
+ part.state = 'done'
540
+ }
541
+ return next
484
542
  }
485
543
 
486
544
  export function interruptUIMessage<M extends UIMessage>(
@@ -488,6 +546,10 @@ export function interruptUIMessage<M extends UIMessage>(
488
546
  toolError = 'Tool execution was interrupted.',
489
547
  ): M {
490
548
  const next = structuredClone(message)
549
+ next.parts = next.parts.filter((value) => {
550
+ const part = value as unknown as MutablePart
551
+ return !isToolPart(part) || part['state'] !== 'input-streaming'
552
+ })
491
553
  for (const value of next.parts as unknown as MutablePart[]) {
492
554
  if (value['type'] === 'text' || value['type'] === 'reasoning') {
493
555
  if (value['state'] === 'streaming') value['state'] = 'done'
@@ -510,7 +572,6 @@ export function interruptUIMessage<M extends UIMessage>(
510
572
  continue
511
573
  }
512
574
  if (
513
- state === 'input-streaming' ||
514
575
  state === 'input-available' ||
515
576
  state === 'approval-requested' ||
516
577
  state === 'approval-responded'
@@ -244,7 +244,6 @@ export async function generateAISDKStep<M extends UIMessage, T extends ToolSet>(
244
244
  stream: toUIMessageStream<T, M>({
245
245
  stream: observed,
246
246
  tools,
247
- originalMessages: input.messages,
248
247
  generateMessageId: () => input.responseMessageId,
249
248
  onError: errorMessage,
250
249
  ...(input.messageMetadata === undefined