fix(coding-agent): cap resume session metadata loads
closes #4583 closes #4591
This commit is contained in:
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
### Fixed
|
### 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 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 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)).
|
- 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;
|
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(
|
async function listSessionsFromDir(
|
||||||
dir: string,
|
dir: string,
|
||||||
onProgress?: SessionListProgress,
|
onProgress?: SessionListProgress,
|
||||||
@@ -634,14 +676,10 @@ async function listSessionsFromDir(
|
|||||||
const total = progressTotal ?? files.length;
|
const total = progressTotal ?? files.length;
|
||||||
|
|
||||||
let loaded = 0;
|
let loaded = 0;
|
||||||
const results = await Promise.all(
|
const results = await buildSessionInfosWithConcurrency(files, () => {
|
||||||
files.map(async (file) => {
|
loaded++;
|
||||||
const info = await buildSessionInfo(file);
|
onProgress?.(progressOffset + loaded, total);
|
||||||
loaded++;
|
});
|
||||||
onProgress?.(progressOffset + loaded, total);
|
|
||||||
return info;
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
for (const info of results) {
|
for (const info of results) {
|
||||||
if (info) {
|
if (info) {
|
||||||
sessions.push(info);
|
sessions.push(info);
|
||||||
@@ -1400,14 +1438,10 @@ export class SessionManager {
|
|||||||
const sessions: SessionInfo[] = [];
|
const sessions: SessionInfo[] = [];
|
||||||
const allFiles = dirFiles.flat();
|
const allFiles = dirFiles.flat();
|
||||||
|
|
||||||
const results = await Promise.all(
|
const results = await buildSessionInfosWithConcurrency(allFiles, () => {
|
||||||
allFiles.map(async (file) => {
|
loaded++;
|
||||||
const info = await buildSessionInfo(file);
|
onProgress?.(loaded, totalFiles);
|
||||||
loaded++;
|
});
|
||||||
onProgress?.(loaded, totalFiles);
|
|
||||||
return info;
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
for (const info of results) {
|
for (const info of results) {
|
||||||
if (info) {
|
if (info) {
|
||||||
|
|||||||
Reference in New Issue
Block a user