/// import type { Observation, StepResult, Task } from './types' const BASE = (import.meta.env.VITE_API_URL as string | undefined) || '' async function post(path: string, body: unknown): Promise { const r = await fetch(`${BASE}${path}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }) if (!r.ok) throw new Error(`${r.status} ${await r.text()}`) return r.json() as Promise } async function get(path: string): Promise { const r = await fetch(`${BASE}${path}`) if (!r.ok) throw new Error(`${r.status} ${await r.text()}`) return r.json() as Promise } export const api = { reset: (task_id: string, model = 'manual') => post('/reset', { task_id, model }), step: (action: Record) => post('/step', action), state: () => get>('/state'), tasks: () => get<{ tasks: Task[] }>('/tasks'), leaderboard: () => get<{ leaderboard: unknown[] }>('/leaderboard'), stats: () => get>('/stats'), history: () => get<{ history: unknown[] }>('/history'), replay: (runId: string) => get>(`/replay/${runId}`), customScenarios: () => get<{ custom_scenarios: string[] }>('/scenarios/custom'), createCustomScenario: (body: Record) => post>('/scenarios/custom', body), memory: () => get<{ memory: unknown[] }>('/memory'), submitFeedback: (body: Record) => post>('/feedback', body), } // SSE helper for live agent streaming export function createAgentStream(body: Record, onEvent: (e: Record) => void, onDone: () => void) { const ctrl = new AbortController() fetch(`${BASE}/agent/run`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), signal: ctrl.signal, }).then(async res => { const reader = res.body?.getReader() const decoder = new TextDecoder() if (!reader) { onDone(); return } let buf = '' while (true) { const { done, value } = await reader.read() if (done) break buf += decoder.decode(value, { stream: true }) const lines = buf.split('\n') buf = lines.pop() || '' for (const line of lines) { if (line.startsWith('data: ')) { try { onEvent(JSON.parse(line.slice(6))) } catch {} } } } onDone() }).catch(() => onDone()) return () => ctrl.abort() } export function createCompareStream(body: Record, onEvent: (e: Record) => void, onDone: () => void) { const ctrl = new AbortController() fetch(`${BASE}/agent/compare`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), signal: ctrl.signal, }).then(async res => { const reader = res.body?.getReader() const decoder = new TextDecoder() if (!reader) { onDone(); return } let buf = '' while (true) { const { done, value } = await reader.read() if (done) break buf += decoder.decode(value, { stream: true }) const lines = buf.split('\n') buf = lines.pop() || '' for (const line of lines) { if (line.startsWith('data: ')) { try { onEvent(JSON.parse(line.slice(6))) } catch {} } } } onDone() }).catch(() => onDone()) return () => ctrl.abort() }