@tanstack/ai 0.40.0 → 0.41.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.
- package/dist/esm/activities/chat/messages.js +7 -0
- package/dist/esm/activities/chat/messages.js.map +1 -1
- package/dist/esm/activities/chat/stream/message-updaters.d.ts +2 -0
- package/dist/esm/activities/chat/stream/message-updaters.js +3 -1
- package/dist/esm/activities/chat/stream/message-updaters.js.map +1 -1
- package/dist/esm/activities/chat/stream/processor.js +18 -1
- package/dist/esm/activities/chat/stream/processor.js.map +1 -1
- package/dist/esm/activities/chat/tools/tool-definition.d.ts +14 -11
- package/dist/esm/activities/chat/tools/tool-definition.js.map +1 -1
- package/dist/esm/activities/generateAudio/index.d.ts +1 -1
- package/dist/esm/activities/generateAudio/index.js.map +1 -1
- package/dist/esm/activities/generateImage/index.d.ts +1 -1
- package/dist/esm/activities/generateImage/index.js +1 -1
- package/dist/esm/activities/generateImage/index.js.map +1 -1
- package/dist/esm/activities/generateSpeech/index.d.ts +1 -1
- package/dist/esm/activities/generateSpeech/index.js.map +1 -1
- package/dist/esm/activities/generateTranscription/index.d.ts +1 -1
- package/dist/esm/activities/generateTranscription/index.js.map +1 -1
- package/dist/esm/activities/generateVideo/index.d.ts +12 -12
- package/dist/esm/activities/generateVideo/index.js.map +1 -1
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/realtime/event-emitter.d.ts +5 -0
- package/dist/esm/realtime/event-emitter.js +27 -0
- package/dist/esm/realtime/event-emitter.js.map +1 -0
- package/dist/esm/realtime/index.d.ts +1 -0
- package/dist/esm/realtime/index.js.map +1 -1
- package/dist/esm/realtime/types.d.ts +9 -1
- package/dist/esm/types.d.ts +9 -0
- package/package.json +1 -1
- package/skills/ai-core/media-generation/SKILL.md +42 -2
- package/skills/ai-core/middleware/SKILL.md +18 -3
- package/skills/ai-core/tool-calling/SKILL.md +13 -1
- package/src/activities/chat/messages.ts +9 -0
- package/src/activities/chat/stream/message-updaters.ts +7 -1
- package/src/activities/chat/stream/processor.ts +30 -2
- package/src/activities/chat/tools/tool-definition.ts +33 -11
- package/src/activities/generateAudio/index.ts +2 -2
- package/src/activities/generateImage/index.ts +2 -2
- package/src/activities/generateSpeech/index.ts +2 -2
- package/src/activities/generateTranscription/index.ts +2 -2
- package/src/activities/generateVideo/index.ts +29 -15
- package/src/index.ts +2 -1
- package/src/realtime/event-emitter.ts +46 -0
- package/src/realtime/index.ts +2 -0
- package/src/realtime/types.ts +9 -0
- package/src/types.ts +9 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-definition.js","sources":["../../../../../src/activities/chat/tools/tool-definition.ts"],"sourcesContent":["import type { StandardJSONSchemaV1 } from '@standard-schema/spec'\nimport type {\n JSONSchema,\n SchemaInput,\n Tool,\n ToolExecuteFunction,\n} from '../../../types'\n\n/**\n * Marker type for server-side tools\n */\nexport interface ServerTool<\n TInput extends SchemaInput = SchemaInput,\n TOutput extends SchemaInput = SchemaInput,\n TName extends string = string,\n TContext = unknown,\n> extends Tool<TInput, TOutput, TName, TContext> {\n __toolSide: 'server'\n}\n\n/**\n * Marker type for client-side tools\n */\nexport interface ClientTool<\n TInput extends SchemaInput = SchemaInput,\n TOutput extends SchemaInput = SchemaInput,\n TName extends string = string,\n TContext = unknown,\n> {\n __toolSide: 'client'\n name: TName\n description: string\n // Note: `inputSchema` / `outputSchema` stay as bare optionals (not\n // widened to `| undefined`). They participate in inference via\n // `InferToolInput` / `InferToolOutput` — widening with `| undefined`\n // breaks the `infer TInput extends StandardJSONSchemaV1<...>` chain\n // because `undefined` doesn't extend the schema constraint.\n inputSchema?: TInput\n outputSchema?: TOutput\n needsApproval?:
|
|
1
|
+
{"version":3,"file":"tool-definition.js","sources":["../../../../../src/activities/chat/tools/tool-definition.ts"],"sourcesContent":["import type { StandardJSONSchemaV1 } from '@standard-schema/spec'\nimport type {\n JSONSchema,\n SchemaInput,\n Tool,\n ToolExecuteFunction,\n} from '../../../types'\n\n/**\n * Marker type for server-side tools\n */\nexport interface ServerTool<\n TInput extends SchemaInput = SchemaInput,\n TOutput extends SchemaInput = SchemaInput,\n TName extends string = string,\n TContext = unknown,\n> extends Tool<TInput, TOutput, TName, TContext> {\n __toolSide: 'server'\n}\n\n/**\n * Marker type for client-side tools\n */\nexport interface ClientTool<\n TInput extends SchemaInput = SchemaInput,\n TOutput extends SchemaInput = SchemaInput,\n TName extends string = string,\n TContext = unknown,\n // Captured as a literal (`true` / `false`) so downstream types — notably\n // the tool-call part's `approval` field — can be gated on it. Defaults to\n // `false` when the tool config omits `needsApproval`.\n TNeedsApproval extends boolean = false,\n> {\n __toolSide: 'client'\n name: TName\n description: string\n // Note: `inputSchema` / `outputSchema` stay as bare optionals (not\n // widened to `| undefined`). They participate in inference via\n // `InferToolInput` / `InferToolOutput` — widening with `| undefined`\n // breaks the `infer TInput extends StandardJSONSchemaV1<...>` chain\n // because `undefined` doesn't extend the schema constraint.\n inputSchema?: TInput\n outputSchema?: TOutput\n needsApproval?: TNeedsApproval\n lazy?: boolean\n metadata?: Record<string, unknown>\n execute?: ToolExecuteFunction<TInput, TOutput, TContext>\n}\n\n/**\n * Tool definition that can be used directly or instantiated for server/client\n */\nexport interface ToolDefinitionInstance<\n TInput extends SchemaInput = SchemaInput,\n TOutput extends SchemaInput = SchemaInput,\n TName extends string = string,\n TContext = unknown,\n TNeedsApproval extends boolean = false,\n> extends Tool<TInput, TOutput, TName, TContext> {\n __toolSide: 'definition'\n // Narrow the base `needsApproval?: boolean` to the captured literal so it\n // survives into `ToolCallPartForTool`'s approval gate.\n needsApproval?: TNeedsApproval\n}\n\n/**\n * Union type for any kind of client-side tool (client tool or definition)\n */\nexport type AnyClientTool =\n | (Omit<ClientTool<any, any, string, any, boolean>, 'execute'> & {\n execute?: ((args: any, context?: any) => any) | undefined\n })\n | (Omit<ToolDefinitionInstance<any, any, string, any, boolean>, 'execute'> & {\n execute?: ((args: any, context?: any) => any) | undefined\n })\n\n/**\n * Extract the tool name as a literal type\n */\nexport type InferToolName<T> = T extends { name: infer N } ? N : never\n\n/**\n * Extract the input type from a tool (inferred from Standard JSON Schema, or `unknown` for plain JSONSchema)\n */\nexport type InferToolInput<T> = T extends { inputSchema?: infer TInput }\n ? TInput extends StandardJSONSchemaV1<infer TInferred, unknown>\n ? TInferred\n : TInput extends JSONSchema\n ? unknown\n : unknown\n : unknown\n\n/**\n * Extract the output type from a tool (inferred from Standard JSON Schema, or `unknown` for plain JSONSchema)\n */\nexport type InferToolOutput<T> = T extends { outputSchema?: infer TOutput }\n ? TOutput extends StandardJSONSchemaV1<infer TInferred, unknown>\n ? TInferred\n : TOutput extends JSONSchema\n ? unknown\n : unknown\n : unknown\n\n/**\n * Tool definition configuration\n */\nexport interface ToolDefinitionConfig<\n TInput extends SchemaInput = SchemaInput,\n TOutput extends SchemaInput = SchemaInput,\n TName extends string = string,\n TNeedsApproval extends boolean = false,\n> {\n name: TName\n description: string\n inputSchema?: TInput\n outputSchema?: TOutput\n needsApproval?: TNeedsApproval\n lazy?: boolean\n metadata?: Record<string, unknown>\n}\n\n/**\n * Tool definition builder that allows creating server or client tools from a shared definition\n */\nexport interface ToolDefinition<\n TInput extends SchemaInput = SchemaInput,\n TOutput extends SchemaInput = SchemaInput,\n TName extends string = string,\n TNeedsApproval extends boolean = false,\n> extends ToolDefinitionInstance<\n TInput,\n TOutput,\n TName,\n unknown,\n TNeedsApproval\n> {\n /**\n * Create a server-side tool with execute function\n */\n server: <TContext = unknown>(\n execute: ToolExecuteFunction<TInput, TOutput, TContext>,\n ) => ServerTool<TInput, TOutput, TName, TContext>\n\n /**\n * Create a client-side tool with optional execute function.\n * Carries the definition's `needsApproval` literal through to the client\n * tool so the tool-call part's `approval` field stays gated on it.\n */\n client: <TContext = unknown>(\n execute?: ToolExecuteFunction<TInput, TOutput, TContext>,\n ) => ClientTool<TInput, TOutput, TName, TContext, TNeedsApproval>\n}\n\n/**\n * Create an isomorphic tool definition that can be used directly or instantiated for server/client\n *\n * The definition contains all tool metadata (name, description, schemas) and can be:\n * 1. Used directly in chat() on the server (as a tool definition without execute)\n * 2. Instantiated as a server tool with .server()\n * 3. Instantiated as a client tool with .client()\n *\n * Supports any Standard JSON Schema compliant library (Zod v4+, ArkType, Valibot, etc.)\n * or plain JSON Schema objects.\n *\n * @example\n * ```typescript\n * import { toolDefinition } from '@tanstack/ai';\n * import { z } from 'zod';\n *\n * // Using Zod (natively supports Standard JSON Schema)\n * const addToCartTool = toolDefinition({\n * name: 'addToCart',\n * description: 'Add a guitar to the shopping cart (requires approval)',\n * needsApproval: true,\n * inputSchema: z.object({\n * guitarId: z.string(),\n * quantity: z.number(),\n * }),\n * outputSchema: z.object({\n * success: z.boolean(),\n * cartId: z.string(),\n * totalItems: z.number(),\n * }),\n * });\n *\n * // Use directly in chat (server-side, no execute function)\n * chat({\n * tools: [addToCartTool],\n * // ...\n * });\n *\n * // Or create server-side implementation\n * const addToCartServer = addToCartTool.server(async (args) => {\n * // args is typed as { guitarId: string; quantity: number }\n * return {\n * success: true,\n * cartId: 'CART_' + Date.now(),\n * totalItems: args.quantity,\n * };\n * });\n *\n * // Or create client-side implementation\n * const addToCartClient = addToCartTool.client(async (args) => {\n * // Client-specific logic (e.g., localStorage)\n * return { success: true, cartId: 'local', totalItems: 1 };\n * });\n * ```\n */\nexport function toolDefinition<\n TInput extends SchemaInput = SchemaInput,\n TOutput extends SchemaInput = SchemaInput,\n TName extends string = string,\n // `const` forces the literal (`true` / `false`) to be captured from the\n // config's optional `needsApproval` — without it TS widens to `boolean`,\n // which collapses the approval gate in `ToolCallPartForTool`.\n const TNeedsApproval extends boolean = false,\n>(\n config: ToolDefinitionConfig<TInput, TOutput, TName, TNeedsApproval>,\n): ToolDefinition<TInput, TOutput, TName, TNeedsApproval> {\n const definition: ToolDefinition<TInput, TOutput, TName, TNeedsApproval> = {\n __toolSide: 'definition',\n ...config,\n server<TContext = unknown>(\n execute: ToolExecuteFunction<TInput, TOutput, TContext>,\n ): ServerTool<TInput, TOutput, TName, TContext> {\n return {\n __toolSide: 'server',\n ...config,\n execute,\n }\n },\n\n client<TContext = unknown>(\n execute?: ToolExecuteFunction<TInput, TOutput, TContext>,\n ): ClientTool<TInput, TOutput, TName, TContext, TNeedsApproval> {\n return {\n __toolSide: 'client',\n ...config,\n ...(execute !== undefined && { execute }),\n }\n },\n }\n\n return definition\n}\n"],"names":[],"mappings":"AAgNO,SAAS,eASd,QACwD;AACxD,QAAM,aAAqE;AAAA,IACzE,YAAY;AAAA,IACZ,GAAG;AAAA,IACH,OACE,SAC8C;AAC9C,aAAO;AAAA,QACL,YAAY;AAAA,QACZ,GAAG;AAAA,QACH;AAAA,MAAA;AAAA,IAEJ;AAAA,IAEA,OACE,SAC8D;AAC9D,aAAO;AAAA,QACL,YAAY;AAAA,QACZ,GAAG;AAAA,QACH,GAAI,YAAY,UAAa,EAAE,QAAA;AAAA,MAAQ;AAAA,IAE3C;AAAA,EAAA;AAGF,SAAO;AACT;"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DebugOption } from '../../logger/types.js';
|
|
2
|
-
import { GenerationMiddleware } from '../middleware.js';
|
|
2
|
+
import { GenerationMiddleware } from '../middleware/types.js';
|
|
3
3
|
import { AudioAdapter } from './adapter.js';
|
|
4
4
|
import { AudioGenerationResult, StreamChunk } from '../../types.js';
|
|
5
5
|
/** The adapter kind this activity handles */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../../src/activities/generateAudio/index.ts"],"sourcesContent":["/**\n * Audio Generation Activity\n *\n * Generates audio (music, sound effects, etc.) from text prompts.\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'\nimport type { InternalLogger } from '../../logger/internal-logger'\nimport type { DebugOption } from '../../logger/types'\nimport type { GenerationMiddleware } from '../middleware'\nimport type { AudioAdapter } from './adapter'\nimport type { AudioGenerationResult, StreamChunk } from '../../types'\n\n// ===========================\n// Activity Kind\n// ===========================\n\n/** The adapter kind this activity handles */\nexport const kind = 'audio' as const\n\n// ===========================\n// Type Extraction Helpers\n// ===========================\n\n/**\n * Extract provider options from an AudioAdapter via ~types.\n */\nexport type AudioProviderOptions<TAdapter> = TAdapter extends {\n '~types': { providerOptions: infer P extends object }\n}\n ? P\n : object\n\n// ===========================\n// Activity Options Type\n// ===========================\n\n/**\n * Options for the audio generation activity.\n * The model is extracted from the adapter's model property.\n *\n * @template TAdapter - The audio adapter type\n * @template TStream - Whether to stream the output\n */\nexport interface AudioActivityOptions<\n TAdapter extends AudioAdapter<string, AudioProviderOptions<TAdapter>>,\n TStream extends boolean = false,\n> {\n /** The audio adapter to use (must be created with a model) */\n adapter: TAdapter & { kind: typeof kind }\n /** Text description of the desired audio */\n prompt: string\n /** Desired duration in seconds */\n duration?: number\n /** Provider-specific options for audio generation */\n modelOptions?: AudioProviderOptions<TAdapter>\n /**\n * Whether to stream the generation result.\n * When true, returns an AsyncIterable<StreamChunk> for streaming transport.\n * When false or not provided, returns a Promise<AudioGenerationResult>.\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 audio generation activity.\n * - If stream is true: AsyncIterable<StreamChunk>\n * - Otherwise: Promise<AudioGenerationResult>\n */\nexport type AudioActivityResult<TStream extends boolean = false> =\n TStream extends true\n ? AsyncIterable<StreamChunk>\n : Promise<AudioGenerationResult>\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 * Audio generation activity - generates audio from text prompts.\n *\n * Uses AI models to create music, sound effects, and other audio content.\n *\n * @example Generate music from a prompt\n * ```ts\n * import { generateAudio } from '@tanstack/ai'\n * import { falAudio } from '@tanstack/ai-fal'\n *\n * const result = await generateAudio({\n * adapter: falAudio('fal-ai/diffrhythm'),\n * prompt: 'An upbeat electronic track with synths',\n * duration: 10\n * })\n *\n * console.log(result.audio.url) // URL to generated audio\n * ```\n */\nexport function generateAudio<\n TAdapter extends AudioAdapter<string, AudioProviderOptions<TAdapter>>,\n TStream extends boolean = false,\n>(\n options: AudioActivityOptions<TAdapter, TStream>,\n): AudioActivityResult<TStream> {\n if (options.stream) {\n return streamGenerationResult(() =>\n runGenerateAudio(options),\n ) as AudioActivityResult<TStream>\n }\n return runGenerateAudio(options) as AudioActivityResult<TStream>\n}\n\n/**\n * Run the core audio generation logic (non-streaming).\n */\nasync function runGenerateAudio<\n TAdapter extends AudioAdapter<string, AudioProviderOptions<TAdapter>>,\n>(\n options: AudioActivityOptions<TAdapter, boolean>,\n): Promise<AudioGenerationResult> {\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('audio')\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: 'audio',\n provider: adapter.name,\n model,\n modelOptions: rest.modelOptions,\n createId,\n })\n\n await runGenerationStart(middleware, mwCtx)\n\n aiEventClient.emit('audio:request:started', {\n requestId,\n provider: adapter.name,\n model,\n prompt: rest.prompt,\n duration: rest.duration,\n modelOptions: rest.modelOptions as Record<string, unknown> | undefined,\n timestamp: startTime,\n })\n\n logger.request(`activity=generateAudio provider=${providerName}`, {\n provider: providerName,\n model,\n })\n\n try {\n const result = await adapter.generateAudio({ ...rest, model, logger })\n const elapsedMs = Date.now() - startTime\n\n aiEventClient.emit('audio:request:completed', {\n requestId,\n provider: adapter.name,\n model,\n audio: result.audio,\n duration: elapsedMs,\n modelOptions: rest.modelOptions as Record<string, unknown> | undefined,\n timestamp: Date.now(),\n })\n\n if (result.usage) {\n aiEventClient.emit('audio:usage', {\n requestId,\n model,\n usage: result.usage,\n modelOptions: rest.modelOptions as Record<string, unknown> | undefined,\n timestamp: Date.now(),\n })\n }\n\n logger.output(`activity=generateAudio provider=${providerName}`, {\n contentType: result.audio.contentType,\n audioDuration: result.audio.duration,\n })\n\n if (result.usage) await runGenerationUsage(middleware, mwCtx, result.usage)\n await runGenerationFinish(middleware, mwCtx, {\n duration: elapsedMs,\n usage: result.usage,\n })\n\n return result\n } catch (error) {\n const elapsedMs = Date.now() - startTime\n const err = error as Error\n aiEventClient.emit('audio:request:error', {\n requestId,\n provider: adapter.name,\n model,\n error: { message: err.message, name: err.name },\n duration: elapsedMs,\n modelOptions: rest.modelOptions as Record<string, unknown> | undefined,\n timestamp: Date.now(),\n })\n await runGenerationError(middleware, mwCtx, {\n error,\n duration: elapsedMs,\n })\n logger.errors('generateAudio activity failed', {\n error,\n source: 'generateAudio',\n })\n throw error\n }\n}\n\n// ===========================\n// Options Factory\n// ===========================\n\n/**\n * Create typed options for the generateAudio() function without executing.\n */\nexport function createAudioOptions<\n TAdapter extends AudioAdapter<string, AudioProviderOptions<TAdapter>>,\n TStream extends boolean = false,\n>(\n options: AudioActivityOptions<TAdapter, TStream>,\n): AudioActivityOptions<TAdapter, TStream> {\n return options\n}\n\n// Re-export adapter types\nexport type {\n AudioAdapter,\n AudioAdapterConfig,\n AnyAudioAdapter,\n} from './adapter'\nexport { BaseAudioAdapter } from './adapter'\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../src/activities/generateAudio/index.ts"],"sourcesContent":["/**\n * Audio Generation Activity\n *\n * Generates audio (music, sound effects, etc.) from text prompts.\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 { AudioAdapter } from './adapter'\nimport type { AudioGenerationResult, StreamChunk } from '../../types'\n\n// ===========================\n// Activity Kind\n// ===========================\n\n/** The adapter kind this activity handles */\nexport const kind = 'audio' as const\n\n// ===========================\n// Type Extraction Helpers\n// ===========================\n\n/**\n * Extract provider options from an AudioAdapter via ~types.\n */\nexport type AudioProviderOptions<TAdapter> = TAdapter extends {\n '~types': { providerOptions: infer P extends object }\n}\n ? P\n : object\n\n// ===========================\n// Activity Options Type\n// ===========================\n\n/**\n * Options for the audio generation activity.\n * The model is extracted from the adapter's model property.\n *\n * @template TAdapter - The audio adapter type\n * @template TStream - Whether to stream the output\n */\nexport interface AudioActivityOptions<\n TAdapter extends AudioAdapter<string, AudioProviderOptions<TAdapter>>,\n TStream extends boolean = false,\n> {\n /** The audio adapter to use (must be created with a model) */\n adapter: TAdapter & { kind: typeof kind }\n /** Text description of the desired audio */\n prompt: string\n /** Desired duration in seconds */\n duration?: number\n /** Provider-specific options for audio generation */\n modelOptions?: AudioProviderOptions<TAdapter>\n /**\n * Whether to stream the generation result.\n * When true, returns an AsyncIterable<StreamChunk> for streaming transport.\n * When false or not provided, returns a Promise<AudioGenerationResult>.\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 audio generation activity.\n * - If stream is true: AsyncIterable<StreamChunk>\n * - Otherwise: Promise<AudioGenerationResult>\n */\nexport type AudioActivityResult<TStream extends boolean = false> =\n TStream extends true\n ? AsyncIterable<StreamChunk>\n : Promise<AudioGenerationResult>\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 * Audio generation activity - generates audio from text prompts.\n *\n * Uses AI models to create music, sound effects, and other audio content.\n *\n * @example Generate music from a prompt\n * ```ts\n * import { generateAudio } from '@tanstack/ai'\n * import { falAudio } from '@tanstack/ai-fal'\n *\n * const result = await generateAudio({\n * adapter: falAudio('fal-ai/diffrhythm'),\n * prompt: 'An upbeat electronic track with synths',\n * duration: 10\n * })\n *\n * console.log(result.audio.url) // URL to generated audio\n * ```\n */\nexport function generateAudio<\n TAdapter extends AudioAdapter<string, AudioProviderOptions<TAdapter>>,\n TStream extends boolean = false,\n>(\n options: AudioActivityOptions<TAdapter, TStream>,\n): AudioActivityResult<TStream> {\n if (options.stream) {\n return streamGenerationResult(() =>\n runGenerateAudio(options),\n ) as AudioActivityResult<TStream>\n }\n return runGenerateAudio(options) as AudioActivityResult<TStream>\n}\n\n/**\n * Run the core audio generation logic (non-streaming).\n */\nasync function runGenerateAudio<\n TAdapter extends AudioAdapter<string, AudioProviderOptions<TAdapter>>,\n>(\n options: AudioActivityOptions<TAdapter, boolean>,\n): Promise<AudioGenerationResult> {\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('audio')\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: 'audio',\n provider: adapter.name,\n model,\n modelOptions: rest.modelOptions,\n createId,\n })\n\n await runGenerationStart(middleware, mwCtx)\n\n aiEventClient.emit('audio:request:started', {\n requestId,\n provider: adapter.name,\n model,\n prompt: rest.prompt,\n duration: rest.duration,\n modelOptions: rest.modelOptions as Record<string, unknown> | undefined,\n timestamp: startTime,\n })\n\n logger.request(`activity=generateAudio provider=${providerName}`, {\n provider: providerName,\n model,\n })\n\n try {\n const result = await adapter.generateAudio({ ...rest, model, logger })\n const elapsedMs = Date.now() - startTime\n\n aiEventClient.emit('audio:request:completed', {\n requestId,\n provider: adapter.name,\n model,\n audio: result.audio,\n duration: elapsedMs,\n modelOptions: rest.modelOptions as Record<string, unknown> | undefined,\n timestamp: Date.now(),\n })\n\n if (result.usage) {\n aiEventClient.emit('audio:usage', {\n requestId,\n model,\n usage: result.usage,\n modelOptions: rest.modelOptions as Record<string, unknown> | undefined,\n timestamp: Date.now(),\n })\n }\n\n logger.output(`activity=generateAudio provider=${providerName}`, {\n contentType: result.audio.contentType,\n audioDuration: result.audio.duration,\n })\n\n if (result.usage) await runGenerationUsage(middleware, mwCtx, result.usage)\n await runGenerationFinish(middleware, mwCtx, {\n duration: elapsedMs,\n usage: result.usage,\n })\n\n return result\n } catch (error) {\n const elapsedMs = Date.now() - startTime\n const err = error as Error\n aiEventClient.emit('audio:request:error', {\n requestId,\n provider: adapter.name,\n model,\n error: { message: err.message, name: err.name },\n duration: elapsedMs,\n modelOptions: rest.modelOptions as Record<string, unknown> | undefined,\n timestamp: Date.now(),\n })\n await runGenerationError(middleware, mwCtx, {\n error,\n duration: elapsedMs,\n })\n logger.errors('generateAudio activity failed', {\n error,\n source: 'generateAudio',\n })\n throw error\n }\n}\n\n// ===========================\n// Options Factory\n// ===========================\n\n/**\n * Create typed options for the generateAudio() function without executing.\n */\nexport function createAudioOptions<\n TAdapter extends AudioAdapter<string, AudioProviderOptions<TAdapter>>,\n TStream extends boolean = false,\n>(\n options: AudioActivityOptions<TAdapter, TStream>,\n): AudioActivityOptions<TAdapter, TStream> {\n return options\n}\n\n// Re-export adapter types\nexport type {\n AudioAdapter,\n AudioAdapterConfig,\n AnyAudioAdapter,\n} from './adapter'\nexport { BaseAudioAdapter } from './adapter'\n"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DebugOption } from '../../logger/types.js';
|
|
2
|
-
import { GenerationMiddleware } from '../middleware.js';
|
|
2
|
+
import { GenerationMiddleware } from '../middleware/types.js';
|
|
3
3
|
import { ImageAdapter } from './adapter.js';
|
|
4
4
|
import { ImageGenerationResult, MediaPrompt, MediaPromptFor, StreamChunk } from '../../types.js';
|
|
5
5
|
/** The adapter kind this activity handles */
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { aiEventClient } from "@tanstack/ai-event-client";
|
|
2
2
|
import { streamGenerationResult } from "../stream-generation-result.js";
|
|
3
3
|
import { resolveDebugOption } from "../../logger/resolve.js";
|
|
4
|
-
import { resolveMediaPrompt } from "../../utilities/media-prompt.js";
|
|
5
4
|
import { createGenerationContext, runGenerationStart, runGenerationUsage, runGenerationFinish, runGenerationError } from "../middleware/run.js";
|
|
5
|
+
import { resolveMediaPrompt } from "../../utilities/media-prompt.js";
|
|
6
6
|
const kind = "image";
|
|
7
7
|
function createId(prefix) {
|
|
8
8
|
return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../../src/activities/generateImage/index.ts"],"sourcesContent":["/**\n * Image Activity\n *\n * Generates images from text prompts.\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'\nimport { resolveMediaPrompt } from '../../utilities/media-prompt'\nimport type { InternalLogger } from '../../logger/internal-logger'\nimport type { DebugOption } from '../../logger/types'\nimport type { GenerationMiddleware } from '../middleware'\nimport type { ImageAdapter } from './adapter'\nimport type {\n ImageGenerationResult,\n MediaPrompt,\n MediaPromptFor,\n StreamChunk,\n} from '../../types'\n\n// ===========================\n// Activity Kind\n// ===========================\n\n/** The adapter kind this activity handles */\nexport const kind = 'image' as const\n\n// ===========================\n// Type Extraction Helpers\n// ===========================\n\n/**\n * Extract model-specific provider options from an ImageAdapter via ~types.\n * If the model has specific options defined in ModelProviderOptions (and not just via index signature),\n * use those; otherwise fall back to base provider options.\n */\nexport type ImageProviderOptionsForModel<TAdapter, TModel extends string> =\n TAdapter extends ImageAdapter<any, infer BaseOptions, infer ModelOptions, any>\n ? string extends keyof ModelOptions\n ? // ModelOptions is Record<string, unknown> or has index signature - use BaseOptions\n BaseOptions\n : // ModelOptions has explicit keys - check if TModel is one of them\n TModel extends keyof ModelOptions\n ? ModelOptions[TModel]\n : BaseOptions\n : object\n\n/**\n * Extract model-specific size options from an ImageAdapter via ~types.\n * If the model has specific sizes defined, use those; otherwise fall back to string.\n */\nexport type ImageSizeForModel<TAdapter, TModel extends string> =\n TAdapter extends ImageAdapter<any, any, any, infer SizeByName>\n ? string extends keyof SizeByName\n ? // SizeByName has index signature - fall back to string\n string\n : // SizeByName has explicit keys - check if TModel is one of them\n TModel extends keyof SizeByName\n ? SizeByName[TModel]\n : string\n : string\n\n/**\n * Extract the prompt type a model accepts from an ImageAdapter via ~types.\n * Adapters declare a per-model input-modality map; models in the map get a\n * `prompt` narrowed to text + their supported part types (text-only models\n * accept `string | Array<TextPart>`), so unsupported media parts fail at\n * compile time. Adapters without a map fall back to the full MediaPrompt.\n */\nexport type ImagePromptForModel<TAdapter, TModel extends string> =\n TAdapter extends ImageAdapter<any, any, any, any, infer ModsByName>\n ? string extends keyof ModsByName\n ? // No explicit map - accept the full union\n MediaPrompt\n : TModel extends keyof ModsByName\n ? MediaPromptFor<ModsByName[TModel][number]>\n : MediaPrompt\n : MediaPrompt\n\n// ===========================\n// Activity Options Type\n// ===========================\n\n/**\n * Options for the image activity.\n * The model is extracted from the adapter's model property.\n *\n * @template TAdapter - The image adapter type\n * @template TStream - Whether to stream the output\n */\nexport type ImageActivityOptions<\n TAdapter extends ImageAdapter<string, any, any, any>,\n TStream extends boolean = false,\n> = {\n /** The image adapter to use (must be created with a model) */\n adapter: TAdapter & { kind: typeof kind }\n /**\n * Description of the desired image(s). Either a plain string, or — for\n * models that support image-conditioned generation — an ordered array of\n * content parts interleaving text with image inputs (image-to-image,\n * reference-guided, edit, multi-reference). Media parts may carry\n * `metadata.role` (`'reference' | 'mask' | 'control' | 'character'`) to\n * disambiguate intent. The accepted part types are narrowed per model via\n * the adapter's input-modality map.\n */\n prompt: ImagePromptForModel<TAdapter, TAdapter['model']>\n /** Number of images to generate (default: 1) */\n numberOfImages?: number\n /** Image size in WIDTHxHEIGHT format (e.g., \"1024x1024\") */\n size?: ImageSizeForModel<TAdapter, TAdapter['model']>\n /**\n * Whether to stream the image generation result.\n * When true, returns an AsyncIterable<StreamChunk> for streaming transport.\n * When false or not provided, returns a Promise<ImageGenerationResult>.\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} & ({} extends ImageProviderOptionsForModel<TAdapter, TAdapter['model']>\n ? {\n /** Provider-specific options for image generation */ modelOptions?: ImageProviderOptionsForModel<\n TAdapter,\n TAdapter['model']\n >\n }\n : {\n /** Provider-specific options for image generation */ modelOptions: ImageProviderOptionsForModel<\n TAdapter,\n TAdapter['model']\n >\n })\n\n// ===========================\n// Activity Result Type\n// ===========================\n\n/**\n * Result type for the image activity.\n * - If stream is true: AsyncIterable<StreamChunk>\n * - Otherwise: Promise<ImageGenerationResult>\n */\nexport type ImageActivityResult<TStream extends boolean = false> =\n TStream extends true\n ? AsyncIterable<StreamChunk>\n : Promise<ImageGenerationResult>\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 * Image activity - generates images from text prompts.\n *\n * Uses AI image generation models to create images based on natural language descriptions.\n *\n * @example Generate a single image\n * ```ts\n * import { generateImage } from '@tanstack/ai'\n * import { openaiImage } from '@tanstack/ai-openai'\n *\n * const result = await generateImage({\n * adapter: openaiImage('dall-e-3'),\n * prompt: 'A serene mountain landscape at sunset'\n * })\n *\n * console.log(result.images[0].url)\n * ```\n *\n * @example Generate multiple images\n * ```ts\n * const result = await generateImage({\n * adapter: openaiImage('dall-e-2'),\n * prompt: 'A cute robot mascot',\n * numberOfImages: 4,\n * size: '512x512'\n * })\n *\n * result.images.forEach((image, i) => {\n * console.log(`Image ${i + 1}: ${image.url}`)\n * })\n * ```\n *\n * @example With provider-specific options\n * ```ts\n * const result = await generateImage({\n * adapter: openaiImage('dall-e-3'),\n * prompt: 'A professional headshot photo',\n * size: '1024x1024',\n * modelOptions: {\n * quality: 'hd',\n * style: 'natural'\n * }\n * })\n * ```\n */\nexport function generateImage<\n TAdapter extends ImageAdapter<string, any, any, any>,\n TStream extends boolean = false,\n>(\n options: ImageActivityOptions<TAdapter, TStream>,\n): ImageActivityResult<TStream> {\n if (options.stream) {\n return streamGenerationResult(() =>\n runGenerateImage(options),\n ) as ImageActivityResult<TStream>\n }\n\n return runGenerateImage(options) as ImageActivityResult<TStream>\n}\n\n/**\n * Internal implementation of image generation (always non-streaming).\n * Contains all devtools event emission logic.\n */\nasync function runGenerateImage<\n TAdapter extends ImageAdapter<string, any, any, any>,\n>(\n options: ImageActivityOptions<TAdapter, boolean>,\n): Promise<ImageGenerationResult> {\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('image')\n const startTime = Date.now()\n const logger: InternalLogger = resolveDebugOption(options.debug)\n\n const mwCtx = createGenerationContext({\n requestId,\n activity: 'image',\n provider: adapter.name,\n model,\n modelOptions: rest.modelOptions,\n createId,\n })\n\n await runGenerationStart(middleware, mwCtx)\n\n // Devtools events carry the flattened prompt text plus media-part counts —\n // the wire payload stays `prompt: string` regardless of the prompt shape.\n const resolved = resolveMediaPrompt(rest.prompt)\n\n aiEventClient.emit('image:request:started', {\n requestId,\n provider: adapter.name,\n model,\n prompt: resolved.text,\n numberOfImages: rest.numberOfImages,\n size: rest.size,\n ...(resolved.images.length > 0 && {\n imageInputCount: resolved.images.length,\n }),\n ...(resolved.videos.length > 0 && {\n videoInputCount: resolved.videos.length,\n }),\n ...(resolved.audios.length > 0 && {\n audioInputCount: resolved.audios.length,\n }),\n modelOptions: rest.modelOptions,\n timestamp: startTime,\n })\n\n logger.request(`activity=generateImage provider=${adapter.name}`, {\n provider: adapter.name,\n model,\n })\n\n try {\n const result = await adapter.generateImages({ ...rest, model, logger })\n const duration = Date.now() - startTime\n\n aiEventClient.emit('image:request:completed', {\n requestId,\n provider: adapter.name,\n model,\n // GeneratedImage is a discriminated `{ url } | { b64Json }` union, but the\n // wire shape on the devtools event is a plain optional pair. Use\n // conditional spreads so the emitted record only sets the field actually\n // present — `exactOptionalPropertyTypes` rejects `field: undefined`\n // against `field?: string` targets.\n images: result.images.map((image) => ({\n url: image.url,\n b64Json: image.b64Json,\n })),\n duration,\n modelOptions: rest.modelOptions,\n timestamp: Date.now(),\n })\n\n if (result.usage) {\n aiEventClient.emit('image:usage', {\n requestId,\n model,\n usage: result.usage,\n modelOptions: rest.modelOptions,\n timestamp: Date.now(),\n })\n }\n\n logger.output(`activity=generateImage count=${result.images.length}`, {\n count: result.images.length,\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 await runGenerationError(middleware, mwCtx, {\n error,\n duration: Date.now() - startTime,\n })\n logger.errors('generateImage activity failed', {\n error,\n source: 'generateImage',\n })\n throw error\n }\n}\n\n// ===========================\n// Options Factory\n// ===========================\n\n/**\n * Create typed options for the generateImage() function without executing.\n */\nexport function createImageOptions<\n TAdapter extends ImageAdapter<string, any, any, any>,\n TStream extends boolean = false,\n>(\n options: ImageActivityOptions<TAdapter, TStream>,\n): ImageActivityOptions<TAdapter, TStream> {\n return options\n}\n\n// Re-export adapter types\nexport type {\n ImageAdapter,\n ImageAdapterConfig,\n AnyImageAdapter,\n} from './adapter'\nexport { BaseImageAdapter } from './adapter'\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../src/activities/generateImage/index.ts"],"sourcesContent":["/**\n * Image Activity\n *\n * Generates images from text prompts.\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 { resolveMediaPrompt } from '../../utilities/media-prompt'\nimport type { InternalLogger } from '../../logger/internal-logger'\nimport type { DebugOption } from '../../logger/types'\nimport type { GenerationMiddleware } from '../middleware/types'\nimport type { ImageAdapter } from './adapter'\nimport type {\n ImageGenerationResult,\n MediaPrompt,\n MediaPromptFor,\n StreamChunk,\n} from '../../types'\n\n// ===========================\n// Activity Kind\n// ===========================\n\n/** The adapter kind this activity handles */\nexport const kind = 'image' as const\n\n// ===========================\n// Type Extraction Helpers\n// ===========================\n\n/**\n * Extract model-specific provider options from an ImageAdapter via ~types.\n * If the model has specific options defined in ModelProviderOptions (and not just via index signature),\n * use those; otherwise fall back to base provider options.\n */\nexport type ImageProviderOptionsForModel<TAdapter, TModel extends string> =\n TAdapter extends ImageAdapter<any, infer BaseOptions, infer ModelOptions, any>\n ? string extends keyof ModelOptions\n ? // ModelOptions is Record<string, unknown> or has index signature - use BaseOptions\n BaseOptions\n : // ModelOptions has explicit keys - check if TModel is one of them\n TModel extends keyof ModelOptions\n ? ModelOptions[TModel]\n : BaseOptions\n : object\n\n/**\n * Extract model-specific size options from an ImageAdapter via ~types.\n * If the model has specific sizes defined, use those; otherwise fall back to string.\n */\nexport type ImageSizeForModel<TAdapter, TModel extends string> =\n TAdapter extends ImageAdapter<any, any, any, infer SizeByName>\n ? string extends keyof SizeByName\n ? // SizeByName has index signature - fall back to string\n string\n : // SizeByName has explicit keys - check if TModel is one of them\n TModel extends keyof SizeByName\n ? SizeByName[TModel]\n : string\n : string\n\n/**\n * Extract the prompt type a model accepts from an ImageAdapter via ~types.\n * Adapters declare a per-model input-modality map; models in the map get a\n * `prompt` narrowed to text + their supported part types (text-only models\n * accept `string | Array<TextPart>`), so unsupported media parts fail at\n * compile time. Adapters without a map fall back to the full MediaPrompt.\n */\nexport type ImagePromptForModel<TAdapter, TModel extends string> =\n TAdapter extends ImageAdapter<any, any, any, any, infer ModsByName>\n ? string extends keyof ModsByName\n ? // No explicit map - accept the full union\n MediaPrompt\n : TModel extends keyof ModsByName\n ? MediaPromptFor<ModsByName[TModel][number]>\n : MediaPrompt\n : MediaPrompt\n\n// ===========================\n// Activity Options Type\n// ===========================\n\n/**\n * Options for the image activity.\n * The model is extracted from the adapter's model property.\n *\n * @template TAdapter - The image adapter type\n * @template TStream - Whether to stream the output\n */\nexport type ImageActivityOptions<\n TAdapter extends ImageAdapter<string, any, any, any>,\n TStream extends boolean = false,\n> = {\n /** The image adapter to use (must be created with a model) */\n adapter: TAdapter & { kind: typeof kind }\n /**\n * Description of the desired image(s). Either a plain string, or — for\n * models that support image-conditioned generation — an ordered array of\n * content parts interleaving text with image inputs (image-to-image,\n * reference-guided, edit, multi-reference). Media parts may carry\n * `metadata.role` (`'reference' | 'mask' | 'control' | 'character'`) to\n * disambiguate intent. The accepted part types are narrowed per model via\n * the adapter's input-modality map.\n */\n prompt: ImagePromptForModel<TAdapter, TAdapter['model']>\n /** Number of images to generate (default: 1) */\n numberOfImages?: number\n /** Image size in WIDTHxHEIGHT format (e.g., \"1024x1024\") */\n size?: ImageSizeForModel<TAdapter, TAdapter['model']>\n /**\n * Whether to stream the image generation result.\n * When true, returns an AsyncIterable<StreamChunk> for streaming transport.\n * When false or not provided, returns a Promise<ImageGenerationResult>.\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} & ({} extends ImageProviderOptionsForModel<TAdapter, TAdapter['model']>\n ? {\n /** Provider-specific options for image generation */ modelOptions?: ImageProviderOptionsForModel<\n TAdapter,\n TAdapter['model']\n >\n }\n : {\n /** Provider-specific options for image generation */ modelOptions: ImageProviderOptionsForModel<\n TAdapter,\n TAdapter['model']\n >\n })\n\n// ===========================\n// Activity Result Type\n// ===========================\n\n/**\n * Result type for the image activity.\n * - If stream is true: AsyncIterable<StreamChunk>\n * - Otherwise: Promise<ImageGenerationResult>\n */\nexport type ImageActivityResult<TStream extends boolean = false> =\n TStream extends true\n ? AsyncIterable<StreamChunk>\n : Promise<ImageGenerationResult>\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 * Image activity - generates images from text prompts.\n *\n * Uses AI image generation models to create images based on natural language descriptions.\n *\n * @example Generate a single image\n * ```ts\n * import { generateImage } from '@tanstack/ai'\n * import { openaiImage } from '@tanstack/ai-openai'\n *\n * const result = await generateImage({\n * adapter: openaiImage('dall-e-3'),\n * prompt: 'A serene mountain landscape at sunset'\n * })\n *\n * console.log(result.images[0].url)\n * ```\n *\n * @example Generate multiple images\n * ```ts\n * const result = await generateImage({\n * adapter: openaiImage('dall-e-2'),\n * prompt: 'A cute robot mascot',\n * numberOfImages: 4,\n * size: '512x512'\n * })\n *\n * result.images.forEach((image, i) => {\n * console.log(`Image ${i + 1}: ${image.url}`)\n * })\n * ```\n *\n * @example With provider-specific options\n * ```ts\n * const result = await generateImage({\n * adapter: openaiImage('dall-e-3'),\n * prompt: 'A professional headshot photo',\n * size: '1024x1024',\n * modelOptions: {\n * quality: 'hd',\n * style: 'natural'\n * }\n * })\n * ```\n */\nexport function generateImage<\n TAdapter extends ImageAdapter<string, any, any, any>,\n TStream extends boolean = false,\n>(\n options: ImageActivityOptions<TAdapter, TStream>,\n): ImageActivityResult<TStream> {\n if (options.stream) {\n return streamGenerationResult(() =>\n runGenerateImage(options),\n ) as ImageActivityResult<TStream>\n }\n\n return runGenerateImage(options) as ImageActivityResult<TStream>\n}\n\n/**\n * Internal implementation of image generation (always non-streaming).\n * Contains all devtools event emission logic.\n */\nasync function runGenerateImage<\n TAdapter extends ImageAdapter<string, any, any, any>,\n>(\n options: ImageActivityOptions<TAdapter, boolean>,\n): Promise<ImageGenerationResult> {\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('image')\n const startTime = Date.now()\n const logger: InternalLogger = resolveDebugOption(options.debug)\n\n const mwCtx = createGenerationContext({\n requestId,\n activity: 'image',\n provider: adapter.name,\n model,\n modelOptions: rest.modelOptions,\n createId,\n })\n\n await runGenerationStart(middleware, mwCtx)\n\n // Devtools events carry the flattened prompt text plus media-part counts —\n // the wire payload stays `prompt: string` regardless of the prompt shape.\n const resolved = resolveMediaPrompt(rest.prompt)\n\n aiEventClient.emit('image:request:started', {\n requestId,\n provider: adapter.name,\n model,\n prompt: resolved.text,\n numberOfImages: rest.numberOfImages,\n size: rest.size,\n ...(resolved.images.length > 0 && {\n imageInputCount: resolved.images.length,\n }),\n ...(resolved.videos.length > 0 && {\n videoInputCount: resolved.videos.length,\n }),\n ...(resolved.audios.length > 0 && {\n audioInputCount: resolved.audios.length,\n }),\n modelOptions: rest.modelOptions,\n timestamp: startTime,\n })\n\n logger.request(`activity=generateImage provider=${adapter.name}`, {\n provider: adapter.name,\n model,\n })\n\n try {\n const result = await adapter.generateImages({ ...rest, model, logger })\n const duration = Date.now() - startTime\n\n aiEventClient.emit('image:request:completed', {\n requestId,\n provider: adapter.name,\n model,\n // GeneratedImage is a discriminated `{ url } | { b64Json }` union, but the\n // wire shape on the devtools event is a plain optional pair. Use\n // conditional spreads so the emitted record only sets the field actually\n // present — `exactOptionalPropertyTypes` rejects `field: undefined`\n // against `field?: string` targets.\n images: result.images.map((image) => ({\n url: image.url,\n b64Json: image.b64Json,\n })),\n duration,\n modelOptions: rest.modelOptions,\n timestamp: Date.now(),\n })\n\n if (result.usage) {\n aiEventClient.emit('image:usage', {\n requestId,\n model,\n usage: result.usage,\n modelOptions: rest.modelOptions,\n timestamp: Date.now(),\n })\n }\n\n logger.output(`activity=generateImage count=${result.images.length}`, {\n count: result.images.length,\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 await runGenerationError(middleware, mwCtx, {\n error,\n duration: Date.now() - startTime,\n })\n logger.errors('generateImage activity failed', {\n error,\n source: 'generateImage',\n })\n throw error\n }\n}\n\n// ===========================\n// Options Factory\n// ===========================\n\n/**\n * Create typed options for the generateImage() function without executing.\n */\nexport function createImageOptions<\n TAdapter extends ImageAdapter<string, any, any, any>,\n TStream extends boolean = false,\n>(\n options: ImageActivityOptions<TAdapter, TStream>,\n): ImageActivityOptions<TAdapter, TStream> {\n return options\n}\n\n// Re-export adapter types\nexport type {\n ImageAdapter,\n ImageAdapterConfig,\n AnyImageAdapter,\n} from './adapter'\nexport { BaseImageAdapter } from './adapter'\n"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DebugOption } from '../../logger/types.js';
|
|
2
|
-
import { GenerationMiddleware } from '../middleware.js';
|
|
2
|
+
import { GenerationMiddleware } from '../middleware/types.js';
|
|
3
3
|
import { TTSAdapter } from './adapter.js';
|
|
4
4
|
import { StreamChunk, TTSResult } from '../../types.js';
|
|
5
5
|
/** The adapter kind this activity handles */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../../src/activities/generateSpeech/index.ts"],"sourcesContent":["/**\n * TTS Activity\n *\n * Generates speech audio from text using text-to-speech 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'\nimport type { InternalLogger } from '../../logger/internal-logger'\nimport type { DebugOption } from '../../logger/types'\nimport type { GenerationMiddleware } from '../middleware'\nimport type { TTSAdapter } from './adapter'\nimport type { StreamChunk, TTSResult } from '../../types'\n\n// ===========================\n// Activity Kind\n// ===========================\n\n/** The adapter kind this activity handles */\nexport const kind = 'tts' as const\n\n// ===========================\n// Type Extraction Helpers\n// ===========================\n\n/**\n * Extract provider options from a TTSAdapter via ~types.\n */\nexport type TTSProviderOptions<TAdapter> =\n TAdapter extends TTSAdapter<any, any>\n ? TAdapter['~types']['providerOptions']\n : object\n\n// ===========================\n// Activity Options Type\n// ===========================\n\n/**\n * Options for the TTS activity.\n * The model is extracted from the adapter's model property.\n *\n * @template TAdapter - The TTS adapter type\n * @template TStream - Whether to stream the output\n */\nexport interface TTSActivityOptions<\n TAdapter extends TTSAdapter<string, TTSProviderOptions<TAdapter>>,\n TStream extends boolean = false,\n> {\n /** The TTS adapter to use (must be created with a model) */\n adapter: TAdapter & { kind: typeof kind }\n /** The text to convert to speech */\n text: string\n /** The voice to use for generation */\n voice?: string\n /** The output audio format */\n format?: 'mp3' | 'opus' | 'aac' | 'flac' | 'wav' | 'pcm'\n /** The speed of the generated audio (0.25 to 4.0) */\n speed?: number\n /** Provider-specific options for TTS generation */\n modelOptions?: TTSProviderOptions<TAdapter>\n /**\n * Whether to stream the generation result.\n * When true, returns an AsyncIterable<StreamChunk> for streaming transport.\n * When false or not provided, returns a Promise<TTSResult>.\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 TTS activity.\n * - If stream is true: AsyncIterable<StreamChunk>\n * - Otherwise: Promise<TTSResult>\n */\nexport type TTSActivityResult<TStream extends boolean = false> =\n TStream extends true ? AsyncIterable<StreamChunk> : Promise<TTSResult>\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 * TTS activity - generates speech from text.\n *\n * Uses AI text-to-speech models to create audio from natural language text.\n *\n * @example Generate speech from text\n * ```ts\n * import { generateSpeech } from '@tanstack/ai'\n * import { openaiSpeech } from '@tanstack/ai-openai'\n *\n * const result = await generateSpeech({\n * adapter: openaiSpeech('tts-1-hd'),\n * text: 'Hello, welcome to TanStack AI!',\n * voice: 'nova'\n * })\n *\n * console.log(result.audio) // base64-encoded audio\n * ```\n *\n * @example With format and speed options\n * ```ts\n * const result = await generateSpeech({\n * adapter: openaiSpeech('tts-1'),\n * text: 'This is slower speech.',\n * voice: 'alloy',\n * format: 'wav',\n * speed: 0.8\n * })\n * ```\n */\nexport function generateSpeech<\n TAdapter extends TTSAdapter<string, TTSProviderOptions<TAdapter>>,\n TStream extends boolean = false,\n>(options: TTSActivityOptions<TAdapter, TStream>): TTSActivityResult<TStream> {\n if (options.stream) {\n return streamGenerationResult(() =>\n runGenerateSpeech(options),\n ) as TTSActivityResult<TStream>\n }\n return runGenerateSpeech(options) as TTSActivityResult<TStream>\n}\n\n/**\n * Run the core TTS generation logic (non-streaming).\n */\nasync function runGenerateSpeech<\n TAdapter extends TTSAdapter<string, TTSProviderOptions<TAdapter>>,\n>(options: TTSActivityOptions<TAdapter, boolean>): Promise<TTSResult> {\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('speech')\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: 'tts',\n provider: adapter.name,\n model,\n modelOptions: rest.modelOptions,\n createId,\n })\n\n await runGenerationStart(middleware, mwCtx)\n\n aiEventClient.emit('speech:request:started', {\n requestId,\n provider: adapter.name,\n model,\n text: rest.text,\n voice: rest.voice,\n format: rest.format,\n speed: rest.speed,\n modelOptions: rest.modelOptions as Record<string, unknown> | undefined,\n timestamp: startTime,\n })\n\n logger.request(`activity=generateSpeech provider=${providerName}`, {\n provider: providerName,\n model,\n })\n\n try {\n const result = await adapter.generateSpeech({ ...rest, model, logger })\n const duration = Date.now() - startTime\n\n aiEventClient.emit('speech:request:completed', {\n requestId,\n provider: adapter.name,\n model,\n audio: result.audio,\n format: result.format,\n audioDuration: result.duration,\n contentType: result.contentType,\n duration,\n modelOptions: rest.modelOptions as Record<string, unknown> | undefined,\n timestamp: Date.now(),\n })\n\n if (result.usage) {\n aiEventClient.emit('speech:usage', {\n requestId,\n model,\n usage: result.usage,\n modelOptions: rest.modelOptions as Record<string, unknown> | undefined,\n timestamp: Date.now(),\n })\n }\n\n logger.output(`activity=generateSpeech bytes=${result.audio.length}`, {\n bytes: result.audio.length,\n contentType: result.contentType,\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('speech: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('generateSpeech activity failed', {\n error,\n source: 'generateSpeech',\n })\n throw error\n }\n}\n\n// ===========================\n// Options Factory\n// ===========================\n\n/**\n * Create typed options for the generateSpeech() function without executing.\n */\nexport function createSpeechOptions<\n TAdapter extends TTSAdapter<string, TTSProviderOptions<TAdapter>>,\n TStream extends boolean = false,\n>(\n options: TTSActivityOptions<TAdapter, TStream>,\n): TTSActivityOptions<TAdapter, TStream> {\n return options\n}\n\n// Re-export adapter types\nexport type { TTSAdapter, TTSAdapterConfig, AnyTTSAdapter } from './adapter'\nexport { BaseTTSAdapter } from './adapter'\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../src/activities/generateSpeech/index.ts"],"sourcesContent":["/**\n * TTS Activity\n *\n * Generates speech audio from text using text-to-speech 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 { TTSAdapter } from './adapter'\nimport type { StreamChunk, TTSResult } from '../../types'\n\n// ===========================\n// Activity Kind\n// ===========================\n\n/** The adapter kind this activity handles */\nexport const kind = 'tts' as const\n\n// ===========================\n// Type Extraction Helpers\n// ===========================\n\n/**\n * Extract provider options from a TTSAdapter via ~types.\n */\nexport type TTSProviderOptions<TAdapter> =\n TAdapter extends TTSAdapter<any, any>\n ? TAdapter['~types']['providerOptions']\n : object\n\n// ===========================\n// Activity Options Type\n// ===========================\n\n/**\n * Options for the TTS activity.\n * The model is extracted from the adapter's model property.\n *\n * @template TAdapter - The TTS adapter type\n * @template TStream - Whether to stream the output\n */\nexport interface TTSActivityOptions<\n TAdapter extends TTSAdapter<string, TTSProviderOptions<TAdapter>>,\n TStream extends boolean = false,\n> {\n /** The TTS adapter to use (must be created with a model) */\n adapter: TAdapter & { kind: typeof kind }\n /** The text to convert to speech */\n text: string\n /** The voice to use for generation */\n voice?: string\n /** The output audio format */\n format?: 'mp3' | 'opus' | 'aac' | 'flac' | 'wav' | 'pcm'\n /** The speed of the generated audio (0.25 to 4.0) */\n speed?: number\n /** Provider-specific options for TTS generation */\n modelOptions?: TTSProviderOptions<TAdapter>\n /**\n * Whether to stream the generation result.\n * When true, returns an AsyncIterable<StreamChunk> for streaming transport.\n * When false or not provided, returns a Promise<TTSResult>.\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 TTS activity.\n * - If stream is true: AsyncIterable<StreamChunk>\n * - Otherwise: Promise<TTSResult>\n */\nexport type TTSActivityResult<TStream extends boolean = false> =\n TStream extends true ? AsyncIterable<StreamChunk> : Promise<TTSResult>\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 * TTS activity - generates speech from text.\n *\n * Uses AI text-to-speech models to create audio from natural language text.\n *\n * @example Generate speech from text\n * ```ts\n * import { generateSpeech } from '@tanstack/ai'\n * import { openaiSpeech } from '@tanstack/ai-openai'\n *\n * const result = await generateSpeech({\n * adapter: openaiSpeech('tts-1-hd'),\n * text: 'Hello, welcome to TanStack AI!',\n * voice: 'nova'\n * })\n *\n * console.log(result.audio) // base64-encoded audio\n * ```\n *\n * @example With format and speed options\n * ```ts\n * const result = await generateSpeech({\n * adapter: openaiSpeech('tts-1'),\n * text: 'This is slower speech.',\n * voice: 'alloy',\n * format: 'wav',\n * speed: 0.8\n * })\n * ```\n */\nexport function generateSpeech<\n TAdapter extends TTSAdapter<string, TTSProviderOptions<TAdapter>>,\n TStream extends boolean = false,\n>(options: TTSActivityOptions<TAdapter, TStream>): TTSActivityResult<TStream> {\n if (options.stream) {\n return streamGenerationResult(() =>\n runGenerateSpeech(options),\n ) as TTSActivityResult<TStream>\n }\n return runGenerateSpeech(options) as TTSActivityResult<TStream>\n}\n\n/**\n * Run the core TTS generation logic (non-streaming).\n */\nasync function runGenerateSpeech<\n TAdapter extends TTSAdapter<string, TTSProviderOptions<TAdapter>>,\n>(options: TTSActivityOptions<TAdapter, boolean>): Promise<TTSResult> {\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('speech')\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: 'tts',\n provider: adapter.name,\n model,\n modelOptions: rest.modelOptions,\n createId,\n })\n\n await runGenerationStart(middleware, mwCtx)\n\n aiEventClient.emit('speech:request:started', {\n requestId,\n provider: adapter.name,\n model,\n text: rest.text,\n voice: rest.voice,\n format: rest.format,\n speed: rest.speed,\n modelOptions: rest.modelOptions as Record<string, unknown> | undefined,\n timestamp: startTime,\n })\n\n logger.request(`activity=generateSpeech provider=${providerName}`, {\n provider: providerName,\n model,\n })\n\n try {\n const result = await adapter.generateSpeech({ ...rest, model, logger })\n const duration = Date.now() - startTime\n\n aiEventClient.emit('speech:request:completed', {\n requestId,\n provider: adapter.name,\n model,\n audio: result.audio,\n format: result.format,\n audioDuration: result.duration,\n contentType: result.contentType,\n duration,\n modelOptions: rest.modelOptions as Record<string, unknown> | undefined,\n timestamp: Date.now(),\n })\n\n if (result.usage) {\n aiEventClient.emit('speech:usage', {\n requestId,\n model,\n usage: result.usage,\n modelOptions: rest.modelOptions as Record<string, unknown> | undefined,\n timestamp: Date.now(),\n })\n }\n\n logger.output(`activity=generateSpeech bytes=${result.audio.length}`, {\n bytes: result.audio.length,\n contentType: result.contentType,\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('speech: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('generateSpeech activity failed', {\n error,\n source: 'generateSpeech',\n })\n throw error\n }\n}\n\n// ===========================\n// Options Factory\n// ===========================\n\n/**\n * Create typed options for the generateSpeech() function without executing.\n */\nexport function createSpeechOptions<\n TAdapter extends TTSAdapter<string, TTSProviderOptions<TAdapter>>,\n TStream extends boolean = false,\n>(\n options: TTSActivityOptions<TAdapter, TStream>,\n): TTSActivityOptions<TAdapter, TStream> {\n return options\n}\n\n// Re-export adapter types\nexport type { TTSAdapter, TTSAdapterConfig, AnyTTSAdapter } from './adapter'\nexport { BaseTTSAdapter } from './adapter'\n"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DebugOption } from '../../logger/types.js';
|
|
2
|
-
import { GenerationMiddleware } from '../middleware.js';
|
|
2
|
+
import { GenerationMiddleware } from '../middleware/types.js';
|
|
3
3
|
import { TranscriptionAdapter } from './adapter.js';
|
|
4
4
|
import { StreamChunk, TranscriptionResponseFormat, TranscriptionResult } from '../../types.js';
|
|
5
5
|
/** The adapter kind this activity handles */
|
|
@@ -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'\nimport type { InternalLogger } from '../../logger/internal-logger'\nimport type { DebugOption } from '../../logger/types'\nimport type { GenerationMiddleware } from '../middleware'\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","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,5 +1,5 @@
|
|
|
1
1
|
import { DebugOption } from '../../logger/types.js';
|
|
2
|
-
import { GenerationMiddleware } from '../middleware.js';
|
|
2
|
+
import { GenerationMiddleware } from '../middleware/types.js';
|
|
3
3
|
import { VideoAdapter } from './adapter.js';
|
|
4
4
|
import { MediaPrompt, MediaPromptFor, StreamChunk, TokenUsage, VideoJobResult, VideoStatusResult, VideoUrlResult } from '../../types.js';
|
|
5
5
|
/** The adapter kind this activity handles */
|
|
@@ -7,18 +7,18 @@ export declare const kind: "video";
|
|
|
7
7
|
/**
|
|
8
8
|
* Extract provider options from a VideoAdapter via ~types.
|
|
9
9
|
*/
|
|
10
|
-
export type VideoProviderOptions<TAdapter> = TAdapter extends VideoAdapter<any, any, any, any> ? TAdapter['~types']['providerOptions'] : object;
|
|
10
|
+
export type VideoProviderOptions<TAdapter> = TAdapter extends VideoAdapter<any, any, any, any, any, any> ? TAdapter['~types']['providerOptions'] : object;
|
|
11
11
|
/**
|
|
12
12
|
* Extract the size type for a VideoAdapter's model via ~types.
|
|
13
13
|
*/
|
|
14
|
-
export type VideoSizeForAdapter<TAdapter> = TAdapter extends VideoAdapter<infer TModel, any, any, infer TSizeMap> ? TModel extends keyof TSizeMap ? TSizeMap[TModel] : string : string;
|
|
14
|
+
export type VideoSizeForAdapter<TAdapter> = TAdapter extends VideoAdapter<infer TModel, any, any, infer TSizeMap, any, any> ? TModel extends keyof TSizeMap ? TSizeMap[TModel] : string : string;
|
|
15
15
|
/**
|
|
16
16
|
* Extract the prompt type a model accepts from a VideoAdapter via ~types.
|
|
17
17
|
* Mirrors `ImagePromptForModel`: models in the adapter's input-modality map
|
|
18
18
|
* get a `prompt` narrowed to text + their supported part types; adapters
|
|
19
19
|
* without a map fall back to the full MediaPrompt.
|
|
20
20
|
*/
|
|
21
|
-
export type VideoPromptForAdapter<TAdapter> = TAdapter extends VideoAdapter<infer TModel, any, any, any, infer ModsByName> ? string extends keyof ModsByName ? MediaPrompt : TModel extends keyof ModsByName ? MediaPromptFor<ModsByName[TModel][number]> : MediaPrompt : MediaPrompt;
|
|
21
|
+
export type VideoPromptForAdapter<TAdapter> = TAdapter extends VideoAdapter<infer TModel, any, any, any, infer ModsByName, any> ? string extends keyof ModsByName ? MediaPrompt : TModel extends keyof ModsByName ? MediaPromptFor<ModsByName[TModel][number]> : MediaPrompt : MediaPrompt;
|
|
22
22
|
/**
|
|
23
23
|
* Extract the duration type for a VideoAdapter's model via ~types.
|
|
24
24
|
* Mirrors `VideoSizeForAdapter`. Falls back to `number` for adapters that
|
|
@@ -29,7 +29,7 @@ export type VideoDurationForAdapter<TAdapter> = TAdapter extends VideoAdapter<in
|
|
|
29
29
|
* Base options shared by all video activity operations.
|
|
30
30
|
* The model is extracted from the adapter's model property.
|
|
31
31
|
*/
|
|
32
|
-
interface VideoActivityBaseOptions<TAdapter extends VideoAdapter<string, any, any, any>> {
|
|
32
|
+
interface VideoActivityBaseOptions<TAdapter extends VideoAdapter<string, any, any, any, any, any>> {
|
|
33
33
|
/** The video adapter to use (must be created with a model) */
|
|
34
34
|
adapter: TAdapter & {
|
|
35
35
|
kind: typeof kind;
|
|
@@ -44,7 +44,7 @@ interface VideoActivityBaseOptions<TAdapter extends VideoAdapter<string, any, an
|
|
|
44
44
|
*
|
|
45
45
|
* @experimental Video generation is an experimental feature and may change.
|
|
46
46
|
*/
|
|
47
|
-
export type VideoCreateOptions<TAdapter extends VideoAdapter<string, any, any, any>, TStream extends boolean = false> = VideoActivityBaseOptions<TAdapter> & {
|
|
47
|
+
export type VideoCreateOptions<TAdapter extends VideoAdapter<string, any, any, any, any, any>, TStream extends boolean = false> = VideoActivityBaseOptions<TAdapter> & {
|
|
48
48
|
/** Request type - create a new job (default if not specified) */
|
|
49
49
|
request?: 'create';
|
|
50
50
|
/**
|
|
@@ -105,7 +105,7 @@ export type VideoCreateOptions<TAdapter extends VideoAdapter<string, any, any, a
|
|
|
105
105
|
*
|
|
106
106
|
* @experimental Video generation is an experimental feature and may change.
|
|
107
107
|
*/
|
|
108
|
-
export interface VideoStatusOptions<TAdapter extends VideoAdapter<string, any, any, any>> extends VideoActivityBaseOptions<TAdapter> {
|
|
108
|
+
export interface VideoStatusOptions<TAdapter extends VideoAdapter<string, any, any, any, any, any>> extends VideoActivityBaseOptions<TAdapter> {
|
|
109
109
|
/** Request type - get job status */
|
|
110
110
|
request: 'status';
|
|
111
111
|
/** The job ID to check status for */
|
|
@@ -116,7 +116,7 @@ export interface VideoStatusOptions<TAdapter extends VideoAdapter<string, any, a
|
|
|
116
116
|
*
|
|
117
117
|
* @experimental Video generation is an experimental feature and may change.
|
|
118
118
|
*/
|
|
119
|
-
export interface VideoUrlOptions<TAdapter extends VideoAdapter<string, any, any, any>> extends VideoActivityBaseOptions<TAdapter> {
|
|
119
|
+
export interface VideoUrlOptions<TAdapter extends VideoAdapter<string, any, any, any, any, any>> extends VideoActivityBaseOptions<TAdapter> {
|
|
120
120
|
/** Request type - get video URL */
|
|
121
121
|
request: 'url';
|
|
122
122
|
/** The job ID to get URL for */
|
|
@@ -128,7 +128,7 @@ export interface VideoUrlOptions<TAdapter extends VideoAdapter<string, any, any,
|
|
|
128
128
|
*
|
|
129
129
|
* @experimental Video generation is an experimental feature and may change.
|
|
130
130
|
*/
|
|
131
|
-
export type VideoActivityOptions<TAdapter extends VideoAdapter<string, any, any, any>, TRequest extends 'create' | 'status' | 'url' = 'create', TStream extends boolean = false> = TRequest extends 'status' ? VideoStatusOptions<TAdapter> : TRequest extends 'url' ? VideoUrlOptions<TAdapter> : VideoCreateOptions<TAdapter, TStream>;
|
|
131
|
+
export type VideoActivityOptions<TAdapter extends VideoAdapter<string, any, any, any, any, any>, TRequest extends 'create' | 'status' | 'url' = 'create', TStream extends boolean = false> = TRequest extends 'status' ? VideoStatusOptions<TAdapter> : TRequest extends 'url' ? VideoUrlOptions<TAdapter> : VideoCreateOptions<TAdapter, TStream>;
|
|
132
132
|
/**
|
|
133
133
|
* Result type for the video activity, based on request type and streaming.
|
|
134
134
|
* - If stream is true (create request): AsyncIterable<StreamChunk>
|
|
@@ -177,7 +177,7 @@ export type VideoActivityResult<TRequest extends 'create' | 'status' | 'url' = '
|
|
|
177
177
|
* return toServerSentEventsResponse(stream)
|
|
178
178
|
* ```
|
|
179
179
|
*/
|
|
180
|
-
export declare function generateVideo<TAdapter extends VideoAdapter<string, any, any, any>, TStream extends boolean = false>(options: VideoCreateOptions<TAdapter, TStream>): VideoActivityResult<'create', TStream>;
|
|
180
|
+
export declare function generateVideo<TAdapter extends VideoAdapter<string, any, any, any, any, any>, TStream extends boolean = false>(options: VideoCreateOptions<TAdapter, TStream>): VideoActivityResult<'create', TStream>;
|
|
181
181
|
/**
|
|
182
182
|
* Get video job status - returns the current status, progress, and URL if available.
|
|
183
183
|
*
|
|
@@ -203,7 +203,7 @@ export declare function generateVideo<TAdapter extends VideoAdapter<string, any,
|
|
|
203
203
|
* }
|
|
204
204
|
* ```
|
|
205
205
|
*/
|
|
206
|
-
export declare function getVideoJobStatus<TAdapter extends VideoAdapter<string, any, any, any>>(options: {
|
|
206
|
+
export declare function getVideoJobStatus<TAdapter extends VideoAdapter<string, any, any, any, any, any>>(options: {
|
|
207
207
|
adapter: TAdapter & {
|
|
208
208
|
kind: typeof kind;
|
|
209
209
|
};
|
|
@@ -218,6 +218,6 @@ export declare function getVideoJobStatus<TAdapter extends VideoAdapter<string,
|
|
|
218
218
|
/**
|
|
219
219
|
* Create typed options for the generateVideo() function without executing.
|
|
220
220
|
*/
|
|
221
|
-
export declare function createVideoOptions<TAdapter extends VideoAdapter<string, any, any, any>, TStream extends boolean = false>(options: VideoCreateOptions<TAdapter, TStream>): VideoCreateOptions<TAdapter, TStream>;
|
|
221
|
+
export declare function createVideoOptions<TAdapter extends VideoAdapter<string, any, any, any, any, any>, TStream extends boolean = false>(options: VideoCreateOptions<TAdapter, TStream>): VideoCreateOptions<TAdapter, TStream>;
|
|
222
222
|
export type { VideoAdapter, VideoAdapterConfig, AnyVideoAdapter, } from './adapter.js';
|
|
223
223
|
export { BaseVideoAdapter } from './adapter.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../../src/activities/generateVideo/index.ts"],"sourcesContent":["/**\n * Video Activity (Experimental)\n *\n * Generates videos from text prompts using a jobs/polling architecture.\n * This is a self-contained module with implementation, types, and JSDoc.\n *\n * @experimental Video generation is an experimental feature and may change.\n */\n\nimport { aiEventClient } from '@tanstack/ai-event-client'\nimport { toRunErrorPayload } from '../error-payload'\nimport { resolveDebugOption } from '../../logger/resolve'\nimport {\n createGenerationContext,\n runGenerationAbort,\n runGenerationError,\n runGenerationFinish,\n runGenerationStart,\n runGenerationUsage,\n} from '../middleware'\nimport type { InternalLogger } from '../../logger/internal-logger'\nimport type { DebugOption } from '../../logger/types'\nimport type { GenerationMiddleware } from '../middleware'\nimport type { VideoAdapter } from './adapter'\nimport type {\n MediaPrompt,\n MediaPromptFor,\n StreamChunk,\n TokenUsage,\n VideoJobResult,\n VideoStatusResult,\n VideoUrlResult,\n} from '../../types'\n\n// ===========================\n// Activity Kind\n// ===========================\n\n/** The adapter kind this activity handles */\nexport const kind = 'video' as const\n\n// ===========================\n// Type Extraction Helpers\n// ===========================\n\n/**\n * Extract provider options from a VideoAdapter via ~types.\n */\nexport type VideoProviderOptions<TAdapter> =\n TAdapter extends VideoAdapter<any, any, any, any>\n ? TAdapter['~types']['providerOptions']\n : object\n\n/**\n * Extract the size type for a VideoAdapter's model via ~types.\n */\nexport type VideoSizeForAdapter<TAdapter> =\n TAdapter extends VideoAdapter<infer TModel, any, any, infer TSizeMap>\n ? TModel extends keyof TSizeMap\n ? TSizeMap[TModel]\n : string\n : string\n\n/**\n * Extract the prompt type a model accepts from a VideoAdapter via ~types.\n * Mirrors `ImagePromptForModel`: models in the adapter's input-modality map\n * get a `prompt` narrowed to text + their supported part types; adapters\n * without a map fall back to the full MediaPrompt.\n */\nexport type VideoPromptForAdapter<TAdapter> =\n TAdapter extends VideoAdapter<infer TModel, any, any, any, infer ModsByName>\n ? string extends keyof ModsByName\n ? MediaPrompt\n : TModel extends keyof ModsByName\n ? MediaPromptFor<ModsByName[TModel][number]>\n : MediaPrompt\n : MediaPrompt\n\n/**\n * Extract the duration type for a VideoAdapter's model via ~types.\n * Mirrors `VideoSizeForAdapter`. Falls back to `number` for adapters that\n * haven't declared per-model duration constraints.\n */\nexport type VideoDurationForAdapter<TAdapter> =\n TAdapter extends VideoAdapter<\n infer TModel,\n any,\n any,\n any,\n any,\n infer TDurationMap\n >\n ? TModel extends keyof TDurationMap\n ? TDurationMap[TModel]\n : number\n : number\n\n// ===========================\n// Activity Options Types\n\nfunction createId(prefix: string): string {\n return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`\n}\n// ===========================\n\n/**\n * Base options shared by all video activity operations.\n * The model is extracted from the adapter's model property.\n */\ninterface VideoActivityBaseOptions<\n TAdapter extends VideoAdapter<string, any, any, any>,\n> {\n /** The video adapter to use (must be created with a model) */\n adapter: TAdapter & { kind: typeof kind }\n}\n\n/**\n * Options for creating a new video generation job.\n * The model is extracted from the adapter's model property.\n *\n * @template TAdapter - The video adapter type\n * @template TStream - Whether to stream the output\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport type VideoCreateOptions<\n TAdapter extends VideoAdapter<string, any, any, any>,\n TStream extends boolean = false,\n> = VideoActivityBaseOptions<TAdapter> & {\n /** Request type - create a new job (default if not specified) */\n request?: 'create'\n /**\n * Description of the desired video. Either a plain string, or — for models\n * that support image-conditioned generation — an ordered array of content\n * parts interleaving text with image inputs. Image parts may carry\n * `metadata.role` (`'start_frame' | 'end_frame' | 'reference' |\n * 'character'`) to disambiguate intent; positional fallback otherwise. The\n * accepted part types are narrowed per model via the adapter's\n * input-modality map.\n */\n prompt: VideoPromptForAdapter<TAdapter>\n /** Video size — format depends on the provider (e.g., \"16:9\", \"1280x720\") */\n size?: VideoSizeForAdapter<TAdapter>\n /**\n * Video duration in seconds. Adapters that declare a per-model duration\n * map narrow this to the model's valid union (e.g. `4 | 6 | 8` for Veo 3).\n * Pass `adapter.snapDuration(seconds)` to coerce raw seconds to a valid\n * value.\n */\n duration?: VideoDurationForAdapter<TAdapter>\n /**\n * Whether to stream the video generation lifecycle.\n * When true, returns an AsyncIterable<StreamChunk> that handles the full\n * job lifecycle: create job, poll for status, yield updates, and yield final result.\n * When false or not provided, returns a Promise<VideoJobResult>.\n *\n * @default false\n */\n stream?: TStream\n /** Polling interval in milliseconds (stream mode only). @default 2000 */\n pollingInterval?: number\n /** Maximum time to wait before timing out in milliseconds (stream mode only). @default 600000 */\n maxDuration?: number\n /** Custom run ID (stream mode only) */\n runId?: string\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. In streaming mode the\n * span covers the full create→poll→complete lifecycle; in non-streaming mode\n * it covers job submission. An abandoned stream fires `onAbort`.\n */\n middleware?: Array<GenerationMiddleware>\n} & ({} extends VideoProviderOptions<TAdapter>\n ? {\n /** Provider-specific options for video generation */ modelOptions?: VideoProviderOptions<TAdapter>\n }\n : {\n /** Provider-specific options for video generation */ modelOptions: VideoProviderOptions<TAdapter>\n })\n\n/**\n * Options for polling the status of a video generation job.\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport interface VideoStatusOptions<\n TAdapter extends VideoAdapter<string, any, any, any>,\n> extends VideoActivityBaseOptions<TAdapter> {\n /** Request type - get job status */\n request: 'status'\n /** The job ID to check status for */\n jobId: string\n}\n\n/**\n * Options for getting the URL of a completed video.\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport interface VideoUrlOptions<\n TAdapter extends VideoAdapter<string, any, any, any>,\n> extends VideoActivityBaseOptions<TAdapter> {\n /** Request type - get video URL */\n request: 'url'\n /** The job ID to get URL for */\n jobId: string\n}\n\n/**\n * Union type for all video activity options.\n * Discriminated by the `request` field.\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport type VideoActivityOptions<\n TAdapter extends VideoAdapter<string, any, any, any>,\n TRequest extends 'create' | 'status' | 'url' = 'create',\n TStream extends boolean = false,\n> = TRequest extends 'status'\n ? VideoStatusOptions<TAdapter>\n : TRequest extends 'url'\n ? VideoUrlOptions<TAdapter>\n : VideoCreateOptions<TAdapter, TStream>\n\n// ===========================\n// Activity Result Types\n// ===========================\n\n/**\n * Result type for the video activity, based on request type and streaming.\n * - If stream is true (create request): AsyncIterable<StreamChunk>\n * - Otherwise: Promise<VideoJobResult | VideoStatusResult | VideoUrlResult>\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport type VideoActivityResult<\n TRequest extends 'create' | 'status' | 'url' = 'create',\n TStream extends boolean = false,\n> = TRequest extends 'status'\n ? Promise<VideoStatusResult>\n : TRequest extends 'url'\n ? Promise<VideoUrlResult>\n : TStream extends true\n ? AsyncIterable<StreamChunk>\n : Promise<VideoJobResult>\n\n// ===========================\n// Activity Implementation\n// ===========================\n\n/**\n * Generate video - creates a video generation job from a text prompt.\n *\n * Uses AI video generation models to create videos based on natural language descriptions.\n * Unlike image generation, video generation is asynchronous and requires polling for completion.\n *\n * When `stream: true` is passed, handles the full job lifecycle automatically:\n * create job → poll for status → stream updates → yield final result.\n *\n * @experimental Video generation is an experimental feature and may change.\n *\n * @example Create a video generation job\n * ```ts\n * import { generateVideo } from '@tanstack/ai'\n * import { openaiVideo } from '@tanstack/ai-openai'\n *\n * // Start a video generation job\n * const { jobId } = await generateVideo({\n * adapter: openaiVideo('sora-2'),\n * prompt: 'A cat chasing a dog in a sunny park'\n * })\n *\n * console.log('Job started:', jobId)\n * ```\n *\n * @example Stream the full video generation lifecycle\n * ```ts\n * import { generateVideo, toServerSentEventsResponse } from '@tanstack/ai'\n * import { openaiVideo } from '@tanstack/ai-openai'\n *\n * const stream = generateVideo({\n * adapter: openaiVideo('sora-2'),\n * prompt: 'A cat chasing a dog in a sunny park',\n * stream: true,\n * pollingInterval: 3000,\n * })\n *\n * return toServerSentEventsResponse(stream)\n * ```\n */\nexport function generateVideo<\n TAdapter extends VideoAdapter<string, any, any, any>,\n TStream extends boolean = false,\n>(\n options: VideoCreateOptions<TAdapter, TStream>,\n): VideoActivityResult<'create', TStream> {\n if (options.stream) {\n return runStreamingVideoGeneration(\n options as VideoCreateOptions<TAdapter, true>,\n ) as VideoActivityResult<'create', TStream>\n }\n\n return runCreateVideoJob(options) as VideoActivityResult<'create', TStream>\n}\n\n/**\n * Internal implementation of non-streaming video job creation.\n */\nasync function runCreateVideoJob<\n TAdapter extends VideoAdapter<string, any, any, any>,\n>(options: VideoCreateOptions<TAdapter, boolean>): Promise<VideoJobResult> {\n const { adapter, prompt, size, duration, modelOptions, middleware } = options\n const model = adapter.model\n const requestId = createId('video')\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: 'video',\n provider: adapter.name,\n model,\n modelOptions,\n createId,\n })\n\n await runGenerationStart(middleware, mwCtx)\n\n logger.request(`activity=generateVideo provider=${providerName}`, {\n provider: providerName,\n model,\n })\n\n try {\n const result = await adapter.createVideoJob({\n model,\n prompt,\n size,\n duration,\n modelOptions,\n logger,\n })\n logger.output(`activity=generateVideo jobId=${result.jobId}`, {\n jobId: result.jobId,\n model: result.model,\n })\n // Non-streaming create only submits the job; usage isn't known until the\n // job completes via polling, so the span covers submission only.\n await runGenerationFinish(middleware, mwCtx, {\n duration: Date.now() - startTime,\n })\n return result\n } catch (error) {\n await runGenerationError(middleware, mwCtx, {\n error,\n duration: Date.now() - startTime,\n })\n logger.errors('generateVideo activity failed', {\n error,\n source: 'generateVideo',\n })\n throw error\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\n/**\n * Internal streaming implementation for video generation.\n * Handles the full job lifecycle: create job → poll for status → stream updates → yield final result.\n */\nasync function* runStreamingVideoGeneration<\n TAdapter extends VideoAdapter<string, any, any, any>,\n>(options: VideoCreateOptions<TAdapter, true>): AsyncIterable<StreamChunk> {\n const { adapter, prompt, size, duration, modelOptions, middleware } = options\n const model = adapter.model\n const runId = options.runId ?? createId('run')\n const requestId = createId('video')\n const obsStartTime = Date.now()\n const pollingInterval = options.pollingInterval ?? 2000\n const maxDuration = options.maxDuration ?? 600_000\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 threadId = createId('thread')\n\n yield {\n type: 'RUN_STARTED',\n runId,\n threadId,\n timestamp: Date.now(),\n } as StreamChunk\n\n const mwCtx = createGenerationContext({\n requestId,\n activity: 'video',\n provider: adapter.name,\n model,\n modelOptions,\n createId,\n })\n\n await runGenerationStart(middleware, mwCtx)\n\n logger.request(\n `activity=generateVideo provider=${providerName} stream=true`,\n {\n provider: providerName,\n model,\n },\n )\n\n // Tracks whether a terminal observer event (finish/error) has already fired,\n // so the `finally` below can fire one on abandonment without double-firing.\n let settled = false\n try {\n // Create the video generation job\n const jobResult = await adapter.createVideoJob({\n model,\n prompt,\n size,\n duration,\n modelOptions,\n logger,\n })\n\n yield {\n type: 'CUSTOM',\n name: 'video:job:created',\n value: { jobId: jobResult.jobId },\n timestamp: Date.now(),\n } as StreamChunk\n\n // Poll for completion\n const startTime = Date.now()\n while (Date.now() - startTime < maxDuration) {\n await sleep(pollingInterval)\n\n const statusResult = await adapter.getVideoStatus(jobResult.jobId)\n\n yield {\n type: 'CUSTOM',\n name: 'video:status',\n value: {\n jobId: jobResult.jobId,\n status: statusResult.status,\n progress: statusResult.progress,\n error: statusResult.error,\n },\n timestamp: Date.now(),\n } as StreamChunk\n\n if (statusResult.status === 'completed') {\n const urlResult = await adapter.getVideoUrl(jobResult.jobId)\n\n logger.output(\n `activity=generateVideo jobId=${jobResult.jobId} status=completed`,\n {\n jobId: jobResult.jobId,\n url: urlResult.url,\n },\n )\n\n // Fire finish before yielding the terminal chunks: the generation has\n // succeeded, so a consumer that stops reading after `generation:result`\n // (without pulling `RUN_FINISHED`) must not trip the abandonment path in\n // `finally`, which would otherwise report a spurious cancellation.\n if (urlResult.usage)\n await runGenerationUsage(middleware, mwCtx, urlResult.usage)\n await runGenerationFinish(middleware, mwCtx, {\n duration: Date.now() - obsStartTime,\n usage: urlResult.usage,\n })\n settled = true\n\n yield {\n type: 'CUSTOM',\n name: 'generation:result',\n value: {\n jobId: jobResult.jobId,\n status: 'completed',\n url: urlResult.url,\n expiresAt: urlResult.expiresAt,\n ...(urlResult.usage ? { usage: urlResult.usage } : {}),\n },\n timestamp: Date.now(),\n } as StreamChunk\n\n yield {\n type: 'RUN_FINISHED',\n runId,\n threadId,\n finishReason: 'stop',\n timestamp: Date.now(),\n } as StreamChunk\n return\n }\n\n if (statusResult.status === 'failed') {\n throw new Error(statusResult.error || 'Video generation failed')\n }\n }\n\n throw new Error('Video generation timed out')\n } catch (error: unknown) {\n const payload = toRunErrorPayload(error, 'Video generation failed')\n // Mark settled before firing onError: if a user error-hook throws, the\n // `finally` below must still not double-fire onAbort over the same op\n // (which would mask the original error and end the span twice).\n settled = true\n await runGenerationError(middleware, mwCtx, {\n error,\n duration: Date.now() - obsStartTime,\n })\n logger.errors('generateVideo activity failed', {\n message: payload.message,\n code: payload.code,\n source: 'generateVideo',\n })\n yield {\n type: 'RUN_ERROR',\n runId,\n threadId,\n message: payload.message,\n code: payload.code,\n error: payload,\n timestamp: Date.now(),\n } as StreamChunk\n } finally {\n if (!settled) {\n // The consumer abandoned the stream (broke the `for await` loop or\n // disconnected) before completion, so the generator is being unwound at\n // a `yield` without reaching finish/error. Fire `onAbort` — a cancel, not\n // an error — so otelMiddleware ends its span instead of leaking it.\n await runGenerationAbort(middleware, mwCtx, {\n reason: 'Video generation stream abandoned before completion',\n duration: Date.now() - obsStartTime,\n })\n }\n }\n}\n\n/**\n * Get video job status - returns the current status, progress, and URL if available.\n *\n * This function combines status checking and URL retrieval. If the job is completed,\n * it will automatically fetch and include the video URL.\n *\n * @experimental Video generation is an experimental feature and may change.\n *\n * @example Check job status\n * ```ts\n * import { getVideoJobStatus } from '@tanstack/ai'\n * import { openaiVideo } from '@tanstack/ai-openai'\n *\n * const result = await getVideoJobStatus({\n * adapter: openaiVideo('sora-2'),\n * jobId: 'job-123'\n * })\n *\n * console.log('Status:', result.status)\n * console.log('Progress:', result.progress)\n * if (result.url) {\n * console.log('Video URL:', result.url)\n * }\n * ```\n */\nexport async function getVideoJobStatus<\n TAdapter extends VideoAdapter<string, any, any, any>,\n>(options: {\n adapter: TAdapter & { kind: typeof kind }\n jobId: string\n}): Promise<{\n status: 'pending' | 'processing' | 'completed' | 'failed'\n progress?: number\n url?: string\n error?: string\n usage?: TokenUsage\n}> {\n const { adapter, jobId } = options\n const requestId = createId('video-status')\n const startTime = Date.now()\n\n aiEventClient.emit('video:request:started', {\n requestId,\n provider: adapter.name,\n model: adapter.model,\n requestType: 'status',\n jobId,\n timestamp: startTime,\n })\n\n // Get status first\n const statusResult = await adapter.getVideoStatus(jobId)\n\n // If completed, also get the URL\n if (statusResult.status === 'completed') {\n try {\n const urlResult = await adapter.getVideoUrl(jobId)\n aiEventClient.emit('video:request:completed', {\n requestId,\n provider: adapter.name,\n model: adapter.model,\n requestType: 'status',\n jobId,\n status: statusResult.status,\n progress: statusResult.progress,\n url: urlResult.url,\n duration: Date.now() - startTime,\n timestamp: Date.now(),\n })\n if (urlResult.usage) {\n aiEventClient.emit('video:usage', {\n requestId,\n model: adapter.model,\n usage: urlResult.usage,\n timestamp: Date.now(),\n })\n }\n return {\n status: statusResult.status,\n progress: statusResult.progress,\n url: urlResult.url,\n ...(urlResult.usage ? { usage: urlResult.usage } : {}),\n }\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'Failed to get video URL'\n aiEventClient.emit('video:request:completed', {\n requestId,\n provider: adapter.name,\n model: adapter.model,\n requestType: 'status',\n jobId,\n status: 'failed',\n progress: statusResult.progress,\n error: errorMessage,\n duration: Date.now() - startTime,\n timestamp: Date.now(),\n })\n // Provider reported completed but result fetch failed — treat as failed\n return {\n status: 'failed' as const,\n progress: statusResult.progress,\n error: errorMessage,\n }\n }\n }\n\n aiEventClient.emit('video:request:completed', {\n requestId,\n provider: adapter.name,\n model: adapter.model,\n requestType: 'status',\n jobId,\n status: statusResult.status,\n progress: statusResult.progress,\n error: statusResult.error,\n duration: Date.now() - startTime,\n timestamp: Date.now(),\n })\n\n // Return status for non-completed jobs\n return {\n status: statusResult.status,\n progress: statusResult.progress,\n error: statusResult.error,\n }\n}\n\n// ===========================\n// Options Factory\n// ===========================\n\n/**\n * Create typed options for the generateVideo() function without executing.\n */\nexport function createVideoOptions<\n TAdapter extends VideoAdapter<string, any, any, any>,\n TStream extends boolean = false,\n>(\n options: VideoCreateOptions<TAdapter, TStream>,\n): VideoCreateOptions<TAdapter, TStream> {\n return options\n}\n\n// Re-export adapter types\nexport type {\n VideoAdapter,\n VideoAdapterConfig,\n AnyVideoAdapter,\n} from './adapter'\nexport { BaseVideoAdapter } from './adapter'\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../src/activities/generateVideo/index.ts"],"sourcesContent":["/**\n * Video Activity (Experimental)\n *\n * Generates videos from text prompts using a jobs/polling architecture.\n * This is a self-contained module with implementation, types, and JSDoc.\n *\n * @experimental Video generation is an experimental feature and may change.\n */\n\nimport { aiEventClient } from '@tanstack/ai-event-client'\nimport { toRunErrorPayload } from '../error-payload'\nimport { resolveDebugOption } from '../../logger/resolve'\nimport {\n createGenerationContext,\n runGenerationAbort,\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 { VideoAdapter } from './adapter'\nimport type {\n MediaPrompt,\n MediaPromptFor,\n StreamChunk,\n TokenUsage,\n VideoJobResult,\n VideoStatusResult,\n VideoUrlResult,\n} from '../../types'\n\n// ===========================\n// Activity Kind\n// ===========================\n\n/** The adapter kind this activity handles */\nexport const kind = 'video' as const\n\n// ===========================\n// Type Extraction Helpers\n// ===========================\n\n/**\n * Extract provider options from a VideoAdapter via ~types.\n */\nexport type VideoProviderOptions<TAdapter> =\n TAdapter extends VideoAdapter<any, any, any, any, any, any>\n ? TAdapter['~types']['providerOptions']\n : object\n\n/**\n * Extract the size type for a VideoAdapter's model via ~types.\n */\nexport type VideoSizeForAdapter<TAdapter> =\n TAdapter extends VideoAdapter<\n infer TModel,\n any,\n any,\n infer TSizeMap,\n any,\n any\n >\n ? TModel extends keyof TSizeMap\n ? TSizeMap[TModel]\n : string\n : string\n\n/**\n * Extract the prompt type a model accepts from a VideoAdapter via ~types.\n * Mirrors `ImagePromptForModel`: models in the adapter's input-modality map\n * get a `prompt` narrowed to text + their supported part types; adapters\n * without a map fall back to the full MediaPrompt.\n */\nexport type VideoPromptForAdapter<TAdapter> =\n TAdapter extends VideoAdapter<\n infer TModel,\n any,\n any,\n any,\n infer ModsByName,\n any\n >\n ? string extends keyof ModsByName\n ? MediaPrompt\n : TModel extends keyof ModsByName\n ? MediaPromptFor<ModsByName[TModel][number]>\n : MediaPrompt\n : MediaPrompt\n\n/**\n * Extract the duration type for a VideoAdapter's model via ~types.\n * Mirrors `VideoSizeForAdapter`. Falls back to `number` for adapters that\n * haven't declared per-model duration constraints.\n */\nexport type VideoDurationForAdapter<TAdapter> =\n TAdapter extends VideoAdapter<\n infer TModel,\n any,\n any,\n any,\n any,\n infer TDurationMap\n >\n ? TModel extends keyof TDurationMap\n ? TDurationMap[TModel]\n : number\n : number\n\n// ===========================\n// Activity Options Types\n\nfunction createId(prefix: string): string {\n return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`\n}\n// ===========================\n\n/**\n * Base options shared by all video activity operations.\n * The model is extracted from the adapter's model property.\n */\ninterface VideoActivityBaseOptions<\n TAdapter extends VideoAdapter<string, any, any, any, any, any>,\n> {\n /** The video adapter to use (must be created with a model) */\n adapter: TAdapter & { kind: typeof kind }\n}\n\n/**\n * Options for creating a new video generation job.\n * The model is extracted from the adapter's model property.\n *\n * @template TAdapter - The video adapter type\n * @template TStream - Whether to stream the output\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport type VideoCreateOptions<\n TAdapter extends VideoAdapter<string, any, any, any, any, any>,\n TStream extends boolean = false,\n> = VideoActivityBaseOptions<TAdapter> & {\n /** Request type - create a new job (default if not specified) */\n request?: 'create'\n /**\n * Description of the desired video. Either a plain string, or — for models\n * that support image-conditioned generation — an ordered array of content\n * parts interleaving text with image inputs. Image parts may carry\n * `metadata.role` (`'start_frame' | 'end_frame' | 'reference' |\n * 'character'`) to disambiguate intent; positional fallback otherwise. The\n * accepted part types are narrowed per model via the adapter's\n * input-modality map.\n */\n prompt: VideoPromptForAdapter<TAdapter>\n /** Video size — format depends on the provider (e.g., \"16:9\", \"1280x720\") */\n size?: VideoSizeForAdapter<TAdapter>\n /**\n * Video duration in seconds. Adapters that declare a per-model duration\n * map narrow this to the model's valid union (e.g. `4 | 6 | 8` for Veo 3).\n * Pass `adapter.snapDuration(seconds)` to coerce raw seconds to a valid\n * value.\n */\n duration?: VideoDurationForAdapter<TAdapter>\n /**\n * Whether to stream the video generation lifecycle.\n * When true, returns an AsyncIterable<StreamChunk> that handles the full\n * job lifecycle: create job, poll for status, yield updates, and yield final result.\n * When false or not provided, returns a Promise<VideoJobResult>.\n *\n * @default false\n */\n stream?: TStream\n /** Polling interval in milliseconds (stream mode only). @default 2000 */\n pollingInterval?: number\n /** Maximum time to wait before timing out in milliseconds (stream mode only). @default 600000 */\n maxDuration?: number\n /** Custom run ID (stream mode only) */\n runId?: string\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. In streaming mode the\n * span covers the full create→poll→complete lifecycle; in non-streaming mode\n * it covers job submission. An abandoned stream fires `onAbort`.\n */\n middleware?: Array<GenerationMiddleware>\n} & ({} extends VideoProviderOptions<TAdapter>\n ? {\n /** Provider-specific options for video generation */ modelOptions?: VideoProviderOptions<TAdapter>\n }\n : {\n /** Provider-specific options for video generation */ modelOptions: VideoProviderOptions<TAdapter>\n })\n\n/**\n * Options for polling the status of a video generation job.\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport interface VideoStatusOptions<\n TAdapter extends VideoAdapter<string, any, any, any, any, any>,\n> extends VideoActivityBaseOptions<TAdapter> {\n /** Request type - get job status */\n request: 'status'\n /** The job ID to check status for */\n jobId: string\n}\n\n/**\n * Options for getting the URL of a completed video.\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport interface VideoUrlOptions<\n TAdapter extends VideoAdapter<string, any, any, any, any, any>,\n> extends VideoActivityBaseOptions<TAdapter> {\n /** Request type - get video URL */\n request: 'url'\n /** The job ID to get URL for */\n jobId: string\n}\n\n/**\n * Union type for all video activity options.\n * Discriminated by the `request` field.\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport type VideoActivityOptions<\n TAdapter extends VideoAdapter<string, any, any, any, any, any>,\n TRequest extends 'create' | 'status' | 'url' = 'create',\n TStream extends boolean = false,\n> = TRequest extends 'status'\n ? VideoStatusOptions<TAdapter>\n : TRequest extends 'url'\n ? VideoUrlOptions<TAdapter>\n : VideoCreateOptions<TAdapter, TStream>\n\n// ===========================\n// Activity Result Types\n// ===========================\n\n/**\n * Result type for the video activity, based on request type and streaming.\n * - If stream is true (create request): AsyncIterable<StreamChunk>\n * - Otherwise: Promise<VideoJobResult | VideoStatusResult | VideoUrlResult>\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport type VideoActivityResult<\n TRequest extends 'create' | 'status' | 'url' = 'create',\n TStream extends boolean = false,\n> = TRequest extends 'status'\n ? Promise<VideoStatusResult>\n : TRequest extends 'url'\n ? Promise<VideoUrlResult>\n : TStream extends true\n ? AsyncIterable<StreamChunk>\n : Promise<VideoJobResult>\n\n// ===========================\n// Activity Implementation\n// ===========================\n\n/**\n * Generate video - creates a video generation job from a text prompt.\n *\n * Uses AI video generation models to create videos based on natural language descriptions.\n * Unlike image generation, video generation is asynchronous and requires polling for completion.\n *\n * When `stream: true` is passed, handles the full job lifecycle automatically:\n * create job → poll for status → stream updates → yield final result.\n *\n * @experimental Video generation is an experimental feature and may change.\n *\n * @example Create a video generation job\n * ```ts\n * import { generateVideo } from '@tanstack/ai'\n * import { openaiVideo } from '@tanstack/ai-openai'\n *\n * // Start a video generation job\n * const { jobId } = await generateVideo({\n * adapter: openaiVideo('sora-2'),\n * prompt: 'A cat chasing a dog in a sunny park'\n * })\n *\n * console.log('Job started:', jobId)\n * ```\n *\n * @example Stream the full video generation lifecycle\n * ```ts\n * import { generateVideo, toServerSentEventsResponse } from '@tanstack/ai'\n * import { openaiVideo } from '@tanstack/ai-openai'\n *\n * const stream = generateVideo({\n * adapter: openaiVideo('sora-2'),\n * prompt: 'A cat chasing a dog in a sunny park',\n * stream: true,\n * pollingInterval: 3000,\n * })\n *\n * return toServerSentEventsResponse(stream)\n * ```\n */\nexport function generateVideo<\n TAdapter extends VideoAdapter<string, any, any, any, any, any>,\n TStream extends boolean = false,\n>(\n options: VideoCreateOptions<TAdapter, TStream>,\n): VideoActivityResult<'create', TStream> {\n if (options.stream) {\n return runStreamingVideoGeneration(\n options as VideoCreateOptions<TAdapter, true>,\n ) as VideoActivityResult<'create', TStream>\n }\n\n return runCreateVideoJob(options) as VideoActivityResult<'create', TStream>\n}\n\n/**\n * Internal implementation of non-streaming video job creation.\n */\nasync function runCreateVideoJob<\n TAdapter extends VideoAdapter<string, any, any, any, any, any>,\n>(options: VideoCreateOptions<TAdapter, boolean>): Promise<VideoJobResult> {\n const { adapter, prompt, size, duration, modelOptions, middleware } = options\n const model = adapter.model\n const requestId = createId('video')\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: 'video',\n provider: adapter.name,\n model,\n modelOptions,\n createId,\n })\n\n await runGenerationStart(middleware, mwCtx)\n\n logger.request(`activity=generateVideo provider=${providerName}`, {\n provider: providerName,\n model,\n })\n\n try {\n const result = await adapter.createVideoJob({\n model,\n prompt,\n size,\n duration,\n modelOptions,\n logger,\n })\n logger.output(`activity=generateVideo jobId=${result.jobId}`, {\n jobId: result.jobId,\n model: result.model,\n })\n // Non-streaming create only submits the job; usage isn't known until the\n // job completes via polling, so the span covers submission only.\n await runGenerationFinish(middleware, mwCtx, {\n duration: Date.now() - startTime,\n })\n return result\n } catch (error) {\n await runGenerationError(middleware, mwCtx, {\n error,\n duration: Date.now() - startTime,\n })\n logger.errors('generateVideo activity failed', {\n error,\n source: 'generateVideo',\n })\n throw error\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\n/**\n * Internal streaming implementation for video generation.\n * Handles the full job lifecycle: create job → poll for status → stream updates → yield final result.\n */\nasync function* runStreamingVideoGeneration<\n TAdapter extends VideoAdapter<string, any, any, any, any, any>,\n>(options: VideoCreateOptions<TAdapter, true>): AsyncIterable<StreamChunk> {\n const { adapter, prompt, size, duration, modelOptions, middleware } = options\n const model = adapter.model\n const runId = options.runId ?? createId('run')\n const requestId = createId('video')\n const obsStartTime = Date.now()\n const pollingInterval = options.pollingInterval ?? 2000\n const maxDuration = options.maxDuration ?? 600_000\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 threadId = createId('thread')\n\n yield {\n type: 'RUN_STARTED',\n runId,\n threadId,\n timestamp: Date.now(),\n } as StreamChunk\n\n const mwCtx = createGenerationContext({\n requestId,\n activity: 'video',\n provider: adapter.name,\n model,\n modelOptions,\n createId,\n })\n\n await runGenerationStart(middleware, mwCtx)\n\n logger.request(\n `activity=generateVideo provider=${providerName} stream=true`,\n {\n provider: providerName,\n model,\n },\n )\n\n // Tracks whether a terminal observer event (finish/error) has already fired,\n // so the `finally` below can fire one on abandonment without double-firing.\n let settled = false\n try {\n // Create the video generation job\n const jobResult = await adapter.createVideoJob({\n model,\n prompt,\n size,\n duration,\n modelOptions,\n logger,\n })\n\n yield {\n type: 'CUSTOM',\n name: 'video:job:created',\n value: { jobId: jobResult.jobId },\n timestamp: Date.now(),\n } as StreamChunk\n\n // Poll for completion\n const startTime = Date.now()\n while (Date.now() - startTime < maxDuration) {\n await sleep(pollingInterval)\n\n const statusResult = await adapter.getVideoStatus(jobResult.jobId)\n\n yield {\n type: 'CUSTOM',\n name: 'video:status',\n value: {\n jobId: jobResult.jobId,\n status: statusResult.status,\n progress: statusResult.progress,\n error: statusResult.error,\n },\n timestamp: Date.now(),\n } as StreamChunk\n\n if (statusResult.status === 'completed') {\n const urlResult = await adapter.getVideoUrl(jobResult.jobId)\n\n logger.output(\n `activity=generateVideo jobId=${jobResult.jobId} status=completed`,\n {\n jobId: jobResult.jobId,\n url: urlResult.url,\n },\n )\n\n // Fire finish before yielding the terminal chunks: the generation has\n // succeeded, so a consumer that stops reading after `generation:result`\n // (without pulling `RUN_FINISHED`) must not trip the abandonment path in\n // `finally`, which would otherwise report a spurious cancellation.\n if (urlResult.usage)\n await runGenerationUsage(middleware, mwCtx, urlResult.usage)\n await runGenerationFinish(middleware, mwCtx, {\n duration: Date.now() - obsStartTime,\n usage: urlResult.usage,\n })\n settled = true\n\n yield {\n type: 'CUSTOM',\n name: 'generation:result',\n value: {\n jobId: jobResult.jobId,\n status: 'completed',\n url: urlResult.url,\n expiresAt: urlResult.expiresAt,\n ...(urlResult.usage ? { usage: urlResult.usage } : {}),\n },\n timestamp: Date.now(),\n } as StreamChunk\n\n yield {\n type: 'RUN_FINISHED',\n runId,\n threadId,\n finishReason: 'stop',\n timestamp: Date.now(),\n } as StreamChunk\n return\n }\n\n if (statusResult.status === 'failed') {\n throw new Error(statusResult.error || 'Video generation failed')\n }\n }\n\n throw new Error('Video generation timed out')\n } catch (error: unknown) {\n const payload = toRunErrorPayload(error, 'Video generation failed')\n // Mark settled before firing onError: if a user error-hook throws, the\n // `finally` below must still not double-fire onAbort over the same op\n // (which would mask the original error and end the span twice).\n settled = true\n await runGenerationError(middleware, mwCtx, {\n error,\n duration: Date.now() - obsStartTime,\n })\n logger.errors('generateVideo activity failed', {\n message: payload.message,\n code: payload.code,\n source: 'generateVideo',\n })\n yield {\n type: 'RUN_ERROR',\n runId,\n threadId,\n message: payload.message,\n code: payload.code,\n error: payload,\n timestamp: Date.now(),\n } as StreamChunk\n } finally {\n if (!settled) {\n // The consumer abandoned the stream (broke the `for await` loop or\n // disconnected) before completion, so the generator is being unwound at\n // a `yield` without reaching finish/error. Fire `onAbort` — a cancel, not\n // an error — so otelMiddleware ends its span instead of leaking it.\n await runGenerationAbort(middleware, mwCtx, {\n reason: 'Video generation stream abandoned before completion',\n duration: Date.now() - obsStartTime,\n })\n }\n }\n}\n\n/**\n * Get video job status - returns the current status, progress, and URL if available.\n *\n * This function combines status checking and URL retrieval. If the job is completed,\n * it will automatically fetch and include the video URL.\n *\n * @experimental Video generation is an experimental feature and may change.\n *\n * @example Check job status\n * ```ts\n * import { getVideoJobStatus } from '@tanstack/ai'\n * import { openaiVideo } from '@tanstack/ai-openai'\n *\n * const result = await getVideoJobStatus({\n * adapter: openaiVideo('sora-2'),\n * jobId: 'job-123'\n * })\n *\n * console.log('Status:', result.status)\n * console.log('Progress:', result.progress)\n * if (result.url) {\n * console.log('Video URL:', result.url)\n * }\n * ```\n */\nexport async function getVideoJobStatus<\n TAdapter extends VideoAdapter<string, any, any, any, any, any>,\n>(options: {\n adapter: TAdapter & { kind: typeof kind }\n jobId: string\n}): Promise<{\n status: 'pending' | 'processing' | 'completed' | 'failed'\n progress?: number\n url?: string\n error?: string\n usage?: TokenUsage\n}> {\n const { adapter, jobId } = options\n const requestId = createId('video-status')\n const startTime = Date.now()\n\n aiEventClient.emit('video:request:started', {\n requestId,\n provider: adapter.name,\n model: adapter.model,\n requestType: 'status',\n jobId,\n timestamp: startTime,\n })\n\n // Get status first\n const statusResult = await adapter.getVideoStatus(jobId)\n\n // If completed, also get the URL\n if (statusResult.status === 'completed') {\n try {\n const urlResult = await adapter.getVideoUrl(jobId)\n aiEventClient.emit('video:request:completed', {\n requestId,\n provider: adapter.name,\n model: adapter.model,\n requestType: 'status',\n jobId,\n status: statusResult.status,\n progress: statusResult.progress,\n url: urlResult.url,\n duration: Date.now() - startTime,\n timestamp: Date.now(),\n })\n if (urlResult.usage) {\n aiEventClient.emit('video:usage', {\n requestId,\n model: adapter.model,\n usage: urlResult.usage,\n timestamp: Date.now(),\n })\n }\n return {\n status: statusResult.status,\n progress: statusResult.progress,\n url: urlResult.url,\n ...(urlResult.usage ? { usage: urlResult.usage } : {}),\n }\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'Failed to get video URL'\n aiEventClient.emit('video:request:completed', {\n requestId,\n provider: adapter.name,\n model: adapter.model,\n requestType: 'status',\n jobId,\n status: 'failed',\n progress: statusResult.progress,\n error: errorMessage,\n duration: Date.now() - startTime,\n timestamp: Date.now(),\n })\n // Provider reported completed but result fetch failed — treat as failed\n return {\n status: 'failed' as const,\n progress: statusResult.progress,\n error: errorMessage,\n }\n }\n }\n\n aiEventClient.emit('video:request:completed', {\n requestId,\n provider: adapter.name,\n model: adapter.model,\n requestType: 'status',\n jobId,\n status: statusResult.status,\n progress: statusResult.progress,\n error: statusResult.error,\n duration: Date.now() - startTime,\n timestamp: Date.now(),\n })\n\n // Return status for non-completed jobs\n return {\n status: statusResult.status,\n progress: statusResult.progress,\n error: statusResult.error,\n }\n}\n\n// ===========================\n// Options Factory\n// ===========================\n\n/**\n * Create typed options for the generateVideo() function without executing.\n */\nexport function createVideoOptions<\n TAdapter extends VideoAdapter<string, any, any, any, any, any>,\n TStream extends boolean = false,\n>(\n options: VideoCreateOptions<TAdapter, TStream>,\n): VideoCreateOptions<TAdapter, TStream> {\n return options\n}\n\n// Re-export adapter types\nexport type {\n VideoAdapter,\n VideoAdapterConfig,\n AnyVideoAdapter,\n} from './adapter'\nexport { BaseVideoAdapter } from './adapter'\n"],"names":[],"mappings":"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"}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -30,8 +30,8 @@ export type { ResolvedMediaPrompt } from './utilities/media-prompt.js';
|
|
|
30
30
|
export type { SystemPrompt, NormalizedSystemPrompt } from './system-prompts.js';
|
|
31
31
|
export { normalizeSystemPrompts } from './system-prompts.js';
|
|
32
32
|
export { detectImageMimeType } from './utils.js';
|
|
33
|
-
export { realtimeToken } from './realtime/index.js';
|
|
34
|
-
export type { RealtimeToken, RealtimeTokenAdapter, RealtimeTokenOptions, RealtimeSessionConfig, VADConfig, RealtimeMessage, RealtimeMessagePart, RealtimeTextPart, RealtimeAudioPart, RealtimeToolCallPart, RealtimeToolResultPart, RealtimeImagePart, RealtimeStatus, RealtimeMode, AudioVisualization, RealtimeEvent, RealtimeEventPayloads, RealtimeEventHandler, RealtimeErrorCode, RealtimeError, RealtimeAdapter, RealtimeConnection, } from './realtime/index.js';
|
|
33
|
+
export { realtimeToken, createRealtimeEventEmitter } from './realtime/index.js';
|
|
34
|
+
export type { RealtimeToken, RealtimeTokenAdapter, RealtimeTokenOptions, RealtimeSessionConfig, RealtimeToolConfig, VADConfig, RealtimeMessage, RealtimeMessagePart, RealtimeTextPart, RealtimeAudioPart, RealtimeToolCallPart, RealtimeToolResultPart, RealtimeImagePart, RealtimeStatus, RealtimeMode, AudioVisualization, RealtimeEvent, RealtimeEventPayloads, RealtimeEventHandler, RealtimeErrorCode, RealtimeError, RealtimeAdapter, RealtimeConnection, } from './realtime/index.js';
|
|
35
35
|
export { convertMessagesToModelMessages, generateMessageId, uiMessageToModelMessages, modelMessageToUIMessage, modelMessagesToUIMessages, normalizeToUIMessage, } from './activities/chat/messages.js';
|
|
36
36
|
export { StreamProcessor, createReplayStream, ImmediateStrategy, PunctuationStrategy, BatchStrategy, WordBoundaryStrategy, CompositeStrategy, PartialJSONParser, defaultJSONParser, parsePartialJSON, } from './activities/chat/stream/index.js';
|
|
37
37
|
export type { ChunkStrategy, ChunkRecording, InternalToolCallState, ProcessorResult, ProcessorState, StreamProcessorEvents, StreamProcessorOptions, ToolCallState, ToolResultState, JSONParser, } from './activities/chat/stream/index.js';
|