@mastra/core 1.55.0-alpha.2 → 1.55.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +86 -0
- package/dist/agent/agent.d.ts.map +1 -1
- package/dist/agent/durable/index.cjs +1 -1
- package/dist/agent/durable/index.js +1 -1
- package/dist/agent/index.cjs +2 -2
- package/dist/agent/index.js +2 -2
- package/dist/{agent-BvRfRKIt.js → agent-0y2cApTZ.js} +57 -82
- package/dist/agent-0y2cApTZ.js.map +1 -0
- package/dist/agent-builder/ee/index.cjs +1 -1
- package/dist/agent-builder/ee/index.js +1 -1
- package/dist/agent-controller/index.cjs +1 -1
- package/dist/agent-controller/index.js +1 -1
- package/dist/{agent-controller-CM6tQSMj.js → agent-controller-ByW51eCC.js} +5 -5
- package/dist/{agent-controller-CM6tQSMj.js.map → agent-controller-ByW51eCC.js.map} +1 -1
- package/dist/{agent-controller-C75dc544.cjs → agent-controller-DahKlMET.cjs} +5 -5
- package/dist/{agent-controller-C75dc544.cjs.map → agent-controller-DahKlMET.cjs.map} +1 -1
- package/dist/{agent-CwUYflGG.cjs → agent-um2LJs-0.cjs} +57 -82
- package/dist/agent-um2LJs-0.cjs.map +1 -0
- package/dist/background-tasks/index.cjs +1 -1
- package/dist/background-tasks/index.js +1 -1
- package/dist/{background-tasks-AKlv5tIo.js → background-tasks-CM94BIj8.js} +2 -2
- package/dist/{background-tasks-AKlv5tIo.js.map → background-tasks-CM94BIj8.js.map} +1 -1
- package/dist/{background-tasks-Chpan7PB.cjs → background-tasks-CobPW4Z3.cjs} +2 -2
- package/dist/{background-tasks-Chpan7PB.cjs.map → background-tasks-CobPW4Z3.cjs.map} +1 -1
- package/dist/browser/index.cjs +1 -1
- package/dist/browser/index.js +1 -1
- package/dist/channels/index.cjs +2 -2
- package/dist/channels/index.js +2 -2
- package/dist/{channels-BW52ccH_.cjs → channels-BgbloDjB.cjs} +2 -2
- package/dist/{channels-BW52ccH_.cjs.map → channels-BgbloDjB.cjs.map} +1 -1
- package/dist/{channels-Da9lEAi1.js → channels-MegO_4KL.js} +2 -2
- package/dist/{channels-Da9lEAi1.js.map → channels-MegO_4KL.js.map} +1 -1
- package/dist/coding-agent/index.cjs +1 -1
- package/dist/coding-agent/index.js +1 -1
- package/dist/{create-durable-agent-DmTTvoGi.cjs → create-durable-agent-ChmjQwzE.cjs} +8 -8
- package/dist/{create-durable-agent-DmTTvoGi.cjs.map → create-durable-agent-ChmjQwzE.cjs.map} +1 -1
- package/dist/{create-durable-agent-Bd4Bm5FV.js → create-durable-agent-DH_dWTMR.js} +8 -8
- package/dist/{create-durable-agent-Bd4Bm5FV.js.map → create-durable-agent-DH_dWTMR.js.map} +1 -1
- package/dist/datasets/index.cjs +1 -1
- package/dist/datasets/index.js +1 -1
- package/dist/{dist-C077BlAN.js → dist-BZBxELZo.js} +2 -2
- package/dist/{dist-C077BlAN.js.map → dist-BZBxELZo.js.map} +1 -1
- package/dist/{dist-CsR_D1uk.cjs → dist-ftJxyNRx.cjs} +2 -2
- package/dist/{dist-CsR_D1uk.cjs.map → dist-ftJxyNRx.cjs.map} +1 -1
- package/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/evals/index.cjs +1 -1
- package/dist/evals/index.js +1 -1
- package/dist/evals/scoreTraces/index.cjs +1 -1
- package/dist/evals/scoreTraces/index.js +1 -1
- package/dist/harness/index.cjs +1 -1
- package/dist/harness/index.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/llm/index.cjs +5 -5
- package/dist/llm/index.js +5 -5
- package/dist/{llm-DlVyw1cX.js → llm-DGuYy_Nx.js} +5 -5
- package/dist/{llm-DlVyw1cX.js.map → llm-DGuYy_Nx.js.map} +1 -1
- package/dist/{llm-Bjt2hZ3f.cjs → llm-DmAhSSgh.cjs} +5 -5
- package/dist/{llm-Bjt2hZ3f.cjs.map → llm-DmAhSSgh.cjs.map} +1 -1
- package/dist/loop/index.cjs +1 -1
- package/dist/loop/index.js +1 -1
- package/dist/{manager-CYGpXJfK.js → manager-DDRcONBK.js} +3 -3
- package/dist/{manager-CYGpXJfK.js.map → manager-DDRcONBK.js.map} +1 -1
- package/dist/{manager-BjrFnt_A.cjs → manager-DqHiikx1.cjs} +3 -3
- package/dist/{manager-BjrFnt_A.cjs.map → manager-DqHiikx1.cjs.map} +1 -1
- package/dist/mastra/index.cjs +1 -1
- package/dist/mastra/index.js +1 -1
- package/dist/{mastra-CVLF1dWt.js → mastra-B6CffFOC.js} +9 -9
- package/dist/{mastra-CVLF1dWt.js.map → mastra-B6CffFOC.js.map} +1 -1
- package/dist/{mastra-Bxx9WPf6.cjs → mastra-BlT9srQJ.cjs} +9 -9
- package/dist/{mastra-Bxx9WPf6.cjs.map → mastra-BlT9srQJ.cjs.map} +1 -1
- package/dist/memory/index.cjs +1 -1
- package/dist/memory/index.js +1 -1
- package/dist/{model-CA0WLISt.js → model-DQzxkQqM.js} +2 -2
- package/dist/{model-CA0WLISt.js.map → model-DQzxkQqM.js.map} +1 -1
- package/dist/{model-DMVq6nAS.cjs → model-Iow-mV9i.cjs} +2 -2
- package/dist/{model-DMVq6nAS.cjs.map → model-Iow-mV9i.cjs.map} +1 -1
- package/dist/{models-dev-Cbus1Uh2.js → models-dev-BFOUCgyS.js} +2 -2
- package/dist/{models-dev-Cbus1Uh2.js.map → models-dev-BFOUCgyS.js.map} +1 -1
- package/dist/{models-dev-D_X4VMSu.cjs → models-dev-BUEaCBxL.cjs} +2 -2
- package/dist/{models-dev-D_X4VMSu.cjs.map → models-dev-BUEaCBxL.cjs.map} +1 -1
- package/dist/{netlify-C-nnPVSj.js → netlify-7eHXUkln.js} +2 -2
- package/dist/{netlify-C-nnPVSj.js.map → netlify-7eHXUkln.js.map} +1 -1
- package/dist/{netlify-CUuCnmtd.cjs → netlify-Db5icdAJ.cjs} +2 -2
- package/dist/{netlify-CUuCnmtd.cjs.map → netlify-Db5icdAJ.cjs.map} +1 -1
- package/dist/processor-provider/index.cjs +1 -1
- package/dist/processor-provider/index.js +1 -1
- package/dist/processors/index.cjs +2 -2
- package/dist/processors/index.js +2 -2
- package/dist/processors/processors/index.d.ts +1 -1
- package/dist/processors/processors/index.d.ts.map +1 -1
- package/dist/processors/tool-result-reminder.d.ts +23 -0
- package/dist/processors/tool-result-reminder.d.ts.map +1 -1
- package/dist/{provider-registry-BFknh6Fu.cjs → provider-registry-DRJihW5_.cjs} +6 -6
- package/dist/{provider-registry-BFknh6Fu.cjs.map → provider-registry-DRJihW5_.cjs.map} +1 -1
- package/dist/{provider-registry-DIbls44Z.js → provider-registry-DzSSAz1R.js} +6 -6
- package/dist/{provider-registry-DIbls44Z.js.map → provider-registry-DzSSAz1R.js.map} +1 -1
- package/dist/relevance/index.cjs +2 -2
- package/dist/relevance/index.js +2 -2
- package/dist/stream/index.cjs +3 -3
- package/dist/stream/index.js +3 -3
- package/dist/{stream-tlVjYkAO.cjs → stream-D-cHV05r.cjs} +3 -3
- package/dist/{stream-tlVjYkAO.cjs.map → stream-D-cHV05r.cjs.map} +1 -1
- package/dist/{stream-Cd_isEZJ.js → stream-DJaosaeO.js} +3 -3
- package/dist/{stream-Cd_isEZJ.js.map → stream-DJaosaeO.js.map} +1 -1
- package/dist/test-utils/llm-mock.cjs +1 -1
- package/dist/test-utils/llm-mock.js +1 -1
- package/dist/tool-loop-agent/index.cjs +1 -1
- package/dist/tool-loop-agent/index.js +1 -1
- package/dist/{tool-loop-agent-th9L-ls9.cjs → tool-loop-agent-ByrutV2Q.cjs} +4 -4
- package/dist/{tool-loop-agent-th9L-ls9.cjs.map → tool-loop-agent-ByrutV2Q.cjs.map} +1 -1
- package/dist/{tool-loop-agent-CcT-TTcT.js → tool-loop-agent-BzHXZDL3.js} +4 -4
- package/dist/{tool-loop-agent-CcT-TTcT.js.map → tool-loop-agent-BzHXZDL3.js.map} +1 -1
- package/dist/{trip-wire-Cj0cJivR.js → trip-wire-DxpTS3jV.js} +2 -2
- package/dist/{trip-wire-Cj0cJivR.js.map → trip-wire-DxpTS3jV.js.map} +1 -1
- package/dist/{trip-wire-BNzxirr0.cjs → trip-wire-utCESgMt.cjs} +2 -2
- package/dist/{trip-wire-BNzxirr0.cjs.map → trip-wire-utCESgMt.cjs.map} +1 -1
- package/dist/{utils-BoQofieM.cjs → utils-CPUQn5dX.cjs} +2 -2
- package/dist/{utils-BoQofieM.cjs.map → utils-CPUQn5dX.cjs.map} +1 -1
- package/dist/{utils-DUfAZ4gr.js → utils-CrKEOVUo.js} +2 -2
- package/dist/{utils-DUfAZ4gr.js.map → utils-CrKEOVUo.js.map} +1 -1
- package/dist/utils.cjs +1 -1
- package/dist/utils.js +1 -1
- package/dist/worker/index.cjs +1 -1
- package/dist/worker/index.js +1 -1
- package/dist/{worker-DwlyX5l8.js → worker-Ciya6mfo.js} +3 -3
- package/dist/{worker-DwlyX5l8.js.map → worker-Ciya6mfo.js.map} +1 -1
- package/dist/{worker-CsbZPhWb.cjs → worker-YT_pMttZ.cjs} +3 -3
- package/dist/{worker-CsbZPhWb.cjs.map → worker-YT_pMttZ.cjs.map} +1 -1
- package/dist/{workflow-BR5D6ij_.cjs → workflow-DcS_0R0Z.cjs} +3 -3
- package/dist/{workflow-BR5D6ij_.cjs.map → workflow-DcS_0R0Z.cjs.map} +1 -1
- package/dist/{workflow-OjZRiiCG.js → workflow-k6s0ESOR.js} +3 -3
- package/dist/{workflow-OjZRiiCG.js.map → workflow-k6s0ESOR.js.map} +1 -1
- package/dist/workflows/evented/index.cjs +1 -1
- package/dist/workflows/evented/index.js +1 -1
- package/dist/workflows/index.cjs +1 -1
- package/dist/workflows/index.js +1 -1
- package/package.json +12 -12
- package/dist/agent-BvRfRKIt.js.map +0 -1
- package/dist/agent-CwUYflGG.cjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"background-tasks-Chpan7PB.cjs","names":["#mastra","#doInit","#ensureExecutionWorkersStarted","z"],"sources":["../src/background-tasks/workflow-id.ts","../src/background-tasks/manager.ts","../src/background-tasks/create.ts","../src/background-tasks/resolve-config.ts","../src/background-tasks/schema-injection.ts","../src/background-tasks/system-prompt.ts"],"sourcesContent":["/**\n * Workflow id used by the bg-task workflow registered on Mastra.\n * Double-underscore prefix marks it as internal — same convention as\n * `__batch-scoring-traces`.\n *\n * Lives in its own file (separate from `./workflow`) so `manager.ts` can\n * reference the id without statically pulling in `../workflows/evented`,\n * which would create a circular import via `agent → background-tasks →\n * workflow → evented → workflows/index → agent`.\n */\nexport const BACKGROUND_TASK_WORKFLOW_ID = '__background-task';\n","import { randomUUID } from 'node:crypto';\nimport type { Mastra } from '..';\nimport type { PubSub } from '../events/pubsub';\nimport type { Event, EventCallback } from '../events/types';\nimport type {\n BackgroundTask,\n BackgroundTaskManagerConfig,\n BackgroundTaskStatus,\n EnqueueResult,\n TaskContext,\n TaskFilter,\n TaskPayload,\n TaskListResult,\n ToolExecutor,\n BackgroundTaskEvent,\n} from './types';\nimport { BACKGROUND_TASK_WORKFLOW_ID } from './workflow-id';\n\nconst TOPIC_DISPATCH = 'background-tasks';\nconst TOPIC_RESULT = 'background-tasks-result';\nconst WORKER_GROUP = 'background-task-workers';\n\nexport class BackgroundTaskManager {\n private pubsub!: PubSub;\n config: Required<\n Pick<BackgroundTaskManagerConfig, 'globalConcurrency' | 'perAgentConcurrency' | 'backpressure' | 'defaultTimeoutMs'>\n > &\n BackgroundTaskManagerConfig;\n\n #mastra?: Mastra;\n\n // Per-task contexts — keyed by task ID, holds closures from the caller's stream.\n /** @internal — read by the workflow-engine step bodies in workflow.ts */\n taskContexts: Map<string, TaskContext> = new Map();\n\n // Static executors keyed by tool name. Populated by `Mastra` for every\n // registered tool, and by `BackgroundTaskWorker.#wireStaticTools` on\n // standalone worker processes. Used as the fallback for cross-process\n // dispatch where the producer's per-task closure (taskContexts) is not\n // visible — a remote worker resolves the tool by name instead.\n private staticExecutors: Map<string, ToolExecutor> = new Map();\n\n // Track active AbortControllers for running tasks (for cancellation + timeout)\n /** @internal — read by the workflow-engine step bodies in workflow.ts */\n activeAbortControllers: Map<string, AbortController> = new Map();\n\n // Pubsub callbacks (kept for unsubscribe)\n private workerCallback?: EventCallback;\n private resultCallback?: EventCallback;\n\n private shuttingDown = false;\n\n // Cleanup interval handle\n private cleanupInterval?: ReturnType<typeof setInterval>;\n\n // Tracks the in-flight `init(pubsub)` so consumers can await readiness.\n // Mastra fires init as fire-and-forget in `#ensureBackgroundTaskManager`,\n // so without this any caller that hits `enqueue`/`resume`/`cancel`\n // before init completes races against worker subscription + workflow\n // registration. Public methods that depend on init await this promise\n // before doing work.\n private initPromise?: Promise<void>;\n\n constructor(config: BackgroundTaskManagerConfig = { enabled: false }) {\n this.config = {\n globalConcurrency: config.globalConcurrency ?? 10,\n perAgentConcurrency: config.perAgentConcurrency ?? 5,\n backpressure: config.backpressure ?? 'queue',\n defaultTimeoutMs: config.defaultTimeoutMs ?? 300_000,\n ...config,\n };\n }\n\n __registerMastra(mastra: Mastra) {\n this.#mastra = mastra;\n }\n\n async getStorage() {\n const storage = this.#mastra?.getStorage();\n if (!storage) {\n throw new Error('Storage is not initialized');\n }\n const bgStore = await storage.getStore('backgroundTasks');\n if (!bgStore) {\n throw new Error('Background tasks storage is not available');\n }\n return bgStore;\n }\n\n async init(pubsub: PubSub): Promise<void> {\n if (this.initPromise) return this.initPromise;\n this.initPromise = this.#doInit(pubsub);\n return this.initPromise;\n }\n\n async #doInit(pubsub: PubSub): Promise<void> {\n this.pubsub = pubsub;\n\n const isProducerOnly = this.config.mode === 'producer';\n\n // Result listener: fan-out so all processes receive results.\n // Both producer and worker modes need this — the producer uses it\n // to receive completion/failure notifications for dispatched tasks.\n this.resultCallback = async (event: Event, ack?: () => Promise<void>) => {\n if (event.type === 'task.completed' || event.type === 'task.failed') {\n await this.handleResult(event);\n }\n await ack?.();\n };\n\n if (!isProducerOnly) {\n // Worker: subscribes with group so only one worker processes each task.\n this.workerCallback = async (event: Event, ack?: () => Promise<void>) => {\n if (event.type === 'task.dispatch' || event.type === 'task.restart') {\n await this.handleDispatch(event);\n } else if (event.type === 'task.resume') {\n await this.handleResume(event);\n } else if (event.type === 'task.cancel') {\n this.handleCancel(event);\n }\n await ack?.();\n };\n\n // Register the workflow BEFORE subscribing the worker so that any\n // dispatch event the worker picks up can immediately resolve the\n // workflow on Mastra. Reversing this order races: a publish that\n // arrives between `subscribe(TOPIC_DISPATCH)` and the workflow\n // registration triggers `__getInternalWorkflow` to throw\n // `Workflow with id __background-task not found`, the task stays at\n // `running` forever, and the dispatch is silently dropped.\n if (this.#mastra) {\n // Dynamic import breaks the static cycle:\n // agent → background-tasks → manager → workflow → workflows/evented →\n // workflows/index → agent. Static import works at runtime but during\n // module evaluation in test environments the cycle leaves `Workflow`\n // undefined when `evented/workflow.ts` evaluates its `class extends`.\n const { buildBackgroundTaskWorkflow } = await import('./workflow');\n const workflow = buildBackgroundTaskWorkflow(this);\n if (!this.#mastra.__hasInternalWorkflow(BACKGROUND_TASK_WORKFLOW_ID)) {\n // The `__background-task` workflow is typed against `EventedEngineType`\n // and a concrete input/output schema, while `__registerInternalWorkflow`\n // accepts the looser default `Workflow` shape. The cast is purely a\n // type-level bridge — the runtime value is a real Workflow.\n this.#mastra.__registerInternalWorkflow(\n workflow as unknown as Parameters<Mastra['__registerInternalWorkflow']>[0],\n );\n }\n }\n\n await this.pubsub.subscribe(TOPIC_DISPATCH, this.workerCallback, { group: WORKER_GROUP });\n }\n\n await this.pubsub.subscribe(TOPIC_RESULT, this.resultCallback);\n\n if (!isProducerOnly) {\n // Recover stale tasks from a previous process — only workers should\n // attempt recovery since they own execution.\n await this.recoverStaleTasks();\n }\n\n // Start periodic cleanup if configured\n const cleanupConfig = this.config.cleanup;\n if (cleanupConfig) {\n const intervalMs = cleanupConfig.cleanupIntervalMs ?? 60_000;\n this.cleanupInterval = setInterval(() => {\n void this.cleanup();\n }, intervalMs);\n }\n }\n\n // --- Per-task context registration ---\n\n /**\n * Register per-task hooks (executor, stream emitter, result injector).\n * Called internally by createBackgroundTask or directly for advanced usage.\n */\n registerTaskContext(taskId: string, context: TaskContext): void {\n this.taskContexts.set(taskId, context);\n }\n\n /**\n * Remove per-task hooks. Called after task reaches terminal state.\n */\n deregisterTaskContext(taskId: string): void {\n this.taskContexts.delete(taskId);\n }\n\n /**\n * Register a tool executor by tool name. Used for cross-process dispatch:\n * when a worker in a different process picks up a `task.dispatch` event,\n * it has no per-task closure (`taskContexts`) for that taskId, but it can\n * resolve the executor by tool name via this registry.\n */\n registerStaticExecutor(toolName: string, executor: ToolExecutor): void {\n if (this.staticExecutors.has(toolName)) {\n this.#mastra?.getLogger?.()?.debug?.(`Overwriting existing static executor for tool \"${toolName}\"`);\n }\n this.staticExecutors.set(toolName, executor);\n }\n\n /**\n * Symmetric to `registerStaticExecutor`. Called when a tool is removed\n * from `Mastra`.\n */\n unregisterStaticExecutor(toolName: string): void {\n this.staticExecutors.delete(toolName);\n }\n\n /**\n * Look up an executor by tool name. Read by the workflow-step body in\n * `workflow.ts:runAttemptStep` as a fallback when no per-task `TaskContext`\n * is registered (cross-process path).\n */\n getStaticExecutor(toolName: string): ToolExecutor | undefined {\n return this.staticExecutors.get(toolName);\n }\n\n // --- Core operations ---\n\n /**\n * Enqueue a task for background execution.\n * Prefer `createBackgroundTask()` which returns a self-contained handle.\n */\n async enqueue(payload: TaskPayload, context?: TaskContext): Promise<EnqueueResult> {\n if (this.shuttingDown) {\n throw new Error('BackgroundTaskManager is shutting down, cannot enqueue new tasks');\n }\n\n // Mastra fires `init` as fire-and-forget. If a caller hits enqueue\n // before init completes, the dispatch publish fires before the worker\n // subscribes and the event is dropped (or, worse, lands on a worker\n // whose Mastra hasn't yet registered the bg-task workflow → \"Workflow\n // with id __background-task not found\"). Await readiness up front.\n if (this.initPromise) await this.initPromise;\n\n const task: BackgroundTask = {\n id: this.#mastra?.generateId() ?? randomUUID(),\n status: 'pending',\n toolName: payload.toolName,\n toolCallId: payload.toolCallId,\n args: payload.args,\n agentId: payload.agentId,\n threadId: payload.threadId,\n resourceId: payload.resourceId,\n runId: payload.runId,\n retryCount: 0,\n maxRetries: payload.maxRetries ?? this.config.defaultRetries?.maxRetries ?? 0,\n timeoutMs: payload.timeoutMs ?? this.config.defaultTimeoutMs,\n createdAt: new Date(),\n };\n\n // Register per-task context if provided\n if (context) {\n this.registerTaskContext(task.id, context);\n }\n\n const storage = await this.getStorage();\n await storage.createTask(task);\n\n const canRun = await this.checkConcurrency(task.agentId);\n\n if (canRun) {\n await this.dispatch(task);\n return { task };\n }\n\n // Backpressure\n switch (this.config.backpressure) {\n case 'reject':\n this.deregisterTaskContext(task.id);\n await storage.deleteTask(task.id);\n throw new Error(`Concurrency limit reached, cannot enqueue task for tool \"${task.toolName}\"`);\n\n case 'fallback-sync':\n this.deregisterTaskContext(task.id);\n await storage.deleteTask(task.id);\n return { task, fallbackToSync: true };\n\n case 'queue':\n default:\n // Task stays pending in storage, will be dispatched when a slot opens\n return { task };\n }\n }\n\n async cancel(taskId: string): Promise<void> {\n if (this.initPromise) await this.initPromise;\n const storage = await this.getStorage();\n const task = await storage.getTask(taskId);\n if (!task) {\n throw new Error(`Task not found: ${taskId}`);\n }\n\n if (\n task.status === 'completed' ||\n task.status === 'failed' ||\n task.status === 'cancelled' ||\n task.status === 'timed_out'\n ) {\n return; // no-op for terminal states\n }\n\n if (task.status === 'pending') {\n await storage.updateTask(taskId, { status: 'cancelled', completedAt: new Date() });\n const cancelledTask = await storage.getTask(taskId);\n if (cancelledTask) await this.publishLifecycleEvent('task.cancelled', cancelledTask);\n this.deregisterTaskContext(taskId);\n return;\n }\n\n if (task.status === 'suspended') {\n // No active executor or AbortController to tear down — the task is\n // sitting on a workflow snapshot. Flip storage, publish, and tell the\n // workflow run to cancel so the snapshot is cleaned up too.\n await storage.updateTask(taskId, { status: 'cancelled', completedAt: new Date() });\n if (this.#mastra) {\n try {\n const workflow = this.#mastra.__getInternalWorkflow(BACKGROUND_TASK_WORKFLOW_ID);\n const wrapper = await workflow.createRun({ runId: taskId });\n await wrapper.cancel();\n } catch (err) {\n this.#mastra?.getLogger?.()?.warn(`background-task workflow cancel failed for ${taskId}:`, err as any);\n }\n }\n const cancelledTask = await storage.getTask(taskId);\n if (cancelledTask) await this.publishLifecycleEvent('task.cancelled', cancelledTask);\n this.deregisterTaskContext(taskId);\n return;\n }\n\n if (task.status === 'running') {\n await storage.updateTask(taskId, { status: 'cancelled', completedAt: new Date() });\n\n // Abort the running tool\n const controller = this.activeAbortControllers.get(taskId);\n if (controller) {\n controller.abort(new Error('Task cancelled'));\n this.activeAbortControllers.delete(taskId);\n }\n\n // Also cancel the workflow run so workflow storage reflects the\n // cancellation (run status flips to 'canceled' and the workflow's\n // abortSignal fires — redundant with the local AbortController above\n // but keeps run history clean and propagates cross-process via the\n // workflow.cancel pubsub event).\n if (this.#mastra) {\n try {\n const workflow = this.#mastra.__getInternalWorkflow(BACKGROUND_TASK_WORKFLOW_ID);\n const wrapper = await workflow.createRun({ runId: taskId });\n await wrapper.cancel();\n } catch (err) {\n this.#mastra?.getLogger?.()?.warn(`background-task workflow cancel failed for ${taskId}:`, err as any);\n }\n }\n\n const cancelledTask = await storage.getTask(taskId);\n if (cancelledTask) await this.publishLifecycleEvent('task.cancelled', cancelledTask);\n this.deregisterTaskContext(taskId);\n\n // Also publish cancel on dispatch topic for distributed worker abort\n await this.pubsub.publish(TOPIC_DISPATCH, {\n type: 'task.cancel',\n data: { taskId },\n runId: taskId,\n });\n }\n }\n\n /**\n * Resume a suspended task. The tool executor must be re-registered via\n * `registerTaskContext(taskId, ...)` before calling this if the original\n * registration is gone (e.g. process restart) — the manager doesn't\n * rehydrate executor closures from storage.\n *\n * `resumeData` is forwarded to the tool's `execute` options on the\n * resumed run.\n */\n async resume(taskId: string, resumeData?: unknown): Promise<BackgroundTask> {\n if (!this.#mastra) {\n throw new Error('Mastra is not registered with this manager');\n }\n\n if (this.initPromise) await this.initPromise;\n\n const storage = await this.getStorage();\n const task = await storage.getTask(taskId);\n if (!task) {\n throw new Error(`Task not found: ${taskId}`);\n }\n if (task.status !== 'suspended') {\n throw new Error(`Cannot resume task in status '${task.status}' (expected 'suspended')`);\n }\n\n const canRun = await this.checkConcurrency(task.agentId);\n if (!canRun) {\n // Resume sits outside the queue/fallback-sync paths — there's no\n // synchronous caller to fall back to, and silently leaving the task\n // suspended hides the failure from the caller. Throw and let the\n // caller retry once a slot frees.\n throw new Error(`Concurrency limit reached, cannot resume task \"${taskId}\" — retry once a slot is available`);\n }\n\n // Resume publishes directly (not via dispatch()), so it needs its own\n // lazy worker start for the library-mode process-restart case.\n await this.#ensureExecutionWorkersStarted();\n\n // Hand off to the worker subscriber. `task.resume` rides the same\n // `TOPIC_DISPATCH` + `WORKER_GROUP` exactly-once channel as\n // `task.dispatch`, so any worker (including a different process from\n // the one that suspended the task) can pick it up.\n await this.pubsub.publish(TOPIC_DISPATCH, {\n type: 'task.resume',\n data: { taskId, resumeData },\n runId: taskId,\n });\n\n return task;\n }\n\n /**\n * Restarts a previously running task. The tool executor is re-registered via\n * `registerTaskContext(taskId, ...)` because the original\n * registration is gone (e.g. process restart) — the manager doesn't\n * rehydrate executor closures from storage.\n *\n */\n async restart(taskId: string, context?: TaskContext): Promise<BackgroundTask> {\n if (!this.#mastra) {\n throw new Error('Mastra is not registered with this manager');\n }\n\n if (this.initPromise) await this.initPromise;\n\n const storage = await this.getStorage();\n const task = await storage.getTask(taskId);\n if (!task) {\n throw new Error(`Task not found: ${taskId}`);\n }\n if (task.status !== 'running') {\n throw new Error(`Cannot restart task in status '${task.status}' (expected 'running')`);\n }\n\n if (context) {\n this.registerTaskContext(task.id, context);\n }\n\n const canRun = await this.checkConcurrency(task.agentId);\n if (!canRun) {\n // Restart sits outside the queue/fallback-sync paths — there's no\n // synchronous caller to fall back to, and silently leaving the task\n // running hides the failure from the caller. Throw and let the\n // caller retry once a slot frees.\n throw new Error(`Concurrency limit reached, cannot restart task \"${taskId}\" — retry once a slot is available`);\n }\n\n await this.dispatch(task, true);\n\n return task;\n }\n\n async getTask(taskId: string): Promise<BackgroundTask | null> {\n const storage = await this.getStorage();\n return storage.getTask(taskId);\n }\n\n async listTasks(filter: TaskFilter = {}): Promise<TaskListResult> {\n const storage = await this.getStorage();\n return storage.listTasks(filter);\n }\n\n /**\n * Deletes old completed/failed/cancelled/timed_out task records from storage.\n */\n async cleanup(): Promise<void> {\n const completedTtlMs = this.config.cleanup?.completedTtlMs ?? 3_600_000;\n const failedTtlMs = this.config.cleanup?.failedTtlMs ?? 86_400_000;\n const now = Date.now();\n\n const storage = await this.getStorage();\n await storage.deleteTasks({\n status: ['completed'],\n toDate: new Date(now - completedTtlMs),\n dateFilterBy: 'completedAt',\n });\n\n await storage.deleteTasks({\n status: ['failed', 'cancelled', 'timed_out'],\n toDate: new Date(now - failedTtlMs),\n dateFilterBy: 'completedAt',\n });\n }\n\n /**\n * Returns a promise that resolves when the next task from the given set\n * reaches a terminal state.\n */\n async waitForNextTask(\n taskIds: string[],\n options?: {\n timeoutMs?: number;\n onProgress?: (elapsedMs: number) => void;\n progressIntervalMs?: number;\n },\n ): Promise<BackgroundTask> {\n const storage = await this.getStorage();\n\n const isTerminal = (status: string) =>\n status === 'completed' || status === 'failed' || status === 'cancelled' || status === 'timed_out';\n\n for (const id of taskIds) {\n const task = await storage.getTask(id);\n if (task && isTerminal(task.status)) {\n return task;\n }\n }\n\n return new Promise((resolve, reject) => {\n const startTime = Date.now();\n\n const timeout = options?.timeoutMs\n ? setTimeout(() => {\n clearInterval(pollInterval);\n if (progressInterval) clearInterval(progressInterval);\n reject(new Error('Timed out waiting for background task'));\n }, options.timeoutMs)\n : undefined;\n\n const progressInterval = options?.onProgress\n ? setInterval(() => {\n options.onProgress!(Date.now() - startTime);\n }, options.progressIntervalMs ?? 3000)\n : undefined;\n\n const pollInterval = setInterval(async () => {\n for (const id of taskIds) {\n const task = await storage.getTask(id);\n if (task && isTerminal(task.status)) {\n clearInterval(pollInterval);\n if (timeout) clearTimeout(timeout);\n if (progressInterval) clearInterval(progressInterval);\n resolve(task);\n return;\n }\n }\n }, 50);\n });\n }\n\n /**\n * Returns a ReadableStream of all background task lifecycle events,\n * filtered by optional criteria. Intended to be piped directly to an SSE response.\n *\n * On connection, emits the current state of all non-terminal tasks as a snapshot,\n * then subscribes to live pubsub events for subsequent updates.\n *\n * Events include:\n * - `task.running` (status: 'running') — task picked up by a worker\n * - `task.completed` (status: 'completed') — task finished successfully\n * - `task.failed` (status: 'failed' or 'timed_out') — task errored or timed out\n * - `task.cancelled` (status: 'cancelled') — task was cancelled\n * - `task.suspended` (status: 'suspended') — task paused via `suspend()` from\n * inside its tool executor; resume with `manager.resume(taskId, data)`\n * - `task.resumed` (status: 'running') — suspended task resumed\n *\n * The stream stays open until the caller's AbortSignal fires (client disconnect).\n */\n stream(options?: {\n agentId?: string;\n runId?: string;\n threadId?: string;\n resourceId?: string;\n taskId?: string;\n abortSignal?: AbortSignal;\n }): ReadableStream<Record<string, unknown>> {\n const manager = this;\n const pubsub = this.pubsub;\n const { agentId, runId, threadId, resourceId, abortSignal, taskId } = options ?? {};\n\n const EVENT_STATUS_MAP: Record<string, BackgroundTaskStatus> = {\n 'task.running': 'running',\n 'task.output': 'running',\n 'task.completed': 'completed',\n 'task.failed': 'failed',\n 'task.cancelled': 'cancelled',\n 'task.suspended': 'suspended',\n 'task.resumed': 'running',\n };\n\n const CHUNK_EVENT_MAP: Record<string, string> = {\n 'task.running': 'background-task-running',\n 'task.output': 'background-task-output',\n 'task.completed': 'background-task-completed',\n 'task.failed': 'background-task-failed',\n 'task.cancelled': 'background-task-cancelled',\n 'task.suspended': 'background-task-suspended',\n 'task.resumed': 'background-task-resumed',\n };\n\n return new ReadableStream({\n async start(controller) {\n // 1. Subscribe to live events first (so we don't miss anything between snapshot and subscribe)\n const handler = async (event: Event) => {\n const status = EVENT_STATUS_MAP[event.type];\n if (!status) return;\n\n const data = event.data;\n if (agentId && data.agentId !== agentId) return;\n if (runId && data.runId !== runId) return;\n if (threadId && data.threadId !== threadId) return;\n if (resourceId && data.resourceId !== resourceId) return;\n if (taskId && data.taskId !== taskId) return;\n\n const payload: Record<string, unknown> = {\n taskId: data.taskId,\n toolName: data.toolName,\n toolCallId: data.toolCallId,\n agentId: data.agentId,\n runId: data.runId,\n };\n\n switch (event.type) {\n case 'task.running':\n payload.startedAt = data.startedAt;\n payload.args = data.args;\n break;\n case 'task.completed':\n payload.completedAt = data.completedAt;\n payload.result = data.result;\n break;\n case 'task.failed':\n payload.completedAt = data.completedAt;\n payload.error = data.error;\n break;\n case 'task.cancelled':\n payload.completedAt = data.completedAt;\n break;\n case 'task.output':\n payload.payload = data.chunk;\n break;\n case 'task.suspended':\n payload.suspendPayload = data.suspendPayload;\n payload.suspendedAt = data.suspendedAt;\n payload.args = data.args;\n break;\n case 'task.resumed':\n payload.startedAt = data.startedAt;\n payload.args = data.args;\n break;\n }\n\n try {\n controller.enqueue({\n type: CHUNK_EVENT_MAP[event.type],\n payload,\n });\n } catch {\n // Controller closed\n }\n };\n\n void pubsub.subscribe(TOPIC_RESULT, handler);\n\n abortSignal?.addEventListener('abort', () => {\n void pubsub.unsubscribe(TOPIC_RESULT, handler);\n try {\n controller.close();\n } catch {\n // Already closed\n }\n });\n\n // 2. Emit snapshot of existing in-flight tasks (running + suspended).\n try {\n const storage = await manager.getStorage();\n if (taskId) {\n const task = await storage.getTask(taskId);\n if (task && task.status === 'running') {\n controller.enqueue({\n type: 'background-task-running',\n payload: {\n taskId: task.id,\n toolName: task.toolName,\n toolCallId: task.toolCallId,\n agentId: task.agentId,\n runId: task.runId,\n startedAt: task.startedAt,\n args: task.args,\n },\n });\n }\n } else {\n const { tasks: existing } = await storage.listTasks({\n agentId,\n runId,\n threadId,\n resourceId,\n status: ['running'],\n });\n\n for (const task of existing) {\n if (abortSignal?.aborted) break;\n try {\n controller.enqueue({\n type: 'background-task-running',\n payload: {\n taskId: task.id,\n toolName: task.toolName,\n toolCallId: task.toolCallId,\n agentId: task.agentId,\n runId: task.runId,\n startedAt: task.startedAt,\n args: task.args,\n },\n });\n } catch {\n break;\n }\n }\n }\n } catch {\n // Storage not available — continue with live events only\n }\n },\n });\n }\n\n async shutdown(): Promise<void> {\n this.shuttingDown = true;\n\n if (this.cleanupInterval) {\n clearInterval(this.cleanupInterval);\n this.cleanupInterval = undefined;\n }\n\n if (this.workerCallback) {\n await this.pubsub.unsubscribe(TOPIC_DISPATCH, this.workerCallback);\n }\n if (this.resultCallback) {\n await this.pubsub.unsubscribe(TOPIC_RESULT, this.resultCallback);\n }\n\n this.taskContexts.clear();\n await this.pubsub.flush();\n }\n\n // --- Internal ---\n\n /**\n * Lazily start Mastra's execution workers before publishing. In \"library\n * mode\" nothing ever calls `mastra.startWorkers()`, so the evented\n * `__background-task` workflow started by `handleDispatch` would publish\n * to the `workflows` topic with no consumer and the task would sit at\n * `running` forever (#19339). A no-op once workers are running; honors the\n * `workers: false` / `MASTRA_WORKERS` opt-outs.\n *\n * Startup failures are logged but don't abort the publish — in distributed\n * topologies a remote worker on the shared broker can still pick the task\n * up, and throwing here would also abort `drainPending()` /\n * `recoverStaleTasks()` loops.\n */\n async #ensureExecutionWorkersStarted(): Promise<void> {\n if (!this.#mastra) return;\n try {\n await this.#mastra.__ensureExecutionWorkersStarted();\n } catch (err) {\n this.#mastra.getLogger?.()?.error('Failed to start execution workers for background task', err as any);\n }\n }\n\n private async dispatch(task: BackgroundTask, isRestart?: boolean): Promise<void> {\n await this.#ensureExecutionWorkersStarted();\n\n // Publish `task.dispatch` on `TOPIC_DISPATCH` with `WORKER_GROUP`, so\n // exactly one worker handles the task. `handleDispatch` flips the\n // task to running and starts the per-task workflow run.\n await this.pubsub.publish(TOPIC_DISPATCH, {\n type: 'task.dispatch',\n data: {\n taskId: task.id,\n toolName: task.toolName,\n toolCallId: task.toolCallId,\n args: task.args,\n agentId: task.agentId,\n threadId: task.threadId,\n resourceId: task.resourceId,\n timeoutMs: task.timeoutMs,\n maxRetries: task.maxRetries,\n runId: task.runId,\n isRestart,\n },\n runId: task.id,\n });\n }\n\n /**\n * Handles a task.dispatch and task.restart events.\n * Both events are similar, but the latter is used to restart a running task.\n */\n private async handleDispatch(event: Event): Promise<void> {\n const { taskId, isRestart } = event.data;\n const deliveryAttempt = event.deliveryAttempt ?? 1;\n\n const storage = await this.getStorage();\n const task = await storage.getTask(taskId);\n if (!task || task.status === 'cancelled') {\n this.deregisterTaskContext(taskId);\n return;\n }\n\n if (isRestart && task.status !== 'running') {\n // Either gone or already done/cancelled by another worker. Drop the\n // event silently — the worker group ensures exactly-once delivery, but\n // the task may have moved on between publish and pickup.\n return;\n }\n\n await storage.updateTask(taskId, { status: 'running', startedAt: new Date(), retryCount: deliveryAttempt - 1 });\n\n // Publish running lifecycle event (fan-out, for stream consumers)\n const runningTask = await storage.getTask(taskId);\n if (runningTask) await this.publishLifecycleEvent('task.running', runningTask);\n\n // Fire-and-forget the workflow run; the workflow step body owns\n // executor invocation, retries, and suspend/resume. The local\n // execution hook still runs here so callers see `onExecution` fire.\n if (this.#mastra) {\n if (runningTask) void this.runLocalExecutionHook(runningTask);\n const workflow = this.#mastra.__getInternalWorkflow(BACKGROUND_TASK_WORKFLOW_ID);\n const prevWorkflowRun = isRestart ? await workflow.getWorkflowRunById(taskId) : undefined;\n const shouldRestart = isRestart && prevWorkflowRun?.status === 'running';\n const run = await workflow.createRun({ runId: taskId });\n const runPromise = shouldRestart ? run.restart() : run.start({ inputData: { taskId } });\n void runPromise\n .then(result => {\n if (result.status !== 'suspended') {\n void workflow.deleteWorkflowRunById(taskId);\n }\n })\n .catch(err => {\n this.#mastra\n ?.getLogger?.()\n ?.error(`background-task workflow ${shouldRestart ? 'restart' : 'start'} failed for ${taskId}:`, err);\n })\n .finally(() => {\n // Free the concurrency slot once the run terminates.\n void this.drainPending();\n });\n }\n }\n\n /**\n * Handles a task.resume event. Mirrors the workflow branch of handleDispatch\n * but resumes an existing run from its suspended snapshot instead of starting\n * a fresh one. Concurrency gating, suspended-status validation, and the\n * `task.resumed` lifecycle publish all happen here so a different process\n * than the one that suspended the task can drive the resume.\n */\n private async handleResume(event: Event): Promise<void> {\n const { taskId, resumeData } = event.data;\n\n const storage = await this.getStorage();\n const task = await storage.getTask(taskId);\n if (!task || task.status !== 'suspended') {\n // Either gone or already resumed/cancelled by another worker. Drop the\n // event silently — the worker group ensures exactly-once delivery, but\n // the task may have moved on between publish and pickup.\n return;\n }\n\n await storage.updateTask(taskId, {\n status: 'running',\n startedAt: new Date(),\n suspendPayload: undefined,\n suspendedAt: undefined,\n });\n const resumedTask = await storage.getTask(taskId);\n if (resumedTask) {\n await this.publishLifecycleEvent('task.resumed', resumedTask);\n }\n\n if (!this.#mastra) return;\n const workflow = this.#mastra.__getInternalWorkflow(BACKGROUND_TASK_WORKFLOW_ID);\n // `createRun({ runId })` reattaches to the existing snapshot when given a\n // stable runId — we don't want a fresh run.\n const run = await workflow.createRun({ runId: taskId });\n void run\n .resume({ resumeData })\n .then(result => {\n if (result.status !== 'suspended') {\n void workflow.deleteWorkflowRunById(taskId);\n }\n })\n .catch(err => {\n this.#mastra?.getLogger?.()?.error(`background-task workflow resume failed for ${taskId}:`, err);\n })\n .finally(() => {\n // Mirror dispatch's drain — resuming frees a slot when it terminates.\n void this.drainPending();\n });\n }\n\n /**\n * Run per-task hooks (onChunk, onResult, onComplete/onFailed) locally in the\n * worker path, before publishing the terminal lifecycle event. Ensures\n * memory / stream state is consistent by the time any pubsub subscriber is\n * notified. After running, the task context is deregistered so\n * `handleResult` (which also fires from pubsub) becomes a no-op for this\n * task in the same process.\n *\n * In distributed deployments where the worker runs in a different process\n * from the dispatcher, `this.taskContexts` won't contain an entry for\n * `task.id` — this method is a no-op there, and `handleResult` in the\n * dispatching process runs the hooks instead.\n */\n /**\n * Terminal-state hooks only. Called when a task reaches `'completed'` or\n * `'failed'`. Suspend is non-terminal — see `runLocalSuspendHooks` for that\n * path.\n *\n * @internal — also called by the workflow-engine step bodies in workflow.ts\n */\n async runLocalCompletionHooks(\n task: BackgroundTask,\n status: 'completed' | 'failed',\n extras: { result?: unknown; error?: { message: string; stack?: string } },\n ): Promise<void> {\n const ctx = this.taskContexts.get(task.id);\n if (!ctx) return;\n\n try {\n if (status === 'completed') {\n ctx.onChunk?.({\n type: 'background-task-completed',\n payload: {\n taskId: task.id,\n toolName: task.toolName,\n toolCallId: task.toolCallId,\n runId: task.runId,\n result: extras.result,\n completedAt: task.completedAt!,\n agentId: task.agentId,\n },\n });\n\n await ctx.onResult?.({\n runId: task.runId,\n taskId: task.id,\n toolCallId: task.toolCallId,\n toolName: task.toolName,\n agentId: task.agentId,\n threadId: task.threadId,\n resourceId: task.resourceId,\n result: extras.result,\n status: 'completed',\n completedAt: task.completedAt!,\n startedAt: task.startedAt!,\n });\n\n // Globals (this.config.onTaskComplete / onTaskFailed) fire from\n // handleResult via pubsub so they run once per subscribing process\n // — in distributed deployments that's the dispatching process, which\n // is where observers/metrics are typically wired.\n await ctx.onComplete?.(task);\n } else {\n ctx.onChunk?.({\n type: 'background-task-failed',\n payload: {\n taskId: task.id,\n toolName: task.toolName,\n toolCallId: task.toolCallId,\n runId: task.runId,\n error: extras.error ?? { message: 'Unknown error' },\n completedAt: task.completedAt!,\n agentId: task.agentId,\n },\n });\n\n await ctx.onResult?.({\n runId: task.runId,\n taskId: task.id,\n toolCallId: task.toolCallId,\n toolName: task.toolName,\n agentId: task.agentId,\n threadId: task.threadId,\n resourceId: task.resourceId,\n error: extras.error,\n status: 'failed',\n completedAt: task.completedAt!,\n startedAt: task.startedAt!,\n });\n\n // See comment above — globals are handled exclusively by\n // handleResult so they fire once per subscribing process.\n await ctx.onFailed?.(task);\n }\n } finally {\n this.deregisterTaskContext(task.id);\n }\n }\n\n /**\n * Per-task suspend hooks. Fires `ctx.onResult({ status: 'suspended', ... })`\n * so the message list / memory pick up the suspension as the tool's\n * current invocation state. Does NOT deregister the task context — resume\n * needs the executor closure intact.\n *\n * @internal — called by the workflow-engine step bodies in workflow.ts\n */\n async runLocalSuspendHooks(task: BackgroundTask): Promise<void> {\n const ctx = this.taskContexts.get(task.id);\n if (!ctx) return;\n await ctx.onExecution?.({\n runId: task.runId,\n taskId: task.id,\n toolCallId: task.toolCallId,\n toolName: task.toolName,\n agentId: task.agentId,\n threadId: task.threadId,\n resourceId: task.resourceId,\n startedAt: task.startedAt!,\n suspendedAt: task.suspendedAt,\n });\n }\n\n /** @internal — also called by the workflow-engine step bodies in workflow.ts */\n async runLocalExecutionHook(task: BackgroundTask): Promise<void> {\n const ctx = this.taskContexts.get(task.id);\n if (!ctx) return;\n\n try {\n await ctx.onExecution?.({\n runId: task.runId,\n taskId: task.id,\n toolCallId: task.toolCallId,\n toolName: task.toolName,\n agentId: task.agentId,\n threadId: task.threadId,\n resourceId: task.resourceId,\n startedAt: task.startedAt!,\n });\n } catch {\n //fail silently\n }\n }\n\n private async handleResult(event: Event): Promise<void> {\n const { taskId, toolName, toolCallId, threadId, resourceId, runId } = event.data;\n const storage = await this.getStorage();\n const task = await storage.getTask(taskId);\n\n if (task?.completedAt) {\n // Look up per-task hooks\n const ctx = this.taskContexts.get(taskId);\n\n if (event.type === 'task.completed') {\n ctx?.onChunk?.({\n type: 'background-task-completed',\n payload: {\n taskId,\n toolName,\n toolCallId,\n runId,\n result: event.data.result,\n completedAt: task.completedAt,\n agentId: task.agentId,\n },\n });\n\n await ctx?.onResult?.({\n runId,\n taskId,\n toolCallId,\n toolName,\n agentId: event.data.agentId,\n threadId,\n resourceId,\n result: event.data.result,\n status: 'completed',\n completedAt: task.completedAt,\n startedAt: task.startedAt!,\n });\n\n if (task) {\n await Promise.all([ctx?.onComplete?.(task), this.config.onTaskComplete?.(task)]);\n }\n }\n\n if (event.type === 'task.failed') {\n ctx?.onChunk?.({\n type: 'background-task-failed',\n payload: {\n taskId,\n toolName,\n toolCallId,\n runId,\n error: event.data.error,\n completedAt: task.completedAt,\n agentId: task.agentId,\n },\n });\n\n await ctx?.onResult?.({\n runId,\n taskId,\n toolCallId,\n toolName,\n agentId: event.data.agentId,\n threadId,\n resourceId,\n error: event.data.error,\n status: 'failed',\n completedAt: task.completedAt,\n startedAt: task.startedAt!,\n });\n\n if (task) {\n await Promise.all([ctx?.onFailed?.(task), this.config.onTaskFailed?.(task)]);\n }\n }\n\n // Clean up context after terminal result\n this.deregisterTaskContext(taskId);\n }\n }\n\n private handleCancel(event: Event): void {\n const { taskId } = event.data;\n const controller = this.activeAbortControllers.get(taskId);\n if (controller) {\n controller.abort(new Error('Task cancelled'));\n this.activeAbortControllers.delete(taskId);\n }\n this.deregisterTaskContext(taskId);\n }\n\n /** @internal — also called by the workflow-engine step bodies in workflow.ts */\n async publishLifecycleEvent(\n type:\n | 'task.running'\n | 'task.completed'\n | 'task.failed'\n | 'task.cancelled'\n | 'task.output'\n | 'task.suspended'\n | 'task.resumed',\n task: BackgroundTaskEvent,\n ): Promise<void> {\n await this.pubsub.publish(TOPIC_RESULT, {\n type,\n data: {\n taskId: task.id,\n toolName: task.toolName,\n toolCallId: task.toolCallId,\n runId: task.runId,\n agentId: task.agentId,\n threadId: task.threadId,\n resourceId: task.resourceId,\n args: task.args,\n result: task.result,\n error: task.error,\n chunk: task.chunk,\n completedAt: task.completedAt,\n startedAt: task.startedAt,\n suspendPayload: task.suspendPayload,\n suspendedAt: task.suspendedAt,\n },\n runId: task.id,\n });\n }\n\n private async checkConcurrency(agentId: string): Promise<boolean> {\n const storage = await this.getStorage();\n const globalRunning = await storage.getRunningCount();\n if (globalRunning >= this.config.globalConcurrency) {\n return false;\n }\n\n const agentRunning = await storage.getRunningCountByAgent(agentId);\n if (agentRunning >= this.config.perAgentConcurrency) {\n return false;\n }\n\n return true;\n }\n\n private async drainPending(): Promise<void> {\n const storage = await this.getStorage();\n const { tasks: pending } = await storage.listTasks({\n status: 'pending',\n orderBy: 'createdAt',\n orderDirection: 'asc',\n });\n\n for (const task of pending) {\n if (await this.checkConcurrency(task.agentId)) {\n await this.dispatch(task);\n }\n }\n }\n\n /**\n * Recovers tasks left in 'running' or 'pending' state from a previous process.\n */\n private async recoverStaleTasks(): Promise<void> {\n try {\n const storage = await this.getStorage();\n const { tasks: staleTasks } = await storage.listTasks({ status: 'running' });\n for (const task of staleTasks) {\n if (task.maxRetries > 0) {\n await storage.updateTask(task.id, {\n status: 'pending',\n startedAt: undefined,\n });\n } else {\n await storage.updateTask(task.id, {\n status: 'failed',\n error: { message: 'Worker process terminated before task completed' },\n completedAt: new Date(),\n });\n }\n }\n\n const { tasks: pendingTasks } = await storage.listTasks({\n status: 'pending',\n orderBy: 'createdAt',\n orderDirection: 'asc',\n });\n for (const task of pendingTasks) {\n if (await this.checkConcurrency(task.agentId)) {\n await this.dispatch(task);\n }\n }\n } catch (error) {\n const logger = this.#mastra?.getLogger();\n if (logger) {\n logger.error('Failed to recover stale background tasks', error);\n }\n }\n }\n}\n","import type { BackgroundTaskManager } from './manager';\nimport type {\n BackgroundTaskHandle,\n CheckIfRunningPayload,\n CheckIfSuspendedPayload,\n CreateBackgroundTaskOptions,\n} from './types';\n\n/**\n * Creates a self-contained background task handle.\n *\n * Bundles the task payload with per-stream hooks (executor, onChunk, onResult)\n * so each dispatch is fully isolated — no shared mutable state on the manager.\n *\n * @example\n * ```ts\n * const bgTask = createBackgroundTask(manager, {\n * toolName: 'research',\n * toolCallId: 'call-1',\n * args: { query: 'solana' },\n * agentId: 'agent-1',\n * runId: 'run-1',\n * context: {\n * executor: { execute: (args, opts) => tool.execute(args, opts) },\n * onChunk: (chunk) => controller.enqueue(chunk),\n * onResult: (params) => messageList.addToolResult(params),\n * },\n * });\n *\n * const { task, fallbackToSync } = await bgTask.dispatch();\n * const completed = await bgTask.waitForCompletion();\n * await bgTask.cancel();\n * ```\n */\nexport function createBackgroundTask(\n manager: BackgroundTaskManager,\n options: CreateBackgroundTaskOptions,\n): BackgroundTaskHandle {\n const { context, ...payload } = options;\n let taskId: string | undefined;\n\n return {\n get task() {\n if (!taskId) throw new Error('Task has not been dispatched yet');\n // Synchronous access to task ID — full task data requires async getTask()\n return { id: taskId } as any;\n },\n\n async dispatch() {\n const result = await manager.enqueue(payload, context);\n taskId = result.task.id;\n return result;\n },\n\n async checkIfSuspended(args: CheckIfSuspendedPayload) {\n const result = await manager.listTasks({\n toolCallId: args.toolCallId,\n runId: args.runId,\n agentId: args.agentId,\n threadId: args.threadId,\n resourceId: args.resourceId,\n toolName: args.toolName,\n status: 'suspended',\n });\n if (result.total > 0) {\n const task = result.tasks[0];\n if (task) {\n taskId = task.id;\n return true;\n }\n }\n\n return false;\n },\n\n async checkIfRunning(args: CheckIfRunningPayload) {\n const result = await manager.listTasks({\n toolCallId: args.toolCallId,\n runId: args.runId,\n agentId: args.agentId,\n threadId: args.threadId,\n resourceId: args.resourceId,\n toolName: args.toolName,\n status: 'running',\n });\n if (result.total > 0) {\n const task = result.tasks[0];\n if (task) {\n taskId = task.id;\n return true;\n }\n }\n\n return false;\n },\n\n async resume(resumeData?: unknown) {\n if (!taskId) throw new Error('Task has not been dispatched yet');\n return manager.resume(taskId, resumeData);\n },\n\n async restart() {\n if (!taskId) throw new Error('Task has not been dispatched yet');\n return manager.restart(taskId, context);\n },\n\n async cancel() {\n if (!taskId) throw new Error('Task has not been dispatched yet');\n return manager.cancel(taskId);\n },\n\n async waitForCompletion(waitOptions) {\n if (!taskId) throw new Error('Task has not been dispatched yet');\n return manager.waitForNextTask([taskId], waitOptions);\n },\n };\n}\n","import type {\n AgentBackgroundConfig,\n AgentBackgroundToolConfig,\n BackgroundTaskManagerConfig,\n LLMBackgroundOverride,\n ToolBackgroundConfig,\n} from './types';\n\nexport interface ResolvedBackgroundConfig {\n runInBackground: boolean;\n timeoutMs: number;\n maxRetries: number;\n}\n\n/**\n * Resolves whether a tool call should run in the background, and with what config.\n *\n * Resolution order (highest to lowest priority):\n * 1. LLM per-call override (`_background` field in tool args)\n * 2. Agent-level backgroundTasks.tools config\n * 3. Tool-level background config\n * 4. Default: foreground\n *\n * Strips the `_background` field from args (mutates the args object).\n */\nexport function resolveBackgroundConfig({\n llmBgOverrides,\n toolName,\n toolConfig,\n agentConfig,\n managerConfig,\n}: {\n llmBgOverrides: Record<string, unknown>;\n toolName: string;\n toolConfig?: ToolBackgroundConfig;\n agentConfig?: AgentBackgroundConfig;\n managerConfig?: BackgroundTaskManagerConfig;\n}): ResolvedBackgroundConfig {\n const llmOverride = llmBgOverrides as LLMBackgroundOverride | undefined;\n\n // If this agent has background tasks disabled, short-circuit so no tool can\n // dispatch a background task even if its own config or the LLM override\n // would otherwise enable it. Default timeoutMs/maxRetries are still returned\n // so callers can use the shape safely.\n if (agentConfig?.disabled) {\n return {\n runInBackground: false,\n timeoutMs: managerConfig?.defaultTimeoutMs ?? 300_000,\n maxRetries: managerConfig?.defaultRetries?.maxRetries ?? 0,\n };\n }\n\n // Resolve agent-level config for this specific tool\n const agentToolConfig = resolveAgentToolConfig(toolName, agentConfig);\n\n // --- enabled ---\n // The LLM `_background` override is a modifier on tools the developer has\n // already opted in at the tool or agent layer — it is NOT a standalone\n // opt-in. A foreground-only tool must stay foreground regardless of what\n // the model emits, so `agent.generate()` / `agent.stream()` keep returning\n // real tool results for deterministic tools. See issue #16783.\n const baseEnabled = agentToolConfig?.enabled ?? toolConfig?.enabled ?? false;\n const enabled = baseEnabled ? (llmOverride?.enabled ?? true) : false;\n\n // --- timeoutMs ---\n const timeoutMs =\n llmOverride?.timeoutMs ??\n agentToolConfig?.timeoutMs ??\n toolConfig?.timeoutMs ??\n managerConfig?.defaultTimeoutMs ??\n 300_000;\n\n // --- maxRetries ---\n const maxRetries =\n llmOverride?.maxRetries ?? toolConfig?.maxRetries ?? managerConfig?.defaultRetries?.maxRetries ?? 0;\n\n return { runInBackground: enabled, timeoutMs, maxRetries };\n}\n\nfunction resolveAgentToolConfig(\n toolName: string,\n agentConfig?: AgentBackgroundConfig,\n): { enabled: boolean; timeoutMs?: number } | undefined {\n if (!agentConfig?.tools) return undefined;\n\n if (agentConfig.tools === 'all') {\n return { enabled: true };\n }\n\n if (toolName.startsWith('agent-')) {\n toolName = toolName.substring('agent-'.length);\n } else if (toolName.startsWith('workflow-')) {\n toolName = toolName.substring('workflow-'.length);\n }\n\n const entry: AgentBackgroundToolConfig | undefined = agentConfig.tools[toolName];\n if (entry === undefined) return undefined;\n if (typeof entry === 'boolean') return { enabled: entry };\n return entry;\n}\n","import { z } from 'zod/v4';\n\n/**\n * JSON Schema definition for the `_background` override field.\n * Injected into background-eligible tool schemas so the LLM can override behavior per-call.\n */\nexport const backgroundOverrideJsonSchema = {\n type: 'object' as const,\n description:\n 'Optional: override background execution behavior for this specific call. ' +\n 'Set enabled=false to force foreground, enabled=true to force background. ' +\n 'Omit entirely to use the default configuration.',\n properties: {\n enabled: {\n type: 'boolean' as const,\n description: 'Force background (true) or foreground (false) execution for this call.',\n },\n timeoutMs: {\n type: 'number' as const,\n description: 'Override timeout in milliseconds for this call.',\n },\n maxRetries: {\n type: 'number' as const,\n description: 'Override maximum retry attempts for this call.',\n },\n },\n additionalProperties: false,\n};\n\nexport const backgroundOverrideZodSchema = z\n .object({\n enabled: z.boolean().optional().describe('Force background (true) or foreground (false) execution for this call.'),\n timeoutMs: z.number().optional().describe('Override timeout in milliseconds for this call.'),\n maxRetries: z.number().optional().describe('Override maximum retry attempts for this call.'),\n })\n .optional()\n .describe(\n 'Optional: override background execution behavior for this specific call. Set enabled=false to force foreground, enabled=true to force background. Omit entirely to use the default configuration.',\n );\n","import type { AgentBackgroundConfig, ToolBackgroundConfig } from './types';\n\ninterface ToolEntry {\n toolName: string;\n toolConfig?: ToolBackgroundConfig;\n /** Whether the tool defaults to background execution */\n defaultBackground: boolean;\n}\n\n/**\n * Generates the system prompt section that tells the LLM about background task capabilities.\n *\n * Returns undefined if no tools are background-eligible (nothing to inject).\n */\nexport function generateBackgroundTaskSystemPrompt(\n tools: Record<string, { background?: ToolBackgroundConfig; description?: string }>,\n agentConfig?: AgentBackgroundConfig,\n): string | undefined {\n const eligibleTools: ToolEntry[] = [];\n\n const enableAll = agentConfig?.tools === 'all';\n\n for (const [toolName, tool] of Object.entries(tools)) {\n const bgEnabledFromAgentConfig =\n agentConfig?.tools === 'all'\n ? false\n : typeof agentConfig?.tools?.[toolName] === 'boolean'\n ? agentConfig.tools[toolName]\n : (agentConfig?.tools?.[toolName]?.enabled ?? false);\n eligibleTools.push({\n toolName,\n toolConfig: tool.background,\n defaultBackground: enableAll ? true : (bgEnabledFromAgentConfig ?? tool.background?.enabled ?? false),\n });\n }\n\n if (eligibleTools.length === 0) {\n return undefined;\n }\n\n const toolLines = eligibleTools\n .map(t => `- ${t.toolName} (default: ${t.defaultBackground ? 'background' : 'foreground'})`)\n .join('\\n');\n\n return `You have the ability to run certain tools in the background while continuing the conversation. The following tools support background execution:\n${toolLines}\n\nFor any of these tools, you can include a \"_background\" field in the tool arguments to override the default:\n \"_background\": { \"enabled\": true/false, \"timeoutMs\": number, \"maxRetries\": number }\n\nAll fields in \"_background\" are optional. Only include what you want to override.\n\nGuidelines:\n- Use background execution when the user doesn't need the result immediately, or when you're launching multiple independent tasks.\n- Use foreground execution when the user is directly waiting for the result and the conversation can't continue without it.\n- If you don't include \"_background\", the tool's default configuration is used.\n- When a tool runs in the background, you'll receive a placeholder result with a task ID. You can reference this in your response to the user.\n\nIMPORTANT: \"_background\" field is always an object. The fields in the _background field should be inside the _background object, not outside of it.`;\n}\n"],"mappings":";;;;;;;;;;;;;AAUA,MAAa,8BAA8B;;;ACQ3C,MAAM,iBAAiB;AACvB,MAAM,eAAe;AACrB,MAAM,eAAe;AAErB,IAAa,wBAAb,MAAmC;CACjC;CACA;CAKA;;CAIA,+BAAyC,IAAI,IAAI;CAOjD,kCAAqD,IAAI,IAAI;;CAI7D,yCAAuD,IAAI,IAAI;CAG/D;CACA;CAEA,eAAuB;CAGvB;CAQA;CAEA,YAAY,SAAsC,EAAE,SAAS,MAAM,GAAG;EACpE,KAAK,SAAS;GACZ,mBAAmB,OAAO,qBAAqB;GAC/C,qBAAqB,OAAO,uBAAuB;GACnD,cAAc,OAAO,gBAAgB;GACrC,kBAAkB,OAAO,oBAAoB;GAC7C,GAAG;EACL;CACF;CAEA,iBAAiB,QAAgB;EAC/B,KAAKA,UAAU;CACjB;CAEA,MAAM,aAAa;EACjB,MAAM,UAAU,KAAKA,SAAS,WAAW;EACzC,IAAI,CAAC,SACH,MAAM,IAAI,MAAM,4BAA4B;EAE9C,MAAM,UAAU,MAAM,QAAQ,SAAS,iBAAiB;EACxD,IAAI,CAAC,SACH,MAAM,IAAI,MAAM,2CAA2C;EAE7D,OAAO;CACT;CAEA,MAAM,KAAK,QAA+B;EACxC,IAAI,KAAK,aAAa,OAAO,KAAK;EAClC,KAAK,cAAc,KAAKC,QAAQ,MAAM;EACtC,OAAO,KAAK;CACd;CAEA,MAAMA,QAAQ,QAA+B;EAC3C,KAAK,SAAS;EAEd,MAAM,iBAAiB,KAAK,OAAO,SAAS;EAK5C,KAAK,iBAAiB,OAAO,OAAc,QAA8B;GACvE,IAAI,MAAM,SAAS,oBAAoB,MAAM,SAAS,eACpD,MAAM,KAAK,aAAa,KAAK;GAE/B,MAAM,MAAM;EACd;EAEA,IAAI,CAAC,gBAAgB;GAEnB,KAAK,iBAAiB,OAAO,OAAc,QAA8B;IACvE,IAAI,MAAM,SAAS,mBAAmB,MAAM,SAAS,gBACnD,MAAM,KAAK,eAAe,KAAK;SAC1B,IAAI,MAAM,SAAS,eACxB,MAAM,KAAK,aAAa,KAAK;SACxB,IAAI,MAAM,SAAS,eACxB,KAAK,aAAa,KAAK;IAEzB,MAAM,MAAM;GACd;GASA,IAAI,KAAKD,SAAS;IAMhB,MAAM,EAAE,gCAAgC,MAAA,QAAA,QAAA,CAAA,CAAA,WAAA,QAAM,yBAAA,CAAA;IAC9C,MAAM,WAAW,4BAA4B,IAAI;IACjD,IAAI,CAAC,KAAKA,QAAQ,sBAAA,mBAAiD,GAKjE,KAAKA,QAAQ,2BACX,QACF;GAEJ;GAEA,MAAM,KAAK,OAAO,UAAU,gBAAgB,KAAK,gBAAgB,EAAE,OAAO,aAAa,CAAC;EAC1F;EAEA,MAAM,KAAK,OAAO,UAAU,cAAc,KAAK,cAAc;EAE7D,IAAI,CAAC,gBAGH,MAAM,KAAK,kBAAkB;EAI/B,MAAM,gBAAgB,KAAK,OAAO;EAClC,IAAI,eAAe;GACjB,MAAM,aAAa,cAAc,qBAAqB;GACtD,KAAK,kBAAkB,kBAAkB;IACvC,KAAU,QAAQ;GACpB,GAAG,UAAU;EACf;CACF;;;;;CAQA,oBAAoB,QAAgB,SAA4B;EAC9D,KAAK,aAAa,IAAI,QAAQ,OAAO;CACvC;;;;CAKA,sBAAsB,QAAsB;EAC1C,KAAK,aAAa,OAAO,MAAM;CACjC;;;;;;;CAQA,uBAAuB,UAAkB,UAA8B;EACrE,IAAI,KAAK,gBAAgB,IAAI,QAAQ,GACnC,KAAKA,SAAS,YAAY,CAAC,EAAE,QAAQ,kDAAkD,SAAS,EAAE;EAEpG,KAAK,gBAAgB,IAAI,UAAU,QAAQ;CAC7C;;;;;CAMA,yBAAyB,UAAwB;EAC/C,KAAK,gBAAgB,OAAO,QAAQ;CACtC;;;;;;CAOA,kBAAkB,UAA4C;EAC5D,OAAO,KAAK,gBAAgB,IAAI,QAAQ;CAC1C;;;;;CAQA,MAAM,QAAQ,SAAsB,SAA+C;EACjF,IAAI,KAAK,cACP,MAAM,IAAI,MAAM,kEAAkE;EAQpF,IAAI,KAAK,aAAa,MAAM,KAAK;EAEjC,MAAM,OAAuB;GAC3B,IAAI,KAAKA,SAAS,WAAW,MAAA,GAAA,OAAA,WAAA,CAAgB;GAC7C,QAAQ;GACR,UAAU,QAAQ;GAClB,YAAY,QAAQ;GACpB,MAAM,QAAQ;GACd,SAAS,QAAQ;GACjB,UAAU,QAAQ;GAClB,YAAY,QAAQ;GACpB,OAAO,QAAQ;GACf,YAAY;GACZ,YAAY,QAAQ,cAAc,KAAK,OAAO,gBAAgB,cAAc;GAC5E,WAAW,QAAQ,aAAa,KAAK,OAAO;GAC5C,2BAAW,IAAI,KAAK;EACtB;EAGA,IAAI,SACF,KAAK,oBAAoB,KAAK,IAAI,OAAO;EAG3C,MAAM,UAAU,MAAM,KAAK,WAAW;EACtC,MAAM,QAAQ,WAAW,IAAI;EAI7B,IAAI,MAFiB,KAAK,iBAAiB,KAAK,OAAO,GAE3C;GACV,MAAM,KAAK,SAAS,IAAI;GACxB,OAAO,EAAE,KAAK;EAChB;EAGA,QAAQ,KAAK,OAAO,cAApB;GACE,KAAK;IACH,KAAK,sBAAsB,KAAK,EAAE;IAClC,MAAM,QAAQ,WAAW,KAAK,EAAE;IAChC,MAAM,IAAI,MAAM,4DAA4D,KAAK,SAAS,EAAE;GAE9F,KAAK;IACH,KAAK,sBAAsB,KAAK,EAAE;IAClC,MAAM,QAAQ,WAAW,KAAK,EAAE;IAChC,OAAO;KAAE;KAAM,gBAAgB;IAAK;GAGtC,SAEE,OAAO,EAAE,KAAK;EAClB;CACF;CAEA,MAAM,OAAO,QAA+B;EAC1C,IAAI,KAAK,aAAa,MAAM,KAAK;EACjC,MAAM,UAAU,MAAM,KAAK,WAAW;EACtC,MAAM,OAAO,MAAM,QAAQ,QAAQ,MAAM;EACzC,IAAI,CAAC,MACH,MAAM,IAAI,MAAM,mBAAmB,QAAQ;EAG7C,IACE,KAAK,WAAW,eAChB,KAAK,WAAW,YAChB,KAAK,WAAW,eAChB,KAAK,WAAW,aAEhB;EAGF,IAAI,KAAK,WAAW,WAAW;GAC7B,MAAM,QAAQ,WAAW,QAAQ;IAAE,QAAQ;IAAa,6BAAa,IAAI,KAAK;GAAE,CAAC;GACjF,MAAM,gBAAgB,MAAM,QAAQ,QAAQ,MAAM;GAClD,IAAI,eAAe,MAAM,KAAK,sBAAsB,kBAAkB,aAAa;GACnF,KAAK,sBAAsB,MAAM;GACjC;EACF;EAEA,IAAI,KAAK,WAAW,aAAa;GAI/B,MAAM,QAAQ,WAAW,QAAQ;IAAE,QAAQ;IAAa,6BAAa,IAAI,KAAK;GAAE,CAAC;GACjF,IAAI,KAAKA,SACP,IAAI;IAGF,OAAM,MAFW,KAAKA,QAAQ,sBAAsB,2BACvB,CAAC,CAAC,UAAU,EAAE,OAAO,OAAO,CAAC,EAAA,CAC5C,OAAO;GACvB,SAAS,KAAK;IACZ,KAAKA,SAAS,YAAY,CAAC,EAAE,KAAK,8CAA8C,OAAO,IAAI,GAAU;GACvG;GAEF,MAAM,gBAAgB,MAAM,QAAQ,QAAQ,MAAM;GAClD,IAAI,eAAe,MAAM,KAAK,sBAAsB,kBAAkB,aAAa;GACnF,KAAK,sBAAsB,MAAM;GACjC;EACF;EAEA,IAAI,KAAK,WAAW,WAAW;GAC7B,MAAM,QAAQ,WAAW,QAAQ;IAAE,QAAQ;IAAa,6BAAa,IAAI,KAAK;GAAE,CAAC;GAGjF,MAAM,aAAa,KAAK,uBAAuB,IAAI,MAAM;GACzD,IAAI,YAAY;IACd,WAAW,sBAAM,IAAI,MAAM,gBAAgB,CAAC;IAC5C,KAAK,uBAAuB,OAAO,MAAM;GAC3C;GAOA,IAAI,KAAKA,SACP,IAAI;IAGF,OAAM,MAFW,KAAKA,QAAQ,sBAAsB,2BACvB,CAAC,CAAC,UAAU,EAAE,OAAO,OAAO,CAAC,EAAA,CAC5C,OAAO;GACvB,SAAS,KAAK;IACZ,KAAKA,SAAS,YAAY,CAAC,EAAE,KAAK,8CAA8C,OAAO,IAAI,GAAU;GACvG;GAGF,MAAM,gBAAgB,MAAM,QAAQ,QAAQ,MAAM;GAClD,IAAI,eAAe,MAAM,KAAK,sBAAsB,kBAAkB,aAAa;GACnF,KAAK,sBAAsB,MAAM;GAGjC,MAAM,KAAK,OAAO,QAAQ,gBAAgB;IACxC,MAAM;IACN,MAAM,EAAE,OAAO;IACf,OAAO;GACT,CAAC;EACH;CACF;;;;;;;;;;CAWA,MAAM,OAAO,QAAgB,YAA+C;EAC1E,IAAI,CAAC,KAAKA,SACR,MAAM,IAAI,MAAM,4CAA4C;EAG9D,IAAI,KAAK,aAAa,MAAM,KAAK;EAGjC,MAAM,OAAO,OAAM,MADG,KAAK,WAAW,EAAA,CACX,QAAQ,MAAM;EACzC,IAAI,CAAC,MACH,MAAM,IAAI,MAAM,mBAAmB,QAAQ;EAE7C,IAAI,KAAK,WAAW,aAClB,MAAM,IAAI,MAAM,iCAAiC,KAAK,OAAO,yBAAyB;EAIxF,IAAI,CAAC,MADgB,KAAK,iBAAiB,KAAK,OAAO,GAMrD,MAAM,IAAI,MAAM,kDAAkD,OAAO,mCAAmC;EAK9G,MAAM,KAAKE,+BAA+B;EAM1C,MAAM,KAAK,OAAO,QAAQ,gBAAgB;GACxC,MAAM;GACN,MAAM;IAAE;IAAQ;GAAW;GAC3B,OAAO;EACT,CAAC;EAED,OAAO;CACT;;;;;;;;CASA,MAAM,QAAQ,QAAgB,SAAgD;EAC5E,IAAI,CAAC,KAAKF,SACR,MAAM,IAAI,MAAM,4CAA4C;EAG9D,IAAI,KAAK,aAAa,MAAM,KAAK;EAGjC,MAAM,OAAO,OAAM,MADG,KAAK,WAAW,EAAA,CACX,QAAQ,MAAM;EACzC,IAAI,CAAC,MACH,MAAM,IAAI,MAAM,mBAAmB,QAAQ;EAE7C,IAAI,KAAK,WAAW,WAClB,MAAM,IAAI,MAAM,kCAAkC,KAAK,OAAO,uBAAuB;EAGvF,IAAI,SACF,KAAK,oBAAoB,KAAK,IAAI,OAAO;EAI3C,IAAI,CAAC,MADgB,KAAK,iBAAiB,KAAK,OAAO,GAMrD,MAAM,IAAI,MAAM,mDAAmD,OAAO,mCAAmC;EAG/G,MAAM,KAAK,SAAS,MAAM,IAAI;EAE9B,OAAO;CACT;CAEA,MAAM,QAAQ,QAAgD;EAE5D,QAAO,MADe,KAAK,WAAW,EAAA,CACvB,QAAQ,MAAM;CAC/B;CAEA,MAAM,UAAU,SAAqB,CAAC,GAA4B;EAEhE,QAAO,MADe,KAAK,WAAW,EAAA,CACvB,UAAU,MAAM;CACjC;;;;CAKA,MAAM,UAAyB;EAC7B,MAAM,iBAAiB,KAAK,OAAO,SAAS,kBAAkB;EAC9D,MAAM,cAAc,KAAK,OAAO,SAAS,eAAe;EACxD,MAAM,MAAM,KAAK,IAAI;EAErB,MAAM,UAAU,MAAM,KAAK,WAAW;EACtC,MAAM,QAAQ,YAAY;GACxB,QAAQ,CAAC,WAAW;GACpB,QAAQ,IAAI,KAAK,MAAM,cAAc;GACrC,cAAc;EAChB,CAAC;EAED,MAAM,QAAQ,YAAY;GACxB,QAAQ;IAAC;IAAU;IAAa;GAAW;GAC3C,QAAQ,IAAI,KAAK,MAAM,WAAW;GAClC,cAAc;EAChB,CAAC;CACH;;;;;CAMA,MAAM,gBACJ,SACA,SAKyB;EACzB,MAAM,UAAU,MAAM,KAAK,WAAW;EAEtC,MAAM,cAAc,WAClB,WAAW,eAAe,WAAW,YAAY,WAAW,eAAe,WAAW;EAExF,KAAK,MAAM,MAAM,SAAS;GACxB,MAAM,OAAO,MAAM,QAAQ,QAAQ,EAAE;GACrC,IAAI,QAAQ,WAAW,KAAK,MAAM,GAChC,OAAO;EAEX;EAEA,OAAO,IAAI,SAAS,SAAS,WAAW;GACtC,MAAM,YAAY,KAAK,IAAI;GAE3B,MAAM,UAAU,SAAS,YACrB,iBAAiB;IACf,cAAc,YAAY;IAC1B,IAAI,kBAAkB,cAAc,gBAAgB;IACpD,uBAAO,IAAI,MAAM,uCAAuC,CAAC;GAC3D,GAAG,QAAQ,SAAS,IACpB,KAAA;GAEJ,MAAM,mBAAmB,SAAS,aAC9B,kBAAkB;IAChB,QAAQ,WAAY,KAAK,IAAI,IAAI,SAAS;GAC5C,GAAG,QAAQ,sBAAsB,GAAI,IACrC,KAAA;GAEJ,MAAM,eAAe,YAAY,YAAY;IAC3C,KAAK,MAAM,MAAM,SAAS;KACxB,MAAM,OAAO,MAAM,QAAQ,QAAQ,EAAE;KACrC,IAAI,QAAQ,WAAW,KAAK,MAAM,GAAG;MACnC,cAAc,YAAY;MAC1B,IAAI,SAAS,aAAa,OAAO;MACjC,IAAI,kBAAkB,cAAc,gBAAgB;MACpD,QAAQ,IAAI;MACZ;KACF;IACF;GACF,GAAG,EAAE;EACP,CAAC;CACH;;;;;;;;;;;;;;;;;;;CAoBA,OAAO,SAOqC;EAC1C,MAAM,UAAU;EAChB,MAAM,SAAS,KAAK;EACpB,MAAM,EAAE,SAAS,OAAO,UAAU,YAAY,aAAa,WAAW,WAAW,CAAC;EAElF,MAAM,mBAAyD;GAC7D,gBAAgB;GAChB,eAAe;GACf,kBAAkB;GAClB,eAAe;GACf,kBAAkB;GAClB,kBAAkB;GAClB,gBAAgB;EAClB;EAEA,MAAM,kBAA0C;GAC9C,gBAAgB;GAChB,eAAe;GACf,kBAAkB;GAClB,eAAe;GACf,kBAAkB;GAClB,kBAAkB;GAClB,gBAAgB;EAClB;EAEA,OAAO,IAAI,eAAe,EACxB,MAAM,MAAM,YAAY;GAEtB,MAAM,UAAU,OAAO,UAAiB;IAEtC,IAAI,CADW,iBAAiB,MAAM,OACzB;IAEb,MAAM,OAAO,MAAM;IACnB,IAAI,WAAW,KAAK,YAAY,SAAS;IACzC,IAAI,SAAS,KAAK,UAAU,OAAO;IACnC,IAAI,YAAY,KAAK,aAAa,UAAU;IAC5C,IAAI,cAAc,KAAK,eAAe,YAAY;IAClD,IAAI,UAAU,KAAK,WAAW,QAAQ;IAEtC,MAAM,UAAmC;KACvC,QAAQ,KAAK;KACb,UAAU,KAAK;KACf,YAAY,KAAK;KACjB,SAAS,KAAK;KACd,OAAO,KAAK;IACd;IAEA,QAAQ,MAAM,MAAd;KACE,KAAK;MACH,QAAQ,YAAY,KAAK;MACzB,QAAQ,OAAO,KAAK;MACpB;KACF,KAAK;MACH,QAAQ,cAAc,KAAK;MAC3B,QAAQ,SAAS,KAAK;MACtB;KACF,KAAK;MACH,QAAQ,cAAc,KAAK;MAC3B,QAAQ,QAAQ,KAAK;MACrB;KACF,KAAK;MACH,QAAQ,cAAc,KAAK;MAC3B;KACF,KAAK;MACH,QAAQ,UAAU,KAAK;MACvB;KACF,KAAK;MACH,QAAQ,iBAAiB,KAAK;MAC9B,QAAQ,cAAc,KAAK;MAC3B,QAAQ,OAAO,KAAK;MACpB;KACF,KAAK;MACH,QAAQ,YAAY,KAAK;MACzB,QAAQ,OAAO,KAAK;MACpB;IACJ;IAEA,IAAI;KACF,WAAW,QAAQ;MACjB,MAAM,gBAAgB,MAAM;MAC5B;KACF,CAAC;IACH,QAAQ,CAER;GACF;GAEA,OAAY,UAAU,cAAc,OAAO;GAE3C,aAAa,iBAAiB,eAAe;IAC3C,OAAY,YAAY,cAAc,OAAO;IAC7C,IAAI;KACF,WAAW,MAAM;IACnB,QAAQ,CAER;GACF,CAAC;GAGD,IAAI;IACF,MAAM,UAAU,MAAM,QAAQ,WAAW;IACzC,IAAI,QAAQ;KACV,MAAM,OAAO,MAAM,QAAQ,QAAQ,MAAM;KACzC,IAAI,QAAQ,KAAK,WAAW,WAC1B,WAAW,QAAQ;MACjB,MAAM;MACN,SAAS;OACP,QAAQ,KAAK;OACb,UAAU,KAAK;OACf,YAAY,KAAK;OACjB,SAAS,KAAK;OACd,OAAO,KAAK;OACZ,WAAW,KAAK;OAChB,MAAM,KAAK;MACb;KACF,CAAC;IAEL,OAAO;KACL,MAAM,EAAE,OAAO,aAAa,MAAM,QAAQ,UAAU;MAClD;MACA;MACA;MACA;MACA,QAAQ,CAAC,SAAS;KACpB,CAAC;KAED,KAAK,MAAM,QAAQ,UAAU;MAC3B,IAAI,aAAa,SAAS;MAC1B,IAAI;OACF,WAAW,QAAQ;QACjB,MAAM;QACN,SAAS;SACP,QAAQ,KAAK;SACb,UAAU,KAAK;SACf,YAAY,KAAK;SACjB,SAAS,KAAK;SACd,OAAO,KAAK;SACZ,WAAW,KAAK;SAChB,MAAM,KAAK;QACb;OACF,CAAC;MACH,QAAQ;OACN;MACF;KACF;IACF;GACF,QAAQ,CAER;EACF,EACF,CAAC;CACH;CAEA,MAAM,WAA0B;EAC9B,KAAK,eAAe;EAEpB,IAAI,KAAK,iBAAiB;GACxB,cAAc,KAAK,eAAe;GAClC,KAAK,kBAAkB,KAAA;EACzB;EAEA,IAAI,KAAK,gBACP,MAAM,KAAK,OAAO,YAAY,gBAAgB,KAAK,cAAc;EAEnE,IAAI,KAAK,gBACP,MAAM,KAAK,OAAO,YAAY,cAAc,KAAK,cAAc;EAGjE,KAAK,aAAa,MAAM;EACxB,MAAM,KAAK,OAAO,MAAM;CAC1B;;;;;;;;;;;;;;CAiBA,MAAME,iCAAgD;EACpD,IAAI,CAAC,KAAKF,SAAS;EACnB,IAAI;GACF,MAAM,KAAKA,QAAQ,gCAAgC;EACrD,SAAS,KAAK;GACZ,KAAKA,QAAQ,YAAY,CAAC,EAAE,MAAM,yDAAyD,GAAU;EACvG;CACF;CAEA,MAAc,SAAS,MAAsB,WAAoC;EAC/E,MAAM,KAAKE,+BAA+B;EAK1C,MAAM,KAAK,OAAO,QAAQ,gBAAgB;GACxC,MAAM;GACN,MAAM;IACJ,QAAQ,KAAK;IACb,UAAU,KAAK;IACf,YAAY,KAAK;IACjB,MAAM,KAAK;IACX,SAAS,KAAK;IACd,UAAU,KAAK;IACf,YAAY,KAAK;IACjB,WAAW,KAAK;IAChB,YAAY,KAAK;IACjB,OAAO,KAAK;IACZ;GACF;GACA,OAAO,KAAK;EACd,CAAC;CACH;;;;;CAMA,MAAc,eAAe,OAA6B;EACxD,MAAM,EAAE,QAAQ,cAAc,MAAM;EACpC,MAAM,kBAAkB,MAAM,mBAAmB;EAEjD,MAAM,UAAU,MAAM,KAAK,WAAW;EACtC,MAAM,OAAO,MAAM,QAAQ,QAAQ,MAAM;EACzC,IAAI,CAAC,QAAQ,KAAK,WAAW,aAAa;GACxC,KAAK,sBAAsB,MAAM;GACjC;EACF;EAEA,IAAI,aAAa,KAAK,WAAW,WAI/B;EAGF,MAAM,QAAQ,WAAW,QAAQ;GAAE,QAAQ;GAAW,2BAAW,IAAI,KAAK;GAAG,YAAY,kBAAkB;EAAE,CAAC;EAG9G,MAAM,cAAc,MAAM,QAAQ,QAAQ,MAAM;EAChD,IAAI,aAAa,MAAM,KAAK,sBAAsB,gBAAgB,WAAW;EAK7E,IAAI,KAAKF,SAAS;GAChB,IAAI,aAAa,KAAU,sBAAsB,WAAW;GAC5D,MAAM,WAAW,KAAKA,QAAQ,sBAAsB,2BAA2B;GAC/E,MAAM,kBAAkB,YAAY,MAAM,SAAS,mBAAmB,MAAM,IAAI,KAAA;GAChF,MAAM,gBAAgB,aAAa,iBAAiB,WAAW;GAC/D,MAAM,MAAM,MAAM,SAAS,UAAU,EAAE,OAAO,OAAO,CAAC;GAEtD,CADmB,gBAAgB,IAAI,QAAQ,IAAI,IAAI,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,EAAA,CAEnF,MAAK,WAAU;IACd,IAAI,OAAO,WAAW,aACpB,SAAc,sBAAsB,MAAM;GAE9C,CAAC,CAAC,CACD,OAAM,QAAO;IACZ,KAAKA,SACD,YAAY,CAAC,EACb,MAAM,4BAA4B,gBAAgB,YAAY,QAAQ,cAAc,OAAO,IAAI,GAAG;GACxG,CAAC,CAAC,CACD,cAAc;IAEb,KAAU,aAAa;GACzB,CAAC;EACL;CACF;;;;;;;;CASA,MAAc,aAAa,OAA6B;EACtD,MAAM,EAAE,QAAQ,eAAe,MAAM;EAErC,MAAM,UAAU,MAAM,KAAK,WAAW;EACtC,MAAM,OAAO,MAAM,QAAQ,QAAQ,MAAM;EACzC,IAAI,CAAC,QAAQ,KAAK,WAAW,aAI3B;EAGF,MAAM,QAAQ,WAAW,QAAQ;GAC/B,QAAQ;GACR,2BAAW,IAAI,KAAK;GACpB,gBAAgB,KAAA;GAChB,aAAa,KAAA;EACf,CAAC;EACD,MAAM,cAAc,MAAM,QAAQ,QAAQ,MAAM;EAChD,IAAI,aACF,MAAM,KAAK,sBAAsB,gBAAgB,WAAW;EAG9D,IAAI,CAAC,KAAKA,SAAS;EACnB,MAAM,WAAW,KAAKA,QAAQ,sBAAsB,2BAA2B;EAI/E,CAAK,MADa,SAAS,UAAU,EAAE,OAAO,OAAO,CAAC,EAAA,CAEnD,OAAO,EAAE,WAAW,CAAC,CAAC,CACtB,MAAK,WAAU;GACd,IAAI,OAAO,WAAW,aACpB,SAAc,sBAAsB,MAAM;EAE9C,CAAC,CAAC,CACD,OAAM,QAAO;GACZ,KAAKA,SAAS,YAAY,CAAC,EAAE,MAAM,8CAA8C,OAAO,IAAI,GAAG;EACjG,CAAC,CAAC,CACD,cAAc;GAEb,KAAU,aAAa;EACzB,CAAC;CACL;;;;;;;;;;;;;;;;;;;;;CAsBA,MAAM,wBACJ,MACA,QACA,QACe;EACf,MAAM,MAAM,KAAK,aAAa,IAAI,KAAK,EAAE;EACzC,IAAI,CAAC,KAAK;EAEV,IAAI;GACF,IAAI,WAAW,aAAa;IAC1B,IAAI,UAAU;KACZ,MAAM;KACN,SAAS;MACP,QAAQ,KAAK;MACb,UAAU,KAAK;MACf,YAAY,KAAK;MACjB,OAAO,KAAK;MACZ,QAAQ,OAAO;MACf,aAAa,KAAK;MAClB,SAAS,KAAK;KAChB;IACF,CAAC;IAED,MAAM,IAAI,WAAW;KACnB,OAAO,KAAK;KACZ,QAAQ,KAAK;KACb,YAAY,KAAK;KACjB,UAAU,KAAK;KACf,SAAS,KAAK;KACd,UAAU,KAAK;KACf,YAAY,KAAK;KACjB,QAAQ,OAAO;KACf,QAAQ;KACR,aAAa,KAAK;KAClB,WAAW,KAAK;IAClB,CAAC;IAMD,MAAM,IAAI,aAAa,IAAI;GAC7B,OAAO;IACL,IAAI,UAAU;KACZ,MAAM;KACN,SAAS;MACP,QAAQ,KAAK;MACb,UAAU,KAAK;MACf,YAAY,KAAK;MACjB,OAAO,KAAK;MACZ,OAAO,OAAO,SAAS,EAAE,SAAS,gBAAgB;MAClD,aAAa,KAAK;MAClB,SAAS,KAAK;KAChB;IACF,CAAC;IAED,MAAM,IAAI,WAAW;KACnB,OAAO,KAAK;KACZ,QAAQ,KAAK;KACb,YAAY,KAAK;KACjB,UAAU,KAAK;KACf,SAAS,KAAK;KACd,UAAU,KAAK;KACf,YAAY,KAAK;KACjB,OAAO,OAAO;KACd,QAAQ;KACR,aAAa,KAAK;KAClB,WAAW,KAAK;IAClB,CAAC;IAID,MAAM,IAAI,WAAW,IAAI;GAC3B;EACF,UAAU;GACR,KAAK,sBAAsB,KAAK,EAAE;EACpC;CACF;;;;;;;;;CAUA,MAAM,qBAAqB,MAAqC;EAC9D,MAAM,MAAM,KAAK,aAAa,IAAI,KAAK,EAAE;EACzC,IAAI,CAAC,KAAK;EACV,MAAM,IAAI,cAAc;GACtB,OAAO,KAAK;GACZ,QAAQ,KAAK;GACb,YAAY,KAAK;GACjB,UAAU,KAAK;GACf,SAAS,KAAK;GACd,UAAU,KAAK;GACf,YAAY,KAAK;GACjB,WAAW,KAAK;GAChB,aAAa,KAAK;EACpB,CAAC;CACH;;CAGA,MAAM,sBAAsB,MAAqC;EAC/D,MAAM,MAAM,KAAK,aAAa,IAAI,KAAK,EAAE;EACzC,IAAI,CAAC,KAAK;EAEV,IAAI;GACF,MAAM,IAAI,cAAc;IACtB,OAAO,KAAK;IACZ,QAAQ,KAAK;IACb,YAAY,KAAK;IACjB,UAAU,KAAK;IACf,SAAS,KAAK;IACd,UAAU,KAAK;IACf,YAAY,KAAK;IACjB,WAAW,KAAK;GAClB,CAAC;EACH,QAAQ,CAER;CACF;CAEA,MAAc,aAAa,OAA6B;EACtD,MAAM,EAAE,QAAQ,UAAU,YAAY,UAAU,YAAY,UAAU,MAAM;EAE5E,MAAM,OAAO,OAAM,MADG,KAAK,WAAW,EAAA,CACX,QAAQ,MAAM;EAEzC,IAAI,MAAM,aAAa;GAErB,MAAM,MAAM,KAAK,aAAa,IAAI,MAAM;GAExC,IAAI,MAAM,SAAS,kBAAkB;IACnC,KAAK,UAAU;KACb,MAAM;KACN,SAAS;MACP;MACA;MACA;MACA;MACA,QAAQ,MAAM,KAAK;MACnB,aAAa,KAAK;MAClB,SAAS,KAAK;KAChB;IACF,CAAC;IAED,MAAM,KAAK,WAAW;KACpB;KACA;KACA;KACA;KACA,SAAS,MAAM,KAAK;KACpB;KACA;KACA,QAAQ,MAAM,KAAK;KACnB,QAAQ;KACR,aAAa,KAAK;KAClB,WAAW,KAAK;IAClB,CAAC;IAED,IAAI,MACF,MAAM,QAAQ,IAAI,CAAC,KAAK,aAAa,IAAI,GAAG,KAAK,OAAO,iBAAiB,IAAI,CAAC,CAAC;GAEnF;GAEA,IAAI,MAAM,SAAS,eAAe;IAChC,KAAK,UAAU;KACb,MAAM;KACN,SAAS;MACP;MACA;MACA;MACA;MACA,OAAO,MAAM,KAAK;MAClB,aAAa,KAAK;MAClB,SAAS,KAAK;KAChB;IACF,CAAC;IAED,MAAM,KAAK,WAAW;KACpB;KACA;KACA;KACA;KACA,SAAS,MAAM,KAAK;KACpB;KACA;KACA,OAAO,MAAM,KAAK;KAClB,QAAQ;KACR,aAAa,KAAK;KAClB,WAAW,KAAK;IAClB,CAAC;IAED,IAAI,MACF,MAAM,QAAQ,IAAI,CAAC,KAAK,WAAW,IAAI,GAAG,KAAK,OAAO,eAAe,IAAI,CAAC,CAAC;GAE/E;GAGA,KAAK,sBAAsB,MAAM;EACnC;CACF;CAEA,aAAqB,OAAoB;EACvC,MAAM,EAAE,WAAW,MAAM;EACzB,MAAM,aAAa,KAAK,uBAAuB,IAAI,MAAM;EACzD,IAAI,YAAY;GACd,WAAW,sBAAM,IAAI,MAAM,gBAAgB,CAAC;GAC5C,KAAK,uBAAuB,OAAO,MAAM;EAC3C;EACA,KAAK,sBAAsB,MAAM;CACnC;;CAGA,MAAM,sBACJ,MAQA,MACe;EACf,MAAM,KAAK,OAAO,QAAQ,cAAc;GACtC;GACA,MAAM;IACJ,QAAQ,KAAK;IACb,UAAU,KAAK;IACf,YAAY,KAAK;IACjB,OAAO,KAAK;IACZ,SAAS,KAAK;IACd,UAAU,KAAK;IACf,YAAY,KAAK;IACjB,MAAM,KAAK;IACX,QAAQ,KAAK;IACb,OAAO,KAAK;IACZ,OAAO,KAAK;IACZ,aAAa,KAAK;IAClB,WAAW,KAAK;IAChB,gBAAgB,KAAK;IACrB,aAAa,KAAK;GACpB;GACA,OAAO,KAAK;EACd,CAAC;CACH;CAEA,MAAc,iBAAiB,SAAmC;EAChE,MAAM,UAAU,MAAM,KAAK,WAAW;EAEtC,IAAI,MADwB,QAAQ,gBAAgB,KAC/B,KAAK,OAAO,mBAC/B,OAAO;EAIT,IAAI,MADuB,QAAQ,uBAAuB,OAAO,KAC7C,KAAK,OAAO,qBAC9B,OAAO;EAGT,OAAO;CACT;CAEA,MAAc,eAA8B;EAE1C,MAAM,EAAE,OAAO,YAAY,OAAM,MADX,KAAK,WAAW,EAAA,CACG,UAAU;GACjD,QAAQ;GACR,SAAS;GACT,gBAAgB;EAClB,CAAC;EAED,KAAK,MAAM,QAAQ,SACjB,IAAI,MAAM,KAAK,iBAAiB,KAAK,OAAO,GAC1C,MAAM,KAAK,SAAS,IAAI;CAG9B;;;;CAKA,MAAc,oBAAmC;EAC/C,IAAI;GACF,MAAM,UAAU,MAAM,KAAK,WAAW;GACtC,MAAM,EAAE,OAAO,eAAe,MAAM,QAAQ,UAAU,EAAE,QAAQ,UAAU,CAAC;GAC3E,KAAK,MAAM,QAAQ,YACjB,IAAI,KAAK,aAAa,GACpB,MAAM,QAAQ,WAAW,KAAK,IAAI;IAChC,QAAQ;IACR,WAAW,KAAA;GACb,CAAC;QAED,MAAM,QAAQ,WAAW,KAAK,IAAI;IAChC,QAAQ;IACR,OAAO,EAAE,SAAS,kDAAkD;IACpE,6BAAa,IAAI,KAAK;GACxB,CAAC;GAIL,MAAM,EAAE,OAAO,iBAAiB,MAAM,QAAQ,UAAU;IACtD,QAAQ;IACR,SAAS;IACT,gBAAgB;GAClB,CAAC;GACD,KAAK,MAAM,QAAQ,cACjB,IAAI,MAAM,KAAK,iBAAiB,KAAK,OAAO,GAC1C,MAAM,KAAK,SAAS,IAAI;EAG9B,SAAS,OAAO;GACd,MAAM,SAAS,KAAKA,SAAS,UAAU;GACvC,IAAI,QACF,OAAO,MAAM,4CAA4C,KAAK;EAElE;CACF;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrrCA,SAAgB,qBACd,SACA,SACsB;CACtB,MAAM,EAAE,SAAS,GAAG,YAAY;CAChC,IAAI;CAEJ,OAAO;EACL,IAAI,OAAO;GACT,IAAI,CAAC,QAAQ,MAAM,IAAI,MAAM,kCAAkC;GAE/D,OAAO,EAAE,IAAI,OAAO;EACtB;EAEA,MAAM,WAAW;GACf,MAAM,SAAS,MAAM,QAAQ,QAAQ,SAAS,OAAO;GACrD,SAAS,OAAO,KAAK;GACrB,OAAO;EACT;EAEA,MAAM,iBAAiB,MAA+B;GACpD,MAAM,SAAS,MAAM,QAAQ,UAAU;IACrC,YAAY,KAAK;IACjB,OAAO,KAAK;IACZ,SAAS,KAAK;IACd,UAAU,KAAK;IACf,YAAY,KAAK;IACjB,UAAU,KAAK;IACf,QAAQ;GACV,CAAC;GACD,IAAI,OAAO,QAAQ,GAAG;IACpB,MAAM,OAAO,OAAO,MAAM;IAC1B,IAAI,MAAM;KACR,SAAS,KAAK;KACd,OAAO;IACT;GACF;GAEA,OAAO;EACT;EAEA,MAAM,eAAe,MAA6B;GAChD,MAAM,SAAS,MAAM,QAAQ,UAAU;IACrC,YAAY,KAAK;IACjB,OAAO,KAAK;IACZ,SAAS,KAAK;IACd,UAAU,KAAK;IACf,YAAY,KAAK;IACjB,UAAU,KAAK;IACf,QAAQ;GACV,CAAC;GACD,IAAI,OAAO,QAAQ,GAAG;IACpB,MAAM,OAAO,OAAO,MAAM;IAC1B,IAAI,MAAM;KACR,SAAS,KAAK;KACd,OAAO;IACT;GACF;GAEA,OAAO;EACT;EAEA,MAAM,OAAO,YAAsB;GACjC,IAAI,CAAC,QAAQ,MAAM,IAAI,MAAM,kCAAkC;GAC/D,OAAO,QAAQ,OAAO,QAAQ,UAAU;EAC1C;EAEA,MAAM,UAAU;GACd,IAAI,CAAC,QAAQ,MAAM,IAAI,MAAM,kCAAkC;GAC/D,OAAO,QAAQ,QAAQ,QAAQ,OAAO;EACxC;EAEA,MAAM,SAAS;GACb,IAAI,CAAC,QAAQ,MAAM,IAAI,MAAM,kCAAkC;GAC/D,OAAO,QAAQ,OAAO,MAAM;EAC9B;EAEA,MAAM,kBAAkB,aAAa;GACnC,IAAI,CAAC,QAAQ,MAAM,IAAI,MAAM,kCAAkC;GAC/D,OAAO,QAAQ,gBAAgB,CAAC,MAAM,GAAG,WAAW;EACtD;CACF;AACF;;;;;;;;;;;;;;AC3FA,SAAgB,wBAAwB,EACtC,gBACA,UACA,YACA,aACA,iBAO2B;CAC3B,MAAM,cAAc;CAMpB,IAAI,aAAa,UACf,OAAO;EACL,iBAAiB;EACjB,WAAW,eAAe,oBAAoB;EAC9C,YAAY,eAAe,gBAAgB,cAAc;CAC3D;CAIF,MAAM,kBAAkB,uBAAuB,UAAU,WAAW;CAuBpE,OAAO;EAAE,iBAfW,iBAAiB,WAAW,YAAY,WAAW,QACxC,aAAa,WAAW,OAAQ;EAc5B,WAVjC,aAAa,aACb,iBAAiB,aACjB,YAAY,aACZ,eAAe,oBACf;EAM4C,YAF5C,aAAa,cAAc,YAAY,cAAc,eAAe,gBAAgB,cAAc;CAE3C;AAC3D;AAEA,SAAS,uBACP,UACA,aACsD;CACtD,IAAI,CAAC,aAAa,OAAO,OAAO,KAAA;CAEhC,IAAI,YAAY,UAAU,OACxB,OAAO,EAAE,SAAS,KAAK;CAGzB,IAAI,SAAS,WAAW,QAAQ,GAC9B,WAAW,SAAS,UAAU,CAAe;MACxC,IAAI,SAAS,WAAW,WAAW,GACxC,WAAW,SAAS,UAAU,CAAkB;CAGlD,MAAM,QAA+C,YAAY,MAAM;CACvE,IAAI,UAAU,KAAA,GAAW,OAAO,KAAA;CAChC,IAAI,OAAO,UAAU,WAAW,OAAO,EAAE,SAAS,MAAM;CACxD,OAAO;AACT;;;;;;;AC7FA,MAAa,+BAA+B;CAC1C,MAAM;CACN,aACE;CAGF,YAAY;EACV,SAAS;GACP,MAAM;GACN,aAAa;EACf;EACA,WAAW;GACT,MAAM;GACN,aAAa;EACf;EACA,YAAY;GACV,MAAM;GACN,aAAa;EACf;CACF;CACA,sBAAsB;AACxB;AAEA,MAAa,8BAA8BG,OAAAA,EACxC,OAAO;CACN,SAASA,OAAAA,EAAE,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,wEAAwE;CACjH,WAAWA,OAAAA,EAAE,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,iDAAiD;CAC3F,YAAYA,OAAAA,EAAE,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,gDAAgD;AAC7F,CAAC,CAAC,CACD,SAAS,CAAC,CACV,SACC,mMACF;;;;;;;;ACxBF,SAAgB,mCACd,OACA,aACoB;CACpB,MAAM,gBAA6B,CAAC;CAEpC,MAAM,YAAY,aAAa,UAAU;CAEzC,KAAK,MAAM,CAAC,UAAU,SAAS,OAAO,QAAQ,KAAK,GAAG;EACpD,MAAM,2BACJ,aAAa,UAAU,QACnB,QACA,OAAO,aAAa,QAAQ,cAAc,YACxC,YAAY,MAAM,YACjB,aAAa,QAAQ,SAAS,EAAE,WAAW;EACpD,cAAc,KAAK;GACjB;GACA,YAAY,KAAK;GACjB,mBAAmB,YAAY,OAAQ,4BAA4B,KAAK,YAAY,WAAW;EACjG,CAAC;CACH;CAEA,IAAI,cAAc,WAAW,GAC3B;CAOF,OAAO;EAJW,cACf,KAAI,MAAK,KAAK,EAAE,SAAS,aAAa,EAAE,oBAAoB,eAAe,aAAa,EAAE,CAAC,CAC3F,KAAK,IAGA,EAAE;;;;;;;;;;;;;;AAcZ"}
|
|
1
|
+
{"version":3,"file":"background-tasks-CobPW4Z3.cjs","names":["#mastra","#doInit","#ensureExecutionWorkersStarted","z"],"sources":["../src/background-tasks/workflow-id.ts","../src/background-tasks/manager.ts","../src/background-tasks/create.ts","../src/background-tasks/resolve-config.ts","../src/background-tasks/schema-injection.ts","../src/background-tasks/system-prompt.ts"],"sourcesContent":["/**\n * Workflow id used by the bg-task workflow registered on Mastra.\n * Double-underscore prefix marks it as internal — same convention as\n * `__batch-scoring-traces`.\n *\n * Lives in its own file (separate from `./workflow`) so `manager.ts` can\n * reference the id without statically pulling in `../workflows/evented`,\n * which would create a circular import via `agent → background-tasks →\n * workflow → evented → workflows/index → agent`.\n */\nexport const BACKGROUND_TASK_WORKFLOW_ID = '__background-task';\n","import { randomUUID } from 'node:crypto';\nimport type { Mastra } from '..';\nimport type { PubSub } from '../events/pubsub';\nimport type { Event, EventCallback } from '../events/types';\nimport type {\n BackgroundTask,\n BackgroundTaskManagerConfig,\n BackgroundTaskStatus,\n EnqueueResult,\n TaskContext,\n TaskFilter,\n TaskPayload,\n TaskListResult,\n ToolExecutor,\n BackgroundTaskEvent,\n} from './types';\nimport { BACKGROUND_TASK_WORKFLOW_ID } from './workflow-id';\n\nconst TOPIC_DISPATCH = 'background-tasks';\nconst TOPIC_RESULT = 'background-tasks-result';\nconst WORKER_GROUP = 'background-task-workers';\n\nexport class BackgroundTaskManager {\n private pubsub!: PubSub;\n config: Required<\n Pick<BackgroundTaskManagerConfig, 'globalConcurrency' | 'perAgentConcurrency' | 'backpressure' | 'defaultTimeoutMs'>\n > &\n BackgroundTaskManagerConfig;\n\n #mastra?: Mastra;\n\n // Per-task contexts — keyed by task ID, holds closures from the caller's stream.\n /** @internal — read by the workflow-engine step bodies in workflow.ts */\n taskContexts: Map<string, TaskContext> = new Map();\n\n // Static executors keyed by tool name. Populated by `Mastra` for every\n // registered tool, and by `BackgroundTaskWorker.#wireStaticTools` on\n // standalone worker processes. Used as the fallback for cross-process\n // dispatch where the producer's per-task closure (taskContexts) is not\n // visible — a remote worker resolves the tool by name instead.\n private staticExecutors: Map<string, ToolExecutor> = new Map();\n\n // Track active AbortControllers for running tasks (for cancellation + timeout)\n /** @internal — read by the workflow-engine step bodies in workflow.ts */\n activeAbortControllers: Map<string, AbortController> = new Map();\n\n // Pubsub callbacks (kept for unsubscribe)\n private workerCallback?: EventCallback;\n private resultCallback?: EventCallback;\n\n private shuttingDown = false;\n\n // Cleanup interval handle\n private cleanupInterval?: ReturnType<typeof setInterval>;\n\n // Tracks the in-flight `init(pubsub)` so consumers can await readiness.\n // Mastra fires init as fire-and-forget in `#ensureBackgroundTaskManager`,\n // so without this any caller that hits `enqueue`/`resume`/`cancel`\n // before init completes races against worker subscription + workflow\n // registration. Public methods that depend on init await this promise\n // before doing work.\n private initPromise?: Promise<void>;\n\n constructor(config: BackgroundTaskManagerConfig = { enabled: false }) {\n this.config = {\n globalConcurrency: config.globalConcurrency ?? 10,\n perAgentConcurrency: config.perAgentConcurrency ?? 5,\n backpressure: config.backpressure ?? 'queue',\n defaultTimeoutMs: config.defaultTimeoutMs ?? 300_000,\n ...config,\n };\n }\n\n __registerMastra(mastra: Mastra) {\n this.#mastra = mastra;\n }\n\n async getStorage() {\n const storage = this.#mastra?.getStorage();\n if (!storage) {\n throw new Error('Storage is not initialized');\n }\n const bgStore = await storage.getStore('backgroundTasks');\n if (!bgStore) {\n throw new Error('Background tasks storage is not available');\n }\n return bgStore;\n }\n\n async init(pubsub: PubSub): Promise<void> {\n if (this.initPromise) return this.initPromise;\n this.initPromise = this.#doInit(pubsub);\n return this.initPromise;\n }\n\n async #doInit(pubsub: PubSub): Promise<void> {\n this.pubsub = pubsub;\n\n const isProducerOnly = this.config.mode === 'producer';\n\n // Result listener: fan-out so all processes receive results.\n // Both producer and worker modes need this — the producer uses it\n // to receive completion/failure notifications for dispatched tasks.\n this.resultCallback = async (event: Event, ack?: () => Promise<void>) => {\n if (event.type === 'task.completed' || event.type === 'task.failed') {\n await this.handleResult(event);\n }\n await ack?.();\n };\n\n if (!isProducerOnly) {\n // Worker: subscribes with group so only one worker processes each task.\n this.workerCallback = async (event: Event, ack?: () => Promise<void>) => {\n if (event.type === 'task.dispatch' || event.type === 'task.restart') {\n await this.handleDispatch(event);\n } else if (event.type === 'task.resume') {\n await this.handleResume(event);\n } else if (event.type === 'task.cancel') {\n this.handleCancel(event);\n }\n await ack?.();\n };\n\n // Register the workflow BEFORE subscribing the worker so that any\n // dispatch event the worker picks up can immediately resolve the\n // workflow on Mastra. Reversing this order races: a publish that\n // arrives between `subscribe(TOPIC_DISPATCH)` and the workflow\n // registration triggers `__getInternalWorkflow` to throw\n // `Workflow with id __background-task not found`, the task stays at\n // `running` forever, and the dispatch is silently dropped.\n if (this.#mastra) {\n // Dynamic import breaks the static cycle:\n // agent → background-tasks → manager → workflow → workflows/evented →\n // workflows/index → agent. Static import works at runtime but during\n // module evaluation in test environments the cycle leaves `Workflow`\n // undefined when `evented/workflow.ts` evaluates its `class extends`.\n const { buildBackgroundTaskWorkflow } = await import('./workflow');\n const workflow = buildBackgroundTaskWorkflow(this);\n if (!this.#mastra.__hasInternalWorkflow(BACKGROUND_TASK_WORKFLOW_ID)) {\n // The `__background-task` workflow is typed against `EventedEngineType`\n // and a concrete input/output schema, while `__registerInternalWorkflow`\n // accepts the looser default `Workflow` shape. The cast is purely a\n // type-level bridge — the runtime value is a real Workflow.\n this.#mastra.__registerInternalWorkflow(\n workflow as unknown as Parameters<Mastra['__registerInternalWorkflow']>[0],\n );\n }\n }\n\n await this.pubsub.subscribe(TOPIC_DISPATCH, this.workerCallback, { group: WORKER_GROUP });\n }\n\n await this.pubsub.subscribe(TOPIC_RESULT, this.resultCallback);\n\n if (!isProducerOnly) {\n // Recover stale tasks from a previous process — only workers should\n // attempt recovery since they own execution.\n await this.recoverStaleTasks();\n }\n\n // Start periodic cleanup if configured\n const cleanupConfig = this.config.cleanup;\n if (cleanupConfig) {\n const intervalMs = cleanupConfig.cleanupIntervalMs ?? 60_000;\n this.cleanupInterval = setInterval(() => {\n void this.cleanup();\n }, intervalMs);\n }\n }\n\n // --- Per-task context registration ---\n\n /**\n * Register per-task hooks (executor, stream emitter, result injector).\n * Called internally by createBackgroundTask or directly for advanced usage.\n */\n registerTaskContext(taskId: string, context: TaskContext): void {\n this.taskContexts.set(taskId, context);\n }\n\n /**\n * Remove per-task hooks. Called after task reaches terminal state.\n */\n deregisterTaskContext(taskId: string): void {\n this.taskContexts.delete(taskId);\n }\n\n /**\n * Register a tool executor by tool name. Used for cross-process dispatch:\n * when a worker in a different process picks up a `task.dispatch` event,\n * it has no per-task closure (`taskContexts`) for that taskId, but it can\n * resolve the executor by tool name via this registry.\n */\n registerStaticExecutor(toolName: string, executor: ToolExecutor): void {\n if (this.staticExecutors.has(toolName)) {\n this.#mastra?.getLogger?.()?.debug?.(`Overwriting existing static executor for tool \"${toolName}\"`);\n }\n this.staticExecutors.set(toolName, executor);\n }\n\n /**\n * Symmetric to `registerStaticExecutor`. Called when a tool is removed\n * from `Mastra`.\n */\n unregisterStaticExecutor(toolName: string): void {\n this.staticExecutors.delete(toolName);\n }\n\n /**\n * Look up an executor by tool name. Read by the workflow-step body in\n * `workflow.ts:runAttemptStep` as a fallback when no per-task `TaskContext`\n * is registered (cross-process path).\n */\n getStaticExecutor(toolName: string): ToolExecutor | undefined {\n return this.staticExecutors.get(toolName);\n }\n\n // --- Core operations ---\n\n /**\n * Enqueue a task for background execution.\n * Prefer `createBackgroundTask()` which returns a self-contained handle.\n */\n async enqueue(payload: TaskPayload, context?: TaskContext): Promise<EnqueueResult> {\n if (this.shuttingDown) {\n throw new Error('BackgroundTaskManager is shutting down, cannot enqueue new tasks');\n }\n\n // Mastra fires `init` as fire-and-forget. If a caller hits enqueue\n // before init completes, the dispatch publish fires before the worker\n // subscribes and the event is dropped (or, worse, lands on a worker\n // whose Mastra hasn't yet registered the bg-task workflow → \"Workflow\n // with id __background-task not found\"). Await readiness up front.\n if (this.initPromise) await this.initPromise;\n\n const task: BackgroundTask = {\n id: this.#mastra?.generateId() ?? randomUUID(),\n status: 'pending',\n toolName: payload.toolName,\n toolCallId: payload.toolCallId,\n args: payload.args,\n agentId: payload.agentId,\n threadId: payload.threadId,\n resourceId: payload.resourceId,\n runId: payload.runId,\n retryCount: 0,\n maxRetries: payload.maxRetries ?? this.config.defaultRetries?.maxRetries ?? 0,\n timeoutMs: payload.timeoutMs ?? this.config.defaultTimeoutMs,\n createdAt: new Date(),\n };\n\n // Register per-task context if provided\n if (context) {\n this.registerTaskContext(task.id, context);\n }\n\n const storage = await this.getStorage();\n await storage.createTask(task);\n\n const canRun = await this.checkConcurrency(task.agentId);\n\n if (canRun) {\n await this.dispatch(task);\n return { task };\n }\n\n // Backpressure\n switch (this.config.backpressure) {\n case 'reject':\n this.deregisterTaskContext(task.id);\n await storage.deleteTask(task.id);\n throw new Error(`Concurrency limit reached, cannot enqueue task for tool \"${task.toolName}\"`);\n\n case 'fallback-sync':\n this.deregisterTaskContext(task.id);\n await storage.deleteTask(task.id);\n return { task, fallbackToSync: true };\n\n case 'queue':\n default:\n // Task stays pending in storage, will be dispatched when a slot opens\n return { task };\n }\n }\n\n async cancel(taskId: string): Promise<void> {\n if (this.initPromise) await this.initPromise;\n const storage = await this.getStorage();\n const task = await storage.getTask(taskId);\n if (!task) {\n throw new Error(`Task not found: ${taskId}`);\n }\n\n if (\n task.status === 'completed' ||\n task.status === 'failed' ||\n task.status === 'cancelled' ||\n task.status === 'timed_out'\n ) {\n return; // no-op for terminal states\n }\n\n if (task.status === 'pending') {\n await storage.updateTask(taskId, { status: 'cancelled', completedAt: new Date() });\n const cancelledTask = await storage.getTask(taskId);\n if (cancelledTask) await this.publishLifecycleEvent('task.cancelled', cancelledTask);\n this.deregisterTaskContext(taskId);\n return;\n }\n\n if (task.status === 'suspended') {\n // No active executor or AbortController to tear down — the task is\n // sitting on a workflow snapshot. Flip storage, publish, and tell the\n // workflow run to cancel so the snapshot is cleaned up too.\n await storage.updateTask(taskId, { status: 'cancelled', completedAt: new Date() });\n if (this.#mastra) {\n try {\n const workflow = this.#mastra.__getInternalWorkflow(BACKGROUND_TASK_WORKFLOW_ID);\n const wrapper = await workflow.createRun({ runId: taskId });\n await wrapper.cancel();\n } catch (err) {\n this.#mastra?.getLogger?.()?.warn(`background-task workflow cancel failed for ${taskId}:`, err as any);\n }\n }\n const cancelledTask = await storage.getTask(taskId);\n if (cancelledTask) await this.publishLifecycleEvent('task.cancelled', cancelledTask);\n this.deregisterTaskContext(taskId);\n return;\n }\n\n if (task.status === 'running') {\n await storage.updateTask(taskId, { status: 'cancelled', completedAt: new Date() });\n\n // Abort the running tool\n const controller = this.activeAbortControllers.get(taskId);\n if (controller) {\n controller.abort(new Error('Task cancelled'));\n this.activeAbortControllers.delete(taskId);\n }\n\n // Also cancel the workflow run so workflow storage reflects the\n // cancellation (run status flips to 'canceled' and the workflow's\n // abortSignal fires — redundant with the local AbortController above\n // but keeps run history clean and propagates cross-process via the\n // workflow.cancel pubsub event).\n if (this.#mastra) {\n try {\n const workflow = this.#mastra.__getInternalWorkflow(BACKGROUND_TASK_WORKFLOW_ID);\n const wrapper = await workflow.createRun({ runId: taskId });\n await wrapper.cancel();\n } catch (err) {\n this.#mastra?.getLogger?.()?.warn(`background-task workflow cancel failed for ${taskId}:`, err as any);\n }\n }\n\n const cancelledTask = await storage.getTask(taskId);\n if (cancelledTask) await this.publishLifecycleEvent('task.cancelled', cancelledTask);\n this.deregisterTaskContext(taskId);\n\n // Also publish cancel on dispatch topic for distributed worker abort\n await this.pubsub.publish(TOPIC_DISPATCH, {\n type: 'task.cancel',\n data: { taskId },\n runId: taskId,\n });\n }\n }\n\n /**\n * Resume a suspended task. The tool executor must be re-registered via\n * `registerTaskContext(taskId, ...)` before calling this if the original\n * registration is gone (e.g. process restart) — the manager doesn't\n * rehydrate executor closures from storage.\n *\n * `resumeData` is forwarded to the tool's `execute` options on the\n * resumed run.\n */\n async resume(taskId: string, resumeData?: unknown): Promise<BackgroundTask> {\n if (!this.#mastra) {\n throw new Error('Mastra is not registered with this manager');\n }\n\n if (this.initPromise) await this.initPromise;\n\n const storage = await this.getStorage();\n const task = await storage.getTask(taskId);\n if (!task) {\n throw new Error(`Task not found: ${taskId}`);\n }\n if (task.status !== 'suspended') {\n throw new Error(`Cannot resume task in status '${task.status}' (expected 'suspended')`);\n }\n\n const canRun = await this.checkConcurrency(task.agentId);\n if (!canRun) {\n // Resume sits outside the queue/fallback-sync paths — there's no\n // synchronous caller to fall back to, and silently leaving the task\n // suspended hides the failure from the caller. Throw and let the\n // caller retry once a slot frees.\n throw new Error(`Concurrency limit reached, cannot resume task \"${taskId}\" — retry once a slot is available`);\n }\n\n // Resume publishes directly (not via dispatch()), so it needs its own\n // lazy worker start for the library-mode process-restart case.\n await this.#ensureExecutionWorkersStarted();\n\n // Hand off to the worker subscriber. `task.resume` rides the same\n // `TOPIC_DISPATCH` + `WORKER_GROUP` exactly-once channel as\n // `task.dispatch`, so any worker (including a different process from\n // the one that suspended the task) can pick it up.\n await this.pubsub.publish(TOPIC_DISPATCH, {\n type: 'task.resume',\n data: { taskId, resumeData },\n runId: taskId,\n });\n\n return task;\n }\n\n /**\n * Restarts a previously running task. The tool executor is re-registered via\n * `registerTaskContext(taskId, ...)` because the original\n * registration is gone (e.g. process restart) — the manager doesn't\n * rehydrate executor closures from storage.\n *\n */\n async restart(taskId: string, context?: TaskContext): Promise<BackgroundTask> {\n if (!this.#mastra) {\n throw new Error('Mastra is not registered with this manager');\n }\n\n if (this.initPromise) await this.initPromise;\n\n const storage = await this.getStorage();\n const task = await storage.getTask(taskId);\n if (!task) {\n throw new Error(`Task not found: ${taskId}`);\n }\n if (task.status !== 'running') {\n throw new Error(`Cannot restart task in status '${task.status}' (expected 'running')`);\n }\n\n if (context) {\n this.registerTaskContext(task.id, context);\n }\n\n const canRun = await this.checkConcurrency(task.agentId);\n if (!canRun) {\n // Restart sits outside the queue/fallback-sync paths — there's no\n // synchronous caller to fall back to, and silently leaving the task\n // running hides the failure from the caller. Throw and let the\n // caller retry once a slot frees.\n throw new Error(`Concurrency limit reached, cannot restart task \"${taskId}\" — retry once a slot is available`);\n }\n\n await this.dispatch(task, true);\n\n return task;\n }\n\n async getTask(taskId: string): Promise<BackgroundTask | null> {\n const storage = await this.getStorage();\n return storage.getTask(taskId);\n }\n\n async listTasks(filter: TaskFilter = {}): Promise<TaskListResult> {\n const storage = await this.getStorage();\n return storage.listTasks(filter);\n }\n\n /**\n * Deletes old completed/failed/cancelled/timed_out task records from storage.\n */\n async cleanup(): Promise<void> {\n const completedTtlMs = this.config.cleanup?.completedTtlMs ?? 3_600_000;\n const failedTtlMs = this.config.cleanup?.failedTtlMs ?? 86_400_000;\n const now = Date.now();\n\n const storage = await this.getStorage();\n await storage.deleteTasks({\n status: ['completed'],\n toDate: new Date(now - completedTtlMs),\n dateFilterBy: 'completedAt',\n });\n\n await storage.deleteTasks({\n status: ['failed', 'cancelled', 'timed_out'],\n toDate: new Date(now - failedTtlMs),\n dateFilterBy: 'completedAt',\n });\n }\n\n /**\n * Returns a promise that resolves when the next task from the given set\n * reaches a terminal state.\n */\n async waitForNextTask(\n taskIds: string[],\n options?: {\n timeoutMs?: number;\n onProgress?: (elapsedMs: number) => void;\n progressIntervalMs?: number;\n },\n ): Promise<BackgroundTask> {\n const storage = await this.getStorage();\n\n const isTerminal = (status: string) =>\n status === 'completed' || status === 'failed' || status === 'cancelled' || status === 'timed_out';\n\n for (const id of taskIds) {\n const task = await storage.getTask(id);\n if (task && isTerminal(task.status)) {\n return task;\n }\n }\n\n return new Promise((resolve, reject) => {\n const startTime = Date.now();\n\n const timeout = options?.timeoutMs\n ? setTimeout(() => {\n clearInterval(pollInterval);\n if (progressInterval) clearInterval(progressInterval);\n reject(new Error('Timed out waiting for background task'));\n }, options.timeoutMs)\n : undefined;\n\n const progressInterval = options?.onProgress\n ? setInterval(() => {\n options.onProgress!(Date.now() - startTime);\n }, options.progressIntervalMs ?? 3000)\n : undefined;\n\n const pollInterval = setInterval(async () => {\n for (const id of taskIds) {\n const task = await storage.getTask(id);\n if (task && isTerminal(task.status)) {\n clearInterval(pollInterval);\n if (timeout) clearTimeout(timeout);\n if (progressInterval) clearInterval(progressInterval);\n resolve(task);\n return;\n }\n }\n }, 50);\n });\n }\n\n /**\n * Returns a ReadableStream of all background task lifecycle events,\n * filtered by optional criteria. Intended to be piped directly to an SSE response.\n *\n * On connection, emits the current state of all non-terminal tasks as a snapshot,\n * then subscribes to live pubsub events for subsequent updates.\n *\n * Events include:\n * - `task.running` (status: 'running') — task picked up by a worker\n * - `task.completed` (status: 'completed') — task finished successfully\n * - `task.failed` (status: 'failed' or 'timed_out') — task errored or timed out\n * - `task.cancelled` (status: 'cancelled') — task was cancelled\n * - `task.suspended` (status: 'suspended') — task paused via `suspend()` from\n * inside its tool executor; resume with `manager.resume(taskId, data)`\n * - `task.resumed` (status: 'running') — suspended task resumed\n *\n * The stream stays open until the caller's AbortSignal fires (client disconnect).\n */\n stream(options?: {\n agentId?: string;\n runId?: string;\n threadId?: string;\n resourceId?: string;\n taskId?: string;\n abortSignal?: AbortSignal;\n }): ReadableStream<Record<string, unknown>> {\n const manager = this;\n const pubsub = this.pubsub;\n const { agentId, runId, threadId, resourceId, abortSignal, taskId } = options ?? {};\n\n const EVENT_STATUS_MAP: Record<string, BackgroundTaskStatus> = {\n 'task.running': 'running',\n 'task.output': 'running',\n 'task.completed': 'completed',\n 'task.failed': 'failed',\n 'task.cancelled': 'cancelled',\n 'task.suspended': 'suspended',\n 'task.resumed': 'running',\n };\n\n const CHUNK_EVENT_MAP: Record<string, string> = {\n 'task.running': 'background-task-running',\n 'task.output': 'background-task-output',\n 'task.completed': 'background-task-completed',\n 'task.failed': 'background-task-failed',\n 'task.cancelled': 'background-task-cancelled',\n 'task.suspended': 'background-task-suspended',\n 'task.resumed': 'background-task-resumed',\n };\n\n return new ReadableStream({\n async start(controller) {\n // 1. Subscribe to live events first (so we don't miss anything between snapshot and subscribe)\n const handler = async (event: Event) => {\n const status = EVENT_STATUS_MAP[event.type];\n if (!status) return;\n\n const data = event.data;\n if (agentId && data.agentId !== agentId) return;\n if (runId && data.runId !== runId) return;\n if (threadId && data.threadId !== threadId) return;\n if (resourceId && data.resourceId !== resourceId) return;\n if (taskId && data.taskId !== taskId) return;\n\n const payload: Record<string, unknown> = {\n taskId: data.taskId,\n toolName: data.toolName,\n toolCallId: data.toolCallId,\n agentId: data.agentId,\n runId: data.runId,\n };\n\n switch (event.type) {\n case 'task.running':\n payload.startedAt = data.startedAt;\n payload.args = data.args;\n break;\n case 'task.completed':\n payload.completedAt = data.completedAt;\n payload.result = data.result;\n break;\n case 'task.failed':\n payload.completedAt = data.completedAt;\n payload.error = data.error;\n break;\n case 'task.cancelled':\n payload.completedAt = data.completedAt;\n break;\n case 'task.output':\n payload.payload = data.chunk;\n break;\n case 'task.suspended':\n payload.suspendPayload = data.suspendPayload;\n payload.suspendedAt = data.suspendedAt;\n payload.args = data.args;\n break;\n case 'task.resumed':\n payload.startedAt = data.startedAt;\n payload.args = data.args;\n break;\n }\n\n try {\n controller.enqueue({\n type: CHUNK_EVENT_MAP[event.type],\n payload,\n });\n } catch {\n // Controller closed\n }\n };\n\n void pubsub.subscribe(TOPIC_RESULT, handler);\n\n abortSignal?.addEventListener('abort', () => {\n void pubsub.unsubscribe(TOPIC_RESULT, handler);\n try {\n controller.close();\n } catch {\n // Already closed\n }\n });\n\n // 2. Emit snapshot of existing in-flight tasks (running + suspended).\n try {\n const storage = await manager.getStorage();\n if (taskId) {\n const task = await storage.getTask(taskId);\n if (task && task.status === 'running') {\n controller.enqueue({\n type: 'background-task-running',\n payload: {\n taskId: task.id,\n toolName: task.toolName,\n toolCallId: task.toolCallId,\n agentId: task.agentId,\n runId: task.runId,\n startedAt: task.startedAt,\n args: task.args,\n },\n });\n }\n } else {\n const { tasks: existing } = await storage.listTasks({\n agentId,\n runId,\n threadId,\n resourceId,\n status: ['running'],\n });\n\n for (const task of existing) {\n if (abortSignal?.aborted) break;\n try {\n controller.enqueue({\n type: 'background-task-running',\n payload: {\n taskId: task.id,\n toolName: task.toolName,\n toolCallId: task.toolCallId,\n agentId: task.agentId,\n runId: task.runId,\n startedAt: task.startedAt,\n args: task.args,\n },\n });\n } catch {\n break;\n }\n }\n }\n } catch {\n // Storage not available — continue with live events only\n }\n },\n });\n }\n\n async shutdown(): Promise<void> {\n this.shuttingDown = true;\n\n if (this.cleanupInterval) {\n clearInterval(this.cleanupInterval);\n this.cleanupInterval = undefined;\n }\n\n if (this.workerCallback) {\n await this.pubsub.unsubscribe(TOPIC_DISPATCH, this.workerCallback);\n }\n if (this.resultCallback) {\n await this.pubsub.unsubscribe(TOPIC_RESULT, this.resultCallback);\n }\n\n this.taskContexts.clear();\n await this.pubsub.flush();\n }\n\n // --- Internal ---\n\n /**\n * Lazily start Mastra's execution workers before publishing. In \"library\n * mode\" nothing ever calls `mastra.startWorkers()`, so the evented\n * `__background-task` workflow started by `handleDispatch` would publish\n * to the `workflows` topic with no consumer and the task would sit at\n * `running` forever (#19339). A no-op once workers are running; honors the\n * `workers: false` / `MASTRA_WORKERS` opt-outs.\n *\n * Startup failures are logged but don't abort the publish — in distributed\n * topologies a remote worker on the shared broker can still pick the task\n * up, and throwing here would also abort `drainPending()` /\n * `recoverStaleTasks()` loops.\n */\n async #ensureExecutionWorkersStarted(): Promise<void> {\n if (!this.#mastra) return;\n try {\n await this.#mastra.__ensureExecutionWorkersStarted();\n } catch (err) {\n this.#mastra.getLogger?.()?.error('Failed to start execution workers for background task', err as any);\n }\n }\n\n private async dispatch(task: BackgroundTask, isRestart?: boolean): Promise<void> {\n await this.#ensureExecutionWorkersStarted();\n\n // Publish `task.dispatch` on `TOPIC_DISPATCH` with `WORKER_GROUP`, so\n // exactly one worker handles the task. `handleDispatch` flips the\n // task to running and starts the per-task workflow run.\n await this.pubsub.publish(TOPIC_DISPATCH, {\n type: 'task.dispatch',\n data: {\n taskId: task.id,\n toolName: task.toolName,\n toolCallId: task.toolCallId,\n args: task.args,\n agentId: task.agentId,\n threadId: task.threadId,\n resourceId: task.resourceId,\n timeoutMs: task.timeoutMs,\n maxRetries: task.maxRetries,\n runId: task.runId,\n isRestart,\n },\n runId: task.id,\n });\n }\n\n /**\n * Handles a task.dispatch and task.restart events.\n * Both events are similar, but the latter is used to restart a running task.\n */\n private async handleDispatch(event: Event): Promise<void> {\n const { taskId, isRestart } = event.data;\n const deliveryAttempt = event.deliveryAttempt ?? 1;\n\n const storage = await this.getStorage();\n const task = await storage.getTask(taskId);\n if (!task || task.status === 'cancelled') {\n this.deregisterTaskContext(taskId);\n return;\n }\n\n if (isRestart && task.status !== 'running') {\n // Either gone or already done/cancelled by another worker. Drop the\n // event silently — the worker group ensures exactly-once delivery, but\n // the task may have moved on between publish and pickup.\n return;\n }\n\n await storage.updateTask(taskId, { status: 'running', startedAt: new Date(), retryCount: deliveryAttempt - 1 });\n\n // Publish running lifecycle event (fan-out, for stream consumers)\n const runningTask = await storage.getTask(taskId);\n if (runningTask) await this.publishLifecycleEvent('task.running', runningTask);\n\n // Fire-and-forget the workflow run; the workflow step body owns\n // executor invocation, retries, and suspend/resume. The local\n // execution hook still runs here so callers see `onExecution` fire.\n if (this.#mastra) {\n if (runningTask) void this.runLocalExecutionHook(runningTask);\n const workflow = this.#mastra.__getInternalWorkflow(BACKGROUND_TASK_WORKFLOW_ID);\n const prevWorkflowRun = isRestart ? await workflow.getWorkflowRunById(taskId) : undefined;\n const shouldRestart = isRestart && prevWorkflowRun?.status === 'running';\n const run = await workflow.createRun({ runId: taskId });\n const runPromise = shouldRestart ? run.restart() : run.start({ inputData: { taskId } });\n void runPromise\n .then(result => {\n if (result.status !== 'suspended') {\n void workflow.deleteWorkflowRunById(taskId);\n }\n })\n .catch(err => {\n this.#mastra\n ?.getLogger?.()\n ?.error(`background-task workflow ${shouldRestart ? 'restart' : 'start'} failed for ${taskId}:`, err);\n })\n .finally(() => {\n // Free the concurrency slot once the run terminates.\n void this.drainPending();\n });\n }\n }\n\n /**\n * Handles a task.resume event. Mirrors the workflow branch of handleDispatch\n * but resumes an existing run from its suspended snapshot instead of starting\n * a fresh one. Concurrency gating, suspended-status validation, and the\n * `task.resumed` lifecycle publish all happen here so a different process\n * than the one that suspended the task can drive the resume.\n */\n private async handleResume(event: Event): Promise<void> {\n const { taskId, resumeData } = event.data;\n\n const storage = await this.getStorage();\n const task = await storage.getTask(taskId);\n if (!task || task.status !== 'suspended') {\n // Either gone or already resumed/cancelled by another worker. Drop the\n // event silently — the worker group ensures exactly-once delivery, but\n // the task may have moved on between publish and pickup.\n return;\n }\n\n await storage.updateTask(taskId, {\n status: 'running',\n startedAt: new Date(),\n suspendPayload: undefined,\n suspendedAt: undefined,\n });\n const resumedTask = await storage.getTask(taskId);\n if (resumedTask) {\n await this.publishLifecycleEvent('task.resumed', resumedTask);\n }\n\n if (!this.#mastra) return;\n const workflow = this.#mastra.__getInternalWorkflow(BACKGROUND_TASK_WORKFLOW_ID);\n // `createRun({ runId })` reattaches to the existing snapshot when given a\n // stable runId — we don't want a fresh run.\n const run = await workflow.createRun({ runId: taskId });\n void run\n .resume({ resumeData })\n .then(result => {\n if (result.status !== 'suspended') {\n void workflow.deleteWorkflowRunById(taskId);\n }\n })\n .catch(err => {\n this.#mastra?.getLogger?.()?.error(`background-task workflow resume failed for ${taskId}:`, err);\n })\n .finally(() => {\n // Mirror dispatch's drain — resuming frees a slot when it terminates.\n void this.drainPending();\n });\n }\n\n /**\n * Run per-task hooks (onChunk, onResult, onComplete/onFailed) locally in the\n * worker path, before publishing the terminal lifecycle event. Ensures\n * memory / stream state is consistent by the time any pubsub subscriber is\n * notified. After running, the task context is deregistered so\n * `handleResult` (which also fires from pubsub) becomes a no-op for this\n * task in the same process.\n *\n * In distributed deployments where the worker runs in a different process\n * from the dispatcher, `this.taskContexts` won't contain an entry for\n * `task.id` — this method is a no-op there, and `handleResult` in the\n * dispatching process runs the hooks instead.\n */\n /**\n * Terminal-state hooks only. Called when a task reaches `'completed'` or\n * `'failed'`. Suspend is non-terminal — see `runLocalSuspendHooks` for that\n * path.\n *\n * @internal — also called by the workflow-engine step bodies in workflow.ts\n */\n async runLocalCompletionHooks(\n task: BackgroundTask,\n status: 'completed' | 'failed',\n extras: { result?: unknown; error?: { message: string; stack?: string } },\n ): Promise<void> {\n const ctx = this.taskContexts.get(task.id);\n if (!ctx) return;\n\n try {\n if (status === 'completed') {\n ctx.onChunk?.({\n type: 'background-task-completed',\n payload: {\n taskId: task.id,\n toolName: task.toolName,\n toolCallId: task.toolCallId,\n runId: task.runId,\n result: extras.result,\n completedAt: task.completedAt!,\n agentId: task.agentId,\n },\n });\n\n await ctx.onResult?.({\n runId: task.runId,\n taskId: task.id,\n toolCallId: task.toolCallId,\n toolName: task.toolName,\n agentId: task.agentId,\n threadId: task.threadId,\n resourceId: task.resourceId,\n result: extras.result,\n status: 'completed',\n completedAt: task.completedAt!,\n startedAt: task.startedAt!,\n });\n\n // Globals (this.config.onTaskComplete / onTaskFailed) fire from\n // handleResult via pubsub so they run once per subscribing process\n // — in distributed deployments that's the dispatching process, which\n // is where observers/metrics are typically wired.\n await ctx.onComplete?.(task);\n } else {\n ctx.onChunk?.({\n type: 'background-task-failed',\n payload: {\n taskId: task.id,\n toolName: task.toolName,\n toolCallId: task.toolCallId,\n runId: task.runId,\n error: extras.error ?? { message: 'Unknown error' },\n completedAt: task.completedAt!,\n agentId: task.agentId,\n },\n });\n\n await ctx.onResult?.({\n runId: task.runId,\n taskId: task.id,\n toolCallId: task.toolCallId,\n toolName: task.toolName,\n agentId: task.agentId,\n threadId: task.threadId,\n resourceId: task.resourceId,\n error: extras.error,\n status: 'failed',\n completedAt: task.completedAt!,\n startedAt: task.startedAt!,\n });\n\n // See comment above — globals are handled exclusively by\n // handleResult so they fire once per subscribing process.\n await ctx.onFailed?.(task);\n }\n } finally {\n this.deregisterTaskContext(task.id);\n }\n }\n\n /**\n * Per-task suspend hooks. Fires `ctx.onResult({ status: 'suspended', ... })`\n * so the message list / memory pick up the suspension as the tool's\n * current invocation state. Does NOT deregister the task context — resume\n * needs the executor closure intact.\n *\n * @internal — called by the workflow-engine step bodies in workflow.ts\n */\n async runLocalSuspendHooks(task: BackgroundTask): Promise<void> {\n const ctx = this.taskContexts.get(task.id);\n if (!ctx) return;\n await ctx.onExecution?.({\n runId: task.runId,\n taskId: task.id,\n toolCallId: task.toolCallId,\n toolName: task.toolName,\n agentId: task.agentId,\n threadId: task.threadId,\n resourceId: task.resourceId,\n startedAt: task.startedAt!,\n suspendedAt: task.suspendedAt,\n });\n }\n\n /** @internal — also called by the workflow-engine step bodies in workflow.ts */\n async runLocalExecutionHook(task: BackgroundTask): Promise<void> {\n const ctx = this.taskContexts.get(task.id);\n if (!ctx) return;\n\n try {\n await ctx.onExecution?.({\n runId: task.runId,\n taskId: task.id,\n toolCallId: task.toolCallId,\n toolName: task.toolName,\n agentId: task.agentId,\n threadId: task.threadId,\n resourceId: task.resourceId,\n startedAt: task.startedAt!,\n });\n } catch {\n //fail silently\n }\n }\n\n private async handleResult(event: Event): Promise<void> {\n const { taskId, toolName, toolCallId, threadId, resourceId, runId } = event.data;\n const storage = await this.getStorage();\n const task = await storage.getTask(taskId);\n\n if (task?.completedAt) {\n // Look up per-task hooks\n const ctx = this.taskContexts.get(taskId);\n\n if (event.type === 'task.completed') {\n ctx?.onChunk?.({\n type: 'background-task-completed',\n payload: {\n taskId,\n toolName,\n toolCallId,\n runId,\n result: event.data.result,\n completedAt: task.completedAt,\n agentId: task.agentId,\n },\n });\n\n await ctx?.onResult?.({\n runId,\n taskId,\n toolCallId,\n toolName,\n agentId: event.data.agentId,\n threadId,\n resourceId,\n result: event.data.result,\n status: 'completed',\n completedAt: task.completedAt,\n startedAt: task.startedAt!,\n });\n\n if (task) {\n await Promise.all([ctx?.onComplete?.(task), this.config.onTaskComplete?.(task)]);\n }\n }\n\n if (event.type === 'task.failed') {\n ctx?.onChunk?.({\n type: 'background-task-failed',\n payload: {\n taskId,\n toolName,\n toolCallId,\n runId,\n error: event.data.error,\n completedAt: task.completedAt,\n agentId: task.agentId,\n },\n });\n\n await ctx?.onResult?.({\n runId,\n taskId,\n toolCallId,\n toolName,\n agentId: event.data.agentId,\n threadId,\n resourceId,\n error: event.data.error,\n status: 'failed',\n completedAt: task.completedAt,\n startedAt: task.startedAt!,\n });\n\n if (task) {\n await Promise.all([ctx?.onFailed?.(task), this.config.onTaskFailed?.(task)]);\n }\n }\n\n // Clean up context after terminal result\n this.deregisterTaskContext(taskId);\n }\n }\n\n private handleCancel(event: Event): void {\n const { taskId } = event.data;\n const controller = this.activeAbortControllers.get(taskId);\n if (controller) {\n controller.abort(new Error('Task cancelled'));\n this.activeAbortControllers.delete(taskId);\n }\n this.deregisterTaskContext(taskId);\n }\n\n /** @internal — also called by the workflow-engine step bodies in workflow.ts */\n async publishLifecycleEvent(\n type:\n | 'task.running'\n | 'task.completed'\n | 'task.failed'\n | 'task.cancelled'\n | 'task.output'\n | 'task.suspended'\n | 'task.resumed',\n task: BackgroundTaskEvent,\n ): Promise<void> {\n await this.pubsub.publish(TOPIC_RESULT, {\n type,\n data: {\n taskId: task.id,\n toolName: task.toolName,\n toolCallId: task.toolCallId,\n runId: task.runId,\n agentId: task.agentId,\n threadId: task.threadId,\n resourceId: task.resourceId,\n args: task.args,\n result: task.result,\n error: task.error,\n chunk: task.chunk,\n completedAt: task.completedAt,\n startedAt: task.startedAt,\n suspendPayload: task.suspendPayload,\n suspendedAt: task.suspendedAt,\n },\n runId: task.id,\n });\n }\n\n private async checkConcurrency(agentId: string): Promise<boolean> {\n const storage = await this.getStorage();\n const globalRunning = await storage.getRunningCount();\n if (globalRunning >= this.config.globalConcurrency) {\n return false;\n }\n\n const agentRunning = await storage.getRunningCountByAgent(agentId);\n if (agentRunning >= this.config.perAgentConcurrency) {\n return false;\n }\n\n return true;\n }\n\n private async drainPending(): Promise<void> {\n const storage = await this.getStorage();\n const { tasks: pending } = await storage.listTasks({\n status: 'pending',\n orderBy: 'createdAt',\n orderDirection: 'asc',\n });\n\n for (const task of pending) {\n if (await this.checkConcurrency(task.agentId)) {\n await this.dispatch(task);\n }\n }\n }\n\n /**\n * Recovers tasks left in 'running' or 'pending' state from a previous process.\n */\n private async recoverStaleTasks(): Promise<void> {\n try {\n const storage = await this.getStorage();\n const { tasks: staleTasks } = await storage.listTasks({ status: 'running' });\n for (const task of staleTasks) {\n if (task.maxRetries > 0) {\n await storage.updateTask(task.id, {\n status: 'pending',\n startedAt: undefined,\n });\n } else {\n await storage.updateTask(task.id, {\n status: 'failed',\n error: { message: 'Worker process terminated before task completed' },\n completedAt: new Date(),\n });\n }\n }\n\n const { tasks: pendingTasks } = await storage.listTasks({\n status: 'pending',\n orderBy: 'createdAt',\n orderDirection: 'asc',\n });\n for (const task of pendingTasks) {\n if (await this.checkConcurrency(task.agentId)) {\n await this.dispatch(task);\n }\n }\n } catch (error) {\n const logger = this.#mastra?.getLogger();\n if (logger) {\n logger.error('Failed to recover stale background tasks', error);\n }\n }\n }\n}\n","import type { BackgroundTaskManager } from './manager';\nimport type {\n BackgroundTaskHandle,\n CheckIfRunningPayload,\n CheckIfSuspendedPayload,\n CreateBackgroundTaskOptions,\n} from './types';\n\n/**\n * Creates a self-contained background task handle.\n *\n * Bundles the task payload with per-stream hooks (executor, onChunk, onResult)\n * so each dispatch is fully isolated — no shared mutable state on the manager.\n *\n * @example\n * ```ts\n * const bgTask = createBackgroundTask(manager, {\n * toolName: 'research',\n * toolCallId: 'call-1',\n * args: { query: 'solana' },\n * agentId: 'agent-1',\n * runId: 'run-1',\n * context: {\n * executor: { execute: (args, opts) => tool.execute(args, opts) },\n * onChunk: (chunk) => controller.enqueue(chunk),\n * onResult: (params) => messageList.addToolResult(params),\n * },\n * });\n *\n * const { task, fallbackToSync } = await bgTask.dispatch();\n * const completed = await bgTask.waitForCompletion();\n * await bgTask.cancel();\n * ```\n */\nexport function createBackgroundTask(\n manager: BackgroundTaskManager,\n options: CreateBackgroundTaskOptions,\n): BackgroundTaskHandle {\n const { context, ...payload } = options;\n let taskId: string | undefined;\n\n return {\n get task() {\n if (!taskId) throw new Error('Task has not been dispatched yet');\n // Synchronous access to task ID — full task data requires async getTask()\n return { id: taskId } as any;\n },\n\n async dispatch() {\n const result = await manager.enqueue(payload, context);\n taskId = result.task.id;\n return result;\n },\n\n async checkIfSuspended(args: CheckIfSuspendedPayload) {\n const result = await manager.listTasks({\n toolCallId: args.toolCallId,\n runId: args.runId,\n agentId: args.agentId,\n threadId: args.threadId,\n resourceId: args.resourceId,\n toolName: args.toolName,\n status: 'suspended',\n });\n if (result.total > 0) {\n const task = result.tasks[0];\n if (task) {\n taskId = task.id;\n return true;\n }\n }\n\n return false;\n },\n\n async checkIfRunning(args: CheckIfRunningPayload) {\n const result = await manager.listTasks({\n toolCallId: args.toolCallId,\n runId: args.runId,\n agentId: args.agentId,\n threadId: args.threadId,\n resourceId: args.resourceId,\n toolName: args.toolName,\n status: 'running',\n });\n if (result.total > 0) {\n const task = result.tasks[0];\n if (task) {\n taskId = task.id;\n return true;\n }\n }\n\n return false;\n },\n\n async resume(resumeData?: unknown) {\n if (!taskId) throw new Error('Task has not been dispatched yet');\n return manager.resume(taskId, resumeData);\n },\n\n async restart() {\n if (!taskId) throw new Error('Task has not been dispatched yet');\n return manager.restart(taskId, context);\n },\n\n async cancel() {\n if (!taskId) throw new Error('Task has not been dispatched yet');\n return manager.cancel(taskId);\n },\n\n async waitForCompletion(waitOptions) {\n if (!taskId) throw new Error('Task has not been dispatched yet');\n return manager.waitForNextTask([taskId], waitOptions);\n },\n };\n}\n","import type {\n AgentBackgroundConfig,\n AgentBackgroundToolConfig,\n BackgroundTaskManagerConfig,\n LLMBackgroundOverride,\n ToolBackgroundConfig,\n} from './types';\n\nexport interface ResolvedBackgroundConfig {\n runInBackground: boolean;\n timeoutMs: number;\n maxRetries: number;\n}\n\n/**\n * Resolves whether a tool call should run in the background, and with what config.\n *\n * Resolution order (highest to lowest priority):\n * 1. LLM per-call override (`_background` field in tool args)\n * 2. Agent-level backgroundTasks.tools config\n * 3. Tool-level background config\n * 4. Default: foreground\n *\n * Strips the `_background` field from args (mutates the args object).\n */\nexport function resolveBackgroundConfig({\n llmBgOverrides,\n toolName,\n toolConfig,\n agentConfig,\n managerConfig,\n}: {\n llmBgOverrides: Record<string, unknown>;\n toolName: string;\n toolConfig?: ToolBackgroundConfig;\n agentConfig?: AgentBackgroundConfig;\n managerConfig?: BackgroundTaskManagerConfig;\n}): ResolvedBackgroundConfig {\n const llmOverride = llmBgOverrides as LLMBackgroundOverride | undefined;\n\n // If this agent has background tasks disabled, short-circuit so no tool can\n // dispatch a background task even if its own config or the LLM override\n // would otherwise enable it. Default timeoutMs/maxRetries are still returned\n // so callers can use the shape safely.\n if (agentConfig?.disabled) {\n return {\n runInBackground: false,\n timeoutMs: managerConfig?.defaultTimeoutMs ?? 300_000,\n maxRetries: managerConfig?.defaultRetries?.maxRetries ?? 0,\n };\n }\n\n // Resolve agent-level config for this specific tool\n const agentToolConfig = resolveAgentToolConfig(toolName, agentConfig);\n\n // --- enabled ---\n // The LLM `_background` override is a modifier on tools the developer has\n // already opted in at the tool or agent layer — it is NOT a standalone\n // opt-in. A foreground-only tool must stay foreground regardless of what\n // the model emits, so `agent.generate()` / `agent.stream()` keep returning\n // real tool results for deterministic tools. See issue #16783.\n const baseEnabled = agentToolConfig?.enabled ?? toolConfig?.enabled ?? false;\n const enabled = baseEnabled ? (llmOverride?.enabled ?? true) : false;\n\n // --- timeoutMs ---\n const timeoutMs =\n llmOverride?.timeoutMs ??\n agentToolConfig?.timeoutMs ??\n toolConfig?.timeoutMs ??\n managerConfig?.defaultTimeoutMs ??\n 300_000;\n\n // --- maxRetries ---\n const maxRetries =\n llmOverride?.maxRetries ?? toolConfig?.maxRetries ?? managerConfig?.defaultRetries?.maxRetries ?? 0;\n\n return { runInBackground: enabled, timeoutMs, maxRetries };\n}\n\nfunction resolveAgentToolConfig(\n toolName: string,\n agentConfig?: AgentBackgroundConfig,\n): { enabled: boolean; timeoutMs?: number } | undefined {\n if (!agentConfig?.tools) return undefined;\n\n if (agentConfig.tools === 'all') {\n return { enabled: true };\n }\n\n if (toolName.startsWith('agent-')) {\n toolName = toolName.substring('agent-'.length);\n } else if (toolName.startsWith('workflow-')) {\n toolName = toolName.substring('workflow-'.length);\n }\n\n const entry: AgentBackgroundToolConfig | undefined = agentConfig.tools[toolName];\n if (entry === undefined) return undefined;\n if (typeof entry === 'boolean') return { enabled: entry };\n return entry;\n}\n","import { z } from 'zod/v4';\n\n/**\n * JSON Schema definition for the `_background` override field.\n * Injected into background-eligible tool schemas so the LLM can override behavior per-call.\n */\nexport const backgroundOverrideJsonSchema = {\n type: 'object' as const,\n description:\n 'Optional: override background execution behavior for this specific call. ' +\n 'Set enabled=false to force foreground, enabled=true to force background. ' +\n 'Omit entirely to use the default configuration.',\n properties: {\n enabled: {\n type: 'boolean' as const,\n description: 'Force background (true) or foreground (false) execution for this call.',\n },\n timeoutMs: {\n type: 'number' as const,\n description: 'Override timeout in milliseconds for this call.',\n },\n maxRetries: {\n type: 'number' as const,\n description: 'Override maximum retry attempts for this call.',\n },\n },\n additionalProperties: false,\n};\n\nexport const backgroundOverrideZodSchema = z\n .object({\n enabled: z.boolean().optional().describe('Force background (true) or foreground (false) execution for this call.'),\n timeoutMs: z.number().optional().describe('Override timeout in milliseconds for this call.'),\n maxRetries: z.number().optional().describe('Override maximum retry attempts for this call.'),\n })\n .optional()\n .describe(\n 'Optional: override background execution behavior for this specific call. Set enabled=false to force foreground, enabled=true to force background. Omit entirely to use the default configuration.',\n );\n","import type { AgentBackgroundConfig, ToolBackgroundConfig } from './types';\n\ninterface ToolEntry {\n toolName: string;\n toolConfig?: ToolBackgroundConfig;\n /** Whether the tool defaults to background execution */\n defaultBackground: boolean;\n}\n\n/**\n * Generates the system prompt section that tells the LLM about background task capabilities.\n *\n * Returns undefined if no tools are background-eligible (nothing to inject).\n */\nexport function generateBackgroundTaskSystemPrompt(\n tools: Record<string, { background?: ToolBackgroundConfig; description?: string }>,\n agentConfig?: AgentBackgroundConfig,\n): string | undefined {\n const eligibleTools: ToolEntry[] = [];\n\n const enableAll = agentConfig?.tools === 'all';\n\n for (const [toolName, tool] of Object.entries(tools)) {\n const bgEnabledFromAgentConfig =\n agentConfig?.tools === 'all'\n ? false\n : typeof agentConfig?.tools?.[toolName] === 'boolean'\n ? agentConfig.tools[toolName]\n : (agentConfig?.tools?.[toolName]?.enabled ?? false);\n eligibleTools.push({\n toolName,\n toolConfig: tool.background,\n defaultBackground: enableAll ? true : (bgEnabledFromAgentConfig ?? tool.background?.enabled ?? false),\n });\n }\n\n if (eligibleTools.length === 0) {\n return undefined;\n }\n\n const toolLines = eligibleTools\n .map(t => `- ${t.toolName} (default: ${t.defaultBackground ? 'background' : 'foreground'})`)\n .join('\\n');\n\n return `You have the ability to run certain tools in the background while continuing the conversation. The following tools support background execution:\n${toolLines}\n\nFor any of these tools, you can include a \"_background\" field in the tool arguments to override the default:\n \"_background\": { \"enabled\": true/false, \"timeoutMs\": number, \"maxRetries\": number }\n\nAll fields in \"_background\" are optional. Only include what you want to override.\n\nGuidelines:\n- Use background execution when the user doesn't need the result immediately, or when you're launching multiple independent tasks.\n- Use foreground execution when the user is directly waiting for the result and the conversation can't continue without it.\n- If you don't include \"_background\", the tool's default configuration is used.\n- When a tool runs in the background, you'll receive a placeholder result with a task ID. You can reference this in your response to the user.\n\nIMPORTANT: \"_background\" field is always an object. The fields in the _background field should be inside the _background object, not outside of it.`;\n}\n"],"mappings":"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"}
|
package/dist/browser/index.cjs
CHANGED
|
@@ -2,7 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
2
2
|
const require_logger = require("../logger-BPclhj7J.cjs");
|
|
3
3
|
const require_base = require("../base-B6soWsYg.cjs");
|
|
4
4
|
const require_tool = require("../tool-Ch0RJiLS.cjs");
|
|
5
|
-
const require_trip_wire = require("../trip-wire-
|
|
5
|
+
const require_trip_wire = require("../trip-wire-utCESgMt.cjs");
|
|
6
6
|
const require_workspace = require("../workspace-D5VRmEXr.cjs");
|
|
7
7
|
let crypto = require("crypto");
|
|
8
8
|
let events = require("events");
|
package/dist/browser/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { a as RegisteredLogger } from "../logger-B_aQzjbm.js";
|
|
2
2
|
import { t as MastraBase } from "../base-BeUQ6mLP.js";
|
|
3
3
|
import { r as createTool } from "../tool-B09dFqXW.js";
|
|
4
|
-
import { E as isProcessorWorkflow } from "../trip-wire-
|
|
4
|
+
import { E as isProcessorWorkflow } from "../trip-wire-DxpTS3jV.js";
|
|
5
5
|
import { d as BrowserCliHandler, f as browserCliHandler } from "../workspace-kJgXwpJp.js";
|
|
6
6
|
import { randomUUID } from "crypto";
|
|
7
7
|
import { EventEmitter } from "events";
|
package/dist/channels/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_agent = require("../agent-
|
|
3
|
-
const require_channels = require("../channels-
|
|
2
|
+
const require_agent = require("../agent-um2LJs-0.cjs");
|
|
3
|
+
const require_channels = require("../channels-BgbloDjB.cjs");
|
|
4
4
|
exports.AgentChannels = require_agent.AgentChannels;
|
|
5
5
|
exports.AgentControllerChannels = require_channels.AgentControllerChannels;
|
|
6
6
|
exports.ChatChannelProcessor = require_agent.ChatChannelProcessor;
|
package/dist/channels/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { F as MastraStateAdapter, I as ChatChannelProcessor, M as AgentChannels, N as resolveWaitUntil, P as defaultTypingStatus } from "../agent-
|
|
2
|
-
import { t as AgentControllerChannels } from "../channels-
|
|
1
|
+
import { F as MastraStateAdapter, I as ChatChannelProcessor, M as AgentChannels, N as resolveWaitUntil, P as defaultTypingStatus } from "../agent-0y2cApTZ.js";
|
|
2
|
+
import { t as AgentControllerChannels } from "../channels-MegO_4KL.js";
|
|
3
3
|
export { AgentChannels, AgentControllerChannels, ChatChannelProcessor, MastraStateAdapter, defaultTypingStatus, resolveWaitUntil };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const require_agent = require("./agent-
|
|
1
|
+
const require_agent = require("./agent-um2LJs-0.cjs");
|
|
2
2
|
//#region src/channels/agent-controller-channels.ts
|
|
3
3
|
/**
|
|
4
4
|
* Runs an AgentController inside chat channels (Slack, Discord, ...).
|
|
@@ -164,4 +164,4 @@ Object.defineProperty(exports, "AgentControllerChannels", {
|
|
|
164
164
|
}
|
|
165
165
|
});
|
|
166
166
|
|
|
167
|
-
//# sourceMappingURL=channels-
|
|
167
|
+
//# sourceMappingURL=channels-BgbloDjB.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channels-BW52ccH_.cjs","names":["AgentChannels"],"sources":["../src/channels/agent-controller-channels.ts"],"sourcesContent":["import type { Message, Thread } from 'chat';\n\nimport type { Agent } from '../agent/agent';\nimport type { MastraProviderMetadata } from '../agent/message-list/state/types';\nimport type { AgentSignalContents } from '../agent/signals';\nimport type { AgentController } from '../agent-controller/agent-controller';\nimport type { Session } from '../agent-controller/session';\nimport type { Mastra } from '../mastra';\nimport type { StorageThreadType } from '../memory/types';\nimport type { RequestContext } from '../request-context';\n\nimport { AgentChannels } from './agent-channels';\nimport type { ChannelConfig } from './types';\n\n/** Configuration for {@link AgentControllerChannels}. Same shape as agent channels. */\nexport type AgentControllerChannelsConfig = ChannelConfig;\n\n/**\n * Runs an AgentController inside chat channels (Slack, Discord, ...).\n *\n * Extends {@link AgentChannels} so all inbound machinery (thread mapping,\n * history, attachments, event context) and all outbound rendering\n * (`ChatChannelOutputProcessor` with native streaming, tool cards, typing\n * status) are reused unchanged. Only the dispatch seams differ: instead of\n * routing into a bare agent, inbound messages route into a controller\n * `Session` — one durable session per chat thread, keyed by the mapped\n * Mastra thread's `resourceId`.\n *\n * V1 targets long-lived servers: controller sessions are in-memory objects\n * and do not survive process restarts.\n */\nexport class AgentControllerChannels extends AgentChannels {\n private controller: AgentController<any> | null = null;\n\n /**\n * Session resourceIds whose adapter can't render approval buttons, so their\n * runs must auto-approve tools (`requireToolApproval: false`) instead of\n * parking forever on an approval nobody can answer. Kept outside session\n * state on purpose: state is validated against the controller's\n * `stateSchema`, which would strip (or reject) an injected flag. Refreshed\n * on every inbound message; in-memory only, matching the v1 long-lived\n * server scope.\n */\n private autoApproveResourceIds = new Set<string>();\n\n /** @internal Called by AgentController's constructor to bind itself. */\n __setController(controller: AgentController<any>): void {\n this.controller = controller;\n }\n\n /**\n * @internal Consulted by the controller's run-option builder: `true` when\n * the session's channel adapter can't render approval buttons and tool\n * calls must auto-approve (the session-side equivalent of the base agent\n * path's `autoResumeSuspendedTools`).\n */\n __isAutoApproveResource(resourceId: string): boolean {\n return this.autoApproveResourceIds.has(resourceId);\n }\n\n /**\n * @internal No-op override. The controller attaches this instance to its\n * mode agents via `Agent.setChannels`, which calls `__setAgent(agent)` —\n * with multiple mode agents the last one would win. Every `this.agent` use\n * is overridden in this subclass, so keep the base field unset rather than\n * holding a misleading ref.\n */\n override __setAgent(_agent: Agent<any, any, any, any>): void {}\n\n protected override getOwnerId(): string | null {\n return this.controller?.id ?? null;\n }\n\n protected override getWebhookBasePath(): string {\n return `/api/agent-controllers/${this.getOwnerId()}`;\n }\n\n protected override getMastra(): Mastra | undefined {\n return this.controller?.getMastra();\n }\n\n /**\n * One session per chat thread: unless the user supplied a custom\n * `resolveResourceId`, key new Mastra threads (and therefore controller\n * sessions) off the platform + external thread id.\n */\n protected override resolveChannelResourceId(args: {\n platform: string;\n chatThread: Thread;\n message: Message;\n defaultResourceId: string;\n }): string | (() => string | Promise<string>) {\n const base = super.resolveChannelResourceId(args);\n // The base returns a thunk only when a custom resolveResourceId was\n // configured — honor it. Otherwise derive the channel-thread key. The\n // adapter's thread id is already platform-prefixed (e.g. `slack:C123:ts`),\n // so don't prepend the platform again or the key double-prefixes.\n if (typeof base === 'function') return base;\n return `channel:${args.chatThread.id}`;\n }\n\n /**\n * Route an inbound chat message into the controller session bound to this\n * chat thread. Output renders back to the platform through the channels\n * output processor: the `requestContext` built by the base class (carrying\n * the channel context and render context) flows through the session into\n * the run.\n */\n protected override async dispatchInboundMessage(args: {\n signalContents: AgentSignalContents;\n attributes: Record<string, string | undefined>;\n providerOptions: MastraProviderMetadata;\n requestContext: RequestContext;\n thread: StorageThreadType;\n memory: { thread: string; resource: string };\n autoResumeSuspendedTools: true | undefined;\n }): Promise<void> {\n const { signalContents, attributes, providerOptions, requestContext, thread, autoResumeSuspendedTools } = args;\n\n // The tenant, when there is one, is already stamped on `requestContext` by\n // the channel handler that accepted this message — a host that maps\n // platform senders to Mastra users writes `user` before calling\n // `defaultHandler`, and gating an unlinked sender means not calling it at\n // all. Core dispatches whatever reaches it.\n const session = await this.getSessionForThread(thread, requestContext);\n\n // The session equivalent of the base path's `autoResumeSuspendedTools`:\n // controller runs set `requireToolApproval` from this marker, so on\n // adapters that can't render approval buttons the run auto-approves\n // instead of parking forever on an approval nobody can answer. Tracked\n // outside session state so the controller's `stateSchema` (which would\n // strip or reject an injected key) never sees it.\n const sessionResourceId = thread.resourceId;\n if (autoResumeSuspendedTools) {\n this.autoApproveResourceIds.add(sessionResourceId);\n } else {\n this.autoApproveResourceIds.delete(sessionResourceId);\n }\n\n const result = session.sendSignal({\n content: signalContents,\n ifActive: { attributes },\n ifIdle: { attributes },\n requestContext,\n providerOptions,\n });\n await result.accepted;\n }\n\n /**\n * Resolve an approval-card \"approve\" action against the controller session's\n * parked tool-approval gate. The run engine — awaiting the gate inside its\n * stream-consumer loop — performs the actual resume itself and keeps\n * consuming, so the continuation renders through the output processor.\n */\n protected override async dispatchApproval(args: {\n runId: string;\n toolCallId: string;\n requestContext: RequestContext;\n memory: { thread: string; resource: string };\n }): Promise<void> {\n await this.respondToSessionApproval({ decision: 'approve', ...args });\n }\n\n /**\n * Resolve an approval-card \"deny\" action against the controller session's\n * parked tool-approval gate (see {@link dispatchApproval}).\n */\n protected override async dispatchDecline(args: {\n runId: string;\n toolCallId: string;\n requestContext: RequestContext;\n memory: { thread: string; resource: string };\n }): Promise<void> {\n await this.respondToSessionApproval({ decision: 'decline', ...args });\n }\n\n /**\n * Shared approve/decline path. Never calls the session's internal\n * `approveToolCall`/`declineToolCall` executors directly — the engine parked\n * at the gate owns the resume. `respondToToolApproval` is a silent no-op\n * when nothing is armed or the toolCallId mismatches, so staleness is\n * pre-checked explicitly (an armed gate does not survive process restarts,\n * so restart-recovered approvals are always stale — consistent with the\n * v1 long-lived-server scope).\n */\n private async respondToSessionApproval({\n decision,\n toolCallId,\n requestContext,\n memory,\n }: {\n decision: 'approve' | 'decline';\n toolCallId: string;\n requestContext: RequestContext;\n memory: { thread: string; resource: string };\n }): Promise<void> {\n const session = await this.getSessionForThread({ id: memory.thread, resourceId: memory.resource });\n if (!session.approval.isArmed() || session.approval.getToolCallId() !== toolCallId) {\n this.log(\n 'info',\n `Ignoring stale tool ${decision === 'approve' ? 'approval' : 'denial'} action (no matching parked approval for toolCallId=${toolCallId})`,\n );\n return;\n }\n // The requestContext carries the channel render context, so the resumed\n // stream renders back to the platform through the output processor.\n session.respondToToolApproval({ decision, toolCallId, requestContext });\n }\n\n /**\n * Get-or-create the durable controller session for a mapped channel thread\n * and bind it to that thread. Keyed off the thread's own `resourceId` so\n * pre-existing threads (custom resolveResourceId, or created before this\n * feature) always pass the session's thread-ownership check.\n */\n protected async getSessionForThread(\n thread: Pick<StorageThreadType, 'id' | 'resourceId'>,\n requestContext?: RequestContext,\n ): Promise<Session<any>> {\n const controller = this.requireController();\n const channelResourceId = thread.resourceId;\n // `createSession` is get-or-create keyed by resourceId, so follow-up messages\n // on the same thread reuse the cached session bound to this thread. The\n // dispatch requestContext must flow in: a dynamic workspace factory is\n // resolved once at session creation with THIS context, and it may need the\n // stamped tenant (`user`) to authorize a repo-backed session workspace.\n const session = await controller.createSession({\n resourceId: channelResourceId,\n id: channelResourceId,\n ownerId: controller.id,\n requestContext,\n });\n // Bind the mapped thread. Guard is mandatory: `switch` aborts any active\n // run, so never re-switch when the session is already on this thread.\n if (session.thread.getId() !== thread.id) {\n await session.thread.switch({ threadId: thread.id });\n }\n return session;\n }\n\n private requireController(): AgentController<any> {\n if (!this.controller) {\n throw new Error(\n 'AgentControllerChannels is not bound to an AgentController. Pass it via `channels` in AgentControllerConfig.',\n );\n }\n return this.controller;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AA+BA,IAAa,0BAAb,cAA6CA,cAAAA,cAAc;CACzD,aAAkD;;;;;;;;;;CAWlD,yCAAiC,IAAI,IAAY;;CAGjD,gBAAgB,YAAwC;EACtD,KAAK,aAAa;CACpB;;;;;;;CAQA,wBAAwB,YAA6B;EACnD,OAAO,KAAK,uBAAuB,IAAI,UAAU;CACnD;;;;;;;;CASA,WAAoB,QAAyC,CAAC;CAE9D,aAA+C;EAC7C,OAAO,KAAK,YAAY,MAAM;CAChC;CAEA,qBAAgD;EAC9C,OAAO,0BAA0B,KAAK,WAAW;CACnD;CAEA,YAAmD;EACjD,OAAO,KAAK,YAAY,UAAU;CACpC;;;;;;CAOA,yBAA4C,MAKE;EAC5C,MAAM,OAAO,MAAM,yBAAyB,IAAI;EAKhD,IAAI,OAAO,SAAS,YAAY,OAAO;EACvC,OAAO,WAAW,KAAK,WAAW;CACpC;;;;;;;;CASA,MAAyB,uBAAuB,MAQ9B;EAChB,MAAM,EAAE,gBAAgB,YAAY,iBAAiB,gBAAgB,QAAQ,6BAA6B;EAO1G,MAAM,UAAU,MAAM,KAAK,oBAAoB,QAAQ,cAAc;EAQrE,MAAM,oBAAoB,OAAO;EACjC,IAAI,0BACF,KAAK,uBAAuB,IAAI,iBAAiB;OAEjD,KAAK,uBAAuB,OAAO,iBAAiB;EAUtD,MAPe,QAAQ,WAAW;GAChC,SAAS;GACT,UAAU,EAAE,WAAW;GACvB,QAAQ,EAAE,WAAW;GACrB;GACA;EACF,CACW,CAAC,CAAC;CACf;;;;;;;CAQA,MAAyB,iBAAiB,MAKxB;EAChB,MAAM,KAAK,yBAAyB;GAAE,UAAU;GAAW,GAAG;EAAK,CAAC;CACtE;;;;;CAMA,MAAyB,gBAAgB,MAKvB;EAChB,MAAM,KAAK,yBAAyB;GAAE,UAAU;GAAW,GAAG;EAAK,CAAC;CACtE;;;;;;;;;;CAWA,MAAc,yBAAyB,EACrC,UACA,YACA,gBACA,UAMgB;EAChB,MAAM,UAAU,MAAM,KAAK,oBAAoB;GAAE,IAAI,OAAO;GAAQ,YAAY,OAAO;EAAS,CAAC;EACjG,IAAI,CAAC,QAAQ,SAAS,QAAQ,KAAK,QAAQ,SAAS,cAAc,MAAM,YAAY;GAClF,KAAK,IACH,QACA,uBAAuB,aAAa,YAAY,aAAa,SAAS,sDAAsD,WAAW,EACzI;GACA;EACF;EAGA,QAAQ,sBAAsB;GAAE;GAAU;GAAY;EAAe,CAAC;CACxE;;;;;;;CAQA,MAAgB,oBACd,QACA,gBACuB;EACvB,MAAM,aAAa,KAAK,kBAAkB;EAC1C,MAAM,oBAAoB,OAAO;EAMjC,MAAM,UAAU,MAAM,WAAW,cAAc;GAC7C,YAAY;GACZ,IAAI;GACJ,SAAS,WAAW;GACpB;EACF,CAAC;EAGD,IAAI,QAAQ,OAAO,MAAM,MAAM,OAAO,IACpC,MAAM,QAAQ,OAAO,OAAO,EAAE,UAAU,OAAO,GAAG,CAAC;EAErD,OAAO;CACT;CAEA,oBAAkD;EAChD,IAAI,CAAC,KAAK,YACR,MAAM,IAAI,MACR,8GACF;EAEF,OAAO,KAAK;CACd;AACF"}
|
|
1
|
+
{"version":3,"file":"channels-BgbloDjB.cjs","names":["AgentChannels"],"sources":["../src/channels/agent-controller-channels.ts"],"sourcesContent":["import type { Message, Thread } from 'chat';\n\nimport type { Agent } from '../agent/agent';\nimport type { MastraProviderMetadata } from '../agent/message-list/state/types';\nimport type { AgentSignalContents } from '../agent/signals';\nimport type { AgentController } from '../agent-controller/agent-controller';\nimport type { Session } from '../agent-controller/session';\nimport type { Mastra } from '../mastra';\nimport type { StorageThreadType } from '../memory/types';\nimport type { RequestContext } from '../request-context';\n\nimport { AgentChannels } from './agent-channels';\nimport type { ChannelConfig } from './types';\n\n/** Configuration for {@link AgentControllerChannels}. Same shape as agent channels. */\nexport type AgentControllerChannelsConfig = ChannelConfig;\n\n/**\n * Runs an AgentController inside chat channels (Slack, Discord, ...).\n *\n * Extends {@link AgentChannels} so all inbound machinery (thread mapping,\n * history, attachments, event context) and all outbound rendering\n * (`ChatChannelOutputProcessor` with native streaming, tool cards, typing\n * status) are reused unchanged. Only the dispatch seams differ: instead of\n * routing into a bare agent, inbound messages route into a controller\n * `Session` — one durable session per chat thread, keyed by the mapped\n * Mastra thread's `resourceId`.\n *\n * V1 targets long-lived servers: controller sessions are in-memory objects\n * and do not survive process restarts.\n */\nexport class AgentControllerChannels extends AgentChannels {\n private controller: AgentController<any> | null = null;\n\n /**\n * Session resourceIds whose adapter can't render approval buttons, so their\n * runs must auto-approve tools (`requireToolApproval: false`) instead of\n * parking forever on an approval nobody can answer. Kept outside session\n * state on purpose: state is validated against the controller's\n * `stateSchema`, which would strip (or reject) an injected flag. Refreshed\n * on every inbound message; in-memory only, matching the v1 long-lived\n * server scope.\n */\n private autoApproveResourceIds = new Set<string>();\n\n /** @internal Called by AgentController's constructor to bind itself. */\n __setController(controller: AgentController<any>): void {\n this.controller = controller;\n }\n\n /**\n * @internal Consulted by the controller's run-option builder: `true` when\n * the session's channel adapter can't render approval buttons and tool\n * calls must auto-approve (the session-side equivalent of the base agent\n * path's `autoResumeSuspendedTools`).\n */\n __isAutoApproveResource(resourceId: string): boolean {\n return this.autoApproveResourceIds.has(resourceId);\n }\n\n /**\n * @internal No-op override. The controller attaches this instance to its\n * mode agents via `Agent.setChannels`, which calls `__setAgent(agent)` —\n * with multiple mode agents the last one would win. Every `this.agent` use\n * is overridden in this subclass, so keep the base field unset rather than\n * holding a misleading ref.\n */\n override __setAgent(_agent: Agent<any, any, any, any>): void {}\n\n protected override getOwnerId(): string | null {\n return this.controller?.id ?? null;\n }\n\n protected override getWebhookBasePath(): string {\n return `/api/agent-controllers/${this.getOwnerId()}`;\n }\n\n protected override getMastra(): Mastra | undefined {\n return this.controller?.getMastra();\n }\n\n /**\n * One session per chat thread: unless the user supplied a custom\n * `resolveResourceId`, key new Mastra threads (and therefore controller\n * sessions) off the platform + external thread id.\n */\n protected override resolveChannelResourceId(args: {\n platform: string;\n chatThread: Thread;\n message: Message;\n defaultResourceId: string;\n }): string | (() => string | Promise<string>) {\n const base = super.resolveChannelResourceId(args);\n // The base returns a thunk only when a custom resolveResourceId was\n // configured — honor it. Otherwise derive the channel-thread key. The\n // adapter's thread id is already platform-prefixed (e.g. `slack:C123:ts`),\n // so don't prepend the platform again or the key double-prefixes.\n if (typeof base === 'function') return base;\n return `channel:${args.chatThread.id}`;\n }\n\n /**\n * Route an inbound chat message into the controller session bound to this\n * chat thread. Output renders back to the platform through the channels\n * output processor: the `requestContext` built by the base class (carrying\n * the channel context and render context) flows through the session into\n * the run.\n */\n protected override async dispatchInboundMessage(args: {\n signalContents: AgentSignalContents;\n attributes: Record<string, string | undefined>;\n providerOptions: MastraProviderMetadata;\n requestContext: RequestContext;\n thread: StorageThreadType;\n memory: { thread: string; resource: string };\n autoResumeSuspendedTools: true | undefined;\n }): Promise<void> {\n const { signalContents, attributes, providerOptions, requestContext, thread, autoResumeSuspendedTools } = args;\n\n // The tenant, when there is one, is already stamped on `requestContext` by\n // the channel handler that accepted this message — a host that maps\n // platform senders to Mastra users writes `user` before calling\n // `defaultHandler`, and gating an unlinked sender means not calling it at\n // all. Core dispatches whatever reaches it.\n const session = await this.getSessionForThread(thread, requestContext);\n\n // The session equivalent of the base path's `autoResumeSuspendedTools`:\n // controller runs set `requireToolApproval` from this marker, so on\n // adapters that can't render approval buttons the run auto-approves\n // instead of parking forever on an approval nobody can answer. Tracked\n // outside session state so the controller's `stateSchema` (which would\n // strip or reject an injected key) never sees it.\n const sessionResourceId = thread.resourceId;\n if (autoResumeSuspendedTools) {\n this.autoApproveResourceIds.add(sessionResourceId);\n } else {\n this.autoApproveResourceIds.delete(sessionResourceId);\n }\n\n const result = session.sendSignal({\n content: signalContents,\n ifActive: { attributes },\n ifIdle: { attributes },\n requestContext,\n providerOptions,\n });\n await result.accepted;\n }\n\n /**\n * Resolve an approval-card \"approve\" action against the controller session's\n * parked tool-approval gate. The run engine — awaiting the gate inside its\n * stream-consumer loop — performs the actual resume itself and keeps\n * consuming, so the continuation renders through the output processor.\n */\n protected override async dispatchApproval(args: {\n runId: string;\n toolCallId: string;\n requestContext: RequestContext;\n memory: { thread: string; resource: string };\n }): Promise<void> {\n await this.respondToSessionApproval({ decision: 'approve', ...args });\n }\n\n /**\n * Resolve an approval-card \"deny\" action against the controller session's\n * parked tool-approval gate (see {@link dispatchApproval}).\n */\n protected override async dispatchDecline(args: {\n runId: string;\n toolCallId: string;\n requestContext: RequestContext;\n memory: { thread: string; resource: string };\n }): Promise<void> {\n await this.respondToSessionApproval({ decision: 'decline', ...args });\n }\n\n /**\n * Shared approve/decline path. Never calls the session's internal\n * `approveToolCall`/`declineToolCall` executors directly — the engine parked\n * at the gate owns the resume. `respondToToolApproval` is a silent no-op\n * when nothing is armed or the toolCallId mismatches, so staleness is\n * pre-checked explicitly (an armed gate does not survive process restarts,\n * so restart-recovered approvals are always stale — consistent with the\n * v1 long-lived-server scope).\n */\n private async respondToSessionApproval({\n decision,\n toolCallId,\n requestContext,\n memory,\n }: {\n decision: 'approve' | 'decline';\n toolCallId: string;\n requestContext: RequestContext;\n memory: { thread: string; resource: string };\n }): Promise<void> {\n const session = await this.getSessionForThread({ id: memory.thread, resourceId: memory.resource });\n if (!session.approval.isArmed() || session.approval.getToolCallId() !== toolCallId) {\n this.log(\n 'info',\n `Ignoring stale tool ${decision === 'approve' ? 'approval' : 'denial'} action (no matching parked approval for toolCallId=${toolCallId})`,\n );\n return;\n }\n // The requestContext carries the channel render context, so the resumed\n // stream renders back to the platform through the output processor.\n session.respondToToolApproval({ decision, toolCallId, requestContext });\n }\n\n /**\n * Get-or-create the durable controller session for a mapped channel thread\n * and bind it to that thread. Keyed off the thread's own `resourceId` so\n * pre-existing threads (custom resolveResourceId, or created before this\n * feature) always pass the session's thread-ownership check.\n */\n protected async getSessionForThread(\n thread: Pick<StorageThreadType, 'id' | 'resourceId'>,\n requestContext?: RequestContext,\n ): Promise<Session<any>> {\n const controller = this.requireController();\n const channelResourceId = thread.resourceId;\n // `createSession` is get-or-create keyed by resourceId, so follow-up messages\n // on the same thread reuse the cached session bound to this thread. The\n // dispatch requestContext must flow in: a dynamic workspace factory is\n // resolved once at session creation with THIS context, and it may need the\n // stamped tenant (`user`) to authorize a repo-backed session workspace.\n const session = await controller.createSession({\n resourceId: channelResourceId,\n id: channelResourceId,\n ownerId: controller.id,\n requestContext,\n });\n // Bind the mapped thread. Guard is mandatory: `switch` aborts any active\n // run, so never re-switch when the session is already on this thread.\n if (session.thread.getId() !== thread.id) {\n await session.thread.switch({ threadId: thread.id });\n }\n return session;\n }\n\n private requireController(): AgentController<any> {\n if (!this.controller) {\n throw new Error(\n 'AgentControllerChannels is not bound to an AgentController. Pass it via `channels` in AgentControllerConfig.',\n );\n }\n return this.controller;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AA+BA,IAAa,0BAAb,cAA6CA,cAAAA,cAAc;CACzD,aAAkD;;;;;;;;;;CAWlD,yCAAiC,IAAI,IAAY;;CAGjD,gBAAgB,YAAwC;EACtD,KAAK,aAAa;CACpB;;;;;;;CAQA,wBAAwB,YAA6B;EACnD,OAAO,KAAK,uBAAuB,IAAI,UAAU;CACnD;;;;;;;;CASA,WAAoB,QAAyC,CAAC;CAE9D,aAA+C;EAC7C,OAAO,KAAK,YAAY,MAAM;CAChC;CAEA,qBAAgD;EAC9C,OAAO,0BAA0B,KAAK,WAAW;CACnD;CAEA,YAAmD;EACjD,OAAO,KAAK,YAAY,UAAU;CACpC;;;;;;CAOA,yBAA4C,MAKE;EAC5C,MAAM,OAAO,MAAM,yBAAyB,IAAI;EAKhD,IAAI,OAAO,SAAS,YAAY,OAAO;EACvC,OAAO,WAAW,KAAK,WAAW;CACpC;;;;;;;;CASA,MAAyB,uBAAuB,MAQ9B;EAChB,MAAM,EAAE,gBAAgB,YAAY,iBAAiB,gBAAgB,QAAQ,6BAA6B;EAO1G,MAAM,UAAU,MAAM,KAAK,oBAAoB,QAAQ,cAAc;EAQrE,MAAM,oBAAoB,OAAO;EACjC,IAAI,0BACF,KAAK,uBAAuB,IAAI,iBAAiB;OAEjD,KAAK,uBAAuB,OAAO,iBAAiB;EAUtD,MAPe,QAAQ,WAAW;GAChC,SAAS;GACT,UAAU,EAAE,WAAW;GACvB,QAAQ,EAAE,WAAW;GACrB;GACA;EACF,CACW,CAAC,CAAC;CACf;;;;;;;CAQA,MAAyB,iBAAiB,MAKxB;EAChB,MAAM,KAAK,yBAAyB;GAAE,UAAU;GAAW,GAAG;EAAK,CAAC;CACtE;;;;;CAMA,MAAyB,gBAAgB,MAKvB;EAChB,MAAM,KAAK,yBAAyB;GAAE,UAAU;GAAW,GAAG;EAAK,CAAC;CACtE;;;;;;;;;;CAWA,MAAc,yBAAyB,EACrC,UACA,YACA,gBACA,UAMgB;EAChB,MAAM,UAAU,MAAM,KAAK,oBAAoB;GAAE,IAAI,OAAO;GAAQ,YAAY,OAAO;EAAS,CAAC;EACjG,IAAI,CAAC,QAAQ,SAAS,QAAQ,KAAK,QAAQ,SAAS,cAAc,MAAM,YAAY;GAClF,KAAK,IACH,QACA,uBAAuB,aAAa,YAAY,aAAa,SAAS,sDAAsD,WAAW,EACzI;GACA;EACF;EAGA,QAAQ,sBAAsB;GAAE;GAAU;GAAY;EAAe,CAAC;CACxE;;;;;;;CAQA,MAAgB,oBACd,QACA,gBACuB;EACvB,MAAM,aAAa,KAAK,kBAAkB;EAC1C,MAAM,oBAAoB,OAAO;EAMjC,MAAM,UAAU,MAAM,WAAW,cAAc;GAC7C,YAAY;GACZ,IAAI;GACJ,SAAS,WAAW;GACpB;EACF,CAAC;EAGD,IAAI,QAAQ,OAAO,MAAM,MAAM,OAAO,IACpC,MAAM,QAAQ,OAAO,OAAO,EAAE,UAAU,OAAO,GAAG,CAAC;EAErD,OAAO;CACT;CAEA,oBAAkD;EAChD,IAAI,CAAC,KAAK,YACR,MAAM,IAAI,MACR,8GACF;EAEF,OAAO,KAAK;CACd;AACF"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { M as AgentChannels } from "./agent-
|
|
1
|
+
import { M as AgentChannels } from "./agent-0y2cApTZ.js";
|
|
2
2
|
//#region src/channels/agent-controller-channels.ts
|
|
3
3
|
/**
|
|
4
4
|
* Runs an AgentController inside chat channels (Slack, Discord, ...).
|
|
@@ -159,4 +159,4 @@ var AgentControllerChannels = class extends AgentChannels {
|
|
|
159
159
|
//#endregion
|
|
160
160
|
export { AgentControllerChannels as t };
|
|
161
161
|
|
|
162
|
-
//# sourceMappingURL=channels-
|
|
162
|
+
//# sourceMappingURL=channels-MegO_4KL.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channels-Da9lEAi1.js","names":[],"sources":["../src/channels/agent-controller-channels.ts"],"sourcesContent":["import type { Message, Thread } from 'chat';\n\nimport type { Agent } from '../agent/agent';\nimport type { MastraProviderMetadata } from '../agent/message-list/state/types';\nimport type { AgentSignalContents } from '../agent/signals';\nimport type { AgentController } from '../agent-controller/agent-controller';\nimport type { Session } from '../agent-controller/session';\nimport type { Mastra } from '../mastra';\nimport type { StorageThreadType } from '../memory/types';\nimport type { RequestContext } from '../request-context';\n\nimport { AgentChannels } from './agent-channels';\nimport type { ChannelConfig } from './types';\n\n/** Configuration for {@link AgentControllerChannels}. Same shape as agent channels. */\nexport type AgentControllerChannelsConfig = ChannelConfig;\n\n/**\n * Runs an AgentController inside chat channels (Slack, Discord, ...).\n *\n * Extends {@link AgentChannels} so all inbound machinery (thread mapping,\n * history, attachments, event context) and all outbound rendering\n * (`ChatChannelOutputProcessor` with native streaming, tool cards, typing\n * status) are reused unchanged. Only the dispatch seams differ: instead of\n * routing into a bare agent, inbound messages route into a controller\n * `Session` — one durable session per chat thread, keyed by the mapped\n * Mastra thread's `resourceId`.\n *\n * V1 targets long-lived servers: controller sessions are in-memory objects\n * and do not survive process restarts.\n */\nexport class AgentControllerChannels extends AgentChannels {\n private controller: AgentController<any> | null = null;\n\n /**\n * Session resourceIds whose adapter can't render approval buttons, so their\n * runs must auto-approve tools (`requireToolApproval: false`) instead of\n * parking forever on an approval nobody can answer. Kept outside session\n * state on purpose: state is validated against the controller's\n * `stateSchema`, which would strip (or reject) an injected flag. Refreshed\n * on every inbound message; in-memory only, matching the v1 long-lived\n * server scope.\n */\n private autoApproveResourceIds = new Set<string>();\n\n /** @internal Called by AgentController's constructor to bind itself. */\n __setController(controller: AgentController<any>): void {\n this.controller = controller;\n }\n\n /**\n * @internal Consulted by the controller's run-option builder: `true` when\n * the session's channel adapter can't render approval buttons and tool\n * calls must auto-approve (the session-side equivalent of the base agent\n * path's `autoResumeSuspendedTools`).\n */\n __isAutoApproveResource(resourceId: string): boolean {\n return this.autoApproveResourceIds.has(resourceId);\n }\n\n /**\n * @internal No-op override. The controller attaches this instance to its\n * mode agents via `Agent.setChannels`, which calls `__setAgent(agent)` —\n * with multiple mode agents the last one would win. Every `this.agent` use\n * is overridden in this subclass, so keep the base field unset rather than\n * holding a misleading ref.\n */\n override __setAgent(_agent: Agent<any, any, any, any>): void {}\n\n protected override getOwnerId(): string | null {\n return this.controller?.id ?? null;\n }\n\n protected override getWebhookBasePath(): string {\n return `/api/agent-controllers/${this.getOwnerId()}`;\n }\n\n protected override getMastra(): Mastra | undefined {\n return this.controller?.getMastra();\n }\n\n /**\n * One session per chat thread: unless the user supplied a custom\n * `resolveResourceId`, key new Mastra threads (and therefore controller\n * sessions) off the platform + external thread id.\n */\n protected override resolveChannelResourceId(args: {\n platform: string;\n chatThread: Thread;\n message: Message;\n defaultResourceId: string;\n }): string | (() => string | Promise<string>) {\n const base = super.resolveChannelResourceId(args);\n // The base returns a thunk only when a custom resolveResourceId was\n // configured — honor it. Otherwise derive the channel-thread key. The\n // adapter's thread id is already platform-prefixed (e.g. `slack:C123:ts`),\n // so don't prepend the platform again or the key double-prefixes.\n if (typeof base === 'function') return base;\n return `channel:${args.chatThread.id}`;\n }\n\n /**\n * Route an inbound chat message into the controller session bound to this\n * chat thread. Output renders back to the platform through the channels\n * output processor: the `requestContext` built by the base class (carrying\n * the channel context and render context) flows through the session into\n * the run.\n */\n protected override async dispatchInboundMessage(args: {\n signalContents: AgentSignalContents;\n attributes: Record<string, string | undefined>;\n providerOptions: MastraProviderMetadata;\n requestContext: RequestContext;\n thread: StorageThreadType;\n memory: { thread: string; resource: string };\n autoResumeSuspendedTools: true | undefined;\n }): Promise<void> {\n const { signalContents, attributes, providerOptions, requestContext, thread, autoResumeSuspendedTools } = args;\n\n // The tenant, when there is one, is already stamped on `requestContext` by\n // the channel handler that accepted this message — a host that maps\n // platform senders to Mastra users writes `user` before calling\n // `defaultHandler`, and gating an unlinked sender means not calling it at\n // all. Core dispatches whatever reaches it.\n const session = await this.getSessionForThread(thread, requestContext);\n\n // The session equivalent of the base path's `autoResumeSuspendedTools`:\n // controller runs set `requireToolApproval` from this marker, so on\n // adapters that can't render approval buttons the run auto-approves\n // instead of parking forever on an approval nobody can answer. Tracked\n // outside session state so the controller's `stateSchema` (which would\n // strip or reject an injected key) never sees it.\n const sessionResourceId = thread.resourceId;\n if (autoResumeSuspendedTools) {\n this.autoApproveResourceIds.add(sessionResourceId);\n } else {\n this.autoApproveResourceIds.delete(sessionResourceId);\n }\n\n const result = session.sendSignal({\n content: signalContents,\n ifActive: { attributes },\n ifIdle: { attributes },\n requestContext,\n providerOptions,\n });\n await result.accepted;\n }\n\n /**\n * Resolve an approval-card \"approve\" action against the controller session's\n * parked tool-approval gate. The run engine — awaiting the gate inside its\n * stream-consumer loop — performs the actual resume itself and keeps\n * consuming, so the continuation renders through the output processor.\n */\n protected override async dispatchApproval(args: {\n runId: string;\n toolCallId: string;\n requestContext: RequestContext;\n memory: { thread: string; resource: string };\n }): Promise<void> {\n await this.respondToSessionApproval({ decision: 'approve', ...args });\n }\n\n /**\n * Resolve an approval-card \"deny\" action against the controller session's\n * parked tool-approval gate (see {@link dispatchApproval}).\n */\n protected override async dispatchDecline(args: {\n runId: string;\n toolCallId: string;\n requestContext: RequestContext;\n memory: { thread: string; resource: string };\n }): Promise<void> {\n await this.respondToSessionApproval({ decision: 'decline', ...args });\n }\n\n /**\n * Shared approve/decline path. Never calls the session's internal\n * `approveToolCall`/`declineToolCall` executors directly — the engine parked\n * at the gate owns the resume. `respondToToolApproval` is a silent no-op\n * when nothing is armed or the toolCallId mismatches, so staleness is\n * pre-checked explicitly (an armed gate does not survive process restarts,\n * so restart-recovered approvals are always stale — consistent with the\n * v1 long-lived-server scope).\n */\n private async respondToSessionApproval({\n decision,\n toolCallId,\n requestContext,\n memory,\n }: {\n decision: 'approve' | 'decline';\n toolCallId: string;\n requestContext: RequestContext;\n memory: { thread: string; resource: string };\n }): Promise<void> {\n const session = await this.getSessionForThread({ id: memory.thread, resourceId: memory.resource });\n if (!session.approval.isArmed() || session.approval.getToolCallId() !== toolCallId) {\n this.log(\n 'info',\n `Ignoring stale tool ${decision === 'approve' ? 'approval' : 'denial'} action (no matching parked approval for toolCallId=${toolCallId})`,\n );\n return;\n }\n // The requestContext carries the channel render context, so the resumed\n // stream renders back to the platform through the output processor.\n session.respondToToolApproval({ decision, toolCallId, requestContext });\n }\n\n /**\n * Get-or-create the durable controller session for a mapped channel thread\n * and bind it to that thread. Keyed off the thread's own `resourceId` so\n * pre-existing threads (custom resolveResourceId, or created before this\n * feature) always pass the session's thread-ownership check.\n */\n protected async getSessionForThread(\n thread: Pick<StorageThreadType, 'id' | 'resourceId'>,\n requestContext?: RequestContext,\n ): Promise<Session<any>> {\n const controller = this.requireController();\n const channelResourceId = thread.resourceId;\n // `createSession` is get-or-create keyed by resourceId, so follow-up messages\n // on the same thread reuse the cached session bound to this thread. The\n // dispatch requestContext must flow in: a dynamic workspace factory is\n // resolved once at session creation with THIS context, and it may need the\n // stamped tenant (`user`) to authorize a repo-backed session workspace.\n const session = await controller.createSession({\n resourceId: channelResourceId,\n id: channelResourceId,\n ownerId: controller.id,\n requestContext,\n });\n // Bind the mapped thread. Guard is mandatory: `switch` aborts any active\n // run, so never re-switch when the session is already on this thread.\n if (session.thread.getId() !== thread.id) {\n await session.thread.switch({ threadId: thread.id });\n }\n return session;\n }\n\n private requireController(): AgentController<any> {\n if (!this.controller) {\n throw new Error(\n 'AgentControllerChannels is not bound to an AgentController. Pass it via `channels` in AgentControllerConfig.',\n );\n }\n return this.controller;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AA+BA,IAAa,0BAAb,cAA6C,cAAc;CACzD,aAAkD;;;;;;;;;;CAWlD,yCAAiC,IAAI,IAAY;;CAGjD,gBAAgB,YAAwC;EACtD,KAAK,aAAa;CACpB;;;;;;;CAQA,wBAAwB,YAA6B;EACnD,OAAO,KAAK,uBAAuB,IAAI,UAAU;CACnD;;;;;;;;CASA,WAAoB,QAAyC,CAAC;CAE9D,aAA+C;EAC7C,OAAO,KAAK,YAAY,MAAM;CAChC;CAEA,qBAAgD;EAC9C,OAAO,0BAA0B,KAAK,WAAW;CACnD;CAEA,YAAmD;EACjD,OAAO,KAAK,YAAY,UAAU;CACpC;;;;;;CAOA,yBAA4C,MAKE;EAC5C,MAAM,OAAO,MAAM,yBAAyB,IAAI;EAKhD,IAAI,OAAO,SAAS,YAAY,OAAO;EACvC,OAAO,WAAW,KAAK,WAAW;CACpC;;;;;;;;CASA,MAAyB,uBAAuB,MAQ9B;EAChB,MAAM,EAAE,gBAAgB,YAAY,iBAAiB,gBAAgB,QAAQ,6BAA6B;EAO1G,MAAM,UAAU,MAAM,KAAK,oBAAoB,QAAQ,cAAc;EAQrE,MAAM,oBAAoB,OAAO;EACjC,IAAI,0BACF,KAAK,uBAAuB,IAAI,iBAAiB;OAEjD,KAAK,uBAAuB,OAAO,iBAAiB;EAUtD,MAPe,QAAQ,WAAW;GAChC,SAAS;GACT,UAAU,EAAE,WAAW;GACvB,QAAQ,EAAE,WAAW;GACrB;GACA;EACF,CACW,CAAC,CAAC;CACf;;;;;;;CAQA,MAAyB,iBAAiB,MAKxB;EAChB,MAAM,KAAK,yBAAyB;GAAE,UAAU;GAAW,GAAG;EAAK,CAAC;CACtE;;;;;CAMA,MAAyB,gBAAgB,MAKvB;EAChB,MAAM,KAAK,yBAAyB;GAAE,UAAU;GAAW,GAAG;EAAK,CAAC;CACtE;;;;;;;;;;CAWA,MAAc,yBAAyB,EACrC,UACA,YACA,gBACA,UAMgB;EAChB,MAAM,UAAU,MAAM,KAAK,oBAAoB;GAAE,IAAI,OAAO;GAAQ,YAAY,OAAO;EAAS,CAAC;EACjG,IAAI,CAAC,QAAQ,SAAS,QAAQ,KAAK,QAAQ,SAAS,cAAc,MAAM,YAAY;GAClF,KAAK,IACH,QACA,uBAAuB,aAAa,YAAY,aAAa,SAAS,sDAAsD,WAAW,EACzI;GACA;EACF;EAGA,QAAQ,sBAAsB;GAAE;GAAU;GAAY;EAAe,CAAC;CACxE;;;;;;;CAQA,MAAgB,oBACd,QACA,gBACuB;EACvB,MAAM,aAAa,KAAK,kBAAkB;EAC1C,MAAM,oBAAoB,OAAO;EAMjC,MAAM,UAAU,MAAM,WAAW,cAAc;GAC7C,YAAY;GACZ,IAAI;GACJ,SAAS,WAAW;GACpB;EACF,CAAC;EAGD,IAAI,QAAQ,OAAO,MAAM,MAAM,OAAO,IACpC,MAAM,QAAQ,OAAO,OAAO,EAAE,UAAU,OAAO,GAAG,CAAC;EAErD,OAAO;CACT;CAEA,oBAAkD;EAChD,IAAI,CAAC,KAAK,YACR,MAAM,IAAI,MACR,8GACF;EAEF,OAAO,KAAK;CACd;AACF"}
|
|
1
|
+
{"version":3,"file":"channels-MegO_4KL.js","names":[],"sources":["../src/channels/agent-controller-channels.ts"],"sourcesContent":["import type { Message, Thread } from 'chat';\n\nimport type { Agent } from '../agent/agent';\nimport type { MastraProviderMetadata } from '../agent/message-list/state/types';\nimport type { AgentSignalContents } from '../agent/signals';\nimport type { AgentController } from '../agent-controller/agent-controller';\nimport type { Session } from '../agent-controller/session';\nimport type { Mastra } from '../mastra';\nimport type { StorageThreadType } from '../memory/types';\nimport type { RequestContext } from '../request-context';\n\nimport { AgentChannels } from './agent-channels';\nimport type { ChannelConfig } from './types';\n\n/** Configuration for {@link AgentControllerChannels}. Same shape as agent channels. */\nexport type AgentControllerChannelsConfig = ChannelConfig;\n\n/**\n * Runs an AgentController inside chat channels (Slack, Discord, ...).\n *\n * Extends {@link AgentChannels} so all inbound machinery (thread mapping,\n * history, attachments, event context) and all outbound rendering\n * (`ChatChannelOutputProcessor` with native streaming, tool cards, typing\n * status) are reused unchanged. Only the dispatch seams differ: instead of\n * routing into a bare agent, inbound messages route into a controller\n * `Session` — one durable session per chat thread, keyed by the mapped\n * Mastra thread's `resourceId`.\n *\n * V1 targets long-lived servers: controller sessions are in-memory objects\n * and do not survive process restarts.\n */\nexport class AgentControllerChannels extends AgentChannels {\n private controller: AgentController<any> | null = null;\n\n /**\n * Session resourceIds whose adapter can't render approval buttons, so their\n * runs must auto-approve tools (`requireToolApproval: false`) instead of\n * parking forever on an approval nobody can answer. Kept outside session\n * state on purpose: state is validated against the controller's\n * `stateSchema`, which would strip (or reject) an injected flag. Refreshed\n * on every inbound message; in-memory only, matching the v1 long-lived\n * server scope.\n */\n private autoApproveResourceIds = new Set<string>();\n\n /** @internal Called by AgentController's constructor to bind itself. */\n __setController(controller: AgentController<any>): void {\n this.controller = controller;\n }\n\n /**\n * @internal Consulted by the controller's run-option builder: `true` when\n * the session's channel adapter can't render approval buttons and tool\n * calls must auto-approve (the session-side equivalent of the base agent\n * path's `autoResumeSuspendedTools`).\n */\n __isAutoApproveResource(resourceId: string): boolean {\n return this.autoApproveResourceIds.has(resourceId);\n }\n\n /**\n * @internal No-op override. The controller attaches this instance to its\n * mode agents via `Agent.setChannels`, which calls `__setAgent(agent)` —\n * with multiple mode agents the last one would win. Every `this.agent` use\n * is overridden in this subclass, so keep the base field unset rather than\n * holding a misleading ref.\n */\n override __setAgent(_agent: Agent<any, any, any, any>): void {}\n\n protected override getOwnerId(): string | null {\n return this.controller?.id ?? null;\n }\n\n protected override getWebhookBasePath(): string {\n return `/api/agent-controllers/${this.getOwnerId()}`;\n }\n\n protected override getMastra(): Mastra | undefined {\n return this.controller?.getMastra();\n }\n\n /**\n * One session per chat thread: unless the user supplied a custom\n * `resolveResourceId`, key new Mastra threads (and therefore controller\n * sessions) off the platform + external thread id.\n */\n protected override resolveChannelResourceId(args: {\n platform: string;\n chatThread: Thread;\n message: Message;\n defaultResourceId: string;\n }): string | (() => string | Promise<string>) {\n const base = super.resolveChannelResourceId(args);\n // The base returns a thunk only when a custom resolveResourceId was\n // configured — honor it. Otherwise derive the channel-thread key. The\n // adapter's thread id is already platform-prefixed (e.g. `slack:C123:ts`),\n // so don't prepend the platform again or the key double-prefixes.\n if (typeof base === 'function') return base;\n return `channel:${args.chatThread.id}`;\n }\n\n /**\n * Route an inbound chat message into the controller session bound to this\n * chat thread. Output renders back to the platform through the channels\n * output processor: the `requestContext` built by the base class (carrying\n * the channel context and render context) flows through the session into\n * the run.\n */\n protected override async dispatchInboundMessage(args: {\n signalContents: AgentSignalContents;\n attributes: Record<string, string | undefined>;\n providerOptions: MastraProviderMetadata;\n requestContext: RequestContext;\n thread: StorageThreadType;\n memory: { thread: string; resource: string };\n autoResumeSuspendedTools: true | undefined;\n }): Promise<void> {\n const { signalContents, attributes, providerOptions, requestContext, thread, autoResumeSuspendedTools } = args;\n\n // The tenant, when there is one, is already stamped on `requestContext` by\n // the channel handler that accepted this message — a host that maps\n // platform senders to Mastra users writes `user` before calling\n // `defaultHandler`, and gating an unlinked sender means not calling it at\n // all. Core dispatches whatever reaches it.\n const session = await this.getSessionForThread(thread, requestContext);\n\n // The session equivalent of the base path's `autoResumeSuspendedTools`:\n // controller runs set `requireToolApproval` from this marker, so on\n // adapters that can't render approval buttons the run auto-approves\n // instead of parking forever on an approval nobody can answer. Tracked\n // outside session state so the controller's `stateSchema` (which would\n // strip or reject an injected key) never sees it.\n const sessionResourceId = thread.resourceId;\n if (autoResumeSuspendedTools) {\n this.autoApproveResourceIds.add(sessionResourceId);\n } else {\n this.autoApproveResourceIds.delete(sessionResourceId);\n }\n\n const result = session.sendSignal({\n content: signalContents,\n ifActive: { attributes },\n ifIdle: { attributes },\n requestContext,\n providerOptions,\n });\n await result.accepted;\n }\n\n /**\n * Resolve an approval-card \"approve\" action against the controller session's\n * parked tool-approval gate. The run engine — awaiting the gate inside its\n * stream-consumer loop — performs the actual resume itself and keeps\n * consuming, so the continuation renders through the output processor.\n */\n protected override async dispatchApproval(args: {\n runId: string;\n toolCallId: string;\n requestContext: RequestContext;\n memory: { thread: string; resource: string };\n }): Promise<void> {\n await this.respondToSessionApproval({ decision: 'approve', ...args });\n }\n\n /**\n * Resolve an approval-card \"deny\" action against the controller session's\n * parked tool-approval gate (see {@link dispatchApproval}).\n */\n protected override async dispatchDecline(args: {\n runId: string;\n toolCallId: string;\n requestContext: RequestContext;\n memory: { thread: string; resource: string };\n }): Promise<void> {\n await this.respondToSessionApproval({ decision: 'decline', ...args });\n }\n\n /**\n * Shared approve/decline path. Never calls the session's internal\n * `approveToolCall`/`declineToolCall` executors directly — the engine parked\n * at the gate owns the resume. `respondToToolApproval` is a silent no-op\n * when nothing is armed or the toolCallId mismatches, so staleness is\n * pre-checked explicitly (an armed gate does not survive process restarts,\n * so restart-recovered approvals are always stale — consistent with the\n * v1 long-lived-server scope).\n */\n private async respondToSessionApproval({\n decision,\n toolCallId,\n requestContext,\n memory,\n }: {\n decision: 'approve' | 'decline';\n toolCallId: string;\n requestContext: RequestContext;\n memory: { thread: string; resource: string };\n }): Promise<void> {\n const session = await this.getSessionForThread({ id: memory.thread, resourceId: memory.resource });\n if (!session.approval.isArmed() || session.approval.getToolCallId() !== toolCallId) {\n this.log(\n 'info',\n `Ignoring stale tool ${decision === 'approve' ? 'approval' : 'denial'} action (no matching parked approval for toolCallId=${toolCallId})`,\n );\n return;\n }\n // The requestContext carries the channel render context, so the resumed\n // stream renders back to the platform through the output processor.\n session.respondToToolApproval({ decision, toolCallId, requestContext });\n }\n\n /**\n * Get-or-create the durable controller session for a mapped channel thread\n * and bind it to that thread. Keyed off the thread's own `resourceId` so\n * pre-existing threads (custom resolveResourceId, or created before this\n * feature) always pass the session's thread-ownership check.\n */\n protected async getSessionForThread(\n thread: Pick<StorageThreadType, 'id' | 'resourceId'>,\n requestContext?: RequestContext,\n ): Promise<Session<any>> {\n const controller = this.requireController();\n const channelResourceId = thread.resourceId;\n // `createSession` is get-or-create keyed by resourceId, so follow-up messages\n // on the same thread reuse the cached session bound to this thread. The\n // dispatch requestContext must flow in: a dynamic workspace factory is\n // resolved once at session creation with THIS context, and it may need the\n // stamped tenant (`user`) to authorize a repo-backed session workspace.\n const session = await controller.createSession({\n resourceId: channelResourceId,\n id: channelResourceId,\n ownerId: controller.id,\n requestContext,\n });\n // Bind the mapped thread. Guard is mandatory: `switch` aborts any active\n // run, so never re-switch when the session is already on this thread.\n if (session.thread.getId() !== thread.id) {\n await session.thread.switch({ threadId: thread.id });\n }\n return session;\n }\n\n private requireController(): AgentController<any> {\n if (!this.controller) {\n throw new Error(\n 'AgentControllerChannels is not bound to an AgentController. Pass it via `channels` in AgentControllerConfig.',\n );\n }\n return this.controller;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AA+BA,IAAa,0BAAb,cAA6C,cAAc;CACzD,aAAkD;;;;;;;;;;CAWlD,yCAAiC,IAAI,IAAY;;CAGjD,gBAAgB,YAAwC;EACtD,KAAK,aAAa;CACpB;;;;;;;CAQA,wBAAwB,YAA6B;EACnD,OAAO,KAAK,uBAAuB,IAAI,UAAU;CACnD;;;;;;;;CASA,WAAoB,QAAyC,CAAC;CAE9D,aAA+C;EAC7C,OAAO,KAAK,YAAY,MAAM;CAChC;CAEA,qBAAgD;EAC9C,OAAO,0BAA0B,KAAK,WAAW;CACnD;CAEA,YAAmD;EACjD,OAAO,KAAK,YAAY,UAAU;CACpC;;;;;;CAOA,yBAA4C,MAKE;EAC5C,MAAM,OAAO,MAAM,yBAAyB,IAAI;EAKhD,IAAI,OAAO,SAAS,YAAY,OAAO;EACvC,OAAO,WAAW,KAAK,WAAW;CACpC;;;;;;;;CASA,MAAyB,uBAAuB,MAQ9B;EAChB,MAAM,EAAE,gBAAgB,YAAY,iBAAiB,gBAAgB,QAAQ,6BAA6B;EAO1G,MAAM,UAAU,MAAM,KAAK,oBAAoB,QAAQ,cAAc;EAQrE,MAAM,oBAAoB,OAAO;EACjC,IAAI,0BACF,KAAK,uBAAuB,IAAI,iBAAiB;OAEjD,KAAK,uBAAuB,OAAO,iBAAiB;EAUtD,MAPe,QAAQ,WAAW;GAChC,SAAS;GACT,UAAU,EAAE,WAAW;GACvB,QAAQ,EAAE,WAAW;GACrB;GACA;EACF,CACW,CAAC,CAAC;CACf;;;;;;;CAQA,MAAyB,iBAAiB,MAKxB;EAChB,MAAM,KAAK,yBAAyB;GAAE,UAAU;GAAW,GAAG;EAAK,CAAC;CACtE;;;;;CAMA,MAAyB,gBAAgB,MAKvB;EAChB,MAAM,KAAK,yBAAyB;GAAE,UAAU;GAAW,GAAG;EAAK,CAAC;CACtE;;;;;;;;;;CAWA,MAAc,yBAAyB,EACrC,UACA,YACA,gBACA,UAMgB;EAChB,MAAM,UAAU,MAAM,KAAK,oBAAoB;GAAE,IAAI,OAAO;GAAQ,YAAY,OAAO;EAAS,CAAC;EACjG,IAAI,CAAC,QAAQ,SAAS,QAAQ,KAAK,QAAQ,SAAS,cAAc,MAAM,YAAY;GAClF,KAAK,IACH,QACA,uBAAuB,aAAa,YAAY,aAAa,SAAS,sDAAsD,WAAW,EACzI;GACA;EACF;EAGA,QAAQ,sBAAsB;GAAE;GAAU;GAAY;EAAe,CAAC;CACxE;;;;;;;CAQA,MAAgB,oBACd,QACA,gBACuB;EACvB,MAAM,aAAa,KAAK,kBAAkB;EAC1C,MAAM,oBAAoB,OAAO;EAMjC,MAAM,UAAU,MAAM,WAAW,cAAc;GAC7C,YAAY;GACZ,IAAI;GACJ,SAAS,WAAW;GACpB;EACF,CAAC;EAGD,IAAI,QAAQ,OAAO,MAAM,MAAM,OAAO,IACpC,MAAM,QAAQ,OAAO,OAAO,EAAE,UAAU,OAAO,GAAG,CAAC;EAErD,OAAO;CACT;CAEA,oBAAkD;EAChD,IAAI,CAAC,KAAK,YACR,MAAM,IAAI,MACR,8GACF;EAEF,OAAO,KAAK;CACd;AACF"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_agent = require("../agent-
|
|
2
|
+
const require_agent = require("../agent-um2LJs-0.cjs");
|
|
3
3
|
const require_task_state_processor = require("../task-state-processor-Dh_GxiNX.cjs");
|
|
4
4
|
const require_workspace = require("../workspace-D5VRmEXr.cjs");
|
|
5
5
|
const require_signals = require("../signals-hN0Te5pc.cjs");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ct as StreamErrorRetryProcessor, dt as ProviderHistoryCompat, lt as isBadRequestError, mt as PrefillErrorHandler, t as Agent } from "../agent-
|
|
1
|
+
import { ct as StreamErrorRetryProcessor, dt as ProviderHistoryCompat, lt as isBadRequestError, mt as PrefillErrorHandler, t as Agent } from "../agent-0y2cApTZ.js";
|
|
2
2
|
import { v as DEFAULT_GOAL_JUDGE_PROMPT } from "../task-state-processor-C7EWwpJ9.js";
|
|
3
3
|
import { G as LocalFilesystem, k as LocalSandbox, x as Workspace } from "../workspace-kJgXwpJp.js";
|
|
4
4
|
import { t as TaskSignalProvider } from "../signals-CEJu21_1.js";
|