UNPKG

@mastra/core

Version:

The core foundation of the Mastra framework, providing essential components and interfaces for building AI-powered applications.

704 lines (700 loc) • 20.6 kB
import { delay } from './chunk-HJQYQAIJ.js'; import { MastraError } from './chunk-4MPQAHTP.js'; import { MastraBase } from './chunk-5IEKR756.js'; import { RegisteredLogger } from './chunk-5YDTZN2X.js'; import { OpenAIReasoningSchemaCompatLayer, OpenAISchemaCompatLayer, GoogleSchemaCompatLayer, AnthropicSchemaCompatLayer, DeepSeekSchemaCompatLayer, MetaSchemaCompatLayer, applyCompatLayer } from '@mastra/schema-compat'; import { jsonSchema, generateText, Output, generateObject, streamText, streamObject } from 'ai'; import { z } from 'zod'; // src/llm/model/base.ts var MastraLLMBase = class extends MastraBase { // @ts-ignore #mastra; #model; constructor({ name, model }) { super({ component: RegisteredLogger.LLM, name }); this.#model = model; } getProvider() { return this.#model.provider; } getModelId() { return this.#model.modelId; } getModel() { return this.#model; } convertToMessages(messages) { if (Array.isArray(messages)) { return messages.map((m) => { if (typeof m === "string") { return { role: "user", content: m }; } return m; }); } return [ { role: "user", content: messages } ]; } __registerPrimitives(p) { if (p.telemetry) { this.__setTelemetry(p.telemetry); } if (p.logger) { this.__setLogger(p.logger); } } __registerMastra(p) { this.#mastra = p; } async __text(input) { this.logger.debug(`[LLMs:${this.name}] Generating text.`, { input }); throw new Error("Method not implemented."); } async __textObject(input) { this.logger.debug(`[LLMs:${this.name}] Generating object.`, { input }); throw new Error("Method not implemented."); } async generate(messages, options) { this.logger.debug(`[LLMs:${this.name}] Generating text.`, { messages, options }); throw new Error("Method not implemented."); } async __stream(input) { this.logger.debug(`[LLMs:${this.name}] Streaming text.`, { input }); throw new Error("Method not implemented."); } async __streamObject(input) { this.logger.debug(`[LLMs:${this.name}] Streaming object.`, { input }); throw new Error("Method not implemented."); } async stream(messages, options) { this.logger.debug(`[LLMs:${this.name}] Streaming text.`, { messages, options }); throw new Error("Method not implemented."); } }; // src/llm/model/model.ts var MastraLLM = class extends MastraLLMBase { #model; #mastra; constructor({ model, mastra }) { super({ name: "aisdk", model }); this.#model = model; if (mastra) { this.#mastra = mastra; if (mastra.getLogger()) { this.__setLogger(this.#mastra.getLogger()); } } } __registerPrimitives(p) { if (p.telemetry) { this.__setTelemetry(p.telemetry); } if (p.logger) { this.__setLogger(p.logger); } } __registerMastra(p) { this.#mastra = p; } getProvider() { return this.#model.provider; } getModelId() { return this.#model.modelId; } getModel() { return this.#model; } _applySchemaCompat(schema) { const model = this.#model; const schemaCompatLayers = []; if (model) { schemaCompatLayers.push( new OpenAIReasoningSchemaCompatLayer(model), new OpenAISchemaCompatLayer(model), new GoogleSchemaCompatLayer(model), new AnthropicSchemaCompatLayer(model), new DeepSeekSchemaCompatLayer(model), new MetaSchemaCompatLayer(model) ); } return applyCompatLayer({ schema, compatLayers: schemaCompatLayers, mode: "aiSdkSchema" }); } async __text({ runId, messages, maxSteps = 5, tools = {}, temperature, toolChoice = "auto", onStepFinish, experimental_output, telemetry, threadId, resourceId, memory, runtimeContext, ...rest }) { const model = this.#model; this.logger.debug(`[LLM] - Generating text`, { runId, messages, maxSteps, threadId, resourceId, tools: Object.keys(tools) }); const argsForExecute = { model, temperature, tools: { ...tools }, toolChoice, maxSteps, onStepFinish: async (props) => { try { await onStepFinish?.(props); } catch (e) { const mastraError = new MastraError( { id: "LLM_TEXT_ON_STEP_FINISH_CALLBACK_EXECUTION_FAILED", domain: "LLM" /* LLM */, category: "USER" /* USER */, details: { modelId: model.modelId, modelProvider: model.provider, runId: runId ?? "unknown", threadId: threadId ?? "unknown", resourceId: resourceId ?? "unknown", finishReason: props?.finishReason, toolCalls: props?.toolCalls ? JSON.stringify(props.toolCalls) : "", toolResults: props?.toolResults ? JSON.stringify(props.toolResults) : "", usage: props?.usage ? JSON.stringify(props.usage) : "" } }, e ); this.logger.trackException(mastraError); throw mastraError; } this.logger.debug("[LLM] - Step Change:", { text: props?.text, toolCalls: props?.toolCalls, toolResults: props?.toolResults, finishReason: props?.finishReason, usage: props?.usage, runId }); if (props?.response?.headers?.["x-ratelimit-remaining-tokens"] && parseInt(props?.response?.headers?.["x-ratelimit-remaining-tokens"], 10) < 2e3) { this.logger.warn("Rate limit approaching, waiting 10 seconds", { runId }); await delay(10 * 1e3); } }, ...rest }; let schema; if (experimental_output) { this.logger.debug("[LLM] - Using experimental output", { runId }); if (typeof experimental_output.parse === "function") { schema = experimental_output; if (schema instanceof z.ZodArray) { schema = schema._def.type; } } else { schema = jsonSchema(experimental_output); } } try { return await generateText({ messages, ...argsForExecute, experimental_telemetry: { ...this.experimental_telemetry, ...telemetry }, experimental_output: schema ? Output.object({ schema }) : void 0 }); } catch (e) { const mastraError = new MastraError( { id: "LLM_GENERATE_TEXT_AI_SDK_EXECUTION_FAILED", domain: "LLM" /* LLM */, category: "THIRD_PARTY" /* THIRD_PARTY */, details: { modelId: model.modelId, modelProvider: model.provider, runId: runId ?? "unknown", threadId: threadId ?? "unknown", resourceId: resourceId ?? "unknown" } }, e ); this.logger.trackException(mastraError); throw mastraError; } } async __textObject({ messages, onStepFinish, maxSteps = 5, tools = {}, structuredOutput, runId, temperature, toolChoice = "auto", telemetry, threadId, resourceId, memory, runtimeContext, ...rest }) { const model = this.#model; this.logger.debug(`[LLM] - Generating a text object`, { runId }); const argsForExecute = { model, temperature, tools: { ...tools }, maxSteps, toolChoice, onStepFinish: async (props) => { try { await onStepFinish?.(props); } catch (e) { const mastraError = new MastraError( { id: "LLM_TEXT_OBJECT_ON_STEP_FINISH_CALLBACK_EXECUTION_FAILED", domain: "LLM" /* LLM */, category: "USER" /* USER */, details: { runId: runId ?? "unknown", threadId: threadId ?? "unknown", resourceId: resourceId ?? "unknown", finishReason: props?.finishReason, toolCalls: props?.toolCalls ? JSON.stringify(props.toolCalls) : "", toolResults: props?.toolResults ? JSON.stringify(props.toolResults) : "", usage: props?.usage ? JSON.stringify(props.usage) : "" } }, e ); this.logger.trackException(mastraError); throw mastraError; } this.logger.debug("[LLM] - Step Change:", { text: props?.text, toolCalls: props?.toolCalls, toolResults: props?.toolResults, finishReason: props?.finishReason, usage: props?.usage, runId }); if (props?.response?.headers?.["x-ratelimit-remaining-tokens"] && parseInt(props?.response?.headers?.["x-ratelimit-remaining-tokens"], 10) < 2e3) { this.logger.warn("Rate limit approaching, waiting 10 seconds", { runId }); await delay(10 * 1e3); } }, ...rest }; let output = "object"; if (structuredOutput instanceof z.ZodArray) { output = "array"; structuredOutput = structuredOutput._def.type; } try { const processedSchema = this._applySchemaCompat(structuredOutput); return await generateObject({ messages, ...argsForExecute, output, schema: processedSchema, experimental_telemetry: { ...this.experimental_telemetry, ...telemetry } }); } catch (e) { const mastraError = new MastraError( { id: "LLM_GENERATE_OBJECT_AI_SDK_EXECUTION_FAILED", domain: "LLM" /* LLM */, category: "THIRD_PARTY" /* THIRD_PARTY */, details: { modelId: model.modelId, modelProvider: model.provider, runId: runId ?? "unknown", threadId: threadId ?? "unknown", resourceId: resourceId ?? "unknown" } }, e ); this.logger.trackException(mastraError); throw mastraError; } } async __stream({ messages, onStepFinish, onFinish, maxSteps = 5, tools = {}, runId, temperature, toolChoice = "auto", experimental_output, telemetry, threadId, resourceId, memory, runtimeContext, ...rest }) { const model = this.#model; this.logger.debug(`[LLM] - Streaming text`, { runId, threadId, resourceId, messages, maxSteps, tools: Object.keys(tools || {}) }); const argsForExecute = { model, temperature, tools: { ...tools }, maxSteps, toolChoice, onStepFinish: async (props) => { try { await onStepFinish?.(props); } catch (e) { const mastraError = new MastraError( { id: "LLM_STREAM_ON_STEP_FINISH_CALLBACK_EXECUTION_FAILED", domain: "LLM" /* LLM */, category: "USER" /* USER */, details: { modelId: model.modelId, modelProvider: model.provider, runId: runId ?? "unknown", threadId: threadId ?? "unknown", resourceId: resourceId ?? "unknown", finishReason: props?.finishReason, toolCalls: props?.toolCalls ? JSON.stringify(props.toolCalls) : "", toolResults: props?.toolResults ? JSON.stringify(props.toolResults) : "", usage: props?.usage ? JSON.stringify(props.usage) : "" } }, e ); this.logger.trackException(mastraError); throw mastraError; } this.logger.debug("[LLM] - Stream Step Change:", { text: props?.text, toolCalls: props?.toolCalls, toolResults: props?.toolResults, finishReason: props?.finishReason, usage: props?.usage, runId }); if (props?.response?.headers?.["x-ratelimit-remaining-tokens"] && parseInt(props?.response?.headers?.["x-ratelimit-remaining-tokens"], 10) < 2e3) { this.logger.warn("Rate limit approaching, waiting 10 seconds", { runId }); await delay(10 * 1e3); } }, onFinish: async (props) => { try { await onFinish?.(props); } catch (e) { const mastraError = new MastraError( { id: "LLM_STREAM_ON_FINISH_CALLBACK_EXECUTION_FAILED", domain: "LLM" /* LLM */, category: "USER" /* USER */, details: { modelId: model.modelId, modelProvider: model.provider, runId: runId ?? "unknown", threadId: threadId ?? "unknown", resourceId: resourceId ?? "unknown", finishReason: props?.finishReason, toolCalls: props?.toolCalls ? JSON.stringify(props.toolCalls) : "", toolResults: props?.toolResults ? JSON.stringify(props.toolResults) : "", usage: props?.usage ? JSON.stringify(props.usage) : "" } }, e ); this.logger.trackException(mastraError); throw mastraError; } this.logger.debug("[LLM] - Stream Finished:", { text: props?.text, toolCalls: props?.toolCalls, toolResults: props?.toolResults, finishReason: props?.finishReason, usage: props?.usage, runId, threadId, resourceId }); }, ...rest }; let schema; if (experimental_output) { this.logger.debug("[LLM] - Using experimental output", { runId }); if (typeof experimental_output.parse === "function") { schema = experimental_output; if (schema instanceof z.ZodArray) { schema = schema._def.type; } } else { schema = jsonSchema(experimental_output); } } try { return await streamText({ messages, ...argsForExecute, experimental_telemetry: { ...this.experimental_telemetry, ...telemetry }, experimental_output: schema ? Output.object({ schema }) : void 0 }); } catch (e) { const mastraError = new MastraError( { id: "LLM_STREAM_TEXT_AI_SDK_EXECUTION_FAILED", domain: "LLM" /* LLM */, category: "THIRD_PARTY" /* THIRD_PARTY */, details: { modelId: model.modelId, modelProvider: model.provider, runId: runId ?? "unknown", threadId: threadId ?? "unknown", resourceId: resourceId ?? "unknown" } }, e ); this.logger.trackException(mastraError); throw mastraError; } } async __streamObject({ messages, runId, tools = {}, maxSteps = 5, toolChoice = "auto", runtimeContext, threadId, resourceId, memory, temperature, onStepFinish, onFinish, structuredOutput, telemetry, ...rest }) { const model = this.#model; this.logger.debug(`[LLM] - Streaming structured output`, { runId, messages, maxSteps, tools: Object.keys(tools || {}) }); const finalTools = tools; const argsForExecute = { model, temperature, tools: { ...finalTools }, maxSteps, toolChoice, onStepFinish: async (props) => { try { await onStepFinish?.(props); } catch (e) { const mastraError = new MastraError( { id: "LLM_STREAM_OBJECT_ON_STEP_FINISH_CALLBACK_EXECUTION_FAILED", domain: "LLM" /* LLM */, category: "USER" /* USER */, details: { modelId: model.modelId, modelProvider: model.provider, runId: runId ?? "unknown", threadId: threadId ?? "unknown", resourceId: resourceId ?? "unknown", usage: props?.usage ? JSON.stringify(props.usage) : "", toolCalls: props?.toolCalls ? JSON.stringify(props.toolCalls) : "", toolResults: props?.toolResults ? JSON.stringify(props.toolResults) : "", finishReason: props?.finishReason } }, e ); this.logger.trackException(mastraError); throw mastraError; } this.logger.debug("[LLM] - Stream Step Change:", { text: props?.text, toolCalls: props?.toolCalls, toolResults: props?.toolResults, finishReason: props?.finishReason, usage: props?.usage, runId, threadId, resourceId }); if (props?.response?.headers?.["x-ratelimit-remaining-tokens"] && parseInt(props?.response?.headers?.["x-ratelimit-remaining-tokens"], 10) < 2e3) { this.logger.warn("Rate limit approaching, waiting 10 seconds", { runId }); await delay(10 * 1e3); } }, onFinish: async (props) => { try { await onFinish?.(props); } catch (e) { const mastraError = new MastraError( { id: "LLM_STREAM_OBJECT_ON_FINISH_CALLBACK_EXECUTION_FAILED", domain: "LLM" /* LLM */, category: "USER" /* USER */, details: { modelId: model.modelId, modelProvider: model.provider, runId: runId ?? "unknown", threadId: threadId ?? "unknown", resourceId: resourceId ?? "unknown", toolCalls: props?.toolCalls ? JSON.stringify(props.toolCalls) : "", toolResults: props?.toolResults ? JSON.stringify(props.toolResults) : "", finishReason: props?.finishReason, usage: props?.usage ? JSON.stringify(props.usage) : "" } }, e ); this.logger.trackException(mastraError); throw mastraError; } this.logger.debug("[LLM] - Stream Finished:", { text: props?.text, toolCalls: props?.toolCalls, toolResults: props?.toolResults, finishReason: props?.finishReason, usage: props?.usage, runId, threadId, resourceId }); }, ...rest }; let output = "object"; if (structuredOutput instanceof z.ZodArray) { output = "array"; structuredOutput = structuredOutput._def.type; } try { const processedSchema = this._applySchemaCompat(structuredOutput); return streamObject({ messages, ...argsForExecute, output, schema: processedSchema, experimental_telemetry: { ...this.experimental_telemetry, ...telemetry } }); } catch (e) { const mastraError = new MastraError( { id: "LLM_STREAM_OBJECT_AI_SDK_EXECUTION_FAILED", domain: "LLM" /* LLM */, category: "THIRD_PARTY" /* THIRD_PARTY */, details: { modelId: model.modelId, modelProvider: model.provider, runId: runId ?? "unknown", threadId: threadId ?? "unknown", resourceId: resourceId ?? "unknown" } }, e ); this.logger.trackException(mastraError); throw mastraError; } } async generate(messages, { maxSteps = 5, output, ...rest }) { const msgs = this.convertToMessages(messages); if (!output) { return await this.__text({ messages: msgs, maxSteps, ...rest }); } return await this.__textObject({ messages: msgs, structuredOutput: output, maxSteps, ...rest }); } async stream(messages, { maxSteps = 5, output, ...rest }) { const msgs = this.convertToMessages(messages); if (!output) { return await this.__stream({ messages: msgs, maxSteps, ...rest }); } return await this.__streamObject({ messages: msgs, structuredOutput: output, maxSteps, ...rest }); } }; export { MastraLLM };