Files
openclaw/src/commands/doctor-gateway-health.ts
Ruslan Kharitonov 8d69251475 fix(doctor): use gateway health status for memory search key check (#22327)
Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: 2f02ec9403
Co-authored-by: therk <901920+therk@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-02-23 14:07:16 -05:00

93 lines
2.7 KiB
TypeScript

import type { OpenClawConfig } from "../config/config.js";
import { buildGatewayConnectionDetails, callGateway } from "../gateway/call.js";
import type { DoctorMemoryStatusPayload } from "../gateway/server-methods/doctor.js";
import { collectChannelStatusIssues } from "../infra/channels-status-issues.js";
import type { RuntimeEnv } from "../runtime.js";
import { note } from "../terminal/note.js";
import { formatHealthCheckFailure } from "./health-format.js";
import { healthCommand } from "./health.js";
export type GatewayMemoryProbe = {
checked: boolean;
ready: boolean;
error?: string;
};
export async function checkGatewayHealth(params: {
runtime: RuntimeEnv;
cfg: OpenClawConfig;
timeoutMs?: number;
}) {
const gatewayDetails = buildGatewayConnectionDetails({ config: params.cfg });
const timeoutMs =
typeof params.timeoutMs === "number" && params.timeoutMs > 0 ? params.timeoutMs : 10_000;
let healthOk = false;
try {
await healthCommand({ json: false, timeoutMs, config: params.cfg }, params.runtime);
healthOk = true;
} catch (err) {
const message = String(err);
if (message.includes("gateway closed")) {
note("Gateway not running.", "Gateway");
note(gatewayDetails.message, "Gateway connection");
} else {
params.runtime.error(formatHealthCheckFailure(err));
}
}
if (healthOk) {
try {
const status = await callGateway({
method: "channels.status",
params: { probe: true, timeoutMs: 5000 },
timeoutMs: 6000,
});
const issues = collectChannelStatusIssues(status);
if (issues.length > 0) {
note(
issues
.map(
(issue) =>
`- ${issue.channel} ${issue.accountId}: ${issue.message}${
issue.fix ? ` (${issue.fix})` : ""
}`,
)
.join("\n"),
"Channel warnings",
);
}
} catch {
// ignore: doctor already reported gateway health
}
}
return { healthOk };
}
export async function probeGatewayMemoryStatus(params: {
cfg: OpenClawConfig;
timeoutMs?: number;
}): Promise<GatewayMemoryProbe> {
const timeoutMs =
typeof params.timeoutMs === "number" && params.timeoutMs > 0 ? params.timeoutMs : 8_000;
try {
const payload = await callGateway<DoctorMemoryStatusPayload>({
method: "doctor.memory.status",
timeoutMs,
config: params.cfg,
});
return {
checked: true,
ready: payload.embedding.ok,
error: payload.embedding.error,
};
} catch (err) {
const message = err instanceof Error ? err.message : String(err);
return {
checked: true,
ready: false,
error: `gateway memory probe unavailable: ${message}`,
};
}
}