@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
JavaScript
'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