@tanstack/ai 0.42.0 → 0.43.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (273) 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 +5 -36
  5. package/dist/esm/activities/chat/agent-loop-strategies.js +75 -21
  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 -21
  11. package/dist/esm/activities/chat/index.js +2100 -1813
  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 +24 -6
  134. package/dist/esm/index.js +30 -98
  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.d.ts +3 -1
  157. package/dist/esm/middlewares/otel.js +599 -732
  158. package/dist/esm/middlewares/otel.js.map +1 -1
  159. package/dist/esm/middlewares/usage-attributes.js +47 -40
  160. package/dist/esm/middlewares/usage-attributes.js.map +1 -1
  161. package/dist/esm/realtime/event-emitter.js +24 -25
  162. package/dist/esm/realtime/event-emitter.js.map +1 -1
  163. package/dist/esm/realtime/index.d.ts +5 -9
  164. package/dist/esm/realtime/index.js +29 -6
  165. package/dist/esm/realtime/index.js.map +1 -1
  166. package/dist/esm/scope.d.ts +47 -0
  167. package/dist/esm/stream-durability.d.ts +171 -0
  168. package/dist/esm/stream-durability.js +295 -0
  169. package/dist/esm/stream-durability.js.map +1 -0
  170. package/dist/esm/stream-to-response.d.ts +178 -13
  171. package/dist/esm/stream-to-response.js +663 -115
  172. package/dist/esm/stream-to-response.js.map +1 -1
  173. package/dist/esm/strip-to-spec-middleware.js +30 -16
  174. package/dist/esm/strip-to-spec-middleware.js.map +1 -1
  175. package/dist/esm/system-prompts.js +27 -21
  176. package/dist/esm/system-prompts.js.map +1 -1
  177. package/dist/esm/tool-registry.js +72 -45
  178. package/dist/esm/tool-registry.js.map +1 -1
  179. package/dist/esm/tools/provider-tool.js +14 -5
  180. package/dist/esm/tools/provider-tool.js.map +1 -1
  181. package/dist/esm/types.d.ts +321 -42
  182. package/dist/esm/types.js +2 -0
  183. package/dist/esm/utilities/ag-ui-wire.js +79 -93
  184. package/dist/esm/utilities/ag-ui-wire.js.map +1 -1
  185. package/dist/esm/utilities/chat-params.d.ts +26 -4
  186. package/dist/esm/utilities/chat-params.js +218 -92
  187. package/dist/esm/utilities/chat-params.js.map +1 -1
  188. package/dist/esm/utilities/errors.js +28 -18
  189. package/dist/esm/utilities/errors.js.map +1 -1
  190. package/dist/esm/utilities/media-prompt.js +46 -41
  191. package/dist/esm/utilities/media-prompt.js.map +1 -1
  192. package/dist/esm/utilities/numbers.js +13 -10
  193. package/dist/esm/utilities/numbers.js.map +1 -1
  194. package/dist/esm/utilities/provider-executed.js +20 -11
  195. package/dist/esm/utilities/provider-executed.js.map +1 -1
  196. package/dist/esm/utilities/sampling-keys.js +31 -19
  197. package/dist/esm/utilities/sampling-keys.js.map +1 -1
  198. package/dist/esm/utilities/tool-result.js +42 -30
  199. package/dist/esm/utilities/tool-result.js.map +1 -1
  200. package/dist/esm/utilities/usage.js +27 -9
  201. package/dist/esm/utilities/usage.js.map +1 -1
  202. package/dist/esm/utils.js +26 -18
  203. package/dist/esm/utils.js.map +1 -1
  204. package/package.json +10 -6
  205. package/skills/ai-core/SKILL.md +69 -18
  206. package/skills/ai-core/adapter-configuration/SKILL.md +44 -21
  207. package/skills/ai-core/adapter-configuration/references/anthropic-adapter.md +1 -3
  208. package/skills/ai-core/adapter-configuration/references/byteplus-adapter.md +148 -0
  209. package/skills/ai-core/adapter-configuration/references/gemini-adapter.md +2 -6
  210. package/skills/ai-core/adapter-configuration/references/groq-adapter.md +2 -6
  211. package/skills/ai-core/adapter-configuration/references/openai-adapter.md +1 -3
  212. package/skills/ai-core/ag-ui-protocol/SKILL.md +1 -1
  213. package/skills/ai-core/chat-experience/SKILL.md +98 -11
  214. package/skills/ai-core/client-persistence/SKILL.md +277 -0
  215. package/skills/ai-core/custom-backend-integration/SKILL.md +1 -1
  216. package/skills/ai-core/debug-logging/SKILL.md +1 -1
  217. package/skills/ai-core/locks/SKILL.md +143 -0
  218. package/skills/ai-core/media-generation/SKILL.md +144 -12
  219. package/skills/ai-core/middleware/SKILL.md +258 -33
  220. package/skills/ai-core/structured-outputs/SKILL.md +1 -1
  221. package/skills/ai-core/tool-calling/SKILL.md +54 -61
  222. package/src/activities/chat/agent-loop-strategies.ts +5 -39
  223. package/src/activities/chat/cancel.ts +81 -0
  224. package/src/activities/chat/index.ts +1091 -200
  225. package/src/activities/chat/mcp/manager.ts +4 -4
  226. package/src/activities/chat/mcp/types.ts +2 -2
  227. package/src/activities/chat/messages.ts +5 -3
  228. package/src/activities/chat/middleware/builder.ts +1 -1
  229. package/src/activities/chat/middleware/compose.ts +186 -9
  230. package/src/activities/chat/middleware/index.ts +26 -0
  231. package/src/activities/chat/middleware/locks.ts +102 -0
  232. package/src/activities/chat/middleware/pending-turn.ts +47 -0
  233. package/src/activities/chat/middleware/run-disconnect.ts +62 -0
  234. package/src/activities/chat/middleware/run-store.ts +412 -0
  235. package/src/activities/chat/middleware/types.ts +62 -1
  236. package/src/activities/chat/stream/processor.ts +189 -5
  237. package/src/activities/chat/tools/approval-schema.ts +205 -0
  238. package/src/activities/chat/tools/tool-calls.ts +106 -13
  239. package/src/activities/chat/tools/tool-definition.ts +210 -39
  240. package/src/activities/generateAudio/index.ts +20 -3
  241. package/src/activities/generateImage/index.ts +20 -3
  242. package/src/activities/generateSpeech/index.ts +25 -3
  243. package/src/activities/generateTranscription/index.ts +26 -3
  244. package/src/activities/generateVideo/index.ts +345 -82
  245. package/src/activities/middleware/index.ts +2 -0
  246. package/src/activities/middleware/run.ts +31 -0
  247. package/src/activities/middleware/types.ts +49 -5
  248. package/src/activities/stream-generation-result.ts +30 -2
  249. package/src/activities/summarize/chat-stream-summarize.ts +5 -0
  250. package/src/activities/summarize/index.ts +200 -10
  251. package/src/adapter-internals.ts +10 -1
  252. package/src/client.ts +244 -0
  253. package/src/custom-events.ts +107 -0
  254. package/src/delivery-detach.ts +72 -0
  255. package/src/delivery-disconnect.ts +84 -0
  256. package/src/index.ts +138 -1
  257. package/src/interrupt-resume.ts +824 -0
  258. package/src/interrupt-serialization.ts +183 -0
  259. package/src/interrupts.ts +146 -0
  260. package/src/locks.ts +17 -0
  261. package/src/logger/types.ts +1 -1
  262. package/src/middlewares/otel.ts +23 -5
  263. package/src/realtime/index.ts +5 -9
  264. package/src/scope.ts +47 -0
  265. package/src/stream-durability.ts +598 -0
  266. package/src/stream-to-response.ts +1051 -95
  267. package/src/strip-to-spec-middleware.ts +3 -3
  268. package/src/types.ts +405 -45
  269. package/src/utilities/chat-params.ts +245 -55
  270. package/dist/esm/activities/index.js.map +0 -1
  271. package/dist/esm/adapter-internals.js.map +0 -1
  272. package/dist/esm/index.js.map +0 -1
  273. package/dist/esm/middlewares/index.js.map +0 -1
@@ -1,109 +1,168 @@
1
- import { aiEventClient } from "@tanstack/ai-event-client";
2
- import { streamGenerationResult } from "../stream-generation-result.js";
3
1
  import { resolveDebugOption } from "../../logger/resolve.js";
4
- import { createGenerationContext, runGenerationStart, runGenerationUsage, runGenerationFinish, runGenerationError } from "../middleware/run.js";
5
- const kind = "transcription";
2
+ import { streamGenerationResult } from "../stream-generation-result.js";
3
+ import { applyGenerationResultTransforms, createGenerationContext, runGenerationError, runGenerationFinish, runGenerationStart, runGenerationUsage } from "../middleware/run.js";
4
+ import "./adapter.js";
5
+ import { aiEventClient } from "@tanstack/ai-event-client";
6
+ //#region src/activities/generateTranscription/index.ts
7
+ /**
8
+ * Transcription Activity
9
+ *
10
+ * Transcribes audio to text using speech-to-text models.
11
+ * This is a self-contained module with implementation, types, and JSDoc.
12
+ */
13
+ /** The adapter kind this activity handles */
14
+ var kind = "transcription";
6
15
  function createId(prefix) {
7
- return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
16
+ return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
8
17
  }
