Class: OllamaAgent::Core::LoopDetector

Inherits:
Object
  • Object
show all
Defined in:
lib/ollama_agent/core/loop_detector.rb

Overview

Detects when the agent is stuck in a repeating tool-call loop.

Strategy: keep a sliding window of (tool_name + args_fingerprint) tokens. If the most-recent window pattern appears THRESHOLD or more times in the accumulated history, we declare a loop.

Constant Summary collapse

DEFAULT_WINDOW =

number of consecutive calls to treat as one pattern

4
DEFAULT_THRESHOLD =

how many times the pattern must repeat

2

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(window: DEFAULT_WINDOW, threshold: DEFAULT_THRESHOLD) ⇒ LoopDetector

Returns a new instance of LoopDetector.



16
17
18
19
20
# File 'lib/ollama_agent/core/loop_detector.rb', line 16

def initialize(window: DEFAULT_WINDOW, threshold: DEFAULT_THRESHOLD)
  @window    = window.to_i.clamp(1, 32)
  @threshold = threshold.to_i.clamp(2, 16)
  @history   = []
end

Instance Attribute Details

#historyObject (readonly)

Returns the value of attribute history.



14
15
16
# File 'lib/ollama_agent/core/loop_detector.rb', line 14

def history
  @history
end

Instance Method Details

#loop_detected?Boolean

Returns true when the recent pattern has repeated enough times.

Returns:

  • (Boolean)


30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/ollama_agent/core/loop_detector.rb', line 30

def loop_detected?
  return false if @history.size < @window * @threshold

  pattern = @history.last(@window)
  matches = 0

  (@history.size - @window + 1).times do |i|
    matches += 1 if @history[i, @window] == pattern
  end

  matches >= @threshold
end

#loop_summaryObject

Human-readable description of the detected loop.



44
45
46
47
48
49
# File 'lib/ollama_agent/core/loop_detector.rb', line 44

def loop_summary
  return nil unless loop_detected?

  pattern = @history.last(@window)
  "Loop detected: pattern [#{pattern.join("")}] repeated #{@threshold}+ times"
end

#record!(tool_name, args = {}) ⇒ Object

Record a tool call. Should be called before executing each tool.

Parameters:

  • tool_name (String)
  • args (Hash, String) (defaults to: {})


25
26
27
# File 'lib/ollama_agent/core/loop_detector.rb', line 25

def record!(tool_name, args = {})
  @history << fingerprint(tool_name, args)
end

#reset!Object



51
52
53
# File 'lib/ollama_agent/core/loop_detector.rb', line 51

def reset!
  @history.clear
end