feat(client): surface subagent activity in sidebar
This commit is contained in:
@@ -15,6 +15,8 @@ export { SlotsService } from './slots.ts'
|
||||
export type { RootOwnerProps } from './slots.ts'
|
||||
export { SessionCreateError, SessionsService, scopeOf, workspaceTitleOf } from './sessions/service.ts'
|
||||
export { SessionHistoryService } from './session-history/service.ts'
|
||||
export { indexSubagentDescendants } from './sessions/subagent-lineage.ts'
|
||||
export type { SubagentDescendantSummary } from './sessions/subagent-lineage.ts'
|
||||
// The provide channel is shared with the client test runtime (one
|
||||
// materialization/projection implementation; no test-side mirror to drift).
|
||||
export { SessionProvideChannel } from './sessions/provide.ts'
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Pure subagent-lineage aggregation over the retained session-list mirror.
|
||||
* Ordinary forks terminate propagation so each visible session owns only its
|
||||
* uninterrupted subagent subtree.
|
||||
* @module @deepseek-ai/dsh-client-runtime/client/sessions/subagent-lineage
|
||||
*/
|
||||
import type { SessionId } from '@deepseek-ai/dsh-client-connection/client'
|
||||
import type { SessionSummary } from './service.ts'
|
||||
|
||||
/** Descendant counts projected for one possible parent session. */
|
||||
export interface SubagentDescendantSummary {
|
||||
/** All descendants connected through uninterrupted subagent-origin lineage. */
|
||||
readonly count: number
|
||||
/** Descendants whose exact session summary is currently running. */
|
||||
readonly runningCount: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Index every subagent descendant under each ancestor it reaches through an
|
||||
* uninterrupted subagent-origin chain. Cycles fail soft and orphan owners
|
||||
* remain harmless map keys until their summaries arrive.
|
||||
* @param summaries - retained session summaries keyed by id.
|
||||
* @returns descendant totals and running totals keyed by possible parent id.
|
||||
*/
|
||||
export function indexSubagentDescendants(
|
||||
summaries: Readonly<Record<SessionId, SessionSummary>>,
|
||||
): ReadonlyMap<SessionId, SubagentDescendantSummary> {
|
||||
const indexed = new Map<SessionId, { count: number; runningCount: number }>()
|
||||
for (const descendant of Object.values(summaries)) {
|
||||
if (descendant.origin !== 'subagent') continue
|
||||
const seen = new Set<SessionId>()
|
||||
let current: SessionSummary | undefined = descendant
|
||||
while (current?.origin === 'subagent' && current.parentId !== undefined
|
||||
&& !seen.has(current.id)) {
|
||||
seen.add(current.id)
|
||||
const aggregate = indexed.get(current.parentId)
|
||||
if (aggregate === undefined) {
|
||||
indexed.set(current.parentId, {
|
||||
count: 1,
|
||||
runningCount: descendant.running ? 1 : 0,
|
||||
})
|
||||
} else {
|
||||
aggregate.count += 1
|
||||
if (descendant.running) aggregate.runningCount += 1
|
||||
}
|
||||
current = summaries[current.parentId]
|
||||
}
|
||||
}
|
||||
return indexed
|
||||
}
|
||||
Reference in New Issue
Block a user