@defai.digital/ax-cli 3.8.6 → 3.8.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -393
- package/config-defaults/models.yaml +0 -24
- package/config-defaults/settings.yaml +16 -16
- package/dist/agent/dependency-resolver.js +22 -1
- package/dist/agent/dependency-resolver.js.map +1 -1
- package/dist/agent/llm-agent.d.ts +23 -2
- package/dist/agent/llm-agent.js +126 -122
- package/dist/agent/llm-agent.js.map +1 -1
- package/dist/agent/loop-detector.d.ts +70 -0
- package/dist/agent/loop-detector.js +339 -0
- package/dist/agent/loop-detector.js.map +1 -0
- package/dist/agent/progress-tracker.d.ts +94 -0
- package/dist/agent/progress-tracker.js +222 -0
- package/dist/agent/progress-tracker.js.map +1 -0
- package/dist/agent/status-reporter.js +2 -2
- package/dist/agent/status-reporter.js.map +1 -1
- package/dist/agent/subagent.js +7 -3
- package/dist/agent/subagent.js.map +1 -1
- package/dist/analyzers/architecture/project-structure-scanner.js +6 -2
- package/dist/analyzers/architecture/project-structure-scanner.js.map +1 -1
- package/dist/analyzers/git/churn-calculator.js +2 -1
- package/dist/analyzers/git/churn-calculator.js.map +1 -1
- package/dist/checkpoint/manager.js +18 -4
- package/dist/checkpoint/manager.js.map +1 -1
- package/dist/checkpoint/storage.d.ts +6 -0
- package/dist/checkpoint/storage.js +96 -49
- package/dist/checkpoint/storage.js.map +1 -1
- package/dist/commands/cache.js +8 -6
- package/dist/commands/cache.js.map +1 -1
- package/dist/commands/doctor.js +19 -27
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/mcp-migrate.js +6 -5
- package/dist/commands/mcp-migrate.js.map +1 -1
- package/dist/commands/mcp.js +14 -2
- package/dist/commands/mcp.js.map +1 -1
- package/dist/commands/models.js +8 -12
- package/dist/commands/models.js.map +1 -1
- package/dist/commands/plan.js +1 -10
- package/dist/commands/plan.js.map +1 -1
- package/dist/commands/setup.js +4 -3
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/status.js +40 -14
- package/dist/commands/status.js.map +1 -1
- package/dist/constants.d.ts +12 -0
- package/dist/constants.js +16 -4
- package/dist/constants.js.map +1 -1
- package/dist/hooks/hook-runner.d.ts +138 -0
- package/dist/hooks/hook-runner.js +429 -0
- package/dist/hooks/hook-runner.js.map +1 -0
- package/dist/hooks/index.d.ts +6 -0
- package/dist/hooks/index.js +7 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/index.js +3 -21
- package/dist/index.js.map +1 -1
- package/dist/llm/client.d.ts +9 -0
- package/dist/llm/client.js +306 -45
- package/dist/llm/client.js.map +1 -1
- package/dist/llm/tools.js +2 -39
- package/dist/llm/tools.js.map +1 -1
- package/dist/llm/types.d.ts +1 -47
- package/dist/llm/types.js +0 -18
- package/dist/llm/types.js.map +1 -1
- package/dist/mcp/automatosx-loader.js +2 -1
- package/dist/mcp/automatosx-loader.js.map +1 -1
- package/dist/mcp/client-v2.d.ts +3 -0
- package/dist/mcp/client-v2.js +85 -19
- package/dist/mcp/client-v2.js.map +1 -1
- package/dist/mcp/config-migrator.js +3 -2
- package/dist/mcp/config-migrator.js.map +1 -1
- package/dist/mcp/config-v2.d.ts +5 -0
- package/dist/mcp/config-v2.js +26 -0
- package/dist/mcp/config-v2.js.map +1 -1
- package/dist/mcp/error-formatter.js +4 -1
- package/dist/mcp/error-formatter.js.map +1 -1
- package/dist/mcp/health.js +1 -1
- package/dist/mcp/health.js.map +1 -1
- package/dist/mcp/reconnection.js +2 -1
- package/dist/mcp/reconnection.js.map +1 -1
- package/dist/mcp/registry.js +3 -2
- package/dist/mcp/registry.js.map +1 -1
- package/dist/mcp/resources.js +2 -1
- package/dist/mcp/resources.js.map +1 -1
- package/dist/mcp/validation.js +9 -0
- package/dist/mcp/validation.js.map +1 -1
- package/dist/memory/context-store.js +4 -6
- package/dist/memory/context-store.js.map +1 -1
- package/dist/memory/types.d.ts +2 -0
- package/dist/memory/types.js +4 -1
- package/dist/memory/types.js.map +1 -1
- package/dist/permissions/index.d.ts +6 -0
- package/dist/permissions/index.js +7 -0
- package/dist/permissions/index.js.map +1 -0
- package/dist/permissions/permission-manager.d.ts +145 -0
- package/dist/permissions/permission-manager.js +401 -0
- package/dist/permissions/permission-manager.js.map +1 -0
- package/dist/planner/plan-storage.js +3 -2
- package/dist/planner/plan-storage.js.map +1 -1
- package/dist/planner/task-planner.js +2 -1
- package/dist/planner/task-planner.js.map +1 -1
- package/dist/planner/types.d.ts +6 -6
- package/dist/schemas/settings-schemas.d.ts +0 -14
- package/dist/schemas/settings-schemas.js +0 -10
- package/dist/schemas/settings-schemas.js.map +1 -1
- package/dist/schemas/tool-schemas.d.ts +2 -2
- package/dist/schemas/yaml-schemas.d.ts +15 -0
- package/dist/schemas/yaml-schemas.js +3 -0
- package/dist/schemas/yaml-schemas.js.map +1 -1
- package/dist/tools/bash.js +35 -10
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/confirmation-tool.js +3 -2
- package/dist/tools/confirmation-tool.js.map +1 -1
- package/dist/tools/registry.d.ts +1 -1
- package/dist/tools/registry.js +2 -1
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/search.js +12 -13
- package/dist/tools/search.js.map +1 -1
- package/dist/tools/text-editor.d.ts +46 -0
- package/dist/tools/text-editor.js +455 -11
- package/dist/tools/text-editor.js.map +1 -1
- package/dist/tools/todo-tool.js +5 -4
- package/dist/tools/todo-tool.js.map +1 -1
- package/dist/ui/components/chat-input.js +10 -1
- package/dist/ui/components/chat-input.js.map +1 -1
- package/dist/ui/components/chat-interface.js +1 -0
- package/dist/ui/components/chat-interface.js.map +1 -1
- package/dist/ui/components/tool-group-display.js +0 -6
- package/dist/ui/components/tool-group-display.js.map +1 -1
- package/dist/ui/hooks/use-input-handler.js +7 -6
- package/dist/ui/hooks/use-input-handler.js.map +1 -1
- package/dist/ui/hooks/use-input-history.js +21 -13
- package/dist/ui/hooks/use-input-history.js.map +1 -1
- package/dist/ui/utils/tool-grouper.d.ts +1 -2
- package/dist/ui/utils/tool-grouper.js +4 -15
- package/dist/ui/utils/tool-grouper.js.map +1 -1
- package/dist/utils/api-error.d.ts +61 -0
- package/dist/utils/api-error.js +176 -0
- package/dist/utils/api-error.js.map +1 -0
- package/dist/utils/audit-logger.js +2 -1
- package/dist/utils/audit-logger.js.map +1 -1
- package/dist/utils/auto-accept-logger.js +3 -3
- package/dist/utils/auto-accept-logger.js.map +1 -1
- package/dist/utils/config-loader.d.ts +3 -0
- package/dist/utils/config-loader.js +27 -2
- package/dist/utils/config-loader.js.map +1 -1
- package/dist/utils/encryption.js +2 -1
- package/dist/utils/encryption.js.map +1 -1
- package/dist/utils/file-cache.js +4 -2
- package/dist/utils/file-cache.js.map +1 -1
- package/dist/utils/history-migration.js +5 -4
- package/dist/utils/history-migration.js.map +1 -1
- package/dist/utils/onboarding-manager.js +2 -1
- package/dist/utils/onboarding-manager.js.map +1 -1
- package/dist/utils/path-helpers.d.ts +8 -0
- package/dist/utils/path-helpers.js +35 -0
- package/dist/utils/path-helpers.js.map +1 -0
- package/dist/utils/path-security.js +3 -2
- package/dist/utils/path-security.js.map +1 -1
- package/dist/utils/retry-helper.d.ts +61 -0
- package/dist/utils/retry-helper.js +206 -0
- package/dist/utils/retry-helper.js.map +1 -0
- package/dist/utils/settings-manager.d.ts +1 -21
- package/dist/utils/settings-manager.js +2 -82
- package/dist/utils/settings-manager.js.map +1 -1
- package/dist/utils/streaming-analyzer.d.ts +2 -13
- package/dist/utils/streaming-analyzer.js +3 -25
- package/dist/utils/streaming-analyzer.js.map +1 -1
- package/dist/utils/token-counter.d.ts +13 -1
- package/dist/utils/token-counter.js +31 -6
- package/dist/utils/token-counter.js.map +1 -1
- package/package.json +3 -2
- package/packages/schemas/README.md +1 -1
- package/packages/schemas/package.json +1 -1
- package/dist/tools/web-search/cache.d.ts +0 -62
- package/dist/tools/web-search/cache.js +0 -105
- package/dist/tools/web-search/cache.js.map +0 -1
- package/dist/tools/web-search/engines/crates.d.ts +0 -19
- package/dist/tools/web-search/engines/crates.js +0 -87
- package/dist/tools/web-search/engines/crates.js.map +0 -1
- package/dist/tools/web-search/engines/npm.d.ts +0 -18
- package/dist/tools/web-search/engines/npm.js +0 -86
- package/dist/tools/web-search/engines/npm.js.map +0 -1
- package/dist/tools/web-search/engines/pypi.d.ts +0 -18
- package/dist/tools/web-search/engines/pypi.js +0 -75
- package/dist/tools/web-search/engines/pypi.js.map +0 -1
- package/dist/tools/web-search/index.d.ts +0 -11
- package/dist/tools/web-search/index.js +0 -11
- package/dist/tools/web-search/index.js.map +0 -1
- package/dist/tools/web-search/router.d.ts +0 -34
- package/dist/tools/web-search/router.js +0 -245
- package/dist/tools/web-search/router.js.map +0 -1
- package/dist/tools/web-search/types.d.ts +0 -45
- package/dist/tools/web-search/types.js +0 -6
- package/dist/tools/web-search/types.js.map +0 -1
- package/dist/tools/web-search/web-search-tool.d.ts +0 -51
- package/dist/tools/web-search/web-search-tool.js +0 -246
- package/dist/tools/web-search/web-search-tool.js.map +0 -1
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Intelligent Loop Detection System
|
|
3
|
+
*
|
|
4
|
+
* Based on Claude Code and industry best practices:
|
|
5
|
+
* 1. Progress-based detection (checks if state changes)
|
|
6
|
+
* 2. Tool-specific thresholds (different tools have different legitimate repeat patterns)
|
|
7
|
+
* 3. Sequence pattern detection (A→B→A→B cycles)
|
|
8
|
+
* 4. Configurable and transparent
|
|
9
|
+
*
|
|
10
|
+
* Key insight: The problem isn't repeated tool calls, it's repeated tool calls
|
|
11
|
+
* that don't make progress. Creating 10 files is fine. Trying to edit the same
|
|
12
|
+
* file 10 times with the same failing edit is not.
|
|
13
|
+
*/
|
|
14
|
+
import { AGENT_CONFIG } from "../constants.js";
|
|
15
|
+
/**
|
|
16
|
+
* Configuration for tool-specific thresholds
|
|
17
|
+
* Higher thresholds for tools that are legitimately called repeatedly
|
|
18
|
+
*/
|
|
19
|
+
const TOOL_THRESHOLDS = {
|
|
20
|
+
// File exploration - often need to view many files
|
|
21
|
+
view_file: 10,
|
|
22
|
+
read_file: 10,
|
|
23
|
+
list_files: 8,
|
|
24
|
+
// File creation - creating multiple files is normal
|
|
25
|
+
create_file: 15,
|
|
26
|
+
write_to_file: 15,
|
|
27
|
+
// Editing - more restrictive since repeated edits usually mean failure
|
|
28
|
+
str_replace_editor: 4,
|
|
29
|
+
// Search - may need multiple searches
|
|
30
|
+
search_files: 6,
|
|
31
|
+
search: 6,
|
|
32
|
+
// Bash - varies widely, use moderate threshold
|
|
33
|
+
bash: 8,
|
|
34
|
+
execute_bash: 8,
|
|
35
|
+
// Todo list - frequently updated
|
|
36
|
+
create_todo_list: 3,
|
|
37
|
+
update_todo_list: 10, // Higher because progress updates are normal
|
|
38
|
+
// Default for unknown tools
|
|
39
|
+
default: 5,
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Tools that should be tracked by unique path/target
|
|
43
|
+
* These count repetitions per-target rather than globally
|
|
44
|
+
*/
|
|
45
|
+
const PATH_TRACKED_TOOLS = new Set([
|
|
46
|
+
'view_file',
|
|
47
|
+
'read_file',
|
|
48
|
+
'create_file',
|
|
49
|
+
'write_to_file',
|
|
50
|
+
'str_replace_editor',
|
|
51
|
+
]);
|
|
52
|
+
/**
|
|
53
|
+
* Tools where failure should lower the threshold
|
|
54
|
+
* (repeated failures are more likely to be loops)
|
|
55
|
+
*/
|
|
56
|
+
const FAILURE_SENSITIVE_TOOLS = new Set([
|
|
57
|
+
'str_replace_editor',
|
|
58
|
+
'bash',
|
|
59
|
+
'execute_bash',
|
|
60
|
+
]);
|
|
61
|
+
export class LoopDetector {
|
|
62
|
+
/** Recent tool calls with full context */
|
|
63
|
+
callHistory = [];
|
|
64
|
+
/** Signature -> count for quick lookup */
|
|
65
|
+
signatureCounts = new Map();
|
|
66
|
+
/** Signature -> consecutive failure count */
|
|
67
|
+
failureCounts = new Map();
|
|
68
|
+
/** Last N signatures for sequence detection */
|
|
69
|
+
recentSequence = [];
|
|
70
|
+
/** Maximum history size */
|
|
71
|
+
maxHistorySize = 100;
|
|
72
|
+
/** Maximum sequence length for pattern detection */
|
|
73
|
+
maxSequenceLength = 20;
|
|
74
|
+
/**
|
|
75
|
+
* Check if a tool call would create a loop
|
|
76
|
+
* Call this BEFORE executing the tool
|
|
77
|
+
*/
|
|
78
|
+
checkForLoop(toolCall) {
|
|
79
|
+
// Check if loop detection is disabled
|
|
80
|
+
if (!AGENT_CONFIG.ENABLE_LOOP_DETECTION) {
|
|
81
|
+
return { isLoop: false, count: 0, threshold: Infinity };
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
const args = this.parseArgs(toolCall);
|
|
85
|
+
const signature = this.createSignature(toolCall.function.name, args);
|
|
86
|
+
const threshold = this.getThreshold(toolCall.function.name, signature);
|
|
87
|
+
const currentCount = this.signatureCounts.get(signature) || 0;
|
|
88
|
+
const failureCount = this.failureCounts.get(signature) || 0;
|
|
89
|
+
// Adjust threshold based on failures
|
|
90
|
+
const adjustedThreshold = this.adjustThresholdForFailures(toolCall.function.name, threshold, failureCount);
|
|
91
|
+
// Check 1: Simple count-based detection with tool-specific threshold
|
|
92
|
+
if (currentCount >= adjustedThreshold) {
|
|
93
|
+
return {
|
|
94
|
+
isLoop: true,
|
|
95
|
+
reason: `Tool "${toolCall.function.name}" called ${currentCount + 1} times with same signature (threshold: ${adjustedThreshold})`,
|
|
96
|
+
suggestion: this.getSuggestion(toolCall.function.name, args),
|
|
97
|
+
count: currentCount + 1,
|
|
98
|
+
threshold: adjustedThreshold,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
// Check 2: Sequence pattern detection (A→B→A→B cycles)
|
|
102
|
+
const cycleResult = this.detectCycle(signature);
|
|
103
|
+
if (cycleResult.isLoop) {
|
|
104
|
+
return {
|
|
105
|
+
...cycleResult,
|
|
106
|
+
count: currentCount + 1,
|
|
107
|
+
threshold: adjustedThreshold,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
isLoop: false,
|
|
112
|
+
count: currentCount + 1,
|
|
113
|
+
threshold: adjustedThreshold,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
// On parse error, don't block
|
|
118
|
+
return { isLoop: false, count: 0, threshold: Infinity };
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Record a tool call after execution
|
|
123
|
+
* Call this AFTER executing the tool
|
|
124
|
+
*/
|
|
125
|
+
recordToolCall(toolCall, success, outputHash) {
|
|
126
|
+
const args = this.parseArgs(toolCall);
|
|
127
|
+
const signature = this.createSignature(toolCall.function.name, args);
|
|
128
|
+
const filePath = this.extractFilePath(args);
|
|
129
|
+
// Record in history
|
|
130
|
+
const record = {
|
|
131
|
+
signature,
|
|
132
|
+
toolName: toolCall.function.name,
|
|
133
|
+
args,
|
|
134
|
+
timestamp: Date.now(),
|
|
135
|
+
success,
|
|
136
|
+
filePath,
|
|
137
|
+
outputHash,
|
|
138
|
+
};
|
|
139
|
+
this.callHistory.push(record);
|
|
140
|
+
// Update signature count
|
|
141
|
+
const count = (this.signatureCounts.get(signature) || 0) + 1;
|
|
142
|
+
this.signatureCounts.set(signature, count);
|
|
143
|
+
// Update failure count
|
|
144
|
+
if (!success) {
|
|
145
|
+
const failures = (this.failureCounts.get(signature) || 0) + 1;
|
|
146
|
+
this.failureCounts.set(signature, failures);
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
// Reset failure count on success
|
|
150
|
+
this.failureCounts.delete(signature);
|
|
151
|
+
}
|
|
152
|
+
// Update sequence
|
|
153
|
+
this.recentSequence.push(signature);
|
|
154
|
+
if (this.recentSequence.length > this.maxSequenceLength) {
|
|
155
|
+
this.recentSequence.shift();
|
|
156
|
+
}
|
|
157
|
+
// Cleanup old entries
|
|
158
|
+
this.cleanup();
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Reset all tracking (call at start of new conversation)
|
|
162
|
+
*/
|
|
163
|
+
reset() {
|
|
164
|
+
this.callHistory = [];
|
|
165
|
+
this.signatureCounts.clear();
|
|
166
|
+
this.failureCounts.clear();
|
|
167
|
+
this.recentSequence = [];
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Get current stats for debugging
|
|
171
|
+
*/
|
|
172
|
+
getStats() {
|
|
173
|
+
return {
|
|
174
|
+
historySize: this.callHistory.length,
|
|
175
|
+
uniqueSignatures: this.signatureCounts.size,
|
|
176
|
+
failedSignatures: this.failureCounts.size,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
// ============================================================================
|
|
180
|
+
// Private Methods
|
|
181
|
+
// ============================================================================
|
|
182
|
+
parseArgs(toolCall) {
|
|
183
|
+
if (!toolCall.function.arguments) {
|
|
184
|
+
return {};
|
|
185
|
+
}
|
|
186
|
+
if (typeof toolCall.function.arguments === 'string') {
|
|
187
|
+
try {
|
|
188
|
+
return JSON.parse(toolCall.function.arguments);
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
return { raw: toolCall.function.arguments };
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return toolCall.function.arguments;
|
|
195
|
+
}
|
|
196
|
+
createSignature(toolName, args) {
|
|
197
|
+
// For path-tracked tools, use path as primary key
|
|
198
|
+
if (PATH_TRACKED_TOOLS.has(toolName)) {
|
|
199
|
+
const path = this.extractFilePath(args);
|
|
200
|
+
if (path) {
|
|
201
|
+
// For editors, include edit content hash to distinguish different edits
|
|
202
|
+
if (toolName === 'str_replace_editor') {
|
|
203
|
+
const oldStr = typeof args.old_str === 'string' ? args.old_str : '';
|
|
204
|
+
const contentKey = this.hashString(oldStr.substring(0, 200));
|
|
205
|
+
return `${toolName}:${path}:${contentKey}`;
|
|
206
|
+
}
|
|
207
|
+
return `${toolName}:${path}`;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
// For bash, use command as key
|
|
211
|
+
if (toolName === 'bash' || toolName === 'execute_bash') {
|
|
212
|
+
const cmd = typeof args.command === 'string'
|
|
213
|
+
? args.command.trim().replace(/\s+/g, ' ')
|
|
214
|
+
: '';
|
|
215
|
+
return `${toolName}:${cmd}`;
|
|
216
|
+
}
|
|
217
|
+
// For search, use query as key
|
|
218
|
+
if (toolName === 'search' || toolName === 'search_files') {
|
|
219
|
+
const query = typeof args.query === 'string'
|
|
220
|
+
? args.query.trim().toLowerCase()
|
|
221
|
+
: '';
|
|
222
|
+
return `${toolName}:${query}`;
|
|
223
|
+
}
|
|
224
|
+
// Default: tool name + stable hash of args
|
|
225
|
+
return `${toolName}:${this.hashString(JSON.stringify(args))}`;
|
|
226
|
+
}
|
|
227
|
+
extractFilePath(args) {
|
|
228
|
+
// Try common path argument names
|
|
229
|
+
for (const key of ['path', 'file_path', 'filepath', 'file']) {
|
|
230
|
+
if (typeof args[key] === 'string') {
|
|
231
|
+
return args[key];
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return undefined;
|
|
235
|
+
}
|
|
236
|
+
getThreshold(toolName, _signature) {
|
|
237
|
+
// Use tool-specific threshold or default
|
|
238
|
+
return TOOL_THRESHOLDS[toolName] || TOOL_THRESHOLDS.default;
|
|
239
|
+
}
|
|
240
|
+
adjustThresholdForFailures(toolName, baseThreshold, failureCount) {
|
|
241
|
+
// For failure-sensitive tools, reduce threshold based on consecutive failures
|
|
242
|
+
if (FAILURE_SENSITIVE_TOOLS.has(toolName) && failureCount > 0) {
|
|
243
|
+
// Each failure reduces threshold by 1, minimum of 2
|
|
244
|
+
return Math.max(2, baseThreshold - failureCount);
|
|
245
|
+
}
|
|
246
|
+
return baseThreshold;
|
|
247
|
+
}
|
|
248
|
+
detectCycle(currentSignature) {
|
|
249
|
+
// Need at least 4 items for a 2-element cycle (A-B-A-B)
|
|
250
|
+
if (this.recentSequence.length < 4) {
|
|
251
|
+
return { isLoop: false, count: 0, threshold: Infinity };
|
|
252
|
+
}
|
|
253
|
+
// Check for 2-element cycles (A-B-A-B pattern)
|
|
254
|
+
const len = this.recentSequence.length;
|
|
255
|
+
const last4 = [...this.recentSequence.slice(-3), currentSignature];
|
|
256
|
+
if (last4[0] === last4[2] && last4[1] === last4[3]) {
|
|
257
|
+
// Check if this pattern has repeated 3+ times
|
|
258
|
+
let patternCount = 1;
|
|
259
|
+
for (let i = len - 4; i >= 1; i -= 2) {
|
|
260
|
+
if (this.recentSequence[i] === last4[1] && this.recentSequence[i - 1] === last4[0]) {
|
|
261
|
+
patternCount++;
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
break;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
if (patternCount >= 3) {
|
|
268
|
+
return {
|
|
269
|
+
isLoop: true,
|
|
270
|
+
reason: `Detected repeating cycle pattern (${patternCount} repetitions)`,
|
|
271
|
+
suggestion: 'The same sequence of operations is repeating. Try a different approach.',
|
|
272
|
+
count: patternCount,
|
|
273
|
+
threshold: 3,
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return { isLoop: false, count: 0, threshold: Infinity };
|
|
278
|
+
}
|
|
279
|
+
getSuggestion(toolName, _args) {
|
|
280
|
+
switch (toolName) {
|
|
281
|
+
case 'str_replace_editor':
|
|
282
|
+
return 'The edit may be failing repeatedly. Check if the old_str matches exactly (including whitespace).';
|
|
283
|
+
case 'bash':
|
|
284
|
+
case 'execute_bash':
|
|
285
|
+
return 'The command may be failing. Check the error output and try a different approach.';
|
|
286
|
+
case 'view_file':
|
|
287
|
+
case 'read_file':
|
|
288
|
+
return 'Consider if you need to read this file again, or if the information is already available.';
|
|
289
|
+
case 'search':
|
|
290
|
+
case 'search_files':
|
|
291
|
+
return 'Try a different search query or search in a different location.';
|
|
292
|
+
default:
|
|
293
|
+
return 'Try a different approach to accomplish your goal.';
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
hashString(str) {
|
|
297
|
+
// Simple hash for signature creation
|
|
298
|
+
let hash = 0;
|
|
299
|
+
for (let i = 0; i < str.length; i++) {
|
|
300
|
+
const char = str.charCodeAt(i);
|
|
301
|
+
hash = ((hash << 5) - hash) + char;
|
|
302
|
+
hash = hash & hash; // Convert to 32bit integer
|
|
303
|
+
}
|
|
304
|
+
return hash.toString(16);
|
|
305
|
+
}
|
|
306
|
+
cleanup() {
|
|
307
|
+
// Remove old history entries
|
|
308
|
+
if (this.callHistory.length > this.maxHistorySize) {
|
|
309
|
+
const removeCount = this.callHistory.length - this.maxHistorySize + 20;
|
|
310
|
+
this.callHistory.splice(0, removeCount);
|
|
311
|
+
}
|
|
312
|
+
// Clean up signature counts for signatures not in recent history
|
|
313
|
+
if (this.signatureCounts.size > this.maxHistorySize * 2) {
|
|
314
|
+
const recentSignatures = new Set(this.callHistory.slice(-this.maxHistorySize).map(r => r.signature));
|
|
315
|
+
for (const sig of this.signatureCounts.keys()) {
|
|
316
|
+
if (!recentSignatures.has(sig)) {
|
|
317
|
+
this.signatureCounts.delete(sig);
|
|
318
|
+
this.failureCounts.delete(sig);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Singleton instance
|
|
326
|
+
*/
|
|
327
|
+
let loopDetectorInstance = null;
|
|
328
|
+
export function getLoopDetector() {
|
|
329
|
+
if (!loopDetectorInstance) {
|
|
330
|
+
loopDetectorInstance = new LoopDetector();
|
|
331
|
+
}
|
|
332
|
+
return loopDetectorInstance;
|
|
333
|
+
}
|
|
334
|
+
export function resetLoopDetector() {
|
|
335
|
+
if (loopDetectorInstance) {
|
|
336
|
+
loopDetectorInstance.reset();
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
//# sourceMappingURL=loop-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop-detector.js","sourceRoot":"","sources":["../../src/agent/loop-detector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Progress-Based Detection System (Phase 2)
|
|
3
|
+
*
|
|
4
|
+
* Tracks state changes to detect actual progress vs. loops.
|
|
5
|
+
* Key insight: The problem isn't repeated tool calls, it's repeated tool calls
|
|
6
|
+
* that don't make progress.
|
|
7
|
+
*
|
|
8
|
+
* Progress Indicators:
|
|
9
|
+
* - File operations: Content changed (hash comparison)
|
|
10
|
+
* - Bash commands: Exit code 0 vs non-zero
|
|
11
|
+
* - Edits: File actually modified
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* File state snapshot for comparison
|
|
15
|
+
*/
|
|
16
|
+
interface FileState {
|
|
17
|
+
path: string;
|
|
18
|
+
hash: string;
|
|
19
|
+
size: number;
|
|
20
|
+
mtime: number;
|
|
21
|
+
exists: boolean;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Progress result for a tool execution
|
|
25
|
+
*/
|
|
26
|
+
export interface ProgressResult {
|
|
27
|
+
madeProgress: boolean;
|
|
28
|
+
reason: string;
|
|
29
|
+
stateChange?: {
|
|
30
|
+
before: FileState | null;
|
|
31
|
+
after: FileState | null;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Bash execution result for progress tracking
|
|
36
|
+
*/
|
|
37
|
+
export interface BashProgressResult {
|
|
38
|
+
madeProgress: boolean;
|
|
39
|
+
reason: string;
|
|
40
|
+
exitCode: number;
|
|
41
|
+
outputChanged: boolean;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Progress tracking for all tool operations
|
|
45
|
+
*/
|
|
46
|
+
export declare class ProgressTracker {
|
|
47
|
+
/** Cache of file states (path -> state) */
|
|
48
|
+
private fileStateCache;
|
|
49
|
+
/** Cache of bash output hashes (command -> hash) */
|
|
50
|
+
private bashOutputCache;
|
|
51
|
+
/** Recent file modifications for pattern detection */
|
|
52
|
+
private recentFileOps;
|
|
53
|
+
/** Maximum recent operations to track */
|
|
54
|
+
private maxRecentOps;
|
|
55
|
+
/**
|
|
56
|
+
* Capture file state before an operation
|
|
57
|
+
*/
|
|
58
|
+
captureFileState(path: string): Promise<FileState | null>;
|
|
59
|
+
/**
|
|
60
|
+
* Check if a file operation made progress
|
|
61
|
+
* Call this AFTER the operation completes
|
|
62
|
+
*/
|
|
63
|
+
checkFileProgress(path: string, operation: 'create' | 'edit' | 'view', success: boolean): Promise<ProgressResult>;
|
|
64
|
+
/**
|
|
65
|
+
* Check if a bash command made progress
|
|
66
|
+
*/
|
|
67
|
+
checkBashProgress(command: string, exitCode: number, output: string): BashProgressResult;
|
|
68
|
+
/**
|
|
69
|
+
* Detect if we're stuck in a file operation loop
|
|
70
|
+
* Returns true if the same file is being operated on repeatedly without progress
|
|
71
|
+
*/
|
|
72
|
+
detectFileOpLoop(path: string): {
|
|
73
|
+
isLoop: boolean;
|
|
74
|
+
reason?: string;
|
|
75
|
+
suggestion?: string;
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* Get progress statistics
|
|
79
|
+
*/
|
|
80
|
+
getStats(): {
|
|
81
|
+
trackedFiles: number;
|
|
82
|
+
trackedCommands: number;
|
|
83
|
+
recentOperations: number;
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* Reset all tracking
|
|
87
|
+
*/
|
|
88
|
+
reset(): void;
|
|
89
|
+
private hashContent;
|
|
90
|
+
private recordFileOp;
|
|
91
|
+
}
|
|
92
|
+
export declare function getProgressTracker(): ProgressTracker;
|
|
93
|
+
export declare function resetProgressTracker(): void;
|
|
94
|
+
export {};
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Progress-Based Detection System (Phase 2)
|
|
3
|
+
*
|
|
4
|
+
* Tracks state changes to detect actual progress vs. loops.
|
|
5
|
+
* Key insight: The problem isn't repeated tool calls, it's repeated tool calls
|
|
6
|
+
* that don't make progress.
|
|
7
|
+
*
|
|
8
|
+
* Progress Indicators:
|
|
9
|
+
* - File operations: Content changed (hash comparison)
|
|
10
|
+
* - Bash commands: Exit code 0 vs non-zero
|
|
11
|
+
* - Edits: File actually modified
|
|
12
|
+
*/
|
|
13
|
+
import { createHash } from 'crypto';
|
|
14
|
+
import { readFile, stat } from 'fs/promises';
|
|
15
|
+
/**
|
|
16
|
+
* Progress tracking for all tool operations
|
|
17
|
+
*/
|
|
18
|
+
export class ProgressTracker {
|
|
19
|
+
/** Cache of file states (path -> state) */
|
|
20
|
+
fileStateCache = new Map();
|
|
21
|
+
/** Cache of bash output hashes (command -> hash) */
|
|
22
|
+
bashOutputCache = new Map();
|
|
23
|
+
/** Recent file modifications for pattern detection */
|
|
24
|
+
recentFileOps = [];
|
|
25
|
+
/** Maximum recent operations to track */
|
|
26
|
+
maxRecentOps = 50;
|
|
27
|
+
/**
|
|
28
|
+
* Capture file state before an operation
|
|
29
|
+
*/
|
|
30
|
+
async captureFileState(path) {
|
|
31
|
+
try {
|
|
32
|
+
const stats = await stat(path);
|
|
33
|
+
const content = await readFile(path);
|
|
34
|
+
const hash = this.hashContent(content);
|
|
35
|
+
const state = {
|
|
36
|
+
path,
|
|
37
|
+
hash,
|
|
38
|
+
size: stats.size,
|
|
39
|
+
mtime: stats.mtimeMs,
|
|
40
|
+
exists: true,
|
|
41
|
+
};
|
|
42
|
+
// Cache for later comparison
|
|
43
|
+
this.fileStateCache.set(path, state);
|
|
44
|
+
return state;
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
// File doesn't exist
|
|
48
|
+
return {
|
|
49
|
+
path,
|
|
50
|
+
hash: '',
|
|
51
|
+
size: 0,
|
|
52
|
+
mtime: 0,
|
|
53
|
+
exists: false,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Check if a file operation made progress
|
|
59
|
+
* Call this AFTER the operation completes
|
|
60
|
+
*/
|
|
61
|
+
async checkFileProgress(path, operation, success) {
|
|
62
|
+
const beforeState = this.fileStateCache.get(path) || null;
|
|
63
|
+
// Record this operation
|
|
64
|
+
this.recordFileOp(path, operation, success);
|
|
65
|
+
if (!success) {
|
|
66
|
+
return {
|
|
67
|
+
madeProgress: false,
|
|
68
|
+
reason: `Operation failed on ${path}`,
|
|
69
|
+
stateChange: { before: beforeState, after: null },
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
// For view operations, always count as progress (reading info)
|
|
73
|
+
if (operation === 'view') {
|
|
74
|
+
return {
|
|
75
|
+
madeProgress: true,
|
|
76
|
+
reason: 'File content retrieved',
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
// For create/edit operations, check if file state changed
|
|
80
|
+
const afterState = await this.captureFileState(path);
|
|
81
|
+
// File was created
|
|
82
|
+
if (!beforeState?.exists && afterState?.exists) {
|
|
83
|
+
return {
|
|
84
|
+
madeProgress: true,
|
|
85
|
+
reason: 'File created',
|
|
86
|
+
stateChange: { before: beforeState, after: afterState },
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
// File content changed
|
|
90
|
+
if (beforeState?.hash !== afterState?.hash) {
|
|
91
|
+
return {
|
|
92
|
+
madeProgress: true,
|
|
93
|
+
reason: 'File content modified',
|
|
94
|
+
stateChange: { before: beforeState, after: afterState },
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
// No change detected
|
|
98
|
+
return {
|
|
99
|
+
madeProgress: false,
|
|
100
|
+
reason: 'File content unchanged (operation had no effect)',
|
|
101
|
+
stateChange: { before: beforeState, after: afterState },
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Check if a bash command made progress
|
|
106
|
+
*/
|
|
107
|
+
checkBashProgress(command, exitCode, output) {
|
|
108
|
+
const outputHash = this.hashContent(Buffer.from(output));
|
|
109
|
+
const previousHash = this.bashOutputCache.get(command);
|
|
110
|
+
// Update cache
|
|
111
|
+
this.bashOutputCache.set(command, outputHash);
|
|
112
|
+
// Cleanup old cache entries
|
|
113
|
+
if (this.bashOutputCache.size > 100) {
|
|
114
|
+
const keys = Array.from(this.bashOutputCache.keys()).slice(0, 50);
|
|
115
|
+
for (const key of keys) {
|
|
116
|
+
this.bashOutputCache.delete(key);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// Exit code 0 = success
|
|
120
|
+
if (exitCode === 0) {
|
|
121
|
+
return {
|
|
122
|
+
madeProgress: true,
|
|
123
|
+
reason: 'Command executed successfully',
|
|
124
|
+
exitCode,
|
|
125
|
+
outputChanged: previousHash !== outputHash,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
// Non-zero exit code
|
|
129
|
+
const outputChanged = previousHash !== outputHash;
|
|
130
|
+
return {
|
|
131
|
+
madeProgress: outputChanged,
|
|
132
|
+
reason: outputChanged
|
|
133
|
+
? 'Command failed but produced different output'
|
|
134
|
+
: 'Command failed with same output (likely stuck)',
|
|
135
|
+
exitCode,
|
|
136
|
+
outputChanged,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Detect if we're stuck in a file operation loop
|
|
141
|
+
* Returns true if the same file is being operated on repeatedly without progress
|
|
142
|
+
*/
|
|
143
|
+
detectFileOpLoop(path) {
|
|
144
|
+
const recentOpsForPath = this.recentFileOps.filter((op) => op.path === path && Date.now() - op.timestamp < 60000 // Last minute
|
|
145
|
+
);
|
|
146
|
+
// Check for repeated failures
|
|
147
|
+
const failures = recentOpsForPath.filter((op) => !op.success);
|
|
148
|
+
if (failures.length >= 3) {
|
|
149
|
+
return {
|
|
150
|
+
isLoop: true,
|
|
151
|
+
reason: `File "${path}" has failed ${failures.length} times in the last minute`,
|
|
152
|
+
suggestion: 'Check if the file exists and has correct permissions',
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
// Check for excessive operations on same file
|
|
156
|
+
if (recentOpsForPath.length >= 5) {
|
|
157
|
+
const edits = recentOpsForPath.filter((op) => op.operation === 'edit');
|
|
158
|
+
if (edits.length >= 4) {
|
|
159
|
+
return {
|
|
160
|
+
isLoop: true,
|
|
161
|
+
reason: `File "${path}" edited ${edits.length} times in rapid succession`,
|
|
162
|
+
suggestion: 'Consider if the edits are achieving the intended changes',
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return { isLoop: false };
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Get progress statistics
|
|
170
|
+
*/
|
|
171
|
+
getStats() {
|
|
172
|
+
return {
|
|
173
|
+
trackedFiles: this.fileStateCache.size,
|
|
174
|
+
trackedCommands: this.bashOutputCache.size,
|
|
175
|
+
recentOperations: this.recentFileOps.length,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Reset all tracking
|
|
180
|
+
*/
|
|
181
|
+
reset() {
|
|
182
|
+
this.fileStateCache.clear();
|
|
183
|
+
this.bashOutputCache.clear();
|
|
184
|
+
this.recentFileOps = [];
|
|
185
|
+
}
|
|
186
|
+
// ============================================================================
|
|
187
|
+
// Private Methods
|
|
188
|
+
// ============================================================================
|
|
189
|
+
hashContent(content) {
|
|
190
|
+
return createHash('md5')
|
|
191
|
+
.update(typeof content === 'string' ? content : content)
|
|
192
|
+
.digest('hex');
|
|
193
|
+
}
|
|
194
|
+
recordFileOp(path, operation, success) {
|
|
195
|
+
this.recentFileOps.push({
|
|
196
|
+
path,
|
|
197
|
+
operation,
|
|
198
|
+
timestamp: Date.now(),
|
|
199
|
+
success,
|
|
200
|
+
});
|
|
201
|
+
// Cleanup old entries
|
|
202
|
+
if (this.recentFileOps.length > this.maxRecentOps) {
|
|
203
|
+
this.recentFileOps = this.recentFileOps.slice(-this.maxRecentOps);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Singleton instance
|
|
209
|
+
*/
|
|
210
|
+
let progressTrackerInstance = null;
|
|
211
|
+
export function getProgressTracker() {
|
|
212
|
+
if (!progressTrackerInstance) {
|
|
213
|
+
progressTrackerInstance = new ProgressTracker();
|
|
214
|
+
}
|
|
215
|
+
return progressTrackerInstance;
|
|
216
|
+
}
|
|
217
|
+
export function resetProgressTracker() {
|
|
218
|
+
if (progressTrackerInstance) {
|
|
219
|
+
progressTrackerInstance.reset();
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
//# sourceMappingURL=progress-tracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progress-tracker.js","sourceRoot":"","sources":["../../src/agent/progress-tracker.ts"],"names":[],"mappings":"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"}
|