ai
Version:
AI SDK by Vercel - The AI Toolkit for TypeScript and JavaScript
1 lines • 589 kB
Source Map (JSON)
{"version":3,"sources":["../core/index.ts","../core/data-stream/create-data-stream.ts","../core/util/prepare-response-headers.ts","../core/data-stream/create-data-stream-response.ts","../core/util/prepare-outgoing-http-headers.ts","../core/util/write-to-server-response.ts","../core/data-stream/pipe-data-stream-to-response.ts","../errors/invalid-argument-error.ts","../util/retry-with-exponential-backoff.ts","../util/retry-error.ts","../core/prompt/prepare-retries.ts","../core/telemetry/assemble-operation-name.ts","../core/telemetry/get-base-telemetry-attributes.ts","../core/telemetry/get-tracer.ts","../core/telemetry/noop-tracer.ts","../core/telemetry/record-span.ts","../core/telemetry/select-telemetry-attributes.ts","../core/embed/embed.ts","../core/util/split-array.ts","../core/embed/embed-many.ts","../errors/no-image-generated-error.ts","../core/generate-text/generated-file.ts","../core/util/detect-mimetype.ts","../core/generate-image/generate-image.ts","../core/generate-object/generate-object.ts","../errors/no-object-generated-error.ts","../util/download-error.ts","../util/download.ts","../core/prompt/data-content.ts","../core/prompt/invalid-data-content-error.ts","../core/prompt/invalid-message-role-error.ts","../core/prompt/split-data-url.ts","../core/prompt/convert-to-language-model-prompt.ts","../core/prompt/prepare-call-settings.ts","../core/prompt/standardize-prompt.ts","../core/prompt/attachments-to-parts.ts","../core/prompt/message-conversion-error.ts","../core/prompt/convert-to-core-messages.ts","../core/prompt/message.ts","../core/types/provider-metadata.ts","../core/types/json-value.ts","../core/prompt/content-part.ts","../core/prompt/tool-result-content.ts","../core/types/usage.ts","../core/generate-object/inject-json-instruction.ts","../core/generate-object/output-strategy.ts","../core/util/async-iterable-stream.ts","../core/generate-object/validate-object-generation-input.ts","../core/prompt/stringify-for-telemetry.ts","../core/generate-object/stream-object.ts","../util/delayed-promise.ts","../util/create-resolvable-promise.ts","../core/util/create-stitchable-stream.ts","../core/util/now.ts","../core/generate-text/generate-text.ts","../errors/no-output-specified-error.ts","../errors/tool-execution-error.ts","../core/prompt/prepare-tools-and-tool-choice.ts","../core/util/is-non-empty-object.ts","../core/util/split-on-last-whitespace.ts","../core/util/remove-text-after-last-whitespace.ts","../core/generate-text/parse-tool-call.ts","../errors/invalid-tool-arguments-error.ts","../errors/no-such-tool-error.ts","../errors/tool-call-repair-error.ts","../core/generate-text/reasoning-detail.ts","../core/generate-text/to-response-messages.ts","../core/generate-text/output.ts","../errors/index.ts","../errors/invalid-stream-part-error.ts","../errors/mcp-client-error.ts","../core/generate-text/smooth-stream.ts","../core/generate-text/stream-text.ts","../util/as-array.ts","../util/consume-stream.ts","../core/util/merge-streams.ts","../core/generate-text/run-tools-transformation.ts","../errors/no-speech-generated-error.ts","../core/generate-speech/generated-audio-file.ts","../core/generate-speech/generate-speech.ts","../errors/no-transcript-generated-error.ts","../core/transcribe/transcribe.ts","../core/util/merge-objects.ts","../core/middleware/default-settings-middleware.ts","../core/util/get-potential-start-index.ts","../core/middleware/extract-reasoning-middleware.ts","../core/middleware/simulate-streaming-middleware.ts","../core/middleware/wrap-language-model.ts","../core/prompt/append-client-message.ts","../core/prompt/append-response-messages.ts","../core/registry/custom-provider.ts","../core/registry/no-such-provider-error.ts","../core/registry/provider-registry.ts","../core/tool/mcp/mcp-client.ts","../core/tool/tool.ts","../core/tool/mcp/mcp-sse-transport.ts","../core/tool/mcp/json-rpc-message.ts","../core/tool/mcp/types.ts","../core/tool/mcp/mcp-transport.ts","../core/util/cosine-similarity.ts","../core/util/simulate-readable-stream.ts","../streams/assistant-response.ts","../streams/langchain-adapter.ts","../streams/stream-callbacks.ts","../streams/llamaindex-adapter.ts","../streams/stream-data.ts","../util/constants.ts"],"sourcesContent":["// re-exports:\nexport { createIdGenerator, generateId } from '@ai-sdk/provider-utils';\nexport type { IDGenerator } from '@ai-sdk/provider-utils';\nexport {\n formatAssistantStreamPart,\n formatDataStreamPart,\n jsonSchema,\n parseAssistantStreamPart,\n parseDataStreamPart,\n processDataStream,\n processTextStream,\n zodSchema,\n} from '@ai-sdk/ui-utils';\nexport type {\n AssistantMessage,\n AssistantStatus,\n Attachment,\n ChatRequest,\n ChatRequestOptions,\n CreateMessage,\n DataMessage,\n DataStreamPart,\n DeepPartial,\n IdGenerator,\n JSONValue,\n Message,\n UIMessage,\n RequestOptions,\n Schema,\n ToolInvocation,\n UseAssistantOptions,\n} from '@ai-sdk/ui-utils';\n\n// directory exports:\nexport * from './data-stream';\nexport * from './embed';\nexport * from './generate-image';\nexport * from './generate-object';\nexport * from './generate-text';\nexport * from './generate-speech';\nexport * from './transcribe';\nexport * from './middleware';\nexport * from './prompt';\nexport * from './registry';\nexport * from './tool';\nexport * from './types';\n\n// telemetry types:\nexport type { TelemetrySettings } from './telemetry/telemetry-settings';\n\n// util exports:\nexport { cosineSimilarity } from './util/cosine-similarity';\nexport { simulateReadableStream } from './util/simulate-readable-stream';\n","import { DataStreamString, formatDataStreamPart } from '@ai-sdk/ui-utils';\nimport { DataStreamWriter } from './data-stream-writer';\n\nexport function createDataStream({\n execute,\n onError = () => 'An error occurred.', // mask error messages for safety by default\n}: {\n execute: (dataStream: DataStreamWriter) => Promise<void> | void;\n onError?: (error: unknown) => string;\n}): ReadableStream<DataStreamString> {\n let controller!: ReadableStreamDefaultController<string>;\n\n const ongoingStreamPromises: Promise<void>[] = [];\n\n const stream = new ReadableStream({\n start(controllerArg) {\n controller = controllerArg;\n },\n });\n\n function safeEnqueue(data: DataStreamString) {\n try {\n controller.enqueue(data);\n } catch (error) {\n // suppress errors when the stream has been closed\n }\n }\n\n try {\n const result = execute({\n write(data: DataStreamString) {\n safeEnqueue(data);\n },\n writeData(data) {\n safeEnqueue(formatDataStreamPart('data', [data]));\n },\n writeMessageAnnotation(annotation) {\n safeEnqueue(formatDataStreamPart('message_annotations', [annotation]));\n },\n writeSource(source) {\n safeEnqueue(formatDataStreamPart('source', source));\n },\n merge(streamArg) {\n ongoingStreamPromises.push(\n (async () => {\n const reader = streamArg.getReader();\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n safeEnqueue(value);\n }\n })().catch(error => {\n safeEnqueue(formatDataStreamPart('error', onError(error)));\n }),\n );\n },\n onError,\n });\n\n if (result) {\n ongoingStreamPromises.push(\n result.catch(error => {\n safeEnqueue(formatDataStreamPart('error', onError(error)));\n }),\n );\n }\n } catch (error) {\n safeEnqueue(formatDataStreamPart('error', onError(error)));\n }\n\n // Wait until all ongoing streams are done. This approach enables merging\n // streams even after execute has returned, as long as there is still an\n // open merged stream. This is important to e.g. forward new streams and\n // from callbacks.\n const waitForStreams: Promise<void> = new Promise(async resolve => {\n while (ongoingStreamPromises.length > 0) {\n await ongoingStreamPromises.shift();\n }\n resolve();\n });\n\n waitForStreams.finally(() => {\n try {\n controller.close();\n } catch (error) {\n // suppress errors when the stream has been closed\n }\n });\n\n return stream;\n}\n","export function prepareResponseHeaders(\n headers: HeadersInit | undefined,\n {\n contentType,\n dataStreamVersion,\n }: { contentType: string; dataStreamVersion?: 'v1' | undefined },\n) {\n const responseHeaders = new Headers(headers ?? {});\n\n if (!responseHeaders.has('Content-Type')) {\n responseHeaders.set('Content-Type', contentType);\n }\n\n if (dataStreamVersion !== undefined) {\n responseHeaders.set('X-Vercel-AI-Data-Stream', dataStreamVersion);\n }\n\n return responseHeaders;\n}\n","import { prepareResponseHeaders } from '../util/prepare-response-headers';\nimport { createDataStream } from './create-data-stream';\nimport { DataStreamWriter } from './data-stream-writer';\n\nexport function createDataStreamResponse({\n status,\n statusText,\n headers,\n execute,\n onError,\n}: ResponseInit & {\n execute: (dataStream: DataStreamWriter) => Promise<void> | void;\n onError?: (error: unknown) => string;\n}): Response {\n return new Response(\n createDataStream({ execute, onError }).pipeThrough(new TextEncoderStream()),\n {\n status,\n statusText,\n headers: prepareResponseHeaders(headers, {\n contentType: 'text/plain; charset=utf-8',\n dataStreamVersion: 'v1',\n }),\n },\n );\n}\n","export function prepareOutgoingHttpHeaders(\n headers: HeadersInit | undefined,\n {\n contentType,\n dataStreamVersion,\n }: { contentType: string; dataStreamVersion?: 'v1' | undefined },\n) {\n const outgoingHeaders: Record<string, string | number | string[]> = {};\n\n if (headers != null) {\n for (const [key, value] of Object.entries(headers)) {\n outgoingHeaders[key] = value;\n }\n }\n\n if (outgoingHeaders['Content-Type'] == null) {\n outgoingHeaders['Content-Type'] = contentType;\n }\n\n if (dataStreamVersion !== undefined) {\n outgoingHeaders['X-Vercel-AI-Data-Stream'] = dataStreamVersion;\n }\n\n return outgoingHeaders;\n}\n","import { ServerResponse } from 'node:http';\n\n/**\n * Writes the content of a stream to a server response.\n */\nexport function writeToServerResponse({\n response,\n status,\n statusText,\n headers,\n stream,\n}: {\n response: ServerResponse;\n status?: number;\n statusText?: string;\n headers?: Record<string, string | number | string[]>;\n stream: ReadableStream<Uint8Array>;\n}): void {\n response.writeHead(status ?? 200, statusText, headers);\n\n const reader = stream.getReader();\n const read = async () => {\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n response.write(value);\n }\n } catch (error) {\n throw error;\n } finally {\n response.end();\n }\n };\n\n read();\n}\n","import { ServerResponse } from 'node:http';\nimport { prepareOutgoingHttpHeaders } from '../util/prepare-outgoing-http-headers';\nimport { writeToServerResponse } from '../util/write-to-server-response';\nimport { createDataStream } from './create-data-stream';\nimport { DataStreamWriter } from './data-stream-writer';\n\nexport function pipeDataStreamToResponse(\n response: ServerResponse,\n {\n status,\n statusText,\n headers,\n execute,\n onError,\n }: ResponseInit & {\n execute: (writer: DataStreamWriter) => Promise<void> | void;\n onError?: (error: unknown) => string;\n },\n): void {\n writeToServerResponse({\n response,\n status,\n statusText,\n headers: prepareOutgoingHttpHeaders(headers, {\n contentType: 'text/plain; charset=utf-8',\n dataStreamVersion: 'v1',\n }),\n stream: createDataStream({ execute, onError }).pipeThrough(\n new TextEncoderStream(),\n ),\n });\n}\n","import { AISDKError } from '@ai-sdk/provider';\n\nconst name = 'AI_InvalidArgumentError';\nconst marker = `vercel.ai.error.${name}`;\nconst symbol = Symbol.for(marker);\n\nexport class InvalidArgumentError extends AISDKError {\n private readonly [symbol] = true; // used in isInstance\n\n readonly parameter: string;\n readonly value: unknown;\n\n constructor({\n parameter,\n value,\n message,\n }: {\n parameter: string;\n value: unknown;\n message: string;\n }) {\n super({\n name,\n message: `Invalid argument for parameter ${parameter}: ${message}`,\n });\n\n this.parameter = parameter;\n this.value = value;\n }\n\n static isInstance(error: unknown): error is InvalidArgumentError {\n return AISDKError.hasMarker(error, marker);\n }\n}\n","import { APICallError } from '@ai-sdk/provider';\nimport { delay, getErrorMessage, isAbortError } from '@ai-sdk/provider-utils';\nimport { RetryError } from './retry-error';\n\nexport type RetryFunction = <OUTPUT>(\n fn: () => PromiseLike<OUTPUT>,\n) => PromiseLike<OUTPUT>;\n\n/**\nThe `retryWithExponentialBackoff` strategy retries a failed API call with an exponential backoff.\nYou can configure the maximum number of retries, the initial delay, and the backoff factor.\n */\nexport const retryWithExponentialBackoff =\n ({\n maxRetries = 2,\n initialDelayInMs = 2000,\n backoffFactor = 2,\n } = {}): RetryFunction =>\n async <OUTPUT>(f: () => PromiseLike<OUTPUT>) =>\n _retryWithExponentialBackoff(f, {\n maxRetries,\n delayInMs: initialDelayInMs,\n backoffFactor,\n });\n\nasync function _retryWithExponentialBackoff<OUTPUT>(\n f: () => PromiseLike<OUTPUT>,\n {\n maxRetries,\n delayInMs,\n backoffFactor,\n }: { maxRetries: number; delayInMs: number; backoffFactor: number },\n errors: unknown[] = [],\n): Promise<OUTPUT> {\n try {\n return await f();\n } catch (error) {\n if (isAbortError(error)) {\n throw error; // don't retry when the request was aborted\n }\n\n if (maxRetries === 0) {\n throw error; // don't wrap the error when retries are disabled\n }\n\n const errorMessage = getErrorMessage(error);\n const newErrors = [...errors, error];\n const tryNumber = newErrors.length;\n\n if (tryNumber > maxRetries) {\n throw new RetryError({\n message: `Failed after ${tryNumber} attempts. Last error: ${errorMessage}`,\n reason: 'maxRetriesExceeded',\n errors: newErrors,\n });\n }\n\n if (\n error instanceof Error &&\n APICallError.isInstance(error) &&\n error.isRetryable === true &&\n tryNumber <= maxRetries\n ) {\n await delay(delayInMs);\n return _retryWithExponentialBackoff(\n f,\n { maxRetries, delayInMs: backoffFactor * delayInMs, backoffFactor },\n newErrors,\n );\n }\n\n if (tryNumber === 1) {\n throw error; // don't wrap the error when a non-retryable error occurs on the first try\n }\n\n throw new RetryError({\n message: `Failed after ${tryNumber} attempts with non-retryable error: '${errorMessage}'`,\n reason: 'errorNotRetryable',\n errors: newErrors,\n });\n }\n}\n","import { AISDKError } from '@ai-sdk/provider';\n\nconst name = 'AI_RetryError';\nconst marker = `vercel.ai.error.${name}`;\nconst symbol = Symbol.for(marker);\n\nexport type RetryErrorReason =\n | 'maxRetriesExceeded'\n | 'errorNotRetryable'\n | 'abort';\n\nexport class RetryError extends AISDKError {\n private readonly [symbol] = true; // used in isInstance\n\n // note: property order determines debugging output\n readonly reason: RetryErrorReason;\n readonly lastError: unknown;\n readonly errors: Array<unknown>;\n\n constructor({\n message,\n reason,\n errors,\n }: {\n message: string;\n reason: RetryErrorReason;\n errors: Array<unknown>;\n }) {\n super({ name, message });\n\n this.reason = reason;\n this.errors = errors;\n\n // separate our last error to make debugging via log easier:\n this.lastError = errors[errors.length - 1];\n }\n\n static isInstance(error: unknown): error is RetryError {\n return AISDKError.hasMarker(error, marker);\n }\n}\n","import { InvalidArgumentError } from '../../errors/invalid-argument-error';\nimport {\n RetryFunction,\n retryWithExponentialBackoff,\n} from '../../util/retry-with-exponential-backoff';\n\n/**\n * Validate and prepare retries.\n */\nexport function prepareRetries({\n maxRetries,\n}: {\n maxRetries: number | undefined;\n}): {\n maxRetries: number;\n retry: RetryFunction;\n} {\n if (maxRetries != null) {\n if (!Number.isInteger(maxRetries)) {\n throw new InvalidArgumentError({\n parameter: 'maxRetries',\n value: maxRetries,\n message: 'maxRetries must be an integer',\n });\n }\n\n if (maxRetries < 0) {\n throw new InvalidArgumentError({\n parameter: 'maxRetries',\n value: maxRetries,\n message: 'maxRetries must be >= 0',\n });\n }\n }\n\n const maxRetriesResult = maxRetries ?? 2;\n\n return {\n maxRetries: maxRetriesResult,\n retry: retryWithExponentialBackoff({ maxRetries: maxRetriesResult }),\n };\n}\n","import { TelemetrySettings } from './telemetry-settings';\n\nexport function assembleOperationName({\n operationId,\n telemetry,\n}: {\n operationId: string;\n telemetry?: TelemetrySettings;\n}) {\n return {\n // standardized operation and resource name:\n 'operation.name': `${operationId}${\n telemetry?.functionId != null ? ` ${telemetry.functionId}` : ''\n }`,\n 'resource.name': telemetry?.functionId,\n\n // detailed, AI SDK specific data:\n 'ai.operationId': operationId,\n 'ai.telemetry.functionId': telemetry?.functionId,\n };\n}\n","import { Attributes } from '@opentelemetry/api';\nimport { CallSettings } from '../prompt/call-settings';\nimport { TelemetrySettings } from './telemetry-settings';\n\nexport function getBaseTelemetryAttributes({\n model,\n settings,\n telemetry,\n headers,\n}: {\n model: { modelId: string; provider: string };\n settings: Omit<CallSettings, 'abortSignal' | 'headers'>;\n telemetry: TelemetrySettings | undefined;\n headers: Record<string, string | undefined> | undefined;\n}): Attributes {\n return {\n 'ai.model.provider': model.provider,\n 'ai.model.id': model.modelId,\n\n // settings:\n ...Object.entries(settings).reduce((attributes, [key, value]) => {\n attributes[`ai.settings.${key}`] = value;\n return attributes;\n }, {} as Attributes),\n\n // add metadata as attributes:\n ...Object.entries(telemetry?.metadata ?? {}).reduce(\n (attributes, [key, value]) => {\n attributes[`ai.telemetry.metadata.${key}`] = value;\n return attributes;\n },\n {} as Attributes,\n ),\n\n // request headers\n ...Object.entries(headers ?? {}).reduce((attributes, [key, value]) => {\n if (value !== undefined) {\n attributes[`ai.request.headers.${key}`] = value;\n }\n return attributes;\n }, {} as Attributes),\n };\n}\n","import { Tracer, trace } from '@opentelemetry/api';\nimport { noopTracer } from './noop-tracer';\n\nexport function getTracer({\n isEnabled = false,\n tracer,\n}: {\n isEnabled?: boolean;\n tracer?: Tracer;\n} = {}): Tracer {\n if (!isEnabled) {\n return noopTracer;\n }\n\n if (tracer) {\n return tracer;\n }\n\n return trace.getTracer('ai');\n}\n","import { Span, SpanContext, Tracer } from '@opentelemetry/api';\n\n/**\n * Tracer implementation that does nothing (null object).\n */\nexport const noopTracer: Tracer = {\n startSpan(): Span {\n return noopSpan;\n },\n\n startActiveSpan<F extends (span: Span) => unknown>(\n name: unknown,\n arg1: unknown,\n arg2?: unknown,\n arg3?: F,\n ): ReturnType<any> {\n if (typeof arg1 === 'function') {\n return arg1(noopSpan);\n }\n if (typeof arg2 === 'function') {\n return arg2(noopSpan);\n }\n if (typeof arg3 === 'function') {\n return arg3(noopSpan);\n }\n },\n};\n\nconst noopSpan: Span = {\n spanContext() {\n return noopSpanContext;\n },\n setAttribute() {\n return this;\n },\n setAttributes() {\n return this;\n },\n addEvent() {\n return this;\n },\n addLink() {\n return this;\n },\n addLinks() {\n return this;\n },\n setStatus() {\n return this;\n },\n updateName() {\n return this;\n },\n end() {\n return this;\n },\n isRecording() {\n return false;\n },\n recordException() {\n return this;\n },\n};\n\nconst noopSpanContext: SpanContext = {\n traceId: '',\n spanId: '',\n traceFlags: 0,\n};\n","import { Attributes, Span, Tracer, SpanStatusCode } from '@opentelemetry/api';\n\nexport function recordSpan<T>({\n name,\n tracer,\n attributes,\n fn,\n endWhenDone = true,\n}: {\n name: string;\n tracer: Tracer;\n attributes: Attributes;\n fn: (span: Span) => Promise<T>;\n endWhenDone?: boolean;\n}) {\n return tracer.startActiveSpan(name, { attributes }, async span => {\n try {\n const result = await fn(span);\n\n if (endWhenDone) {\n span.end();\n }\n\n return result;\n } catch (error) {\n try {\n if (error instanceof Error) {\n span.recordException({\n name: error.name,\n message: error.message,\n stack: error.stack,\n });\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error.message,\n });\n } else {\n span.setStatus({ code: SpanStatusCode.ERROR });\n }\n } finally {\n // always stop the span when there is an error:\n span.end();\n }\n\n throw error;\n }\n });\n}\n","import type { Attributes, AttributeValue } from '@opentelemetry/api';\nimport type { TelemetrySettings } from './telemetry-settings';\n\nexport function selectTelemetryAttributes({\n telemetry,\n attributes,\n}: {\n telemetry?: TelemetrySettings;\n attributes: {\n [attributeKey: string]:\n | AttributeValue\n | { input: () => AttributeValue | undefined }\n | { output: () => AttributeValue | undefined }\n | undefined;\n };\n}): Attributes {\n // when telemetry is disabled, return an empty object to avoid serialization overhead:\n if (telemetry?.isEnabled !== true) {\n return {};\n }\n\n return Object.entries(attributes).reduce((attributes, [key, value]) => {\n if (value === undefined) {\n return attributes;\n }\n\n // input value, check if it should be recorded:\n if (\n typeof value === 'object' &&\n 'input' in value &&\n typeof value.input === 'function'\n ) {\n // default to true:\n if (telemetry?.recordInputs === false) {\n return attributes;\n }\n\n const result = value.input();\n\n return result === undefined\n ? attributes\n : { ...attributes, [key]: result };\n }\n\n // output value, check if it should be recorded:\n if (\n typeof value === 'object' &&\n 'output' in value &&\n typeof value.output === 'function'\n ) {\n // default to true:\n if (telemetry?.recordOutputs === false) {\n return attributes;\n }\n\n const result = value.output();\n\n return result === undefined\n ? attributes\n : { ...attributes, [key]: result };\n }\n\n // value is an attribute value already:\n return { ...attributes, [key]: value };\n }, {});\n}\n","import { prepareRetries } from '../prompt/prepare-retries';\nimport { assembleOperationName } from '../telemetry/assemble-operation-name';\nimport { getBaseTelemetryAttributes } from '../telemetry/get-base-telemetry-attributes';\nimport { getTracer } from '../telemetry/get-tracer';\nimport { recordSpan } from '../telemetry/record-span';\nimport { selectTelemetryAttributes } from '../telemetry/select-telemetry-attributes';\nimport { TelemetrySettings } from '../telemetry/telemetry-settings';\nimport { EmbeddingModel } from '../types';\nimport { EmbedResult } from './embed-result';\n\n/**\nEmbed a value using an embedding model. The type of the value is defined by the embedding model.\n\n@param model - The embedding model to use.\n@param value - The value that should be embedded.\n\n@param maxRetries - Maximum number of retries. Set to 0 to disable retries. Default: 2.\n@param abortSignal - An optional abort signal that can be used to cancel the call.\n@param headers - Additional HTTP headers to be sent with the request. Only applicable for HTTP-based providers.\n\n@returns A result object that contains the embedding, the value, and additional information.\n */\nexport async function embed<VALUE>({\n model,\n value,\n maxRetries: maxRetriesArg,\n abortSignal,\n headers,\n experimental_telemetry: telemetry,\n}: {\n /**\nThe embedding model to use.\n */\n model: EmbeddingModel<VALUE>;\n\n /**\nThe value that should be embedded.\n */\n value: VALUE;\n\n /**\nMaximum number of retries per embedding model call. Set to 0 to disable retries.\n\n@default 2\n */\n maxRetries?: number;\n\n /**\nAbort signal.\n */\n abortSignal?: AbortSignal;\n\n /**\nAdditional headers to include in the request.\nOnly applicable for HTTP-based providers.\n */\n headers?: Record<string, string>;\n\n /**\n * Optional telemetry configuration (experimental).\n */\n experimental_telemetry?: TelemetrySettings;\n}): Promise<EmbedResult<VALUE>> {\n const { maxRetries, retry } = prepareRetries({ maxRetries: maxRetriesArg });\n\n const baseTelemetryAttributes = getBaseTelemetryAttributes({\n model,\n telemetry,\n headers,\n settings: { maxRetries },\n });\n\n const tracer = getTracer(telemetry);\n\n return recordSpan({\n name: 'ai.embed',\n attributes: selectTelemetryAttributes({\n telemetry,\n attributes: {\n ...assembleOperationName({ operationId: 'ai.embed', telemetry }),\n ...baseTelemetryAttributes,\n 'ai.value': { input: () => JSON.stringify(value) },\n },\n }),\n tracer,\n fn: async span => {\n const { embedding, usage, rawResponse } = await retry(() =>\n // nested spans to align with the embedMany telemetry data:\n recordSpan({\n name: 'ai.embed.doEmbed',\n attributes: selectTelemetryAttributes({\n telemetry,\n attributes: {\n ...assembleOperationName({\n operationId: 'ai.embed.doEmbed',\n telemetry,\n }),\n ...baseTelemetryAttributes,\n // specific settings that only make sense on the outer level:\n 'ai.values': { input: () => [JSON.stringify(value)] },\n },\n }),\n tracer,\n fn: async doEmbedSpan => {\n const modelResponse = await model.doEmbed({\n values: [value],\n abortSignal,\n headers,\n });\n\n const embedding = modelResponse.embeddings[0];\n const usage = modelResponse.usage ?? { tokens: NaN };\n\n doEmbedSpan.setAttributes(\n selectTelemetryAttributes({\n telemetry,\n attributes: {\n 'ai.embeddings': {\n output: () =>\n modelResponse.embeddings.map(embedding =>\n JSON.stringify(embedding),\n ),\n },\n 'ai.usage.tokens': usage.tokens,\n },\n }),\n );\n\n return {\n embedding,\n usage,\n rawResponse: modelResponse.rawResponse,\n };\n },\n }),\n );\n\n span.setAttributes(\n selectTelemetryAttributes({\n telemetry,\n attributes: {\n 'ai.embedding': { output: () => JSON.stringify(embedding) },\n 'ai.usage.tokens': usage.tokens,\n },\n }),\n );\n\n return new DefaultEmbedResult({ value, embedding, usage, rawResponse });\n },\n });\n}\n\nclass DefaultEmbedResult<VALUE> implements EmbedResult<VALUE> {\n readonly value: EmbedResult<VALUE>['value'];\n readonly embedding: EmbedResult<VALUE>['embedding'];\n readonly usage: EmbedResult<VALUE>['usage'];\n readonly rawResponse: EmbedResult<VALUE>['rawResponse'];\n\n constructor(options: {\n value: EmbedResult<VALUE>['value'];\n embedding: EmbedResult<VALUE>['embedding'];\n usage: EmbedResult<VALUE>['usage'];\n rawResponse?: EmbedResult<VALUE>['rawResponse'];\n }) {\n this.value = options.value;\n this.embedding = options.embedding;\n this.usage = options.usage;\n this.rawResponse = options.rawResponse;\n }\n}\n","/**\n * Splits an array into chunks of a specified size.\n *\n * @template T - The type of elements in the array.\n * @param {T[]} array - The array to split.\n * @param {number} chunkSize - The size of each chunk.\n * @returns {T[][]} - A new array containing the chunks.\n */\nexport function splitArray<T>(array: T[], chunkSize: number): T[][] {\n if (chunkSize <= 0) {\n throw new Error('chunkSize must be greater than 0');\n }\n\n const result = [];\n for (let i = 0; i < array.length; i += chunkSize) {\n result.push(array.slice(i, i + chunkSize));\n }\n\n return result;\n}\n","import { prepareRetries } from '../prompt/prepare-retries';\nimport { assembleOperationName } from '../telemetry/assemble-operation-name';\nimport { getBaseTelemetryAttributes } from '../telemetry/get-base-telemetry-attributes';\nimport { getTracer } from '../telemetry/get-tracer';\nimport { recordSpan } from '../telemetry/record-span';\nimport { selectTelemetryAttributes } from '../telemetry/select-telemetry-attributes';\nimport { TelemetrySettings } from '../telemetry/telemetry-settings';\nimport { Embedding, EmbeddingModel } from '../types';\nimport { splitArray } from '../util/split-array';\nimport { EmbedManyResult } from './embed-many-result';\n\n/**\nEmbed several values using an embedding model. The type of the value is defined\nby the embedding model.\n\n`embedMany` automatically splits large requests into smaller chunks if the model\nhas a limit on how many embeddings can be generated in a single call.\n\n@param model - The embedding model to use.\n@param values - The values that should be embedded.\n\n@param maxRetries - Maximum number of retries. Set to 0 to disable retries. Default: 2.\n@param abortSignal - An optional abort signal that can be used to cancel the call.\n@param headers - Additional HTTP headers to be sent with the request. Only applicable for HTTP-based providers.\n\n@returns A result object that contains the embeddings, the value, and additional information.\n */\nexport async function embedMany<VALUE>({\n model,\n values,\n maxRetries: maxRetriesArg,\n abortSignal,\n headers,\n experimental_telemetry: telemetry,\n}: {\n /**\nThe embedding model to use.\n */\n model: EmbeddingModel<VALUE>;\n\n /**\nThe values that should be embedded.\n */\n values: Array<VALUE>;\n\n /**\nMaximum number of retries per embedding model call. Set to 0 to disable retries.\n\n@default 2\n */\n maxRetries?: number;\n\n /**\nAbort signal.\n */\n abortSignal?: AbortSignal;\n\n /**\nAdditional headers to include in the request.\nOnly applicable for HTTP-based providers.\n */\n headers?: Record<string, string>;\n\n /**\n * Optional telemetry configuration (experimental).\n */\n experimental_telemetry?: TelemetrySettings;\n}): Promise<EmbedManyResult<VALUE>> {\n const { maxRetries, retry } = prepareRetries({ maxRetries: maxRetriesArg });\n\n const baseTelemetryAttributes = getBaseTelemetryAttributes({\n model,\n telemetry,\n headers,\n settings: { maxRetries },\n });\n\n const tracer = getTracer(telemetry);\n\n return recordSpan({\n name: 'ai.embedMany',\n attributes: selectTelemetryAttributes({\n telemetry,\n attributes: {\n ...assembleOperationName({ operationId: 'ai.embedMany', telemetry }),\n ...baseTelemetryAttributes,\n // specific settings that only make sense on the outer level:\n 'ai.values': {\n input: () => values.map(value => JSON.stringify(value)),\n },\n },\n }),\n tracer,\n fn: async span => {\n const maxEmbeddingsPerCall = model.maxEmbeddingsPerCall;\n\n // the model has not specified limits on\n // how many embeddings can be generated in a single call\n if (maxEmbeddingsPerCall == null) {\n const { embeddings, usage } = await retry(() => {\n // nested spans to align with the embedMany telemetry data:\n return recordSpan({\n name: 'ai.embedMany.doEmbed',\n attributes: selectTelemetryAttributes({\n telemetry,\n attributes: {\n ...assembleOperationName({\n operationId: 'ai.embedMany.doEmbed',\n telemetry,\n }),\n ...baseTelemetryAttributes,\n // specific settings that only make sense on the outer level:\n 'ai.values': {\n input: () => values.map(value => JSON.stringify(value)),\n },\n },\n }),\n tracer,\n fn: async doEmbedSpan => {\n const modelResponse = await model.doEmbed({\n values,\n abortSignal,\n headers,\n });\n\n const embeddings = modelResponse.embeddings;\n const usage = modelResponse.usage ?? { tokens: NaN };\n\n doEmbedSpan.setAttributes(\n selectTelemetryAttributes({\n telemetry,\n attributes: {\n 'ai.embeddings': {\n output: () =>\n embeddings.map(embedding => JSON.stringify(embedding)),\n },\n 'ai.usage.tokens': usage.tokens,\n },\n }),\n );\n\n return { embeddings, usage };\n },\n });\n });\n\n span.setAttributes(\n selectTelemetryAttributes({\n telemetry,\n attributes: {\n 'ai.embeddings': {\n output: () =>\n embeddings.map(embedding => JSON.stringify(embedding)),\n },\n 'ai.usage.tokens': usage.tokens,\n },\n }),\n );\n\n return new DefaultEmbedManyResult({ values, embeddings, usage });\n }\n\n // split the values into chunks that are small enough for the model:\n const valueChunks = splitArray(values, maxEmbeddingsPerCall);\n\n // serially embed the chunks:\n const embeddings: Array<Embedding> = [];\n let tokens = 0;\n\n for (const chunk of valueChunks) {\n const { embeddings: responseEmbeddings, usage } = await retry(() => {\n // nested spans to align with the embedMany telemetry data:\n return recordSpan({\n name: 'ai.embedMany.doEmbed',\n attributes: selectTelemetryAttributes({\n telemetry,\n attributes: {\n ...assembleOperationName({\n operationId: 'ai.embedMany.doEmbed',\n telemetry,\n }),\n ...baseTelemetryAttributes,\n // specific settings that only make sense on the outer level:\n 'ai.values': {\n input: () => chunk.map(value => JSON.stringify(value)),\n },\n },\n }),\n tracer,\n fn: async doEmbedSpan => {\n const modelResponse = await model.doEmbed({\n values: chunk,\n abortSignal,\n headers,\n });\n\n const embeddings = modelResponse.embeddings;\n const usage = modelResponse.usage ?? { tokens: NaN };\n\n doEmbedSpan.setAttributes(\n selectTelemetryAttributes({\n telemetry,\n attributes: {\n 'ai.embeddings': {\n output: () =>\n embeddings.map(embedding => JSON.stringify(embedding)),\n },\n 'ai.usage.tokens': usage.tokens,\n },\n }),\n );\n\n return { embeddings, usage };\n },\n });\n });\n\n embeddings.push(...responseEmbeddings);\n tokens += usage.tokens;\n }\n\n span.setAttributes(\n selectTelemetryAttributes({\n telemetry,\n attributes: {\n 'ai.embeddings': {\n output: () =>\n embeddings.map(embedding => JSON.stringify(embedding)),\n },\n 'ai.usage.tokens': tokens,\n },\n }),\n );\n\n return new DefaultEmbedManyResult({\n values,\n embeddings,\n usage: { tokens },\n });\n },\n });\n}\n\nclass DefaultEmbedManyResult<VALUE> implements EmbedManyResult<VALUE> {\n readonly values: EmbedManyResult<VALUE>['values'];\n readonly embeddings: EmbedManyResult<VALUE>['embeddings'];\n readonly usage: EmbedManyResult<VALUE>['usage'];\n\n constructor(options: {\n values: EmbedManyResult<VALUE>['values'];\n embeddings: EmbedManyResult<VALUE>['embeddings'];\n usage: EmbedManyResult<VALUE>['usage'];\n }) {\n this.values = options.values;\n this.embeddings = options.embeddings;\n this.usage = options.usage;\n }\n}\n","import { AISDKError } from '@ai-sdk/provider';\nimport { ImageModelResponseMetadata } from '../core/types/image-model-response-metadata';\n\nconst name = 'AI_NoImageGeneratedError';\nconst marker = `vercel.ai.error.${name}`;\nconst symbol = Symbol.for(marker);\n\n/**\nThrown when no image could be generated. This can have multiple causes:\n\n- The model failed to generate a response.\n- The model generated a response that could not be parsed.\n */\nexport class NoImageGeneratedError extends AISDKError {\n private readonly [symbol] = true; // used in isInstance\n\n /**\nThe response metadata for each call.\n */\n readonly responses: Array<ImageModelResponseMetadata> | undefined;\n\n constructor({\n message = 'No image generated.',\n cause,\n responses,\n }: {\n message?: string;\n cause?: Error;\n responses?: Array<ImageModelResponseMetadata>;\n }) {\n super({ name, message, cause });\n\n this.responses = responses;\n }\n\n static isInstance(error: unknown): error is NoImageGeneratedError {\n return AISDKError.hasMarker(error, marker);\n }\n}\n","import {\n convertBase64ToUint8Array,\n convertUint8ArrayToBase64,\n} from '@ai-sdk/provider-utils';\n\n/**\n * A generated file.\n */\nexport interface GeneratedFile {\n /**\nFile as a base64 encoded string.\n */\n readonly base64: string;\n\n /**\nFile as a Uint8Array.\n */\n readonly uint8Array: Uint8Array;\n\n /**\nMIME type of the file\n */\n readonly mimeType: string;\n}\n\nexport class DefaultGeneratedFile implements GeneratedFile {\n private base64Data: string | undefined;\n private uint8ArrayData: Uint8Array | undefined;\n\n readonly mimeType: string;\n\n constructor({\n data,\n mimeType,\n }: {\n data: string | Uint8Array;\n mimeType: string;\n }) {\n const isUint8Array = data instanceof Uint8Array;\n this.base64Data = isUint8Array ? undefined : data;\n this.uint8ArrayData = isUint8Array ? data : undefined;\n this.mimeType = mimeType;\n }\n\n // lazy conversion with caching to avoid unnecessary conversion overhead:\n get base64() {\n if (this.base64Data == null) {\n this.base64Data = convertUint8ArrayToBase64(this.uint8ArrayData!);\n }\n return this.base64Data;\n }\n\n // lazy conversion with caching to avoid unnecessary conversion overhead:\n get uint8Array() {\n if (this.uint8ArrayData == null) {\n this.uint8ArrayData = convertBase64ToUint8Array(this.base64Data!);\n }\n return this.uint8ArrayData;\n }\n}\n\nexport class DefaultGeneratedFileWithType extends DefaultGeneratedFile {\n readonly type = 'file';\n\n constructor(options: { data: string | Uint8Array; mimeType: string }) {\n super(options);\n }\n}\n","import { convertBase64ToUint8Array } from '@ai-sdk/provider-utils';\n\nexport const imageMimeTypeSignatures = [\n {\n mimeType: 'image/gif' as const,\n bytesPrefix: [0x47, 0x49, 0x46],\n base64Prefix: 'R0lG',\n },\n {\n mimeType: 'image/png' as const,\n bytesPrefix: [0x89, 0x50, 0x4e, 0x47],\n base64Prefix: 'iVBORw',\n },\n {\n mimeType: 'image/jpeg' as const,\n bytesPrefix: [0xff, 0xd8],\n base64Prefix: '/9j/',\n },\n {\n mimeType: 'image/webp' as const,\n bytesPrefix: [0x52, 0x49, 0x46, 0x46],\n base64Prefix: 'UklGRg',\n },\n {\n mimeType: 'image/bmp' as const,\n bytesPrefix: [0x42, 0x4d],\n base64Prefix: 'Qk',\n },\n {\n mimeType: 'image/tiff' as const,\n bytesPrefix: [0x49, 0x49, 0x2a, 0x00],\n base64Prefix: 'SUkqAA',\n },\n {\n mimeType: 'image/tiff' as const,\n bytesPrefix: [0x4d, 0x4d, 0x00, 0x2a],\n base64Prefix: 'TU0AKg',\n },\n {\n mimeType: 'image/avif' as const,\n bytesPrefix: [\n 0x00, 0x00, 0x00, 0x20, 0x66, 0x74, 0x79, 0x70, 0x61, 0x76, 0x69, 0x66,\n ],\n base64Prefix: 'AAAAIGZ0eXBhdmlm',\n },\n {\n mimeType: 'image/heic' as const,\n bytesPrefix: [\n 0x00, 0x00, 0x00, 0x20, 0x66, 0x74, 0x79, 0x70, 0x68, 0x65, 0x69, 0x63,\n ],\n base64Prefix: 'AAAAIGZ0eXBoZWlj',\n },\n] as const;\n\nexport const audioMimeTypeSignatures = [\n {\n mimeType: 'audio/mpeg' as const,\n bytesPrefix: [0xff, 0xfb],\n base64Prefix: '//s=',\n },\n {\n mimeType: 'audio/wav' as const,\n bytesPrefix: [0x52, 0x49, 0x46, 0x46],\n base64Prefix: 'UklGR',\n },\n {\n mimeType: 'audio/ogg' as const,\n bytesPrefix: [0x4f, 0x67, 0x67, 0x53],\n base64Prefix: 'T2dnUw',\n },\n {\n mimeType: 'audio/flac' as const,\n bytesPrefix: [0x66, 0x4c, 0x61, 0x43],\n base64Prefix: 'ZkxhQw',\n },\n {\n mimeType: 'audio/aac' as const,\n bytesPrefix: [0x40, 0x15, 0x00, 0x00],\n base64Prefix: 'QBUA',\n },\n {\n mimeType: 'audio/mp4' as const,\n bytesPrefix: [0x66, 0x74, 0x79, 0x70],\n base64Prefix: 'ZnR5cA',\n },\n] as const;\n\nconst stripID3 = (data: Uint8Array | string) => {\n const bytes =\n typeof data === 'string' ? convertBase64ToUint8Array(data) : data;\n const id3Size =\n ((bytes[6] & 0x7f) << 21) |\n ((bytes[7] & 0x7f) << 14) |\n ((bytes[8] & 0x7f) << 7) |\n (bytes[9] & 0x7f);\n\n // The raw MP3 starts here\n return bytes.slice(id3Size + 10);\n};\n\nfunction stripID3TagsIfPresent(data: Uint8Array | string): Uint8Array | string {\n const hasId3 =\n (typeof data === 'string' && data.startsWith('SUQz')) ||\n (typeof data !== 'string' &&\n data.length > 10 &&\n data[0] === 0x49 && // 'I'\n data[1] === 0x44 && // 'D'\n data[2] === 0x33); // '3'\n\n return hasId3 ? stripID3(data) : data;\n}\n\nexport function detectMimeType({\n data,\n signatures,\n}: {\n data: Uint8Array | string;\n signatures: typeof audioMimeTypeSignatures | typeof imageMimeTypeSignatures;\n}): (typeof signatures)[number]['mimeType'] | undefined {\n const processedData = stripID3TagsIfPresent(data);\n\n for (const signature of signatures) {\n if (\n typeof processedData === 'string'\n ? processedData.startsWith(signature.base64Prefix)\n : processedData.length >= signature.bytesPrefix.length &&\n signature.bytesPrefix.every(\n (byte, index) => processedData[index] === byte,\n )\n ) {\n return signature.mimeType;\n }\n }\n\n return undefined;\n}\n","import { AISDKError, ImageModelV1, JSONValue } from '@ai-sdk/provider';\nimport { NoImageGeneratedError } from '../../errors/no-image-generated-error';\nimport {\n DefaultGeneratedFile,\n GeneratedFile,\n} from '../generate-text/generated-file';\nimport { prepareRetries } from '../prompt/prepare-retries';\nimport { ImageGenerationWarning } from '../types/image-model';\nimport { ImageModelResponseMetadata } from '../types/image-model-response-metadata';\nimport { GenerateImageResult } from './generate-image-result';\nimport {\n detectMimeType,\n imageMimeTypeSignatures,\n} from '../util/detect-mimetype';\n\n/**\nGenerates images using an image model.\n\n@param model - The image model to use.\n@param prompt - The prompt that should be used to generate the image.\n@param n - Number of images to generate. Default: 1.\n@param size - Size of the images to generate. Must have the format `{width}x{height}`.\n@param aspectRatio - Aspect ratio of the images to generate. Must have the format `{width}:{height}`.\n@param seed - Seed for the image generation.\n@param providerOptions - Additional provider-specific options that are passed through to the provider\nas body parameters.\n@param maxRetries - Maximum number of retries. Set to 0 to disable retries. Default: 2.\n@param abortSignal - An optional abort signal that can be used to cancel the call.\n@param headers - Additional HTTP headers to be sent with the request. Only applicable for HTTP-based providers.\n\n@returns A result object that contains the generated images.\n */\nexport async function generateImage({\n model,\n prompt,\n n = 1,\n size,\n aspectRatio,\n seed,\n providerOptions,\n maxRetries: maxRetriesArg,\n abortSignal,\n headers,\n}: {\n /**\nThe image model to use.\n */\n model: ImageModelV1;\n\n /**\nThe prompt that should be used to generate the image.\n */\n prompt: string;\n\n /**\nNumber of images to generate.\n */\n n?: number;\n\n /**\nSize of the images to generate. Must have the format `{width}x{height}`. If not provided, the default size will be used.\n */\n size?: `${number}x${number}`;\n\n /**\nAspect ratio of the images to generate. Must have the format `{width}:{height}`. If not provided, the default aspect ratio will be used.\n */\n aspectRatio?: `${number}:${number}`;\n\n /**\nSeed for the image generation. If not provided, the default seed will be used.\n */\n seed?: number;\n\n /**\nAdditional provider-specific options that are passed through to the provider\nas body parameters.\n\nThe outer record is keyed by the provider name, and the inner\nrecord is keyed by the provider-specific metadata key.\n```ts\n{\n \"openai\": {\n \"style\": \"vivid\"\n }\n}\n```\n */\n providerOptions?: Record<string, Record<string, JSONValue>>;\n\n /**\nMaximum number of retries per embedding model call. Set to 0 to disable retries.\n\n@default 2\n */\n maxRetries?: number;\n\n /**\nAbort signal.\n */\n abortSignal?: AbortSignal;\n\n /**\nAdditional headers to include in the request.\nOnly applicable for HTTP-based providers.\n */\n headers?: Record<string, string>;\n}): Promise<GenerateImageResult> {\n const { retry } = prepareRetries({ maxRetries: maxRetriesArg });\n\n // default to 1 if the model has not specified limits on\n // how many images can be generated in a single call\n const maxImagesPerCall = model.maxImagesPerCall ?? 1;\n\n // parallelize calls to the model:\n const callCount = Math.ceil(n / maxImagesPerCall);\n const callImageCounts = Array.from({ length: callCount }, (_, i) => {\n if (i < callCount - 1) {\n return maxImagesPerCall;\n }\n\n const remainder = n % maxImagesPerCall;\n return remainder === 0 ? maxImagesPerCall : remainder;\n });\n const results = await Promise.all(\n callImageCounts.map(async callImageCount =>\n retry(() =>\n model.doGenerate({\n prompt,\n n: callImageCount,\n abortSignal,\n headers,\n size,\n aspectRatio,\n seed,\n providerOptions: providerOptions ?? {},\n }),\n ),\n ),\n );\n\n // collect result images, warnings, and response metadata\n const images: Array<DefaultGeneratedFile> = [];\n const warnings: Array<ImageGenerationWarning> = [];\n const responses: Array<ImageModelResponseMetadata> = [];\n for (const result of results) {\n images.push(\n ...result.images.map(\n image =>\n new DefaultGeneratedFile({\n data: image,\n mimeType:\n detectMimeType({\n data: image,\n signatures: imageMimeTypeSignatures,\n }) ?? 'image/png',\n }),\n ),\n );\n warnings.push(...result.warnings);\n responses.push(result.response);\n }\n\n if (!images.length) {\n throw new NoImageGeneratedError({ responses });\n }\n\n return new DefaultGenerateImageResult({ images, warnings, responses });\n}\n\nclass DefaultGenerateImageResult implements GenerateImageResult {\n readonly images: Array<GeneratedFile>;\n readonly warnings: Array<ImageGenerationWarning>;\n readonly responses: Array<ImageModelResponseMetadata>;\n\n constructor(options: {\n images: Array<GeneratedFile>;\n warnings: Array<ImageGenerationWarning>;\n responses: Array<ImageModelResponseMetadata>;\n }) {\n this.images = options.images;\n this.warnings = options.warnings;\n this.responses = options.responses;\n }\n\n get image() {\n return this.images[0];\n }\n}\n","import {\n JSONParseError,\n JSONValue,\n TypeValidationError,\n} from '@ai-sdk/provider';\nimport { createIdGenerator, safeParseJSON } from '@ai-sdk/provider-utils';\nimport { Schema } from '@ai-sdk/ui-utils';\nimport { z } from 'zod';\nimport { NoObjectGeneratedError } from '../../errors/no-object