mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-27 04:47:03 -06:00
fix(agents): keep provider error detail truncation UTF-16 safe (#102496)
* fix(agents): keep provider error detail truncation UTF-16 safe Replace the raw detail.slice(0, limit - 1) in truncateErrorDetail with truncateUtf16Safe so provider error previews do not emit lone surrogates when an emoji falls on the truncation boundary. Adds a regression test that places an emoji at the default truncation boundary and asserts the formatted detail contains no lone surrogates. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test(agents): prove provider error UTF-16 boundary --------- Co-authored-by: chengzhichao-xydt <chengzhichao-xydt@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
committed by
GitHub
parent
bacf048ab9
commit
51bb5f6847
@@ -136,6 +136,21 @@ describe("provider error utils", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("does not split UTF-16 surrogate pairs when truncating provider error details", async () => {
|
||||
const safePrefix = "a".repeat(218);
|
||||
const message = `${safePrefix}😀suffix`;
|
||||
const response = new Response(
|
||||
JSON.stringify({
|
||||
error: { message, code: "utf16_test" },
|
||||
}),
|
||||
{ status: 400 },
|
||||
);
|
||||
|
||||
await expect(assertOkOrThrowProviderError(response, "Provider API error")).rejects.toThrow(
|
||||
`Provider API error (400): ${safePrefix}… [code=utf16_test]`,
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps HTTP status metadata when error body reads fail", async () => {
|
||||
const response = {
|
||||
ok: false,
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* Transport adapters use this module to turn provider-specific response bodies,
|
||||
* request ids, and binary payload guardrails into stable OpenClaw error shapes.
|
||||
*/
|
||||
import { truncateUtf16Safe } from "@openclaw/normalization-core/utf16-slice";
|
||||
export { asFiniteNumber } from "../../packages/normalization-core/src/number-coercion.js";
|
||||
import { normalizeOptionalString as trimToUndefined } from "../../packages/normalization-core/src/string-coerce.js";
|
||||
import { readResponseWithLimit } from "../infra/http-body.js";
|
||||
@@ -25,7 +26,7 @@ export function asObject(value: unknown): Record<string, unknown> | undefined {
|
||||
|
||||
/** Trims provider error details to a log- and prompt-safe preview length. */
|
||||
export function truncateErrorDetail(detail: string, limit = 220): string {
|
||||
return detail.length <= limit ? detail : `${detail.slice(0, limit - 1)}…`;
|
||||
return detail.length <= limit ? detail : `${truncateUtf16Safe(detail, limit - 1)}…`;
|
||||
}
|
||||
|
||||
/** Redacts secrets before preserving a bounded provider error body preview. */
|
||||
|
||||
Reference in New Issue
Block a user