@mastra/core
Version:
The core foundation of the Mastra framework, providing essential components and interfaces for building AI-powered applications.
454 lines (447 loc) • 16.2 kB
JavaScript
var chunkLABUWBKX_cjs = require('./chunk-LABUWBKX.cjs');
var crypto = require('crypto');
var ai = require('ai');
var jsonSchemaToZod = require('json-schema-to-zod');
var zod = require('zod');
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
var jsonSchemaToZod__default = /*#__PURE__*/_interopDefault(jsonSchemaToZod);
// src/tools/tool.ts
var Tool = class {
id;
description;
inputSchema;
outputSchema;
execute;
mastra;
constructor(opts) {
this.id = opts.id;
this.description = opts.description;
this.inputSchema = opts.inputSchema;
this.outputSchema = opts.outputSchema;
this.execute = opts.execute;
this.mastra = opts.mastra;
}
};
function createTool(opts) {
return new Tool(opts);
}
var delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
function jsonSchemaPropertiesToTSTypes(value) {
if (!value?.type) {
return zod.z.object({});
}
if (Array.isArray(value.type)) {
const types = value.type.map((type) => {
return jsonSchemaPropertiesToTSTypes({ ...value, type });
});
return zod.z.union(types).describe((value.description || "") + (value.examples ? `
Examples: ${value.examples.join(", ")}` : ""));
}
let zodType;
switch (value.type) {
case "string":
zodType = zod.z.string().describe((value.description || "") + (value.examples ? `
Examples: ${value.examples.join(", ")}` : ""));
break;
case "number":
zodType = zod.z.number().describe((value.description || "") + (value.examples ? `
Examples: ${value.examples.join(", ")}` : ""));
break;
case "integer":
zodType = zod.z.number().int().describe((value.description || "") + (value.examples ? `
Examples: ${value.examples.join(", ")}` : ""));
break;
case "boolean":
zodType = zod.z.boolean().describe((value.description || "") + (value.examples ? `
Examples: ${value.examples.join(", ")}` : ""));
break;
case "array":
if (!value.items || !value.items?.type) {
value.items = value.items ? { ...value.items, type: "string" } : { type: "string" };
}
zodType = zod.z.array(jsonSchemaPropertiesToTSTypes(value.items)).describe((value.description || "") + (value.examples ? `
Examples: ${value.examples.join(", ")}` : ""));
break;
case "object":
zodType = jsonSchemaToModel(value).describe(
(value.description || "") + (value.examples ? `
Examples: ${value.examples.join(", ")}` : "")
);
break;
case "null":
zodType = zod.z.null().describe(value.description || "");
break;
default:
throw new Error(`Unsupported JSON schema type: ${value.type}`);
}
return zodType;
}
function jsonSchemaToModel(jsonSchema) {
const properties = jsonSchema.properties;
const requiredFields = jsonSchema.required || [];
if (!properties) {
return zod.z.object({});
}
const zodSchema = {};
for (const [key, _] of Object.entries(properties)) {
const value = _;
let zodType;
if (value.anyOf) {
const anyOfTypes = value.anyOf.map((schema) => jsonSchemaPropertiesToTSTypes(schema));
zodType = zod.z.union(anyOfTypes).describe((value.description || "") + (value.examples ? `
Examples: ${value.examples.join(", ")}` : ""));
} else if (value.allOf) {
const allOfTypes = value.allOf.map((schema) => jsonSchemaPropertiesToTSTypes(schema));
zodType = zod.z.intersection(
allOfTypes[0],
allOfTypes.slice(1).reduce((acc, schema) => acc.and(schema), allOfTypes[0])
).describe((value.description || "") + (value.examples ? `
Examples: ${value.examples.join(", ")}` : ""));
} else {
if (!value.type) {
value.type = "string";
}
zodType = jsonSchemaPropertiesToTSTypes(value);
}
if (value.description) {
zodType = zodType.describe(value.description);
}
const isTypeRequired = value.type === "null";
if (requiredFields.includes(key) || isTypeRequired) {
zodSchema[key] = zodType;
} else {
zodSchema[key] = zodType.nullable().optional();
}
}
return zod.z.object(zodSchema);
}
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 isVercelTool(tool) {
return !!(tool && !(tool instanceof Tool) && "parameters" in tool);
}
function 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`
};
}
function createExecute(tool, options, logType) {
const { logger, mastra: _mastra, memory: _memory, runtimeContext, ...rest } = options;
const { start, error } = createLogMessageOptions({
agentName: options.agentName,
toolName: options.name,
type: logType
});
const execFunction = async (args, execOptions) => {
if (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: runtimeContext ?? new chunkLABUWBKX_cjs.RuntimeContext()
},
execOptions
) ?? void 0;
};
return async (args, execOptions) => {
try {
logger.debug(start, { ...rest, args });
return await execFunction(args, execOptions);
} catch (err) {
logger.error(error, { ...rest, error: err, args });
throw err;
}
};
}
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 (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 convertInputSchema(tool) {
const schema = tool.inputSchema ?? zod.z.object({});
return isZodType(schema) ? schema : resolveSerializedZodOutput(jsonSchemaToZod__default.default(schema));
}
function makeCoreTool(tool, options, logType) {
const getParameters = () => {
if (isVercelTool(tool)) {
return convertVercelToolParameters(tool);
}
return convertInputSchema(tool);
};
const isProviderDefined = "type" in tool && tool.type === "provider-defined" && "id" in tool && typeof tool.id === "string" && tool.id.includes(".");
if (isProviderDefined) {
return {
type: "provider-defined",
id: tool.id,
args: "args" in tool ? tool.args : {},
description: tool.description,
parameters: getParameters(),
execute: tool.execute ? createExecute(tool, { ...options, description: tool.description }, logType) : void 0
};
}
return {
type: "function",
description: tool.description,
parameters: getParameters(),
execute: tool.execute ? createExecute(tool, { ...options, description: tool.description }, logType) : void 0
};
}
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));
}
function ensureAllMessagesAreCoreMessages(messages) {
return messages.map((message) => {
if (isUiMessage(message)) {
return ai.convertToCoreMessages([message]);
}
if (isCoreMessage(message)) {
return message;
}
const characteristics = detectSingleMessageCharacteristics(message);
throw new Error(
`Message does not appear to be a core message or a UI message but must be one of the two, found "${characteristics}" type for message:
${JSON.stringify(message, null, 2)}
`
);
}).flat();
}
exports.Tool = Tool;
exports.checkEvalStorageFields = checkEvalStorageFields;
exports.createMastraProxy = createMastraProxy;
exports.createTool = createTool;
exports.deepMerge = deepMerge;
exports.delay = delay;
exports.ensureAllMessagesAreCoreMessages = ensureAllMessagesAreCoreMessages;
exports.ensureToolProperties = ensureToolProperties;
exports.isVercelTool = isVercelTool;
exports.isZodType = isZodType;
exports.jsonSchemaPropertiesToTSTypes = jsonSchemaPropertiesToTSTypes;
exports.jsonSchemaToModel = jsonSchemaToModel;
exports.makeCoreTool = makeCoreTool;
exports.maskStreamTags = maskStreamTags;
exports.resolveSerializedZodOutput = resolveSerializedZodOutput;
;