UNPKG

@mastra/core

Version:

Mastra is a framework for building AI-powered applications and agents with a modern TypeScript stack.

465 lines (456 loc) 14.4 kB
'use strict'; var chunkB3HPYVQP_cjs = require('./chunk-B3HPYVQP.cjs'); var chunkBKPEQNQF_cjs = require('./chunk-BKPEQNQF.cjs'); var chunkM5AKMHS2_cjs = require('./chunk-M5AKMHS2.cjs'); var chunkCAVARKYS_cjs = require('./chunk-CAVARKYS.cjs'); // src/worker/worker.ts var MastraWorker = class { mastra; deps; /** Called by Mastra during registration to provide the instance reference. */ __registerMastra(mastra) { this.mastra = mastra; } /** Initialize with infrastructure deps. Called before start(). */ async init(deps) { this.deps = deps; if (!this.mastra && deps.mastra) { this.mastra = deps.mastra; } } }; // src/worker/strategies/http-remote-strategy.ts var HttpRemoteStrategy = class _HttpRemoteStrategy { #baseUrl; #auth; #timeoutMs; constructor({ serverUrl, auth, timeoutMs }) { const normalized = serverUrl.endsWith("/") ? serverUrl : `${serverUrl}/`; this.#baseUrl = new URL(normalized); this.#auth = auth ?? _HttpRemoteStrategy.#authFromEnv(); this.#timeoutMs = timeoutMs ?? 3e4; } /** * Default credential resolution: when `MASTRA_WORKER_AUTH_TOKEN` is set, * send it as a bearer token. The server's auth provider decides whether * to accept it. */ static #authFromEnv() { const token = process.env.MASTRA_WORKER_AUTH_TOKEN; if (!token) return void 0; return { type: "bearer", token }; } async executeStep(params) { const url = new URL( `workflows/${encodeURIComponent(params.workflowId)}/runs/${encodeURIComponent(params.runId)}/steps/execute`, this.#baseUrl ); const body = this.#buildBody(params); const signal = this.#combineSignals(params.abortSignal); const res = await fetch(url, { method: "POST", headers: { "content-type": "application/json", ...this.#buildAuthHeaders() }, body, signal }); if (!res.ok) { const text = await res.text(); throw new StepExecutionError(res.status, text); } return res.json(); } /** * Build a JSON-serializable request body. The `params.requestContext` is * a plain object; if a caller stuffed a non-serializable value into it we * surface a clear error instead of silently dropping fields. * * `abortSignal` is consumed via fetch's `signal` argument — it must not * be in the body. */ #buildBody(params) { const { abortSignal: _abortSignal, requestContext, ...rest } = params; let safeRequestContext; try { safeRequestContext = JSON.parse(JSON.stringify(requestContext ?? {})); } catch (err) { throw new Error( `HttpRemoteStrategy: requestContext is not JSON-serializable. ${err instanceof Error ? err.message : String(err)}` ); } return JSON.stringify({ ...rest, requestContext: safeRequestContext }); } #combineSignals(externalSignal) { const timeoutSignal = AbortSignal.timeout(this.#timeoutMs); if (!externalSignal) return timeoutSignal; if (typeof AbortSignal.any === "function") { return AbortSignal.any([timeoutSignal, externalSignal]); } const controller = new AbortController(); const onAbort = (reason) => controller.abort(reason); if (externalSignal.aborted) onAbort(externalSignal.reason); else externalSignal.addEventListener("abort", () => onAbort(externalSignal.reason), { once: true }); if (timeoutSignal.aborted) onAbort(timeoutSignal.reason); else timeoutSignal.addEventListener("abort", () => onAbort(timeoutSignal.reason), { once: true }); return controller.signal; } #buildAuthHeaders() { if (!this.#auth) return {}; if (this.#auth.type === "api-key") { return { "x-worker-api-key": this.#auth.key }; } if (this.#auth.type === "header") { return { [this.#auth.name]: this.#auth.value }; } return { authorization: `Bearer ${this.#auth.token}` }; } }; var StepExecutionError = class extends Error { status; body; constructor(status, body) { super(`Step execution failed with status ${status}: ${body}`); this.name = "StepExecutionError"; this.status = status; this.body = body; } }; // src/worker/transport/pull-transport.ts var TOPIC_WORKFLOWS = "workflows"; var PullTransport = class { #pubsub; #group; #logger; #callbacks = []; constructor({ pubsub, group, logger }) { this.#pubsub = pubsub; this.#group = group; this.#logger = logger; } async start(router) { if (this.#callbacks.length > 0) { this.#logger?.debug("[PullTransport] start() called while already subscribed; ignoring duplicate call"); return; } const workflowCb = (event, ack, nack) => { router.route(event, ack, nack).catch((err) => { try { if (typeof nack === "function") { void nack(); } } finally { this.#logger?.error("[PullTransport] router.route rejected", { err }); } }); }; await this.#pubsub.subscribe(TOPIC_WORKFLOWS, workflowCb, { group: this.#group }); this.#callbacks.push({ topic: TOPIC_WORKFLOWS, cb: workflowCb }); } async stop() { for (const { topic, cb } of this.#callbacks) { await this.#pubsub.unsubscribe(topic, cb); } this.#callbacks = []; await this.#pubsub.flush(); } }; // src/worker/workers/orchestration-worker.ts var DEFAULT_GROUP = "mastra-orchestration"; var OrchestrationWorker = class extends MastraWorker { name = "orchestration"; #config; #transport; #processor; #strategy; #running = false; constructor(config = {}) { super(); this.#config = config; } async init(deps) { await super.init(deps); if (!deps.mastra) { throw new Error("OrchestrationWorker requires Mastra instance"); } const modes = deps.pubsub.supportedModes ?? ["pull"]; if (!modes.includes("pull")) { throw new Error( `OrchestrationWorker requires a pull-capable PubSub, but the configured pubsub only supports: ${modes.join(", ")}. Either remove OrchestrationWorker from the workers list or use a pull-capable PubSub (e.g. Redis Streams).` ); } const remoteUrl = process.env.MASTRA_STEP_EXECUTION_URL; if (remoteUrl) { this.#strategy = new HttpRemoteStrategy({ serverUrl: remoteUrl }); } this.#processor = new chunkBKPEQNQF_cjs.WorkflowEventProcessor({ mastra: deps.mastra, stepExecutionStrategy: this.#strategy }); } async start() { if (this.#running) return; if (!this.deps) throw new Error("OrchestrationWorker: call init() before start()"); const group = this.#config.group ?? DEFAULT_GROUP; this.#transport = new PullTransport({ pubsub: this.deps.pubsub, group, logger: this.deps.logger }); await this.#transport.start({ route: (event, ack, nack) => this.#processEvent(event, ack, nack) }); this.#running = true; } async stop() { if (!this.#running) return; try { if (this.#transport) { await this.#transport.stop(); this.#transport = void 0; } } finally { this.#running = false; } } get isRunning() { return this.#running; } async #processEvent(event, ack, nack) { if (!this.#processor) { throw new Error("OrchestrationWorker not initialized"); } const result = await this.#processor.handle(event); if (result.ok) { try { await ack?.(); } catch (e) { this.deps?.logger?.error("OrchestrationWorker: error acking event", { error: e }); } return; } this.deps?.logger?.error("OrchestrationWorker: error processing event", { type: event.type, runId: event.runId, retry: result.retry }); if (nack) { await nack(); } } }; // src/worker/workers/scheduler-worker.ts var SchedulerWorker = class extends MastraWorker { name = "scheduler"; #scheduler; #config; #running = false; constructor(config = {}) { super(); this.#config = config; } async init(deps) { await super.init(deps); if (!deps.storage) { deps.logger.warn("SchedulerWorker: no storage configured, scheduler will not run"); return; } const schedulesStore = await deps.storage.getStore("schedules"); if (!schedulesStore) { deps.logger.warn("SchedulerWorker: no schedules store available, scheduler will not run"); return; } const mastra = this.mastra; const isWorkflowRegistered = mastra ? (workflowId) => { try { mastra.getWorkflowById(workflowId); return true; } catch { return false; } } : void 0; this.#scheduler = new chunkB3HPYVQP_cjs.WorkflowScheduler({ schedulesStore, pubsub: deps.pubsub, config: { ...this.#config, isWorkflowRegistered } }); this.#scheduler.__setLogger(deps.logger); if (this.mastra) { try { await this.mastra.registerDeclarativeSchedules(schedulesStore); } catch (err) { deps.logger.error?.("SchedulerWorker: failed to register declarative schedules", { error: err }); } } } async start() { if (this.#running) return; if (this.#scheduler) { await this.#scheduler.start(); } this.#running = true; } async stop() { if (!this.#running) return; if (this.#scheduler) { await this.#scheduler.stop(); } this.#running = false; } get isRunning() { return this.#running; } /** Expose the underlying scheduler for direct API access (e.g., schedule management). */ get scheduler() { return this.#scheduler; } }; // src/worker/workers/background-task-worker.ts var BackgroundTaskWorker = class extends MastraWorker { name = "backgroundTasks"; #manager; #ownsManager = false; #config; #running = false; constructor(config = {}) { super(); this.#config = config; } async init(deps) { await super.init(deps); const existing = deps.mastra?.backgroundTaskManager; if (existing) { this.#manager = existing; this.#ownsManager = false; return; } this.#manager = new chunkM5AKMHS2_cjs.BackgroundTaskManager({ enabled: true, globalConcurrency: this.#config.globalConcurrency, perAgentConcurrency: this.#config.perAgentConcurrency, backpressure: this.#config.backpressure, defaultTimeoutMs: this.#config.defaultTimeoutMs }); this.#ownsManager = true; if (deps.mastra) { this.#manager.__registerMastra(deps.mastra); this.#wireStaticTools(deps.mastra); } } /** * Populate the manager's static executor registry from tools registered * on `Mastra`, so that cross-process dispatches can be resolved by tool * name on this worker. Mirrors the wiring Mastra does for its own * managed background-task manager — the worker owns a separate manager * instance, so it has to populate its own registry. */ #wireStaticTools(mastra) { const listTools = mastra.listTools; const tools = listTools?.call(mastra); if (!tools || !this.#manager) return; for (const [name, tool] of Object.entries(tools)) { if (!tool || typeof tool.execute !== "function") continue; const execute = tool.execute.bind(tool); this.#manager.registerStaticExecutor(name, { execute: async (args, options) => { return execute(args, { toolCallId: "", messages: [], abortSignal: options?.abortSignal }); } }); } } async start() { if (this.#running) return; if (!this.#manager || !this.deps) { throw new Error("BackgroundTaskWorker: call init() before start()"); } if (this.#ownsManager) { await this.#manager.init(this.deps.pubsub); } this.#running = true; } async stop() { if (!this.#running) return; if (this.#manager && this.#ownsManager) { await this.#manager.shutdown(); } this.#running = false; } get isRunning() { return this.#running; } /** Expose the underlying manager for direct API access. */ get manager() { return this.#manager; } }; // src/worker/strategies/in-process-strategy.ts var InProcessStrategy = class { #mastra; constructor({ mastra } = {}) { this.#mastra = mastra; } __registerMastra(mastra) { this.#mastra = mastra; } async executeStep(params) { if (!this.#mastra) { throw new Error("InProcessStrategy requires Mastra instance. Call __registerMastra() first."); } const workflow = this.#mastra.getWorkflow(params.workflowId); const step = chunkBKPEQNQF_cjs.getStep(workflow, params.executionPath); if (!step) { throw new Error( `InProcessStrategy: could not resolve step "${params.stepId}" at executionPath [${params.executionPath.join(",")}] in workflow "${params.workflowId}"` ); } const rc = new chunkCAVARKYS_cjs.RequestContext(Object.entries(params.requestContext ?? {})); let abortController; if (params.abortSignal) { abortController = new AbortController(); if (params.abortSignal.aborted) { abortController.abort(params.abortSignal.reason); } else { params.abortSignal.addEventListener( "abort", () => { abortController.abort(params.abortSignal.reason); }, { once: true } ); } } const executor = new chunkBKPEQNQF_cjs.StepExecutor({ mastra: this.#mastra }); return executor.execute({ workflowId: params.workflowId, step, runId: params.runId, stepResults: params.stepResults, state: params.state, requestContext: rc, input: params.input, resumeData: params.resumeData, retryCount: params.retryCount, foreachIdx: params.foreachIdx, validateInputs: params.validateInputs, abortController, format: params.format, perStep: params.perStep }); } }; exports.BackgroundTaskWorker = BackgroundTaskWorker; exports.HttpRemoteStrategy = HttpRemoteStrategy; exports.InProcessStrategy = InProcessStrategy; exports.MastraWorker = MastraWorker; exports.OrchestrationWorker = OrchestrationWorker; exports.PullTransport = PullTransport; exports.SchedulerWorker = SchedulerWorker; exports.StepExecutionError = StepExecutionError; //# sourceMappingURL=chunk-LPGOWFV7.cjs.map //# sourceMappingURL=chunk-LPGOWFV7.cjs.map