import "./pi-embedded-utils-BmQgIEul.js";
import { J as logVerbose } from "./subsystem-Ci61Iebe.js";
import "./paths-aMBPuCJR.js";
import "./auth-profiles-CfyCILIe.js";
import "./env-3oW17BWM.js";
import { b as parseAgentSessionKey, y as isSubagentSessionKey } from "./session-key-j5Y_js6r.js";
import "./exec-B5OgjUV4.js";
import { c as resolveAgentWorkspaceDir } from "./agent-scope-CCFV2dzL.js";
import "./github-copilot-token-CgLcR-3z.js";
import "./reliability-B6TVU4OW.js";
import "./sqlite-CbyDDiup.js";
import "./pi-model-discovery-C9hP1DnY.js";
import "./tokens-Bvij_SSC.js";
import "./heartbeat-Bf1PpFld.js";
import { $ as getSubagentDepthFromSessionStore, C as truncateLine, D as resolveSubagentTargetFromRuns, E as resolveSubagentLabel, J as listSubagentRunsForRequester, O as sortSubagentRuns, S as resolveTotalTokens, T as getTemplate, X as markSubagentRunTerminated, Y as markSubagentRunForSteerRestart, Z as replaceSubagentRunAfterSteer, b as formatDurationCompact, nt as clearSessionQueues, q as clearSubagentRunSteerRestart, r as abortEmbeddedPiRun, w as spawnSubagentDirect, x as formatTokenUsageDisplay } from "./pi-embedded-runner-B7I92FYZ.js";
import "./accounts-TaYXhwSR.js";
import "./dock-BRgbOpqS.js";
import "./normalize-Dz9m5w2g.js";
import "./bindings-jC2ZutIF.js";
import "./helpers-Bu7dwsdB.js";
import "./client-BVxlvc45.js";
import "./plugins-6aUfx6Yt.js";
import "./diagnostic-CfwHM9PU.js";
import "./diagnostic-session-state-8XCWMS55.js";
import { n as AGENT_LANE_SUBAGENT } from "./lanes-BUEJliXF.js";
import "./send-Bq6jbXbH.js";
import { t as INTERNAL_MESSAGE_CHANNEL } from "./message-channel-BCPYwYUJ.js";
import "./route-reply-C7S9S-na.js";
import "./tts-BKXJ7fIm.js";
import "./image-ops-DfgorOBP.js";
import "./pi-embedded-helpers-DmbNPuyh.js";
import { n as loadConfig } from "./config-CaBTSkpu.js";
import "./manifest-registry-BPLS_vpk.js";
import "./chrome-CDWGRT0_.js";
import "./server-context-CU0HZM8q.js";
import "./skills-CEb7zc7i.js";
import "./redact-BXcZFg1V.js";
import "./errors-CGLTQpIl.js";
import "./ssrf-Clw7QAxV.js";
import { c as updateSessionStore, i as loadSessionStore } from "./sessions-FK8zYE33.js";
import { s as resolveStorePath } from "./paths-a4Li8t1f.js";
import "./tool-images-D39TNWEi.js";
import "./thinking-B4KYQMkY.js";
import "./image-tool.helpers-B7jX77eL.js";
import "./chat-trace-YVp5bEfe.js";
import "./response-prefix-template-CpJqwkyc.js";
import "./tool-tracking-CLcHzyfL.js";
import "./manager-CwxGvAk_.js";
import "./gemini-auth-UIYR3_Rv.js";
import "./session-files-CpNR2YZS.js";
import "./retry-13lqGuBf.js";
import "./hybrid-DRv9Yggt.js";
import { a as jsonResult, o as readNumberParam, u as readStringParam } from "./common-BkBiFnII.js";
import "./replies-CpIxmKIz.js";
import "./chunk-CbeEZcZX.js";
import "./markdown-tables-COuv9r7p.js";
import "./fetch-guard-1C45XE5F.js";
import "./fetch-Cn7DNoxz.js";
import "./media-CrEbBlaK.js";
import "./ir-pL2nbM8K.js";
import "./render-MTSxc7LK.js";
import "./commands-registry-BPtbhRwL.js";
import { n as callGateway } from "./call-CHvC3jba.js";
import { f as resolveInternalSessionKey, p as resolveMainSessionAlias } from "./sessions-helpers-BkUTlqiP.js";
import "./external-content-CfbWCLcb.js";
import "./runner-B3zVBP2H.js";
import "./image-DP51oWEy.js";
import "./skill-commands-D0ICIAHz.js";
import "./gateway-B-qVaiZA.js";
import "./nodes-utils-MqV9QJHm.js";
import "./resolve-route-CirHUsAv.js";
import "./knowledge-graph-CJ2-NLrF.js";
import "./model-fallback-tYPGXASj.js";
import "./active-listener-Ch-ciMyT.js";
import "./reply-prefix-BukioEEd.js";
import "./proxy-BoiJAz4L.js";
import { r as optionalStringEnum } from "./typebox-BrLUZMNm.js";
import * as path$1 from "node:path";
import { Type } from "@sinclair/typebox";
import * as fs$1 from "node:fs";
import crypto from "node:crypto";

//#region src/agents/subagents/orchestration/orchestration-aggregation.ts
/**
* Orchestration aggregation — builds a structured prompt from task results
* and spawns a single aggregation subagent to synthesize them.
*/
/**
* Format task results into a structured prompt section, appending the
* user's aggregation prompt at the end.
*/
function buildAggregationPrompt(results, userPrompt) {
	const parts = [];
	parts.push("## Orchestration Results");
	parts.push("");
	for (const task of results) {
		const statusTag = task.status;
		parts.push(`### Task: ${task.label} (${statusTag})`);
		if (task.resultText) parts.push(task.resultText);
		else if (task.error) parts.push(`Error: ${task.error}`);
		else parts.push("(no output)");
		parts.push("");
		parts.push("---");
		parts.push("");
	}
	parts.push("## Your Task");
	parts.push(userPrompt);
	return parts.join("\n");
}
/**
* Spawn a single aggregation subagent that synthesizes all task results.
* Returns the aggregation result text or null on failure.
*/
async function runAggregation(params) {
	const prompt = buildAggregationPrompt(params.results, params.aggregationPrompt);
	const aggregationDir = path$1.join(params.orchestrationDir, "aggregation");
	fs$1.mkdirSync(aggregationDir, { recursive: true });
	try {
		return (await params.spawnFn({
			label: "aggregation",
			prompt,
			template: params.aggregationTemplate,
			index: -1
		}, aggregationDir)).resultText ?? null;
	} catch {
		return null;
	}
}

