Preserve active subagents across reload
This commit is contained in:
@@ -30,6 +30,7 @@ import {
|
||||
uniqueId,
|
||||
trackTempFile,
|
||||
readScreen,
|
||||
sendCommand,
|
||||
PI_TIMEOUT,
|
||||
type TestEnv,
|
||||
} from "./harness.ts";
|
||||
@@ -103,6 +104,57 @@ for (const backend of backends) {
|
||||
}
|
||||
});
|
||||
|
||||
// ── Reload preservation ──
|
||||
|
||||
it("keeps a running subagent and fresh tool wrappers across parent extension reload", async () => {
|
||||
const id = uniqueId();
|
||||
const startedFile = `/tmp/pi-integ-reload-start-${id}.txt`;
|
||||
const completedFile = `/tmp/pi-integ-reload-done-${id}.txt`;
|
||||
const followupFile = `/tmp/pi-integ-reload-followup-${id}.txt`;
|
||||
trackTempFile(env, startedFile);
|
||||
trackTempFile(env, completedFile);
|
||||
trackTempFile(env, followupFile);
|
||||
|
||||
const surface = createTrackedSurface(env, `reload-${id}`);
|
||||
await sleep(1000);
|
||||
|
||||
const task = [
|
||||
`Call the subagent tool once with these EXACT parameters:`,
|
||||
` name: "Reload-${id}"`,
|
||||
` agent: "test-echo"`,
|
||||
` task: "Run: echo 'START_${id}' > '${startedFile}'; sleep 10; echo 'DONE_${id}' > '${completedFile}'"`,
|
||||
`Do not run the command yourself.`,
|
||||
`After that subagent result arrives, call the subagent tool once more with these EXACT parameters:`,
|
||||
` name: "Reload-followup-${id}"`,
|
||||
` agent: "test-echo"`,
|
||||
` task: "Write 'FOLLOWUP_${id}' to '${followupFile}'"`,
|
||||
`After the second subagent result arrives, say RELOAD_SURVIVED_${id}.`,
|
||||
].join("\n");
|
||||
|
||||
startPi(surface, env.dir, task);
|
||||
await waitForFile(startedFile, PI_TIMEOUT, /START_/);
|
||||
|
||||
sendCommand(surface, "/reload");
|
||||
|
||||
const completed = await waitForFile(completedFile, PI_TIMEOUT, /DONE_/);
|
||||
assert.ok(completed.includes(`DONE_${id}`), "child should finish after parent reload");
|
||||
const followup = await waitForFile(followupFile, PI_TIMEOUT, /FOLLOWUP_/);
|
||||
assert.ok(
|
||||
followup.includes(`FOLLOWUP_${id}`),
|
||||
"the result-triggered turn should spawn through the fresh tool wrapper",
|
||||
);
|
||||
|
||||
const resultMarker = `RELOAD_SURVIVED_${id}`;
|
||||
const responseLine = new RegExp(`^ ${resultMarker}\\s*$`, "m");
|
||||
const screen = await waitForScreen(surface, responseLine, PI_TIMEOUT, 300);
|
||||
assert.equal(
|
||||
screen.match(new RegExp(`^ ${resultMarker}\\s*$`, "gm"))?.length,
|
||||
1,
|
||||
"the fresh runtime should receive the completion exactly once",
|
||||
);
|
||||
assert.doesNotMatch(screen, /Subagent cancelled|ctx is stale after session replacement or reload/i);
|
||||
});
|
||||
|
||||
// ── In-progress activity snapshots ──
|
||||
|
||||
it("keeps a long active tool call from surfacing false stalled status", async () => {
|
||||
|
||||
Reference in New Issue
Block a user