From bb1fa4012ecffa3ed37f6b08cccf030a5789c6e5 Mon Sep 17 00:00:00 2001 From: lsr911 Date: Thu, 9 Jul 2026 17:38:43 +0800 Subject: [PATCH] fix(memory-host): use truncateUtf16Safe for QMD stderr context truncation (#102547) * fix(memory-host): use truncateUtf16Safe for QMD stderr context truncation * test(memory): cover UTF-16-safe qmd stderr summary --------- Co-authored-by: Peter Steinberger --- .../memory-host-sdk/src/host/qmd-query-parser.test.ts | 9 +++++++++ packages/memory-host-sdk/src/host/qmd-query-parser.ts | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/memory-host-sdk/src/host/qmd-query-parser.test.ts b/packages/memory-host-sdk/src/host/qmd-query-parser.test.ts index 8f14646cb8b4..e41d16069f64 100644 --- a/packages/memory-host-sdk/src/host/qmd-query-parser.test.ts +++ b/packages/memory-host-sdk/src/host/qmd-query-parser.test.ts @@ -60,6 +60,15 @@ complete`, expect(parseQmdQueryJson("", "[qmd] warning: no results found\n")).toStrictEqual([]); }); + it("keeps bounded stderr context UTF-16 safe", () => { + const prefix = "a".repeat(116); + const stderr = `${prefix}😀${"b".repeat(120)}`; + + expect(() => parseQmdQueryJson("", stderr)).toThrow( + `qmd query returned invalid JSON: stdout empty (stderr: ${prefix}...)`, + ); + }); + it("does not treat arbitrary non-marker text as no-results output", () => { expect(() => parseQmdQueryJson("warning: search completed; no results found for this query", ""), diff --git a/packages/memory-host-sdk/src/host/qmd-query-parser.ts b/packages/memory-host-sdk/src/host/qmd-query-parser.ts index a8be1db36958..5a31a376a07e 100644 --- a/packages/memory-host-sdk/src/host/qmd-query-parser.ts +++ b/packages/memory-host-sdk/src/host/qmd-query-parser.ts @@ -1,4 +1,5 @@ // Memory Host SDK module implements qmd query parser behavior. +import { truncateUtf16Safe } from "@openclaw/normalization-core/utf16-slice"; import { formatErrorMessage } from "./error-utils.js"; import { normalizeLowercaseStringOrEmpty } from "./string-utils.js"; @@ -81,7 +82,7 @@ function isQmdNoResultsLine(line: string): boolean { /** Bound stderr context included in parse errors. */ function summarizeQmdStderr(raw: string): string { - return raw.length <= 120 ? raw : `${raw.slice(0, 117)}...`; + return raw.length <= 120 ? raw : `${truncateUtf16Safe(raw, 117)}...`; } /** Parse and normalize a strict qmd JSON array payload. */