//#endregion
//#region src/agents/subagents/orchestration/orchestration-manifest.ts
/**
* Orchestration manifest lifecycle — create, update, complete, read.
* The manifest.json is the durable record of orchestration state.
*/
/**
* Write `manifest.json` and an auto-generated `README.md` at the orchestration root.
*/
function createManifest(orchestrationDir, manifest) {
	const manifestPath = path$1.join(orchestrationDir, "manifest.json");
	fs$1.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
	const readmePath = path$1.join(orchestrationDir, "README.md");
	const readme = buildReadme(manifest);
	fs$1.writeFileSync(readmePath, readme, "utf-8");
}
/**
* Update a specific task entry in the manifest by index.
*/
function updateManifestTask(orchestrationDir, index, update) {
	const manifest = readManifest(orchestrationDir);
	if (!manifest) return;
	const task = manifest.tasks.find((t) => t.index === index);
	if (!task) return;
	Object.assign(task, update);
	const manifestPath = path$1.join(orchestrationDir, "manifest.json");
	fs$1.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
}
/**
* Set orchestration status and completedAt timestamp on the manifest.
*/
function completeManifest(orchestrationDir, status, completedAt) {
	const manifest = readManifest(orchestrationDir);
	if (!manifest) return;
	manifest.status = status;
	manifest.completedAt = completedAt ?? Date.now();
	const manifestPath = path$1.join(orchestrationDir, "manifest.json");
	fs$1.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
}
/**
* Read and parse manifest.json from orchestration directory.
* Returns null if missing or invalid.
*/
function readManifest(orchestrationDir) {
	const manifestPath = path$1.join(orchestrationDir, "manifest.json");
	try {
		const raw = fs$1.readFileSync(manifestPath, "utf-8");
		return JSON.parse(raw);
	} catch {
		return null;
	}
}
function buildReadme(manifest) {
	const lines = [];
	lines.push(`# Orchestration: ${manifest.orchestrationId}`);
	lines.push("");
	lines.push(`- **Mode:** ${manifest.mode}`);
	lines.push(`- **Status:** ${manifest.status}`);
	lines.push(`- **Started:** ${new Date(manifest.startedAt).toISOString()}`);
	if (manifest.completedAt) lines.push(`- **Completed:** ${new Date(manifest.completedAt).toISOString()}`);
	lines.push(`- **Tasks:** ${manifest.taskCount}`);
	lines.push("");
	lines.push("## Tasks");
	lines.push("");
	for (const task of manifest.tasks) {
		const templateSuffix = task.template ? ` (template: ${task.template})` : "";
		lines.push(`- [${task.status}] ${task.label}${templateSuffix}`);
	}
	lines.push("");
	return lines.join("\n");
}

//#endregion
//#region src/agents/subagents/orchestration/orchestration-output.ts
/**
* Orchestration output directory management — handles filesystem
* conventions for orchestration output (dirs, status.json, gather).
*/
/**
* Create the root orchestration directory at `{agentWorkspace}/orchestrations/{orchestrationId}/`.
* Creates recursively and returns the absolute path.
*/
function createOrchestrationDir(agentWorkspace, orchestrationId) {
	const dir = path$1.join(agentWorkspace, "orchestrations", orchestrationId);
	fs$1.mkdirSync(dir, { recursive: true });
	return dir;
}
/**
* Create a task subdirectory named `{paddedIndex}_{sanitizedLabel}`.
* Index is zero-padded to 2 digits (01, 02, ...).
*/
function createTaskDir(orchestrationDir, index, label) {
	const dirName = `${String(index).padStart(2, "0")}_${sanitizeLabel(label)}`;
	const dir = path$1.join(orchestrationDir, dirName);
	fs$1.mkdirSync(dir, { recursive: true });
	return dir;
}
/**
* Sanitize a label for use as a directory name:
* - Lowercase
* - Replace non-[a-z0-9-] with hyphen
* - Collapse multiple dashes
* - Truncate to 50 chars
* - Trim leading/trailing dashes
*/
function sanitizeLabel(label) {
	return label.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-{2,}/g, "-").replace(/^-+|-+$/g, "").slice(0, 50).replace(/^-+|-+$/g, "");
}
/**
* Read and parse StatusJson from `{taskDir}/status.json`.
* Returns null if missing or invalid JSON.
*/
function readStatusJson(taskDir) {
	const filePath = path$1.join(taskDir, "status.json");
	try {
		const raw = fs$1.readFileSync(filePath, "utf-8");
		const validation = validateStatusJson(JSON.parse(raw));
		if (validation.valid && validation.statusJson) return validation.statusJson;
		return null;
	} catch {
		return null;
	}
}
/**
* Validate a raw value as a StatusJson shape.
* Returns `{ valid: true, statusJson }` or `{ valid: false, errors }`.
*/
function validateStatusJson(raw) {
	if (raw == null || typeof raw !== "object" || Array.isArray(raw)) return {
		valid: false,
		errors: ["StatusJson must be an object"]
	};
	const obj = raw;
	const errors = [];
	if (obj.status !== "ok" && obj.status !== "error") errors.push("Field 'status' must be 'ok' or 'error'");
	if (typeof obj.summary !== "string") errors.push("Field 'summary' must be a string");
	if (!Array.isArray(obj.outputFiles)) errors.push("Field 'outputFiles' must be an array");
	if (errors.length > 0) return {
		valid: false,
		errors
	};
	return {
		valid: true,
		statusJson: {
			status: obj.status,
			summary: obj.summary,
			outputFiles: obj.outputFiles,
			error: typeof obj.error === "string" ? obj.error : void 0,
			metrics: obj.metrics != null && typeof obj.metrics === "object" && !Array.isArray(obj.metrics) ? obj.metrics : void 0
		}
	};
}
const DEFAULT_MAX_INLINE_BYTES = 10240;
/**
* Read task output for gather: status.json + file listing.
* Files under `maxInlineBytes` are inlined; larger files are listed as paths only.
*/
function readTaskOutputForGather(taskDir, maxInlineBytes) {
	const maxBytes = maxInlineBytes ?? DEFAULT_MAX_INLINE_BYTES;
	const status = readStatusJson(taskDir);
	const files = [];
	try {
		const entries = fs$1.readdirSync(taskDir, { withFileTypes: true });
		for (const entry of entries) {
			if (!entry.isFile() || entry.name === "status.json") continue;
			const filePath = path$1.join(taskDir, entry.name);
			try {
				const stat = fs$1.statSync(filePath);
				const fileEntry = {
					name: entry.name,
					path: filePath,
					size: stat.size
				};
				if (stat.size <= maxBytes) fileEntry.content = fs$1.readFileSync(filePath, "utf-8");
				files.push(fileEntry);
			} catch {}
		}
	} catch {}
	return {
		status,
		files
	};
}

//#endregion
//#region src/agents/subagents/orchestration/orchestration-types.ts
/**
* Orchestration types — defines all type contracts for the multi-agent
* orchestration system (fan-out, pipeline, failure policies, manifests).
*/
const DEFAULT_MAX_CONCURRENCY = 5;
const MAX_TASKS_PER_ORCHESTRATION = 20;
const RATE_LIMIT_PER_MINUTE = 5;

