import { i as redactSecrets } from "./redact-ClDPSbEB.js";
import { n as parseBooleanValue } from "./boolean-CrriykWV.js";
import { n as parseSqliteSessionFileMarker } from "./sqlite-marker-BejbySI1.js";
import { n as TRAJECTORY_RUNTIME_EVENT_MAX_BYTES } from "./paths-BnjVAz8z.js";
import { t as sanitizeDiagnosticPayload } from "./payload-redaction-DYka6NSX.js";
import { t as safeJsonStringify } from "./safe-json-CY5cd4H1.js";
import { t as appendSqliteTrajectoryRuntimeEvents } from "./runtime-store.sqlite-rSI_OCha.js";
//#region src/trajectory/runtime.ts
const TRAJECTORY_RUNTIME_DATA_STRING_MAX_CHARS = 32768;
const TRAJECTORY_RUNTIME_DATA_ARRAY_MAX_ITEMS = 64;
const TRAJECTORY_RUNTIME_DATA_OBJECT_MAX_KEYS = 64;
const TRAJECTORY_RUNTIME_DATA_MAX_DEPTH = 6;
const TRAJECTORY_RUNTIME_OVERSIZE_PRESERVED_DATA_KEYS = ["usage", "promptCache"];
function truncateOversizedTrajectoryEvent(event, line) {
	const bytes = Buffer.byteLength(line, "utf8");
	if (bytes <= 262144) return line;
	const originalData = event.data ?? {};
	const originalDataKeys = Object.keys(originalData);
	const preservedDataKeys = /* @__PURE__ */ new Set();
	const baseData = {
		truncated: true,
		originalBytes: bytes,
		limitBytes: TRAJECTORY_RUNTIME_EVENT_MAX_BYTES,
		reason: "trajectory-event-size-limit"
	};
	const buildTruncatedEventLine = (includeDroppedFields) => {
		const data = { ...baseData };
		for (const key of TRAJECTORY_RUNTIME_OVERSIZE_PRESERVED_DATA_KEYS) if (preservedDataKeys.has(key)) data[key] = originalData[key];
		if (includeDroppedFields) {
			const droppedFields = originalDataKeys.filter((key) => !preservedDataKeys.has(key));
			if (droppedFields.length > 0) data.droppedFields = droppedFields;
		}
		const truncated = safeJsonStringify({
			...event,
			data
		});
		if (truncated && Buffer.byteLength(truncated, "utf8") <= 262144) return truncated;
	};
	let best = buildTruncatedEventLine(true) ?? buildTruncatedEventLine(false);
	if (!best) return;
	for (const key of TRAJECTORY_RUNTIME_OVERSIZE_PRESERVED_DATA_KEYS) {
		if (!Object.hasOwn(originalData, key)) continue;
		preservedDataKeys.add(key);
		const next = buildTruncatedEventLine(true) ?? buildTruncatedEventLine(false);
		if (next) {
			best = next;
			continue;
		}
		preservedDataKeys.delete(key);
	}
	return best;
}
function truncatedTrajectoryValue(reason, details = {}) {
	return {
		truncated: true,
		reason,
		...details
	};
}
function limitTrajectoryPayloadValue(value, depth = 0, seen = /* @__PURE__ */ new WeakSet()) {
	if (typeof value === "string") {
		if (value.length > TRAJECTORY_RUNTIME_DATA_STRING_MAX_CHARS) return truncatedTrajectoryValue("trajectory-field-size-limit", {
			originalChars: value.length,
			limitChars: TRAJECTORY_RUNTIME_DATA_STRING_MAX_CHARS
		});
		return value;
	}
	if (typeof value !== "object" || value === null) return value;
	if (seen.has(value)) return truncatedTrajectoryValue("trajectory-circular-reference");
	if (depth >= TRAJECTORY_RUNTIME_DATA_MAX_DEPTH) return truncatedTrajectoryValue("trajectory-depth-limit", { limitDepth: TRAJECTORY_RUNTIME_DATA_MAX_DEPTH });
	seen.add(value);
	if (Array.isArray(value)) {
		const limited = value.slice(0, TRAJECTORY_RUNTIME_DATA_ARRAY_MAX_ITEMS).map((item) => limitTrajectoryPayloadValue(item, depth + 1, seen));
		if (value.length > TRAJECTORY_RUNTIME_DATA_ARRAY_MAX_ITEMS) limited.push(truncatedTrajectoryValue("trajectory-array-size-limit", {
			originalLength: value.length,
			limitItems: TRAJECTORY_RUNTIME_DATA_ARRAY_MAX_ITEMS
		}));
		seen.delete(value);
		return limited;
	}
	const record = value;
	const keys = Object.keys(record);
	const limited = {};
	for (const key of keys.slice(0, TRAJECTORY_RUNTIME_DATA_OBJECT_MAX_KEYS)) limited[key] = limitTrajectoryPayloadValue(record[key], depth + 1, seen);
	if (keys.length > TRAJECTORY_RUNTIME_DATA_OBJECT_MAX_KEYS) limited["_truncated"] = truncatedTrajectoryValue("trajectory-object-size-limit", {
		originalKeys: keys.length,
		limitKeys: TRAJECTORY_RUNTIME_DATA_OBJECT_MAX_KEYS
	});
	seen.delete(value);
	return limited;
}
function sanitizeTrajectoryPayload(data) {
	return redactSecrets(sanitizeDiagnosticPayload(limitTrajectoryPayloadValue(data)));
}
function describeTrajectoryWriterFlushState(writer) {
	const diagnostics = writer.describeQueue?.();
	if (!diagnostics) return;
	const parts = [
		`pendingWrites=${diagnostics.pendingWrites}`,
		`queuedBytes=${diagnostics.queuedBytes}`,
		`activeOperation=${diagnostics.activeOperation}`,
		`yieldBeforeWrite=${diagnostics.yieldBeforeWrite}`
	];
	if (diagnostics.activeWriteBytes !== void 0) parts.push(`activeWriteBytes=${diagnostics.activeWriteBytes}`);
	if (diagnostics.maxQueuedBytes !== void 0) parts.push(`maxQueuedBytes=${diagnostics.maxQueuedBytes}`);
	if (diagnostics.maxFileBytes !== void 0) parts.push(`maxFileBytes=${diagnostics.maxFileBytes}`);
	return parts.join(" ");
}
function createFileTrajectoryRuntimeSink(writer) {
	return {
		describeFlushState: () => describeTrajectoryWriterFlushState(writer),
		flush: async () => {
			await writer.flush();
		},
		nextSourceSeq: writer.nextSourceSeq,
		write: (_event, line) => {
			writer.write(`${line}\n`);
		}
	};
}
function createSqliteTrajectoryRuntimeSink(params) {
	const marker = parseSqliteSessionFileMarker(params.sessionFile);
	if (!marker || marker.sessionId !== params.sessionId) return null;
	let pendingEvents = [];
	let queuedBytes = 0;
	return {
		describeFlushState: () => pendingEvents.length > 0 ? `pendingRows=${pendingEvents.length} queuedBytes=${queuedBytes} activeOperation=sqlite-append` : void 0,
		flush: async () => {
			if (pendingEvents.length === 0) return;
			const events = pendingEvents;
			pendingEvents = [];
			queuedBytes = 0;
			appendSqliteTrajectoryRuntimeEvents({
				agentId: marker.agentId,
				env: params.env,
				maxRuntimeBytes: params.maxRuntimeFileBytes,
				sessionId: marker.sessionId,
				storePath: marker.storePath
			}, events);
		},
		write: (event, line) => {
			pendingEvents.push(event);
			queuedBytes += Buffer.byteLength(line, "utf8") + 1;
		}
	};
}
function toTrajectoryToolDefinitions(tools) {
	return tools.flatMap((tool) => {
		const name = tool.name?.trim();
		if (!name) return [];
		return [{
			name,
			description: tool.description,
			parameters: sanitizeDiagnosticPayload(limitTrajectoryPayloadValue(tool.parameters))
		}];
	}).toSorted((left, right) => left.name.localeCompare(right.name));
}
function createTrajectoryRuntimeRecorder(params) {
	const env = params.env ?? process.env;
	if (!(parseBooleanValue(env.OPENCLAW_TRAJECTORY) ?? true)) return null;
	const maxRuntimeFileBytes = Math.max(1, Math.floor(params.maxRuntimeFileBytes ?? 10485760));
	const sink = params.writer ? createFileTrajectoryRuntimeSink(params.writer) : createSqliteTrajectoryRuntimeSink({
		env,
		maxRuntimeFileBytes,
		sessionFile: params.sessionFile,
		sessionId: params.sessionId
	});
	if (!sink) return null;
	let seq = 0;
	const traceId = params.sessionId;
	const buildEvent = (type, data) => {
		const nextSeq = seq + 1;
		const sourceSeq = sink.nextSourceSeq?.() ?? nextSeq;
		const event = {
			traceSchema: "openclaw-trajectory",
			schemaVersion: 1,
			traceId,
			source: "runtime",
			type,
			ts: (/* @__PURE__ */ new Date()).toISOString(),
			seq: nextSeq,
			sourceSeq,
			sessionId: params.sessionId,
			sessionKey: params.sessionKey,
			runId: params.runId,
			workspaceDir: params.workspaceDir,
			provider: params.provider,
			modelId: params.modelId,
			modelApi: params.modelApi,
			data: data ? sanitizeTrajectoryPayload(data) : void 0
		};
		const line = safeJsonStringify(event);
		if (!line) return;
		const boundedLine = truncateOversizedTrajectoryEvent(event, line);
		if (!boundedLine) return;
		const boundedEvent = JSON.parse(boundedLine);
		seq = nextSeq;
		return {
			event: boundedEvent,
			line: boundedLine
		};
	};
	return {
		enabled: true,
		recordEvent: (type, data) => {
			const built = buildEvent(type, data);
			if (!built) return;
			sink.write(built.event, built.line);
		},
		flush: async () => {
			await sink.flush();
		},
		describeFlushState: () => sink.describeFlushState()
	};
}
//#endregion
export { toTrajectoryToolDefinitions as n, createTrajectoryRuntimeRecorder as t };
