attocode 0.2.0 → 0.2.2

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.
Files changed (179) hide show
  1. package/CHANGELOG.md +111 -1
  2. package/README.md +7 -0
  3. package/dist/src/adapters.d.ts +6 -1
  4. package/dist/src/adapters.d.ts.map +1 -1
  5. package/dist/src/adapters.js +14 -1
  6. package/dist/src/adapters.js.map +1 -1
  7. package/dist/src/agent.d.ts +50 -0
  8. package/dist/src/agent.d.ts.map +1 -1
  9. package/dist/src/agent.js +734 -316
  10. package/dist/src/agent.js.map +1 -1
  11. package/dist/src/defaults.d.ts +1 -1
  12. package/dist/src/defaults.d.ts.map +1 -1
  13. package/dist/src/defaults.js +2 -0
  14. package/dist/src/defaults.js.map +1 -1
  15. package/dist/src/integrations/agent-registry.d.ts +9 -2
  16. package/dist/src/integrations/agent-registry.d.ts.map +1 -1
  17. package/dist/src/integrations/agent-registry.js +30 -4
  18. package/dist/src/integrations/agent-registry.js.map +1 -1
  19. package/dist/src/integrations/async-subagent.d.ts +135 -0
  20. package/dist/src/integrations/async-subagent.d.ts.map +1 -0
  21. package/dist/src/integrations/async-subagent.js +213 -0
  22. package/dist/src/integrations/async-subagent.js.map +1 -0
  23. package/dist/src/integrations/auto-checkpoint.d.ts +98 -0
  24. package/dist/src/integrations/auto-checkpoint.d.ts.map +1 -0
  25. package/dist/src/integrations/auto-checkpoint.js +252 -0
  26. package/dist/src/integrations/auto-checkpoint.js.map +1 -0
  27. package/dist/src/integrations/budget-pool.d.ts +13 -1
  28. package/dist/src/integrations/budget-pool.d.ts.map +1 -1
  29. package/dist/src/integrations/budget-pool.js +17 -0
  30. package/dist/src/integrations/budget-pool.js.map +1 -1
  31. package/dist/src/integrations/complexity-classifier.d.ts +86 -0
  32. package/dist/src/integrations/complexity-classifier.d.ts.map +1 -0
  33. package/dist/src/integrations/complexity-classifier.js +233 -0
  34. package/dist/src/integrations/complexity-classifier.js.map +1 -0
  35. package/dist/src/integrations/delegation-protocol.d.ts +86 -0
  36. package/dist/src/integrations/delegation-protocol.d.ts.map +1 -0
  37. package/dist/src/integrations/delegation-protocol.js +127 -0
  38. package/dist/src/integrations/delegation-protocol.js.map +1 -0
  39. package/dist/src/integrations/dynamic-budget.d.ts +81 -0
  40. package/dist/src/integrations/dynamic-budget.d.ts.map +1 -0
  41. package/dist/src/integrations/dynamic-budget.js +151 -0
  42. package/dist/src/integrations/dynamic-budget.js.map +1 -0
  43. package/dist/src/integrations/economics.d.ts +44 -1
  44. package/dist/src/integrations/economics.d.ts.map +1 -1
  45. package/dist/src/integrations/economics.js +182 -3
  46. package/dist/src/integrations/economics.js.map +1 -1
  47. package/dist/src/integrations/environment-facts.d.ts +52 -0
  48. package/dist/src/integrations/environment-facts.d.ts.map +1 -0
  49. package/dist/src/integrations/environment-facts.js +84 -0
  50. package/dist/src/integrations/environment-facts.js.map +1 -0
  51. package/dist/src/integrations/index.d.ts +16 -1
  52. package/dist/src/integrations/index.d.ts.map +1 -1
  53. package/dist/src/integrations/index.js +31 -1
  54. package/dist/src/integrations/index.js.map +1 -1
  55. package/dist/src/integrations/injection-budget.d.ts +71 -0
  56. package/dist/src/integrations/injection-budget.d.ts.map +1 -0
  57. package/dist/src/integrations/injection-budget.js +136 -0
  58. package/dist/src/integrations/injection-budget.js.map +1 -0
  59. package/dist/src/integrations/mcp-client.d.ts.map +1 -1
  60. package/dist/src/integrations/mcp-client.js +14 -0
  61. package/dist/src/integrations/mcp-client.js.map +1 -1
  62. package/dist/src/integrations/mcp-custom-tools.d.ts +102 -0
  63. package/dist/src/integrations/mcp-custom-tools.d.ts.map +1 -0
  64. package/dist/src/integrations/mcp-custom-tools.js +232 -0
  65. package/dist/src/integrations/mcp-custom-tools.js.map +1 -0
  66. package/dist/src/integrations/mcp-tool-validator.d.ts +60 -0
  67. package/dist/src/integrations/mcp-tool-validator.d.ts.map +1 -0
  68. package/dist/src/integrations/mcp-tool-validator.js +141 -0
  69. package/dist/src/integrations/mcp-tool-validator.js.map +1 -0
  70. package/dist/src/integrations/routing.d.ts +2 -1
  71. package/dist/src/integrations/routing.d.ts.map +1 -1
  72. package/dist/src/integrations/routing.js.map +1 -1
  73. package/dist/src/integrations/self-improvement.d.ts +90 -0
  74. package/dist/src/integrations/self-improvement.d.ts.map +1 -0
  75. package/dist/src/integrations/self-improvement.js +217 -0
  76. package/dist/src/integrations/self-improvement.js.map +1 -0
  77. package/dist/src/integrations/smart-decomposer.d.ts +4 -0
  78. package/dist/src/integrations/smart-decomposer.d.ts.map +1 -1
  79. package/dist/src/integrations/smart-decomposer.js +55 -28
  80. package/dist/src/integrations/smart-decomposer.js.map +1 -1
  81. package/dist/src/integrations/subagent-output-store.d.ts +91 -0
  82. package/dist/src/integrations/subagent-output-store.d.ts.map +1 -0
  83. package/dist/src/integrations/subagent-output-store.js +257 -0
  84. package/dist/src/integrations/subagent-output-store.js.map +1 -0
  85. package/dist/src/integrations/swarm/index.d.ts +1 -1
  86. package/dist/src/integrations/swarm/index.d.ts.map +1 -1
  87. package/dist/src/integrations/swarm/index.js +1 -1
  88. package/dist/src/integrations/swarm/index.js.map +1 -1
  89. package/dist/src/integrations/swarm/model-selector.d.ts +1 -0
  90. package/dist/src/integrations/swarm/model-selector.d.ts.map +1 -1
  91. package/dist/src/integrations/swarm/model-selector.js +37 -3
  92. package/dist/src/integrations/swarm/model-selector.js.map +1 -1
  93. package/dist/src/integrations/swarm/swarm-config-loader.d.ts +10 -1
  94. package/dist/src/integrations/swarm/swarm-config-loader.d.ts.map +1 -1
  95. package/dist/src/integrations/swarm/swarm-config-loader.js +72 -6
  96. package/dist/src/integrations/swarm/swarm-config-loader.js.map +1 -1
  97. package/dist/src/integrations/swarm/swarm-event-bridge.d.ts.map +1 -1
  98. package/dist/src/integrations/swarm/swarm-event-bridge.js +26 -4
  99. package/dist/src/integrations/swarm/swarm-event-bridge.js.map +1 -1
  100. package/dist/src/integrations/swarm/swarm-events.d.ts +11 -0
  101. package/dist/src/integrations/swarm/swarm-events.d.ts.map +1 -1
  102. package/dist/src/integrations/swarm/swarm-events.js +4 -0
  103. package/dist/src/integrations/swarm/swarm-events.js.map +1 -1
  104. package/dist/src/integrations/swarm/swarm-orchestrator.d.ts +11 -0
  105. package/dist/src/integrations/swarm/swarm-orchestrator.d.ts.map +1 -1
  106. package/dist/src/integrations/swarm/swarm-orchestrator.js +233 -10
  107. package/dist/src/integrations/swarm/swarm-orchestrator.js.map +1 -1
  108. package/dist/src/integrations/swarm/swarm-quality-gate.d.ts +9 -2
  109. package/dist/src/integrations/swarm/swarm-quality-gate.d.ts.map +1 -1
  110. package/dist/src/integrations/swarm/swarm-quality-gate.js +128 -11
  111. package/dist/src/integrations/swarm/swarm-quality-gate.js.map +1 -1
  112. package/dist/src/integrations/swarm/task-queue.d.ts +11 -1
  113. package/dist/src/integrations/swarm/task-queue.d.ts.map +1 -1
  114. package/dist/src/integrations/swarm/task-queue.js +125 -15
  115. package/dist/src/integrations/swarm/task-queue.js.map +1 -1
  116. package/dist/src/integrations/swarm/types.d.ts +40 -1
  117. package/dist/src/integrations/swarm/types.d.ts.map +1 -1
  118. package/dist/src/integrations/swarm/types.js +6 -1
  119. package/dist/src/integrations/swarm/types.js.map +1 -1
  120. package/dist/src/integrations/swarm/worker-pool.d.ts +9 -3
  121. package/dist/src/integrations/swarm/worker-pool.d.ts.map +1 -1
  122. package/dist/src/integrations/swarm/worker-pool.js +89 -17
  123. package/dist/src/integrations/swarm/worker-pool.js.map +1 -1
  124. package/dist/src/integrations/thinking-strategy.d.ts +52 -0
  125. package/dist/src/integrations/thinking-strategy.d.ts.map +1 -0
  126. package/dist/src/integrations/thinking-strategy.js +129 -0
  127. package/dist/src/integrations/thinking-strategy.js.map +1 -0
  128. package/dist/src/integrations/tool-recommendation.d.ts +58 -0
  129. package/dist/src/integrations/tool-recommendation.d.ts.map +1 -0
  130. package/dist/src/integrations/tool-recommendation.js +215 -0
  131. package/dist/src/integrations/tool-recommendation.js.map +1 -0
  132. package/dist/src/integrations/verification-gate.d.ts +80 -0
  133. package/dist/src/integrations/verification-gate.d.ts.map +1 -0
  134. package/dist/src/integrations/verification-gate.js +146 -0
  135. package/dist/src/integrations/verification-gate.js.map +1 -0
  136. package/dist/src/integrations/work-log.d.ts +87 -0
  137. package/dist/src/integrations/work-log.d.ts.map +1 -0
  138. package/dist/src/integrations/work-log.js +275 -0
  139. package/dist/src/integrations/work-log.js.map +1 -0
  140. package/dist/src/main.js +5 -4
  141. package/dist/src/main.js.map +1 -1
  142. package/dist/src/modes.d.ts +6 -0
  143. package/dist/src/modes.d.ts.map +1 -1
  144. package/dist/src/modes.js +73 -2
  145. package/dist/src/modes.js.map +1 -1
  146. package/dist/src/providers/adapters/anthropic.d.ts.map +1 -1
  147. package/dist/src/providers/adapters/anthropic.js +20 -3
  148. package/dist/src/providers/adapters/anthropic.js.map +1 -1
  149. package/dist/src/providers/adapters/openrouter.d.ts.map +1 -1
  150. package/dist/src/providers/adapters/openrouter.js +3 -1
  151. package/dist/src/providers/adapters/openrouter.js.map +1 -1
  152. package/dist/src/providers/types.d.ts +4 -0
  153. package/dist/src/providers/types.d.ts.map +1 -1
  154. package/dist/src/providers/types.js.map +1 -1
  155. package/dist/src/tools/bash.d.ts +8 -2
  156. package/dist/src/tools/bash.d.ts.map +1 -1
  157. package/dist/src/tools/bash.js +14 -1
  158. package/dist/src/tools/bash.js.map +1 -1
  159. package/dist/src/tools/coercion.d.ts +14 -0
  160. package/dist/src/tools/coercion.d.ts.map +1 -0
  161. package/dist/src/tools/coercion.js +25 -0
  162. package/dist/src/tools/coercion.js.map +1 -0
  163. package/dist/src/tools/file.d.ts +2 -2
  164. package/dist/src/tools/file.d.ts.map +1 -1
  165. package/dist/src/tools/file.js +2 -1
  166. package/dist/src/tools/file.js.map +1 -1
  167. package/dist/src/tools/standard.d.ts +17 -1
  168. package/dist/src/tools/standard.d.ts.map +1 -1
  169. package/dist/src/tools/standard.js +64 -11
  170. package/dist/src/tools/standard.js.map +1 -1
  171. package/dist/src/tui/app.d.ts.map +1 -1
  172. package/dist/src/tui/app.js +8 -1
  173. package/dist/src/tui/app.js.map +1 -1
  174. package/dist/src/tui/event-display.d.ts.map +1 -1
  175. package/dist/src/tui/event-display.js +8 -1
  176. package/dist/src/tui/event-display.js.map +1 -1
  177. package/dist/src/types.d.ts +26 -0
  178. package/dist/src/types.d.ts.map +1 -1
  179. package/package.json +6 -2
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Dynamic Budget Rebalancing
3
+ *
4
+ * Extends SharedBudgetPool with dynamic rebalancing that prevents
5
+ * starvation when spawning subagents sequentially.
6
+ *
7
+ * Key features:
8
+ * - setExpectedChildren(count) for upfront capacity planning
9
+ * - Sequential spawn cap: never take >60% of remaining budget
10
+ * - Rebalance on child completion (return unused budget to pool)
11
+ * - Priority-based allocation (critical children get more)
12
+ */
13
+ import { SharedBudgetPool } from './budget-pool.js';
14
+ // =============================================================================
15
+ // CONSTANTS
16
+ // =============================================================================
17
+ const PRIORITY_MULTIPLIERS = {
18
+ low: 0.5,
19
+ normal: 1.0,
20
+ high: 1.5,
21
+ critical: 2.0,
22
+ };
23
+ const DEFAULT_DYNAMIC_CONFIG = {
24
+ maxRemainingRatio: 0.6,
25
+ minPerExpectedChild: 10000,
26
+ autoRebalance: true,
27
+ };
28
+ // =============================================================================
29
+ // DYNAMIC BUDGET POOL
30
+ // =============================================================================
31
+ export class DynamicBudgetPool extends SharedBudgetPool {
32
+ dynamicConfig;
33
+ expectedChildren = 0;
34
+ spawnedCount = 0;
35
+ completedCount = 0;
36
+ childPriorities = new Map();
37
+ constructor(config) {
38
+ super(config);
39
+ this.dynamicConfig = {
40
+ ...config,
41
+ maxRemainingRatio: config.maxRemainingRatio ?? DEFAULT_DYNAMIC_CONFIG.maxRemainingRatio,
42
+ minPerExpectedChild: config.minPerExpectedChild ?? DEFAULT_DYNAMIC_CONFIG.minPerExpectedChild,
43
+ autoRebalance: config.autoRebalance ?? DEFAULT_DYNAMIC_CONFIG.autoRebalance,
44
+ };
45
+ }
46
+ /**
47
+ * Set the expected number of children for capacity planning.
48
+ * This adjusts maxPerChild to ensure fair distribution.
49
+ */
50
+ setExpectedChildren(count) {
51
+ this.expectedChildren = count;
52
+ this.updateMaxPerChild();
53
+ }
54
+ /**
55
+ * Set priority for a child agent.
56
+ */
57
+ setChildPriority(priority) {
58
+ this.childPriorities.set(priority.childId, priority);
59
+ }
60
+ /**
61
+ * Reserve with dynamic capacity planning.
62
+ * Respects expected children and remaining ratio cap.
63
+ */
64
+ reserveDynamic(childId, priority) {
65
+ // Set priority if provided
66
+ if (priority) {
67
+ this.setChildPriority({ childId, priority });
68
+ }
69
+ // Calculate dynamic max for this child
70
+ const stats = this.getStats();
71
+ const remaining = stats.tokensRemaining;
72
+ if (remaining <= 0)
73
+ return null;
74
+ // Cap at maxRemainingRatio of remaining budget
75
+ const ratioCap = Math.floor(remaining * this.dynamicConfig.maxRemainingRatio);
76
+ // Reserve for expected future children
77
+ const unreservedChildren = Math.max(0, this.expectedChildren - this.spawnedCount - 1);
78
+ const reserveForFuture = unreservedChildren * this.dynamicConfig.minPerExpectedChild;
79
+ const afterReserve = Math.max(0, remaining - reserveForFuture);
80
+ // Apply priority multiplier
81
+ const priorityLevel = this.childPriorities.get(childId)?.priority ?? 'normal';
82
+ const multiplier = PRIORITY_MULTIPLIERS[priorityLevel] ?? 1.0;
83
+ const priorityAdjusted = Math.floor(afterReserve * multiplier / Math.max(1, unreservedChildren + 1));
84
+ // Final allocation: min of all caps
85
+ const dynamicMax = Math.min(ratioCap, afterReserve, Math.max(priorityAdjusted, this.dynamicConfig.minPerExpectedChild));
86
+ // Temporarily set max per child for this reservation
87
+ this.setMaxPerChild(dynamicMax);
88
+ const allocation = this.reserve(childId);
89
+ this.resetMaxPerChild();
90
+ if (allocation) {
91
+ this.spawnedCount++;
92
+ }
93
+ return allocation;
94
+ }
95
+ /**
96
+ * Release with optional auto-rebalancing.
97
+ */
98
+ releaseDynamic(childId) {
99
+ this.release(childId);
100
+ this.completedCount++;
101
+ this.childPriorities.delete(childId);
102
+ }
103
+ /**
104
+ * Get enhanced stats including dynamic info.
105
+ */
106
+ getDynamicStats() {
107
+ const base = this.getStats();
108
+ const pending = this.spawnedCount - this.completedCount;
109
+ return {
110
+ ...base,
111
+ expectedChildren: this.expectedChildren,
112
+ spawnedCount: this.spawnedCount,
113
+ completedCount: this.completedCount,
114
+ pendingCount: pending,
115
+ avgPerChild: this.spawnedCount > 0
116
+ ? Math.floor(base.tokensUsed / this.spawnedCount)
117
+ : 0,
118
+ };
119
+ }
120
+ // ===========================================================================
121
+ // INTERNAL
122
+ // ===========================================================================
123
+ updateMaxPerChild() {
124
+ if (this.expectedChildren <= 0)
125
+ return;
126
+ const stats = this.getStats();
127
+ const remaining = stats.tokensRemaining;
128
+ const unreserved = Math.max(1, this.expectedChildren - this.spawnedCount);
129
+ // Fair share: remaining / unreserved children, capped by ratio
130
+ const fairShare = Math.floor(remaining / unreserved);
131
+ const ratioCap = Math.floor(remaining * this.dynamicConfig.maxRemainingRatio);
132
+ this.setMaxPerChild(Math.min(fairShare, ratioCap));
133
+ }
134
+ }
135
+ /**
136
+ * Create a dynamic budget pool from a parent's budget.
137
+ */
138
+ export function createDynamicBudgetPool(parentBudgetTokens, parentReserveRatio = 0.25, config) {
139
+ const parentReserve = Math.floor(parentBudgetTokens * parentReserveRatio);
140
+ const poolTokens = parentBudgetTokens - parentReserve;
141
+ return new DynamicBudgetPool({
142
+ totalTokens: poolTokens,
143
+ maxPerChild: Math.min(config?.maxPerChild ?? 100000, poolTokens),
144
+ totalCost: 0.50,
145
+ maxCostPerChild: 0.25,
146
+ maxRemainingRatio: config?.maxRemainingRatio ?? 0.6,
147
+ minPerExpectedChild: config?.minPerExpectedChild ?? 10000,
148
+ autoRebalance: config?.autoRebalance ?? true,
149
+ });
150
+ }
151
+ //# sourceMappingURL=dynamic-budget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dynamic-budget.js","sourceRoot":"","sources":["../../../src/integrations/dynamic-budget.ts"],"names":[],"mappings":"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"}
@@ -62,6 +62,8 @@ export interface LoopDetectionState {
62
62
  consecutiveCount: number;
63
63
  /** Threshold for doom loop detection (default: 3) */
64
64
  threshold: number;
65
+ /** Threshold for fuzzy doom loop detection (default: threshold + 1) */
66
+ fuzzyThreshold: number;
65
67
  /** Timestamp of last doom loop warning */
66
68
  lastWarningTime: number;
67
69
  }
