UNPKG

@mastra/core

Version:
1 lines 13.5 kB
{"version":3,"file":"model-CxJfDXLP.cjs","names":["#model"],"sources":["../src/llm/model/aisdk/generate-to-stream.ts","../src/llm/model/aisdk/v5/model.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\n/**\n * Converts a doGenerate result to a ReadableStream format.\n * This is shared between V2 and V3 model wrappers since the content/result structure is compatible.\n */\nexport function createStreamFromGenerateResult(result: {\n warnings: unknown[];\n response?: {\n id?: string;\n modelId?: string;\n timestamp?: Date;\n };\n content: Array<{\n type: string;\n [key: string]: unknown;\n }>;\n finishReason: unknown;\n usage: unknown;\n providerMetadata?: unknown;\n}): ReadableStream {\n return new ReadableStream({\n start(controller) {\n controller.enqueue({ type: 'stream-start', warnings: result.warnings });\n controller.enqueue({\n type: 'response-metadata',\n id: result.response?.id,\n modelId: result.response?.modelId,\n timestamp: result.response?.timestamp,\n });\n\n const toolCallMeta: Record<string, { providerExecuted?: boolean }> = {};\n for (const message of result.content) {\n if (message.type === 'tool-call') {\n const toolCall = message as {\n type: 'tool-call';\n toolCallId: string;\n toolName: string;\n input: unknown;\n providerExecuted?: boolean;\n dynamic?: boolean;\n providerMetadata?: unknown;\n };\n toolCallMeta[toolCall.toolCallId] = { providerExecuted: toolCall.providerExecuted };\n controller.enqueue({\n type: 'tool-input-start',\n id: toolCall.toolCallId,\n toolName: toolCall.toolName,\n providerExecuted: toolCall.providerExecuted,\n dynamic: toolCall.dynamic,\n providerMetadata: toolCall.providerMetadata,\n });\n controller.enqueue({\n type: 'tool-input-delta',\n id: toolCall.toolCallId,\n delta: toolCall.input,\n providerMetadata: toolCall.providerMetadata,\n });\n controller.enqueue({\n type: 'tool-input-end',\n id: toolCall.toolCallId,\n providerMetadata: toolCall.providerMetadata,\n });\n controller.enqueue(toolCall);\n } else if (message.type === 'tool-result') {\n const toolResult = message as { type: 'tool-result'; toolCallId: string; [key: string]: unknown };\n const meta = toolCallMeta[toolResult.toolCallId];\n if (meta?.providerExecuted) {\n controller.enqueue({ ...toolResult, providerExecuted: meta.providerExecuted });\n } else {\n controller.enqueue(message);\n }\n } else if (message.type === 'text') {\n const text = message as {\n type: 'text';\n text: string;\n providerMetadata?: unknown;\n };\n const id = `msg_${randomUUID()}`;\n controller.enqueue({\n type: 'text-start',\n id,\n providerMetadata: text.providerMetadata,\n });\n controller.enqueue({\n type: 'text-delta',\n id,\n delta: text.text,\n });\n controller.enqueue({\n type: 'text-end',\n id,\n });\n } else if (message.type === 'reasoning') {\n const id = `reasoning_${randomUUID()}`;\n const reasoning = message as {\n type: 'reasoning';\n text: string;\n providerMetadata?: unknown;\n };\n controller.enqueue({\n type: 'reasoning-start',\n id,\n providerMetadata: reasoning.providerMetadata,\n });\n controller.enqueue({\n type: 'reasoning-delta',\n id,\n delta: reasoning.text,\n providerMetadata: reasoning.providerMetadata,\n });\n controller.enqueue({\n type: 'reasoning-end',\n id,\n providerMetadata: reasoning.providerMetadata,\n });\n } else if (message.type === 'file') {\n const file = message as {\n type: 'file';\n mediaType: string;\n data: unknown;\n };\n controller.enqueue({\n type: 'file',\n mediaType: file.mediaType,\n data: file.data,\n });\n } else if (message.type === 'source') {\n const source = message as {\n type: 'source';\n sourceType: 'url' | 'document';\n id: string;\n url?: string;\n mediaType?: string;\n filename?: string;\n title?: string;\n providerMetadata?: unknown;\n };\n if (source.sourceType === 'url') {\n controller.enqueue({\n type: 'source',\n id: source.id,\n sourceType: 'url',\n url: source.url,\n title: source.title,\n providerMetadata: source.providerMetadata,\n });\n } else {\n controller.enqueue({\n type: 'source',\n id: source.id,\n sourceType: 'document',\n mediaType: source.mediaType,\n filename: source.filename,\n title: source.title,\n providerMetadata: source.providerMetadata,\n });\n }\n }\n }\n\n controller.enqueue({\n type: 'finish',\n finishReason: result.finishReason,\n usage: result.usage,\n providerMetadata: result.providerMetadata,\n });\n\n controller.close();\n },\n });\n}\n","import type { LanguageModelV2, LanguageModelV2CallOptions } from '@ai-sdk/provider-v5';\nimport type { MastraLanguageModelV2 } from '../../shared.types';\nimport { createStreamFromGenerateResult } from '../generate-to-stream';\n\ntype StreamResult = Awaited<ReturnType<LanguageModelV2['doStream']>>;\n\n/**\n * Strips per-tool `strict` from function tools (V2 providers don't support it)\n * and, when any tool had `strict: true`, injects `strictJsonSchema: true` into\n * the OpenAI provider options so the V2 OpenAI provider enables strict mode\n * globally for all tools.\n */\nfunction applyStrictForV2(options: LanguageModelV2CallOptions): LanguageModelV2CallOptions {\n if (!options.tools?.length) {\n return options;\n }\n\n let hasStrictTool = false;\n const sanitizedTools = options.tools.map((tool: Record<string, unknown>) => {\n if (tool.type !== 'function' || !('strict' in tool)) {\n return tool;\n }\n\n if (tool.strict === true) {\n hasStrictTool = true;\n }\n\n const { strict: _strict, ...rest } = tool;\n return rest;\n });\n\n let result: LanguageModelV2CallOptions = {\n ...options,\n tools: sanitizedTools as typeof options.tools,\n };\n\n // V2 OpenAI providers use a global `strictJsonSchema` option instead of per-tool strict.\n // When any tool requested strict mode, propagate it to the provider option so the\n // V2 OpenAI provider applies strict JSON schema validation to all tool parameters.\n if (hasStrictTool) {\n const existingOpenai = (options.providerOptions?.openai ?? {}) as Record<string, unknown>;\n // Only inject if the user hasn't already set strictJsonSchema explicitly\n if (existingOpenai.strictJsonSchema == null) {\n result = {\n ...result,\n providerOptions: {\n ...options.providerOptions,\n openai: {\n ...existingOpenai,\n strictJsonSchema: true,\n },\n },\n };\n }\n }\n\n return result;\n}\n\n/**\n * Wrapper class for AI SDK V5 (LanguageModelV2) that converts doGenerate to return\n * a stream format for consistency with Mastra's streaming architecture.\n */\nexport class AISDKV5LanguageModel implements MastraLanguageModelV2 {\n /**\n * The language model must specify which language model interface version it implements.\n */\n readonly specificationVersion: 'v2' = 'v2';\n /**\n * Name of the provider for logging purposes.\n */\n readonly provider: string;\n /**\n * Provider-specific model ID for logging purposes.\n */\n readonly modelId: string;\n readonly gatewayId?: string;\n /**\n * Supported URL patterns by media type for the provider.\n *\n * The keys are media type patterns or full media types (e.g. `*\\/*` for everything, `audio/*`, `video/*`, or `application/pdf`).\n * and the values are arrays of regular expressions that match the URL paths.\n * The matching should be against lower-case URLs.\n * Matched URLs are supported natively by the model and are not downloaded.\n * @returns A map of supported URL patterns by media type (as a promise or a plain object).\n */\n supportedUrls: PromiseLike<Record<string, RegExp[]>> | Record<string, RegExp[]>;\n\n #model: LanguageModelV2;\n\n constructor(config: LanguageModelV2) {\n this.#model = config;\n this.provider = this.#model.provider;\n this.modelId = this.#model.modelId;\n this.gatewayId = (config as { gatewayId?: string }).gatewayId;\n this.supportedUrls = this.#model.supportedUrls;\n }\n\n async doGenerate(options: LanguageModelV2CallOptions) {\n const result = await this.#model.doGenerate(applyStrictForV2(options));\n\n return {\n ...result,\n request: result.request!,\n response: result.response as unknown as StreamResult['response'],\n stream: createStreamFromGenerateResult(result),\n };\n }\n\n async doStream(options: LanguageModelV2CallOptions) {\n return await this.#model.doStream(applyStrictForV2(options));\n }\n\n /**\n * Custom serialization for tracing/observability spans.\n * `#model` is already a true JS private field and not enumerable, so\n * the wrapped provider SDK client can't leak. This method makes the\n * safe shape explicit and avoids walking `supportedUrls` (a\n * PromiseLike / regex map that isn't useful in spans).\n */\n serializeForSpan(): { specificationVersion: 'v2'; modelId: string; provider: string; gatewayId?: string } {\n return {\n specificationVersion: this.specificationVersion,\n modelId: this.modelId,\n provider: this.provider,\n gatewayId: this.gatewayId,\n };\n }\n}\n"],"mappings":"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"}