import { A as PERSISTED_STUB_PREFIX, C as normalizeShellCommand, D as TOOL_USE_CANCELLED_MESSAGE, E as SHELL_CASCADE_CANCEL_MESSAGE, I as resolvePersistDir, L as resolveTasksDir, M as buildPersistedStub, N as cleanupPersistedSession, O as TOOL_USE_SKIPPED_MESSAGE, P as maybePersistToolResult, S as defaultRepeatGuardTracked, T as INTERRUPT_MESSAGE_FOR_TOOL_USE, a as multiEdit, c as grep, d as createAgent, g as createSkillsRunScriptTool, h as createSkillsUseTool, j as PERSISTENCE_PREVIEW_BYTES, k as validateToolArgs, l as glob, n as createSpawnTool, p as waitTask, s as createInteractionTool, u as edit, v as createSkillsReadTool, w as stableStringify, x as defaultRepeatGuardNormalize, y as createShellTool } from "./tools-NxnEmzYg.js";
import { n as estimateTokens, r as utf8ByteLength, t as BYTES_PER_TOKEN } from "./utils-ngQzYzZD.js";
import { c as baseten, d as anthropic, f as applyAnthropicCacheBreakpoints, n as openai, r as local, s as cerebras, t as openrouter, u as arcee } from "./providers-BGBB18zz.js";
import { a as AgentToolNotAllowedError, d as matchesContextExceeded, i as AgentProviderError, l as errorMessage, n as AgentBudgetExceededError, o as AgentToolPairingError, p as toTypedError, r as AgentContextExceededError, s as CONTEXT_EXCEEDED_MESSAGE_PATTERNS, t as AgentAbortedError } from "./errors-DkR6GPJw.js";
import { A as renderSystemForWire, C as sanitizeToolSpecs, D as appendStaticSection, E as appendDynamicSection, M as splitSystemPrompt, O as hasSystemPromptBoundary, S as sanitizeToolSchema, T as SYSTEM_PROMPT_BOUNDARY, _ as classifyOpenAICompatError, a as detectTurnInterruption, c as filterUnresolvedToolUses, d as remintDuplicateToolCallIds, f as toAnthropic, h as OpenAICompatHttpError, i as autoDetectAndConvert, j as replaceDynamicSection, k as joinSystemPrompt, l as fromAnthropic, m as toWireMessages, n as SYNTHETIC_TOOL_RESULT_PLACEHOLDER, o as ensureEndsWithUserMessage, p as toOpenAI, r as TOOL_USE_INTERRUPTED_MARKER, s as ensureToolResultPairing, t as ORPHANED_TOOL_RESULT_MARKER, u as fromOpenAI, v as mapOAIFinishReason, y as openaiCompat } from "./messages-C_1AmSpk.js";
import { a as toolResultToText, i as toolOutputByteLength, r as toolOutputBudgetByteLength } from "./types-BiobHM1D.js";
import { n as createSandboxContext, r as createProcessContext, t as resolveDetachedTasksCapability } from "./contexts-BJVgG0LY.js";
import { o as readStateKey, s as resolveReadStateMap, t as getReadState } from "./read-state-BFqpQRc5.js";
import { _ as validateResourcePath, a as writeSkillsToDisk, b as validateSkillName, d as buildCatalog, f as IMPLICITLY_ALLOWED_SKILL_TOOLS, g as parseAllowedToolPattern, h as matchesAllowedTool, i as writeSkillToDisk, m as isToolAllowedByUnion, n as stripShellInterpolations, o as discoverSkills, p as installAllowedToolsGate, r as resolveSkills, t as interpolateShellCommands, u as parseSkillFile, v as validateResourcePathReal, x as createSkillActivationState, y as validateSkillForWrite } from "./interpolate-Dy7Lunvg.js";
import { a as resultToString, c as McpOAuthProvider, i as normalizeMcpServers, l as createMemoryMcpCredentialStore, n as connectMcpServers, r as normalizeMcpBlocks, u as hasAuthorizationHeader } from "./mcp-tevNihk_.js";
import { i as statsByModel, n as flattenTurns } from "./stats-DAKBEKjc.js";
import { C as stripImagesFromTurns, D as CompactPromptTooLongError, E as CompactInvalidInputError, S as sliceForCompaction, T as truncateHeadForPtlRetry, _ as buildFullCompactPrompt, a as createLoggingHooks, b as ANCHOR_PREVIEW_MAX_CHARS, c as selectFilesFromReadState, d as compactConversation, f as BASE_INSTRUCTIONS, g as buildFromCompactPrompt, h as buildCompactPrompt, i as createLogger, l as selectFilesFromSession, m as TRAILER, n as startOAuthCallback, o as jsonSink, p as NO_TOOLS_PREAMBLE, r as consoleSink, s as buildPostCompactAttachments, t as loginMcpServer, u as selectRecentFiles, v as buildTailCompactPrompt, w as summaryToTurn, x as anchorPreviewFor, y as buildUpToCompactPrompt } from "./login-0jP1pnSJ.js";
import { i as basic_default, n as definePreset, r as basicTools } from "./presets-Cm2BPJaU.js";
import { a as headlessEventToJsonl, c as runHeadless, d as createRunSummaryCollector, l as transcriptToOpenAIMessages } from "./headless-CPaunZsU.js";
import { a as createFileMapStore, i as createMemoryStore, n as loadSession, r as createRemoteStore, t as createSession } from "./session-CtAWwwkn.js";
import { EFFICIENCY_METRICS, EvalMetricError, artifactPath, buildEvalRunSummary, buildRegisteredEvals, buildTrajectory, clearRegisteredEvals, computeEvalTagScores, createEvalAgent, createEvalRunReporter, createReusableExecutionContext, defineEval, defineMetrics, efficiencyMetricValues, emitEfficiencyMetrics, fileContains, fileContentQuality, fileExists, fileExistsOneOf, finalizeEvalMetrics, formatEvalCaseSummary, formatEvalRunSummary, formatTrajectoryLine, functionalityMetric, llmJudge, normalizeMetric, registerEvalTests, relativeArtifactPath, runEvalCase, statusCompleted } from "./eval.js";
import { defineSkill } from "./skills.js";
//#region src/cache-telemetry.ts
const FNV_OFFSET = 2166136261;
const FNV_PRIME = 16777619;
/**
* FNV-1a-style 32-bit hash over UTF-16 code units. Pure, allocation-free,
* ~10 ns per KB. Cryptographic strength is irrelevant here — we only need
* change detection, and this has effectively zero collision risk for the
* small number of dimensions tracked.
*
* Feeds the FULL char code into the mix (same as read-state's
* `hashContent`) — masking to the low byte would collapse code points that
* share a low byte, so a non-ASCII system-prompt change could hash
* identically and silently hide a cache-dimension drift.
*
* Exported for tests; callers shouldn't typically import directly.
*/
function fnv1a32(s) {
	let h = FNV_OFFSET;
	for (let i = 0; i < s.length; i++) {
		h ^= s.charCodeAt(i);
		h = Math.imul(h, FNV_PRIME);
	}
	return h >>> 0;
}
/**
* Build a {@link CacheDimensionSnapshot} from a `turn:before` payload.
*
* Pure — exported so hosts can compute snapshots outside the logger (e.g.
* stamping them onto custom telemetry spans). The hash is deterministic on
* byte-identical inputs.
*/
function snapshotCacheDimensions(options) {
	const toolsJson = JSON.stringify(options.tools ?? []);
	return {
		systemHash: fnv1a32(options.system),
		systemBytes: options.system.length,
		toolsHash: fnv1a32(toolsJson),
		toolsCount: Array.isArray(options.tools) ? options.tools.length : 0,
		model: options.model,
		thinking: options.thinking ?? "off",
		thinkingBudget: options.thinkingBudget ?? 0
	};
}
/**
* Compare two snapshots and return the list of dimensions whose bytes
* differ. The `details` map carries a short human-readable description per
* changed dimension (e.g. `system: 1024 → 1031 bytes`).
*
* Pure / no I/O. Use this in tests to assert the diff logic; the logger
* itself just formats and emits the result.
*/
function diffCacheDimensions(prev, curr) {
	const changed = [];
	const details = {};
	if (prev.systemHash !== curr.systemHash) {
		changed.push("system");
		details.system = `${prev.systemBytes} → ${curr.systemBytes} bytes (hash ${hex(prev.systemHash)} → ${hex(curr.systemHash)})`;
	}
	if (prev.toolsHash !== curr.toolsHash) {
		changed.push("tools");
		details.tools = `${prev.toolsCount} → ${curr.toolsCount} tools (hash ${hex(prev.toolsHash)} → ${hex(curr.toolsHash)})`;
	}
	if (prev.model !== curr.model) {
		changed.push("model");
		details.model = `${prev.model} → ${curr.model}`;
	}
	if (prev.thinking !== curr.thinking) {
		changed.push("thinking");
		details.thinking = `${prev.thinking} → ${curr.thinking}`;
	}
	if (prev.thinkingBudget !== curr.thinkingBudget) {
		changed.push("thinkingBudget");
		details.thinkingBudget = `${prev.thinkingBudget} → ${curr.thinkingBudget}`;
	}
	return {
		changed,
		details
	};
}
function hex(n) {
	return `0x${n.toString(16).padStart(8, "0")}`;
}
/**
* Install the cache-break logger on an agent's hook bus.
*
* Subscribes to `turn:before` (snapshot) + `turn:after` (compare with prior
* snapshot, log breaks). Returns an `uninstall` fn that detaches both
* listeners. Idempotent w.r.t. agent lifecycle — installs/uninstalls cleanly
* across runs.
*
* Recommended setup:
*
* ```ts
* const uninstall = installCacheBreakLogger(agent.hooks, {
*   log: line => logger.debug(line),
*   verbose: !!process.env.ZIDANE_DEBUG?.includes('cache'),
* })
* // ...
* uninstall()
* ```
*
* Performance: hashing runs on each `turn:before` and is bounded by the
* input size (system + tools serialization). Disabled callers pay nothing
* (don't install).
*/
function installCacheBreakLogger(hooks, options = {}) {
	const log = options.log ?? ((line) => console.error(line));
	const verbose = options.verbose === true;
	const expectedReadAtLeast = options.expectedReadAtLeast ?? 1;
	let prev;
	let turnIndex = 0;
	let pending;
	function onTurnBefore(ctx) {
		const curr = snapshotCacheDimensions(ctx.options);
		turnIndex += 1;
		if (verbose) log(formatVerboseLine({
			turn: turnIndex,
			turnId: ctx.turnId,
			snapshot: curr
		}));
		pending = {
			snapshot: curr,
			turnIndex,
			turnId: ctx.turnId
		};
	}
	function onTurnAfter(ctx) {
		if (!pending || pending.turnId !== ctx.turnId) return;
		const { snapshot: curr, turnIndex: tIdx } = pending;
		pending = void 0;
		if (prev && tIdx > 1 && typeof ctx.usage.cacheRead === "number") {
			const cacheRead = ctx.usage.cacheRead;
			if (cacheRead < expectedReadAtLeast) {
				const diff = diffCacheDimensions(prev, curr);
				if (diff.changed.length > 0) log(formatBreakLine({
					turn: tIdx,
					turnId: ctx.turnId,
					cacheRead,
					cacheCreation: ctx.usage.cacheCreation ?? 0,
					diff
				}));
			}
		}
		prev = curr;
	}
	const unregisterBefore = hooks.hook("turn:before", onTurnBefore);
	const unregisterAfter = hooks.hook("turn:after", onTurnAfter);
	return () => {
		unregisterBefore();
		unregisterAfter();
	};
}
function formatBreakLine(input) {
	const names = input.diff.changed.join(", ");
	const details = input.diff.changed.map((d) => `  ${d}: ${input.diff.details[d]}`).join("\n");
	return [
		`[zidane:cache-break] turn=${input.turn} turnId=${input.turnId} cacheRead=${input.cacheRead} cacheCreation=${input.cacheCreation}`,
		`  changed: ${names}`,
		details
	].join("\n");
}
function formatVerboseLine(input) {
	const s = input.snapshot;
	return `[zidane:cache] turn=${input.turn} turnId=${input.turnId} system=${hex(s.systemHash)}(${s.systemBytes}b) tools=${hex(s.toolsHash)}(${s.toolsCount}) model=${s.model} thinking=${s.thinking}/${s.thinkingBudget}`;
}
//#endregion
//#region src/metrics.ts
function prefixed$1(prefix, name) {
	return prefix ? `${prefix}${name}` : name;
}
/**
* Drop `undefined` entries before handing attributes to a metrics
* backend. OTel's `@opentelemetry/api` rejects `undefined` attribute
* values (and Prometheus / StatsD adapters silently mis-label them); the
* helper's own API surface allows `undefined` for ergonomic call sites
* (`{...(cond ? { foo } : {})}`-style spreads), so we strip here at the
* boundary.
*/
function mergeAttrs(base, extra) {
	const out = {};
	if (base) {
		for (const [k, v] of Object.entries(base)) if (v !== void 0) out[k] = v;
	}
	for (const [k, v] of Object.entries(extra)) if (v !== void 0) out[k] = v;
	return out;
}
/**
* Build a set of metrics hook handlers that can be installed on an agent.
*
* @example OpenTelemetry
* ```ts
* import { metrics } from '@opentelemetry/api'
* const meter = metrics.getMeter('zidane')
* const m = createMetricsHooks({ meter, baseAttributes: { service: 'tui' } })
* const uninstall = m.install(agent.hooks)
* try { await agent.run({ prompt }) }
* finally { uninstall() }
* ```
*/
function createMetricsHooks(options) {
	const ns = options.namespace;
	const base = options.baseAttributes;
	const onError = options.onError ?? (() => {});
	const make = {
		counter: (name, opts) => safeFactory(() => options.meter.createCounter(prefixed$1(ns, name), opts), name, onError),
		histogram: (name, opts) => safeFactory(() => options.meter.createHistogram(prefixed$1(ns, name), opts), name, onError),
		upDown: (name, opts) => safeFactory(() => options.meter.createUpDownCounter(prefixed$1(ns, name), opts), name, onError)
	};
	const turnDuration = make.histogram("gen_ai.client.operation.duration", {
		unit: "ms",
		description: "Per-turn LLM operation duration."
	});
	const tokenUsage = make.histogram("gen_ai.client.token.usage", {
		unit: "tokens",
		description: "Per-turn token usage (tagged by gen_ai.token.type)."
	});
	const ttft = make.histogram("gen_ai.client.time_to_first_token", {
		unit: "ms",
		description: "Per-turn time to first token."
	});
	const toolDuration = make.histogram("gen_ai.tool.duration", {
		unit: "ms",
		description: "Native tool execution wall clock."
	});
	const toolOutput = make.histogram("gen_ai.tool.output_bytes", {
		unit: "By",
		description: "Native tool output bytes."
	});
	const mcpToolDuration = make.histogram("gen_ai.mcp.tool.duration", {
		unit: "ms",
		description: "MCP tool execution wall clock."
	});
	const mcpBootstrapDuration = make.histogram("gen_ai.mcp.bootstrap.duration", {
		unit: "ms",
		description: "MCP server bootstrap duration."
	});
	const runsStarted = make.counter("gen_ai.agent.runs", { description: "Runs started." });
	const runsCompleted = make.counter("gen_ai.agent.runs.completed", { description: "Runs completed." });
	const aborts = make.counter("gen_ai.agent.aborts", { description: "Run abort events." });
	const toolCalls = make.counter("gen_ai.tool.calls", { description: "Tool dispatches (tagged by outcome)." });
	const toolErrors = make.counter("gen_ai.tool.errors", { description: "Native tool errors." });
	const mcpToolErrors = make.counter("gen_ai.mcp.tool.errors", { description: "MCP tool errors." });
	const streamErrors = make.counter("gen_ai.stream.errors", { description: "Provider stream errors." });
	const validationRejects = make.counter("gen_ai.validation.rejects", { description: "Tool input validation rejects." });
	const validationCoercions = make.counter("gen_ai.validation.coercions", { description: "Tool input auto-coercions." });
	const gateBlocks = make.counter("gen_ai.gate.blocks", { description: "Tool-gate refusals." });
	const budgetExceeded = make.counter("gen_ai.budget.exceeded", { description: "Per-turn byte budget exceedances." });
	const toolBudgetExceeded = make.counter("gen_ai.tool_budget.exceeded", { description: "Per-tool dispatch budget exceedances." });
	const pairingRepairs = make.counter("gen_ai.pairing.repairs", { description: "Tool-pairing repair counts." });
	const oauthRefreshes = make.counter("gen_ai.oauth.refreshes", { description: "Provider OAuth credential refreshes." });
	const mcpErrors = make.counter("gen_ai.mcp.errors", { description: "MCP server errors." });
	const mcpAuthRequired = make.counter("gen_ai.mcp.auth.required", { description: "MCP bootstrap blocked on missing auth." });
	const costMeter = make.counter("gen_ai.cost_usd", {
		unit: "USD",
		description: "Cumulative cost across turns."
	});
	const runsActive = make.upDown("gen_ai.agent.runs.active", { description: "In-flight agent runs." });
	return { install(hooks) {
		const turnStart = /* @__PURE__ */ new Map();
		const toolStart = /* @__PURE__ */ new Map();
		const mcpStart = /* @__PURE__ */ new Map();
		const unregisters = [];
		const record = (instrument, value, attrs, kind) => {
			if (!instrument) return;
			try {
				instrument.record(value, mergeAttrs(base, attrs));
			} catch (err) {
				try {
					onError(kind, err);
				} catch {}
			}
		};
		const add = (instrument, value, attrs, kind) => {
			if (!instrument) return;
			try {
				instrument.add(value, mergeAttrs(base, attrs));
			} catch (err) {
				try {
					onError(kind, err);
				} catch {}
			}
		};
		unregisters.push(hooks.hook("agent:start", (ctx) => {
			const attrs = {
				"gen_ai.agent.depth": ctx.depth,
				...ctx.agentName ? { "gen_ai.agent.name": ctx.agentName } : {}
			};
			add(runsStarted, 1, attrs, "runs");
			add(runsActive, 1, attrs, "runs.active");
		}));
		unregisters.push(hooks.hook("agent:done", () => {
			add(runsCompleted, 1, {}, "runs.completed");
			add(runsActive, -1, {}, "runs.active");
		}));
		unregisters.push(hooks.hook("agent:abort", () => {
			add(aborts, 1, {}, "aborts");
		}));
		unregisters.push(hooks.hook("turn:before", (ctx) => {
			turnStart.set(ctx.turnId, Date.now());
		}));
		unregisters.push(hooks.hook("turn:after", (ctx) => {
			const started = turnStart.get(ctx.turnId);
			turnStart.delete(ctx.turnId);
			const tagsBase = {
				"gen_ai.operation.name": "chat",
				...ctx.usage.modelId ? { "gen_ai.response.model": ctx.usage.modelId } : {},
				...ctx.usage.finishReason ? { "gen_ai.response.finish_reason": ctx.usage.finishReason } : {}
			};
			if (typeof started === "number") record(turnDuration, Date.now() - started, tagsBase, "turn.duration");
			if (typeof ctx.usage.timeToFirstTokenMs === "number") record(ttft, ctx.usage.timeToFirstTokenMs, tagsBase, "ttft");
			record(tokenUsage, ctx.usage.input, {
				...tagsBase,
				"gen_ai.token.type": "input"
			}, "token.input");
			record(tokenUsage, ctx.usage.output, {
				...tagsBase,
				"gen_ai.token.type": "output"
			}, "token.output");
			if (typeof ctx.usage.cacheRead === "number" && ctx.usage.cacheRead > 0) record(tokenUsage, ctx.usage.cacheRead, {
				...tagsBase,
				"gen_ai.token.type": "cache_read"
			}, "token.cache_read");
			if (typeof ctx.usage.cacheCreation === "number" && ctx.usage.cacheCreation > 0) record(tokenUsage, ctx.usage.cacheCreation, {
				...tagsBase,
				"gen_ai.token.type": "cache_creation"
			}, "token.cache_creation");
			if (typeof ctx.usage.cost === "number" && ctx.usage.cost > 0) add(costMeter, ctx.usage.cost, tagsBase, "cost");
		}));
		unregisters.push(hooks.hook("stream:error", (ctx) => {
			add(streamErrors, 1, {
				"http.response.status_code": ctx.statusCode,
				"error.type": ctx.err instanceof Error ? ctx.err.name : "unknown"
			}, "stream.error");
		}));
		unregisters.push(hooks.hook("tool:before", (ctx) => {
			toolStart.set(ctx.callId, Date.now());
		}));
		unregisters.push(hooks.hook("tool:after", (ctx) => {
			const started = toolStart.get(ctx.callId);
			toolStart.delete(ctx.callId);
			const tags = { "gen_ai.tool.name": ctx.name };
			if (typeof started === "number") record(toolDuration, Date.now() - started, tags, "tool.duration");
			record(toolOutput, ctx.outputBytes, tags, "tool.output_bytes");
		}));
		unregisters.push(hooks.hook("tool:error", (ctx) => {
			add(toolErrors, 1, {
				"gen_ai.tool.name": ctx.name,
				"error.type": ctx.error.name
			}, "tool.errors");
		}));
		unregisters.push(hooks.hook("tool:cancelled", (ctx) => {
			toolStart.delete(ctx.callId);
		}));
		unregisters.push(hooks.hook("tool:dispatched", (ctx) => {
			add(toolCalls, 1, {
				"gen_ai.tool.name": ctx.name,
				"outcome": ctx.outcome
			}, "tool.calls");
			if (ctx.outcome === "gate-block") add(gateBlocks, 1, {
				"gen_ai.tool.name": ctx.name,
				...ctx.reason ? { reason: ctx.reason } : {}
			}, "gate.blocks");
			if (ctx.outcome === "unknown") toolStart.delete(ctx.callId);
		}));
		unregisters.push(hooks.hook("validation:reject", (ctx) => {
			add(validationRejects, 1, { "gen_ai.tool.name": ctx.name }, "validation.rejects");
		}));
		unregisters.push(hooks.hook("validation:coerce", (ctx) => {
			add(validationCoercions, 1, {
				"gen_ai.tool.name": ctx.name,
				"coercions": ctx.coercions.length
			}, "validation.coercions");
		}));
		unregisters.push(hooks.hook("budget:exceeded", (ctx) => {
			add(budgetExceeded, 1, {
				bytes: ctx.bytes,
				budget: ctx.budget
			}, "budget.exceeded");
		}));
		unregisters.push(hooks.hook("tool-budget:exceeded", (ctx) => {
			add(toolBudgetExceeded, 1, {
				"gen_ai.tool.name": ctx.tool,
				"mode": ctx.mode,
				"count": ctx.count,
				"max": ctx.max
			}, "tool_budget.exceeded");
		}));
		unregisters.push(hooks.hook("pairing:repair", (ctx) => {
			add(pairingRepairs, 1, { mode: ctx.mode }, "pairing.repairs");
		}));
		unregisters.push(hooks.hook("oauth:refresh", (ctx) => {
			add(oauthRefreshes, 1, {
				provider: ctx.provider,
				source: ctx.source
			}, "oauth.refreshes");
		}));
		unregisters.push(hooks.hook("mcp:tool:before", (ctx) => {
			mcpStart.set(ctx.callId, Date.now());
		}));
		unregisters.push(hooks.hook("mcp:tool:after", (ctx) => {
			const started = mcpStart.get(ctx.callId);
			mcpStart.delete(ctx.callId);
			const tags = {
				"gen_ai.mcp.server": ctx.server,
				"gen_ai.tool.name": ctx.displayName
			};
			if (typeof started === "number") record(mcpToolDuration, Date.now() - started, tags, "mcp.tool.duration");
		}));
		unregisters.push(hooks.hook("mcp:tool:error", (ctx) => {
			mcpStart.delete(ctx.callId);
			add(mcpToolErrors, 1, {
				"gen_ai.mcp.server": ctx.server,
				"gen_ai.tool.name": ctx.displayName,
				"error.type": ctx.error.name
			}, "mcp.tool.errors");
		}));
		unregisters.push(hooks.hook("mcp:bootstrap:end", (ctx) => {
			record(mcpBootstrapDuration, ctx.durationMs, {
				"gen_ai.mcp.server": ctx.name,
				"ok": ctx.ok
			}, "mcp.bootstrap.duration");
		}));
		unregisters.push(hooks.hook("mcp:error", (ctx) => {
			add(mcpErrors, 1, {
				"gen_ai.mcp.server": ctx.name,
				"error.type": ctx.error.name
			}, "mcp.errors");
		}));
		unregisters.push(hooks.hook("mcp:auth:required", (ctx) => {
			add(mcpAuthRequired, 1, {
				"gen_ai.mcp.server": ctx.name,
				"transport": ctx.transport,
				"reason": ctx.reason
			}, "mcp.auth.required");
		}));
		let disposed = false;
		return function uninstall() {
			if (disposed) return;
			disposed = true;
			for (const un of unregisters) try {
				un();
			} catch {}
			turnStart.clear();
			toolStart.clear();
			mcpStart.clear();
		};
	} };
}
/**
* Defensive factory wrapper — returns undefined when meter creation
* throws. Lets a half-broken meter (one unsupported instrument) still
* give partial metrics rather than collapsing the whole install.
*/
function safeFactory(factory, name, onError) {
	try {
		return factory();
	} catch (err) {
		try {
			onError(`createInstrument:${name}`, err);
		} catch {}
		return;
	}
}
//#endregion
//#region src/tracing.ts
/**
* Stable keys we emit unconditionally — present in BOTH Sentry and OTel
* conventions with identical semantics, so no `conventions` branching is
* needed at the call site.
*/
const GEN_AI = {
	system: "gen_ai.system",
	operationName: "gen_ai.operation.name",
	requestModel: "gen_ai.request.model",
	responseModel: "gen_ai.response.model",
	responseFinishReasons: "gen_ai.response.finish_reasons",
	responseId: "gen_ai.response.id",
	responseStreaming: "gen_ai.response.streaming",
	responseTokensPerSecond: "gen_ai.response.tokens_per_second",
	responseTimeToFirstTokenSeconds: "gen_ai.response.time_to_first_token",
	responseTimeToFirstTokenMs: "gen_ai.client.time_to_first_token",
	usageInputTokens: "gen_ai.usage.input_tokens",
	usageOutputTokens: "gen_ai.usage.output_tokens",
	usageTotalTokens: "gen_ai.usage.total_tokens",
	usageInputTokensCached: "gen_ai.usage.input_tokens.cached",
	usageInputTokensCacheWrite: "gen_ai.usage.input_tokens.cache_write",
	usageOutputTokensReasoning: "gen_ai.usage.output_tokens.reasoning",
	usageCacheReadInputTokens: "gen_ai.usage.cache_read_input_tokens",
	usageCacheCreationInputTokens: "gen_ai.usage.cache_creation_input_tokens",
	usageReasoningTokens: "gen_ai.usage.reasoning_tokens",
	costTotalTokens: "gen_ai.cost.total_tokens",
	costInputTokens: "gen_ai.cost.input_tokens",
	costOutputTokens: "gen_ai.cost.output_tokens",
	usageCostUsd: "gen_ai.usage.cost_usd",
	toolName: "gen_ai.tool.name",
	toolDescription: "gen_ai.tool.description",
	toolType: "gen_ai.tool.type",
	toolCallId: "gen_ai.tool.call.id",
	toolCallArguments: "gen_ai.tool.call.arguments",
	toolCallResult: "gen_ai.tool.call.result",
	toolMessage: "gen_ai.tool.message",
	toolInputDeprecated: "gen_ai.tool.input",
	toolOutputDeprecated: "gen_ai.tool.output",
	requestMaxTokens: "gen_ai.request.max_tokens",
	requestTemperature: "gen_ai.request.temperature",
	requestTopP: "gen_ai.request.top_p",
	requestTopK: "gen_ai.request.top_k",
	requestSeed: "gen_ai.request.seed",
	requestFrequencyPenalty: "gen_ai.request.frequency_penalty",
	requestPresencePenalty: "gen_ai.request.presence_penalty",
	inputMessages: "gen_ai.input.messages",
	outputMessages: "gen_ai.output.messages",
	systemInstructions: "gen_ai.system_instructions",
	toolDefinitions: "gen_ai.tool.definitions",
	agentName: "gen_ai.agent.name",
	agentRunId: "gen_ai.agent.run.id",
	agentParentRunId: "gen_ai.agent.parent_run.id",
	agentDepth: "gen_ai.agent.depth",
	pipelineName: "gen_ai.pipeline.name",
	turn: "gen_ai.agent.turn",
	mcpServer: "gen_ai.mcp.server",
	mcpToolCount: "gen_ai.mcp.tool_count"
};
/** Compose namespace prefix once. */
function prefixed(namespace, name) {
	return namespace ? `${namespace}/${name}` : name;
}
/** Drop undefined entries — tracers vary on how they render `undefined`. */
function compact(attrs) {
	const out = {};
	for (const [k, v] of Object.entries(attrs)) if (v !== void 0) out[k] = v;
	return out;
}
function blockToParts(block) {
	switch (block.type) {
		case "text": return [{
			type: "text",
			content: typeof block.text === "string" ? block.text : ""
		}];
		case "image": return [{
			type: "text",
			content: "[Blob substitute]"
		}];
		case "tool_call": return [{
			type: "tool_call",
			...typeof block.name === "string" ? { name: block.name } : {},
			...typeof block.id === "string" ? { call_id: block.id } : {},
			arguments: safeJson(block.input)
		}];
		case "tool_result": {
			const output = block.output;
			const text = typeof output === "string" ? output : Array.isArray(output) ? output.map((b) => b.type === "image" ? "[Blob substitute]" : b.text ?? "").join("\n") : "";
			return [{
				type: "tool_result",
				...typeof block.callId === "string" ? { call_id: block.callId } : {},
				content: text
			}];
		}
		case "thinking": return [{
			type: "reasoning",
			content: typeof block.text === "string" ? block.text : ""
		}];
		default: return [];
	}
}
function messageToSentry(msg) {
	const parts = [];
	for (const block of msg.content) parts.push(...blockToParts(block));
	return {
		role: msg.role,
		parts
	};
}
function safeJson(value) {
	try {
		return JSON.stringify(value ?? null);
	} catch {
		return "\"[unserializable]\"";
	}
}
/**
* Stringify an array of `SessionMessage`s into Sentry's `gen_ai.input.messages`
* format. Each entry's role + content is mapped via `messageToSentry`.
* Returns `undefined` when the input is empty or unserializable.
*/
function stringifyMessages(messages) {
	if (messages.length === 0) return void 0;
	try {
		const sentry = messages.map((m) => messageToSentry({
			role: m.role,
			content: m.content
		}));
		return JSON.stringify(sentry);
	} catch {
		return;
	}
}
/**
* Stringify a `StreamOptions.tools` array into Sentry's
* `gen_ai.tool.definitions` format: `[{name, description?, parameters?}, …]`.
*
* The input is `unknown[]` because `StreamOptions.tools` carries the
* provider-formatted shape (Anthropic / OpenAI / OpenAI-compat all
* differ). We probe the three names that overlap (`name`, `description`,
* `inputSchema` / `parameters`) and degrade gracefully otherwise.
*/
function stringifyToolDefs(tools) {
	if (!tools || tools.length === 0) return void 0;
	try {
		return JSON.stringify(tools.map((raw) => {
			if (!raw || typeof raw !== "object") return { name: "anonymous" };
			const t = raw;
			const name = typeof t.name === "string" ? t.name : "anonymous";
			const description = typeof t.description === "string" ? t.description : void 0;
			const parameters = t.parameters ?? t.input_schema ?? t.inputSchema;
			return {
				name,
				...description ? { description } : {},
				...parameters !== void 0 ? { parameters } : {}
			};
		}));
	} catch {
		return;
	}
}
/**
* Build the usage attribute set per the configured conventions. Sentry
* expects `input_tokens` to include cached, with `input_tokens.cached`
* + `input_tokens.cache_write` subkeys; OTel splits cache into
* separate top-level keys. `'both'` emits everything.
*/
function buildUsageAttrs(usage, conventions) {
	const cacheRead = usage.cacheRead ?? 0;
	const cacheWrite = usage.cacheCreation ?? 0;
	const inputInclCache = usage.input + cacheRead + cacheWrite;
	const totalTokens = inputInclCache + usage.output;
	const wantSentry = conventions === "sentry" || conventions === "both";
	const wantOtel = conventions === "otel" || conventions === "both";
	const out = {
		[GEN_AI.responseModel]: usage.modelId,
		[GEN_AI.responseFinishReasons]: usage.finishReason ? [usage.finishReason] : void 0,
		[GEN_AI.usageOutputTokens]: usage.output,
		[GEN_AI.usageTotalTokens]: totalTokens
	};
	if (wantSentry) {
		out[GEN_AI.usageInputTokens] = inputInclCache;
		if (cacheRead > 0) out[GEN_AI.usageInputTokensCached] = cacheRead;
		if (cacheWrite > 0) out[GEN_AI.usageInputTokensCacheWrite] = cacheWrite;
		if (typeof usage.thinking === "number" && usage.thinking > 0) out[GEN_AI.usageOutputTokensReasoning] = usage.thinking;
		if (typeof usage.cost === "number") out[GEN_AI.costTotalTokens] = usage.cost;
		if (typeof usage.timeToFirstTokenMs === "number") out[GEN_AI.responseTimeToFirstTokenSeconds] = usage.timeToFirstTokenMs / 1e3;
	}
	if (wantOtel) {
		if (!wantSentry) out[GEN_AI.usageInputTokens] = usage.input;
		if (cacheRead > 0) out[GEN_AI.usageCacheReadInputTokens] = cacheRead;
		if (cacheWrite > 0) out[GEN_AI.usageCacheCreationInputTokens] = cacheWrite;
		if (typeof usage.thinking === "number" && usage.thinking > 0) out[GEN_AI.usageReasoningTokens] = usage.thinking;
		if (typeof usage.cost === "number") out[GEN_AI.usageCostUsd] = usage.cost;
		if (typeof usage.timeToFirstTokenMs === "number") out[GEN_AI.responseTimeToFirstTokenMs] = usage.timeToFirstTokenMs;
	}
	return out;
}
/**
* Build a set of tracing hook handlers that can be installed on an agent.
*
* @example Sentry
* ```ts
* const tracing = createTracingHooks({
*   startSpan: (name, attrs) => Sentry.startInactiveSpan({ name, attributes: attrs }),
* })
* const uninstall = tracing.install(agent.hooks)
* try { await agent.run({ prompt }) }
* finally { uninstall() }
* ```
*
* @example OpenTelemetry with parent-context propagation
* ```ts
* import { trace, context, propagation } from '@opentelemetry/api'
*
* const tracer = trace.getTracer('zidane')
* const tracing = createTracingHooks({
*   startSpan: (name, attrs, parentCtx) => {
*     const ctx = parentCtx ? propagation.extract(context.active(), parentCtx) : context.active()
*     return tracer.startSpan(name, { attributes: attrs }, ctx)
*   },
*   getActiveTraceContext: () => {
*     const carrier: Record<string, string> = {}
*     propagation.inject(context.active(), carrier)
*     return carrier
*   },
* })
* ```
*/
function createTracingHooks(options) {
	const namespace = options.namespace;
	const legacy = options.legacyAttributes ?? true;
	const conventions = options.conventions ?? "sentry";
	const wantSentry = conventions === "sentry" || conventions === "both";
	const captureContent = options.captureMessageContent !== false;
	const onError = options.onError ?? (() => {});
	return { install(hooks) {
		const runSpans = /* @__PURE__ */ new Map();
		const turnSpans = /* @__PURE__ */ new Map();
		const toolSpans = /* @__PURE__ */ new Map();
		const mcpSpans = /* @__PURE__ */ new Map();
		const spawnSpans = /* @__PURE__ */ new Map();
		const bootstrapSpans = /* @__PURE__ */ new Map();
		let activeSystem;
		const turnTrack = /* @__PURE__ */ new Map();
		let activeRunSpan;
		function safeStartSpan(name, attrs, parentContext) {
			try {
				return options.startSpan(prefixed(namespace, name), compact(attrs), parentContext);
			} catch (err) {
				try {
					onError("startSpan", err);
				} catch {}
				return;
			}
		}
		function safeSetAttrs(span, attrs) {
			if (!span?.setAttributes) return;
			try {
				span.setAttributes(compact(attrs));
			} catch (err) {
				try {
					onError("setAttributes", err);
				} catch {}
			}
		}
		function safeEnd(map, key) {
			const span = map.get(key);
			if (!span) return;
			try {
				span.end();
			} catch (err) {
				try {
					onError("end", err);
				} catch {}
			}
			map.delete(key);
		}
		function endAll(map) {
			for (const [, span] of map) try {
				span.end();
			} catch (err) {
				try {
					onError("end", err);
				} catch {}
			}
			map.clear();
		}
		function safeAddEvent(span, name, attrs) {
			if (!span) return;
			if (typeof span.addEvent === "function") {
				try {
					span.addEvent(name, compact(attrs));
				} catch (err) {
					try {
						onError("addEvent", err);
					} catch {}
				}
				return;
			}
			safeSetAttrs(span, Object.fromEntries(Object.entries(compact(attrs)).map(([k, v]) => [`event.${name}.${k}`, v])));
		}
		function redact(kind, value, meta) {
			if (typeof options.redact !== "function") return value;
			try {
				return options.redact(kind, value, meta);
			} catch (err) {
				try {
					onError("redact", err);
				} catch {}
				return value;
			}
		}
		const unregisters = [];
		unregisters.push(hooks.hook("agent:start", (ctx) => {
			activeSystem = ctx.providerName;
			const span = safeStartSpan(`invoke_agent ${ctx.agentName && ctx.agentName.length > 0 ? ctx.agentName : "agent"}`, {
				[GEN_AI.operationName]: "invoke_agent",
				[GEN_AI.system]: activeSystem,
				[GEN_AI.agentName]: ctx.agentName,
				[GEN_AI.agentRunId]: ctx.runId,
				[GEN_AI.agentParentRunId]: ctx.parentRunId,
				[GEN_AI.agentDepth]: ctx.depth,
				"sentry.op": "gen_ai.invoke_agent",
				...legacy ? {
					runId: ctx.runId,
					parentRunId: ctx.parentRunId,
					agentName: ctx.agentName,
					depth: ctx.depth
				} : {}
			}, ctx.tracingContext);
			if (span) {
				runSpans.set(ctx.runId, span);
				activeRunSpan = span;
			}
		}));
		unregisters.push(hooks.hook("agent:done", (stats) => {
			const usageAttrs = buildUsageAttrs({
				input: stats.totalIn,
				output: stats.totalOut,
				cacheRead: stats.totalCacheRead,
				cacheCreation: stats.totalCacheCreation,
				cost: stats.cost,
				timeToFirstTokenMs: stats.timeTillFirstTokenMs
			}, conventions);
			for (const [, span] of runSpans) safeSetAttrs(span, {
				...usageAttrs,
				[GEN_AI.turn]: stats.turns,
				"gen_ai.agent.elapsed_ms": stats.elapsed,
				...legacy ? {
					totalIn: stats.totalIn,
					totalOut: stats.totalOut,
					totalCacheRead: stats.totalCacheRead,
					totalCacheCreation: stats.totalCacheCreation,
					cost: stats.cost,
					turns: stats.turns,
					elapsed: stats.elapsed
				} : {}
			});
			endAll(runSpans);
			endAll(turnSpans);
			endAll(toolSpans);
			endAll(mcpSpans);
			endAll(spawnSpans);
			endAll(bootstrapSpans);
			activeRunSpan = void 0;
			activeSystem = void 0;
			turnTrack.clear();
		}));
		unregisters.push(hooks.hook("agent:abort", () => {
			for (const [, span] of runSpans) safeSetAttrs(span, { "gen_ai.agent.status": "aborted" });
		}));
		unregisters.push(hooks.hook("turn:before", (ctx) => {
			const requestedModel = ctx.options.model;
			const baseAttrs = {
				[GEN_AI.operationName]: "chat",
				[GEN_AI.system]: activeSystem,
				[GEN_AI.requestModel]: requestedModel,
				[GEN_AI.turn]: ctx.turn,
				[GEN_AI.responseStreaming]: true,
				[GEN_AI.requestMaxTokens]: ctx.options.maxTokens,
				"sentry.op": "gen_ai.chat",
				"gen_ai.agent.turn_id": ctx.turnId,
				...legacy ? {
					turnId: ctx.turnId,
					turn: ctx.turn
				} : {}
			};
			if (captureContent) {
				const systemText = ctx.options.system;
				if (systemText) baseAttrs[GEN_AI.systemInstructions] = redact("system", systemText, {
					turnId: ctx.turnId,
					turn: ctx.turn
				});
				const inputMsgs = stringifyMessages(ctx.options.messages);
				if (inputMsgs) baseAttrs[GEN_AI.inputMessages] = redact("prompt", inputMsgs, {
					turnId: ctx.turnId,
					turn: ctx.turn
				});
				const toolDefs = stringifyToolDefs(ctx.options.tools);
				if (toolDefs) baseAttrs[GEN_AI.toolDefinitions] = toolDefs;
			}
			const span = safeStartSpan(`chat${requestedModel ? ` ${requestedModel}` : ""}`, baseAttrs);
			if (span) {
				turnSpans.set(ctx.turnId, span);
				turnTrack.set(ctx.turnId, { startedAt: Date.now() });
			}
		}));
		unregisters.push(hooks.hook("stream:start", (ctx) => {
			safeAddEvent(turnSpans.get(ctx.turnId), "gen_ai.stream.start", { startedAt: ctx.startedAt });
		}));
		unregisters.push(hooks.hook("turn:after", (ctx) => {
			const span = turnSpans.get(ctx.turnId);
			const tracked = turnTrack.get(ctx.turnId);
			turnTrack.delete(ctx.turnId);
			let tokensPerSecond;
			if (tracked && ctx.usage.output > 0) {
				const elapsedMs = Date.now() - tracked.startedAt;
				if (elapsedMs > 0) tokensPerSecond = ctx.usage.output / elapsedMs * 1e3;
			}
			const usageAttrs = buildUsageAttrs(ctx.usage, conventions);
			const cumInputTokens = wantSentry ? ctx.cumulativeUsage.input + ctx.cumulativeUsage.cacheRead + ctx.cumulativeUsage.cacheCreation : ctx.cumulativeUsage.input;
			const attrs = {
				...usageAttrs,
				[GEN_AI.responseTokensPerSecond]: tokensPerSecond,
				"gen_ai.agent.cumulative.input_tokens": cumInputTokens,
				"gen_ai.agent.cumulative.output_tokens": ctx.cumulativeUsage.output,
				"gen_ai.agent.cumulative.total_tokens": cumInputTokens + ctx.cumulativeUsage.output,
				"gen_ai.agent.cumulative.cache_read_input_tokens": ctx.cumulativeUsage.cacheRead,
				"gen_ai.agent.cumulative.cache_creation_input_tokens": ctx.cumulativeUsage.cacheCreation,
				"gen_ai.agent.cumulative.cost_usd": ctx.cumulativeUsage.cost,
				"gen_ai.agent.cumulative.turns": ctx.cumulativeUsage.turns,
				...legacy ? {
					inputTokens: ctx.usage.input,
					outputTokens: ctx.usage.output,
					finishReason: ctx.usage.finishReason,
					modelId: ctx.usage.modelId
				} : {}
			};
			if (captureContent && ctx.message && ctx.message.role !== "system") {
				const outputMsgs = stringifyMessages([{
					role: ctx.message.role,
					content: ctx.message.content
				}]);
				if (outputMsgs) attrs[GEN_AI.outputMessages] = redact("stream-text", outputMsgs, {
					turnId: ctx.turnId,
					turn: ctx.turn
				});
			}
			safeSetAttrs(span, attrs);
			safeEnd(turnSpans, ctx.turnId);
		}));
		unregisters.push(hooks.hook("stream:error", (ctx) => {
			const span = turnSpans.get(ctx.turnId);
			const message = ctx.err instanceof Error ? ctx.err.message : String(ctx.err);
			safeSetAttrs(span, {
				"error.type": ctx.err instanceof Error ? ctx.err.name : "unknown",
				"error.message": message,
				"http.response.status_code": ctx.statusCode,
				"gen_ai.request.id": ctx.requestId
			});
			safeAddEvent(span, "gen_ai.stream.error", {
				"error.type": ctx.err instanceof Error ? ctx.err.name : "unknown",
				"error.message": message,
				"http.response.status_code": ctx.statusCode,
				"gen_ai.request.id": ctx.requestId
			});
		}));
		unregisters.push(hooks.hook("tool:before", (ctx) => {
			const span = safeStartSpan(`execute_tool ${ctx.displayName}`, {
				[GEN_AI.operationName]: "execute_tool",
				[GEN_AI.system]: activeSystem,
				[GEN_AI.toolName]: ctx.name,
				[GEN_AI.toolType]: "function",
				[GEN_AI.toolCallId]: ctx.callId,
				"sentry.op": "gen_ai.execute_tool",
				"gen_ai.tool.display_name": ctx.displayName,
				"gen_ai.agent.turn_id": ctx.turnId,
				"gen_ai.agent.depth": ctx.depth,
				"gen_ai.agent.run.id": ctx.runId,
				"gen_ai.agent.parent_run.id": ctx.parentRunId,
				...legacy ? {
					toolName: ctx.name,
					displayName: ctx.displayName,
					turnId: ctx.turnId,
					callId: ctx.callId
				} : {}
			});
			if (span) {
				toolSpans.set(ctx.callId, span);
				if (captureContent) try {
					const redacted = redact("tool-input", JSON.stringify(ctx.input), {
						toolName: ctx.name,
						displayName: ctx.displayName,
						callId: ctx.callId,
						turnId: ctx.turnId
					});
					const attrs = {};
					if (wantSentry) attrs[GEN_AI.toolCallArguments] = redacted;
					if (conventions === "otel" || conventions === "both") attrs[GEN_AI.toolInputDeprecated] = redacted;
					safeSetAttrs(span, attrs);
				} catch {}
			}
		}));
		unregisters.push(hooks.hook("tool:after", (ctx) => {
			const span = toolSpans.get(ctx.callId);
			safeSetAttrs(span, {
				"gen_ai.tool.output_bytes": ctx.outputBytes,
				"gen_ai.tool.coercions": ctx.coercions?.length ?? 0
			});
			if (captureContent && typeof ctx.result === "string") {
				const redacted = redact("tool-result", ctx.result, {
					toolName: ctx.name,
					callId: ctx.callId
				});
				const attrs = {};
				if (wantSentry) attrs[GEN_AI.toolCallResult] = redacted;
				if (conventions === "otel" || conventions === "both") attrs[GEN_AI.toolOutputDeprecated] = redacted;
				safeSetAttrs(span, attrs);
			}
			safeEnd(toolSpans, ctx.callId);
		}));
		unregisters.push(hooks.hook("tool:error", (ctx) => {
			safeSetAttrs(toolSpans.get(ctx.callId), {
				"error.type": ctx.error.name,
				"error.message": ctx.error.message
			});
			safeEnd(toolSpans, ctx.callId);
		}));
		unregisters.push(hooks.hook("tool:dispatched", (ctx) => {
			if (ctx.outcome === "gate-block") safeAddEvent(activeRunSpan, "gen_ai.gate.block", {
				[GEN_AI.toolName]: ctx.name,
				[GEN_AI.toolCallId]: ctx.callId,
				reason: ctx.reason
			});
			else if (ctx.outcome === "gate-substitute") safeAddEvent(activeRunSpan, "gen_ai.gate.substitute", {
				[GEN_AI.toolName]: ctx.name,
				[GEN_AI.toolCallId]: ctx.callId
			});
			else if (ctx.outcome === "unknown") safeAddEvent(activeRunSpan, "gen_ai.tool.unknown", {
				[GEN_AI.toolName]: ctx.name,
				[GEN_AI.toolCallId]: ctx.callId
			});
			else if (ctx.outcome === "invalid-input") safeAddEvent(activeRunSpan, "gen_ai.tool.invalid_input", {
				[GEN_AI.toolName]: ctx.name,
				[GEN_AI.toolCallId]: ctx.callId
			});
		}));
		unregisters.push(hooks.hook("validation:reject", (ctx) => {
			safeAddEvent(activeRunSpan, "gen_ai.validation.reject", {
				[GEN_AI.toolName]: ctx.name,
				[GEN_AI.toolCallId]: ctx.callId,
				reason: ctx.reason
			});
		}));
		unregisters.push(hooks.hook("validation:coerce", (ctx) => {
			safeAddEvent(activeRunSpan, "gen_ai.validation.coerce", {
				[GEN_AI.toolName]: ctx.name,
				[GEN_AI.toolCallId]: ctx.callId,
				coercions: ctx.coercions
			});
		}));
		unregisters.push(hooks.hook("budget:exceeded", (ctx) => {
			safeAddEvent(activeRunSpan, "gen_ai.budget.exceeded", {
				turnId: ctx.turnId,
				bytes: ctx.bytes,
				budget: ctx.budget
			});
		}));
		unregisters.push(hooks.hook("tool-budget:exceeded", (ctx) => {
			safeAddEvent(activeRunSpan, "gen_ai.tool_budget.exceeded", {
				[GEN_AI.toolName]: ctx.tool,
				turnId: ctx.turnId,
				count: ctx.count,
				max: ctx.max,
				mode: ctx.mode
			});
		}));
		unregisters.push(hooks.hook("pairing:repair", (ctx) => {
			safeAddEvent(activeRunSpan, "gen_ai.pairing.repair", {
				mode: ctx.mode,
				callId: ctx.callId,
				turnId: ctx.turnId
			});
		}));
		unregisters.push(hooks.hook("oauth:refresh", (ctx) => {
			safeAddEvent(activeRunSpan, "gen_ai.oauth.refresh", {
				provider: ctx.provider,
				providerId: ctx.providerId,
				source: ctx.source
			});
		}));
		unregisters.push(hooks.hook("mcp:tool:before", (ctx) => {
			const span = safeStartSpan(`execute_tool ${ctx.server}.${ctx.tool}`, {
				[GEN_AI.operationName]: "execute_tool",
				[GEN_AI.system]: activeSystem,
				[GEN_AI.toolName]: ctx.displayName,
				[GEN_AI.toolType]: "extension",
				[GEN_AI.toolCallId]: ctx.callId,
				[GEN_AI.mcpServer]: ctx.server,
				"sentry.op": "gen_ai.execute_tool",
				"gen_ai.mcp.tool": ctx.tool,
				"gen_ai.agent.turn_id": ctx.turnId,
				"gen_ai.agent.run.id": ctx.runId,
				...legacy ? {
					server: ctx.server,
					tool: ctx.tool,
					displayName: ctx.displayName,
					turnId: ctx.turnId,
					callId: ctx.callId
				} : {}
			});
			if (span) {
				mcpSpans.set(ctx.callId, span);
				if (captureContent) try {
					const redacted = redact("mcp-tool-input", JSON.stringify(ctx.input), {
						server: ctx.server,
						tool: ctx.tool,
						callId: ctx.callId
					});
					const attrs = {};
					if (wantSentry) attrs[GEN_AI.toolCallArguments] = redacted;
					if (conventions === "otel" || conventions === "both") attrs[GEN_AI.toolInputDeprecated] = redacted;
					safeSetAttrs(span, attrs);
				} catch {}
			}
		}));
		unregisters.push(hooks.hook("mcp:tool:after", (ctx) => {
			const span = mcpSpans.get(ctx.callId);
			safeSetAttrs(span, { "gen_ai.tool.output_bytes": ctx.outputBytes });
			if (captureContent && typeof ctx.result === "string") {
				const redacted = redact("mcp-tool-result", ctx.result, {
					server: ctx.server,
					tool: ctx.tool,
					callId: ctx.callId
				});
				const attrs = {};
				if (wantSentry) attrs[GEN_AI.toolCallResult] = redacted;
				if (conventions === "otel" || conventions === "both") attrs[GEN_AI.toolOutputDeprecated] = redacted;
				safeSetAttrs(span, attrs);
			}
			safeEnd(mcpSpans, ctx.callId);
		}));
		unregisters.push(hooks.hook("mcp:tool:error", (ctx) => {
			safeSetAttrs(mcpSpans.get(ctx.callId), {
				"error.type": ctx.error.name,
				"error.message": ctx.error.message
			});
			safeEnd(mcpSpans, ctx.callId);
		}));
		unregisters.push(hooks.hook("mcp:bootstrap:start", (ctx) => {
			const span = safeStartSpan(`mcp.bootstrap ${ctx.name}`, {
				[GEN_AI.operationName]: "mcp.bootstrap",
				[GEN_AI.system]: activeSystem,
				[GEN_AI.mcpServer]: ctx.name,
				"gen_ai.mcp.transport": ctx.transport
			});
			if (span) bootstrapSpans.set(ctx.name, span);
		}));
		unregisters.push(hooks.hook("mcp:bootstrap:end", (ctx) => {
			const span = bootstrapSpans.get(ctx.name);
			const ok = ctx.ok;
			safeSetAttrs(span, {
				"gen_ai.mcp.bootstrap.duration_ms": ctx.durationMs,
				"gen_ai.mcp.bootstrap.ok": ok,
				...ok ? {
					[GEN_AI.mcpToolCount]: ctx.toolCount,
					"gen_ai.mcp.lazy": ctx.lazy,
					"gen_ai.mcp.cached": ctx.cached
				} : {
					"error.type": ctx.error.name,
					"error.message": ctx.error.message
				}
			});
			safeEnd(bootstrapSpans, ctx.name);
		}));
		unregisters.push(hooks.hook("mcp:auth:required", (ctx) => {
			safeAddEvent(bootstrapSpans.get(ctx.name) ?? activeRunSpan, "gen_ai.mcp.auth.required", {
				server: ctx.name,
				transport: ctx.transport,
				reason: ctx.reason
			});
		}));
		unregisters.push(hooks.hook("mcp:error", (ctx) => {
			safeAddEvent(activeRunSpan, "gen_ai.mcp.error", {
				"server": ctx.name,
				"error.type": ctx.error.name,
				"error.message": ctx.error.message
			});
		}));
		unregisters.push(hooks.hook("spawn:before", (ctx) => {
			const span = safeStartSpan(`handoff to ${ctx.task.length > 60 ? `${ctx.task.slice(0, 57)}…` : ctx.task}`, {
				[GEN_AI.operationName]: "handoff",
				[GEN_AI.system]: activeSystem,
				"sentry.op": "gen_ai.handoff",
				"gen_ai.agent.spawn.id": ctx.id,
				"gen_ai.agent.spawn.task": ctx.task,
				"gen_ai.agent.depth": ctx.depth
			});
			if (span) spawnSpans.set(ctx.id, span);
			if (typeof options.getActiveTraceContext === "function" && ctx.tracingContext) {
				let carrier;
				try {
					carrier = options.getActiveTraceContext();
				} catch (err) {
					try {
						onError("getActiveTraceContext", err);
					} catch {}
				}
				if (carrier) for (const [k, v] of Object.entries(carrier)) ctx.tracingContext[k] = v;
			}
		}));
		unregisters.push(hooks.hook("spawn:complete", (ctx) => {
			const span = spawnSpans.get(ctx.id);
			const childUsage = buildUsageAttrs({
				input: ctx.stats.totalIn,
				output: ctx.stats.totalOut,
				cacheRead: ctx.stats.totalCacheRead,
				cacheCreation: ctx.stats.totalCacheCreation,
				cost: ctx.stats.cost
			}, conventions);
			safeSetAttrs(span, {
				"gen_ai.agent.spawn.status": ctx.status ?? "completed",
				"gen_ai.agent.spawn.depth": ctx.depth,
				...childUsage
			});
			safeEnd(spawnSpans, ctx.id);
		}));
		unregisters.push(hooks.hook("spawn:error", (ctx) => {
			safeSetAttrs(spawnSpans.get(ctx.id), {
				"error.type": ctx.error.name,
				"error.message": ctx.error.message
			});
			safeEnd(spawnSpans, ctx.id);
		}));
		let disposed = false;
		return function uninstall() {
			if (disposed) return;
			disposed = true;
			for (const un of unregisters) try {
				un();
			} catch {}
			endAll(runSpans);
			endAll(turnSpans);
			endAll(toolSpans);
			endAll(mcpSpans);
			endAll(spawnSpans);
			endAll(bootstrapSpans);
			activeRunSpan = void 0;
		};
	} };
}
/**
* OpenTelemetry Gen AI semantic-convention attribute keys used by the
* built-in tracer. Exported so consumers integrating with raw OTel SDKs
* (instead of going through `createTracingHooks`) can stay aligned with
* the names the harness itself emits.
*/
const GEN_AI_ATTRIBUTES = GEN_AI;
//#endregion
//#region src/zod.ts
/**
* Zod v4 integration helper.
*
* Normalizes the output of z.toJsonSchema() for use as ToolSpec.inputSchema.
* Zod is an optional peer dependency — consumers call z.toJsonSchema() themselves.
*
* Usage:
*   import { z } from 'zod'
*   import { zodToJsonSchema } from 'zidane'
*   const schema = zodToJsonSchema(z.toJsonSchema(z.object({ name: z.string() })))
*/
/**
* Normalize a JSON Schema (e.g. from zod v4's z.toJsonSchema()) for use
* as a ToolSpec.inputSchema.
*
* Strips the $schema key that some providers reject.
*/
function zodToJsonSchema(jsonSchema) {
	const { $schema, ...rest } = jsonSchema;
	return rest;
}
//#endregion
export { ANCHOR_PREVIEW_MAX_CHARS, AgentAbortedError, AgentBudgetExceededError, AgentContextExceededError, AgentProviderError, AgentToolNotAllowedError, AgentToolPairingError, BASE_INSTRUCTIONS, BYTES_PER_TOKEN, CONTEXT_EXCEEDED_MESSAGE_PATTERNS, CompactInvalidInputError, CompactPromptTooLongError, EFFICIENCY_METRICS, EvalMetricError, GEN_AI_ATTRIBUTES, IMPLICITLY_ALLOWED_SKILL_TOOLS, INTERRUPT_MESSAGE_FOR_TOOL_USE, McpOAuthProvider, NO_TOOLS_PREAMBLE, ORPHANED_TOOL_RESULT_MARKER, OpenAICompatHttpError, PERSISTED_STUB_PREFIX, PERSISTENCE_PREVIEW_BYTES, SHELL_CASCADE_CANCEL_MESSAGE, SYNTHETIC_TOOL_RESULT_PLACEHOLDER, SYSTEM_PROMPT_BOUNDARY, TOOL_USE_CANCELLED_MESSAGE, TOOL_USE_INTERRUPTED_MARKER, TOOL_USE_SKIPPED_MESSAGE, TRAILER, anchorPreviewFor, anthropic, appendDynamicSection, appendStaticSection, applyAnthropicCacheBreakpoints, arcee, artifactPath, autoDetectAndConvert, baseten, basic_default as basic, basicTools, buildCatalog, buildCompactPrompt, buildEvalRunSummary, buildFromCompactPrompt, buildFullCompactPrompt, buildPersistedStub, buildPostCompactAttachments, buildRegisteredEvals, buildTailCompactPrompt, buildTrajectory, buildUpToCompactPrompt, cerebras, classifyOpenAICompatError, cleanupPersistedSession, clearRegisteredEvals, compactConversation, computeEvalTagScores, connectMcpServers, consoleSink, createAgent, createEvalAgent, createEvalRunReporter, createFileMapStore, createInteractionTool, createLogger, createLoggingHooks, createMemoryMcpCredentialStore, createMemoryStore, createMetricsHooks, createProcessContext, createRemoteStore, createReusableExecutionContext, createRunSummaryCollector, createSandboxContext, createSession, createShellTool, createSkillActivationState, createSkillsReadTool, createSkillsRunScriptTool, createSkillsUseTool, createSpawnTool, createTracingHooks, defaultRepeatGuardNormalize, defaultRepeatGuardTracked, defineEval, defineMetrics, definePreset, defineSkill, detectTurnInterruption, diffCacheDimensions, discoverSkills, edit, efficiencyMetricValues, emitEfficiencyMetrics, ensureEndsWithUserMessage, ensureToolResultPairing, errorMessage, estimateTokens, fileContains, fileContentQuality, fileExists, fileExistsOneOf, filterUnresolvedToolUses, finalizeEvalMetrics, flattenTurns, fnv1a32, formatEvalCaseSummary, formatEvalRunSummary, formatTrajectoryLine, fromAnthropic, fromOpenAI, functionalityMetric, getReadState, glob, grep, hasAuthorizationHeader, hasSystemPromptBoundary, headlessEventToJsonl, installAllowedToolsGate, installCacheBreakLogger, interpolateShellCommands, isToolAllowedByUnion, joinSystemPrompt, jsonSink, llmJudge, loadSession, local, loginMcpServer, mapOAIFinishReason, matchesAllowedTool, matchesContextExceeded, maybePersistToolResult, multiEdit, normalizeMcpBlocks, normalizeMcpServers, normalizeMetric, normalizeShellCommand, openai, openaiCompat, openrouter, parseAllowedToolPattern, parseSkillFile, readStateKey, registerEvalTests, relativeArtifactPath, remintDuplicateToolCallIds, renderSystemForWire, replaceDynamicSection, resolveDetachedTasksCapability, resolvePersistDir, resolveReadStateMap, resolveSkills, resolveTasksDir, resultToString, runEvalCase, runHeadless, sanitizeToolSchema, sanitizeToolSpecs, selectFilesFromReadState, selectFilesFromSession, selectRecentFiles, sliceForCompaction, snapshotCacheDimensions, splitSystemPrompt, stableStringify, startOAuthCallback, statsByModel, statusCompleted, stripImagesFromTurns, stripShellInterpolations, summaryToTurn, toAnthropic, toOpenAI, toTypedError, toWireMessages, toolOutputBudgetByteLength, toolOutputByteLength, toolResultToText, transcriptToOpenAIMessages, truncateHeadForPtlRetry, utf8ByteLength, validateResourcePath, validateResourcePathReal, validateSkillForWrite, validateSkillName, validateToolArgs, waitTask, writeSkillToDisk, writeSkillsToDisk, zodToJsonSchema };

//# sourceMappingURL=index.js.map