@@ -87,6 +89,24 @@ export interface PhaseState {
87
89
  iterationsInPhase: number;
88
90
  /** Files read in recent iterations (for diminishing returns) */
89
91
  recentNewFiles: number;
92
+ /** Whether the last test passed */
93
+ lastTestPassed: boolean | null;
94
+ /** Consecutive test failures count */
95
+ consecutiveTestFailures: number;
96
+ /** Whether agent is in a test-fix cycle */
97
+ inTestFixCycle: boolean;
98
+ }
99
+ /**
100
+ * Phase-aware budget allocation config.
101
+ * Prevents spending too long in exploration and reserves time for verification.
102
+ */
103
+ export interface PhaseBudgetConfig {
104
+ /** Max percent of iterations for exploration (default: 30%) */
105
+ maxExplorationPercent: number;
106
+ /** Percent of iterations reserved for verification (default: 20%) */
107
+ reservedVerificationPercent: number;
108
+ /** Whether phase budget enforcement is enabled */
109
+ enabled: boolean;
90
110
  }
91
111
  /**
92
112
  * Budget check result.
@@ -163,6 +183,13 @@ export type EconomicsEventListener = (event: EconomicsEvent) => void;
163
183
  * Forces a structured JSON summary so the parent agent can make intelligent follow-up decisions.
164
184
  */
