import * as backend from './backend'; // State let runs = []; let unsubscribeRunEvents = null; // Event listeners for UI components const listeners = { runs: [], chats: {}, }; class RunListener { constructor() { this.runIds = new Set(); this.callbacks = []; this.cancelled = false; } setIdList(runIds) { this.runIds = new Set(runIds); } addRunId(runId) { this.runIds.add(runId); } addCallback(callback) { this.callbacks.push(callback); } cancel() { this.cancelled = true; listeners.runs = listeners.runs.filter(l => l !== this); } hasRunId(runId) { return this.runIds.has(runId); } emitChange(data) { if (this.cancelled) return; for (let cb of this.callbacks) cb(data); } } // Update a run based on an incoming event function updateRun(event) { const { name, runId, data } = event.data; // Find the run by ID const runIndex = runs.findIndex(r => r.id === runId); let run = runIndex >= 0 ? runs[runIndex] : null; if (name == 'created') { if (!run) { run = Object.assign({}, data, {id: runId, events: []}); runs.push(run); } else { console.warn("Created but existing?", run, data); } } else if (name == 'done') { run.done = true; run.endTime = data.endTime; run.output = data.output; } else if (name == 'chat-message') { let chatListeners = listeners.chats[data.chatId] || []; for (let f of chatListeners) { f({runId: runId, ...data}); } } if (run) { run.events.push(event); for (let listener of listeners.runs) { if (listener.hasRunId(runId)) { listener.emitChange(run); } } } else { console.error('Bad run event (non-existing run)', event); } } // Initialize the runs module async function init() { // Listen for connection establishment const res = await backend.sendAction("get-agent-runs"); runs = res.runs || []; // Listen for run events unsubscribeRunEvents = backend.onAction('run-event', updateRun); } backend.onConnect(init); // Get all runs export function getRuns() { return runs; } // Get a specific run by ID export function getRun(runId) { return runs.find(r => r.id === runId); } // Cancel a run export async function cancelRun(runId) { try { const res = await backend.sendAction("cancel-agent-run", { runId }); console.log(`Cancelled run ${runId}`, res); return res; } catch (err) { console.error(`Failed to cancel run ${runId}:`, err); throw err; } } // Subscribe to runs changes export function addRunListener(callback) { const listener = new RunListener(); listener.addCallback(callback); listeners.runs.push(listener); return listener; } // Subscribe to run chat message events export function onChatMessage(chatId, callback) { let chatListeners = listeners.chats[chatId]; if (!chatListeners) { chatListeners = []; listeners.chats[chatId] = chatListeners; } chatListeners.push(callback); return () => { const index = chatListeners.indexOf(callback); if (index > -1) { chatListeners.splice(index, 1); } }; }