@tanstack/ai 0.41.0 → 0.43.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 (272) hide show
  1. package/README.md +15 -1
  2. package/dist/esm/activities/chat/adapter.js +23 -16
  3. package/dist/esm/activities/chat/adapter.js.map +1 -1
  4. package/dist/esm/activities/chat/agent-loop-strategies.d.ts +10 -4
  5. package/dist/esm/activities/chat/agent-loop-strategies.js +75 -17
  6. package/dist/esm/activities/chat/agent-loop-strategies.js.map +1 -1
  7. package/dist/esm/activities/chat/cancel.d.ts +40 -0
  8. package/dist/esm/activities/chat/cancel.js +54 -0
  9. package/dist/esm/activities/chat/cancel.js.map +1 -0
  10. package/dist/esm/activities/chat/index.d.ts +28 -16
  11. package/dist/esm/activities/chat/index.js +2100 -1744
  12. package/dist/esm/activities/chat/index.js.map +1 -1
  13. package/dist/esm/activities/chat/mcp/manager.d.ts +2 -2
  14. package/dist/esm/activities/chat/mcp/manager.js +90 -77
  15. package/dist/esm/activities/chat/mcp/manager.js.map +1 -1
  16. package/dist/esm/activities/chat/mcp/types.d.ts +2 -2
  17. package/dist/esm/activities/chat/messages.js +397 -346
  18. package/dist/esm/activities/chat/messages.js.map +1 -1
  19. package/dist/esm/activities/chat/middleware/builder.js +17 -15
  20. package/dist/esm/activities/chat/middleware/builder.js.map +1 -1
  21. package/dist/esm/activities/chat/middleware/capabilities.js +78 -43
  22. package/dist/esm/activities/chat/middleware/capabilities.js.map +1 -1
  23. package/dist/esm/activities/chat/middleware/compose.d.ts +94 -1
  24. package/dist/esm/activities/chat/middleware/compose.js +623 -531
  25. package/dist/esm/activities/chat/middleware/compose.js.map +1 -1
  26. package/dist/esm/activities/chat/middleware/define.js +12 -5
  27. package/dist/esm/activities/chat/middleware/define.js.map +1 -1
  28. package/dist/esm/activities/chat/middleware/index.d.ts +5 -1
  29. package/dist/esm/activities/chat/middleware/locks.d.ts +50 -0
  30. package/dist/esm/activities/chat/middleware/locks.js +71 -0
  31. package/dist/esm/activities/chat/middleware/locks.js.map +1 -0
  32. package/dist/esm/activities/chat/middleware/pending-turn.d.ts +15 -0
  33. package/dist/esm/activities/chat/middleware/pending-turn.js +35 -0
  34. package/dist/esm/activities/chat/middleware/pending-turn.js.map +1 -0
  35. package/dist/esm/activities/chat/middleware/run-disconnect.d.ts +23 -0
  36. package/dist/esm/activities/chat/middleware/run-disconnect.js +42 -0
  37. package/dist/esm/activities/chat/middleware/run-disconnect.js.map +1 -0
  38. package/dist/esm/activities/chat/middleware/run-store.d.ts +283 -0
  39. package/dist/esm/activities/chat/middleware/run-store.js +176 -0
  40. package/dist/esm/activities/chat/middleware/run-store.js.map +1 -0
  41. package/dist/esm/activities/chat/middleware/sandbox-runtime.js +14 -8
  42. package/dist/esm/activities/chat/middleware/sandbox-runtime.js.map +1 -1
  43. package/dist/esm/activities/chat/middleware/tool-cache-middleware.js +79 -70
  44. package/dist/esm/activities/chat/middleware/tool-cache-middleware.js.map +1 -1
  45. package/dist/esm/activities/chat/middleware/types.d.ts +59 -2
  46. package/dist/esm/activities/chat/middleware/validate.js +23 -28
  47. package/dist/esm/activities/chat/middleware/validate.js.map +1 -1
  48. package/dist/esm/activities/chat/stream/json-parser.js +39 -25
  49. package/dist/esm/activities/chat/stream/json-parser.js.map +1 -1
  50. package/dist/esm/activities/chat/stream/message-updaters.js +275 -234
  51. package/dist/esm/activities/chat/stream/message-updaters.js.map +1 -1
  52. package/dist/esm/activities/chat/stream/processor.d.ts +24 -4
  53. package/dist/esm/activities/chat/stream/processor.js +1341 -1542
  54. package/dist/esm/activities/chat/stream/processor.js.map +1 -1
  55. package/dist/esm/activities/chat/stream/strategies.js +69 -53
  56. package/dist/esm/activities/chat/stream/strategies.js.map +1 -1
  57. package/dist/esm/activities/chat/tools/approval-schema.d.ts +19 -0
  58. package/dist/esm/activities/chat/tools/approval-schema.js +117 -0
  59. package/dist/esm/activities/chat/tools/approval-schema.js.map +1 -0
  60. package/dist/esm/activities/chat/tools/lazy-tool-manager.js +164 -191
  61. package/dist/esm/activities/chat/tools/lazy-tool-manager.js.map +1 -1
  62. package/dist/esm/activities/chat/tools/lazy-tools.js +24 -12
  63. package/dist/esm/activities/chat/tools/lazy-tools.js.map +1 -1
  64. package/dist/esm/activities/chat/tools/schema-converter.js +293 -146
  65. package/dist/esm/activities/chat/tools/schema-converter.js.map +1 -1
  66. package/dist/esm/activities/chat/tools/tool-calls.d.ts +18 -2
  67. package/dist/esm/activities/chat/tools/tool-calls.js +522 -531
  68. package/dist/esm/activities/chat/tools/tool-calls.js.map +1 -1
  69. package/dist/esm/activities/chat/tools/tool-definition.d.ts +75 -16
  70. package/dist/esm/activities/chat/tools/tool-definition.js +95 -23
  71. package/dist/esm/activities/chat/tools/tool-definition.js.map +1 -1
  72. package/dist/esm/activities/error-payload.js +85 -47
  73. package/dist/esm/activities/error-payload.js.map +1 -1
  74. package/dist/esm/activities/generateAudio/adapter.js +22 -15
  75. package/dist/esm/activities/generateAudio/adapter.js.map +1 -1
  76. package/dist/esm/activities/generateAudio/index.d.ts +4 -0
  77. package/dist/esm/activities/generateAudio/index.js +141 -105
  78. package/dist/esm/activities/generateAudio/index.js.map +1 -1
  79. package/dist/esm/activities/generateImage/adapter.js +22 -15
  80. package/dist/esm/activities/generateImage/adapter.js.map +1 -1
  81. package/dist/esm/activities/generateImage/index.d.ts +4 -0
  82. package/dist/esm/activities/generateImage/index.js +155 -111
  83. package/dist/esm/activities/generateImage/index.js.map +1 -1
  84. package/dist/esm/activities/generateSpeech/adapter.js +22 -15
  85. package/dist/esm/activities/generateSpeech/adapter.js.map +1 -1
  86. package/dist/esm/activities/generateSpeech/index.d.ts +4 -0
  87. package/dist/esm/activities/generateSpeech/index.js +159 -110
  88. package/dist/esm/activities/generateSpeech/index.js.map +1 -1
  89. package/dist/esm/activities/generateTranscription/adapter.js +22 -15
  90. package/dist/esm/activities/generateTranscription/adapter.js.map +1 -1
  91. package/dist/esm/activities/generateTranscription/index.d.ts +4 -0
  92. package/dist/esm/activities/generateTranscription/index.js +159 -100
  93. package/dist/esm/activities/generateTranscription/index.js.map +1 -1
  94. package/dist/esm/activities/generateVideo/adapter.js +36 -29
  95. package/dist/esm/activities/generateVideo/adapter.js.map +1 -1
  96. package/dist/esm/activities/generateVideo/index.d.ts +143 -19
  97. package/dist/esm/activities/generateVideo/index.js +456 -279
  98. package/dist/esm/activities/generateVideo/index.js.map +1 -1
  99. package/dist/esm/activities/generateVideo/snap.js +60 -48
  100. package/dist/esm/activities/generateVideo/snap.js.map +1 -1
  101. package/dist/esm/activities/index.js +8 -34
  102. package/dist/esm/activities/middleware/index.d.ts +1 -1
  103. package/dist/esm/activities/middleware/run.d.ts +10 -0
  104. package/dist/esm/activities/middleware/run.js +53 -29
  105. package/dist/esm/activities/middleware/run.js.map +1 -1
  106. package/dist/esm/activities/middleware/types.d.ts +44 -6
  107. package/dist/esm/activities/stream-generation-result.d.ts +4 -1
  108. package/dist/esm/activities/stream-generation-result.js +79 -44
  109. package/dist/esm/activities/stream-generation-result.js.map +1 -1
  110. package/dist/esm/activities/summarize/adapter.js +22 -15
  111. package/dist/esm/activities/summarize/adapter.js.map +1 -1
  112. package/dist/esm/activities/summarize/chat-stream-summarize.js +252 -202
  113. package/dist/esm/activities/summarize/chat-stream-summarize.js.map +1 -1
  114. package/dist/esm/activities/summarize/index.d.ts +27 -0
  115. package/dist/esm/activities/summarize/index.js +268 -102
  116. package/dist/esm/activities/summarize/index.js.map +1 -1
  117. package/dist/esm/adapter-internals.d.ts +2 -1
  118. package/dist/esm/adapter-internals.js +4 -11
  119. package/dist/esm/client.d.ts +25 -3
  120. package/dist/esm/client.js +131 -64
  121. package/dist/esm/client.js.map +1 -1
  122. package/dist/esm/custom-events.d.ts +76 -0
  123. package/dist/esm/custom-events.js +37 -0
  124. package/dist/esm/custom-events.js.map +1 -0
  125. package/dist/esm/delivery-detach.d.ts +50 -0
  126. package/dist/esm/delivery-detach.js +71 -0
  127. package/dist/esm/delivery-detach.js.map +1 -0
  128. package/dist/esm/delivery-disconnect.d.ts +62 -0
  129. package/dist/esm/delivery-disconnect.js +81 -0
  130. package/dist/esm/delivery-disconnect.js.map +1 -0
  131. package/dist/esm/extend-adapter.js +19 -17
  132. package/dist/esm/extend-adapter.js.map +1 -1
  133. package/dist/esm/index.d.ts +23 -5
  134. package/dist/esm/index.js +30 -97
  135. package/dist/esm/interrupt-resume.d.ts +71 -0
  136. package/dist/esm/interrupt-resume.js +438 -0
  137. package/dist/esm/interrupt-resume.js.map +1 -0
  138. package/dist/esm/interrupt-serialization.d.ts +12 -0
  139. package/dist/esm/interrupt-serialization.js +178 -0
  140. package/dist/esm/interrupt-serialization.js.map +1 -0
  141. package/dist/esm/interrupts.d.ts +84 -0
  142. package/dist/esm/interrupts.js +31 -0
  143. package/dist/esm/interrupts.js.map +1 -0
  144. package/dist/esm/locks.d.ts +10 -0
  145. package/dist/esm/locks.js +2 -0
  146. package/dist/esm/logger/console-logger.js +101 -78
  147. package/dist/esm/logger/console-logger.js.map +1 -1
  148. package/dist/esm/logger/internal-logger.js +104 -89
  149. package/dist/esm/logger/internal-logger.js.map +1 -1
  150. package/dist/esm/logger/resolve.js +54 -49
  151. package/dist/esm/logger/resolve.js.map +1 -1
  152. package/dist/esm/logger/types.d.ts +1 -1
  153. package/dist/esm/middlewares/content-guard.js +142 -148
  154. package/dist/esm/middlewares/content-guard.js.map +1 -1
  155. package/dist/esm/middlewares/index.js +2 -6
  156. package/dist/esm/middlewares/otel.js +598 -732
  157. package/dist/esm/middlewares/otel.js.map +1 -1
  158. package/dist/esm/middlewares/usage-attributes.js +47 -40
  159. package/dist/esm/middlewares/usage-attributes.js.map +1 -1
  160. package/dist/esm/realtime/event-emitter.js +24 -25
  161. package/dist/esm/realtime/event-emitter.js.map +1 -1
  162. package/dist/esm/realtime/index.d.ts +5 -9
  163. package/dist/esm/realtime/index.js +29 -6
  164. package/dist/esm/realtime/index.js.map +1 -1
  165. package/dist/esm/scope.d.ts +47 -0
  166. package/dist/esm/stream-durability.d.ts +171 -0
  167. package/dist/esm/stream-durability.js +295 -0
  168. package/dist/esm/stream-durability.js.map +1 -0
  169. package/dist/esm/stream-to-response.d.ts +178 -13
  170. package/dist/esm/stream-to-response.js +663 -115
  171. package/dist/esm/stream-to-response.js.map +1 -1
  172. package/dist/esm/strip-to-spec-middleware.js +30 -16
  173. package/dist/esm/strip-to-spec-middleware.js.map +1 -1
  174. package/dist/esm/system-prompts.js +27 -21
  175. package/dist/esm/system-prompts.js.map +1 -1
  176. package/dist/esm/tool-registry.js +72 -45
  177. package/dist/esm/tool-registry.js.map +1 -1
  178. package/dist/esm/tools/provider-tool.js +14 -5
  179. package/dist/esm/tools/provider-tool.js.map +1 -1
  180. package/dist/esm/types.d.ts +332 -21
  181. package/dist/esm/types.js +2 -0
  182. package/dist/esm/utilities/ag-ui-wire.js +79 -93
  183. package/dist/esm/utilities/ag-ui-wire.js.map +1 -1
  184. package/dist/esm/utilities/chat-params.d.ts +26 -4
  185. package/dist/esm/utilities/chat-params.js +218 -92
  186. package/dist/esm/utilities/chat-params.js.map +1 -1
  187. package/dist/esm/utilities/errors.js +28 -18
  188. package/dist/esm/utilities/errors.js.map +1 -1
  189. package/dist/esm/utilities/media-prompt.js +46 -41
  190. package/dist/esm/utilities/media-prompt.js.map +1 -1
  191. package/dist/esm/utilities/numbers.js +13 -10
  192. package/dist/esm/utilities/numbers.js.map +1 -1
  193. package/dist/esm/utilities/provider-executed.js +20 -11
  194. package/dist/esm/utilities/provider-executed.js.map +1 -1
  195. package/dist/esm/utilities/sampling-keys.js +31 -19
  196. package/dist/esm/utilities/sampling-keys.js.map +1 -1
  197. package/dist/esm/utilities/tool-result.js +42 -30
  198. package/dist/esm/utilities/tool-result.js.map +1 -1
  199. package/dist/esm/utilities/usage.js +27 -9
  200. package/dist/esm/utilities/usage.js.map +1 -1
  201. package/dist/esm/utils.js +26 -18
  202. package/dist/esm/utils.js.map +1 -1
  203. package/package.json +10 -6
  204. package/skills/ai-core/SKILL.md +69 -18
  205. package/skills/ai-core/adapter-configuration/SKILL.md +44 -21
  206. package/skills/ai-core/adapter-configuration/references/anthropic-adapter.md +1 -3
  207. package/skills/ai-core/adapter-configuration/references/byteplus-adapter.md +148 -0
  208. package/skills/ai-core/adapter-configuration/references/gemini-adapter.md +2 -6
  209. package/skills/ai-core/adapter-configuration/references/groq-adapter.md +2 -6
  210. package/skills/ai-core/adapter-configuration/references/openai-adapter.md +1 -3
  211. package/skills/ai-core/ag-ui-protocol/SKILL.md +1 -1
  212. package/skills/ai-core/chat-experience/SKILL.md +156 -11
  213. package/skills/ai-core/client-persistence/SKILL.md +277 -0
  214. package/skills/ai-core/custom-backend-integration/SKILL.md +1 -1
  215. package/skills/ai-core/debug-logging/SKILL.md +1 -1
  216. package/skills/ai-core/locks/SKILL.md +143 -0
  217. package/skills/ai-core/media-generation/SKILL.md +144 -12
  218. package/skills/ai-core/middleware/SKILL.md +258 -33
  219. package/skills/ai-core/structured-outputs/SKILL.md +1 -1
  220. package/skills/ai-core/tool-calling/SKILL.md +54 -59
  221. package/src/activities/chat/agent-loop-strategies.ts +10 -4
  222. package/src/activities/chat/cancel.ts +81 -0
  223. package/src/activities/chat/index.ts +1152 -153
  224. package/src/activities/chat/mcp/manager.ts +4 -4
  225. package/src/activities/chat/mcp/types.ts +2 -2
  226. package/src/activities/chat/messages.ts +5 -3
  227. package/src/activities/chat/middleware/builder.ts +1 -1
  228. package/src/activities/chat/middleware/compose.ts +186 -9
  229. package/src/activities/chat/middleware/index.ts +26 -0
  230. package/src/activities/chat/middleware/locks.ts +102 -0
  231. package/src/activities/chat/middleware/pending-turn.ts +47 -0
  232. package/src/activities/chat/middleware/run-disconnect.ts +62 -0
  233. package/src/activities/chat/middleware/run-store.ts +412 -0
  234. package/src/activities/chat/middleware/types.ts +62 -1
  235. package/src/activities/chat/stream/processor.ts +189 -5
  236. package/src/activities/chat/tools/approval-schema.ts +205 -0
  237. package/src/activities/chat/tools/tool-calls.ts +106 -13
  238. package/src/activities/chat/tools/tool-definition.ts +210 -39
  239. package/src/activities/generateAudio/index.ts +20 -3
  240. package/src/activities/generateImage/index.ts +20 -3
  241. package/src/activities/generateSpeech/index.ts +25 -3
  242. package/src/activities/generateTranscription/index.ts +26 -3
  243. package/src/activities/generateVideo/index.ts +345 -82
  244. package/src/activities/middleware/index.ts +2 -0
  245. package/src/activities/middleware/run.ts +31 -0
  246. package/src/activities/middleware/types.ts +49 -5
  247. package/src/activities/stream-generation-result.ts +30 -2
  248. package/src/activities/summarize/chat-stream-summarize.ts +5 -0
  249. package/src/activities/summarize/index.ts +200 -10
  250. package/src/adapter-internals.ts +10 -1
  251. package/src/client.ts +244 -0
  252. package/src/custom-events.ts +107 -0
  253. package/src/delivery-detach.ts +72 -0
  254. package/src/delivery-disconnect.ts +84 -0
  255. package/src/index.ts +138 -0
  256. package/src/interrupt-resume.ts +824 -0
  257. package/src/interrupt-serialization.ts +183 -0
  258. package/src/interrupts.ts +146 -0
  259. package/src/locks.ts +17 -0
  260. package/src/logger/types.ts +1 -1
  261. package/src/middlewares/otel.ts +1 -0
  262. package/src/realtime/index.ts +5 -9
  263. package/src/scope.ts +47 -0
  264. package/src/stream-durability.ts +598 -0
  265. package/src/stream-to-response.ts +1051 -95
  266. package/src/strip-to-spec-middleware.ts +3 -3
  267. package/src/types.ts +416 -24
  268. package/src/utilities/chat-params.ts +245 -55
  269. package/dist/esm/activities/index.js.map +0 -1
  270. package/dist/esm/adapter-internals.js.map +0 -1
  271. package/dist/esm/index.js.map +0 -1
  272. package/dist/esm/middlewares/index.js.map +0 -1
