UNPKG

ai

Version:

Vercel AI SDK - The AI Toolkit for TypeScript and JavaScript

1 lines • 332 kB
{"version":3,"sources":["../streams/index.ts","../util/retry-with-exponential-backoff.ts","../util/delay.ts","../util/retry-error.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","../core/generate-object/generate-object.ts","../core/prompt/convert-to-language-model-prompt.ts","../util/download-error.ts","../util/download.ts","../core/util/detect-image-mimetype.ts","../core/prompt/data-content.ts","../core/prompt/invalid-data-content-error.ts","../core/prompt/invalid-message-role-error.ts","../core/prompt/get-validated-prompt.ts","../errors/invalid-argument-error.ts","../core/prompt/prepare-call-settings.ts","../core/types/token-usage.ts","../core/util/prepare-response-headers.ts","../core/util/schema.ts","../core/generate-object/inject-json-schema-into-system.ts","../core/generate-object/no-object-generated-error.ts","../core/generate-object/stream-object.ts","../util/create-resolvable-promise.ts","../util/delayed-promise.ts","../core/util/async-iterable-stream.ts","../core/util/is-non-empty-object.ts","../core/prompt/prepare-tools-and-tool-choice.ts","../core/generate-text/tool-call.ts","../errors/invalid-tool-arguments-error.ts","../errors/no-such-tool-error.ts","../core/generate-text/generate-text.ts","../core/util/merge-streams.ts","../core/generate-text/run-tools-transformation.ts","../core/generate-text/stream-text.ts","../core/prompt/attachments-to-parts.ts","../core/prompt/convert-to-core-messages.ts","../core/registry/invalid-model-id-error.ts","../core/registry/no-such-model-error.ts","../core/registry/no-such-provider-error.ts","../core/registry/provider-registry.ts","../core/tool/tool.ts","../core/util/cosine-similarity.ts","../errors/index.ts","../streams/ai-stream.ts","../streams/stream-data.ts","../streams/anthropic-stream.ts","../streams/assistant-response.ts","../streams/aws-bedrock-stream.ts","../streams/cohere-stream.ts","../streams/google-generative-ai-stream.ts","../streams/huggingface-stream.ts","../streams/inkeep-stream.ts","../streams/langchain-adapter.ts","../streams/langchain-stream.ts","../streams/mistral-stream.ts","../streams/openai-stream.ts","../streams/replicate-stream.ts","../streams/stream-to-response.ts","../streams/streaming-text-response.ts"],"sourcesContent":["// forwarding exports from ui-utils:\nexport {\n formatStreamPart,\n parseStreamPart,\n readDataStream,\n parseComplexResponse,\n} from '@ai-sdk/ui-utils';\nexport type {\n AssistantStatus,\n UseAssistantOptions,\n Message,\n CreateMessage,\n DataMessage,\n AssistantMessage,\n JSONValue,\n ChatRequest,\n ChatRequestOptions,\n Function,\n FunctionCall,\n FunctionCallHandler,\n ToolInvocation,\n Tool,\n ToolCall,\n ToolCallHandler,\n ToolChoice,\n StreamPart,\n IdGenerator,\n RequestOptions,\n} from '@ai-sdk/ui-utils';\n\nimport { generateId as generateIdImpl } from '@ai-sdk/provider-utils';\nexport const generateId = generateIdImpl;\n\n/**\n@deprecated Use `generateId` instead.\n */\n// TODO remove nanoid export (breaking change)\nexport const nanoid = generateIdImpl;\n\nexport * from '../core/index';\nexport * from '../errors/index';\n\nexport * from './ai-stream';\nexport * from './anthropic-stream';\nexport * from './assistant-response';\nexport * from './aws-bedrock-stream';\nexport * from './cohere-stream';\nexport * from './google-generative-ai-stream';\nexport * from './huggingface-stream';\nexport * from './inkeep-stream';\nexport * as LangChainAdapter from './langchain-adapter';\nexport * from './langchain-stream';\nexport * from './mistral-stream';\nexport * from './openai-stream';\nexport * from './replicate-stream';\nexport * from './stream-data';\nexport * from './stream-to-response';\nexport * from './streaming-text-response';\n","import { APICallError } from '@ai-sdk/provider';\nimport { getErrorMessage, isAbortError } from '@ai-sdk/provider-utils';\nimport { delay } from './delay';\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.isAPICallError(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","export async function delay(delayInMs: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, delayInMs));\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 /**\n * @deprecated use `isInstance` instead\n */\n static isRetryError(error: unknown): error is RetryError {\n return (\n error instanceof Error &&\n error.name === name &&\n typeof (error as RetryError).reason === 'string' &&\n Array.isArray((error as RetryError).errors)\n );\n }\n\n /**\n * @deprecated Do not use this method. It will be removed in the next major version.\n */\n toJSON() {\n return {\n name: this.name,\n message: this.message,\n reason: this.reason,\n lastError: this.lastError,\n errors: this.errors,\n };\n }\n}\n","import { TelemetrySettings } from './telemetry-settings';\n\nexport function assembleOperationName({\n operationName,\n telemetry,\n}: {\n operationName: string;\n telemetry?: TelemetrySettings;\n}) {\n return {\n 'operation.name': `${operationName}${\n telemetry?.functionId != null ? ` ${telemetry.functionId}` : ''\n }`,\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 // special telemetry information\n 'resource.name': telemetry?.functionId,\n 'ai.telemetry.functionId': telemetry?.functionId,\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\n/**\n * Tracer variable for testing. Tests can set this to a mock tracer.\n */\nlet testTracer: Tracer | undefined = undefined;\n\nexport function setTestTracer(tracer: Tracer | undefined) {\n testTracer = tracer;\n}\n\nexport function getTracer({ isEnabled }: { isEnabled: boolean }): Tracer {\n if (!isEnabled) {\n return noopTracer;\n }\n\n if (testTracer) {\n return testTracer;\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 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 { retryWithExponentialBackoff } from '../../util/retry-with-exponential-backoff';\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,\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 baseTelemetryAttributes = getBaseTelemetryAttributes({\n model,\n telemetry,\n headers,\n settings: { maxRetries },\n });\n\n const tracer = getTracer({ isEnabled: telemetry?.isEnabled ?? false });\n\n return recordSpan({\n name: 'ai.embed',\n attributes: selectTelemetryAttributes({\n telemetry,\n attributes: {\n ...assembleOperationName({ operationName: 'ai.embed', telemetry }),\n ...baseTelemetryAttributes,\n 'ai.value': { input: () => JSON.stringify(value) },\n },\n }),\n tracer,\n fn: async span => {\n const retry = retryWithExponentialBackoff({ maxRetries });\n\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 operationName: '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 { retryWithExponentialBackoff } from '../../util/retry-with-exponential-backoff';\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,\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 baseTelemetryAttributes = getBaseTelemetryAttributes({\n model,\n telemetry,\n headers,\n settings: { maxRetries },\n });\n\n const tracer = getTracer({ isEnabled: telemetry?.isEnabled ?? false });\n\n return recordSpan({\n name: 'ai.embedMany',\n attributes: selectTelemetryAttributes({\n telemetry,\n attributes: {\n ...assembleOperationName({ operationName: '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 retry = retryWithExponentialBackoff({ maxRetries });\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 operationName: '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 operationName: '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 { safeParseJSON } from '@ai-sdk/provider-utils';\nimport { z } from 'zod';\nimport { retryWithExponentialBackoff } from '../../util/retry-with-exponential-backoff';\nimport { CallSettings } from '../prompt/call-settings';\nimport { convertToLanguageModelPrompt } from '../prompt/convert-to-language-model-prompt';\nimport { getValidatedPrompt } from '../prompt/get-validated-prompt';\nimport { prepareCallSettings } from '../prompt/prepare-call-settings';\nimport { Prompt } from '../prompt/prompt';\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 { CallWarning, FinishReason, LanguageModel, LogProbs } from '../types';\nimport { calculateCompletionTokenUsage } from '../types/token-usage';\nimport { prepareResponseHeaders } from '../util/prepare-response-headers';\nimport { Schema, asSchema } from '../util/schema';\nimport { GenerateObjectResult } from './generate-object-result';\nimport { injectJsonSchemaIntoSystem } from './inject-json-schema-into-system';\nimport { NoObjectGeneratedError } from './no-object-generated-error';\n\n/**\nGenerate a structured, typed object for a given prompt and schema using a language model.\n\nThis function does not stream the output. If you want to stream the output, use `streamObject` instead.\n\n@param model - The language model to use.\n\n@param schema - The schema of the object that the model should generate.\n@param schemaName - Optional name of the output that should be generated. Used by some providers for additional LLM guidance, e.g. via tool or schema name.\n@param schemaDescription - Optional description of the output that should be generated. Used by some providers for additional LLM guidance, e.g. via tool or schema description.\n@param mode - The mode to use for object generation. Not all models support all modes. Defaults to 'auto'.\n\n@param system - A system message that will be part of the prompt.\n@param prompt - A simple text prompt. You can either use `prompt` or `messages` but not both.\n@param messages - A list of messages. You can either use `prompt` or `messages` but not both.\n\n@param maxTokens - Maximum number of tokens to generate.\n@param temperature - Temperature setting.\nThe value is passed through to the provider. The range depends on the provider and model.\nIt is recommended to set either `temperature` or `topP`, but not both.\n@param topP - Nucleus sampling.\nThe value is passed through to the provider. The range depends on the provider and model.\nIt is recommended to set either `temperature` or `topP`, but not both.\n@param topK - Only sample from the top K options for each subsequent token.\nUsed to remove \"long tail\" low probability responses.\nRecommended for advanced use cases only. You usually only need to use temperature.\n@param presencePenalty - Presence penalty setting.\nIt affects the likelihood of the model to repeat information that is already in the prompt.\nThe value is passed through to the provider. The range depends on the provider and model.\n@param frequencyPenalty - Frequency penalty setting.\nIt affects the likelihood of the model to repeatedly use the same words or phrases.\nThe value is passed through to the provider. The range depends on the provider and model.\n@param seed - The seed (integer) to use for random sampling.\nIf set and supported by the model, calls will generate deterministic results.\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\nA result object that contains the generated object, the finish reason, the token usage, and additional information.\n */\nexport async function generateObject<T>({\n model,\n schema: inputSchema,\n schemaName,\n schemaDescription,\n mode,\n system,\n prompt,\n messages,\n maxRetries,\n abortSignal,\n headers,\n experimental_telemetry: telemetry,\n ...settings\n}: Omit<CallSettings, 'stopSequences'> &\n Prompt & {\n /**\nThe language model to use.\n */\n model: LanguageModel;\n\n /**\nThe schema of the object that the model should generate.\n */\n schema: z.Schema<T, z.ZodTypeDef, any> | Schema<T>;\n\n /**\nOptional name of the output that should be generated.\nUsed by some providers for additional LLM guidance, e.g.\nvia tool or schema name.\n */\n schemaName?: string;\n\n /**\nOptional description of the output that should be generated.\nUsed by some providers for additional LLM guidance, e.g.\nvia tool or schema description.\n */\n schemaDescription?: string;\n\n /**\nThe mode to use for object generation.\n\nThe schema is converted in a JSON schema and used in one of the following ways\n\n- 'auto': The provider will choose the best mode for the model.\n- 'tool': A tool with the JSON schema as parameters is is provided and the provider is instructed to use it.\n- 'json': The JSON schema and an instruction is injected into the prompt. If the provider supports JSON mode, it is enabled. If the provider supports JSON grammars, the grammar is used.\n\nPlease note that most providers do not support all modes.\n\nDefault and recommended: 'auto' (best mode for the model).\n */\n mode?: 'auto' | 'json' | 'tool';\n\n /**\n * Optional telemetry configuration (experimental).\n */\n experimental_telemetry?: TelemetrySettings;\n }): Promise<DefaultGenerateObjectResult<T>> {\n const baseTelemetryAttributes = getBaseTelemetryAttributes({\n model,\n telemetry,\n headers,\n settings: { ...settings, maxRetries },\n });\n\n const schema = asSchema(inputSchema);\n\n const tracer = getTracer({ isEnabled: telemetry?.isEnabled ?? false });\n return recordSpan({\n name: 'ai.generateObject',\n attributes: selectTelemetryAttributes({\n telemetry,\n attributes: {\n ...assembleOperationName({\n operationName: 'ai.generateObject',\n telemetry,\n }),\n ...baseTelemetryAttributes,\n // specific settings that only make sense on the outer level:\n 'ai.prompt': {\n input: () => JSON.stringify({ system, prompt, messages }),\n },\n 'ai.schema': {\n input: () => JSON.stringify(schema.jsonSchema),\n },\n 'ai.schema.name': schemaName,\n 'ai.schema.description': schemaDescription,\n 'ai.settings.mode': mode,\n },\n }),\n tracer,\n fn: async span => {\n const retry = retryWithExponentialBackoff({ maxRetries });\n\n // use the default provider mode when the mode is set to 'auto' or unspecified\n if (mode === 'auto' || mode == null) {\n mode = model.defaultObjectGenerationMode;\n }\n\n let result: string;\n let finishReason: FinishReason;\n let usage: Parameters<typeof calculateCompletionTokenUsage>[0];\n let warnings: CallWarning[] | undefined;\n let rawResponse: { headers?: Record<string, string> } | undefined;\n let logprobs: LogProbs | undefined;\n\n switch (mode) {\n case 'json': {\n const validatedPrompt = getValidatedPrompt({\n system: model.supportsStructuredOutputs\n ? system\n : injectJsonSchemaIntoSystem({\n system,\n schema: schema.jsonSchema,\n }),\n prompt,\n messages,\n });\n\n const promptMessages = await convertToLanguageModelPrompt({\n prompt: validatedPrompt,\n modelSupportsImageUrls: model.supportsImageUrls,\n });\n\n const inputFormat = validatedPrompt.type;\n\n const generateResult = await retry(() =>\n recordSpan({\n name: 'ai.generateObject.doGenerate',\n attributes: selectTelemetryAttributes({\n telemetry,\n attributes: {\n ...assembleOperationName({\n operationName: 'ai.generateObject.doGenerate',\n telemetry,\n }),\n ...baseTelemetryAttributes,\n 'ai.prompt.format': {\n input: () => inputFormat,\n },\n 'ai.prompt.messages': {\n input: () => JSON.stringify(promptMessages),\n },\n 'ai.settings.mode': mode,\n\n // standardized gen-ai llm span attributes:\n 'gen_ai.request.model': model.modelId,\n 'gen_ai.system': model.provider,\n 'gen_ai.request.max_tokens': settings.maxTokens,\n 'gen_ai.request.temperature': settings.temperature,\n 'gen_ai.request.top_p': settings.topP,\n },\n }),\n tracer,\n fn: async span => {\n const result = await model.doGenerate({\n mode: {\n type: 'object-json',\n schema: schema.jsonSchema,\n name: schemaName,\n description: schemaDescription,\n },\n ...prepareCallSettings(settings),\n inputFormat,\n prompt: promptMessages,\n abortSignal,\n headers,\n });\n\n if (result.text === undefined) {\n throw new NoObjectGeneratedError();\n }\n\n // Add response information to the span:\n span.setAttributes(\n selectTelemetryAttributes({\n telemetry,\n attributes: {\n 'ai.finishReason': result.finishReason,\n 'ai.usage.promptTokens': result.usage.promptTokens,\n 'ai.usage.completionTokens':\n result.usage.completionTokens,\n 'ai.result.object': { output: () => result.text },\n\n // standardized gen-ai llm span attributes:\n 'gen_ai.response.finish_reasons': [result.finishReason],\n 'gen_ai.usage.prompt_tokens': result.usage.promptTokens,\n 'gen_ai.usage.completion_tokens':\n result.usage.completionTokens,\n },\n }),\n );\n\n return { ...result, objectText: result.text };\n },\n }),\n );\n\n result = generateResult.objectText;\n finishReason = generateResult.finishReason;\n usage = generateResult.usage;\n warnings = generateResult.warnings;\n rawResponse = generateResult.rawResponse;\n logprobs = generateResult.logprobs;\n\n break;\n }\n\n case 'tool': {\n const validatedPrompt = getValidatedPrompt({\n system,\n prompt,\n messages,\n });\n\n const promptMessages = await convertToLanguageModelPrompt({\n prompt: validatedPrompt,\n modelSupportsImageUrls: model.supportsImageUrls,\n });\n const inputFormat = validatedPrompt.type;\n\n const generateResult = await retry(() =>\n recordSpan({\n name: 'ai.generateObject.doGenerate',\n attributes: selectTelemetryAttributes({\n telemetry,\n attributes: {\n ...assembleOperationName({\n operationName: 'ai.generateObject.doGenerate',\n telemetry,\n }),\n ...baseTelemetryAttributes,\n 'ai.prompt.format': {\n input: () => inputFormat,\n },\n 'ai.prompt.messages': {\n input: () => JSON.stringify(promptMessages),\n },\n 'ai.settings.mode': mode,\n\n // standardized gen-ai llm span attributes:\n 'gen_ai.request.model': model.modelId,\n 'gen_ai.system': model.provider,\n 'gen_ai.request.max_tokens': settings.maxTokens,\n 'gen_ai.request.temperature': settings.temperature,\n 'gen_ai.request.top_p': settings.topP,\n },\n }),\n tracer,\n fn: async span => {\n const result = await model.doGenerate({\n mode: {\n type: 'object-tool',\n tool: {\n type: 'function',\n name: schemaName ?? 'json',\n description:\n schemaDescription ?? 'Respond with a JSON object.',\n parameters: schema.jsonSchema,\n },\n },\n ...prepareCallSettings(settings),\n inputFormat,\n prompt: promptMessages,\n abortSignal,\n headers,\n });\n\n const objectText = result.toolCalls?.[0]?.args;\n\n if (objectText === undefined) {\n throw new NoObjectGeneratedError();\n }\n\n // Add response information to the span:\n span.setAttributes(\n selectTelemetryAttributes({\n telemetry,\n attributes: {\n 'ai.finishReason': result.finishReason,\n 'ai.usage.promptTokens': result.usage.promptTokens,\n 'ai.usage.completionTokens':\n result.usage.completionTokens,\n 'ai.result.object': { output: () => objectText },\n\n // standardized gen-ai llm span attributes:\n 'gen_ai.response.finish_reasons': [result.finishReason],\n 'gen_ai.usage.prompt_tokens': result.usage.promptTokens,\n 'gen_ai.usage.completion_tokens':\n result.usage.completionTokens,\n },\n }),\n );\n\n return { ...result, objectText };\n },\n }),\n );\n\n result = generateResult.objectText;\n finishReason = generateResult.finishReason;\n usage = generateResult.usage;\n warnings = generateResult.warnings;\n rawResponse = generateResult.rawResponse;\n logprobs = generateResult.logprobs;\n\n break;\n }\n\n case undefined: {\n throw new Error(\n 'Model does not have a default object generation mode.',\n );\n }\n\n default: {\n const _exhaustiveCheck: never = mode;\n throw new Error(`Unsupported mode: ${_exhaustiveCheck}`);\n }\n }\n\n const parseResult = safeParseJSON({ text: result, schema });\n\n if (!parseResult.success) {\n throw parseResult.error;\n }\n\n // Add response information to the span:\n span.setAttributes(\n selectTelemetryAttributes({\n telemetry,\n attributes: {\n 'ai.finishReason': finishReason,\n 'ai.usage.promptTokens': usage.promptTokens,\n 'ai.usage.completionTokens': usage.completionTokens,\n 'ai.result.object': {\n output: () => JSON.stringify(parseResult.value),\n },\n },\n }),\n );\n\n return new DefaultGenerateObjectResult({\n object: parseResult.value,\n finishReason,\n usage: calculateCompletionTokenUsage(usage),\n warnings,\n rawResponse,\n logprobs,\n });\n },\n });\n}\n\nclass DefaultGenerateObjectResult<T> implements GenerateObjectResult<T> {\n readonly object: GenerateObjectResult<T>['object'];\n readonly finishReason: GenerateObjectResult<T>['finishReason'];\n readonly usage: GenerateObjectResult<T>['usage'];\n readonly warnings: GenerateObjectResult<T>['warnings'];\n readonly rawResponse: GenerateObjectResult<T>['rawResponse'];\n readonly logprobs: GenerateObjectResult<T>['logprobs'];\n\n constructor(options: {\n object: GenerateObjectResult<T>['object'];\n finishReason: GenerateObjectResult<T>['finishReason'];\n usage: GenerateObjectResult<T>['usage'];\n warnings: GenerateObjectResult<T>['warnings'];\n rawResponse: GenerateObjectResult<T>['rawResponse'];\n logprobs: GenerateObjectResult<T>['logprobs'];\n }) {\n this.object = options.object;\n this.finishReason = options.finishReason;\n this.usage = options.usage;\n this.warnings = options.warnings;\n this.rawResponse = options.rawResponse;\n this.logprobs = options.logprobs;\n }\n\n toJsonResponse(init?: ResponseInit): Response {\n return new Response(JSON.stringify(this.object), {\n status: init?.status ?? 200,\n headers: prepareResponseHeaders(init, {\n contentType: 'application/json; charset=utf-8',\n }),\n });\n }\n}\n\n/**\n * @deprecated Use `generateObject` instead.\n */\nexport const experimental_generateObject = generateObject;\n","import {\n LanguageModelV1ImagePart,\n LanguageModelV1Message,\n LanguageModelV1Prompt,\n LanguageModelV1TextPart,\n} from '@ai-sdk/provider';\nimport { getErrorMessage } from '@ai-sdk/provider-utils';\nimport { download } from '../../util/download';\nimport { CoreMessage } from '../prompt/message';\nimport { detectImageMimeType } from '../util/detect-image-mimetype';\nimport { ImagePart, TextPart } from './content-part';\nimport { convertDataContentToUint8Array } from './data-content';\nimport { ValidatedPrompt } from './get-validated-prompt';\nimport { InvalidMessageRoleError } from './invalid-message-role-error';\n\nexport async function convertToLanguageModelPrompt({\n prompt,\n modelSupportsImageUrls = true,\n downloadImplementation = download,\n}: {\n prompt: ValidatedPrompt;\n modelSupportsImageUrls: boolean | undefined;\n downloadImplementation?: typeof download;\n}): Promise<LanguageModelV1Prompt> {\n const languageModelMessages: LanguageModelV1Prompt = [];\n\n if (prompt.system != null) {\n languageModelMessages.push({ role: 'system', content: prompt.system });\n }\n\n const downloadedImages =\n modelSupportsImageUrls || prompt.messages == null\n ? null\n : await downloadImages(prompt.messages, downloadImplementation);\n\n const promptType = prompt.type;\n switch (promptType) {\n case 'prompt': {\n languageModelMessages.push({\n role: 'user',\n content: [{ type: 'text', text: prompt.prompt }],\n });\n break;\n }\n\n case 'messages': {\n languageModelMessages.push(\n ...prompt.messages.map(\n (message): LanguageModelV1Message =>\n convertToLanguageModelMessage(message, downloadedImages),\n ),\n );\n break;\n }\n\n default: {\n const _exhaustiveCheck: never = promptType;\n throw new Error(`Unsupported prompt type: ${_exhaustiveCheck}`);\n }\n }\n\n return languageModelMessages;\n}\n\n/**\n * Convert a CoreMessage to a LanguageModelV1Message.\n *\n * @param message The CoreMessage to convert.\n * @param downloadedImages A map of image URLs to their downloaded data. Only\n * available if the model does not support image URLs, null otherwise.\n */\nexport function convertToLanguageModelMessage(\n message: CoreMessage,\n downloadedImages: Record<\n string,\n { mimeType: string | undefined; data: Uint8Array }\n > | null,\n): LanguageModelV1Message {\n const role = message.role;\n switch (role) {\n case 'system': {\n return { role: 'system', content: message.content };\n }\n\n case 'user': {\n if (typeof message.content === 'string') {\n return {\n role: 'user',\n content: [{ type: 'text', text: message.content }],\n };\n }\n\n return {\n role: 'user',\n content: message.content.map(\n (part): LanguageModelV1TextPart | LanguageModelV1ImagePart => {\n switch (part.type) {\n case 'text': {\n return part;\n }\n\n case 'image': {\n if (part.image instanceof URL) {\n if (downloadedImages == null) {\n return {\n type: 'image',\n i