fix(resume): recover cleanly after Pi exits
This commit is contained in:
+2
-1
@@ -20,6 +20,7 @@ export interface BuildAppDeps {
|
||||
listModels?: ListModelsFn;
|
||||
getSettings?: () => Settings;
|
||||
readiness?: ReadinessManager;
|
||||
hub?: SseHub;
|
||||
}
|
||||
|
||||
export function buildApp(config: AppConfig, deps?: BuildAppDeps): FastifyInstance {
|
||||
@@ -39,7 +40,7 @@ export function buildApp(config: AppConfig, deps?: BuildAppDeps): FastifyInstanc
|
||||
dataRoot: config.dataRoot,
|
||||
});
|
||||
const mgr = deps?.mgr ?? new PiProcessManager(config, deps?.spawnFn ? { spawnFn: deps.spawnFn } : undefined);
|
||||
const hub = new SseHub();
|
||||
const hub = deps?.hub ?? new SseHub();
|
||||
const readiness = deps?.readiness ?? new ReadinessManager(
|
||||
tht as ThtRunner,
|
||||
Math.round(config.ollamaEnsureTimeoutMs / 1000),
|
||||
|
||||
@@ -33,7 +33,7 @@ export class SessionBridge {
|
||||
m.message?.role === "assistant" &&
|
||||
m.message?.stopReason === "error"
|
||||
) {
|
||||
this.state = "failed";
|
||||
this.markFailed();
|
||||
this.fan({
|
||||
type: "info",
|
||||
level: "error",
|
||||
@@ -69,6 +69,9 @@ export class SessionBridge {
|
||||
|
||||
beginTurn(): void { this.state = "running"; }
|
||||
|
||||
/** Record a backend-detected failure; callers own any sanitized client message. */
|
||||
markFailed(): void { this.state = "failed"; }
|
||||
|
||||
onClientEvent(cb: (e: ClientEvent) => void): void { this.cbs.add(cb); }
|
||||
|
||||
/** Eventi generati dal backend stesso (es. exit inatteso del child Pi), non da Pi. */
|
||||
|
||||
@@ -103,6 +103,7 @@ export class PiProcessManager {
|
||||
child.on("exit", (code) => {
|
||||
console.error(`[pi:${sessionId}] exited code=${code ?? "?"} mapped=${this.runtimes.get(sessionId) === rt}`);
|
||||
if (this.runtimes.get(sessionId) === rt) {
|
||||
rt.bridge.markFailed();
|
||||
this.runtimes.delete(sessionId);
|
||||
rt.bridge.emitClientEvent({
|
||||
type: "info",
|
||||
|
||||
@@ -106,8 +106,6 @@ export function sessionRoutes(
|
||||
if (state === "running" || state === "waiting") {
|
||||
return reply.code(200).send({ id, alreadyActive: true });
|
||||
}
|
||||
d.mgr.teardown(id);
|
||||
d.hub.clear(id);
|
||||
}
|
||||
const manifest = (await d.tht.sessionShow(id, d.getSettings().workspace)) as { status?: string; archived?: boolean } | null;
|
||||
if (manifest?.status === "finalized" || manifest?.archived) {
|
||||
@@ -124,6 +122,8 @@ export function sessionRoutes(
|
||||
author: getUser(req).id,
|
||||
mode: "resume" as const,
|
||||
};
|
||||
if (existing) d.mgr.teardown(id);
|
||||
d.hub.clear(id);
|
||||
await d.tht.reopenSession(id, settings.workspace);
|
||||
const rt = d.mgr.createFor(id, options);
|
||||
bindRuntime(id, rt);
|
||||
|
||||
Reference in New Issue
Block a user