@tanstack/ai 0.63.0 → 0.64.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 (61) hide show
  1. package/dist/esm/activities/chat/agents/spawn.js +2 -28
  2. package/dist/esm/activities/chat/agents/spawn.js.map +1 -1
  3. package/dist/esm/activities/chat/index.d.ts +2 -0
  4. package/dist/esm/activities/chat/index.js +10 -3
  5. package/dist/esm/activities/chat/index.js.map +1 -1
  6. package/dist/esm/activities/chat/messages.js +13 -4
  7. package/dist/esm/activities/chat/messages.js.map +1 -1
  8. package/dist/esm/activities/chat/stream/message-updaters.js +4 -1
  9. package/dist/esm/activities/chat/stream/message-updaters.js.map +1 -1
  10. package/dist/esm/activities/chat/tools/schema-converter.d.ts +8 -0
  11. package/dist/esm/activities/chat/tools/schema-converter.js +6 -5
  12. package/dist/esm/activities/chat/tools/schema-converter.js.map +1 -1
  13. package/dist/esm/activities/chat/tools/tool-calls.d.ts +5 -2
  14. package/dist/esm/activities/chat/tools/tool-calls.js +73 -22
  15. package/dist/esm/activities/chat/tools/tool-calls.js.map +1 -1
  16. package/dist/esm/activities/generateSpeech/index.d.ts +1 -1
  17. package/dist/esm/activities/generateSpeech/index.js +1 -1
  18. package/dist/esm/activities/generateSpeech/index.js.map +1 -1
  19. package/dist/esm/activities/generateVideo/adapter.d.ts +14 -6
  20. package/dist/esm/activities/generateVideo/adapter.js +6 -3
  21. package/dist/esm/activities/generateVideo/adapter.js.map +1 -1
  22. package/dist/esm/activities/generateVideo/index.d.ts +5 -4
  23. package/dist/esm/activities/generateVideo/index.js.map +1 -1
  24. package/dist/esm/activities/generateVideo/snap.d.ts +12 -3
  25. package/dist/esm/activities/generateVideo/snap.js +47 -8
  26. package/dist/esm/activities/generateVideo/snap.js.map +1 -1
  27. package/dist/esm/activities/generateVoice/index.d.ts +1 -1
  28. package/dist/esm/activities/generateVoice/index.js +1 -1
  29. package/dist/esm/activities/generateVoice/index.js.map +1 -1
  30. package/dist/esm/activities/index.d.ts +2 -2
  31. package/dist/esm/activities/index.js +2 -2
  32. package/dist/esm/adapter-internals.d.ts +1 -0
  33. package/dist/esm/adapter-internals.js +2 -1
  34. package/dist/esm/types.d.ts +28 -3
  35. package/dist/esm/utilities/ag-ui-wire.js +3 -1
  36. package/dist/esm/utilities/ag-ui-wire.js.map +1 -1
  37. package/dist/esm/utilities/merge-streams.d.ts +6 -0
  38. package/dist/esm/utilities/merge-streams.js +37 -0
  39. package/dist/esm/utilities/merge-streams.js.map +1 -0
  40. package/dist/esm/utilities/reasoning-encrypted-value.d.ts +8 -0
  41. package/dist/esm/utilities/reasoning-encrypted-value.js +11 -1
  42. package/dist/esm/utilities/reasoning-encrypted-value.js.map +1 -1
  43. package/package.json +1 -1
  44. package/skills/ai-core/media-generation/SKILL.md +3 -3
  45. package/src/activities/chat/agents/spawn.ts +2 -31
  46. package/src/activities/chat/index.ts +13 -3
  47. package/src/activities/chat/messages.ts +14 -2
  48. package/src/activities/chat/stream/message-updaters.ts +5 -0
  49. package/src/activities/chat/tools/schema-converter.ts +17 -5
  50. package/src/activities/chat/tools/tool-calls.ts +121 -63
  51. package/src/activities/generateSpeech/index.ts +1 -1
  52. package/src/activities/generateVideo/adapter.ts +21 -7
  53. package/src/activities/generateVideo/index.ts +5 -4
  54. package/src/activities/generateVideo/snap.ts +64 -6
  55. package/src/activities/generateVoice/index.ts +1 -1
  56. package/src/activities/index.ts +2 -1
  57. package/src/adapter-internals.ts +1 -0
  58. package/src/types.ts +28 -4
  59. package/src/utilities/ag-ui-wire.ts +5 -1
  60. package/src/utilities/merge-streams.ts +34 -0
  61. package/src/utilities/reasoning-encrypted-value.ts +12 -0
