Files
MuyueWorkspace/extension/src/lib/api.js
Augustin f4af63afec
All checks were successful
Beta Release / beta (push) Successful in 1m25s
feat(extension): Chrome/Edge only + side panel chat tabs (v0.9.0)
- Remove Firefox build support (CI, Makefile, wxt config)
- Fix chrome.alarms undefined error (add 'alarms' permission)
- Add Chat tab to side panel connected to Studio API (/api/chat)
- Streaming SSE, tool calls, code blocks, thinking display
- Shared chat history with desktop Studio
- New lib/api.js client for extension chat endpoints

💘 Generated with Crush

Assisted-by: GLM-5.1 via Crush <crush@charm.land>
2026-04-27 18:48:04 +02:00

78 lines
2.4 KiB
JavaScript

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);
});
}