import { ValidationError } from "../exceptions.js";
import { getLogger } from "../utils/logger.js";
import { inferModelTier } from "../utils/model-tiers.js";
import { EVENT_AI_RESPONSE, EVENT_EMBEDDING, EVENT_SCORE, EVENT_SESSION_END, EVENT_SESSION_ENRICHMENT, EVENT_SPAN, EVENT_TOOL_CALL, EVENT_USER_MESSAGE, MAX_SERIALIZED_LENGTH, PROP_ABANDONMENT_TURN, PROP_AGENT_CHAIN, PROP_AGENT_DESCRIPTION, PROP_AGENT_ID, PROP_AGENT_VERSION, PROP_ATTACHMENTS, PROP_ATTACHMENT_COUNT, PROP_ATTACHMENT_TYPES, PROP_CACHE_CREATION_TOKENS, PROP_CACHE_READ_TOKENS, PROP_COMMENT, PROP_COMPONENT_TYPE, PROP_CONTEXT, PROP_COST_USD, PROP_CUSTOMER_ORG_ID, PROP_EDITED_MESSAGE_ID, PROP_EMBEDDING_DIMENSIONS, PROP_ENRICHMENTS, PROP_ENV, PROP_ERROR_MESSAGE, PROP_ERROR_SOURCE, PROP_ERROR_TYPE, PROP_EVALUATION_SOURCE, PROP_FINISH_REASON, PROP_GIT_REF, PROP_GIT_REPO, PROP_GIT_SHA, PROP_HAS_ATTACHMENTS, PROP_HAS_REASONING, PROP_IDLE_TIMEOUT_MINUTES, PROP_INPUT_STATE, PROP_INPUT_TOKENS, PROP_INVOCATION_ID, PROP_IS_EDIT, PROP_IS_ERROR, PROP_IS_REGENERATION, PROP_IS_STREAMING, PROP_LATENCY_MS, PROP_LOCALE, PROP_MAX_OUTPUT_TOKENS, PROP_MESSAGE_ID, PROP_MESSAGE_LABELS, PROP_MESSAGE_LABEL_MAP, PROP_MESSAGE_SOURCE, PROP_MODEL_NAME, PROP_MODEL_TIER, PROP_OUTPUT_STATE, PROP_OUTPUT_TOKENS, PROP_PARENT_AGENT_ID, PROP_PARENT_MESSAGE_ID, PROP_PARENT_SPAN_ID, PROP_PROMPT_ID, PROP_PROVIDER, PROP_QUALITY_SCORE, PROP_REASONING_CONTENT, PROP_REASONING_TOKENS, PROP_REQUEST_COMPLEXITY, PROP_ROOT_AGENT_NAME, PROP_RUNTIME, PROP_SCORE_NAME, PROP_SCORE_VALUE, PROP_SDK_VERSION, PROP_SENTIMENT_SCORE, PROP_SESSION_ID, PROP_SESSION_REPLAY_ID, PROP_SPAN_ID, PROP_SPAN_KIND, PROP_SPAN_NAME, PROP_STACK_TRACE, PROP_SYSTEM_PROMPT, PROP_SYSTEM_PROMPT_LENGTH, PROP_TAGS, PROP_TARGET_ID, PROP_TARGET_TYPE, PROP_TASK_FAILURE_REASON, PROP_TASK_FAILURE_TYPE, PROP_TEMPERATURE, PROP_TOOL_CALLS, PROP_TOOL_DEFINITIONS, PROP_TOOL_DEFINITIONS_COUNT, PROP_TOOL_DEFINITIONS_HASH, PROP_TOOL_INPUT, PROP_TOOL_NAME, PROP_TOOL_OUTPUT, PROP_TOOL_OWNER, PROP_TOOL_SUCCESS, PROP_TOOL_TYPE, PROP_TOP_P, PROP_TOTAL_ATTACHMENT_SIZE, PROP_TOTAL_TOKENS, PROP_TRACE_ID, PROP_TTFB_MS, PROP_TURN_ID, PROP_WAS_CACHED, PROP_WAS_COPIED, SDK_RUNTIME, SDK_VERSION } from "./constants.js";
import { PrivacyConfig, getTextFromLlmMessage, sanitizeStructuredContent } from "./privacy.js";
import { randomUUID } from "node:crypto";

