fix(background): replay persisted updates before launch order
This commit is contained in:
19
index.ts
19
index.ts
@@ -110,7 +110,9 @@ export default function subagentsExtension(pi: ExtensionAPI, deps: any = {}) {
|
|||||||
}, { triggerTurn: false });
|
}, { triggerTurn: false });
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// monitorRun errors are non-fatal here
|
// Monitoring runs happens in the background. Failures here should not
|
||||||
|
// block tool registration or the foreground session; monitorRun errors
|
||||||
|
// are best-effort and final failures are logged via result.json.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,18 +180,25 @@ export default function subagentsExtension(pi: ExtensionAPI, deps: any = {}) {
|
|||||||
// replay persisted runs if session manager provides entries
|
// replay persisted runs if session manager provides entries
|
||||||
try {
|
try {
|
||||||
const entries = ctx.sessionManager?.getEntries?.() ?? [];
|
const entries = ctx.sessionManager?.getEntries?.() ?? [];
|
||||||
// clear existing registry and rebuild from session entries
|
const launches: any[] = [];
|
||||||
registry.replay([]);
|
const updates: any[] = [];
|
||||||
|
|
||||||
for (const e of entries) {
|
for (const e of entries) {
|
||||||
const type = (e.type ?? e.customType) as string | undefined;
|
const type = (e.type ?? e.customType) as string | undefined;
|
||||||
if (type === "pi-subagents:bg-run") {
|
if (type === "pi-subagents:bg-run") {
|
||||||
const run = e.data?.run ?? e.data;
|
const run = e.data?.run ?? e.data;
|
||||||
if (run && run.runId) registry.recordLaunch(run as any);
|
if (run && run.runId) launches.push(run);
|
||||||
} else if (type === "pi-subagents:bg-update") {
|
} else if (type === "pi-subagents:bg-update") {
|
||||||
const data = e.data;
|
const data = e.data;
|
||||||
if (data && data.runId) registry.recordUpdate(data.runId, data as any);
|
if (data && data.runId) updates.push(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Rebuild in two passes so out-of-order persisted entries cannot drop
|
||||||
|
// terminal updates that happen to appear before their launch entry.
|
||||||
|
registry.replay([]);
|
||||||
|
for (const run of launches) registry.recordLaunch(run as any);
|
||||||
|
for (const update of updates) registry.recordUpdate(update.runId, update as any);
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
|
|
||||||
updateStatus();
|
updateStatus();
|
||||||
|
|||||||
@@ -535,3 +535,73 @@ test("background completion updates footer status, appends session updates, noti
|
|||||||
else process.env.PI_SUBAGENTS_CHILD = original;
|
else process.env.PI_SUBAGENTS_CHILD = original;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("session_start replay applies bg-update entries even when they appear before bg-run", async () => {
|
||||||
|
const original = process.env.PI_SUBAGENTS_CHILD;
|
||||||
|
if (original !== undefined) delete process.env.PI_SUBAGENTS_CHILD;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const handlers: any = {};
|
||||||
|
const registeredTools: any[] = [];
|
||||||
|
|
||||||
|
subagentsExtension({
|
||||||
|
on(event: string, handler: (event: any, ctx: any) => Promise<void> | void) {
|
||||||
|
handlers[event] = handler;
|
||||||
|
},
|
||||||
|
registerTool(tool: any) {
|
||||||
|
registeredTools.push(tool);
|
||||||
|
},
|
||||||
|
registerProvider() {},
|
||||||
|
appendEntry() {},
|
||||||
|
sendMessage() {},
|
||||||
|
} as any);
|
||||||
|
|
||||||
|
await handlers.session_start?.(
|
||||||
|
{ reason: "startup" },
|
||||||
|
{
|
||||||
|
modelRegistry: {
|
||||||
|
getAvailable: () => [{ provider: "openai", id: "gpt-5" }],
|
||||||
|
},
|
||||||
|
ui: {
|
||||||
|
notify() {},
|
||||||
|
setStatus() {},
|
||||||
|
},
|
||||||
|
sessionManager: {
|
||||||
|
getEntries: () => [
|
||||||
|
{
|
||||||
|
type: "pi-subagents:bg-update",
|
||||||
|
data: { runId: "run-1", status: "completed", exitCode: 0, finalText: "done" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "pi-subagents:bg-run",
|
||||||
|
data: {
|
||||||
|
run: {
|
||||||
|
runId: "run-1",
|
||||||
|
preset: "repo-scout",
|
||||||
|
task: "inspect auth",
|
||||||
|
status: "running",
|
||||||
|
startTime: Date.now(),
|
||||||
|
paths: {
|
||||||
|
eventsPath: "/tmp/run-1/events.jsonl",
|
||||||
|
resultPath: "/tmp/run-1/result.json",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const statusTool = registeredTools.find((tool) => tool.name === "background_agent_status");
|
||||||
|
assert(statusTool, "background_agent_status registered");
|
||||||
|
|
||||||
|
const result: any = await statusTool.execute("tool-1", { runId: "run-1" }, undefined, undefined, undefined);
|
||||||
|
assert.equal(result.details.runs.length, 1);
|
||||||
|
assert.equal(result.details.runs[0].status, "completed");
|
||||||
|
assert.equal(result.details.counts.completed, 1);
|
||||||
|
} finally {
|
||||||
|
if (original === undefined) delete process.env.PI_SUBAGENTS_CHILD;
|
||||||
|
else process.env.PI_SUBAGENTS_CHILD = original;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user