import { M as state, o as logger } from "./logger-CtGm8dC_.js";
import { n as sleep } from "./time-b8bV6BmZ.js";
import { t as getTraceStore } from "./store-CkGPZXW-.js";
import { r as getToolNameFromAttributes } from "./toolAttributes-CZLAG5VV.js";
//#region src/tracing/traceContext.ts
const DEFAULT_MAX_RETRIES = 3;
const DEFAULT_RETRY_DELAY_MS = 500;
const SPAN_KIND_MAP = {
	0: "unspecified",
	1: "internal",
	2: "server",
	3: "client",
	4: "producer",
	5: "consumer"
};
function resolveSpanKind(span) {
	const attributes = span.attributes || {};
	const attributeKind = attributes["span.kind"] || attributes["otel.span.kind"] || attributes["spanKind"] || attributes["kind"];
	if (attributeKind) return `${attributeKind}`.toLowerCase();
	const numericKind = attributes["otel.span.kind_code"];
	if (typeof numericKind === "number" && numericKind in SPAN_KIND_MAP) return SPAN_KIND_MAP[numericKind];
	return "unspecified";
}
function mapStatusCode(span) {
	switch (span.statusCode) {
		case 1: return "ok";
		case 2: return "error";
		default: return "unset";
	}
}
function buildSpanTree(spans) {
	const depthMap = /* @__PURE__ */ new Map();
	const spansById = new Map(spans.map((span) => [span.spanId, span]));
	const computeDepth = (span) => {
		if (depthMap.has(span.spanId)) return depthMap.get(span.spanId);
		if (!span.parentSpanId || !spansById.has(span.parentSpanId)) {
			depthMap.set(span.spanId, 0);
			return 0;
		}
		const depth = computeDepth(spansById.get(span.parentSpanId)) + 1;
		depthMap.set(span.spanId, depth);
		return depth;
	};
	spans.forEach((span) => computeDepth(span));
	return depthMap;
}
function createTraceSpans(spans) {
	const depthMap = buildSpanTree(spans);
	return spans.map((span) => {
		const endTime = span.endTime ?? span.startTime;
		const durationMs = Math.max(0, endTime - span.startTime);
		return {
			spanId: span.spanId,
			parentSpanId: span.parentSpanId,
			name: span.name,
			kind: resolveSpanKind(span),
			startTime: span.startTime,
			endTime: span.endTime,
			durationMs,
			attributes: span.attributes || {},
			status: {
				code: mapStatusCode(span),
				message: span.statusMessage
			},
			depth: depthMap.get(span.spanId) ?? 0,
			events: []
		};
	});
}
function deriveInsights(traceSpans) {
	if (traceSpans.length === 0) return [];
	const insights = [];
	traceSpans.filter((span) => span.status.code === "error").forEach((span) => {
		const statusMessage = span.status.message ? `: ${span.status.message}` : "";
		insights.push(`Error span "${span.name}" (${span.spanId.slice(0, 8)})${statusMessage}`);
	});
	traceSpans.map((span) => ({
		span,
		toolName: getToolNameFromAttributes(span.attributes)
	})).filter((entry) => entry.toolName).forEach(({ span, toolName }) => {
		insights.push(`Tool call ${toolName} via "${span.name}" (duration ${span.durationMs ?? 0}ms)`);
	});
	traceSpans.filter((span) => span.attributes["guardrail.name"] || span.attributes["guardrails.decision"]).forEach((span) => {
		const decision = span.attributes["guardrails.decision"] ?? span.attributes["guardrail.decision"];
		insights.push(`Guardrail ${span.attributes["guardrail.name"] ?? span.name} decision: ${decision ?? "unknown"}`);
	});
	return insights.slice(0, 20);
}
function extractTraceIdFromTraceparent(traceparent) {
	if (!traceparent) return null;
	const parts = traceparent.split("-");
	if (parts.length < 2) return null;
	return parts[1];
}
async function fetchTraceContext(traceId, options = {}) {
	const { includeInternalSpans = true, sanitizeAttributes = true, maxRetries = DEFAULT_MAX_RETRIES, retryDelayMs = DEFAULT_RETRY_DELAY_MS, ...spanOptions } = options;
	const traceStore = getTraceStore();
	for (let attempt = 0; attempt <= maxRetries; attempt++) try {
		const spans = await traceStore.getSpans(traceId, {
			includeInternalSpans,
			sanitizeAttributes,
			...spanOptions
		});
		if (spans.length === 0) {
			if (attempt === maxRetries) {
				logger.debug(`[TraceContext] No spans found for trace ${traceId} after ${attempt + 1} attempts`);
				return null;
			}
			logger.debug(`[TraceContext] No spans yet for trace ${traceId}, retrying in ${retryDelayMs}ms (attempt ${attempt + 1}/${maxRetries})`);
			await sleep(retryDelayMs);
			continue;
		}
		const traceSpans = createTraceSpans(spans);
		const insights = deriveInsights(traceSpans);
		const context = {
			traceId,
			spans: traceSpans,
			insights,
			fetchedAt: Date.now()
		};
		logger.debug(`[TraceContext] Resolved ${traceSpans.length} spans for trace ${traceId} with ${insights.length} insights`);
		return context;
	} catch (error) {
		logger.error(`[TraceContext] Failed to fetch spans for trace ${traceId}: ${error}`);
		if (attempt === maxRetries) return null;
		await sleep(retryDelayMs);
	}
	return null;
}
//#endregion
//#region src/redteam/providers/traceFormatting.ts
const DEFAULT_MAX_SPANS = 10;
function formatDuration(durationMs) {
	if (!durationMs || Number.isNaN(durationMs)) return "0ms";
	if (durationMs < 1e3) return `${Math.round(durationMs)}ms`;
	if (durationMs < 6e4) return `${(durationMs / 1e3).toFixed(1)}s`;
	return `${(durationMs / 6e4).toFixed(1)}m`;
}
function formatSpan(span) {
	const parts = [];
	const duration = formatDuration(span.durationMs);
	parts.push(`[${duration}] ${span.name}${span.kind && span.kind !== "unspecified" ? ` (${span.kind})` : ""}`);
	const tool = getToolNameFromAttributes(span.attributes);
	if (tool) parts.push(`tool=${tool}`);
	const model = span.attributes["model"] || span.attributes["llm.model"];
	if (model) parts.push(`model=${model}`);
	if (span.status.code === "error") parts.push(`ERROR: ${span.status.message ?? "Unknown error"}`);
	return parts.join(" | ");
}
function formatTraceSummary(trace, options = {}) {
	if (!trace || trace.spans.length === 0) return "No trace spans recorded during this iteration.";
	const maxSpans = options.maxSpans ?? DEFAULT_MAX_SPANS;
	const spans = trace.spans.slice(0, maxSpans);
	return [
		`Trace ${trace.traceId.slice(0, 8)} • ${trace.spans.length} span${trace.spans.length === 1 ? "" : "s"}`,
		"",
		"Execution Flow:",
		spans.map((span, index) => `${index + 1}. ${formatSpan(span)}`).join("\n"),
		"",
		"Key Observations:",
		trace.insights.length > 0 ? trace.insights.map((i) => `• ${i}`).join("\n") : "None"
	].join("\n");
}
function formatTraceForMetadata(trace) {
	return {
		traceId: trace.traceId,
		fetchedAt: trace.fetchedAt,
		spanCount: trace.spans.length,
		insights: trace.insights
	};
}
//#endregion
//#region src/redteam/providers/tracingOptions.ts
const DEFAULT_TRACING_OPTIONS = {
	enabled: false,
	includeInAttack: true,
	includeInGrading: true,
	includeInternalSpans: false,
	maxSpans: 50,
	maxDepth: 5,
	maxRetries: 3,
	retryDelayMs: 500,
	spanFilter: void 0,
	sanitizeAttributes: true
};
function mergeTracingConfig(...configs) {
	return configs.reduce((acc, config) => config ? {
		...acc,
		...config
	} : acc, {});
}
function normalizeTracingOptions(config) {
	const merged = {
		...DEFAULT_TRACING_OPTIONS,
		...config
	};
	return {
		enabled: Boolean(merged.enabled),
		includeInAttack: merged.includeInAttack ?? DEFAULT_TRACING_OPTIONS.includeInAttack ?? true,
		includeInGrading: merged.includeInGrading ?? DEFAULT_TRACING_OPTIONS.includeInGrading ?? true,
		includeInternalSpans: merged.includeInternalSpans ?? DEFAULT_TRACING_OPTIONS.includeInternalSpans ?? false,
		maxSpans: merged.maxSpans ?? DEFAULT_TRACING_OPTIONS.maxSpans,
		maxDepth: merged.maxDepth ?? DEFAULT_TRACING_OPTIONS.maxDepth,
		maxRetries: merged.maxRetries ?? DEFAULT_TRACING_OPTIONS.maxRetries,
		retryDelayMs: merged.retryDelayMs ?? DEFAULT_TRACING_OPTIONS.retryDelayMs,
		spanFilter: merged.spanFilter,
		sanitizeAttributes: merged.sanitizeAttributes ?? DEFAULT_TRACING_OPTIONS.sanitizeAttributes
	};
}
function resolveTracingOptions({ strategyId, test, config }) {
	const globalConfig = state.config?.redteam?.tracing ?? void 0;
	const testConfig = test?.metadata?.tracing ?? void 0;
	const metadataStrategyConfig = (test?.metadata?.strategyConfig)?.tracing;
	const providerStrategyConfig = config?.tracing ?? void 0;
	return normalizeTracingOptions(mergeTracingConfig(globalConfig, testConfig, metadataStrategyConfig, providerStrategyConfig, strategyId && globalConfig?.strategies ? globalConfig.strategies[strategyId] : void 0, strategyId && testConfig?.strategies ? testConfig.strategies[strategyId] : void 0, strategyId && metadataStrategyConfig?.strategies ? metadataStrategyConfig.strategies[strategyId] : void 0, strategyId && providerStrategyConfig?.strategies ? providerStrategyConfig.strategies[strategyId] : void 0));
}
//#endregion
export { fetchTraceContext as a, extractTraceIdFromTraceparent as i, formatTraceForMetadata as n, formatTraceSummary as r, resolveTracingOptions as t };

//# sourceMappingURL=tracingOptions-BXCp7mF0.js.map