UNPKG

@tanstack/ai

Version:

Type-safe TypeScript AI SDK for streaming chat, tool calling, agents, structured outputs, and multimodal generation.

122 lines (121 loc) 3.69 kB
import { aiEventClient } from "@tanstack/ai-event-client"; import { streamGenerationResult } from "../stream-generation-result.js"; import { resolveDebugOption } from "../../logger/resolve.js"; import { resolveMediaPrompt } from "../../utilities/media-prompt.js"; import { createGenerationContext, runGenerationStart, runGenerationUsage, runGenerationFinish, runGenerationError } from "../middleware/run.js"; const kind = "image"; function createId(prefix) { return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`; } function generateImage(options) { if (options.stream) { return streamGenerationResult( () => runGenerateImage(options) ); } return runGenerateImage(options); } async function runGenerateImage(options) { const { adapter, stream: _stream, debug: _debug, middleware, ...rest } = options; const model = adapter.model; const requestId = createId("image"); const startTime = Date.now(); const logger = resolveDebugOption(options.debug); const mwCtx = createGenerationContext({ requestId, activity: "image", provider: adapter.name, model, modelOptions: rest.modelOptions, createId }); await runGenerationStart(middleware, mwCtx); const resolved = resolveMediaPrompt(rest.prompt); aiEventClient.emit("image:request:started", { requestId, provider: adapter.name, model, prompt: resolved.text, numberOfImages: rest.numberOfImages, size: rest.size, ...resolved.images.length > 0 && { imageInputCount: resolved.images.length }, ...resolved.videos.length > 0 && { videoInputCount: resolved.videos.length }, ...resolved.audios.length > 0 && { audioInputCount: resolved.audios.length }, modelOptions: rest.modelOptions, timestamp: startTime }); logger.request(`activity=generateImage provider=${adapter.name}`, { provider: adapter.name, model }); try { const result = await adapter.generateImages({ ...rest, model, logger }); const duration = Date.now() - startTime; aiEventClient.emit("image:request:completed", { requestId, provider: adapter.name, model, // GeneratedImage is a discriminated `{ url } | { b64Json }` union, but the // wire shape on the devtools event is a plain optional pair. Use // conditional spreads so the emitted record only sets the field actually // present — `exactOptionalPropertyTypes` rejects `field: undefined` // against `field?: string` targets. images: result.images.map((image) => ({ url: image.url, b64Json: image.b64Json })), duration, modelOptions: rest.modelOptions, timestamp: Date.now() }); if (result.usage) { aiEventClient.emit("image:usage", { requestId, model, usage: result.usage, modelOptions: rest.modelOptions, timestamp: Date.now() }); } logger.output(`activity=generateImage count=${result.images.length}`, { count: result.images.length }); if (result.usage) await runGenerationUsage(middleware, mwCtx, result.usage); await runGenerationFinish(middleware, mwCtx, { duration, usage: result.usage }); return result; } catch (error) { await runGenerationError(middleware, mwCtx, { error, duration: Date.now() - startTime }); logger.errors("generateImage activity failed", { error, source: "generateImage" }); throw error; } } function createImageOptions(options) { return options; } export { createImageOptions, generateImage, kind }; //# sourceMappingURL=index.js.map