mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-07-10 14:28:43 +02:00
171 lines
4.9 KiB
JavaScript
171 lines
4.9 KiB
JavaScript
const AGENT_MODES = [
|
|
{ id: 'eino_single', label: 'Eino Single (ADK)', path: '/api/eino-agent/stream' },
|
|
{ id: 'deep', label: 'Deep (DeepAgent)', path: '/api/multi-agent/stream', orchestration: 'deep' },
|
|
{ id: 'plan_execute', label: 'Plan-Execute', path: '/api/multi-agent/stream', orchestration: 'plan_execute' },
|
|
{ id: 'supervisor', label: 'Supervisor', path: '/api/multi-agent/stream', orchestration: 'supervisor' },
|
|
];
|
|
|
|
function agentModeById(id) {
|
|
return AGENT_MODES.find((m) => m.id === id) || AGENT_MODES[0];
|
|
}
|
|
|
|
async function apiFetch(baseUrl, path, options = {}) {
|
|
let res;
|
|
try {
|
|
res = await fetch(baseUrl + path, options);
|
|
} catch (err) {
|
|
const e = err instanceof Error ? err : new Error(String(err));
|
|
e.network = true;
|
|
throw e;
|
|
}
|
|
const text = await res.text();
|
|
let json = null;
|
|
try {
|
|
json = text ? JSON.parse(text) : null;
|
|
} catch (_) {
|
|
json = null;
|
|
}
|
|
if (!res.ok) {
|
|
const err = new Error((json && json.error) || text || `HTTP ${res.status}`);
|
|
err.status = res.status;
|
|
throw err;
|
|
}
|
|
return json;
|
|
}
|
|
|
|
async function loginAndValidate(baseUrl, password, signal) {
|
|
const login = await apiFetch(baseUrl, '/api/auth/login', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
|
|
body: JSON.stringify({ password }),
|
|
signal,
|
|
});
|
|
const token = login && login.token;
|
|
if (!token) throw new Error('Login response missing token');
|
|
await validateTokenSession(baseUrl, token, signal);
|
|
return {
|
|
token,
|
|
expiresAt: (login && login.expires_at) || '',
|
|
};
|
|
}
|
|
|
|
async function validateTokenSession(baseUrl, token, signal) {
|
|
await apiFetch(baseUrl, '/api/auth/validate', {
|
|
method: 'GET',
|
|
headers: { Authorization: `Bearer ${token}` },
|
|
signal,
|
|
});
|
|
}
|
|
|
|
async function fetchProjects(baseUrl, token, signal) {
|
|
const data = await apiFetch(baseUrl, '/api/projects?limit=500', {
|
|
headers: { Authorization: `Bearer ${token}` },
|
|
signal,
|
|
});
|
|
const list = (data && data.projects) || [];
|
|
const out = [{ id: '', label: '(none)' }];
|
|
for (const p of list) {
|
|
if (!p.id) continue;
|
|
let label = p.name || p.id;
|
|
if (p.status === 'archived') label += ' [archived]';
|
|
out.push({ id: p.id, label });
|
|
}
|
|
return out;
|
|
}
|
|
|
|
async function fetchRoles(baseUrl, token, signal) {
|
|
const data = await apiFetch(baseUrl, '/api/roles', {
|
|
headers: { Authorization: `Bearer ${token}` },
|
|
signal,
|
|
});
|
|
const list = (data && data.roles) || [];
|
|
const out = [{ id: '', label: 'Default' }];
|
|
for (const r of list) {
|
|
if (r.enabled === false) continue;
|
|
if (!r.name) continue;
|
|
out.push({ id: r.name, label: r.name });
|
|
}
|
|
return out;
|
|
}
|
|
|
|
function extractConversationId(ev) {
|
|
if (!ev || typeof ev !== 'object') return '';
|
|
if (ev.conversationId) return String(ev.conversationId).trim();
|
|
if (ev.data && ev.data.conversationId) return String(ev.data.conversationId).trim();
|
|
return '';
|
|
}
|
|
|
|
async function streamTest(baseUrl, token, options, handlers) {
|
|
const mode = agentModeById(options.agentMode);
|
|
const body = {
|
|
message: options.message,
|
|
conversationId: '',
|
|
role: options.role || '',
|
|
};
|
|
if (options.projectId) body.projectId = options.projectId;
|
|
if (mode.orchestration) body.orchestration = mode.orchestration;
|
|
|
|
const controller = new AbortController();
|
|
if (handlers.setAbortController) handlers.setAbortController(controller);
|
|
|
|
const res = await fetch(baseUrl + mode.path, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
Accept: 'text/event-stream',
|
|
Authorization: `Bearer ${token}`,
|
|
},
|
|
body: JSON.stringify(body),
|
|
signal: controller.signal,
|
|
});
|
|
|
|
if (!res.ok) {
|
|
const t = await res.text();
|
|
const err = new Error(t || `HTTP ${res.status}`);
|
|
err.status = res.status;
|
|
throw err;
|
|
}
|
|
|
|
const reader = res.body.getReader();
|
|
const decoder = new TextDecoder();
|
|
let buffer = '';
|
|
|
|
while (true) {
|
|
const { done, value } = await reader.read();
|
|
if (done) break;
|
|
buffer += decoder.decode(value, { stream: true });
|
|
const lines = buffer.split('\n');
|
|
buffer = lines.pop() || '';
|
|
for (const line of lines) {
|
|
if (!line.startsWith('data:')) continue;
|
|
const json = line.slice(5).trim();
|
|
if (!json) continue;
|
|
let ev;
|
|
try {
|
|
ev = JSON.parse(json);
|
|
} catch (_) {
|
|
continue;
|
|
}
|
|
const type = ev.type || '';
|
|
const message = ev.message || '';
|
|
if (handlers.onEvent) handlers.onEvent(type, message, ev);
|
|
if (type === 'done') {
|
|
if (handlers.onDone) handlers.onDone();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
if (handlers.onDone) handlers.onDone();
|
|
}
|
|
|
|
async function cancelByConversationId(baseUrl, token, conversationId) {
|
|
await apiFetch(baseUrl, '/api/agent-loop/cancel', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
Authorization: `Bearer ${token}`,
|
|
},
|
|
body: JSON.stringify({ conversationId }),
|
|
});
|
|
}
|