fix: format acpx doctor details safely

This commit is contained in:
Peter Steinberger
2026-04-25 05:14:58 +01:00
parent 757aee4cdd
commit c2139635ff
2 changed files with 57 additions and 2 deletions

View File

@@ -276,6 +276,32 @@ describe("createAcpxRuntimeService", () => {
await service.stop?.(ctx);
});
it("formats non-string doctor details without losing object payloads", async () => {
const workspaceDir = await makeTempDir();
const ctx = createServiceContext(workspaceDir);
const runtime = createMockRuntime({
doctor: async () => ({
ok: false,
message: "probe failed",
details: [{ code: "ACP_CLOSED", agent: "codex" }, new Error("stdin closed")],
}),
isHealthy: () => false,
});
const service = createAcpxRuntimeService({
runtimeFactory: () => runtime as never,
});
await service.start(ctx);
await vi.waitFor(() => {
expect(ctx.logger.warn).toHaveBeenCalledWith(
'embedded acpx runtime backend probe failed: probe failed ({"code":"ACP_CLOSED","agent":"codex"}; stdin closed)',
);
});
await service.stop?.(ctx);
});
it("can skip the embedded runtime backend via env", async () => {
process.env.OPENCLAW_SKIP_ACPX_RUNTIME = "1";
const workspaceDir = await makeTempDir();

View File

@@ -1,4 +1,5 @@
import fs from "node:fs/promises";
import { inspect } from "node:util";
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
import type {
AcpRuntime,
@@ -79,8 +80,36 @@ function warnOnIgnoredLegacyCompatibilityConfig(params: {
);
}
function formatDoctorFailureMessage(report: { message: string; details?: string[] }): string {
const detailText = report.details?.filter(Boolean).join("; ").trim();
function formatDoctorDetail(detail: unknown): string | null {
if (!detail) {
return null;
}
if (typeof detail === "string") {
return detail.trim() || null;
}
if (detail instanceof Error) {
return formatErrorMessage(detail);
}
if (typeof detail === "object") {
try {
return JSON.stringify(detail) ?? inspect(detail, { breakLength: Infinity, depth: 3 });
} catch {
return inspect(detail, { breakLength: Infinity, depth: 3 });
}
}
if (
typeof detail === "number" ||
typeof detail === "boolean" ||
typeof detail === "bigint" ||
typeof detail === "symbol"
) {
return detail.toString();
}
return inspect(detail, { breakLength: Infinity, depth: 3 });
}
function formatDoctorFailureMessage(report: { message: string; details?: unknown[] }): string {
const detailText = report.details?.map(formatDoctorDetail).filter(Boolean).join("; ").trim();
return detailText ? `${report.message} (${detailText})` : report.message;
}