@mastra/core
Version:
The core foundation of the Mastra framework, providing essential components and interfaces for building AI-powered applications.
409 lines (402 loc) • 14.8 kB
JavaScript
;
var chunk4Z3OU5RY_cjs = require('./chunk-4Z3OU5RY.cjs');
var chunkU3XRKJNN_cjs = require('./chunk-U3XRKJNN.cjs');
var chunkP3Q73CAW_cjs = require('./chunk-P3Q73CAW.cjs');
var chunkLABUWBKX_cjs = require('./chunk-LABUWBKX.cjs');
var crypto = require('crypto');
var jsonSchemaToZod = require('json-schema-to-zod');
var zod = require('zod');
var schemaCompat = require('@mastra/schema-compat');
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
var jsonSchemaToZod__default = /*#__PURE__*/_interopDefault(jsonSchemaToZod);
var CoreToolBuilder = class extends chunkP3Q73CAW_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 (chunk4Z3OU5RY_cjs.isVercelTool(this.originalTool)) {
return this.originalTool.parameters ?? zod.z.object({});
}
return this.originalTool.inputSchema ?? zod.z.object({});
};
// 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(".")) {
return {
type: "provider-defined",
id: tool.id,
args: "args" in this.originalTool ? this.originalTool.args : {},
description: tool.description,
parameters: schemaCompat.convertZodSchemaToAISDKSchema(this.getParameters()),
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) {
const { logger, mastra: _mastra, memory: _memory, runtimeContext, ...rest } = options;
const { start, error } = this.createLogMessageOptions({
agentName: options.agentName,
toolName: options.name,
type: logType
});
const execFunction = async (args, execOptions) => {
if (chunk4Z3OU5RY_cjs.isVercelTool(tool)) {
return tool?.execute?.(args, execOptions) ?? void 0;
}
return tool?.execute?.(
{
context: args,
threadId: options.threadId,
resourceId: options.resourceId,
mastra: options.mastra,
memory: options.memory,
runId: options.runId,
runtimeContext: options.runtimeContext ?? new chunkLABUWBKX_cjs.RuntimeContext()
},
execOptions
) ?? void 0;
};
return async (args, execOptions) => {
let logger2 = options.logger || this.logger;
try {
logger2.debug(start, { ...rest, args });
return await execFunction(args, execOptions);
} catch (err) {
const mastraError = new chunkU3XRKJNN_cjs.MastraError(
{
id: "TOOL_EXECUTION_FAILED",
domain: "TOOL" /* TOOL */,
category: "USER" /* USER */,
details: {
error,
args,
model: rest.model?.modelId ?? ""
}
},
err
);
logger2.trackException(mastraError);
logger2.error(error, { ...rest, error: mastraError, args });
throw mastraError;
}
};
}
build() {
const providerTool = this.buildProviderTool(this.originalTool);
if (providerTool) {
return providerTool;
}
const definition = {
type: "function",
description: this.originalTool.description,
parameters: this.getParameters(),
execute: this.originalTool.execute ? this.createExecute(
this.originalTool,
{ ...this.options, description: this.originalTool.description },
this.logType
) : void 0
};
const model = this.options.model;
const schemaCompatLayers = [];
if (model) {
schemaCompatLayers.push(
new schemaCompat.OpenAIReasoningSchemaCompatLayer(model),
new schemaCompat.OpenAISchemaCompatLayer(model),
new schemaCompat.GoogleSchemaCompatLayer(model),
new schemaCompat.AnthropicSchemaCompatLayer(model),
new schemaCompat.DeepSeekSchemaCompatLayer(model),
new schemaCompat.MetaSchemaCompatLayer(model)
);
}
const processedSchema = schemaCompat.applyCompatLayer({
schema: this.getParameters(),
compatLayers: schemaCompatLayers,
mode: "aiSdkSchema"
});
return {
...definition,
parameters: processedSchema
};
}
};
// 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;
}
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.createHash("sha256").update(input).digest("hex").slice(0, 8);
}
function setVercelToolProperties(tool) {
const 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 (chunk4Z3OU5RY_cjs.isVercelTool(tool)) {
acc[key] = setVercelToolProperties(tool);
} else {
acc[key] = tool;
}
}
return acc;
}, {});
return toolsWithProperties;
}
function convertVercelToolParameters(tool) {
const schema = tool.parameters ?? zod.z.object({});
return isZodType(schema) ? schema : resolveSerializedZodOutput(jsonSchemaToZod__default.default(schema));
}
function makeCoreTool(originalTool, options, logType) {
return new CoreToolBuilder({ originalTool, options, logType }).build();
}
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;
}
exports.checkEvalStorageFields = checkEvalStorageFields;
exports.createMastraProxy = createMastraProxy;
exports.deepMerge = deepMerge;
exports.delay = delay;
exports.ensureToolProperties = ensureToolProperties;
exports.isCoreMessage = isCoreMessage;
exports.isUiMessage = isUiMessage;
exports.isZodType = isZodType;
exports.makeCoreTool = makeCoreTool;
exports.maskStreamTags = maskStreamTags;
exports.parseFieldKey = parseFieldKey;
exports.parseSqlIdentifier = parseSqlIdentifier;
exports.resolveSerializedZodOutput = resolveSerializedZodOutput;