From 2c6b75c4a63858c6fdc8a0f641e7d30396d664de Mon Sep 17 00:00:00 2001 From: seekskyworld Date: Fri, 4 Sep 2026 16:23:55 +0800 Subject: [PATCH 1/2] fix(web): bound browser request duration Signed-off-by: seekskyworld --- web/ui/app.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/web/ui/app.js b/web/ui/app.js index bcff449d..ea27baf0 100644 --- a/web/ui/app.js +++ b/web/ui/app.js @@ -196,10 +196,18 @@ function renderMarkdown(value) { } async function api(path, options = {}) { - const response = await fetch(path, { - ...options, - headers: { ...headers(Boolean(options.body)), ...options.headers }, - }); + const controller = new AbortController(); + const timeout = window.setTimeout(() => controller.abort(), 30_000); + let response; + try { + response = await fetch(path, { + ...options, + headers: { ...headers(Boolean(options.body)), ...options.headers }, + signal: options.signal || controller.signal, + }); + } finally { + window.clearTimeout(timeout); + } const body = await response.json().catch(() => ({})); if (!response.ok) throw new Error(body.error || `Request failed (${response.status})`); return body; From d1bea405190009e94faafcddfc0866a7965374bf Mon Sep 17 00:00:00 2001 From: seekskyworld Date: Fri, 4 Sep 2026 16:25:03 +0800 Subject: [PATCH 2/2] feat(web): classify tool evidence renderers Signed-off-by: seekskyworld --- web/ui/app.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/web/ui/app.js b/web/ui/app.js index ea27baf0..398cfd6c 100644 --- a/web/ui/app.js +++ b/web/ui/app.js @@ -390,8 +390,17 @@ function messageMarkup(entry) { } if (message.role === "toolResult") { const toolName = message.toolName || "tool"; + const kind = /(?:read|cat|file)/iu.test(toolName) + ? "file" + : /diff/iu.test(toolName) + ? "diff" + : /test/iu.test(toolName) + ? "test" + : /(?:bash|terminal|exec)/iu.test(toolName) + ? "terminal" + : "generic"; const summary = compactSummary(message.content || "completed"); - return `
+ return `
${escapeHtml(toolName)} ยท ${escapeHtml(summary)}
${escapeHtml(message.content || "completed")}