| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206 |
- const messagesEl = document.querySelector("#messages");
- const statusEl = document.querySelector("#connection-status");
- const chatForm = document.querySelector("#chat-form");
- const userMessage = document.querySelector("#user-message");
- const systemPrompts = document.querySelector("#system-prompts");
- const preMessages = document.querySelector("#pre-messages");
- const preMessageTemplate = document.querySelector("#pre-message-template");
- const toolList = document.querySelector("#tool-list");
- let socket = null;
- let activeAssistant = null;
- let runStartedAt = 0;
- let firstTokenAt = 0;
- document.querySelector("#add-system-prompt").addEventListener("click", () => {
- const textarea = document.createElement("textarea");
- textarea.className = "system-prompt";
- textarea.rows = 4;
- systemPrompts.append(textarea);
- });
- document.querySelector("#add-pre-message").addEventListener("click", () => {
- preMessages.append(preMessageTemplate.content.cloneNode(true));
- });
- chatForm.addEventListener("submit", (event) => {
- event.preventDefault();
- runDebugSession();
- });
- loadTools();
- async function loadTools() {
- try {
- const response = await fetch("/api/tools");
- if (!response.ok) {
- throw new Error(`Tool API failed: ${response.status}`);
- }
- renderTools(await response.json());
- } catch (error) {
- toolList.textContent = "Failed to load tools";
- }
- }
- function renderTools(tools) {
- toolList.textContent = "";
- if (!tools.length) {
- toolList.textContent = "No tools available";
- return;
- }
- tools.forEach((tool) => {
- const label = document.createElement("label");
- label.className = "checkbox";
- label.title = tool.description || tool.name;
- const checkbox = document.createElement("input");
- checkbox.type = "checkbox";
- checkbox.className = "tool-toggle";
- checkbox.value = tool.name;
- checkbox.checked = true;
- label.append(checkbox, ` ${tool.name}`);
- toolList.append(label);
- });
- }
- function runDebugSession() {
- closeSocket();
- resetRun();
- socket = new WebSocket(wsUrl());
- socket.addEventListener("open", () => {
- statusEl.textContent = "Streaming";
- runStartedAt = performance.now();
- socket.send(JSON.stringify(buildRequest()));
- });
- socket.addEventListener("message", (event) => {
- handleServerMessage(JSON.parse(event.data));
- });
- socket.addEventListener("close", () => {
- statusEl.textContent = "Idle";
- updateElapsed();
- });
- socket.addEventListener("error", () => {
- appendLog("error", "WebSocket connection failed");
- });
- }
- function buildRequest() {
- return {
- user_message: userMessage.value,
- system_prompts: [...document.querySelectorAll(".system-prompt")]
- .map((input) => input.value.trim())
- .filter(Boolean),
- pre_messages: [...document.querySelectorAll(".pre-message")]
- .map((row) => ({
- role: row.querySelector(".pre-role").value,
- content: row.querySelector(".pre-content").value.trim(),
- }))
- .filter((message) => message.content),
- chat_agent: {
- model: document.querySelector("#model").value.trim(),
- temperature: Number(document.querySelector("#temperature").value),
- max_tokens: Number(document.querySelector("#max-tokens").value),
- },
- event_agent: {
- enabled_tools: selectedTools(),
- max_event_loops: Number(document.querySelector("#max-event-loops").value),
- },
- };
- }
- function selectedTools() {
- return [...toolList.querySelectorAll(".tool-toggle:checked")].map(
- (input) => input.value,
- );
- }
- function handleServerMessage(message) {
- if (message.type === "session_started") {
- appendLog("session", "Session started");
- return;
- }
- if (message.type === "message_delta") {
- appendAssistantDelta(message.content || "");
- return;
- }
- if (message.type === "usage") {
- updateUsage(message.usage || {});
- return;
- }
- if (message.type === "event") {
- appendLog("event", `${message.event.name}: ${JSON.stringify(message.event.arguments)}`);
- return;
- }
- if (message.type === "tool_result") {
- appendLog("tool", message.message.content);
- return;
- }
- if (message.type === "error") {
- appendLog("error", message.message);
- return;
- }
- if (message.type === "done") {
- appendLog("session", "Done");
- closeSocket();
- }
- }
- function appendAssistantDelta(content) {
- if (!firstTokenAt) {
- firstTokenAt = performance.now();
- document.querySelector("#stat-ttft").textContent = `${Math.round(firstTokenAt - runStartedAt)}ms`;
- }
- if (!activeAssistant) {
- activeAssistant = document.createElement("div");
- activeAssistant.className = "message assistant";
- messagesEl.append(activeAssistant);
- }
- activeAssistant.textContent += content;
- updateElapsed();
- messagesEl.scrollTop = messagesEl.scrollHeight;
- }
- function appendLog(kind, content) {
- const item = document.createElement("div");
- item.className = `message ${kind}`;
- item.textContent = content;
- messagesEl.append(item);
- messagesEl.scrollTop = messagesEl.scrollHeight;
- }
- function updateUsage(usage) {
- document.querySelector("#stat-tokens").textContent = usage.total_tokens || 0;
- document.querySelector("#stat-cached").textContent = usage.cached_tokens || 0;
- }
- function updateElapsed() {
- if (!runStartedAt) {
- return;
- }
- document.querySelector("#stat-elapsed").textContent = `${Math.round(performance.now() - runStartedAt)}ms`;
- }
- function resetRun() {
- activeAssistant = null;
- runStartedAt = 0;
- firstTokenAt = 0;
- messagesEl.textContent = "";
- document.querySelector("#stat-tokens").textContent = "0";
- document.querySelector("#stat-cached").textContent = "0";
- document.querySelector("#stat-ttft").textContent = "-";
- document.querySelector("#stat-elapsed").textContent = "-";
- }
- function closeSocket() {
- if (socket && socket.readyState < WebSocket.CLOSING) {
- socket.close();
- }
- }
- function wsUrl() {
- const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
- return `${protocol}//${window.location.host}/ws/debug`;
- }
|