From 23ae6243747e5e0f55cad8691e78ac6265fb4e00 Mon Sep 17 00:00:00 2001 From: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com> Date: Sat, 2 May 2026 19:51:37 +0000 Subject: [PATCH] fix(gateway): reuse subagent registry snapshot in session listing --- src/gateway/session-utils.ts | 42 ++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/src/gateway/session-utils.ts b/src/gateway/session-utils.ts index 2f89a956b44..519682cd4e1 100644 --- a/src/gateway/session-utils.ts +++ b/src/gateway/session-utils.ts @@ -381,9 +381,9 @@ function resolveRuntimeChildSessionKeys( ): string[] | undefined { const childSessionKeys = new Set(); const controllerKey = controllerSessionKey.trim(); - const runs = - subagentRuns?.runsByControllerSessionKey.get(controllerKey) ?? - listSubagentRunsForController(controllerSessionKey); + const runs = subagentRuns + ? (subagentRuns.runsByControllerSessionKey.get(controllerKey) ?? []) + : listSubagentRunsForController(controllerSessionKey); for (const entry of runs) { const childSessionKey = normalizeOptionalString(entry.childSessionKey); if (!childSessionKey) { @@ -1919,11 +1919,21 @@ export function listSessionsFromStore(params: { const now = Date.now(); const sessionListTranscriptUsageMaxBytes = 64 * 1024; const sessionListTranscriptFieldRows = 100; - const rowContext = buildSessionListRowContext({ store, now }); + let rowContext: SessionListRowContext | undefined; + const getRowContext = () => { + rowContext ??= buildSessionListRowContext({ store, now }); + return rowContext; + }; const includeDerivedTitles = opts.includeDerivedTitles === true; const includeLastMessage = opts.includeLastMessage === true; + const hasSpawnedByFilter = typeof opts.spawnedBy === "string" && opts.spawnedBy.length > 0; - const entries = filterAndSortSessionEntries({ store, opts, now, rowContext }); + const entries = filterAndSortSessionEntries({ + store, + opts, + now, + rowContext: hasSpawnedByFilter ? getRowContext() : undefined, + }); const sessions = entries.map(([key, entry], index) => { const includeTranscriptFields = index < sessionListTranscriptFieldRows; @@ -1938,8 +1948,8 @@ export function listSessionsFromStore(params: { includeDerivedTitles: includeTranscriptFields && includeDerivedTitles, includeLastMessage: includeTranscriptFields && includeLastMessage, transcriptUsageMaxBytes: sessionListTranscriptUsageMaxBytes, - storeChildSessionsByKey: rowContext.storeChildSessionsByKey, - rowContext, + storeChildSessionsByKey: getRowContext().storeChildSessionsByKey, + rowContext: getRowContext(), }); }); @@ -1973,11 +1983,21 @@ export async function listSessionsFromStoreAsync(params: { const now = Date.now(); const sessionListTranscriptUsageMaxBytes = 64 * 1024; const sessionListTranscriptFieldRows = 100; - const rowContext = buildSessionListRowContext({ store, now }); + let rowContext: SessionListRowContext | undefined; + const getRowContext = () => { + rowContext ??= buildSessionListRowContext({ store, now }); + return rowContext; + }; const includeDerivedTitles = opts.includeDerivedTitles === true; const includeLastMessage = opts.includeLastMessage === true; + const hasSpawnedByFilter = typeof opts.spawnedBy === "string" && opts.spawnedBy.length > 0; - const entries = filterAndSortSessionEntries({ store, opts, now, rowContext }); + const entries = filterAndSortSessionEntries({ + store, + opts, + now, + rowContext: hasSpawnedByFilter ? getRowContext() : undefined, + }); const sessions: GatewaySessionRow[] = []; for (let i = 0; i < entries.length; i++) { @@ -1994,8 +2014,8 @@ export async function listSessionsFromStoreAsync(params: { includeDerivedTitles: false, includeLastMessage: false, transcriptUsageMaxBytes: sessionListTranscriptUsageMaxBytes, - storeChildSessionsByKey: rowContext.storeChildSessionsByKey, - rowContext, + storeChildSessionsByKey: getRowContext().storeChildSessionsByKey, + rowContext: getRowContext(), }); if ( entry?.sessionId &&