UNPKG

@mastra/core

Version:

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

1,680 lines (1,673 loc) 127 kB
'use strict'; var chunkKXWR3FNX_cjs = require('./chunk-KXWR3FNX.cjs'); var chunkZMMZXEOL_cjs = require('./chunk-ZMMZXEOL.cjs'); var chunkUVRGQEMD_cjs = require('./chunk-UVRGQEMD.cjs'); var chunkFXAV2WYX_cjs = require('./chunk-FXAV2WYX.cjs'); var chunkRO52JMKQ_cjs = require('./chunk-RO52JMKQ.cjs'); var chunkO7IW545H_cjs = require('./chunk-O7IW545H.cjs'); var chunkLABUWBKX_cjs = require('./chunk-LABUWBKX.cjs'); var chunkST5RMVLG_cjs = require('./chunk-ST5RMVLG.cjs'); var chunkRWTSGWWL_cjs = require('./chunk-RWTSGWWL.cjs'); var api = require('@opentelemetry/api'); var zod = require('zod'); var radash = require('radash'); var crypto$1 = require('crypto'); var EventEmitter = require('events'); var sift = require('sift'); var xstate = require('xstate'); function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; } var EventEmitter__default = /*#__PURE__*/_interopDefault(EventEmitter); var sift__default = /*#__PURE__*/_interopDefault(sift); // src/workflows/step.ts var Step = class { id; description; inputSchema; outputSchema; payload; execute; retryConfig; mastra; constructor({ id, description, execute, payload, outputSchema, inputSchema, retryConfig }) { this.id = id; this.description = description ?? ""; this.inputSchema = inputSchema; this.payload = payload; this.outputSchema = outputSchema; this.execute = execute; this.retryConfig = retryConfig; } }; // src/workflows/types.ts var WhenConditionReturnValue = /* @__PURE__ */(WhenConditionReturnValue2 => { WhenConditionReturnValue2["CONTINUE"] = "continue"; WhenConditionReturnValue2["CONTINUE_FAILED"] = "continue_failed"; WhenConditionReturnValue2["ABORT"] = "abort"; WhenConditionReturnValue2["LIMBO"] = "limbo"; return WhenConditionReturnValue2; })(WhenConditionReturnValue || {}); function resoolveMaybePromise(value, cb) { if (value instanceof Promise) { return value.then(cb); } return cb(value); } var _Agent_decorators, _init, _a; _Agent_decorators = [chunkUVRGQEMD_cjs.InstrumentClass({ prefix: "agent", excludeMethods: ["hasOwnMemory", "getMemory", "__primitive", "__registerMastra", "__registerPrimitives", "__setTools", "__setLogger", "__setTelemetry", "log", "getModel", "getInstructions", "getTools", "getLLM"] })]; exports.Agent = class Agent extends (_a = chunkRO52JMKQ_cjs.MastraBase) { id; name; #instructions; model; #mastra; #memory; #defaultGenerateOptions; #defaultStreamOptions; #tools; /** @deprecated This property is deprecated. Use evals instead. */ metrics; evals; #voice; constructor(config) { super({ component: chunkO7IW545H_cjs.RegisteredLogger.AGENT }); this.name = config.name; this.id = config.name; this.#instructions = config.instructions; if (!config.model) { throw new Error(`LanguageModel is required to create an Agent. Please provide the 'model'.`); } this.model = config.model; this.#defaultGenerateOptions = config.defaultGenerateOptions || {}; this.#defaultStreamOptions = config.defaultStreamOptions || {}; this.#tools = config.tools || {}; this.metrics = {}; this.evals = {}; if (config.mastra) { this.__registerMastra(config.mastra); this.__registerPrimitives({ telemetry: config.mastra.getTelemetry(), logger: config.mastra.getLogger() }); } if (config.metrics) { this.logger.warn("The metrics property is deprecated. Please use evals instead to add evaluation metrics."); this.metrics = config.metrics; this.evals = config.metrics; } if (config.evals) { this.evals = config.evals; } if (config.memory) { this.#memory = config.memory; } if (config.voice) { this.#voice = config.voice; if (typeof config.tools !== "function") { this.#voice?.addTools(this.tools); } if (typeof config.instructions === "string") { this.#voice?.addInstructions(config.instructions); } } else { this.#voice = new chunkKXWR3FNX_cjs.DefaultVoice(); } } hasOwnMemory() { return Boolean(this.#memory); } getMemory() { return this.#memory ?? this.#mastra?.memory; } get voice() { if (typeof this.#instructions === "function") { throw new Error("Voice is not compatible when instructions are a function. Please use getVoice() instead."); } return this.#voice; } async getVoice({ runtimeContext } = {}) { if (this.#voice) { const voice = this.#voice; voice?.addTools(await this.getTools({ runtimeContext })); voice?.addInstructions(await this.getInstructions({ runtimeContext })); return voice; } else { return new chunkKXWR3FNX_cjs.DefaultVoice(); } } get instructions() { this.logger.warn("The instructions property is deprecated. Please use getInstructions() instead."); if (typeof this.#instructions === "function") { throw new Error("Instructions are not compatible when instructions are a function. Please use getInstructions() instead."); } return this.#instructions; } getInstructions({ runtimeContext = new chunkLABUWBKX_cjs.RuntimeContext() } = {}) { if (typeof this.#instructions === "string") { return this.#instructions; } const result = this.#instructions({ runtimeContext }); return resoolveMaybePromise(result, instructions => { if (!instructions) { this.logger.error(`[Agent:${this.name}] - Function-based instructions returned empty value`); throw new Error("Instructions are required to use an Agent. The function-based instructions returned an empty value."); } return instructions; }); } get tools() { this.logger.warn("The tools property is deprecated. Please use getTools() instead."); if (typeof this.#tools === "function") { throw new Error("Tools are not compatible when tools are a function. Please use getTools() instead."); } return chunkFXAV2WYX_cjs.ensureToolProperties(this.#tools); } getTools({ runtimeContext = new chunkLABUWBKX_cjs.RuntimeContext() } = {}) { if (typeof this.#tools !== "function") { return chunkFXAV2WYX_cjs.ensureToolProperties(this.#tools); } const result = this.#tools({ runtimeContext }); return resoolveMaybePromise(result, tools => { if (!tools) { this.logger.error(`[Agent:${this.name}] - Function-based tools returned empty value`); throw new Error("Tools are required when using a function to provide them. The function returned an empty value."); } return chunkFXAV2WYX_cjs.ensureToolProperties(tools); }); } get llm() { this.logger.warn("The llm property is deprecated. Please use getLLM() instead."); if (typeof this.model === "function") { throw new Error("LLM is not compatible when model is a function. Please use getLLM() instead."); } return this.getLLM(); } /** * Gets or creates an LLM instance based on the current model * @param options Options for getting the LLM * @returns A promise that resolves to the LLM instance */ getLLM({ runtimeContext = new chunkLABUWBKX_cjs.RuntimeContext() } = {}) { const model = this.getModel({ runtimeContext }); return resoolveMaybePromise(model, model2 => { const llm = new chunkZMMZXEOL_cjs.MastraLLM({ model: model2, mastra: this.#mastra }); if (this.#primitives) { llm.__registerPrimitives(this.#primitives); } if (this.#mastra) { llm.__registerMastra(this.#mastra); } return llm; }); } /** * Gets the model, resolving it if it's a function * @param options Options for getting the model * @returns A promise that resolves to the model */ getModel({ runtimeContext = new chunkLABUWBKX_cjs.RuntimeContext() } = {}) { if (typeof this.model !== "function") { if (!this.model) { this.logger.error(`[Agent:${this.name}] - No model provided`); throw new Error("Model is required to use an Agent."); } return this.model; } const result = this.model({ runtimeContext }); return resoolveMaybePromise(result, model => { if (!model) { this.logger.error(`[Agent:${this.name}] - Function-based model returned empty value`); throw new Error("Model is required to use an Agent. The function-based model returned an empty value."); } return model; }); } __updateInstructions(newInstructions) { this.#instructions = newInstructions; this.logger.debug(`[Agents:${this.name}] Instructions updated.`, { model: this.model, name: this.name }); } #primitives; __registerPrimitives(p) { if (p.telemetry) { this.__setTelemetry(p.telemetry); } if (p.logger) { this.__setLogger(p.logger); } this.#primitives = p; this.logger.debug(`[Agents:${this.name}] initialized.`, { model: this.model, name: this.name }); } __registerMastra(mastra) { this.#mastra = mastra; } /** * Set the concrete tools for the agent * @param tools */ __setTools(tools) { this.#tools = tools; this.logger.debug(`[Agents:${this.name}] Tools set for agent ${this.name}`, { model: this.model, name: this.name }); } async generateTitleFromUserMessage({ message, runtimeContext = new chunkLABUWBKX_cjs.RuntimeContext() }) { const llm = await this.getLLM({ runtimeContext }); const { text } = await llm.__text({ runtimeContext, messages: [{ role: "system", content: ` - you will generate a short title based on the first message a user begins a conversation with - ensure it is not more than 80 characters long - the title should be a summary of the user's message - do not use quotes or colons - the entire text you return will be used as the title` }, { role: "user", content: JSON.stringify(message) }] }); const cleanedText = text.replace(/<think>[\s\S]*?<\/think>/g, "").trim(); return cleanedText; } getMostRecentUserMessage(messages) { const userMessages = messages.filter(message => message.role === "user"); return userMessages.at(-1); } async genTitle(userMessage) { let title = `New Thread ${(/* @__PURE__ */new Date()).toISOString()}`; try { if (userMessage) { title = await this.generateTitleFromUserMessage({ message: userMessage }); } } catch (e) { console.error("Error generating title:", e); } return title; } async fetchMemory({ threadId, thread: passedThread, memoryConfig, resourceId, userMessages, systemMessage, runId }) { const memory = this.getMemory(); if (memory) { const thread = passedThread ?? (await memory.getThreadById({ threadId })); if (!thread) { return { threadId: threadId || "", messages: userMessages }; } const newMessages = chunkFXAV2WYX_cjs.ensureAllMessagesAreCoreMessages(userMessages); const now = Date.now(); const messages = newMessages.map((u, index) => { return { id: this.getMemory()?.generateId(), createdAt: new Date(now + index), threadId, ...u, content: u.content, role: u.role, type: "text" }; }); const [memoryMessages, memorySystemMessage] = threadId && memory ? await Promise.all([memory.rememberMessages({ threadId, resourceId, config: memoryConfig, systemMessage, vectorMessageSearch: messages.slice(-1).map(m => { if (typeof m === `string`) { return m; } return m?.content || ``; }).join(` `) }).then(r => r.messages), memory.getSystemMessage({ threadId, memoryConfig })]) : [[], null]; this.logger.debug("Saved messages to memory", { threadId, runId }); const processedMessages = memory.processMessages({ messages: this.sanitizeResponseMessages(memoryMessages), newMessages, systemMessage: typeof systemMessage?.content === `string` ? systemMessage.content : void 0, memorySystemMessage: memorySystemMessage ?? `` }); return { threadId: thread.id, messages: [memorySystemMessage ? { role: "system", content: memorySystemMessage } : null, ...processedMessages, ...newMessages].filter(message => Boolean(message)) }; } return { threadId: threadId || "", messages: userMessages }; } getResponseMessages({ messages, threadId, resourceId, now }) { if (!messages) return []; const messagesArray = Array.isArray(messages) ? messages : [messages]; return this.sanitizeResponseMessages(messagesArray).map((message, index) => { const messageId = crypto$1.randomUUID(); let toolCallIds; let toolCallArgs; let toolNames; let type = "text"; if (message.role === "tool") { toolCallIds = message.content.map(content => content.toolCallId); type = "tool-result"; } if (message.role === "assistant") { const assistantContent = message.content; const assistantToolCalls = assistantContent.map(content => { if (content.type === "tool-call") { return { toolCallId: content.toolCallId, toolArgs: content.args, toolName: content.toolName }; } return void 0; })?.filter(Boolean); toolCallIds = assistantToolCalls?.map(toolCall => toolCall.toolCallId); toolCallArgs = assistantToolCalls?.map(toolCall => toolCall.toolArgs); toolNames = assistantToolCalls?.map(toolCall => toolCall.toolName); type = assistantContent?.[0]?.type; } return { id: messageId, threadId, resourceId, role: message.role, content: message.content, createdAt: new Date(now + index), // use Date.now() + index to make sure every message is atleast one millisecond apart toolCallIds: toolCallIds?.length ? toolCallIds : void 0, toolCallArgs: toolCallArgs?.length ? toolCallArgs : void 0, toolNames: toolNames?.length ? toolNames : void 0, type }; }); } sanitizeResponseMessages(messages) { let toolResultIds = []; let toolCallIds = []; for (const message of messages) { if (!Array.isArray(message.content)) continue; if (message.role === "tool") { for (const content of message.content) { if (content.type === "tool-result") { toolResultIds.push(content.toolCallId); } } } else if (message.role === "assistant" || message.role === "user") { for (const content of message.content) { if (typeof content !== `string`) { if (content.type === `tool-call`) { toolCallIds.push(content.toolCallId); } } } } } const messagesBySanitizedContent = messages.map(message => { if (message.role !== "assistant" && message.role !== `tool` && message.role !== `user`) return message; if (!Array.isArray(message.content)) { return message; } const sanitizedContent = message.content.filter(content => { if (content.type === `tool-call`) { return toolResultIds.includes(content.toolCallId); } if (content.type === `text`) { return content.text.trim() !== ``; } if (content.type === `tool-result`) { return toolCallIds.includes(content.toolCallId); } return true; }); return { ...message, content: sanitizedContent }; }); return messagesBySanitizedContent.filter(message => { if (typeof message.content === `string`) { if (message.role === "assistant") { return true; } return message.content !== ""; } if (Array.isArray(message.content)) { return message.content.length && message.content.every(c => { if (c.type === `text`) { return c.text && c.text !== ""; } return true; }); } return true; }); } async convertTools({ toolsets, clientTools, threadId, resourceId, runId, runtimeContext }) { this.logger.debug(`[Agents:${this.name}] - Assigning tools`, { runId, threadId, resourceId }); const memory = this.getMemory(); const memoryTools = memory?.getTools?.(); let mastraProxy = void 0; const logger = this.logger; if (this.#mastra) { mastraProxy = chunkFXAV2WYX_cjs.createMastraProxy({ mastra: this.#mastra, logger }); } const tools = await this.getTools({ runtimeContext }); const convertedEntries = await Promise.all(Object.entries(tools || {}).map(async ([k, tool]) => { if (tool) { const options = { name: k, runId, threadId, resourceId, logger: this.logger, mastra: mastraProxy, memory, agentName: this.name, runtimeContext, model: typeof this.model === "function" ? await this.getModel({ runtimeContext }) : this.model }; return [k, chunkFXAV2WYX_cjs.makeCoreTool(tool, options)]; } return void 0; })); const converted = Object.fromEntries(convertedEntries.filter(entry => Boolean(entry))); let convertedMemoryTools = {}; if (memoryTools) { const memoryToolEntries = await Promise.all(Object.entries(memoryTools).map(async ([k, tool]) => { return [k, { description: tool.description, parameters: tool.parameters, execute: typeof tool?.execute === "function" ? async (args, options) => { try { this.logger.debug(`[Agent:${this.name}] - Executing memory tool ${k}`, { name: k, description: tool.description, args, runId, threadId, resourceId }); return tool?.execute?.({ context: args, mastra: mastraProxy, memory, runId, threadId, resourceId, logger: this.logger, agentName: this.name, runtimeContext }, options) ?? void 0; } catch (err) { this.logger.error(`[Agent:${this.name}] - Failed memory tool execution`, { error: err, runId, threadId, resourceId }); throw err; } } : void 0 }]; })); convertedMemoryTools = Object.fromEntries(memoryToolEntries.filter(entry => Boolean(entry))); } const toolsFromToolsetsConverted = { ...converted, ...convertedMemoryTools }; const toolsFromToolsets = Object.values(toolsets || {}); if (toolsFromToolsets.length > 0) { this.logger.debug(`[Agent:${this.name}] - Adding tools from toolsets ${Object.keys(toolsets || {}).join(", ")}`, { runId }); for (const toolset of toolsFromToolsets) { for (const [toolName, tool] of Object.entries(toolset)) { const toolObj = tool; const options = { name: toolName, runId, threadId, resourceId, logger: this.logger, mastra: mastraProxy, memory, agentName: this.name, runtimeContext, model: typeof this.model === "function" ? await this.getModel({ runtimeContext }) : this.model }; const convertedToCoreTool = chunkFXAV2WYX_cjs.makeCoreTool(toolObj, options, "toolset"); toolsFromToolsetsConverted[toolName] = convertedToCoreTool; } } } const clientToolsForInput = Object.entries(clientTools || {}); if (clientToolsForInput.length > 0) { this.logger.debug(`[Agent:${this.name}] - Adding client tools ${Object.keys(clientTools || {}).join(", ")}`, { runId }); for (const [toolName, tool] of clientToolsForInput) { const { execute, ...rest } = tool; const options = { name: toolName, runId, threadId, resourceId, logger: this.logger, mastra: mastraProxy, memory, agentName: this.name, runtimeContext, model: typeof this.model === "function" ? await this.getModel({ runtimeContext }) : this.model }; const convertedToCoreTool = chunkFXAV2WYX_cjs.makeCoreTool(rest, options, "client-tool"); toolsFromToolsetsConverted[toolName] = convertedToCoreTool; } } return toolsFromToolsetsConverted; } async preExecute({ resourceId, runId, threadId, thread, memoryConfig, messages, systemMessage }) { let coreMessages = []; let threadIdToUse = threadId; this.logger.debug(`Saving user messages in memory for agent ${this.name}`, { runId }); const saveMessageResponse = await this.fetchMemory({ threadId, thread, resourceId, userMessages: messages, memoryConfig, systemMessage }); coreMessages = saveMessageResponse.messages; threadIdToUse = saveMessageResponse.threadId; return { coreMessages, threadIdToUse }; } __primitive({ instructions, messages, context, threadId, memoryConfig, resourceId, runId, toolsets, clientTools, runtimeContext }) { return { before: async () => { if (process.env.NODE_ENV !== "test") { this.logger.debug(`[Agents:${this.name}] - Starting generation`, { runId }); } const systemMessage = { role: "system", content: instructions || `${this.instructions}.` }; let coreMessages = messages; let threadIdToUse = threadId; let thread; const memory = this.getMemory(); if (threadId && memory && !resourceId) { throw new Error(`A resourceId must be provided when passing a threadId and using Memory. Saw threadId ${threadId} but resourceId is ${resourceId}`); } if (memory && resourceId) { this.logger.debug(`[Agent:${this.name}] - Memory persistence enabled: store=${this.getMemory()?.constructor.name}, resourceId=${resourceId}`, { runId, resourceId, threadId: threadIdToUse, memoryStore: this.getMemory()?.constructor.name }); thread = threadIdToUse ? await memory.getThreadById({ threadId: threadIdToUse }) : void 0; if (!thread) { thread = await memory.createThread({ threadId: threadIdToUse, resourceId, memoryConfig }); } threadIdToUse = thread.id; const preExecuteResult = await this.preExecute({ resourceId, runId, threadId: threadIdToUse, thread, memoryConfig, messages, systemMessage }); coreMessages = preExecuteResult.coreMessages; threadIdToUse = preExecuteResult.threadIdToUse; } let convertedTools; const reasons = []; if (toolsets && Object.keys(toolsets || {}).length > 0) { reasons.push(`toolsets present (${Object.keys(toolsets || {}).length} tools)`); } if (this.getMemory() && resourceId) { reasons.push("memory and resourceId available"); } this.logger.debug(`[Agent:${this.name}] - Enhancing tools: ${reasons.join(", ")}`, { runId, toolsets: toolsets ? Object.keys(toolsets) : void 0, clientTools: clientTools ? Object.keys(clientTools) : void 0, hasMemory: !!this.getMemory(), hasResourceId: !!resourceId }); convertedTools = await this.convertTools({ toolsets, clientTools, threadId: threadIdToUse, resourceId, runId, runtimeContext }); const messageObjects = [systemMessage, ...(context || []), ...coreMessages]; return { messageObjects, convertedTools, threadId: threadIdToUse, thread }; }, after: async ({ result, thread: threadAfter, threadId: threadId2, memoryConfig: memoryConfig2, outputText, runId: runId2 }) => { const resToLog = { text: result?.text, object: result?.object, toolResults: result?.toolResults, toolCalls: result?.toolCalls, usage: result?.usage, steps: result?.steps?.map(s => { return { stepType: s?.stepType, text: result?.text, object: result?.object, toolResults: result?.toolResults, toolCalls: result?.toolCalls, usage: result?.usage }; }) }; this.logger.debug(`[Agent:${this.name}] - Post processing LLM response`, { runId: runId2, result: resToLog, threadId: threadId2 }); const memory = this.getMemory(); const thread = threadAfter || (threadId2 ? await memory?.getThreadById({ threadId: threadId2 }) : void 0); if (memory && resourceId && thread) { try { const userMessage = this.getMostRecentUserMessage(messages); const now = Date.now(); const threadMessages = this.sanitizeResponseMessages(chunkFXAV2WYX_cjs.ensureAllMessagesAreCoreMessages(messages)).map((u, index) => { return { id: this.getMemory()?.generateId(), createdAt: new Date(now + index), threadId: thread.id, resourceId, ...u, content: u.content, role: u.role, type: "text" }; }); const dateResponseMessagesFrom = (threadMessages.at(-1)?.createdAt?.getTime?.() || Date.now()) + 1; void (async () => { if (!thread.title?.startsWith("New Thread")) { return; } const config = memory.getMergedThreadConfig(memoryConfig2); const title = config?.threads?.generateTitle ? await this.genTitle(userMessage) : void 0; if (!title) { return; } return memory.createThread({ threadId: thread.id, resourceId, memoryConfig: memoryConfig2, title }); })(); let responseMessages = result.response.messages; if (!responseMessages && result.object) { responseMessages = [{ role: "assistant", content: [{ type: "text", text: outputText }] }]; } await memory.saveMessages({ messages: [...threadMessages, ...this.getResponseMessages({ threadId: threadId2, resourceId, messages: responseMessages, now: dateResponseMessagesFrom })], memoryConfig: memoryConfig2 }); } catch (e) { const message = e instanceof Error ? e.message : JSON.stringify(e); this.logger.error("Error saving response", { error: message, runId: runId2, result: resToLog, threadId: threadId2 }); } } if (Object.keys(this.evals || {}).length > 0) { const input = messages.map(message => message.content).join("\n"); const runIdToUse = runId2 || crypto.randomUUID(); for (const metric of Object.values(this.evals || {})) { chunkST5RMVLG_cjs.executeHook("onGeneration" /* ON_GENERATION */, { input, output: outputText, runId: runIdToUse, metric, agentName: this.name, instructions: instructions || this.instructions }); } } } }; } async generate(messages, generateOptions = {}) { const { instructions, context, threadId: threadIdInFn, memoryOptions, resourceId, maxSteps, onStepFinish, runId, output, toolsets, clientTools, temperature, toolChoice = "auto", experimental_output, telemetry, runtimeContext = new chunkLABUWBKX_cjs.RuntimeContext(), ...rest } = Object.assign({}, this.#defaultGenerateOptions, generateOptions); let messagesToUse = []; if (typeof messages === `string`) { messagesToUse = [{ role: "user", content: messages }]; } else if (Array.isArray(messages)) { messagesToUse = messages.map(message => { if (typeof message === `string`) { return { role: "user", content: message }; } return message; }); } else { messagesToUse = [messages]; } const runIdToUse = runId || crypto$1.randomUUID(); const instructionsToUse = instructions || (await this.getInstructions({ runtimeContext })); const llm = await this.getLLM({ runtimeContext }); const { before, after } = this.__primitive({ instructions: instructionsToUse, messages: messagesToUse, context, threadId: threadIdInFn, memoryConfig: memoryOptions, resourceId, runId: runIdToUse, toolsets, clientTools, runtimeContext }); const { threadId, thread, messageObjects, convertedTools } = await before(); if (!output && experimental_output) { const result2 = await llm.__text({ messages: messageObjects, tools: convertedTools, onStepFinish: result3 => { void onStepFinish?.(result3); }, maxSteps, runId: runIdToUse, temperature, toolChoice: toolChoice || "auto", experimental_output, threadId, resourceId, memory: this.getMemory(), runtimeContext, ...rest }); const outputText2 = result2.text; await after({ result: result2, threadId, thread, memoryConfig: memoryOptions, outputText: outputText2, runId: runIdToUse }); const newResult = result2; newResult.object = result2.experimental_output; return newResult; } if (!output) { const result2 = await llm.__text({ messages: messageObjects, tools: convertedTools, onStepFinish: result3 => { void onStepFinish?.(result3); }, maxSteps, runId: runIdToUse, temperature, toolChoice, telemetry, threadId, resourceId, memory: this.getMemory(), runtimeContext, ...rest }); const outputText2 = result2.text; await after({ result: result2, thread, threadId, memoryConfig: memoryOptions, outputText: outputText2, runId: runIdToUse }); return result2; } const result = await llm.__textObject({ messages: messageObjects, tools: convertedTools, structuredOutput: output, onStepFinish: result2 => { void onStepFinish?.(result2); }, maxSteps, runId: runIdToUse, temperature, toolChoice, telemetry, memory: this.getMemory(), runtimeContext, ...rest }); const outputText = JSON.stringify(result.object); await after({ result, thread, threadId, memoryConfig: memoryOptions, outputText, runId: runIdToUse }); return result; } async stream(messages, streamOptions = {}) { const { instructions, context, threadId: threadIdInFn, memoryOptions, resourceId, maxSteps, onFinish, onStepFinish, runId, toolsets, clientTools, output, temperature, toolChoice = "auto", experimental_output, telemetry, runtimeContext = new chunkLABUWBKX_cjs.RuntimeContext(), ...rest } = Object.assign({}, this.#defaultStreamOptions, streamOptions); const runIdToUse = runId || crypto$1.randomUUID(); const instructionsToUse = instructions || (await this.getInstructions({ runtimeContext })); const llm = await this.getLLM({ runtimeContext }); let messagesToUse = []; if (typeof messages === `string`) { messagesToUse = [{ role: "user", content: messages }]; } else { messagesToUse = messages.map(message => { if (typeof message === `string`) { return { role: "user", content: message }; } return message; }); } const { before, after } = this.__primitive({ instructions: instructionsToUse, messages: messagesToUse, context, threadId: threadIdInFn, memoryConfig: memoryOptions, resourceId, runId: runIdToUse, toolsets, clientTools, runtimeContext }); const { threadId, thread, messageObjects, convertedTools } = await before(); if (!output && experimental_output) { this.logger.debug(`Starting agent ${this.name} llm stream call`, { runId }); const streamResult = await llm.__stream({ messages: messageObjects, temperature, tools: convertedTools, onStepFinish: result => { void onStepFinish?.(result); }, onFinish: async result => { try { const outputText = result.text; await after({ result, thread, threadId, memoryConfig: memoryOptions, outputText, runId: runIdToUse }); } catch (e) { this.logger.error("Error saving memory on finish", { error: e, runId }); } void onFinish?.(result); }, maxSteps, runId: runIdToUse, toolChoice, experimental_output, memory: this.getMemory(), runtimeContext, ...rest }); const newStreamResult = streamResult; newStreamResult.partialObjectStream = streamResult.experimental_partialOutputStream; return newStreamResult; } else if (!output) { this.logger.debug(`Starting agent ${this.name} llm stream call`, { runId }); return llm.__stream({ messages: messageObjects, temperature, tools: convertedTools, onStepFinish: result => { void onStepFinish?.(result); }, onFinish: async result => { try { const outputText = result.text; await after({ result, thread, threadId, memoryConfig: memoryOptions, outputText, runId: runIdToUse }); } catch (e) { this.logger.error("Error saving memory on finish", { error: e, runId }); } void onFinish?.(result); }, maxSteps, runId: runIdToUse, toolChoice, telemetry, memory: this.getMemory(), runtimeContext, ...rest }); } this.logger.debug(`Starting agent ${this.name} llm streamObject call`, { runId }); return llm.__streamObject({ messages: messageObjects, tools: convertedTools, temperature, structuredOutput: output, onStepFinish: result => { void onStepFinish?.(result); }, onFinish: async result => { try { const outputText = JSON.stringify(result.object); await after({ result, thread, threadId, memoryConfig: memoryOptions, outputText, runId: runIdToUse }); } catch (e) { this.logger.error("Error saving memory on finish", { error: e, runId }); } void onFinish?.(result); }, runId: runIdToUse, toolChoice, telemetry, memory: this.getMemory(), runtimeContext, ...rest }); } /** * Convert text to speech using the configured voice provider * @param input Text or text stream to convert to speech * @param options Speech options including speaker and provider-specific options * @returns Audio stream * @deprecated Use agent.voice.speak() instead */ async speak(input, options) { if (!this.voice) { throw new Error("No voice provider configured"); } this.logger.warn("Warning: agent.speak() is deprecated. Please use agent.voice.speak() instead."); try { return this.voice.speak(input, options); } catch (e) { this.logger.error("Error during agent speak", { error: e }); throw e; } } /** * Convert speech to text using the configured voice provider * @param audioStream Audio stream to transcribe * @param options Provider-specific transcription options * @returns Text or text stream * @deprecated Use agent.voice.listen() instead */ async listen(audioStream, options) { if (!this.voice) { throw new Error("No voice provider configured"); } this.logger.warn("Warning: agent.listen() is deprecated. Please use agent.voice.listen() instead"); try { return this.voice.listen(audioStream, options); } catch (e) { this.logger.error("Error during agent listen", { error: e }); throw e; } } /** * Get a list of available speakers from the configured voice provider * @throws {Error} If no voice provider is configured * @returns {Promise<Array<{voiceId: string}>>} List of available speakers * @deprecated Use agent.voice.getSpeakers() instead */ async getSpeakers() { if (!this.voice) { throw new Error("No voice provider configured"); } this.logger.warn("Warning: agent.getSpeakers() is deprecated. Please use agent.voice.getSpeakers() instead."); try { return await this.voice.getSpeakers(); } catch (e) { this.logger.error("Error during agent getSpeakers", { error: e }); throw e; } } toStep() { const x = agentToStep(this); return new Step(x); } }; exports.Agent = /*@__PURE__*/(_ => { _init = chunkRWTSGWWL_cjs.__decoratorStart(_a); exports.Agent = chunkRWTSGWWL_cjs.__decorateElement(_init, 0, "Agent", _Agent_decorators, exports.Agent); chunkRWTSGWWL_cjs.__runInitializers(_init, 1, exports.Agent); // src/workflows/utils.ts return exports.Agent; })(); // src/workflows/utils.ts function isErrorEvent(stateEvent) { return stateEvent.type.startsWith("xstate.error.actor."); } function isTransitionEvent(stateEvent) { return stateEvent.type.startsWith("xstate.done.actor."); } function isVariableReference(value) { return typeof value === "object" && "step" in value && "path" in value; } function getStepResult(result) { if (result?.status === "success") return result.output; return void 0; } function getSuspendedPaths({ value, path, suspendedPaths }) { if (typeof value === "string") { if (value === "suspended") { suspendedPaths.add(path); } } else { Object.keys(value).forEach(key => getSuspendedPaths({ value: value[key], path: path ? `${path}.${key}` : key, suspendedPaths })); } } function isFinalState(status) { return ["completed", "failed"].includes(status); } function isLimboState(status) { return status === "limbo"; } function recursivelyCheckForFinalState({ value, suspendedPaths, path }) { if (typeof value === "string") { return isFinalState(value) || isLimboState(value) || suspendedPaths.has(path); } return Object.keys(value).every(key => recursivelyCheckForFinalState({ value: value[key], suspendedPaths, path: path ? `${path}.${key}` : key })); } function getActivePathsAndStatus(value) { const paths = []; const traverse = (current, path = []) => { for (const [key, value2] of Object.entries(current)) { const currentPath = [...path, key]; if (typeof value2 === "string") { paths.push({ stepPath: currentPath, stepId: key, status: value2 }); } else if (typeof value2 === "object" && value2 !== null) { traverse(value2, currentPath); } } }; traverse(value); return paths; } function mergeChildValue(startStepId, parent, child) { const traverse = current => { const obj = {}; for (const [key, value] of Object.entries(current)) { if (key === startStepId) { obj[key] = { ...child }; } else if (typeof value === "string") { obj[key] = value; } else if (typeof value === "object" && value !== null) { obj[key] = traverse(value); } } return obj; }; return traverse(parent); } var updateStepInHierarchy = (value, targetStepId) => { const result = {}; for (const key of Object.keys(value)) { const currentValue = value[key]; if (key === targetStepId) { result[key] = "pending"; } else if (typeof currentValue === "object" && currentValue !== null) { result[key] = updateStepInHierarchy(currentValue, targetStepId); } else { result[key] = currentValue; } } return result; }; function getResultActivePaths(state) { const activePaths = getActivePathsAndStatus(state.value); const activePathsAndStatus = activePaths.reduce((acc, curr) => { const entry = { status: curr.status, stepPath: curr.stepPath }; if (curr.status === "suspended") { entry.suspendPayload = state.context.steps[curr.stepId].suspendPayload; entry.stepPath = curr.stepPath; } acc.set(curr.stepId, entry); return acc; }, /* @__PURE__ */new Map()); return activePathsAndStatus; } function isWorkflow(step) { return step instanceof Workflow; } function isAgent(step) { return step instanceof exports.Agent; } function resolveVariables({ runId, logger, variables, context }) { const resolvedData = {}; for (const [key, variable] of Object.entries(variables)) { const sourceData = variable.step === "trigger" ? context.triggerData : getStepResult(context.steps[variable.step.id ?? variable.step.name]); logger.debug(`Got source data for ${key} variable from ${variable.step === "trigger" ? "trigger" : variable.step.id ?? variable.step.name}`, { sourceData, path: variable.path, runId }); if (!sourceData && variable.step !== "trigger") { resolvedData[key] = void 0; continue; } const value = variable.path === "" || variable.path === "." ? sourceData : radash.get(sourceData, variable.path); logger.debug(`Resolved variable ${key}`, { value, runId }); resolvedData[key] = value; } return resolvedData; } function agentToStep(agent, { mastra } = {}) { return { id: agent.name, inputSchema: zod.z.object({ prompt: zod.z.string(), resourceId: zod.z.string().optional(), threadId: zod.z.string().optional() }), outputSchema: zod.z.object({ text: zod.z.string() }), execute: async ({ context, runId, mastra: mastraFromExecute }) => { const realMastra = mastraFromExecute ?? mastra; if (!realMastra) { throw new Error("Mastra instance not found"); } agent.__registerMastra(realMastra); agent.__registerPrimitives({ logger: realMastra.getLogger(), telemetry: realMastra.getTelemetry() }); const result = await agent.generate(context.inputData.prompt, { runId, resourceId: context.inputData.resourceId, threadId: context.inputData.threadId }); return { text: result.text }; } }; } function workflowToStep(workflow, { mastra }) { workflow.setNested(true); return { id: workflow.name, workflow, workflowId: toCamelCaseWithRandomSuffix(workflow.name), execute: async ({ context, suspend, emit, mastra: mastraFromExecute, runtimeContext }) => { const realMastra = mastraFromExecute ?? mastra; if (realMastra) { workflow.__registerMastra(realMastra); workflow.__registerPrimitives({ logger: realMastra.getLogger(), telemetry: realMastra.getTelemetry() }); } const run = context.isResume ? workflow.createRun({ runId: context.isResume.runId }) : workflow.createRun(); const unwatch = run.watch(state => { emit("state-update", workflow.name, state.results, { ...context, ...{ [workflow.name]: state.results } }); }); const awaitedResult = context.isResume && context.isResume.stepId.includes(".") ? await run.resume({ stepId: context.isResume.stepId.split(".").slice(1).join("."), context: context.inputData, runtimeContext }) : await run.start({ triggerData: context.inputData, runtimeContext }); unwatch(); if (!awaitedResult) { throw new Error("Workflow run failed"); } if (awaitedResult.activePaths?.size > 0) { const suspendedStep = [...awaitedResult.activePaths.entries()].find(([, { status }]) => { return status === "suspended"; }); if (suspendedStep) { await suspend(suspendedStep[1].suspendPayload, { ...awaitedResult, runId: run.runId }); } } return { ...awaitedResult, runId: run.runId }; } }; } function toCamelCaseWithRandomSuffix(str) { if (!str) return ""; const normalizedStr = str.replace(/[-_]/g, " "); const words = normalizedStr.split(" ").filter(word => word.length > 0); const camelCase = words.map((word, index) => { word = word.replace(/[^a-zA-Z0-9]/g, ""); if (index === 0) { return word.toLowerCase(); } return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase(); }).join(""); const randomString = generateRandomLetters(3); return camelCase + randomString; } function generateRandomLetters(length) { const characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; let result = ""; for (let i = 0; i < length; i++) { const randomIndex = Math.floor(Math.random() * characters.length); result += characters.charAt(randomIndex); } return result; } function isConditionalKey(key) { return key.startsWith("__") && (key.includes("_if") || key.includes("_else")); } var Machine = class extends EventEmitter__default.default { logger; #mastra; #runtimeContext; #workflowInstance; #executionSpan; #stepGraph; #machine; #runId; #startStepId; name; #actor = null; #steps = {}; #retryConfig; constructor({ logger, mastra, runtimeContext, workflowInstance, executionSpan, name, runId, steps, stepGraph, retryConfig, startStepId }) { super(); this.#mastra = mastra; this.#workflowInstance = workflowInstance; this.#runtimeContext = runtimeContext; this.#executionSpan = executionSpan; this.logger = logger; this.#runId = runId; this.#startStepId = startStepId; this.name = name; this.#stepGraph = stepGraph; this.#steps = steps; this.#retryConfig = retryConfig; this.initializeMachine(); } get startStepId() { return this.#startStepId; } async execute({ stepId, input, snapshot, resumeData } = {}) { if (snapshot) { this.logger.debug(`Workflow snapshot received`, { runId: this.#runId, snapshot }); } const origSteps = input.steps; const isResumedInitialStep = this.#stepGraph?.initial[0]?.step?.id === stepId; if (isResumedInitialStep) { snapshot = void 0; input.steps = {}; } this.logger.debug(`Machine input prepared`, { runId: this.#runId, input }); const actorSnapshot = snapshot ? { ...snapshot, context: { ...input, inputData: { ...(snapshot?.context?.inputData || {}), ...resumeData }, // ts-ignore is needed here because our snapshot types don't really match xstate snapshot types right now. We should fix