//#endregion
//#region src/agents/subagents/orchestration/orchestration-engine.ts
/**
* Orchestration engine — executes parallel fan-out with concurrency control,
* failure policies (gather-available, fail-all, retry), budget cap, and dry run.
*/
/**
* Execute an orchestration: spawn tasks with concurrency control,
* apply failure policies, track budget, write manifest.
*/
async function executeOrchestration(config, spawnFn, context) {
	const orchestrationId = config.orchestrationId ?? crypto.randomUUID();
	const mode = config.mode;
	const maxConcurrency = config.maxConcurrency ?? DEFAULT_MAX_CONCURRENCY;
	const onFailure = config.onFailure ?? "gather-available";
	const maxRetries = config.maxRetries ?? 1;
	const maxTotalTokens = config.maxTotalTokens;
	if (config.dryRun) return {
		orchestrationId,
		mode,
		status: "completed",
		tasks: [],
		totalDurationMs: 0,
		tokensUsed: 0
	};
	const tasks = config.tasks ?? [];
	if (tasks.length === 0) return {
		orchestrationId,
		mode,
		status: "completed",
		tasks: [],
		totalDurationMs: 0,
		tokensUsed: 0
	};
	const orchestrationDir = createOrchestrationDir(context.agentWorkspace, orchestrationId);
	const manifestTasks = tasks.map((t, i) => ({
		index: i,
		label: t.label,
		template: t.template,
		status: "pending"
	}));
	createManifest(orchestrationDir, {
		orchestrationId,
		mode,
		startedAt: Date.now(),
		taskCount: tasks.length,
		status: "running",
		tasks: manifestTasks
	});
	const startTime = performance.now();
	const results = Array.from({ length: tasks.length });
	let totalTokensUsed = 0;
	let budgetExceeded = false;
	let failureDetected = false;
	const queue = tasks.map((task, i) => ({
		task,
		index: i
	}));
	let queuePos = 0;
	let activeCount = 0;
	await new Promise((resolveAll) => {
		let completedCount = 0;
		function tryStartNext() {
			while (activeCount < maxConcurrency && queuePos < queue.length && !budgetExceeded && !(failureDetected && onFailure === "fail-all")) {
				const item = queue[queuePos];
				queuePos++;
				activeCount++;
				runTask(item.task, item.index);
			}
			if (budgetExceeded || failureDetected && onFailure === "fail-all") {
				for (let i = queuePos; i < queue.length; i++) {
					const item = queue[i];
					if (!results[item.index]) {
						results[item.index] = {
							label: item.task.label,
							index: item.index,
							status: "skipped",
							durationMs: 0
						};
						completedCount++;
						updateManifestTask(orchestrationDir, item.index, { status: "skipped" });
					}
				}
				queuePos = queue.length;
			}
			if (completedCount >= tasks.length) resolveAll();
		}
		async function runTask(task, index) {
			const taskDir = createTaskDir(orchestrationDir, index, task.label);
			updateManifestTask(orchestrationDir, index, {
				status: "running",
				startedAt: Date.now(),
				outputDir: taskDir
			});
			let attempt = 0;
			const maxAttempts = onFailure === "retry" ? maxRetries + 1 : 1;
			let lastResult;
			while (attempt < maxAttempts) {
				attempt++;
				try {
					const result = await spawnFn({
						...task,
						index
					}, taskDir);
					result.index = index;
					lastResult = result;
					if (result.status === "completed") {
						results[index] = result;
						totalTokensUsed += result.tokensUsed ?? 0;
						updateManifestTask(orchestrationDir, index, {
							status: "completed",
							completedAt: Date.now()
						});
						if (maxTotalTokens && totalTokensUsed >= maxTotalTokens) budgetExceeded = true;
						break;
					}
					if (attempt < maxAttempts) {
						const backoffMs = 1e3 * 2 ** (attempt - 1);
						await new Promise((r) => setTimeout(r, backoffMs));
						continue;
					}
					results[index] = result;
					totalTokensUsed += result.tokensUsed ?? 0;
					failureDetected = true;
					updateManifestTask(orchestrationDir, index, {
						status: result.status === "timeout" ? "timeout" : "failed",
						completedAt: Date.now(),
						error: result.error
					});
				} catch (err) {
					const error = err instanceof Error ? err.message : String(err);
					lastResult = {
						label: task.label,
						index,
						status: "failed",
						error,
						durationMs: 0
					};
					if (attempt < maxAttempts) {
						const backoffMs = 1e3 * 2 ** (attempt - 1);
						await new Promise((r) => setTimeout(r, backoffMs));
						continue;
					}
					results[index] = lastResult;
					failureDetected = true;
					updateManifestTask(orchestrationDir, index, {
						status: "failed",
						completedAt: Date.now(),
						error
					});
				}
			}
			if (!results[index] && lastResult) results[index] = lastResult;
			completedCount++;
			activeCount--;
			tryStartNext();
		}
		tryStartNext();
	});
	const totalDurationMs = Math.round(performance.now() - startTime);
	let finalStatus = "completed";
	if (failureDetected) {
		if (onFailure === "fail-all") finalStatus = "failed";
	}
	completeManifest(orchestrationDir, finalStatus);
	return {
		orchestrationId,
		mode,
		status: finalStatus,
		tasks: results.filter(Boolean),
		totalDurationMs,
		tokensUsed: totalTokensUsed
	};
}

//#endregion
//#region src/agents/subagents/orchestration/orchestration-gather.ts
/**
* Orchestration gather — collects task results by orchestrationId,
* reads status.json and output files, supports filtering and cleanup.
*/
/**
* Gather results for an orchestration by reading the manifest and task output
* directories. Pure disk reads (no state mutation except cleanup).
*/
function gatherOrchestrationResults(params) {
	const manifest = readManifest(params.orchestrationDir);
	if (!manifest) return {
		orchestrationId: params.orchestrationId,
		status: "pending",
		taskCount: 0,
		tasks: []
	};
	let filteredTasks = manifest.tasks;
	if (params.template) filteredTasks = filteredTasks.filter((t) => t.template === params.template);
	if (params.label) filteredTasks = filteredTasks.filter((t) => t.label === params.label);
	if (!params.includeRunning) filteredTasks = filteredTasks.filter((t) => t.status !== "running" && t.status !== "pending");
	const gatherTasks = [];
	for (const manifestTask of filteredTasks) {
		const taskResult = buildGatherTaskResult(manifestTask, params);
		gatherTasks.push(taskResult);
	}
	const isInterrupted = manifest.status === "interrupted";
	const completedCount = manifest.tasks.filter((t) => t.status === "completed" || t.status === "failed").length;
	const incompleteCount = manifest.tasks.filter((t) => t.status === "pending" || t.status === "running" || t.status === "skipped").length;
	const result = {
		orchestrationId: params.orchestrationId,
		status: manifest.status,
		mode: manifest.mode,
		startedAt: manifest.startedAt,
		completedAt: manifest.completedAt,
		taskCount: manifest.taskCount,
		tasks: gatherTasks,
		...isInterrupted ? {
			interrupted: true,
			completedTasks: completedCount,
			incompleteTasks: incompleteCount,
			canResume: true
		} : {}
	};
	if (params.cleanup) try {
		fs$1.rmSync(params.orchestrationDir, {
			recursive: true,
			force: true
		});
	} catch {}
	return result;
}
function buildGatherTaskResult(manifestTask, params) {
	if (manifestTask.status === "running" || manifestTask.status === "pending") return {
		index: manifestTask.index,
		label: manifestTask.label,
		template: manifestTask.template,
		status: manifestTask.status,
		statusJson: null,
		files: []
	};
	if (manifestTask.outputDir) {
		const output = readTaskOutputForGather(manifestTask.outputDir, params.maxInlineBytes);
		const run = params.runs.find((r) => r.orchestrationId === params.orchestrationId && r.label === manifestTask.label);
		return {
			index: manifestTask.index,
			label: manifestTask.label,
			template: manifestTask.template,
			status: manifestTask.status,
			statusJson: output.status,
			files: output.files,
			resultText: run?.resultText ?? output.status?.summary,
			error: manifestTask.error
		};
	}
	return {
		index: manifestTask.index,
		label: manifestTask.label,
		template: manifestTask.template,
		status: manifestTask.status,
		statusJson: null,
		files: [],
		error: manifestTask.error
	};
}