//#region src/core/tracking.ts
function validateRequiredStr(value, fieldName) {
	if (typeof value !== "string" || !value) throw new ValidationError(`${fieldName} must be a non-empty string, got ${String(value)}`);
}
function validateIdentity(userId, deviceId) {
	const hasUser = typeof userId === "string" && userId.length > 0;
	const hasDevice = typeof deviceId === "string" && deviceId.length > 0;
	if (!hasUser && !hasDevice) throw new ValidationError("At least one of userId or deviceId must be a non-empty string");
}
function validateNonNegative(value, fieldName) {
	if (typeof value === "number" && value < 0) throw new ValidationError(`${fieldName} must be >= 0, got ${value}`);
}
function validateNumeric(value, fieldName) {
	if (typeof value !== "number") throw new ValidationError(`${fieldName} must be numeric, got ${typeof value}`);
}
function serializeToJsonString(value, maxLength = MAX_SERIALIZED_LENGTH) {
	let serialized;
	if (typeof value === "string") serialized = value;
	else try {
		serialized = JSON.stringify(value);
	} catch {
		serialized = String(value);
	}
	if (serialized.length > maxLength) {
		const truncateAt = Math.max(0, maxLength - 14);
		return `${serialized.slice(0, truncateAt)}...[truncated]`;
	}
	return serialized;
}
function withSdkManagedProperties(eventProperties, managedProperties) {
	return {
		...eventProperties ?? {},
		...managedProperties
	};
}
/**
* Set `event.session_id` from a browser session ID when valid and positive.
* Idempotent: does not overwrite an existing `session_id`.
*/
function applyBrowserSessionId(event, browserSessionId) {
	if (event.session_id != null) return;
	if (browserSessionId == null) return;
	const numericSessionId = Number(browserSessionId);
	if (!Number.isNaN(numericSessionId) && numericSessionId > 0) event.session_id = numericSessionId;
}
function trackUserMessage(opts) {
	const pc = opts.privacyConfig ?? new PrivacyConfig();
	if (pc.validate) {
		validateIdentity(opts.userId, opts.deviceId);
		validateRequiredStr(opts.sessionId, "sessionId");
	}
	const messageId = opts.messageId || randomUUID();
	const contentData = pc.sanitizeContent(opts.messageContent);
	const properties = withSdkManagedProperties(opts.eventProperties, {
		[PROP_TURN_ID]: opts.turnId ?? 1,
		[PROP_MESSAGE_ID]: messageId,
		[PROP_COMPONENT_TYPE]: "user_input",
		[PROP_SDK_VERSION]: SDK_VERSION,
		[PROP_RUNTIME]: SDK_RUNTIME
	});
	if (opts.sessionId) properties[PROP_SESSION_ID] = opts.sessionId;
	if (opts.traceId) properties[PROP_TRACE_ID] = opts.traceId;
	if (opts.conversationId && !opts.sessionId) properties[PROP_SESSION_ID] = opts.conversationId;
	if (opts.env) properties[PROP_ENV] = opts.env;
	if (opts.locale) properties[PROP_LOCALE] = opts.locale;
	if (opts.agentId) properties[PROP_AGENT_ID] = opts.agentId;
	if (opts.parentAgentId) properties[PROP_PARENT_AGENT_ID] = opts.parentAgentId;
	if (opts.customerOrgId) properties[PROP_CUSTOMER_ORG_ID] = opts.customerOrgId;
	if (opts.agentVersion) properties[PROP_AGENT_VERSION] = opts.agentVersion;
	if (opts.description) properties[PROP_AGENT_DESCRIPTION] = opts.description;
	if (opts.messageSource) properties[PROP_MESSAGE_SOURCE] = opts.messageSource;
	if (opts.context) properties[PROP_CONTEXT] = serializeToJsonString(opts.context);
	if (opts.isRegeneration) properties[PROP_IS_REGENERATION] = true;
	if (opts.isEdit) properties[PROP_IS_EDIT] = true;
	if (opts.editedMessageId) properties[PROP_EDITED_MESSAGE_ID] = opts.editedMessageId;
	if (opts.attachments?.length) {
		properties[PROP_HAS_ATTACHMENTS] = true;
		properties[PROP_ATTACHMENT_COUNT] = opts.attachments.length;
		properties[PROP_ATTACHMENT_TYPES] = [...new Set(opts.attachments.map((a) => String(a.type ?? "unknown")))];
		const totalSize = opts.attachments.reduce((sum, a) => sum + (typeof a.size_bytes === "number" ? a.size_bytes : 0), 0);
		if (totalSize > 0) properties[PROP_TOTAL_ATTACHMENT_SIZE] = totalSize;
		properties[PROP_ATTACHMENTS] = serializeToJsonString(opts.attachments);
	}
	if (opts.labels?.length) properties[PROP_MESSAGE_LABELS] = serializeToJsonString(opts.labels.map((lbl) => lbl.toDict()));
	if (opts.idleTimeoutMinutes != null) properties[PROP_IDLE_TIMEOUT_MINUTES] = opts.idleTimeoutMinutes;
	Object.assign(properties, contentData);
	const event = {
		event_type: EVENT_USER_MESSAGE,
		user_id: opts.userId || void 0,
		device_id: opts.deviceId || void 0,
		event_properties: properties
	};
	if (opts.userProperties) event.user_properties = opts.userProperties;
	if (opts.groups) event.groups = opts.groups;
	applyBrowserSessionId(event, opts.browserSessionId);
	try {
		opts.amplitude.track(event);
		getLogger(opts.amplitude).debug(`Tracked ${EVENT_USER_MESSAGE} for user ${opts.userId}`);
	} catch (e) {
		getLogger(opts.amplitude).error(`Failed to track ${EVENT_USER_MESSAGE}: ${e}`);
	}
	return messageId;
}
function trackAiMessage(opts) {
	const pc = opts.privacyConfig ?? new PrivacyConfig();
	if (pc.validate) {
		validateIdentity(opts.userId, opts.deviceId);
		validateRequiredStr(opts.modelName, "model");
		validateNonNegative(opts.latencyMs, "latencyMs");
	}
	const messageId = opts.messageId || randomUUID();
	const contentData = pc.sanitizeContent(opts.responseContent);
	const properties = withSdkManagedProperties(opts.eventProperties, {
		[PROP_TURN_ID]: opts.turnId ?? 2,
		[PROP_MESSAGE_ID]: messageId,
		[PROP_MODEL_NAME]: opts.modelName,
		[PROP_PROVIDER]: opts.provider,
		[PROP_LATENCY_MS]: opts.latencyMs,
		[PROP_IS_ERROR]: opts.isError ?? false,
		[PROP_COMPONENT_TYPE]: "llm",
		[PROP_SDK_VERSION]: SDK_VERSION,
		[PROP_RUNTIME]: SDK_RUNTIME
	});
	if (opts.sessionId) properties[PROP_SESSION_ID] = opts.sessionId;
	if (opts.traceId) properties[PROP_TRACE_ID] = opts.traceId;
	if (opts.conversationId && !opts.sessionId) properties[PROP_SESSION_ID] = opts.conversationId;
	if (opts.env) properties[PROP_ENV] = opts.env;
	if (opts.locale) properties[PROP_LOCALE] = opts.locale;
	if (opts.agentId) properties[PROP_AGENT_ID] = opts.agentId;
	if (opts.parentAgentId) properties[PROP_PARENT_AGENT_ID] = opts.parentAgentId;
	if (opts.customerOrgId) properties[PROP_CUSTOMER_ORG_ID] = opts.customerOrgId;
	if (opts.agentVersion) properties[PROP_AGENT_VERSION] = opts.agentVersion;
	if (opts.description) properties[PROP_AGENT_DESCRIPTION] = opts.description;
	if (opts.context) properties[PROP_CONTEXT] = serializeToJsonString(opts.context);
	if (opts.spanKind) properties[PROP_SPAN_KIND] = opts.spanKind;
	if (opts.wasCopied) properties[PROP_WAS_COPIED] = true;
	if (opts.wasCached) properties[PROP_WAS_CACHED] = true;
	if (opts.modelTier != null) properties[PROP_MODEL_TIER] = opts.modelTier;
	else properties[PROP_MODEL_TIER] = inferModelTier(opts.modelName);
	Object.assign(properties, contentData);
	if (opts.inputTokens != null) properties[PROP_INPUT_TOKENS] = opts.inputTokens;
	if (opts.outputTokens != null) properties[PROP_OUTPUT_TOKENS] = opts.outputTokens;
	if (opts.totalTokens != null) properties[PROP_TOTAL_TOKENS] = opts.totalTokens;
	if (opts.reasoningTokens != null) properties[PROP_REASONING_TOKENS] = opts.reasoningTokens;
	if (opts.cacheReadInputTokens != null) properties[PROP_CACHE_READ_TOKENS] = opts.cacheReadInputTokens;
	if (opts.cacheCreationInputTokens != null) properties[PROP_CACHE_CREATION_TOKENS] = opts.cacheCreationInputTokens;
	if (opts.totalCostUsd != null) properties[PROP_COST_USD] = opts.totalCostUsd;
	if (opts.providerTtfbMs != null) properties[PROP_TTFB_MS] = opts.providerTtfbMs;
	if (opts.finishReason != null) properties[PROP_FINISH_REASON] = opts.finishReason;
	if (opts.errorMessage != null) properties[PROP_ERROR_MESSAGE] = opts.errorMessage;
	if (opts.errorType != null) properties[PROP_ERROR_TYPE] = opts.errorType;
	if (opts.stackTrace != null) properties[PROP_STACK_TRACE] = opts.stackTrace;
	if (opts.toolCalls != null) properties[PROP_TOOL_CALLS] = serializeToJsonString(opts.toolCalls);
	const reasoningProps = pc.sanitizeReasoningContent(opts.reasoningContent ?? null, opts.reasoningTokens);
	Object.assign(properties, reasoningProps);
	const systemPromptProps = pc.sanitizeSystemPrompt(opts.systemPrompt ?? null);
	Object.assign(properties, systemPromptProps);
	const toolDefProps = pc.sanitizeToolDefinitions(opts.toolDefinitions);
	Object.assign(properties, toolDefProps);
	if (opts.temperature != null) properties[PROP_TEMPERATURE] = opts.temperature;
	if (opts.maxOutputTokens != null) properties[PROP_MAX_OUTPUT_TOKENS] = opts.maxOutputTokens;
	if (opts.topP != null) properties[PROP_TOP_P] = opts.topP;
	if (opts.isStreaming != null) properties[PROP_IS_STREAMING] = opts.isStreaming;
	if (opts.promptId != null) properties[PROP_PROMPT_ID] = opts.promptId;
	if (opts.attachments?.length) {
		properties[PROP_HAS_ATTACHMENTS] = true;
		properties[PROP_ATTACHMENT_COUNT] = opts.attachments.length;
		properties[PROP_ATTACHMENT_TYPES] = [...new Set(opts.attachments.map((a) => String(a.type ?? "unknown")))];
		const totalSize = opts.attachments.reduce((sum, a) => sum + (typeof a.size_bytes === "number" ? a.size_bytes : 0), 0);
		if (totalSize > 0) properties[PROP_TOTAL_ATTACHMENT_SIZE] = totalSize;
		properties[PROP_ATTACHMENTS] = serializeToJsonString(opts.attachments);
	}
	if (opts.labels?.length) properties[PROP_MESSAGE_LABELS] = serializeToJsonString(opts.labels.map((lbl) => lbl.toDict()));
	const event = {
		event_type: EVENT_AI_RESPONSE,
		user_id: opts.userId || void 0,
		device_id: opts.deviceId || void 0,
		event_properties: properties
	};
	if (opts.userProperties) event.user_properties = opts.userProperties;
	if (opts.groups) event.groups = opts.groups;
	applyBrowserSessionId(event, opts.browserSessionId);
	try {
		opts.amplitude.track(event);
		getLogger(opts.amplitude).debug(`Tracked ${EVENT_AI_RESPONSE} for user ${opts.userId}`);
	} catch (e) {
		getLogger(opts.amplitude).error(`Failed to track ${EVENT_AI_RESPONSE}: ${e}`);
	}
	return messageId;
}
function trackToolCall(opts) {
	const pc = opts.privacyConfig ?? new PrivacyConfig();
	if (pc.validate) {
		validateIdentity(opts.userId, opts.deviceId);
		validateRequiredStr(opts.toolName, "toolName");
		validateNonNegative(opts.latencyMs, "latencyMs");
	}
	const invocationId = opts.invocationId || randomUUID();
	const properties = withSdkManagedProperties(opts.eventProperties, {
		[PROP_TURN_ID]: opts.turnId ?? 1,
		[PROP_INVOCATION_ID]: invocationId,
		[PROP_TOOL_NAME]: opts.toolName,
		[PROP_TOOL_SUCCESS]: opts.success,
		[PROP_IS_ERROR]: !opts.success,
		[PROP_LATENCY_MS]: opts.latencyMs,
		[PROP_COMPONENT_TYPE]: "tool",
		[PROP_SDK_VERSION]: SDK_VERSION,
		[PROP_RUNTIME]: SDK_RUNTIME
	});
	if (opts.sessionId) properties[PROP_SESSION_ID] = opts.sessionId;
	if (opts.traceId) properties[PROP_TRACE_ID] = opts.traceId;
	if (opts.conversationId && !opts.sessionId) properties[PROP_SESSION_ID] = opts.conversationId;
	if (opts.parentMessageId) properties[PROP_PARENT_MESSAGE_ID] = opts.parentMessageId;
	if (opts.agentId) properties[PROP_AGENT_ID] = opts.agentId;
	if (opts.parentAgentId) properties[PROP_PARENT_AGENT_ID] = opts.parentAgentId;
	if (opts.customerOrgId) properties[PROP_CUSTOMER_ORG_ID] = opts.customerOrgId;
	if (opts.agentVersion) properties[PROP_AGENT_VERSION] = opts.agentVersion;
	if (opts.description) properties[PROP_AGENT_DESCRIPTION] = opts.description;
	if (opts.context) properties[PROP_CONTEXT] = serializeToJsonString(opts.context);
	if (opts.errorMessage) properties[PROP_ERROR_MESSAGE] = opts.errorMessage;
	if (opts.errorType) properties[PROP_ERROR_TYPE] = opts.errorType;
	if (opts.stackTrace) properties[PROP_STACK_TRACE] = opts.stackTrace;
	if (opts.env) properties[PROP_ENV] = opts.env;
	if (opts.locale) properties[PROP_LOCALE] = opts.locale;
	if (opts.spanKind) properties[PROP_SPAN_KIND] = opts.spanKind;
	if (opts.toolType) properties[PROP_TOOL_TYPE] = opts.toolType;
	if (opts.toolOwner) properties[PROP_TOOL_OWNER] = opts.toolOwner;
	let effectiveMode = pc.contentMode;
	if (effectiveMode == null) effectiveMode = pc.privacyMode ? "metadata_only" : "full";
	if (opts.toolInput != null && effectiveMode === "full") properties[PROP_TOOL_INPUT] = serializeToJsonString(sanitizeStructuredContent(opts.toolInput, pc.redactPii));
	if (opts.toolOutput != null && effectiveMode === "full") properties[PROP_TOOL_OUTPUT] = serializeToJsonString(sanitizeStructuredContent(opts.toolOutput, pc.redactPii));
	const event = {
		event_type: EVENT_TOOL_CALL,
		user_id: opts.userId || void 0,
		device_id: opts.deviceId || void 0,
		event_properties: properties
	};
	if (opts.userProperties) event.user_properties = opts.userProperties;
	if (opts.groups) event.groups = opts.groups;
	applyBrowserSessionId(event, opts.browserSessionId);
	try {
		opts.amplitude.track(event);
		getLogger(opts.amplitude).debug(`Tracked ${EVENT_TOOL_CALL} for user ${opts.userId}`);
	} catch (e) {
		getLogger(opts.amplitude).error(`Failed to track ${EVENT_TOOL_CALL}: ${e}`);
	}
	return invocationId;
}
/**
* Track a complete conversation of user, assistant, and tool messages.
*
* Supported roles: `user`, `assistant`/`ai`, and `tool`. `system` messages are
* intentionally skipped (system content belongs on a response's `systemPrompt`,
* not a standalone event); any other role is skipped with a debug log rather
* than dropped silently.
*/
function trackConversation(opts) {
	const effectiveSessionId = opts.sessionId ?? opts.conversationId ?? randomUUID();
	let turnId = 1;
	for (const message of opts.messages) {
		const role = String(message.role ?? "");
		const content = String(message.content ?? "");
		if (role === "user") trackUserMessage({
			amplitude: opts.amplitude,
			userId: opts.userId,
			deviceId: opts.deviceId,
			messageContent: content,
			sessionId: effectiveSessionId,
			turnId,
			agentId: opts.agentId,
			parentAgentId: opts.parentAgentId,
			customerOrgId: opts.customerOrgId,
			agentVersion: opts.agentVersion,
			description: opts.description,
			context: opts.context,
			env: opts.env,
			locale: opts.locale,
			eventProperties: opts.eventProperties,
			userProperties: opts.userProperties,
			groups: opts.groups,
			privacyConfig: opts.privacyConfig,
			browserSessionId: opts.browserSessionId
		});
		else if (role === "assistant" || role === "ai") trackAiMessage({
			amplitude: opts.amplitude,
			userId: opts.userId,
			deviceId: opts.deviceId,
			modelName: String(message.model ?? "unknown"),
			provider: String(message.provider ?? "unknown"),
			responseContent: content,
			latencyMs: Number(message.latency_ms ?? 0),
			sessionId: effectiveSessionId,
			turnId,
			inputTokens: message.input_tokens,
			outputTokens: message.output_tokens,
			totalTokens: message.total_tokens,
			totalCostUsd: message.total_cost_usd,
			agentId: opts.agentId,
			parentAgentId: opts.parentAgentId,
			customerOrgId: opts.customerOrgId,
			agentVersion: opts.agentVersion,
			description: opts.description,
			context: opts.context,
			env: opts.env,
			locale: opts.locale,
			eventProperties: opts.eventProperties,
			userProperties: opts.userProperties,
			groups: opts.groups,
			privacyConfig: opts.privacyConfig,
			browserSessionId: opts.browserSessionId
		});
		else if (role === "tool") trackToolCall({
			amplitude: opts.amplitude,
			userId: opts.userId,
			deviceId: opts.deviceId,
			toolName: String(message.tool_name ?? message.name ?? ""),
			success: message.success == null ? true : Boolean(message.success),
			latencyMs: Number(message.latency_ms ?? 0),
			sessionId: effectiveSessionId,
			turnId,
			toolInput: message.tool_input,
			toolOutput: message.tool_output ?? content,
			agentId: opts.agentId,
			parentAgentId: opts.parentAgentId,
			customerOrgId: opts.customerOrgId,
			agentVersion: opts.agentVersion,
			description: opts.description,
			context: opts.context,
			env: opts.env,
			locale: opts.locale,
			eventProperties: opts.eventProperties,
			userProperties: opts.userProperties,
			groups: opts.groups,
			privacyConfig: opts.privacyConfig,
			browserSessionId: opts.browserSessionId
		});
		else if (role === "system") getLogger(opts.amplitude).debug("trackConversation: skipping 'system' message (no standalone event)");
		else getLogger(opts.amplitude).debug(`trackConversation: skipping message with unhandled role '${role}'`);
		turnId++;
	}
}
function trackEmbedding(opts) {
	if ((opts.privacyConfig ?? new PrivacyConfig()).validate) {
		validateIdentity(opts.userId, opts.deviceId);
		validateNonNegative(opts.latencyMs, "latencyMs");
	}
	const spanId = randomUUID();
	const properties = withSdkManagedProperties(opts.eventProperties, {
		[PROP_SPAN_ID]: spanId,
		[PROP_MODEL_NAME]: opts.model,
		[PROP_PROVIDER]: opts.provider,
		[PROP_LATENCY_MS]: opts.latencyMs,
		[PROP_COMPONENT_TYPE]: "embedding",
		[PROP_SDK_VERSION]: SDK_VERSION,
		[PROP_RUNTIME]: SDK_RUNTIME
	});
	if (opts.sessionId) properties[PROP_SESSION_ID] = opts.sessionId;
	if (opts.traceId != null) properties[PROP_TRACE_ID] = opts.traceId;
	if (opts.turnId != null) properties[PROP_TURN_ID] = opts.turnId;
	if (opts.inputTokens != null) properties[PROP_INPUT_TOKENS] = opts.inputTokens;
	if (opts.dimensions != null) properties[PROP_EMBEDDING_DIMENSIONS] = opts.dimensions;
	if (opts.totalCostUsd != null) properties[PROP_COST_USD] = opts.totalCostUsd;
	if (opts.agentId) properties[PROP_AGENT_ID] = opts.agentId;
	if (opts.parentAgentId) properties[PROP_PARENT_AGENT_ID] = opts.parentAgentId;
	if (opts.customerOrgId) properties[PROP_CUSTOMER_ORG_ID] = opts.customerOrgId;
	if (opts.agentVersion) properties[PROP_AGENT_VERSION] = opts.agentVersion;
	if (opts.description) properties[PROP_AGENT_DESCRIPTION] = opts.description;
	if (opts.context) properties[PROP_CONTEXT] = serializeToJsonString(opts.context);
	if (opts.env) properties[PROP_ENV] = opts.env;
	const event = {
		event_type: EVENT_EMBEDDING,
		user_id: opts.userId || void 0,
		device_id: opts.deviceId || void 0,
		event_properties: properties
	};
	if (opts.groups) event.groups = opts.groups;
	applyBrowserSessionId(event, opts.browserSessionId);
	try {
		opts.amplitude.track(event);
		getLogger(opts.amplitude).debug(`Tracked ${EVENT_EMBEDDING} for user ${opts.userId}`);
	} catch (e) {
		getLogger(opts.amplitude).error(`Failed to track ${EVENT_EMBEDDING}: ${e}`);
	}
	return spanId;
}
function trackSpan(opts) {
	const pc = opts.privacyConfig ?? new PrivacyConfig();
	if (pc.validate) {
		validateIdentity(opts.userId, opts.deviceId);
		validateNonNegative(opts.latencyMs, "latencyMs");
	}
	const spanId = randomUUID();
	const properties = withSdkManagedProperties(opts.eventProperties, {
		[PROP_SPAN_ID]: spanId,
		[PROP_SPAN_NAME]: opts.spanName,
		[PROP_TRACE_ID]: opts.traceId,
		[PROP_LATENCY_MS]: opts.latencyMs,
		[PROP_IS_ERROR]: opts.isError ?? false,
		[PROP_SDK_VERSION]: SDK_VERSION,
		[PROP_RUNTIME]: SDK_RUNTIME
	});
	if (opts.sessionId) properties[PROP_SESSION_ID] = opts.sessionId;
	if (opts.turnId != null) properties[PROP_TURN_ID] = opts.turnId;
	if (opts.parentSpanId) properties[PROP_PARENT_SPAN_ID] = opts.parentSpanId;
	if (opts.errorMessage) properties[PROP_ERROR_MESSAGE] = opts.errorMessage;
	if (opts.errorType) properties[PROP_ERROR_TYPE] = opts.errorType;
	if (opts.agentId) properties[PROP_AGENT_ID] = opts.agentId;
	if (opts.parentAgentId) properties[PROP_PARENT_AGENT_ID] = opts.parentAgentId;
	if (opts.customerOrgId) properties[PROP_CUSTOMER_ORG_ID] = opts.customerOrgId;
	if (opts.agentVersion) properties[PROP_AGENT_VERSION] = opts.agentVersion;
	if (opts.description) properties[PROP_AGENT_DESCRIPTION] = opts.description;
	if (opts.context) properties[PROP_CONTEXT] = serializeToJsonString(opts.context);
	if (opts.env) properties[PROP_ENV] = opts.env;
	let effectiveMode = pc.contentMode;
	if (effectiveMode == null) effectiveMode = pc.privacyMode ? "metadata_only" : "full";
	if (opts.inputState != null && effectiveMode === "full") properties[PROP_INPUT_STATE] = serializeToJsonString(sanitizeStructuredContent(opts.inputState, pc.redactPii));
	if (opts.outputState != null && effectiveMode === "full") properties[PROP_OUTPUT_STATE] = serializeToJsonString(sanitizeStructuredContent(opts.outputState, pc.redactPii));
	const event = {
		event_type: EVENT_SPAN,
		user_id: opts.userId || void 0,
		device_id: opts.deviceId || void 0,
		event_properties: properties
	};
	if (opts.groups) event.groups = opts.groups;
	applyBrowserSessionId(event, opts.browserSessionId);
	try {
		opts.amplitude.track(event);
		getLogger(opts.amplitude).debug(`Tracked ${EVENT_SPAN} for user ${opts.userId}`);
	} catch (e) {
		getLogger(opts.amplitude).error(`Failed to track ${EVENT_SPAN}: ${e}`);
	}
	return spanId;
}
function trackSessionEnd(opts) {
	if ((opts.privacyConfig ?? new PrivacyConfig()).validate) {
		validateIdentity(opts.userId, opts.deviceId);
		validateRequiredStr(opts.sessionId, "sessionId");
	}
	const properties = withSdkManagedProperties(opts.eventProperties, {
		[PROP_SESSION_ID]: opts.sessionId,
		[PROP_SDK_VERSION]: SDK_VERSION,
		[PROP_RUNTIME]: SDK_RUNTIME
	});
	if (opts.traceId != null) properties[PROP_TRACE_ID] = opts.traceId;
	if (opts.turnId != null) properties[PROP_TURN_ID] = opts.turnId;
	if (opts.agentId) properties[PROP_AGENT_ID] = opts.agentId;
	if (opts.parentAgentId) properties[PROP_PARENT_AGENT_ID] = opts.parentAgentId;
	if (opts.customerOrgId) properties[PROP_CUSTOMER_ORG_ID] = opts.customerOrgId;
	if (opts.agentVersion) properties[PROP_AGENT_VERSION] = opts.agentVersion;
	if (opts.description) properties[PROP_AGENT_DESCRIPTION] = opts.description;
	if (opts.context) properties[PROP_CONTEXT] = serializeToJsonString(opts.context);
	if (opts.env) properties[PROP_ENV] = opts.env;
	if (opts.abandonmentTurn != null) properties[PROP_ABANDONMENT_TURN] = opts.abandonmentTurn;
	if (opts.idleTimeoutMinutes != null) properties[PROP_IDLE_TIMEOUT_MINUTES] = opts.idleTimeoutMinutes;
	if (opts.enrichments != null) properties[PROP_ENRICHMENTS] = serializeToJsonString(typeof opts.enrichments.toDict === "function" ? opts.enrichments.toDict() : opts.enrichments);
	const event = {
		event_type: EVENT_SESSION_END,
		user_id: opts.userId || void 0,
		device_id: opts.deviceId || void 0,
		event_properties: properties
	};
	if (opts.groups) event.groups = opts.groups;
	applyBrowserSessionId(event, opts.browserSessionId);
	try {
		opts.amplitude.track(event);
		getLogger(opts.amplitude).debug(`Tracked ${EVENT_SESSION_END} for user ${opts.userId}`);
	} catch (e) {
		getLogger(opts.amplitude).error(`Failed to track ${EVENT_SESSION_END}: ${e}`);
	}
}
function trackSessionEnrichment(opts) {
	if ((opts.privacyConfig ?? new PrivacyConfig()).validate) {
		validateIdentity(opts.userId, opts.deviceId);
		validateRequiredStr(opts.sessionId, "sessionId");
	}
	const properties = withSdkManagedProperties(opts.eventProperties, {
		[PROP_SESSION_ID]: opts.sessionId,
		[PROP_SDK_VERSION]: SDK_VERSION,
		[PROP_RUNTIME]: SDK_RUNTIME
	});
	if (opts.traceId != null) properties[PROP_TRACE_ID] = opts.traceId;
	if (opts.turnId != null) properties[PROP_TURN_ID] = opts.turnId;
	if (opts.agentId) properties[PROP_AGENT_ID] = opts.agentId;
	if (opts.parentAgentId) properties[PROP_PARENT_AGENT_ID] = opts.parentAgentId;
	if (opts.customerOrgId) properties[PROP_CUSTOMER_ORG_ID] = opts.customerOrgId;
	if (opts.agentVersion) properties[PROP_AGENT_VERSION] = opts.agentVersion;
	if (opts.description) properties[PROP_AGENT_DESCRIPTION] = opts.description;
	if (opts.context) properties[PROP_CONTEXT] = serializeToJsonString(opts.context);
	if (opts.env) properties[PROP_ENV] = opts.env;
	properties[PROP_ENRICHMENTS] = serializeToJsonString(typeof opts.enrichments.toDict === "function" ? opts.enrichments.toDict() : opts.enrichments);
	const event = {
		event_type: EVENT_SESSION_ENRICHMENT,
		user_id: opts.userId || void 0,
		device_id: opts.deviceId || void 0,
		event_properties: properties
	};
	if (opts.groups) event.groups = opts.groups;
	applyBrowserSessionId(event, opts.browserSessionId);
	try {
		opts.amplitude.track(event);
		getLogger(opts.amplitude).debug(`Tracked ${EVENT_SESSION_ENRICHMENT} for user ${opts.userId}`);
	} catch (e) {
		getLogger(opts.amplitude).error(`Failed to track ${EVENT_SESSION_ENRICHMENT}: ${e}`);
	}
}
function trackScore(opts) {
	const pc = opts.privacyConfig ?? new PrivacyConfig();
	if (pc.validate) {
		validateIdentity(opts.userId, opts.deviceId);
		validateNumeric(opts.value, "value");
	}
	const properties = withSdkManagedProperties(opts.eventProperties, {
		[PROP_SCORE_NAME]: opts.name,
		[PROP_SCORE_VALUE]: opts.value,
		[PROP_TARGET_ID]: opts.targetId,
		[PROP_TARGET_TYPE]: opts.targetType ?? "message",
		[PROP_EVALUATION_SOURCE]: opts.source ?? "user",
		[PROP_SDK_VERSION]: SDK_VERSION,
		[PROP_RUNTIME]: SDK_RUNTIME
	});
	if (opts.sessionId) properties[PROP_SESSION_ID] = opts.sessionId;
	if (opts.traceId != null) properties[PROP_TRACE_ID] = opts.traceId;
	if (opts.turnId != null) properties[PROP_TURN_ID] = opts.turnId;
	if (opts.agentId) properties[PROP_AGENT_ID] = opts.agentId;
	if (opts.parentAgentId) properties[PROP_PARENT_AGENT_ID] = opts.parentAgentId;
	if (opts.customerOrgId) properties[PROP_CUSTOMER_ORG_ID] = opts.customerOrgId;
	if (opts.agentVersion) properties[PROP_AGENT_VERSION] = opts.agentVersion;
	if (opts.description) properties[PROP_AGENT_DESCRIPTION] = opts.description;
	if (opts.context) properties[PROP_CONTEXT] = serializeToJsonString(opts.context);
	if (opts.env) properties[PROP_ENV] = opts.env;
	if (opts.comment != null) {
		const commentData = pc.sanitizeContent(opts.comment);
		if ("$llm_message" in commentData) {
			const msg = commentData.$llm_message;
			properties[PROP_COMMENT] = getTextFromLlmMessage(msg);
		}
	}
	const event = {
		event_type: EVENT_SCORE,
		user_id: opts.userId || void 0,
		device_id: opts.deviceId || void 0,
		event_properties: properties
	};
	if (opts.groups) event.groups = opts.groups;
	applyBrowserSessionId(event, opts.browserSessionId);
	try {
		opts.amplitude.track(event);
		getLogger(opts.amplitude).debug(`Tracked ${EVENT_SCORE} for user ${opts.userId}`);
	} catch (e) {
		getLogger(opts.amplitude).error(`Failed to track ${EVENT_SCORE}: ${e}`);
	}
}

