@@ -19,7 +19,17 @@ describe("before_tool_call loop detection behavior", () => {
1919 hasHooks : ReturnType < typeof vi . fn > ;
2020 runBeforeToolCall : ReturnType < typeof vi . fn > ;
2121 } ;
22- const defaultToolContext = { agentId : "main" , sessionKey : "main" } ;
22+ const enabledLoopDetectionContext = {
23+ agentId : "main" ,
24+ sessionKey : "main" ,
25+ loopDetection : { enabled : true } ,
26+ } ;
27+
28+ const disabledLoopDetectionContext = {
29+ agentId : "main" ,
30+ sessionKey : "main" ,
31+ loopDetection : { enabled : false } ,
32+ } ;
2333
2434 beforeEach ( ( ) => {
2535 resetDiagnosticSessionStateForTest ( ) ;
@@ -33,10 +43,14 @@ describe("before_tool_call loop detection behavior", () => {
3343 hookRunner . hasHooks . mockReturnValue ( false ) ;
3444 } ) ;
3545
36- function createWrappedTool ( name : string , execute : ReturnType < typeof vi . fn > ) {
46+ function createWrappedTool (
47+ name : string ,
48+ execute : ReturnType < typeof vi . fn > ,
49+ loopDetectionContext = enabledLoopDetectionContext ,
50+ ) {
3751 return wrapToolWithBeforeToolCallHook (
3852 { name, execute } as unknown as AnyAgentTool ,
39- defaultToolContext ,
53+ loopDetectionContext ,
4054 ) ;
4155 }
4256
@@ -95,7 +109,6 @@ describe("before_tool_call loop detection behavior", () => {
95109 }
96110 }
97111 }
98-
99112 it ( "blocks known poll loops when no progress repeats" , async ( ) => {
100113 const execute = vi . fn ( ) . mockResolvedValue ( {
101114 content : [ { type : "text" , text : "(no new output)\n\nProcess still running." } ] ,
@@ -113,6 +126,22 @@ describe("before_tool_call loop detection behavior", () => {
113126 ) . rejects . toThrow ( "CRITICAL" ) ;
114127 } ) ;
115128
129+ it ( "does nothing when loopDetection.enabled is false" , async ( ) => {
130+ const execute = vi . fn ( ) . mockResolvedValue ( {
131+ content : [ { type : "text" , text : "(no new output)\n\nProcess still running." } ] ,
132+ details : { status : "running" , aggregated : "steady" } ,
133+ } ) ;
134+ // oxlint-disable-next-line typescript/no-explicit-any
135+ const tool = wrapToolWithBeforeToolCallHook ( { name : "process" , execute } as any , {
136+ ...disabledLoopDetectionContext ,
137+ } ) ;
138+ const params = { action : "poll" , sessionId : "sess-off" } ;
139+
140+ for ( let i = 0 ; i < CRITICAL_THRESHOLD ; i += 1 ) {
141+ await expect ( tool . execute ( `poll-${ i } ` , params , undefined , undefined ) ) . resolves . toBeDefined ( ) ;
142+ }
143+ } ) ;
144+
116145 it ( "does not block known poll loops when output progresses" , async ( ) => {
117146 const execute = vi . fn ( ) . mockImplementation ( async ( toolCallId : string ) => {
118147 return {
0 commit comments