mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-16 22:31:38 +00:00
fix(agents): keep failover detail truncation UTF-16 safe (#104487)
* fix(agents): keep failover detail truncation UTF-16 safe Replace raw .slice(0, MAX_FAILOVER_DETAIL_CHARS) with truncateUtf16Safe so provider error details containing emoji or other non-BMP characters are not split at a surrogate-pair boundary before failover classification. Adds a regression test via extractFailoverSignalDetails. * test(agents): tighten failover UTF-16 coverage --------- Co-authored-by: chengzhichao-xydt <chengzhichao-xydt@users.noreply.github.com> Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
committed by
GitHub
parent
1bd4887a5e
commit
aa8f78788c
@@ -4,7 +4,11 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { OpenClawConfig } from "../../config/types.openclaw.js";
|
||||
import { MALFORMED_STREAMING_FRAGMENT_ERROR_MESSAGE } from "../../shared/assistant-error-format.js";
|
||||
import { makeAssistantMessageFixture } from "../test-helpers/assistant-message-fixtures.js";
|
||||
import { formatAssistantErrorText, isLikelyContextOverflowError } from "./errors.js";
|
||||
import {
|
||||
extractFailoverSignalDetails,
|
||||
formatAssistantErrorText,
|
||||
isLikelyContextOverflowError,
|
||||
} from "./errors.js";
|
||||
|
||||
const { toolPolicyAuditInfo } = vi.hoisted(() => ({
|
||||
toolPolicyAuditInfo: vi.fn(),
|
||||
@@ -98,6 +102,25 @@ describe("formatAssistantErrorText streaming JSON parse classification", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("extractFailoverSignalDetails", () => {
|
||||
it.each([
|
||||
{
|
||||
name: "backs off before a split surrogate pair",
|
||||
input: `${"a".repeat(999)}🎉!`,
|
||||
expected: "a".repeat(999),
|
||||
},
|
||||
{
|
||||
name: "keeps the full ASCII budget",
|
||||
input: "a".repeat(1001),
|
||||
expected: "a".repeat(1000),
|
||||
},
|
||||
])("$name in nested provider details", ({ input, expected }) => {
|
||||
const details = extractFailoverSignalDetails({ error: { body: { detail: input } } });
|
||||
|
||||
expect(details).toEqual([expected]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("isLikelyContextOverflowError", () => {
|
||||
it("detects Codex promptError wording for a full context window", () => {
|
||||
expect(
|
||||
|
||||
@@ -308,7 +308,7 @@ function normalizeFailoverDetailString(value: string | undefined): string | unde
|
||||
return undefined;
|
||||
}
|
||||
return trimmed.length > MAX_FAILOVER_DETAIL_CHARS
|
||||
? trimmed.slice(0, MAX_FAILOVER_DETAIL_CHARS)
|
||||
? truncateUtf16Safe(trimmed, MAX_FAILOVER_DETAIL_CHARS)
|
||||
: trimmed;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user