pi session context persistence, fix new session button, add clear all sessions
- handle pi process death by nulling piProcess ref so next message respawns - replay conversation history on respawn via --session flag - fix user message JSONL format to array for pi compatibility - fix container sessions mount to match storage path - fix ChatPanelWrapper: key on inner component so usePiChat resets on new session - add bulk delete sessions endpoint and clear all button in chat header Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -286,8 +286,37 @@ async function handleChat(
|
||||
if (!session.piProcess) {
|
||||
try {
|
||||
const onEvent = createEventHandler(sessionId, model, cwd, homeDir);
|
||||
session.piProcess = await piBridge.spawnPi(cwd, model, userId, email, onEvent, sandboxed ? { userId, username, email, homeDir } : undefined);
|
||||
logger.info('Spawned Pi process for session', { sessionId, model, cwd, sandboxed });
|
||||
const sandbox = sandboxed ? { userId, username, email, homeDir } : undefined;
|
||||
|
||||
// If session has history, save to disk and pass --session for context replay
|
||||
let spawnOptions: { sessionFile?: string } | undefined;
|
||||
if (session.messages.length > 0) {
|
||||
await storage.saveSession(homeDir, sessionId, session.meta, session.messages);
|
||||
const hostPath = await storage.getSessionFilePath(homeDir, sessionId);
|
||||
if (hostPath) {
|
||||
if (sandboxed) {
|
||||
const containerHome = `/home/${username}`;
|
||||
const sessionsPrefix = join(homeDir, '.pi', 'agent', 'sessions');
|
||||
const relativePart = hostPath.slice(sessionsPrefix.length);
|
||||
spawnOptions = { sessionFile: `${containerHome}/.pi/agent/sessions${relativePart}` };
|
||||
} else {
|
||||
spawnOptions = { sessionFile: hostPath };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
session.piProcess = await piBridge.spawnPi(cwd, model, userId, email, onEvent, sandbox, spawnOptions);
|
||||
|
||||
// Null out piProcess when the process dies so next message triggers respawn
|
||||
const proc = session.piProcess;
|
||||
proc.exited.then(() => {
|
||||
if (session.piProcess === proc) {
|
||||
session.piProcess = null;
|
||||
logger.info('Pi process exited, nulled reference', { sessionId });
|
||||
}
|
||||
});
|
||||
|
||||
logger.info('Spawned Pi process for session', { sessionId, model, cwd, sandboxed, hasSessionFile: !!spawnOptions?.sessionFile });
|
||||
} catch (err) {
|
||||
logger.error('Failed to spawn Pi process', { sessionId, model, error: String(err) });
|
||||
sendToClient(ws, { type: 'error', message: 'Failed to start Pi process' });
|
||||
@@ -361,8 +390,36 @@ async function handleResume(
|
||||
const homeDir = getHomeDir(email);
|
||||
const sandbox = session.sandboxed && session.userId ? { userId: session.userId, username: ws.data.username, email, homeDir } : undefined;
|
||||
const onEvent = createEventHandler(sessionId, session.model, session.cwd, homeDir);
|
||||
session.piProcess = await piBridge.spawnPi(session.cwd, session.model, session.userId!, email, onEvent, sandbox);
|
||||
logger.info('Spawned fresh Pi process for resumed session', { sessionId, model: session.model, sandboxed: session.sandboxed });
|
||||
|
||||
// If session has history, save to disk and pass --session for context replay
|
||||
let spawnOptions: { sessionFile?: string } | undefined;
|
||||
if (session.messages.length > 0) {
|
||||
await storage.saveSession(homeDir, sessionId, session.meta, session.messages);
|
||||
const hostPath = await storage.getSessionFilePath(homeDir, sessionId);
|
||||
if (hostPath) {
|
||||
if (sandbox) {
|
||||
const containerHome = `/home/${ws.data.username}`;
|
||||
const sessionsPrefix = join(homeDir, '.pi', 'agent', 'sessions');
|
||||
const relativePart = hostPath.slice(sessionsPrefix.length);
|
||||
spawnOptions = { sessionFile: `${containerHome}/.pi/agent/sessions${relativePart}` };
|
||||
} else {
|
||||
spawnOptions = { sessionFile: hostPath };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
session.piProcess = await piBridge.spawnPi(session.cwd, session.model, session.userId!, email, onEvent, sandbox, spawnOptions);
|
||||
|
||||
// Null out piProcess when the process dies so next message triggers respawn
|
||||
const proc = session.piProcess;
|
||||
proc.exited.then(() => {
|
||||
if (session.piProcess === proc) {
|
||||
session.piProcess = null;
|
||||
logger.info('Pi process exited, nulled reference', { sessionId });
|
||||
}
|
||||
});
|
||||
|
||||
logger.info('Spawned fresh Pi process for resumed session', { sessionId, model: session.model, sandboxed: session.sandboxed, hasSessionFile: !!spawnOptions?.sessionFile });
|
||||
} catch (err) {
|
||||
logger.error('Failed to spawn Pi process for resume', { sessionId, error: String(err) });
|
||||
sendToClient(ws, { type: 'error', message: 'Failed to start Pi process' });
|
||||
|
||||
Reference in New Issue
Block a user