1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
// Package detector provides a mechanism to detect repetitive patterns in agent actions.
package detector
import (
"sync"
)
// Action represents a single step taken by the agent.
type Action struct {
ToolName string
Input string
Output string
}
// LoopDetector tracks the history of actions to detect repetitive cycles.
type LoopDetector struct {
history []Action
historyMu sync.Mutex
maxHistory int
threshold int
}
// NewLoopDetector creates a new detector with a given history limit and threshold.
func NewLoopDetector(maxHistory, threshold int) *LoopDetector {
return &LoopDetector{
history: make([]Action, 0),
maxHistory: maxHistory,
threshold: threshold,
}
}
// Record adds an action to the history and returns true if a loop is detected.
func (d *LoopDetector) Record(action Action) bool {
d.historyMu.Lock()
defer d.historyMu.Unlock()
// Check if the current action (tool + input + output) has occurred consecutively.
count := 0
for i := len(d.history) - 1; i >= 0; i-- {
if d.history[i].ToolName == action.ToolName &&
d.history[i].Input == action.Input &&
d.history[i].Output == action.Output {
count++
if count >= d.threshold {
return true
}
} else {
break
}
}
// Append the new action.
d.history = append(d.history, action)
if len(d.history) > d.maxHistory {
d.history = d.history[1:]
}
return false
}
// Reset forgets every recorded action and keeps the settings. It is what the
// /new command calls: a new session is a new task, and a command the model
// repeated in the previous one must not be flagged as a loop in this one.
//
// d := detector.NewLoopDetector(10, 3)
// // ... a session's worth of Record calls ...
// d.Reset() // start the count again
func (d *LoopDetector) Reset() {
d.historyMu.Lock()
defer d.historyMu.Unlock()
d.history = d.history[:0]
}
// LoopError returns a standardized error message when a loop is detected.
func (d *LoopDetector) LoopError() string {
return "[LOOP_DETECTED: You have attempted the same action multiple times with the same result. Please try a different approach or provide more information.]"
}
|