import { getLogger } from "../utils/logger.js";
import { PROP_AGENT_ID, PROP_AGENT_VERSION, PROP_COMPONENT_TYPE, PROP_CONTEXT, PROP_CUSTOMER_ORG_ID, PROP_ENV, PROP_ERROR_SOURCE, PROP_GIT_REF as PROP_GIT_REF$1, PROP_GIT_REPO as PROP_GIT_REPO$1, PROP_GIT_SHA as PROP_GIT_SHA$1, PROP_INPUT_STATE, PROP_OUTPUT_STATE, PROP_PARENT_AGENT_ID, PROP_PARENT_SPAN_ID, PROP_SPAN_ID, PROP_SPAN_KIND, PROP_STACK_TRACE as PROP_STACK_TRACE$1, PROP_TAGS as PROP_TAGS$1, PROP_TOOL_OWNER, PROP_TOOL_TYPE } from "../core/constants.js";
import { trackAiMessage, trackEmbedding, trackSessionEnd, trackSpan, trackToolCall, trackUserMessage } from "../core/tracking.js";
import { getActiveContext } from "../context.js";
import { calculateCost } from "../utils/costs.js";
import { AMP_AGENT_DESCRIPTION, AMP_AGENT_ID, AMP_AGENT_VERSION, AMP_CONTEXT, AMP_CUSTOMER_ORG_ID, AMP_ENV, AMP_ERROR_SOURCE, AMP_EVENT_TYPE, AMP_GIT_REF, AMP_GIT_REPO, AMP_GIT_SHA, AMP_INPUT_STATE, AMP_OUTPUT_STATE, AMP_PARENT_AGENT_ID, AMP_SKIP_AUTO_USER_TRACKING, AMP_SPAN_KIND, AMP_STACK_TRACE, AMP_TAGS, AMP_TOOL_OWNER, AMP_TOOL_TYPE, EVENT_TYPE_AI_RESPONSE, EVENT_TYPE_EMBEDDING, EVENT_TYPE_SESSION_END, EVENT_TYPE_TOOL_CALL, EVENT_TYPE_USER_MESSAGE, GENAI_AGENT_ID, GENAI_AGENT_NAME, GENAI_CACHE_CREATION_INPUT_TOKENS, GENAI_CACHE_READ_INPUT_TOKENS, GENAI_CONVERSATION_ID, GENAI_EMBEDDING_DIMENSIONS, GENAI_ENDUSER_ID, GENAI_ERROR_TYPE, GENAI_FINISH_REASONS, GENAI_INPUT_MESSAGES, GENAI_INPUT_TOKENS, GENAI_OPERATION_NAME, GENAI_OUTPUT_MESSAGES, GENAI_OUTPUT_TOKENS, GENAI_PROVIDER_NAME, GENAI_REQUEST_MAX_TOKENS, GENAI_REQUEST_MODEL, GENAI_REQUEST_TEMPERATURE, GENAI_REQUEST_TOP_P, GENAI_RESPONSE_MODEL, GENAI_SYSTEM_INSTRUCTIONS, GENAI_TOOL_NAME, OP_CHAT, OP_CREATE_AGENT, OP_EMBEDDINGS, OP_EXECUTE_TOOL, OP_GENERATE_CONTENT, OP_INVOKE_AGENT, OP_TEXT_COMPLETION, SPAN_KIND_AGENT, SPAN_KIND_LLM, SPAN_KIND_SESSION, SPAN_KIND_TOOL } from "./conventions.js";
import { getGitMetadata } from "../utils/git_metadata.js";

