import { runWorkflow } from "../../agent/workflow/runtime.js";
import "../runtime/script-runtime.js";
import { randomUUID } from "node:crypto";
//#region src/workflows/engine/workflow-engine.ts
var WorkflowEngine = class {
	constructor(options) {
		this.options = options;
	}
	async startRun(definition, options) {
		const runId = options.runId ?? randomUUID();
		const createdAtMs = Date.now();
		const phaseTitleToId = buildPhaseTitleToId(definition);
		let currentPhaseId;
		let eventQueue = Promise.resolve();
		const run = {
			id: runId,
			definitionId: definition.id,
			definitionVersion: definition.version,
			title: definition.title,
			goal: options.goal ?? definition.description,
			input: options.input ?? {},
			status: "queued",
			source: options.source,
			metrics: {
				agentCount: 0,
				doneAgentCount: 0,
				errorAgentCount: 0,
				skippedAgentCount: 0,
				artifactCount: 0
			},
			createdAtMs
		};
		const appendEvent = (type, payload, createdAtMsOverride) => {
			eventQueue = eventQueue.then(() => this.options.eventStore.append({
				runId,
				type,
				payload,
				createdAtMs: createdAtMsOverride
			})).then(async (event) => {
				this.options.onEventAppended?.(event);
				const view = await this.options.runStore.rebuildRunView(runId);
				if (view) this.options.onRunViewUpdated?.(view);
			});
			return eventQueue;
		};
		await appendEvent("run_queued", { run }, createdAtMs);
		await appendEvent("run_started", { startedAtMs: Date.now() });
		try {
			const runtimeResult = await runWorkflow(definition.runtime.source, {
				runner: this.options.runner,
				resolveModelId: this.options.resolveModelId
			}, {
				cwd: this.options.cwd,
				args: options.input,
				signal: options.signal,
				concurrency: options.concurrency ?? definition.defaults.concurrency,
				maxSubagents: options.maxSubagents ?? definition.defaults.maxSubagents,
				tokenBudget: options.tokenBudget,
				onPhase: (title) => {
					const nextPhaseId = phaseTitleToId.get(title) ?? normalizePhaseId(title);
					if (currentPhaseId && currentPhaseId !== nextPhaseId) appendEvent("phase_completed", { phaseId: currentPhaseId });
					currentPhaseId = nextPhaseId;
					appendEvent("phase_started", {
						phaseId: nextPhaseId,
						title
					});
				},
				onLog: (message) => {
					appendEvent("log_appended", { message });
				},
				onAgentQueued: (event) => {
					const phaseId = event.phase ? phaseTitleToId.get(event.phase) ?? normalizePhaseId(event.phase) : currentPhaseId;
					appendEvent("agent_queued", {
						agentId: formatRuntimeAgentId(event.id),
						label: event.label,
						phaseId,
						prompt: event.prompt
					});
				},
				onAgentStart: (event) => {
					appendEvent("agent_started", { agentId: formatRuntimeAgentId(event.id) });
				},
				onAgentEnd: (event) => {
					const completedStatus = normalizeCompletedAgentStatus(event.status);
					appendEvent("agent_completed", {
						agentId: formatRuntimeAgentId(event.id),
						status: completedStatus,
						resultPreview: previewWorkflowValue(event.result),
						error: completedStatus === "error" ? "Subagent failed" : void 0
					});
				}
			});
			await eventQueue;
			if (currentPhaseId) await appendEvent("phase_completed", { phaseId: currentPhaseId });
			await appendEvent("run_completed", { result: toWorkflowResultEnvelope(runtimeResult.result) });
		} catch (err) {
			await eventQueue;
			const error = toWorkflowRunError(err, options.signal?.aborted === true);
			if (error.code === "cancelled") await appendEvent("run_cancelled", { reason: error.message });
			else await appendEvent("run_failed", { error });
		}
		const view = await this.options.runStore.readRunView(runId);
		if (!view) throw new Error(`workflow run view was not created for ${runId}`);
		return view;
	}
};
function buildPhaseTitleToId(definition) {
	const phaseTitleToId = /* @__PURE__ */ new Map();
	for (const phase of definition.phases) phaseTitleToId.set(phase.title, phase.id);
	return phaseTitleToId;
}
function normalizePhaseId(title) {
	return title.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "phase";
}
function formatRuntimeAgentId(id) {
	return `agent-${id}`;
}
function normalizeCompletedAgentStatus(status) {
	if (status === "done" || status === "error" || status === "skipped") return status;
	return "error";
}
function previewWorkflowValue(value) {
	if (value === null || value === void 0) return;
	if (typeof value === "string") return truncate(value, 300);
	try {
		return truncate(JSON.stringify(value), 300);
	} catch {
		return truncate(String(value), 300);
	}
}
function truncate(value, maxLength) {
	const trimmed = value.trim();
	if (trimmed.length <= maxLength) return trimmed;
	return `${trimmed.slice(0, maxLength - 1)}…`;
}
function toWorkflowResultEnvelope(value) {
	if (isWorkflowResultEnvelope(value)) return value;
	if (typeof value === "string") return {
		summary: truncate(value, 800),
		sections: [{
			kind: "text",
			title: "Result",
			content: value
		}],
		raw: value
	};
	return {
		summary: "Workflow completed.",
		sections: [{
			kind: "json",
			title: "Result",
			value
		}],
		raw: value
	};
}
function isWorkflowResultEnvelope(value) {
	if (!value || typeof value !== "object" || Array.isArray(value)) return false;
	const record = value;
	return typeof record.summary === "string" && Array.isArray(record.sections);
}
function toWorkflowRunError(err, wasAborted) {
	const message = err instanceof Error ? err.message : String(err);
	if (wasAborted || /aborted|cancelled/i.test(message)) return {
		code: "cancelled",
		message: message || "Workflow run cancelled",
		recoverable: true
	};
	if (/timeout/i.test(message)) return {
		code: "timeout",
		message,
		recoverable: true
	};
	if (/quota/i.test(message)) return {
		code: "agent_quota_exceeded",
		message,
		recoverable: true
	};
	return {
		code: "runtime_error",
		message,
		recoverable: false
	};
}
//#endregion
export { WorkflowEngine };

//# sourceMappingURL=workflow-engine.js.map