Skip to content

Commit 5f56a54

Browse files
ZengWen-DTsteipete
andauthored
fix(opencode): preserve Unicode in catalog tool input (#109591)
Co-authored-by: Peter Steinberger <[email protected]>
1 parent 17c2ce0 commit 5f56a54

2 files changed

Lines changed: 23 additions & 2 deletions

File tree

extensions/opencode/session-catalog.test.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ function captureOpenCodeSessionRegistrations(pluginConfig: unknown = {}) {
8686
async function installFakeOpenCode(
8787
assistantText = "hi",
8888
sessionTitle = "Catalog session",
89+
toolInput: unknown = { command: "pwd" },
8990
): Promise<string> {
9091
const directory = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-opencode-catalog-"));
9192
temporaryDirectories.push(directory);
@@ -125,7 +126,7 @@ async function installFakeOpenCode(
125126
id: "prt_tool",
126127
type: "tool",
127128
tool: "bash",
128-
state: { status: "completed", input: { command: "pwd" }, output: "/workspace" },
129+
state: { status: "completed", input: toolInput, output: "/workspace" },
129130
},
130131
],
131132
},
@@ -299,6 +300,25 @@ describe("OpenCode session catalog", () => {
299300
},
300301
);
301302

303+
it.runIf(process.platform !== "win32")(
304+
"keeps truncated tool input on a valid UTF-16 boundary",
305+
async () => {
306+
await installFakeOpenCode("hi", "Catalog session", {
307+
value: `${"x".repeat(19_989)}🎉`,
308+
});
309+
const transcript = await readLocalOpenCodeTranscriptPage({
310+
threadId: "ses_test",
311+
limit: 20,
312+
});
313+
const toolCall = transcript.items.find((item) => item.type === "toolCall");
314+
315+
expect(toolCall?.text).toMatch(/$/u);
316+
expect(toolCall?.text).not.toMatch(
317+
/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/u,
318+
);
319+
},
320+
);
321+
302322
it.runIf(process.platform !== "win32")(
303323
"auto-detects the CLI and honors the node-local Web UI switch",
304324
async () => {

extensions/opencode/session-catalog.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type {
66
SessionsCatalogReadResult,
77
} from "openclaw/plugin-sdk/session-catalog";
88
import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
9+
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
910
import {
1011
materializeWindowsSpawnProgram,
1112
resolveWindowsSpawnProgram,
@@ -352,7 +353,7 @@ export async function listLocalOpenCodeSessionPage(value?: unknown): Promise<Ope
352353
function jsonText(value: unknown, maxLength = 20_000): string | undefined {
353354
try {
354355
const text = JSON.stringify(value);
355-
return text.length > maxLength ? `${text.slice(0, maxLength)}…` : text;
356+
return text.length > maxLength ? `${truncateUtf16Safe(text, maxLength)}…` : text;
356357
} catch {
357358
return undefined;
358359
}

0 commit comments

Comments
 (0)