UNPKG

@mastra/core

Version:

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

1,716 lines (1,711 loc) • 46.9 kB
import { InstrumentClass } from './chunk-W5HVJX45.js'; import { ensureToolProperties, ensureAllMessagesAreCoreMessages, createMastraProxy, makeCoreTool, delay } from './chunk-2YF5JYTJ.js'; import { MastraBase } from './chunk-VN4M67DA.js'; import { RegisteredLogger } from './chunk-L7CR75HA.js'; import { executeHook } from './chunk-BB4KXGBU.js'; import { __decoratorStart, __decorateElement, __runInitializers } from './chunk-C6A6W6XS.js'; import { randomUUID } from 'crypto'; import { jsonSchema, generateText, Output, generateObject, streamText, streamObject } from 'ai'; import { z } from 'zod'; // src/llm/model/base.ts var MastraLLMBase = class extends MastraBase { // @ts-ignore #mastra; #model; constructor({ name, model }) { super({ component: RegisteredLogger.LLM, name }); this.#model = model; } getProvider() { return this.#model.provider; } getModelId() { return this.#model.modelId; } getModel() { return this.#model; } convertToMessages(messages) { if (Array.isArray(messages)) { return messages.map(m => { if (typeof m === "string") { return { role: "user", content: m }; } return m; }); } return [{ role: "user", content: messages }]; } __registerPrimitives(p) { if (p.telemetry) { this.__setTelemetry(p.telemetry); } if (p.logger) { this.__setLogger(p.logger); } } __registerMastra(p) { this.#mastra = p; } async __text(input) { this.logger.debug(`[LLMs:${this.name}] Generating text.`, { input }); throw new Error("Method not implemented."); } async __textObject(input) { this.logger.debug(`[LLMs:${this.name}] Generating object.`, { input }); throw new Error("Method not implemented."); } async generate(messages, options = {}) { this.logger.debug(`[LLMs:${this.name}] Generating text.`, { messages, options }); throw new Error("Method not implemented."); } async __stream(input) { this.logger.debug(`[LLMs:${this.name}] Streaming text.`, { input }); throw new Error("Method not implemented."); } async __streamObject(input) { this.logger.debug(`[LLMs:${this.name}] Streaming object.`, { input }); throw new Error("Method not implemented."); } async stream(messages, options = {}) { this.logger.debug(`[LLMs:${this.name}] Streaming text.`, { messages, options }); throw new Error("Method not implemented."); } }; var MastraLLM = class extends MastraLLMBase { #model; #mastra; constructor({ model, mastra }) { super({ name: "aisdk", model }); this.#model = model; if (mastra) { this.#mastra = mastra; if (mastra.getLogger()) { this.__setLogger(mastra.getLogger()); } } } __registerPrimitives(p) { if (p.telemetry) { this.__setTelemetry(p.telemetry); } if (p.logger) { this.__setLogger(p.logger); } } __registerMastra(p) { this.#mastra = p; } getProvider() { return this.#model.provider; } getModelId() { return this.#model.modelId; } getModel() { return this.#model; } convertTools({ tools, runId, threadId, resourceId, memory } = {}) { this.logger.debug("Starting tool conversion for LLM"); let mastraProxy = void 0; const logger = this.logger; if (this.#mastra) { mastraProxy = createMastraProxy({ mastra: this.#mastra, logger }); } const converted = Object.entries(tools || {}).reduce((memo, value) => { const k = value[0]; const tool = value[1]; if (tool) { const options = { name: k, runId, threadId, resourceId, logger: this.logger, memory, mastra: mastraProxy }; memo[k] = makeCoreTool(tool, options); } return memo; }, {}); this.logger.debug(`Converted tools for LLM`); return converted; } async __text({ runId, messages, maxSteps, tools, convertedTools, temperature, toolChoice = "auto", onStepFinish, experimental_output, telemetry, threadId, resourceId, memory, ...rest }) { const model = this.#model; this.logger.debug(`[LLM] - Generating text`, { runId, messages, maxSteps, threadId, resourceId, tools: Object.keys(tools || convertedTools || {}) }); const finalTools = convertedTools || this.convertTools({ tools, runId, threadId, resourceId, memory }); const argsForExecute = { model, temperature, tools: { ...finalTools }, toolChoice, maxSteps, onStepFinish: async props => { void onStepFinish?.(props); this.logger.debug("[LLM] - Step Change:", { text: props?.text, toolCalls: props?.toolCalls, toolResults: props?.toolResults, finishReason: props?.finishReason, usage: props?.usage, runId }); if (props?.response?.headers?.["x-ratelimit-remaining-tokens"] && parseInt(props?.response?.headers?.["x-ratelimit-remaining-tokens"], 10) < 2e3) { this.logger.warn("Rate limit approaching, waiting 10 seconds", { runId }); await delay(10 * 1e3); } }, ...rest }; let schema; if (experimental_output) { this.logger.debug("[LLM] - Using experimental output", { runId }); if (typeof experimental_output.parse === "function") { schema = experimental_output; if (schema instanceof z.ZodArray) { schema = schema._def.type; } } else { schema = jsonSchema(experimental_output); } } return await generateText({ messages, ...argsForExecute, experimental_telemetry: { ...this.experimental_telemetry, ...telemetry }, experimental_output: schema ? Output.object({ schema }) : void 0 }); } async __textObject({ messages, onStepFinish, maxSteps = 5, tools, convertedTools, structuredOutput, runId, temperature, toolChoice = "auto", telemetry, threadId, resourceId, memory, ...rest }) { const model = this.#model; this.logger.debug(`[LLM] - Generating a text object`, { runId }); const finalTools = convertedTools || this.convertTools({ tools, runId, threadId, resourceId, memory }); const argsForExecute = { model, temperature, tools: { ...finalTools }, maxSteps, toolChoice, onStepFinish: async props => { void onStepFinish?.(props); this.logger.debug("[LLM] - Step Change:", { text: props?.text, toolCalls: props?.toolCalls, toolResults: props?.toolResults, finishReason: props?.finishReason, usage: props?.usage, runId }); if (props?.response?.headers?.["x-ratelimit-remaining-tokens"] && parseInt(props?.response?.headers?.["x-ratelimit-remaining-tokens"], 10) < 2e3) { this.logger.warn("Rate limit approaching, waiting 10 seconds", { runId }); await delay(10 * 1e3); } }, ...rest }; let schema; let output = "object"; if (typeof structuredOutput.parse === "function") { schema = structuredOutput; if (schema instanceof z.ZodArray) { output = "array"; schema = schema._def.type; } } else { schema = jsonSchema(structuredOutput); } return await generateObject({ messages, ...argsForExecute, output, schema, experimental_telemetry: { ...this.experimental_telemetry, ...telemetry } }); } async __stream({ messages, onStepFinish, onFinish, maxSteps = 5, tools, convertedTools, runId, temperature, toolChoice = "auto", experimental_output, telemetry, threadId, resourceId, memory, ...rest }) { const model = this.#model; this.logger.debug(`[LLM] - Streaming text`, { runId, threadId, resourceId, messages, maxSteps, tools: Object.keys(tools || convertedTools || {}) }); const finalTools = convertedTools || this.convertTools({ tools, runId, threadId, resourceId, memory }); const argsForExecute = { model, temperature, tools: { ...finalTools }, maxSteps, toolChoice, onStepFinish: async props => { void onStepFinish?.(props); this.logger.debug("[LLM] - Stream Step Change:", { text: props?.text, toolCalls: props?.toolCalls, toolResults: props?.toolResults, finishReason: props?.finishReason, usage: props?.usage, runId }); if (props?.response?.headers?.["x-ratelimit-remaining-tokens"] && parseInt(props?.response?.headers?.["x-ratelimit-remaining-tokens"], 10) < 2e3) { this.logger.warn("Rate limit approaching, waiting 10 seconds", { runId }); await delay(10 * 1e3); } }, onFinish: async props => { void onFinish?.(props); this.logger.debug("[LLM] - Stream Finished:", { text: props?.text, toolCalls: props?.toolCalls, toolResults: props?.toolResults, finishReason: props?.finishReason, usage: props?.usage, runId, threadId, resourceId }); }, ...rest }; let schema; if (experimental_output) { this.logger.debug("[LLM] - Using experimental output", { runId }); if (typeof experimental_output.parse === "function") { schema = experimental_output; if (schema instanceof z.ZodArray) { schema = schema._def.type; } } else { schema = jsonSchema(experimental_output); } } return await streamText({ messages, ...argsForExecute, experimental_telemetry: { ...this.experimental_telemetry, ...telemetry }, experimental_output: schema ? Output.object({ schema }) : void 0 }); } async __streamObject({ messages, onStepFinish, onFinish, maxSteps = 5, tools, convertedTools, structuredOutput, runId, temperature, toolChoice = "auto", telemetry, threadId, resourceId, memory, ...rest }) { const model = this.#model; this.logger.debug(`[LLM] - Streaming structured output`, { runId, messages, maxSteps, tools: Object.keys(tools || convertedTools || {}) }); const finalTools = convertedTools || this.convertTools({ tools, runId, threadId, resourceId, memory }); const argsForExecute = { model, temperature, tools: { ...finalTools }, maxSteps, toolChoice, onStepFinish: async props => { void onStepFinish?.(props); this.logger.debug("[LLM] - Stream Step Change:", { text: props?.text, toolCalls: props?.toolCalls, toolResults: props?.toolResults, finishReason: props?.finishReason, usage: props?.usage, runId, threadId, resourceId }); if (props?.response?.headers?.["x-ratelimit-remaining-tokens"] && parseInt(props?.response?.headers?.["x-ratelimit-remaining-tokens"], 10) < 2e3) { this.logger.warn("Rate limit approaching, waiting 10 seconds", { runId }); await delay(10 * 1e3); } }, onFinish: async props => { void onFinish?.(props); this.logger.debug("[LLM] - Stream Finished:", { text: props?.text, toolCalls: props?.toolCalls, toolResults: props?.toolResults, finishReason: props?.finishReason, usage: props?.usage, runId, threadId, resourceId }); }, ...rest }; let schema; let output = "object"; if (typeof structuredOutput.parse === "function") { schema = structuredOutput; if (schema instanceof z.ZodArray) { output = "array"; schema = schema._def.type; } } else { schema = jsonSchema(structuredOutput); } return streamObject({ messages, ...argsForExecute, output, schema, experimental_telemetry: { ...this.experimental_telemetry, ...telemetry } }); } async generate(messages, { maxSteps = 5, onStepFinish, tools, convertedTools, runId, output, temperature, telemetry, memory, ...rest } = {}) { const msgs = this.convertToMessages(messages); if (!output) { return await this.__text({ messages: msgs, onStepFinish, maxSteps, tools, convertedTools, runId, temperature, memory, ...rest }); } return await this.__textObject({ messages: msgs, structuredOutput: output, onStepFinish, maxSteps, tools, convertedTools, runId, telemetry, memory, ...rest }); } async stream(messages, { maxSteps = 5, onFinish, onStepFinish, tools, convertedTools, runId, output, temperature, telemetry, ...rest } = {}) { const msgs = this.convertToMessages(messages); if (!output) { return await this.__stream({ messages: msgs, onStepFinish, onFinish, maxSteps, tools, convertedTools, runId, temperature, telemetry, ...rest }); } return await this.__streamObject({ messages: msgs, structuredOutput: output, onStepFinish, onFinish, maxSteps, tools, convertedTools, runId, temperature, telemetry, ...rest }); } convertToUIMessages(messages) { function addToolMessageToChat({ toolMessage, messages: messages2, toolResultContents }) { const chatMessages2 = messages2.map(message => { if (message.toolInvocations) { return { ...message, toolInvocations: message.toolInvocations.map(toolInvocation => { const toolResult = toolMessage.content.find(tool => tool.toolCallId === toolInvocation.toolCallId); if (toolResult) { return { ...toolInvocation, state: "result", result: toolResult.result }; } return toolInvocation; }) }; } return message; }); const resultContents = [...toolResultContents, ...toolMessage.content]; return { chatMessages: chatMessages2, toolResultContents: resultContents }; } const { chatMessages } = messages.reduce((obj, message) => { if (message.role === "tool") { return addToolMessageToChat({ toolMessage: message, messages: obj.chatMessages, toolResultContents: obj.toolResultContents }); } let textContent = ""; let toolInvocations = []; if (typeof message.content === "string") { textContent = message.content; } else if (typeof message.content === "number") { textContent = String(message.content); } else if (Array.isArray(message.content)) { for (const content of message.content) { if (content.type === "text") { textContent += content.text; } else if (content.type === "tool-call") { const toolResult = obj.toolResultContents.find(tool => tool.toolCallId === content.toolCallId); toolInvocations.push({ state: toolResult ? "result" : "call", toolCallId: content.toolCallId, toolName: content.toolName, args: content.args, result: toolResult?.result }); } } } obj.chatMessages.push({ id: message.id, role: message.role, content: textContent, toolInvocations }); return obj; }, { chatMessages: [], toolResultContents: [] }); return chatMessages; } }; // src/agent/index.ts var _Agent_decorators, _init, _a; _Agent_decorators = [InstrumentClass({ prefix: "agent", excludeMethods: ["__setTools", "__setLogger", "__setTelemetry", "log"] })]; var Agent = class extends (_a = MastraBase) { name; llm; instructions; model; #mastra; #memory; tools; /** @deprecated This property is deprecated. Use evals instead. */ metrics; evals; voice; constructor(config) { super({ component: RegisteredLogger.AGENT }); this.name = config.name; this.instructions = config.instructions; if (!config.model) { throw new Error(`LanguageModel is required to create an Agent. Please provide the 'model'.`); } this.llm = new MastraLLM({ model: config.model, mastra: config.mastra }); this.tools = {}; this.metrics = {}; this.evals = {}; if (config.tools) { this.tools = ensureToolProperties(config.tools); } 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; this.voice?.addTools(this.tools); this.voice?.addInstructions(config.instructions); } } hasOwnMemory() { return Boolean(this.#memory); } getMemory() { return this.#memory ?? this.#mastra?.memory; } __updateInstructions(newInstructions) { this.instructions = newInstructions; this.logger.debug(`[Agents:${this.name}] Instructions updated.`, { model: this.model, name: this.name }); } __registerPrimitives(p) { if (p.telemetry) { this.__setTelemetry(p.telemetry); } if (p.logger) { this.__setLogger(p.logger); } this.llm.__registerPrimitives(p); this.logger.debug(`[Agents:${this.name}] initialized.`, { model: this.model, name: this.name }); } __registerMastra(mastra) { this.#mastra = mastra; this.llm.__registerMastra(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 }) { const { text } = await this.llm.__text({ 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, memoryConfig, resourceId, userMessages, runId }) { const memory = this.getMemory(); if (memory) { const thread = await memory.getThreadById({ threadId }); if (!thread) { return { threadId: threadId || "", messages: userMessages }; } const newMessages = ensureAllMessagesAreCoreMessages(userMessages); const messages = newMessages.map(u => { return { id: this.getMemory()?.generateId(), createdAt: /* @__PURE__ */new Date(), threadId, ...u, content: u.content, role: u.role, type: "text" }; }); const [memoryMessages, memorySystemMessage] = threadId && memory ? await Promise.all([memory.rememberMessages({ threadId, resourceId, config: memoryConfig, 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 }); return { threadId: thread.id, messages: [memorySystemMessage ? { role: "system", content: memorySystemMessage } : null, ...this.sanitizeResponseMessages(memoryMessages), ...newMessages].filter(message => Boolean(message)) }; } return { threadId: threadId || "", messages: userMessages }; } async saveResponse({ result, threadId, resourceId, runId, memoryConfig }) { const { response } = result; try { if (response.messages) { const ms = Array.isArray(response.messages) ? response.messages : [response.messages]; const responseMessagesWithoutIncompleteToolCalls = this.sanitizeResponseMessages(ms); const memory = this.getMemory(); if (memory) { this.logger.debug(`[Agent:${this.name}] - Memory persistence: store=${this.getMemory()?.constructor.name} threadId=${threadId}`, { runId, resourceId, threadId, memoryStore: this.getMemory()?.constructor.name }); await memory.saveMessages({ memoryConfig, messages: responseMessagesWithoutIncompleteToolCalls.map((message, index) => { const messageId = 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, role: message.role, content: message.content, createdAt: new Date(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 }; }) }); } } } catch (err) { this.logger.error(`[Agent:${this.name}] - Failed to save assistant response`, { error: err, runId }); } } 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 (!message.content || typeof message.content === "string" || typeof message.content === "number") { 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`) { 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; }); } convertTools({ toolsets, threadId, resourceId, runId }) { 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 = createMastraProxy({ mastra: this.#mastra, logger }); } const converted = Object.entries(this.tools || {}).reduce((memo, value) => { const k = value[0]; const tool = this.tools[k]; if (tool) { const options = { name: k, runId, threadId, resourceId, logger: this.logger, mastra: mastraProxy, memory, agentName: this.name }; memo[k] = makeCoreTool(tool, options); } return memo; }, {}); const convertedMemoryTools = memoryTools ? Object.entries(memoryTools).reduce((memo, [k, tool]) => { memo[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 }, options) ?? void 0; } catch (err) { this.logger.error(`[Agent:${this.name}] - Failed memory tool execution`, { error: err, runId, threadId, resourceId }); throw err; } } : void 0 }; return memo; }, {}) : {}; 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 }); toolsFromToolsets.forEach(toolset => { Object.entries(toolset).forEach(([toolName, tool]) => { const toolObj = tool; const options = { name: toolName, runId, threadId, resourceId, logger: this.logger, agentName: this.name }; toolsFromToolsetsConverted[toolName] = makeCoreTool(toolObj, options, "toolset"); }); }); } return toolsFromToolsetsConverted; } async preExecute({ resourceId, runId, threadId, memoryConfig, messages }) { let coreMessages = []; let threadIdToUse = threadId; this.logger.debug(`Saving user messages in memory for agent ${this.name}`, { runId }); const saveMessageResponse = await this.fetchMemory({ threadId, resourceId, userMessages: messages, memoryConfig }); coreMessages = saveMessageResponse.messages; threadIdToUse = saveMessageResponse.threadId; return { coreMessages, threadIdToUse }; } __primitive({ instructions, messages, context, threadId, memoryConfig, resourceId, runId, toolsets }) { 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; 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 }); let 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, memoryConfig, messages }); coreMessages = preExecuteResult.coreMessages; threadIdToUse = preExecuteResult.threadIdToUse; } let convertedTools; if (toolsets && Object.keys(toolsets || {}).length > 0 || this.getMemory() && resourceId) { 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, hasMemory: !!this.getMemory(), hasResourceId: !!resourceId }); convertedTools = this.convertTools({ toolsets, threadId: threadIdToUse, resourceId, runId }); } const messageObjects = [systemMessage, ...(context || []), ...coreMessages]; return { messageObjects, convertedTools, threadId: threadIdToUse }; }, after: async ({ result, 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 = threadId2 ? await memory?.getThreadById({ threadId: threadId2 }) : void 0; if (memory && resourceId && thread) { try { const userMessage = this.getMostRecentUserMessage(messages); const newMessages = userMessage ? [userMessage] : messages; const threadMessages = newMessages.map(u => { return { id: this.getMemory()?.generateId(), createdAt: /* @__PURE__ */new Date(), threadId: thread.id, ...u, content: u.content, role: u.role, type: "text" }; }); await Promise.all([(async () => { await memory.saveMessages({ messages: threadMessages, memoryConfig: memoryConfig2 }); await this.saveResponse({ result, threadId: threadId2, resourceId, memoryConfig: memoryConfig2, runId: runId2 }); })(), (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 }); })()]); } catch (e) { this.logger.error("Error saving response", { error: e, 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 || {})) { executeHook("onGeneration" /* ON_GENERATION */, { input, output: outputText, runId: runIdToUse, metric, agentName: this.name, instructions: instructions || this.instructions }); } } } }; } async generate(messages, { instructions, context, threadId: threadIdInFn, memoryOptions, resourceId, maxSteps = 5, onStepFinish, runId, output, toolsets, temperature, toolChoice = "auto", experimental_output, telemetry, ...rest } = {}) { 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 || randomUUID(); const { before, after } = this.__primitive({ instructions, messages: messagesToUse, context, threadId: threadIdInFn, memoryConfig: memoryOptions, resourceId, runId: runIdToUse, toolsets }); const { threadId, messageObjects, convertedTools } = await before(); if (!output && experimental_output) { const result2 = await this.llm.__text({ messages: messageObjects, tools: this.tools, convertedTools, onStepFinish: result3 => { void onStepFinish?.(result3); }, maxSteps: maxSteps || 5, runId: runIdToUse, temperature, toolChoice: toolChoice || "auto", experimental_output, threadId, resourceId, memory: this.getMemory(), ...rest }); const outputText2 = result2.text; await after({ result: result2, threadId, memoryConfig: memoryOptions, outputText: outputText2, runId: runIdToUse }); const newResult = result2; newResult.object = result2.experimental_output; return newResult; } if (!output) { const result2 = await this.llm.__text({ messages: messageObjects, tools: this.tools, convertedTools, onStepFinish: result3 => { void onStepFinish?.(result3); }, maxSteps, runId: runIdToUse, temperature, toolChoice, telemetry, threadId, resourceId, memory: this.getMemory(), ...rest }); const outputText2 = result2.text; await after({ result: result2, threadId, memoryConfig: memoryOptions, outputText: outputText2, runId: runIdToUse }); return result2; } const result = await this.llm.__textObject({ messages: messageObjects, tools: this.tools, structuredOutput: output, convertedTools, onStepFinish: result2 => { void onStepFinish?.(result2); }, maxSteps, runId: runIdToUse, temperature, toolChoice, telemetry, memory: this.getMemory(), ...rest }); const outputText = JSON.stringify(result.object); await after({ result, threadId, memoryConfig: memoryOptions, outputText, runId: runIdToUse }); return result; } async stream(messages, { instructions, context, threadId: threadIdInFn, memoryOptions, resourceId, maxSteps = 5, onFinish, onStepFinish, runId, toolsets, output, temperature, toolChoice = "auto", experimental_output, telemetry, ...rest } = {}) { const runIdToUse = runId || randomUUID(); 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, messages: messagesToUse, context, threadId: threadIdInFn, memoryConfig: memoryOptions, resourceId, runId: runIdToUse, toolsets }); const { threadId, messageObjects, convertedTools } = await before(); if (!output && experimental_output) { this.logger.debug(`Starting agent ${this.name} llm stream call`, { runId }); const streamResult = await this.llm.__stream({ messages: messageObjects, temperature, tools: this.tools, convertedTools, onStepFinish: result => { void onStepFinish?.(result); }, onFinish: async result => { try { const outputText = result.text; await after({ result, 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(), ...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 this.llm.__stream({ messages: messageObjects, temperature, tools: this.tools, convertedTools, onStepFinish: result => { void onStepFinish?.(result); }, onFinish: async result => { try { const outputText = result.text; await after({ result, 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(), ...rest }); } this.logger.debug(`Starting agent ${this.name} llm streamObject call`, { runId }); return this.llm.__streamObject({ messages: messageObjects, tools: this.tools, temperature, structuredOutput: output, convertedTools, onStepFinish: result => { void onStepFinish?.(result); }, onFinish: async result => { try { const outputText = JSON.stringify(result.object); await after({ result, 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(), ...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; } } }; Agent = /*@__PURE__*/(_ => { _init = __decoratorStart(_a); Agent = __decorateElement(_init, 0, "Agent", _Agent_decorators, Agent); __runInitializers(_init, 1, Agent); return Agent; })(); export { Agent };