attocode 0.2.2 → 0.2.4
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/CHANGELOG.md +169 -3
- package/README.md +65 -5
- package/dist/src/adapters.d.ts.map +1 -1
- package/dist/src/adapters.js +15 -11
- package/dist/src/adapters.js.map +1 -1
- package/dist/src/agent.d.ts +44 -98
- package/dist/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +716 -2648
- package/dist/src/agent.js.map +1 -1
- package/dist/src/cli.d.ts.map +1 -1
- package/dist/src/cli.js +25 -3
- package/dist/src/cli.js.map +1 -1
- package/dist/src/commands/handler.d.ts.map +1 -1
- package/dist/src/commands/handler.js +11 -3
- package/dist/src/commands/handler.js.map +1 -1
- package/dist/src/commands/init-commands.d.ts.map +1 -1
- package/dist/src/commands/init-commands.js +16 -1
- package/dist/src/commands/init-commands.js.map +1 -1
- package/dist/src/commands/init.d.ts.map +1 -1
- package/dist/src/commands/init.js +31 -0
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/config/base-types.d.ts +45 -0
- package/dist/src/config/base-types.d.ts.map +1 -0
- package/dist/src/config/base-types.js +9 -0
- package/dist/src/config/base-types.js.map +1 -0
- package/dist/src/config/config-manager.d.ts +35 -0
- package/dist/src/config/config-manager.d.ts.map +1 -0
- package/dist/src/config/config-manager.js +108 -0
- package/dist/src/config/config-manager.js.map +1 -0
- package/dist/src/config/index.d.ts +4 -0
- package/dist/src/config/index.d.ts.map +1 -0
- package/dist/src/config/index.js +3 -0
- package/dist/src/config/index.js.map +1 -0
- package/dist/src/config/schema.d.ts +1546 -0
- package/dist/src/config/schema.d.ts.map +1 -0
- package/dist/src/config/schema.js +268 -0
- package/dist/src/config/schema.js.map +1 -0
- package/dist/src/config.d.ts +4 -1
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/config.js +8 -12
- package/dist/src/config.js.map +1 -1
- package/dist/src/core/agent-state-machine.d.ts +131 -0
- package/dist/src/core/agent-state-machine.d.ts.map +1 -0
- package/dist/src/core/agent-state-machine.js +302 -0
- package/dist/src/core/agent-state-machine.js.map +1 -0
- package/dist/src/core/base-manager.d.ts +79 -0
- package/dist/src/core/base-manager.d.ts.map +1 -0
- package/dist/src/core/base-manager.js +170 -0
- package/dist/src/core/base-manager.js.map +1 -0
- package/dist/src/core/completion-analyzer.d.ts +15 -0
- package/dist/src/core/completion-analyzer.d.ts.map +1 -0
- package/dist/src/core/completion-analyzer.js +53 -0
- package/dist/src/core/completion-analyzer.js.map +1 -0
- package/dist/src/core/execution-loop.d.ts +46 -0
- package/dist/src/core/execution-loop.d.ts.map +1 -0
- package/dist/src/core/execution-loop.js +1258 -0
- package/dist/src/core/execution-loop.js.map +1 -0
- package/dist/src/core/index.d.ts +7 -0
- package/dist/src/core/index.d.ts.map +1 -1
- package/dist/src/core/index.js +9 -0
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/core/process-handlers.d.ts.map +1 -1
- package/dist/src/core/process-handlers.js +14 -0
- package/dist/src/core/process-handlers.js.map +1 -1
- package/dist/src/core/protocol/types.d.ts +4 -4
- package/dist/src/core/response-handler.d.ts +16 -0
- package/dist/src/core/response-handler.d.ts.map +1 -0
- package/dist/src/core/response-handler.js +234 -0
- package/dist/src/core/response-handler.js.map +1 -0
- package/dist/src/core/subagent-spawner.d.ts +43 -0
- package/dist/src/core/subagent-spawner.d.ts.map +1 -0
- package/dist/src/core/subagent-spawner.js +966 -0
- package/dist/src/core/subagent-spawner.js.map +1 -0
- package/dist/src/core/tool-executor.d.ts +59 -0
- package/dist/src/core/tool-executor.d.ts.map +1 -0
- package/dist/src/core/tool-executor.js +677 -0
- package/dist/src/core/tool-executor.js.map +1 -0
- package/dist/src/core/types.d.ts +133 -0
- package/dist/src/core/types.d.ts.map +1 -0
- package/dist/src/core/types.js +12 -0
- package/dist/src/core/types.js.map +1 -0
- package/dist/src/defaults.d.ts +8 -3
- package/dist/src/defaults.d.ts.map +1 -1
- package/dist/src/defaults.js +65 -3
- package/dist/src/defaults.js.map +1 -1
- package/dist/src/integrations/agent-registry.d.ts +11 -0
- package/dist/src/integrations/agent-registry.d.ts.map +1 -1
- package/dist/src/integrations/agent-registry.js.map +1 -1
- package/dist/src/integrations/auto-compaction.d.ts.map +1 -1
- package/dist/src/integrations/auto-compaction.js +8 -3
- package/dist/src/integrations/auto-compaction.js.map +1 -1
- package/dist/src/integrations/bash-policy.d.ts +33 -0
- package/dist/src/integrations/bash-policy.d.ts.map +1 -0
- package/dist/src/integrations/bash-policy.js +142 -0
- package/dist/src/integrations/bash-policy.js.map +1 -0
- package/dist/src/integrations/budget-pool.d.ts +7 -0
- package/dist/src/integrations/budget-pool.d.ts.map +1 -1
- package/dist/src/integrations/budget-pool.js +43 -0
- package/dist/src/integrations/budget-pool.js.map +1 -1
- package/dist/src/integrations/codebase-ast.d.ts +52 -0
- package/dist/src/integrations/codebase-ast.d.ts.map +1 -0
- package/dist/src/integrations/codebase-ast.js +457 -0
- package/dist/src/integrations/codebase-ast.js.map +1 -0
- package/dist/src/integrations/codebase-context.d.ts +23 -0
- package/dist/src/integrations/codebase-context.d.ts.map +1 -1
- package/dist/src/integrations/codebase-context.js +230 -17
- package/dist/src/integrations/codebase-context.js.map +1 -1
- package/dist/src/integrations/compaction.d.ts.map +1 -1
- package/dist/src/integrations/compaction.js +14 -6
- package/dist/src/integrations/compaction.js.map +1 -1
- package/dist/src/integrations/context-engineering.d.ts +8 -0
- package/dist/src/integrations/context-engineering.d.ts.map +1 -1
- package/dist/src/integrations/context-engineering.js +19 -0
- package/dist/src/integrations/context-engineering.js.map +1 -1
- package/dist/src/integrations/delegation-protocol.js +2 -2
- package/dist/src/integrations/delegation-protocol.js.map +1 -1
- package/dist/src/integrations/economics.d.ts +67 -1
- package/dist/src/integrations/economics.d.ts.map +1 -1
- package/dist/src/integrations/economics.js +328 -33
- package/dist/src/integrations/economics.js.map +1 -1
- package/dist/src/integrations/edit-validator.d.ts +30 -0
- package/dist/src/integrations/edit-validator.d.ts.map +1 -0
- package/dist/src/integrations/edit-validator.js +85 -0
- package/dist/src/integrations/edit-validator.js.map +1 -0
- package/dist/src/integrations/file-cache.d.ts +7 -0
- package/dist/src/integrations/file-cache.d.ts.map +1 -1
- package/dist/src/integrations/file-cache.js +54 -0
- package/dist/src/integrations/file-cache.js.map +1 -1
- package/dist/src/integrations/health-check.d.ts.map +1 -1
- package/dist/src/integrations/health-check.js +3 -2
- package/dist/src/integrations/health-check.js.map +1 -1
- package/dist/src/integrations/hierarchical-config.d.ts +3 -0
- package/dist/src/integrations/hierarchical-config.d.ts.map +1 -1
- package/dist/src/integrations/hierarchical-config.js +20 -0
- package/dist/src/integrations/hierarchical-config.js.map +1 -1
- package/dist/src/integrations/hooks.d.ts +2 -0
- package/dist/src/integrations/hooks.d.ts.map +1 -1
- package/dist/src/integrations/hooks.js +99 -15
- package/dist/src/integrations/hooks.js.map +1 -1
- package/dist/src/integrations/index.d.ts +10 -1
- package/dist/src/integrations/index.d.ts.map +1 -1
- package/dist/src/integrations/index.js +12 -2
- package/dist/src/integrations/index.js.map +1 -1
- package/dist/src/integrations/logger.d.ts +104 -0
- package/dist/src/integrations/logger.d.ts.map +1 -0
- package/dist/src/integrations/logger.js +219 -0
- package/dist/src/integrations/logger.js.map +1 -0
- package/dist/src/integrations/lsp.d.ts.map +1 -1
- package/dist/src/integrations/lsp.js +5 -4
- package/dist/src/integrations/lsp.js.map +1 -1
- package/dist/src/integrations/mcp-client.d.ts.map +1 -1
- package/dist/src/integrations/mcp-client.js +8 -7
- package/dist/src/integrations/mcp-client.js.map +1 -1
- package/dist/src/integrations/observability.d.ts.map +1 -1
- package/dist/src/integrations/observability.js +5 -4
- package/dist/src/integrations/observability.js.map +1 -1
- package/dist/src/integrations/openrouter-pricing.d.ts.map +1 -1
- package/dist/src/integrations/openrouter-pricing.js +4 -3
- package/dist/src/integrations/openrouter-pricing.js.map +1 -1
- package/dist/src/integrations/persistence.d.ts.map +1 -1
- package/dist/src/integrations/persistence.js +5 -4
- package/dist/src/integrations/persistence.js.map +1 -1
- package/dist/src/integrations/planning.d.ts.map +1 -1
- package/dist/src/integrations/planning.js +5 -4
- package/dist/src/integrations/planning.js.map +1 -1
- package/dist/src/integrations/policy-engine.d.ts +55 -0
- package/dist/src/integrations/policy-engine.d.ts.map +1 -0
- package/dist/src/integrations/policy-engine.js +247 -0
- package/dist/src/integrations/policy-engine.js.map +1 -0
- package/dist/src/integrations/retry.d.ts +1 -0
- package/dist/src/integrations/retry.d.ts.map +1 -1
- package/dist/src/integrations/retry.js.map +1 -1
- package/dist/src/integrations/routing.d.ts.map +1 -1
- package/dist/src/integrations/routing.js +2 -1
- package/dist/src/integrations/routing.js.map +1 -1
- package/dist/src/integrations/safety.d.ts +5 -4
- package/dist/src/integrations/safety.d.ts.map +1 -1
- package/dist/src/integrations/safety.js +45 -20
- package/dist/src/integrations/safety.js.map +1 -1
- package/dist/src/integrations/sandbox/basic.d.ts +7 -0
- package/dist/src/integrations/sandbox/basic.d.ts.map +1 -1
- package/dist/src/integrations/sandbox/basic.js +27 -2
- package/dist/src/integrations/sandbox/basic.js.map +1 -1
- package/dist/src/integrations/sandbox/docker.d.ts.map +1 -1
- package/dist/src/integrations/sandbox/docker.js +2 -1
- package/dist/src/integrations/sandbox/docker.js.map +1 -1
- package/dist/src/integrations/sandbox/index.d.ts +6 -0
- package/dist/src/integrations/sandbox/index.d.ts.map +1 -1
- package/dist/src/integrations/sandbox/index.js +8 -4
- package/dist/src/integrations/sandbox/index.js.map +1 -1
- package/dist/src/integrations/sandbox/landlock.d.ts.map +1 -1
- package/dist/src/integrations/sandbox/landlock.js +3 -0
- package/dist/src/integrations/sandbox/landlock.js.map +1 -1
- package/dist/src/integrations/self-improvement.d.ts.map +1 -1
- package/dist/src/integrations/self-improvement.js +12 -0
- package/dist/src/integrations/self-improvement.js.map +1 -1
- package/dist/src/integrations/session-store.d.ts +1 -0
- package/dist/src/integrations/session-store.d.ts.map +1 -1
- package/dist/src/integrations/session-store.js +1 -0
- package/dist/src/integrations/session-store.js.map +1 -1
- package/dist/src/integrations/shared-blackboard.d.ts +3 -0
- package/dist/src/integrations/shared-blackboard.d.ts.map +1 -1
- package/dist/src/integrations/shared-blackboard.js +47 -0
- package/dist/src/integrations/shared-blackboard.js.map +1 -1
- package/dist/src/integrations/smart-decomposer.d.ts +45 -1
- package/dist/src/integrations/smart-decomposer.d.ts.map +1 -1
- package/dist/src/integrations/smart-decomposer.js +486 -30
- package/dist/src/integrations/smart-decomposer.js.map +1 -1
- package/dist/src/integrations/sqlite-store.d.ts +2 -0
- package/dist/src/integrations/sqlite-store.d.ts.map +1 -1
- package/dist/src/integrations/sqlite-store.js +18 -6
- package/dist/src/integrations/sqlite-store.js.map +1 -1
- package/dist/src/integrations/swarm/failure-classifier.d.ts +11 -0
- package/dist/src/integrations/swarm/failure-classifier.d.ts.map +1 -0
- package/dist/src/integrations/swarm/failure-classifier.js +95 -0
- package/dist/src/integrations/swarm/failure-classifier.js.map +1 -0
- package/dist/src/integrations/swarm/index.d.ts +1 -1
- package/dist/src/integrations/swarm/index.d.ts.map +1 -1
- package/dist/src/integrations/swarm/index.js.map +1 -1
- package/dist/src/integrations/swarm/model-selector.d.ts +15 -0
- package/dist/src/integrations/swarm/model-selector.d.ts.map +1 -1
- package/dist/src/integrations/swarm/model-selector.js +100 -20
- package/dist/src/integrations/swarm/model-selector.js.map +1 -1
- package/dist/src/integrations/swarm/swarm-budget.d.ts +4 -0
- package/dist/src/integrations/swarm/swarm-budget.d.ts.map +1 -1
- package/dist/src/integrations/swarm/swarm-budget.js +6 -0
- package/dist/src/integrations/swarm/swarm-budget.js.map +1 -1
- package/dist/src/integrations/swarm/swarm-config-loader.d.ts +8 -0
- package/dist/src/integrations/swarm/swarm-config-loader.d.ts.map +1 -1
- package/dist/src/integrations/swarm/swarm-config-loader.js +249 -7
- package/dist/src/integrations/swarm/swarm-config-loader.js.map +1 -1
- package/dist/src/integrations/swarm/swarm-event-bridge.d.ts +86 -1
- package/dist/src/integrations/swarm/swarm-event-bridge.d.ts.map +1 -1
- package/dist/src/integrations/swarm/swarm-event-bridge.js +207 -23
- package/dist/src/integrations/swarm/swarm-event-bridge.js.map +1 -1
- package/dist/src/integrations/swarm/swarm-events.d.ts +58 -1
- package/dist/src/integrations/swarm/swarm-events.d.ts.map +1 -1
- package/dist/src/integrations/swarm/swarm-events.js +22 -5
- package/dist/src/integrations/swarm/swarm-events.js.map +1 -1
- package/dist/src/integrations/swarm/swarm-orchestrator.d.ts +147 -8
- package/dist/src/integrations/swarm/swarm-orchestrator.d.ts.map +1 -1
- package/dist/src/integrations/swarm/swarm-orchestrator.js +2179 -132
- package/dist/src/integrations/swarm/swarm-orchestrator.js.map +1 -1
- package/dist/src/integrations/swarm/swarm-quality-gate.d.ts +83 -2
- package/dist/src/integrations/swarm/swarm-quality-gate.d.ts.map +1 -1
- package/dist/src/integrations/swarm/swarm-quality-gate.js +278 -19
- package/dist/src/integrations/swarm/swarm-quality-gate.js.map +1 -1
- package/dist/src/integrations/swarm/swarm-state-store.d.ts +4 -1
- package/dist/src/integrations/swarm/swarm-state-store.d.ts.map +1 -1
- package/dist/src/integrations/swarm/swarm-state-store.js +8 -1
- package/dist/src/integrations/swarm/swarm-state-store.js.map +1 -1
- package/dist/src/integrations/swarm/task-queue.d.ts +54 -0
- package/dist/src/integrations/swarm/task-queue.d.ts.map +1 -1
- package/dist/src/integrations/swarm/task-queue.js +310 -12
- package/dist/src/integrations/swarm/task-queue.js.map +1 -1
- package/dist/src/integrations/swarm/types.d.ts +251 -13
- package/dist/src/integrations/swarm/types.d.ts.map +1 -1
- package/dist/src/integrations/swarm/types.js +70 -8
- package/dist/src/integrations/swarm/types.js.map +1 -1
- package/dist/src/integrations/swarm/worker-pool.d.ts +21 -4
- package/dist/src/integrations/swarm/worker-pool.d.ts.map +1 -1
- package/dist/src/integrations/swarm/worker-pool.js +223 -44
- package/dist/src/integrations/swarm/worker-pool.js.map +1 -1
- package/dist/src/integrations/task-manager.d.ts +33 -1
- package/dist/src/integrations/task-manager.d.ts.map +1 -1
- package/dist/src/integrations/task-manager.js +78 -4
- package/dist/src/integrations/task-manager.js.map +1 -1
- package/dist/src/integrations/tool-recommendation.d.ts +7 -4
- package/dist/src/integrations/tool-recommendation.d.ts.map +1 -1
- package/dist/src/integrations/tool-recommendation.js +58 -5
- package/dist/src/integrations/tool-recommendation.js.map +1 -1
- package/dist/src/integrations/work-log.js +4 -4
- package/dist/src/integrations/work-log.js.map +1 -1
- package/dist/src/main.js +106 -30
- package/dist/src/main.js.map +1 -1
- package/dist/src/modes/repl.d.ts.map +1 -1
- package/dist/src/modes/repl.js +50 -12
- package/dist/src/modes/repl.js.map +1 -1
- package/dist/src/modes/tui.d.ts.map +1 -1
- package/dist/src/modes/tui.js +41 -6
- package/dist/src/modes/tui.js.map +1 -1
- package/dist/src/modes.d.ts.map +1 -1
- package/dist/src/modes.js +4 -27
- package/dist/src/modes.js.map +1 -1
- package/dist/src/observability/tracer.d.ts.map +1 -1
- package/dist/src/observability/tracer.js +2 -1
- package/dist/src/observability/tracer.js.map +1 -1
- package/dist/src/persistence/schema.d.ts.map +1 -1
- package/dist/src/persistence/schema.js +11 -0
- package/dist/src/persistence/schema.js.map +1 -1
- package/dist/src/providers/adapters/anthropic.d.ts.map +1 -1
- package/dist/src/providers/adapters/anthropic.js +3 -2
- package/dist/src/providers/adapters/anthropic.js.map +1 -1
- package/dist/src/providers/adapters/openai.d.ts.map +1 -1
- package/dist/src/providers/adapters/openai.js +3 -2
- package/dist/src/providers/adapters/openai.js.map +1 -1
- package/dist/src/providers/adapters/openrouter.d.ts.map +1 -1
- package/dist/src/providers/adapters/openrouter.js +11 -11
- package/dist/src/providers/adapters/openrouter.js.map +1 -1
- package/dist/src/providers/circuit-breaker.d.ts +1 -0
- package/dist/src/providers/circuit-breaker.d.ts.map +1 -1
- package/dist/src/providers/circuit-breaker.js.map +1 -1
- package/dist/src/providers/provider.d.ts.map +1 -1
- package/dist/src/providers/provider.js +2 -1
- package/dist/src/providers/provider.js.map +1 -1
- package/dist/src/providers/resilient-provider.d.ts.map +1 -1
- package/dist/src/providers/resilient-provider.js +2 -1
- package/dist/src/providers/resilient-provider.js.map +1 -1
- package/dist/src/session-picker.d.ts.map +1 -1
- package/dist/src/session-picker.js +40 -5
- package/dist/src/session-picker.js.map +1 -1
- package/dist/src/shared/budget-tracker.d.ts +65 -0
- package/dist/src/shared/budget-tracker.d.ts.map +1 -0
- package/dist/src/shared/budget-tracker.js +128 -0
- package/dist/src/shared/budget-tracker.js.map +1 -0
- package/dist/src/shared/context-engine.d.ts +64 -0
- package/dist/src/shared/context-engine.d.ts.map +1 -0
- package/dist/src/shared/context-engine.js +117 -0
- package/dist/src/shared/context-engine.js.map +1 -0
- package/dist/src/shared/index.d.ts +12 -0
- package/dist/src/shared/index.d.ts.map +1 -0
- package/dist/src/shared/index.js +12 -0
- package/dist/src/shared/index.js.map +1 -0
- package/dist/src/shared/persistence.d.ts +57 -0
- package/dist/src/shared/persistence.d.ts.map +1 -0
- package/dist/src/shared/persistence.js +168 -0
- package/dist/src/shared/persistence.js.map +1 -0
- package/dist/src/shared/shared-context-state.d.ts +89 -0
- package/dist/src/shared/shared-context-state.d.ts.map +1 -0
- package/dist/src/shared/shared-context-state.js +175 -0
- package/dist/src/shared/shared-context-state.js.map +1 -0
- package/dist/src/shared/shared-economics-state.d.ts +61 -0
- package/dist/src/shared/shared-economics-state.d.ts.map +1 -0
- package/dist/src/shared/shared-economics-state.js +100 -0
- package/dist/src/shared/shared-economics-state.js.map +1 -0
- package/dist/src/tools/agent.d.ts.map +1 -1
- package/dist/src/tools/agent.js +11 -2
- package/dist/src/tools/agent.js.map +1 -1
- package/dist/src/tools/bash.d.ts +1 -1
- package/dist/src/tools/bash.d.ts.map +1 -1
- package/dist/src/tools/bash.js +2 -1
- package/dist/src/tools/bash.js.map +1 -1
- package/dist/src/tools/coercion.d.ts +6 -0
- package/dist/src/tools/coercion.d.ts.map +1 -1
- package/dist/src/tools/coercion.js +13 -0
- package/dist/src/tools/coercion.js.map +1 -1
- package/dist/src/tools/file.d.ts +5 -5
- package/dist/src/tools/file.js +2 -2
- package/dist/src/tools/file.js.map +1 -1
- package/dist/src/tools/permission.d.ts.map +1 -1
- package/dist/src/tools/permission.js +10 -116
- package/dist/src/tools/permission.js.map +1 -1
- package/dist/src/tools/types.d.ts +1 -0
- package/dist/src/tools/types.d.ts.map +1 -1
- package/dist/src/tools/types.js.map +1 -1
- package/dist/src/tracing/trace-collector.d.ts +292 -0
- package/dist/src/tracing/trace-collector.d.ts.map +1 -1
- package/dist/src/tracing/trace-collector.js +249 -5
- package/dist/src/tracing/trace-collector.js.map +1 -1
- package/dist/src/tracing/types.d.ts +200 -1
- package/dist/src/tracing/types.d.ts.map +1 -1
- package/dist/src/tracing/types.js.map +1 -1
- package/dist/src/tricks/failure-evidence.d.ts.map +1 -1
- package/dist/src/tricks/failure-evidence.js +2 -1
- package/dist/src/tricks/failure-evidence.js.map +1 -1
- package/dist/src/tui/app.d.ts +13 -0
- package/dist/src/tui/app.d.ts.map +1 -1
- package/dist/src/tui/app.js +162 -19
- package/dist/src/tui/app.js.map +1 -1
- package/dist/src/tui/components/ErrorBoundary.d.ts.map +1 -1
- package/dist/src/tui/components/ErrorBoundary.js +3 -2
- package/dist/src/tui/components/ErrorBoundary.js.map +1 -1
- package/dist/src/tui/event-display.d.ts.map +1 -1
- package/dist/src/tui/event-display.js +36 -62
- package/dist/src/tui/event-display.js.map +1 -1
- package/dist/src/tui/index.d.ts +4 -0
- package/dist/src/tui/index.d.ts.map +1 -1
- package/dist/src/tui/index.js +17 -0
- package/dist/src/tui/index.js.map +1 -1
- package/dist/src/types.d.ts +214 -1
- package/dist/src/types.d.ts.map +1 -1
- package/package.json +18 -3
|
@@ -44,6 +44,13 @@ const DOOM_LOOP_PROMPT = (tool, count) => `[System] You've called ${tool} with t
|
|
|
44
44
|
1. Try a DIFFERENT approach or tool
|
|
45
45
|
2. If blocked, explain what's preventing progress
|
|
46
46
|
3. If the task is complete, say so explicitly`;
|
|
47
|
+
/**
|
|
48
|
+
* Global doom loop prompt - injected when the same tool call is repeated across multiple workers.
|
|
49
|
+
*/
|
|
50
|
+
const GLOBAL_DOOM_LOOP_PROMPT = (tool, workerCount, totalCalls) => `[System] GLOBAL DOOM LOOP: ${totalCalls} calls to ${tool} across ${workerCount} workers. The entire swarm is stuck on this approach.
|
|
51
|
+
1. Try a fundamentally different strategy
|
|
52
|
+
2. Do NOT retry the same tool/parameters
|
|
53
|
+
3. Consider whether the task goal itself needs re-evaluation`;
|
|
47
54
|
/**
|
|
48
55
|
* Exploration saturation prompt - gentle nudge to start making edits.
|
|
49
56
|
*/
|
|
@@ -62,6 +69,30 @@ Do not retry the same fix. Try a new approach.`;
|
|
|
62
69
|
/**
|
|
63
70
|
* Phase budget exploration exceeded prompt.
|
|
64
71
|
*/
|
|
72
|
+
/** Detect bash commands that are doing file write operations (write/append/redirect/heredoc). */
|
|
73
|
+
const BASH_FILE_WRITE_RE = /^\s*(cat|echo|printf)\b.*(?:>>?|<<)\s*/;
|
|
74
|
+
/** Check whether a bash command is attempting file operations that should use dedicated tools. */
|
|
75
|
+
function isBashFileOperation(command) {
|
|
76
|
+
return BASH_FILE_READ_RE.test(command) || BASH_FILE_WRITE_RE.test(command) || /heredoc|EOF/i.test(command);
|
|
77
|
+
}
|
|
78
|
+
const BASH_FAILURE_CASCADE_PROMPT = (failures, lastCommand) => {
|
|
79
|
+
const isFileOp = lastCommand && isBashFileOperation(lastCommand);
|
|
80
|
+
if (isFileOp) {
|
|
81
|
+
return `[System] ${failures} consecutive bash commands have failed trying to do file operations.
|
|
82
|
+
STOP using bash for file operations. Use the correct tool:
|
|
83
|
+
- To CREATE a file: write_file (not cat/echo with redirect)
|
|
84
|
+
- To MODIFY a file: edit_file (not sed/awk)
|
|
85
|
+
- To READ a file: read_file (not cat/head/tail)
|
|
86
|
+
Switch to the correct tool NOW.`;
|
|
87
|
+
}
|
|
88
|
+
return `[System] ${failures} consecutive bash commands have failed. STOP and:
|
|
89
|
+
1. Explain what you're trying to accomplish
|
|
90
|
+
2. Try a DIFFERENT approach or tool
|
|
91
|
+
3. Do not run another bash command with the same pattern`;
|
|
92
|
+
};
|
|
93
|
+
const SUMMARY_LOOP_PROMPT = `[System] You've produced text-only responses without using tools. You should be DOING work, not summarizing it.
|
|
94
|
+
Pick the most important remaining task and start working on it NOW using your tools (write_file, edit_file, bash, etc.).
|
|
95
|
+
Do NOT output another status summary or task list.`;
|
|
65
96
|
const EXPLORATION_BUDGET_EXCEEDED_PROMPT = (pct) => `[System] You've spent ${pct}% of your iterations in exploration. Start making edits NOW.
|
|
66
97
|
Do not read more files. Use what you know to make the fix.`;
|
|
67
98
|
/**
|
|
@@ -69,6 +100,41 @@ Do not read more files. Use what you know to make the fix.`;
|
|
|
69
100
|
*/
|
|
70
101
|
const VERIFICATION_RESERVE_PROMPT = `[System] You are running low on iterations. Run your tests NOW to verify your changes.
|
|
71
102
|
Do not make more edits until you've confirmed whether the current fix works.`;
|
|
103
|
+
const BUDGET_ADVISORY_PROMPT = (reason) => `[System] Budget advisory (${reason}) detected. Continue execution and focus on concrete tool actions to complete the task.`;
|
|
104
|
+
/**
|
|
105
|
+
* Extract success and output from a bash tool result.
|
|
106
|
+
* In production, bash results are objects `{ success, output, metadata }`.
|
|
107
|
+
* Tests may pass strings directly. This normalizes both.
|
|
108
|
+
*/
|
|
109
|
+
export function extractBashResult(result) {
|
|
110
|
+
if (result && typeof result === 'object') {
|
|
111
|
+
const obj = result;
|
|
112
|
+
return {
|
|
113
|
+
success: obj.success !== false,
|
|
114
|
+
output: typeof obj.output === 'string' ? obj.output : '',
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
if (typeof result === 'string') {
|
|
118
|
+
return { success: true, output: result };
|
|
119
|
+
}
|
|
120
|
+
return { success: true, output: '' };
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Regex for common bash file-read commands (simple, no pipes/redirects).
|
|
124
|
+
* Captures the file path for normalized doom loop fingerprinting.
|
|
125
|
+
*/
|
|
126
|
+
const BASH_FILE_READ_RE = /^\s*(cat|head|tail|wc|less|more|file|stat|md5sum|sha256sum)\b(?:\s+-[^\s]+)*\s+((?:\/|\.\/|\.\.\/)[\w.\/\-@]+|[\w.\-@][\w.\/\-@]*)\s*$/;
|
|
127
|
+
/**
|
|
128
|
+
* Extract the file target from a simple bash file-read command.
|
|
129
|
+
* Returns null for complex commands (pipes, redirects, non-file-read commands).
|
|
130
|
+
* Used to normalize doom loop fingerprints across cat/head/tail/wc targeting the same file.
|
|
131
|
+
*/
|
|
132
|
+
export function extractBashFileTarget(command) {
|
|
133
|
+
if (/[|;&<>]/.test(command))
|
|
134
|
+
return null; // pipes/redirects = complex, skip
|
|
135
|
+
const match = command.match(BASH_FILE_READ_RE);
|
|
136
|
+
return match ? match[2] : null;
|
|
137
|
+
}
|
|
72
138
|
/**
|
|
73
139
|
* Primary argument keys that identify the *target* of a tool call.
|
|
74
140
|
* Used for fuzzy doom loop detection — ignoring secondary/optional args.
|
|
@@ -83,6 +149,13 @@ const PRIMARY_KEYS = ['path', 'file_path', 'command', 'pattern', 'query', 'url',
|
|
|
83
149
|
export function computeToolFingerprint(toolName, argsStr) {
|
|
84
150
|
try {
|
|
85
151
|
const args = JSON.parse(argsStr || '{}');
|
|
152
|
+
// W1: Normalize bash file-read commands so cat/head/tail/wc targeting the same file
|
|
153
|
+
// produce the same fingerprint, triggering doom loop detection.
|
|
154
|
+
if (toolName === 'bash' && typeof args.command === 'string') {
|
|
155
|
+
const fileTarget = extractBashFileTarget(args.command);
|
|
156
|
+
if (fileTarget)
|
|
157
|
+
return `bash:file_read:${fileTarget}`;
|
|
158
|
+
}
|
|
86
159
|
const primaryArgs = {};
|
|
87
160
|
for (const key of PRIMARY_KEYS) {
|
|
88
161
|
if (key in args) {
|
|
@@ -115,8 +188,17 @@ export class ExecutionEconomicsManager {
|
|
|
115
188
|
pauseStart = null;
|
|
116
189
|
listeners = [];
|
|
117
190
|
extensionHandler;
|
|
118
|
-
|
|
191
|
+
// Shared economics state for cross-worker doom loop aggregation
|
|
192
|
+
sharedEconomics;
|
|
193
|
+
workerId;
|
|
194
|
+
// Adaptive budget: stores original maxIterations for reversible reduction
|
|
195
|
+
originalMaxIterations = null;
|
|
196
|
+
constructor(budget, sharedEconomics, workerId) {
|
|
197
|
+
this.sharedEconomics = sharedEconomics ?? null;
|
|
198
|
+
this.workerId = workerId ?? 'root';
|
|
199
|
+
const tuning = budget?.tuning;
|
|
119
200
|
this.budget = {
|
|
201
|
+
enforcementMode: budget?.enforcementMode ?? 'strict',
|
|
120
202
|
// Hard limits
|
|
121
203
|
maxTokens: budget?.maxTokens ?? 200000,
|
|
122
204
|
maxCost: budget?.maxCost ?? 1.00,
|
|
@@ -128,6 +210,8 @@ export class ExecutionEconomicsManager {
|
|
|
128
210
|
// Iteration guidance
|
|
129
211
|
targetIterations: budget?.targetIterations ?? 20,
|
|
130
212
|
maxIterations: budget?.maxIterations ?? 100,
|
|
213
|
+
// Tuning
|
|
214
|
+
tuning,
|
|
131
215
|
};
|
|
132
216
|
this.usage = {
|
|
133
217
|
tokens: 0,
|
|
@@ -147,13 +231,13 @@ export class ExecutionEconomicsManager {
|
|
|
147
231
|
lastMeaningfulProgress: Date.now(),
|
|
148
232
|
stuckCount: 0,
|
|
149
233
|
};
|
|
150
|
-
// Initialize doom loop detection state
|
|
234
|
+
// Initialize doom loop detection state (thresholds configurable via tuning)
|
|
151
235
|
this.loopState = {
|
|
152
236
|
doomLoopDetected: false,
|
|
153
237
|
lastTool: null,
|
|
154
238
|
consecutiveCount: 0,
|
|
155
|
-
threshold: 3,
|
|
156
|
-
fuzzyThreshold: 4,
|
|
239
|
+
threshold: tuning?.doomLoopThreshold ?? 3,
|
|
240
|
+
fuzzyThreshold: tuning?.doomLoopFuzzyThreshold ?? (tuning?.doomLoopThreshold ? tuning.doomLoopThreshold + 1 : 4),
|
|
157
241
|
lastWarningTime: 0,
|
|
158
242
|
};
|
|
159
243
|
// Initialize phase tracking state
|
|
@@ -170,6 +254,8 @@ export class ExecutionEconomicsManager {
|
|
|
170
254
|
lastTestPassed: null,
|
|
171
255
|
consecutiveTestFailures: 0,
|
|
172
256
|
inTestFixCycle: false,
|
|
257
|
+
consecutiveBashFailures: 0,
|
|
258
|
+
consecutiveTextOnlyTurns: 0,
|
|
173
259
|
};
|
|
174
260
|
this.startTime = Date.now();
|
|
175
261
|
}
|
|
@@ -235,12 +321,21 @@ export class ExecutionEconomicsManager {
|
|
|
235
321
|
// Update duration
|
|
236
322
|
this.usage.duration = this.getEffectiveDuration();
|
|
237
323
|
}
|
|
324
|
+
/**
|
|
325
|
+
* Record a text-only turn (LLM response with no tool calls).
|
|
326
|
+
* Increments the consecutive text-only turn counter for summary-loop detection.
|
|
327
|
+
*/
|
|
328
|
+
recordTextOnlyTurn() {
|
|
329
|
+
this.phaseState.consecutiveTextOnlyTurns++;
|
|
330
|
+
}
|
|
238
331
|
/**
|
|
239
332
|
* Record a tool call for progress tracking and loop detection.
|
|
240
333
|
*/
|
|
241
334
|
recordToolCall(toolName, args, _result) {
|
|
242
335
|
this.usage.toolCalls++;
|
|
243
336
|
this.usage.iterations++;
|
|
337
|
+
// Any tool call resets the text-only turn counter
|
|
338
|
+
this.phaseState.consecutiveTextOnlyTurns = 0;
|
|
244
339
|
const now = Date.now();
|
|
245
340
|
// Track for loop detection (stableStringify ensures consistent ordering for comparison)
|
|
246
341
|
const argsStr = stableStringify(args);
|
|
@@ -253,6 +348,11 @@ export class ExecutionEconomicsManager {
|
|
|
253
348
|
// DOOM LOOP DETECTION (OpenCode pattern)
|
|
254
349
|
// =========================================================================
|
|
255
350
|
this.updateDoomLoopState(toolName, argsStr);
|
|
351
|
+
// Report to shared economics for cross-worker doom loop aggregation
|
|
352
|
+
if (this.sharedEconomics) {
|
|
353
|
+
const fingerprint = computeToolFingerprint(toolName, argsStr);
|
|
354
|
+
this.sharedEconomics.recordToolCall(this.workerId, fingerprint);
|
|
355
|
+
}
|
|
256
356
|
// =========================================================================
|
|
257
357
|
// PHASE TRACKING
|
|
258
358
|
// =========================================================================
|
|
@@ -293,6 +393,17 @@ export class ExecutionEconomicsManager {
|
|
|
293
393
|
this.progress.commandsRun.push(command);
|
|
294
394
|
this.progress.lastMeaningfulProgress = now;
|
|
295
395
|
this.progress.stuckCount = 0;
|
|
396
|
+
// Extract result from bash tool output (object or string)
|
|
397
|
+
const bashResult = extractBashResult(_result);
|
|
398
|
+
// Track consecutive bash failures (any bash command, not just tests)
|
|
399
|
+
if (_result !== undefined) {
|
|
400
|
+
if (!bashResult.success) {
|
|
401
|
+
this.phaseState.consecutiveBashFailures++;
|
|
402
|
+
}
|
|
403
|
+
else {
|
|
404
|
+
this.phaseState.consecutiveBashFailures = 0;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
296
407
|
// Detect test runs and track outcomes
|
|
297
408
|
if (command.includes('test') || command.includes('pytest') || command.includes('npm test') || command.includes('jest')) {
|
|
298
409
|
this.phaseState.testsRun++;
|
|
@@ -300,10 +411,9 @@ export class ExecutionEconomicsManager {
|
|
|
300
411
|
if (this.phaseState.phase === 'acting' && this.phaseState.filesModified.size > 0) {
|
|
301
412
|
this.transitionPhase('verifying', 'Tests run after edits');
|
|
302
413
|
}
|
|
303
|
-
//
|
|
304
|
-
if (
|
|
305
|
-
|
|
306
|
-
this.parseTestOutcome(command, resultStr);
|
|
414
|
+
// Fix: extract output from result object, not treat as string
|
|
415
|
+
if (bashResult.output) {
|
|
416
|
+
this.parseTestOutcome(command, bashResult.output);
|
|
307
417
|
}
|
|
308
418
|
}
|
|
309
419
|
}
|
|
@@ -416,8 +526,9 @@ export class ExecutionEconomicsManager {
|
|
|
416
526
|
this.phaseState.shouldTransition = false;
|
|
417
527
|
return;
|
|
418
528
|
}
|
|
419
|
-
// After
|
|
420
|
-
|
|
529
|
+
// After N+ unique files without edits, suggest transition (configurable, default: 10)
|
|
530
|
+
const fileThreshold = this.budget.tuning?.explorationFileThreshold ?? 10;
|
|
531
|
+
if (uniqueFilesRead.size >= fileThreshold && filesModified.size === 0) {
|
|
421
532
|
this.phaseState.shouldTransition = true;
|
|
422
533
|
this.emit({
|
|
423
534
|
type: 'exploration.saturation',
|
|
@@ -426,8 +537,9 @@ export class ExecutionEconomicsManager {
|
|
|
426
537
|
});
|
|
427
538
|
return;
|
|
428
539
|
}
|
|
429
|
-
// After
|
|
430
|
-
|
|
540
|
+
// After N+ iterations in exploration with diminishing returns (configurable, default: 15)
|
|
541
|
+
const iterThreshold = this.budget.tuning?.explorationIterThreshold ?? 15;
|
|
542
|
+
if (iterationsInPhase >= iterThreshold && recentNewFiles < 2 && filesModified.size === 0) {
|
|
431
543
|
this.phaseState.shouldTransition = true;
|
|
432
544
|
this.emit({
|
|
433
545
|
type: 'exploration.saturation',
|
|
@@ -443,9 +555,22 @@ export class ExecutionEconomicsManager {
|
|
|
443
555
|
*/
|
|
444
556
|
checkBudget() {
|
|
445
557
|
this.usage.duration = this.getEffectiveDuration();
|
|
558
|
+
const strictBudgetEnforcement = (this.budget.enforcementMode ?? 'strict') === 'strict';
|
|
446
559
|
// Check hard limits first
|
|
447
560
|
if (this.usage.tokens >= this.budget.maxTokens) {
|
|
448
561
|
this.emit({ type: 'budget.exceeded', budgetType: 'tokens', limit: this.budget.maxTokens, actual: this.usage.tokens });
|
|
562
|
+
if (!strictBudgetEnforcement) {
|
|
563
|
+
return {
|
|
564
|
+
canContinue: true,
|
|
565
|
+
reason: `Token budget exceeded (${this.usage.tokens.toLocaleString()} / ${this.budget.maxTokens.toLocaleString()})`,
|
|
566
|
+
budgetType: 'tokens',
|
|
567
|
+
isHardLimit: false,
|
|
568
|
+
isSoftLimit: true,
|
|
569
|
+
percentUsed: (this.usage.tokens / this.budget.maxTokens) * 100,
|
|
570
|
+
suggestedAction: 'warn',
|
|
571
|
+
injectedPrompt: BUDGET_ADVISORY_PROMPT('tokens'),
|
|
572
|
+
};
|
|
573
|
+
}
|
|
449
574
|
return {
|
|
450
575
|
canContinue: false,
|
|
451
576
|
reason: `Token budget exceeded (${this.usage.tokens.toLocaleString()} / ${this.budget.maxTokens.toLocaleString()})`,
|
|
@@ -458,6 +583,18 @@ export class ExecutionEconomicsManager {
|
|
|
458
583
|
}
|
|
459
584
|
if (this.usage.cost >= this.budget.maxCost) {
|
|
460
585
|
this.emit({ type: 'budget.exceeded', budgetType: 'cost', limit: this.budget.maxCost, actual: this.usage.cost });
|
|
586
|
+
if (!strictBudgetEnforcement) {
|
|
587
|
+
return {
|
|
588
|
+
canContinue: true,
|
|
589
|
+
reason: `Cost budget exceeded ($${this.usage.cost.toFixed(2)} / $${this.budget.maxCost.toFixed(2)})`,
|
|
590
|
+
budgetType: 'cost',
|
|
591
|
+
isHardLimit: false,
|
|
592
|
+
isSoftLimit: true,
|
|
593
|
+
percentUsed: (this.usage.cost / this.budget.maxCost) * 100,
|
|
594
|
+
suggestedAction: 'warn',
|
|
595
|
+
injectedPrompt: BUDGET_ADVISORY_PROMPT('cost'),
|
|
596
|
+
};
|
|
597
|
+
}
|
|
461
598
|
return {
|
|
462
599
|
canContinue: false,
|
|
463
600
|
reason: `Cost budget exceeded ($${this.usage.cost.toFixed(2)} / $${this.budget.maxCost.toFixed(2)})`,
|
|
@@ -470,6 +607,18 @@ export class ExecutionEconomicsManager {
|
|
|
470
607
|
}
|
|
471
608
|
if (this.usage.duration >= this.budget.maxDuration) {
|
|
472
609
|
this.emit({ type: 'budget.exceeded', budgetType: 'duration', limit: this.budget.maxDuration, actual: this.usage.duration });
|
|
610
|
+
if (!strictBudgetEnforcement) {
|
|
611
|
+
return {
|
|
612
|
+
canContinue: true,
|
|
613
|
+
reason: `Duration limit exceeded (${Math.round(this.usage.duration / 1000)}s / ${Math.round(this.budget.maxDuration / 1000)}s)`,
|
|
614
|
+
budgetType: 'duration',
|
|
615
|
+
isHardLimit: false,
|
|
616
|
+
isSoftLimit: true,
|
|
617
|
+
percentUsed: (this.usage.duration / this.budget.maxDuration) * 100,
|
|
618
|
+
suggestedAction: 'warn',
|
|
619
|
+
injectedPrompt: BUDGET_ADVISORY_PROMPT('duration'),
|
|
620
|
+
};
|
|
621
|
+
}
|
|
473
622
|
return {
|
|
474
623
|
canContinue: false,
|
|
475
624
|
reason: `Duration limit exceeded (${Math.round(this.usage.duration / 1000)}s / ${Math.round(this.budget.maxDuration / 1000)}s)`,
|
|
@@ -480,10 +629,13 @@ export class ExecutionEconomicsManager {
|
|
|
480
629
|
suggestedAction: 'stop',
|
|
481
630
|
};
|
|
482
631
|
}
|
|
483
|
-
// Max iterations reached
|
|
632
|
+
// Max iterations reached — allow exactly ONE more turn for summary, then terminate.
|
|
633
|
+
// First time at maxIterations: canContinue=true + forceTextOnly for a clean summary.
|
|
634
|
+
// Beyond maxIterations: canContinue=false to stop the loop.
|
|
484
635
|
if (this.usage.iterations >= this.budget.maxIterations) {
|
|
636
|
+
const isFirstOverage = this.usage.iterations === this.budget.maxIterations;
|
|
485
637
|
return {
|
|
486
|
-
canContinue:
|
|
638
|
+
canContinue: isFirstOverage, // Only allow one summary turn
|
|
487
639
|
reason: `Maximum iterations reached (${this.usage.iterations} / ${this.budget.maxIterations})`,
|
|
488
640
|
budgetType: 'iterations',
|
|
489
641
|
isHardLimit: true,
|
|
@@ -495,6 +647,50 @@ export class ExecutionEconomicsManager {
|
|
|
495
647
|
};
|
|
496
648
|
}
|
|
497
649
|
// =========================================================================
|
|
650
|
+
// ZERO PROGRESS DETECTION — nudge workers making no tool calls (D1)
|
|
651
|
+
// Raised threshold to 10 (from 5) to give agents more time to plan.
|
|
652
|
+
// No longer forces text-only — instead injects a strong nudge while
|
|
653
|
+
// still allowing tool calls so the agent can recover.
|
|
654
|
+
// =========================================================================
|
|
655
|
+
const zeroProgressThreshold = this.budget.tuning?.zeroProgressThreshold ?? 10;
|
|
656
|
+
if (this.usage.iterations >= zeroProgressThreshold && this.usage.toolCalls === 0) {
|
|
657
|
+
// Only force text-only after 2x the threshold (complete stall)
|
|
658
|
+
const isCompleteStall = this.usage.iterations >= zeroProgressThreshold * 2;
|
|
659
|
+
return {
|
|
660
|
+
canContinue: true,
|
|
661
|
+
reason: `Zero tool calls in ${this.usage.iterations} iterations`,
|
|
662
|
+
budgetType: 'iterations',
|
|
663
|
+
isHardLimit: false,
|
|
664
|
+
isSoftLimit: true,
|
|
665
|
+
percentUsed: (this.usage.iterations / this.budget.maxIterations) * 100,
|
|
666
|
+
suggestedAction: isCompleteStall ? 'stop' : 'warn',
|
|
667
|
+
forceTextOnly: isCompleteStall,
|
|
668
|
+
injectedPrompt: `[System] WARNING: You have completed ${this.usage.iterations} iterations without making a single tool call. ` +
|
|
669
|
+
`You MUST use your tools (read_file, write_file, grep, bash, etc.) to accomplish your task. ` +
|
|
670
|
+
`Start by reading a relevant file or running a command NOW.` +
|
|
671
|
+
(isCompleteStall ? ` This is your LAST chance — respond with a summary if you cannot proceed.` : ''),
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
// =========================================================================
|
|
675
|
+
// ADAPTIVE ITERATION BUDGET — reversible reduction at checkpoint (D4)
|
|
676
|
+
// Stores original maxIterations so it can be restored if tools resume.
|
|
677
|
+
// =========================================================================
|
|
678
|
+
const checkpoint = this.budget.tuning?.progressCheckpoint ?? 10;
|
|
679
|
+
if (this.usage.iterations === checkpoint && this.usage.toolCalls === 0) {
|
|
680
|
+
if (!this.originalMaxIterations) {
|
|
681
|
+
this.originalMaxIterations = this.budget.maxIterations;
|
|
682
|
+
}
|
|
683
|
+
const reducedMax = checkpoint + 5; // give 5 more iterations (up from 3)
|
|
684
|
+
if (this.budget.maxIterations > reducedMax) {
|
|
685
|
+
this.budget.maxIterations = reducedMax;
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
// Restore original maxIterations if tools start being used after reduction
|
|
689
|
+
if (this.originalMaxIterations && this.usage.toolCalls > 0 && this.budget.maxIterations < this.originalMaxIterations) {
|
|
690
|
+
this.budget.maxIterations = this.originalMaxIterations;
|
|
691
|
+
this.originalMaxIterations = null;
|
|
692
|
+
}
|
|
693
|
+
// =========================================================================
|
|
498
694
|
// DOOM LOOP DETECTION - Strong intervention
|
|
499
695
|
// =========================================================================
|
|
500
696
|
if (this.loopState.doomLoopDetected) {
|
|
@@ -510,6 +706,26 @@ export class ExecutionEconomicsManager {
|
|
|
510
706
|
};
|
|
511
707
|
}
|
|
512
708
|
// =========================================================================
|
|
709
|
+
// GLOBAL DOOM LOOP DETECTION - Cross-worker stuck pattern
|
|
710
|
+
// =========================================================================
|
|
711
|
+
if (this.sharedEconomics && this.progress.recentToolCalls.length > 0) {
|
|
712
|
+
const lastCall = this.progress.recentToolCalls[this.progress.recentToolCalls.length - 1];
|
|
713
|
+
const fingerprint = computeToolFingerprint(lastCall.tool, lastCall.args);
|
|
714
|
+
if (this.sharedEconomics.isGlobalDoomLoop(fingerprint)) {
|
|
715
|
+
const info = this.sharedEconomics.getGlobalLoopInfo(fingerprint);
|
|
716
|
+
return {
|
|
717
|
+
canContinue: true,
|
|
718
|
+
reason: `Global doom loop: ${lastCall.tool} repeated across ${info?.workerCount ?? 0} workers`,
|
|
719
|
+
budgetType: 'iterations',
|
|
720
|
+
isHardLimit: false,
|
|
721
|
+
isSoftLimit: true,
|
|
722
|
+
percentUsed: (this.usage.iterations / this.budget.targetIterations) * 100,
|
|
723
|
+
suggestedAction: 'warn',
|
|
724
|
+
injectedPrompt: GLOBAL_DOOM_LOOP_PROMPT(lastCall.tool, info?.workerCount ?? 0, info?.count ?? 0),
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
// =========================================================================
|
|
513
729
|
// EXPLORATION SATURATION - Gentle nudge
|
|
514
730
|
// =========================================================================
|
|
515
731
|
if (this.phaseState.shouldTransition) {
|
|
@@ -540,6 +756,54 @@ export class ExecutionEconomicsManager {
|
|
|
540
756
|
};
|
|
541
757
|
}
|
|
542
758
|
// =========================================================================
|
|
759
|
+
// BASH FAILURE CASCADE - Strong intervention after 3+ consecutive failures
|
|
760
|
+
// =========================================================================
|
|
761
|
+
if (this.phaseState.consecutiveBashFailures >= 3) {
|
|
762
|
+
// Extract last bash command for tool-aware remediation
|
|
763
|
+
let lastBashCommand;
|
|
764
|
+
for (let i = this.progress.recentToolCalls.length - 1; i >= 0; i--) {
|
|
765
|
+
if (this.progress.recentToolCalls[i].tool === 'bash') {
|
|
766
|
+
try {
|
|
767
|
+
const parsed = JSON.parse(this.progress.recentToolCalls[i].args);
|
|
768
|
+
lastBashCommand = parsed.command;
|
|
769
|
+
}
|
|
770
|
+
catch { /* ignore parse errors */ }
|
|
771
|
+
break;
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
return {
|
|
775
|
+
canContinue: true,
|
|
776
|
+
reason: `${this.phaseState.consecutiveBashFailures} consecutive bash failures`,
|
|
777
|
+
budgetType: 'iterations',
|
|
778
|
+
isHardLimit: false,
|
|
779
|
+
isSoftLimit: true,
|
|
780
|
+
percentUsed: (this.usage.iterations / this.budget.targetIterations) * 100,
|
|
781
|
+
suggestedAction: 'warn',
|
|
782
|
+
injectedPrompt: BASH_FAILURE_CASCADE_PROMPT(this.phaseState.consecutiveBashFailures, lastBashCommand),
|
|
783
|
+
};
|
|
784
|
+
}
|
|
785
|
+
// =========================================================================
|
|
786
|
+
// SUMMARY LOOP DETECTION - Nudge after 2+ consecutive text-only turns
|
|
787
|
+
// Skip when close to budget limit — the agent can't "start working" if
|
|
788
|
+
// forceTextOnly would be set on the next check (contradictory nudge).
|
|
789
|
+
// =========================================================================
|
|
790
|
+
if (this.phaseState.consecutiveTextOnlyTurns >= 2) {
|
|
791
|
+
const nearBudgetLimit = this.usage.iterations >= this.budget.maxIterations - 1;
|
|
792
|
+
if (!nearBudgetLimit) {
|
|
793
|
+
return {
|
|
794
|
+
canContinue: true,
|
|
795
|
+
reason: `${this.phaseState.consecutiveTextOnlyTurns} consecutive text-only turns (summary loop)`,
|
|
796
|
+
budgetType: 'iterations',
|
|
797
|
+
isHardLimit: false,
|
|
798
|
+
isSoftLimit: true,
|
|
799
|
+
percentUsed: (this.usage.iterations / this.budget.targetIterations) * 100,
|
|
800
|
+
suggestedAction: 'warn',
|
|
801
|
+
injectedPrompt: SUMMARY_LOOP_PROMPT,
|
|
802
|
+
};
|
|
803
|
+
}
|
|
804
|
+
// Near budget limit: skip nudge, let MAX_STEPS_PROMPT handle it next turn
|
|
805
|
+
}
|
|
806
|
+
// =========================================================================
|
|
543
807
|
// PHASE-AWARE BUDGET ALLOCATION (opt-in, used in eval mode)
|
|
544
808
|
// =========================================================================
|
|
545
809
|
if (this.phaseBudget?.enabled) {
|
|
@@ -716,7 +980,9 @@ export class ExecutionEconomicsManager {
|
|
|
716
980
|
const budget = this.budget;
|
|
717
981
|
const tokenPct = Math.round((usage.tokens / budget.maxTokens) * 100);
|
|
718
982
|
const remainingTokens = budget.maxTokens - usage.tokens;
|
|
719
|
-
const remainingSec =
|
|
983
|
+
const remainingSec = budget.maxDuration === Infinity
|
|
984
|
+
? Infinity
|
|
985
|
+
: Math.max(0, Math.round((budget.maxDuration - usage.duration) / 1000));
|
|
720
986
|
// Determine urgency level
|
|
721
987
|
let urgency = '';
|
|
722
988
|
if (tokenPct >= 90) {
|
|
@@ -725,7 +991,8 @@ export class ExecutionEconomicsManager {
|
|
|
725
991
|
else if (tokenPct >= 70) {
|
|
726
992
|
urgency = '⚡ WARNING: ';
|
|
727
993
|
}
|
|
728
|
-
|
|
994
|
+
const timeStr = remainingSec === Infinity ? 'no time limit' : `~${remainingSec}s remaining`;
|
|
995
|
+
return `${urgency}Budget: ${usage.tokens.toLocaleString()}/${budget.maxTokens.toLocaleString()} tokens (${tokenPct}%), ${timeStr}. ${tokenPct >= 70 ? 'Wrap up soon!' : ''}`.trim();
|
|
729
996
|
}
|
|
730
997
|
/**
|
|
731
998
|
* Check if approaching budget limit (for proactive warnings).
|
|
@@ -755,6 +1022,12 @@ export class ExecutionEconomicsManager {
|
|
|
755
1022
|
stuckCount: this.progress.stuckCount,
|
|
756
1023
|
};
|
|
757
1024
|
}
|
|
1025
|
+
/**
|
|
1026
|
+
* Get actual file paths modified during this session.
|
|
1027
|
+
*/
|
|
1028
|
+
getModifiedFilePaths() {
|
|
1029
|
+
return [...this.progress.filesModified];
|
|
1030
|
+
}
|
|
758
1031
|
/**
|
|
759
1032
|
* Get doom loop detection state.
|
|
760
1033
|
*/
|
|
@@ -776,6 +1049,7 @@ export class ExecutionEconomicsManager {
|
|
|
776
1049
|
lastTestPassed: this.phaseState.lastTestPassed,
|
|
777
1050
|
consecutiveTestFailures: this.phaseState.consecutiveTestFailures,
|
|
778
1051
|
inTestFixCycle: this.phaseState.inTestFixCycle,
|
|
1052
|
+
consecutiveBashFailures: this.phaseState.consecutiveBashFailures,
|
|
779
1053
|
};
|
|
780
1054
|
}
|
|
781
1055
|
/**
|
|
@@ -811,13 +1085,14 @@ export class ExecutionEconomicsManager {
|
|
|
811
1085
|
lastMeaningfulProgress: Date.now(),
|
|
812
1086
|
stuckCount: 0,
|
|
813
1087
|
};
|
|
814
|
-
// Reset loop detection state
|
|
1088
|
+
// Reset loop detection state (preserve tuning thresholds)
|
|
1089
|
+
const tuning = this.budget.tuning;
|
|
815
1090
|
this.loopState = {
|
|
816
1091
|
doomLoopDetected: false,
|
|
817
1092
|
lastTool: null,
|
|
818
1093
|
consecutiveCount: 0,
|
|
819
|
-
threshold: 3,
|
|
820
|
-
fuzzyThreshold: 4,
|
|
1094
|
+
threshold: tuning?.doomLoopThreshold ?? 3,
|
|
1095
|
+
fuzzyThreshold: tuning?.doomLoopFuzzyThreshold ?? (tuning?.doomLoopThreshold ? tuning.doomLoopThreshold + 1 : 4),
|
|
821
1096
|
lastWarningTime: 0,
|
|
822
1097
|
};
|
|
823
1098
|
// Reset phase tracking state
|
|
@@ -834,10 +1109,13 @@ export class ExecutionEconomicsManager {
|
|
|
834
1109
|
lastTestPassed: null,
|
|
835
1110
|
consecutiveTestFailures: 0,
|
|
836
1111
|
inTestFixCycle: false,
|
|
1112
|
+
consecutiveBashFailures: 0,
|
|
1113
|
+
consecutiveTextOnlyTurns: 0,
|
|
837
1114
|
};
|
|
838
1115
|
this.startTime = Date.now();
|
|
839
1116
|
this.pausedDuration = 0;
|
|
840
1117
|
this.pauseStart = null;
|
|
1118
|
+
this.originalMaxIterations = null;
|
|
841
1119
|
}
|
|
842
1120
|
// -------------------------------------------------------------------------
|
|
843
1121
|
// PRIVATE METHODS
|
|
@@ -938,13 +1216,13 @@ export const STANDARD_BUDGET = {
|
|
|
938
1216
|
* and other parallel subagents.
|
|
939
1217
|
*/
|
|
940
1218
|
export const SUBAGENT_BUDGET = {
|
|
941
|
-
maxTokens:
|
|
942
|
-
softTokenLimit:
|
|
943
|
-
maxCost: 0.
|
|
944
|
-
maxDuration:
|
|
945
|
-
softDurationLimit:
|
|
946
|
-
targetIterations:
|
|
947
|
-
maxIterations:
|
|
1219
|
+
maxTokens: 250000, // 250k tokens — coders need room for explore + code
|
|
1220
|
+
softTokenLimit: 180000, // Warn at 180k
|
|
1221
|
+
maxCost: 0.75, // Increased ceiling for heavier workloads
|
|
1222
|
+
maxDuration: 480000, // 8 minutes
|
|
1223
|
+
softDurationLimit: 420000, // Warn at 7 minutes
|
|
1224
|
+
targetIterations: 30,
|
|
1225
|
+
maxIterations: 60,
|
|
948
1226
|
};
|
|
949
1227
|
/**
|
|
950
1228
|
* Large task budget - for complex multi-step tasks.
|
|
@@ -956,6 +1234,23 @@ export const LARGE_BUDGET = {
|
|
|
956
1234
|
targetIterations: 50,
|
|
957
1235
|
maxIterations: 200,
|
|
958
1236
|
};
|
|
1237
|
+
/**
|
|
1238
|
+
* TUI root agent budget - no time limit, high iteration cap.
|
|
1239
|
+
* The TUI root agent must be able to run as long as needed (swarm tasks,
|
|
1240
|
+
* multi-step workflows). Duration is effectively unlimited; token/cost
|
|
1241
|
+
* limits still apply as a safety net.
|
|
1242
|
+
*/
|
|
1243
|
+
export const TUI_ROOT_BUDGET = {
|
|
1244
|
+
enforcementMode: 'doomloop_only',
|
|
1245
|
+
maxTokens: 500000,
|
|
1246
|
+
softTokenLimit: 400000,
|
|
1247
|
+
maxCost: 5.00,
|
|
1248
|
+
softCostLimit: 4.00,
|
|
1249
|
+
maxDuration: Infinity, // No time limit — run as long as tasks remain
|
|
1250
|
+
softDurationLimit: Infinity,
|
|
1251
|
+
targetIterations: 100,
|
|
1252
|
+
maxIterations: 500,
|
|
1253
|
+
};
|
|
959
1254
|
/**
|
|
960
1255
|
* Unlimited budget - no limits (use with caution).
|
|
961
1256
|
*/
|
|
@@ -971,13 +1266,13 @@ export const UNLIMITED_BUDGET = {
|
|
|
971
1266
|
* Each worker gets a small slice of the total swarm budget.
|
|
972
1267
|
*/
|
|
973
1268
|
export const SWARM_WORKER_BUDGET = {
|
|
974
|
-
maxTokens:
|
|
975
|
-
softTokenLimit:
|
|
976
|
-
maxCost: 0.
|
|
977
|
-
maxDuration:
|
|
978
|
-
softDurationLimit:
|
|
979
|
-
targetIterations:
|
|
980
|
-
maxIterations:
|
|
1269
|
+
maxTokens: 30000,
|
|
1270
|
+
softTokenLimit: 25000,
|
|
1271
|
+
maxCost: 0.08,
|
|
1272
|
+
maxDuration: 180000, // 3 minutes
|
|
1273
|
+
softDurationLimit: 150000, // Warn at 2.5 min
|
|
1274
|
+
targetIterations: 15,
|
|
1275
|
+
maxIterations: 25,
|
|
981
1276
|
};
|
|
982
1277
|
/**
|
|
983
1278
|
* Swarm orchestrator budget - moderate budget for decomposition and quality gates.
|