//#endregion
//#region src/agents/subagents/orchestration/orchestration-pipeline.ts
/**
* Pipeline mode execution — processes stages sequentially with
* fan-out within each stage and {{previousOutput}} injection.
*/
/**
* Execute a pipeline orchestration: stages run sequentially, tasks within
* each stage run in parallel (fan-out). Output from completed stages is
* injected as `{{previousOutput}}` into next stage task prompts.
*/
async function executePipeline(config, spawnFn, context) {
	const orchestrationId = config.orchestrationId ?? crypto.randomUUID();
	const maxConcurrency = config.maxConcurrency ?? DEFAULT_MAX_CONCURRENCY;
	const stages = config.stages ?? [];
	if (stages.length === 0) return {
		orchestrationId,
		mode: "pipeline",
		status: "completed",
		tasks: [],
		totalDurationMs: 0,
		tokensUsed: 0
	};
	const orchestrationDir = createOrchestrationDir(context.agentWorkspace, orchestrationId);
	const allTasks = [];
	let globalIndex = 0;
	for (let si = 0; si < stages.length; si++) for (const task of stages[si].tasks) {
		allTasks.push({
			task,
			stageIndex: si,
			globalIndex
		});
		globalIndex++;
	}
	const manifestTasks = allTasks.map((entry) => ({
		index: entry.globalIndex,
		label: entry.task.label,
		template: entry.task.template,
		status: "pending"
	}));
	createManifest(orchestrationDir, {
		orchestrationId,
		mode: "pipeline",
		startedAt: Date.now(),
		taskCount: allTasks.length,
		status: "running",
		tasks: manifestTasks
	});
	const startTime = performance.now();
	const allResults = [];
	let totalTokensUsed = 0;
	let previousOutput = "";
	let pipelineStatus = "completed";
	let pipelineFailed = false;
	for (let stageIndex = 0; stageIndex < stages.length; stageIndex++) {
		if (pipelineFailed) {
			const stageTasks = allTasks.filter((e) => e.stageIndex === stageIndex);
			for (const entry of stageTasks) {
				allResults.push({
					label: entry.task.label,
					index: entry.globalIndex,
					status: "skipped",
					durationMs: 0
				});
				updateManifestTask(orchestrationDir, entry.globalIndex, { status: "skipped" });
			}
			continue;
		}
		const stage = stages[stageIndex];
		const stageTasks = allTasks.filter((e) => e.stageIndex === stageIndex);
		const onStageFailure = stage.onStageFailure ?? "stop";
		const stageName = stageTasks[0]?.task.label ?? "stage";
		const stageDir = createStageDir(orchestrationDir, stageIndex, stageName);
		const stageResults = await executeStageParallel(stageTasks.map((entry) => ({
			...entry,
			task: {
				...entry.task,
				prompt: entry.task.prompt.replace(/\{\{previousOutput\}\}/g, previousOutput),
				index: entry.globalIndex
			}
		})).map((e) => ({
			task: e.task,
			globalIndex: e.globalIndex
		})), spawnFn, stageDir, orchestrationDir, maxConcurrency);
		let stageHasFailure = false;
		for (const result of stageResults) {
			allResults.push(result);
			totalTokensUsed += result.tokensUsed ?? 0;
			if (result.status === "failed" || result.status === "timeout") stageHasFailure = true;
		}
		const stageOutputParts = stageResults.filter((r) => r.resultText).map((r) => `### ${r.label}\n${r.resultText}`);
		if (stageOutputParts.length > 0) previousOutput = stageOutputParts.join("\n\n---\n\n");
		if (stageHasFailure) if (onStageFailure === "stop") {
			pipelineFailed = true;
			pipelineStatus = "failed";
			const errorParts = stageResults.filter((r) => r.status === "failed" || r.status === "timeout").map((r) => `### ${r.label} (${r.status})\n${r.error ?? "Unknown error"}`);
			if (errorParts.length > 0) previousOutput += "\n\n---\n\n## Stage Errors\n\n" + errorParts.join("\n\n");
		} else {
			const errorParts = stageResults.filter((r) => r.status === "failed" || r.status === "timeout").map((r) => `### ${r.label} (${r.status})\n${r.error ?? "Unknown error"}`);
			if (errorParts.length > 0) previousOutput += "\n\n---\n\n## Stage Errors\n\n" + errorParts.join("\n\n");
		}
	}
	const totalDurationMs = Math.round(performance.now() - startTime);
	completeManifest(orchestrationDir, pipelineStatus);
	return {
		orchestrationId,
		mode: "pipeline",
		status: pipelineStatus,
		tasks: allResults,
		totalDurationMs,
		tokensUsed: totalTokensUsed
	};
}
async function executeStageParallel(tasks, spawnFn, stageDir, orchestrationDir, maxConcurrency) {
	const results = Array.from({ length: tasks.length });
	let queuePos = 0;
	let activeCount = 0;
	await new Promise((resolveAll) => {
		let completedCount = 0;
		function tryStartNext() {
			while (activeCount < maxConcurrency && queuePos < tasks.length) {
				const item = tasks[queuePos];
				queuePos++;
				activeCount++;
				runStageTask(item, queuePos - 1);
			}
			if (completedCount >= tasks.length) resolveAll();
		}
		async function runStageTask(item, localIndex) {
			const taskLabel = sanitizeLabel(item.task.label);
			const paddedLocal = String(localIndex).padStart(2, "0");
			const taskDir = path$1.join(stageDir, `${paddedLocal}_${taskLabel}`);
			fs$1.mkdirSync(taskDir, { recursive: true });
			updateManifestTask(orchestrationDir, item.globalIndex, {
				status: "running",
				startedAt: Date.now(),
				outputDir: taskDir
			});
			try {
				const result = await spawnFn(item.task, taskDir);
				result.index = item.globalIndex;
				results[localIndex] = result;
				updateManifestTask(orchestrationDir, item.globalIndex, {
					status: result.status === "completed" ? "completed" : result.status,
					completedAt: Date.now(),
					error: result.error
				});
			} catch (err) {
				const error = err instanceof Error ? err.message : String(err);
				results[localIndex] = {
					label: item.task.label,
					index: item.globalIndex,
					status: "failed",
					error,
					durationMs: 0
				};
				updateManifestTask(orchestrationDir, item.globalIndex, {
					status: "failed",
					completedAt: Date.now(),
					error
				});
			}
			completedCount++;
			activeCount--;
			tryStartNext();
		}
		tryStartNext();
	});
	return results;
}
function createStageDir(orchestrationDir, stageIndex, firstTaskLabel) {
	const dirName = `stage_${String(stageIndex + 1).padStart(2, "0")}_${sanitizeLabel(firstTaskLabel)}`;
	const dir = path$1.join(orchestrationDir, dirName);
	fs$1.mkdirSync(dir, { recursive: true });
	return dir;
}

