import { getServerUrl } from './config'; async function request(path, options = {}) { const base = await getServerUrl(); const res = await fetch(`${base}/api${path}`, { ...options, headers: { 'Content-Type': 'application/json', ...(options.headers || {}) }, }); if (!res.ok) { const err = await res.json().catch(() => ({ error: res.statusText })); throw new Error(err.error || res.statusText); } return res.json(); } export async function getChatHistory() { return request('/chat/history'); } export async function clearChat() { return request('/chat/clear', { method: 'POST' }); } export async function summarizeChat() { return request('/chat/summarize', { method: 'POST' }); } export async function sendChat(message, stream = true, onChunk, signal) { const base = await getServerUrl(); if (!stream) { return request('/chat', { method: 'POST', body: JSON.stringify({ message, stream: false }), }); } return new Promise((resolve, reject) => { fetch(`${base}/api/chat`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ message, stream: true }), signal, }).then(async (res) => { if (!res.ok) { const err = await res.json().catch(() => ({ error: res.statusText })); reject(new Error(err.error || res.statusText)); return; } const reader = res.body.getReader(); const decoder = new TextDecoder(); let full = ''; while (true) { const { done, value } = await reader.read(); if (done) break; const text = decoder.decode(value, { stream: true }); for (const line of text.split('\n')) { if (!line.startsWith('data: ')) continue; try { const data = JSON.parse(line.slice(6)); if (data.error) { reject(new Error(data.error)); return; } if (data.done) { resolve(full); return; } if (data.content) { full += data.content; if (onChunk) onChunk(full, data); } else if (data.thinking !== undefined || data.thinking_end) { if (onChunk) onChunk(full, data); } else if (data.tool_call || data.tool_result) { if (onChunk) onChunk(full, data); } } catch {} } } resolve(full); }).catch(reject); }); }