Merge pull request #1373 from yazinsai/main

Add auto-refresh polling for debug view
This commit is contained in:
Peter Steinberger
2026-01-22 02:25:24 +00:00
committed by GitHub
7 changed files with 123 additions and 2 deletions

View File

@@ -11,6 +11,7 @@ Docs: https://docs.clawd.bot
### Fixes ### Fixes
- Doctor: warn when gateway.mode is unset with configure/config guidance. - Doctor: warn when gateway.mode is unset with configure/config guidance.
- UI: refresh debug panel on route-driven tab changes. (#1373) Thanks @yazinsai.
## 2026.1.21 ## 2026.1.21

View File

@@ -273,7 +273,7 @@ describe("update-cli", () => {
try { try {
await fs.writeFile( await fs.writeFile(
path.join(tempDir, "package.json"), path.join(tempDir, "package.json"),
JSON.stringify({ name: "clawdbot", version: "2026.1.18-1" }), JSON.stringify({ name: "clawdbot", version: "1.0.0" }),
"utf-8", "utf-8",
); );

View File

@@ -14,6 +14,8 @@ import {
startNodesPolling, startNodesPolling,
stopLogsPolling, stopLogsPolling,
stopNodesPolling, stopNodesPolling,
startDebugPolling,
stopDebugPolling,
} from "./app-polling"; } from "./app-polling";
type LifecycleHost = { type LifecycleHost = {
@@ -52,6 +54,9 @@ export function handleConnected(host: LifecycleHost) {
if (host.tab === "logs") { if (host.tab === "logs") {
startLogsPolling(host as unknown as Parameters<typeof startLogsPolling>[0]); startLogsPolling(host as unknown as Parameters<typeof startLogsPolling>[0]);
} }
if (host.tab === "debug") {
startDebugPolling(host as unknown as Parameters<typeof startDebugPolling>[0]);
}
} }
export function handleFirstUpdated(host: LifecycleHost) { export function handleFirstUpdated(host: LifecycleHost) {
@@ -62,6 +67,7 @@ export function handleDisconnected(host: LifecycleHost) {
window.removeEventListener("popstate", host.popStateHandler); window.removeEventListener("popstate", host.popStateHandler);
stopNodesPolling(host as unknown as Parameters<typeof stopNodesPolling>[0]); stopNodesPolling(host as unknown as Parameters<typeof stopNodesPolling>[0]);
stopLogsPolling(host as unknown as Parameters<typeof stopLogsPolling>[0]); stopLogsPolling(host as unknown as Parameters<typeof stopLogsPolling>[0]);
stopDebugPolling(host as unknown as Parameters<typeof stopDebugPolling>[0]);
detachThemeListener( detachThemeListener(
host as unknown as Parameters<typeof detachThemeListener>[0], host as unknown as Parameters<typeof detachThemeListener>[0],
); );

View File

@@ -1,10 +1,12 @@
import { loadLogs } from "./controllers/logs"; import { loadLogs } from "./controllers/logs";
import { loadNodes } from "./controllers/nodes"; import { loadNodes } from "./controllers/nodes";
import { loadDebug } from "./controllers/debug";
import type { ClawdbotApp } from "./app"; import type { ClawdbotApp } from "./app";
type PollingHost = { type PollingHost = {
nodesPollInterval: number | null; nodesPollInterval: number | null;
logsPollInterval: number | null; logsPollInterval: number | null;
debugPollInterval: number | null;
tab: string; tab: string;
}; };
@@ -35,3 +37,17 @@ export function stopLogsPolling(host: PollingHost) {
clearInterval(host.logsPollInterval); clearInterval(host.logsPollInterval);
host.logsPollInterval = null; host.logsPollInterval = null;
} }
export function startDebugPolling(host: PollingHost) {
if (host.debugPollInterval != null) return;
host.debugPollInterval = window.setInterval(() => {
if (host.tab !== "debug") return;
void loadDebug(host as unknown as ClawdbotApp);
}, 3000);
}
export function stopDebugPolling(host: PollingHost) {
if (host.debugPollInterval == null) return;
clearInterval(host.debugPollInterval);
host.debugPollInterval = null;
}

View File

@@ -0,0 +1,91 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { Tab } from "./navigation";
type SettingsHost = Parameters<typeof import("./app-settings").setTabFromRoute>[0];
const createHost = (tab: Tab): SettingsHost => ({
settings: {
gatewayUrl: "",
token: "",
sessionKey: "main",
lastActiveSessionKey: "main",
theme: "system",
chatFocusMode: false,
chatShowThinking: true,
splitRatio: 0.6,
navCollapsed: false,
navGroupsCollapsed: {},
},
theme: "system",
themeResolved: "dark",
applySessionKey: "main",
sessionKey: "main",
tab,
connected: false,
chatHasAutoScrolled: false,
logsAtBottom: false,
eventLog: [],
eventLogBuffer: [],
basePath: "",
themeMedia: null,
themeMediaHandler: null,
});
describe("setTabFromRoute", () => {
beforeEach(() => {
vi.resetModules();
});
it("starts and stops log polling based on the tab", async () => {
const startLogsPolling = vi.fn();
const stopLogsPolling = vi.fn();
const startDebugPolling = vi.fn();
const stopDebugPolling = vi.fn();
vi.doMock("./app-polling", () => ({
startLogsPolling,
stopLogsPolling,
startDebugPolling,
stopDebugPolling,
}));
const { setTabFromRoute } = await import("./app-settings");
const host = createHost("chat");
setTabFromRoute(host, "logs");
expect(startLogsPolling).toHaveBeenCalledTimes(1);
expect(stopLogsPolling).not.toHaveBeenCalled();
expect(startDebugPolling).not.toHaveBeenCalled();
expect(stopDebugPolling).toHaveBeenCalledTimes(1);
setTabFromRoute(host, "chat");
expect(stopLogsPolling).toHaveBeenCalledTimes(1);
});
it("starts and stops debug polling based on the tab", async () => {
const startLogsPolling = vi.fn();
const stopLogsPolling = vi.fn();
const startDebugPolling = vi.fn();
const stopDebugPolling = vi.fn();
vi.doMock("./app-polling", () => ({
startLogsPolling,
stopLogsPolling,
startDebugPolling,
stopDebugPolling,
}));
const { setTabFromRoute } = await import("./app-settings");
const host = createHost("chat");
setTabFromRoute(host, "debug");
expect(startDebugPolling).toHaveBeenCalledTimes(1);
expect(stopDebugPolling).not.toHaveBeenCalled();
expect(startLogsPolling).not.toHaveBeenCalled();
expect(stopLogsPolling).toHaveBeenCalledTimes(1);
setTabFromRoute(host, "chat");
expect(stopDebugPolling).toHaveBeenCalledTimes(1);
});
});

View File

@@ -14,7 +14,7 @@ import { saveSettings, type UiSettings } from "./storage";
import { resolveTheme, type ResolvedTheme, type ThemeMode } from "./theme"; import { resolveTheme, type ResolvedTheme, type ThemeMode } from "./theme";
import { startThemeTransition, type ThemeTransitionContext } from "./theme-transition"; import { startThemeTransition, type ThemeTransitionContext } from "./theme-transition";
import { scheduleChatScroll, scheduleLogsScroll } from "./app-scroll"; import { scheduleChatScroll, scheduleLogsScroll } from "./app-scroll";
import { startLogsPolling, stopLogsPolling } from "./app-polling"; import { startLogsPolling, stopLogsPolling, startDebugPolling, stopDebugPolling } from "./app-polling";
import { refreshChat } from "./app-chat"; import { refreshChat } from "./app-chat";
import type { ClawdbotApp } from "./app"; import type { ClawdbotApp } from "./app";
@@ -116,6 +116,9 @@ export function setTab(host: SettingsHost, next: Tab) {
if (next === "logs") if (next === "logs")
startLogsPolling(host as unknown as Parameters<typeof startLogsPolling>[0]); startLogsPolling(host as unknown as Parameters<typeof startLogsPolling>[0]);
else stopLogsPolling(host as unknown as Parameters<typeof stopLogsPolling>[0]); else stopLogsPolling(host as unknown as Parameters<typeof stopLogsPolling>[0]);
if (next === "debug")
startDebugPolling(host as unknown as Parameters<typeof startDebugPolling>[0]);
else stopDebugPolling(host as unknown as Parameters<typeof stopDebugPolling>[0]);
void refreshActiveTab(host); void refreshActiveTab(host);
syncUrlWithTab(host, next, false); syncUrlWithTab(host, next, false);
} }
@@ -261,6 +264,9 @@ export function setTabFromRoute(host: SettingsHost, next: Tab) {
if (next === "logs") if (next === "logs")
startLogsPolling(host as unknown as Parameters<typeof startLogsPolling>[0]); startLogsPolling(host as unknown as Parameters<typeof startLogsPolling>[0]);
else stopLogsPolling(host as unknown as Parameters<typeof stopLogsPolling>[0]); else stopLogsPolling(host as unknown as Parameters<typeof stopLogsPolling>[0]);
if (next === "debug")
startDebugPolling(host as unknown as Parameters<typeof startDebugPolling>[0]);
else stopDebugPolling(host as unknown as Parameters<typeof stopDebugPolling>[0]);
if (host.connected) void refreshActiveTab(host); if (host.connected) void refreshActiveTab(host);
} }

View File

@@ -226,6 +226,7 @@ export class ClawdbotApp extends LitElement {
private chatUserNearBottom = true; private chatUserNearBottom = true;
private nodesPollInterval: number | null = null; private nodesPollInterval: number | null = null;
private logsPollInterval: number | null = null; private logsPollInterval: number | null = null;
private debugPollInterval: number | null = null;
private logsScrollFrame: number | null = null; private logsScrollFrame: number | null = null;
private toolStreamById = new Map<string, ToolStreamEntry>(); private toolStreamById = new Map<string, ToolStreamEntry>();
private toolStreamOrder: string[] = []; private toolStreamOrder: string[] = [];