mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-04 07:33:18 +00:00
fix(pi): require Reload after the native process exits (#8718)
Reject new turns before accepting work into a known dead Pi runtime. Keep process liveness separate from explicit session cleanup so Reload can still release resources and resume the conversation. Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
This commit is contained in:
@@ -2194,6 +2194,33 @@ describe("PiRpcAgentSession", () => {
|
||||
});
|
||||
});
|
||||
|
||||
test.each([false, true])(
|
||||
"rejects new turns with Reload guidance after the Pi process exits (active: %s)",
|
||||
async (active) => {
|
||||
const { pi, session, events } = await createSession();
|
||||
try {
|
||||
if (active) {
|
||||
await session.startTurn("before crash");
|
||||
}
|
||||
const runtime = pi.latestSession();
|
||||
runtime.emit({ type: "process_exit", error: "Pi exited" });
|
||||
if (active) {
|
||||
await expect(events.nextTurnFailure()).resolves.toMatchObject({ error: "Pi exited" });
|
||||
}
|
||||
const promptCount = runtime.prompts.length;
|
||||
|
||||
for (let attempt = 0; attempt < 2; attempt += 1) {
|
||||
await expect(session.startTurn("after crash")).rejects.toThrow(
|
||||
"Pi process exited. Reload agent before sending another message.",
|
||||
);
|
||||
}
|
||||
expect(runtime.prompts).toHaveLength(promptCount);
|
||||
} finally {
|
||||
await session.close();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
test("fails an autonomous turn when the Pi process exits before settlement", async () => {
|
||||
const { pi, events } = await createSession();
|
||||
const fakeSession = pi.latestSession();
|
||||
|
||||
@@ -1223,6 +1223,7 @@ export class PiRpcAgentSession implements AgentSession {
|
||||
private readonly logger: Logger;
|
||||
private readonly usagePoller: PiUsagePoller;
|
||||
private closed = false;
|
||||
private runtimeDead = false;
|
||||
private readonly closeController = new AbortController();
|
||||
private readonly pendingExtensionHydrations = new Set<Promise<void>>();
|
||||
private pendingOutput: Promise<void> | null = null;
|
||||
@@ -1305,6 +1306,9 @@ export class PiRpcAgentSession implements AgentSession {
|
||||
}
|
||||
|
||||
async startTurn(prompt: AgentPromptInput, options?: AgentRunOptions): Promise<StartTurnResult> {
|
||||
if (this.runtimeDead) {
|
||||
throw new Error("Pi process exited. Reload agent before sending another message.");
|
||||
}
|
||||
if (this.activeTurnId) {
|
||||
throw new Error("A Pi turn is already active");
|
||||
}
|
||||
@@ -2190,6 +2194,7 @@ export class PiRpcAgentSession implements AgentSession {
|
||||
}
|
||||
|
||||
private handleProcessExit(error: string): void {
|
||||
this.runtimeDead = true;
|
||||
this.rejectAllExtensionResults(new Error(error));
|
||||
this.interruptingTurn = null;
|
||||
if (!this.activeTurnId && !this.activeTurnStarted) {
|
||||
|
||||
Reference in New Issue
Block a user