'use strict'; var chunkGMFOMFCM_cjs = require('../../chunk-GMFOMFCM.cjs'); var chunkD37QL5LB_cjs = require('../../chunk-D37QL5LB.cjs'); var chunkZCBG4ZQT_cjs = require('../../chunk-ZCBG4ZQT.cjs'); var chunkNYGUBLK3_cjs = require('../../chunk-NYGUBLK3.cjs'); var chunkAWVVTLZF_cjs = require('../../chunk-AWVVTLZF.cjs'); var chunkD324RFFU_cjs = require('../../chunk-D324RFFU.cjs'); var chunk6QR4RQID_cjs = require('../../chunk-6QR4RQID.cjs'); var chunkER5YO3AZ_cjs = require('../../chunk-ER5YO3AZ.cjs'); var chunkRS7FSLKM_cjs = require('../../chunk-RS7FSLKM.cjs'); var chunkFHPG32XN_cjs = require('../../chunk-FHPG32XN.cjs'); var chunkLP4WZA6D_cjs = require('../../chunk-LP4WZA6D.cjs'); var chunk23FX5JPX_cjs = require('../../chunk-23FX5JPX.cjs'); var chunk2TATDSHU_cjs = require('../../chunk-2TATDSHU.cjs'); var chunkPJIAL3WK_cjs = require('../../chunk-PJIAL3WK.cjs'); var ttlcache = require('@isaacs/ttlcache'); var web = require('stream/web'); var zod = require('zod'); // src/agent/durable/constants.ts var AGENT_STREAM_TOPIC = (runId) => `agent.stream.${runId}`; var AgentStreamEventTypes = { /** Chunk of streaming data (text, tool call, etc.) */ CHUNK: "chunk", /** Start of a new step in the agentic loop */ STEP_START: "step-start", /** End of a step in the agentic loop */ STEP_FINISH: "step-finish", /** Agent execution completed successfully */ FINISH: "finish", /** Error occurred during execution */ ERROR: "error", /** Workflow suspended (e.g., for tool approval) */ SUSPENDED: "suspended" }; var DurableAgentDefaults = { /** Default maximum number of agentic loop iterations */ MAX_STEPS: 5, /** * Default tool call concurrency. * NOTE: Currently unused — durable workflows run tool calls sequentially * (concurrency: 1) because tool approval and suspension require sequential * execution. The serialized toolCallConcurrency option is preserved in * workflow input for future use when dynamic foreach concurrency is supported. */ TOOL_CALL_CONCURRENCY: 10 }; var DurableStepIds = { /** LLM execution step */ LLM_EXECUTION: "durable-llm-execution", /** Tool call step */ TOOL_CALL: "durable-tool-call", /** LLM mapping step (combines results) */ LLM_MAPPING: "durable-llm-mapping", /** Agentic execution workflow (one iteration) */ AGENTIC_EXECUTION: "durable-agentic-execution", /** Full agentic loop workflow */ AGENTIC_LOOP: "durable-agentic-loop", /** Scorer execution step */ SCORER_EXECUTION: "durable-scorer-execution" }; // src/agent/durable/durable-stream-until-idle.ts var TERMINAL_BG_CHUNKS = /* @__PURE__ */ new Set([ "background-task-completed", "background-task-failed", "background-task-cancelled", // Suspended is non-terminal for the bg task itself (it can be resumed // later via `manager.resume`), but it IS terminal-for-this-iteration of // the streamUntilIdle wrapper: the agent should react to the suspend in // a follow-up turn so the user is told the task is parked. Without // this, the wrapper waits indefinitely for completed/failed/cancelled // and the stream times out. "background-task-suspended" ]); async function resolveScope(agent, mergedOptions) { const requestContext = mergedOptions?.requestContext ?? new chunkPJIAL3WK_cjs.RequestContext(); const memory = await agent.getMemory(); if (!memory) return null; const threadIdFromContext = requestContext.get(chunkPJIAL3WK_cjs.MASTRA_THREAD_ID_KEY); const resourceIdFromContext = requestContext.get(chunkPJIAL3WK_cjs.MASTRA_RESOURCE_ID_KEY); const threadIdFromArgs = typeof mergedOptions?.memory?.thread === "string" ? mergedOptions.memory.thread : mergedOptions?.memory?.thread?.id; const threadId = threadIdFromContext ?? threadIdFromArgs; const resourceId = resourceIdFromContext ?? mergedOptions?.memory?.resource; const scopeKey = threadId || resourceId ? `${threadId ?? ""}|${resourceId ?? ""}` : null; return { threadId, resourceId, scopeKey }; } function buildContinuationDirective(batch) { const entries = batch.map((chunk) => { const payload = chunk.payload ?? {}; return { toolCallId: payload.toolCallId, toolName: payload.toolName, isSuspended: !!payload.suspendedAt }; }).filter((e) => !!e.toolCallId); const idList = entries.filter((e) => !e.isSuspended).map((e) => e.toolName ? `${e.toolCallId} (${e.toolName})` : e.toolCallId).join(", "); const suspendedIdList = entries.filter((e) => e.isSuspended).map((e) => `${e.toolCallId} (${e.toolName})`).join(", "); return `Background task(s) you previously dispatched have completed. Process ONLY these tool-call IDs (their results are now in the conversation): ${idList}. IMPORTANT: Do NOT process any tool-call IDs that were not in the list, and do NOT call the same tool again \u2014 the result is already available. Use these result(s) to answer the user's original question.IMPORTANT: The following tool-call IDs are suspended: ${suspendedIdList}. Do not attempt to resume them; let the user know they are waiting for explicit resume input.`; } function buildContinuationOpts(baseContinuationOpts, callerContext, batch) { const directive = buildContinuationDirective(batch); return { ...baseContinuationOpts, context: [...callerContext ?? [], { role: "user", content: directive }] }; } function acquireStreamSlot(activeStreams, scopeKey, closer) { if (!scopeKey) return; const priorClose = activeStreams.get(scopeKey); priorClose?.(); activeStreams.set(scopeKey, closer); } function releaseStreamSlot(activeStreams, scopeKey, closer) { if (!scopeKey) return; if (activeStreams.get(scopeKey) === closer) { activeStreams.delete(scopeKey); } } async function runDurableStreamUntilIdle(agent, messages, streamOptions, deps) { const { maxIdleMs: _maxIdleMs, ...restStreamOptions } = streamOptions ?? {}; const defaultOptions = await agent.getDefaultOptions({ requestContext: streamOptions?.requestContext }); const mergedOptions = chunkER5YO3AZ_cjs.deepMerge( defaultOptions, restStreamOptions ?? {} ); const scope = await resolveScope(agent, mergedOptions); if (!deps.bgManager || !scope) { return agent.stream(messages, restStreamOptions); } const { threadId, resourceId, scopeKey } = scope; const maxIdleMs = _maxIdleMs ?? 5 * 6e4; const baseContinuationOpts = { ...restStreamOptions ?? {}, onFinish: void 0, _skipBgTaskWait: true }; const initialStreamOpts = { ...restStreamOptions ?? {}, _skipBgTaskWait: true }; const runningTaskIds = /* @__PURE__ */ new Set(); const pendingCompletions = []; const processedTerminalKeys = /* @__PURE__ */ new Set(); const innerCleanups = []; let isProcessing = false; let closed = false; let idleTimer; let outerController; const outerAbort = new AbortController(); let firstRunId; const forceClose = () => { if (closed) return; closed = true; if (idleTimer) { clearTimeout(idleTimer); idleTimer = void 0; } outerAbort.abort(); try { outerController.close(); } catch { } for (const fn of innerCleanups) { try { fn(); } catch { } } releaseStreamSlot(deps.activeStreams, scopeKey, forceClose); }; const tryClose = () => { if (closed) return; if (isProcessing) return; if (runningTaskIds.size > 0) return; if (pendingCompletions.length > 0) return; forceClose(); }; const clearIdleTimer = () => { if (idleTimer) { clearTimeout(idleTimer); idleTimer = void 0; } }; const updateIdleTimer = () => { if (closed) return; clearIdleTimer(); if (isProcessing) return; if (runningTaskIds.size === 0) return; if (pendingCompletions.length > 0) return; idleTimer = setTimeout(forceClose, maxIdleMs); }; const pipeInner = async (inner) => { const reader = inner.getReader(); try { while (true) { if (outerAbort.signal.aborted) break; const { done, value } = await reader.read(); if (done) break; clearIdleTimer(); try { outerController.enqueue(value); } catch { break; } if (value && typeof value === "object" && value.type === "background-task-started") { const taskId = value.payload?.taskId; if (taskId) runningTaskIds.add(taskId); } } } finally { reader.releaseLock(); } }; const processIfIdle = async () => { if (isProcessing || closed || pendingCompletions.length === 0) return; isProcessing = true; try { const batch = pendingCompletions.splice(0, pendingCompletions.length); for (const chunk of batch) { const tid = chunk.payload?.taskId; const ctype = chunk.type; if (tid && ctype) processedTerminalKeys.add(`${tid}:${ctype}`); } const continuationOpts = buildContinuationOpts(baseContinuationOpts, restStreamOptions?.context, batch); const inner = await agent.stream([], continuationOpts); innerCleanups.push(inner.cleanup); await pipeInner(inner.fullStream); } catch (err) { try { outerController.error(err); } catch { } forceClose(); return; } finally { isProcessing = false; if (pendingCompletions.length > 0) { void processIfIdle(); } else { tryClose(); updateIdleTimer(); } } }; acquireStreamSlot(deps.activeStreams, scopeKey, forceClose); streamOptions?.abortSignal?.addEventListener("abort", forceClose); const combinedStream = new ReadableStream({ start(controller) { outerController = controller; }, cancel() { closed = true; outerAbort.abort(); clearIdleTimer(); } }); const bgStream = deps.bgManager.stream({ agentId: agent.id, threadId, resourceId, abortSignal: outerAbort.signal }); const bgReader = bgStream.getReader(); void (async () => { try { while (true) { if (outerAbort.signal.aborted) break; const { done, value } = await bgReader.read(); if (done) break; const chunk = value; if (!chunk || typeof chunk !== "object" || typeof chunk.type !== "string") continue; const taskId = chunk.payload?.taskId; const terminalKey = taskId && TERMINAL_BG_CHUNKS.has(chunk.type) ? `${taskId}:${chunk.type}` : void 0; if (terminalKey && processedTerminalKeys.has(terminalKey)) { continue; } updateIdleTimer(); try { outerController.enqueue(chunk); } catch { break; } if (!taskId) continue; if (chunk.type === "background-task-running") { runningTaskIds.add(taskId); } else if (TERMINAL_BG_CHUNKS.has(chunk.type)) { runningTaskIds.delete(taskId); pendingCompletions.push(chunk); void processIfIdle(); } } } catch { } finally { bgReader.releaseLock(); } })(); isProcessing = true; clearIdleTimer(); let first; try { first = await agent.stream(messages, initialStreamOpts); } catch (err) { forceClose(); throw err; } firstRunId = first.runId; innerCleanups.push(first.cleanup); void (async () => { try { await pipeInner(first.fullStream); } catch (err) { try { outerController.error(err); } catch { } } isProcessing = false; if (pendingCompletions.length > 0) { void processIfIdle(); } else { tryClose(); updateIdleTimer(); } })(); return { output: new Proxy(first.output, { get(target, prop) { if (prop === "fullStream") return combinedStream; const value = Reflect.get(target, prop, target); return typeof value === "function" ? value.bind(target) : value; } }), get fullStream() { return combinedStream; }, runId: firstRunId, threadId, resourceId, cleanup: forceClose }; } // src/agent/durable/utils/serialize-state.ts function serializeToolMetadata(name, tool) { let inputSchema = { type: "object" }; if (tool.parameters) { if ("type" in tool.parameters && typeof tool.parameters.type === "string") { inputSchema = tool.parameters; } else if ("jsonSchema" in tool.parameters) { inputSchema = tool.parameters.jsonSchema; } else if ("_def" in tool.parameters) { inputSchema = { type: "object" }; } } return { id: "id" in tool && typeof tool.id === "string" ? tool.id : name, name, description: tool.description, inputSchema, requireApproval: tool.requireApproval, hasSuspendSchema: tool.hasSuspendSchema }; } function serializeToolsMetadata(tools) { return Object.entries(tools).map(([name, tool]) => serializeToolMetadata(name, tool)); } function serializeModelConfig(model) { return { provider: model.provider, modelId: model.modelId, specificationVersion: model.specificationVersion, // Store the original config string for runtime resolution (e.g., 'openai/gpt-4o') originalConfig: `${model.provider}/${model.modelId}` // Note: We don't serialize model settings here - they come from execution options }; } function serializeModelListEntry(entry) { const model = entry.model; return { id: entry.id, config: { provider: model.provider, modelId: model.modelId, specificationVersion: model.specificationVersion, originalConfig: `${model.provider}/${model.modelId}`, providerOptions: entry.providerOptions }, maxRetries: entry.maxRetries, enabled: entry.enabled }; } function serializeModelList(models) { return models.filter((m) => m.enabled !== false).map(serializeModelListEntry); } function serializeScorersConfig(scorers) { const result = {}; for (const [key, entry] of Object.entries(scorers)) { const scorerName = typeof entry.scorer === "string" ? entry.scorer : entry.scorer.name; const scorerEntry = { scorerName }; if (entry.sampling) { scorerEntry.sampling = entry.sampling; } result[key] = scorerEntry; } return result; } function serializeDurableState(params) { return { memoryConfig: params.memoryConfig, threadId: params.threadId, resourceId: params.resourceId, threadExists: params.threadExists, savePerStep: params.savePerStep, observationalMemory: params.observationalMemory }; } function serializeDurableOptions(options) { let serializedToolChoice; if (options.toolChoice) { if (typeof options.toolChoice === "string") { serializedToolChoice = options.toolChoice; } else if (typeof options.toolChoice === "object" && "type" in options.toolChoice) { if (options.toolChoice.type === "tool" && "toolName" in options.toolChoice) { serializedToolChoice = { type: "tool", toolName: options.toolChoice.toolName }; } } } return { maxSteps: options.maxSteps, toolChoice: serializedToolChoice, activeTools: options.activeTools, temperature: options.temperature, requireToolApproval: options.requireToolApproval, toolCallConcurrency: options.toolCallConcurrency, autoResumeSuspendedTools: options.autoResumeSuspendedTools, maxProcessorRetries: options.maxProcessorRetries, includeRawChunks: options.includeRawChunks, returnScorerData: options.returnScorerData, hasErrorProcessors: options.hasErrorProcessors, providerOptions: options.providerOptions, structuredOutput: options.structuredOutput, skipBgTaskWait: options.skipBgTaskWait }; } function createWorkflowInput(params) { return { __workflowKind: "durable-agent", runId: params.runId, agentId: params.agentId, agentName: params.agentName, messageListState: params.messageList.serialize(), toolsMetadata: serializeToolsMetadata(params.tools), modelConfig: serializeModelConfig(params.model), modelList: params.modelList ? serializeModelList(params.modelList) : void 0, scorers: params.scorers ? serializeScorersConfig(params.scorers) : void 0, options: serializeDurableOptions(params.options), state: serializeDurableState(params.state), messageId: params.messageId, agentSpanData: params.agentSpanData, modelSpanData: params.modelSpanData }; } function serializeError(error) { if (error instanceof Error) { return { name: error.name, message: error.message, stack: error.stack }; } return { name: "Error", message: String(error) }; } // src/agent/durable/preparation.ts async function prepareForDurableExecution(options) { const { agent, messages, options: execOptions, runId: providedRunId, requestContext: providedRequestContext, logger, mastra } = options; const typedAgent = agent; const runId = providedRunId ?? crypto.randomUUID(); const messageId = crypto.randomUUID(); const requestContext = providedRequestContext ?? new chunkPJIAL3WK_cjs.RequestContext(); const requestVersions = requestContext.get(chunkPJIAL3WK_cjs.MASTRA_VERSIONS_KEY); let mergedVersions = chunkPJIAL3WK_cjs.mergeVersionOverrides(mastra?.getVersionOverrides?.(), requestVersions); if (execOptions?.versions) { mergedVersions = chunkPJIAL3WK_cjs.mergeVersionOverrides(mergedVersions, execOptions.versions); } if (mergedVersions) { requestContext.set(chunkPJIAL3WK_cjs.MASTRA_VERSIONS_KEY, mergedVersions); } const thread = typeof execOptions?.memory?.thread === "string" ? { id: execOptions.memory.thread } : execOptions?.memory?.thread; const threadId = thread?.id; const resourceId = execOptions?.memory?.resource; let threadObject; let threadExists = false; const messageList = new chunk2TATDSHU_cjs.MessageList({ threadId, resourceId }); const instructions = await typedAgent.getInstructions({ requestContext }); if (instructions) { if (typeof instructions === "string") { messageList.addSystem(instructions); } else if (Array.isArray(instructions)) { for (const inst of instructions) { messageList.addSystem(inst); } } else { messageList.addSystem(instructions); } } const workspace = await typedAgent.getWorkspace({ requestContext }); if (workspace) { const hasFs = typeof workspace.hasFilesystemConfig === "function" ? workspace.hasFilesystemConfig() : !!workspace.filesystem; const hasSb = typeof workspace.hasSandboxConfig === "function" ? workspace.hasSandboxConfig() : !!workspace.sandbox; if (hasFs || hasSb) { const wsInstructions = typeof workspace.getInstructionsAsync === "function" ? await workspace.getInstructionsAsync({ requestContext }) : workspace.getInstructions({ requestContext }); if (wsInstructions) { messageList.addSystem({ role: "system", content: wsInstructions }); } } } if (execOptions?.context) { messageList.add(execOptions.context, "context"); } messageList.add(messages, "input"); const processorStates = /* @__PURE__ */ new Map(); let inputProcessors = []; let outputProcessors = []; let errorProcessors = []; try { inputProcessors = await typedAgent.listInputProcessors(requestContext); outputProcessors = await typedAgent.listOutputProcessors(requestContext); errorProcessors = await typedAgent.listErrorProcessors(requestContext); } catch (error) { logger?.warn?.(`[DurableAgent] Error resolving processors: ${error}`); } if (inputProcessors.length > 0) { try { const memory2 = await typedAgent.getMemory({ requestContext }); const memoryConfig2 = execOptions?.memory?.options; if (memory2 && threadId && resourceId) { const existingThread = await memory2.getThreadById({ threadId }); threadObject = existingThread ?? await memory2.createThread({ threadId, metadata: thread?.metadata, title: thread?.title, memoryConfig: memoryConfig2, resourceId, saveThread: true }); threadExists = true; requestContext.set("MastraMemory", { thread: threadObject, resourceId, memoryConfig: memoryConfig2 }); } const { ProcessorRunner: ProcessorRunner2 } = await import('../../runner-YB2BMTW2.cjs'); const runner = new ProcessorRunner2({ inputProcessors, outputProcessors, errorProcessors, logger, agentName: agent.name, processorStates }); await runner.runInputProcessors(messageList, {}, requestContext, 0); } catch (error) { logger?.warn?.(`[DurableAgent] Error running input processors: ${error}`); } } let tools = {}; try { tools = await typedAgent.getToolsForExecution({ toolsets: execOptions?.toolsets, clientTools: execOptions?.clientTools, threadId, resourceId, runId, requestContext, memoryConfig: execOptions?.memory?.options, autoResumeSuspendedTools: execOptions?.autoResumeSuspendedTools, hooks: execOptions?.hooks }); } catch (error) { logger?.warn?.(`[DurableAgent] Error converting tools: ${error}`); } const model = await typedAgent.getModel({ requestContext }); if (!model) { throw new Error("Agent model not available"); } const modelList = await typedAgent.getModelList(requestContext); const overrideScorers = execOptions?.scorers; let scorers; if (overrideScorers) { scorers = overrideScorers; } else { try { const agentScorers = await typedAgent.listScorers({ requestContext }); if (agentScorers && Object.keys(agentScorers).length > 0) { scorers = agentScorers; } } catch (error) { logger?.debug?.(`[DurableAgent] Error getting scorers: ${error}`); } } const memory = await typedAgent.getMemory({ requestContext }); const memoryConfig = execOptions?.memory?.options; const saveQueueManager = memory ? new chunkD37QL5LB_cjs.SaveQueueManager({ logger, memory }) : void 0; let serializedStructuredOutput; if (execOptions?.structuredOutput) { const so = execOptions.structuredOutput; if (so.schema) { serializedStructuredOutput = { jsonPromptInjection: so.jsonPromptInjection, useAgent: so.useAgent }; if (typeof so.schema === "object" && "type" in so.schema) { serializedStructuredOutput.schema = so.schema; } else if (typeof so.schema === "object" && "jsonSchema" in so.schema) { serializedStructuredOutput.schema = so.schema.jsonSchema; } } } const backgroundTasksConfig = typedAgent.getBackgroundTasksConfig?.(); const backgroundTaskManager = mastra?.backgroundTaskManager; const savePerStep = execOptions?.savePerStep; const observationalMemory = !!memoryConfig?.observationalMemory; const agentSpan = chunkLP4WZA6D_cjs.getOrCreateSpan({ type: "agent_run" /* AGENT_RUN */, name: `agent run: '${agent.id}'`, entityType: chunkLP4WZA6D_cjs.EntityType.AGENT, entityId: agent.id, entityName: agent.name, input: messages, metadata: { runId, resourceId, threadId }, tracingContext: execOptions?.tracingContext, tracingOptions: execOptions?.tracingOptions, requestContext, mastra }); const modelSpan = agentSpan?.createChildSpan({ type: "model_generation" /* MODEL_GENERATION */, name: `llm: '${model.modelId}'`, attributes: { model: model.modelId, provider: model.provider, streaming: true }, metadata: { runId, threadId, resourceId }, requestContext }); const workflowInput = createWorkflowInput({ runId, agentId: agent.id, agentName: agent.name, messageList, tools, model, modelList: modelList ?? void 0, scorers, options: { maxSteps: execOptions?.maxSteps, toolChoice: execOptions?.toolChoice, activeTools: execOptions?.activeTools, temperature: execOptions?.modelSettings?.temperature, // Durable runs serialize their options, so a function-valued global approval policy // can't be persisted. Degrade safely by requiring approval for every tool call. requireToolApproval: typeof execOptions?.requireToolApproval === "function" ? true : execOptions?.requireToolApproval, toolCallConcurrency: execOptions?.toolCallConcurrency, autoResumeSuspendedTools: execOptions?.autoResumeSuspendedTools, maxProcessorRetries: execOptions?.maxProcessorRetries, includeRawChunks: execOptions?.includeRawChunks, returnScorerData: execOptions?.returnScorerData, hasErrorProcessors: errorProcessors.length > 0, providerOptions: execOptions?.providerOptions, structuredOutput: serializedStructuredOutput, skipBgTaskWait: execOptions?._skipBgTaskWait }, state: { memoryConfig, threadId, resourceId, threadExists, savePerStep, observationalMemory }, messageId, agentSpanData: agentSpan?.exportSpan(), modelSpanData: modelSpan?.exportSpan() }); const registryEntry = { tools, saveQueueManager, memory, model, modelList: modelList ? modelList.map((entry) => ({ id: entry.id, model: entry.model, maxRetries: entry.maxRetries ?? 0, enabled: entry.enabled ?? true })) : void 0, workspace, requestContext, inputProcessors, outputProcessors, errorProcessors, processorStates, backgroundTaskManager, backgroundTasksConfig, agentSpan, modelSpan, cleanup: () => { } }; return { runId, messageId, workflowInput, registryEntry, messageList, threadId, resourceId }; } var globalRunRegistry = new ttlcache.TTLCache({ max: 1e3, ttl: 10 * 60 * 1e3, updateAgeOnGet: true, dispose: (entry) => { entry.cleanup?.(); }, noDisposeOnSet: true }); function endRunSpansWithError(runId, error) { try { const entry = globalRunRegistry.get(runId); (entry?.resumeModelSpan ?? entry?.modelSpan)?.error({ error, endSpan: true }); (entry?.resumeAgentSpan ?? entry?.agentSpan)?.error({ error, endSpan: true }); } catch { } } var RunRegistry = class { #entries = /* @__PURE__ */ new Map(); /** * Register non-serializable state for a run * @param runId - The unique run identifier * @param entry - The registry entry containing tools, saveQueueManager, etc. */ register(runId, entry) { this.cleanup(runId); this.#entries.set(runId, entry); } /** * Get the registry entry for a run * @param runId - The unique run identifier * @returns The registry entry or undefined if not found */ get(runId) { return this.#entries.get(runId); } /** * Get tools for a specific run * @param runId - The unique run identifier * @returns The tools record or an empty object if not found */ getTools(runId) { return this.#entries.get(runId)?.tools ?? {}; } /** * Get SaveQueueManager for a specific run * @param runId - The unique run identifier * @returns The SaveQueueManager or undefined if not found */ getSaveQueueManager(runId) { return this.#entries.get(runId)?.saveQueueManager; } /** * Get the language model for a specific run * @param runId - The unique run identifier * @returns The MastraLanguageModel or undefined if not found */ getModel(runId) { return this.#entries.get(runId)?.model; } /** * Check if a run is registered * @param runId - The unique run identifier * @returns True if the run is registered */ has(runId) { return this.#entries.has(runId); } /** * Cleanup and remove a run's entry from the registry * @param runId - The unique run identifier */ cleanup(runId) { const entry = this.#entries.get(runId); if (entry) { entry.cleanup?.(); this.#entries.delete(runId); } } /** * Get the number of active runs in the registry */ get size() { return this.#entries.size; } /** * Get all active run IDs */ get runIds() { return Array.from(this.#entries.keys()); } /** * Clear all entries from the registry * Calls cleanup on each entry before removing */ clear() { for (const runId of this.#entries.keys()) { this.cleanup(runId); } } }; var ExtendedRunRegistry = class extends RunRegistry { #messageLists = /* @__PURE__ */ new Map(); #memoryInfo = /* @__PURE__ */ new Map(); /** * Register non-serializable state for a run including MessageList */ registerWithMessageList(runId, entry, messageList, memoryInfo) { this.register(runId, entry); this.#messageLists.set(runId, messageList); if (memoryInfo) { this.#memoryInfo.set(runId, memoryInfo); } } /** * Get MessageList for a specific run */ getMessageList(runId) { return this.#messageLists.get(runId); } /** * Get memory info for a specific run */ getMemoryInfo(runId) { return this.#memoryInfo.get(runId); } /** * Override cleanup to also remove MessageList and memory info */ cleanup(runId) { super.cleanup(runId); this.#messageLists.delete(runId); this.#memoryInfo.delete(runId); } /** * Override clear to also clear MessageLists and memory info */ clear() { super.clear(); this.#messageLists.clear(); this.#memoryInfo.clear(); } }; function createDurableAgentStream(options) { const { pubsub, runId, messageId, model, threadId, resourceId, offset, onChunk, onStepFinish, onFinish, onError, onSuspended, logger } = options; const logError = (message, error) => { if (logger) { logger.error(message, error); } else { console.error(message, error); } }; const messageList = new chunk2TATDSHU_cjs.MessageList({ threadId, resourceId }); let isSubscribed = false; let cancelled = false; let controller = null; let resolveReady; let rejectReady; const ready = new Promise((resolve, reject) => { resolveReady = resolve; rejectReady = reject; }); const handleEvent = async (event) => { if (!controller) return; const streamEvent = event; try { switch (streamEvent.type) { case AgentStreamEventTypes.CHUNK: { const chunk = streamEvent.data; chunkNYGUBLK3_cjs.safeEnqueue(controller, chunk); await onChunk?.(chunk); break; } case AgentStreamEventTypes.STEP_START: { const chunk = streamEvent.data; if (chunk && "type" in chunk) { chunkNYGUBLK3_cjs.safeEnqueue(controller, chunk); } break; } case AgentStreamEventTypes.STEP_FINISH: { const data = streamEvent.data; await onStepFinish?.(data); break; } case AgentStreamEventTypes.FINISH: { const data = streamEvent.data; const finishChunk = { type: "finish", payload: { output: data.output, stepResult: data.stepResult } }; chunkNYGUBLK3_cjs.safeEnqueue(controller, finishChunk); chunkNYGUBLK3_cjs.safeClose(controller); try { await onFinish?.(data); } catch (callbackError) { logError(`[DurableAgentStream] onFinish callback error:`, callbackError); } break; } case AgentStreamEventTypes.ERROR: { const data = streamEvent.data; const error = new Error(data.error.message); error.name = data.error.name; if (data.error.stack) { error.stack = data.error.stack; } try { controller.error(error); } catch { } try { await onError?.(error); } catch (callbackError) { logError(`[DurableAgentStream] onError callback error:`, callbackError); } break; } case AgentStreamEventTypes.SUSPENDED: { const data = streamEvent.data; await onSuspended?.(data); break; } } } catch (error) { logError(`[DurableAgentStream] Error handling event ${streamEvent.type}:`, error); } }; const stream = new web.ReadableStream({ start(ctrl) { controller = ctrl; const topic = AGENT_STREAM_TOPIC(runId); const subscribePromise = offset !== void 0 ? pubsub.subscribeFromOffset(topic, offset, handleEvent) : pubsub.subscribeWithReplay(topic, handleEvent); subscribePromise.then(() => { if (cancelled) { void pubsub.unsubscribe(topic, handleEvent).catch((error) => { logError(`[DurableAgentStream] Failed to unsubscribe from ${topic}:`, error); }); resolveReady(); return; } isSubscribed = true; resolveReady(); }).catch((error) => { logError(`[DurableAgentStream] Failed to subscribe to ${topic}:`, error); rejectReady(error); ctrl.error(error); }); }, cancel() { cleanup(); } }); const cleanup = () => { cancelled = true; if (isSubscribed) { isSubscribed = false; const topic = AGENT_STREAM_TOPIC(runId); void pubsub.unsubscribe(topic, handleEvent).catch((error) => { logError(`[DurableAgentStream] Failed to unsubscribe from ${topic}:`, error); }); } controller = null; }; const output = new chunkNYGUBLK3_cjs.MastraModelOutput({ model, stream, messageList, messageId, options: { runId } }); return { output, cleanup, ready }; } async function emitChunkEvent(pubsub, runId, chunk) { const topic = AGENT_STREAM_TOPIC(runId); await pubsub.publish(topic, { type: AgentStreamEventTypes.CHUNK, runId, data: chunk }); } async function emitStepStartEvent(pubsub, runId, data) { await pubsub.publish(AGENT_STREAM_TOPIC(runId), { type: AgentStreamEventTypes.STEP_START, runId, data }); } async function emitStepFinishEvent(pubsub, runId, data) { await pubsub.publish(AGENT_STREAM_TOPIC(runId), { type: AgentStreamEventTypes.STEP_FINISH, runId, data }); } async function emitFinishEvent(pubsub, runId, data) { await pubsub.publish(AGENT_STREAM_TOPIC(runId), { type: AgentStreamEventTypes.FINISH, runId, data }); } async function emitErrorEvent(pubsub, runId, error) { await pubsub.publish(AGENT_STREAM_TOPIC(runId), { type: AgentStreamEventTypes.ERROR, runId, data: { error: { name: error.name, message: error.message // stack intentionally omitted — avoid leaking internals through external pubsub } } }); } async function emitSuspendedEvent(pubsub, runId, data) { await pubsub.publish(AGENT_STREAM_TOPIC(runId), { type: AgentStreamEventTypes.SUSPENDED, runId, data }); } // src/agent/durable/workflows/shared/execute-tool-calls.ts async function executeDurableToolCalls(ctx) { const toolResults = []; for (const toolCall of ctx.toolCalls) { if (toolCall.providerExecuted && toolCall.output !== void 0) { toolResults.push({ ...toolCall, result: toolCall.output }); continue; } const tool = ctx.tools[toolCall.toolName]; if (!tool) { const error = { name: "ToolNotFoundError", message: `Tool ${toolCall.toolName} not found` }; await ctx.onToolError?.(toolCall, error); toolResults.push({ ...toolCall, error }); continue; } await ctx.onToolStart?.(toolCall); try { if (tool.execute) { const result = await tool.execute(toolCall.args, { toolCallId: toolCall.toolCallId, messages: [], workspace: ctx.workspace, requestContext: ctx.requestContext }); await ctx.onToolResult?.(toolCall, result); toolResults.push({ ...toolCall, result }); } else { await ctx.onToolResult?.(toolCall, void 0); toolResults.push({ ...toolCall, result: void 0 }); } } catch (error) { const toolError = { name: "ToolExecutionError", message: error instanceof Error ? error.message : String(error), stack: error instanceof Error ? error.stack : void 0 }; await ctx.onToolError?.(toolCall, toolError); toolResults.push({ ...toolCall, error: toolError }); } } return toolResults; } var modelConfigSchema = zod.z.object({ provider: zod.z.string(), modelId: zod.z.string(), specificationVersion: zod.z.string().optional(), settings: zod.z.record(zod.z.string(), zod.z.any()).optional(), providerOptions: zod.z.record(zod.z.string(), zod.z.any()).optional() }); var modelListEntrySchema = zod.z.object({ id: zod.z.string(), config: zod.z.object({ provider: zod.z.string(), modelId: zod.z.string(), specificationVersion: zod.z.string().optional(), originalConfig: zod.z.union([zod.z.string(), zod.z.record(zod.z.string(), zod.z.any())]).optional(), providerOptions: zod.z.record(zod.z.string(), zod.z.any()).optional() }), maxRetries: zod.z.number(), enabled: zod.z.boolean() }); var accumulatedUsageSchema = zod.z.object({ inputTokens: zod.z.number(), outputTokens: zod.z.number(), totalTokens: zod.z.number() }); var durableAgenticOutputSchema = zod.z.object({ messageListState: zod.z.any(), messageId: zod.z.string(), stepResult: zod.z.any(), output: zod.z.object({ text: zod.z.string().optional(), usage: zod.z.any(), steps: zod.z.array(zod.z.any()) }), state: zod.z.any() }); var baseDurableAgenticInputSchema = zod.z.object({ runId: zod.z.string(), agentId: zod.z.string(), agentName: zod.z.string().optional(), messageListState: zod.z.any(), toolsMetadata: zod.z.array(zod.z.any()), modelConfig: modelConfigSchema, options: zod.z.any(), state: zod.z.any(), messageId: zod.z.string() }); var baseIterationStateSchema = zod.z.object({ // Original input fields runId: zod.z.string(), agentId: zod.z.string(), agentName: zod.z.string().optional(), messageListState: zod.z.any(), toolsMetadata: zod.z.array(zod.z.any()), modelConfig: zod.z.any(), options: zod.z.any(), state: zod.z.any(), messageId: zod.z.string(), // Iteration tracking iterationCount: zod.z.number(), accumulatedSteps: zod.z.array(zod.z.any()), accumulatedUsage: accumulatedUsageSchema, // Last step result for continuation check lastStepResult: zod.z.any().optional(), // Background task tracking backgroundTaskPending: zod.z.boolean().optional(), // Span data, carried unchanged so every iteration shares one trace agentSpanData: zod.z.any().optional(), modelSpanData: zod.z.any().optional() }); // src/agent/durable/workflows/shared/iteration-state.ts function calculateAccumulatedUsage(currentUsage, executionUsage) { return { inputTokens: currentUsage.inputTokens + (executionUsage?.inputTokens || 0), outputTokens: currentUsage.outputTokens + (executionUsage?.outputTokens || 0), totalTokens: currentUsage.totalTokens + (executionUsage?.totalTokens || 0) }; } function buildStepRecord(executionOutput) { return { text: executionOutput.output.text, toolCalls: executionOutput.output.toolCalls, toolResults: executionOutput.toolResults, usage: executionOutput.output.usage, finishReason: executionOutput.stepResult.reason }; } function createBaseIterationStateUpdate(input) { const { currentState, executionOutput } = input; const newUsage = calculateAccumulatedUsage(currentState.accumulatedUsage, executionOutput.output.usage); const stepRecord = buildStepRecord(executionOutput); return { runId: currentState.runId, agentId: currentState.agentId, agentName: currentState.agentName, messageListState: executionOutput.messageListState, toolsMetadata: currentState.toolsMetadata, modelConfig: currentState.modelConfig, options: currentState.options, state: executionOutput.state, messageId: executionOutput.messageId, iterationCount: currentState.iterationCount + 1, accumulatedSteps: [...currentState.accumulatedSteps, stepRecord], accumulatedUsage: newUsage, lastStepResult: executionOutput.stepResult, backgroundTaskPending: executionOutput.backgroundTaskPending, // Carry span identity forward unchanged so every iteration shares one trace. agentSpanData: currentState.agentSpanData, modelSpanData: currentState.modelSpanData }; } var BG_CHECK_STEP_ID = `${DurableStepIds.AGENTIC_EXECUTION}-bg-task-check`; var bgCheckInputSchema = zod.z.any(); var bgCheckOutputSchema = zod.z.any(); function createDurableBackgroundTaskCheckStep() { return chunkD37QL5LB_cjs.createStep({ id: BG_CHECK_STEP_ID, inputSchema: bgCheckInputSchema, outputSchema: bgCheckOutputSchema, execute: async (params) => { const { inputData, retryCount, getInitData } = params; const pubsub = params[chunkZCBG4ZQT_cjs.PUBSUB_SYMBOL]; const typedInput = inputData; const initData = getInitData(); const { runId, agentId } = initData; const registryEntry = globalRunRegistry.get(runId); const bgManager = registryEntry?.backgroundTaskManager; if (!bgManager) { return typedInput; } const runningResult = await bgManager.listTasks({ agentId, status: "running", threadId: initData.state?.threadId, resourceId: initData.state?.resourceId }); const runningTasks = runningResult?.tasks; if (!runningTasks || runningTasks.length === 0) { return typedInput; } if (initData.options?.skipBgTaskWait) { return { ...typedInput, backgroundTaskPending: true }; } const taskIds = runningTasks.map((task) => task.id); const bgConfig = registryEntry?.backgroundTasksConfig; const managerConfig = bgManager.config; const waitTimeoutMs = bgConfig?.waitTimeoutMs ?? managerConfig?.waitTimeoutMs; if (retryCount === 0 || !waitTimeoutMs) { return { ...typedInput, backgroundTaskPending: true }; } if (pubsub) { try { await emitChunkEvent(pubsub, runId, { type: "background-task-progress", runId, from: "AGENT" /* AGENT */, payload: { taskIds, runningCount: runningTasks.length, elapsedMs: 0 } }); } catch { } } try { await bgManager.waitForNextTask(taskIds, { timeoutMs: waitTimeoutMs, onProgress: (elapsedMs) => { if (!pubsub) return; void emitChunkEvent(pubsub, runId, { type: "background-task-progress", runId, from: "AGENT" /* AGENT */, payload: { taskIds, runningCount: runningTasks.length, elapsedMs } }).catch(() => { }); }, progressIntervalMs: 3e3 }); } catch { return typedInput; } if (typedInput.stepResult) { return { ...typedInput, backgroundTaskPending: true, stepResult: { ...typedInput.stepResult, isContinued: true } }; } return { ...typedInput, backgroundTaskPending: true }; } }); } // src/agent/durable/utils/resolve-runtime.ts async function resolveRuntimeDependencies(options) { const { mastra, runId, agentId, input, logger } = options; const messageList = new chunk2TATDSHU_cjs.MessageList({ threadId: input.state.threadId, resourceId: input.state.resourceId }); messageList.deserialize(input.messageListState); const globalEntry = globalRunRegistry.get(runId); let tools = globalEntry?.tools ?? {}; let model = globalEntry?.model; let modelList = globalEntry?.modelList; let workspace = globalEntry?.workspace; let memory; if (globalEntry) { logger?.debug?.(`[DurableAgent:${agentId}] Using model and tools from global registry for run ${runId}`); } else if (mastra) { try { const agent = mastra.getAgentById(agentId); const resolveRequestContext = new chunkPJIAL3WK_cjs.RequestContext(); tools = await agent.getToolsForExecution({ runId, threadId: input.state.threadId, resourceId: input.state.resourceId, requestContext: resolveRequestContext, memoryConfig: input.state.memoryConfig, autoResumeSuspendedTools: input.options?.autoResumeSuspendedTools }); model = await agent.getModel?.({ requestContext: resolveRequestContext }) ?? resolveModel(input.modelConfig); const rawModelList = await agent.getModelList?.(resolveRequestContext); if (rawModelList && Array.isArray(rawModelList)) { modelList = rawModelList.map((entry) => ({ id: entry.id, model: entry.model, maxRetries: entry.maxRetries ?? 0, enabled: entry.enabled ?? true })); } memory = await agent.getMemory?.({ requestContext: resolveRequestContext }); workspace = await agent.getWorkspace?.({ requestContext: resolveRequestContext }); } catch (error) { logger?.debug?.(`[DurableAgent:${agentId}] Failed to get agent from Mastra: ${error}`); model = resolveModel(input.modelConfig); } } else { logger?.debug?.(`[DurableAgent:${agentId}] No Mastra instance available, using fallback model`); model = resolveModel(input.modelConfig); } if (Object.keys(tools).length === 0) { logger?.debug?.(`[DurableAgent:${agentId}] No tools resolved for run ${runId}`); } let saveQueueManager; if (memory) { saveQueueManager = new chunkD37QL5LB_cjs.SaveQueueManager({ logger: mastra?.getLogger?.(), memory }); } const _internal = resolveInternalState({ state: input.state, memory, saveQueueManager, tools }); return { _internal, tools, model, modelList, messageList, memory, saveQueueManager, workspace }; } function resolveModel(config, _mastra) { const metadataError = () => { throw new Error( `Model ${config.provider}/${config.modelId} is a metadata-only stub. The actual model instance should be resolved from the run registry.` ); }; return { provider: config.provider, modelId: config.modelId, specificationVersion: config.specificationVersion ?? "v2", supportedUrls: {}, doGenerate: metadataError, doStream: metadataError, __metadataOnly: true }; } function resolveInternalState(options) { const { state, memory, saveQueueManager, tools } = options; return { // Functions - create fresh now: () => Date.now(), generateId: () => crypto.randomUUID(), currentDate: () => /* @__PURE__ */ new Date(), // Class instances - from resolved state saveQueueManager, memory, // Serializable state memoryConfig: state.memoryConfig, threadId: state.threadId, resourceId: state.resourceId, threadExists: state.threadExists, // Tools if provided - cast to ToolSet for compatibility // CoreTool and ToolSet are structurally compatible at runtime stepTools: tools }; } function resolveTool(toolName, mastra) { try { return mastra?.getTool?.(toolName); } catch { return void 0; } } async function toolRequiresApproval(tool, globalRequireApproval, args) { let requires = !!(globalRequireApproval || tool.requireApproval); const needsApprovalFn = chunkRS7FSLKM_cjs.getNeedsApprovalFn(tool); if (needsApprovalFn) { try { requires = !!await needsApprovalFn(args ?? {}); } catch { requires = true; } } return requires; } async function resolveModelFromConfig(config, mastra) { const requestContext = new chunkPJIAL3WK_cjs.RequestContext(); const modelConfigString = config.originalConfig ?? `${config.provider}/${config.modelId}`; if (typeof modelConfigString === "string") { return await chunkAWVVTLZF_cjs.resolveModelConfig(modelConfigString, requestContext, mastra); } return await chunkAWVVTLZF_cjs.resolveModelConfig( modelConfigString, requestContext, mastra ); } async function resolveModelFromListEntry(entry, mastra) { return resolveModelFromConfig(entry.config, mastra); } // src/agent/durable/workflows/steps/llm-execution.ts var durableLLMInputSchema = zod.z.object({ runId: zod.z.string(), agentId: zod.z.string(), agentName: zod.z.string().optional(), messageListState: zod.z.any(), // SerializedMessageListState toolsMetadata: zod.z.array(zod.z.any()), modelConfig: zod.z.object({ provider: zod.z.string(), modelId: zod.z.string(), specificationVersion: zod.z.string().optional(), originalConfig: zod.z.union([zod.z.string(), zod.z.record(zod.z.string(), zod.z.any())]).optional(), settings: zod.z.record(zod.z.string(), zod.z.any()).optional(), providerOptions: zod.z.record(zod.z.string(), zod.z.any()).optional() }), // Model list for fallback support (when agent configured with array of models) modelList: zod.z.array( zod.z.object({ id: zod.z.string(), config: zod.z.object({ provider: zod.z.string(), modelId: zod.z.string(), specificationVersion: zod.z.string().optional(), originalConfig: zod.z.union([zod.z.string(), zod.z.record(zod.z.string(), zod.z.any())]).optional(), providerOptions: zod.z.record(zod.z.string(), zod.z.any()).optional() }), maxRetries: zod.z.number(), enabled: zod.z.boolean() }) ).optional(), options: zod.z.any(), state: zod.z.any(), messageId: zod.z.string(), // Agent span data for model span parenting agentSpanData: zod.z.any().optional(), // Model span data (ONE span for entire agent run, created before workflow) modelSpanData: zod.z.any().optional(), // Step index for continuation (step: 0, 1, 2, ...) stepIndex: zod.z.number().optional() }); var durableLLMOutputSchema = zod.z.object({ messageListState: zod.z.any(), text: zod.z.string().optional(), toolCalls: zod.z.array( zod.z.object({ toolCallId: zod.z.string(), toolName: zod.z.string(), args: zod.z.record(zod.z.string(), zod.z.any()), providerMetadata: zod.z.record(zod.z.string(), zod.z.any()).optional(), activeTools: zod.z.array(zod.z.string()).nullable().optional() }) ), stepResult: zod.z.object({ reason: zod.z.string(), warnings: zod.z.array(zod.z.any()), isContinued: zod.z.boolean(), totalUsage: zod.z.any().optional() }), metadata: zod.z.any(), processorRetryCount: zod.z.number().optional(), processorRetryFeedback: zod.z.string().optional(), state: zod.z.any(), // Step index used in this execution (for tracking) stepIndex: zod.z.number().optional(), // Exported span data forwarded to downstream steps for trace nesting/closing modelSpanData: zod.z.any().optional(), stepSpanData: zod.z.any().optional(), stepFinishPayload: zod.z.any().optional() }); function createDurableLLMExecutionStep(_options) { return chunkD37QL5LB_cjs.createStep({ id: DurableStepIds.LLM_EXECUTION, inputSchema: durableLLMInputSchema, outputSchema: durableLLMOutputSchema, execute: async (params) => { const { inputData, mastra, tracingContext, requestContext, abortSignal } = params; const pubsub = params[chunkZCBG4ZQT_cjs.PUBSUB_SYMBOL]; const typedInput = inputData; const { agentId, messageId, options: execOptions } = typedInput; const runId = typedInput.runId; const logger = mastra?.getLogger?.(); const resolved = await resolveRuntimeDependencies({ mastra, runId, agentId, input: typedInput, logger }); const { messageList, tools, model: resolvedModel, modelList: resolvedModelList } = resolved; const hasModelList = typedInput.modelList && typedInput.modelList.length > 0; const modelList = hasModelList ? typedInput.modelList.filter((m) => m.enabled) : [ { id: `${typedInput.modelConfig.provider}/${typedInput.modelConfig.modelId}`, config: typedInput.modelConfig, maxRetries: 0, enabled: true } ]; if (modelList.length === 0) { throw new Error("No enabled models available for execution"); } let lastError; for (let modelIndex = 0; modelIndex < modelList.length; modelIndex++) { const modelEntry = modelList[modelIndex]; const maxRetries = modelEntry.maxRetries || 0; for (let attempt = 0; attempt <= maxRetries; attempt++) { try { const model = !hasModelList ? resolvedModel : resolvedModelList?.find((m) => m.id === modelEntry.id)?.model ?? await resolveModelFromListEntry(modelEntry, mastra); if (!chunkNYGUBLK3_cjs.isSupportedLanguageModel(model)) { const hint = model.__metadataOnly ? " The model could not be resolved from the run registry or Mastra instance." : ""; throw new Error( `Unsupported model version: ${model.specificationVersion}. Model must implement doStream.${hint}` ); } let currentMessageId = messageId; let currentModel = model; let currentTools = tools; let currentToolChoice = execOptions.toolChoice; let currentActiveTools = execOptions.activeTools; let currentModelSettings = { temperature: execOptions.temperature }; let currentProviderOptions = chunkD37QL5LB_cjs.mergeProviderOptions( execOptions.providerOptions, modelEntry.config.providerOptions ); const observability = mastra?.observability?.getSelectedInstance({ requestContext }); const inputModelSpanData = globalRunRegistry.get(runId)?.resumeModelSpanData ?? inputData.modelSpanData; const modelSpan = inputModelSpanData ? observability?.rebuildSpan(inputModelSpanData) : void 0; const modelSpanTracker = modelSpan?.createTracker(); const stepIndex = inputData.stepIndex ?? 0; modelSpanTracker?.setStepIndex(stepIndex); const structuredOutputConfig = execOptions.structuredOutput; const structuredOutput = structuredOutputConfig?.schema && !structuredOutputConfig?.structuringModelConfig ? { schema: structuredOutputConfig.schema, jsonPromptInjection: structuredOutputConfig.jsonPromptInjection } : void 0; const registryEntry = globalRunRegistry.get(runId); const executionAbortSignal = registryEntry?.abortSignal ?? abortSignal; if (registryEntry?.inputProcessors?.length) { const inputStepWriter = pubsub ? { custom: async (data) => { await emitChunkEvent(pubsub, runId, data); } } : void 0; const runner = new chunkNYGUBLK3_cjs.ProcessorRunner({ inputProcessors: registryEntry.inputProcessors, outputProcessors: registryEntry.outputProcessors ?? [], errorProcessors: registryEntry.errorProcessors ?? [], logger, agentName: typedInput.agentName ?? typedInput.agentId, processorStates: registryEntry.processorStates }); const processInputStepResult = await runner.runProcessInputStep({ messageList, stepNumber: stepIndex, steps: inputData.accumulatedSteps ?? [], tracingContext: modelSpanTracker?.getTracingContext() ?? tracingContext, requestContext, memory: registryEntry.memory, resourceId: typedInput.state?.resourceId, threadId: typedInput.state?.threadId, model: currentModel, messageId: currentMessageId, rotateResponseMessageId: () => { currentMessageId = crypto.randomUUID(); return currentMessageId; }, tools: currentTools, toolChoice: currentToolChoice, providerOptions: currentProviderOptions, activeTools: currentActiveTools, modelSettings: currentModelSettings, structuredOutput, retryCount: inputData.processorRetryCount ?? 0, abortSignal: executionAbortSignal, writer: inputStepWriter }); currentMessageId = processInputStepResult.messageId ?? currentMessageId; currentModel = processInputStepResult.model ?? currentModel; currentTools = processInputStepResult.tools ?? currentTools; currentToolChoice = processInputStepResult.toolChoice; currentProviderOptions = processInputStepResult.providerOptions ?? currentProviderOptions; currentActiveTools = processInputStepResult.activeTools; currentModelSettings = { ...currentModelSettings, ...processInputStepResult.modelSettings ?? {} }; } const inputMessages = await messageList.get.all.aiV5.llmPrompt(); modelSpanTracker?.setDeferStepClose(true); let warnings = []; let request = {}; let rawResponse = {}; const textDeltas = []; const toolCalls = []; let finishReason = "stop"; let usage = { inputTokens: 0, outputTokens: 0, totalTokens: 0 }; let responseMetadata = {}; modelSpanTracker?.startStep(); modelSpanTracker?.setInferenceContext?.({ parameters: currentModelSettings, providerOptions: currentProviderOptions, availableTools: chunkLP4WZA6D_cjs.getStepAvailableToolNames( currentTools, currentActiveTools ), toolChoice: currentToolChoice, responseFormat: structuredOutput ? "json_schema" : void 0 }); modelSpanTracker?.startInference?.(); const modelResult = chunkD37QL5LB_cjs.execute({ runId, model: currentModel, providerOptions: currentProviderOptions, inputMessages, tools: currentTools, toolChoice: currentToolChoice, activeTools: currentActiveTools, options: { abortSignal: executionAbortSignal }, modelSettings: { ...currentModelSettings, maxRetries: 0 }, includeRawChunks: execOptions.includeRawChunks, methodType: "stream", structuredOutput, onResult: ({ warnings: w, request: r, rawResponse: rr }) => { warnings = w || []; request = r || {}; rawResponse = rr || {}; modelSpanTracker?.updateStep?.({ request, inputMessages, warnings, messageId: currentMessageId }); if (pubsub) { void emitStepStartEvent(pubsub, runId, { stepId: DurableStepIds.LLM_EXECUTION, request, warnings }); } } }); const outputStream = new chunkNYGUBLK3_cjs.MastraModelOutput({ model: { modelId: currentModel.modelId, provider: currentModel.provider, version: currentModel.specificationVersion }, stream: modelResult, messageList, messageId: currentMessageId, options: { runId, tracingContext: modelSpanTracker?.getTracingContext() ?? tracingContext, requestContext } }); const baseStream = outputStream._getBaseStream(); const stepBoundaryStream = baseStream.pipeThrough( new TransformStream({ transform(chunk, controller) { if (chunk?.type === "finish") { controller.enqueue({ ...chunk, type: "step-finish" }); } else { controller.enqueue(chunk); } } }) ); const trackedStream = modelSpanTracker?.wrapStream(stepBoundaryStream) ?? stepBoundaryStream; try { for await (const chunk of trackedStream) { if (!chunk) continue; if (pubsub) { await emitChunkEvent(pubsub, runId, chunk); } switch (chunk.type) { case "text-delta": { const payload = chunk.payload; textDeltas.push(payload.text); break; } case "tool-call": { const payload = chunk.payload; toolCalls.push({ toolCallId: payload.toolCallId, toolName: payload.toolName, args: payload.args || {}, providerMetadata: payload.providerMetadata, providerExecuted: payload.providerExecuted, output: payload.output, activeTools: currentActiveTools ?? null }); break; } case "step-finish": { const payload = chunk.payload; finishReason = payload.stepResult?.reason || payload.finishReason || "stop"; usage = payload.output?.usage || payload.usage || usage; break; } case "response-metadata": { const payload = chunk.payload; responseMetadata = { id: payload.id, timestamp: payload.timestamp, modelId: payload.modelId, headers: payload.headers }; break; } case "error": { const payload = chunk.payload; const errorMessage = payload?.error?.message || payload?.message || "LLM execution error"; const errorObj = new Error(errorMessage); throw errorObj; } } } } catch (error) { logger?.error?.("Error processing LLM stream", { error, runId }); const errorObj = error instanceof Error ? error : new Error(String(error)); if (modelSpanTracker) { modelSpanTracker.reportGenerationError({ error: errorObj }); } else if (modelSpan) { modelSpan.error({ error: errorObj }); } lastError = errorObj; if (attempt < maxRetries) continue; break; } const streamError = outputStream.error; if (streamError) { logger?.error?.("Stream captured error", { error: streamError, runId }); if (modelSpanTracker) { modelSpanTracker.reportGenerationError({ error: streamError }); } else if (modelSpan) { modelSpan.error({ error: streamError }); } lastError = streamError; if (attempt < maxRetries) continue; break; } if (textDeltas.length > 0 || toolCalls.length > 0) { const parts = []; if (textDeltas.length > 0) { parts.push({ type: "text", text: textDeltas.join("") }); } for (const tc of toolCalls) { parts.push({ type: "tool-invocation", toolInvocation: { state: "call", toolCallId: tc.toolCallId, toolName: tc.toolName, args: tc.args } }); } const assistantMessage = { id: currentMessageId, role: "assistant", content: { format: 2, parts }, createdAt: /* @__PURE__ */ new Date() }; messageList.add(assistantMessage, "response"); } const isContinued = toolCalls.length > 0 && finishReason !== "stop"; const hasToolCalls = toolCalls.length > 0; const stepSpanData = hasToolCalls ? modelSpanTracker?.exportCurrentStep() : void 0; const stepFinishPayload = hasToolCalls ? modelSpanTracker?.getPendingStepFinishPayload() : void 0; const output = { messageListState: messageList.serialize(), text: textDeltas.join(""), toolCalls, stepResult: { reason: finishReason, warnings, isContinued, totalUsage: usage, headers: rawResponse?.headers, request }, metadata: { id: responseMetadata.id, modelId: responseMetadata.modelId || currentModel.modelId, timestamp: responseMetadata.timestamp || (/* @__PURE__ */ new Date()).toISOString(), providerMetadata: responseMetadata, headers: rawResponse?.headers, request }, state: typedInput.state, // Pass span data so tool calls can be children of model_step modelSpanData: hasToolCalls ? modelSpan?.exportSpan?.() : void 0, stepSpanData, stepFinishPayload }; if (!hasToolCalls) { const pendingPayload = modelSpanTracker?.getPendingStepFinishPayload(); if (pendingPayload) { const stepSpan = modelSpanTracker?.exportCurrentStep(); if (stepSpan && observability) { const rebuiltStepSpan = observability.rebuildSpan(stepSpan); rebuiltStepSpan?.end({ output: { text: textDeltas.join(""), toolCalls: [] }, attributes: { usage: pendingPayload.output?.usage, finishReason: pendingPayload.stepResult?.reason, isContinued: pendingPayload.stepResult?.isContinued } }); } } } return output; } catch (error) { lastError = error instanceof Error ? error : new Error(String(error)); const modelId = modelEntry.config.modelId; logger?.error?.(`Error executing model ${modelId}, attempt ${attempt + 1}/${maxRetries + 1}`, { error: lastError, runId, modelIndex, attempt }); const registryEntry = globalRunRegistry.get(runId); if (registryEntry?.errorProcessors?.length) { try { const runner = new chunkNYGUBLK3_cjs.ProcessorRunner({ inputProcessors: registryEntry.inputProcessors ?? [], outputProcessors: registryEntry.outputProcessors ?? [], errorProcessors: registryEntry.errorProcessors, logger, agentName: typedInput.agentName ?? typedInput.agentId, processorStates: registryEntry.processorStates }); const currentMessageList = new chunk2TATDSHU_cjs.MessageList(); currentMessageList.deserialize(typedInput.messageListState); const { retry } = await runner.runProcessAPIError({ error: lastError, messages: currentMessageList.get.all.db(), messageList: currentMessageList, stepNumber: inputData.stepIndex ?? 0, steps: [], requestContext }); if (retry) { logger?.debug?.(`processAPIError requested retry for model ${modelId}`, { runId }); continue; } } catch (processorError) { logger?.debug?.(`processAPIError handler failed: ${processorError}`, { runId }); } } if (attempt >= maxRetries) { logger?.debug?.(`Exhausted retries for model ${modelId}, trying next model`, { runId }); break; } const delayMs = Math.min(1e3 * Math.pow(2, attempt), 1e4); logger?.debug?.(`Retrying model ${modelId} after ${delayMs}ms`, { runId, attempt }); await new Promise((resolve) => setTimeout(resolve, delayMs)); } } } const fatalError = lastError ?? new Error("Exhausted all fallback models and reached the maximum number of retries."); endRunSpansWithError(runId, fatalError); throw fatalError; } }); } var durableToolCallInputSchema = zod.z.object({ toolCallId: zod.z.string(), toolName: zod.z.string(), args: zod.z.record(zod.z.string(), zod.z.any()), providerMetadata: zod.z.record(zod.z.string(), zod.z.any()).optional(), providerExecuted: zod.z.boolean().optional(), output: zod.z.any().optional(), activeTools: zod.z.array(zod.z.string()).nullable().optional(), // Exported MODEL_STEP span so the TOOL_CALL nests under the LLM call stepSpanData: zod.z.any().optional() }); var durableToolCallOutputSchema = durableToolCallInputSchema.extend({ result: zod.z.any().optional(), error: zod.z.object({ name: zod.z.string(), message: zod.z.string(), stack: zod.z.string().optional() }).optional() }); async function flushMessagesBeforeSuspension({ saveQueueManager, messageList, memory, threadId, resourceId, memoryConfig, threadExists, onThreadCreated }) { if (!saveQueueManager || !messageList || !threadId) { return; } try { if (memory && !threadExists && resourceId) { const thread = await memory.getThreadById?.({ threadId }); if (!thread) { await memory.createThread?.({ threadId, resourceId, memoryConfig }); } onThreadCreated?.(); } await saveQueueManager.flushMessages(messageList, threadId, memoryConfig); } catch { } } function createDurableToolCallStep() { return chunkD37QL5LB_cjs.createStep({ id: DurableStepIds.TOOL_CALL, inputSchema: durableToolCallInputSchema, outputSchema: durableToolCallOutputSchema, execute: async (params) => { const { inputData, mastra, suspend, resumeData, requestContext, getInitData } = params; const pubsub = params[chunkZCBG4ZQT_cjs.PUBSUB_SYMBOL]; const typedInput = inputData; const { toolCallId, toolName, args, providerExecuted, output, activeTools } = typedInput; const initData = getInitData(); const { runId, options: agentOptions, state } = initData; const logger = mastra?.getLogger?.(); const endSpansAsSuspended = (info) => { try { const obs = mastra?.observability?.getSelectedInstance({ requestContext }); if (!obs) return; const output2 = { status: "suspended", reason: info.reason, toolName: info.toolName, toolCallId: info.toolCallId }; const reg = globalRunRegistry.get(runId); const agentSpanData = reg?.resumeAgentSpanData ?? initData.agentSpanData; const modelSpanData = reg?.resumeModelSpanData ?? initData.modelSpanData; if (typedInput.stepSpanData) { obs.rebuildSpan(typedInput.stepSpanData)?.end({ output: output2 }); } if (modelSpanData) { obs.rebuildSpan(modelSpanData)?.end({ output: output2 }); } if (agentSpanData) { obs.rebuildSpan(agentSpanData)?.end({ output: output2 }); } } catch (error) { logger?.warn?.(`[DurableAgent] Failed to end spans on suspend: ${error}`); } }; if (providerExecuted && output !== void 0) { return { ...typedInput, result: output }; } const registryEntry = globalRunRegistry.get(runId); let tool = registryEntry?.tools?.[toolName]; if (!tool) { tool = resolveTool(toolName, mastra); } const toolKey = registryEntry?.tools?.[toolName] ? toolName : Object.entries(registryEntry?.tools ?? {}).find(([, registeredTool]) => registeredTool === tool)?.[0]; const effectiveActiveTools = activeTools === null ? void 0 : activeTools ?? agentOptions.activeTools; const activeToolKey = toolKey ?? toolName; const isHiddenByActiveTools = effectiveActiveTools !== void 0 && !effectiveActiveTools.includes(activeToolKey); if (!tool || isHiddenByActiveTools) { const availableToolNames = effectiveActiveTools ?? Object.keys(registryEntry?.tools ?? {}); const availableToolsStr = availableToolNames.length > 0 ? ` Available tools: ${availableToolNames.join(", ")}` : ""; const error = { name: "ToolNotFoundError", message: `Tool "${toolName}" not found.${availableToolsStr}. Call tools by their exact name only \u2014 never add prefixes, namespaces, or colons.` }; if (pubsub) { await emitChunkEvent(pubsub, runId, { type: "tool-error", runId, from: "AGENT" /* AGENT */, payload: { toolCallId, toolName, args, error } }); } return { ...typedInput, error }; } const saveQueueManager = registryEntry?.saveQueueManager; const memory = registryEntry?.memory; const workspace = registryEntry?.workspace; let threadExists = state?.threadExists ?? false; let messageList; const extendedEntry = globalRunRegistry.get(runId); if (extendedEntry?.messageList) { messageList = extendedEntry.messageList; } const doFlush = () => flushMessagesBeforeSuspension({ saveQueueManager, messageList, memory, threadId: state?.threadId, resourceId: state?.resourceId, memoryConfig: state?.memoryConfig, threadExists, onThreadCreated: () => { threadExists = true; } }); const requiresApproval = await toolRequiresApproval(tool, agentOptions.requireToolApproval, args); if (requiresApproval && !resumeData) { const resumeSchema = JSON.stringify({ type: "object", properties: { approved: { type: "boolean" } }, required: ["approved"] }); if (pubsub) { await emitChunkEvent(pubsub, runId, { type: "tool-call-approval", runId, from: "AGENT" /* AGENT */, payload: { toolCallId, toolName, args, resumeSchema } }); } if (pubsub) { await emitSuspendedEvent(pubsub, runId, { toolCallId, toolName, args, type: "approval", resumeSchema }); } await doFlush(); endSpansAsSuspended({ toolCallId, toolName, reason: "approval" }); return suspend( { type: "approval", toolCallId, toolName, args }, { resumeLabel: toolCallId } ); } if (resumeData && typeof resumeData === "object" && resumeData !== null && "approved" in resumeData) { if (!resumeData.approved) { return { ...typedInput, result: "Tool call was not approved by the user" }; } } const isResumingFromSuspension = resumeData && typeof resumeData === "object" && resumeData !== null && !("approved" in resumeData); const bgManager = registryEntry?.backgroundTaskManager; const bgConfig = registryEntry?.backgroundTasksConfig; const toolBgConfig = tool.backgroundConfig; const llmBgOverrides = typeof args === "object" && args !== null && "_background" in args ? args._background : void 0; const cleanedArgs = { ...args }; if ("_background" in cleanedArgs) { delete cleanedArgs._background; } if (!tool.execute) { return { ...typedInput, result: void 0 }; } const observability = mastra?.observability?.getSelectedInstance({ requestContext }); const stepSpan = typedInput.stepSpanData && observability ? observability.rebuildSpan(typedInput.stepSpanData) : void 0; const toolTracingContext = stepSpan ? { currentSpan: stepSpan } : void 0; const toolOptions = { toolCallId, messages: [], workspace, requestContext, tracingContext: toolTracingContext, resumeData: isResumingFromSuspension ? resumeData : void 0, // In-execution suspend callback — allows tools to suspend mid-execution suspend: async (suspendPayload, suspendOptions) => { if (suspendOptions?.requireToolApproval) { const approvalResumeSchema = JSON.stringify({ type: "object", properties: { approved: { type: "boolean" } }, required: ["approved"] }); if (pubsub) { await emitChunkEvent(pubsub, runId, { type: "tool-call-approval", runId, from: "AGENT" /* AGENT */, payload: { toolCallId, toolName, args, resumeSchema: approvalResumeSchema } }); } if (pubsub) { await emitSuspendedEvent(pubsub, runId, { toolCallId, toolName, args, type: "approval", resumeSchema: approvalResumeSchema }); } await doFlush(); endSpansAsSuspended({ toolCallId, toolName, reason: "approval" }); return suspend( { type: "approval", requireToolApproval: { toolCallId, toolName, args } }, { resumeLabel: toolCallId } ); } else { const suspendedEventData = { toolCallId, toolName, args, suspendPayload, type: "suspension", resumeSchema: suspendOptions?.resumeSchema }; if (pubsub) { await emitChunkEvent(pubsub, runId, { type: "tool-call-suspended", runId, from: "AGENT" /* AGENT */, payload: { toolCallId, toolName, suspendPayload, args, resumeSchema: suspendOptions?.resumeSchema } }); await emitSuspendedEvent(pubsub, runId, suspendedEventData); } await doFlush(); endSpansAsSuspended({ toolCallId, toolName, reason: "suspension" }); return suspend( { type: "suspension", toolCallSuspended: suspendPayload, toolName, resumeLabel: suspendOptions?.resumeLabel }, { resumeLabel: toolCallId } ); } } }; if (bgManager && !bgConfig?.disabled && typeof cleanedArgs === "object" && cleanedArgs !== null) { const bgResolved = chunk23FX5JPX_cjs.resolveBackgroundConfig({ llmBgOverrides, toolName, toolConfig: toolBgConfig, agentConfig: bgConfig, managerConfig: bgManager.config }); if (bgResolved.runInBackground) { try { const bgTask = chunk23FX5JPX_cjs.createBackgroundTask(bgManager, { toolName, toolCallId, args: cleanedArgs, agentId: initData.agentId, threadId: state?.threadId, resourceId: state?.resourceId, runId, timeoutMs: bgResolved.timeoutMs, maxRetries: bgResolved.maxRetries, context: { executor: { execute: async (taskArgs, taskContext) => { return tool.execute(taskArgs, { ...toolOptions, ...taskContext?.resumeData !== void 0 ? { resumeData: taskContext.resumeData } : {}, suspend: async (data, options) => { await toolOptions.suspend?.(data, options); return taskContext?.suspend?.(data, options); } }); } }, onChunk: (chunk) => { if (!pubsub) return; try { const bgRunId = chunk.payload.runId; if (bgRunId !== runId || bgRunId === runId && resumeData) { void emitChunkEvent(pubsub, bgRunId, { type: "tool-call", runId: bgRunId, from: "AGENT" /* AGENT */, payload: { toolCallId: chunk.payload.toolCallId, toolName: chunk.payload.toolName, args: cleanedArgs } }); } if (chunk.type === "background-task-completed") { void emitChunkEvent(pubsub, bgRunId, { type: "tool-result", runId: bgRunId, from: "AGENT" /* AGENT */, payload: { toolCallId: chunk.payload.toolCallId, toolName: chunk.payload.toolName, args: cleanedArgs, result: chunk.payload.result } }); } else if (chunk.type === "background-task-failed") { void emitChunkEvent(pubsub, bgRunId, { type: "tool-error", runId: bgRunId, from: "AGENT" /* AGENT */, payload: { toolCallId: chunk.payload.toolCallId, toolName: chunk.payload.toolName, error: chunk.payload.error, args: cleanedArgs } }); } } catch { } }, onResult: async (params2) => { if (!messageList) return; const result = params2.status === "failed" ? `Background task failed: ${params2.error?.message ?? "Unknown error"}` : params2.result; const updated = messageList.updateToolInvocation( { type: "tool-invocation", toolInvocation: { state: "result", toolCallId: params2.toolCallId, toolName: params2.toolName, args: cleanedArgs, result } }, { backgroundTasks: { [params2.toolCallId]: { startedAt: params2.startedAt, completedAt: params2.completedAt, taskId: params2.taskId } } } ); if (!updated) { if (params2.runId !== runId || params2.runId === runId && resumeData) { messageList.add( [ { role: "tool", type: "tool-call", id: crypto.randomUUID(), createdAt: /* @__PURE__ */ new Date(), content: [ { type: "tool-call", toolCallId: params2.toolCallId, toolName: params2.toolName, args: cleanedArgs } ] } ], "response" ); } messageList.add( [ { role: "tool", content: [ { type: "tool-result", toolCallId: params2.toolCallId, toolName: params2.toolName, result, isError: params2.status === "failed" } ] } ], "response" ); } if (saveQueueManager && state?.threadId) { await saveQueueManager.flushMessages(messageList, state.threadId, state.memoryConfig); } }, onExecution: async (params2) => { if (!messageList) return; messageList.updateToolInvocation( { type: "tool-invocation", toolInvocation: { state: "call", toolCallId: params2.toolCallId, toolName: params2.toolName, args: cleanedArgs } }, { backgroundTasks: { [params2.toolCallId]: { startedAt: params2.startedAt, suspendedAt: params2.suspendedAt, taskId: params2.taskId } } } ); }, onComplete: toolBgConfig?.onComplete ?? bgConfig?.onTaskComplete, onFailed: toolBgConfig?.onFailed ?? bgConfig?.onTaskFailed } }); const isSuspendedBgResume = isResumingFromSuspension && resumeData && typeof resumeData === "object" && resumeData !== null; if (isSuspendedBgResume) { const isSuspended = await bgTask.checkIfSuspended({ toolCallId, runId, agentId: initData.agentId, threadId: state?.threadId, resourceId: state?.resourceId, toolName }); if (isSuspended) { const task2 = await bgTask.resume(resumeData); return { ...typedInput, args: cleanedArgs, result: `Background task resumed. Task ID: ${task2.id}. The tool "${toolName}" is running in the background. You will be notified when it completes.` }; } } const { task, fallbackToSync } = await bgTask.dispatch(); if (!fallbackToSync) { if (pubsub) { await emitChunkEvent(pubsub, runId, { type: "background-task-started", runId, from: "AGENT" /* AGENT */, payload: { taskId: task.id, toolName, toolCallId } }); } return { ...typedInput, args: cleanedArgs, result: `Background task started. Task ID: ${task.id}. The tool "${toolName}" is running in the background. You will be notified when it completes.` }; } } catch (bgError) { logger?.debug?.( `[DurableAgent] Background task dispatch failed for ${toolName}, falling back to sync: ${bgError}` ); } } } try { const result = await tool.execute(cleanedArgs, toolOptions); if (pubsub) { try { await emitChunkEvent(pubsub, runId, { type: "tool-result", runId, from: "AGENT" /* AGENT */, payload: { toolCallId, toolName, args, result } }); } catch (emitError) { logger?.warn?.(`[DurableAgent] Failed to emit tool-result chunk for ${toolName}: ${emitError}`); } } return { ...typedInput, result }; } catch (error) { const toolError = serializeError(error); if (pubsub) { try { await emitChunkEvent(pubsub, runId, { type: "tool-error", runId, from: "AGENT" /* AGENT */, payload: { toolCallId, toolName, args, error: toolError } }); } catch (emitError) { logger?.warn?.(`[DurableAgent] Failed to emit tool-error chunk for ${toolName}: ${emitError}`); } } return { ...typedInput, error: toolError }; } } }); } var durableLLMMappingInputSchema = zod.z.object({ llmOutput: zod.z.any(), // DurableLLMStepOutput toolResults: zod.z.array(zod.z.any()), // DurableToolCallOutput[] runId: zod.z.string(), agentId: zod.z.string(), messageId: zod.z.string(), state: zod.z.any() // SerializableDurableState }); var durableLLMMappingOutputSchema = zod.z.object({ messageListState: zod.z.any(), messageId: zod.z.string(), stepResult: zod.z.any(), toolResults: zod.z.array(zod.z.any()), output: zod.z.object({ text: zod.z.string().optional(), toolCalls: zod.z.array(zod.z.any()).optional(), usage: zod.z.any(), steps: zod.z.array(zod.z.any()) }), state: zod.z.any(), processorRetryCount: zod.z.number().optional(), processorRetryFeedback: zod.z.string().optional() }); function createDurableLLMMappingStep() { return chunkD37QL5LB_cjs.createStep({ id: DurableStepIds.LLM_MAPPING, inputSchema: durableLLMMappingInputSchema, outputSchema: durableLLMMappingOutputSchema, execute: async ({ inputData, mastra, requestContext }) => { const { llmOutput, toolResults, messageId, state } = inputData; const messageList = new chunk2TATDSHU_cjs.MessageList({ threadId: state.threadId, resourceId: state.resourceId }); messageList.deserialize(llmOutput.messageListState); if (toolResults.length > 0) { for (const toolResult of toolResults) { const result = toolResult.error ? toolResult.error.message : toolResult.result; const updated = messageList.updateToolInvocation({ type: "tool-invocation", toolInvocation: { state: "result", toolCallId: toolResult.toolCallId, toolName: toolResult.toolName, args: toolResult.args, result } }); if (!updated) { messageList.add( [ { role: "tool", content: [ { type: "tool-result", toolCallId: toolResult.toolCallId, toolName: toolResult.toolName, result, isError: toolResult.error !== void 0 } ] } ], "response" ); } } } const allToolsErrored = toolResults.length > 0 && toolResults.every((r) => r.error !== void 0); const allToolsNotFound = allToolsErrored && toolResults.every((r) => r.error?.name === "ToolNotFoundError"); const isContinued = llmOutput.stepResult.isContinued && (!allToolsErrored || allToolsNotFound); const output = { messageListState: messageList.serialize(), messageId, stepResult: { ...llmOutput.stepResult, isContinued }, toolResults, output: { text: llmOutput.text, toolCalls: llmOutput.toolCalls, usage: llmOutput.stepResult.totalUsage ?? { inputTokens: 0, outputTokens: 0, totalTokens: 0 }, steps: [] // Steps are accumulated at the loop level }, state: { ...state, threadExists: state.threadExists }, processorRetryCount: llmOutput.processorRetryCount, processorRetryFeedback: llmOutput.processorRetryFeedback }; if (llmOutput.stepSpanData) { try { const observability = mastra?.observability?.getSelectedInstance({ requestContext }); const stepSpan = observability?.rebuildSpan(llmOutput.stepSpanData); const pendingPayload = llmOutput.stepFinishPayload; stepSpan?.end({ output: { text: llmOutput.text, toolCalls: llmOutput.toolCalls }, attributes: { usage: pendingPayload?.output?.usage, finishReason: pendingPayload?.stepResult?.reason, isContinued: pendingPayload?.stepResult?.isContinued } }); } catch (error) { mastra?.getLogger?.()?.warn?.(`[DurableAgent] Failed to close model_step span: ${error}`); } } return output; } }); } // src/agent/durable/workflows/create-durable-agentic-workflow.ts var durableAgenticInputSchema = zod.z.object({ __workflowKind: zod.z.literal("durable-agent"), runId: zod.z.string(), agentId: zod.z.string(), agentName: zod.z.string().optional(), messageListState: zod.z.any(), toolsMetadata: zod.z.array(zod.z.any()), modelConfig: modelConfigSchema, // Model list for fallback support (when agent configured with array of models) modelList: zod.z.array(modelListEntrySchema).optional(), options: zod.z.any(), state: zod.z.any(), messageId: zod.z.string(), // Exported AGENT_RUN / MODEL_GENERATION span data, threaded so the run shares one trace agentSpanData: zod.z.any().optional(), modelSpanData: zod.z.any().optional() }); var iterationStateSchema = baseIterationStateSchema.extend({ // Model list for fallback support modelList: zod.z.array(zod.z.any()).optional() }); function createDurableAgenticWorkflow(options) { const maxSteps = options?.maxSteps ?? DurableAgentDefaults.MAX_STEPS; const llmExecutionStep = createDurableLLMExecutionStep(); const toolCallStep = createDurableToolCallStep(); const llmMappingStep = createDurableLLMMappingStep(); const backgroundTaskCheckStep = createDurableBackgroundTaskCheckStep(); const singleIterationWorkflow = chunkD37QL5LB_cjs.createWorkflow({ id: DurableStepIds.AGENTIC_EXECUTION, inputSchema: iterationStateSchema, outputSchema: iterationStateSchema, options: { shouldPersistSnapshot: ({ workflowStatus }) => workflowStatus === "suspended", validateInputs: false, sharePubsub: true, // Internal durable-agent execution plumbing — hide workflow spans; // the agent/tool/model spans within still surface for users. tracingPolicy: { internal: 1 /* WORKFLOW */ } } }).map( async ({ inputData }) => { const state = inputData; return { runId: state.runId, agentId: state.agentId, agentName: state.agentName, messageListState: state.messageListState, toolsMetadata: state.toolsMetadata, modelConfig: state.modelConfig, modelList: state.modelList, options: state.options, state: state.state, messageId: state.messageId, stepIndex: state.iterationCount, agentSpanData: state.agentSpanData, modelSpanData: state.modelSpanData }; }, { id: "map-to-llm-input" } ).then(llmExecutionStep).map( async ({ inputData }) => { const llmOutput = inputData; return (llmOutput.toolCalls ?? []).map((toolCall) => ({ ...toolCall, stepSpanData: llmOutput.stepSpanData })); }, { id: "extract-tool-calls" } ).foreach(toolCallStep).map( async ({ inputData, getStepResult, getInitData }) => { const toolResults = inputData; const llmOutput = getStepResult(llmExecutionStep.id); const initData = getInitData(); return { llmOutput, toolResults, runId: initData.runId, agentId: initData.agentId, messageId: initData.messageId, state: llmOutput?.state ?? initData.state }; }, { id: "collect-tool-results" } ).then(llmMappingStep).then(backgroundTaskCheckStep).map( async ({ inputData, getInitData }) => { const executionOutput = inputData; const initData = getInitData(); const baseUpdate = createBaseIterationStateUpdate({ currentState: initData, executionOutput }); const newIterationState = { ...baseUpdate, modelList: initData.modelList }; return newIterationState; }, { id: "update-iteration-state" } ).commit(); return chunkD37QL5LB_cjs.createWorkflow({ id: DurableStepIds.AGENTIC_LOOP, inputSchema: durableAgenticInputSchema, outputSchema: durableAgenticOutputSchema, options: { shouldPersistSnapshot: ({ workflowStatus }) => workflowStatus === "suspended", validateInputs: false, // Internal durable-agent execution plumbing — see singleIterationWorkflow. tracingPolicy: { internal: 1 /* WORKFLOW */ } } }).map( async ({ inputData }) => { const input = inputData; const iterationState = { ...input, iterationCount: 0, accumulatedSteps: [], accumulatedUsage: { inputTokens: 0, outputTokens: 0, totalTokens: 0 }, lastStepResult: void 0 }; return iterationState; }, { id: "init-iteration-state" } ).dowhile(singleIterationWorkflow, async ({ inputData }) => { const state = inputData; const shouldContinue = state.lastStepResult?.isContinued === true; const runMaxSteps = state.options?.maxSteps ?? maxSteps; const underMaxSteps = state.iterationCount < runMaxSteps; return shouldContinue && underMaxSteps; }).map( async (params) => { const { inputData, mastra, requestContext } = params; const state = inputData; const initData = params.getInitData(); const pubsub = params[chunkZCBG4ZQT_cjs.PUBSUB_SYMBOL]; const logger = mastra?.getLogger?.(); const lastStep = state.accumulatedSteps[state.accumulatedSteps.length - 1]; const finalText = lastStep?.text; const registryEntry = globalRunRegistry.get(state.runId); if (registryEntry?.outputProcessors?.length) { try { const { ProcessorRunner: ProcessorRunner2 } = await import('../../runner-YB2BMTW2.cjs'); const runner = new ProcessorRunner2({ inputProcessors: registryEntry.inputProcessors ?? [], outputProcessors: registryEntry.outputProcessors, errorProcessors: registryEntry.errorProcessors ?? [], logger, agentName: initData.agentName ?? initData.agentId, processorStates: registryEntry.processorStates }); const outputMessageList = new chunk2TATDSHU_cjs.MessageList(); outputMessageList.deserialize(state.messageListState); await runner.runOutputProcessors(outputMessageList, {}, requestContext ?? new chunkPJIAL3WK_cjs.RequestContext(), 0); } catch (error) { logger?.warn?.(`[DurableAgent] Error running output processors: ${error}`); } } const durableState = initData.state; if (registryEntry?.saveQueueManager && registryEntry.memory && durableState?.threadId && durableState?.resourceId && !durableState.observationalMemory) { try { const memoryMessageList = new chunk2TATDSHU_cjs.MessageList(); memoryMessageList.deserialize(state.messageListState); if (!durableState.threadExists) { await registryEntry.memory.createThread?.({ threadId: durableState.threadId, resourceId: durableState.resourceId, memoryConfig: durableState.memoryConfig }); } await registryEntry.saveQueueManager.flushMessages( memoryMessageList, durableState.threadId, durableState.memoryConfig ); } catch (error) { logger?.warn?.(`[DurableAgent] Error persisting messages: ${error}`); } } const finalOutput = { messageListState: state.messageListState, messageId: state.messageId, stepResult: state.lastStepResult || { reason: "stop", warnings: [], isContinued: false }, output: { text: finalText, usage: state.accumulatedUsage, steps: state.accumulatedSteps }, state: state.state }; if (pubsub) { await emitFinishEvent(pubsub, state.runId, { output: finalOutput.output, stepResult: finalOutput.stepResult }); } try { const observability = mastra?.observability?.getSelectedInstance({ requestContext }); const reg = globalRunRegistry.get(initData.runId); const modelSpanData = reg?.resumeModelSpanData ?? initData.modelSpanData; const agentSpanData = reg?.resumeAgentSpanData ?? initData.agentSpanData; if (observability) { if (modelSpanData) { const modelSpan = observability.rebuildSpan( modelSpanData ); modelSpan?.createTracker()?.endGeneration({ output: { text: finalText }, attributes: { finishReason: finalOutput.stepResult?.reason }, usage: state.accumulatedUsage }); } if (agentSpanData) { const agentSpan = observability.rebuildSpan(agentSpanData); agentSpan?.end({ output: { text: finalText } }); } } } catch (error) { logger?.warn?.(`[DurableAgent] Error ending observability spans: ${error}`); } return finalOutput; }, { id: "map-final-output" } ).map( async (params) => { const { inputData, getInitData, mastra, requestContext, tracingContext } = params; const finalOutput = inputData; const initData = getInitData(); const scorers = initData.scorers; if (!scorers || Object.keys(scorers).length === 0) { return finalOutput; } const logger = mastra?.getLogger?.(); const inputMessageList = new chunk2TATDSHU_cjs.MessageList(); inputMessageList.deserialize(initData.messageListState); const scorerInput = { inputMessages: inputMessageList.getPersisted.input.db(), rememberedMessages: inputMessageList.getPersisted.remembered.db(), systemMessages: inputMessageList.getSystemMessages(), taggedSystemMessages: inputMessageList.getPersisted.taggedSystemMessages }; const outputMessageList = new chunk2TATDSHU_cjs.MessageList(); outputMessageList.deserialize(finalOutput.messageListState); const scorerOutput = outputMessageList.getPersisted.response.db(); const resolveContext = requestContext ?? new chunkPJIAL3WK_cjs.RequestContext(); for (const [scorerKey, scorerEntry] of Object.entries(scorers)) { const { scorerName, sampling } = scorerEntry; try { const scorer = mastra?.getScorer?.(scorerName); if (!scorer) { logger?.warn?.(`Scorer ${scorerName} not found in Mastra, skipping`, { runId: initData.runId, scorerKey }); continue; } const scorerObject = { scorer, sampling }; chunkD37QL5LB_cjs.runScorer({ runId: initData.runId, scorerId: scorerKey, scorerObject, input: scorerInput, output: scorerOutput, requestContext: resolveContext, entity: { id: initData.agentId, name: initData.agentName ?? initData.agentId }, structuredOutput: false, source: "LIVE", entityType: "AGENT", threadId: initData.state?.threadId, resourceId: initData.state?.resourceId, ...chunkFHPG32XN_cjs.createObservabilityContext(tracingContext) }); } catch (error) { logger?.warn?.(`Error executing scorer ${scorerName}`, { error, runId: initData.runId, scorerKey }); } } return finalOutput; }, { id: "execute-scorers" } ).commit(); } // src/agent/durable/durable-agent.ts var DurableAgent = class extends chunkD37QL5LB_cjs.Agent { /** The wrapped agent */ #wrappedAgent; /** Registry for per-run non-serializable state */ #runRegistry; /** The durable workflow for agent execution */ #workflow = null; /** Maximum steps for the agentic loop */ #maxSteps; /** Inner pubsub (before CachingPubSub wrapper) */ #innerPubsub; /** Whether the user explicitly provided a pubsub (don't override with mastra.pubsub) */ #hasCustomPubsub; /** User-provided cache (undefined = inherit from mastra, false = disabled) */ #cacheConfig; /** Resolved cache instance (lazily initialized) */ #resolvedCache = null; /** CachingPubSub instance (lazily initialized) */ #cachingPubsub = null; /** Mastra instance (set via __setMastra when registered) */ #mastra; /** Active streamUntilIdle wrappers keyed by scope (threadId|resourceId) */ #activeStreamUntilIdle = /* @__PURE__ */ new Map(); /** Timeout for auto-cleanup after stream finishes (0 = disabled) */ #cleanupTimeoutMs; /** * Create a new DurableAgent that wraps an existing Agent */ constructor(config) { const { agent, id: idOverride, name: nameOverride, pubsub, cache, maxSteps, cleanupTimeoutMs } = config; const agentId = idOverride ?? agent.id; const agentName = nameOverride ?? agent.name ?? agent.id; super({ id: agentId, name: agentName, // Delegate to wrapped agent's instructions instructions: ({ requestContext }) => agent.getInstructions({ requestContext }), // We need to provide model to satisfy the base class, but we'll delegate to wrapped agent model: agent.__model ?? agent.getModel() }); this.#wrappedAgent = agent; this.#runRegistry = new ExtendedRunRegistry(); this.#maxSteps = maxSteps; this.#hasCustomPubsub = !!pubsub; this.#innerPubsub = pubsub ?? new chunkD324RFFU_cjs.EventEmitterPubSub(); this.#cacheConfig = cache; this.#cleanupTimeoutMs = cleanupTimeoutMs ?? 3e4; } // =========================================================================== // Lazy PubSub/Cache initialization (allows inheriting cache from Mastra) // =========================================================================== /** * Get the resolved cache instance. * Lazily initialized to allow inheriting from Mastra. */ get cache() { this.#ensurePubsubInitialized(); return this.#resolvedCache; } /** * Get the PubSub instance. * Returns CachingPubSub if caching is enabled, otherwise the inner pubsub. */ get pubsub() { this.#ensurePubsubInitialized(); return this.#cachingPubsub; } /** * Ensure pubsub and cache are initialized. * Called lazily on first access to allow inheriting cache from Mastra. */ #ensurePubsubInitialized() { if (this.#cachingPubsub) return; if (this.#cacheConfig === false) { this.#cachingPubsub = this.#innerPubsub; this.#resolvedCache = null; } else { const resolvedCache = this.#cacheConfig ?? this.#mastra?.serverCache ?? new chunk6QR4RQID_cjs.InMemoryServerCache(); this.#resolvedCache = resolvedCache; this.#cachingPubsub = new chunkGMFOMFCM_cjs.CachingPubSub(this.#innerPubsub, resolvedCache); } } // =========================================================================== // Delegate to wrapped agent // =========================================================================== /** * Get the wrapped agent instance. */ get agent() { return this.#wrappedAgent; } /** * Get the run registry (for testing and advanced usage) */ get runRegistry() { return this.#runRegistry; } /** * Get the max steps configured for this agent */ get maxSteps() { return this.#maxSteps; } /** * Get the cleanup timeout in milliseconds. * Returns 0 if auto-cleanup is disabled. */ get cleanupTimeoutMs() { return this.#cleanupTimeoutMs; } // Delegate Agent methods to wrapped agent getModel(options) { return this.#wrappedAgent.getModel(options); } getInstructions(options) { return this.#wrappedAgent.getInstructions(options); } listTools(options) { return this.#wrappedAgent.listTools(options); } getMemory() { return this.#wrappedAgent.getMemory(); } getVoice() { return this.#wrappedAgent.getVoice(); } // =========================================================================== // Protected methods for subclass overrides // =========================================================================== /** * Get the PubSub instance for use by subclasses. * @internal */ get pubsubInternal() { return this.pubsub; } /** * Get the run registry for use by subclasses. * @internal */ get runRegistryInternal() { return this.#runRegistry; } /** * Execute the durable workflow. * * Subclasses override this method to customize how the workflow is executed: * - DurableAgent (this): Runs the workflow directly via createRun + start * - EventedAgent: Uses run.startAsync() for fire-and-forget execution * - InngestAgent: Uses inngest.send() to trigger Inngest function * * @param runId - The unique run ID * @param workflowInput - The serialized workflow input * @internal */ async executeWorkflow(runId, workflowInput) { const workflow = this.getWorkflow(); const entry = globalRunRegistry.get(runId); const requestContext = entry?.requestContext; const run = await workflow.createRun({ runId, pubsub: this.pubsub }); const result = await run.start({ inputData: workflowInput, requestContext, ...chunkFHPG32XN_cjs.createObservabilityContext({ currentSpan: entry?.agentSpan }) }); if (result?.status === "failed") { const error = new Error(result.error?.message || "Workflow execution failed"); await this.emitError(runId, error); } } /** * Create the durable workflow for this agent. * * Subclasses can override this method to use a different workflow implementation: * - DurableAgent (this): Uses createDurableAgenticWorkflow() * - InngestAgent: Uses createInngestDurableAgenticWorkflow() * * @internal */ createWorkflow() { return createDurableAgenticWorkflow({ maxSteps: this.#maxSteps }); } /** * Emit an error event to pubsub. * * @param runId - The run ID * @param error - The error to emit * @internal */ async emitError(runId, error) { endRunSpansWithError(runId, error); await emitErrorEvent(this.pubsub, runId, error); } // =========================================================================== // Public API // =========================================================================== /** * Stream a response from the agent using durable execution. */ // @ts-expect-error - Intentionally different signature for durable execution async stream(messages, options) { const preparation = await prepareForDurableExecution({ agent: this.#wrappedAgent, messages, options, runId: options?.runId, requestContext: options?.requestContext, mastra: this.#mastra }); const { runId, messageId, workflowInput, registryEntry, messageList, threadId, resourceId } = preparation; this.#runRegistry.registerWithMessageList(runId, registryEntry, messageList, { threadId, resourceId }); globalRunRegistry.set(runId, { ...registryEntry, messageList }); let cleanedUp = false; let autoCleanupTimer = null; const scheduleAutoCleanup = () => { if (autoCleanupTimer || cleanedUp || this.#cleanupTimeoutMs === 0) return; autoCleanupTimer = setTimeout(() => { if (!cleanedUp) { this.#runRegistry.cleanup(runId); globalRunRegistry.delete(runId); this.#clearPubsubTopic(runId); cleanedUp = true; } }, this.#cleanupTimeoutMs); }; const { output, cleanup: streamCleanup, ready } = createDurableAgentStream({ pubsub: this.pubsub, runId, messageId, model: { modelId: workflowInput.modelConfig.modelId, provider: workflowInput.modelConfig.provider, version: "v3" }, threadId, resourceId, onChunk: options?.onChunk, onStepFinish: options?.onStepFinish, onFinish: async (result) => { await options?.onFinish?.(result); scheduleAutoCleanup(); }, onError: async (error) => { await options?.onError?.(error); scheduleAutoCleanup(); }, onSuspended: options?.onSuspended }); ready.then(() => this.executeWorkflow(runId, workflowInput)).catch((error) => { void this.emitError(runId, error); }); const cleanup = () => { if (autoCleanupTimer) { clearTimeout(autoCleanupTimer); autoCleanupTimer = null; } if (!cleanedUp) { streamCleanup(); this.#runRegistry.cleanup(runId); globalRunRegistry.delete(runId); this.#clearPubsubTopic(runId); cleanedUp = true; } }; return { output, get fullStream() { return output.fullStream; }, runId, threadId, resourceId, cleanup }; } /** * Resume a suspended workflow execution. */ async resume(runId, resumeData, options) { const entry = this.#runRegistry.get(runId); if (!entry) { throw new Error(`No registry entry found for run ${runId}. Cannot resume.`); } const memoryInfo = this.#runRegistry.getMemoryInfo(runId); let cleanedUp = false; let autoCleanupTimer = null; const scheduleAutoCleanup = () => { if (autoCleanupTimer || cleanedUp || this.#cleanupTimeoutMs === 0) return; autoCleanupTimer = setTimeout(() => { if (!cleanedUp) { this.#runRegistry.cleanup(runId); globalRunRegistry.delete(runId); this.#clearPubsubTopic(runId); cleanedUp = true; } }, this.#cleanupTimeoutMs); }; const globalEntry = globalRunRegistry.get(runId); const resumeModel = globalEntry?.model; const { output, cleanup: streamCleanup, ready } = createDurableAgentStream({ pubsub: this.pubsub, runId, messageId: crypto.randomUUID(), model: { modelId: resumeModel?.modelId, provider: resumeModel?.provider, version: "v3" }, threadId: memoryInfo?.threadId, resourceId: memoryInfo?.resourceId, onChunk: options?.onChunk, onStepFinish: options?.onStepFinish, onFinish: async (result) => { await options?.onFinish?.(result); scheduleAutoCleanup(); }, onError: async (error) => { await options?.onError?.(error); scheduleAutoCleanup(); }, onSuspended: options?.onSuspended }); const workflow = this.getWorkflow(); const requestContext = globalRunRegistry.get(runId)?.requestContext; const origTraceId = entry.agentSpan?.traceId; if (origTraceId && this.#mastra?.observability) { try { const ag = this.#wrappedAgent; const resumeAgentSpan = chunkLP4WZA6D_cjs.getOrCreateSpan({ type: "agent_run" /* AGENT_RUN */, name: `agent run (resumed): '${ag.id}'`, entityType: chunkLP4WZA6D_cjs.EntityType.AGENT, entityId: ag.id, entityName: ag.name, metadata: { runId, resumed: true }, tracingOptions: { traceId: origTraceId }, requestContext, mastra: this.#mastra }); const resumeModelSpan = resumeAgentSpan?.createChildSpan({ type: "model_generation" /* MODEL_GENERATION */, name: `llm: '${resumeModel?.modelId ?? ""}'`, attributes: { model: resumeModel?.modelId, provider: resumeModel?.provider, streaming: true }, metadata: { runId, resumed: true }, requestContext }); for (const reg of [entry, globalRunRegistry.get(runId)]) { if (!reg) continue; reg.resumeAgentSpan = resumeAgentSpan; reg.resumeModelSpan = resumeModelSpan; reg.resumeAgentSpanData = resumeAgentSpan?.exportSpan(); reg.resumeModelSpanData = resumeModelSpan?.exportSpan(); } } catch (error) { this.#mastra?.getLogger?.()?.warn?.(`[DurableAgent] Failed to open resume spans: ${error}`); } } ready.then(async () => { const run = await workflow.createRun({ runId, pubsub: this.pubsub }); const result = await run.resume({ resumeData, requestContext, ...chunkFHPG32XN_cjs.createObservabilityContext({ currentSpan: entry.resumeAgentSpan ?? entry.agentSpan }) }); if (result?.status === "failed") { const error = new Error(result.error?.message || "Workflow resume failed"); void this.emitError(runId, error); } }).catch((error) => { void this.emitError(runId, error); }); const cleanup = () => { if (autoCleanupTimer) { clearTimeout(autoCleanupTimer); autoCleanupTimer = null; } if (!cleanedUp) { streamCleanup(); this.#runRegistry.cleanup(runId); globalRunRegistry.delete(runId); this.#clearPubsubTopic(runId); cleanedUp = true; } }; return { output, get fullStream() { return output.fullStream; }, runId, threadId: memoryInfo?.threadId, resourceId: memoryInfo?.resourceId, cleanup }; } /** * Observe an existing stream. * Use this to reconnect to a stream after a network disconnection. * * **Warning:** The returned `cleanup()` function destroys the run's registry * entries and cached PubSub events. Only call it when you are done with the * run entirely. If the workflow is suspended and you intend to resume later, * do not call cleanup — let the auto-cleanup timer handle it after * FINISH/ERROR. Auto-cleanup does not fire on SUSPENDED events. */ async observe(runId, options) { const memoryInfo = this.#runRegistry.getMemoryInfo(runId); let cleanedUp = false; let autoCleanupTimer = null; const scheduleAutoCleanup = () => { if (autoCleanupTimer || cleanedUp || this.#cleanupTimeoutMs === 0) return; autoCleanupTimer = setTimeout(() => { if (!cleanedUp) { this.#runRegistry.cleanup(runId); globalRunRegistry.delete(runId); this.#clearPubsubTopic(runId); cleanedUp = true; } }, this.#cleanupTimeoutMs); }; const { output, cleanup: streamCleanup, ready } = createDurableAgentStream({ pubsub: this.pubsub, runId, messageId: crypto.randomUUID(), model: { modelId: void 0, provider: void 0, version: "v3" }, threadId: memoryInfo?.threadId, resourceId: memoryInfo?.resourceId, offset: options?.offset, onChunk: options?.onChunk, onStepFinish: options?.onStepFinish, onFinish: async (result) => { await options?.onFinish?.(result); scheduleAutoCleanup(); }, onError: async (error) => { await options?.onError?.(error); scheduleAutoCleanup(); }, onSuspended: options?.onSuspended }); await ready; const cleanup = () => { if (autoCleanupTimer) { clearTimeout(autoCleanupTimer); autoCleanupTimer = null; } if (!cleanedUp) { streamCleanup(); this.#runRegistry.cleanup(runId); globalRunRegistry.delete(runId); this.#clearPubsubTopic(runId); cleanedUp = true; } }; return { output, get fullStream() { return output.fullStream; }, runId, threadId: memoryInfo?.threadId, resourceId: memoryInfo?.resourceId, cleanup }; } /** * Clear cached pubsub events for a run's topic. * Only effective when pubsub supports clearTopic (e.g. CachingPubSub). */ #clearPubsubTopic(runId) { const pubsub = this.pubsub; if ("clearTopic" in pubsub && typeof pubsub.clearTopic === "function") { void pubsub.clearTopic(AGENT_STREAM_TOPIC(runId)); } } /** * Get the workflow instance for direct execution. * Lazily creates the workflow and registers Mastra on it (needed for * getAgentById in execution steps). */ getWorkflow() { if (!this.#workflow) { this.#workflow = this.createWorkflow(); if (this.#mastra) { this.#workflow.__registerMastra(this.#mastra); this.#workflow.__registerPrimitives({ logger: this.#mastra.getLogger(), storage: this.#mastra.getStorage() }); } } return this.#workflow; } /** * Stream until all background tasks complete and the agent is idle. * Mirrors the regular Agent's streamUntilIdle but adapted for durable execution. */ // @ts-expect-error - Intentionally different return type for durable execution async streamUntilIdle(messages, streamOptions) { return runDurableStreamUntilIdle( this, messages, streamOptions, { activeStreams: this.#activeStreamUntilIdle, bgManager: this.#mastra?.backgroundTaskManager } ); } /** * Prepare for durable execution without starting it. */ async prepare(messages, options) { const preparation = await prepareForDurableExecution({ agent: this.#wrappedAgent, messages, options, requestContext: options?.requestContext, mastra: this.#mastra }); this.#runRegistry.registerWithMessageList(preparation.runId, preparation.registryEntry, preparation.messageList, { threadId: preparation.threadId, resourceId: preparation.resourceId }); globalRunRegistry.set(preparation.runId, { ...preparation.registryEntry, messageList: preparation.messageList }); return { runId: preparation.runId, messageId: preparation.messageId, workflowInput: preparation.workflowInput, registryEntry: preparation.registryEntry, threadId: preparation.threadId, resourceId: preparation.resourceId }; } /** * Get the durable workflows required by this agent. * Called by Mastra during agent registration. * @internal */ getDurableWorkflows() { return [this.getWorkflow()]; } /** * Set the Mastra instance. * Called by the durable agent registration path in addAgent(). * Delegates to __registerMastra so the pubsub wiring and agent * registration happen regardless of which entry point is called first. * @internal */ __setMastra(mastra) { this.__registerMastra(mastra); } /** * Register the Mastra instance. * Called by Mastra during agent registration (normal Agent path). * * Also wires mastra.pubsub as the inner pubsub (if the user didn't provide * a custom one), so that the OBSERVE_AGENT_STREAM_ROUTE handler can subscribe * to the same PubSub instance that this agent publishes to. * @internal */ __registerMastra(mastra) { super.__registerMastra(mastra); this.#mastra = mastra; this.#wrappedAgent.__registerMastra(mastra); if (!this.#hasCustomPubsub && !this.#cachingPubsub) { this.#innerPubsub = mastra.pubsub; } } }; // src/agent/durable/create-durable-agent.ts function createDurableAgent(options) { const { agent, id, name, cache, pubsub, maxSteps } = options; return new DurableAgent({ agent, id, name, cache, pubsub, maxSteps }); } function isDurableAgent(obj) { return obj instanceof DurableAgent; } var isLocalDurableAgent = isDurableAgent; // src/agent/durable/evented-agent.ts var EventedAgent = class extends DurableAgent { /** * Create a new EventedAgent that wraps an existing Agent */ constructor(config) { super(config); } /** * Execute the durable workflow using fire-and-forget pattern. * * Unlike DurableAgent which runs the workflow synchronously, EventedAgent uses * the workflow's startAsync() method for non-blocking execution. * * @param runId - The unique run ID * @param workflowInput - The serialized workflow input * @internal */ async executeWorkflow(runId, workflowInput) { try { const workflow = this.getWorkflow(); const run = await workflow.createRun({ runId, pubsub: this.pubsubInternal }); const entry = globalRunRegistry.get(runId); await run.startAsync({ inputData: workflowInput, requestContext: entry?.requestContext, ...chunkFHPG32XN_cjs.createObservabilityContext({ currentSpan: entry?.agentSpan }) }); } catch (error) { await this.emitError(runId, error instanceof Error ? error : new Error(String(error))); } } }; function isEventedAgentClass(obj) { return obj instanceof EventedAgent; } // src/agent/durable/create-evented-agent.ts function createEventedAgent(options) { const { agent, pubsub, cache, maxSteps } = options; return new EventedAgent({ agent, pubsub, cache, maxSteps }); } function isEventedAgent(obj) { return obj instanceof EventedAgent; } exports.AGENT_STREAM_TOPIC = AGENT_STREAM_TOPIC; exports.AgentStreamEventTypes = AgentStreamEventTypes; exports.DurableAgent = DurableAgent; exports.DurableAgentDefaults = DurableAgentDefaults; exports.DurableStepIds = DurableStepIds; exports.EventedAgent = EventedAgent; exports.ExtendedRunRegistry = ExtendedRunRegistry; exports.RunRegistry = RunRegistry; exports.accumulatedUsageSchema = accumulatedUsageSchema; exports.baseDurableAgenticInputSchema = baseDurableAgenticInputSchema; exports.baseIterationStateSchema = baseIterationStateSchema; exports.buildStepRecord = buildStepRecord; exports.calculateAccumulatedUsage = calculateAccumulatedUsage; exports.createBaseIterationStateUpdate = createBaseIterationStateUpdate; exports.createDurableAgent = createDurableAgent; exports.createDurableAgentStream = createDurableAgentStream; exports.createDurableAgenticWorkflow = createDurableAgenticWorkflow; exports.createDurableBackgroundTaskCheckStep = createDurableBackgroundTaskCheckStep; exports.createDurableLLMExecutionStep = createDurableLLMExecutionStep; exports.createDurableLLMMappingStep = createDurableLLMMappingStep; exports.createDurableToolCallStep = createDurableToolCallStep; exports.createEventedAgent = createEventedAgent; exports.createWorkflowInput = createWorkflowInput; exports.durableAgenticOutputSchema = durableAgenticOutputSchema; exports.emitChunkEvent = emitChunkEvent; exports.emitErrorEvent = emitErrorEvent; exports.emitFinishEvent = emitFinishEvent; exports.emitStepFinishEvent = emitStepFinishEvent; exports.emitStepStartEvent = emitStepStartEvent; exports.emitSuspendedEvent = emitSuspendedEvent; exports.executeDurableToolCalls = executeDurableToolCalls; exports.isDurableAgent = isDurableAgent; exports.isEventedAgent = isEventedAgent; exports.isEventedAgentClass = isEventedAgentClass; exports.isLocalDurableAgent = isLocalDurableAgent; exports.modelConfigSchema = modelConfigSchema; exports.modelListEntrySchema = modelListEntrySchema; exports.prepareForDurableExecution = prepareForDurableExecution; exports.resolveInternalState = resolveInternalState; exports.resolveModel = resolveModel; exports.resolveRuntimeDependencies = resolveRuntimeDependencies; exports.resolveTool = resolveTool; exports.runDurableStreamUntilIdle = runDurableStreamUntilIdle; exports.serializeDurableOptions = serializeDurableOptions; exports.serializeDurableState = serializeDurableState; exports.serializeModelConfig = serializeModelConfig; exports.serializeToolsMetadata = serializeToolsMetadata; exports.toolRequiresApproval = toolRequiresApproval; //# sourceMappingURL=index.cjs.map //# sourceMappingURL=index.cjs.map