Skip to content

Commit 7e34687

Browse files
authored
fix(scripts): preserve emoji in issue label prompts (#109477)
1 parent 6bd15d0 commit 7e34687

2 files changed

Lines changed: 39 additions & 1 deletion

File tree

scripts/label-open-issues.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
44
import { homedir } from "node:os";
55
import { dirname, join } from "node:path";
66
import { pathToFileURL } from "node:url";
7+
import { truncateUtf16Safe } from "@openclaw/normalization-core/utf16-slice";
78
import { isRecord } from "../src/utils.js";
89
import { readBoundedResponseText as readBoundedBodyText } from "./lib/bounded-response.ts";
910
import { parseStrictIntegerOption } from "./lib/dev-tooling-safety.ts";
@@ -644,7 +645,7 @@ function truncateBody(body: string): string {
644645
if (body.length <= MAX_BODY_CHARS) {
645646
return body;
646647
}
647-
return `${body.slice(0, MAX_BODY_CHARS)}\n\n[truncated]`;
648+
return `${truncateUtf16Safe(body, MAX_BODY_CHARS)}\n\n[truncated]`;
648649
}
649650

650651
function buildItemPrompt(item: LabelItem, kind: "issue" | "pull request"): string {

test/scripts/label-open-issues.test.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,4 +226,41 @@ describe("label-open-issues helpers", () => {
226226
/OPENCLAW_LABEL_OPEN_ISSUES_OPENAI_TIMEOUT_MS must be an integer/u,
227227
);
228228
});
229+
230+
it("does not split boundary emoji in model prompts", async () => {
231+
let requestBody = "";
232+
const response = new Response(
233+
JSON.stringify({
234+
output_text: JSON.stringify({
235+
category: "bug",
236+
isSupport: false,
237+
isSkillOnly: false,
238+
}),
239+
}),
240+
{ status: 200 },
241+
);
242+
243+
await testing.classifyItem(
244+
{
245+
...labelItem,
246+
body: `${"a".repeat(5999)}😀tail`,
247+
},
248+
"issue",
249+
{
250+
apiKey: "placeholder",
251+
model: "test-model",
252+
timeoutMs: 50,
253+
fetchImpl: ((_url, init) => {
254+
requestBody = String(init?.body ?? "");
255+
return Promise.resolve(response);
256+
}) as typeof fetch,
257+
},
258+
);
259+
260+
const payload = JSON.parse(requestBody) as { input: Array<{ content: string }> };
261+
const prompt = payload.input[1]?.content ?? "";
262+
expect(prompt).toContain(`${"a".repeat(5999)}\n\n[truncated]`);
263+
expect(prompt).not.toContain("\uD83D");
264+
expect(prompt).not.toContain("tail");
265+
});
229266
});

0 commit comments

Comments
 (0)