fix(ui): show session runtime in sessions table

This commit is contained in:
Vincent Koc
2026-05-05 15:52:58 -07:00
committed by GitHub
parent 430814ebc1
commit 16454f5c7a
3 changed files with 51 additions and 3 deletions

View File

@@ -87,6 +87,7 @@ Docs: https://docs.openclaw.ai
### Fixes
- Agents/generated media: treat attachment-style message tool actions as completed chat sends, preventing duplicate fallback media posts when generated files were already uploaded.
- Control UI/sessions: show each session's agent runtime in the Sessions table and allow filtering by runtime labels, matching the Agents panel runtime wording. Thanks @vincentkoc.
- Discord/streaming: show live reasoning text in progress drafts instead of a bare `Reasoning` status line.
- Doctor/status: warn when `OPENCLAW_GATEWAY_TOKEN` would shadow a different active `gateway.auth.token` source for local CLI commands, while avoiding false positives when config points at the same env token. Fixes #74271. Thanks @yelog.
- Gateway/HTTP: avoid loading managed outgoing-image media handlers for unrelated requests, so disabled OpenAI-compatible routes return 404 without waiting on lazy media sidecars. Thanks @vincentkoc.

View File

@@ -367,6 +367,41 @@ describe("sessions view", () => {
expect(badge?.textContent?.trim()).toBe("cron");
});
it("renders and filters the session runtime", async () => {
const container = document.createElement("div");
render(
renderSessions({
...buildProps(
buildMultiResult([
{
key: "agent:main:claude",
kind: "direct",
updatedAt: 20,
agentRuntime: { id: "claude-cli", fallback: "none", source: "agent" },
},
{
key: "agent:main:pi",
kind: "direct",
updatedAt: 10,
agentRuntime: { id: "pi", source: "implicit" },
},
]),
),
searchQuery: "fallback none",
}),
container,
);
await Promise.resolve();
expect(
Array.from(container.querySelectorAll("thead th")).map((cell) => cell.textContent?.trim()),
).toContain("Runtime");
expect(container.querySelector(".session-runtime-cell")?.textContent?.trim()).toBe(
"claude-cli (fallback none)",
);
expect(container.textContent).not.toContain("agent:main:pi");
});
it("keeps raw keys for inherited identity object properties", async () => {
const container = document.createElement("div");
render(

View File

@@ -13,6 +13,7 @@ import type {
SessionCompactionCheckpoint,
SessionsListResult,
} from "../types.ts";
import { resolveAgentRuntimeLabel } from "./agents-utils.ts";
export type SessionsProps = {
loading: boolean;
@@ -178,7 +179,14 @@ function filterRows(
const label = normalizeLowercaseStringOrEmpty(row.label);
const kind = normalizeLowercaseStringOrEmpty(row.kind);
const displayName = normalizeLowercaseStringOrEmpty(row.displayName);
if (key.includes(q) || label.includes(q) || kind.includes(q) || displayName.includes(q)) {
const runtime = normalizeLowercaseStringOrEmpty(resolveAgentRuntimeLabel(row.agentRuntime));
if (
key.includes(q) ||
label.includes(q) ||
kind.includes(q) ||
displayName.includes(q) ||
runtime.includes(q)
) {
return true;
}
const keyParts = parseSessionKeyParts(row.key);
@@ -543,6 +551,7 @@ export function renderSessions(props: SessionsProps) {
${sortHeader("key", t("sessionsView.key"), "data-table-key-col")}
<th>${t("sessionsView.label")}</th>
${sortHeader("kind", t("sessionsView.kind"))}
<th>${t("agents.context.runtime")}</th>
${sortHeader("updated", t("sessionsView.updated"))}
${sortHeader("tokens", t("sessionsView.tokens"))}
<th>${t("sessionsView.compaction")}</th>
@@ -556,7 +565,7 @@ export function renderSessions(props: SessionsProps) {
${paginated.length === 0
? html`
<tr>
<td colspan="11" class="data-table-empty-cell">
<td colspan="12" class="data-table-empty-cell">
${emptyBecauseFiltered
? html`
<div class="data-table-empty-state" role="status" aria-live="polite">
@@ -748,6 +757,9 @@ function renderRows(row: GatewaySessionRow, props: SessionsProps) {
<td>
<span class="data-table-badge ${badgeClass}">${row.kind}</span>
</td>
<td class="session-runtime-cell">
<span class="mono">${resolveAgentRuntimeLabel(row.agentRuntime)}</span>
</td>
<td>${updated}</td>
<td class="session-token-cell">${formatSessionTokens(row)}</td>
<td>
@@ -858,7 +870,7 @@ function renderRows(row: GatewaySessionRow, props: SessionsProps) {
...(isExpanded && hasCheckpoints
? [
html`<tr id=${detailsId} class="session-checkpoint-details-row">
<td colspan="11" style="padding: 0;">
<td colspan="12" style="padding: 0;">
<div
style="padding: 14px 16px; border-top: 1px solid var(--border); background: var(--surface-2, rgba(127, 127, 127, 0.05));"
>