UNPKG

@mastra/core

Version:

Mastra is a framework for building AI-powered applications and agents with a modern TypeScript stack.

1,466 lines (1,454 loc) • 96.2 kB
'use strict'; var chunkGPWMM745_cjs = require('./chunk-GPWMM745.cjs'); var chunk5NTO7S5I_cjs = require('./chunk-5NTO7S5I.cjs'); var chunkX7F4CSGR_cjs = require('./chunk-X7F4CSGR.cjs'); var chunkVF676YCO_cjs = require('./chunk-VF676YCO.cjs'); var chunk6VOPKVYH_cjs = require('./chunk-6VOPKVYH.cjs'); var chunkA5KDVZDL_cjs = require('./chunk-A5KDVZDL.cjs'); var crypto$1 = require('crypto'); var jsonSchemaToZod = require('json-schema-to-zod'); var zod = require('zod'); var schemaCompat = require('@mastra/schema-compat'); var web = require('stream/web'); function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; } var jsonSchemaToZod__default = /*#__PURE__*/_interopDefault(jsonSchemaToZod); // src/ai-tracing/types.ts var AISpanType = /* @__PURE__ */ ((AISpanType2) => { AISpanType2["AGENT_RUN"] = "agent_run"; AISpanType2["GENERIC"] = "generic"; AISpanType2["MODEL_GENERATION"] = "model_generation"; AISpanType2["MODEL_STEP"] = "model_step"; AISpanType2["MODEL_CHUNK"] = "model_chunk"; AISpanType2["MCP_TOOL_CALL"] = "mcp_tool_call"; AISpanType2["PROCESSOR_RUN"] = "processor_run"; AISpanType2["TOOL_CALL"] = "tool_call"; AISpanType2["WORKFLOW_RUN"] = "workflow_run"; AISpanType2["WORKFLOW_STEP"] = "workflow_step"; AISpanType2["WORKFLOW_CONDITIONAL"] = "workflow_conditional"; AISpanType2["WORKFLOW_CONDITIONAL_EVAL"] = "workflow_conditional_eval"; AISpanType2["WORKFLOW_PARALLEL"] = "workflow_parallel"; AISpanType2["WORKFLOW_LOOP"] = "workflow_loop"; AISpanType2["WORKFLOW_SLEEP"] = "workflow_sleep"; AISpanType2["WORKFLOW_WAIT_EVENT"] = "workflow_wait_event"; return AISpanType2; })(AISpanType || {}); var InternalSpans = /* @__PURE__ */ ((InternalSpans2) => { InternalSpans2[InternalSpans2["NONE"] = 0] = "NONE"; InternalSpans2[InternalSpans2["WORKFLOW"] = 1] = "WORKFLOW"; InternalSpans2[InternalSpans2["AGENT"] = 2] = "AGENT"; InternalSpans2[InternalSpans2["TOOL"] = 4] = "TOOL"; InternalSpans2[InternalSpans2["MODEL"] = 8] = "MODEL"; InternalSpans2[InternalSpans2["ALL"] = 15] = "ALL"; return InternalSpans2; })(InternalSpans || {}); var SamplingStrategyType = /* @__PURE__ */ ((SamplingStrategyType2) => { SamplingStrategyType2["ALWAYS"] = "always"; SamplingStrategyType2["NEVER"] = "never"; SamplingStrategyType2["RATIO"] = "ratio"; SamplingStrategyType2["CUSTOM"] = "custom"; return SamplingStrategyType2; })(SamplingStrategyType || {}); var AITracingEventType = /* @__PURE__ */ ((AITracingEventType2) => { AITracingEventType2["SPAN_STARTED"] = "span_started"; AITracingEventType2["SPAN_UPDATED"] = "span_updated"; AITracingEventType2["SPAN_ENDED"] = "span_ended"; return AITracingEventType2; })(AITracingEventType || {}); // src/ai-tracing/spans/base.ts function isSpanInternal(spanType, flags) { if (flags === void 0 || flags === 0 /* NONE */) { return false; } switch (spanType) { // Workflow-related spans case "workflow_run" /* WORKFLOW_RUN */: case "workflow_step" /* WORKFLOW_STEP */: case "workflow_conditional" /* WORKFLOW_CONDITIONAL */: case "workflow_conditional_eval" /* WORKFLOW_CONDITIONAL_EVAL */: case "workflow_parallel" /* WORKFLOW_PARALLEL */: case "workflow_loop" /* WORKFLOW_LOOP */: case "workflow_sleep" /* WORKFLOW_SLEEP */: case "workflow_wait_event" /* WORKFLOW_WAIT_EVENT */: return (flags & 1 /* WORKFLOW */) !== 0; // Agent-related spans case "agent_run" /* AGENT_RUN */: return (flags & 2 /* AGENT */) !== 0; // Tool-related spans case "tool_call" /* TOOL_CALL */: case "mcp_tool_call" /* MCP_TOOL_CALL */: return (flags & 4 /* TOOL */) !== 0; // Model-related spans case "model_generation" /* MODEL_GENERATION */: case "model_step" /* MODEL_STEP */: case "model_chunk" /* MODEL_CHUNK */: return (flags & 8 /* MODEL */) !== 0; // Default: never internal default: return false; } } var BaseAISpan = class { name; type; attributes; parent; startTime; endTime; isEvent; isInternal; aiTracing; input; output; errorInfo; metadata; traceState; /** Parent span ID (for root spans that are children of external spans) */ parentSpanId; constructor(options, aiTracing) { this.name = options.name; this.type = options.type; this.attributes = deepClean(options.attributes) || {}; this.metadata = deepClean(options.metadata); this.parent = options.parent; this.startTime = /* @__PURE__ */ new Date(); this.aiTracing = aiTracing; this.isEvent = options.isEvent ?? false; this.isInternal = isSpanInternal(this.type, options.tracingPolicy?.internal); this.traceState = options.traceState; if (this.isEvent) { this.output = deepClean(options.output); } else { this.input = deepClean(options.input); } } createChildSpan(options) { return this.aiTracing.startSpan({ ...options, parent: this, isEvent: false }); } createEventSpan(options) { return this.aiTracing.startSpan({ ...options, parent: this, isEvent: true }); } /** Returns `TRUE` if the span is the root span of a trace */ get isRootSpan() { return !this.parent; } /** Get the closest parent spanId that isn't an internal span */ getParentSpanId(includeInternalSpans) { if (!this.parent) { return this.parentSpanId; } if (includeInternalSpans) return this.parent.id; if (this.parent.isInternal) return this.parent.getParentSpanId(includeInternalSpans); return this.parent.id; } /** Find the closest parent span of a specific type by walking up the parent chain */ findParent(spanType) { let current = this.parent; while (current) { if (current.type === spanType) { return current; } current = current.parent; } return void 0; } /** Returns a lightweight span ready for export */ exportSpan(includeInternalSpans) { return { id: this.id, traceId: this.traceId, name: this.name, type: this.type, attributes: this.attributes, metadata: this.metadata, startTime: this.startTime, endTime: this.endTime, input: this.input, output: this.output, errorInfo: this.errorInfo, isEvent: this.isEvent, isRootSpan: this.isRootSpan, parentSpanId: this.getParentSpanId(includeInternalSpans) }; } }; var DEFAULT_KEYS_TO_STRIP = /* @__PURE__ */ new Set([ "logger", "experimental_providerMetadata", "providerMetadata", "steps", "tracingContext" ]); function deepClean(value, options = {}, _seen = /* @__PURE__ */ new WeakSet(), _depth = 0) { const { keysToStrip = DEFAULT_KEYS_TO_STRIP, maxDepth = 10 } = options; if (_depth > maxDepth) { return "[MaxDepth]"; } if (value === null || typeof value !== "object") { try { JSON.stringify(value); return value; } catch (error) { return `[${error instanceof Error ? error.message : String(error)}]`; } } if (_seen.has(value)) { return "[Circular]"; } _seen.add(value); if (Array.isArray(value)) { return value.map((item) => deepClean(item, options, _seen, _depth + 1)); } const cleaned = {}; for (const [key, val] of Object.entries(value)) { if (keysToStrip.has(key)) { continue; } try { cleaned[key] = deepClean(val, options, _seen, _depth + 1); } catch (error) { cleaned[key] = `[${error instanceof Error ? error.message : String(error)}]`; } } return cleaned; } // src/ai-tracing/spans/default.ts var DefaultAISpan = class extends BaseAISpan { id; traceId; constructor(options, aiTracing) { super(options, aiTracing); this.id = generateSpanId(); if (options.parent) { this.traceId = options.parent.traceId; } else if (options.traceId) { if (isValidTraceId(options.traceId)) { this.traceId = options.traceId; } else { console.error( `[Mastra Tracing] Invalid traceId: must be 1-32 hexadecimal characters, got "${options.traceId}". Generating new trace ID.` ); this.traceId = generateTraceId(); } } else { this.traceId = generateTraceId(); } if (!options.parent && options.parentSpanId) { if (isValidSpanId(options.parentSpanId)) { this.parentSpanId = options.parentSpanId; } else { console.error( `[Mastra Tracing] Invalid parentSpanId: must be 1-16 hexadecimal characters, got "${options.parentSpanId}". Ignoring parent span ID.` ); } } } end(options) { if (this.isEvent) { return; } this.endTime = /* @__PURE__ */ new Date(); if (options?.output !== void 0) { this.output = deepClean(options.output); } if (options?.attributes) { this.attributes = { ...this.attributes, ...deepClean(options.attributes) }; } if (options?.metadata) { this.metadata = { ...this.metadata, ...deepClean(options.metadata) }; } } error(options) { if (this.isEvent) { return; } const { error, endSpan = true, attributes, metadata } = options; this.errorInfo = error instanceof chunk5NTO7S5I_cjs.MastraError ? { id: error.id, details: error.details, category: error.category, domain: error.domain, message: error.message } : { message: error.message }; if (attributes) { this.attributes = { ...this.attributes, ...deepClean(attributes) }; } if (metadata) { this.metadata = { ...this.metadata, ...deepClean(metadata) }; } if (endSpan) { this.end(); } else { this.update({}); } } update(options) { if (this.isEvent) { return; } if (options.input !== void 0) { this.input = deepClean(options.input); } if (options.output !== void 0) { this.output = deepClean(options.output); } if (options.attributes) { this.attributes = { ...this.attributes, ...deepClean(options.attributes) }; } if (options.metadata) { this.metadata = { ...this.metadata, ...deepClean(options.metadata) }; } } get isValid() { return true; } async export() { return JSON.stringify({ spanId: this.id, traceId: this.traceId, startTime: this.startTime, endTime: this.endTime, attributes: this.attributes, metadata: this.metadata }); } }; function generateSpanId() { const bytes = new Uint8Array(8); if (typeof crypto !== "undefined" && crypto.getRandomValues) { crypto.getRandomValues(bytes); } else { for (let i = 0; i < 8; i++) { bytes[i] = Math.floor(Math.random() * 256); } } return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join(""); } function generateTraceId() { const bytes = new Uint8Array(16); if (typeof crypto !== "undefined" && crypto.getRandomValues) { crypto.getRandomValues(bytes); } else { for (let i = 0; i < 16; i++) { bytes[i] = Math.floor(Math.random() * 256); } } return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join(""); } function isValidTraceId(traceId) { return /^[0-9a-f]{1,32}$/i.test(traceId); } function isValidSpanId(spanId) { return /^[0-9a-f]{1,16}$/i.test(spanId); } // src/ai-tracing/spans/no-op.ts var NoOpAISpan = class extends BaseAISpan { id; traceId; constructor(options, aiTracing) { super(options, aiTracing); this.id = "no-op"; this.traceId = "no-op-trace"; } end(_options) { } error(_options) { } update(_options) { } get isValid() { return false; } }; // src/ai-tracing/exporters/base.ts var BaseExporter = class { /** Mastra logger instance */ logger; /** Whether this exporter is disabled */ isDisabled = false; /** * Initialize the base exporter with logger */ constructor(config = {}) { const logLevel = this.resolveLogLevel(config.logLevel); this.logger = config.logger ?? new chunkA5KDVZDL_cjs.ConsoleLogger({ level: logLevel, name: this.constructor.name }); } /** * Set the logger for the exporter (called by Mastra/AITracing during initialization) */ __setLogger(logger) { this.logger = logger; this.logger.debug(`Logger updated for exporter [name=${this.name}]`); } /** * Convert string log level to LogLevel enum */ resolveLogLevel(logLevel) { if (!logLevel) { return chunkA5KDVZDL_cjs.LogLevel.INFO; } if (typeof logLevel === "number") { return logLevel; } const logLevelMap = { debug: chunkA5KDVZDL_cjs.LogLevel.DEBUG, info: chunkA5KDVZDL_cjs.LogLevel.INFO, warn: chunkA5KDVZDL_cjs.LogLevel.WARN, error: chunkA5KDVZDL_cjs.LogLevel.ERROR }; return logLevelMap[logLevel] ?? chunkA5KDVZDL_cjs.LogLevel.INFO; } /** * Mark the exporter as disabled and log a message * * @param reason - Reason why the exporter is disabled */ setDisabled(reason) { this.isDisabled = true; this.logger.warn(`${this.name} disabled: ${reason}`); } /** * Export a tracing event * * This method checks if the exporter is disabled before calling _exportEvent. * Subclasses should implement _exportEvent instead of overriding this method. */ async exportEvent(event) { if (this.isDisabled) { return; } await this._exportEvent(event); } /** * Shutdown the exporter and clean up resources * * Default implementation just logs. Override to add custom cleanup. */ async shutdown() { this.logger.info(`${this.name} shutdown complete`); } }; var CoreToolBuilder = class extends chunk6VOPKVYH_cjs.MastraBase { originalTool; options; logType; constructor(input) { super({ name: "CoreToolBuilder" }); this.originalTool = input.originalTool; this.options = input.options; this.logType = input.logType; } // Helper to get parameters based on tool type getParameters = () => { if (chunkVF676YCO_cjs.isVercelTool(this.originalTool)) { let schema2 = this.originalTool.parameters ?? ("inputSchema" in this.originalTool ? this.originalTool.inputSchema : void 0) ?? zod.z.object({}); if (typeof schema2 === "function") { schema2 = schema2(); } return schema2; } let schema = this.originalTool.inputSchema ?? zod.z.object({}); if (typeof schema === "function") { schema = schema(); } return schema; }; getOutputSchema = () => { if ("outputSchema" in this.originalTool) { let schema = this.originalTool.outputSchema; if (typeof schema === "function") { schema = schema(); } return schema; } return null; }; // For provider-defined tools, we need to include all required properties buildProviderTool(tool) { if ("type" in tool && tool.type === "provider-defined" && "id" in tool && typeof tool.id === "string" && tool.id.includes(".")) { const parameters = this.getParameters(); const outputSchema = this.getOutputSchema(); return { type: "provider-defined", id: tool.id, args: "args" in this.originalTool ? this.originalTool.args : {}, description: tool.description, parameters: parameters.jsonSchema ? parameters : schemaCompat.convertZodSchemaToAISDKSchema(parameters), ...outputSchema ? { outputSchema: outputSchema.jsonSchema ? outputSchema : schemaCompat.convertZodSchemaToAISDKSchema(outputSchema) } : {}, execute: this.originalTool.execute ? this.createExecute( this.originalTool, { ...this.options, description: this.originalTool.description }, this.logType ) : void 0 }; } return void 0; } createLogMessageOptions({ agentName, toolName, type }) { if (!agentName) { return { start: `Executing tool ${toolName}`, error: `Failed tool execution` }; } const prefix = `[Agent:${agentName}]`; const toolType = type === "toolset" ? "toolset" : "tool"; return { start: `${prefix} - Executing ${toolType} ${toolName}`, error: `${prefix} - Failed ${toolType} execution` }; } createExecute(tool, options, logType, processedSchema) { const { logger, mastra: _mastra, memory: _memory, runtimeContext, model, ...rest } = options; const logModelObject = { modelId: model?.modelId, provider: model?.provider, specificationVersion: model?.specificationVersion }; const { start, error } = this.createLogMessageOptions({ agentName: options.agentName, toolName: options.name, type: logType }); const execFunction = async (args, execOptions) => { const tracingContext = execOptions.tracingContext || options.tracingContext; const toolSpan = tracingContext?.currentSpan?.createChildSpan({ type: "tool_call" /* TOOL_CALL */, name: `tool: '${options.name}'`, input: args, attributes: { toolId: options.name, toolDescription: options.description, toolType: logType || "tool" }, tracingPolicy: options.tracingPolicy }); try { let result; if (chunkVF676YCO_cjs.isVercelTool(tool)) { result = await tool?.execute?.(args, execOptions); } else { const wrappedMastra = options.mastra ? wrapMastra(options.mastra, { currentSpan: toolSpan }) : options.mastra; result = await tool?.execute?.( { context: args, threadId: options.threadId, resourceId: options.resourceId, mastra: wrappedMastra, memory: options.memory, runId: options.runId, runtimeContext: options.runtimeContext ?? new chunkGPWMM745_cjs.RuntimeContext(), writer: new chunkX7F4CSGR_cjs.ToolStream( { prefix: "tool", callId: execOptions.toolCallId, name: options.name, runId: options.runId }, options.writableStream || execOptions.writableStream ), tracingContext: { currentSpan: toolSpan } }, execOptions ); } toolSpan?.end({ output: result }); return result ?? void 0; } catch (error2) { toolSpan?.error({ error: error2 }); throw error2; } }; return async (args, execOptions) => { let logger2 = options.logger || this.logger; try { logger2.debug(start, { ...rest, model: logModelObject, args }); const parameters = processedSchema || this.getParameters(); const { data, error: error2 } = chunkVF676YCO_cjs.validateToolInput(parameters, args, options.name); if (error2) { logger2.warn(`Tool input validation failed for '${options.name}'`, { toolName: options.name, errors: error2.validationErrors, args }); return error2; } args = data; return await new Promise((resolve, reject) => { setImmediate(async () => { try { const result = await execFunction(args, execOptions); resolve(result); } catch (err) { reject(err); } }); }); } catch (err) { const mastraError = new chunk5NTO7S5I_cjs.MastraError( { id: "TOOL_EXECUTION_FAILED", domain: "TOOL" /* TOOL */, category: "USER" /* USER */, details: { errorMessage: String(error), argsJson: JSON.stringify(args), model: model?.modelId ?? "" } }, err ); logger2.trackException(mastraError); logger2.error(error, { ...rest, model: logModelObject, error: mastraError, args }); return mastraError; } }; } buildV5() { const builtTool = this.build(); if (!builtTool.parameters) { throw new Error("Tool parameters are required"); } const base = { ...builtTool, inputSchema: builtTool.parameters, onInputStart: "onInputStart" in this.originalTool ? this.originalTool.onInputStart : void 0, onInputDelta: "onInputDelta" in this.originalTool ? this.originalTool.onInputDelta : void 0, onInputAvailable: "onInputAvailable" in this.originalTool ? this.originalTool.onInputAvailable : void 0 }; if (builtTool.type === "provider-defined") { const { execute, parameters, ...rest } = base; const name = builtTool.id.split(".")[1] || builtTool.id; return { ...rest, type: builtTool.type, id: builtTool.id, name, args: builtTool.args }; } return base; } build() { const providerTool = this.buildProviderTool(this.originalTool); if (providerTool) { return providerTool; } const model = this.options.model; const schemaCompatLayers = []; if (model) { const supportsStructuredOutputs = model.specificationVersion !== "v2" ? model.supportsStructuredOutputs ?? false : false; const modelInfo = { modelId: model.modelId, supportsStructuredOutputs, provider: model.provider }; schemaCompatLayers.push( new schemaCompat.OpenAIReasoningSchemaCompatLayer(modelInfo), new schemaCompat.OpenAISchemaCompatLayer(modelInfo), new schemaCompat.GoogleSchemaCompatLayer(modelInfo), new schemaCompat.AnthropicSchemaCompatLayer(modelInfo), new schemaCompat.DeepSeekSchemaCompatLayer(modelInfo), new schemaCompat.MetaSchemaCompatLayer(modelInfo) ); } let processedZodSchema; let processedSchema; const originalSchema = this.getParameters(); const applicableLayer = schemaCompatLayers.find((layer) => layer.shouldApply()); if (applicableLayer && originalSchema) { processedZodSchema = applicableLayer.processZodType(originalSchema); processedSchema = schemaCompat.applyCompatLayer({ schema: originalSchema, compatLayers: schemaCompatLayers, mode: "aiSdkSchema" }); } else { processedZodSchema = originalSchema; processedSchema = schemaCompat.applyCompatLayer({ schema: originalSchema, compatLayers: schemaCompatLayers, mode: "aiSdkSchema" }); } let processedOutputSchema; if (this.getOutputSchema()) { processedOutputSchema = schemaCompat.applyCompatLayer({ schema: this.getOutputSchema(), compatLayers: [], mode: "aiSdkSchema" }); } const definition = { type: "function", description: this.originalTool.description, parameters: this.getParameters(), outputSchema: this.getOutputSchema(), requireApproval: this.options.requireApproval, execute: this.originalTool.execute ? this.createExecute( this.originalTool, { ...this.options, description: this.originalTool.description }, this.logType, processedZodSchema // Pass the processed Zod schema for validation ) : void 0 }; return { ...definition, id: "id" in this.originalTool ? this.originalTool.id : void 0, parameters: processedSchema, outputSchema: processedOutputSchema }; } }; // src/utils.ts var delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); function deepMerge(target, source) { const output = { ...target }; if (!source) return output; Object.keys(source).forEach((key) => { const targetValue = output[key]; const sourceValue = source[key]; if (Array.isArray(targetValue) && Array.isArray(sourceValue)) { output[key] = sourceValue; } else if (sourceValue instanceof Object && targetValue instanceof Object && !Array.isArray(sourceValue) && !Array.isArray(targetValue)) { output[key] = deepMerge(targetValue, sourceValue); } else if (sourceValue !== void 0) { output[key] = sourceValue; } }); return output; } function generateEmptyFromSchema(schema) { try { const parsedSchema = JSON.parse(schema); if (!parsedSchema || parsedSchema.type !== "object" || !parsedSchema.properties) return {}; const obj = {}; const TYPE_DEFAULTS = { string: "", array: [], object: {}, number: 0, integer: 0, boolean: false }; for (const [key, prop] of Object.entries(parsedSchema.properties)) { obj[key] = TYPE_DEFAULTS[prop.type] ?? null; } return obj; } catch { return {}; } } async function* maskStreamTags(stream, tag, options = {}) { const { onStart, onEnd, onMask } = options; const openTag = `<${tag}>`; const closeTag = `</${tag}>`; let buffer = ""; let fullContent = ""; let isMasking = false; let isBuffering = false; const trimOutsideDelimiter = (text, delimiter, trim) => { if (!text.includes(delimiter)) { return text; } const parts = text.split(delimiter); if (trim === `before-start`) { return `${delimiter}${parts[1]}`; } return `${parts[0]}${delimiter}`; }; const startsWith = (text, pattern) => { if (pattern.includes(openTag.substring(0, 3))) { pattern = trimOutsideDelimiter(pattern, `<`, `before-start`); } return text.trim().startsWith(pattern.trim()); }; for await (const chunk of stream) { fullContent += chunk; if (isBuffering) buffer += chunk; const chunkHasTag = startsWith(chunk, openTag); const bufferHasTag = !chunkHasTag && isBuffering && startsWith(openTag, buffer); let toYieldBeforeMaskedStartTag = ``; if (!isMasking && (chunkHasTag || bufferHasTag)) { isMasking = true; isBuffering = false; const taggedTextToMask = trimOutsideDelimiter(buffer, `<`, `before-start`); if (taggedTextToMask !== buffer.trim()) { toYieldBeforeMaskedStartTag = buffer.replace(taggedTextToMask, ``); } buffer = ""; onStart?.(); } if (!isMasking && !isBuffering && startsWith(openTag, chunk) && chunk.trim() !== "") { isBuffering = true; buffer += chunk; continue; } if (isBuffering && buffer && !startsWith(openTag, buffer)) { yield buffer; buffer = ""; isBuffering = false; continue; } if (isMasking && fullContent.includes(closeTag)) { onMask?.(chunk); onEnd?.(); isMasking = false; const lastFullContent = fullContent; fullContent = ``; const textUntilEndTag = trimOutsideDelimiter(lastFullContent, closeTag, "after-end"); if (textUntilEndTag !== lastFullContent) { yield lastFullContent.replace(textUntilEndTag, ``); } continue; } if (isMasking) { onMask?.(chunk); if (toYieldBeforeMaskedStartTag) { yield toYieldBeforeMaskedStartTag; } continue; } yield chunk; } } function resolveSerializedZodOutput(schema) { return Function("z", `"use strict";return (${schema});`)(zod.z); } function isZodType(value) { return typeof value === "object" && value !== null && "_def" in value && "parse" in value && typeof value.parse === "function" && "safeParse" in value && typeof value.safeParse === "function"; } function createDeterministicId(input) { return crypto$1.createHash("sha256").update(input).digest("hex").slice(0, 8); } function setVercelToolProperties(tool) { const inputSchema = "inputSchema" in tool ? tool.inputSchema : convertVercelToolParameters(tool); const toolId = !("id" in tool) ? tool.description ? `tool-${createDeterministicId(tool.description)}` : `tool-${Math.random().toString(36).substring(2, 9)}` : tool.id; return { ...tool, id: toolId, inputSchema }; } function ensureToolProperties(tools) { const toolsWithProperties = Object.keys(tools).reduce((acc, key) => { const tool = tools?.[key]; if (tool) { if (chunkVF676YCO_cjs.isVercelTool(tool)) { acc[key] = setVercelToolProperties(tool); } else { acc[key] = tool; } } return acc; }, {}); return toolsWithProperties; } function convertVercelToolParameters(tool) { let schema = tool.parameters ?? zod.z.object({}); if (typeof schema === "function") { schema = schema(); } return isZodType(schema) ? schema : resolveSerializedZodOutput(jsonSchemaToZod__default.default(schema)); } function makeCoreTool(originalTool, options, logType) { return new CoreToolBuilder({ originalTool, options, logType }).build(); } function makeCoreToolV5(originalTool, options, logType) { return new CoreToolBuilder({ originalTool, options, logType }).buildV5(); } function createMastraProxy({ mastra, logger }) { return new Proxy(mastra, { get(target, prop) { const hasProp = Reflect.has(target, prop); if (hasProp) { const value = Reflect.get(target, prop); const isFunction = typeof value === "function"; if (isFunction) { return value.bind(target); } return value; } if (prop === "logger") { logger.warn(`Please use 'getLogger' instead, logger is deprecated`); return Reflect.apply(target.getLogger, target, []); } if (prop === "telemetry") { logger.warn(`Please use 'getTelemetry' instead, telemetry is deprecated`); return Reflect.apply(target.getTelemetry, target, []); } if (prop === "storage") { logger.warn(`Please use 'getStorage' instead, storage is deprecated`); return Reflect.get(target, "storage"); } if (prop === "agents") { logger.warn(`Please use 'getAgents' instead, agents is deprecated`); return Reflect.apply(target.getAgents, target, []); } if (prop === "tts") { logger.warn(`Please use 'getTTS' instead, tts is deprecated`); return Reflect.apply(target.getTTS, target, []); } if (prop === "vectors") { logger.warn(`Please use 'getVectors' instead, vectors is deprecated`); return Reflect.apply(target.getVectors, target, []); } if (prop === "memory") { logger.warn(`Please use 'getMemory' instead, memory is deprecated`); return Reflect.get(target, "memory"); } return Reflect.get(target, prop); } }); } function checkEvalStorageFields(traceObject, logger) { const missingFields = []; if (!traceObject.input) missingFields.push("input"); if (!traceObject.output) missingFields.push("output"); if (!traceObject.agentName) missingFields.push("agent_name"); if (!traceObject.metricName) missingFields.push("metric_name"); if (!traceObject.instructions) missingFields.push("instructions"); if (!traceObject.globalRunId) missingFields.push("global_run_id"); if (!traceObject.runId) missingFields.push("run_id"); if (missingFields.length > 0) { if (logger) { logger.warn("Skipping evaluation storage due to missing required fields", { missingFields, runId: traceObject.runId, agentName: traceObject.agentName }); } else { console.warn("Skipping evaluation storage due to missing required fields", { missingFields, runId: traceObject.runId, agentName: traceObject.agentName }); } return false; } return true; } function detectSingleMessageCharacteristics(message) { if (typeof message === "object" && message !== null && (message.role === "function" || // UI-only role message.role === "data" || // UI-only role "toolInvocations" in message || // UI-specific field "parts" in message || // UI-specific field "experimental_attachments" in message)) { return "has-ui-specific-parts"; } else if (typeof message === "object" && message !== null && "content" in message && (Array.isArray(message.content) || // Core messages can have array content "experimental_providerMetadata" in message || "providerOptions" in message)) { return "has-core-specific-parts"; } else if (typeof message === "object" && message !== null && "role" in message && "content" in message && typeof message.content === "string" && ["system", "user", "assistant", "tool"].includes(message.role)) { return "message"; } else { return "other"; } } function isUiMessage(message) { return detectSingleMessageCharacteristics(message) === `has-ui-specific-parts`; } function isCoreMessage(message) { return [`has-core-specific-parts`, `message`].includes(detectSingleMessageCharacteristics(message)); } var SQL_IDENTIFIER_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_]*$/; function parseSqlIdentifier(name, kind = "identifier") { if (!SQL_IDENTIFIER_PATTERN.test(name) || name.length > 63) { throw new Error( `Invalid ${kind}: ${name}. Must start with a letter or underscore, contain only letters, numbers, or underscores, and be at most 63 characters long.` ); } return name; } function parseFieldKey(key) { if (!key) throw new Error("Field key cannot be empty"); const segments = key.split("."); for (const segment of segments) { if (!SQL_IDENTIFIER_PATTERN.test(segment) || segment.length > 63) { throw new Error(`Invalid field key segment: ${segment} in ${key}`); } } return key; } async function fetchWithRetry(url, options = {}, maxRetries = 3) { let retryCount = 0; let lastError = null; while (retryCount < maxRetries) { try { const response = await fetch(url, options); if (!response.ok) { throw new Error(`Request failed with status: ${response.status} ${response.statusText}`); } return response; } catch (error) { lastError = error instanceof Error ? error : new Error(String(error)); retryCount++; if (retryCount >= maxRetries) { break; } const delay2 = Math.min(1e3 * Math.pow(2, retryCount) * 1e3, 1e4); await new Promise((resolve) => setTimeout(resolve, delay2)); } } throw lastError || new Error("Request failed after multiple retry attempts"); } // src/ai-tracing/exporters/cloud.ts var CloudExporter = class extends BaseExporter { name = "mastra-cloud-ai-tracing-exporter"; config; buffer; flushTimer = null; constructor(config = {}) { super(config); const accessToken = config.accessToken ?? process.env.MASTRA_CLOUD_ACCESS_TOKEN; if (!accessToken) { this.setDisabled( "MASTRA_CLOUD_ACCESS_TOKEN environment variable not set.\n\u{1F680} Sign up at https://cloud.mastra.ai to see your AI traces online and obtain your access token." ); } const endpoint = config.endpoint ?? process.env.MASTRA_CLOUD_AI_TRACES_ENDPOINT ?? "https://api.mastra.ai/ai/spans/publish"; this.config = { logger: this.logger, logLevel: config.logLevel ?? chunkA5KDVZDL_cjs.LogLevel.INFO, maxBatchSize: config.maxBatchSize ?? 1e3, maxBatchWaitMs: config.maxBatchWaitMs ?? 5e3, maxRetries: config.maxRetries ?? 3, accessToken: accessToken || "", endpoint }; this.buffer = { spans: [], totalSize: 0 }; } async _exportEvent(event) { if (event.type !== "span_ended" /* SPAN_ENDED */) { return; } this.addToBuffer(event); if (this.shouldFlush()) { this.flush().catch((error) => { this.logger.error("Batch flush failed", { error: error instanceof Error ? error.message : String(error) }); }); } else if (this.buffer.totalSize === 1) { this.scheduleFlush(); } } addToBuffer(event) { if (this.buffer.totalSize === 0) { this.buffer.firstEventTime = /* @__PURE__ */ new Date(); } const spanRecord = this.formatSpan(event.exportedSpan); this.buffer.spans.push(spanRecord); this.buffer.totalSize++; } formatSpan(span) { const spanRecord = { traceId: span.traceId, spanId: span.id, parentSpanId: span.parentSpanId ?? null, name: span.name, spanType: span.type, attributes: span.attributes ?? null, metadata: span.metadata ?? null, startedAt: span.startTime, endedAt: span.endTime ?? null, input: span.input ?? null, output: span.output ?? null, error: span.errorInfo, isEvent: span.isEvent, createdAt: /* @__PURE__ */ new Date(), updatedAt: null }; return spanRecord; } shouldFlush() { if (this.buffer.totalSize >= this.config.maxBatchSize) { return true; } if (this.buffer.firstEventTime && this.buffer.totalSize > 0) { const elapsed = Date.now() - this.buffer.firstEventTime.getTime(); if (elapsed >= this.config.maxBatchWaitMs) { return true; } } return false; } scheduleFlush() { if (this.flushTimer) { clearTimeout(this.flushTimer); } this.flushTimer = setTimeout(() => { this.flush().catch((error) => { const mastraError = new chunk5NTO7S5I_cjs.MastraError( { id: `CLOUD_AI_TRACING_FAILED_TO_SCHEDULE_FLUSH`, domain: "MASTRA_OBSERVABILITY" /* MASTRA_OBSERVABILITY */, category: "USER" /* USER */ }, error ); this.logger.trackException(mastraError); this.logger.error("Scheduled flush failed", mastraError); }); }, this.config.maxBatchWaitMs); } async flush() { if (this.flushTimer) { clearTimeout(this.flushTimer); this.flushTimer = null; } if (this.buffer.totalSize === 0) { return; } const startTime = Date.now(); const spansCopy = [...this.buffer.spans]; const flushReason = this.buffer.totalSize >= this.config.maxBatchSize ? "size" : "time"; this.resetBuffer(); try { await this.batchUpload(spansCopy); const elapsed = Date.now() - startTime; this.logger.debug("Batch flushed successfully", { batchSize: spansCopy.length, flushReason, durationMs: elapsed }); } catch (error) { const mastraError = new chunk5NTO7S5I_cjs.MastraError( { id: `CLOUD_AI_TRACING_FAILED_TO_BATCH_UPLOAD`, domain: "MASTRA_OBSERVABILITY" /* MASTRA_OBSERVABILITY */, category: "USER" /* USER */, details: { droppedBatchSize: spansCopy.length } }, error ); this.logger.trackException(mastraError); this.logger.error("Batch upload failed after all retries, dropping batch", mastraError); } } /** * Uploads spans to cloud API using fetchWithRetry for all retry logic */ async batchUpload(spans) { const headers = { Authorization: `Bearer ${this.config.accessToken}`, "Content-Type": "application/json" }; const options = { method: "POST", headers, body: JSON.stringify({ spans }) }; await fetchWithRetry(this.config.endpoint, options, this.config.maxRetries); } resetBuffer() { this.buffer.spans = []; this.buffer.firstEventTime = void 0; this.buffer.totalSize = 0; } async shutdown() { if (this.isDisabled) { return; } if (this.flushTimer) { clearTimeout(this.flushTimer); this.flushTimer = null; } if (this.buffer.totalSize > 0) { this.logger.info("Flushing remaining events on shutdown", { remainingEvents: this.buffer.totalSize }); try { await this.flush(); } catch (error) { const mastraError = new chunk5NTO7S5I_cjs.MastraError( { id: `CLOUD_AI_TRACING_FAILED_TO_FLUSH_REMAINING_EVENTS_DURING_SHUTDOWN`, domain: "MASTRA_OBSERVABILITY" /* MASTRA_OBSERVABILITY */, category: "USER" /* USER */, details: { remainingEvents: this.buffer.totalSize } }, error ); this.logger.trackException(mastraError); this.logger.error("Failed to flush remaining events during shutdown", mastraError); } } this.logger.info("CloudExporter shutdown complete"); } }; // src/ai-tracing/exporters/console.ts var ConsoleExporter = class extends BaseExporter { name = "tracing-console-exporter"; constructor(config = {}) { super(config); } async _exportEvent(event) { const span = event.exportedSpan; const formatAttributes = (attributes) => { try { return JSON.stringify(attributes, null, 2); } catch (error) { const errMsg = error instanceof Error ? error.message : "Unknown formatting error"; return `[Unable to serialize attributes: ${errMsg}]`; } }; const formatDuration = (startTime, endTime) => { if (!endTime) return "N/A"; const duration = endTime.getTime() - startTime.getTime(); return `${duration}ms`; }; switch (event.type) { case "span_started" /* SPAN_STARTED */: this.logger.info(`\u{1F680} SPAN_STARTED`); this.logger.info(` Type: ${span.type}`); this.logger.info(` Name: ${span.name}`); this.logger.info(` ID: ${span.id}`); this.logger.info(` Trace ID: ${span.traceId}`); if (span.input !== void 0) { this.logger.info(` Input: ${formatAttributes(span.input)}`); } this.logger.info(` Attributes: ${formatAttributes(span.attributes)}`); this.logger.info("\u2500".repeat(80)); break; case "span_ended" /* SPAN_ENDED */: const duration = formatDuration(span.startTime, span.endTime); this.logger.info(`\u2705 SPAN_ENDED`); this.logger.info(` Type: ${span.type}`); this.logger.info(` Name: ${span.name}`); this.logger.info(` ID: ${span.id}`); this.logger.info(` Duration: ${duration}`); this.logger.info(` Trace ID: ${span.traceId}`); if (span.input !== void 0) { this.logger.info(` Input: ${formatAttributes(span.input)}`); } if (span.output !== void 0) { this.logger.info(` Output: ${formatAttributes(span.output)}`); } if (span.errorInfo) { this.logger.info(` Error: ${formatAttributes(span.errorInfo)}`); } this.logger.info(` Attributes: ${formatAttributes(span.attributes)}`); this.logger.info("\u2500".repeat(80)); break; case "span_updated" /* SPAN_UPDATED */: this.logger.info(`\u{1F4DD} SPAN_UPDATED`); this.logger.info(` Type: ${span.type}`); this.logger.info(` Name: ${span.name}`); this.logger.info(` ID: ${span.id}`); this.logger.info(` Trace ID: ${span.traceId}`); if (span.input !== void 0) { this.logger.info(` Input: ${formatAttributes(span.input)}`); } if (span.output !== void 0) { this.logger.info(` Output: ${formatAttributes(span.output)}`); } if (span.errorInfo) { this.logger.info(` Error: ${formatAttributes(span.errorInfo)}`); } this.logger.info(` Updated Attributes: ${formatAttributes(span.attributes)}`); this.logger.info("\u2500".repeat(80)); break; default: this.logger.warn(`Tracing event type not implemented: ${event.type}`); } } async shutdown() { this.logger.info("ConsoleExporter shutdown"); } }; // src/ai-tracing/exporters/default.ts function resolveStrategy(userConfig, storage, logger) { if (userConfig.strategy && userConfig.strategy !== "auto") { const hints = storage.aiTracingStrategy; if (hints.supported.includes(userConfig.strategy)) { return userConfig.strategy; } logger.warn("User-specified AI tracing strategy not supported by storage adapter, falling back to auto-selection", { userStrategy: userConfig.strategy, storageAdapter: storage.constructor.name, supportedStrategies: hints.supported, fallbackStrategy: hints.preferred }); } return storage.aiTracingStrategy.preferred; } var DefaultExporter = class { name = "tracing-default-exporter"; logger; mastra = null; config; resolvedStrategy; buffer; flushTimer = null; // Track all spans that have been created, persists across flushes allCreatedSpans = /* @__PURE__ */ new Set(); constructor(config = {}, logger) { if (logger) { this.logger = logger; } else { this.logger = new chunkA5KDVZDL_cjs.ConsoleLogger({ level: chunkA5KDVZDL_cjs.LogLevel.INFO }); } this.config = { maxBatchSize: config.maxBatchSize ?? 1e3, maxBufferSize: config.maxBufferSize ?? 1e4, maxBatchWaitMs: config.maxBatchWaitMs ?? 5e3, maxRetries: config.maxRetries ?? 4, retryDelayMs: config.retryDelayMs ?? 500, strategy: config.strategy ?? "auto" }; this.buffer = { creates: [], updates: [], insertOnly: [], seenSpans: /* @__PURE__ */ new Set(), spanSequences: /* @__PURE__ */ new Map(), completedSpans: /* @__PURE__ */ new Set(), outOfOrderCount: 0, totalSize: 0 }; this.resolvedStrategy = "batch-with-updates"; } strategyInitialized = false; /** * Register the Mastra instance (called after Mastra construction is complete) */ __registerMastra(mastra) { this.mastra = mastra; } /** * Initialize the exporter (called after all dependencies are ready) */ init(_config) { if (!this.mastra) { throw new Error("DefaultExporter: init() called before __registerMastra()"); } const storage = this.mastra.getStorage(); if (!storage) { this.logger.warn("DefaultExporter disabled: Storage not available. Traces will not be persisted."); return; } this.initializeStrategy(storage); } /** * Initialize the resolved strategy once storage is available */ initializeStrategy(storage) { if (this.strategyInitialized) return; this.resolvedStrategy = resolveStrategy(this.config, storage, this.logger); this.strategyInitialized = true; this.logger.debug("AI tracing exporter initialized", { strategy: this.resolvedStrategy, source: this.config.strategy !== "auto" ? "user" : "auto", storageAdapter: storage.constructor.name, maxBatchSize: this.config.maxBatchSize, maxBatchWaitMs: this.config.maxBatchWaitMs }); } /** * Builds a unique span key for tracking */ buildSpanKey(traceId, spanId) { return `${traceId}:${spanId}`; } /** * Gets the next sequence number for a span */ getNextSequence(spanKey) { const current = this.buffer.spanSequences.get(spanKey) || 0; const next = current + 1; this.buffer.spanSequences.set(spanKey, next); return next; } /** * Handles out-of-order span updates by logging and skipping */ handleOutOfOrderUpdate(event) { this.logger.warn("Out-of-order span update detected - skipping event", { spanId: event.exportedSpan.id, traceId: event.exportedSpan.traceId, spanName: event.exportedSpan.name, eventType: event.type }); } /** * Adds an event to the appropriate buffer based on strategy */ addToBuffer(event) { const spanKey = this.buildSpanKey(event.exportedSpan.traceId, event.exportedSpan.id); if (this.buffer.totalSize === 0) { this.buffer.firstEventTime = /* @__PURE__ */ new Date(); } switch (event.type) { case "span_started" /* SPAN_STARTED */: if (this.resolvedStrategy === "batch-with-updates") { const createRecord = this.buildCreateRecord(event.exportedSpan); this.buffer.creates.push(createRecord); this.buffer.seenSpans.add(spanKey); this.allCreatedSpans.add(spanKey); } break; case "span_updated" /* SPAN_UPDATED */: if (this.resolvedStrategy === "batch-with-updates") { if (this.allCreatedSpans.has(spanKey)) { this.buffer.updates.push({ traceId: event.exportedSpan.traceId, spanId: event.exportedSpan.id, updates: this.buildUpdateRecord(event.exportedSpan), sequenceNumber: this.getNextSequence(spanKey) }); } else { this.handleOutOfOrderUpdate(event); this.buffer.outOfOrderCount++; } } break; case "span_ended" /* SPAN_ENDED */: if (this.resolvedStrategy === "batch-with-updates") { if (this.allCreatedSpans.has(spanKey)) { this.buffer.updates.push({ traceId: event.exportedSpan.traceId, spanId: event.exportedSpan.id, updates: this.buildUpdateRecord(event.exportedSpan), sequenceNumber: this.getNextSequence(spanKey) }); this.buffer.completedSpans.add(spanKey); } else if (event.exportedSpan.isEvent) { const createRecord = this.buildCreateRecord(event.exportedSpan); this.buffer.creates.push(createRecord); this.buffer.seenSpans.add(spanKey); this.allCreatedSpans.add(spanKey); this.buffer.completedSpans.add(spanKey); } else { this.handleOutOfOrderUpdate(event); this.buffer.outOfOrderCount++; } } else if (this.resolvedStrategy === "insert-only") { const createRecord = this.buildCreateRecord(event.exportedSpan); this.buffer.insertOnly.push(createRecord); this.buffer.completedSpans.add(spanKey); this.allCreatedSpans.add(spanKey); } break; } this.buffer.totalSize = this.buffer.creates.length + this.buffer.updates.length + this.buffer.insertOnly.length; } /** * Checks if buffer should be flushed based on size or time triggers */ shouldFlush() { if (this.buffer.totalSize >= this.config.maxBufferSize) { return true; } if (this.buffer.totalSize >= this.config.maxBatchSize) { return true; } if (this.buffer.firstEventTime &