From 46f629882b508db9979b7fed1f0ecb097fd8ab10 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Wed, 29 Jul 2026 16:50:37 +0800 Subject: [PATCH] refactor(gateway): own health summary contract --- src/cli/daemon-cli/restart-health-probe.ts | 2 +- src/cli/daemon-cli/restart-health.ts | 2 +- src/cli/daemon-cli/restart-health.types.ts | 2 +- src/commands/health-format.ts | 2 +- src/commands/health.ts | 22 +++++++++---------- .../health/types.ts} | 8 +++---- src/gateway/server-methods/health.ts | 2 +- src/gateway/server-methods/shared-types.ts | 2 +- .../server.roles-allowlist-update.test.ts | 2 +- ...essage-handler.post-connect-health.test.ts | 2 +- src/system-agent/greeting.ts | 2 +- 11 files changed, 24 insertions(+), 24 deletions(-) rename src/{commands/health.types.ts => gateway/health/types.ts} (89%) diff --git a/src/cli/daemon-cli/restart-health-probe.ts b/src/cli/daemon-cli/restart-health-probe.ts index 7b9a4aafbf05..a5193ebc0fc7 100644 --- a/src/cli/daemon-cli/restart-health-probe.ts +++ b/src/cli/daemon-cli/restart-health-probe.ts @@ -2,9 +2,9 @@ import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, } from "@openclaw/normalization-core/string-coerce"; -import type { PluginHealthErrorSummary } from "../../commands/health.types.js"; import { createConfigIO } from "../../config/io.js"; import type { OpenClawConfig } from "../../config/types.openclaw.js"; +import type { PluginHealthErrorSummary } from "../../gateway/health/types.js"; import { resolveGatewayProbeAuthSafeWithSecretInputs } from "../../gateway/probe-auth.js"; import { probeGateway } from "../../gateway/probe.js"; import { inspectPortUsage, type PortUsage } from "../../infra/ports.js"; diff --git a/src/cli/daemon-cli/restart-health.ts b/src/cli/daemon-cli/restart-health.ts index 34d9c8913a27..4ca9beb1b3da 100644 --- a/src/cli/daemon-cli/restart-health.ts +++ b/src/cli/daemon-cli/restart-health.ts @@ -1,8 +1,8 @@ // Restart health probes for gateway service restarts and port listener recovery. import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce"; -import type { PluginHealthErrorSummary } from "../../commands/health.types.js"; import type { GatewayServiceRuntime } from "../../daemon/service-runtime.js"; import type { GatewayService } from "../../daemon/service.js"; +import type { PluginHealthErrorSummary } from "../../gateway/health/types.js"; import { classifyPortListener, inspectPortUsage, type PortUsage } from "../../infra/ports.js"; import { hasActiveStartupMigrationLease, diff --git a/src/cli/daemon-cli/restart-health.types.ts b/src/cli/daemon-cli/restart-health.types.ts index f8ab24a58cda..8a16510dff74 100644 --- a/src/cli/daemon-cli/restart-health.types.ts +++ b/src/cli/daemon-cli/restart-health.types.ts @@ -1,5 +1,5 @@ -import type { PluginHealthErrorSummary } from "../../commands/health.types.js"; import type { GatewayServiceRuntime } from "../../daemon/service-runtime.js"; +import type { PluginHealthErrorSummary } from "../../gateway/health/types.js"; import type { PortUsage } from "../../infra/ports.js"; export type GatewayRestartWaitOutcome = diff --git a/src/commands/health-format.ts b/src/commands/health-format.ts index 1cc6b4a64c1d..ff017d57ea8d 100644 --- a/src/commands/health-format.ts +++ b/src/commands/health-format.ts @@ -5,7 +5,7 @@ import { sanitizeTerminalText } from "../../packages/terminal-core/src/safe-text import { colorize, isRich, theme } from "../../packages/terminal-core/src/theme.js"; import { formatChannelStatusState } from "../channels/plugins/status-state.js"; import { isGatewayTransportError } from "../gateway/call.js"; -import type { ChannelAccountHealthSummary, HealthSummary } from "./health.types.js"; +import type { ChannelAccountHealthSummary, HealthSummary } from "../gateway/health/types.js"; export function formatGatewayClosedDiagnostic(err: unknown): string | undefined { if (!isGatewayTransportError(err) || err.kind !== "closed") { diff --git a/src/commands/health.ts b/src/commands/health.ts index e72a565f72c7..f4fa00bd474b 100644 --- a/src/commands/health.ts +++ b/src/commands/health.ts @@ -36,6 +36,16 @@ import { } from "../gateway/channel-health-policy.js"; import type { GatewayHotReloadStatus } from "../gateway/config-reload-status.types.js"; import { isGatewaySecretRefUnavailableError } from "../gateway/credentials.js"; +import type { + AgentHealthSummary, + ChannelAccountHealthSummary, + ChannelHealthSummary, + ContextEngineHealthSummary, + DeliveryQueueHealthSummary, + HealthSummary, + PluginHealthErrorSummary, + PluginHealthSummary, +} from "../gateway/health/types.js"; import type { ChannelRuntimeSnapshot } from "../gateway/server-channel-runtime.types.js"; import { info } from "../globals.js"; import { countFailedDeliveryQueueEntries } from "../infra/delivery-queue-sqlite.js"; @@ -59,19 +69,9 @@ import { gatewayProbeResultSawGateway, } from "./gateway-health-auth-diagnostic.js"; import { formatHealthChannelLines } from "./health-format.js"; -import type { - AgentHealthSummary, - ChannelAccountHealthSummary, - ChannelHealthSummary, - ContextEngineHealthSummary, - DeliveryQueueHealthSummary, - HealthSummary, - PluginHealthErrorSummary, - PluginHealthSummary, -} from "./health.types.js"; import { logGatewayConnectionDetails } from "./status.gateway-connection.js"; export { formatHealthChannelLines } from "./health-format.js"; -export type { HealthSummary } from "./health.types.js"; +export type { HealthSummary } from "../gateway/health/types.js"; const DEFAULT_TIMEOUT_MS = 10_000; const healthLog = createSubsystemLogger("health"); diff --git a/src/commands/health.types.ts b/src/gateway/health/types.ts similarity index 89% rename from src/commands/health.types.ts rename to src/gateway/health/types.ts index c7d528821ae1..fc3b23e1b55b 100644 --- a/src/commands/health.types.ts +++ b/src/gateway/health/types.ts @@ -20,7 +20,7 @@ export type AgentHealthSummary = { agentId: string; name?: string; isDefault: boolean; - heartbeat: import("../infra/heartbeat-summary.js").HeartbeatSummary; + heartbeat: import("../../infra/heartbeat-summary.js").HeartbeatSummary; sessions: HealthSummary["sessions"]; }; @@ -44,7 +44,7 @@ export type PluginHealthSummary = { state: "configured-unavailable"; diagnostic: { kind: "plugin-verification"; - reason: import("../plugins/runtime-degraded-state.js").PluginVerificationFailureReason; + reason: import("../../plugins/runtime-degraded-state.js").PluginVerificationFailureReason; detail: string; }; }>; @@ -81,7 +81,7 @@ export type DeliveryQueueHealthSummary = { /** Config hot-reload watcher status, present only when a reloader is running. */ type ConfigReloadHealthSummary = { - hotReloadStatus: import("../gateway/config-reload-status.types.js").GatewayHotReloadStatus; + hotReloadStatus: import("../config-reload-status.types.js").GatewayHotReloadStatus; }; /** Full gateway health payload consumed by `openclaw health`. */ @@ -89,7 +89,7 @@ export type HealthSummary = { ok: true; ts: number; durationMs: number; - eventLoop?: import("../gateway/server/event-loop-health.js").GatewayEventLoopHealth; + eventLoop?: import("../server/event-loop-health.js").GatewayEventLoopHealth; plugins?: PluginHealthSummary; contextEngines?: ContextEngineHealthSummary; deliveryQueues?: DeliveryQueueHealthSummary; diff --git a/src/gateway/server-methods/health.ts b/src/gateway/server-methods/health.ts index 71b46c1ce020..6bbcf43e40dc 100644 --- a/src/gateway/server-methods/health.ts +++ b/src/gateway/server-methods/health.ts @@ -3,10 +3,10 @@ import { ErrorCodes, errorShape } from "../../../packages/gateway-protocol/src/index.js"; import type { ChannelAccountSnapshot } from "../../channels/plugins/types.public.js"; import { buildDeliveryQueueHealthSummary } from "../../commands/health.js"; -import type { ChannelHealthSummary, HealthSummary } from "../../commands/health.types.js"; import { getStatusSummary } from "../../commands/status.js"; import { listContextEngineQuarantines } from "../../context-engine/registry.js"; import type { GatewayHotReloadStatus } from "../config-reload-status.types.js"; +import type { ChannelHealthSummary, HealthSummary } from "../health/types.js"; import type { ChannelRuntimeSnapshot } from "../server-channel-runtime.types.js"; import { HEALTH_REFRESH_INTERVAL_MS } from "../server-constants.js"; import { formatError } from "../server-utils.js"; diff --git a/src/gateway/server-methods/shared-types.ts b/src/gateway/server-methods/shared-types.ts index 29ac58c10ad4..91b6d604cf48 100644 --- a/src/gateway/server-methods/shared-types.ts +++ b/src/gateway/server-methods/shared-types.ts @@ -11,7 +11,6 @@ import type { } from "../../../packages/gateway-protocol/src/schema/frames.js"; import type { ModelCatalogEntry } from "../../agents/model-catalog.types.js"; import type { CliDeps } from "../../cli/deps.types.js"; -import type { HealthSummary } from "../../commands/health.types.js"; import type { OpenClawConfig } from "../../config/types.openclaw.js"; import type { PluginApprovalRequest, @@ -26,6 +25,7 @@ import type { AgentRuntimeIdentity } from "../agent-runtime-identity-token.js"; import type { ChatAbortControllerEntry } from "../chat-abort.js"; import type { GatewayHotReloadStatus } from "../config-reload-status.types.js"; import type { ExecApprovalManager, ExecApprovalRecord } from "../exec-approval-manager.js"; +import type { HealthSummary } from "../health/types.js"; import type { GatewayMethodRegistryView } from "../methods/descriptor.js"; import type { NodeRegistry } from "../node-registry.js"; import type { PluginNodeCapabilitySurface } from "../plugin-node-capability.js"; diff --git a/src/gateway/server.roles-allowlist-update.test.ts b/src/gateway/server.roles-allowlist-update.test.ts index 9e745b9d0034..383d42264226 100644 --- a/src/gateway/server.roles-allowlist-update.test.ts +++ b/src/gateway/server.roles-allowlist-update.test.ts @@ -5,7 +5,6 @@ import os from "node:os"; import path from "node:path"; import { beforeEach, describe, expect, test, vi } from "vitest"; import { WebSocket } from "ws"; -import type { HealthSummary } from "../commands/health.types.js"; import type { DeviceIdentity } from "../infra/device-identity.js"; import { loadOrCreateDeviceIdentity } from "../infra/device-identity.js"; import { approveDevicePairing, listDevicePairing } from "../infra/device-pairing.js"; @@ -20,6 +19,7 @@ import { type GatewayClientName, } from "../utils/message-channel.js"; import type { GatewayClient } from "./client.js"; +import type { HealthSummary } from "./health/types.js"; vi.mock("../infra/update-runner.js", () => ({ resolveUpdateInstallSurface: vi.fn(async () => ({ diff --git a/src/gateway/server/ws-connection/message-handler.post-connect-health.test.ts b/src/gateway/server/ws-connection/message-handler.post-connect-health.test.ts index 1b5c41e4b17a..8fe30a0f347d 100644 --- a/src/gateway/server/ws-connection/message-handler.post-connect-health.test.ts +++ b/src/gateway/server/ws-connection/message-handler.post-connect-health.test.ts @@ -4,7 +4,6 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import type { WebSocket } from "ws"; import { ConnectErrorDetailCodes } from "../../../../packages/gateway-protocol/src/connect-error-details.js"; import { ErrorCodes, PROTOCOL_VERSION } from "../../../../packages/gateway-protocol/src/index.js"; -import type { HealthSummary } from "../../../commands/health.types.js"; import { onInternalDiagnosticEvent, resetDiagnosticEventsForTest, @@ -19,6 +18,7 @@ import { withOpenClawTestState } from "../../../test-utils/openclaw-test-state.j import { mintAgentRuntimeIdentityToken } from "../../agent-runtime-identity-token.js"; import type { AuthRateLimiter } from "../../auth-rate-limit.js"; import type { ResolvedGatewayAuth } from "../../auth.js"; +import type { HealthSummary } from "../../health/types.js"; import { getOperatorApprovalRuntimeToken } from "../../operator-approval-runtime-token.js"; import { handleGatewayRequest } from "../../server-methods.js"; import type { GatewayRequestContext } from "../../server-methods/types.js"; diff --git a/src/system-agent/greeting.ts b/src/system-agent/greeting.ts index 7093f9ed1ca9..32c2221d8532 100644 --- a/src/system-agent/greeting.ts +++ b/src/system-agent/greeting.ts @@ -2,12 +2,12 @@ import { createHash } from "node:crypto"; import { truncateUtf16Safe } from "@openclaw/normalization-core/utf16-slice"; import type { SystemAgentChatQuestion } from "../../packages/gateway-protocol/src/index.js"; -import type { HealthSummary } from "../commands/health.types.js"; import { CONFIG_AUDIT_MAX_ENTRIES, CONFIG_AUDIT_SCOPE, type ConfigAuditRecord, } from "../config/io.audit.js"; +import type { HealthSummary } from "../gateway/health/types.js"; import { getHealthCache } from "../gateway/server/health-state.js"; import { createSqliteAuditRecordStore } from "../infra/sqlite-audit-record-store.js"; import { getUpdateAvailable, type UpdateAvailable } from "../infra/update-startup.js";