fix: prevent infinite loop in performAgentChain on repeating tool calls#178
Conversation
There was a problem hiding this comment.
Pull request overview
Prevents runaway performAgentChain executions in backend/pkg/providers/performer.go by adding hard stops for excessive looping and repeated tool-call patterns, addressing resource exhaustion described in #175.
Changes:
- Add a maximum iteration cap to the main
performAgentChainloop. - Escalate repeating tool-call detections from a soft warning to a terminating error after a configured threshold.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
The performAgentChain loop has no iteration cap, allowing infinite loops when a model repeatedly calls the same tool. The repeating detector returns a message (not an error), so the loop never breaks. Add two safety mechanisms: - Hard cap of 100 iterations on the main agent chain loop - Escalation to error after 5 consecutive repeating detections (8 total identical calls: 3 before first detection + 5 detections) The soft "please try another tool" response is preserved for the first 4 detections, giving the LLM a chance to course-correct before aborting. Closes vxcontrol#175 Signed-off-by: mason5052 <ehehwnwjs5052@gmail.com>
- Rename maxRepeatingDetectionsBeforeErr to maxSoftDetectionsBeforeAbort
for clarity (name now matches behavior: 4 soft warnings before abort)
- Adjust threshold value from 5 to 4 and remove -1 from condition
(same runtime behavior: abort on 7th consecutive identical call)
- Use errors.New() instead of fmt.Errorf("%s", msg) for non-formatted
error strings (more idiomatic Go)
Signed-off-by: mason5052 <ehehwnwjs5052@gmail.com>
917b371 to
536ea86
Compare
|
Hi @asdek -- just a heads up that all four PRs (#178, #179, #180, #181) have been rebased onto the latest master (post-#185 merge) and are now cleanly mergeable. This PR addresses the infinite loop reported in #175. The companion test PR is #180 (merge this one first). Similarly, #179 fixes the detached context cancellation from #176, with tests in #181. Happy to adjust anything based on your feedback. |
|
hey @mason5052 thank you for the PR, it's very useful! |
Description of the Change
Problem
The
performAgentChainloop inperformer.gois an unboundedfor {}with no iteration cap. When a model repeatedly calls the same tool, therepeatingDetectorfires and returns a message (nilerror), so the loop never breaks. This can result in 4,800+ iterations in a single session, consuming resources indefinitely.Closes #175
Solution
Add two safety mechanisms:
Iteration cap (
maxAgentChainIterations = 100): Hard limit on the main loop. Normal pentest flows use far fewer iterations; 100 is generous while preventing runaway loops.Repeating escalation (
maxSoftDetectionsBeforeAbort = 4): After 4 consecutive soft detection warnings (7 total identical calls), escalate from a soft message to an actual error that terminates the chain. The existing soft response is preserved for the first 4 detections, giving the LLM a chance to course-correct.Type of Change
Areas Affected
Testing and Verification
Test Configuration
Test Steps
maxRetriesToCallSimpleChain, etc.)for iteration := 0; ; iteration++preserves all existing loop semanticslen(detector.funcCalls)is accessible (same package) and correctly tracks consecutive identical calls (resets on different calls perhelpers.go:detect())RepeatingToolCallThreshold(3) + maxSoftDetectionsBeforeAbort(4) = 7, so error fires on the 7th consecutive identical callSecurity Considerations
No security impact. This is a resource exhaustion prevention fix.
Checklist
go fmtandgo vet