@@ -166,7 +166,7 @@ function createId(prefix: string): string {
166
166
  * if (!preview) throw new Error('No voice candidates returned')
167
167
  *
168
168
  * const speech = await generateSpeech({
169
- * adapter: elevenlabsSpeech('eleven_v3'),
169
+ * adapter: elevenlabsSpeech('eleven_v4'),
170
170
  * text: 'Once upon a time...',
171
171
  * voice: preview.voiceId,
172
172
  * })
@@ -209,9 +209,10 @@ export {
209
209
  type VideoAdapterConfig,
210
210
  type AnyVideoAdapter,
211
211
  type DurationOptions,
212
+ type VideoDurationSpell,
212
213
  } from './generateVideo/adapter'
213
214
 
214
- export { snapToDurationOption } from './generateVideo/snap'
215
+ export { durationToSeconds, snapToDurationOption } from './generateVideo/snap'
215
216
 
216
217
  // ===========================
217
218
  // TTS Activity
@@ -59,3 +59,4 @@ export {
59
59
  } from './utilities/structured-output-events'
60
60
  export { tanstackMetadata } from './utilities/merge-metadata'
61
61
  export { isSpecTopLevelKey } from './utilities/spec-event-keys'
62
+ export { REDACTED_THINKING_ID_PREFIX } from './utilities/reasoning-encrypted-value'
package/src/types.ts CHANGED
@@ -381,7 +381,12 @@ export interface ModelMessage<
381
381
  name?: string
382
382
  toolCalls?: Array<ToolCall>
383
383
  toolCallId?: string
384
- thinking?: Array<{ content: string; signature?: string }>
384
+ /**
385
+ * Signed thinking to send back to the provider. `redacted: true` marks a
386
+ * block the provider encrypted: `content` is empty and `signature` holds its
387
+ * opaque data. See `ThinkingPart.signature` for the planned rename.
388
+ */
389
+ thinking?: Array<{ content: string; signature?: string; redacted?: boolean }>
385
390
  /** Error reported by an AG-UI tool message. */
386
391
  error?: string
387
392
  /** Optional AG-UI message metadata. TanStack-owned fields live under `tanstack`. */
@@ -465,7 +470,20 @@ export interface ThinkingPart {
465
470
  type: 'thinking'
466
471
  content: string
467
472
  stepId?: string
473
+ /**
474
+ * The provider's opaque reasoning artefact, sent back unchanged: an
475
+ * Anthropic signature, Anthropic redacted data, or OpenAI encrypted content.
476
+ * TODO(#1581): rename to `encryptedValue` to match AG-UI's `ReasoningMessage`.
477
+ * Renaming breaks stored messages, so it needs a read shim for `signature`.
478
+ */
468
479
  signature?: string
480
+ /**
481
+ * The provider encrypted this thinking block (Anthropic `redacted_thinking`).
482
+ * `content` is empty, and `signature` holds the opaque data that goes back
483
+ * to the provider unchanged. On the AG-UI wire, the reasoning message id
484
+ * starts with `redacted_thinking-` instead.
485
+ */
486
+ redacted?: boolean
469
487
  }
470
488
 
471
489
  /**
@@ -1088,6 +1106,11 @@ export interface TextOptions<
1088
1106
  */
1089
1107
  systemPrompts?: Array<SystemPrompt>
1090
1108
  agentLoopStrategy?: AgentLoopStrategy
1109
+ /**
1110
+ * How the server tools of one model turn run. `'parallel'` (the default)
1111
+ * starts them together, and `'sequential'` runs them one at a time.
1112
+ */
1113
+ toolExecution?: 'parallel' | 'sequential'
1091
1114
  /**
1092
1115
  * Optional configuration for lazy-tool discovery (tools marked `lazy: true`).
1093
1116
  * Tunes how much of each lazy tool's description appears in the discovery
@@ -2277,9 +2300,10 @@ export interface VideoGenerationOptions<
2277
2300
  /** Video size — format depends on the provider (e.g., "16:9", "1280x720") */
2278
2301
  size?: TSize
2279
2302
  /**
2280
- * Video duration in seconds. Adapters that declare a per-model duration
2281
- * map narrow this to the model's valid union; use
2282
- * `adapter.snapDuration(seconds)` to coerce raw seconds to a valid value.
2303
+ * Video duration. Adapters that declare a per-model duration map narrow
2304
+ * this to that model's union (a number, `"8"`, or `"8s"`). Use
2305
+ * `adapter.snapDuration(input)` to coerce a raw value. `input` may be
2306
+ * seconds, a `"6s"` template, or `"auto"` when the model lists it.
2283
2307
  */
2284
2308
  duration?: TDuration
2285
2309
  /** Model-specific options for video generation */
@@ -21,6 +21,7 @@ import type {
21
21
  import type { MetadataRecord } from './merge-metadata'
22
22
  import { tanstackMetadata } from './merge-metadata'
23
23
  import { isProviderExecutedToolCall } from './provider-executed'
24
+ import { REDACTED_THINKING_ID_PREFIX } from './reasoning-encrypted-value'
24
25
  import { normalizeToolResult } from './tool-result'
25
26
  import { wireSubagentInfo, wireSubagentRunId } from './subagent-wire'
26
27
  import type { SubagentWireInfo } from './subagent-wire'
@@ -614,7 +615,10 @@ function collectToolCalls(
614
615
  }
615
616
 
616
617
  function deriveReasoningId(messageId: string, part: MessagePart): string {
617
- return `${messageId}-reasoning-${(part as { id?: string }).id ?? hashContent((part as { content: string }).content)}`
618
+ const id = `${messageId}-reasoning-${(part as { id?: string }).id ?? hashContent((part as { content: string }).content)}`
619
+ return part.type === 'thinking' && part.redacted
620
+ ? `${REDACTED_THINKING_ID_PREFIX}${id}`
621
+ : id
618
622
  }
619
623
 
620
624
  function deriveToolMessageId(toolCallId: string): string {
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Yield the items of several async streams as they arrive. If the reader
3
+ * stops early, every stream that is still open is closed, so its `finally`
4
+ * runs.
5
+ */
6
+ export async function* mergeStreams<T>(streams: Array<AsyncIterable<T>>) {
7
+ const readers = streams.map((stream) => {
8
+ const iterator = stream[Symbol.asyncIterator]()
9
+ return {
10
+ iterator,
11
+ next: iterator.next(),
12
+ }
13
+ })
14
+
15
+ try {
16
+ while (readers.length > 0) {
17
+ const indexed = readers.map((reader, index) =>
18
+ reader.next.then((result) => ({ index, result, reader })),
19
+ )
20
+ const winner = await Promise.race(indexed)
21
+ if (winner.result.done) {
22
+ readers.splice(winner.index, 1)
23
+ continue
24
+ }
25
+ yield winner.result.value
26
+ winner.reader.next = winner.reader.iterator.next()
27
+ }
28
+ } finally {
29
+ // The reader stopped early. Close every stream so its finally runs.
30
+ for (const reader of readers) {
31
+ void reader.iterator.return?.().catch(() => {})
32
+ }
33
+ }
34
+ }
@@ -16,3 +16,15 @@ export function reasoningEncryptedValue(opts: {
16
16
  ...(opts.timestamp !== undefined ? { timestamp: opts.timestamp } : {}),
17
17
  }
18
18
  }
19
+
20
+ /**
21
+ * Id prefix for the reasoning message of a redacted thinking block (Anthropic
22
+ * `redacted_thinking`). AG-UI's `encryptedValue` does not say what kind of
23
+ * bytes it holds (ag-ui-protocol/ag-ui#2884), so the id that `entityId` points
24
+ * to says it. AG-UI clients keep message ids, but they drop event metadata.
25
+ */
26
+ export const REDACTED_THINKING_ID_PREFIX = 'redacted_thinking-'
27
+
28
+ export function isRedactedThinkingId(id: unknown): boolean {
29
+ return typeof id === 'string' && id.startsWith(REDACTED_THINKING_ID_PREFIX)
30
+ }