165
185
  export declare const TIMEOUT_WRAPUP_PROMPT = "[System] You are about to be stopped due to timeout. You MUST respond with a structured summary NOW.\n\nRespond with ONLY this JSON (no tool calls):\n{\n \"findings\": [\"what you discovered or accomplished\"],\n \"actionsTaken\": [\"files read, modifications made, commands run\"],\n \"failures\": [\"what failed or was blocked\"],\n \"remainingWork\": [\"what you didn't finish\"],\n \"suggestedNextSteps\": [\"what the parent agent should do next\"]\n}";
186
+ /**
187
+ * Compute a structural fingerprint for a tool call.
188
+ * Extracts only the primary argument (path, command, pattern, query) and ignores
189
+ * secondary arguments (encoding, timeout, flags). This catches near-identical calls
190
+ * that differ only in optional parameters.
191
+ */
192
+ export declare function computeToolFingerprint(toolName: string, argsStr: string): string;
166
193
  /**
167
194
  * ExecutionEconomicsManager handles budget tracking and progress detection.
168
195
  */
@@ -172,6 +199,7 @@ export declare class ExecutionEconomicsManager {
172
199
  private progress;
173
200
  private loopState;
174
201
  private phaseState;
202
+ private phaseBudget;
175
203
  private startTime;
176
204
  private pausedDuration;
177
205
  private pauseStart;
@@ -192,6 +220,11 @@ export declare class ExecutionEconomicsManager {
192
220
  * Get the effective duration accounting for paused time.
193
221
  */
194
222
  private getEffectiveDuration;
223
+ /**
224
+ * Configure phase-aware budget allocation.
225
+ * Only active when enabled=true (eval mode). TUI mode leaves it off.
226
+ */
227
+ setPhaseBudget(config: PhaseBudgetConfig): void;
195
228
  /**
196
229
  * Set the extension request handler.
197
230
  */
@@ -210,7 +243,9 @@ export declare class ExecutionEconomicsManager {
210
243
  recordToolCall(toolName: string, args: Record<string, unknown>, _result?: unknown): void;
211
244
  /**
212
245
  * Update doom loop detection state.
213
- * Detects when the same tool+args are called consecutively.
246
+ * Uses two-tier detection:
247
+ * 1. Exact match: same tool+args string (threshold: 3)
248
+ * 2. Fuzzy match: same tool + same primary args, ignoring optional params (threshold: 4)
214
249
  */
215
250
  private updateDoomLoopState;
216
251
  /**
@@ -283,6 +318,9 @@ export declare class ExecutionEconomicsManager {
283
318
  testsRun: number;
284
319
  shouldTransition: boolean;
285
320
  iterationsInPhase: number;
321
+ lastTestPassed: boolean | null;
322
+ consecutiveTestFailures: number;
323
+ inTestFixCycle: boolean;
286
324
  };
287
325
  /**
288
326
  * Subscribe to events.
@@ -293,6 +331,11 @@ export declare class ExecutionEconomicsManager {
293
331
  */
294
332
  reset(): void;
295
333
  private emit;
334
+ /**
335
+ * Parse test outcome from bash command output.
336
+ * Updates phaseState test tracking fields.
337
+ */
338
+ private parseTestOutcome;
296
339
  private isStuck;
297
340
  }
298
341
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"economics.d.ts","sourceRoot":"","sources":["../../../src/integrations/economics.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"economics.d.ts","sourceRoot":"","sources":["../../../src/integrations/economics.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AASH;;GAEG;AACH,MAAM,WAAW,eAAe;IAE9B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IAGpB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;IAG1B,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACvB,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC3B,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,eAAe,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC1E,sBAAsB,EAAE,MAAM,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,uCAAuC;IACvC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,wDAAwD;IACxD,gBAAgB,EAAE,MAAM,CAAC;IACzB,qDAAqD;IACrD,SAAS,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,cAAc,EAAE,MAAM,CAAC;IACvB,0CAA0C;IAC1C,eAAe,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,iCAAiC;IACjC,KAAK,EAAE,WAAW,GAAG,UAAU,GAAG,QAAQ,GAAG,WAAW,CAAC;IACzD,yCAAyC;IACzC,yBAAyB,EAAE,MAAM,CAAC;IAClC,2CAA2C;IAC3C,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7B,sCAAsC;IACtC,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC5B,oCAAoC;IACpC,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC3B,0BAA0B;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,8CAA8C;IAC9C,gBAAgB,EAAE,OAAO,CAAC;IAC1B,wCAAwC;IACxC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gEAAgE;IAChE,cAAc,EAAE,MAAM,CAAC;IACvB,mCAAmC;IACnC,cAAc,EAAE,OAAO,GAAG,IAAI,CAAC;IAC/B,sCAAsC;IACtC,uBAAuB,EAAE,MAAM,CAAC;IAChC,2CAA2C;IAC3C,cAAc,EAAE,OAAO,CAAC;CACzB;AAED;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,+DAA+D;IAC/D,qBAAqB,EAAE,MAAM,CAAC;IAC9B,qEAAqE;IACrE,2BAA2B,EAAE,MAAM,CAAC;IACpC,kDAAkD;IAClD,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,UAAU,GAAG,YAAY,CAAC;IAC3D,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,UAAU,GAAG,mBAAmB,GAAG,MAAM,GAAG,MAAM,CAAC;IACrE,uDAAuD;IACvD,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,+CAA+C;IAC/C,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,cAAc,CAAC;IAC7B,MAAM,EAAE,eAAe,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;CAC9C;AAED;;GAEG;AACH,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACtF;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC9E;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GACpE;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,GACnE;IAAE,IAAI,EAAE,qBAAqB,CAAC;IAAC,OAAO,EAAE,gBAAgB,CAAA;CAAE,GAC1D;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,SAAS,EAAE,OAAO,CAAC,eAAe,CAAC,CAAA;CAAE,GAClE;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,oBAAoB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAA;CAAE,GACtE;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACtE;IAAE,IAAI,EAAE,wBAAwB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9E,MAAM,MAAM,sBAAsB,GAAG,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;AAiBrE;;;GAGG;AACH,eAAO,MAAM,qBAAqB,idAShC,CAAC;AAkDH;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAoBhF;AAED;;GAEG;AACH,qBAAa,yBAAyB;IACpC,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,KAAK,CAAiB;IAC9B,OAAO,CAAC,QAAQ,CAAgB;IAChC,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,WAAW,CAAkC;IACrD,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,SAAS,CAAgC;IACjD,OAAO,CAAC,gBAAgB,CAAC,CAA0E;gBAEvF,MAAM,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC;IAkE7C;;;;OAIG;IACH,aAAa,IAAI,IAAI;IAMrB;;OAEG;IACH,cAAc,IAAI,IAAI;IAOtB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAK5B;;;OAGG;IACH,cAAc,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI;IAI/C;;OAEG;IACH,mBAAmB,CACjB,OAAO,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,GAAG,IAAI,CAAC,GAC/E,IAAI;IAIP;;;;;;OAMG;IACH,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI;IAkBpG;;OAEG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI;IAoGxF;;;;;OAKG;IACH,OAAO,CAAC,mBAAmB;IAoD3B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IASxB;;OAEG;IACH,OAAO,CAAC,eAAe;IAoBvB;;OAEG;IACH,OAAO,CAAC,0BAA0B;IAkClC;;OAEG;IACH,WAAW,IAAI,iBAAiB;IA4NhC;;OAEG;IACG,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAmCxD;;OAEG;IACH,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,IAAI;IAWvD;;OAEG;IACH,QAAQ,IAAI,cAAc;IAK1B;;OAEG;IACH,SAAS,IAAI,eAAe;IAI5B;;;OAGG;IACH,qBAAqB,IAAI,MAAM;IAqB/B;;OAEG;IACH,kBAAkB,IAAI;QAAE,WAAW,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE;IAiBnF;;OAEG;IACH,WAAW,IAAI;QACb,SAAS,EAAE,MAAM,CAAC;QAClB,aAAa,EAAE,MAAM,CAAC;QACtB,WAAW,EAAE,MAAM,CAAC;QACpB,OAAO,EAAE,OAAO,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;KACpB;IAUD;;OAEG;IACH,YAAY,IAAI,kBAAkB;IAIlC;;OAEG;IACH,aAAa,IAAI;QACf,KAAK,EAAE,MAAM,CAAC;QACd,eAAe,EAAE,MAAM,CAAC;QACxB,cAAc,EAAE,MAAM,CAAC;QACvB,aAAa,EAAE,MAAM,CAAC;QACtB,QAAQ,EAAE,MAAM,CAAC;QACjB,gBAAgB,EAAE,OAAO,CAAC;QAC1B,iBAAiB,EAAE,MAAM,CAAC;QAC1B,cAAc,EAAE,OAAO,GAAG,IAAI,CAAC;QAC/B,uBAAuB,EAAE,MAAM,CAAC;QAChC,cAAc,EAAE,OAAO,CAAC;KACzB;IAeD;;OAEG;IACH,EAAE,CAAC,QAAQ,EAAE,sBAAsB,GAAG,MAAM,IAAI;IAQhD;;OAEG;IACH,KAAK,IAAI,IAAI;IAuDb,OAAO,CAAC,IAAI;IAUZ;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IA0BxB,OAAO,CAAC,OAAO;CAkBhB;AAMD;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,GAChC,yBAAyB,CAE3B;AAMD;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,OAAO,CAAC,eAAe,CAMjD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,OAAO,CAAC,eAAe,CAMpD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,eAAe,EAAE,OAAO,CAAC,eAAe,CAQpD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,OAAO,CAAC,eAAe,CAMjD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,OAAO,CAAC,eAAe,CAMrD,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,mBAAmB,EAAE,OAAO,CAAC,eAAe,CAQxD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,yBAAyB,EAAE,OAAO,CAAC,eAAe,CAQ9D,CAAC"}
@@ -51,6 +51,55 @@ const EXPLORATION_NUDGE_PROMPT = (filesRead, iterations) => `[System] You've rea
51
51
  - Make the code changes now
52
52
  - Run tests to verify
53
53
  If you're still gathering context, briefly explain what you're looking for.`;
54
+ /**
55
+ * Test-fix rethink prompt - injected after consecutive test failures.
56
+ */
57
+ const TEST_FIX_RETHINK_PROMPT = (failures) => `[System] You've had ${failures} consecutive test failures. Step back and rethink:
58
+ 1. Re-read the error messages carefully
59
+ 2. Consider whether your approach is fundamentally wrong
60
+ 3. Try a DIFFERENT fix strategy instead of iterating on the same one
61
+ Do not retry the same fix. Try a new approach.`;
62
+ /**
63
+ * Phase budget exploration exceeded prompt.
64
+ */
65
+ const EXPLORATION_BUDGET_EXCEEDED_PROMPT = (pct) => `[System] You've spent ${pct}% of your iterations in exploration. Start making edits NOW.
66
+ Do not read more files. Use what you know to make the fix.`;
67
+ /**
68
+ * Phase budget verification reserve prompt.
69
+ */
70
+ const VERIFICATION_RESERVE_PROMPT = `[System] You are running low on iterations. Run your tests NOW to verify your changes.
71
+ Do not make more edits until you've confirmed whether the current fix works.`;
72
+ /**
73
+ * Primary argument keys that identify the *target* of a tool call.
74
+ * Used for fuzzy doom loop detection — ignoring secondary/optional args.
75
+ */
76
+ const PRIMARY_KEYS = ['path', 'file_path', 'command', 'pattern', 'query', 'url', 'content', 'filename'];
77
+ /**
78
+ * Compute a structural fingerprint for a tool call.
79
+ * Extracts only the primary argument (path, command, pattern, query) and ignores
80
+ * secondary arguments (encoding, timeout, flags). This catches near-identical calls
81
+ * that differ only in optional parameters.
82
+ */
83
+ export function computeToolFingerprint(toolName, argsStr) {
84
+ try {
85
+ const args = JSON.parse(argsStr || '{}');
86
+ const primaryArgs = {};
87
+ for (const key of PRIMARY_KEYS) {
88
+ if (key in args) {
89
+ primaryArgs[key] = args[key];
90
+ }
91
+ }
92
+ // If no primary keys found, fall back to full args
93
+ if (Object.keys(primaryArgs).length === 0) {
94
+ return `${toolName}:${stableStringify(args)}`;
95
+ }
96
+ return `${toolName}:${stableStringify(primaryArgs)}`;
97
+ }
98
+ catch {
99
+ // If args can't be parsed, use raw string
100
+ return `${toolName}:${argsStr}`;
101
+ }
102
+ }
54
103
  /**
55
104
  * ExecutionEconomicsManager handles budget tracking and progress detection.
56
105
  */
@@ -60,6 +109,7 @@ export class ExecutionEconomicsManager {
60
109
  progress;
61
110
  loopState;
62
111
  phaseState;
112
+ phaseBudget = null;
63
113
  startTime;
64
114
  pausedDuration = 0;
65
115
  pauseStart = null;
@@ -103,6 +153,7 @@ export class ExecutionEconomicsManager {
103
153
  lastTool: null,
104
154
  consecutiveCount: 0,
105
155
  threshold: 3,
156
+ fuzzyThreshold: 4,
106
157
  lastWarningTime: 0,
107
158
  };
108
159
  // Initialize phase tracking state
@@ -116,6 +167,9 @@ export class ExecutionEconomicsManager {
116
167
  shouldTransition: false,
117
168
  iterationsInPhase: 0,
118
169
  recentNewFiles: 0,
170
+ lastTestPassed: null,
171
+ consecutiveTestFailures: 0,
172
+ inTestFixCycle: false,
119
173
  };
120
174
  this.startTime = Date.now();
121
175
  }
@@ -145,6 +199,13 @@ export class ExecutionEconomicsManager {
145
199
  const currentPaused = this.pauseStart !== null ? Date.now() - this.pauseStart : 0;
146
200
  return Date.now() - this.startTime - this.pausedDuration - currentPaused;
147
201
  }
202
+ /**
203
+ * Configure phase-aware budget allocation.
204
+ * Only active when enabled=true (eval mode). TUI mode leaves it off.
205
+ */
206
+ setPhaseBudget(config) {
207
+ this.phaseBudget = config;
208
+ }
148
209
  /**
149
210
  * Set the extension request handler.
150
211
  */
@@ -232,13 +293,18 @@ export class ExecutionEconomicsManager {
232
293
  this.progress.commandsRun.push(command);
233
294
  this.progress.lastMeaningfulProgress = now;
234
295
  this.progress.stuckCount = 0;
235
- // Detect test runs
296
+ // Detect test runs and track outcomes
236
297
  if (command.includes('test') || command.includes('pytest') || command.includes('npm test') || command.includes('jest')) {
237
298
  this.phaseState.testsRun++;
238
299
  // Transition to verifying phase when tests are run after edits
239
300
  if (this.phaseState.phase === 'acting' && this.phaseState.filesModified.size > 0) {
240
301
  this.transitionPhase('verifying', 'Tests run after edits');
241
302
  }
303
+ // Track test pass/fail from result if available
304
+ if (_result !== undefined) {
305
+ const resultStr = typeof _result === 'string' ? _result : '';
306
+ this.parseTestOutcome(command, resultStr);
307
+ }
242
308
  }
243
309
  }
244
310
  // Update exploration saturation check
@@ -258,12 +324,14 @@ export class ExecutionEconomicsManager {
258
324
  }
259
325
  /**
260
326
  * Update doom loop detection state.
261
- * Detects when the same tool+args are called consecutively.
327
+ * Uses two-tier detection:
328
+ * 1. Exact match: same tool+args string (threshold: 3)
329
+ * 2. Fuzzy match: same tool + same primary args, ignoring optional params (threshold: 4)
262
330
  */
263
331
  updateDoomLoopState(toolName, argsStr) {
264
332
  const currentCall = `${toolName}:${argsStr}`;
265
333
  const recentCalls = this.progress.recentToolCalls;
266
- // Count consecutive identical calls from the end
334
+ // === EXACT MATCH: Count consecutive identical calls from the end ===
267
335
  let consecutiveCount = 0;
268
336
  for (let i = recentCalls.length - 1; i >= 0; i--) {
269
337
  const call = recentCalls[i];
@@ -274,6 +342,26 @@ export class ExecutionEconomicsManager {
274
342
  break;
275
343
  }
276
344
  }
345
+ // === FUZZY MATCH: Catches near-identical calls that differ only in optional params ===
346
+ // Only check if exact match didn't already trigger
347
+ if (consecutiveCount < this.loopState.threshold) {
348
+ const currentFingerprint = computeToolFingerprint(toolName, argsStr);
349
+ let fuzzyCount = 0;
350
+ for (let i = recentCalls.length - 1; i >= 0; i--) {
351
+ const call = recentCalls[i];
352
+ const callFingerprint = computeToolFingerprint(call.tool, call.args);
353
+ if (callFingerprint === currentFingerprint) {
354
+ fuzzyCount++;
355
+ }
356
+ else {
357
+ break;
358
+ }
359
+ }
360
+ // Use fuzzy count if it exceeds the fuzzy threshold
361
+ if (fuzzyCount >= this.loopState.fuzzyThreshold) {
362
+ consecutiveCount = Math.max(consecutiveCount, fuzzyCount);
363
+ }
364
+ }
277
365
  this.loopState.consecutiveCount = consecutiveCount;
278
366
  this.loopState.lastTool = toolName;
279
367
  // Detect doom loop when threshold reached
@@ -436,6 +524,60 @@ export class ExecutionEconomicsManager {
436
524
  injectedPrompt: EXPLORATION_NUDGE_PROMPT(this.phaseState.uniqueFilesRead.size, this.phaseState.iterationsInPhase),
437
525
  };
438
526
  }
527
+ // =========================================================================
528
+ // TEST-FIX CYCLE - Nudge to rethink after 3+ consecutive failures
529
+ // =========================================================================
530
+ if (this.phaseState.consecutiveTestFailures >= 3) {
531
+ return {
532
+ canContinue: true,
533
+ reason: `${this.phaseState.consecutiveTestFailures} consecutive test failures`,
534
+ budgetType: 'iterations',
535
+ isHardLimit: false,
536
+ isSoftLimit: true,
537
+ percentUsed: (this.usage.iterations / this.budget.targetIterations) * 100,
538
+ suggestedAction: 'warn',
539
+ injectedPrompt: TEST_FIX_RETHINK_PROMPT(this.phaseState.consecutiveTestFailures),
540
+ };
541
+ }
542
+ // =========================================================================
543
+ // PHASE-AWARE BUDGET ALLOCATION (opt-in, used in eval mode)
544
+ // =========================================================================
545
+ if (this.phaseBudget?.enabled) {
546
+ const iterPct = (this.usage.iterations / this.budget.maxIterations) * 100;
547
+ const explorationPct = this.phaseState.phase === 'exploring'
548
+ ? (this.phaseState.iterationsInPhase / this.budget.maxIterations) * 100
549
+ : 0;
550
+ // Too much time in exploration
551
+ if (explorationPct > this.phaseBudget.maxExplorationPercent && this.phaseState.filesModified.size === 0) {
552
+ return {
553
+ canContinue: true,
554
+ reason: `Exploration exceeds ${this.phaseBudget.maxExplorationPercent}% of budget`,
555
+ budgetType: 'iterations',
556
+ isHardLimit: false,
557
+ isSoftLimit: true,
558
+ percentUsed: iterPct,
559
+ suggestedAction: 'warn',
560
+ injectedPrompt: EXPLORATION_BUDGET_EXCEEDED_PROMPT(Math.round(explorationPct)),
561
+ };
562
+ }
563
+ // Only verification-reserve iterations remain
564
+ const remainingPct = 100 - iterPct;
565
+ if (remainingPct <= this.phaseBudget.reservedVerificationPercent
566
+ && this.phaseState.phase !== 'verifying'
567
+ && this.phaseState.filesModified.size > 0
568
+ && this.phaseState.testsRun === 0) {
569
+ return {
570
+ canContinue: true,
571
+ reason: `Only ${Math.round(remainingPct)}% budget remaining, verification needed`,
572
+ budgetType: 'iterations',
573
+ isHardLimit: false,
574
+ isSoftLimit: true,
575
+ percentUsed: iterPct,
576
+ suggestedAction: 'warn',
577
+ injectedPrompt: VERIFICATION_RESERVE_PROMPT,
578
+ };
579
+ }
580
+ }
439
581
  // Check soft limits (warnings)
440
582
  // Two-tier approach: 67-79% = warning, 80%+ = forceTextOnly to prevent overshoot
441
583
  if (this.usage.tokens >= this.budget.softTokenLimit) {
@@ -631,6 +773,9 @@ export class ExecutionEconomicsManager {
631
773
  testsRun: this.phaseState.testsRun,
632
774
  shouldTransition: this.phaseState.shouldTransition,
633
775
  iterationsInPhase: this.phaseState.iterationsInPhase,
776
+ lastTestPassed: this.phaseState.lastTestPassed,
777
+ consecutiveTestFailures: this.phaseState.consecutiveTestFailures,
778
+ inTestFixCycle: this.phaseState.inTestFixCycle,
634
779
  };
635
780
  }
636
781
  /**
@@ -672,6 +817,7 @@ export class ExecutionEconomicsManager {
672
817
  lastTool: null,
673
818
  consecutiveCount: 0,
674
819
  threshold: 3,
820
+ fuzzyThreshold: 4,
675
821
  lastWarningTime: 0,
676
822
  };
677
823
  // Reset phase tracking state
@@ -685,6 +831,9 @@ export class ExecutionEconomicsManager {
685
831
  shouldTransition: false,
686
832
  iterationsInPhase: 0,
687
833
  recentNewFiles: 0,
834
+ lastTestPassed: null,
835
+ consecutiveTestFailures: 0,
836
+ inTestFixCycle: false,
688
837
  };
689
838
  this.startTime = Date.now();
690
839
  this.pausedDuration = 0;
@@ -703,6 +852,36 @@ export class ExecutionEconomicsManager {
703
852
  }
704
853
  }
705
854
  }
855
+ /**
856
+ * Parse test outcome from bash command output.
857
+ * Updates phaseState test tracking fields.
858
+ */
859
+ parseTestOutcome(_command, output) {
860
+ if (!output)
861
+ return;
862
+ // Detect pass/fail from pytest-style output
863
+ const hasPassed = /(\d+)\s+passed/.test(output) || output.includes('PASSED');
864
+ const hasFailed = /(\d+)\s+failed/.test(output) || output.includes('FAILED') || output.includes('ERROR');
865
+ if (hasFailed && !hasPassed) {
866
+ // Pure failure
867
+ this.phaseState.lastTestPassed = false;
868
+ this.phaseState.consecutiveTestFailures++;
869
+ this.phaseState.inTestFixCycle = true;
870
+ }
871
+ else if (hasPassed && !hasFailed) {
872
+ // Pure pass
873
+ this.phaseState.lastTestPassed = true;
874
+ this.phaseState.consecutiveTestFailures = 0;
875
+ this.phaseState.inTestFixCycle = false;
876
+ }
877
+ else if (hasPassed && hasFailed) {
878
+ // Mixed - some passed, some failed
879
+ this.phaseState.lastTestPassed = false;
880
+ this.phaseState.consecutiveTestFailures++;
881
+ this.phaseState.inTestFixCycle = true;
882
+ }
883
+ // If no clear signal, don't update
884
+ }
706
885
  isStuck() {
707
886
  // Check for repeated tool calls
708
887
  if (this.progress.recentToolCalls.length >= 3) {