@@ -1,10 +1,15 @@
1
- import { AGUIError, RunAgentInputSchema } from '@ag-ui/core'
2
- import type { Context as AGUIContext } from '@ag-ui/core'
1
+ import { AGUIError } from '@ag-ui/core'
3
2
  import type {
3
+ Context as AGUIContext,
4
+ Message as AGUIMessage,
5
+ ResumeEntry as AGUIResumeEntry,
6
+ Role as AGUIRole,
7
+ } from '@ag-ui/core'
8
+ import type {
9
+ AnyTool,
4
10
  JSONSchema,
5
11
  ModelMessage,
6
- SchemaInput,
7
- Tool,
12
+ RunAgentResumeItem,
8
13
  UIMessage,
9
14
  } from '../types'
10
15
 
@@ -29,6 +34,162 @@ function isValidParts(value: unknown): value is Array<{ type: string }> {
29
34
  return true
30
35
  }
31
36
 
37
+ /**
38
+ * Keyed by `AGUIRole` so a role added upstream fails to compile here until it
39
+ * is handled, rather than silently falling through as an unknown role.
40
+ */
41
+ const AGUI_ROLES: Record<AGUIRole, true> = {
42
+ developer: true,
43
+ system: true,
44
+ assistant: true,
45
+ user: true,
46
+ tool: true,
47
+ activity: true,
48
+ reasoning: true,
49
+ }
50
+
51
+ function isAGUIRole(value: unknown): value is AGUIRole {
52
+ return typeof value === 'string' && value in AGUI_ROLES
53
+ }
54
+
55
+ function isRecord(value: unknown): value is Record<string, unknown> {
56
+ return typeof value === 'object' && value !== null && !Array.isArray(value)
57
+ }
58
+
59
+ /**
60
+ * Reject the request body, pointing at the migration guide. Mirrors the
61
+ * message the previous `RunAgentInputSchema.safeParse` failure produced.
62
+ */
63
+ function invalidBody(reason: string): never {
64
+ throw new AGUIError(
65
+ `Request body is not a valid AG-UI RunAgentInput. ` +
66
+ `If you're upgrading from a previous @tanstack/ai-client release, ` +
67
+ `see docs/migration/ag-ui-compliance.md. ` +
68
+ `Validation errors: ${reason}`,
69
+ )
70
+ }
71
+
72
+ function requireString(value: unknown, at: string): string {
73
+ if (typeof value !== 'string') invalidBody(`${at} must be a string`)
74
+ return value
75
+ }
76
+
77
+ function requireArray(value: unknown, at: string): Array<unknown> {
78
+ if (!Array.isArray(value)) invalidBody(`${at} must be an array`)
79
+ return value
80
+ }
81
+
82
+ /**
83
+ * Assert one AG-UI `Message`, discriminating on `role` exactly as the upstream
84
+ * `MessageSchema` discriminated union does. The record view is retained on the
85
+ * asserted type so callers can still inspect non-AG-UI extras like `parts`.
86
+ */
87
+ function assertAGUIMessage(
88
+ value: Record<string, unknown>,
89
+ at: string,
90
+ ): asserts value is Record<string, unknown> & AGUIMessage {
91
+ requireString(value.id, `${at}.id`)
92
+
93
+ const role = value.role
94
+ if (!isAGUIRole(role)) {
95
+ invalidBody(
96
+ `${at}.role must be one of ${Object.keys(AGUI_ROLES).join(' | ')}`,
97
+ )
98
+ }
99
+
100
+ switch (role) {
101
+ case 'assistant':
102
+ // Both optional: a tool-calling turn carries no text content.
103
+ if (value.content !== undefined) {
104
+ requireString(value.content, `${at}.content`)
105
+ }
106
+ if (value.toolCalls !== undefined) {
107
+ requireArray(value.toolCalls, `${at}.toolCalls`)
108
+ }
109
+ break
110
+ case 'user':
111
+ if (typeof value.content !== 'string' && !Array.isArray(value.content)) {
112
+ invalidBody(
113
+ `${at}.content must be a string or an array of content parts`,
114
+ )
115
+ }
116
+ break
117
+ case 'tool':
118
+ requireString(value.content, `${at}.content`)
119
+ requireString(value.toolCallId, `${at}.toolCallId`)
120
+ break
121
+ case 'activity':
122
+ requireString(value.activityType, `${at}.activityType`)
123
+ if (!isRecord(value.content)) {
124
+ invalidBody(`${at}.content must be an object`)
125
+ }
126
+ break
127
+ case 'developer':
128
+ case 'system':
129
+ case 'reasoning':
130
+ requireString(value.content, `${at}.content`)
131
+ break
132
+ }
133
+ }
134
+
135
+ function validateMessage(value: unknown, index: number): AGUIMessage {
136
+ const at = `messages[${index}]`
137
+ if (!isRecord(value)) invalidBody(`${at} must be an object`)
138
+ assertAGUIMessage(value, at)
139
+
140
+ // `parts` is TanStack's canonical extra, carried through so the UIMessage
141
+ // path inside `chat()` can use it. Keep it only when it holds recognized
142
+ // part types — the previous schema-based path dropped `parts` during parse
143
+ // and re-attached it from the raw body behind this same check.
144
+ if ('parts' in value && !isValidParts(value.parts)) {
145
+ const withoutParts = { ...value }
146
+ Reflect.deleteProperty(withoutParts, 'parts')
147
+ return withoutParts
148
+ }
149
+ return value
150
+ }
151
+
152
+ function validateTool(
153
+ value: unknown,
154
+ index: number,
155
+ ): { name: string; description: string; parameters: JSONSchema } {
156
+ const at = `tools[${index}]`
157
+ if (!isRecord(value)) invalidBody(`${at} must be an object`)
158
+ return {
159
+ name: requireString(value.name, `${at}.name`),
160
+ description: requireString(value.description, `${at}.description`),
161
+ // Upstream `ToolSchema` types this as optional `any`; it reaches the
162
+ // provider as a raw JSON Schema either way.
163
+ parameters: value.parameters as JSONSchema,
164
+ }
165
+ }
166
+
167
+ function validateContext(value: unknown, index: number): AGUIContext {
168
+ const at = `context[${index}]`
169
+ if (!isRecord(value)) invalidBody(`${at} must be an object`)
170
+ return {
171
+ description: requireString(value.description, `${at}.description`),
172
+ value: requireString(value.value, `${at}.value`),
173
+ }
174
+ }
175
+
176
+ function validateResumeEntry(value: unknown, index: number): AGUIResumeEntry {
177
+ const at = `resume[${index}]`
178
+ if (!isRecord(value)) invalidBody(`${at} must be an object`)
179
+ const status = value.status
180
+ if (status !== 'resolved' && status !== 'cancelled') {
181
+ invalidBody(`${at}.status must be "resolved" or "cancelled"`)
182
+ }
183
+ const entry: AGUIResumeEntry = {
184
+ interruptId: requireString(value.interruptId, `${at}.interruptId`),
185
+ status,
186
+ }
187
+ // Omit the key entirely when absent, matching the optional-field shape the
188
+ // schema produced.
189
+ if (value.payload !== undefined) entry.payload = value.payload
190
+ return entry
191
+ }
192
+
32
193
  /**
33
194
  * Parse and validate an HTTP request body as an AG-UI `RunAgentInput`.
34
195
  *
@@ -37,11 +198,14 @@ function isValidParts(value: unknown): value is Array<{ type: string }> {
37
198
  * `convertMessagesToModelMessages` handles AG-UI fan-out dedup and
38
199
  * reasoning/activity/developer-role normalization internally.
39
200
  *
201
+ * Validated structurally against the AG-UI `RunAgentInput` contract without a
202
+ * schema library, so this package pulls in no validation runtime of its own.
203
+ *
40
204
  * @throws An error with a migration-pointing message when the body does
41
- * not conform to AG-UI 0.0.52 `RunAgentInputSchema`. Surface this as a
205
+ * not conform to AG-UI `RunAgentInput`. Surface this as a
42
206
  * 400 Bad Request to the client.
43
207
  */
