import runDbClient_default from "../../../data/db/runDbClient.js";
import { getLogger as getLogger$1 } from "../../../logger.js";
import { toolSessionManager } from "../agents/services/ToolSessionManager.js";
import { detectOversizedArtifact } from "../artifacts/artifact-utils.js";
import { getCompressionConfigForModel, getModelContextWindow } from "../utils/model-context-utils.js";
import { distillConversation } from "../tools/distill-conversation-tool.js";
import { tracer } from "../utils/tracer.js";
import { agentSessionManager } from "../session/AgentSession.js";
import { GENERATION_TYPES, SPAN_KEYS, estimateTokens, getLedgerArtifacts, updateLedgerArtifactParts } from "@inkeep/agents-core";
import { SpanStatusCode } from "@opentelemetry/api";
import { randomUUID } from "node:crypto";

//#region src/domains/run/compression/BaseCompressor.ts
const logger = getLogger$1("BaseCompressor");
function stripStructureHints(value) {
	if (typeof value === "string") try {
		return stripStructureHints(JSON.parse(value));
	} catch {
		return value;
	}
	if (value && typeof value === "object" && !Array.isArray(value)) {
		const { _structureHints, ...rest } = value;
		return rest;
	}
	return value;
}
var BaseCompressor = class {
	processedToolCalls = /* @__PURE__ */ new Set();
	cumulativeSummary = null;
	contextWindowSize;
	toolCallInputMap = /* @__PURE__ */ new Map();
	constructor(sessionId, conversationId, tenantId, projectId, agentId, config, summarizerModel, baseModel) {
		this.sessionId = sessionId;
		this.conversationId = conversationId;
		this.tenantId = tenantId;
		this.projectId = projectId;
		this.agentId = agentId;
		this.config = config;
		this.summarizerModel = summarizerModel;
		this.baseModel = baseModel;
		if (baseModel) this.contextWindowSize = getModelContextWindow(baseModel).contextWindow ?? void 0;
	}
	getHardLimit() {
		return this.config.hardLimit;
	}
	estimateTokens(content) {
		return estimateTokens(typeof content === "string" ? content : JSON.stringify(content));
	}
	calculateContextSize(messages) {
		return messages.reduce((total, msg) => {
			if (Array.isArray(msg.content)) {
				for (const block of msg.content) if (block.type === "text") total += this.estimateTokens(block.text || "");
				else if (block.type === "tool-call") total += this.estimateTokens(JSON.stringify({
					toolCallId: block.toolCallId,
					toolName: block.toolName,
					input: block.input
				}));
				else if (block.type === "tool-result") total += this.estimateTokens(JSON.stringify({
					toolCallId: block.toolCallId,
					toolName: block.toolName,
					output: block.output
				}));
			} else if (typeof msg.content === "string") total += this.estimateTokens(msg.content);
			else if (msg.content) total += this.estimateTokens(JSON.stringify(msg.content));
			return total;
		}, 0);
	}
	async saveToolResultsAsArtifacts(messages, startIndex = 0) {
		const session = agentSessionManager.getSession(this.sessionId);
		if (!session) throw new Error(`No session found: ${this.sessionId}`);
		const messagesToProcess = messages.slice(startIndex);
		this.toolCallInputMap = /* @__PURE__ */ new Map();
		for (const message of messagesToProcess) if (Array.isArray(message.content)) {
			for (const block of message.content) if (block.type === "tool-call" && block.toolCallId != null) this.toolCallInputMap.set(block.toolCallId, block.input);
		}
		const toolCallIds = this.extractToolCallIds(messagesToProcess);
		const existingArtifacts = await this.findExistingArtifacts([...new Set(toolCallIds)]);
		const toolCallToArtifactMap = {};
		for (const message of messagesToProcess) {
			this.convertDatabaseFormatMessage(message);
			if (Array.isArray(message.content)) {
				for (const block of message.content) if (block.type === "tool-result") {
					const artifactInfo = await this.processToolResult(block, session, existingArtifacts);
					if (artifactInfo) toolCallToArtifactMap[block.toolCallId] = artifactInfo;
				}
			}
		}
		return toolCallToArtifactMap;
	}
	async findExistingArtifacts(toolCallIds) {
		const result = /* @__PURE__ */ new Map();
		if (toolCallIds.length === 0) return result;
		try {
			const artifacts = await getLedgerArtifacts(runDbClient_default)({
				scopes: {
					tenantId: this.tenantId,
					projectId: this.projectId
				},
				toolCallIds
			});
			for (const artifact of artifacts) if (artifact.toolCallId) {
				const dataPart = artifact.parts?.find((p) => p.kind === "data");
				result.set(artifact.toolCallId, {
					artifactId: artifact.artifactId,
					isOversized: artifact.metadata?.isOversized ?? false,
					toolArgs: artifact.metadata?.toolArgs,
					toolName: artifact.metadata?.toolName,
					summaryData: dataPart?.data?.summary ?? dataPart?.data,
					name: artifact.name,
					description: artifact.description
				});
			}
		} catch (error) {
			logger.warn({
				sessionId: this.sessionId,
				toolCallCount: toolCallIds.length,
				error: error instanceof Error ? error.message : String(error)
			}, "Artifact batch lookup failed — existing artifacts may not be reused");
		}
		return result;
	}
	convertDatabaseFormatMessage(message) {
		if (message.messageType === "tool-result" && !Array.isArray(message.content) && message.content?.text) {
			const toolName = message.metadata?.a2a_metadata?.toolName;
			const toolCallId = message.metadata?.a2a_metadata?.toolCallId;
			if (this.shouldSkipToolCall(toolName)) return;
			if (toolName && toolCallId) {
				const a2a = message.metadata?.a2a_metadata;
				message.content = [{
					type: "tool-result",
					toolCallId,
					toolName,
					input: a2a?.toolArgs ?? null,
					output: a2a?.toolOutput ?? message.content.text
				}];
			}
		}
	}
	async processToolResult(block, session, existingArtifacts) {
		if (this.shouldSkipToolCall(block.toolName)) {
			this.processedToolCalls.add(block.toolCallId);
			return null;
		}
		if (this.processedToolCalls.has(block.toolCallId)) return null;
		const existing = existingArtifacts.get(block.toolCallId);
		if (existing) {
			this.processedToolCalls.add(block.toolCallId);
			return {
				artifactId: existing.artifactId,
				isOversized: existing.isOversized,
				toolArgs: existing.toolArgs,
				summaryData: existing.summaryData,
				name: existing.name,
				description: existing.description
			};
		}
		return await this.createNewArtifact(block, session);
	}
	shouldSkipToolCall(toolName) {
		return toolName === "get_reference_artifact" || toolName === "load_skill" || toolName === "thinking_complete" || toolName?.includes("save_tool_result") || toolName?.startsWith("transfer_to_");
	}
	extractToolCallIds(messages) {
		const toolCallIds = [];
		for (const message of messages) {
			if (message.messageType === "tool-result" && !Array.isArray(message.content)) {
				const toolCallId = message.metadata?.a2a_metadata?.toolCallId;
				if (toolCallId && !this.shouldSkipToolCall(message.metadata?.a2a_metadata?.toolName)) toolCallIds.push(toolCallId);
			}
			if (Array.isArray(message.content)) {
				for (const block of message.content) if (block.type === "tool-result" && !this.shouldSkipToolCall(block.toolName)) toolCallIds.push(block.toolCallId);
			}
		}
		return toolCallIds;
	}
	isEmpty(data) {
		if (!data.toolResult) return true;
		if (typeof data.toolResult === "object" && Object.keys(data.toolResult).length === 0) return true;
		return false;
	}
	buildArtifactData(artifactId, block, toolResultData) {
		const toolInput = block.input ?? this.toolCallInputMap.get(block.toolCallId) ?? null;
		const oversized = detectOversizedArtifact(toolResultData, this.contextWindowSize, {
			artifactId,
			toolCallId: block.toolCallId,
			toolName: block.toolName
		});
		const summaryData = {
			toolCallId: block.toolCallId,
			toolName: block.toolName,
			toolInput: this.generatePreview(toolInput),
			resultPreview: this.generatePreview(toolResultData.toolResult),
			note: `Tool result from ${block.toolName} - compressed to save context space`
		};
		if (oversized.isOversized) {
			summaryData._oversizedWarning = oversized.oversizedWarning;
			summaryData._structureInfo = oversized.structureInfo;
		}
		return {
			artifactId,
			taskId: `task_${this.conversationId}-${this.sessionId}`,
			toolCallId: block.toolCallId,
			artifactType: "tool_result",
			pendingGeneration: true,
			tenantId: this.tenantId,
			projectId: this.projectId,
			contextId: this.conversationId,
			subAgentId: this.sessionId,
			metadata: {
				toolCallId: block.toolCallId,
				toolName: block.toolName,
				toolArgs: toolInput ?? null,
				compressionReason: this.getCompressionType(),
				isOversized: oversized.isOversized,
				originalTokenSize: oversized.originalTokenSize,
				contextWindowSize: oversized.contextWindowSize,
				retrievalBlocked: oversized.retrievalBlocked
			},
			summaryData,
			data: toolResultData
		};
	}
	async createNewArtifact(block, session) {
		const artifactId = `compress_${block.toolName || "tool"}_${block.toolCallId || Date.now()}_${randomUUID().slice(0, 8)}`;
		const toolInput = block.input ?? this.toolCallInputMap.get(block.toolCallId) ?? null;
		const toolResult = toolSessionManager.getToolResult(this.sessionId, block.toolCallId)?.result ?? stripStructureHints(block.output);
		const toolResultData = {
			toolName: block.toolName,
			toolInput,
			toolResult,
			compressedAt: (/* @__PURE__ */ new Date()).toISOString()
		};
		if (this.isEmpty(toolResultData)) return null;
		const artifactData = this.buildArtifactData(artifactId, block, toolResultData);
		session.recordEvent("artifact_saved", this.sessionId, artifactData);
		this.processedToolCalls.add(block.toolCallId);
		return {
			artifactId,
			isOversized: artifactData.metadata.isOversized,
			toolArgs: artifactData.metadata.toolArgs ?? void 0,
			structureInfo: artifactData.summaryData._structureInfo,
			oversizedWarning: artifactData.summaryData._oversizedWarning,
			summaryData: artifactData.summaryData
		};
	}
	formatMessagesForDistillation(messages, toolCallToArtifactMap, maxTotalChars) {
		let nonToolResultChars = 0;
		let numToolResults = 0;
		for (const msg of messages) if (typeof msg.content === "string") nonToolResultChars += msg.content.length;
		else if (Array.isArray(msg.content)) {
			for (const block of msg.content) if (block.type === "text") nonToolResultChars += (block.text || "").length;
			else if (block.type === "tool-call") nonToolResultChars += JSON.stringify(block.input || {}).length + (block.toolName || "").length;
			else if (block.type === "tool-result" && toolCallToArtifactMap?.[block.toolCallId]) numToolResults++;
		} else if (msg.content?.text) nonToolResultChars += msg.content.text.length;
		const perResultLimit = maxTotalChars && numToolResults > 0 ? Math.max(200, Math.floor((maxTotalChars - nonToolResultChars) / numToolResults)) : maxTotalChars;
		return messages.map((msg) => {
			const parts = [];
			if (typeof msg.content === "string") parts.push(msg.content);
			else if (Array.isArray(msg.content)) {
				for (const block of msg.content) if (block.type === "text") parts.push(block.text);
				else if (block.type === "tool-call") parts.push(`[TOOL CALL] ${block.toolName}(${JSON.stringify(block.input)}) [ID: ${block.toolCallId}]`);
				else if (block.type === "tool-result") {
					const artifactInfo = toolCallToArtifactMap?.[block.toolCallId];
					if (artifactInfo) {
						const header = artifactInfo.name ? `[TOOL RESULT] ${block.toolName} [ARTIFACT: ${artifactInfo.artifactId}] "${artifactInfo.name}"` : `[TOOL RESULT] ${block.toolName} [ARTIFACT: ${artifactInfo.artifactId}]`;
						const descriptionLine = artifactInfo.description ? `Description: ${artifactInfo.description}\n` : "";
						const summary = artifactInfo.summaryData ? JSON.stringify(artifactInfo.summaryData) : "";
						const truncated = perResultLimit && summary.length > perResultLimit ? `${summary.slice(0, perResultLimit)}...` : summary;
						parts.push(`${header}\n${descriptionLine}${truncated}`);
					} else logger.debug({
						toolCallId: block.toolCallId,
						toolName: block.toolName
					}, "Skipping tool result without artifact mapping in distillation");
				}
			} else if (msg.content?.text) parts.push(msg.content.text);
			return parts.length > 0 ? `${msg.role || "system"}: ${parts.join("\n")}` : "";
		}).filter((line) => line.trim().length > 0).join("\n\n");
	}
	async createConversationSummary(messages, toolCallToArtifactMap, compressionCycle = 0) {
		const oversizedArtifacts = Object.values(toolCallToArtifactMap).filter((a) => a.isOversized);
		if (oversizedArtifacts.length > 0) logger.warn({
			sessionId: this.sessionId,
			oversizedArtifacts: oversizedArtifacts.map((a) => ({
				artifactId: a.artifactId,
				oversizedWarning: a.oversizedWarning
			}))
		}, "Distilling conversation with oversized artifacts — warning may not reach agent");
		const currentSummary = await this.refreshSummaryArtifactNames();
		const summary = await distillConversation({
			conversationId: this.conversationId,
			currentSummary,
			summarizerModel: this.summarizerModel,
			messageFormatter: (maxChars) => this.formatMessagesForDistillation(messages, toolCallToArtifactMap, maxChars),
			compressionCycle,
			usageContext: {
				tenantId: this.tenantId,
				projectId: this.projectId,
				agentId: this.agentId,
				generationType: GENERATION_TYPES.MID_GENERATION_COMPRESSION
			}
		});
		logger.info({
			sessionId: this.sessionId,
			highLevel: summary.high_level,
			nextStepsForAgent: summary.next_steps?.for_agent,
			relatedArtifacts: summary.related_artifacts?.map((a) => ({
				id: a.id,
				name: a.name,
				keyFindings: a.key_findings
			}))
		}, "Distillation summary produced");
		this.cumulativeSummary = summary;
		if (summary.related_artifacts?.length) try {
			const persistResult = await this.persistArtifactKeyFindings(summary.related_artifacts);
			logger.debug({
				...persistResult,
				conversationId: this.conversationId
			}, "Artifact key_findings persistence completed");
		} catch (err) {
			logger.warn({
				conversationId: this.conversationId,
				artifactIds: summary.related_artifacts.map((a) => a.id),
				err: err instanceof Error ? err.message : String(err)
			}, "Failed to persist key_findings to artifacts");
		}
		return summary;
	}
	async refreshSummaryArtifactNames() {
		if (!this.cumulativeSummary?.related_artifacts?.length) return this.cumulativeSummary;
		const toolCallIds = this.cumulativeSummary.related_artifacts.filter((a) => !!a.tool_call_id).map((a) => a.tool_call_id);
		if (!toolCallIds.length) return this.cumulativeSummary;
		try {
			const artifacts = await getLedgerArtifacts(runDbClient_default)({
				scopes: {
					tenantId: this.tenantId,
					projectId: this.projectId
				},
				toolCallIds
			});
			if (!artifacts.length) return this.cumulativeSummary;
			const nameMap = new Map(artifacts.filter((a) => a.toolCallId && (a.name || a.description)).map((a) => [a.toolCallId, {
				name: a.name,
				description: a.description
			}]));
			return {
				...this.cumulativeSummary,
				related_artifacts: this.cumulativeSummary.related_artifacts.map((a) => {
					const db = nameMap.get(a.tool_call_id);
					return db ? {
						...a,
						name: db.name ?? a.name,
						...db.description ? { description: db.description } : {}
					} : a;
				})
			};
		} catch (error) {
			logger.warn({
				sessionId: this.sessionId,
				error: error instanceof Error ? error.message : String(error)
			}, "Failed to refresh artifact names from DB, using cached summary");
			return this.cumulativeSummary;
		}
	}
	generatePreview(value, maxChars = 150) {
		if (value == null) return null;
		try {
			const str = typeof value === "string" ? value : JSON.stringify(value);
			return str.length > maxChars ? `${str.slice(0, maxChars).replace(/\s+/g, " ").trim()}...` : str.replace(/\s+/g, " ").trim();
		} catch {
			return null;
		}
	}
	recordCompressionEvent(eventData) {
		const session = agentSessionManager.getSession(this.sessionId);
		if (session) session.recordEvent("compression", this.sessionId, eventData);
	}
	getCompressionSummary() {
		return this.cumulativeSummary;
	}
	hasSummarizedArtifact(artifactId) {
		return this.cumulativeSummary?.related_artifacts?.some((a) => a.id === artifactId) ?? false;
	}
	getSummarizedArtifact(artifactId) {
		const artifact = this.cumulativeSummary?.related_artifacts?.find((a) => a.id === artifactId);
		if (!artifact) return null;
		return {
			key_findings: artifact.key_findings,
			tool_call_id: artifact.tool_call_id
		};
	}
	async persistArtifactKeyFindings(relatedArtifacts) {
		const result = {
			persisted: 0,
			skipped: 0,
			failed: 0
		};
		const scopes = {
			tenantId: this.tenantId,
			projectId: this.projectId
		};
		const artifactsWithFindings = relatedArtifacts.filter((a) => a.key_findings?.length);
		result.skipped += relatedArtifacts.length - artifactsWithFindings.length;
		if (artifactsWithFindings.length === 0) return result;
		const fetchResults = await Promise.allSettled(artifactsWithFindings.map((artifact) => getLedgerArtifacts(runDbClient_default)({
			scopes,
			artifactId: artifact.id
		}).then((existing) => ({
			artifact,
			existing
		}))));
		const updates = [];
		for (const settled of fetchResults) {
			if (settled.status === "rejected") {
				result.failed++;
				logger.warn({
					conversationId: this.conversationId,
					error: String(settled.reason)
				}, "Failed to fetch artifact for key_findings persistence");
				continue;
			}
			const { artifact, existing } = settled.value;
			if (existing.length === 0) {
				logger.debug({ artifactId: artifact.id }, "Artifact not found in DB, skipping key_findings persistence");
				result.skipped++;
				continue;
			}
			const parts = structuredClone(existing[0].parts ?? []);
			const firstPart = parts[0];
			if (!firstPart || firstPart.kind !== "data" || !firstPart.data?.summary) {
				logger.debug({
					artifactId: artifact.id,
					hasParts: parts.length > 0
				}, "Artifact has no data part with summary structure, skipping key_findings persistence");
				result.skipped++;
				continue;
			}
			firstPart.data.summary = {
				...firstPart.data.summary,
				key_findings: artifact.key_findings
			};
			updates.push({
				artifact,
				parts
			});
		}
		const updateResults = await Promise.allSettled(updates.map(({ artifact, parts }) => updateLedgerArtifactParts(runDbClient_default)({
			scopes,
			artifactId: artifact.id,
			parts
		}).then((updated) => ({
			artifact,
			updated
		}))));
		for (const settled of updateResults) {
			if (settled.status === "rejected") {
				result.failed++;
				logger.warn({
					conversationId: this.conversationId,
					error: String(settled.reason)
				}, "Failed to persist key_findings to artifact");
				continue;
			}
			const { artifact, updated } = settled.value;
			if (updated) result.persisted++;
			else {
				logger.warn({ artifactId: artifact.id }, "updateLedgerArtifactParts matched no rows");
				result.failed++;
			}
		}
		return result;
	}
	cleanup(options = {}) {
		const { resetSummary = false, keepRecentToolCalls = 0 } = options;
		if (keepRecentToolCalls > 0) this.processedToolCalls = new Set(Array.from(this.processedToolCalls).slice(-keepRecentToolCalls));
		else this.processedToolCalls.clear();
		if (resetSummary) this.cumulativeSummary = null;
	}
	partialCleanup() {
		this.cleanup({ keepRecentToolCalls: 50 });
	}
	fullCleanup() {
		this.cleanup({ resetSummary: true });
	}
	getState() {
		return {
			config: this.config,
			processedToolCalls: Array.from(this.processedToolCalls),
			cumulativeSummary: this.cumulativeSummary
		};
	}
	async safeCompress(messages, fullContextSize) {
		const hardLimit = this.getHardLimit();
		const triggerAt = hardLimit - this.config.safetyBuffer;
		const generatedTokens = this.calculateContextSize(messages);
		const totalContextTokens = fullContextSize ?? generatedTokens;
		const baseContextTokens = totalContextTokens - generatedTokens;
		return await tracer.startActiveSpan("compressor.safe_compress", { attributes: {
			[SPAN_KEYS.COMPRESSION_TYPE]: this.getCompressionType(),
			[SPAN_KEYS.COMPRESSION_SESSION_ID]: this.sessionId,
			[SPAN_KEYS.COMPRESSION_MESSAGE_COUNT]: messages.length,
			[SPAN_KEYS.COMPRESSION_BASE_CONTEXT_TOKENS]: baseContextTokens,
			[SPAN_KEYS.COMPRESSION_GENERATED_TOKENS]: generatedTokens,
			[SPAN_KEYS.COMPRESSION_TOTAL_CONTEXT_TOKENS]: totalContextTokens,
			[SPAN_KEYS.COMPRESSION_HARD_LIMIT]: hardLimit,
			[SPAN_KEYS.COMPRESSION_TRIGGER_AT]: triggerAt,
			[SPAN_KEYS.COMPRESSION_SAFETY_BUFFER]: this.config.safetyBuffer,
			[SPAN_KEYS.COMPRESSION_OVERAGE]: totalContextTokens - triggerAt
		} }, async (compressionSpan) => {
			try {
				const result = await this.compress(messages);
				const resultTokens = Array.isArray(result.summary) ? this.calculateContextSize(result.summary) : this.estimateTokens(result.summary);
				const summary = Array.isArray(result.summary) ? null : result.summary;
				compressionSpan.setAttributes({
					[SPAN_KEYS.COMPRESSION_SUCCESS]: true,
					[SPAN_KEYS.COMPRESSION_RESULT_ARTIFACT_COUNT]: result.artifactIds.length,
					[SPAN_KEYS.COMPRESSION_RESULT_ARTIFACT_IDS]: result.artifactIds.join(","),
					[SPAN_KEYS.COMPRESSION_RESULT_OUTPUT_TOKENS]: resultTokens,
					[SPAN_KEYS.COMPRESSION_RESULT_COMPRESSION_RATIO]: generatedTokens > 0 ? (generatedTokens - resultTokens) / generatedTokens : 0,
					[SPAN_KEYS.COMPRESSION_RESULT_HIGH_LEVEL]: summary?.high_level ?? "",
					[SPAN_KEYS.COMPRESSION_RESULT_USER_INTENT]: summary?.user_intent ?? "",
					[SPAN_KEYS.COMPRESSION_RESULT_DECISIONS_COUNT]: summary?.decisions?.length ?? 0,
					[SPAN_KEYS.COMPRESSION_RESULT_NEXT_STEPS_FOR_AGENT_COUNT]: summary?.next_steps?.for_agent?.length ?? 0,
					[SPAN_KEYS.COMPRESSION_RESULT_OPEN_QUESTIONS_COUNT]: summary?.open_questions?.length ?? 0,
					[SPAN_KEYS.COMPRESSION_RESULT_RELATED_ARTIFACT_COUNT]: summary?.related_artifacts?.length ?? 0
				});
				compressionSpan.setStatus({ code: SpanStatusCode.OK });
				return result;
			} catch (error) {
				logger.error({
					sessionId: this.sessionId,
					conversationId: this.conversationId,
					error: error instanceof Error ? error.message : String(error),
					stack: error instanceof Error ? error.stack : void 0
				}, "Compression failed, using simple fallback");
				compressionSpan.setAttributes({ [SPAN_KEYS.COMPRESSION_ERROR]: error instanceof Error ? error.message : String(error) });
				try {
					const fallbackResult = await this.simpleCompressionFallback(messages);
					const fallbackTokens = Array.isArray(fallbackResult.summary) ? this.calculateContextSize(fallbackResult.summary) : this.estimateTokens(fallbackResult.summary);
					compressionSpan.setAttributes({
						[SPAN_KEYS.COMPRESSION_SUCCESS]: true,
						[SPAN_KEYS.COMPRESSION_RESULT_ARTIFACT_COUNT]: fallbackResult.artifactIds.length,
						[SPAN_KEYS.COMPRESSION_RESULT_ARTIFACT_IDS]: fallbackResult.artifactIds.join(","),
						[SPAN_KEYS.COMPRESSION_RESULT_OUTPUT_TOKENS]: fallbackTokens,
						[SPAN_KEYS.COMPRESSION_RESULT_COMPRESSION_RATIO]: generatedTokens > 0 ? (generatedTokens - fallbackTokens) / generatedTokens : 0
					});
					compressionSpan.setStatus({ code: SpanStatusCode.OK });
					return fallbackResult;
				} catch (fallbackError) {
					logger.error({
						sessionId: this.sessionId,
						error: fallbackError instanceof Error ? fallbackError.message : String(fallbackError)
					}, "Simple compression fallback also failed");
					compressionSpan.setAttributes({
						[SPAN_KEYS.COMPRESSION_SUCCESS]: false,
						[SPAN_KEYS.COMPRESSION_ERROR]: fallbackError instanceof Error ? fallbackError.message : String(fallbackError)
					});
					compressionSpan.setStatus({ code: SpanStatusCode.ERROR });
					throw fallbackError;
				}
			} finally {
				compressionSpan.end();
			}
		});
	}
	async simpleCompressionFallback(messages) {
		if (messages.length === 0) return {
			artifactIds: [],
			summary: []
		};
		const targetTokens = Math.floor(this.getHardLimit() * .5);
		let totalTokens = this.calculateContextSize(messages);
		if (totalTokens <= targetTokens) return {
			artifactIds: [],
			summary: messages
		};
		const result = [...messages];
		while (totalTokens > targetTokens && result.length > 1) {
			const dropped = result.shift();
			if (dropped) totalTokens -= this.estimateTokens(dropped);
		}
		logger.info({
			sessionId: this.sessionId,
			conversationId: this.conversationId,
			originalCount: messages.length,
			compressedCount: result.length
		}, "Simple compression fallback completed");
		return {
			artifactIds: [],
			summary: result
		};
	}
};
function getModelAwareCompressionConfig(modelSettings, targetPercentage) {
	const config = getCompressionConfigForModel(modelSettings, targetPercentage);
	return {
		hardLimit: config.hardLimit,
		safetyBuffer: config.safetyBuffer,
		enabled: config.enabled
	};
}

//#endregion
export { BaseCompressor, getModelAwareCompressionConfig };