@@ -30,9 +30,7 @@ const DISABLED_CODEX_WEB_SEARCH_THREAD_CONFIG_FINGERPRINT = JSON.stringify({
3030 web_search : "disabled" ,
3131} ) ;
3232
33- function writeCodexAppServerBinding (
34- ...args : Parameters < typeof writeRawCodexAppServerBinding >
35- ) {
33+ function writeCodexAppServerBinding ( ...args : Parameters < typeof writeRawCodexAppServerBinding > ) {
3634 const [ sessionFile , binding , lookup ] = args ;
3735 return writeRawCodexAppServerBinding (
3836 sessionFile ,
@@ -44,13 +42,19 @@ function writeCodexAppServerBinding(
4442 ) ;
4543}
4644
45+ function createLoopDetectionParams ( sessionFile : string , workspaceDir : string ) {
46+ const params = createParams ( sessionFile , workspaceDir ) ;
47+ params . config = { tools : { loopDetection : { enabled : true } } } as never ;
48+ return params ;
49+ }
50+
4751describe ( "runCodexAppServerAttempt native hook relay" , ( ) => {
4852 it ( "registers native hook relay config for an enabled Codex turn and cleans it up" , async ( ) => {
4953 const sessionFile = path . join ( tempDir , "session.jsonl" ) ;
5054 const workspaceDir = path . join ( tempDir , "workspace" ) ;
5155 const harness = createStartedThreadHarness ( ) ;
5256
53- const run = runCodexAppServerAttempt ( createParams ( sessionFile , workspaceDir ) , {
57+ const run = runCodexAppServerAttempt ( createLoopDetectionParams ( sessionFile , workspaceDir ) , {
5458 nativeHookRelay : {
5559 enabled : true ,
5660 events : [ "pre_tool_use" ] ,
@@ -93,7 +97,7 @@ describe("runCodexAppServerAttempt native hook relay", () => {
9397 const sessionFile = path . join ( tempDir , "session.jsonl" ) ;
9498 const workspaceDir = path . join ( tempDir , "workspace" ) ;
9599 const harness = createStartedThreadHarness ( ) ;
96- const params = createParams ( sessionFile , workspaceDir ) ;
100+ const params = createLoopDetectionParams ( sessionFile , workspaceDir ) ;
97101 params . messageChannel = "discord" ;
98102 params . currentChannelId = "channel:target" ;
99103
@@ -157,7 +161,7 @@ describe("runCodexAppServerAttempt native hook relay", () => {
157161 const relayFloorMs = 30 * 60_000 ;
158162
159163 const startedAtMs = Date . now ( ) ;
160- const run = runCodexAppServerAttempt ( createParams ( sessionFile , workspaceDir ) , {
164+ const run = runCodexAppServerAttempt ( createLoopDetectionParams ( sessionFile , workspaceDir ) , {
161165 nativeHookRelay : {
162166 enabled : true ,
163167 events : [ "pre_tool_use" ] ,
@@ -185,7 +189,7 @@ describe("runCodexAppServerAttempt native hook relay", () => {
185189 const workspaceDir = path . join ( tempDir , "workspace" ) ;
186190 const harness = createStartedThreadHarness ( ) ;
187191
188- const run = runCodexAppServerAttempt ( createParams ( sessionFile , workspaceDir ) , {
192+ const run = runCodexAppServerAttempt ( createLoopDetectionParams ( sessionFile , workspaceDir ) , {
189193 nativeHookRelay : {
190194 enabled : true ,
191195 events : [ "pre_tool_use" ] ,
@@ -250,7 +254,7 @@ describe("runCodexAppServerAttempt native hook relay", () => {
250254 const explicitTtlMs = 123_456 ;
251255
252256 const startedAtMs = Date . now ( ) ;
253- const run = runCodexAppServerAttempt ( createParams ( sessionFile , workspaceDir ) , {
257+ const run = runCodexAppServerAttempt ( createLoopDetectionParams ( sessionFile , workspaceDir ) , {
254258 nativeHookRelay : {
255259 enabled : true ,
256260 events : [ "pre_tool_use" ] ,
@@ -292,19 +296,13 @@ describe("runCodexAppServerAttempt native hook relay", () => {
292296 const startConfig = ( startRequest ?. params as { config ?: Record < string , unknown > } | undefined )
293297 ?. config ;
294298 expect ( startConfig ?. [ "features.hooks" ] ) . toBe ( true ) ;
295- expect ( Array . isArray ( startConfig ?. [ "hooks.PreToolUse" ] ) ) . toBe ( true ) ;
299+ expect ( startConfig ?. [ "hooks.PreToolUse" ] ) . toEqual ( [ ] ) ;
296300 expect ( startConfig ?. [ "hooks.PostToolUse" ] ) . toEqual ( [ ] ) ;
297301 expect ( startConfig ?. [ "hooks.Stop" ] ) . toEqual ( [ ] ) ;
298302 expect ( startConfig ) . not . toHaveProperty ( "hooks.PermissionRequest" ) ;
299- const relayId = extractRelayIdFromThreadRequest ( startRequest ?. params ) ;
300- expect (
301- nativeHookRelayTesting . getNativeHookRelayRegistrationForTests ( relayId ) ?. allowedEvents ,
302- ) . toEqual ( [ "pre_tool_use" , "post_tool_use" , "before_agent_finalize" ] ) ;
303-
304303 await harness . completeTurn ( { threadId : "thread-1" , turnId : "turn-1" } ) ;
305304 await run ;
306305 testing . flushPendingCodexNativeHookRelayUnregistersForTests ( ) ;
307- expect ( nativeHookRelayTesting . getNativeHookRelayRegistrationForTests ( relayId ) ) . toBeUndefined ( ) ;
308306 } ) ;
309307
310308 it ( "preserves explicit native permission request relay events in app-server approval modes" , async ( ) => {
@@ -357,6 +355,7 @@ describe("runCodexAppServerAttempt native hook relay", () => {
357355 params . abortSignal = abortController . signal ;
358356
359357 const startedAtMs = Date . now ( ) ;
358+ params . config = { tools : { loopDetection : { enabled : true } } } as never ;
360359 const run = runCodexAppServerAttempt ( params , {
361360 nativeHookRelay : {
362361 enabled : true ,
@@ -397,12 +396,15 @@ describe("runCodexAppServerAttempt native hook relay", () => {
397396 const workspaceDir = path . join ( tempDir , "workspace" ) ;
398397 const firstHarness = createStartedThreadHarness ( ) ;
399398
400- const firstRun = runCodexAppServerAttempt ( createParams ( sessionFile , workspaceDir ) , {
401- nativeHookRelay : {
402- enabled : true ,
403- events : [ "pre_tool_use" ] ,
399+ const firstRun = runCodexAppServerAttempt (
400+ createLoopDetectionParams ( sessionFile , workspaceDir ) ,
401+ {
402+ nativeHookRelay : {
403+ enabled : true ,
404+ events : [ "pre_tool_use" ] ,
405+ } ,
404406 } ,
405- } ) ;
407+ ) ;
406408 await firstHarness . waitForMethod ( "turn/start" ) ;
407409 await firstHarness . completeTurn ( { threadId : "thread-1" , turnId : "turn-1" } ) ;
408410 await firstRun ;
@@ -429,7 +431,7 @@ describe("runCodexAppServerAttempt native hook relay", () => {
429431 ) . resolves . toMatchObject ( { exitCode : 0 } ) ;
430432
431433 const secondHarness = createResumeHarness ( ) ;
432- const secondParams = createParams ( sessionFile , workspaceDir ) ;
434+ const secondParams = createLoopDetectionParams ( sessionFile , workspaceDir ) ;
433435 secondParams . runId = "run-2" ;
434436 const secondRun = runCodexAppServerAttempt ( secondParams , {
435437 nativeHookRelay : {
@@ -470,12 +472,15 @@ describe("runCodexAppServerAttempt native hook relay", () => {
470472 const workspaceDir = path . join ( tempDir , "workspace" ) ;
471473 const firstHarness = createStartedThreadHarness ( ) ;
472474
473- const firstRun = runCodexAppServerAttempt ( createParams ( sessionFile , workspaceDir ) , {
474- nativeHookRelay : {
475- enabled : true ,
476- events : [ "pre_tool_use" ] ,
475+ const firstRun = runCodexAppServerAttempt (
476+ createLoopDetectionParams ( sessionFile , workspaceDir ) ,
477+ {
478+ nativeHookRelay : {
479+ enabled : true ,
480+ events : [ "pre_tool_use" ] ,
481+ } ,
477482 } ,
478- } ) ;
483+ ) ;
479484 await firstHarness . waitForMethod ( "turn/start" ) ;
480485 const firstStartRequest = firstHarness . requests . find (
481486 ( request ) => request . method === "thread/start" ,
@@ -490,7 +495,7 @@ describe("runCodexAppServerAttempt native hook relay", () => {
490495 ) ;
491496
492497 const secondHarness = createResumeHarness ( ) ;
493- const secondParams = createParams ( sessionFile , workspaceDir ) ;
498+ const secondParams = createLoopDetectionParams ( sessionFile , workspaceDir ) ;
494499 secondParams . runId = "run-2" ;
495500 const secondRun = runCodexAppServerAttempt ( secondParams , {
496501 nativeHookRelay : {
@@ -523,7 +528,7 @@ describe("runCodexAppServerAttempt native hook relay", () => {
523528 } ) ;
524529 const harness = createResumeHarness ( ) ;
525530
526- const run = runCodexAppServerAttempt ( createParams ( sessionFile , workspaceDir ) , {
531+ const run = runCodexAppServerAttempt ( createLoopDetectionParams ( sessionFile , workspaceDir ) , {
527532 nativeHookRelay : {
528533 enabled : true ,
529534 events : [ "pre_tool_use" ] ,
@@ -587,7 +592,7 @@ describe("runCodexAppServerAttempt native hook relay", () => {
587592 } ) ;
588593 const harness = createStartedThreadHarness ( ) ;
589594
590- const run = runCodexAppServerAttempt ( createParams ( sessionFile , workspaceDir ) , {
595+ const run = runCodexAppServerAttempt ( createLoopDetectionParams ( sessionFile , workspaceDir ) , {
591596 nativeHookRelay : {
592597 enabled : true ,
593598 events : [ "pre_tool_use" ] ,
@@ -641,7 +646,7 @@ describe("runCodexAppServerAttempt native hook relay", () => {
641646 return undefined ;
642647 } ) ;
643648
644- const run = runCodexAppServerAttempt ( createParams ( sessionFile , workspaceDir ) , {
649+ const run = runCodexAppServerAttempt ( createLoopDetectionParams ( sessionFile , workspaceDir ) , {
645650 nativeHookRelay : {
646651 enabled : true ,
647652 events : [ "pre_tool_use" ] ,
0 commit comments