fix(coding-agent): cap resume session metadata loads
closes #4583 closes #4591
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed `--resume` session listing to cap in-flight session metadata loads and avoid OOM on large session histories ([#4583](https://github.com/earendil-works/pi/issues/4583)).
|
||||
- Fixed interactive error messages to render with trailing spacing so reload errors do not run into resource listings ([#4510](https://github.com/earendil-works/pi/issues/4510)).
|
||||
- Fixed nested code fences in the Termux setup documentation so the example AGENTS.md renders correctly ([#4503](https://github.com/earendil-works/pi/issues/4503)).
|
||||
- Fixed tool output expansion while extension confirmation dialogs are focused ([#4429](https://github.com/earendil-works/pi/issues/4429)).
|
||||
|
||||
@@ -617,6 +617,48 @@ async function buildSessionInfo(filePath: string): Promise<SessionInfo | null> {
|
||||
|
||||
export type SessionListProgress = (loaded: number, total: number) => void;
|
||||
|
||||
const MAX_CONCURRENT_SESSION_INFO_LOADS = 10;
|
||||
|
||||
async function buildSessionInfosWithConcurrency(
|
||||
files: string[],
|
||||
onLoaded: () => void,
|
||||
): Promise<(SessionInfo | null)[]> {
|
||||
const results: (SessionInfo | null)[] = new Array(files.length).fill(null);
|
||||
const inFlight = new Set<Promise<void>>();
|
||||
let nextIndex = 0;
|
||||
|
||||
const startNext = (): void => {
|
||||
const index = nextIndex++;
|
||||
const file = files[index];
|
||||
if (!file) return;
|
||||
|
||||
let task: Promise<void>;
|
||||
task = buildSessionInfo(file)
|
||||
.then((info) => {
|
||||
results[index] = info;
|
||||
})
|
||||
.catch(() => {
|
||||
results[index] = null;
|
||||
})
|
||||
.finally(() => {
|
||||
inFlight.delete(task);
|
||||
onLoaded();
|
||||
});
|
||||
inFlight.add(task);
|
||||
};
|
||||
|
||||
while (nextIndex < files.length || inFlight.size > 0) {
|
||||
while (nextIndex < files.length && inFlight.size < MAX_CONCURRENT_SESSION_INFO_LOADS) {
|
||||
startNext();
|
||||
}
|
||||
if (inFlight.size > 0) {
|
||||
await Promise.race(inFlight);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
async function listSessionsFromDir(
|
||||
dir: string,
|
||||
onProgress?: SessionListProgress,
|
||||
@@ -634,14 +676,10 @@ async function listSessionsFromDir(
|
||||
const total = progressTotal ?? files.length;
|
||||
|
||||
let loaded = 0;
|
||||
const results = await Promise.all(
|
||||
files.map(async (file) => {
|
||||
const info = await buildSessionInfo(file);
|
||||
loaded++;
|
||||
onProgress?.(progressOffset + loaded, total);
|
||||
return info;
|
||||
}),
|
||||
);
|
||||
const results = await buildSessionInfosWithConcurrency(files, () => {
|
||||
loaded++;
|
||||
onProgress?.(progressOffset + loaded, total);
|
||||
});
|
||||
for (const info of results) {
|
||||
if (info) {
|
||||
sessions.push(info);
|
||||
@@ -1400,14 +1438,10 @@ export class SessionManager {
|
||||
const sessions: SessionInfo[] = [];
|
||||
const allFiles = dirFiles.flat();
|
||||
|
||||
const results = await Promise.all(
|
||||
allFiles.map(async (file) => {
|
||||
const info = await buildSessionInfo(file);
|
||||
loaded++;
|
||||
onProgress?.(loaded, totalFiles);
|
||||
return info;
|
||||
}),
|
||||
);
|
||||
const results = await buildSessionInfosWithConcurrency(allFiles, () => {
|
||||
loaded++;
|
||||
onProgress?.(loaded, totalFiles);
|
||||
});
|
||||
|
||||
for (const info of results) {
|
||||
if (info) {
|
||||
|
||||
Reference in New Issue
Block a user