mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 06:50:43 +00:00
fix(doctor): treat gateway memory probe timeout as inconclusive (#72618)
This commit is contained in:
@@ -29,6 +29,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Exec/node: skip approval-plan preparation for full-trust `host=node` runs so interpreter and script commands no longer fail with `SYSTEM_RUN_DENIED: approval cannot safely bind` when effective policy is `security=full` and `ask=off`. Fixes #48457 and duplicate #69251. Thanks @ajtran303, @jaserNo1, @Blakeshannon, @lesliefag, and @AvIsBeastMC.
|
||||
- Exec/node: synthesize a local approval plan when a paired node advertises `system.run` without `system.run.prepare`, unblocking approval-required `host=node` exec on current macOS companion nodes while preserving remote prepare for node hosts that support it. Fixes #37591 and duplicate #66839; carries forward #69725. Thanks @soloclz.
|
||||
- Memory/QMD: prefer QMD's `--mask` collection pattern flag so root memory indexing stays scoped to `MEMORY.md` instead of widening to every markdown file in the workspace. Thanks @codex.
|
||||
- Memory/doctor: treat the specific `gateway timeout after ...` gateway memory probe result as inconclusive instead of reporting embeddings not ready, while preserving warnings for explicit failures. Fixes #44426; carries forward #46576 with the Greptile review feedback applied. Thanks Cengiz (@ghost).
|
||||
- Gateway/memory: defer QMD startup for implicit non-default agents and scope memory runtime loading to the selected memory slot so Gateway boot and first memory recall avoid broad plugin runtime fanout. Thanks @vincentkoc.
|
||||
- Gateway/startup: keep core request handlers, setup wizard, and channel runtime helpers off the boot path until the first matching request, wizard run, or channel start, reducing no-plugin Gateway ready RSS and avoidable startup imports. Thanks @vincentkoc.
|
||||
- CLI/Gateway: use a parse-only config snapshot for plain `gateway status` reads and reuse same-path service config context so status no longer spends tens of seconds in full config validation before printing. Thanks @vincentkoc.
|
||||
|
||||
57
src/commands/doctor-gateway-health.test.ts
Normal file
57
src/commands/doctor-gateway-health.test.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
|
||||
const callGateway = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock("../gateway/call.js", () => ({
|
||||
buildGatewayConnectionDetails: vi.fn(() => ({
|
||||
message: "Gateway target: ws://127.0.0.1:18789",
|
||||
})),
|
||||
callGateway,
|
||||
}));
|
||||
|
||||
vi.mock("./health.js", () => ({
|
||||
healthCommand: vi.fn(),
|
||||
}));
|
||||
|
||||
import { probeGatewayMemoryStatus } from "./doctor-gateway-health.js";
|
||||
|
||||
describe("probeGatewayMemoryStatus", () => {
|
||||
const cfg = {} as OpenClawConfig;
|
||||
|
||||
beforeEach(() => {
|
||||
callGateway.mockReset();
|
||||
});
|
||||
|
||||
it("treats outer gateway timeouts as inconclusive", async () => {
|
||||
callGateway.mockRejectedValue(
|
||||
new Error("gateway timeout after 8000ms\nGateway target: ws://127.0.0.1:18789"),
|
||||
);
|
||||
|
||||
await expect(probeGatewayMemoryStatus({ cfg })).resolves.toEqual({
|
||||
checked: false,
|
||||
ready: false,
|
||||
error: expect.stringContaining("gateway memory probe timed out"),
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps gateway request timeouts as explicit failures", async () => {
|
||||
callGateway.mockRejectedValue(new Error("gateway request timeout for doctor.memory.status"));
|
||||
|
||||
await expect(probeGatewayMemoryStatus({ cfg })).resolves.toEqual({
|
||||
checked: true,
|
||||
ready: false,
|
||||
error: "gateway memory probe unavailable: gateway request timeout for doctor.memory.status",
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps non-timeout gateway errors as explicit failures", async () => {
|
||||
callGateway.mockRejectedValue(new Error("gateway closed (1006): no close reason"));
|
||||
|
||||
await expect(probeGatewayMemoryStatus({ cfg })).resolves.toEqual({
|
||||
checked: true,
|
||||
ready: false,
|
||||
error: "gateway memory probe unavailable: gateway closed (1006): no close reason",
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -14,6 +14,10 @@ export type GatewayMemoryProbe = {
|
||||
error?: string;
|
||||
};
|
||||
|
||||
function isGatewayCallTimeout(message: string): boolean {
|
||||
return /^gateway timeout after \d+ms(?:\n|$)/.test(message);
|
||||
}
|
||||
|
||||
export async function checkGatewayHealth(params: {
|
||||
runtime: RuntimeEnv;
|
||||
cfg: OpenClawConfig;
|
||||
@@ -84,6 +88,13 @@ export async function probeGatewayMemoryStatus(params: {
|
||||
};
|
||||
} catch (err) {
|
||||
const message = formatErrorMessage(err);
|
||||
if (isGatewayCallTimeout(message)) {
|
||||
return {
|
||||
checked: false,
|
||||
ready: false,
|
||||
error: `gateway memory probe timed out: ${message}`,
|
||||
};
|
||||
}
|
||||
return {
|
||||
checked: true,
|
||||
ready: false,
|
||||
|
||||
@@ -228,6 +228,24 @@ describe("noteMemorySearchHealth", () => {
|
||||
expect(note).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not treat an inconclusive gateway timeout as local embeddings not ready", async () => {
|
||||
resolveMemorySearchConfig.mockReturnValue({
|
||||
provider: "local",
|
||||
local: {},
|
||||
remote: {},
|
||||
});
|
||||
|
||||
await noteMemorySearchHealth(cfg, {
|
||||
gatewayMemoryProbe: {
|
||||
checked: false,
|
||||
ready: false,
|
||||
error: "gateway memory probe timed out: gateway timeout after 8000ms",
|
||||
},
|
||||
});
|
||||
|
||||
expect(note).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not warn when local provider has an explicit hf: modelPath", async () => {
|
||||
resolveMemorySearchConfig.mockReturnValue({
|
||||
provider: "local",
|
||||
|
||||
Reference in New Issue
Block a user