18
+ /**
19
+ * Transcription activity - converts audio to text.
20
+ *
21
+ * Uses AI speech-to-text models to transcribe audio content.
22
+ *
23
+ * @example Transcribe an audio file
24
+ * ```ts
25
+ * import { generateTranscription } from '@tanstack/ai'
26
+ * import { openaiTranscription } from '@tanstack/ai-openai'
27
+ *
28
+ * const result = await generateTranscription({
29
+ * adapter: openaiTranscription('whisper-1'),
30
+ * audio: audioFile, // File, Blob, or base64 string
31
+ * language: 'en'
32
+ * })
33
+ *
34
+ * console.log(result.text)
35
+ * ```
36
+ *
37
+ * @example With verbose output for timestamps
38
+ * ```ts
39
+ * const result = await generateTranscription({
40
+ * adapter: openaiTranscription('whisper-1'),
41
+ * audio: audioFile,
42
+ * responseFormat: 'verbose_json'
43
+ * })
44
+ *
45
+ * result.segments?.forEach(segment => {
46
+ * console.log(`[${segment.start}s - ${segment.end}s]: ${segment.text}`)
47
+ * })
48
+ * ```
49
+ *
50
+ * @example Streaming transcription result
51
+ * ```ts
52
+ * for await (const chunk of generateTranscription({
53
+ * adapter: openaiTranscription('whisper-1'),
54
+ * audio: audioFile,
55
+ * stream: true
56
+ * })) {
57
+ * console.log(chunk)
58
+ * }
59
+ * ```
60
+ */
9
61
  function generateTranscription(options) {
10
- if (options.stream) {
11
- return streamGenerationResult(
12
- () => runGenerateTranscription(options)
13
- );
14
- }
15
- return runGenerateTranscription(
16
- options
17
- );
62
+ if (options.stream) return streamGenerationResult((resolved) => runGenerateTranscription({
63
+ ...options,
64
+ runId: resolved.runId
65
+ }), options);
66
+ return runGenerateTranscription(options);
18
67
  }
68
+ /**
69
+ * Run non-streaming transcription
70
+ */
19
71
  async function runGenerateTranscription(options) {
20
- const {
21
- adapter,
22
- stream: _stream,
23
- debug: _debug,
24
- middleware,
25
- ...rest
26
- } = options;
27
- const model = adapter.model;
28
- const requestId = createId("transcription");
29
- const startTime = Date.now();
30
- const logger = resolveDebugOption(options.debug);
31
- const providerName = adapter.provider ?? adapter.name ?? "unknown";
32
- const mwCtx = createGenerationContext({
33
- requestId,
34
- activity: "transcription",
35
- provider: adapter.name,
36
- model,
37
- modelOptions: rest.modelOptions,
38
- createId
39
- });
40
- await runGenerationStart(middleware, mwCtx);
41
- aiEventClient.emit("transcription:request:started", {
42
- requestId,
43
- provider: adapter.name,
44
- model,
45
- language: rest.language,
46
- prompt: rest.prompt,
47
- responseFormat: rest.responseFormat,
48
- modelOptions: rest.modelOptions,
49
- timestamp: startTime
50
- });
51
- logger.request(`activity=generateTranscription provider=${providerName}`, {
52
- provider: providerName,
53
- model
54
- });
55
- try {
56
- const result = await adapter.transcribe({ ...rest, model, logger });
57
- const duration = Date.now() - startTime;
58
- aiEventClient.emit("transcription:request:completed", {
59
- requestId,
60
- provider: adapter.name,
61
- model,
62
- text: result.text,
63
- language: result.language,
64
- duration,
65
- modelOptions: rest.modelOptions,
66
- timestamp: Date.now()
67
- });
68
- logger.output(
69
- `activity=generateTranscription length=${result.text.length}`,
70
- { hasText: !!result.text }
71
- );
72
- if (result.usage) await runGenerationUsage(middleware, mwCtx, result.usage);
73
- await runGenerationFinish(middleware, mwCtx, {
74
- duration,
75
- usage: result.usage
76
- });
77
- return result;
78
- } catch (error) {
79
- const duration = Date.now() - startTime;
80
- const err = error;
81
- aiEventClient.emit("transcription:request:error", {
82
- requestId,
83
- provider: adapter.name,
84
- model,
85
- error: { message: err.message, name: err.name },
86
- duration,
87
- modelOptions: rest.modelOptions,
88
- timestamp: Date.now()
89
- });
90
- await runGenerationError(middleware, mwCtx, {
91
- error,
92
- duration
93
- });
94
- logger.errors("generateTranscription activity failed", {
95
- error,
96
- source: "generateTranscription"
97
- });
98
- throw error;
99
- }
72
+ const { adapter, stream: _stream, debug: _debug, middleware, threadId, runId, ...rest } = options;
73
+ const model = adapter.model;
74
+ const requestId = createId("transcription");
75
+ const startTime = Date.now();
76
+ const logger = resolveDebugOption(options.debug);
77
+ const providerName = adapter.provider ?? adapter.name ?? "unknown";
78
+ const mwCtx = createGenerationContext({
79
+ requestId,
80
+ activity: "transcription",
81
+ provider: adapter.name,
82
+ model,
83
+ modelOptions: rest.modelOptions,
84
+ artifactInputs: {
85
+ audio: rest.audio,
86
+ language: rest.language,
87
+ prompt: rest.prompt,
88
+ responseFormat: rest.responseFormat
89
+ },
90
+ threadId,
91
+ runId,
92
+ createId
93
+ });
94
+ await runGenerationStart(middleware, mwCtx);
95
+ aiEventClient.emit("transcription:request:started", {
96
+ requestId,
97
+ provider: adapter.name,
98
+ model,
99
+ language: rest.language,
100
+ prompt: rest.prompt,
101
+ responseFormat: rest.responseFormat,
102
+ modelOptions: rest.modelOptions,
103
+ timestamp: startTime
104
+ });
105
+ logger.request(`activity=generateTranscription provider=${providerName}`, {
106
+ provider: providerName,
107
+ model
108
+ });
109
+ try {
110
+ const result = await applyGenerationResultTransforms(mwCtx, await adapter.transcribe({
111
+ ...rest,
112
+ model,
113
+ logger
114
+ }));
115
+ const duration = Date.now() - startTime;
116
+ aiEventClient.emit("transcription:request:completed", {
117
+ requestId,
118
+ provider: adapter.name,
119
+ model,
120
+ text: result.text,
121
+ language: result.language,
122
+ duration,
123
+ modelOptions: rest.modelOptions,
124
+ timestamp: Date.now()
125
+ });
126
+ logger.output(`activity=generateTranscription length=${result.text.length}`, { hasText: !!result.text });
127
+ if (result.usage) await runGenerationUsage(middleware, mwCtx, result.usage);
128
+ await runGenerationFinish(middleware, mwCtx, {
129
+ duration,
130
+ usage: result.usage
131
+ });
132
+ return result;
133
+ } catch (error) {
134
+ const duration = Date.now() - startTime;
135
+ const err = error;
136
+ aiEventClient.emit("transcription:request:error", {
137
+ requestId,
138
+ provider: adapter.name,
139
+ model,
140
+ error: {
141
+ message: err.message,
142
+ name: err.name
143
+ },
144
+ duration,
145
+ modelOptions: rest.modelOptions,
146
+ timestamp: Date.now()
147
+ });
148
+ await runGenerationError(middleware, mwCtx, {
149
+ error,
150
+ duration
151
+ });
152
+ logger.errors("generateTranscription activity failed", {
153
+ error,
154
+ source: "generateTranscription"
155
+ });
156
+ throw error;
157
+ }
100
158
  }
159
+ /**
160
+ * Create typed options for the generateTranscription() function without executing.
161
+ */
101
162
  function createTranscriptionOptions(options) {
102
- return options;
163
+ return options;
103
164
  }
