




























@@ -50,6 +50,191 @@ export function listRunsForControllerFromRuns(
5050return [...runs.values()].filter((entry) => resolveControllerSessionKey(entry) === key);
5151}
525253+type LatestRunPair = {
54+runId: string;
55+entry: SubagentRunRecord;
56+};
57+58+export type SubagentRunReadIndex = {
59+getDisplaySubagentRun(childSessionKey: string): SubagentRunRecord | null;
60+countActiveDescendantRuns(rootSessionKey: string): number;
61+runsByControllerSessionKey: ReadonlyMap<string, readonly SubagentRunRecord[]>;
62+};
63+64+function rememberLatestRunEntry(
65+map: Map<string, SubagentRunRecord>,
66+key: string,
67+entry: SubagentRunRecord,
68+): void {
69+const existing = map.get(key);
70+if (!existing || entry.createdAt > existing.createdAt) {
71+map.set(key, entry);
72+}
73+}
74+75+function rememberLatestRunPair(
76+map: Map<string, LatestRunPair>,
77+key: string,
78+runId: string,
79+entry: SubagentRunRecord,
80+): void {
81+const existing = map.get(key);
82+if (!existing || entry.createdAt > existing.entry.createdAt) {
83+map.set(key, { runId, entry });
84+}
85+}
86+87+export function buildSubagentRunReadIndexFromRuns(params: {
88+runs: Map<string, SubagentRunRecord>;
89+inMemoryRuns?: Iterable<SubagentRunRecord>;
90+now?: number;
91+}): SubagentRunReadIndex {
92+const { runs } = params;
93+const now = params.now ?? Date.now();
94+const inMemoryDisplayByChildSessionKey = new Map<
95+string,
96+{
97+latestInMemoryActive: SubagentRunRecord | null;
98+latestInMemoryEnded: SubagentRunRecord | null;
99+}
100+>();
101+const latestSnapshotActiveByChildSessionKey = new Map<string, SubagentRunRecord>();
102+const latestSnapshotEndedByChildSessionKey = new Map<string, SubagentRunRecord>();
103+const latestRunByChildSessionKey = new Map<string, LatestRunPair>();
104+const runsByControllerSessionKey = new Map<string, SubagentRunRecord[]>();
105+const latestRunByRequesterAndChildSessionKey = new Map<string, Map<string, LatestRunPair>>();
106+const activeDescendantCountBySessionKey = new Map<string, number>();
107+108+for (const entry of params.inMemoryRuns ?? []) {
109+const childSessionKey = entry.childSessionKey.trim();
110+if (!childSessionKey) {
111+continue;
112+}
113+let display = inMemoryDisplayByChildSessionKey.get(childSessionKey);
114+if (!display) {
115+display = { latestInMemoryActive: null, latestInMemoryEnded: null };
116+inMemoryDisplayByChildSessionKey.set(childSessionKey, display);
117+}
118+if (hasSubagentRunEnded(entry)) {
119+if (!display.latestInMemoryEnded || entry.createdAt > display.latestInMemoryEnded.createdAt) {
120+display.latestInMemoryEnded = entry;
121+}
122+continue;
123+}
124+if (!display.latestInMemoryActive || entry.createdAt > display.latestInMemoryActive.createdAt) {
125+display.latestInMemoryActive = entry;
126+}
127+}
128+129+for (const [runId, entry] of runs.entries()) {
130+const childSessionKey = entry.childSessionKey.trim();
131+const controllerSessionKey = resolveControllerSessionKey(entry);
132+if (controllerSessionKey) {
133+let controllerRuns = runsByControllerSessionKey.get(controllerSessionKey);
134+if (!controllerRuns) {
135+controllerRuns = [];
136+runsByControllerSessionKey.set(controllerSessionKey, controllerRuns);
137+}
138+controllerRuns.push(entry);
139+}
140+if (!childSessionKey) {
141+continue;
142+}
143+if (isLiveUnendedSubagentRun(entry, now)) {
144+rememberLatestRunEntry(latestSnapshotActiveByChildSessionKey, childSessionKey, entry);
145+} else {
146+rememberLatestRunEntry(latestSnapshotEndedByChildSessionKey, childSessionKey, entry);
147+}
148+rememberLatestRunPair(latestRunByChildSessionKey, childSessionKey, runId, entry);
149+150+const requesterSessionKey = entry.requesterSessionKey;
151+if (!requesterSessionKey) {
152+continue;
153+}
154+let latestByChild = latestRunByRequesterAndChildSessionKey.get(requesterSessionKey);
155+if (!latestByChild) {
156+latestByChild = new Map<string, LatestRunPair>();
157+latestRunByRequesterAndChildSessionKey.set(requesterSessionKey, latestByChild);
158+}
159+rememberLatestRunPair(latestByChild, childSessionKey, runId, entry);
160+}
161+162+const getDisplaySubagentRun = (childSessionKey: string): SubagentRunRecord | null => {
163+const key = childSessionKey.trim();
164+if (!key) {
165+return null;
166+}
167+const inMemoryDisplay = inMemoryDisplayByChildSessionKey.get(key);
168+if (inMemoryDisplay) {
169+const latestInMemoryEnded = inMemoryDisplay.latestInMemoryEnded;
170+const latestInMemoryActive = inMemoryDisplay.latestInMemoryActive;
171+if (latestInMemoryEnded || latestInMemoryActive) {
172+if (
173+latestInMemoryEnded &&
174+(!latestInMemoryActive || latestInMemoryEnded.createdAt > latestInMemoryActive.createdAt)
175+) {
176+return latestInMemoryEnded;
177+}
178+return latestInMemoryActive ?? latestInMemoryEnded;
179+}
180+}
181+return (
182+latestSnapshotActiveByChildSessionKey.get(key) ??
183+latestSnapshotEndedByChildSessionKey.get(key) ??
184+null
185+);
186+};
187+188+const countActiveDescendantRuns = (rootSessionKey: string): number => {
189+const root = rootSessionKey.trim();
190+if (!root) {
191+return 0;
192+}
193+if (activeDescendantCountBySessionKey.has(root)) {
194+return activeDescendantCountBySessionKey.get(root) ?? 0;
195+}
196+let count = 0;
197+const pending = [root];
198+const visited = new Set<string>([root]);
199+for (let index = 0; index < pending.length; index += 1) {
200+const requester = pending[index];
201+if (!requester) {
202+continue;
203+}
204+const latestByChild = latestRunByRequesterAndChildSessionKey.get(requester);
205+if (!latestByChild) {
206+continue;
207+}
208+for (const [childSessionKey, pair] of latestByChild.entries()) {
209+const latestForChildSession = latestRunByChildSessionKey.get(childSessionKey);
210+if (
211+!latestForChildSession ||
212+latestForChildSession.runId !== pair.runId ||
213+latestForChildSession.entry.requesterSessionKey !== requester
214+) {
215+continue;
216+}
217+if (isLiveUnendedSubagentRun(pair.entry, now)) {
218+count += 1;
219+}
220+if (!childSessionKey || visited.has(childSessionKey)) {
221+continue;
222+}
223+visited.add(childSessionKey);
224+pending.push(childSessionKey);
225+}
226+}
227+activeDescendantCountBySessionKey.set(root, count);
228+return count;
229+};
230+231+return {
232+ getDisplaySubagentRun,
233+ countActiveDescendantRuns,
234+ runsByControllerSessionKey,
235+};
236+}
237+53238function findLatestRunForChildSession(
54239runs: Map<string, SubagentRunRecord>,
55240childSessionKey: string,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。