import { o as createSubsystemLogger, yt as resolveStateDir } from "./entry.js";
import { o as normalizeAgentId, s as normalizeMainKey, v as isCronRunSessionKey, x as parseAgentSessionKey } from "./session-key-CFxFgYxM.js";
import { c as resolveAgentWorkspaceDir, l as resolveDefaultAgentId } from "./agent-scope-C-Jte08L.js";
import { C as DEFAULT_MODEL, S as DEFAULT_CONTEXT_TOKENS, d as parseModelRef, h as resolveDefaultModelForAgent, m as resolveConfiguredModelRef, w as DEFAULT_PROVIDER } from "./model-selection-CMx1evaF.js";
import { t as resolveSymiAgentDir } from "./agent-paths-DryQawbH.js";
import { i as loadConfig } from "./config-D7TcU4qN.js";
import { F as resolveMainSessionKey, J as normalizeSessionDeliveryFields, M as canonicalizeMainSessionAlias, N as resolveAgentMainSessionKey, b as readSessionTitleFieldsFromTranscript, j as resolveFreshSessionTotalTokens, o as loadSessionStore, x as resolveSessionTranscriptCandidates, z as buildGroupDisplayName } from "./sessions-Dn6VXn4p.js";
import { c as resolveStorePath } from "./paths-DtiEyjsC.js";
import { t as ensureSymiModelsJson } from "./models-config-CiR_RUxw.js";
import path from "node:path";
import fs from "node:fs";

//#region src/agents/context.ts
function applyDiscoveredContextWindows(params) {
	for (const model of params.models) {
		if (!model?.id) continue;
		const contextWindow = typeof model.contextWindow === "number" ? Math.trunc(model.contextWindow) : void 0;
		if (!contextWindow || contextWindow <= 0) continue;
		const existing = params.cache.get(model.id);
		if (existing === void 0 || contextWindow < existing) params.cache.set(model.id, contextWindow);
	}
}
function applyConfiguredContextWindows(params) {
	const providers = params.modelsConfig?.providers;
	if (!providers || typeof providers !== "object") return;
	for (const provider of Object.values(providers)) {
		if (!Array.isArray(provider?.models)) continue;
		for (const model of provider.models) {
			const modelId = typeof model?.id === "string" ? model.id : void 0;
			const contextWindow = typeof model?.contextWindow === "number" ? model.contextWindow : void 0;
			if (!modelId || !contextWindow || contextWindow <= 0) continue;
			params.cache.set(modelId, contextWindow);
		}
	}
}
const MODEL_CACHE = /* @__PURE__ */ new Map();
(async () => {
	let cfg;
	try {
		cfg = loadConfig();
	} catch {
		return;
	}
	try {
		await ensureSymiModelsJson(cfg);
	} catch {}
	try {
		const { discoverAuthStorage, discoverModels } = await import("./pi-model-discovery-EgBaDO8n.js").then((n) => n.r);
		const agentDir = resolveSymiAgentDir();
		const modelRegistry = discoverModels(discoverAuthStorage(agentDir), agentDir);
		applyDiscoveredContextWindows({
			cache: MODEL_CACHE,
			models: typeof modelRegistry.getAvailable === "function" ? modelRegistry.getAvailable() : modelRegistry.getAll()
		});
	} catch {}
	applyConfiguredContextWindows({
		cache: MODEL_CACHE,
		modelsConfig: cfg.models
	});
})().catch(() => {});
function lookupContextTokens(modelId) {
	if (!modelId) return;
	return MODEL_CACHE.get(modelId);
}

