/** * Agent + Session persistence RPC handlers. */ import type { SidecarManager } from "../sidecar-manager.ts"; import type { SessionDb } from "../session-db.ts"; export function createAgentHandlers( sidecarManager: SidecarManager, sessionDb: SessionDb, sendToWebview: { send: Record void> }, ) { return { "agent.start": ({ sessionId, provider, prompt, cwd, model, systemPrompt, maxTurns, permissionMode, claudeConfigDir, extraEnv, additionalDirectories, worktreeName }: Record) => { try { const result = sidecarManager.startSession( sessionId as string, provider as string, prompt as string, { cwd, model, systemPrompt, maxTurns, permissionMode, claudeConfigDir, extraEnv, additionalDirectories, worktreeName } as Record, ); if (result.ok) { sidecarManager.onMessage(sessionId as string, (sid: string, messages: unknown) => { try { (sendToWebview.send as Record)["agent.message"]({ sessionId: sid, messages }); } catch (err) { console.error("[agent.message] forward error:", err); } }); sidecarManager.onStatus(sessionId as string, (sid: string, status: string, error?: string) => { try { (sendToWebview.send as Record)["agent.status"]({ sessionId: sid, status, error }); } catch (err) { console.error("[agent.status] forward error:", err); } const sessions = sidecarManager.listSessions(); const session = sessions.find((s: Record) => s.sessionId === sid); if (session) { try { (sendToWebview.send as Record)["agent.cost"]({ sessionId: sid, costUsd: session.costUsd, inputTokens: session.inputTokens, outputTokens: session.outputTokens, }); } catch { /* ignore */ } } }); } return result; } catch (err) { const error = err instanceof Error ? err.message : String(err); console.error("[agent.start]", err); return { ok: false, error }; } }, "agent.stop": ({ sessionId }: { sessionId: string }) => { try { return sidecarManager.stopSession(sessionId); } catch (err) { const error = err instanceof Error ? err.message : String(err); console.error("[agent.stop]", err); return { ok: false, error }; } }, "agent.prompt": ({ sessionId, prompt }: { sessionId: string; prompt: string }) => { try { return sidecarManager.writePrompt(sessionId, prompt); } catch (err) { const error = err instanceof Error ? err.message : String(err); console.error("[agent.prompt]", err); return { ok: false, error }; } }, "agent.list": () => { try { return { sessions: sidecarManager.listSessions() }; } catch (err) { console.error("[agent.list]", err); return { sessions: [] }; } }, // Session persistence "session.save": ({ projectId, sessionId, provider, status, costUsd, inputTokens, outputTokens, model, error, createdAt, updatedAt }: Record) => { try { sessionDb.saveSession({ projectId, sessionId, provider, status, costUsd, inputTokens, outputTokens, model, error, createdAt, updatedAt } as Record); return { ok: true }; } catch (err) { console.error("[session.save]", err); return { ok: false }; } }, "session.load": ({ projectId }: { projectId: string }) => { try { return { session: sessionDb.loadSession(projectId) }; } catch (err) { console.error("[session.load]", err); return { session: null }; } }, "session.list": ({ projectId }: { projectId: string }) => { try { return { sessions: sessionDb.listSessionsByProject(projectId) }; } catch (err) { console.error("[session.list]", err); return { sessions: [] }; } }, "session.messages.save": ({ messages }: { messages: Array> }) => { try { sessionDb.saveMessages(messages.map((m) => ({ sessionId: m.sessionId, msgId: m.msgId, role: m.role, content: m.content, toolName: m.toolName, toolInput: m.toolInput, timestamp: m.timestamp, costUsd: (m.costUsd as number) ?? 0, inputTokens: (m.inputTokens as number) ?? 0, outputTokens: (m.outputTokens as number) ?? 0, }))); return { ok: true }; } catch (err) { console.error("[session.messages.save]", err); return { ok: false }; } }, "session.messages.load": ({ sessionId }: { sessionId: string }) => { try { return { messages: sessionDb.loadMessages(sessionId) }; } catch (err) { console.error("[session.messages.load]", err); return { messages: [] }; } }, }; }