import type { AgentEvent, BenchItem, CompareResult, EvalListItem, EvalState, Experiment, ExpPlan, GpuStatus, Health, CloudProvider, Device, Providers, AutoRun, AutoSettings, LibItem, LibItemIn, ProbeResult, TrackDetail, TrackSummary, Translation, JobRequest, JobState, JobSummary, Sample, } from './types'; async function req(url: string, init?: RequestInit): Promise { const r = await fetch(url, { ...init, headers: { 'Content-Type': 'application/json', ...(init?.headers || {}) }, }); if (!r.ok) { let msg = `${r.status} ${r.statusText}`; try { const body = await r.json(); // FastAPI doğrulama hataları bir liste olarak gelir: ham JSON yerine okunur iletiler gösterilir msg = typeof body.detail === 'string' ? body.detail : Array.isArray(body.detail) ? body.detail.map((d: { loc?: unknown[]; msg?: string }) => `${(d.loc || []).filter((x) => x !== 'body').join('.')}: ${d.msg}`).join(' · ') : JSON.stringify(body.detail ?? body); } catch { /* yoksay */ } throw new Error(msg); } return r.json() as Promise; } export const api = { health: () => req('/api/health'), gpu: () => req('/api/gpu'), samples: () => req('/api/samples'), createJob: (body: JobRequest) => req<{ id: string }>('/api/jobs', { method: 'POST', body: JSON.stringify(body) }), job: (id: string) => req(`/api/jobs/${id}`), jobs: () => req('/api/jobs'), cancel: (id: string) => req<{ ok: boolean }>(`/api/jobs/${id}/cancel`, { method: 'POST' }), benchmark: () => req('/api/benchmark'), startEval: (body: Record) => req<{ id: string }>('/api/evals', { method: 'POST', body: JSON.stringify(body) }), evals: () => req('/api/evals'), resumeEval: (id: string) => req<{ ok: boolean }>(`/api/evals/${id}/resume`, { method: 'POST' }), pauseEval: (id: string) => req<{ ok: boolean }>(`/api/evals/${id}/pause`, { method: 'POST' }), compare: (a: string, b: string) => req(`/api/compare?a=${a}&b=${b}`), expPlan: (profile: string, models: string[]) => req(`/api/experiments/plan?profile=${profile}&models=${encodeURIComponent(models.join(','))}`), experiments: () => req('/api/experiments/runs'), experiment: (id: string) => req(`/api/experiments/runs/${id}`), startExperiment: (body: { profile: string; models: string[]; max_mutants: number }) => req<{ id: string }>('/api/experiments/runs', { method: 'POST', body: JSON.stringify(body) }), translate: (id: string, lang: string) => req & { lang: string; original?: boolean }>(`/api/jobs/${id}/translate`, { method: 'POST', body: JSON.stringify({ lang }) }), cancelExperiment: (id: string) => req<{ ok: boolean }>(`/api/experiments/runs/${id}/cancel`, { method: 'POST' }), cancelEval: (id: string) => req<{ ok: boolean }>(`/api/evals/${id}/cancel`, { method: 'POST' }), pauseExperiment: (id: string) => req<{ ok: boolean }>(`/api/experiments/runs/${id}/pause`, { method: 'POST' }), retryExperiment: (id: string) => req<{ ok: boolean }>(`/api/experiments/runs/${id}/retry-failed`, { method: 'POST' }), resumeExperiment: (id: string) => req<{ ok: boolean }>(`/api/experiments/runs/${id}/resume`, { method: 'POST' }), evalState: (id: string) => req(`/api/evals/${id}`), providers: () => req('/api/providers'), autoRuns: () => req('/api/automation/runs'), tracking: () => req('/api/tracking'), trackingDetail: (key: string) => req(`/api/tracking/${key}`), probeModels: (models: string[], force = true) => req>('/api/models/probe', { method: 'POST', body: JSON.stringify({ models, force }) }), library: () => req('/api/automation/library'), addLibrary: (items: LibItemIn[]) => req<{ ids: string[] }>('/api/automation/library', { method: 'POST', body: JSON.stringify(items) }), deleteLibrary: (id: string) => req<{ ok: boolean }>(`/api/automation/library/${encodeURIComponent(id)}`, { method: 'DELETE' }), startAuto: (sample_ids: string[], settings: AutoSettings) => req<{ id: string }>('/api/automation/runs', { method: 'POST', body: JSON.stringify({ sample_ids, settings }) }), pauseAuto: (id: string) => req<{ ok: boolean }>(`/api/automation/runs/${id}/pause`, { method: 'POST' }), resumeAuto: (id: string) => req<{ ok: boolean }>(`/api/automation/runs/${id}/resume`, { method: 'POST' }), cancelAuto: (id: string) => req<{ ok: boolean }>(`/api/automation/runs/${id}/cancel`, { method: 'POST' }), seenAuto: (id: string) => req<{ ok: boolean }>(`/api/automation/runs/${id}/seen`, { method: 'POST' }), rebuildAuto: (id: string) => req(`/api/automation/runs/${id}/rebuild-reports`, { method: 'POST' }), deleteAuto: (id: string) => req<{ ok: boolean }>(`/api/automation/runs/${id}`, { method: 'DELETE' }), settings: () => req<{ prefs: Record; file_name: string; folder: string; exists: boolean; docker: boolean }>('/api/settings'), savePrefs: (values: Record) => req<{ prefs: Record }>('/api/settings/prefs', { method: 'PUT', body: JSON.stringify(values), keepalive: true }), importSettings: (doc: unknown) => req<{ prefs: Record; providers: Providers }>('/api/settings/import', { method: 'POST', body: JSON.stringify(doc) }), connectProvider: (id: string, body: { api_key?: string; base_url?: string }) => req(`/api/providers/${id}`, { method: 'PUT', body: JSON.stringify(body) }), syncProvider: (id: string) => req(`/api/providers/${id}/sync`, { method: 'POST' }), disconnectProvider: (id: string) => req(`/api/providers/${id}`, { method: 'DELETE' }), setDevice: (device: Device) => req<{ device: Device }>('/api/providers/device', { method: 'PUT', body: JSON.stringify({ device }) }), }; /** Sunucu olay akışına (SSE) abone olur; kapatma fonksiyonu döndürür. */ export function subscribe(jobId: string, onEvent: (e: AgentEvent) => void, onEnd: () => void): () => void { const es = new EventSource(`/api/jobs/${jobId}/events`); es.onmessage = (m) => onEvent(JSON.parse(m.data)); es.addEventListener('end', () => { es.close(); onEnd(); }); es.onerror = () => { es.close(); onEnd(); }; return () => es.close(); }