@@ -4,6 +4,7 @@ import { runAgentCleanupStep } from "./run-cleanup-timeout.js";
44
55const AGENT_CLEANUP_STEP_TIMEOUT_MS = 10_000 ;
66const CLEANUP_TIMEOUT_DETAILS_MAX_CHARS = 512 ;
7+ const CLEANUP_TIMEOUT_DETAILS_TRUNCATED_SUFFIX = "...[truncated]" ;
78
89describe ( "agent cleanup timeout" , ( ) => {
910 const log = {
@@ -115,6 +116,33 @@ describe("agent cleanup timeout", () => {
115116 ) ;
116117 } ) ;
117118
119+ it ( "keeps truncated cleanup timeout details UTF-16 safe" , async ( ) => {
120+ const cleanup = vi . fn ( async ( ) => new Promise < never > ( ( ) => { } ) ) ;
121+ const prefixLength =
122+ CLEANUP_TIMEOUT_DETAILS_MAX_CHARS - CLEANUP_TIMEOUT_DETAILS_TRUNCATED_SUFFIX . length ;
123+ const detailsPrefix = "a" . repeat ( prefixLength - 1 ) ;
124+ const oversizedDetails = `${ detailsPrefix } 😀${ "b" . repeat ( CLEANUP_TIMEOUT_DETAILS_MAX_CHARS ) } ` ;
125+
126+ const result = runAgentCleanupStep ( {
127+ runId : "run-trajectory" ,
128+ sessionId : "session-trajectory" ,
129+ step : "agent-trajectory-flush" ,
130+ cleanup,
131+ log,
132+ timeoutMs : 5 ,
133+ getTimeoutDetails : ( ) => oversizedDetails ,
134+ } ) ;
135+
136+ await vi . advanceTimersByTimeAsync ( 5 ) ;
137+ await expect ( result ) . resolves . toBeUndefined ( ) ;
138+
139+ const message = String ( log . warn . mock . calls . at ( - 1 ) ?. [ 0 ] ?? "" ) ;
140+ expect ( message ) . toContain (
141+ ` details=${ detailsPrefix } ${ CLEANUP_TIMEOUT_DETAILS_TRUNCATED_SUFFIX } ` ,
142+ ) ;
143+ expect ( message ) . not . toContain ( "�" ) ;
144+ } ) ;
145+
118146 it ( "does not fail cleanup when timeout details throw" , async ( ) => {
119147 const cleanup = vi . fn ( async ( ) => new Promise < never > ( ( ) => { } ) ) ;
120148
@@ -257,31 +285,28 @@ describe("agent cleanup timeout", () => {
257285 OPENCLAW_AGENT_CLEANUP_TIMEOUT_MS : "0x10" ,
258286 } ,
259287 } ,
260- ] ) (
261- "ignores invalid cleanup timeout environment values" ,
262- async ( { runId, sessionId, env } ) => {
263- const cleanup = vi . fn ( async ( ) => new Promise < never > ( ( ) => { } ) ) ;
264-
265- const result = runAgentCleanupStep ( {
266- runId,
267- sessionId,
268- step : "openclaw-trajectory-flush" ,
269- cleanup,
270- log,
271- env,
272- } ) ;
288+ ] ) ( "ignores invalid cleanup timeout environment values" , async ( { runId, sessionId, env } ) => {
289+ const cleanup = vi . fn ( async ( ) => new Promise < never > ( ( ) => { } ) ) ;
273290
274- await vi . advanceTimersByTimeAsync ( AGENT_CLEANUP_STEP_TIMEOUT_MS - 1 ) ;
275- expect ( log . warn ) . not . toHaveBeenCalled ( ) ;
291+ const result = runAgentCleanupStep ( {
292+ runId,
293+ sessionId,
294+ step : "openclaw-trajectory-flush" ,
295+ cleanup,
296+ log,
297+ env,
298+ } ) ;
276299
277- await vi . advanceTimersByTimeAsync ( 1 ) ;
278- await expect ( result ) . resolves . toBeUndefined ( ) ;
300+ await vi . advanceTimersByTimeAsync ( AGENT_CLEANUP_STEP_TIMEOUT_MS - 1 ) ;
301+ expect ( log . warn ) . not . toHaveBeenCalled ( ) ;
279302
280- expect ( log . warn ) . toHaveBeenCalledWith (
281- `agent cleanup timed out: runId=${ runId } sessionId=${ sessionId } step=openclaw-trajectory-flush timeoutMs=10000` ,
282- ) ;
283- } ,
284- ) ;
303+ await vi . advanceTimersByTimeAsync ( 1 ) ;
304+ await expect ( result ) . resolves . toBeUndefined ( ) ;
305+
306+ expect ( log . warn ) . toHaveBeenCalledWith (
307+ `agent cleanup timed out: runId=${ runId } sessionId=${ sessionId } step=openclaw-trajectory-flush timeoutMs=10000` ,
308+ ) ;
309+ } ) ;
285310
286311 it ( "logs cleanup rejection without throwing" , async ( ) => {
287312 await expect (
0 commit comments