import { o as logger } from "./logger-CfDSdx1q.js";
import { t as fetchWithProxy } from "./fetch-CHx36OdV.js";
import { t as OpenAiGenericProvider } from "./openai-BbztqDfK.js";
import { loadAgentDefinition, loadHandoffs, loadInputGuardrails, loadOutputGuardrails, loadSandboxConfig, loadSessionDefinition, loadTools, loadValueFromFile, t as resolveModelSettings } from "./agents-loader-Dfu6h5CD.js";
import { BatchTraceProcessor, addTraceProcessor, getOrCreateTrace, protocol, run, startTraceExportLoop } from "@openai/agents";
//#region src/providers/openai/agents-tracing.ts
const DEFAULT_OTLP_ENDPOINT = "http://localhost:4318";
const INTERNAL_TRACE_METADATA_KEYS = new Set(["promptfoo.otlp_endpoint", "promptfoo.parent_span_id"]);
/**
* OTLP Tracing Exporter for OpenAI Agents.
*
* The Agents SDK emits a framework-native span model. Promptfoo needs those spans
* normalized into OTLP attributes that its trajectory assertions understand.
*/
var OTLPTracingExporter = class {
	/**
	* Export traces and spans to their configured OTLP endpoint.
	*/
	async export(items, signal) {
		const spans = items.filter((item) => item.type === "trace.span");
		if (spans.length === 0) {
			logger.debug("[AgentsTracing] No spans to export");
			return;
		}
		const spansByEndpoint = groupSpansByEndpoint(spans);
		logger.debug("[AgentsTracing] Exporting spans to OTLP", {
			endpointCount: spansByEndpoint.size,
			spanCount: spans.length
		});
		await Promise.all([...spansByEndpoint.entries()].map(async ([otlpEndpoint, endpointSpans]) => {
			try {
				const otlpPayload = this.transformToOTLP(endpointSpans);
				const url = `${otlpEndpoint}/v1/traces`;
				logger.debug("[AgentsTracing] Sending OTLP payload", {
					url,
					spanCount: endpointSpans.length
				});
				const response = await fetchWithProxy(url, {
					method: "POST",
					headers: { "Content-Type": "application/json" },
					body: JSON.stringify(otlpPayload),
					signal
				});
				if (response.ok) logger.debug("[AgentsTracing] Successfully exported traces to OTLP", {
					otlpEndpoint,
					spanCount: endpointSpans.length
				});
				else logger.error(`[AgentsTracing] OTLP export failed: ${response.status} ${response.statusText}`, { otlpEndpoint });
			} catch (error) {
				logger.error("[AgentsTracing] Failed to export traces to OTLP", {
					error,
					otlpEndpoint
				});
			}
		}));
	}
	/**
	* Transform openai-agents-js spans to OTLP JSON format.
	*/
	transformToOTLP(spans) {
		return { resourceSpans: [{
			resource: { attributes: [{
				key: "service.name",
				value: { stringValue: "promptfoo-agents" }
			}] },
			scopeSpans: [{
				scope: { name: "openai-agents-js" },
				spans: spans.map((span) => this.spanToOTLP(span))
			}]
		}] };
	}
	/**
	* Convert a single span to OTLP format.
	*/
	spanToOTLP(span) {
		const startTime = span.startedAt ? new Date(span.startedAt).getTime() : Date.now();
		const endTime = span.endedAt ? new Date(span.endedAt).getTime() : void 0;
		const traceId = span.traceId || this.generateTraceId();
		const spanId = span.spanId || this.generateSpanId();
		const parentSpanId = span.parentId || getStringTraceMetadata(span, "promptfoo.parent_span_id") || void 0;
		return {
			traceId: this.hexToBase64(traceId, "trace"),
			spanId: this.hexToBase64(spanId, "span"),
			parentSpanId: parentSpanId ? this.hexToBase64(parentSpanId, "span") : void 0,
			name: this.getSpanName(span),
			kind: 1,
			startTimeUnixNano: String(startTime * 1e6),
			endTimeUnixNano: endTime ? String(endTime * 1e6) : void 0,
			attributes: this.attributesToOTLP(this.getSpanAttributes(span)),
			status: this.getSpanStatus(span)
		};
	}
	getSpanName(span) {
		const data = span.spanData;
		switch (data.type) {
			case "function": return `tool ${data.name || "function"}`;
			case "handoff": return `handoff ${data.from_agent || "unknown"} -> ${data.to_agent || "unknown"}`;
			case "agent": return `agent ${data.name || "agent"}`;
			case "generation": return `generation ${data.model || "unknown-model"}`;
			case "response": return `response ${data.response_id || "response"}`;
			case "guardrail": return `guardrail ${data.name || "guardrail"}`;
			case "custom": return this.getCustomSpanName(data);
			default: return data.type ? `agent.${data.type}` : "agent.span";
		}
	}
	getCustomSpanName(data) {
		const sandboxOperation = (isRecord(data.data) ? data.data : {})["sandbox.operation"];
		if (typeof sandboxOperation === "string" && sandboxOperation) return `sandbox.${sandboxOperation}`;
		return data.name || "custom";
	}
	getSpanStatus(span) {
		if (span.error) return {
			code: 2,
			message: span.error.message || String(span.error)
		};
		return { code: 0 };
	}
	getSpanAttributes(span) {
		const data = span.spanData;
		const attributes = { "openai.agents.span_type": data.type };
		switch (data.type) {
			case "function":
				attributes["tool.name"] = data.name;
				if (data.input !== void 0) attributes["tool.arguments"] = data.input;
				if (data.output !== void 0) attributes["tool.output"] = data.output;
				break;
			case "handoff":
				attributes["handoff.from_agent"] = data.from_agent;
				attributes["handoff.to_agent"] = data.to_agent;
				break;
			case "agent":
				attributes["agent.name"] = data.name;
				if (data.tools !== void 0) attributes["agent.tools"] = data.tools;
				if (data.handoffs !== void 0) attributes["agent.handoffs"] = data.handoffs;
				if (data.output_type !== void 0) attributes["agent.output_type"] = data.output_type;
				break;
			case "generation":
				attributes["gen_ai.request.model"] = data.model;
				if (data.usage?.input_tokens !== void 0) attributes["gen_ai.usage.input_tokens"] = data.usage.input_tokens;
				if (data.usage?.output_tokens !== void 0) attributes["gen_ai.usage.output_tokens"] = data.usage.output_tokens;
				if (data.usage && "total_tokens" in data.usage) attributes["gen_ai.usage.total_tokens"] = data.usage.total_tokens;
				break;
			case "response":
				attributes["openai.response_id"] = data.response_id;
				break;
			case "guardrail":
				attributes["guardrail.name"] = data.name;
				attributes["guardrail.triggered"] = data.triggered;
				break;
			case "custom":
				this.applyCustomSpanAttributes(data, attributes);
				break;
			default:
				this.applyGenericSpanAttributes(data, attributes);
				break;
		}
		for (const [key, value] of Object.entries(span.traceMetadata ?? {})) {
			if (INTERNAL_TRACE_METADATA_KEYS.has(key)) continue;
			if (key === "evaluation.id" || key === "test.case.id") attributes[key] = value;
			else attributes[`trace.metadata.${key}`] = value;
		}
		return attributes;
	}
	applyCustomSpanAttributes(data, attributes) {
		attributes["openai.agents.custom_span.name"] = data.name;
		if (!isRecord(data.data)) return;
		for (const [key, value] of Object.entries(data.data)) attributes[key] = sanitizeAttributeValue(value);
		const command = commandToString(data.data.command ?? data.data.cmd);
		if (command) attributes.command = command;
		const exitCode = data.data.exit_code ?? data.data.exitCode;
		if (typeof exitCode === "number") attributes["process.exit.code"] = exitCode;
	}
	applyGenericSpanAttributes(data, attributes) {
		for (const [key, value] of Object.entries(data)) {
			if (key === "type") continue;
			attributes[`agent.${key}`] = sanitizeAttributeValue(value);
		}
	}
	attributesToOTLP(attributes) {
		return Object.entries(attributes).filter(([, value]) => value !== void 0).map(([key, value]) => ({
			key,
			value: this.valueToOTLP(value)
		}));
	}
	valueToOTLP(value) {
		if (value === null || value === void 0) return { stringValue: "" };
		if (typeof value === "string") return { stringValue: value };
		if (typeof value === "number") return Number.isInteger(value) ? { intValue: String(value) } : { doubleValue: value };
		if (typeof value === "boolean") return { boolValue: value };
		if (Array.isArray(value)) return { arrayValue: { values: value.map((entry) => this.valueToOTLP(entry)) } };
		if (typeof value === "object") return { stringValue: safeJsonStringify(value) };
		return { stringValue: String(value) };
	}
	/**
	* Convert hex string to base64 for OTLP JSON payloads.
	*/
	hexToBase64(hex, kind) {
		if (!hex) return "";
		try {
			let cleanHex = hex.replace(/^(trace_|span_|group_)/, "");
			const targetLength = kind === "span" ? 16 : 32;
			if (cleanHex.length > targetLength) cleanHex = cleanHex.substring(0, targetLength);
			else if (cleanHex.length < targetLength) cleanHex = cleanHex.padEnd(targetLength, "0");
			return Buffer.from(cleanHex, "hex").toString("base64");
		} catch (error) {
			logger.error(`[AgentsTracing] Failed to convert hex to base64: ${hex}`, { error });
			const fallbackLen = kind === "span" ? 16 : 32;
			return Buffer.from(this.generateRandomHex(fallbackLen), "hex").toString("base64");
		}
	}
	generateTraceId() {
		return this.generateRandomHex(32);
	}
	generateSpanId() {
		return this.generateRandomHex(16);
	}
	generateRandomHex(length) {
		const bytes = Math.ceil(length / 2);
		const buffer = Buffer.alloc(bytes);
		for (let i = 0; i < bytes; i++) buffer[i] = Math.floor(Math.random() * 256);
		return buffer.toString("hex").substring(0, length);
	}
};
function groupSpansByEndpoint(spans) {
	const grouped = /* @__PURE__ */ new Map();
	for (const span of spans) {
		const otlpEndpoint = getStringTraceMetadata(span, "promptfoo.otlp_endpoint") ?? DEFAULT_OTLP_ENDPOINT;
		const endpointSpans = grouped.get(otlpEndpoint) ?? [];
		endpointSpans.push(span);
		grouped.set(otlpEndpoint, endpointSpans);
	}
	return grouped;
}
function getStringTraceMetadata(span, key) {
	const value = span.traceMetadata?.[key];
	return typeof value === "string" && value ? value : void 0;
}
function commandToString(value) {
	if (value === void 0 || value === null) return;
	if (typeof value === "string") return value.trim() || void 0;
	if (Array.isArray(value)) return value.map((part) => String(part).trim()).filter(Boolean).join(" ") || void 0;
	return String(value).trim() || void 0;
}
function sanitizeAttributeValue(value) {
	if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
	if (Array.isArray(value)) return value.map((entry) => sanitizeAttributeValue(entry));
	if (isRecord(value)) return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, sanitizeAttributeValue(entry)]));
	return String(value);
}
function safeJsonStringify(value) {
	try {
		return JSON.stringify(value);
	} catch {
		return String(value);
	}
}
function isRecord(value) {
	return !!value && typeof value === "object" && !Array.isArray(value);
}
//#endregion
//#region src/providers/openai/agents.ts
/**
* OpenAI Agents Provider
*
* Integrates openai-agents-js SDK as a promptfoo provider.
* Supports multi-turn agent workflows with tools, handoffs, and tracing.
*/
var OpenAiAgentsProvider = class extends OpenAiGenericProvider {
	agentConfig;
	agent;
	session;
	sessionInitialization;
	sessionQueues = /* @__PURE__ */ new WeakMap();
	constructor(modelName, options = {}) {
		super(modelName, options);
		this.agentConfig = options.config || {};
	}
	id() {
		return `openai:agents:${this.modelName}`;
	}
	toString() {
		return `[OpenAI Agents Provider ${this.modelName}]`;
	}
	/**
	* Call the agent with the given prompt
	*/
	async callApi(prompt, context, callApiOptions) {
		logger.debug("[AgentsProvider] Starting agent call", {
			prompt: prompt.substring(0, 100),
			hasContext: !!context
		});
		try {
			if (!this.agent) this.agent = await this.initializeAgent();
			await this.setupTracingIfNeeded(context);
			const result = await this.runAgent(prompt, context, callApiOptions);
			logger.debug("[AgentsProvider] Agent run completed", {
				outputLength: result.output?.length || 0,
				tokenUsage: result.tokenUsage
			});
			return result;
		} catch (error) {
			logger.error("[AgentsProvider] Agent call failed", { error });
			throw error;
		}
	}
	/**
	* Initialize the agent from configuration
	*/
	async initializeAgent() {
		logger.debug("[AgentsProvider] Initializing agent");
		if (!this.agentConfig.agent) throw new Error("No agent configuration provided");
		try {
			const agent = await loadAgentDefinition(this.agentConfig.agent);
			const [tools, handoffs, inputGuardrails, outputGuardrails] = await Promise.all([
				loadTools(this.agentConfig.tools),
				loadHandoffs(this.agentConfig.handoffs),
				loadInputGuardrails(this.agentConfig.inputGuardrails),
				loadOutputGuardrails(this.agentConfig.outputGuardrails)
			]);
			const configuredAgent = agent.clone({
				tools: mergeArrays(agent.tools, tools),
				handoffs: mergeArrays(agent.handoffs, handoffs),
				inputGuardrails: mergeArrays(agent.inputGuardrails, inputGuardrails),
				outputGuardrails: mergeArrays(agent.outputGuardrails, outputGuardrails)
			});
			const mockAwareAgent = this.wrapToolsIfNeeded(configuredAgent);
			logger.debug("[AgentsProvider] Agent initialized successfully", {
				name: mockAwareAgent.name,
				toolCount: mockAwareAgent.tools.length,
				handoffCount: mockAwareAgent.handoffs.length,
				inputGuardrailCount: mockAwareAgent.inputGuardrails.length,
				outputGuardrailCount: mockAwareAgent.outputGuardrails.length
			});
			return mockAwareAgent;
		} catch (error) {
			logger.error("[AgentsProvider] Failed to initialize agent", { error });
			throw new Error(`Failed to initialize agent: ${error}`);
		}
	}
	/**
	* Setup tracing if enabled
	*/
	async setupTracingIfNeeded(context) {
		if (!(this.agentConfig.tracing === true || context?.test?.metadata?.tracingEnabled === true || process.env.PROMPTFOO_TRACING_ENABLED === "true")) {
			logger.debug("[AgentsProvider] Tracing not enabled");
			return;
		}
		logger.debug("[AgentsProvider] Setting up tracing");
		try {
			await ensureTracingExporterRegistered();
			logger.debug("[AgentsProvider] Tracing setup complete");
		} catch (error) {
			logger.error("[AgentsProvider] Failed to setup tracing", { error });
		}
	}
	/**
	* Run the agent with the given prompt
	*/
	async runAgent(prompt, context, callApiOptions) {
		try {
			const maxTurns = this.agentConfig.maxTurns === void 0 ? 10 : this.agentConfig.maxTurns;
			logger.debug("[AgentsProvider] Running agent", {
				agentName: this.agent?.name,
				maxTurns
			});
			const runOptions = {
				...await this.resolveRunOptions(context),
				context: context?.vars,
				maxTurns,
				signal: callApiOptions?.abortSignal
			};
			if (this.agentConfig.model) runOptions.model = this.agentConfig.model;
			if (this.agentConfig.modelSettings) runOptions.modelSettings = resolveModelSettings(this.agentConfig.modelSettings);
			const traceContext = parseTraceparent(context?.traceparent);
			const traceMetadata = buildTraceMetadata(context, this.agentConfig.otlpEndpoint, traceContext);
			const executeRun = () => getOrCreateTrace(async () => {
				return await run(this.agent, this.parsePromptInput(prompt), runOptions);
			}, {
				...traceContext ? { traceId: `trace_${traceContext.traceId}` } : {},
				...Object.keys(traceMetadata).length ? { metadata: traceMetadata } : {}
			});
			const result = runOptions.session ? await this.withSessionLock(runOptions.session, executeRun) : await executeRun();
			logger.debug("[AgentsProvider] Agent run result", {
				hasOutput: !!result.finalOutput,
				turns: result.newItems?.length || 0
			});
			return {
				output: result.finalOutput,
				tokenUsage: this.extractTokenUsage(result),
				cached: false,
				cost: this.calculateCost(result)
			};
		} catch (error) {
			logger.error("[AgentsProvider] Failed to run agent", { error });
			throw error;
		}
	}
	/**
	* Extract token usage from agent result
	*/
	extractTokenUsage(result) {
		const usage = result.runContext?.usage ?? result.state?.usage ?? result.usage;
		if (!usage) return {};
		const inputDetails = summarizeUsageDetails(usage.inputTokensDetails);
		const outputDetails = summarizeUsageDetails(usage.outputTokensDetails);
		const cachedInputTokens = inputDetails.cached_tokens ?? inputDetails.cache_read_input_tokens ?? inputDetails.cacheReadInputTokens;
		const completionDetails = {
			...outputDetails.reasoning_tokens === void 0 ? {} : { reasoning: outputDetails.reasoning_tokens },
			...outputDetails.accepted_prediction_tokens === void 0 ? {} : { acceptedPrediction: outputDetails.accepted_prediction_tokens },
			...outputDetails.rejected_prediction_tokens === void 0 ? {} : { rejectedPrediction: outputDetails.rejected_prediction_tokens },
			...cachedInputTokens === void 0 ? {} : { cacheReadInputTokens: cachedInputTokens }
		};
		return {
			total: usage.totalTokens ?? void 0,
			prompt: usage.inputTokens ?? usage.promptTokens ?? void 0,
			completion: usage.outputTokens ?? usage.completionTokens ?? void 0,
			...cachedInputTokens === void 0 ? {} : { cached: cachedInputTokens },
			...usage.requests === void 0 ? {} : { numRequests: usage.requests },
			...Object.keys(completionDetails).length ? { completionDetails } : {}
		};
	}
	/**
	* Calculate cost from agent result
	*/
	calculateCost(_result) {}
	wrapToolsIfNeeded(agent) {
		if (this.agentConfig.executeTools !== false && this.agentConfig.executeTools !== "mock") return agent;
		const toolMocks = this.agentConfig.toolMocks ?? {};
		const tools = agent.tools.map((tool) => {
			if (tool.type !== "function") return tool;
			const mockValue = toolMocks[tool.name];
			return {
				...tool,
				invoke: async () => mockValue ?? {
					mocked: true,
					tool: tool.name
				}
			};
		});
		return agent.clone({ tools });
	}
	parsePromptInput(prompt) {
		try {
			const parsedInput = parseAgentInputItems(JSON.parse(prompt));
			if (parsedInput) return parsedInput;
		} catch {}
		return prompt;
	}
	async resolveRunOptions(context) {
		const runOptions = { ...this.agentConfig.runOptions ?? {} };
		delete runOptions.stream;
		if (typeof runOptions.sessionInputCallback === "string") runOptions.sessionInputCallback = await loadValueFromFile(runOptions.sessionInputCallback, "session input callback");
		if (typeof runOptions.callModelInputFilter === "string") runOptions.callModelInputFilter = await loadValueFromFile(runOptions.callModelInputFilter, "call model input filter");
		if (typeof runOptions.toolErrorFormatter === "string") runOptions.toolErrorFormatter = await loadValueFromFile(runOptions.toolErrorFormatter, "tool error formatter");
		if (typeof runOptions.errorHandlers === "string") runOptions.errorHandlers = await loadValueFromFile(runOptions.errorHandlers, "run error handlers");
		if (runOptions.session) runOptions.session = await loadSessionDefinition(runOptions.session, context);
		else if (this.agentConfig.session) runOptions.session = await this.resolveConfiguredSession(context);
		if (runOptions.sandbox) runOptions.sandbox = await loadSandboxConfig(runOptions.sandbox, context);
		else if (this.agentConfig.sandbox) runOptions.sandbox = await loadSandboxConfig(this.agentConfig.sandbox, context);
		return runOptions;
	}
	async resolveConfiguredSession(context) {
		if (typeof this.agentConfig.session === "function") {
			const session = await loadSessionDefinition(this.agentConfig.session, context);
			if (!session) throw new Error("Failed to initialize configured session");
			return session;
		}
		if (typeof this.agentConfig.session === "string" && this.agentConfig.session.startsWith("file://")) {
			const exportedSession = await loadValueFromFile(this.agentConfig.session, "session");
			if (typeof exportedSession === "function") {
				const session = await loadSessionDefinition(exportedSession, context);
				if (!session) throw new Error("Failed to initialize configured session");
				return session;
			}
		}
		if (!this.session) {
			this.sessionInitialization ??= loadSessionDefinition(this.agentConfig.session, context).then((session) => {
				if (!session) throw new Error("Failed to initialize configured session");
				this.session = session;
				return session;
			}).catch((error) => {
				this.sessionInitialization = void 0;
				throw error;
			});
			return await this.sessionInitialization;
		}
		return this.session;
	}
	async withSessionLock(session, callback) {
		const previousRun = this.sessionQueues.get(session) ?? Promise.resolve();
		let release = () => {};
		const currentRun = new Promise((resolve) => {
			release = resolve;
		});
		this.sessionQueues.set(session, currentRun);
		await previousRun;
		try {
			return await callback();
		} finally {
			release();
			if (this.sessionQueues.get(session) === currentRun) this.sessionQueues.delete(session);
		}
	}
};
function mergeArrays(existing, additions) {
	if (!existing?.length && !additions?.length) return;
	return [...existing ?? [], ...additions ?? []];
}
let tracingProcessorRegistration;
async function ensureTracingExporterRegistered() {
	if (!tracingProcessorRegistration) tracingProcessorRegistration = Promise.resolve().then(() => {
		addTraceProcessor(new BatchTraceProcessor(new OTLPTracingExporter(), {
			maxQueueSize: 100,
			maxBatchSize: 10,
			scheduleDelay: 1e3
		}));
		startTraceExportLoop();
		logger.debug("[AgentsProvider] Tracing processor registered");
	});
	await tracingProcessorRegistration;
}
function parseTraceparent(traceparent) {
	if (!traceparent) return;
	const match = traceparent.trim().toLowerCase().match(/^[\da-f]{2}-([\da-f]{32})-([\da-f]{16})-[\da-f]{2}$/);
	if (!match) return;
	return {
		traceId: match[1],
		parentSpanId: match[2]
	};
}
function buildTraceMetadata(context, otlpEndpoint, traceContext) {
	return {
		...context?.evaluationId ? { "evaluation.id": context.evaluationId } : {},
		...context?.testCaseId ? { "test.case.id": context.testCaseId } : {},
		...traceContext?.parentSpanId ? { "promptfoo.parent_span_id": traceContext.parentSpanId } : {},
		...otlpEndpoint ? { "promptfoo.otlp_endpoint": otlpEndpoint } : {}
	};
}
function summarizeUsageDetails(details) {
	const entries = Array.isArray(details) ? details : details ? [details] : [];
	const summary = {};
	for (const entry of entries) for (const [key, value] of Object.entries(entry)) if (typeof value === "number") summary[key] = (summary[key] ?? 0) + value;
	return summary;
}
function parseAgentInputItems(value) {
	if (Array.isArray(value)) {
		if (value.length === 0) return;
		const parsedItems = [];
		for (const item of value) {
			const parsedItem = protocol.ModelItem.safeParse(item);
			if (!parsedItem.success) return;
			parsedItems.push(parsedItem.data);
		}
		return parsedItems;
	}
	const parsedItem = protocol.ModelItem.safeParse(value);
	if (!parsedItem.success) return;
	return [parsedItem.data];
}
//#endregion
export { OpenAiAgentsProvider };

//# sourceMappingURL=agents-D81L_1NW.js.map