bots-garden/mini-mepublic Fork 0
d72271127802973540c648bfb372176cdaaa8e4f
Commits
Clone
git clone https://git.rickub.com/bots-garden/mini-me.git
git clone ssh://git@rickub.com/bots-garden/mini-me.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

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