//#endregion
export { EVENT_AI_RESPONSE, EVENT_EMBEDDING, EVENT_SCORE, EVENT_SESSION_END, EVENT_SESSION_ENRICHMENT, EVENT_SPAN, EVENT_TOOL_CALL, EVENT_USER_MESSAGE, MAX_SERIALIZED_LENGTH, PROP_ABANDONMENT_TURN, PROP_AGENT_CHAIN, PROP_AGENT_DESCRIPTION, PROP_AGENT_ID, PROP_AGENT_VERSION, PROP_ATTACHMENTS, PROP_ATTACHMENT_COUNT, PROP_ATTACHMENT_TYPES, PROP_CACHE_CREATION_TOKENS, PROP_CACHE_READ_TOKENS, PROP_COMMENT, PROP_COMPONENT_TYPE, PROP_CONTEXT, PROP_COST_USD, PROP_CUSTOMER_ORG_ID, PROP_EDITED_MESSAGE_ID, PROP_EMBEDDING_DIMENSIONS, PROP_ENRICHMENTS, PROP_ENV, PROP_ERROR_MESSAGE, PROP_ERROR_SOURCE, PROP_ERROR_TYPE, PROP_EVALUATION_SOURCE, PROP_FINISH_REASON, PROP_GIT_REF, PROP_GIT_REPO, PROP_GIT_SHA, PROP_HAS_ATTACHMENTS, PROP_HAS_REASONING, PROP_IDLE_TIMEOUT_MINUTES, PROP_INPUT_STATE, PROP_INPUT_TOKENS, PROP_INVOCATION_ID, PROP_IS_EDIT, PROP_IS_ERROR, PROP_IS_REGENERATION, PROP_IS_STREAMING, PROP_LATENCY_MS, PROP_LOCALE, PROP_MAX_OUTPUT_TOKENS, PROP_MESSAGE_ID, PROP_MESSAGE_LABELS, PROP_MESSAGE_LABEL_MAP, PROP_MESSAGE_SOURCE, PROP_MODEL_NAME, PROP_MODEL_TIER, PROP_OUTPUT_STATE, PROP_OUTPUT_TOKENS, PROP_PARENT_AGENT_ID, PROP_PARENT_MESSAGE_ID, PROP_PARENT_SPAN_ID, PROP_PROMPT_ID, PROP_PROVIDER, PROP_QUALITY_SCORE, PROP_REASONING_CONTENT, PROP_REASONING_TOKENS, PROP_REQUEST_COMPLEXITY, PROP_ROOT_AGENT_NAME, PROP_RUNTIME, PROP_SCORE_NAME, PROP_SCORE_VALUE, PROP_SDK_VERSION, PROP_SENTIMENT_SCORE, PROP_SESSION_ID, PROP_SESSION_REPLAY_ID, PROP_SPAN_ID, PROP_SPAN_KIND, PROP_SPAN_NAME, PROP_STACK_TRACE, PROP_SYSTEM_PROMPT, PROP_SYSTEM_PROMPT_LENGTH, PROP_TAGS, PROP_TARGET_ID, PROP_TARGET_TYPE, PROP_TASK_FAILURE_REASON, PROP_TASK_FAILURE_TYPE, PROP_TEMPERATURE, PROP_TOOL_CALLS, PROP_TOOL_DEFINITIONS, PROP_TOOL_DEFINITIONS_COUNT, PROP_TOOL_DEFINITIONS_HASH, PROP_TOOL_INPUT, PROP_TOOL_NAME, PROP_TOOL_OUTPUT, PROP_TOOL_OWNER, PROP_TOOL_SUCCESS, PROP_TOOL_TYPE, PROP_TOP_P, PROP_TOTAL_ATTACHMENT_SIZE, PROP_TOTAL_TOKENS, PROP_TRACE_ID, PROP_TTFB_MS, PROP_TURN_ID, PROP_WAS_CACHED, PROP_WAS_COPIED, SDK_RUNTIME, SDK_VERSION, serializeToJsonString, trackAiMessage, trackConversation, trackEmbedding, trackScore, trackSessionEnd, trackSessionEnrichment, trackSpan, trackToolCall, trackUserMessage };
//# sourceMappingURL=tracking.js.map