This commit is contained in:
Dobromir Popov
2026-07-07 18:49:32 +03:00
parent e9a094b620
commit b1f08c45cd
6 changed files with 541 additions and 26 deletions

View File

@@ -88,6 +88,9 @@
.status-processing { color:var(--accent); }
.status-failed { color:var(--bad); }
.status-complete { color:var(--ok); }
.status-canceled { color:var(--dim); }
button.btn-cancel { color:var(--dim); padding:0 5px; min-width:1.4em; line-height:1.2; }
button.btn-cancel:hover { color:var(--bad); border-color:var(--bad); }
</style>
</head>
<body>
@@ -350,6 +353,13 @@ function buildCallWallStates(events) {
rec.elapsed = f.elapsed_seconds;
rec.stream = f.stream;
rec.terminal = e;
} else if (msg === "proxy canceled") {
rec.status = "canceled";
rec.model = rec.model || f.model || f.route_model || "?";
rec.tokens = f.tokens;
rec.tps = f.tokens_per_sec;
rec.elapsed = f.elapsed_seconds;
rec.terminal = e;
} else if (msg === "proxy failed" || msg === "direct proxy failed after relay") {
rec.status = "failed";
rec.model = rec.model || f.model || f.route_model || "?";
@@ -379,7 +389,7 @@ function renderCallWall(consoleData, stats) {
const terminal = [];
for (const rec of states.values()) {
if (rec.status === "pending" || rec.status === "processing") active.push(rec);
else if (rec.status === "complete" || rec.status === "failed") terminal.push(rec);
else if (rec.status === "complete" || rec.status === "failed" || rec.status === "canceled") terminal.push(rec);
}
active.sort((a, b) => (a.started || 0) - (b.started || 0));
terminal.sort((a, b) => (b.terminal && b.terminal.ts) - (a.terminal && a.terminal.ts));
@@ -401,10 +411,13 @@ function renderCallWall(consoleData, stats) {
`</div>`;
if (active.length) {
html += table(["status", "age", "model", "request", "live tps", "tokens", "queue", "route / note"], active.map(rec => {
const canCancelProxies = isAdmin || !isLoggedIn;
const headers = ["status", "age", "model", "request", "live tps", "tokens", "queue", "route / note"];
if (canCancelProxies) headers.push("");
html += table(headers, active.map(rec => {
const statusCls = rec.status === "pending" ? "status-pending" : "status-processing";
const note = rec.warn || (rec.route ? short(String(rec.route), 28) : "");
return [
const row = [
`<span class="${statusCls}">${esc(rec.status)}</span>`,
`<span class="num">${esc(callWallAgeSeconds(rec, nowSec).toFixed(1))}s</span>`,
esc(short(rec.model || "?", 28)),
@@ -414,6 +427,12 @@ function renderCallWall(consoleData, stats) {
`<span class="num">${esc(String(callWallMaxQueue(rec)))}</span>`,
esc(note),
];
if (canCancelProxies) {
row.push(
`<button type="button" class="small btn-cancel" data-cancel-request="${esc(rec.id)}" title="Cancel request">×</button>`,
);
}
return row;
}));
} else {
html += '<div class="empty">no in-flight requests</div>';
@@ -422,10 +441,16 @@ function renderCallWall(consoleData, stats) {
const historyRows = terminal.slice(0, 40).map(rec => {
const e = rec.terminal || {};
const f = e.fields || {};
const statusCls = rec.status === "failed" ? "status-failed" : "status-complete";
const statusCls = rec.status === "failed"
? "status-failed"
: rec.status === "canceled"
? "status-canceled"
: "status-complete";
const detail = rec.status === "failed"
? esc(short(rec.error || "?", 40))
: (f.stream ? "stream" : "json");
: rec.status === "canceled"
? "canceled"
: (f.stream ? "stream" : "json");
return [
new Date((e.ts || 0) * 1000).toLocaleTimeString(),
`<span class="${statusCls}">${esc(rec.status)}</span>`,
@@ -437,7 +462,7 @@ function renderCallWall(consoleData, stats) {
detail,
];
});
html += '<div style="margin-top:8px"><b class="dim">recent completed / failed</b></div>';
html += '<div style="margin-top:8px"><b class="dim">recent completed / failed / canceled</b></div>';
html += historyRows.length
? table(["time", "status", "model", "request", "tps", "tokens", "sec", "detail"], historyRows)
: '<div class="empty">no completed requests yet</div>';
@@ -956,6 +981,23 @@ async function renderAdminPanel() {
$("admin").innerHTML = table(["account", "role", "keys", "balance (USDT)", "created"], rows);
}
async function cancelProxyRequest(requestId) {
const r = await apiCall(
`/v1/proxy/requests/${encodeURIComponent(requestId)}/cancel`,
"POST",
{},
);
if (r.ok) refresh();
}
$("call-wall").addEventListener("click", (event) => {
const button = event.target.closest("[data-cancel-request]");
if (!button) return;
event.preventDefault();
const requestId = button.getAttribute("data-cancel-request");
if (requestId) cancelProxyRequest(requestId);
});
async function refresh() {
$("self-url").textContent = location.host;
const [raft, map, stats, models, consoleData, adminData] = await Promise.all([