44
- export function chatParamsFromRequestBody(body: unknown): Promise<{
208
+ export async function chatParamsFromRequestBody(body: unknown): Promise<{
45
209
  messages: Array<UIMessage | ModelMessage>
46
210
  threadId: string
47
211
  runId: string
@@ -49,6 +213,7 @@ export function chatParamsFromRequestBody(body: unknown): Promise<{
49
213
  tools: Array<{ name: string; description: string; parameters: JSONSchema }>
50
214
  forwardedProps: Record<string, unknown>
51
215
  state: unknown
216
+ resume?: Array<RunAgentResumeItem>
52
217
  /**
53
218
  * @deprecated Use `aguiContext` instead. This alias will be removed in a
54
219
  * future release.
@@ -56,54 +221,41 @@ export function chatParamsFromRequestBody(body: unknown): Promise<{
56
221
  context: Array<AGUIContext>
57
222
  aguiContext: Array<AGUIContext>
58
223
  }> {
59
- const parseResult = RunAgentInputSchema.safeParse(body)
60
- if (!parseResult.success) {
61
- return Promise.reject(
62
- new AGUIError(
63
- `Request body is not a valid AG-UI RunAgentInput. ` +
64
- `If you're upgrading from a previous @tanstack/ai-client release, ` +
65
- `see docs/migration/ag-ui-compliance.md. ` +
66
- `Validation errors: ${parseResult.error.message}`,
67
- ),
68
- )
224
+ if (!isRecord(body)) invalidBody('body must be a JSON object')
225
+
226
+ const threadId = requireString(body.threadId, 'threadId')
227
+ const runId = requireString(body.runId, 'runId')
228
+ const parentRunId =
229
+ body.parentRunId === undefined
230
+ ? undefined
231
+ : requireString(body.parentRunId, 'parentRunId')
232
+
233
+ const messages = requireArray(body.messages, 'messages').map(validateMessage)
234
+ const tools = requireArray(body.tools, 'tools').map(validateTool)
235
+ const aguiContext = requireArray(body.context, 'context').map(validateContext)
236
+ const resume =
237
+ body.resume === undefined
238
+ ? undefined
239
+ : requireArray(body.resume, 'resume').map(validateResumeEntry)
240
+
241
+ if (body.forwardedProps !== undefined && !isRecord(body.forwardedProps)) {
242
+ invalidBody('forwardedProps must be an object')
69
243
  }
70
244
 
71
- const parsed = parseResult.data
72
- const aguiContext = parsed.context
73
-
74
- // AG-UI Zod uses `.strip()` so extra fields like `parts` on messages are
75
- // dropped during parse. We re-attach them from the original body so the
76
- // existing UIMessage path inside `chat()` can use them directly.
77
- const rawMessages =
78
- (body as { messages?: Array<Record<string, unknown>> }).messages ?? []
79
- const messages = parsed.messages.map((m, i) => {
80
- const raw = rawMessages[i]
81
- if (
82
- raw &&
83
- typeof raw === 'object' &&
84
- 'parts' in raw &&
85
- isValidParts(raw.parts)
86
- ) {
87
- return { ...m, parts: raw.parts } as UIMessage | ModelMessage
88
- }
89
- return m as ModelMessage
90
- })
91
-
92
- return Promise.resolve({
93
- messages,
94
- threadId: parsed.threadId,
95
- runId: parsed.runId,
96
- parentRunId: parsed.parentRunId,
97
- tools: parsed.tools as Array<{
98
- name: string
99
- description: string
100
- parameters: JSONSchema
101
- }>,
102
- forwardedProps: (parsed.forwardedProps ?? {}) as Record<string, unknown>,
103
- state: parsed.state,
245
+ return {
246
+ // Unknown top-level fields (e.g. a legacy `cursor`) are dropped by
247
+ // construction: only the fields below are copied onto the result.
248
+ messages: messages as Array<UIMessage | ModelMessage>,
249
+ threadId,
250
+ runId,
251
+ parentRunId,
252
+ tools,
253
+ forwardedProps: (body.forwardedProps ?? {}) as Record<string, unknown>,
254
+ state: body.state,
255
+ resume: resume as Array<RunAgentResumeItem> | undefined,
104
256
  context: aguiContext,
105
257
  aguiContext,
106
- })
258
+ }
107
259
  }
108
260
 
109
261
  /**
@@ -163,6 +315,20 @@ export async function chatParamsFromRequest(
163
315
  }
164
316
  }
165
317
 
318
+ /**
319
+ * Client-declared tool stub (no execute). `name` is `string`, so arrays that
320
+ * include these stubs intentionally widen `TypedStreamChunk` tool-name
321
+ * discrimination — pass server tools alone when you need a closed name union.
322
+ */
323
+ export type ClientToolDeclaration = {
324
+ name: string
325
+ description: string
326
+ inputSchema: JSONSchema
327
+ }
328
+
329
+ export type MergedAgentTools<TServerTools extends ReadonlyArray<AnyTool>> =
330
+ ReadonlyArray<TServerTools[number] | ClientToolDeclaration>
331
+
166
332
  /**
167
333
  * Merge a server-side tool array with the AG-UI client-declared tools
168
334
  * received in the request body.
@@ -178,22 +344,46 @@ export async function chatParamsFromRequest(
178
344
  * them — server emits a tool-call request, client executes via its
179
345
  * registered handler, client posts back the result.
180
346
  *
347
+ * Typing:
348
+ * - Empty `clientTools` preserves the server tuple (closed name union).
349
+ * - Non-empty `clientTools` returns a widened array that honestly includes
350
+ * client stubs, so `TypedStreamChunk` does not claim a closed server-only
351
+ * name union.
352
+ *
181
353
  * @param serverTools - The server's tool array (e.g. from
182
354
  * `[myToolDef.server(...)]`). Pass directly to `chat({ tools })`.
183
355
  * @param clientTools - The `tools` array received from
184
356
  * `chatParamsFromRequest(...)` / `chatParamsFromRequestBody(...)`.
185
357
  * @returns A merged array suitable for `chat({ tools })`.
186
358
  */
187
- export function mergeAgentTools<TContext = unknown>(
188
- serverTools: ReadonlyArray<Tool<SchemaInput, SchemaInput, string, TContext>>,
359
+ export function mergeAgentTools<
360
+ const TServerTools extends ReadonlyArray<AnyTool>,
361
+ >(serverTools: TServerTools, clientTools: readonly []): TServerTools
362
+ export function mergeAgentTools<
363
+ const TServerTools extends ReadonlyArray<AnyTool>,
364
+ >(
365
+ serverTools: TServerTools,
189
366
  clientTools: ReadonlyArray<{
190
367
  name: string
191
368
  description: string
192
369
  parameters: JSONSchema
193
370
  }>,
194
- ): Array<Tool<SchemaInput, SchemaInput, string, TContext>> {
371
+ ): MergedAgentTools<TServerTools>
372
+ export function mergeAgentTools<
373
+ const TServerTools extends ReadonlyArray<AnyTool>,
374
+ >(
375
+ serverTools: TServerTools,
376
+ clientTools: ReadonlyArray<{
377
+ name: string
378
+ description: string
379
+ parameters: JSONSchema
380
+ }>,
381
+ ): TServerTools | MergedAgentTools<TServerTools> {
382
+ if (clientTools.length === 0) {
383
+ return serverTools
384
+ }
195
385
  const seen = new Set(serverTools.map((t) => t.name))
196
- const merged: Array<Tool<SchemaInput, SchemaInput, string, TContext>> = [
386
+ const merged: Array<TServerTools[number] | ClientToolDeclaration> = [
197
387
  ...serverTools,
198
388
  ]
199
389
  for (const ct of clientTools) {
@@ -208,7 +398,7 @@ export function mergeAgentTools<TContext = unknown>(
208
398
  inputSchema: ct.parameters,
209
399
  // No `execute` — runtime treats this as a client-side tool and
210
400
  // emits ClientToolRequest events.
211
- } as Tool<SchemaInput, SchemaInput, string, TContext>)
401
+ })
212
402
  }
213
403
  return merged
214
404
  }
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"adapter-internals.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}