@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
package/src/client.ts CHANGED
@@ -1,3 +1,194 @@
1
+ import type {
2
+ AudioGenerationOptions,
3
+ ImageGenerationOptions,
4
+ TTSOptions,
5
+ TranscriptionOptions,
6
+ VideoGenerationOptions,
7
+ } from './types'
8
+
9
+ export type GenerationKind =
10
+ | 'image'
11
+ | 'audio'
12
+ | 'tts'
13
+ | 'video'
14
+ | 'transcription'
15
+
16
+ type GenerationInputByKind = {
17
+ image: Omit<ImageGenerationOptions, 'logger' | 'model'>
18
+ audio: Omit<AudioGenerationOptions, 'logger' | 'model'>
19
+ tts: Omit<TTSOptions, 'logger' | 'model'>
20
+ video: Omit<VideoGenerationOptions, 'logger' | 'model'>
21
+ transcription: Omit<TranscriptionOptions, 'logger' | 'model'>
22
+ }
23
+
24
+ export interface GenerationParams<TKind extends GenerationKind> {
25
+ input: GenerationInputByKind[TKind]
26
+ forwardedProps: Record<string, unknown>
27
+ threadId?: string
28
+ runId?: string
29
+ }
30
+
31
+ const generationKinds = [
32
+ 'image',
33
+ 'audio',
34
+ 'tts',
35
+ 'video',
36
+ 'transcription',
37
+ ] as const satisfies ReadonlyArray<GenerationKind>
38
+
39
+ function isRecord(value: unknown): value is Record<string, unknown> {
40
+ return typeof value === 'object' && value !== null && !Array.isArray(value)
41
+ }
42
+
43
+ function hasOwnKey(value: Record<string, unknown>, key: string): boolean {
44
+ return Object.prototype.hasOwnProperty.call(value, key)
45
+ }
46
+
47
+ function isGenerationEnvelope(body: unknown): body is Record<string, unknown> {
48
+ return (
49
+ isRecord(body) &&
50
+ (hasOwnKey(body, 'data') || hasOwnKey(body, 'forwardedProps'))
51
+ )
52
+ }
53
+
54
+ function assertGenerationKind(kind: unknown): asserts kind is GenerationKind {
55
+ if (!generationKinds.includes(kind as GenerationKind)) {
56
+ throw new Error(
57
+ `Unsupported generation kind: ${String(
58
+ kind,
59
+ )}. Expected one of ${generationKinds.join(', ')}.`,
60
+ )
61
+ }
62
+ }
63
+
64
+ function assertInputForKind(
65
+ kind: GenerationKind,
66
+ input: unknown,
67
+ ): asserts input is GenerationInputByKind[GenerationKind] {
68
+ if (!isRecord(input)) {
69
+ throw new Error(`Generation ${kind} input must be an object.`)
70
+ }
71
+
72
+ const requiredKey =
73
+ kind === 'tts' ? 'text' : kind === 'transcription' ? 'audio' : 'prompt'
74
+
75
+ if (!hasOwnKey(input, requiredKey)) {
76
+ throw new Error(`Generation ${kind} input must include ${requiredKey}.`)
77
+ }
78
+ }
79
+
80
+ function isInputForKind(kind: GenerationKind, input: unknown): boolean {
81
+ if (!isRecord(input)) return false
82
+
83
+ const requiredKey =
84
+ kind === 'tts' ? 'text' : kind === 'transcription' ? 'audio' : 'prompt'
85
+
86
+ return hasOwnKey(input, requiredKey)
87
+ }
88
+
89
+ function forwardedPropsFromEnvelope(
90
+ envelope: Record<string, unknown>,
91
+ ): Record<string, unknown> {
92
+ if (!hasOwnKey(envelope, 'forwardedProps')) {
93
+ return {}
94
+ }
95
+
96
+ if (!isRecord(envelope.forwardedProps)) {
97
+ throw new Error('Generation envelope forwardedProps must be an object.')
98
+ }
99
+
100
+ return envelope.forwardedProps
101
+ }
102
+
103
+ function optionalStringField(
104
+ envelope: Record<string, unknown>,
105
+ key: 'threadId' | 'runId',
106
+ ): string | undefined {
107
+ if (!hasOwnKey(envelope, key)) {
108
+ return undefined
109
+ }
110
+
111
+ const value = envelope[key]
112
+ if (typeof value !== 'string') {
113
+ throw new Error(`Generation envelope ${key} must be a string.`)
114
+ }
115
+
116
+ return value
117
+ }
118
+
119
+ function generationIdentityFields(envelope: Record<string, unknown>): {
120
+ threadId?: string
121
+ runId?: string
122
+ } {
123
+ const identity: {
124
+ threadId?: string
125
+ runId?: string
126
+ } = {}
127
+ const threadId = optionalStringField(envelope, 'threadId')
128
+ const runId = optionalStringField(envelope, 'runId')
129
+
130
+ if (threadId !== undefined) identity.threadId = threadId
131
+ if (runId !== undefined) identity.runId = runId
132
+
133
+ return identity
134
+ }
135
+
136
+ export function generationParamsFromBody<TKind extends GenerationKind>(
137
+ kind: TKind,
138
+ body: unknown,
139
+ ): GenerationParams<TKind> {
140
+ assertGenerationKind(kind)
141
+
142
+ if (isInputForKind(kind, body)) {
143
+ assertInputForKind(kind, body)
144
+ return {
145
+ input: body as GenerationInputByKind[TKind],
146
+ forwardedProps: {},
147
+ }
148
+ }
149
+
150
+ if (!isGenerationEnvelope(body)) {
151
+ assertInputForKind(kind, body)
152
+ return {
153
+ input: body as GenerationInputByKind[TKind],
154
+ forwardedProps: {},
155
+ }
156
+ }
157
+
158
+ if (!hasOwnKey(body, 'data')) {
159
+ throw new Error(`Generation ${kind} envelope must include data.`)
160
+ }
161
+
162
+ const input = body.data
163
+ assertInputForKind(kind, input)
164
+
165
+ const forwardedProps = forwardedPropsFromEnvelope(body)
166
+
167
+ return {
168
+ input: input as GenerationInputByKind[TKind],
169
+ forwardedProps,
170
+ ...generationIdentityFields(body),
171
+ }
172
+ }
173
+
174
+ export async function generationParamsFromRequest<TKind extends GenerationKind>(
175
+ kind: TKind,
176
+ request: Request,
177
+ ): Promise<GenerationParams<TKind>> {
178
+ let body: unknown
179
+ try {
180
+ body = await request.json()
181
+ } catch (error) {
182
+ throw new Error('Invalid JSON request body.', { cause: error })
183
+ }
184
+
185
+ if (!isRecord(body)) {
186
+ throw new Error('Generation request body must be a JSON object.')
187
+ }
188
+
189
+ return generationParamsFromBody(kind, body)
190
+ }
191
+
1
192
  export enum EventType {
2
193
  TEXT_MESSAGE_START = 'TEXT_MESSAGE_START',
3
194
  TEXT_MESSAGE_CONTENT = 'TEXT_MESSAGE_CONTENT',
@@ -41,15 +232,35 @@ export {
41
232
  type InferToolInput,
42
233
  type InferToolName,
43
234
  type InferToolOutput,
235
+ type ApprovalCapabilityOf,
236
+ type ApprovalSchemaConfig,
237
+ type ApprovalSchemaOf,
238
+ type InputSchemaOf,
239
+ type OutputSchemaOf,
240
+ type NoSchema,
44
241
  type ToolDefinition,
45
242
  type ToolDefinitionConfig,
46
243
  type ToolDefinitionInstance,
47
244
  } from './activities/chat/tools/tool-definition'
48
245
 
246
+ export {
247
+ hashSchemaInput,
248
+ normalizeApprovalSchema,
249
+ type NormalizedApprovalSchema,
250
+ type NormalizedSchemaInput,
251
+ } from './activities/chat/tools/approval-schema'
252
+
253
+ export {
254
+ canonicalInterruptJson,
255
+ cloneAndDeepFreezeJson,
256
+ digestInterruptJson,
257
+ } from './interrupt-serialization'
258
+
49
259
  export {
50
260
  convertSchemaToJsonSchema,
51
261
  isStandardSchema,
52
262
  parseWithStandardSchema,
263
+ validateWithStandardSchema,
53
264
  } from './activities/chat/tools/schema-converter'
54
265
 
55
266
  export {
@@ -103,8 +314,14 @@ export type {
103
314
  MediaPromptPart,
104
315
  MessagePart,
105
316
  ModelMessage,
317
+ PersistedArtifactActivity,
318
+ PersistedArtifactRef,
319
+ PersistedArtifactRole,
320
+ Interrupt,
321
+ RunAgentResumeItem,
106
322
  RunErrorEvent,
107
323
  RunFinishedEvent,
324
+ RunFinishedOutcome,
108
325
  SchemaInput,
109
326
  StreamChunk,
110
327
  StructuredOutputPart,
@@ -119,6 +336,33 @@ export type {
119
336
  InferSchemaType,
120
337
  } from './types'
121
338
 
339
+ // Enumerated, not `export *` — see the matching note in `index.ts`. The
340
+ // interrupt protocol surface is a commitment, so it is published field by
341
+ // field.
342
+ export {
343
+ INTERRUPT_BINDING_VERSION,
344
+ canonicalizeInterruptResolutions,
345
+ } from './interrupts'
346
+ export type {
347
+ BatchInterruptError,
348
+ BatchInterruptErrorCode,
349
+ InterruptBinding,
350
+ InterruptCorrelation,
351
+ InterruptSubmissionError,
352
+ ItemInterruptError,
353
+ ItemInterruptErrorCode,
354
+ ToolApprovalResolution,
355
+ UnopenedInterruptBinding,
356
+ } from './interrupts'
357
+
358
+ export {
359
+ INTERRUPT_BINDING_METADATA_KEY,
360
+ readInterruptBinding,
361
+ readUnopenedInterruptBinding,
362
+ withInterruptBinding,
363
+ withoutInterruptBinding,
364
+ } from './interrupt-resume'
365
+
122
366
  export type {
123
367
  AudioVisualization,
124
368
  RealtimeAdapter,
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Catalog of well-known AG-UI `CUSTOM` event names used by the sandbox/agent
3
+ * layers, plus their payload shapes.
4
+ *
5
+ * The persisted run log is the AG-UI `StreamChunk` stream itself — there is no
6
+ * separate `RunEvent` type. Agent activity that has no first-class AG-UI event
7
+ * (process output, file diffs, ports, approvals, artifacts, sandbox lifecycle)
8
+ * rides on `CUSTOM` events carrying one of these names. Centralizing the names +
9
+ * payloads here keeps emitters (harness adapters, sandbox) and consumers
10
+ * (persistence projections, devtools, diff/terminal panels) in agreement without
11
+ * inventing a parallel event union.
12
+ */
13
+ import { EventType } from './types'
14
+ import type { CustomEvent, StreamChunk } from './types'
15
+
16
+ /** Well-known CUSTOM event names. */
17
+ export const CUSTOM_EVENT = {
18
+ FILE_CHANGED: 'file.changed',
19
+ PROCESS_STDOUT: 'process.stdout',
20
+ PROCESS_STDERR: 'process.stderr',
21
+ PORT_OPENED: 'port.opened',
22
+ APPROVAL_REQUESTED: 'approval.requested',
23
+ APPROVAL_RESOLVED: 'approval.resolved',
24
+ ARTIFACT_CREATED: 'artifact.created',
25
+ SANDBOX_CREATED: 'sandbox.created',
26
+ SANDBOX_RESUMED: 'sandbox.resumed',
27
+ } as const
28
+
29
+ /** Union of the well-known CUSTOM event name literals. */
30
+ export type WellKnownCustomEventName =
31
+ (typeof CUSTOM_EVENT)[keyof typeof CUSTOM_EVENT]
32
+
33
+ // ---- Payload shapes ----
34
+
35
+ export interface FileChangedPayload {
36
+ type: 'create' | 'change' | 'delete'
37
+ /** Absolute path inside the sandbox (under the workspace root). */
38
+ path: string
39
+ /** Unified diff, when the harness can produce one. */
40
+ diff?: string
41
+ timestamp: number
42
+ }
43
+
44
+ export interface ProcessOutputPayload {
45
+ /** Stable id for the spawned process whose output this is. */
46
+ processId: string
47
+ /** A chunk of stdout/stderr text. */
48
+ chunk: string
49
+ }
50
+
51
+ export interface PortOpenedPayload {
52
+ port: number
53
+ /** Externally reachable URL, when the provider exposes one. */
54
+ url?: string
55
+ }
56
+
57
+ export interface ApprovalRequestedPayload {
58
+ approvalId: string
59
+ title: string
60
+ /** Free-form detail describing the action awaiting approval. */
61
+ [key: string]: unknown
62
+ }
63
+
64
+ export interface ApprovalResolvedPayload {
65
+ approvalId: string
66
+ granted: boolean
67
+ }
68
+
69
+ export interface ArtifactCreatedPayload {
70
+ artifactId: string
71
+ name: string
72
+ mimeType: string
73
+ size: number
74
+ }
75
+
76
+ export interface SandboxLifecyclePayload {
77
+ sandboxId: string
78
+ provider: string
79
+ }
80
+
81
+ /** Maps each well-known name to its payload type. */
82
+ export interface CustomEventPayloads {
83
+ [CUSTOM_EVENT.FILE_CHANGED]: FileChangedPayload
84
+ [CUSTOM_EVENT.PROCESS_STDOUT]: ProcessOutputPayload
85
+ [CUSTOM_EVENT.PROCESS_STDERR]: ProcessOutputPayload
86
+ [CUSTOM_EVENT.PORT_OPENED]: PortOpenedPayload
87
+ [CUSTOM_EVENT.APPROVAL_REQUESTED]: ApprovalRequestedPayload
88
+ [CUSTOM_EVENT.APPROVAL_RESOLVED]: ApprovalResolvedPayload
89
+ [CUSTOM_EVENT.ARTIFACT_CREATED]: ArtifactCreatedPayload
90
+ [CUSTOM_EVENT.SANDBOX_CREATED]: SandboxLifecyclePayload
91
+ [CUSTOM_EVENT.SANDBOX_RESUMED]: SandboxLifecyclePayload
92
+ }
93
+
94
+ /** A CUSTOM event narrowed to a specific well-known name and its payload. */
95
+ export type WellKnownCustomEvent<TName extends WellKnownCustomEventName> =
96
+ CustomEvent & { name: TName; value: CustomEventPayloads[TName] }
97
+
98
+ /**
99
+ * Type guard: is `chunk` a CUSTOM event with the given well-known `name`?
100
+ * Narrows the payload type when true, so consumers read `chunk.value` typed.
101
+ */
102
+ export function isCustomEvent<TName extends WellKnownCustomEventName>(
103
+ chunk: StreamChunk,
104
+ name: TName,
105
+ ): chunk is WellKnownCustomEvent<TName> {
106
+ return chunk.type === EventType.CUSTOM && chunk.name === name
107
+ }
@@ -0,0 +1,72 @@
1
+ /**
2
+ * The one-way channel from a chat run to the durable DELIVERY sink that is
3
+ * persisting it.
4
+ *
5
+ * The sink (`durableStreamSource` in `./stream-to-response.ts`) has to answer one
6
+ * question on the abort path: was this disconnect a DETACH — the agent keeps
7
+ * running and a later attach will continue the log — or the end of the run? Only
8
+ * the run's own middleware can answer it (`withSandbox`'s `onAbort` resolves both
9
+ * out-of-band cancel bands and `detachOnDisconnect`), and the sink cannot reach
10
+ * the middleware capability bus: it lives one layer up, in the transport, and is
11
+ * handed nothing but the stream and a durability adapter.
12
+ *
13
+ * So the fact travels on the STREAM ITSELF, keyed by the exact object `chat()`
14
+ * returned. That is the seam an application cannot forget to wire: passing the
15
+ * stream to `toServerSentEventsResponse(stream, { durability })` is already
16
+ * mandatory, and it is the same object both sides hold. The alternative — a
17
+ * `detachable` flag on the response options — has to be re-wired correctly at
18
+ * every durable call site, and a forgotten one silently terminalizes a healthy
19
+ * detached run's log, which is the exact defect this channel exists to fix.
20
+ *
21
+ * The value is a THUNK, not a boolean: the verdict is only known during the run's
22
+ * teardown, long after the response object was built.
23
+ */
24
+
25
+ /**
26
+ * Per-stream detach predicates. Keyed weakly by the stream object, so a stream
27
+ * that is dropped without ever being consumed takes its entry with it.
28
+ */
29
+ const detachSignals = new WeakMap<object, () => boolean>()
30
+
31
+ /**
32
+ * Publish `stream`'s detach predicate. Called by `chat()` on the object it hands
33
+ * back, once per stream.
34
+ *
35
+ * Wired on BOTH streaming paths — `runStreamingText` and
36
+ * `runStreamingStructuredOutput` — since either can be handed to a durable
37
+ * transport helper. The non-streaming paths (`stream: false`, and the
38
+ * `Promise<T>` structured-output variant) resolve a value rather than yielding a
39
+ * stream, so there is no delivery sink to inform and nothing to publish.
40
+ *
41
+ * @internal
42
+ */
43
+ export function publishRunDetachedSignal(
44
+ stream: object,
45
+ wasDetached: () => boolean,
46
+ ): void {
47
+ detachSignals.set(stream, wasDetached)
48
+ }
49
+
50
+ /**
51
+ * Whether the run behind `stream` declared its abort a detach.
52
+ *
53
+ * `false` for anything that never published a predicate — a hand-rolled
54
+ * iterable, a `chat()` from an older build, a non-object source — so an unknown
55
+ * stream keeps the terminalize-and-close behavior rather than being spared it.
56
+ *
57
+ * A throwing predicate is also `false`, for the same reason: this is consulted on
58
+ * a teardown path where the only safe default is to terminalize. Leaving a log
59
+ * open because a probe threw would park every tailer forever.
60
+ *
61
+ * @internal
62
+ */
63
+ export function wasRunDetached(stream: unknown): boolean {
64
+ if (typeof stream !== 'object' || stream === null) return false
65
+ const signal = detachSignals.get(stream)
66
+ if (signal === undefined) return false
67
+ try {
68
+ return signal()
69
+ } catch {
70
+ return false
71
+ }
72
+ }
@@ -0,0 +1,84 @@
1
+ /**
2
+ * The one-way channel from the durable DELIVERY sink back to the chat run: "your
3
+ * viewer is gone, but you are not."
4
+ *
5
+ * This is the MIRROR of `./delivery-detach.ts`. That module answers a question the
6
+ * sink asks the run (was this abort a detach?); this one delivers a fact the sink
7
+ * learns first and the run cannot observe at all — the response body was
8
+ * cancelled. Both are keyed weakly by the exact stream object `chat()` returned,
9
+ * for the same reason: passing that object to
10
+ * `toServerSentEventsResponse(stream, { durability })` is already mandatory, so it
11
+ * is the one seam an application cannot forget to wire.
12
+ *
13
+ * WHY THE RUN CANNOT JUST WATCH AN ABORT SIGNAL. Before this channel existed, the
14
+ * only way a disconnect reached a run's middleware was for the application to
15
+ * mirror `request.signal` into `chat()`'s `abortController` — which ABORTS THE RUN.
16
+ * For a durable run that is precisely wrong, and wrong in the most expensive
17
+ * direction: `chat()` returns at its `isCancelled()` check immediately after
18
+ * middleware setup, so the harness adapter's `chatStream` is never called and the
19
+ * agent in the freshly-created sandbox is NEVER LAUNCHED. The user re-attaches to
20
+ * an empty log belonging to a run that did nothing, and no takeover can recover it
21
+ * because there is no journal to replay. The application was forced to choose
22
+ * between "the middleware learns about the disconnect" and "the run survives it".
23
+ *
24
+ * So the disconnect travels as a NOTIFICATION rather than a cancellation. The run
25
+ * hands it to whatever subscribed through `RunDisconnectCapability` — bookkeeping
26
+ * only, no teardown — and keeps producing into its still-open durable log, which
27
+ * is exactly what a re-attaching client tails to catch up.
28
+ *
29
+ * DISPATCHED FROM THE TRANSPORT, NOT FROM THE RUN'S UNWINDING. That is what makes
30
+ * it prompt. A run suspended inside a minutes-wide `setup` (cloning a repo into a
31
+ * sandbox) cannot dispatch anything from its own `finally`, because the `finally`
32
+ * is reached only once the generator unwinds — which is what made `detachedSince`
33
+ * land three minutes late instead of immediately.
34
+ */
35
+
36
+ /**
37
+ * Per-stream disconnect handlers. Keyed weakly by the stream object, so a stream
38
+ * dropped without ever being consumed takes its entry with it.
39
+ */
40
+ const disconnectHandlers = new WeakMap<object, () => void>()
41
+
42
+ /**
43
+ * Publish `stream`'s disconnect handler. Called by `chat()` on the object it hands
44
+ * back, once per stream.
45
+ *
46
+ * Wired on BOTH streaming paths — `runStreamingText` and
47
+ * `runStreamingStructuredOutput` — since either can be handed to a durable
48
+ * transport helper, matching `publishRunDetachedSignal`.
49
+ *
50
+ * @internal
51
+ */
52
+ export function publishRunDisconnectHandler(
53
+ stream: object,
54
+ onDisconnect: () => void,
55
+ ): void {
56
+ disconnectHandlers.set(stream, onDisconnect)
57
+ }
58
+
59
+ /**
60
+ * Tell the run behind `stream` that its delivery socket closed.
61
+ *
62
+ * A NO-OP for anything that never published a handler — a hand-rolled iterable, a
63
+ * `chat()` from an older build, a non-object source — so an unknown stream simply
64
+ * keeps today's behavior.
65
+ *
66
+ * NEVER THROWS and never returns a promise to await. This is called from
67
+ * `ReadableStream.cancel()`, whose rejection would surface as an unhandled error
68
+ * on a path where the consumer has already gone away; and the handler's own work
69
+ * is tracked by the run (which awaits it before finishing), not by this call. A
70
+ * throwing handler is swallowed for the same reason `wasRunDetached` swallows: the
71
+ * disconnect path has no second channel to report on.
72
+ *
73
+ * @internal
74
+ */
75
+ export function notifyRunDisconnected(stream: unknown): void {
76
+ if (typeof stream !== 'object' || stream === null) return
77
+ const handler = disconnectHandlers.get(stream)
78
+ if (handler === undefined) return
79
+ try {
80
+ handler()
81
+ } catch {
82
+ // Intentionally empty: see above.
83
+ }
84
+ }