UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

1,333 lines 52.4 kB
import { a as asOptionalRecord } from "./record-coerce-DItp3I4t.js";
import { n as normalizeAgentId } from "./agent-id-CeT3w4ap.js";
import { c as resolveAgentConfig } from "./agent-scope-config-DcbEhP0R.js";
import { _ as scopeLegacySessionKeyToAgent } from "./session-key-BnWWjqNc.js";
import { t as isIncognitoSessionKey } from "./incognito-session-key-BwpD1Lwd.js";
import { t as formatErrorMessage } from "./errors-Db3Ymjlb.js";
import { o as measureDiagnosticsTimelineSpan, s as measureDiagnosticsTimelineSpanSync } from "./diagnostics-timeline-CRX1LXmg.js";
import { b as findModelCatalogEntry } from "./model-selection-shared-BlLyx1r2.js";
import { _ as resolveSessionAgentId } from "./agent-scope-DbtJyKUL.js";
import { t as ErrorCodes } from "./gateway-error-details-w0nAGBBp.js";
import { G as validateChatMessageGetParams, J as validateChatStartupParams, K as validateChatMetadataParams, U as validateChatHistoryParams, W as validateChatInjectParams, Y as validateChatToolTitlesParams } from "./src-BiL5aQto.js";
import { d as errorShape } from "./error-codes-Bo8q2D1o.js";
import { n as CHAT_PENDING_INPUT_MESSAGE_PREFIX, t as CHAT_HISTORY_MAX_ENTRIES } from "./chat-history-constants-C-H8nkgi.js";
import { i as jsonUtf8BytesOrInfinity, r as jsonUtf8Bytes } from "./json-utf8-bytes-fm9i4b7G.js";
import "./model-catalog-DOgUhUHe.js";
import { $t as listSessionPendingInputs, M as isSessionTranscriptProjectionUnavailableError, Qt as listSessionPendingInputReceipts, en as readSessionPendingInput, ot as resolveSessionTranscriptActiveLeafEntryId } from "./session-accessor-YsytfDtG.js";
import { v as resolveSessionKeyBySessionId } from "./session-accessor.sqlite-entry-CWk3jL7s.js";
import { n as beginSessionWorkAdmission } from "./session-lifecycle-admission-CS8v45tk.js";
import { a as MAX_PAYLOAD_BYTES, u as getMaxChatHistoryMessagesBytes } from "./server-constants-BrVEC7RW.js";
import { t as resolveConfiguredThinkingDefault } from "./model-thinking-default-1g_x1V4J.js";
import { S as resolveActiveEmbeddedRunOwner, b as resolveActiveEmbeddedRunHandleSessionId } from "./runs-Cb42qain.js";
import "./sessions-9nxpeTwt.js";
import { f as resolveSessionWorkStartError } from "./lifecycle-BaroCBMc.js";
import { A as augmentChatHistoryWithCanvasBlocks, C as createCurrentUserProfileMessageProjector, O as dropPreSessionStartAnnouncePairs, S as resolveCurrentUserProfileDisplay, T as projectChatDisplayMessages, _ as ArchivedTranscriptReader, b as projectSessionMessagePayload, d as resolveTranscriptReadTarget, g as readTranscriptDisplayDelta, h as readSessionTranscriptHistoryAnchorPage, i as readSessionMessageByIdAsync, k as isHeartbeatHistoryTurnBoundaryMessage, o as readSessionMessagesAsync, p as toTranscriptReadScope, v as capArrayByJsonBytes, w as projectChatDisplayMessage, x as projectTranscriptEntryMessage } from "./session-transcript-readers-CYDRQsH5.js";
import { f as resolveEffectiveChatHistoryMaxChars } from "./chat-display-projection.helpers-DYkWC7LH.js";
import { n as resolveSessionModelRef } from "./session-model-ref-CPZiclLt.js";
import { t as getSessionDefaults } from "./session-utils-model-BYAclq2V.js";
import { i as buildGatewaySessionInfo } from "./session-utils-list-B0k8KJn5.js";
import { i as tryResolveSessionCompatibilityOwnerAgentId } from "./session-request-agent-CCRSEGCB.js";
import { i as loadGatewaySessionEntryReadOnly, r as loadGatewaySessionEntry } from "./session-utils-store-CInT2loy.js";
import "./session-utils-Cai0_C6U.js";
import { a as runWithCronCreatorAuthorityCapability, i as createCronCreatorAuthorityCapability } from "./cron-creator-authority-context-CkDgGats.js";
import { d as resolveInFlightRunSnapshot, o as projectInFlightRunSnapshot, r as boundInFlightRunSnapshotForChatHistory } from "./chat-abort-qLn3eFOg.js";
import { t as logLargePayload } from "./diagnostic-payload-B51qzY4j.js";
import { t as formatForLog } from "./ws-log-Dkg9wKNU.js";
import { l as resolveClaudeCliBindingSessionId } from "./cli-session-history.claude-5nFgZ0im.js";
import { n as resolveChatHistoryWithCliSessionImports, t as readChatHistoryCliSessionImportSnapshot } from "./cli-session-history-CfRW-vJa.js";
import { d as resolveRequestedChatAgentId, f as validateChatSelectedAgent, h as sendGlobalAwareNodeChatPayload, m as resolveGlobalAwareNodeChatDeliveryKeys, t as handleChatSend } from "./chat-send-handler-Dpw17Gmy.js";
import { n as readTranscriptDisplayPosition, t as composeTranscriptDisplay } from "./transcript-display-position-3BMmjSOO.js";
import { n as buildGatewaySessionSnapshot } from "./session-event-payload-COi33-eM.js";
import { t as resolveSessionKeyFromResolveParams } from "./sessions-resolve-CjCEkUZ8.js";
import { a as prepareSessionWorkspaceIcon } from "./workspace-icon-http-B9NCfRKP.js";
import { n as readChatHistoryMessageSeq, r as readIncrementalChatHistoryTail, t as dropChatHistoryOverreadContextMessage } from "./session-history-tail-BuFrV1Wb.js";
import { t as ModelAccountConnectAuthorityError } from "./model-account-connect-BqlZBB8r.js";
import { t as resolveAgentIdOrRespondError } from "./agent-id-shared-MLgRqPvR.js";
import { n as resolveAuthenticatedProfileId } from "./users-profile-access-Cefbw_TB.js";
import { t as preparePersonalModelAccountSelection } from "./users-model-account-access-B9iXjlLs.js";
import { t as assertValidParams } from "./validation-pzrlzFvo.js";
import { h as normalizeOptionalChatText } from "./chat-abort-runtime-CKI3fkKr.js";
import { i as resolveVisibleActiveSessionRunState } from "./session-active-runs-CCNuJW7B.js";
import { t as resolveGatewayModelSelectionPolicy } from "./session-model-selection-policy-BiBt__vw.js";
import { n as readSessionPlacementFields } from "./session-placement-read-projection-eZkSl0va.js";
import { t as appendAssistantTranscriptMessage } from "./chat-transcript-persistence-Bo3WmQ0i.js";
import { t as resolveGatewayChatCronCreatorAuthorityAdmission } from "./cron-creator-authority-admission-6ZFDdF9M.js";
//#region src/gateway/server-methods/chat-history-budget.ts
const CHAT_HISTORY_MAX_SINGLE_MESSAGE_BYTES = 131072;
const CHAT_HISTORY_OVERSIZED_PLACEHOLDER = "[chat.history omitted: message too large]";
const CHAT_HISTORY_UNAVAILABLE_SENTINEL = "[chat.history unavailable: transcript too large to display; the full history is preserved on disk]";
let chatHistoryOmittedEmitCount = 0;
function createChatHistoryByteCounter() {
	const sizes = /* @__PURE__ */ new Map();
	const messageBytes = (message) => {
		const cached = sizes.get(message);
		if (cached !== void 0) return cached;
		const bytes = jsonUtf8Bytes(message);
		sizes.set(message, bytes);
		return bytes;
	};
	return {
		messageBytes,
		messagesBytes: (messages) => 2 + messages.reduce((bytes, message) => bytes + messageBytes(message), 0) + Math.max(0, messages.length - 1)
	};
}
function buildChatHistoryUnavailableSentinel() {
	return {
		role: "assistant",
		timestamp: Date.now(),
		content: [{
			type: "text",
			text: CHAT_HISTORY_UNAVAILABLE_SENTINEL
		}]
	};
}
function buildOversizedHistoryPlaceholder(message) {
	const role = message && typeof message === "object" && typeof message.role === "string" ? message.role : "assistant";
	const timestamp = message && typeof message === "object" && typeof message.timestamp === "number" ? message.timestamp : Date.now();
	const rawMetadata = message && typeof message === "object" ? message["__openclaw"] : void 0;
	const metadata = rawMetadata && typeof rawMetadata === "object" && !Array.isArray(rawMetadata) ? rawMetadata : {};
	const metadataId = typeof metadata.id === "string" ? metadata.id : void 0;
	const metadataSeq = typeof metadata.seq === "number" ? metadata.seq : void 0;
	const metadataIdempotencyKey = typeof metadata.idempotencyKey === "string" ? metadata.idempotencyKey : void 0;
	const turnBoundary = metadata.turnBoundary === true;
	const transcriptPosition = readTranscriptDisplayPosition(metadata.transcriptPosition);
	return {
		role,
		timestamp,
		content: [{
			type: "text",
			text: CHAT_HISTORY_OVERSIZED_PLACEHOLDER
		}],
		__openclaw: {
			...metadataId ? { id: metadataId } : {},
			...metadataSeq !== void 0 ? { seq: metadataSeq } : {},
			...metadataIdempotencyKey ? { idempotencyKey: metadataIdempotencyKey } : {},
			...turnBoundary ? { turnBoundary: true } : {},
			...transcriptPosition ? { transcriptPosition } : {},
			truncated: true,
			reason: "oversized"
		}
	};
}
function replaceOversizedChatHistoryMessages(params) {
	const { messages, maxSingleMessageBytes } = params;
	const byteCounter = params.byteCounter ?? createChatHistoryByteCounter();
	if (messages.length === 0) return {
		messages,
		replacedCount: 0
	};
	let replacedCount = 0;
	const next = messages.map((message) => {
		if (byteCounter.messageBytes(message) <= maxSingleMessageBytes) return message;
		replacedCount += 1;
		const placeholder = buildOversizedHistoryPlaceholder(message);
		return byteCounter.messageBytes(placeholder) <= maxSingleMessageBytes ? placeholder : buildChatHistoryUnavailableSentinel();
	});
	return {
		messages: replacedCount > 0 ? next : messages,
		replacedCount
	};
}
function reportOmittedChatHistory(params) {
	const { originalMessages, finalMessages, getNormalizedBytes, maxHistoryBytes, logDebug } = params;
	const survivors = new Set(finalMessages);
	let omittedCount = 0;
	for (const message of originalMessages) if (!survivors.has(message)) omittedCount += 1;
	if (omittedCount === 0) return 0;
	chatHistoryOmittedEmitCount += omittedCount;
	logLargePayload({
		surface: "gateway.chat.history",
		action: "truncated",
		bytes: getNormalizedBytes(),
		limitBytes: maxHistoryBytes,
		count: omittedCount,
		reason: "chat_history_budget"
	});
	logDebug(`chat.history omitted oversized payloads count=${omittedCount} total=${chatHistoryOmittedEmitCount}`);
	return omittedCount;
}
//#endregion
//#region src/gateway/server-methods/chat-history-delta.ts
const CHAT_HISTORY_DELTA_MAX_EVENTS = 200;
const CHAT_HISTORY_DELTA_MAX_BYTES = 1e6;
function readMessageEvent(event) {
	const record = asOptionalRecord(event);
	if (!record) return;
	if (record.message === void 0) return;
	return {
		message: record.message,
		...typeof record.id === "string" && record.id ? { messageId: record.id } : {}
	};
}
function containsTranscriptDiscontinuity(result) {
	return result.events.some((row) => {
		const event = asOptionalRecord(row.event);
		if (!event) return false;
		const type = event.type;
		return type === "reset" || type === "compaction";
	});
}
function readChatHistoryDelta(params) {
	const maxBytes = Math.min(params.maxBytes ?? Infinity, CHAT_HISTORY_DELTA_MAX_BYTES);
	const result = readTranscriptDisplayDelta(params.scope, {
		cursor: params.cursor,
		maxBytes,
		maxEvents: CHAT_HISTORY_DELTA_MAX_EVENTS
	});
	if (result.kind !== "page" || result.hasMore || containsTranscriptDiscontinuity(result)) return { kind: "reset" };
	let projectionState = {
		streamErrorFallbackPending: false,
		turnBoundaryPending: false
	};
	const projectCurrentUserProfile = createCurrentUserProfileMessageProjector(resolveCurrentUserProfileDisplay);
	const messages = [];
	let messagesBytes = 2;
	for (const row of result.events) {
		const event = readMessageEvent(row.event);
		if (!event || row.messageSeq === void 0) continue;
		const projected = projectSessionMessagePayload({
			agentId: params.agentId,
			message: event.message,
			...event.messageId ? { messageId: event.messageId } : {},
			messageSeq: row.messageSeq,
			transcriptPosition: row.displayPosition,
			projectionState,
			projectCurrentUserProfile,
			sessionKey: params.sessionKey,
			sessionSnapshot: params.sessionSnapshot
		});
		projectionState = projected.projectionState;
		if (projected.payload) {
			messagesBytes += jsonUtf8BytesOrInfinity(projected.payload) + (messages.length > 0 ? 1 : 0);
			if (messagesBytes > maxBytes) return { kind: "reset" };
			messages.push(projected.payload);
		}
	}
	return {
		activeLeafEntryId: result.activeLeafEntryId,
		deltaCursor: result.cursor,
		kind: "delta",
		messages: composeTranscriptDisplay(messages, (envelope) => envelope.message)
	};
}
//#endregion
//#region src/gateway/session-transcript-anchor-reader.ts
/** Reads one message-id-anchored page from a single transcript snapshot. */
async function readSessionMessagesAroundIdWithStatsAsync(scope, opts) {
	const target = resolveTranscriptReadTarget(scope);
	const sessionFile = !scope.sessionFile && scope.sessionEntry?.sessionId && scope.sessionEntry.sessionId !== scope.sessionId ? void 0 : target.sessionFile;
	const page = readSessionTranscriptHistoryAnchorPage(toTranscriptReadScope(target), opts);
	if (!page.found) {
		if (opts.allowResetArchiveFallback === true) return await new ArchivedTranscriptReader({
			agentId: target.agentId,
			sessionFile,
			sessionId: target.sessionId,
			storePath: target.storePath
		}).readAroundId({
			...opts,
			resetArchiveOnly: true
		});
		return {
			found: false,
			hasOverreadContext: false,
			messages: [],
			offset: 0,
			totalMessages: page.totalMessages,
			transcriptPath: target.sessionFile
		};
	}
	return {
		found: true,
		displaySource: page.displaySource,
		hasOverreadContext: page.hasOverreadContext,
		messages: page.events.flatMap((entry) => {
			const message = projectTranscriptEntryMessage(entry.event, entry.seq, entry.displayPosition);
			return message === void 0 ? [] : [message];
		}),
		offset: page.offset,
		totalMessages: page.totalMessages,
		transcriptPath: target.sessionFile
	};
}
//#endregion
//#region src/gateway/server-methods/chat-history-pages.ts
function readChatHistoryMessageId(message) {
	const metadata = asOptionalRecord(asOptionalRecord(message)?.["__openclaw"]);
	return typeof metadata?.id === "string" ? metadata.id : void 0;
}
function resolveChatHistoryNextOffset(params) {
	const oldestSeq = params.messages.map((message) => readChatHistoryMessageSeq(message)).find((seq) => typeof seq === "number");
	if (oldestSeq === void 0) return params.offset + params.rawPageMessages;
	const recordOffset = params.totalMessages - oldestSeq + 1;
	const replayOffset = recordOffset - 1;
	if (params.replayOldestRecord && replayOffset > params.offset) return replayOffset;
	return Math.max(params.offset + 1, recordOffset);
}
function shouldReplayOldestChatHistoryRecord(params) {
	const oldestSeq = params.bounded.map((message) => readChatHistoryMessageSeq(message)).find((seq) => typeof seq === "number");
	return oldestSeq !== void 0 && params.bounded.filter((message) => readChatHistoryMessageSeq(message) === oldestSeq).length < params.projected.filter((message) => readChatHistoryMessageSeq(message) === oldestSeq).length;
}
function resolveChatHistoryActiveLeafEntryId(readPage) {
	if (readPage.transcriptSource !== "active") return null;
	if (Object.hasOwn(readPage, "activeLeafEntryId")) return readPage.activeLeafEntryId ?? null;
	return resolveSessionTranscriptActiveLeafEntryId(readPage.transcriptEvents ?? []) ?? null;
}
/** Add checkpoint token metrics to the synthetic transcript compaction marker. */
function enrichChatHistoryCompactionMarkers(messages, entry) {
	const checkpoints = entry?.compactionCheckpoints;
	if (!Array.isArray(checkpoints) || checkpoints.length === 0) return messages;
	const checkpointByEntryId = new Map(checkpoints.flatMap((checkpoint) => {
		const entryId = checkpoint.postCompaction?.entryId;
		return typeof entryId === "string" && entryId ? [[entryId, checkpoint]] : [];
	}));
	let changed = false;
	const enriched = messages.map((message) => {
		const record = asOptionalRecord(message);
		const metadata = asOptionalRecord(record?.["__openclaw"]);
		if (metadata?.kind !== "compaction" || typeof metadata.id !== "string") return message;
		const checkpoint = checkpointByEntryId.get(metadata.id);
		if (!checkpoint) return message;
		const tokensBefore = checkpoint.tokensBefore;
		const tokensAfter = checkpoint.tokensAfter;
		if ((typeof tokensBefore !== "number" || !Number.isFinite(tokensBefore)) && (typeof tokensAfter !== "number" || !Number.isFinite(tokensAfter))) return message;
		changed = true;
		return {
			...record,
			__openclaw: {
				...metadata,
				...typeof tokensBefore === "number" && Number.isFinite(tokensBefore) ? { tokensBefore } : {},
				...typeof tokensAfter === "number" && Number.isFinite(tokensAfter) ? { tokensAfter } : {}
			}
		};
	});
	return changed ? enriched : messages;
}
function resolveChatHistoryMessageGroup(messages, index, messageCost) {
	const seq = readChatHistoryMessageSeq(messages[index]);
	let start = index;
	let end = index + 1;
	let cost = messageCost(messages[index]);
	if (seq === void 0) return {
		start,
		end,
		cost
	};
	while (start > 0 && readChatHistoryMessageSeq(messages[start - 1]) === seq) {
		start -= 1;
		cost += messageCost(messages[start]);
	}
	while (end < messages.length && readChatHistoryMessageSeq(messages[end]) === seq) {
		cost += messageCost(messages[end]);
		end += 1;
	}
	return {
		start,
		end,
		cost
	};
}
function capChatHistoryAroundMessage(params) {
	const anchorIndex = params.messages.findIndex((message) => readChatHistoryMessageId(message) === params.messageId);
	if (anchorIndex === -1) return [];
	const messageCost = params.messageCost ?? (() => 1);
	const anchorGroup = resolveChatHistoryMessageGroup(params.messages, anchorIndex, messageCost);
	if (!(anchorGroup.cost <= params.maxCost)) return [params.messages[anchorIndex]];
	let { start, end, cost } = anchorGroup;
	let canGrowOlder = start > 0;
	let canGrowNewer = end < params.messages.length;
	while (canGrowOlder || canGrowNewer) {
		if (canGrowOlder) {
			const olderGroup = resolveChatHistoryMessageGroup(params.messages, start - 1, messageCost);
			if (cost + olderGroup.cost <= params.maxCost) {
				start = olderGroup.start;
				cost += olderGroup.cost;
			} else canGrowOlder = false;
		}
		canGrowOlder &&= start > 0;
		if (canGrowNewer) {
			const newerGroup = resolveChatHistoryMessageGroup(params.messages, end, messageCost);
			if (cost + newerGroup.cost <= params.maxCost) {
				end = newerGroup.end;
				cost += newerGroup.cost;
			} else canGrowNewer = false;
		}
		canGrowNewer &&= end < params.messages.length;
	}
	return params.messages.slice(start, end);
}
async function readChatHistoryPage(params) {
	const { entry, provider, sessionId, storePath, sessionAgentId, canonicalKey, max, maxHistoryBytes, effectiveMaxChars, offset, messageId } = params;
	if (!sessionId || !storePath) {
		if (messageId) return { messages: [] };
		return {
			...(offset ?? 0) === 0 ? { activeLeafEntryId: null } : {},
			messages: [],
			...offset !== void 0 ? { responseOffset: offset } : {},
			pagination: {
				offset: offset ?? 0,
				totalMessages: 0,
				rawPageMessages: 0
			}
		};
	}
	const readScope = {
		agentId: sessionAgentId,
		sessionEntry: entry,
		sessionId,
		sessionKey: canonicalKey,
		storePath
	};
	const cliSessionId = params.ignoreCliSessionImports ? void 0 : resolveClaudeCliBindingSessionId(entry);
	if ((offset !== void 0 || messageId) && !cliSessionId) {
		let pageOffset = offset ?? 0;
		let hasOverreadContext = false;
		let readPage;
		let incrementalTail;
		if (messageId) {
			const anchoredPage = await readSessionMessagesAroundIdWithStatsAsync(readScope, {
				messageId,
				maxMessages: max,
				allowResetArchiveFallback: true
			});
			if (!anchoredPage.found) return { messages: [] };
			pageOffset = anchoredPage.offset;
			hasOverreadContext = anchoredPage.hasOverreadContext;
			readPage = anchoredPage;
		} else {
			incrementalTail = await readIncrementalChatHistoryTail({
				entry,
				readScope,
				effectiveMaxChars,
				max,
				maxBytes: maxHistoryBytes,
				offset: pageOffset
			});
			readPage = incrementalTail.readPage;
		}
		const isTailPage = !messageId && pageOffset === 0;
		const overreadContextMessage = incrementalTail ? incrementalTail.overreadContextMessage : hasOverreadContext || readPage.messages.length > max ? readPage.messages[0] : void 0;
		const localMessages = incrementalTail ? incrementalTail.rawMessages : dropChatHistoryOverreadContextMessage(dropPreSessionStartAnnouncePairs(readPage.messages, typeof entry?.sessionStartedAt === "number" ? entry.sessionStartedAt : void 0), overreadContextMessage);
		const rawPageMessages = incrementalTail ? incrementalTail.rawPageMessages : Math.min(max, Math.max(readPage.messages.length, readPage.totalMessages > pageOffset ? 1 : 0));
		const projected = incrementalTail ? incrementalTail.projected : projectChatDisplayMessages(localMessages, {
			includeCommentaryFallbacks: true,
			maxChars: effectiveMaxChars,
			resolveCurrentUserProfileDisplay,
			turnBoundaryPending: isHeartbeatHistoryTurnBoundaryMessage(overreadContextMessage)
		});
		const windowed = messageId ? capChatHistoryAroundMessage({
			messages: projected,
			messageId,
			maxCost: max
		}) : projected;
		if (messageId) return { messages: augmentChatHistoryWithCanvasBlocks(windowed) };
		return {
			...isTailPage ? {
				activeLeafEntryId: resolveChatHistoryActiveLeafEntryId(readPage),
				...readPage.transcriptSource === "active" && readPage.deltaCursor ? { deltaCursor: readPage.deltaCursor } : {}
			} : {},
			messages: augmentChatHistoryWithCanvasBlocks(windowed),
			responseOffset: pageOffset,
			pagination: {
				offset: pageOffset,
				totalMessages: readPage.totalMessages,
				rawPageMessages
			}
		};
	}
	const incrementalTail = await readIncrementalChatHistoryTail({
		entry,
		readScope,
		effectiveMaxChars,
		max,
		maxBytes: maxHistoryBytes
	});
	const { readPage } = incrementalTail;
	const activeLeafEntryId = resolveChatHistoryActiveLeafEntryId(readPage);
	const localMessagesWithBoundaryFilter = incrementalTail.rawMessages;
	const importedMessages = params.ignoreCliSessionImports ? [] : await readChatHistoryCliSessionImportSnapshot({
		entry,
		provider,
		localMessages: localMessagesWithBoundaryFilter
	});
	const cliHistory = params.ignoreCliSessionImports ? {
		messages: localMessagesWithBoundaryFilter,
		imported: false
	} : resolveChatHistoryWithCliSessionImports({
		entry,
		provider,
		localMessages: localMessagesWithBoundaryFilter,
		preparedImportedMessages: importedMessages
	});
	if ((offset !== void 0 || messageId) && !cliHistory.imported) return readChatHistoryPage({
		...params,
		ignoreCliSessionImports: true
	});
	if (cliHistory.imported) {
		const completeLocalMessages = dropPreSessionStartAnnouncePairs(await readSessionMessagesAsync(readScope, {
			mode: "full",
			reason: "chat.history CLI import merge",
			allowResetArchiveFallback: true
		}), typeof entry?.sessionStartedAt === "number" ? entry.sessionStartedAt : void 0);
		const completeCliHistory = resolveChatHistoryWithCliSessionImports({
			entry,
			provider,
			localMessages: completeLocalMessages,
			preparedImportedMessages: importedMessages
		});
		if (!completeCliHistory.imported) return readChatHistoryPage({
			...params,
			ignoreCliSessionImports: true
		});
		const mergedMessages = dropPreSessionStartAnnouncePairs(completeCliHistory.messages, typeof entry?.sessionStartedAt === "number" ? entry.sessionStartedAt : void 0);
		const displayMessages = projectChatDisplayMessages(mergedMessages, {
			includeCommentaryFallbacks: true,
			maxChars: effectiveMaxChars,
			resolveCurrentUserProfileDisplay
		});
		if (messageId && !displayMessages.some((message) => readChatHistoryMessageId(message) === messageId)) return { messages: [] };
		return {
			activeLeafEntryId,
			messages: augmentChatHistoryWithCanvasBlocks(displayMessages),
			completeCliImport: true,
			pagination: {
				offset: 0,
				totalMessages: mergedMessages.length,
				rawPageMessages: mergedMessages.length,
				exhausted: true
			}
		};
	}
	return {
		activeLeafEntryId,
		...readPage.transcriptSource === "active" && readPage.deltaCursor ? { deltaCursor: readPage.deltaCursor } : {},
		messages: augmentChatHistoryWithCanvasBlocks(incrementalTail.projected),
		pagination: {
			offset: 0,
			totalMessages: readPage.totalMessages,
			rawPageMessages: incrementalTail.rawPageMessages
		}
	};
}
//#endregion
//#region src/gateway/server-methods/chat-metadata-handler.ts
async function handleChatMetadataRequest({ params, respond, context, client, signal }) {
	if (!assertValidParams(params, validateChatMetadataParams, "chat.metadata", respond)) return;
	const metadataParams = params;
	const cfg = context.getRuntimeConfig();
	if (metadataParams.sessionKey) {
		const requested = resolveRequestedChatAgentId({
			cfg,
			requestedSessionKey: metadataParams.sessionKey,
			agentId: metadataParams.agentId
		});
		if (!requested.ok) {
			respond(false, void 0, requested.error);
			return;
		}
		const session = loadGatewaySessionEntryReadOnly(metadataParams.sessionKey, {
			agentId: requested.agentId,
			projection: "list"
		});
		respond(true, await context.readChatMetadata({
			agentId: resolveSessionAgentId({
				sessionKey: metadataParams.sessionKey,
				config: session.cfg,
				agentId: requested.agentId
			}),
			sessionKey: session.canonicalKey,
			sessionEntry: session.entry,
			requesterProfileId: resolveAuthenticatedProfileId(client)
		}));
		return;
	}
	const resolvedAgent = resolveAgentIdOrRespondError({
		rawAgentId: metadataParams.agentId,
		respond,
		cfg,
		normalize: (rawAgentId) => typeof rawAgentId === "string" && rawAgentId.trim() ? normalizeAgentId(rawAgentId) : void 0
	});
	if (!resolvedAgent) return;
	try {
		const draftAccountSelection = metadataParams.authProfileId ? preparePersonalModelAccountSelection({
			client,
			context,
			signal
		}, metadataParams.authProfileId, "operator.read") : void 0;
		const metadata = await context.readChatMetadata({
			agentId: resolvedAgent.agentId,
			requesterProfileId: draftAccountSelection?.owner ?? resolveAuthenticatedProfileId(client),
			...draftAccountSelection ? { draftAccountSelection } : {}
		});
		draftAccountSelection?.assertCurrent();
		respond(true, metadata);
	} catch (error) {
		if (!(error instanceof ModelAccountConnectAuthorityError)) throw error;
		respond(false, void 0, errorShape(ErrorCodes.FORBIDDEN, error.message));
	}
}
//#endregion
//#region src/gateway/server-methods/chat-pending-inputs.ts
const PENDING_INPUT_DISPLAY_MAX_BYTES = 131072;
const PENDING_INPUT_CORRELATION_MAX_CHARS = 256;
function projectPendingInputMessage(input, maxChars) {
	const message = projectChatDisplayMessage(input.message, {
		maxChars,
		resolveCurrentUserProfileDisplay
	});
	if (!message) return;
	const metadata = { ...asOptionalRecord(message["__openclaw"]) };
	delete metadata.idempotencyKey;
	delete metadata.runId;
	return {
		...message,
		timestamp: input.acceptedAt,
		idempotencyKey: void 0,
		__openclaw: {
			...metadata,
			id: `${CHAT_PENDING_INPUT_MESSAGE_PREFIX}${input.id}`
		}
	};
}
function readChatPendingInputs(scope, options) {
	const page = listSessionPendingInputs(scope, {
		before: options.before,
		limit: Math.min(options.limit, 20)
	});
	const visible = page.items.flatMap((input) => {
		const message = projectPendingInputMessage(input, options.maxChars);
		return message ? [{
			input,
			message
		}] : [];
	});
	const messages = replaceOversizedChatHistoryMessages({
		messages: visible.map(({ message }) => message),
		maxSingleMessageBytes: Math.floor(PENDING_INPUT_DISPLAY_MAX_BYTES / Math.max(page.items.length, 1))
	}).messages;
	return {
		...page,
		items: visible.map(({ input: item }, index) => {
			const display = {
				id: item.id,
				acceptedAt: item.acceptedAt,
				state: item.state,
				message: messages[index]
			};
			if (item.runId.length <= PENDING_INPUT_CORRELATION_MAX_CHARS) display.runId = item.runId;
			return display;
		})
	};
}
//#endregion
//#region src/gateway/server-methods/chat-history-handler.ts
function respondChatHistoryUnavailable(method, respond) {
	respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, "session history is rebuilding; retry shortly", {
		details: { method },
		retryable: true,
		retryAfterMs: 250
	}));
}
function resolveEmbeddedAgentRunRecoverySnapshot(params) {
	const sessionId = params.sessionId ?? resolveActiveEmbeddedRunHandleSessionId(params.canonicalSessionKey) ?? resolveActiveEmbeddedRunHandleSessionId(params.requestedSessionKey);
	if (!sessionId) return;
	const owner = resolveActiveEmbeddedRunOwner(sessionId);
	if (!owner) return;
	return projectInFlightRunSnapshot({
		chatRunState: params.chatRunState,
		runId: owner.runId,
		startedAtMs: owner.startedAtMs,
		sessionAbortable: true
	});
}
async function handleChatHistoryRequest({ params, respond, client, context, method }) {
	if (!assertValidParams(params, validateChatHistoryParams, method, respond)) return;
	const { sessionKey, limit, offset, cursor, messageId, sessionId: requestedSessionId, maxChars, maxBytes, pendingBefore, inputRunIds } = params;
	if (offset !== void 0 && messageId !== void 0) {
		respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "offset and messageId cannot be used together"));
		return;
	}
	if (cursor !== void 0 && (offset !== void 0 || messageId !== void 0)) {
		respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "cursor cannot be used with offset or messageId"));
		return;
	}
	if (requestedSessionId !== void 0 && messageId === void 0) {
		respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "sessionId requires messageId"));
		return;
	}
	const requestConfig = context.getRuntimeConfig();
	const agentIdOverride = normalizeOptionalChatText(params.agentId);
	const requestedAgent = resolveRequestedChatAgentId({
		cfg: requestConfig,
		requestedSessionKey: sessionKey,
		agentId: agentIdOverride
	});
	if (!requestedAgent.ok) {
		respond(false, void 0, requestedAgent.error);
		return;
	}
	const { cfg, storePath, store, entry, canonicalKey } = measureDiagnosticsTimelineSpanSync(`gateway.${method}.session_entry`, () => loadGatewaySessionEntryReadOnly(sessionKey, {
		agentId: requestedAgent.agentId,
		clone: false,
		includeStoreChildEntries: true,
		projection: "list"
	}), {
		config: requestConfig,
		phase: method
	});
	const selectedAgent = validateChatSelectedAgent({
		cfg,
		requestedSessionKey: sessionKey,
		explicitAgentId: agentIdOverride
	});
	if (!selectedAgent.ok) {
		respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, selectedAgent.error));
		return;
	}
	const sessionAgentId = resolveSessionAgentId({
		sessionKey,
		config: cfg,
		agentId: selectedAgent.agentId
	});
	if (requestedSessionId) {
		const transcriptSessionKey = resolveSessionKeyBySessionId({
			agentId: sessionAgentId,
			sessionId: requestedSessionId,
			storePath
		});
		if (!transcriptSessionKey || scopeLegacySessionKeyToAgent({
			sessionKey: transcriptSessionKey,
			agentId: sessionAgentId
		}) !== scopeLegacySessionKeyToAgent({
			sessionKey: canonicalKey,
			agentId: sessionAgentId
		})) {
			respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "sessionId does not belong to sessionKey"));
			return;
		}
	}
	if (method === "chat.startup") prepareSessionWorkspaceIcon({
		sessionKey,
		agentId: sessionAgentId
	}).catch((error) => {
		context.logGateway.debug(`chat.startup continuing without a workspace icon: ${formatErrorMessage(error)}`);
	});
	const readStartupProjection = () => measureDiagnosticsTimelineSpan(`gateway.${method}.startup_projection`, async () => {
		try {
			return await context.readChatStartupProjection?.({
				agentId: sessionAgentId,
				sessionKey: canonicalKey,
				sessionEntry: entry,
				requesterProfileId: resolveAuthenticatedProfileId(client),
				readPolicy: method === "chat.history" ? "ready" : "current"
			});
		} catch (error) {
			context.logGateway.debug(`${method} continuing without prepared startup projection: ${formatErrorMessage(error)}`);
			return;
		}
	}, {
		config: cfg,
		phase: method,
		attributes: { agentId: sessionAgentId }
	});
	const startupProjectionPromise = entry?.authProfileOverride?.trim() ? readStartupProjection() : void 0;
	const sessionId = requestedSessionId ?? entry?.sessionId;
	const historyEntry = requestedSessionId && requestedSessionId !== entry?.sessionId ? void 0 : entry;
	const resolvedSessionModel = resolveSessionModelRef(cfg, entry, sessionAgentId, { allowPluginNormalization: false });
	const max = Math.min(CHAT_HISTORY_MAX_ENTRIES, typeof limit === "number" ? limit : 200);
	const maxHistoryBytes = Math.min(maxBytes ?? Infinity, getMaxChatHistoryMessagesBytes());
	const effectiveMaxChars = resolveEffectiveChatHistoryMaxChars(cfg, maxChars);
	const pendingInputs = sessionId && sessionId === entry?.sessionId ? readChatPendingInputs({
		agentId: sessionAgentId,
		sessionKey: canonicalKey,
		sessionId,
		storePath
	}, {
		before: pendingBefore,
		limit: max,
		maxChars: effectiveMaxChars
	}) : {
		items: [],
		total: 0
	};
	const inputReceipts = inputRunIds ? !messageId && sessionId && sessionId === entry?.sessionId ? listSessionPendingInputReceipts({
		agentId: sessionAgentId,
		sessionKey: canonicalKey,
		sessionId,
		storePath
	}, { runIds: inputRunIds }) : [] : void 0;
	const inputConsumptions = inputReceipts?.flatMap((receipt) => receipt.state === "consumed" ? [{
		runId: receipt.runId,
		consumedByEventId: receipt.consumedByEventId
	}] : []);
	let historyPage;
	try {
		historyPage = cursor ? { messages: [] } : await measureDiagnosticsTimelineSpan(`gateway.${method}.history_page`, () => readChatHistoryPage({
			entry: historyEntry,
			provider: resolvedSessionModel.provider,
			sessionId,
			storePath,
			sessionAgentId,
			canonicalKey,
			max,
			maxHistoryBytes,
			effectiveMaxChars,
			offset,
			messageId
		}), {
			config: cfg,
			phase: method,
			attributes: {
				limit: max,
				hasMessageId: Boolean(messageId),
				hasOffset: offset !== void 0
			}
		});
	} catch (error) {
		if (!isSessionTranscriptProjectionUnavailableError(error)) throw error;
		respondChatHistoryUnavailable(method, respond);
		return;
	}
	const normalized = enrichChatHistoryCompactionMarkers(historyPage.messages, historyEntry);
	const responseHistoryBytes = historyPage.completeCliImport ? getMaxChatHistoryMessagesBytes() : maxHistoryBytes;
	const perMessageHardCap = Math.min(CHAT_HISTORY_MAX_SINGLE_MESSAGE_BYTES, getMaxChatHistoryMessagesBytes());
	const byteCounter = createChatHistoryByteCounter();
	const replaced = replaceOversizedChatHistoryMessages({
		byteCounter,
		messages: normalized,
		maxSingleMessageBytes: perMessageHardCap
	});
	const capped = messageId ? capChatHistoryAroundMessage({
		messages: replaced.messages,
		messageId,
		maxCost: responseHistoryBytes - 1,
		messageCost: (message) => byteCounter.messageBytes(message) + 1
	}) : capArrayByJsonBytes(replaced.messages, responseHistoryBytes, byteCounter.messageBytes).items;
	const historyBudgetPreserved = replaced.replacedCount === 0 && capped.length === normalized.length && capped.every((message, index) => message === normalized[index]);
	const pagination = historyPage.pagination;
	const candidateNextOffset = pagination === void 0 ? void 0 : resolveChatHistoryNextOffset({
		messages: capped,
		totalMessages: pagination.totalMessages,
		offset: pagination.offset,
		rawPageMessages: pagination.rawPageMessages,
		replayOldestRecord: shouldReplayOldestChatHistoryRecord({
			projected: normalized,
			bounded: capped
		})
	});
	const hasMore = pagination !== void 0 && candidateNextOffset !== void 0 ? pagination.exhausted !== true && candidateNextOffset < pagination.totalMessages : void 0;
	const nextOffset = hasMore ? candidateNextOffset : void 0;
	reportOmittedChatHistory({
		originalMessages: normalized,
		finalMessages: capped,
		getNormalizedBytes: () => byteCounter.messagesBytes(normalized),
		maxHistoryBytes: responseHistoryBytes,
		logDebug: (message) => context.logGateway.debug(message)
	});
	const compatibilityOwnerAgentId = tryResolveSessionCompatibilityOwnerAgentId(cfg, sessionKey);
	const startupProjection = await (startupProjectionPromise ?? readStartupProjection());
	const startupMetadata = method === "chat.startup" ? startupProjection?.metadata : void 0;
	const sessionModelCatalog = startupProjection?.sessionModelCatalog;
	const defaultModelCatalog = startupProjection?.defaultModelCatalog;
	const sessionInfo = measureDiagnosticsTimelineSpanSync(`gateway.${method}.session_info`, () => buildGatewaySessionInfo({
		cfg,
		storePath,
		store,
		key: canonicalKey,
		entry,
		agentId: selectedAgent.agentId,
		modelCatalog: sessionModelCatalog
	}), {
		config: cfg,
		phase: method,
		attributes: { storeEntries: Object.keys(store).length }
	});
	const activeRunAgentId = selectedAgent.agentId;
	const activeRunState = resolveVisibleActiveSessionRunState({
		context,
		requestedKey: sessionKey,
		canonicalKey,
		sessionId,
		...activeRunAgentId ? { agentId: activeRunAgentId } : {},
		defaultAgentId: compatibilityOwnerAgentId,
		includeTerminalPersistence: true
	});
	sessionInfo.hasActiveRun = activeRunState.active;
	if (activeRunState.runIds !== void 0) sessionInfo.activeRunIds = activeRunState.runIds;
	if (activeRunState.active) sessionInfo.status = activeRunState.status ?? "running";
	Object.assign(sessionInfo, readSessionPlacementFields(context, entry?.sessionId));
	const embeddedRecovery = resolveEmbeddedAgentRunRecoverySnapshot({
		chatRunState: context.chatRunState,
		requestedSessionKey: sessionKey,
		canonicalSessionKey: canonicalKey,
		sessionId
	});
	if (Object.hasOwn(historyPage, "activeLeafEntryId")) sessionInfo.activeLeafEntryId = historyPage.activeLeafEntryId ?? null;
	const defaults = cursor === void 0 ? {
		...getSessionDefaults(cfg, defaultModelCatalog, {
			agentId: sessionAgentId,
			allowPluginNormalization: false,
			providerPolicySource: "active"
		}),
		modelSelectionTarget: resolveGatewayModelSelectionPolicy({
			agentId: sessionAgentId,
			callerScopes: client?.connect?.scopes ?? [],
			cfg
		}).target
	} : void 0;
	for (const [projection, catalog] of [[sessionInfo, sessionModelCatalog], [defaults, defaultModelCatalog]]) {
		if (!projection) continue;
		const provider = projection.modelProvider;
		const model = projection.model;
		if (typeof (catalog && provider && model ? findModelCatalogEntry(catalog, {
			provider,
			modelId: model
		}) : void 0)?.reasoning === "boolean") continue;
		delete projection.thinkingLevels;
		delete projection.thinkingOptions;
		projection.thinkingDefault = resolveAgentConfig(cfg, sessionAgentId)?.thinkingDefault ?? (provider && model ? resolveConfiguredThinkingDefault({
			cfg,
			provider,
			model
		}) : cfg.agents?.defaults?.thinkingDefault);
	}
	const thinkingLevel = sessionInfo.thinkingLevel ?? sessionInfo.thinkingDefault;
	const verboseLevel = entry?.verboseLevel ?? cfg.agents?.defaults?.verboseDefault;
	sessionInfo.verboseLevel = verboseLevel;
	const inFlightRun = resolveInFlightRunSnapshot({
		chatAbortControllers: context.chatAbortControllers,
		chatRunState: context.chatRunState,
		requestedSessionKey: sessionKey,
		canonicalSessionKey: canonicalKey,
		agentId: activeRunAgentId,
		defaultAgentId: compatibilityOwnerAgentId
	}) ?? embeddedRecovery;
	if (cursor !== void 0) {
		if (!sessionId || !storePath || resolveClaudeCliBindingSessionId(entry)) {
			respond(true, { kind: "reset" });
			return;
		}
		const sessionSnapshot = buildGatewaySessionSnapshot({
			sessionRow: sessionInfo,
			agentId: sessionAgentId,
			includeSession: true,
			activeRunState
		});
		let delta;
		try {
			delta = readChatHistoryDelta({
				agentId: sessionAgentId,
				cursor,
				maxBytes: maxHistoryBytes,
				scope: {
					agentId: sessionAgentId,
					sessionEntry: entry,
					sessionId,
					sessionKey: canonicalKey,
					storePath
				},
				sessionKey: canonicalKey,
				sessionSnapshot
			});
		} catch (error) {
			if (!isSessionTranscriptProjectionUnavailableError(error)) throw error;
			respondChatHistoryUnavailable(method, respond);
			return;
		}
		if (delta.kind === "reset") {
			respond(true, delta);
			return;
		}
		sessionInfo.activeLeafEntryId = delta.activeLeafEntryId;
		const boundedInFlightRun = boundInFlightRunSnapshotForChatHistory({
			snapshot: inFlightRun,
			messages: delta.messages,
			maxBytes: maxHistoryBytes
		});
		respond(true, {
			kind: "delta",
			messages: delta.messages,
			deltaCursor: delta.deltaCursor,
			pendingInputs,
			...inputReceipts ? {
				inputReceipts,
				inputConsumptions
			} : {},
			sessionInfo,
			...boundedInFlightRun ? { inFlightRun: boundedInFlightRun } : {},
			...startupMetadata ? { metadata: startupMetadata } : {}
		});
		return;
	}
	const boundedInFlightRun = boundInFlightRunSnapshotForChatHistory({
		snapshot: inFlightRun,
		messages: capped,
		maxBytes: responseHistoryBytes
	});
	respond(true, {
		sessionKey,
		sessionId,
		messages: composeTranscriptDisplay(capped),
		pendingInputs,
		...inputReceipts ? {
			inputReceipts,
			inputConsumptions
		} : {},
		...historyPage.deltaCursor ? { deltaCursor: historyPage.deltaCursor } : {},
		...historyPage.responseOffset !== void 0 ? { offset: historyPage.responseOffset } : {},
		...hasMore ? { nextOffset } : {},
		...hasMore !== void 0 ? { hasMore } : {},
		...pagination !== void 0 ? { totalMessages: pagination.totalMessages } : {},
		...historyPage.completeCliImport && !hasMore && historyBudgetPreserved ? { completeSnapshot: true } : {},
		defaults,
		sessionInfo,
		thinkingLevel,
		fastMode: entry?.fastMode,
		toolOverrides: entry?.toolOverrides,
		verboseLevel,
		...boundedInFlightRun ? { inFlightRun: boundedInFlightRun } : {},
		...startupMetadata ? { metadata: startupMetadata } : {}
	});
}
const chatHistoryHandlers = {
	"chat.history": async (opts) => {
		await handleChatHistoryRequest({
			...opts,
			method: "chat.history"
		});
	},
	"chat.startup": async (opts) => {
		if (!assertValidParams(opts.params, validateChatStartupParams, "chat.startup", opts.respond)) return;
		if ("sessionKey" in opts.params) {
			await handleChatHistoryRequest({
				...opts,
				method: "chat.startup"
			});
			return;
		}
		const connId = opts.client?.connId?.trim();
		if (connId) {
			opts.context.subscribeSessionEvents(connId);
			if (!opts.context.getSessionEventSubscriberConnIds().has(connId)) {
				opts.respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, "connection closed before chat startup"));
				return;
			}
		}
		const { shortId, slugHint, agentId, limit, maxBytes } = opts.params;
		const resolution = await resolveSessionKeyFromResolveParams({
			cfg: opts.context.getRuntimeConfig(),
			client: opts.client,
			p: {
				shortId,
				slugHint,
				agentId,
				allowMissing: true
			}
		});
		if (!resolution.ok) {
			opts.respond(false, void 0, resolution.error);
			return;
		}
		if ("missing" in resolution || "ambiguous" in resolution) {
			opts.respond(true, { resolution: {
				ok: false,
				..."ambiguous" in resolution ? { candidates: resolution.candidates } : {}
			} });
			return;
		}
		await handleChatHistoryRequest({
			...opts,
			params: {
				sessionKey: resolution.key,
				agentId: resolution.agentId,
				limit,
				maxBytes
			},
			method: "chat.startup",
			respond: (ok, payload, error, meta) => opts.respond(ok, ok ? {
				...asOptionalRecord(payload),
				resolution
			} : payload, error, meta)
		});
	},
	"chat.metadata": handleChatMetadataRequest
};
//#endregion
//#region src/gateway/server-methods/chat-message-get-handler.ts
async function isChatMessageIdVisibleAfterHistoryFilters(params) {
	if (params.sessionStartedAt === void 0) return true;
	const { messages } = await readSessionMessagesAroundIdWithStatsAsync({
		agentId: params.agentId,
		sessionEntry: params.sessionEntry,
		sessionId: params.sessionId,
		sessionKey: params.sessionKey,
		storePath: params.storePath
	}, {
		maxMessages: 1,
		messageId: params.messageId,
		...params.allowResetArchiveFallback === true ? { allowResetArchiveFallback: true } : {}
	});
	return dropPreSessionStartAnnouncePairs(messages, params.sessionStartedAt).some((message) => readChatHistoryMessageId(message) === params.messageId);
}
const chatMessageGetHandlers = { "chat.message.get": async ({ params, respond, context }) => {
	if (!assertValidParams(params, validateChatMessageGetParams, "chat.message.get", respond)) return;
	const { sessionKey, messageId, maxChars } = params;
	const agentIdOverride = normalizeOptionalChatText(params.agentId);
	const requestedAgent = resolveRequestedChatAgentId({
		cfg: context.getRuntimeConfig?.(),
		requestedSessionKey: sessionKey,
		agentId: agentIdOverride
	});
	if (!requestedAgent.ok) {
		respond(false, void 0, requestedAgent.error);
		return;
	}
	const requestedAgentId = requestedAgent.agentId;
	const { cfg, storePath, entry, canonicalKey } = loadGatewaySessionEntryReadOnly(sessionKey, requestedAgentId ? { agentId: requestedAgentId } : void 0);
	const selectedAgent = validateChatSelectedAgent({
		cfg,
		requestedSessionKey: sessionKey,
		explicitAgentId: agentIdOverride
	});
	if (!selectedAgent.ok) {
		respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, selectedAgent.error));
		return;
	}
	const sessionId = entry?.sessionId;
	if (!sessionId) {
		respond(true, {
			ok: false,
			unavailableReason: "not_found"
		});
		return;
	}
	const sessionAgentId = resolveSessionAgentId({
		sessionKey,
		config: cfg,
		agentId: selectedAgent.agentId
	});
	const effectiveMaxChars = typeof maxChars === "number" ? maxChars : Math.min(MAX_PAYLOAD_BYTES, 1e6);
	if (messageId.startsWith("pending:")) {
		const pending = readSessionPendingInput({
			agentId: sessionAgentId,
			sessionKey: canonicalKey,
			sessionId,
			storePath
		}, messageId.slice(CHAT_PENDING_INPUT_MESSAGE_PREFIX.length));
		if (!pending) {
			respond(true, {
				ok: false,
				unavailableReason: "not_found"
			});
			return;
		}
		const message = projectPendingInputMessage(pending, effectiveMaxChars);
		if (!message) {
			respond(true, {
				ok: false,
				unavailableReason: "not_visible"
			});
			return;
		}
		respond(true, jsonUtf8Bytes(message) > 26213376 ? {
			ok: false,
			unavailableReason: "oversized"
		} : {
			ok: true,
			message
		});
		return;
	}
	const resolved = await readSessionMessageByIdAsync({
		agentId: sessionAgentId,
		sessionEntry: entry,
		sessionId,
		sessionKey,
		storePath
	}, messageId, { allowResetArchiveFallback: true });
	if (!resolved.found) {
		respond(true, {
			ok: false,
			unavailableReason: "not_found"
		});
		return;
	}
	if (!await isChatMessageIdVisibleAfterHistoryFilters({
		sessionId,
		storePath,
		sessionEntry: entry,
		sessionKey,
		agentId: sessionAgentId,
		messageId,
		sessionStartedAt: typeof entry?.sessionStartedAt === "number" ? entry.sessionStartedAt : void 0,
		allowResetArchiveFallback: true
	})) {
		respond(true, {
			ok: false,
			unavailableReason: "not_found"
		});
		return;
	}
	if (resolved.oversized) {
		respond(true, {
			ok: false,
			unavailableReason: "oversized"
		});
		return;
	}
	const projectedMessage = resolved.message ? projectChatDisplayMessage(resolved.message, {
		maxChars: effectiveMaxChars,
		resolveCurrentUserProfileDisplay
	}) : void 0;
	const projected = projectedMessage ? augmentChatHistoryWithCanvasBlocks([projectedMessage])[0] : void 0;
	if (!projected) {
		respond(true, {
			ok: false,
			unavailableReason: "not_visible"
		});
		return;
	}
	respond(true, {
		ok: true,
		message: projected
	});
} };
//#endregion
//#region src/gateway/server-methods/chat-send-external-entry.ts
const externalAuthorityAdmission = {
	resolve: (params) => {
		const authority = resolveGatewayChatCronCreatorAuthorityAdmission({
			runId: params.runId,
			resolvedSessionKey: params.sessionKey,
			spawnedBy: params.spawnedBy,
			client: params.client,
			inputProvenance: params.inputProvenance,
			hasExplicitOrigin: params.hasExplicitOrigin,
			hasRestoredCronContinuation: params.hasRestoredCronContinuation,
			isIncognito: params.isIncognitoEntry || isIncognitoSessionKey(params.sessionKey),
			isReconnectResume: params.isReconnectResume,
			isSystemGenerated: params.isSystemGenerated,
			turnKind: params.turnKind,
			isDirectExternalUser: true
		});
		return authority ? createCronCreatorAuthorityCapability(authority.runId, authority.callerOrigin, authority.controlUiAdmin) : void 0;
	},
	run: (capability, run, signal) => runWithCronCreatorAuthorityCapability(capability, run, signal)
};
/** Authenticated external chat entry; internal re-entry must call handleChatSend directly. */
function handleDirectExternalChatSend(options, onAdmissionOwned) {
	return handleChatSend(options, onAdmissionOwned, externalAuthorityAdmission);
}
//#endregion
//#region src/gateway/server-methods/chat.ts
const chatHandlers = {
	...chatHistoryHandlers,
	...chatMessageGetHandlers,
	"chat.toolTitles": async ({ params, respond }) => {
		if (!assertValidParams(params, validateChatToolTitlesParams, "chat.toolTitles", respond)) return;
		respond(true, {
			titles: {},
			disabled: true
		});
	},
	"chat.send": handleDirectExternalChatSend,
	"chat.inject": async ({ params, respond, context }) => {
		if (!assertValidParams(params, validateChatInjectParams, "chat.inject", respond)) return;
		const p = params;
		const rawSessionKey = p.sessionKey;
		const agentIdOverride = normalizeOptionalChatText(p.agentId);
		const requestedAgent = resolveRequestedChatAgentId({
			cfg: context.getRuntimeConfig?.(),
			requestedSessionKey: rawSessionKey,
			agentId: agentIdOverride
		});
		if (!requestedAgent.ok) {
			respond(false, void 0, requestedAgent.error);
			return;
		}
		const requestedAgentId = requestedAgent.agentId;
		const sessionLoadOptions = requestedAgentId ? { agentId: requestedAgentId } : void 0;
		const { cfg, storePath, entry, canonicalKey: sessionKey } = loadGatewaySessionEntry(rawSessionKey, sessionLoadOptions);
		const selectedAgent = validateChatSelectedAgent({
			cfg,
			requestedSessionKey: rawSessionKey,
			explicitAgentId: agentIdOverride
		});
		if (!selectedAgent.ok) {
			respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, selectedAgent.error));
			return;
		}
		const sessionId = entry?.sessionId;
		if (!sessionId || !storePath) {
			respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "session not found"));
			return;
		}
		const agentId = resolveSessionAgentId({
			sessionKey,
			config: cfg,
			agentId: selectedAgent.agentId
		});
		let appended;
		try {
			const admission = await beginSessionWorkAdmission({
				scope: storePath,
				identities: [sessionKey, sessionId],
				assertAllowed: () => {
					const latestEntry = loadGatewaySessionEntry(rawSessionKey, sessionLoadOptions).entry;
					if (!latestEntry) throw new Error(`Session "${sessionKey}" was deleted while starting work. Retry.`);
					if (latestEntry.sessionId !== sessionId) throw new Error(`Session "${sessionKey}" changed while starting work. Retry.`);
					const archivedError = resolveSessionWorkStartError(sessionKey, latestEntry);
					if (archivedError) throw new Error(archivedError);
				}
			});
			try {
				appended = await admission.run(async () => await appendAssistantTranscriptMessage({
					sessionKey,
					message: p.message,
					label: p.label,
					sessionId,
					storePath,
					agentId,
					createIfMissing: true,
					cfg
				}));
			} finally {
				admission.release();
			}
		} catch (err) {
			respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, formatForLog(err)));
			return;
		}
		if (!appended.ok || !appended.messageId || !appended.message) {
			respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, `failed to write transcript: ${appended.error ?? "unknown error"}`));
			return;
		}
		const message = projectChatDisplayMessage(appended.message, { maxChars: resolveEffectiveChatHistoryMaxChars(cfg) });
		const chatPayload = {
			runId: `inject-${appended.messageId}`,
			sessionKey,
			...agentId ? { agentId } : {},
			seq: 0,
			state: "final",
			message
		};
		context.broadcast("chat", chatPayload, { sessionKeys: resolveGlobalAwareNodeChatDeliveryKeys({
			cfg,
			sessionKey,
			agentId
		}) });
		sendGlobalAwareNodeChatPayload({
			context,
			sessionKey,
			agentId,
			event: "chat",
			payload: chatPayload
		});
		respond(true, {
			ok: true,
			messageId: appended.messageId
		});
	}
};
//#endregion
export { readChatHistoryPage as a, CHAT_HISTORY_MAX_SINGLE_MESSAGE_BYTES as c, enrichChatHistoryCompactionMarkers as i, replaceOversizedChatHistoryMessages as l, handleDirectExternalChatSend as n, resolveChatHistoryNextOffset as o, capChatHistoryAroundMessage as r, shouldReplayOldestChatHistoryRecord as s, chatHandlers as t, reportOmittedChatHistory as u };