@tanstack/ai 0.58.0 → 0.61.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 (144) hide show
  1. package/dist/esm/activities/chat/adapter.d.ts +9 -0
  2. package/dist/esm/activities/chat/adapter.js +1 -0
  3. package/dist/esm/activities/chat/adapter.js.map +1 -1
  4. package/dist/esm/activities/chat/agents/define-agent.d.ts +81 -0
  5. package/dist/esm/activities/chat/agents/define-agent.js +34 -0
  6. package/dist/esm/activities/chat/agents/define-agent.js.map +1 -0
  7. package/dist/esm/activities/chat/agents/route.d.ts +53 -0
  8. package/dist/esm/activities/chat/agents/route.js +59 -0
  9. package/dist/esm/activities/chat/agents/route.js.map +1 -0
  10. package/dist/esm/activities/chat/agents/spawn.d.ts +124 -0
  11. package/dist/esm/activities/chat/agents/spawn.js +490 -0
  12. package/dist/esm/activities/chat/agents/spawn.js.map +1 -0
  13. package/dist/esm/activities/chat/agents/turn.d.ts +36 -0
  14. package/dist/esm/activities/chat/agents/turn.js +78 -0
  15. package/dist/esm/activities/chat/agents/turn.js.map +1 -0
  16. package/dist/esm/activities/chat/index.d.ts +13 -3
  17. package/dist/esm/activities/chat/index.js +462 -26
  18. package/dist/esm/activities/chat/index.js.map +1 -1
  19. package/dist/esm/activities/chat/messages.d.ts +7 -1
  20. package/dist/esm/activities/chat/messages.js +99 -19
  21. package/dist/esm/activities/chat/messages.js.map +1 -1
  22. package/dist/esm/activities/chat/middleware/run-store.d.ts +43 -7
  23. package/dist/esm/activities/chat/middleware/run-store.js +8 -1
  24. package/dist/esm/activities/chat/middleware/run-store.js.map +1 -1
  25. package/dist/esm/activities/chat/middleware/types.d.ts +47 -1
  26. package/dist/esm/activities/chat/middleware/types.js.map +1 -1
  27. package/dist/esm/activities/chat/stream/message-updaters.js +9 -2
  28. package/dist/esm/activities/chat/stream/message-updaters.js.map +1 -1
  29. package/dist/esm/activities/chat/stream/processor.d.ts +46 -1
  30. package/dist/esm/activities/chat/stream/processor.js +294 -18
  31. package/dist/esm/activities/chat/stream/processor.js.map +1 -1
  32. package/dist/esm/activities/chat/tools/tool-calls.d.ts +17 -3
  33. package/dist/esm/activities/chat/tools/tool-calls.js +56 -5
  34. package/dist/esm/activities/chat/tools/tool-calls.js.map +1 -1
  35. package/dist/esm/activities/embed/adapter.d.ts +7 -0
  36. package/dist/esm/activities/embed/adapter.js +1 -0
  37. package/dist/esm/activities/embed/adapter.js.map +1 -1
  38. package/dist/esm/activities/embed/index.js +2 -0
  39. package/dist/esm/activities/embed/index.js.map +1 -1
  40. package/dist/esm/activities/files/adapter.d.ts +97 -0
  41. package/dist/esm/activities/files/adapter.js +45 -0
  42. package/dist/esm/activities/files/adapter.js.map +1 -0
  43. package/dist/esm/activities/files/index.d.ts +66 -0
  44. package/dist/esm/activities/files/index.js +78 -0
  45. package/dist/esm/activities/files/index.js.map +1 -0
  46. package/dist/esm/activities/generateAudio/index.js +1 -1
  47. package/dist/esm/activities/generateImage/adapter.d.ts +8 -0
  48. package/dist/esm/activities/generateImage/adapter.js +1 -0
  49. package/dist/esm/activities/generateImage/adapter.js.map +1 -1
  50. package/dist/esm/activities/generateImage/index.js +3 -1
  51. package/dist/esm/activities/generateImage/index.js.map +1 -1
  52. package/dist/esm/activities/generateLiveVideo/index.js +1 -1
  53. package/dist/esm/activities/generateSpeech/index.js +1 -1
  54. package/dist/esm/activities/generateTranscription/index.js +1 -1
  55. package/dist/esm/activities/generateVideo/adapter.d.ts +8 -0
  56. package/dist/esm/activities/generateVideo/adapter.js +1 -0
  57. package/dist/esm/activities/generateVideo/adapter.js.map +1 -1
  58. package/dist/esm/activities/generateVideo/index.js +3 -0
  59. package/dist/esm/activities/generateVideo/index.js.map +1 -1
  60. package/dist/esm/activities/generateVoice/index.js +1 -1
  61. package/dist/esm/activities/generateWorld/adapter.d.ts +4 -2
  62. package/dist/esm/activities/generateWorld/adapter.js.map +1 -1
  63. package/dist/esm/activities/generateWorld/index.d.ts +4 -3
  64. package/dist/esm/activities/generateWorld/index.js +6 -5
  65. package/dist/esm/activities/generateWorld/index.js.map +1 -1
  66. package/dist/esm/activities/index.d.ts +9 -3
  67. package/dist/esm/activities/index.js +17 -13
  68. package/dist/esm/activities/summarize/chat-stream-summarize.d.ts +2 -0
  69. package/dist/esm/activities/summarize/chat-stream-summarize.js +8 -8
  70. package/dist/esm/activities/summarize/chat-stream-summarize.js.map +1 -1
  71. package/dist/esm/activities/summarize/index.js +1 -1
  72. package/dist/esm/client.d.ts +7 -36
  73. package/dist/esm/client.js +5 -37
  74. package/dist/esm/client.js.map +1 -1
  75. package/dist/esm/index.d.ts +8 -2
  76. package/dist/esm/index.js +9 -4
  77. package/dist/esm/middlewares/content-guard.js.map +1 -1
  78. package/dist/esm/types.d.ts +179 -98
  79. package/dist/esm/utilities/adapter-yield-chunk.d.ts +5 -1
  80. package/dist/esm/utilities/ag-ui-usage.d.ts +9 -9
  81. package/dist/esm/utilities/ag-ui-usage.js +66 -3
  82. package/dist/esm/utilities/ag-ui-usage.js.map +1 -1
  83. package/dist/esm/utilities/ag-ui-wire.js +90 -13
  84. package/dist/esm/utilities/ag-ui-wire.js.map +1 -1
  85. package/dist/esm/utilities/content-source.d.ts +60 -0
  86. package/dist/esm/utilities/content-source.js +85 -0
  87. package/dist/esm/utilities/content-source.js.map +1 -0
  88. package/dist/esm/utilities/normalize-stream-chunk.js +7 -2
  89. package/dist/esm/utilities/normalize-stream-chunk.js.map +1 -1
  90. package/dist/esm/utilities/provider-executed.d.ts +7 -0
  91. package/dist/esm/utilities/provider-executed.js +10 -1
  92. package/dist/esm/utilities/provider-executed.js.map +1 -1
  93. package/dist/esm/utilities/spec-event-keys.js +13 -8
  94. package/dist/esm/utilities/spec-event-keys.js.map +1 -1
  95. package/dist/esm/utilities/subagent-wire.d.ts +36 -0
  96. package/dist/esm/utilities/subagent-wire.js +131 -0
  97. package/dist/esm/utilities/subagent-wire.js.map +1 -0
  98. package/dist/esm/utilities/tool-result.d.ts +12 -2
  99. package/dist/esm/utilities/tool-result.js +23 -3
  100. package/dist/esm/utilities/tool-result.js.map +1 -1
  101. package/package.json +3 -3
  102. package/skills/ai-core/adapter-configuration/SKILL.md +62 -0
  103. package/skills/ai-core/adapter-configuration/references/grok-adapter.md +1 -1
  104. package/skills/ai-core/chat-experience/SKILL.md +14 -0
  105. package/skills/ai-core/media-generation/SKILL.md +10 -2
  106. package/skills/ai-core/middleware/SKILL.md +7 -4
  107. package/src/activities/chat/adapter.ts +10 -0
  108. package/src/activities/chat/agents/define-agent.ts +121 -0
  109. package/src/activities/chat/agents/route.ts +115 -0
  110. package/src/activities/chat/agents/spawn.ts +806 -0
  111. package/src/activities/chat/agents/turn.ts +151 -0
  112. package/src/activities/chat/index.ts +734 -30
  113. package/src/activities/chat/messages.ts +137 -16
  114. package/src/activities/chat/middleware/run-store.ts +56 -7
  115. package/src/activities/chat/middleware/types.ts +47 -0
  116. package/src/activities/chat/stream/message-updaters.ts +24 -2
  117. package/src/activities/chat/stream/processor.ts +452 -30
  118. package/src/activities/chat/tools/tool-calls.ts +83 -11
  119. package/src/activities/embed/adapter.ts +7 -0
  120. package/src/activities/embed/index.ts +5 -0
  121. package/src/activities/files/adapter.ts +120 -0
  122. package/src/activities/files/index.ts +113 -0
  123. package/src/activities/generateImage/adapter.ts +8 -0
  124. package/src/activities/generateImage/index.ts +4 -0
  125. package/src/activities/generateVideo/adapter.ts +8 -0
  126. package/src/activities/generateVideo/index.ts +7 -0
  127. package/src/activities/generateWorld/adapter.ts +4 -2
  128. package/src/activities/generateWorld/index.ts +7 -6
  129. package/src/activities/index.ts +40 -1
  130. package/src/activities/summarize/chat-stream-summarize.ts +22 -12
  131. package/src/client.ts +29 -35
  132. package/src/index.ts +39 -0
  133. package/src/middlewares/content-guard.ts +7 -5
  134. package/src/types.ts +226 -103
  135. package/src/utilities/adapter-yield-chunk.ts +10 -2
  136. package/src/utilities/ag-ui-usage.test.ts +38 -0
  137. package/src/utilities/ag-ui-usage.ts +98 -11
  138. package/src/utilities/ag-ui-wire.ts +134 -16
  139. package/src/utilities/content-source.ts +138 -0
  140. package/src/utilities/normalize-stream-chunk.ts +10 -2
  141. package/src/utilities/provider-executed.ts +13 -0
  142. package/src/utilities/spec-event-keys.ts +34 -7
  143. package/src/utilities/subagent-wire.ts +184 -0
  144. package/src/utilities/tool-result.ts +38 -2
