


























@@ -13,6 +13,7 @@ import { withProgress } from "../cli/progress.js";
1313import { getRuntimeConfig } from "../config/config.js";
1414import { resolveStorePath } from "../config/sessions/paths.js";
1515import type { OpenClawConfig } from "../config/types.openclaw.js";
16+import { listContextEngineQuarantines } from "../context-engine/registry.js";
1617import {
1718buildGatewayConnectionDetails,
1819callGateway,
@@ -43,6 +44,7 @@ import type {
4344AgentHealthSummary,
4445ChannelAccountHealthSummary,
4546ChannelHealthSummary,
47+ContextEngineHealthSummary,
4648HealthSummary,
4749PluginHealthErrorSummary,
4850PluginHealthSummary,
@@ -166,6 +168,32 @@ export function formatModelPricingHealthLine(summary: HealthSummary): string | n
166168return `Model pricing: warning (optional pricing refresh degraded)${detail}`;
167169}
168170171+function buildContextEngineHealthSummary(): ContextEngineHealthSummary | undefined {
172+const quarantined: ContextEngineHealthSummary["quarantined"] = [];
173+for (const entry of listContextEngineQuarantines()) {
174+const summary: ContextEngineHealthSummary["quarantined"][number] = {
175+engineId: entry.engineId,
176+operation: entry.operation,
177+reason: entry.reason,
178+failedAt: entry.failedAt.getTime(),
179+};
180+if (entry.owner) {
181+summary.owner = entry.owner;
182+}
183+quarantined.push(summary);
184+}
185+return quarantined.length > 0 ? { quarantined } : undefined;
186+}
187+188+export function formatContextEngineHealthLine(summary: HealthSummary): string | null {
189+const quarantined = summary.contextEngines?.quarantined ?? [];
190+if (quarantined.length === 0) {
191+return null;
192+}
193+const engines = quarantined.map((entry) => entry.engineId).join(", ");
194+return `Context engine: warning (${quarantined.length} quarantined; downgraded to legacy: ${engines})`;
195+}
196+169197const resolveHeartbeatSummary = (cfg: OpenClawConfig, agentId: string) =>
170198resolveHeartbeatSummaryForAgent(cfg, agentId);
171199@@ -571,12 +599,14 @@ export async function getHealthSnapshot(params?: {
571599}
572600573601const pluginHealth = buildPluginHealthSummary();
602+const contextEngineHealth = buildContextEngineHealthSummary();
574603const summary: HealthSummary = {
575604ok: true,
576605ts: Date.now(),
577606durationMs: Date.now() - start,
578607 ...(params?.eventLoop ? { eventLoop: params.eventLoop } : {}),
579608 ...(pluginHealth ? { plugins: pluginHealth } : {}),
609+ ...(contextEngineHealth ? { contextEngines: contextEngineHealth } : {}),
580610modelPricing: getGatewayModelPricingHealth({ enabled: isGatewayModelPricingEnabled(cfg) }),
581611 channels,
582612 channelOrder,
@@ -782,6 +812,10 @@ export async function healthCommand(
782812if (modelPricingLine) {
783813runtime.log(styleHealthChannelLine(modelPricingLine, rich));
784814}
815+const contextEngineLine = formatContextEngineHealthLine(summary);
816+if (contextEngineLine) {
817+runtime.log(styleHealthChannelLine(contextEngineLine, rich));
818+}
785819for (const plugin of displayPlugins) {
786820const channelSummary = summary.channels?.[plugin.id];
787821if (!channelSummary || channelSummary.linked !== true) {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。