@@ -333,9 +333,8 @@ function shouldKeepStoreOnlyChildLink(entry: SessionEntry, now: number): boolean
333333 ) ;
334334}
335335
336- function resolveChildSessionKeys (
336+ function resolveRuntimeChildSessionKeys (
337337 controllerSessionKey : string ,
338- store : Record < string , SessionEntry > ,
339338 now = Date . now ( ) ,
340339) : string [ ] | undefined {
341340 const childSessionKeys = new Set < string > ( ) ;
@@ -364,23 +363,47 @@ function resolveChildSessionKeys(
364363 }
365364 childSessionKeys . add ( childSessionKey ) ;
366365 }
366+ const childSessions = Array . from ( childSessionKeys ) ;
367+ return childSessions . length > 0 ? childSessions : undefined ;
368+ }
369+
370+ function addChildSessionKey (
371+ childSessionsByKey : Map < string , string [ ] > ,
372+ parentKey : string ,
373+ childKey : string ,
374+ ) {
375+ const current = childSessionsByKey . get ( parentKey ) ;
376+ if ( current ) {
377+ if ( ! current . includes ( childKey ) ) {
378+ current . push ( childKey ) ;
379+ }
380+ return ;
381+ }
382+ childSessionsByKey . set ( parentKey , [ childKey ] ) ;
383+ }
384+
385+ function buildStoreChildSessionIndex (
386+ store : Record < string , SessionEntry > ,
387+ now = Date . now ( ) ,
388+ ) : Map < string , string [ ] > {
389+ const childSessionsByKey = new Map < string , string [ ] > ( ) ;
367390 for ( const [ key , entry ] of Object . entries ( store ) ) {
368- if ( ! entry || key === controllerSessionKey ) {
391+ if ( ! entry ) {
369392 continue ;
370393 }
371- const spawnedBy = normalizeOptionalString ( entry . spawnedBy ) ;
372- const parentSessionKey = normalizeOptionalString ( entry . parentSessionKey ) ;
373- if ( spawnedBy !== controllerSessionKey && parentSessionKey !== controllerSessionKey ) {
394+ const parentKeys = [
395+ normalizeOptionalString ( entry . spawnedBy ) ,
396+ normalizeOptionalString ( entry . parentSessionKey ) ,
397+ ] . filter ( ( value ) : value is string => Boolean ( value ) && value !== key ) ;
398+ if ( parentKeys . length === 0 ) {
374399 continue ;
375400 }
376401 const latest = getSessionDisplaySubagentRunByChildSessionKey ( key ) ;
402+ let latestControllerSessionKey : string | undefined ;
377403 if ( latest ) {
378- const latestControllerSessionKey =
404+ latestControllerSessionKey =
379405 normalizeOptionalString ( latest . controllerSessionKey ) ||
380406 normalizeOptionalString ( latest . requesterSessionKey ) ;
381- if ( latestControllerSessionKey !== controllerSessionKey ) {
382- continue ;
383- }
384407 if (
385408 ! shouldKeepSubagentRunChildLink ( latest , {
386409 activeDescendants : countActiveDescendantRuns ( key ) ,
@@ -392,10 +415,37 @@ function resolveChildSessionKeys(
392415 } else if ( ! shouldKeepStoreOnlyChildLink ( entry , now ) ) {
393416 continue ;
394417 }
395- childSessionKeys . add ( key ) ;
418+ for ( const parentKey of parentKeys ) {
419+ if ( latestControllerSessionKey && latestControllerSessionKey !== parentKey ) {
420+ continue ;
421+ }
422+ addChildSessionKey ( childSessionsByKey , parentKey , key ) ;
423+ }
396424 }
397- const childSessions = Array . from ( childSessionKeys ) ;
398- return childSessions . length > 0 ? childSessions : undefined ;
425+ return childSessionsByKey ;
426+ }
427+
428+ function mergeChildSessionKeys (
429+ runtimeChildSessions : string [ ] | undefined ,
430+ storeChildSessions : string [ ] | undefined ,
431+ ) : string [ ] | undefined {
432+ if ( ! runtimeChildSessions ?. length ) {
433+ return storeChildSessions ?. length ? storeChildSessions : undefined ;
434+ }
435+ if ( ! storeChildSessions ?. length ) {
436+ return runtimeChildSessions ;
437+ }
438+ return Array . from ( new Set ( [ ...runtimeChildSessions , ...storeChildSessions ] ) ) ;
439+ }
440+
441+ function resolveChildSessionKeys (
442+ controllerSessionKey : string ,
443+ store : Record < string , SessionEntry > ,
444+ now = Date . now ( ) ,
445+ ) : string [ ] | undefined {
446+ const runtimeChildSessions = resolveRuntimeChildSessionKeys ( controllerSessionKey , now ) ;
447+ const storeChildSessions = buildStoreChildSessionIndex ( store , now ) . get ( controllerSessionKey ) ;
448+ return mergeChildSessionKeys ( runtimeChildSessions , storeChildSessions ) ;
399449}
400450
401451function resolveTranscriptUsageFallback ( params : {
@@ -1313,6 +1363,7 @@ export function buildGatewaySessionRow(params: {
13131363 includeDerivedTitles ?: boolean ;
13141364 includeLastMessage ?: boolean ;
13151365 transcriptUsageMaxBytes ?: number ;
1366+ storeChildSessionsByKey ?: Map < string , string [ ] > ;
13161367} ) : GatewaySessionRow {
13171368 const { cfg, storePath, store, key, entry } = params ;
13181369 const now = params . now ?? Date . now ( ) ;
@@ -1448,7 +1499,12 @@ export function buildGatewaySessionRow(params: {
14481499 typeof totalTokens === "number" && Number . isFinite ( totalTokens ) && totalTokens > 0
14491500 ? true
14501501 : transcriptUsage ?. totalTokensFresh === true ;
1451- const childSessions = resolveChildSessionKeys ( key , store , now ) ;
1502+ const childSessions = params . storeChildSessionsByKey
1503+ ? mergeChildSessionKeys (
1504+ resolveRuntimeChildSessionKeys ( key , now ) ,
1505+ params . storeChildSessionsByKey . get ( key ) ,
1506+ )
1507+ : resolveChildSessionKeys ( key , store , now ) ;
14521508 const latestCompactionCheckpoint = resolveLatestCompactionCheckpoint ( entry ) ;
14531509 const agentRuntime = resolveAgentRuntimeMetadata ( cfg , sessionAgentId ) ;
14541510 const selectedOrRuntimeModelProvider = selectedModel ?. provider ?? modelProvider ;
@@ -1630,6 +1686,7 @@ export function listSessionsFromStore(params: {
16301686 const now = Date . now ( ) ;
16311687 const sessionListTranscriptUsageMaxBytes = 64 * 1024 ;
16321688 const sessionListTranscriptFieldRows = 100 ;
1689+ const storeChildSessionsByKey = buildStoreChildSessionIndex ( store , now ) ;
16331690
16341691 const includeGlobal = opts . includeGlobal === true ;
16351692 const includeUnknown = opts . includeUnknown === true ;
@@ -1738,6 +1795,7 @@ export function listSessionsFromStore(params: {
17381795 includeDerivedTitles : includeTranscriptFields && includeDerivedTitles ,
17391796 includeLastMessage : includeTranscriptFields && includeLastMessage ,
17401797 transcriptUsageMaxBytes : sessionListTranscriptUsageMaxBytes ,
1798+ storeChildSessionsByKey,
17411799 } ) ;
17421800 } ) ;
17431801
0 commit comments