104
- export {
105
- createTranscriptionOptions,
106
- generateTranscription,
107
- kind
108
- };
109
- //# sourceMappingURL=index.js.map
165
+ //#endregion
166
+ export { createTranscriptionOptions, generateTranscription, kind };
167
+
168
+ //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../../src/activities/generateTranscription/index.ts"],"sourcesContent":["/**\n * Transcription Activity\n *\n * Transcribes audio to text using speech-to-text models.\n * This is a self-contained module with implementation, types, and JSDoc.\n */\n\nimport { aiEventClient } from '@tanstack/ai-event-client'\nimport { streamGenerationResult } from '../stream-generation-result.js'\nimport { resolveDebugOption } from '../../logger/resolve'\nimport {\n createGenerationContext,\n runGenerationError,\n runGenerationFinish,\n runGenerationStart,\n runGenerationUsage,\n} from '../middleware/run'\nimport type { InternalLogger } from '../../logger/internal-logger'\nimport type { DebugOption } from '../../logger/types'\nimport type { GenerationMiddleware } from '../middleware/types'\nimport type { TranscriptionAdapter } from './adapter'\nimport type {\n StreamChunk,\n TranscriptionResponseFormat,\n TranscriptionResult,\n} from '../../types'\n\n// ===========================\n// Activity Kind\n// ===========================\n\n/** The adapter kind this activity handles */\nexport const kind = 'transcription' as const\n\n// ===========================\n// Type Extraction Helpers\n// ===========================\n\n/**\n * Extract provider options from a TranscriptionAdapter via ~types.\n */\nexport type TranscriptionProviderOptions<TAdapter> =\n TAdapter extends TranscriptionAdapter<any, any>\n ? TAdapter['~types']['providerOptions']\n : object\n\n// ===========================\n// Activity Options Type\n// ===========================\n\n/**\n * Options for the transcription activity.\n * The model is extracted from the adapter's model property.\n *\n * @template TAdapter - The transcription adapter type\n * @template TStream - Whether to stream the output\n */\nexport interface TranscriptionActivityOptions<\n TAdapter extends TranscriptionAdapter<\n string,\n TranscriptionProviderOptions<TAdapter>\n >,\n TStream extends boolean = false,\n> {\n /** The transcription adapter to use (must be created with a model) */\n adapter: TAdapter & { kind: typeof kind }\n /** The audio data to transcribe - can be base64 string, File, Blob, or Buffer */\n audio: string | File | Blob | ArrayBuffer\n /** The language of the audio in ISO-639-1 format (e.g., 'en') */\n language?: string\n /** An optional prompt to guide the transcription */\n prompt?: string\n /** The format of the transcription output */\n responseFormat?: TranscriptionResponseFormat\n /** Provider-specific options for transcription */\n modelOptions?: TranscriptionProviderOptions<TAdapter>\n /**\n * Whether to stream the transcription result.\n * When true, returns an AsyncIterable<StreamChunk> for streaming transport.\n * When false or not provided, returns a Promise<TranscriptionResult>.\n *\n * @default false\n */\n stream?: TStream\n /**\n * Enable debug logging. Pass `true` to enable all categories, `false` to\n * silence everything including errors, or a `DebugConfig` object for granular\n * control and/or a custom `Logger`.\n */\n debug?: DebugOption\n /**\n * Observe-only middleware notified on start, usage, success, and error. Pass\n * `otelMiddleware()` to emit OpenTelemetry spans, or implement the\n * `GenerationMiddleware` contract for a custom backend.\n */\n middleware?: Array<GenerationMiddleware>\n}\n\n// ===========================\n// Activity Result Type\n// ===========================\n\n/**\n * Result type for the transcription activity.\n * - If stream is true: AsyncIterable<StreamChunk>\n * - Otherwise: Promise<TranscriptionResult>\n */\nexport type TranscriptionActivityResult<TStream extends boolean = false> =\n TStream extends true\n ? AsyncIterable<StreamChunk>\n : Promise<TranscriptionResult>\n\nfunction createId(prefix: string): string {\n return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`\n}\n\n// ===========================\n// Activity Implementation\n// ===========================\n\n/**\n * Transcription activity - converts audio to text.\n *\n * Uses AI speech-to-text models to transcribe audio content.\n *\n * @example Transcribe an audio file\n * ```ts\n * import { generateTranscription } from '@tanstack/ai'\n * import { openaiTranscription } from '@tanstack/ai-openai'\n *\n * const result = await generateTranscription({\n * adapter: openaiTranscription('whisper-1'),\n * audio: audioFile, // File, Blob, or base64 string\n * language: 'en'\n * })\n *\n * console.log(result.text)\n * ```\n *\n * @example With verbose output for timestamps\n * ```ts\n * const result = await generateTranscription({\n * adapter: openaiTranscription('whisper-1'),\n * audio: audioFile,\n * responseFormat: 'verbose_json'\n * })\n *\n * result.segments?.forEach(segment => {\n * console.log(`[${segment.start}s - ${segment.end}s]: ${segment.text}`)\n * })\n * ```\n *\n * @example Streaming transcription result\n * ```ts\n * for await (const chunk of generateTranscription({\n * adapter: openaiTranscription('whisper-1'),\n * audio: audioFile,\n * stream: true\n * })) {\n * console.log(chunk)\n * }\n * ```\n */\nexport function generateTranscription<\n TAdapter extends TranscriptionAdapter<\n string,\n TranscriptionProviderOptions<TAdapter>\n >,\n TStream extends boolean = false,\n>(\n options: TranscriptionActivityOptions<TAdapter, TStream>,\n): TranscriptionActivityResult<TStream> {\n if (options.stream) {\n return streamGenerationResult(() =>\n runGenerateTranscription(options),\n ) as TranscriptionActivityResult<TStream>\n }\n\n return runGenerateTranscription(\n options,\n ) as TranscriptionActivityResult<TStream>\n}\n\n/**\n * Run non-streaming transcription\n */\nasync function runGenerateTranscription<\n TAdapter extends TranscriptionAdapter<\n string,\n TranscriptionProviderOptions<TAdapter>\n >,\n>(\n options: TranscriptionActivityOptions<TAdapter, boolean>,\n): Promise<TranscriptionResult> {\n const {\n adapter,\n stream: _stream,\n debug: _debug,\n middleware,\n ...rest\n } = options\n const model = adapter.model\n const requestId = createId('transcription')\n const startTime = Date.now()\n const logger: InternalLogger = resolveDebugOption(options.debug)\n const providerName =\n (adapter as { name?: string; provider?: string }).provider ??\n (adapter as { name?: string }).name ??\n 'unknown'\n\n const mwCtx = createGenerationContext({\n requestId,\n activity: 'transcription',\n provider: adapter.name,\n model,\n modelOptions: rest.modelOptions,\n createId,\n })\n\n await runGenerationStart(middleware, mwCtx)\n\n aiEventClient.emit('transcription:request:started', {\n requestId,\n provider: adapter.name,\n model,\n language: rest.language,\n prompt: rest.prompt,\n responseFormat: rest.responseFormat,\n modelOptions: rest.modelOptions as Record<string, unknown> | undefined,\n timestamp: startTime,\n })\n\n logger.request(`activity=generateTranscription provider=${providerName}`, {\n provider: providerName,\n model,\n })\n\n try {\n const result = await adapter.transcribe({ ...rest, model, logger })\n const duration = Date.now() - startTime\n\n aiEventClient.emit('transcription:request:completed', {\n requestId,\n provider: adapter.name,\n model,\n text: result.text,\n language: result.language,\n duration,\n modelOptions: rest.modelOptions as Record<string, unknown> | undefined,\n timestamp: Date.now(),\n })\n\n logger.output(\n `activity=generateTranscription length=${result.text.length}`,\n { hasText: !!result.text },\n )\n\n if (result.usage) await runGenerationUsage(middleware, mwCtx, result.usage)\n await runGenerationFinish(middleware, mwCtx, {\n duration,\n usage: result.usage,\n })\n\n return result\n } catch (error) {\n const duration = Date.now() - startTime\n const err = error as Error\n aiEventClient.emit('transcription:request:error', {\n requestId,\n provider: adapter.name,\n model,\n error: { message: err.message, name: err.name },\n duration,\n modelOptions: rest.modelOptions as Record<string, unknown> | undefined,\n timestamp: Date.now(),\n })\n await runGenerationError(middleware, mwCtx, {\n error,\n duration,\n })\n logger.errors('generateTranscription activity failed', {\n error,\n source: 'generateTranscription',\n })\n throw error\n }\n}\n\n// ===========================\n// Options Factory\n// ===========================\n\n/**\n * Create typed options for the generateTranscription() function without executing.\n */\nexport function createTranscriptionOptions<\n TAdapter extends TranscriptionAdapter<\n string,\n TranscriptionProviderOptions<TAdapter>\n >,\n TStream extends boolean = false,\n>(\n options: TranscriptionActivityOptions<TAdapter, TStream>,\n): TranscriptionActivityOptions<TAdapter, TStream> {\n return options\n}\n\n// Re-export adapter types\nexport type {\n TranscriptionAdapter,\n TranscriptionAdapterConfig,\n AnyTranscriptionAdapter,\n} from './adapter'\nexport { BaseTranscriptionAdapter } from './adapter'\n"],"names":[],"mappings":";;;;AAgCO,MAAM,OAAO;AAgFpB,SAAS,SAAS,QAAwB;AACxC,SAAO,GAAG,MAAM,IAAI,KAAK,IAAA,CAAK,IAAI,KAAK,OAAA,EAAS,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AAC1E;AAiDO,SAAS,sBAOd,SACsC;AACtC,MAAI,QAAQ,QAAQ;AAClB,WAAO;AAAA,MAAuB,MAC5B,yBAAyB,OAAO;AAAA,IAAA;AAAA,EAEpC;AAEA,SAAO;AAAA,IACL;AAAA,EAAA;AAEJ;AAKA,eAAe,yBAMb,SAC8B;AAC9B,QAAM;AAAA,IACJ;AAAA,IACA,QAAQ;AAAA,IACR,OAAO;AAAA,IACP;AAAA,IACA,GAAG;AAAA,EAAA,IACD;AACJ,QAAM,QAAQ,QAAQ;AACtB,QAAM,YAAY,SAAS,eAAe;AAC1C,QAAM,YAAY,KAAK,IAAA;AACvB,QAAM,SAAyB,mBAAmB,QAAQ,KAAK;AAC/D,QAAM,eACH,QAAiD,YACjD,QAA8B,QAC/B;AAEF,QAAM,QAAQ,wBAAwB;AAAA,IACpC;AAAA,IACA,UAAU;AAAA,IACV,UAAU,QAAQ;AAAA,IAClB;AAAA,IACA,cAAc,KAAK;AAAA,IACnB;AAAA,EAAA,CACD;AAED,QAAM,mBAAmB,YAAY,KAAK;AAE1C,gBAAc,KAAK,iCAAiC;AAAA,IAClD;AAAA,IACA,UAAU,QAAQ;AAAA,IAClB;AAAA,IACA,UAAU,KAAK;AAAA,IACf,QAAQ,KAAK;AAAA,IACb,gBAAgB,KAAK;AAAA,IACrB,cAAc,KAAK;AAAA,IACnB,WAAW;AAAA,EAAA,CACZ;AAED,SAAO,QAAQ,2CAA2C,YAAY,IAAI;AAAA,IACxE,UAAU;AAAA,IACV;AAAA,EAAA,CACD;AAED,MAAI;AACF,UAAM,SAAS,MAAM,QAAQ,WAAW,EAAE,GAAG,MAAM,OAAO,QAAQ;AAClE,UAAM,WAAW,KAAK,IAAA,IAAQ;AAE9B,kBAAc,KAAK,mCAAmC;AAAA,MACpD;AAAA,MACA,UAAU,QAAQ;AAAA,MAClB;AAAA,MACA,MAAM,OAAO;AAAA,MACb,UAAU,OAAO;AAAA,MACjB;AAAA,MACA,cAAc,KAAK;AAAA,MACnB,WAAW,KAAK,IAAA;AAAA,IAAI,CACrB;AAED,WAAO;AAAA,MACL,yCAAyC,OAAO,KAAK,MAAM;AAAA,MAC3D,EAAE,SAAS,CAAC,CAAC,OAAO,KAAA;AAAA,IAAK;AAG3B,QAAI,OAAO,MAAO,OAAM,mBAAmB,YAAY,OAAO,OAAO,KAAK;AAC1E,UAAM,oBAAoB,YAAY,OAAO;AAAA,MAC3C;AAAA,MACA,OAAO,OAAO;AAAA,IAAA,CACf;AAED,WAAO;AAAA,EACT,SAAS,OAAO;AACd,UAAM,WAAW,KAAK,IAAA,IAAQ;AAC9B,UAAM,MAAM;AACZ,kBAAc,KAAK,+BAA+B;AAAA,MAChD;AAAA,MACA,UAAU,QAAQ;AAAA,MAClB;AAAA,MACA,OAAO,EAAE,SAAS,IAAI,SAAS,MAAM,IAAI,KAAA;AAAA,MACzC;AAAA,MACA,cAAc,KAAK;AAAA,MACnB,WAAW,KAAK,IAAA;AAAA,IAAI,CACrB;AACD,UAAM,mBAAmB,YAAY,OAAO;AAAA,MAC1C;AAAA,MACA;AAAA,IAAA,CACD;AACD,WAAO,OAAO,yCAAyC;AAAA,MACrD;AAAA,MACA,QAAQ;AAAA,IAAA,CACT;AACD,UAAM;AAAA,EACR;AACF;AASO,SAAS,2BAOd,SACiD;AACjD,SAAO;AACT;"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/activities/generateTranscription/index.ts"],"sourcesContent":["/**\n * Transcription Activity\n *\n * Transcribes audio to text using speech-to-text models.\n * This is a self-contained module with implementation, types, and JSDoc.\n */\n\nimport { aiEventClient } from '@tanstack/ai-event-client'\nimport { streamGenerationResult } from '../stream-generation-result.js'\nimport { resolveDebugOption } from '../../logger/resolve'\nimport {\n applyGenerationResultTransforms,\n createGenerationContext,\n runGenerationError,\n runGenerationFinish,\n runGenerationStart,\n runGenerationUsage,\n} from '../middleware/run'\nimport type { InternalLogger } from '../../logger/internal-logger'\nimport type { DebugOption } from '../../logger/types'\nimport type { GenerationMiddleware } from '../middleware/types'\nimport type { TranscriptionAdapter } from './adapter'\nimport type {\n StreamChunk,\n TranscriptionResponseFormat,\n TranscriptionResult,\n} from '../../types'\n\n// ===========================\n// Activity Kind\n// ===========================\n\n/** The adapter kind this activity handles */\nexport const kind = 'transcription' as const\n\n// ===========================\n// Type Extraction Helpers\n// ===========================\n\n/**\n * Extract provider options from a TranscriptionAdapter via ~types.\n */\nexport type TranscriptionProviderOptions<TAdapter> =\n TAdapter extends TranscriptionAdapter<any, any>\n ? TAdapter['~types']['providerOptions']\n : object\n\n// ===========================\n// Activity Options Type\n// ===========================\n\n/**\n * Options for the transcription activity.\n * The model is extracted from the adapter's model property.\n *\n * @template TAdapter - The transcription adapter type\n * @template TStream - Whether to stream the output\n */\nexport interface TranscriptionActivityOptions<\n TAdapter extends TranscriptionAdapter<\n string,\n TranscriptionProviderOptions<TAdapter>\n >,\n TStream extends boolean = false,\n> {\n /** The transcription adapter to use (must be created with a model) */\n adapter: TAdapter & { kind: typeof kind }\n /** The audio data to transcribe - can be base64 string, File, Blob, or Buffer */\n audio: string | File | Blob | ArrayBuffer\n /** The language of the audio in ISO-639-1 format (e.g., 'en') */\n language?: string\n /** An optional prompt to guide the transcription */\n prompt?: string\n /** The format of the transcription output */\n responseFormat?: TranscriptionResponseFormat\n /** Provider-specific options for transcription */\n modelOptions?: TranscriptionProviderOptions<TAdapter>\n /**\n * Whether to stream the transcription result.\n * When true, returns an AsyncIterable<StreamChunk> for streaming transport.\n * When false or not provided, returns a Promise<TranscriptionResult>.\n *\n * @default false\n */\n stream?: TStream\n /**\n * Enable debug logging. Pass `true` to enable all categories, `false` to\n * silence everything including errors, or a `DebugConfig` object for granular\n * control and/or a custom `Logger`.\n */\n debug?: DebugOption\n /**\n * Observe-only middleware notified on start, usage, success, and error. Pass\n * `otelMiddleware()` to emit OpenTelemetry spans, or implement the\n * `GenerationMiddleware` contract for a custom backend.\n */\n middleware?: Array<GenerationMiddleware>\n /** Stable conversation/thread id for correlating this run when persisted. */\n threadId?: string\n /** Stable run id for correlating this run when persisted. */\n runId?: string\n}\n\n// ===========================\n// Activity Result Type\n// ===========================\n\n/**\n * Result type for the transcription activity.\n * - If stream is true: AsyncIterable<StreamChunk>\n * - Otherwise: Promise<TranscriptionResult>\n */\nexport type TranscriptionActivityResult<TStream extends boolean = false> =\n TStream extends true\n ? AsyncIterable<StreamChunk>\n : Promise<TranscriptionResult>\n\nfunction createId(prefix: string): string {\n return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`\n}\n\n// ===========================\n// Activity Implementation\n// ===========================\n\n/**\n * Transcription activity - converts audio to text.\n *\n * Uses AI speech-to-text models to transcribe audio content.\n *\n * @example Transcribe an audio file\n * ```ts\n * import { generateTranscription } from '@tanstack/ai'\n * import { openaiTranscription } from '@tanstack/ai-openai'\n *\n * const result = await generateTranscription({\n * adapter: openaiTranscription('whisper-1'),\n * audio: audioFile, // File, Blob, or base64 string\n * language: 'en'\n * })\n *\n * console.log(result.text)\n * ```\n *\n * @example With verbose output for timestamps\n * ```ts\n * const result = await generateTranscription({\n * adapter: openaiTranscription('whisper-1'),\n * audio: audioFile,\n * responseFormat: 'verbose_json'\n * })\n *\n * result.segments?.forEach(segment => {\n * console.log(`[${segment.start}s - ${segment.end}s]: ${segment.text}`)\n * })\n * ```\n *\n * @example Streaming transcription result\n * ```ts\n * for await (const chunk of generateTranscription({\n * adapter: openaiTranscription('whisper-1'),\n * audio: audioFile,\n * stream: true\n * })) {\n * console.log(chunk)\n * }\n * ```\n */\nexport function generateTranscription<\n TAdapter extends TranscriptionAdapter<\n string,\n TranscriptionProviderOptions<TAdapter>\n >,\n TStream extends boolean = false,\n>(\n options: TranscriptionActivityOptions<TAdapter, TStream>,\n): TranscriptionActivityResult<TStream> {\n if (options.stream) {\n return streamGenerationResult(\n // Only `runId` is taken from the resolved wire identity. `threadId` stays\n // the CALLER's: `streamGenerationResult` mints one for the RUN_* chunks\n // when none was passed, and spreading that over the options would hand\n // middleware a thread id known to nobody, which persistence would then\n // file the run under. Matches `generateVideo`.\n (resolved) =>\n runGenerateTranscription({ ...options, runId: resolved.runId }),\n options,\n ) as TranscriptionActivityResult<TStream>\n }\n\n return runGenerateTranscription(\n options,\n ) as TranscriptionActivityResult<TStream>\n}\n\n/**\n * Run non-streaming transcription\n */\nasync function runGenerateTranscription<\n TAdapter extends TranscriptionAdapter<\n string,\n TranscriptionProviderOptions<TAdapter>\n >,\n>(\n options: TranscriptionActivityOptions<TAdapter, boolean>,\n): Promise<TranscriptionResult> {\n const {\n adapter,\n stream: _stream,\n debug: _debug,\n middleware,\n threadId,\n runId,\n ...rest\n } = options\n const model = adapter.model\n const requestId = createId('transcription')\n const startTime = Date.now()\n const logger: InternalLogger = resolveDebugOption(options.debug)\n const providerName =\n (adapter as { name?: string; provider?: string }).provider ??\n (adapter as { name?: string }).name ??\n 'unknown'\n\n const mwCtx = createGenerationContext({\n requestId,\n activity: 'transcription',\n provider: adapter.name,\n model,\n modelOptions: rest.modelOptions,\n artifactInputs: {\n audio: rest.audio,\n language: rest.language,\n prompt: rest.prompt,\n responseFormat: rest.responseFormat,\n },\n threadId,\n runId,\n createId,\n })\n\n await runGenerationStart(middleware, mwCtx)\n\n aiEventClient.emit('transcription:request:started', {\n requestId,\n provider: adapter.name,\n model,\n language: rest.language,\n prompt: rest.prompt,\n responseFormat: rest.responseFormat,\n modelOptions: rest.modelOptions as Record<string, unknown> | undefined,\n timestamp: startTime,\n })\n\n logger.request(`activity=generateTranscription provider=${providerName}`, {\n provider: providerName,\n model,\n })\n\n try {\n const rawResult = await adapter.transcribe({ ...rest, model, logger })\n const result = await applyGenerationResultTransforms(mwCtx, rawResult)\n const duration = Date.now() - startTime\n\n aiEventClient.emit('transcription:request:completed', {\n requestId,\n provider: adapter.name,\n model,\n text: result.text,\n language: result.language,\n duration,\n modelOptions: rest.modelOptions as Record<string, unknown> | undefined,\n timestamp: Date.now(),\n })\n\n logger.output(\n `activity=generateTranscription length=${result.text.length}`,\n { hasText: !!result.text },\n )\n\n if (result.usage) await runGenerationUsage(middleware, mwCtx, result.usage)\n await runGenerationFinish(middleware, mwCtx, {\n duration,\n usage: result.usage,\n })\n\n return result\n } catch (error) {\n const duration = Date.now() - startTime\n const err = error as Error\n aiEventClient.emit('transcription:request:error', {\n requestId,\n provider: adapter.name,\n model,\n error: { message: err.message, name: err.name },\n duration,\n modelOptions: rest.modelOptions as Record<string, unknown> | undefined,\n timestamp: Date.now(),\n })\n await runGenerationError(middleware, mwCtx, {\n error,\n duration,\n })\n logger.errors('generateTranscription activity failed', {\n error,\n source: 'generateTranscription',\n })\n throw error\n }\n}\n\n// ===========================\n// Options Factory\n// ===========================\n\n/**\n * Create typed options for the generateTranscription() function without executing.\n */\nexport function createTranscriptionOptions<\n TAdapter extends TranscriptionAdapter<\n string,\n TranscriptionProviderOptions<TAdapter>\n >,\n TStream extends boolean = false,\n>(\n options: TranscriptionActivityOptions<TAdapter, TStream>,\n): TranscriptionActivityOptions<TAdapter, TStream> {\n return options\n}\n\n// Re-export adapter types\nexport type {\n TranscriptionAdapter,\n TranscriptionAdapterConfig,\n AnyTranscriptionAdapter,\n} from './adapter'\nexport { BaseTranscriptionAdapter } from './adapter'\n"],"mappings":";;;;;;;;;;;;;AAiCA,IAAa,OAAO;AAoFpB,SAAS,SAAS,QAAwB;CACxC,OAAO,GAAG,OAAO,GAAG,KAAK,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC;AACzE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiDA,SAAgB,sBAOd,SACsC;CACtC,IAAI,QAAQ,QACV,OAAO,wBAMJ,aACC,yBAAyB;EAAE,GAAG;EAAS,OAAO,SAAS;CAAM,CAAC,GAChE,OACF;CAGF,OAAO,yBACL,OACF;AACF;;;;AAKA,eAAe,yBAMb,SAC8B;CAC9B,MAAM,EACJ,SACA,QAAQ,SACR,OAAO,QACP,YACA,UACA,OACA,GAAG,SACD;CACJ,MAAM,QAAQ,QAAQ;CACtB,MAAM,YAAY,SAAS,eAAe;CAC1C,MAAM,YAAY,KAAK,IAAI;CAC3B,MAAM,SAAyB,mBAAmB,QAAQ,KAAK;CAC/D,MAAM,eACH,QAAiD,YACjD,QAA8B,QAC/B;CAEF,MAAM,QAAQ,wBAAwB;EACpC;EACA,UAAU;EACV,UAAU,QAAQ;EAClB;EACA,cAAc,KAAK;EACnB,gBAAgB;GACd,OAAO,KAAK;GACZ,UAAU,KAAK;GACf,QAAQ,KAAK;GACb,gBAAgB,KAAK;EACvB;EACA;EACA;EACA;CACF,CAAC;CAED,MAAM,mBAAmB,YAAY,KAAK;CAE1C,cAAc,KAAK,iCAAiC;EAClD;EACA,UAAU,QAAQ;EAClB;EACA,UAAU,KAAK;EACf,QAAQ,KAAK;EACb,gBAAgB,KAAK;EACrB,cAAc,KAAK;EACnB,WAAW;CACb,CAAC;CAED,OAAO,QAAQ,2CAA2C,gBAAgB;EACxE,UAAU;EACV;CACF,CAAC;CAED,IAAI;EAEF,MAAM,SAAS,MAAM,gCAAgC,OAAO,MADpC,QAAQ,WAAW;GAAE,GAAG;GAAM;GAAO;EAAO,CAAC,CACA;EACrE,MAAM,WAAW,KAAK,IAAI,IAAI;EAE9B,cAAc,KAAK,mCAAmC;GACpD;GACA,UAAU,QAAQ;GAClB;GACA,MAAM,OAAO;GACb,UAAU,OAAO;GACjB;GACA,cAAc,KAAK;GACnB,WAAW,KAAK,IAAI;EACtB,CAAC;EAED,OAAO,OACL,yCAAyC,OAAO,KAAK,UACrD,EAAE,SAAS,CAAC,CAAC,OAAO,KAAK,CAC3B;EAEA,IAAI,OAAO,OAAO,MAAM,mBAAmB,YAAY,OAAO,OAAO,KAAK;EAC1E,MAAM,oBAAoB,YAAY,OAAO;GAC3C;GACA,OAAO,OAAO;EAChB,CAAC;EAED,OAAO;CACT,SAAS,OAAO;EACd,MAAM,WAAW,KAAK,IAAI,IAAI;EAC9B,MAAM,MAAM;EACZ,cAAc,KAAK,+BAA+B;GAChD;GACA,UAAU,QAAQ;GAClB;GACA,OAAO;IAAE,SAAS,IAAI;IAAS,MAAM,IAAI;GAAK;GAC9C;GACA,cAAc,KAAK;GACnB,WAAW,KAAK,IAAI;EACtB,CAAC;EACD,MAAM,mBAAmB,YAAY,OAAO;GAC1C;GACA;EACF,CAAC;EACD,OAAO,OAAO,yCAAyC;GACrD;GACA,QAAQ;EACV,CAAC;EACD,MAAM;CACR;AACF;;;;AASA,SAAgB,2BAOd,SACiD;CACjD,OAAO;AACT"}
@@ -1,30 +1,37 @@
1
- class BaseVideoAdapter {
2
- kind = "video";
3
- model;
4
- config;
5
- constructor(config = {}, model) {
6
- this.config = config;
7
- this.model = model;
8
- }
9
- /**
10
- * Default implementation returns `{ kind: 'none' }`. Adapters that have
11
- * declared their per-model duration map should override this.
12
- */
13
- availableDurations() {
14
- return { kind: "none" };
15
- }
16
- /**
17
- * Default implementation returns `undefined`. Adapters that have declared
18
- * their per-model duration map should override.
19
- */
20
- snapDuration(_seconds) {
21
- return void 0;
22
- }
23
- generateId() {
24
- return `${this.name}-${Date.now()}-${Math.random().toString(36).substring(7)}`;
25
- }
26
- }
27
- export {
28
- BaseVideoAdapter
1
+ //#region src/activities/generateVideo/adapter.ts
2
+ /**
3
+ * Abstract base class for video generation adapters.
4
+ * Extend this class to implement a video adapter for a specific provider.
5
+ *
6
+ * @experimental Video generation is an experimental feature and may change.
7
+ *
8
+ * Generic parameters match VideoAdapter - all pre-resolved by the provider function.
9
+ */
10
+ var BaseVideoAdapter = class {
11
+ kind = "video";
12
+ model;
13
+ config;
14
+ constructor(config = {}, model) {
15
+ this.config = config;
16
+ this.model = model;
17
+ }
18
+ /**
19
+ * Default implementation returns `{ kind: 'none' }`. Adapters that have
20
+ * declared their per-model duration map should override this.
21
+ */
22
+ availableDurations() {
23
+ return { kind: "none" };
24
+ }
25
+ /**
26
+ * Default implementation returns `undefined`. Adapters that have declared
27
+ * their per-model duration map should override.
28
+ */
29
+ snapDuration(_seconds) {}
30
+ generateId() {
31
+ return `${this.name}-${Date.now()}-${Math.random().toString(36).substring(7)}`;
32
+ }
29
33
  };
30
- //# sourceMappingURL=adapter.js.map
34
+ //#endregion
35
+ export { BaseVideoAdapter };
36
+
37
+ //# sourceMappingURL=adapter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.js","sources":["../../../../src/activities/generateVideo/adapter.ts"],"sourcesContent":["import type {\n ModelInputModalitiesByName,\n VideoGenerationOptions,\n VideoJobResult,\n VideoStatusResult,\n VideoUrlResult,\n} from '../../types'\n\n/**\n * Structured description of the durations a video model accepts.\n *\n * Tagged union so the same shape can express discrete enums (OpenAI Sora,\n * Veo), continuous ranges, mixed shapes, and models with no duration field.\n * Consumed by `VideoAdapter.availableDurations()`.\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport type DurationOptions<T extends string | number | undefined> =\n | { kind: 'discrete'; values: ReadonlyArray<NonNullable<T>> }\n | { kind: 'range'; min: number; max: number; step?: number; unit: 'seconds' }\n | {\n kind: 'mixed'\n values: ReadonlyArray<NonNullable<T>>\n range?: { min: number; max: number; step?: number }\n }\n | { kind: 'none' }\n\n/**\n * Configuration for video adapter instances\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport interface VideoAdapterConfig {\n apiKey?: string\n baseUrl?: string\n timeout?: number\n maxRetries?: number\n headers?: Record<string, string>\n}\n\n/**\n * Video adapter interface with pre-resolved generics.\n *\n * An adapter is created by a provider function: `provider('model')` → `adapter`\n * All type resolution happens at the provider call site, not in this interface.\n *\n * @experimental Video generation is an experimental feature and may change.\n *\n * Generic parameters:\n * - TModel: The specific model name (e.g., 'sora-2')\n * - TProviderOptions: Provider-specific options (already resolved)\n * - TModelProviderOptionsByName: Map from model name to its specific provider options\n * - TModelSizeByName: Map from model name to its supported sizes\n * - TModelInputModalitiesByName: Map from model name to the non-text prompt\n * modalities it accepts (constrains the `prompt` part types at compile time)\n * - TModelDurationByName: Map from model name to its supported duration\n * union. Defaults to `Record<string, number>` so adapters that haven't\n * declared a map keep today's `duration?: number` typing.\n */\nexport interface VideoAdapter<\n TModel extends string = string,\n TProviderOptions extends object = Record<string, unknown>,\n TModelProviderOptionsByName extends Record<string, any> = Record<string, any>,\n TModelSizeByName extends Record<string, string | undefined> = Record<\n string,\n string\n >,\n TModelInputModalitiesByName extends ModelInputModalitiesByName =\n ModelInputModalitiesByName,\n TModelDurationByName extends Record<string, string | number | undefined> =\n Record<string, number>,\n> {\n /** Discriminator for adapter kind - used to determine API shape */\n readonly kind: 'video'\n /** Adapter name identifier */\n readonly name: string\n /** The model this adapter is configured for */\n readonly model: TModel\n\n /**\n * @internal Type-only properties for inference. Not assigned at runtime.\n */\n '~types': {\n providerOptions: TProviderOptions\n modelProviderOptionsByName: TModelProviderOptionsByName\n modelSizeByName: TModelSizeByName\n modelInputModalitiesByName: TModelInputModalitiesByName\n modelDurationByName: TModelDurationByName\n }\n\n /**\n * Create a new video generation job.\n * Returns a job ID that can be used to poll for status and retrieve the video.\n */\n createVideoJob: (\n options: VideoGenerationOptions<\n TProviderOptions,\n TModelSizeByName[TModel],\n TModelDurationByName[TModel]\n >,\n ) => Promise<VideoJobResult>\n\n /**\n * Get the current status of a video generation job.\n */\n getVideoStatus: (jobId: string) => Promise<VideoStatusResult>\n\n /**\n * Get the URL to download/view the generated video.\n * Should only be called after status is 'completed'.\n */\n getVideoUrl: (jobId: string) => Promise<VideoUrlResult>\n\n /**\n * Describe the durations this adapter's model accepts. Returns a tagged\n * union so consumers can render UI / coerce input without provider-specific\n * knowledge.\n */\n availableDurations: () => DurationOptions<TModelDurationByName[TModel]>\n\n /**\n * Coerce a raw seconds value to the closest valid duration for this model.\n * Returns `undefined` for models with no duration field.\n */\n snapDuration: (seconds: number) => TModelDurationByName[TModel] | undefined\n}\n\n/**\n * A VideoAdapter with any/unknown type parameters.\n * Useful as a constraint in generic functions and interfaces.\n */\nexport type AnyVideoAdapter = VideoAdapter<any, any, any, any, any, any>\n\n/**\n * Abstract base class for video generation adapters.\n * Extend this class to implement a video adapter for a specific provider.\n *\n * @experimental Video generation is an experimental feature and may change.\n *\n * Generic parameters match VideoAdapter - all pre-resolved by the provider function.\n */\nexport abstract class BaseVideoAdapter<\n TModel extends string = string,\n TProviderOptions extends object = Record<string, unknown>,\n TModelProviderOptionsByName extends Record<string, any> = Record<string, any>,\n TModelSizeByName extends Record<string, string | undefined> = Record<\n string,\n string\n >,\n TModelInputModalitiesByName extends ModelInputModalitiesByName =\n ModelInputModalitiesByName,\n TModelDurationByName extends Record<string, string | number | undefined> =\n Record<string, number>,\n> implements VideoAdapter<\n TModel,\n TProviderOptions,\n TModelProviderOptionsByName,\n TModelSizeByName,\n TModelInputModalitiesByName,\n TModelDurationByName\n> {\n readonly kind = 'video' as const\n abstract readonly name: string\n readonly model: TModel\n\n // Type-only property - never assigned at runtime\n declare '~types': {\n providerOptions: TProviderOptions\n modelProviderOptionsByName: TModelProviderOptionsByName\n modelSizeByName: TModelSizeByName\n modelInputModalitiesByName: TModelInputModalitiesByName\n modelDurationByName: TModelDurationByName\n }\n\n protected config: VideoAdapterConfig\n\n constructor(config: VideoAdapterConfig = {}, model: TModel) {\n this.config = config\n this.model = model\n }\n\n abstract createVideoJob(\n options: VideoGenerationOptions<\n TProviderOptions,\n TModelSizeByName[TModel],\n TModelDurationByName[TModel]\n >,\n ): Promise<VideoJobResult>\n\n abstract getVideoStatus(jobId: string): Promise<VideoStatusResult>\n\n abstract getVideoUrl(jobId: string): Promise<VideoUrlResult>\n\n /**\n * Default implementation returns `{ kind: 'none' }`. Adapters that have\n * declared their per-model duration map should override this.\n */\n availableDurations(): DurationOptions<TModelDurationByName[TModel]> {\n return { kind: 'none' }\n }\n\n /**\n * Default implementation returns `undefined`. Adapters that have declared\n * their per-model duration map should override.\n */\n snapDuration(_seconds: number): TModelDurationByName[TModel] | undefined {\n return undefined\n }\n\n protected generateId(): string {\n return `${this.name}-${Date.now()}-${Math.random().toString(36).substring(7)}`\n }\n}\n"],"names":[],"mappings":"AA6IO,MAAe,iBAmBpB;AAAA,EACS,OAAO;AAAA,EAEP;AAAA,EAWC;AAAA,EAEV,YAAY,SAA6B,CAAA,GAAI,OAAe;AAC1D,SAAK,SAAS;AACd,SAAK,QAAQ;AAAA,EACf;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBA,qBAAoE;AAClE,WAAO,EAAE,MAAM,OAAA;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAa,UAA4D;AACvE,WAAO;AAAA,EACT;AAAA,EAEU,aAAqB;AAC7B,WAAO,GAAG,KAAK,IAAI,IAAI,KAAK,KAAK,IAAI,KAAK,OAAA,EAAS,SAAS,EAAE,EAAE,UAAU,CAAC,CAAC;AAAA,EAC9E;AACF;"}
1
+ {"version":3,"file":"adapter.js","names":[],"sources":["../../../../src/activities/generateVideo/adapter.ts"],"sourcesContent":["import type {\n ModelInputModalitiesByName,\n VideoGenerationOptions,\n VideoJobResult,\n VideoStatusResult,\n VideoUrlResult,\n} from '../../types'\n\n/**\n * Structured description of the durations a video model accepts.\n *\n * Tagged union so the same shape can express discrete enums (OpenAI Sora,\n * Veo), continuous ranges, mixed shapes, and models with no duration field.\n * Consumed by `VideoAdapter.availableDurations()`.\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport type DurationOptions<T extends string | number | undefined> =\n | { kind: 'discrete'; values: ReadonlyArray<NonNullable<T>> }\n | { kind: 'range'; min: number; max: number; step?: number; unit: 'seconds' }\n | {\n kind: 'mixed'\n values: ReadonlyArray<NonNullable<T>>\n range?: { min: number; max: number; step?: number }\n }\n | { kind: 'none' }\n\n/**\n * Configuration for video adapter instances\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport interface VideoAdapterConfig {\n apiKey?: string\n baseUrl?: string\n timeout?: number\n maxRetries?: number\n headers?: Record<string, string>\n}\n\n/**\n * Video adapter interface with pre-resolved generics.\n *\n * An adapter is created by a provider function: `provider('model')` → `adapter`\n * All type resolution happens at the provider call site, not in this interface.\n *\n * @experimental Video generation is an experimental feature and may change.\n *\n * Generic parameters:\n * - TModel: The specific model name (e.g., 'sora-2')\n * - TProviderOptions: Provider-specific options (already resolved)\n * - TModelProviderOptionsByName: Map from model name to its specific provider options\n * - TModelSizeByName: Map from model name to its supported sizes\n * - TModelInputModalitiesByName: Map from model name to the non-text prompt\n * modalities it accepts (constrains the `prompt` part types at compile time)\n * - TModelDurationByName: Map from model name to its supported duration\n * union. Defaults to `Record<string, number>` so adapters that haven't\n * declared a map keep today's `duration?: number` typing.\n */\nexport interface VideoAdapter<\n TModel extends string = string,\n TProviderOptions extends object = Record<string, unknown>,\n TModelProviderOptionsByName extends Record<string, any> = Record<string, any>,\n TModelSizeByName extends Record<string, string | undefined> = Record<\n string,\n string\n >,\n TModelInputModalitiesByName extends ModelInputModalitiesByName =\n ModelInputModalitiesByName,\n TModelDurationByName extends Record<string, string | number | undefined> =\n Record<string, number>,\n> {\n /** Discriminator for adapter kind - used to determine API shape */\n readonly kind: 'video'\n /** Adapter name identifier */\n readonly name: string\n /** The model this adapter is configured for */\n readonly model: TModel\n\n /**\n * @internal Type-only properties for inference. Not assigned at runtime.\n */\n '~types': {\n providerOptions: TProviderOptions\n modelProviderOptionsByName: TModelProviderOptionsByName\n modelSizeByName: TModelSizeByName\n modelInputModalitiesByName: TModelInputModalitiesByName\n modelDurationByName: TModelDurationByName\n }\n\n /**\n * Create a new video generation job.\n * Returns a job ID that can be used to poll for status and retrieve the video.\n */\n createVideoJob: (\n options: VideoGenerationOptions<\n TProviderOptions,\n TModelSizeByName[TModel],\n TModelDurationByName[TModel]\n >,\n ) => Promise<VideoJobResult>\n\n /**\n * Get the current status of a video generation job.\n */\n getVideoStatus: (jobId: string) => Promise<VideoStatusResult>\n\n /**\n * Get the URL to download/view the generated video.\n * Should only be called after status is 'completed'.\n */\n getVideoUrl: (jobId: string) => Promise<VideoUrlResult>\n\n /**\n * Describe the durations this adapter's model accepts. Returns a tagged\n * union so consumers can render UI / coerce input without provider-specific\n * knowledge.\n */\n availableDurations: () => DurationOptions<TModelDurationByName[TModel]>\n\n /**\n * Coerce a raw seconds value to the closest valid duration for this model.\n * Returns `undefined` for models with no duration field.\n */\n snapDuration: (seconds: number) => TModelDurationByName[TModel] | undefined\n}\n\n/**\n * A VideoAdapter with any/unknown type parameters.\n * Useful as a constraint in generic functions and interfaces.\n */\nexport type AnyVideoAdapter = VideoAdapter<any, any, any, any, any, any>\n\n/**\n * Abstract base class for video generation adapters.\n * Extend this class to implement a video adapter for a specific provider.\n *\n * @experimental Video generation is an experimental feature and may change.\n *\n * Generic parameters match VideoAdapter - all pre-resolved by the provider function.\n */\nexport abstract class BaseVideoAdapter<\n TModel extends string = string,\n TProviderOptions extends object = Record<string, unknown>,\n TModelProviderOptionsByName extends Record<string, any> = Record<string, any>,\n TModelSizeByName extends Record<string, string | undefined> = Record<\n string,\n string\n >,\n TModelInputModalitiesByName extends ModelInputModalitiesByName =\n ModelInputModalitiesByName,\n TModelDurationByName extends Record<string, string | number | undefined> =\n Record<string, number>,\n> implements VideoAdapter<\n TModel,\n TProviderOptions,\n TModelProviderOptionsByName,\n TModelSizeByName,\n TModelInputModalitiesByName,\n TModelDurationByName\n> {\n readonly kind = 'video' as const\n abstract readonly name: string\n readonly model: TModel\n\n // Type-only property - never assigned at runtime\n declare '~types': {\n providerOptions: TProviderOptions\n modelProviderOptionsByName: TModelProviderOptionsByName\n modelSizeByName: TModelSizeByName\n modelInputModalitiesByName: TModelInputModalitiesByName\n modelDurationByName: TModelDurationByName\n }\n\n protected config: VideoAdapterConfig\n\n constructor(config: VideoAdapterConfig = {}, model: TModel) {\n this.config = config\n this.model = model\n }\n\n abstract createVideoJob(\n options: VideoGenerationOptions<\n TProviderOptions,\n TModelSizeByName[TModel],\n TModelDurationByName[TModel]\n >,\n ): Promise<VideoJobResult>\n\n abstract getVideoStatus(jobId: string): Promise<VideoStatusResult>\n\n abstract getVideoUrl(jobId: string): Promise<VideoUrlResult>\n\n /**\n * Default implementation returns `{ kind: 'none' }`. Adapters that have\n * declared their per-model duration map should override this.\n */\n availableDurations(): DurationOptions<TModelDurationByName[TModel]> {\n return { kind: 'none' }\n }\n\n /**\n * Default implementation returns `undefined`. Adapters that have declared\n * their per-model duration map should override.\n */\n snapDuration(_seconds: number): TModelDurationByName[TModel] | undefined {\n return undefined\n }\n\n protected generateId(): string {\n return `${this.name}-${Date.now()}-${Math.random().toString(36).substring(7)}`\n }\n}\n"],"mappings":";;;;;;;;;AA6IA,IAAsB,mBAAtB,MAmBE;CACA,OAAgB;CAEhB;CAWA;CAEA,YAAY,SAA6B,CAAC,GAAG,OAAe;EAC1D,KAAK,SAAS;EACd,KAAK,QAAQ;CACf;;;;;CAkBA,qBAAoE;EAClE,OAAO,EAAE,MAAM,OAAO;CACxB;;;;;CAMA,aAAa,UAA4D,CAEzE;CAEA,aAA+B;EAC7B,OAAO,GAAG,KAAK,KAAK,GAAG,KAAK,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,UAAU,CAAC;CAC7E;AACF"}
@@ -1,7 +1,7 @@
1
1
  import { DebugOption } from '../../logger/types.js';
2
2
  import { GenerationMiddleware } from '../middleware/types.js';
3
3
  import { VideoAdapter } from './adapter.js';
4
- import { MediaPrompt, MediaPromptFor, StreamChunk, TokenUsage, VideoJobResult, VideoStatusResult, VideoUrlResult } from '../../types.js';
4
+ import { MediaPrompt, MediaPromptFor, PersistedArtifactRef, StreamChunk, TokenUsage, VideoJobResult, VideoStatusResult, VideoUrlResult } from '../../types.js';
5
5
  /** The adapter kind this activity handles */
6
6
  export declare const kind: "video";
7
7
  /**
@@ -79,8 +79,28 @@ export type VideoCreateOptions<TAdapter extends VideoAdapter<string, any, any, a
79
79
  pollingInterval?: number;
80
80
  /** Maximum time to wait before timing out in milliseconds (stream mode only). @default 600000 */
81
81
  maxDuration?: number;
82
- /** Custom run ID (stream mode only) */
82
+ /**
83
+ * Custom run id (stream mode only) — the id stamped on the emitted
84
+ * `RUN_STARTED` / `RUN_FINISHED` chunks.
85
+ *
86
+ * IGNORED by a non-streaming submit. That run spans two calls, and its id is
87
+ * derived from the provider's job instead, so {@link getVideoJobStatus} can
88
+ * recompute it from the `jobId` you already have to poll with. Honoring a
89
+ * custom id here would reintroduce the failure this avoids: a caller who set
90
+ * it on the submit and forgot it on the poll would silently open a second
91
+ * record while the first sat unfinished forever.
92
+ */
83
93
  runId?: string;
94
+ /**
95
+ * Stable conversation/thread id for correlating this run when persisted.
96
+ *
97
+ * Also the `threadId` stamped on the emitted `RUN_STARTED` / `RUN_FINISHED`
98
+ * chunks; when omitted a throwaway id is minted for those chunks only, and
99
+ * the persisted run record carries NO thread link rather than a fabricated
100
+ * one. Pass it whenever persistence is on — it is the slot a reloading client
101
+ * hydrates by, so a run stored without it can only be fetched by run id.
102
+ */
103
+ threadId?: string;
84
104
  /**
85
105
  * Enable debug logging. Pass `true` to enable all categories, `false` to
86
106
  * silence everything including errors, or a `DebugConfig` object for granular
@@ -89,10 +109,29 @@ export type VideoCreateOptions<TAdapter extends VideoAdapter<string, any, any, a
89
109
  debug?: DebugOption;
90
110
  /**
91
111
  * Observe-only middleware notified on start, usage, success, and error. Pass
92
- * `otelMiddleware()` to emit OpenTelemetry spans, or implement the
93
- * `GenerationMiddleware` contract for a custom backend. In streaming mode the
94
- * span covers the full create→poll→complete lifecycle; in non-streaming mode
95
- * it covers job submission. An abandoned stream fires `onAbort`.
112
+ * `otelMiddleware()` to emit OpenTelemetry spans, `withGenerationPersistence()`
113
+ * to persist the run, or implement the `GenerationMiddleware` contract for a
114
+ * custom backend.
115
+ *
116
+ * In streaming mode one run covers the full create→poll→complete lifecycle:
117
+ * `onStart` at submission, a terminal `onFinish`/`onError` when the job
118
+ * settles, and `onAbort` if the consumer abandons the stream.
119
+ *
120
+ * In NON-streaming mode the call only SUBMITS the job, so it only opens the
121
+ * run: no terminal hook fires here, because the video does not exist yet.
122
+ * Pass the same `middleware` and `threadId` to {@link getVideoJobStatus}; the
123
+ * poll that observes a terminal job state finishes the run and is where the
124
+ * result and its artifacts are recorded. Nothing else has to be threaded
125
+ * through — both calls derive the run id from the provider's `jobId`, the one
126
+ * id a poller cannot be missing.
127
+ *
128
+ * Because the job id only exists once the provider accepts the job, `onStart`
129
+ * fires AFTER the submit request rather than before it — an observer's span
130
+ * therefore covers the run from acceptance onward, not the submit round-trip.
131
+ * A submission that FAILS has no job to key on, so it opens and immediately
132
+ * fails a run under this call's `requestId`: the thread's latest run reports
133
+ * the failure (a client hydrating the slot sees it) even though there is no
134
+ * job to resume.
96
135
  */
97
136
  middleware?: Array<GenerationMiddleware>;
98
137
  } & ({} extends VideoProviderOptions<TAdapter> ? {
@@ -150,7 +189,7 @@ export type VideoActivityResult<TRequest extends 'create' | 'status' | 'url' = '
150
189
  *
151
190
  * @example Create a video generation job
152
191
  * ```ts
153
- * import { generateVideo } from '@tanstack/ai'
192
+ * import { generateVideo, getVideoJobStatus } from '@tanstack/ai'
154
193
  * import { openaiVideo } from '@tanstack/ai-openai'
155
194
  *
156
195
  * // Start a video generation job
@@ -160,6 +199,14 @@ export type VideoActivityResult<TRequest extends 'create' | 'status' | 'url' = '
160
199
  * })
161
200
  *
162
201
  * console.log('Job started:', jobId)
202
+ *
203
+ * // The submission only OPENS the run; the poll that sees a terminal state is
204
+ * // what completes it. The `jobId` is the whole correlation — pass the same
205
+ * // `middleware` and `threadId` when you use them.
206
+ * const status = await getVideoJobStatus({
207
+ * adapter: openaiVideo('sora-2'),
208
+ * jobId,
209
+ * })
163
210
  * ```
164
211
  *
165
212
  * @example Stream the full video generation lifecycle
@@ -178,12 +225,71 @@ export type VideoActivityResult<TRequest extends 'create' | 'status' | 'url' = '
178
225
  * ```
179
226
  */
180
227
  export declare function generateVideo<TAdapter extends VideoAdapter<string, any, any, any, any, any>, TStream extends boolean = false>(options: VideoCreateOptions<TAdapter, TStream>): VideoActivityResult<'create', TStream>;
228
+ /**
229
+ * Options for {@link getVideoJobStatus}.
230
+ *
231
+ * The run this poll finishes is identified by `adapter` + `jobId` alone — the
232
+ * same pair the submitting `generateVideo()` call derived it from — so there is
233
+ * no run id to thread through. Pass the submission's `threadId` and the same
234
+ * `middleware`.
235
+ *
236
+ * @experimental Video generation is an experimental feature and may change.
237
+ */
238
+ export interface VideoJobStatusOptions<TAdapter extends VideoAdapter<string, any, any, any, any, any>> {
239
+ /** The video adapter to use (must be created with a model) */
240
+ adapter: TAdapter & {
241
+ kind: typeof kind;
242
+ };
243
+ /** The job ID to check status for */
244
+ jobId: string;
245
+ /**
246
+ * The scope the run is filed under. Must match the submission's `threadId` —
247
+ * generation persistence REFUSES a run without a scope (a run filed under
248
+ * none can never be hydrated by one), so omitting it throws rather than
249
+ * quietly filing the finished video somewhere unreachable.
250
+ */
251
+ threadId?: string;
252
+ /**
253
+ * Observe-only middleware. Hooks fire ONLY on the poll that observes a
254
+ * terminal job state: `onStart` (resuming the submission's run), then the
255
+ * result transforms — which is where persistence copies the video into a blob
256
+ * store and rewrites `url` to a durable one, so the returned result carries
257
+ * the same urls as the stored record — then `onFinish`, or `onError` when the
258
+ * job failed. Intermediate polls invoke nothing, so a middleware is not
259
+ * charged for the wait.
260
+ */
261
+ middleware?: Array<GenerationMiddleware>;
262
+ }
263
+ /**
264
+ * The status of a video job, plus the video itself once the job completed.
265
+ *
266
+ * @experimental Video generation is an experimental feature and may change.
267
+ */
268
+ export interface VideoJobStatusResult {
269
+ /** Job identifier */
270
+ jobId: string;
271
+ status: 'pending' | 'processing' | 'completed' | 'failed';
272
+ progress?: number;
273
+ url?: string;
274
+ /** When the provider url expires, if it reported one. */
275
+ expiresAt?: Date;
276
+ error?: string;
277
+ usage?: TokenUsage;
278
+ /** Durable artifact references, when generation persistence is wired. */
279
+ artifacts?: Array<PersistedArtifactRef>;
280
+ }
181
281
  /**
182
282
  * Get video job status - returns the current status, progress, and URL if available.
183
283
  *
184
284
  * This function combines status checking and URL retrieval. If the job is completed,
185
285
  * it will automatically fetch and include the video URL.
186
286
  *
287
+ * It is also where a non-streaming `generateVideo()` run ENDS: pass the same
288
+ * `middleware` and `threadId`, and the poll that first sees a terminal job state
289
+ * finishes the run (recording the result and its artifacts) or fails it. The run
290
+ * is identified by `adapter` + `jobId`, exactly what the submission derived it
291
+ * from, so there is nothing else to carry between the two calls.
292
+ *
187
293
  * @experimental Video generation is an experimental feature and may change.
188
294
  *
189
295
  * @example Check job status
@@ -202,19 +308,37 @@ export declare function generateVideo<TAdapter extends VideoAdapter<string, any,
202
308
  * console.log('Video URL:', result.url)
203
309
  * }
204
310
  * ```
311
+ *
312
+ * @example Submit and poll one persisted run
313
+ * ```ts
314
+ * import { generateVideo, getVideoJobStatus } from '@tanstack/ai'
315
+ * import { withGenerationPersistence } from '@tanstack/ai-persistence'
316
+ * import { openaiVideo } from '@tanstack/ai-openai'
317
+ *
318
+ * const adapter = openaiVideo('sora-2')
319
+ * const middleware = [withGenerationPersistence(persistence)]
320
+ *
321
+ * // Opens the run (status `running`, jobId recorded). Its run id is derived
322
+ * // from the provider job, so nothing has to be stored to resume it.
323
+ * const { jobId } = await generateVideo({
324
+ * adapter,
325
+ * prompt: 'A cat chasing a dog in a sunny park',
326
+ * threadId,
327
+ * middleware,
328
+ * })
329
+ *
330
+ * // Completes the SAME run once the job settles — this is what writes the
331
+ * // video, its artifacts, and the terminal status. Works from a different
332
+ * // request or process: the jobId is the only correlation.
333
+ * const status = await getVideoJobStatus({
334
+ * adapter,
335
+ * jobId,
336
+ * threadId,
337
+ * middleware,
338
+ * })
339
+ * ```
205
340
  */
206
- export declare function getVideoJobStatus<TAdapter extends VideoAdapter<string, any, any, any, any, any>>(options: {
207
- adapter: TAdapter & {
208
- kind: typeof kind;
209
- };
210
- jobId: string;
211
- }): Promise<{
212
- status: 'pending' | 'processing' | 'completed' | 'failed';
213
- progress?: number;
214
- url?: string;
215
- error?: string;
216
- usage?: TokenUsage;
217
- }>;
341
+ export declare function getVideoJobStatus<TAdapter extends VideoAdapter<string, any, any, any, any, any>>(options: VideoJobStatusOptions<TAdapter>): Promise<VideoJobStatusResult>;
218
342
  /**
219
343
  * Create typed options for the generateVideo() function without executing.
220
344
  */