|
@@ -2,6 +2,7 @@ const messagesEl = document.querySelector("#messages");
|
|
|
const statusEl = document.querySelector("#connection-status");
|
|
const statusEl = document.querySelector("#connection-status");
|
|
|
const chatForm = document.querySelector("#chat-form");
|
|
const chatForm = document.querySelector("#chat-form");
|
|
|
const userMessage = document.querySelector("#user-message");
|
|
const userMessage = document.querySelector("#user-message");
|
|
|
|
|
+const runButton = document.querySelector("#run-button");
|
|
|
const promptSetName = document.querySelector("#prompt-set-name");
|
|
const promptSetName = document.querySelector("#prompt-set-name");
|
|
|
const savedPromptSets = document.querySelector("#saved-prompt-sets");
|
|
const savedPromptSets = document.querySelector("#saved-prompt-sets");
|
|
|
const systemPrompts = document.querySelector("#system-prompts");
|
|
const systemPrompts = document.querySelector("#system-prompts");
|
|
@@ -16,6 +17,7 @@ let socket = null;
|
|
|
let activeAssistant = null;
|
|
let activeAssistant = null;
|
|
|
let runStartedAt = 0;
|
|
let runStartedAt = 0;
|
|
|
let firstTokenAt = 0;
|
|
let firstTokenAt = 0;
|
|
|
|
|
+let elapsedTimer = 0;
|
|
|
let hasBackendRoundStats = false;
|
|
let hasBackendRoundStats = false;
|
|
|
let pendingEnabledTools = null;
|
|
let pendingEnabledTools = null;
|
|
|
|
|
|
|
@@ -349,20 +351,32 @@ function writePromptSets(store) {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function runDebugSession() {
|
|
function runDebugSession() {
|
|
|
|
|
+ const submittedMessage = userMessage.value.trim();
|
|
|
|
|
+ if (!submittedMessage) {
|
|
|
|
|
+ statusEl.textContent = "Message required";
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
closeSocket();
|
|
closeSocket();
|
|
|
resetRun();
|
|
resetRun();
|
|
|
|
|
+ appendLog("user", submittedMessage);
|
|
|
|
|
+ setRunState(true);
|
|
|
|
|
+ runStartedAt = performance.now();
|
|
|
|
|
+ startElapsedTimer();
|
|
|
|
|
+ statusEl.textContent = "Connecting";
|
|
|
|
|
|
|
|
socket = new WebSocket(wsUrl());
|
|
socket = new WebSocket(wsUrl());
|
|
|
socket.addEventListener("open", () => {
|
|
socket.addEventListener("open", () => {
|
|
|
- statusEl.textContent = "Streaming";
|
|
|
|
|
- runStartedAt = performance.now();
|
|
|
|
|
- socket.send(JSON.stringify(buildRequest()));
|
|
|
|
|
|
|
+ statusEl.textContent = "Waiting for first token";
|
|
|
|
|
+ socket.send(JSON.stringify(buildRequest(submittedMessage)));
|
|
|
});
|
|
});
|
|
|
socket.addEventListener("message", (event) => {
|
|
socket.addEventListener("message", (event) => {
|
|
|
handleServerMessage(JSON.parse(event.data));
|
|
handleServerMessage(JSON.parse(event.data));
|
|
|
});
|
|
});
|
|
|
socket.addEventListener("close", () => {
|
|
socket.addEventListener("close", () => {
|
|
|
statusEl.textContent = "Idle";
|
|
statusEl.textContent = "Idle";
|
|
|
|
|
+ stopElapsedTimer();
|
|
|
|
|
+ setRunState(false);
|
|
|
updateElapsed();
|
|
updateElapsed();
|
|
|
});
|
|
});
|
|
|
socket.addEventListener("error", () => {
|
|
socket.addEventListener("error", () => {
|
|
@@ -370,9 +384,9 @@ function runDebugSession() {
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-function buildRequest() {
|
|
|
|
|
|
|
+function buildRequest(submittedMessage = userMessage.value) {
|
|
|
return {
|
|
return {
|
|
|
- user_message: userMessage.value,
|
|
|
|
|
|
|
+ user_message: submittedMessage,
|
|
|
system_prompts: [...document.querySelectorAll(".system-prompt")]
|
|
system_prompts: [...document.querySelectorAll(".system-prompt")]
|
|
|
.map((input) => input.value.trim())
|
|
.map((input) => input.value.trim())
|
|
|
.filter(Boolean),
|
|
.filter(Boolean),
|
|
@@ -456,6 +470,7 @@ function formatAuditMessage(message) {
|
|
|
function appendAssistantDelta(content) {
|
|
function appendAssistantDelta(content) {
|
|
|
if (!firstTokenAt) {
|
|
if (!firstTokenAt) {
|
|
|
firstTokenAt = performance.now();
|
|
firstTokenAt = performance.now();
|
|
|
|
|
+ statusEl.textContent = "Streaming";
|
|
|
if (!hasBackendRoundStats) {
|
|
if (!hasBackendRoundStats) {
|
|
|
document.querySelector("#stat-ttft").textContent = `${Math.round(firstTokenAt - runStartedAt)}ms`;
|
|
document.querySelector("#stat-ttft").textContent = `${Math.round(firstTokenAt - runStartedAt)}ms`;
|
|
|
}
|
|
}
|
|
@@ -487,7 +502,9 @@ function updateUsage(usage) {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function updateRoundStats(stats) {
|
|
function updateRoundStats(stats) {
|
|
|
- hasBackendRoundStats = true;
|
|
|
|
|
|
|
+ if (firstTokenAt) {
|
|
|
|
|
+ hasBackendRoundStats = true;
|
|
|
|
|
+ }
|
|
|
document.querySelector("#stat-tokens").textContent = stats.total_tokens || 0;
|
|
document.querySelector("#stat-tokens").textContent = stats.total_tokens || 0;
|
|
|
document.querySelector("#stat-cached").textContent = stats.cached_tokens || 0;
|
|
document.querySelector("#stat-cached").textContent = stats.cached_tokens || 0;
|
|
|
const ttftText = formatMs(stats.ttft_ms);
|
|
const ttftText = formatMs(stats.ttft_ms);
|
|
@@ -505,13 +522,30 @@ function formatMs(value) {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function updateElapsed() {
|
|
function updateElapsed() {
|
|
|
- if (!runStartedAt || hasBackendRoundStats) {
|
|
|
|
|
|
|
+ if (!runStartedAt || (hasBackendRoundStats && firstTokenAt)) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
document.querySelector("#stat-elapsed").textContent = `${Math.round(performance.now() - runStartedAt)}ms`;
|
|
document.querySelector("#stat-elapsed").textContent = `${Math.round(performance.now() - runStartedAt)}ms`;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+function startElapsedTimer() {
|
|
|
|
|
+ stopElapsedTimer();
|
|
|
|
|
+ elapsedTimer = window.setInterval(updateElapsed, 100);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function stopElapsedTimer() {
|
|
|
|
|
+ if (elapsedTimer) {
|
|
|
|
|
+ window.clearInterval(elapsedTimer);
|
|
|
|
|
+ elapsedTimer = 0;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function setRunState(isRunning) {
|
|
|
|
|
+ runButton.disabled = isRunning;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
function resetRun() {
|
|
function resetRun() {
|
|
|
|
|
+ stopElapsedTimer();
|
|
|
activeAssistant = null;
|
|
activeAssistant = null;
|
|
|
runStartedAt = 0;
|
|
runStartedAt = 0;
|
|
|
firstTokenAt = 0;
|
|
firstTokenAt = 0;
|