@@ -0,0 +1,184 @@
1
+ import type { SubagentInfo as AGUISubagentInfo } from '@ag-ui/core'
2
+ import type { SubagentHandleData } from '../types'
3
+
4
+ /**
5
+ * Card data that travels on each child wire message, in
6
+ * `metadata.tanstack.subagent`. The messages carry the AG-UI `subagentRunId`.
7
+ */
8
+ export interface SubagentWireInfo
9
+ extends
10
+ AGUISubagentInfo,
11
+ Pick<
12
+ SubagentHandleData,
13
+ | 'status'
14
+ | 'error'
15
+ | 'interruptIds'
16
+ | 'parentSubagentRunId'
17
+ | 'parentToolCallId'
18
+ | 'metadata'
19
+ > {
20
+ /** The child has no messages yet. This wire message only holds the card. */
21
+ placeholder?: true
22
+ }
23
+
24
+ export interface SubagentWireGroup<T> {
25
+ id: string
26
+ info: SubagentWireInfo
27
+ /** The child's messages without its own tag. Nested children keep theirs. */
28
+ messages: Array<T>
29
+ /** Index in `top` of the last message before this child, or -1. */
30
+ hostIndex: number
31
+ }
32
+
33
+ function isRecord(value: unknown): value is Record<string, unknown> {
34
+ return typeof value === 'object' && value !== null && !Array.isArray(value)
35
+ }
36
+
37
+ export function wireSubagentRunId(message: unknown): string | undefined {
38
+ if (!isRecord(message) || 'parts' in message) return undefined
39
+ const id = message.subagentRunId
40
+ return typeof id === 'string' && id !== '' ? id : undefined
41
+ }
42
+
43
+ export function wireSubagentInfo(
44
+ message: unknown,
45
+ ): SubagentWireInfo | undefined {
46
+ if (!isRecord(message) || !isRecord(message.metadata)) return undefined
47
+ const tanstack = message.metadata.tanstack
48
+ if (!isRecord(tanstack) || !isRecord(tanstack.subagent)) return undefined
49
+ // Wire data comes from the client. Keep only well-formed fields.
50
+ const { name, status, error, interruptIds } = tanstack.subagent
51
+ if (typeof name !== 'string' || !isStatus(status)) return undefined
52
+ const {
53
+ description,
54
+ parentSubagentRunId,
55
+ parentToolCallId,
56
+ metadata,
57
+ placeholder,
58
+ } = tanstack.subagent
59
+ return {
60
+ name,
61
+ status,
62
+ ...(typeof description === 'string' && { description }),
63
+ ...(isRecord(error) &&
64
+ typeof error.message === 'string' && {
65
+ error: {
66
+ message: error.message,
67
+ ...(typeof error.code === 'string' && { code: error.code }),
68
+ },
69
+ }),
70
+ ...(Array.isArray(interruptIds) && {
71
+ interruptIds: interruptIds.filter(
72
+ (id): id is string => typeof id === 'string',
73
+ ),
74
+ }),
75
+ ...(typeof parentSubagentRunId === 'string' && { parentSubagentRunId }),
76
+ ...(typeof parentToolCallId === 'string' && { parentToolCallId }),
77
+ ...(isRecord(metadata) && { metadata }),
78
+ ...(placeholder === true && { placeholder: true as const }),
79
+ }
80
+ }
81
+
82
+ function isStatus(value: unknown): value is SubagentWireInfo['status'] {
83
+ return (
84
+ value === 'running' ||
85
+ value === 'finished' ||
86
+ value === 'error' ||
87
+ value === 'suspended'
88
+ )
89
+ }
90
+
91
+ function untag<T>(message: T): T {
92
+ if (!isRecord(message)) return message
93
+ const { subagentRunId: _id, ...rest } = message
94
+ void _id
95
+ const metadata = isRecord(rest.metadata) ? rest.metadata : undefined
96
+ const tanstack = isRecord(metadata?.tanstack) ? metadata.tanstack : undefined
97
+ if (!metadata || !tanstack || !('subagent' in tanstack)) return rest as T
98
+ const { subagent: _info, ...tanstackRest } = tanstack
99
+ void _info
100
+ return { ...rest, metadata: { ...metadata, tanstack: tanstackRest } } as T
101
+ }
102
+
103
+ /**
104
+ * Split wire messages into the parent's own messages and one group per direct
105
+ * child. A nested child's messages stay inside its parent's group.
106
+ */
107
+ export function splitSubagentWire<T>(messages: ReadonlyArray<T>): {
108
+ top: Array<T>
109
+ groups: Array<SubagentWireGroup<T>>
110
+ } {
111
+ const parentOf = new Map<string, string | undefined>()
112
+ for (const message of messages) {
113
+ const id = wireSubagentRunId(message)
114
+ if (id !== undefined && !parentOf.has(id)) {
115
+ parentOf.set(id, wireSubagentInfo(message)?.parentSubagentRunId)
116
+ }
117
+ }
118
+ const rootOf = (id: string) => {
119
+ let current = id
120
+ for (let depth = 0; depth < 64; depth++) {
121
+ const parent = parentOf.get(current)
122
+ if (parent === undefined || !parentOf.has(parent)) return current
123
+ current = parent
124
+ }
125
+ return current
126
+ }
127
+
128
+ const top: Array<T> = []
129
+ const groups = new Map<string, SubagentWireGroup<T>>()
130
+ for (const message of messages) {
131
+ const id = wireSubagentRunId(message)
132
+ if (id === undefined) {
133
+ top.push(message)
134
+ continue
135
+ }
136
+ const root = rootOf(id)
137
+ let group = groups.get(root)
138
+ if (!group) {
139
+ group = {
140
+ id: root,
141
+ info: { name: 'subagent', status: 'finished' },
142
+ messages: [],
143
+ hostIndex: top.length - 1,
144
+ }
145
+ groups.set(root, group)
146
+ }
147
+ if (id !== root) {
148
+ group.messages.push(message)
149
+ continue
150
+ }
151
+ const info = wireSubagentInfo(message)
152
+ if (info) group.info = info
153
+ if (!info?.placeholder) group.messages.push(untag(message))
154
+ }
155
+ return { top, groups: [...groups.values()] }
156
+ }
157
+
158
+ /** Text a child wrote, for the parent model and for a later child. */
159
+ export function subagentWireText(messages: ReadonlyArray<unknown>): string {
160
+ const blocks: Array<string> = []
161
+ for (const message of messages) {
162
+ if (!isRecord(message) || message.role !== 'assistant') continue
163
+ if (wireSubagentRunId(message) !== undefined) continue
164
+ const content = message.content
165
+ if (typeof content === 'string' && content.trim() !== '') {
166
+ blocks.push(content.trim())
167
+ }
168
+ }
169
+ const nested = splitSubagentWire(messages).groups
170
+ for (const group of nested) {
171
+ const text = subagentWireText(group.messages)
172
+ if (text !== '') blocks.push(`${group.info.name}:\n${text}`)
173
+ }
174
+ return blocks.join('\n\n')
175
+ }
176
+
177
+ /**
178
+ * The id of the parent assistant message that hosts a routed turn's cards.
179
+ * The persistence recorder writes that message, and a handoff run passes the
180
+ * same id so the stored thread keeps one copy.
181
+ */
182
+ export function subagentHostMessageId(runId: string) {
183
+ return `assistant:${runId}`
184
+ }
@@ -10,8 +10,9 @@ const CONTENT_PART_TYPES = new Set([
10
10
 
11
11
  /**
12
12
  * Structural check for a single `ContentPart`. A text part must carry a string
13
- * `content`; every other modality must carry a `source` with `type` of
14
- * `'url' | 'data'` and a string `value`.
13
+ * `content`. Every other part carries a source with a string `value`; a file
14
+ * source's `value` is a non-empty opaque handle, and its optional `provider`
15
+ * is a string.
15
16
  */
16
17
  export function isContentPart(value: unknown): value is ContentPart {
17
18
  if (typeof value !== 'object' || value === null) return false
@@ -26,6 +27,14 @@ export function isContentPart(value: unknown): value is ContentPart {
26
27
  if (typeof source !== 'object' || source === null) return false
27
28
  const src = source as Record<string, unknown>
28
29
  if (typeof src.value !== 'string') return false
30
+ // `file` sources carry an opaque handle in `value`; `provider`, when set,
31
+ // names the issuer.
32
+ if (src.type === 'file') {
33
+ return (
34
+ src.value.length > 0 &&
35
+ (src.provider === undefined || typeof src.provider === 'string')
36
+ )
37
+ }
29
38
  // `data` sources require a mimeType (matches ContentPartDataSource); `url`
30
39
  // sources don't. Requiring it here keeps the runtime guard consistent with
31
40
  // the type and avoids emitting `data:undefined;base64,...` downstream.
@@ -45,6 +54,33 @@ export function isContentPartArray(
45
54
  return Array.isArray(value) && value.length > 0 && value.every(isContentPart)
46
55
  }
47
56
 
57
+ /**
58
+ * Error text for a failed tool result: `output.error` when it is a string,
59
+ * else the output itself when it is a string, else a generic message.
60
+ * `StreamProcessor` and `chat()` history share it, so a reload shows the
61
+ * same text as the live stream.
62
+ */
63
+ export function toolResultErrorText(output: unknown): string {
64
+ if (
65
+ output &&
66
+ typeof output === 'object' &&
67
+ 'error' in output &&
68
+ typeof output.error === 'string'
69
+ ) {
70
+ return output.error
71
+ }
72
+ return typeof output === 'string' ? output : 'Tool execution failed'
73
+ }
74
+
75
+ /** Parse tool result content as JSON. Plain text stays a string. */
76
+ export function parseToolOutput(content: string): unknown {
77
+ try {
78
+ return JSON.parse(content)
79
+ } catch {
80
+ return content
81
+ }
82
+ }
83
+
48
84
  /**
49
85
  * Normalize a tool's return value for transport:
50
86
  * - string → unchanged