Skip to content

Commit 1b8b850

Browse files
authored
fix(auto-reply): truncate user-facing text on UTF-16 boundary (#97299)
Summary: - The PR imports `truncateUtf16Safe` and uses it for the Codex usage-limit preview and verbose working-label truncation paths in auto-reply. - PR surface: Source +2. Total +2 across 2 files. - Reproducibility: yes. Current main uses raw `slice(0, N)` at both reported user-facing truncation sites, and ... ludes terminal before/after output showing dangling surrogates before the fix and safe truncation after it. Automerge notes: - No ClawSweeper repair was needed after automerge opt-in. Validation: - ClawSweeper review passed for head 74a0a32. - Required merge gates passed before the squash merge. Prepared head SHA: 74a0a32 Review: #97299 (comment) Co-authored-by: zenglingbiao <[email protected]> Approved-by: takhoffman
1 parent c29e1fe commit 1b8b850

2 files changed

Lines changed: 4 additions & 2 deletions

File tree

src/auto-reply/reply/agent-runner-execution.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ import { CommandLaneClearedError, GatewayDrainingError } from "../../process/com
8787
import { CommandLane } from "../../process/lanes.js";
8888
import { defaultRuntime } from "../../runtime.js";
8989
import { shouldPreserveUserFacingSessionStateForInputProvenance } from "../../sessions/input-provenance.js";
90+
import { truncateUtf16Safe } from "../../shared/utf16-slice.js";
9091
import {
9192
isMarkdownCapableMessageChannel,
9293
resolveMessageChannel,
@@ -753,7 +754,7 @@ function extractCodexUsageLimitMessage(text: string): string | undefined {
753754
if (!message) {
754755
return undefined;
755756
}
756-
return message.length > 500 ? `${message.slice(0, 497)}...` : message;
757+
return message.length > 500 ? `${truncateUtf16Safe(message, 497)}...` : message;
757758
}
758759

759760
function isPureTransientRateLimitSummary(err: unknown): boolean {

src/auto-reply/reply/dispatch-from-config.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ import { isAcpSessionKey } from "../../routing/session-key.js";
9595
import { resolveSendPolicy } from "../../sessions/send-policy.js";
9696
import { createLazyImportLoader } from "../../shared/lazy-promise.js";
9797
import { resolveSilentReplyPolicyFromPolicies } from "../../shared/silent-reply-policy.js";
98+
import { truncateUtf16Safe } from "../../shared/utf16-slice.js";
9899
import { createTtsDirectiveTextStreamCleaner } from "../../tts/directives.js";
99100
import {
100101
normalizeTtsAutoMode,
@@ -2565,7 +2566,7 @@ export async function dispatchReplyFromConfig(
25652566
if (collapsed.length <= 80) {
25662567
return collapsed;
25672568
}
2568-
return `${collapsed.slice(0, 77).trimEnd()}...`;
2569+
return `${truncateUtf16Safe(collapsed, 77).trimEnd()}...`;
25692570
};
25702571
const formatPlanUpdateText = (payload: { explanation?: string; steps?: string[] }) => {
25712572
const explanation = payload.explanation?.replace(/\s+/g, " ").trim();

0 commit comments

Comments
 (0)