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