export interface SessionSummary { id: string state: string model: string agent: string // Available in 9P mode, not in DBus list (fetch config for these) cwd?: string backend?: string } // Compat alias for components still using the old name. export type IdxEntry = SessionSummary export interface SessionConfig { model?: string backend?: string agent?: string cwd?: string state?: string [key: string]: string | undefined } export async function listSessions(): Promise { const r = await fetch('/sessions') if (!r.ok) return [] const data = await r.json() return Array.isArray(data) ? (data as SessionSummary[]) : [] } export async function getSessionCfg(id: string): Promise { const r = await fetch(`/sessions/${id}/config`) if (!r.ok) throw new Error(`config ${r.status}`) const data = await r.json() return (data && typeof data === 'object' && !Array.isArray(data)) ? (data as SessionConfig) : {} } export async function getChatLines(id: string): Promise { const r = await fetch(`/sessions/${id}/chat`) if (!r.ok) return [] const text = await r.text() if (!text.trim()) return [] return text.trimEnd().split('\n') } export async function getChatWithOffset(id: string, offset: number): Promise<{ text: string; newOffset: number }> { const r = await fetch(`/sessions/${id}/chat?offset=${offset}`) if (!r.ok) return { text: '', newOffset: offset } const text = await r.text() const newOffset = parseInt(r.headers.get('X-Chat-Offset') ?? String(offset), 10) return { text, newOffset } } export async function sendPrompt(id: string, prompt: string): Promise { await fetch(`/sessions/${id}/submit`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ prompt }), }) } export async function interruptSession(id: string): Promise { await fetch(`/sessions/${id}/interrupt`, { method: 'POST' }) } export async function createSession(params: { cwd?: string backend?: string model?: string agent?: string }): Promise { const r = await fetch('/sessions', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(params), }) if (!r.ok) return null const data = await r.json() return data.id ?? null } export async function killSession(id: string): Promise { await fetch(`/sessions/${id}`, { method: 'DELETE' }) } export async function renameSession(id: string, newName: string): Promise { await fetch(`/sessions/${id}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: newName }), }) } export async function setConfig(id: string, key: string, value: string): Promise { await fetch(`/sessions/${id}/config`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ key, value }), }) } export async function getState(id: string): Promise { const r = await fetch(`/sessions/${id}/state`) if (!r.ok) return 'unknown' const data = await r.json() return data.state ?? 'unknown' } export async function getBackends(): Promise { const r = await fetch('/backends') if (!r.ok) return [] const data = await r.json() return Array.isArray(data) ? (data as string[]) : [] } export async function getAgents(): Promise { const r = await fetch('/agents') if (!r.ok) return [] const data = await r.json() return Array.isArray(data) ? (data as string[]) : [] } export async function getModels(sessionId: string): Promise { const r = await fetch(`/sessions/${sessionId}/models`) if (!r.ok) return [] const data = await r.json() return Array.isArray(data) ? (data as string[]) : [] } export async function getUsage(id: string): Promise { const r = await fetch(`/sessions/${id}/usage`) if (!r.ok) return '' const data = await r.json() return data.usage ?? '' } export async function getCost(id: string): Promise { const r = await fetch(`/sessions/${id}/cost`) if (!r.ok) return '' const data = await r.json() return data.cost ?? '' } // --- Compat: sendCtl maps to interrupt for "stop" --- export async function sendCtl(id: string, ctl: string): Promise { if (ctl === 'stop') { await interruptSession(id) } } // --- Models cache (for NewSession) --- const MODELS_CACHE_KEY = 'ollie:models' export function loadModelsCache(): Record { try { const raw = localStorage.getItem(MODELS_CACHE_KEY) if (raw) return JSON.parse(raw) } catch {} return {} } export async function fetchModels(): Promise> { // In dbus mode we don't have a global models endpoint. // Return cached data; individual session model lists are fetched via getModels(). return loadModelsCache() } // --- 9P browsing stubs (not available in dbus mode) --- export async function browse9p(_path: string): Promise { return null } export async function write9p(_path: string, _content: string): Promise { return false }