import { d as createAgent } from "./tools-NxnEmzYg.js";
import { f as toAnthropic, s as ensureToolResultPairing } from "./messages-C_1AmSpk.js";
import { a as toolResultToText, n as documentBlockMarker } from "./types-BiobHM1D.js";
import { r as createProcessContext } from "./contexts-BJVgG0LY.js";
import { i as statsByModel } from "./stats-DAKBEKjc.js";
import { i as basic_default } from "./presets-Cm2BPJaU.js";
import { i as createMemoryStore, t as createSession } from "./session-CtAWwwkn.js";
//#region src/run-summary.ts
/**
* Build a run-summary collector. State is created fresh inside each
* `install()` call, so a single collector instance can be installed
* across multiple agents without attribution cross-talk. `latest()`
* returns the most-recent summary across **any** install — install
* per-agent collectors if you need separate post-run snapshots.
*
* @example
* ```ts
* const collector = createRunSummaryCollector({
*   onSummary: s => console.log(JSON.stringify(s)),
* })
* const uninstall = collector.install(agent.hooks)
* try { await agent.run({ prompt }) }
* finally { uninstall() }
* ```
*/
function createRunSummaryCollector(options = {}) {
	let last;
	return {
		latest: () => last,
		install(hooks) {
			let runId;
			let parentRunId;
			let depth = 0;
			let agentName;
			let startedAt = Date.now();
			let aborted = false;
			const errors = [];
			const blocks = [];
			const validationRejects = [];
			const budgetEvents = [];
			const repeatGuardEvents = [];
			const pairingRepairs = {};
			const children = [];
			function resetForNewRun() {
				aborted = false;
				errors.length = 0;
				blocks.length = 0;
				validationRejects.length = 0;
				budgetEvents.length = 0;
				repeatGuardEvents.length = 0;
				for (const k of Object.keys(pairingRepairs)) delete pairingRepairs[k];
				children.length = 0;
			}
			const unregisters = [];
			unregisters.push(hooks.hook("agent:start", (ctx) => {
				resetForNewRun();
				runId = ctx.runId;
				parentRunId = ctx.parentRunId;
				depth = ctx.depth;
				agentName = ctx.agentName;
				startedAt = ctx.startedAt;
			}));
			unregisters.push(hooks.hook("agent:abort", () => {
				aborted = true;
			}));
			unregisters.push(hooks.hook("stream:error", (ctx) => {
				const msg = ctx.err instanceof Error ? ctx.err.message : String(ctx.err);
				const errorType = ctx.err instanceof Error ? ctx.err.name : "unknown";
				errors.push({
					kind: "stream",
					message: msg,
					errorType,
					turnId: ctx.turnId,
					...ctx.statusCode !== void 0 ? { statusCode: ctx.statusCode } : {},
					...ctx.requestId !== void 0 ? { requestId: ctx.requestId } : {}
				});
			}));
			unregisters.push(hooks.hook("tool:error", (ctx) => {
				errors.push({
					kind: "tool",
					message: ctx.error.message,
					errorType: ctx.error.name,
					turnId: ctx.turnId,
					callId: ctx.callId,
					toolName: ctx.name
				});
			}));
			unregisters.push(hooks.hook("mcp:tool:error", (ctx) => {
				errors.push({
					kind: "mcp-tool",
					message: ctx.error.message,
					errorType: ctx.error.name,
					turnId: ctx.turnId,
					callId: ctx.callId,
					server: ctx.server,
					toolName: ctx.displayName
				});
			}));
			unregisters.push(hooks.hook("mcp:error", (ctx) => {
				errors.push({
					kind: "mcp",
					message: ctx.error.message,
					errorType: ctx.error.name,
					server: ctx.name
				});
			}));
			unregisters.push(hooks.hook("spawn:error", (ctx) => {
				errors.push({
					kind: "spawn",
					message: ctx.error.message,
					errorType: ctx.error.name,
					childId: ctx.id
				});
			}));
			unregisters.push(hooks.hook("tool:dispatched", (ctx) => {
				if (ctx.outcome === "gate-block" || ctx.outcome === "unknown" || ctx.outcome === "invalid-input") blocks.push({
					callId: ctx.callId,
					toolName: ctx.name,
					outcome: ctx.outcome,
					...ctx.reason ? { reason: ctx.reason } : {}
				});
			}));
			unregisters.push(hooks.hook("validation:reject", (ctx) => {
				validationRejects.push({
					callId: ctx.callId,
					toolName: ctx.name,
					reason: ctx.reason
				});
			}));
			unregisters.push(hooks.hook("budget:exceeded", (ctx) => {
				budgetEvents.push({
					kind: "bytes",
					observed: ctx.bytes,
					limit: ctx.budget,
					turnId: ctx.turnId
				});
			}));
			unregisters.push(hooks.hook("tool-budget:exceeded", (ctx) => {
				budgetEvents.push({
					kind: "tool-count",
					toolName: ctx.tool,
					mode: ctx.mode,
					observed: ctx.count,
					limit: ctx.max,
					turnId: ctx.turnId
				});
			}));
			unregisters.push(hooks.hook("repeat-guard:exceeded", (ctx) => {
				repeatGuardEvents.push({
					toolName: ctx.tool,
					count: ctx.count,
					threshold: ctx.threshold,
					action: ctx.action,
					turnId: ctx.turnId
				});
			}));
			unregisters.push(hooks.hook("pairing:repair", (ctx) => {
				pairingRepairs[ctx.mode] = (pairingRepairs[ctx.mode] ?? 0) + 1;
			}));
			unregisters.push(hooks.hook("agent:done", (stats) => {
				const endedAt = Date.now();
				const byModel = [];
				for (const [modelId, usage] of statsByModel(stats)) byModel.push({
					modelId,
					input: usage.input,
					output: usage.output,
					cacheRead: usage.cacheRead,
					cacheCreation: usage.cacheCreation,
					cost: usage.cost,
					turns: usage.turns
				});
				for (const c of stats.children ?? []) children.push(minimalSummaryFromStats(c.stats, {
					depth: c.depth ?? depth + 1,
					status: c.status === "aborted" ? "aborted" : "completed"
				}));
				const summary = {
					...runId ? { runId } : {},
					...parentRunId ? { parentRunId } : {},
					depth,
					...agentName ? { agentName } : {},
					startedAt,
					endedAt,
					durationMs: endedAt - startedAt,
					status: aborted ? "aborted" : "completed",
					turns: stats.turns,
					totals: buildTotals(stats),
					byModel,
					errors: errors.slice(),
					blocks: blocks.slice(),
					validationRejects: validationRejects.slice(),
					budgetEvents: budgetEvents.slice(),
					repeatGuardEvents: repeatGuardEvents.slice(),
					pairingRepairs: { ...pairingRepairs },
					...children.length > 0 ? { children: children.slice() } : {}
				};
				last = summary;
				try {
					options.onSummary?.(summary);
				} catch {}
			}));
			let disposed = false;
			return function uninstall() {
				if (disposed) return;
				disposed = true;
				for (const un of unregisters) try {
					un();
				} catch {}
			};
		}
	};
}
function buildTotals(stats) {
	return {
		input: stats.totalIn,
		output: stats.totalOut,
		cacheRead: stats.totalCacheRead,
		cacheCreation: stats.totalCacheCreation,
		...typeof stats.cost === "number" ? { cost: stats.cost } : {},
		...typeof stats.timeTillFirstTokenMs === "number" ? { ttftMs: stats.timeTillFirstTokenMs } : {}
	};
}
function minimalSummaryFromStats(stats, meta) {
	const byModel = [];
	for (const [modelId, usage] of statsByModel(stats)) byModel.push({
		modelId,
		input: usage.input,
		output: usage.output,
		cacheRead: usage.cacheRead,
		cacheCreation: usage.cacheCreation,
		cost: usage.cost,
		turns: usage.turns
	});
	const children = [];
	for (const c of stats.children ?? []) children.push(minimalSummaryFromStats(c.stats, {
		depth: c.depth ?? meta.depth + 1,
		status: c.status === "aborted" ? "aborted" : "completed"
	}));
	return {
		depth: meta.depth,
		startedAt: 0,
		endedAt: 0,
		durationMs: stats.elapsed,
		status: meta.status,
		turns: stats.turns,
		totals: buildTotals(stats),
		byModel,
		errors: [],
		blocks: [],
		validationRejects: [],
		budgetEvents: [],
		repeatGuardEvents: [],
		pairingRepairs: {},
		...children.length > 0 ? { children } : {}
	};
}
//#endregion
//#region src/headless.ts
function exitCodeForHeadlessResult(result) {
	switch (result.status) {
		case "completed": return 0;
		case "timeout": return 124;
		case "aborted": return 130;
		default: return 1;
	}
}
/** Serialize one event as a newline-terminated JSON line (stream-json). */
function headlessEventToJsonl(event) {
	return `${JSON.stringify(event)}\n`;
}
function formattedHeadlessTurnEventToJsonl(event) {
	return `${JSON.stringify(event)}\n`;
}
function providerTranscriptFormatForProvider(providerName) {
	return providerName === "anthropic" ? "anthropic" : "openai";
}
function transcriptToProviderMessages(turns, providerName) {
	if (providerTranscriptFormatForProvider(providerName) === "anthropic") return turns.filter((turn) => turn.role === "user" || turn.role === "assistant").map((turn) => toAnthropic({
		role: turn.role,
		content: turn.content
	}));
	return transcriptToOpenAIMessages(turns, { strictToolPairing: false });
}
function formatHeadlessResult(result, options) {
	if (options.format === "zidane") return result;
	return transcriptToProviderMessages(result.transcript, options.providerName);
}
function formatHeadlessTurnEvent(event, options) {
	if (options.format === "zidane") return event;
	return transcriptToProviderMessages([event.turn], options.providerName);
}
/**
* Run a prompt to completion, headless, and return a single serializable
* {@link HeadlessResult}. Safe to call concurrently for parallel rollouts —
* each call builds its own agent + session and tears them down in `finally`.
*/
async function runHeadless(opts) {
	const startedAt = Date.now();
	const execution = opts.execution ?? createProcessContext({ cwd: opts.cwd });
	const session = opts.session ?? await createSession({ store: opts.store ?? createMemoryStore() });
	const behavior = { ...opts.behavior ?? {} };
	if (opts.maxTurns !== void 0) behavior.maxTurns = opts.maxTurns;
	if (opts.maxTokens !== void 0) behavior.maxTokens = opts.maxTokens;
	if (opts.schema !== void 0) behavior.schema = opts.schema;
	const agent = createAgent({
		...basic_default,
		provider: opts.provider,
		execution,
		session,
		behavior,
		...opts.tools !== void 0 ? { tools: opts.tools } : {},
		...opts.mcpServers !== void 0 ? { mcpServers: opts.mcpServers } : {},
		...opts.skills !== void 0 ? { skills: opts.skills } : {}
	});
	const collector = createRunSummaryCollector();
	const uninstallSummary = collector.install(agent.hooks);
	const uninstallEvents = opts.onEvent ? installHeadlessEventAdapter(agent.hooks, opts.onEvent) : noop;
	const runStartIndex = session.turns.length;
	const controller = new AbortController();
	const onExternalAbort = () => controller.abort(opts.signal.reason);
	if (opts.signal) if (opts.signal.aborted) controller.abort(opts.signal.reason);
	else opts.signal.addEventListener("abort", onExternalAbort, { once: true });
	let timedOut = false;
	const timer = opts.timeoutMs && opts.timeoutMs > 0 ? setTimeout(() => {
		timedOut = true;
		controller.abort(/* @__PURE__ */ new Error(`Headless run timed out after ${opts.timeoutMs}ms`));
	}, opts.timeoutMs) : void 0;
	let stats;
	let error;
	try {
		stats = await agent.run({
			prompt: opts.prompt,
			signal: controller.signal,
			...opts.model !== void 0 ? { model: opts.model } : {},
			...opts.system !== void 0 ? { system: opts.system } : {},
			...opts.thinking !== void 0 ? { thinking: opts.thinking } : {}
		});
	} catch (err) {
		const e = err instanceof Error ? err : new Error(String(err));
		error = {
			message: e.message,
			type: e.name
		};
	} finally {
		if (timer) clearTimeout(timer);
		opts.signal?.removeEventListener("abort", onExternalAbort);
		uninstallEvents();
		uninstallSummary();
		await agent.destroy();
	}
	let status;
	if (error) status = timedOut ? "timeout" : controller.signal.aborted ? "aborted" : "error";
	else if (controller.signal.aborted) status = timedOut ? "timeout" : "aborted";
	else status = "completed";
	const rawTranscript = session.turns.slice(runStartIndex);
	const transcript = opts.includeThinking === false ? stripThinking(rawTranscript) : rawTranscript;
	const summary = collector.latest();
	const result = {
		status,
		finalText: extractFinalText(rawTranscript),
		...stats?.output ? { output: stats.output } : {},
		usage: {
			input: stats?.totalIn ?? 0,
			output: stats?.totalOut ?? 0,
			cacheRead: stats?.totalCacheRead ?? 0,
			cacheCreation: stats?.totalCacheCreation ?? 0,
			...typeof stats?.cost === "number" ? { cost: stats.cost } : {}
		},
		turns: stats?.turns ?? 0,
		durationMs: stats?.elapsed ?? Date.now() - startedAt,
		numToolCalls: countToolCalls(rawTranscript),
		...status !== "aborted" && status !== "timeout" && lastFinishReason(stats) ? { finishReason: lastFinishReason(stats) } : {},
		...error ? { error } : {},
		sessionId: session.id,
		...summary ? { summary } : {},
		transcript
	};
	opts.onEvent?.({
		type: "result",
		result
	});
	return result;
}
/**
* Convert raw `session.turns` into standard OpenAI chat-completion messages:
* assistant turns carry `tool_calls`, and each `tool_result` becomes its own
* `role: 'tool'` message. This is the drop-in shape for an SFT renderer —
* unlike `toOpenAI` (session/messages.ts), which emits an internal `_tag`
* envelope meant for re-sending to a provider, not for training data.
*
* Fails closed on corrupt raw turns instead of fabricating tool results; silent
* placeholders would create structurally-valid but semantically-poisoned SFT
* examples.
*/
function transcriptToOpenAIMessages(turns, options = {}) {
	const { strictToolPairing = true } = options;
	const messages = [];
	let chunk = [];
	const flushChunk = () => {
		if (chunk.length === 0) return;
		let paired = chunk;
		if (strictToolPairing) {
			const repairs = [];
			paired = ensureToolResultPairing(chunk, { onRepair: (repair) => repairs.push(repair) });
			if (repairs.length > 0) throw new Error(`Cannot convert transcript to OpenAI messages: tool pairing repair required (${repairs.map((r) => r.mode).join(", ")})`);
		}
		for (const msg of paired) pushOpenAIChatMessage(messages, msg);
		chunk = [];
	};
	for (const turn of turns) {
		if (turn.role === "system") {
			flushChunk();
			messages.push({
				role: "system",
				content: textOf(turn.content)
			});
			continue;
		}
		chunk.push({
			role: turn.role,
			content: turn.content
		});
	}
	flushChunk();
	return messages;
}
function pushOpenAIChatMessage(messages, msg) {
	const text = textOf(msg.content);
	if (msg.role === "assistant") {
		const toolCalls = msg.content.filter((b) => b.type === "tool_call");
		const out = {
			role: "assistant",
			content: text || null
		};
		if (toolCalls.length > 0) out.tool_calls = toolCalls.map((b) => ({
			id: b.id,
			type: "function",
			function: {
				name: b.name,
				arguments: JSON.stringify(b.input)
			}
		}));
		messages.push(out);
		return;
	}
	const userParts = contentPartsFromBlocks(msg.content);
	if (userParts.length > 0) messages.push({
		role: "user",
		content: simplifyOpenAIContent(userParts)
	});
	for (const tr of msg.content.filter((b) => b.type === "tool_result")) {
		const { text, images } = summarizeToolResultForOpenAI(tr.output);
		if (images.length === 0) {
			messages.push({
				role: "tool",
				tool_call_id: tr.callId,
				content: text
			});
			continue;
		}
		const noun = images.length === 1 ? "image" : "images";
		const marker = `[${images.length} ${noun} attached — see next user message]`;
		messages.push({
			role: "tool",
			tool_call_id: tr.callId,
			content: text.length > 0 ? `${text}\n\n${marker}` : marker
		});
		messages.push({
			role: "user",
			content: [...images.map(toOpenAIImagePart), {
				type: "text",
				text: `(${noun} returned by tool call ${tr.callId})`
			}]
		});
	}
}
function noop() {}
function textOf(content) {
	return content.filter((b) => b.type === "text").map((b) => b.text).join("");
}
function contentPartsFromBlocks(content) {
	const parts = [];
	for (const block of content) if (block.type === "image") parts.push(toOpenAIImagePart(block));
	else if (block.type === "document") parts.push({
		type: "text",
		text: documentMarker(block)
	});
	else if (block.type === "text" && block.text.length > 0) parts.push({
		type: "text",
		text: block.text
	});
	return parts;
}
function simplifyOpenAIContent(parts) {
	if (parts.length === 1 && parts[0].type === "text") return parts[0].text;
	return parts;
}
function toOpenAIImagePart(image) {
	return {
		type: "image_url",
		image_url: { url: `data:${image.mediaType};base64,${image.data}` }
	};
}
function summarizeToolResultForOpenAI(output) {
	if (typeof output === "string") return {
		text: output,
		images: []
	};
	const texts = [];
	const images = [];
	for (const block of output) if (block.type === "text") texts.push(block.text);
	else if (block.type === "image") images.push({
		mediaType: block.mediaType,
		data: block.data
	});
	else texts.push(documentMarker(block));
	return {
		text: texts.join("\n"),
		images
	};
}
function documentMarker(doc) {
	return documentBlockMarker(doc, "document omitted");
}
function extractFinalText(turns) {
	for (let i = turns.length - 1; i >= 0; i--) {
		const turn = turns[i];
		if (turn.role !== "assistant") continue;
		const text = textOf(turn.content);
		if (text) return text;
	}
	return "";
}
function countToolCalls(turns) {
	let n = 0;
	for (const turn of turns) for (const block of turn.content) if (block.type === "tool_call") n++;
	return n;
}
function lastFinishReason(stats) {
	const usages = stats?.turnUsage;
	if (!usages) return void 0;
	for (let i = usages.length - 1; i >= 0; i--) if (usages[i].finishReason) return usages[i].finishReason;
}
function stripThinking(turns) {
	return turns.map((turn) => ({
		...turn,
		content: turn.content.filter((b) => b.type !== "thinking" && b.type !== "redacted_thinking")
	}));
}
function installHeadlessEventAdapter(hooks, onEvent) {
	const unregs = [];
	const emittedTurnIds = /* @__PURE__ */ new Set();
	const emit = (event) => {
		try {
			onEvent(event);
		} catch {}
	};
	unregs.push(hooks.hook("agent:start", (ctx) => emit({
		type: "start",
		runId: ctx.runId,
		...ctx.providerName ? { provider: ctx.providerName } : {}
	})));
	unregs.push(hooks.hook("stream:text", (ctx) => emit({
		type: "text",
		delta: ctx.delta
	})));
	unregs.push(hooks.hook("stream:thinking", (ctx) => emit({
		type: "thinking",
		delta: ctx.delta
	})));
	unregs.push(hooks.hook("tool:before", (ctx) => emit({
		type: "tool_call",
		callId: ctx.callId,
		name: ctx.name,
		input: ctx.input
	})));
	unregs.push(hooks.hook("tool:after", (ctx) => emit({
		type: "tool_result",
		callId: ctx.callId,
		name: ctx.name,
		output: toolResultToText(ctx.result),
		isError: false
	})));
	unregs.push(hooks.hook("tool:error", (ctx) => emit({
		type: "tool_result",
		callId: ctx.callId,
		name: ctx.name,
		output: ctx.error.message,
		isError: true
	})));
	unregs.push(hooks.hook("session:turns", (ctx) => {
		const startIndex = ctx.count - ctx.turns.length;
		ctx.turns.forEach((turn, i) => {
			if (emittedTurnIds.has(turn.id)) return;
			emittedTurnIds.add(turn.id);
			emit({
				type: "turn",
				index: startIndex + i,
				turn
			});
		});
	}));
	unregs.push(hooks.hook("spawn:before", (ctx) => emit({
		type: "spawn",
		event: "before",
		id: ctx.id
	})));
	unregs.push(hooks.hook("spawn:complete", (ctx) => emit({
		type: "spawn",
		event: "complete",
		id: ctx.id,
		info: { status: ctx.status ?? "completed" }
	})));
	unregs.push(hooks.hook("spawn:error", (ctx) => emit({
		type: "spawn",
		event: "error",
		id: ctx.id,
		info: { message: ctx.error.message }
	})));
	unregs.push(hooks.hook("stream:error", (ctx) => emit({
		type: "error",
		message: ctx.err instanceof Error ? ctx.err.message : String(ctx.err),
		...ctx.err instanceof Error ? { errorType: ctx.err.name } : {}
	})));
	return () => {
		for (const un of unregs) try {
			un();
		} catch {}
	};
}
//#endregion
export { headlessEventToJsonl as a, runHeadless as c, createRunSummaryCollector as d, formattedHeadlessTurnEventToJsonl as i, transcriptToOpenAIMessages as l, formatHeadlessResult as n, installHeadlessEventAdapter as o, formatHeadlessTurnEvent as r, providerTranscriptFormatForProvider as s, exitCodeForHeadlessResult as t, transcriptToProviderMessages as u };

//# sourceMappingURL=headless-CPaunZsU.js.map