//#endregion
//#region src/gateway/session-utils.ts
const log = createSubsystemLogger("session-utils");
const DERIVED_TITLE_MAX_LEN = 60;
const AVATAR_MAX_BYTES = 2 * 1024 * 1024;
const AVATAR_DATA_RE = /^data:/i;
const AVATAR_HTTP_RE = /^https?:\/\//i;
const AVATAR_SCHEME_RE = /^[a-z][a-z0-9+.-]*:/i;
const WINDOWS_ABS_RE = /^[a-zA-Z]:[\\/]/;
const AVATAR_MIME_BY_EXT = {
	".png": "image/png",
	".jpg": "image/jpeg",
	".jpeg": "image/jpeg",
	".webp": "image/webp",
	".gif": "image/gif",
	".svg": "image/svg+xml",
	".bmp": "image/bmp",
	".tif": "image/tiff",
	".tiff": "image/tiff"
};
function resolveAvatarMime(filePath) {
	return AVATAR_MIME_BY_EXT[path.extname(filePath).toLowerCase()] ?? "application/octet-stream";
}
function isWorkspaceRelativePath(value) {
	if (!value) return false;
	if (value.startsWith("~")) return false;
	if (AVATAR_SCHEME_RE.test(value) && !WINDOWS_ABS_RE.test(value)) return false;
	return true;
}
function resolveIdentityAvatarUrl(cfg, agentId, avatar) {
	if (!avatar) return;
	const trimmed = avatar.trim();
	if (!trimmed) return;
	if (AVATAR_DATA_RE.test(trimmed) || AVATAR_HTTP_RE.test(trimmed)) return trimmed;
	if (!isWorkspaceRelativePath(trimmed)) return;
	const workspaceDir = resolveAgentWorkspaceDir(cfg, agentId);
	const workspaceRoot = path.resolve(workspaceDir);
	const resolved = path.resolve(workspaceRoot, trimmed);
	const relative = path.relative(workspaceRoot, resolved);
	if (relative.startsWith("..") || path.isAbsolute(relative)) return;
	try {
		const stat = fs.statSync(resolved);
		if (!stat.isFile() || stat.size > AVATAR_MAX_BYTES) return;
		const buffer = fs.readFileSync(resolved);
		return `data:${resolveAvatarMime(resolved)};base64,${buffer.toString("base64")}`;
	} catch {
		return;
	}
}
function formatSessionIdPrefix(sessionId, updatedAt) {
	const prefix = sessionId.slice(0, 8);
	if (updatedAt && updatedAt > 0) return `${prefix} (${new Date(updatedAt).toISOString().slice(0, 10)})`;
	return prefix;
}
function truncateTitle(text, maxLen) {
	if (text.length <= maxLen) return text;
	const cut = text.slice(0, maxLen - 1);
	const lastSpace = cut.lastIndexOf(" ");
	if (lastSpace > maxLen * .6) return cut.slice(0, lastSpace) + "…";
	return cut + "…";
}
function deriveSessionTitle(entry, firstUserMessage) {
	if (!entry) return;
	if (entry.displayName?.trim()) return entry.displayName.trim();
	if (entry.subject?.trim()) return entry.subject.trim();
	if (firstUserMessage?.trim()) return truncateTitle(firstUserMessage.replace(/\s+/g, " ").trim(), DERIVED_TITLE_MAX_LEN);
	if (entry.sessionId) return formatSessionIdPrefix(entry.sessionId, entry.updatedAt);
}
/**
* Repair a session entry whose sessionFile points to a non-existent transcript.
* Scans the sessions directory for valid .jsonl files and returns the most recent
* one with actual content. This handles the case where session reset updates
* sessions.json with a new sessionId but the transcript file wasn't created.
*/
function repairMissingSessionFile(params) {
	const { entry, storePath, agentId } = params;
	if (resolveSessionTranscriptCandidates(entry.sessionId, storePath, entry.sessionFile, agentId).find((p) => fs.existsSync(p))) return {
		repairedFile: null,
		repairedSessionId: null
	};
	const sessionsDir = path.dirname(storePath);
	let files;
	try {
		files = fs.readdirSync(sessionsDir, { withFileTypes: true });
	} catch {
		return {
			repairedFile: null,
			repairedSessionId: null
		};
	}
	const jsonlFiles = [];
	for (const dirent of files) {
		if (!dirent.isFile() || !dirent.name.endsWith(".jsonl")) continue;
		if (dirent.name.includes(".bak.") || dirent.name.includes(".reset.") || dirent.name.includes(".deleted.")) continue;
		const filePath = path.join(sessionsDir, dirent.name);
		try {
			const stat = fs.statSync(filePath);
			if (stat.size > 0) jsonlFiles.push({
				name: dirent.name,
				path: filePath,
				mtimeMs: stat.mtimeMs,
				size: stat.size
			});
		} catch {}
	}
	if (jsonlFiles.length === 0) return {
		repairedFile: null,
		repairedSessionId: null
	};
	jsonlFiles.sort((a, b) => b.mtimeMs - a.mtimeMs);
	const mostRecent = jsonlFiles[0];
	const sessionIdMatch = mostRecent.name.match(/^([a-f0-9-]{36})\.jsonl$/i);
	if (!sessionIdMatch) return {
		repairedFile: null,
		repairedSessionId: null
	};
	const repairedSessionId = sessionIdMatch[1];
	log.info("repaired missing session file", {
		originalSessionId: entry.sessionId,
		repairedSessionId,
		repairedFile: mostRecent.path
	});
	return {
		repairedFile: mostRecent.path,
		repairedSessionId
	};
}
/**
* Persist a session file repair to the sessions.json store.
* Called asynchronously to avoid blocking the current request.
*/
function persistSessionFileRepair(params) {
	const { storePath, sessionKey, sessionFile, sessionId } = params;
	setImmediate(async () => {
		try {
			const store = loadSessionStore(storePath, { skipCache: true });
			const entry = store[sessionKey];
			if (entry) {
				entry.sessionFile = sessionFile;
				entry.sessionId = sessionId;
				entry.updatedAt = Date.now();
				const json = JSON.stringify(store, null, 2);
				await fs.promises.writeFile(storePath, json, "utf-8");
				log.info("persisted session file repair", {
					sessionKey,
					sessionId
				});
			}
		} catch (err) {
			log.warn("failed to persist session file repair", {
				sessionKey,
				error: String(err)
			});
		}
	});
}
function loadSessionEntry(sessionKey) {
	const cfg = loadConfig();
	const sessionCfg = cfg.session;
	const canonicalKey = resolveSessionStoreKey({
		cfg,
		sessionKey
	});
	const agentId = resolveSessionStoreAgentId(cfg, canonicalKey);
	const storePath = resolveStorePath(sessionCfg?.store, { agentId });
	const store = loadSessionStore(storePath);
	const match = findStoreMatch(store, canonicalKey, sessionKey.trim());
	const legacyKey = match?.key !== canonicalKey ? match?.key : void 0;
	let entry = match?.entry;
	if (entry?.sessionId) {
		const repair = repairMissingSessionFile({
			entry,
			storePath,
			agentId
		});
		if (repair.repairedFile && repair.repairedSessionId) {
			entry = {
				...entry,
				sessionFile: repair.repairedFile,
				sessionId: repair.repairedSessionId
			};
			persistSessionFileRepair({
				storePath,
				sessionKey: match?.key ?? canonicalKey,
				sessionFile: repair.repairedFile,
				sessionId: repair.repairedSessionId
			});
		}
	}
	return {
		cfg,
		storePath,
		store,
		entry,
		canonicalKey,
		legacyKey
	};
}
/**
* Find a session entry by exact or case-insensitive key match.
* Returns both the entry and the actual store key it was found under,
* so callers can clean up legacy mixed-case keys when they differ from canonicalKey.
*/
function findStoreMatch(store, ...candidates) {
	for (const candidate of candidates) if (candidate && store[candidate]) return {
		entry: store[candidate],
		key: candidate
	};
	const loweredSet = new Set(candidates.filter(Boolean).map((c) => c.toLowerCase()));
	for (const key of Object.keys(store)) if (loweredSet.has(key.toLowerCase())) return {
		entry: store[key],
		key
	};
}
/**
* Find all on-disk store keys that match the given key case-insensitively.
* Returns every key from the store whose lowercased form equals the target's lowercased form.
*/
function findStoreKeysIgnoreCase(store, targetKey) {
	const lowered = targetKey.toLowerCase();
	const matches = [];
	for (const key of Object.keys(store)) if (key.toLowerCase() === lowered) matches.push(key);
	return matches;
}
/**
* Remove legacy key variants for one canonical session key.
* Candidates can include aliases (for example, "agent:ops:main" when canonical is "agent:ops:work").
*/
function pruneLegacyStoreKeys(params) {
	const keysToDelete = /* @__PURE__ */ new Set();
	for (const candidate of params.candidates) {
		const trimmed = String(candidate ?? "").trim();
		if (!trimmed) continue;
		if (trimmed !== params.canonicalKey) keysToDelete.add(trimmed);
		for (const match of findStoreKeysIgnoreCase(params.store, trimmed)) if (match !== params.canonicalKey) keysToDelete.add(match);
	}
	for (const key of keysToDelete) delete params.store[key];
}
function classifySessionKey(key, entry) {
	if (key === "global") return "global";
	if (key === "unknown") return "unknown";
	if (entry?.chatType === "group" || entry?.chatType === "channel") return "group";
	if (key.includes(":group:") || key.includes(":channel:")) return "group";
	return "direct";
}
function parseGroupKey(key) {
	const parts = (parseAgentSessionKey(key)?.rest ?? key).split(":").filter(Boolean);
	if (parts.length >= 3) {
		const [channel, kind, ...rest] = parts;
		if (kind === "group" || kind === "channel") return {
			channel,
			kind,
			id: rest.join(":")
		};
	}
	return null;
}
function isStorePathTemplate(store) {
	return typeof store === "string" && store.includes("{agentId}");
}
function listExistingAgentIdsFromDisk() {
	const root = resolveStateDir();
	const agentsDir = path.join(root, "agents");
	try {
		return fs.readdirSync(agentsDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => normalizeAgentId(entry.name)).filter(Boolean);
	} catch {
		return [];
	}
}
function listConfiguredAgentIds(cfg) {
	const agents = cfg.agents?.list ?? [];
	if (agents.length > 0) {
		const ids = /* @__PURE__ */ new Set();
		for (const entry of agents) if (entry?.id) ids.add(normalizeAgentId(entry.id));
		const defaultId = normalizeAgentId(resolveDefaultAgentId(cfg));
		ids.add(defaultId);
		const sorted = Array.from(ids).filter(Boolean);
		sorted.sort((a, b) => a.localeCompare(b));
		return sorted.includes(defaultId) ? [defaultId, ...sorted.filter((id) => id !== defaultId)] : sorted;
	}
	const ids = /* @__PURE__ */ new Set();
	const defaultId = normalizeAgentId(resolveDefaultAgentId(cfg));
	ids.add(defaultId);
	for (const id of listExistingAgentIdsFromDisk()) ids.add(id);
	const sorted = Array.from(ids).filter(Boolean);
	sorted.sort((a, b) => a.localeCompare(b));
	if (sorted.includes(defaultId)) return [defaultId, ...sorted.filter((id) => id !== defaultId)];
	return sorted;
}
function listAgentsForGateway(cfg) {
	const defaultId = normalizeAgentId(resolveDefaultAgentId(cfg));
	const mainKey = normalizeMainKey(cfg.session?.mainKey);
	const scope = cfg.session?.scope ?? "per-sender";
	const configuredById = /* @__PURE__ */ new Map();
	for (const entry of cfg.agents?.list ?? []) {
		if (!entry?.id) continue;
		const identity = entry.identity ? {
			name: entry.identity.name?.trim() || void 0,
			theme: entry.identity.theme?.trim() || void 0,
			emoji: entry.identity.emoji?.trim() || void 0,
			avatar: entry.identity.avatar?.trim() || void 0,
			avatarUrl: resolveIdentityAvatarUrl(cfg, normalizeAgentId(entry.id), entry.identity.avatar?.trim())
		} : void 0;
		configuredById.set(normalizeAgentId(entry.id), {
			name: typeof entry.name === "string" && entry.name.trim() ? entry.name.trim() : void 0,
			identity
		});
	}
	const explicitIds = new Set((cfg.agents?.list ?? []).map((entry) => entry?.id ? normalizeAgentId(entry.id) : "").filter(Boolean));
	const allowedIds = explicitIds.size > 0 ? new Set([...explicitIds, defaultId]) : null;
	let agentIds = listConfiguredAgentIds(cfg).filter((id) => allowedIds ? allowedIds.has(id) : true);
	if (mainKey && !agentIds.includes(mainKey) && (!allowedIds || allowedIds.has(mainKey))) agentIds = [...agentIds, mainKey];
	return {
		defaultId,
		mainKey,
		scope,
		agents: agentIds.map((id) => {
			const meta = configuredById.get(id);
			return {
				id,
				name: meta?.name,
				identity: meta?.identity
			};
		})
	};
}
function canonicalizeSessionKeyForAgent(agentId, key) {
	const lowered = key.toLowerCase();
	if (lowered === "global" || lowered === "unknown") return lowered;
	if (lowered.startsWith("agent:")) return lowered;
	return `agent:${normalizeAgentId(agentId)}:${lowered}`;
}
function resolveDefaultStoreAgentId(cfg) {
	return normalizeAgentId(resolveDefaultAgentId(cfg));
}
function resolveSessionStoreKey(params) {
	const raw = params.sessionKey.trim();
	if (!raw) return raw;
	const rawLower = raw.toLowerCase();
	if (rawLower === "global" || rawLower === "unknown") return rawLower;
	const parsed = parseAgentSessionKey(raw);
	if (parsed) {
		const agentId = normalizeAgentId(parsed.agentId);
		const lowered = raw.toLowerCase();
		const canonical = canonicalizeMainSessionAlias({
			cfg: params.cfg,
			agentId,
			sessionKey: lowered
		});
		if (canonical !== lowered) return canonical;
		return lowered;
	}
	const lowered = raw.toLowerCase();
	const rawMainKey = normalizeMainKey(params.cfg.session?.mainKey);
	if (lowered === "main" || lowered === rawMainKey) return resolveMainSessionKey(params.cfg);
	return canonicalizeSessionKeyForAgent(resolveDefaultStoreAgentId(params.cfg), lowered);
}
function resolveSessionStoreAgentId(cfg, canonicalKey) {
	if (canonicalKey === "global" || canonicalKey === "unknown") return resolveDefaultStoreAgentId(cfg);
	const parsed = parseAgentSessionKey(canonicalKey);
	if (parsed?.agentId) return normalizeAgentId(parsed.agentId);
	return resolveDefaultStoreAgentId(cfg);
}
function canonicalizeSpawnedByForAgent(cfg, agentId, spawnedBy) {
	const raw = spawnedBy?.trim();
	if (!raw) return;
	const lower = raw.toLowerCase();
	if (lower === "global" || lower === "unknown") return lower;
	let result;
	if (raw.toLowerCase().startsWith("agent:")) result = raw.toLowerCase();
	else result = `agent:${normalizeAgentId(agentId)}:${lower}`;
	const parsed = parseAgentSessionKey(result);
	return canonicalizeMainSessionAlias({
		cfg,
		agentId: parsed?.agentId ? normalizeAgentId(parsed.agentId) : agentId,
		sessionKey: result
	});
}
function resolveGatewaySessionStoreTarget(params) {
	const key = params.key.trim();
	const canonicalKey = resolveSessionStoreKey({
		cfg: params.cfg,
		sessionKey: key
	});
	const agentId = resolveSessionStoreAgentId(params.cfg, canonicalKey);
	const storeConfig = params.cfg.session?.store;
	const storePath = resolveStorePath(storeConfig, { agentId });
	if (canonicalKey === "global" || canonicalKey === "unknown") return {
		agentId,
		storePath,
		canonicalKey,
		storeKeys: key && key !== canonicalKey ? [canonicalKey, key] : [key]
	};
	const storeKeys = /* @__PURE__ */ new Set();
	storeKeys.add(canonicalKey);
	if (key && key !== canonicalKey) storeKeys.add(key);
	if (params.scanLegacyKeys !== false) {
		const scanTargets = new Set(storeKeys);
		if (canonicalKey === resolveAgentMainSessionKey({
			cfg: params.cfg,
			agentId
		})) scanTargets.add(`agent:${agentId}:main`);
		const store = params.store ?? loadSessionStore(storePath);
		for (const seed of scanTargets) for (const legacyKey of findStoreKeysIgnoreCase(store, seed)) storeKeys.add(legacyKey);
	}
	return {
		agentId,
		storePath,
		canonicalKey,
		storeKeys: Array.from(storeKeys)
	};
}
function mergeSessionEntryIntoCombined(params) {
	const { cfg, combined, entry, agentId, canonicalKey } = params;
	const existing = combined[canonicalKey];
	if (existing && (existing.updatedAt ?? 0) > (entry.updatedAt ?? 0)) combined[canonicalKey] = {
		...entry,
		...existing,
		spawnedBy: canonicalizeSpawnedByForAgent(cfg, agentId, existing.spawnedBy ?? entry.spawnedBy)
	};
	else combined[canonicalKey] = {
		...existing,
		...entry,
		spawnedBy: canonicalizeSpawnedByForAgent(cfg, agentId, entry.spawnedBy ?? existing?.spawnedBy)
	};
}
function loadCombinedSessionStoreForGateway(cfg) {
	const storeConfig = cfg.session?.store;
	if (storeConfig && !isStorePathTemplate(storeConfig)) {
		const storePath = resolveStorePath(storeConfig);
		const defaultAgentId = normalizeAgentId(resolveDefaultAgentId(cfg));
		const store = loadSessionStore(storePath);
		const combined = {};
		for (const [key, entry] of Object.entries(store)) mergeSessionEntryIntoCombined({
			cfg,
			combined,
			entry,
			agentId: defaultAgentId,
			canonicalKey: canonicalizeSessionKeyForAgent(defaultAgentId, key)
		});
		return {
			storePath,
			store: combined
		};
	}
	const agentIds = listConfiguredAgentIds(cfg);
	const combined = {};
	for (const agentId of agentIds) {
		const store = loadSessionStore(resolveStorePath(storeConfig, { agentId }));
		for (const [key, entry] of Object.entries(store)) mergeSessionEntryIntoCombined({
			cfg,
			combined,
			entry,
			agentId,
			canonicalKey: canonicalizeSessionKeyForAgent(agentId, key)
		});
	}
	return {
		storePath: typeof storeConfig === "string" && storeConfig.trim() ? storeConfig.trim() : "(multiple)",
		store: combined
	};
}
function getSessionDefaults(cfg) {
	const resolved = resolveConfiguredModelRef({
		cfg,
		defaultProvider: DEFAULT_PROVIDER,
		defaultModel: DEFAULT_MODEL
	});
	const contextTokens = cfg.agents?.defaults?.contextTokens ?? lookupContextTokens(resolved.model) ?? DEFAULT_CONTEXT_TOKENS;
	return {
		modelProvider: resolved.provider ?? null,
		model: resolved.model ?? null,
		contextTokens: contextTokens ?? null
	};
}
function resolveSessionModelRef(cfg, entry, agentId) {
	const resolved = agentId ? resolveDefaultModelForAgent({
		cfg,
		agentId
	}) : resolveConfiguredModelRef({
		cfg,
		defaultProvider: DEFAULT_PROVIDER,
		defaultModel: DEFAULT_MODEL
	});
	let provider = resolved.provider;
	let model = resolved.model;
	const runtimeModel = entry?.model?.trim();
	const runtimeProvider = entry?.modelProvider?.trim();
	if (runtimeModel) {
		const parsedRuntime = parseModelRef(runtimeModel, runtimeProvider || provider || DEFAULT_PROVIDER);
		if (parsedRuntime) {
			provider = parsedRuntime.provider;
			model = parsedRuntime.model;
		} else {
			provider = runtimeProvider || provider;
			model = runtimeModel;
		}
		return {
			provider,
			model
		};
	}
	const storedModelOverride = entry?.modelOverride?.trim();
	if (storedModelOverride) {
		const overrideProvider = entry?.providerOverride?.trim() || provider || DEFAULT_PROVIDER;
		const parsedOverride = parseModelRef(storedModelOverride, overrideProvider);
		if (parsedOverride) {
			provider = parsedOverride.provider;
			model = parsedOverride.model;
		} else {
			provider = overrideProvider;
			model = storedModelOverride;
		}
	}
	return {
		provider,
		model
	};
}
function listSessionsFromStore(params) {
	const { cfg, storePath, store, opts } = params;
	const now = Date.now();
	const includeGlobal = opts.includeGlobal === true;
	const includeUnknown = opts.includeUnknown === true;
	const includeDerivedTitles = opts.includeDerivedTitles === true;
	const includeLastMessage = opts.includeLastMessage === true;
	const spawnedBy = typeof opts.spawnedBy === "string" ? opts.spawnedBy : "";
	const label = typeof opts.label === "string" ? opts.label.trim() : "";
	const agentId = typeof opts.agentId === "string" ? normalizeAgentId(opts.agentId) : "";
	const search = typeof opts.search === "string" ? opts.search.trim().toLowerCase() : "";
	const activeMinutes = typeof opts.activeMinutes === "number" && Number.isFinite(opts.activeMinutes) ? Math.max(1, Math.floor(opts.activeMinutes)) : void 0;
	let sessions = Object.entries(store).filter(([key]) => {
		if (isCronRunSessionKey(key)) return false;
		if (!includeGlobal && key === "global") return false;
		if (!includeUnknown && key === "unknown") return false;
		if (agentId) {
			if (key === "global" || key === "unknown") return false;
			const parsed = parseAgentSessionKey(key);
			if (!parsed) return false;
			return normalizeAgentId(parsed.agentId) === agentId;
		}
		return true;
	}).filter(([key, entry]) => {
		if (!spawnedBy) return true;
		if (key === "unknown" || key === "global") return false;
		return entry?.spawnedBy === spawnedBy;
	}).filter(([, entry]) => {
		if (!label) return true;
		return entry?.label === label;
	}).map(([key, entry]) => {
		const updatedAt = entry?.updatedAt ?? null;
		const total = resolveFreshSessionTotalTokens(entry);
		const totalTokensFresh = typeof entry?.totalTokens === "number" ? entry?.totalTokensFresh !== false : false;
		const parsed = parseGroupKey(key);
		const channel = entry?.channel ?? parsed?.channel;
		const subject = entry?.subject;
		const groupChannel = entry?.groupChannel;
		const space = entry?.space;
		const id = parsed?.id;
		const origin = entry?.origin;
		const originLabel = origin?.label;
		const displayName = entry?.displayName ?? (channel ? buildGroupDisplayName({
			provider: channel,
			subject,
			groupChannel,
			space,
			id,
			key
		}) : void 0) ?? entry?.label ?? originLabel;
		const deliveryFields = normalizeSessionDeliveryFields(entry);
		const resolvedModel = resolveSessionModelRef(cfg, entry, normalizeAgentId(parseAgentSessionKey(key)?.agentId ?? resolveDefaultAgentId(cfg)));
		const modelProvider = resolvedModel.provider ?? DEFAULT_PROVIDER;
		const model = resolvedModel.model ?? DEFAULT_MODEL;
		return {
			key,
			entry,
			kind: classifySessionKey(key, entry),
			label: entry?.label,
			displayName,
			channel,
			subject,
			groupChannel,
			space,
			chatType: entry?.chatType,
			origin,
			updatedAt,
			sessionId: entry?.sessionId,
			systemSent: entry?.systemSent,
			abortedLastRun: entry?.abortedLastRun,
			thinkingLevel: entry?.thinkingLevel,
			verboseLevel: entry?.verboseLevel,
			reasoningLevel: entry?.reasoningLevel,
			elevatedLevel: entry?.elevatedLevel,
			sendPolicy: entry?.sendPolicy,
			inputTokens: entry?.inputTokens,
			outputTokens: entry?.outputTokens,
			totalTokens: total,
			totalTokensFresh,
			responseUsage: entry?.responseUsage,
			modelProvider,
			model,
			contextTokens: entry?.contextTokens,
			deliveryContext: deliveryFields.deliveryContext,
			lastChannel: deliveryFields.lastChannel ?? entry?.lastChannel,
			lastTo: deliveryFields.lastTo ?? entry?.lastTo,
			lastAccountId: deliveryFields.lastAccountId ?? entry?.lastAccountId
		};
	}).toSorted((a, b) => (b.updatedAt ?? 0) - (a.updatedAt ?? 0));
	if (search) sessions = sessions.filter((s) => {
		return [
			s.displayName,
			s.label,
			s.subject,
			s.sessionId,
			s.key
		].some((f) => typeof f === "string" && f.toLowerCase().includes(search));
	});
	if (activeMinutes !== void 0) {
		const cutoff = now - activeMinutes * 6e4;
		sessions = sessions.filter((s) => (s.updatedAt ?? 0) >= cutoff);
	}
	if (typeof opts.limit === "number" && Number.isFinite(opts.limit)) {
		const limit = Math.max(1, Math.floor(opts.limit));
		sessions = sessions.slice(0, limit);
	}
	const finalSessions = sessions.map((s) => {
		const { entry, ...rest } = s;
		let derivedTitle;
		let lastMessagePreview;
		if (entry?.sessionId) {
			if (includeDerivedTitles || includeLastMessage) {
				const parsed = parseAgentSessionKey(s.key);
				const agentId = parsed && parsed.agentId ? normalizeAgentId(parsed.agentId) : resolveDefaultAgentId(cfg);
				const fields = readSessionTitleFieldsFromTranscript(entry.sessionId, storePath, entry.sessionFile, agentId);
				if (includeDerivedTitles) derivedTitle = deriveSessionTitle(entry, fields.firstUserMessage);
				if (includeLastMessage && fields.lastMessagePreview) lastMessagePreview = fields.lastMessagePreview;
			}
		}
		return {
			...rest,
			derivedTitle,
			lastMessagePreview
		};
	});
	return {
		ts: now,
		path: storePath,
		count: finalSessions.length,
		defaults: getSessionDefaults(cfg),
		sessions: finalSessions
	};
}

//#endregion
export { loadCombinedSessionStoreForGateway as a, resolveGatewaySessionStoreTarget as c, listSessionsFromStore as i, resolveSessionModelRef as l, classifySessionKey as n, loadSessionEntry as o, listAgentsForGateway as r, pruneLegacyStoreKeys as s, canonicalizeSpawnedByForAgent as t, lookupContextTokens as u };