From 7e34687015a133db4f054cc7b8c7b6f7aba722d3 Mon Sep 17 00:00:00 2001 From: Leon-SK668 <0668001470@xydigit.com> Date: Fri, 17 Jul 2026 13:27:04 +0800 Subject: [PATCH] fix(scripts): preserve emoji in issue label prompts (#109477) --- scripts/label-open-issues.ts | 3 ++- test/scripts/label-open-issues.test.ts | 37 ++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/scripts/label-open-issues.ts b/scripts/label-open-issues.ts index 65402ba74b2..6f49ae129d4 100644 --- a/scripts/label-open-issues.ts +++ b/scripts/label-open-issues.ts @@ -4,6 +4,7 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"; import { homedir } from "node:os"; import { dirname, join } from "node:path"; import { pathToFileURL } from "node:url"; +import { truncateUtf16Safe } from "@openclaw/normalization-core/utf16-slice"; import { isRecord } from "../src/utils.js"; import { readBoundedResponseText as readBoundedBodyText } from "./lib/bounded-response.ts"; import { parseStrictIntegerOption } from "./lib/dev-tooling-safety.ts"; @@ -644,7 +645,7 @@ function truncateBody(body: string): string { if (body.length <= MAX_BODY_CHARS) { return body; } - return `${body.slice(0, MAX_BODY_CHARS)}\n\n[truncated]`; + return `${truncateUtf16Safe(body, MAX_BODY_CHARS)}\n\n[truncated]`; } function buildItemPrompt(item: LabelItem, kind: "issue" | "pull request"): string { diff --git a/test/scripts/label-open-issues.test.ts b/test/scripts/label-open-issues.test.ts index f74b0a54cff..cabf430b8d9 100644 --- a/test/scripts/label-open-issues.test.ts +++ b/test/scripts/label-open-issues.test.ts @@ -226,4 +226,41 @@ describe("label-open-issues helpers", () => { /OPENCLAW_LABEL_OPEN_ISSUES_OPENAI_TIMEOUT_MS must be an integer/u, ); }); + + it("does not split boundary emoji in model prompts", async () => { + let requestBody = ""; + const response = new Response( + JSON.stringify({ + output_text: JSON.stringify({ + category: "bug", + isSupport: false, + isSkillOnly: false, + }), + }), + { status: 200 }, + ); + + await testing.classifyItem( + { + ...labelItem, + body: `${"a".repeat(5999)}😀tail`, + }, + "issue", + { + apiKey: "placeholder", + model: "test-model", + timeoutMs: 50, + fetchImpl: ((_url, init) => { + requestBody = String(init?.body ?? ""); + return Promise.resolve(response); + }) as typeof fetch, + }, + ); + + const payload = JSON.parse(requestBody) as { input: Array<{ content: string }> }; + const prompt = payload.input[1]?.content ?? ""; + expect(prompt).toContain(`${"a".repeat(5999)}\n\n[truncated]`); + expect(prompt).not.toContain("\uD83D"); + expect(prompt).not.toContain("tail"); + }); });