//#endregion
//#region src/agents/tools/sessions/subagents-tool.ts
const SUBAGENT_ACTIONS = [
	"list",
	"kill",
	"steer",
	"orchestrate",
	"gather",
	"orchestrations"
];
const DEFAULT_RECENT_MINUTES = 30;
const MAX_RECENT_MINUTES = 1440;
const MAX_STEER_MESSAGE_CHARS = 4e3;
const STEER_RATE_LIMIT_MS = 2e3;
const STEER_ABORT_SETTLE_TIMEOUT_MS = 5e3;
const steerRateLimit = /* @__PURE__ */ new Map();
const orchestrateRateWindow = [];
const SubagentsToolSchema = Type.Object({
	action: optionalStringEnum(SUBAGENT_ACTIONS),
	target: Type.Optional(Type.String()),
	message: Type.Optional(Type.String()),
	recentMinutes: Type.Optional(Type.Number({ minimum: 1 })),
	mode: Type.Optional(Type.String()),
	tasks: Type.Optional(Type.Array(Type.Object({
		label: Type.String(),
		prompt: Type.String(),
		template: Type.Optional(Type.String()),
		model: Type.Optional(Type.String()),
		timeoutSeconds: Type.Optional(Type.Number())
	}))),
	stages: Type.Optional(Type.Array(Type.Object({
		tasks: Type.Array(Type.Object({
			label: Type.String(),
			prompt: Type.String(),
			template: Type.Optional(Type.String()),
			model: Type.Optional(Type.String()),
			timeoutSeconds: Type.Optional(Type.Number())
		})),
		onStageFailure: Type.Optional(Type.String())
	}))),
	maxConcurrency: Type.Optional(Type.Number()),
	onFailure: Type.Optional(Type.String()),
	maxRetries: Type.Optional(Type.Number()),
	maxTotalTokens: Type.Optional(Type.Number()),
	aggregationPrompt: Type.Optional(Type.String()),
	aggregationTemplate: Type.Optional(Type.String()),
	dryRun: Type.Optional(Type.Boolean()),
	orchestrationId: Type.Optional(Type.String()),
	template: Type.Optional(Type.String()),
	label: Type.Optional(Type.String()),
	includeRunning: Type.Optional(Type.Boolean()),
	cleanup: Type.Optional(Type.Boolean()),
	resumeOrchestrationId: Type.Optional(Type.String()),
	status: Type.Optional(Type.String()),
	since: Type.Optional(Type.Number()),
	until: Type.Optional(Type.Number())
});
function resolveRunStatus(entry) {
	if (!entry.endedAt) return "running";
	const status = entry.outcome?.status ?? "done";
	if (status === "ok") return "done";
	if (status === "error") return "failed";
	return status;
}
function resolveModelRef(entry) {
	const model = typeof entry?.model === "string" ? entry.model.trim() : "";
	const provider = typeof entry?.modelProvider === "string" ? entry.modelProvider.trim() : "";
	if (model.includes("/")) return model;
	if (model && provider) return `${provider}/${model}`;
	if (model) return model;
	if (provider) return provider;
	const overrideModel = typeof entry?.modelOverride === "string" ? entry.modelOverride.trim() : "";
	const overrideProvider = typeof entry?.providerOverride === "string" ? entry.providerOverride.trim() : "";
	if (overrideModel.includes("/")) return overrideModel;
	if (overrideModel && overrideProvider) return `${overrideProvider}/${overrideModel}`;
	if (overrideModel) return overrideModel;
	return overrideProvider || void 0;
}
function resolveModelDisplay(entry, fallbackModel) {
	const modelRef = resolveModelRef(entry) || fallbackModel || void 0;
	if (!modelRef) return "model n/a";
	const slash = modelRef.lastIndexOf("/");
	if (slash >= 0 && slash < modelRef.length - 1) return modelRef.slice(slash + 1);
	return modelRef;
}
function resolveSubagentTarget(runs, token, options) {
	return resolveSubagentTargetFromRuns({
		runs,
		token,
		recentWindowMinutes: options?.recentMinutes ?? DEFAULT_RECENT_MINUTES,
		label: (entry) => resolveSubagentLabel(entry),
		errors: {
			missingTarget: "Missing subagent target.",
			invalidIndex: (value) => `Invalid subagent index: ${value}`,
			unknownSession: (value) => `Unknown subagent session: ${value}`,
			ambiguousLabel: (value) => `Ambiguous subagent label: ${value}`,
			ambiguousLabelPrefix: (value) => `Ambiguous subagent label prefix: ${value}`,
			ambiguousRunIdPrefix: (value) => `Ambiguous subagent run id prefix: ${value}`,
			unknownTarget: (value) => `Unknown subagent target: ${value}`
		}
	});
}
function resolveStorePathForKey(cfg, key, parsed) {
	return resolveStorePath(cfg.session?.store, { agentId: parsed?.agentId });
}
function resolveSessionEntryForKey(params) {
	const parsed = parseAgentSessionKey(params.key);
	const storePath = resolveStorePathForKey(params.cfg, params.key, parsed);
	let store = params.cache.get(storePath);
	if (!store) {
		store = loadSessionStore(storePath);
		params.cache.set(storePath, store);
	}
	return {
		storePath,
		entry: store[params.key]
	};
}
function resolveRequesterKey(params) {
	const { mainKey, alias } = resolveMainSessionAlias(params.cfg);
	const callerSessionKey = resolveInternalSessionKey({
		key: params.agentSessionKey?.trim() || alias,
		alias,
		mainKey
	});
	if (!isSubagentSessionKey(callerSessionKey)) return {
		requesterSessionKey: callerSessionKey,
		callerSessionKey,
		callerIsSubagent: false
	};
	if (getSubagentDepthFromSessionStore(callerSessionKey, { cfg: params.cfg }) < (params.cfg.agents?.defaults?.subagents?.maxSpawnDepth ?? 2)) return {
		requesterSessionKey: callerSessionKey,
		callerSessionKey,
		callerIsSubagent: true
	};
	const cache = /* @__PURE__ */ new Map();
	const callerEntry = resolveSessionEntryForKey({
		cfg: params.cfg,
		key: callerSessionKey,
		cache
	}).entry;
	return {
		requesterSessionKey: (typeof callerEntry?.spawnedBy === "string" ? callerEntry.spawnedBy.trim() : "") || callerSessionKey,
		callerSessionKey,
		callerIsSubagent: true
	};
}
async function killSubagentRun(params) {
	if (params.entry.endedAt) return { killed: false };
	const childSessionKey = params.entry.childSessionKey;
	const resolved = resolveSessionEntryForKey({
		cfg: params.cfg,
		key: childSessionKey,
		cache: params.cache
	});
	const sessionId = resolved.entry?.sessionId;
	const aborted = sessionId ? abortEmbeddedPiRun(sessionId) : false;
	const cleared = clearSessionQueues([childSessionKey, sessionId]);
	if (cleared.followupCleared > 0 || cleared.laneCleared > 0) logVerbose(`subagents tool kill: cleared followups=${cleared.followupCleared} lane=${cleared.laneCleared} keys=${cleared.keys.join(",")}`);
	if (resolved.entry) await updateSessionStore(resolved.storePath, (store) => {
		const current = store[childSessionKey];
		if (!current) return;
		current.abortedLastRun = true;
		current.updatedAt = Date.now();
		store[childSessionKey] = current;
	});
	return {
		killed: markSubagentRunTerminated({
			runId: params.entry.runId,
			childSessionKey,
			reason: "killed"
		}) > 0 || aborted || cleared.followupCleared > 0 || cleared.laneCleared > 0,
		sessionId
	};
}
/**
* Recursively kill all descendant subagent runs spawned by a given parent session key.
* This ensures that when a subagent is killed, all of its children (and their children) are also killed.
*/
async function cascadeKillChildren(params) {
	const childRuns = listSubagentRunsForRequester(params.parentChildSessionKey);
	const seenChildSessionKeys = params.seenChildSessionKeys ?? /* @__PURE__ */ new Set();
	let killed = 0;
	const labels = [];
	for (const run of childRuns) {
		const childKey = run.childSessionKey?.trim();
		if (!childKey || seenChildSessionKeys.has(childKey)) continue;
		seenChildSessionKeys.add(childKey);
		if (!run.endedAt) {
			if ((await killSubagentRun({
				cfg: params.cfg,
				entry: run,
				cache: params.cache
			})).killed) {
				killed += 1;
				labels.push(resolveSubagentLabel(run));
			}
		}
		const cascade = await cascadeKillChildren({
			cfg: params.cfg,
			parentChildSessionKey: childKey,
			cache: params.cache,
			seenChildSessionKeys
		});
		killed += cascade.killed;
		labels.push(...cascade.labels);
	}
	return {
		killed,
		labels
	};
}
function buildListText(params) {
	const lines = [];
	lines.push("active subagents:");
	if (params.active.length === 0) lines.push("(none)");
	else lines.push(...params.active.map((entry) => entry.line));
	lines.push("");
	lines.push(`recent (last ${params.recentMinutes}m):`);
	if (params.recent.length === 0) lines.push("(none)");
	else lines.push(...params.recent.map((entry) => entry.line));
	return lines.join("\n");
}
function createSubagentsTool(opts) {
	return {
		label: "Subagents",
		name: "subagents",
		description: "Manage sub-agents: list, kill, steer, orchestrate (fan-out/pipeline), gather results, or list orchestrations.",
		parameters: SubagentsToolSchema,
		execute: async (_toolCallId, args) => {
			const params = args;
			const action = readStringParam(params, "action") ?? "list";
			const cfg = loadConfig();
			const requester = resolveRequesterKey({
				cfg,
				agentSessionKey: opts?.agentSessionKey
			});
			const runs = sortSubagentRuns(listSubagentRunsForRequester(requester.requesterSessionKey));
			const recentMinutesRaw = readNumberParam(params, "recentMinutes");
			const recentMinutes = recentMinutesRaw ? Math.max(1, Math.min(MAX_RECENT_MINUTES, Math.floor(recentMinutesRaw))) : DEFAULT_RECENT_MINUTES;
			if (action === "list") {
				const now = Date.now();
				const recentCutoff = now - recentMinutes * 6e4;
				const cache = /* @__PURE__ */ new Map();
				let index = 1;
				const buildListEntry = (entry, runtimeMs) => {
					const sessionEntry = resolveSessionEntryForKey({
						cfg,
						key: entry.childSessionKey,
						cache
					}).entry;
					const totalTokens = resolveTotalTokens(sessionEntry);
					const usageText = formatTokenUsageDisplay(sessionEntry);
					const status = resolveRunStatus(entry);
					const runtime = formatDurationCompact(runtimeMs);
					const label = truncateLine(resolveSubagentLabel(entry), 48);
					const task = truncateLine(entry.task.trim(), 72);
					const line = `${index}. ${label} (${resolveModelDisplay(sessionEntry, entry.model)}, ${runtime}${usageText ? `, ${usageText}` : ""}) ${status}${task.toLowerCase() !== label.toLowerCase() ? ` - ${task}` : ""}`;
					const baseView = {
						index,
						runId: entry.runId,
						sessionKey: entry.childSessionKey,
						label,
						task,
						status,
						runtime,
						runtimeMs,
						model: resolveModelRef(sessionEntry) || entry.model,
						totalTokens,
						startedAt: entry.startedAt
					};
					index += 1;
					return {
						line,
						view: entry.endedAt ? {
							...baseView,
							endedAt: entry.endedAt
						} : baseView
					};
				};
				const active = runs.filter((entry) => !entry.endedAt).map((entry) => buildListEntry(entry, now - (entry.startedAt ?? entry.createdAt)));
				const recent = runs.filter((entry) => !!entry.endedAt && (entry.endedAt ?? 0) >= recentCutoff).map((entry) => buildListEntry(entry, (entry.endedAt ?? now) - (entry.startedAt ?? entry.createdAt)));
				const text = buildListText({
					active,
					recent,
					recentMinutes
				});
				return jsonResult({
					status: "ok",
					action: "list",
					requesterSessionKey: requester.requesterSessionKey,
					callerSessionKey: requester.callerSessionKey,
					callerIsSubagent: requester.callerIsSubagent,
					total: runs.length,
					active: active.map((entry) => entry.view),
					recent: recent.map((entry) => entry.view),
					text
				});
			}
			if (action === "kill") {
				const target = readStringParam(params, "target", { required: true });
				if (target === "all" || target === "*") {
					const cache = /* @__PURE__ */ new Map();
					const seenChildSessionKeys = /* @__PURE__ */ new Set();
					const killedLabels = [];
					let killed = 0;
					for (const entry of runs) {
						const childKey = entry.childSessionKey?.trim();
						if (!childKey || seenChildSessionKeys.has(childKey)) continue;
						seenChildSessionKeys.add(childKey);
						if (!entry.endedAt) {
							if ((await killSubagentRun({
								cfg,
								entry,
								cache
							})).killed) {
								killed += 1;
								killedLabels.push(resolveSubagentLabel(entry));
							}
						}
						const cascade = await cascadeKillChildren({
							cfg,
							parentChildSessionKey: childKey,
							cache,
							seenChildSessionKeys
						});
						killed += cascade.killed;
						killedLabels.push(...cascade.labels);
					}
					return jsonResult({
						status: "ok",
						action: "kill",
						target: "all",
						killed,
						labels: killedLabels,
						text: killed > 0 ? `killed ${killed} subagent${killed === 1 ? "" : "s"}.` : "no running subagents to kill."
					});
				}
				const resolved = resolveSubagentTarget(runs, target, { recentMinutes });
				if (!resolved.entry) return jsonResult({
					status: "error",
					action: "kill",
					target,
					error: resolved.error ?? "Unknown subagent target."
				});
				const killCache = /* @__PURE__ */ new Map();
				const stopResult = await killSubagentRun({
					cfg,
					entry: resolved.entry,
					cache: killCache
				});
				const seenChildSessionKeys = /* @__PURE__ */ new Set();
				const targetChildKey = resolved.entry.childSessionKey?.trim();
				if (targetChildKey) seenChildSessionKeys.add(targetChildKey);
				const cascade = await cascadeKillChildren({
					cfg,
					parentChildSessionKey: resolved.entry.childSessionKey,
					cache: killCache,
					seenChildSessionKeys
				});
				if (!stopResult.killed && cascade.killed === 0) return jsonResult({
					status: "done",
					action: "kill",
					target,
					runId: resolved.entry.runId,
					sessionKey: resolved.entry.childSessionKey,
					text: `${resolveSubagentLabel(resolved.entry)} is already finished.`
				});
				const cascadeText = cascade.killed > 0 ? ` (+ ${cascade.killed} descendant${cascade.killed === 1 ? "" : "s"})` : "";
				return jsonResult({
					status: "ok",
					action: "kill",
					target,
					runId: resolved.entry.runId,
					sessionKey: resolved.entry.childSessionKey,
					label: resolveSubagentLabel(resolved.entry),
					cascadeKilled: cascade.killed,
					cascadeLabels: cascade.killed > 0 ? cascade.labels : void 0,
					text: stopResult.killed ? `killed ${resolveSubagentLabel(resolved.entry)}${cascadeText}.` : `killed ${cascade.killed} descendant${cascade.killed === 1 ? "" : "s"} of ${resolveSubagentLabel(resolved.entry)}.`
				});
			}
			if (action === "steer") {
				const target = readStringParam(params, "target", { required: true });
				const message = readStringParam(params, "message", { required: true });
				if (message.length > MAX_STEER_MESSAGE_CHARS) return jsonResult({
					status: "error",
					action: "steer",
					target,
					error: `Message too long (${message.length} chars, max ${MAX_STEER_MESSAGE_CHARS}).`
				});
				const resolved = resolveSubagentTarget(runs, target, { recentMinutes });
				if (!resolved.entry) return jsonResult({
					status: "error",
					action: "steer",
					target,
					error: resolved.error ?? "Unknown subagent target."
				});
				if (resolved.entry.endedAt) return jsonResult({
					status: "done",
					action: "steer",
					target,
					runId: resolved.entry.runId,
					sessionKey: resolved.entry.childSessionKey,
					text: `${resolveSubagentLabel(resolved.entry)} is already finished.`
				});
				if (requester.callerIsSubagent && requester.callerSessionKey === resolved.entry.childSessionKey) return jsonResult({
					status: "forbidden",
					action: "steer",
					target,
					runId: resolved.entry.runId,
					sessionKey: resolved.entry.childSessionKey,
					error: "Subagents cannot steer themselves."
				});
				const rateKey = `${requester.callerSessionKey}:${resolved.entry.childSessionKey}`;
				const now = Date.now();
				if (now - (steerRateLimit.get(rateKey) ?? 0) < STEER_RATE_LIMIT_MS) return jsonResult({
					status: "rate_limited",
					action: "steer",
					target,
					runId: resolved.entry.runId,
					sessionKey: resolved.entry.childSessionKey,
					error: "Steer rate limit exceeded. Wait a moment before sending another steer."
				});
				steerRateLimit.set(rateKey, now);
				markSubagentRunForSteerRestart(resolved.entry.runId);
				const targetSession = resolveSessionEntryForKey({
					cfg,
					key: resolved.entry.childSessionKey,
					cache: /* @__PURE__ */ new Map()
				});
				const sessionId = typeof targetSession.entry?.sessionId === "string" && targetSession.entry.sessionId.trim() ? targetSession.entry.sessionId.trim() : void 0;
				if (sessionId) abortEmbeddedPiRun(sessionId);
				const cleared = clearSessionQueues([resolved.entry.childSessionKey, sessionId]);
				if (cleared.followupCleared > 0 || cleared.laneCleared > 0) logVerbose(`subagents tool steer: cleared followups=${cleared.followupCleared} lane=${cleared.laneCleared} keys=${cleared.keys.join(",")}`);
				try {
					await callGateway({
						method: "agent.wait",
						params: {
							runId: resolved.entry.runId,
							timeoutMs: STEER_ABORT_SETTLE_TIMEOUT_MS
						},
						timeoutMs: STEER_ABORT_SETTLE_TIMEOUT_MS + 2e3
					});
				} catch {}
				const idempotencyKey = crypto.randomUUID();
				let runId = idempotencyKey;
				try {
					const response = await callGateway({
						method: "agent",
						params: {
							message,
							sessionKey: resolved.entry.childSessionKey,
							sessionId,
							idempotencyKey,
							deliver: false,
							channel: INTERNAL_MESSAGE_CHANNEL,
							lane: AGENT_LANE_SUBAGENT,
							timeout: 0
						},
						timeoutMs: 1e4
					});
					if (typeof response?.runId === "string" && response.runId) runId = response.runId;
				} catch (err) {
					clearSubagentRunSteerRestart(resolved.entry.runId);
					const error = err instanceof Error ? err.message : String(err);
					return jsonResult({
						status: "error",
						action: "steer",
						target,
						runId,
						sessionKey: resolved.entry.childSessionKey,
						sessionId,
						error
					});
				}
				replaceSubagentRunAfterSteer({
					previousRunId: resolved.entry.runId,
					nextRunId: runId,
					fallback: resolved.entry,
					runTimeoutSeconds: resolved.entry.runTimeoutSeconds ?? 0
				});
				return jsonResult({
					status: "accepted",
					action: "steer",
					target,
					runId,
					sessionKey: resolved.entry.childSessionKey,
					sessionId,
					mode: "restart",
					label: resolveSubagentLabel(resolved.entry),
					text: `steered ${resolveSubagentLabel(resolved.entry)}.`
				});
			}
			if (action === "orchestrate") {
				const mode = readStringParam(params, "mode");
				if (mode !== "parallel" && mode !== "pipeline") return jsonResult({
					status: "error",
					action: "orchestrate",
					error: "mode is required and must be 'parallel' or 'pipeline'."
				});
				const tasksRaw = params.tasks;
				const stagesRaw = params.stages;
				if (mode === "parallel" && (!tasksRaw || tasksRaw.length === 0)) return jsonResult({
					status: "error",
					action: "orchestrate",
					error: "tasks array is required for parallel mode."
				});
				if (mode === "pipeline" && (!stagesRaw || stagesRaw.length === 0)) return jsonResult({
					status: "error",
					action: "orchestrate",
					error: "stages array is required for pipeline mode."
				});
				let totalTaskCount = 0;
				const allTasksList = [];
				if (mode === "parallel" && tasksRaw) {
					totalTaskCount = tasksRaw.length;
					allTasksList.push(...tasksRaw);
				} else if (mode === "pipeline" && stagesRaw) for (const stage of stagesRaw) {
					totalTaskCount += stage.tasks.length;
					allTasksList.push(...stage.tasks);
				}
				if (totalTaskCount > MAX_TASKS_PER_ORCHESTRATION) return jsonResult({
					status: "error",
					action: "orchestrate",
					error: `Too many tasks (${totalTaskCount}). Maximum is ${MAX_TASKS_PER_ORCHESTRATION} per orchestrate call.`
				});
				const now = Date.now();
				const windowStart = now - 6e4;
				while (orchestrateRateWindow.length > 0 && orchestrateRateWindow[0] < windowStart) orchestrateRateWindow.shift();
				if (orchestrateRateWindow.length >= RATE_LIMIT_PER_MINUTE) return jsonResult({
					status: "rate_limited",
					action: "orchestrate",
					error: `Orchestrate rate limit exceeded (max ${RATE_LIMIT_PER_MINUTE}/minute). Wait before starting another orchestration.`
				});
				orchestrateRateWindow.push(now);
				const callerDepth = getSubagentDepthFromSessionStore(requester.callerSessionKey, { cfg });
				const maxSpawnDepth = cfg.agents?.defaults?.subagents?.maxSpawnDepth ?? 2;
				if (callerDepth + 1 >= maxSpawnDepth) return jsonResult({
					status: "forbidden",
					action: "orchestrate",
					error: `Insufficient spawn depth for orchestration (current: ${callerDepth}, max: ${maxSpawnDepth}). Workers need at least 1 level.`
				});
				for (const task of allTasksList) if (task.template) {
					if (!getTemplate(task.template)) return jsonResult({
						status: "error",
						action: "orchestrate",
						error: `Template "${task.template}" not found for task "${task.label}".`
					});
				}
				const agentId = parseAgentSessionKey(requester.callerSessionKey)?.agentId ?? "main";
				const agentWorkspace = resolveAgentWorkspaceDir(cfg, agentId);
				const spawnCtx = { agentSessionKey: opts?.agentSessionKey };
				const spawnFn = async (task, outputDir) => {
					const startMs = performance.now();
					try {
						const result = await spawnSubagentDirect({
							task: task.prompt,
							label: task.label,
							template: task.template,
							model: task.model,
							runTimeoutSeconds: task.timeoutSeconds,
							cleanup: "keep"
						}, spawnCtx);
						if (result.status === "error" || result.status === "forbidden") return {
							label: task.label,
							index: task.index ?? 0,
							status: "failed",
							error: result.error ?? "Spawn failed",
							durationMs: Math.round(performance.now() - startMs),
							childSessionKey: result.childSessionKey,
							runId: result.runId,
							template: task.template
						};
						const waitTimeoutMs = (task.timeoutSeconds ?? 300) * 1e3;
						try {
							const waitResult = await callGateway({
								method: "agent.wait",
								params: {
									runId: result.runId,
									timeoutMs: waitTimeoutMs
								},
								timeoutMs: waitTimeoutMs + 1e4
							});
							const durationMs = Math.round(performance.now() - startMs);
							const statusJson = readStatusJson(outputDir);
							if (waitResult?.status === "error") return {
								label: task.label,
								index: task.index ?? 0,
								status: "failed",
								error: waitResult.error ?? "Subagent failed",
								durationMs,
								childSessionKey: result.childSessionKey,
								runId: result.runId,
								template: task.template
							};
							if (waitResult?.status === "timeout") return {
								label: task.label,
								index: task.index ?? 0,
								status: "timeout",
								error: "Subagent timed out",
								durationMs,
								childSessionKey: result.childSessionKey,
								runId: result.runId,
								template: task.template
							};
							return {
								label: task.label,
								index: task.index ?? 0,
								status: "completed",
								resultText: statusJson?.summary ?? "Completed",
								durationMs,
								childSessionKey: result.childSessionKey,
								runId: result.runId,
								template: task.template
							};
						} catch {
							return {
								label: task.label,
								index: task.index ?? 0,
								status: "timeout",
								error: "Subagent wait timed out",
								durationMs: Math.round(performance.now() - startMs),
								childSessionKey: result.childSessionKey,
								runId: result.runId,
								template: task.template
							};
						}
					} catch (err) {
						return {
							label: task.label,
							index: task.index ?? 0,
							status: "failed",
							error: err instanceof Error ? err.message : String(err),
							durationMs: Math.round(performance.now() - startMs),
							template: task.template
						};
					}
				};
				const orchestrationContext = {
					agentWorkspace,
					agentId,
					requesterSessionKey: requester.requesterSessionKey
				};
				const orchestrationConfig = {
					mode,
					tasks: mode === "parallel" ? tasksRaw : void 0,
					stages: mode === "pipeline" ? stagesRaw : void 0,
					maxConcurrency: readNumberParam(params, "maxConcurrency") ?? void 0,
					onFailure: readStringParam(params, "onFailure"),
					maxRetries: readNumberParam(params, "maxRetries") ?? void 0,
					maxTotalTokens: readNumberParam(params, "maxTotalTokens") ?? void 0,
					aggregationPrompt: readStringParam(params, "aggregationPrompt") ?? void 0,
					aggregationTemplate: readStringParam(params, "aggregationTemplate") ?? void 0,
					dryRun: params.dryRun === true,
					orchestrationId: readStringParam(params, "orchestrationId") ?? void 0
				};
				let orchestrationResult;
				if (mode === "parallel") orchestrationResult = await executeOrchestration(orchestrationConfig, spawnFn, orchestrationContext);
				else orchestrationResult = await executePipeline(orchestrationConfig, spawnFn, orchestrationContext);
				if (orchestrationConfig.aggregationPrompt && orchestrationResult.tasks.length > 0) {
					const orchDir = path$1.join(agentWorkspace, "orchestrations", orchestrationResult.orchestrationId);
					const aggregationText = await runAggregation({
						aggregationPrompt: orchestrationConfig.aggregationPrompt,
						results: orchestrationResult.tasks,
						orchestrationDir: orchDir,
						spawnFn,
						aggregationTemplate: orchestrationConfig.aggregationTemplate
					});
					if (aggregationText) orchestrationResult.aggregationResult = aggregationText;
				}
				return jsonResult({
					status: "ok",
					action: "orchestrate",
					orchestrationId: orchestrationResult.orchestrationId,
					mode: orchestrationResult.mode,
					orchestrationStatus: orchestrationResult.status,
					taskCount: orchestrationResult.tasks.length,
					completedCount: orchestrationResult.tasks.filter((t) => t.status === "completed").length,
					failedCount: orchestrationResult.tasks.filter((t) => t.status === "failed" || t.status === "timeout").length,
					totalDurationMs: orchestrationResult.totalDurationMs,
					tokensUsed: orchestrationResult.tokensUsed,
					aggregationResult: orchestrationResult.aggregationResult ?? void 0,
					tasks: orchestrationResult.tasks.map((t) => ({
						label: t.label,
						status: t.status,
						resultText: t.resultText,
						error: t.error,
						durationMs: t.durationMs,
						template: t.template
					}))
				});
			}
			if (action === "gather") {
				const orchestrationId = readStringParam(params, "orchestrationId");
				if (!orchestrationId) return jsonResult({
					status: "error",
					action: "gather",
					error: "orchestrationId is required for gather action."
				});
				const agentWorkspace = resolveAgentWorkspaceDir(cfg, parseAgentSessionKey(requester.callerSessionKey)?.agentId ?? "main");
				const orchestrationDir = path$1.join(agentWorkspace, "orchestrations", orchestrationId);
				if (!readManifest(orchestrationDir)) return jsonResult({
					status: "error",
					action: "gather",
					orchestrationId,
					error: `Orchestration "${orchestrationId}" not found.`
				});
				const gatherResult = gatherOrchestrationResults({
					orchestrationDir,
					orchestrationId,
					template: readStringParam(params, "template") ?? void 0,
					label: readStringParam(params, "label") ?? void 0,
					includeRunning: params.includeRunning === true,
					cleanup: params.cleanup === true,
					runs
				});
				return jsonResult({
					status: "ok",
					action: "gather",
					orchestrationId: gatherResult.orchestrationId,
					orchestrationStatus: gatherResult.status,
					mode: gatherResult.mode,
					startedAt: gatherResult.startedAt,
					completedAt: gatherResult.completedAt,
					taskCount: gatherResult.taskCount,
					tasks: gatherResult.tasks,
					interrupted: gatherResult.interrupted,
					completedTasks: gatherResult.completedTasks,
					incompleteTasks: gatherResult.incompleteTasks,
					canResume: gatherResult.canResume
				});
			}
			if (action === "orchestrations") {
				const agentWorkspace = resolveAgentWorkspaceDir(cfg, parseAgentSessionKey(requester.callerSessionKey)?.agentId ?? "main");
				const orchestrationsDir = path$1.join(agentWorkspace, "orchestrations");
				if (!fs$1.existsSync(orchestrationsDir)) return jsonResult({
					status: "ok",
					action: "orchestrations",
					orchestrations: [],
					total: 0
				});
				const statusFilter = readStringParam(params, "status") ?? void 0;
				const sinceFilter = readNumberParam(params, "since") ?? void 0;
				const untilFilter = readNumberParam(params, "until") ?? void 0;
				const entries = fs$1.readdirSync(orchestrationsDir, { withFileTypes: true });
				const orchestrations = [];
				for (const entry of entries) {
					if (!entry.isDirectory()) continue;
					const manifest = readManifest(path$1.join(orchestrationsDir, entry.name));
					if (!manifest) continue;
					if (statusFilter && manifest.status !== statusFilter) continue;
					if (sinceFilter && manifest.startedAt < sinceFilter) continue;
					if (untilFilter && manifest.startedAt > untilFilter) continue;
					orchestrations.push({
						orchestrationId: manifest.orchestrationId,
						status: manifest.status,
						mode: manifest.mode,
						taskCount: manifest.taskCount,
						startedAt: manifest.startedAt,
						completedAt: manifest.completedAt
					});
				}
				orchestrations.sort((a, b) => b.startedAt - a.startedAt);
				return jsonResult({
					status: "ok",
					action: "orchestrations",
					orchestrations,
					total: orchestrations.length
				});
			}
			return jsonResult({
				status: "error",
				error: "Unsupported action."
			});
		}
	};
}

//#endregion
export { createSubagentsTool };