//#region src/otel/mapper.ts
/**
* Unified span → event mapper for Amplitude AI SDK.
*
* SpanEventMapper is the single place that decides which [Agent] event type
* to emit and which properties to populate, regardless of how the span was
* created (provider wrapper, @observe, external OTEL instrumentor, or manual span).
*/
const logger = getLogger();
const PROP_TAGS = PROP_TAGS$1;
const PROP_GIT_SHA = PROP_GIT_SHA$1;
const PROP_GIT_REF = PROP_GIT_REF$1;
const PROP_GIT_REPO = PROP_GIT_REPO$1;
const PROP_STACK_TRACE = PROP_STACK_TRACE$1;
const PROP_ERROR_SOURCE_PROP = PROP_ERROR_SOURCE;
const PROP_SPAN_KIND_PROP = PROP_SPAN_KIND;
var SpanEventMapper = class {
	_amplitude;
	_defaultUserId;
	_defaultDeviceId;
	_privacyConfig;
	constructor(options) {
		this._amplitude = options.amplitude;
		this._defaultUserId = options.defaultUserId ?? null;
		this._defaultDeviceId = options.defaultDeviceId ?? null;
		this._privacyConfig = options.privacyConfig ?? null;
	}
	mapAndTrack(span) {
		try {
			this._mapAndTrackInner(span);
		} catch (e) {
			logger.debug(`Failed to map OTEL span to Amplitude event: ${e}`);
		}
	}
	_mapAndTrackInner(span) {
		const attrs = { ...span.attributes ?? {} };
		const ctx = getActiveContext();
		if (ctx?.trackerManaged) {
			logger.debug("Skipping span — trackerManaged context is active");
			return;
		}
		const userId = this._resolveUserId(attrs, ctx);
		const deviceId = ctx?.deviceId ?? this._defaultDeviceId;
		if (!userId && !deviceId) {
			logger.warn("No user_id or device_id available, skipping span mapping");
			return;
		}
		const sessionId = ctx?.sessionId ?? strOrNull(attrs[GENAI_CONVERSATION_ID]);
		let traceId = ctx?.traceId ?? null;
		if (!traceId) traceId = this._extractOtelTraceId(span);
		const turnId = ctx?.nextTurnId() ?? null;
		let agentId = ctx?.agentId ?? strOrNull(attrs[AMP_AGENT_ID]);
		const parentAgentId = ctx?.parentAgentId ?? strOrNull(attrs[AMP_PARENT_AGENT_ID]);
		const env = ctx?.env ?? strOrNull(attrs[AMP_ENV]);
		const customerOrgId = ctx?.customerOrgId ?? strOrNull(attrs[AMP_CUSTOMER_ORG_ID]);
		const agentVersion = ctx?.agentVersion ?? strOrNull(attrs[AMP_AGENT_VERSION]);
		const contextDict = ctx?.context ?? this._parseContextAttr(attrs[AMP_CONTEXT]);
		const groups = ctx?.groups ?? null;
		const description = ctx?.description ?? strOrNull(attrs[AMP_AGENT_DESCRIPTION]);
		const model = String(attrs[GENAI_RESPONSE_MODEL] ?? attrs[GENAI_REQUEST_MODEL] ?? "unknown");
		const provider = String(attrs[GENAI_PROVIDER_NAME] ?? attrs["gen_ai.system"] ?? "unknown");
		const inputTokens = safeInt(attrs[GENAI_INPUT_TOKENS]);
		const outputTokens = safeInt(attrs[GENAI_OUTPUT_TOKENS]);
		const totalTokens = inputTokens != null || outputTokens != null ? (inputTokens ?? 0) + (outputTokens ?? 0) : null;
		const cacheReadInputTokens = safeInt(attrs[GENAI_CACHE_READ_INPUT_TOKENS]);
		const cacheCreationInputTokens = safeInt(attrs[GENAI_CACHE_CREATION_INPUT_TOKENS]);
		const finishReasons = attrs[GENAI_FINISH_REASONS];
		const finishReason = Array.isArray(finishReasons) && finishReasons.length > 0 ? String(finishReasons[0]) : typeof finishReasons === "string" ? finishReasons : null;
		const latencyMs = this._computeLatencyMs(span);
		let costUsd = null;
		if (inputTokens != null || outputTokens != null) try {
			costUsd = calculateCost({
				modelName: model,
				inputTokens: inputTokens ?? 0,
				outputTokens: outputTokens ?? 0,
				cacheReadInputTokens: cacheReadInputTokens ?? 0,
				cacheCreationInputTokens: cacheCreationInputTokens ?? 0,
				defaultProvider: provider !== "unknown" ? provider : void 0
			});
		} catch {}
		const isError = Boolean(attrs[GENAI_ERROR_TYPE]) || span.status?.code === 2;
		const errorMessage = isError ? String(attrs[GENAI_ERROR_TYPE] ?? span.status?.message ?? "") : null;
		const errorType = attrs[GENAI_ERROR_TYPE] ? String(attrs[GENAI_ERROR_TYPE]) : null;
		const temperature = safeFloat(attrs[GENAI_REQUEST_TEMPERATURE]);
		const maxTokens = safeInt(attrs[GENAI_REQUEST_MAX_TOKENS]);
		const topP = safeFloat(attrs[GENAI_REQUEST_TOP_P]);
		const userContent = this._extractUserContent(attrs);
		const aiContent = this._extractAiContent(attrs);
		const systemPrompt = this._extractSystemPrompt(attrs);
		const skipAutoUser = (ctx?.skipAutoUserTracking ?? false) || Boolean(attrs[AMP_SKIP_AUTO_USER_TRACKING]);
		const otelAgentId = attrs[GENAI_AGENT_ID];
		const otelAgentName = attrs[GENAI_AGENT_NAME];
		if (otelAgentId && !agentId) agentId = String(otelAgentId);
		const extraProps = this._buildExtraProperties(attrs, {
			agentId,
			parentAgentId,
			env,
			customerOrgId,
			agentVersion,
			contextDict,
			otelAgentName: otelAgentName != null ? String(otelAgentName) : null,
			span,
			sessionContext: ctx
		});
		const shared = {
			amplitude: this._amplitude,
			userId: userId ?? void 0,
			deviceId: deviceId ?? void 0,
			sessionId: sessionId ?? void 0,
			traceId: traceId ?? "",
			agentId: agentId ?? void 0,
			parentAgentId: parentAgentId ?? void 0,
			customerOrgId: customerOrgId ?? void 0,
			agentVersion: agentVersion ?? void 0,
			description: description ?? void 0,
			context: contextDict ?? void 0,
			env: env ?? void 0,
			groups: groups ?? void 0,
			privacyConfig: this._privacyConfig
		};
		const explicitType = strOrNull(attrs[AMP_EVENT_TYPE]);
		if (explicitType) {
			this._routeExplicitType(explicitType, attrs, span, shared, extraProps, {
				model,
				provider,
				latencyMs,
				inputTokens,
				outputTokens,
				totalTokens,
				cacheReadInputTokens,
				cacheCreationInputTokens,
				costUsd,
				isError,
				errorMessage,
				errorType,
				finishReason,
				temperature,
				maxTokens,
				topP,
				userContent,
				aiContent,
				systemPrompt,
				turnId,
				skipAutoUser
			});
			return;
		}
		const operation = String(attrs[GENAI_OPERATION_NAME] ?? "");
		if (operation) {
			this._routeGenaiOperation(operation, attrs, span, shared, extraProps, {
				model,
				provider,
				latencyMs,
				inputTokens,
				outputTokens,
				totalTokens,
				cacheReadInputTokens,
				cacheCreationInputTokens,
				costUsd,
				isError,
				errorMessage,
				finishReason,
				temperature,
				maxTokens,
				topP,
				userContent,
				aiContent,
				systemPrompt,
				turnId,
				skipAutoUser
			});
			return;
		}
		const spanKind = strOrNull(attrs[AMP_SPAN_KIND]);
		if (spanKind) {
			this._routeSpanKind(spanKind, attrs, span, shared, extraProps, {
				model,
				provider,
				latencyMs,
				inputTokens,
				outputTokens,
				totalTokens,
				cacheReadInputTokens,
				cacheCreationInputTokens,
				costUsd,
				isError,
				errorMessage,
				errorType,
				finishReason,
				temperature,
				maxTokens,
				topP,
				userContent,
				aiContent,
				systemPrompt,
				turnId
			});
			return;
		}
		if (Object.keys(attrs).some((k) => k.startsWith("gen_ai."))) trackAiMessage({
			...shared,
			modelName: model,
			provider,
			responseContent: aiContent ?? "",
			latencyMs,
			turnId: turnId ?? 1,
			inputTokens,
			outputTokens,
			totalTokens,
			cacheReadInputTokens,
			cacheCreationInputTokens,
			totalCostUsd: costUsd,
			isError,
			errorMessage,
			finishReason,
			eventProperties: Object.keys(extraProps).length > 0 ? extraProps : void 0
		});
		else {
			const spanName = span.name ?? "";
			trackSpan({
				...shared,
				spanName,
				latencyMs,
				isError,
				errorMessage,
				errorType,
				turnId,
				eventProperties: Object.keys(extraProps).length > 0 ? extraProps : void 0
			});
		}
	}
	_routeExplicitType(eventType, attrs, span, shared, extraProps, fields) {
		const ep = Object.keys(extraProps).length > 0 ? extraProps : void 0;
		if (eventType === EVENT_TYPE_USER_MESSAGE) {
			if (!fields.skipAutoUser) trackUserMessage({
				...shared,
				messageContent: fields.userContent ?? "",
				turnId: fields.turnId ?? 1,
				eventProperties: ep
			});
		} else if (eventType === EVENT_TYPE_AI_RESPONSE) trackAiMessage({
			...shared,
			modelName: fields.model,
			provider: fields.provider,
			responseContent: fields.aiContent ?? "",
			latencyMs: fields.latencyMs,
			turnId: fields.turnId ?? 2,
			inputTokens: fields.inputTokens,
			outputTokens: fields.outputTokens,
			totalTokens: fields.totalTokens,
			cacheReadInputTokens: fields.cacheReadInputTokens,
			cacheCreationInputTokens: fields.cacheCreationInputTokens,
			totalCostUsd: fields.costUsd,
			isError: fields.isError,
			errorMessage: fields.errorMessage,
			finishReason: fields.finishReason,
			systemPrompt: fields.systemPrompt,
			temperature: fields.temperature,
			maxOutputTokens: fields.maxTokens,
			topP: fields.topP,
			eventProperties: ep
		});
		else if (eventType === EVENT_TYPE_TOOL_CALL) {
			const toolName = String(attrs[GENAI_TOOL_NAME] ?? "") || span.name || "unknown_tool";
			const [toolInput, toolOutput] = this._extractIoState(attrs);
			trackToolCall({
				...shared,
				toolName,
				toolType: strOrNull(attrs[AMP_TOOL_TYPE]) ?? void 0,
				toolOwner: strOrNull(attrs[AMP_TOOL_OWNER]) ?? void 0,
				success: !fields.isError,
				latencyMs: fields.latencyMs,
				turnId: fields.turnId ?? 1,
				toolInput,
				toolOutput,
				errorMessage: fields.errorMessage,
				errorType: fields.errorType,
				eventProperties: ep
			});
		} else if (eventType === EVENT_TYPE_EMBEDDING) {
			const dimensions = safeInt(attrs[GENAI_EMBEDDING_DIMENSIONS]);
			trackEmbedding({
				...shared,
				model: fields.model,
				provider: fields.provider,
				latencyMs: fields.latencyMs,
				inputTokens: fields.inputTokens,
				dimensions,
				eventProperties: ep
			});
		} else if (eventType === EVENT_TYPE_SESSION_END) trackSessionEnd({
			...shared,
			turnId: fields.turnId,
			eventProperties: ep
		});
		else {
			const spanName = span.name ?? "";
			trackSpan({
				...shared,
				spanName,
				latencyMs: fields.latencyMs,
				isError: fields.isError,
				errorMessage: fields.errorMessage,
				errorType: fields.errorType,
				turnId: fields.turnId,
				eventProperties: ep
			});
		}
	}
	_routeGenaiOperation(operation, attrs, span, shared, extraProps, fields) {
		const ep = Object.keys(extraProps).length > 0 ? extraProps : void 0;
		if (operation === OP_CHAT || operation === OP_TEXT_COMPLETION || operation === OP_GENERATE_CONTENT) {
			if (fields.userContent && !fields.skipAutoUser) trackUserMessage({
				...shared,
				messageContent: fields.userContent,
				turnId: fields.turnId ?? 1,
				eventProperties: ep
			});
			trackAiMessage({
				...shared,
				modelName: fields.model,
				provider: fields.provider,
				responseContent: fields.aiContent ?? "",
				latencyMs: fields.latencyMs,
				turnId: fields.turnId ?? 2,
				inputTokens: fields.inputTokens,
				outputTokens: fields.outputTokens,
				totalTokens: fields.totalTokens,
				cacheReadInputTokens: fields.cacheReadInputTokens,
				cacheCreationInputTokens: fields.cacheCreationInputTokens,
				totalCostUsd: fields.costUsd,
				isError: fields.isError,
				errorMessage: fields.errorMessage,
				finishReason: fields.finishReason,
				systemPrompt: fields.systemPrompt,
				temperature: fields.temperature,
				maxOutputTokens: fields.maxTokens,
				topP: fields.topP,
				eventProperties: ep
			});
		} else if (operation === OP_EMBEDDINGS) {
			const dimensions = safeInt(attrs[GENAI_EMBEDDING_DIMENSIONS]);
			trackEmbedding({
				...shared,
				model: fields.model,
				provider: fields.provider,
				latencyMs: fields.latencyMs,
				inputTokens: fields.inputTokens,
				dimensions,
				eventProperties: ep
			});
		} else if (operation === OP_EXECUTE_TOOL) {
			let toolName = String(attrs[GENAI_TOOL_NAME] ?? "");
			if (!toolName) {
				toolName = span.name ?? "unknown_tool";
				if (toolName.startsWith("execute_tool ")) toolName = toolName.slice(13);
			}
			trackToolCall({
				...shared,
				toolName,
				success: !fields.isError,
				latencyMs: fields.latencyMs,
				turnId: fields.turnId ?? 1,
				errorMessage: fields.errorMessage,
				eventProperties: ep
			});
		} else if (operation === OP_INVOKE_AGENT || operation === OP_CREATE_AGENT) trackAiMessage({
			...shared,
			modelName: fields.model,
			provider: fields.provider,
			responseContent: fields.aiContent ?? "",
			latencyMs: fields.latencyMs,
			turnId: fields.turnId ?? 1,
			inputTokens: fields.inputTokens,
			outputTokens: fields.outputTokens,
			totalTokens: fields.totalTokens,
			cacheReadInputTokens: fields.cacheReadInputTokens,
			cacheCreationInputTokens: fields.cacheCreationInputTokens,
			totalCostUsd: fields.costUsd,
			isError: fields.isError,
			errorMessage: fields.errorMessage,
			finishReason: fields.finishReason,
			systemPrompt: fields.systemPrompt,
			temperature: fields.temperature,
			maxOutputTokens: fields.maxTokens,
			topP: fields.topP,
			eventProperties: ep
		});
		else trackAiMessage({
			...shared,
			modelName: fields.model,
			provider: fields.provider,
			responseContent: fields.aiContent ?? "",
			latencyMs: fields.latencyMs,
			turnId: fields.turnId ?? 1,
			inputTokens: fields.inputTokens,
			outputTokens: fields.outputTokens,
			totalTokens: fields.totalTokens,
			cacheReadInputTokens: fields.cacheReadInputTokens,
			cacheCreationInputTokens: fields.cacheCreationInputTokens,
			totalCostUsd: fields.costUsd,
			isError: fields.isError,
			errorMessage: fields.errorMessage,
			finishReason: fields.finishReason,
			eventProperties: ep
		});
	}
	_routeSpanKind(spanKind, attrs, span, shared, extraProps, fields) {
		const [toolInput, toolOutput] = this._extractIoState(attrs);
		const spanName = span.name ?? "";
		const parentSpanId = this._extractParentSpanId(span);
		const ep = Object.keys(extraProps).length > 0 ? extraProps : void 0;
		if (spanKind === SPAN_KIND_TOOL) {
			const toolName = String(attrs[GENAI_TOOL_NAME] ?? "") || spanName || "unknown_tool";
			if (extraProps[PROP_COMPONENT_TYPE] == null) extraProps[PROP_COMPONENT_TYPE] = "tool";
			trackToolCall({
				...shared,
				toolName,
				toolType: strOrNull(attrs[AMP_TOOL_TYPE]) ?? void 0,
				toolOwner: strOrNull(attrs[AMP_TOOL_OWNER]) ?? void 0,
				success: !fields.isError,
				latencyMs: fields.latencyMs,
				turnId: fields.turnId ?? 1,
				toolInput,
				toolOutput,
				errorMessage: fields.errorMessage,
				errorType: fields.errorType,
				eventProperties: Object.keys(extraProps).length > 0 ? extraProps : void 0
			});
		} else if (spanKind === SPAN_KIND_AGENT) {
			if (extraProps[PROP_COMPONENT_TYPE] == null) extraProps[PROP_COMPONENT_TYPE] = "agent";
			if (toolInput != null) extraProps[PROP_INPUT_STATE] = serializeToJson(toolInput);
			if (toolOutput != null) extraProps[PROP_OUTPUT_STATE] = serializeToJson(toolOutput);
			trackSpan({
				...shared,
				spanName,
				latencyMs: fields.latencyMs,
				isError: fields.isError,
				errorMessage: fields.errorMessage,
				errorType: fields.errorType,
				turnId: fields.turnId,
				parentSpanId,
				eventProperties: Object.keys(extraProps).length > 0 ? extraProps : void 0
			});
		} else if (spanKind === SPAN_KIND_LLM) trackAiMessage({
			...shared,
			modelName: fields.model,
			provider: fields.provider,
			responseContent: fields.aiContent ?? "",
			latencyMs: fields.latencyMs,
			turnId: fields.turnId ?? 1,
			inputTokens: fields.inputTokens,
			outputTokens: fields.outputTokens,
			totalTokens: fields.totalTokens,
			cacheReadInputTokens: fields.cacheReadInputTokens,
			cacheCreationInputTokens: fields.cacheCreationInputTokens,
			totalCostUsd: fields.costUsd,
			isError: fields.isError,
			errorMessage: fields.errorMessage,
			finishReason: fields.finishReason,
			systemPrompt: fields.systemPrompt,
			temperature: fields.temperature,
			maxOutputTokens: fields.maxTokens,
			topP: fields.topP,
			eventProperties: ep
		});
		else if (spanKind === SPAN_KIND_SESSION && spanName === "session.end") trackSessionEnd({
			...shared,
			turnId: fields.turnId,
			eventProperties: ep
		});
		else {
			if (extraProps[PROP_COMPONENT_TYPE] == null) extraProps[PROP_COMPONENT_TYPE] = "span";
			if (toolInput != null) extraProps[PROP_INPUT_STATE] = serializeToJson(toolInput);
			if (toolOutput != null) extraProps[PROP_OUTPUT_STATE] = serializeToJson(toolOutput);
			trackSpan({
				...shared,
				spanName,
				latencyMs: fields.latencyMs,
				isError: fields.isError,
				errorMessage: fields.errorMessage,
				errorType: fields.errorType,
				turnId: fields.turnId,
				parentSpanId,
				eventProperties: Object.keys(extraProps).length > 0 ? extraProps : void 0
			});
		}
	}
	_buildExtraProperties(attrs, opts) {
		const extra = {};
		if (opts.agentId) extra[PROP_AGENT_ID] = opts.agentId;
		if (opts.parentAgentId) extra[PROP_PARENT_AGENT_ID] = opts.parentAgentId;
		if (opts.env) extra[PROP_ENV] = opts.env;
		if (opts.customerOrgId) extra[PROP_CUSTOMER_ORG_ID] = opts.customerOrgId;
		if (opts.agentVersion) extra[PROP_AGENT_VERSION] = opts.agentVersion;
		if (opts.contextDict) extra[PROP_CONTEXT] = JSON.stringify(opts.contextDict);
		if (opts.otelAgentName) extra["[Agent] Agent Name"] = opts.otelAgentName;
		const tags = attrs[AMP_TAGS];
		if (tags != null) extra[PROP_TAGS] = typeof tags === "string" ? tags : JSON.stringify(tags);
		else if (opts.sessionContext?.tags != null && opts.sessionContext.tags.length > 0) extra[PROP_TAGS] = JSON.stringify(opts.sessionContext.tags);
		if (attrs[AMP_GIT_SHA]) extra[PROP_GIT_SHA] = String(attrs[AMP_GIT_SHA]);
		if (attrs[AMP_GIT_REF]) extra[PROP_GIT_REF] = String(attrs[AMP_GIT_REF]);
		if (attrs[AMP_GIT_REPO]) extra[PROP_GIT_REPO] = String(attrs[AMP_GIT_REPO]);
		if (!extra[PROP_GIT_SHA] || !extra[PROP_GIT_REF] || !extra[PROP_GIT_REPO]) {
			const gitMeta = getGitMetadata();
			if (!extra[PROP_GIT_SHA] && gitMeta.gitSha) extra[PROP_GIT_SHA] = gitMeta.gitSha;
			if (!extra[PROP_GIT_REF] && gitMeta.gitRef) extra[PROP_GIT_REF] = gitMeta.gitRef;
			if (!extra[PROP_GIT_REPO] && gitMeta.gitRepo) extra[PROP_GIT_REPO] = gitMeta.gitRepo;
		}
		if (attrs[AMP_STACK_TRACE]) extra[PROP_STACK_TRACE] = String(attrs[AMP_STACK_TRACE]);
		else if (opts.span.events?.length) {
			const exceptionEvent = opts.span.events.find((e) => e.name === "exception");
			if (exceptionEvent?.attributes) {
				const stacktrace = exceptionEvent.attributes["exception.stacktrace"];
				if (stacktrace) extra[PROP_STACK_TRACE] = String(stacktrace);
			}
		}
		if (attrs[AMP_ERROR_SOURCE]) extra[PROP_ERROR_SOURCE_PROP] = String(attrs[AMP_ERROR_SOURCE]);
		if (attrs[AMP_TOOL_TYPE]) extra[PROP_TOOL_TYPE] = String(attrs[AMP_TOOL_TYPE]);
		if (attrs[AMP_TOOL_OWNER]) extra[PROP_TOOL_OWNER] = String(attrs[AMP_TOOL_OWNER]);
		const ampSpanKind = attrs[AMP_SPAN_KIND];
		if (ampSpanKind) {
			extra[PROP_COMPONENT_TYPE] = String(ampSpanKind);
			extra[PROP_SPAN_KIND_PROP] = String(ampSpanKind);
		}
		const otelSpanId = this._extractOtelSpanId(opts.span);
		if (otelSpanId) extra[PROP_SPAN_ID] = otelSpanId;
		const otelParentSpanId = this._extractParentSpanId(opts.span);
		if (otelParentSpanId) extra[PROP_PARENT_SPAN_ID] = otelParentSpanId;
		return extra;
	}
	_extractUserContent(attrs) {
		const raw = attrs[GENAI_INPUT_MESSAGES];
		const messages = parseJsonAttr(raw);
		if (!messages) return null;
		for (let i = messages.length - 1; i >= 0; i--) {
			const msg = messages[i];
			if (msg && msg.role === "user") return extractTextFromParts(msg);
		}
		return null;
	}
	_extractAiContent(attrs) {
		const raw = attrs[GENAI_OUTPUT_MESSAGES];
		const messages = parseJsonAttr(raw);
		if (!messages || messages.length === 0) return null;
		const first = messages[0];
		if (first) return extractTextFromParts(first);
		return null;
	}
	_extractSystemPrompt(attrs) {
		const rawAttr = attrs[GENAI_SYSTEM_INSTRUCTIONS];
		if (rawAttr == null) return null;
		let items;
		if (typeof rawAttr === "string") try {
			const parsed = JSON.parse(rawAttr);
			if (Array.isArray(parsed)) items = parsed;
			else return rawAttr;
		} catch {
			return rawAttr;
		}
		else if (Array.isArray(rawAttr)) items = rawAttr;
		else return null;
		const parts = [];
		for (const item of items) if (typeof item === "object" && item != null && "content" in item) {
			const content = item.content;
			if (content) parts.push(String(content));
		} else if (typeof item === "string") parts.push(item);
		return parts.length > 0 ? parts.join("\n") : null;
	}
	_extractIoState(attrs) {
		const rawInput = attrs[AMP_INPUT_STATE];
		const rawOutput = attrs[AMP_OUTPUT_STATE];
		return [parseJsonOrPassthrough(rawInput), parseJsonOrPassthrough(rawOutput)];
	}
	_resolveUserId(attrs, ctx) {
		if (ctx?.userId) return ctx.userId;
		const enduser = attrs[GENAI_ENDUSER_ID];
		if (enduser) return String(enduser);
		return this._defaultUserId;
	}
	_extractOtelTraceId(span) {
		const spanCtxFn = span.spanContext;
		if (typeof spanCtxFn === "function") {
			const ctx$1 = spanCtxFn();
			if (ctx$1?.traceId) return ctx$1.traceId;
		}
		const ctx = span.context;
		if (!ctx) return null;
		if (ctx.traceId) return ctx.traceId;
		const traceId = ctx.trace_id;
		if (traceId && typeof traceId === "number" && traceId !== 0) return traceId.toString(16).padStart(32, "0");
		return null;
	}
	_extractOtelSpanId(span) {
		const spanCtxFn = span.spanContext;
		if (typeof spanCtxFn === "function") {
			const ctx$1 = spanCtxFn();
			if (ctx$1?.spanId) return ctx$1.spanId;
		}
		const ctx = span.context;
		if (!ctx) return null;
		if (ctx.spanId) return ctx.spanId;
		const spanId = ctx.span_id;
		if (spanId && typeof spanId === "number" && spanId !== 0) return spanId.toString(16).padStart(16, "0");
		return null;
	}
	_extractParentSpanId(span) {
		if (span.parentSpanId) return span.parentSpanId;
		const parent = span.parent;
		if (!parent) return null;
		if (parent.spanId) return parent.spanId;
		const parentSpanId = parent.span_id;
		if (parentSpanId && typeof parentSpanId === "number" && parentSpanId !== 0) return parentSpanId.toString(16).padStart(16, "0");
		return null;
	}
	_computeLatencyMs(span) {
		if (span.startTime && span.endTime) {
			const startNs = span.startTime[0] * 1e9 + span.startTime[1];
			const endNs = span.endTime[0] * 1e9 + span.endTime[1];
			return Math.round((endNs - startNs) / 1e6 * 100) / 100;
		}
		if (span.startTimeUnixNano != null && span.endTimeUnixNano != null) {
			const start = Number(span.startTimeUnixNano);
			const end = Number(span.endTimeUnixNano);
			return Math.round((end - start) / 1e6 * 100) / 100;
		}
		if (span.start_time != null && span.end_time != null) return Math.round((span.end_time - span.start_time) / 1e6 * 100) / 100;
		return 0;
	}
	_parseContextAttr(value) {
		if (value == null) return null;
		if (typeof value === "object" && !Array.isArray(value)) return value;
		if (typeof value === "string") try {
			const parsed = JSON.parse(value);
			if (typeof parsed === "object" && parsed != null && !Array.isArray(parsed)) return parsed;
		} catch {}
		return null;
	}
};
function strOrNull(value) {
	if (value == null) return null;
	return String(value) || null;
}
function safeInt(value) {
	if (value == null) return null;
	const n = Number(value);
	return Number.isNaN(n) ? null : Math.trunc(n);
}
function safeFloat(value) {
	if (value == null) return null;
	const n = Number(value);
	return Number.isNaN(n) ? null : n;
}
function parseJsonAttr(value) {
	if (value == null) return null;
	if (Array.isArray(value)) return value;
	if (typeof value === "string") try {
		const parsed = JSON.parse(value);
		if (Array.isArray(parsed)) return parsed;
	} catch {}
	return null;
}
function parseJsonOrPassthrough(value) {
	if (value == null) return null;
	if (typeof value === "string") try {
		return JSON.parse(value);
	} catch {
		return value;
	}
	return value;
}
function extractTextFromParts(msg) {
	const content = msg.content;
	if (typeof content === "string") return content;
	const parts = msg.parts;
	if (!Array.isArray(parts)) return null;
	const textParts = [];
	for (const part of parts) if (typeof part === "object" && part != null && part.type === "text") {
		const text = part.content;
		if (text) textParts.push(String(text));
	}
	return textParts.length > 0 ? textParts.join("\n") : null;
}
function serializeToJson(value) {
	try {
		return JSON.stringify(value);
	} catch {
		return String(value);
	}
}

//#endregion
export { SpanEventMapper };
//# sourceMappingURL=mapper.js.map