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
|
@@ -108,11 +108,10 @@ export class SmartDecomposer {
|
|
|
108
108
|
continue;
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
|
-
// Both attempts failed →
|
|
112
|
-
this.emit({ type: 'llm.fallback', reason: 'LLM failed after 2 attempts', task });
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
strategy = heuristicResult.strategy;
|
|
111
|
+
// Both attempts failed → return empty so orchestrator can try lastResortDecompose
|
|
112
|
+
this.emit({ type: 'llm.fallback', reason: 'LLM failed after 2 attempts — skipping heuristic', task });
|
|
113
|
+
subtasks = [];
|
|
114
|
+
strategy = 'adaptive';
|
|
116
115
|
llmAssisted = false;
|
|
117
116
|
}
|
|
118
117
|
}
|
|
@@ -180,6 +179,9 @@ export class SmartDecomposer {
|
|
|
180
179
|
idMap.set(`task-${index}`, id);
|
|
181
180
|
idMap.set(`subtask-${index}`, id);
|
|
182
181
|
idMap.set(`st-${index}`, id);
|
|
182
|
+
// F14: Populate modifies/reads from relevantFiles so downstream consumers
|
|
183
|
+
// (F12 hollow retry prompts, quality gate) get concrete file targets.
|
|
184
|
+
const isModifyType = ['implement', 'fix', 'refactor', 'integrate', 'test', 'deploy'].includes(s.type);
|
|
183
185
|
return {
|
|
184
186
|
id,
|
|
185
187
|
description: s.description,
|
|
@@ -189,6 +191,8 @@ export class SmartDecomposer {
|
|
|
189
191
|
type: s.type,
|
|
190
192
|
parallelizable: s.parallelizable,
|
|
191
193
|
relevantFiles: s.relevantFiles,
|
|
194
|
+
modifies: isModifyType ? s.relevantFiles : undefined,
|
|
195
|
+
reads: s.relevantFiles,
|
|
192
196
|
suggestedRole: s.suggestedRole,
|
|
193
197
|
};
|
|
194
198
|
});
|
|
@@ -671,7 +675,14 @@ export class SmartDecomposer {
|
|
|
671
675
|
}
|
|
672
676
|
}
|
|
673
677
|
if (group.length === 0) {
|
|
674
|
-
// No progress
|
|
678
|
+
// No progress — circular dependency detected.
|
|
679
|
+
// Force remaining tasks into sequential single-task groups
|
|
680
|
+
// so they still reach the task queue instead of silently vanishing.
|
|
681
|
+
for (const id of remaining) {
|
|
682
|
+
groups.push([id]);
|
|
683
|
+
completed.add(id);
|
|
684
|
+
}
|
|
685
|
+
remaining.clear();
|
|
675
686
|
break;
|
|
676
687
|
}
|
|
677
688
|
groups.push(group);
|
|
@@ -789,6 +800,73 @@ export class SmartDecomposer {
|
|
|
789
800
|
}
|
|
790
801
|
}
|
|
791
802
|
}
|
|
803
|
+
/**
|
|
804
|
+
* F5: Validate a decomposition result for structural correctness, feasibility, and granularity.
|
|
805
|
+
*
|
|
806
|
+
* Checks:
|
|
807
|
+
* 1. Structural: no cycles, valid dependency refs, each subtask has description
|
|
808
|
+
* 2. Feasibility: referenced files exist (warning only)
|
|
809
|
+
* 3. Granularity: no subtask complexity > 7 (should split further)
|
|
810
|
+
*/
|
|
811
|
+
export function validateDecomposition(result) {
|
|
812
|
+
const issues = [];
|
|
813
|
+
const warnings = [];
|
|
814
|
+
const taskIds = new Set(result.subtasks.map(s => s.id));
|
|
815
|
+
// 1. Structural checks
|
|
816
|
+
// Cycle detection
|
|
817
|
+
if (result.dependencyGraph.cycles.length > 0) {
|
|
818
|
+
for (const cycle of result.dependencyGraph.cycles) {
|
|
819
|
+
issues.push(`Dependency cycle detected: ${cycle.join(' → ')}`);
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
// Valid dependency references
|
|
823
|
+
for (const subtask of result.subtasks) {
|
|
824
|
+
for (const dep of subtask.dependencies) {
|
|
825
|
+
if (!taskIds.has(dep)) {
|
|
826
|
+
issues.push(`Task ${subtask.id} references non-existent dependency: ${dep}`);
|
|
827
|
+
}
|
|
828
|
+
if (dep === subtask.id) {
|
|
829
|
+
issues.push(`Task ${subtask.id} depends on itself`);
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
// Each subtask must have a meaningful description
|
|
833
|
+
if (!subtask.description || subtask.description.trim().length < 5) {
|
|
834
|
+
issues.push(`Task ${subtask.id} has empty or trivial description`);
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
// 2. Feasibility: check if referenced files exist (warnings only — files may be created by earlier tasks)
|
|
838
|
+
for (const subtask of result.subtasks) {
|
|
839
|
+
if (subtask.relevantFiles) {
|
|
840
|
+
for (const file of subtask.relevantFiles) {
|
|
841
|
+
try {
|
|
842
|
+
const fs = require('node:fs');
|
|
843
|
+
const path = require('node:path');
|
|
844
|
+
if (!fs.existsSync(path.resolve(file))) {
|
|
845
|
+
warnings.push(`Task ${subtask.id} references non-existent file: ${file}`);
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
catch {
|
|
849
|
+
// Can't check — skip
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
// 3. Granularity: flag overly complex subtasks
|
|
855
|
+
for (const subtask of result.subtasks) {
|
|
856
|
+
if (subtask.complexity > 7) {
|
|
857
|
+
warnings.push(`Task ${subtask.id} has complexity ${subtask.complexity} (>7) — consider splitting further`);
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
// Additional structural check: at least 2 subtasks
|
|
861
|
+
if (result.subtasks.length < 2) {
|
|
862
|
+
issues.push(`Decomposition produced only ${result.subtasks.length} subtask(s) — too few for swarm mode`);
|
|
863
|
+
}
|
|
864
|
+
return {
|
|
865
|
+
valid: issues.length === 0,
|
|
866
|
+
issues,
|
|
867
|
+
warnings,
|
|
868
|
+
};
|
|
869
|
+
}
|
|
792
870
|
// =============================================================================
|
|
793
871
|
// FACTORY FUNCTIONS
|
|
794
872
|
// =============================================================================
|
|
@@ -854,37 +932,415 @@ export function createDecompositionPrompt(task, context) {
|
|
|
854
932
|
return parts.join('\n');
|
|
855
933
|
}
|
|
856
934
|
/**
|
|
857
|
-
*
|
|
935
|
+
* Normalize a raw subtask object from JSON into a consistent shape.
|
|
858
936
|
*/
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
937
|
+
function normalizeSubtask(s) {
|
|
938
|
+
return {
|
|
939
|
+
description: s.description || s.desc || s.title || s.name || '',
|
|
940
|
+
type: s.type || s.task_type || s.category || 'implement',
|
|
941
|
+
complexity: s.complexity || s.difficulty || 3,
|
|
942
|
+
dependencies: s.dependencies || s.deps || s.depends_on || [],
|
|
943
|
+
parallelizable: s.parallelizable ?? s.parallel ?? true,
|
|
944
|
+
relevantFiles: s.relevantFiles || s.relevant_files || s.files,
|
|
945
|
+
suggestedRole: s.suggestedRole || s.suggested_role || s.role,
|
|
946
|
+
};
|
|
947
|
+
}
|
|
948
|
+
/**
|
|
949
|
+
* Try to extract subtasks from a parsed JSON object/array.
|
|
950
|
+
* Returns null if the structure doesn't contain usable subtask data.
|
|
951
|
+
*/
|
|
952
|
+
function extractSubtasksFromParsed(parsed) {
|
|
953
|
+
// Handle array-at-root: some models return [{...}, {...}] instead of {"subtasks": [...]}
|
|
954
|
+
if (Array.isArray(parsed)) {
|
|
955
|
+
parsed = { subtasks: parsed, strategy: 'adaptive', reasoning: '(array-at-root)' };
|
|
956
|
+
}
|
|
957
|
+
// Normalize alternative key names: tasks, steps, task_list → subtasks
|
|
958
|
+
const subtasksArray = parsed.subtasks
|
|
959
|
+
?? parsed.tasks
|
|
960
|
+
?? parsed.steps
|
|
961
|
+
?? parsed.task_list
|
|
962
|
+
?? parsed.decomposition;
|
|
963
|
+
if (!subtasksArray || !Array.isArray(subtasksArray) || subtasksArray.length === 0) {
|
|
964
|
+
return null;
|
|
965
|
+
}
|
|
966
|
+
return {
|
|
967
|
+
subtasks: subtasksArray.map(normalizeSubtask),
|
|
968
|
+
strategy: parsed.strategy || 'adaptive',
|
|
969
|
+
reasoning: parsed.reasoning || '',
|
|
970
|
+
};
|
|
971
|
+
}
|
|
972
|
+
/**
|
|
973
|
+
* Layer 1: Lenient JSON repair.
|
|
974
|
+
* Fixes common LLM JSON mistakes before parsing:
|
|
975
|
+
* - Trailing commas before ] and }
|
|
976
|
+
* - JS-style comments (// and block comments)
|
|
977
|
+
* - Single-quoted strings → double-quoted
|
|
978
|
+
* - Unquoted object keys
|
|
979
|
+
*/
|
|
980
|
+
export function repairJSON(jsonStr) {
|
|
981
|
+
let s = jsonStr;
|
|
982
|
+
// Strip JS-style line comments (// ...) outside strings
|
|
983
|
+
s = s.replace(/("(?:[^"\\]|\\.)*")|\/\/[^\n]*/g, (_match, str) => str ?? '');
|
|
984
|
+
// Strip JS-style block comments outside strings
|
|
985
|
+
s = s.replace(/("(?:[^"\\]|\\.)*")|\/\*[\s\S]*?\*\//g, (_match, str) => str ?? '');
|
|
986
|
+
// Replace single-quoted strings with double-quoted (outside existing double-quoted strings)
|
|
987
|
+
s = s.replace(/("(?:[^"\\]|\\.)*")|'((?:[^'\\]|\\.)*)'/g, (_match, dq, sq) => {
|
|
988
|
+
if (dq)
|
|
989
|
+
return dq; // Already double-quoted, keep as-is
|
|
990
|
+
const escaped = sq.replace(/(?<!\\)"/g, '\\"');
|
|
991
|
+
return `"${escaped}"`;
|
|
992
|
+
});
|
|
993
|
+
// Fix unquoted object keys: { key: "value" } → { "key": "value" }
|
|
994
|
+
s = s.replace(/("(?:[^"\\]|\\.)*")|\b([a-zA-Z_][a-zA-Z0-9_]*)\s*:/g, (match, str, key) => {
|
|
995
|
+
if (str)
|
|
996
|
+
return match; // Inside a string, keep as-is
|
|
997
|
+
return `"${key}":`;
|
|
998
|
+
});
|
|
999
|
+
// Strip trailing commas before ] and }
|
|
1000
|
+
s = s.replace(/,\s*([}\]])/g, '$1');
|
|
1001
|
+
return s;
|
|
1002
|
+
}
|
|
1003
|
+
/**
|
|
1004
|
+
* Layer 2: Extract subtasks from natural language (numbered/bulleted lists).
|
|
1005
|
+
* Handles formats like:
|
|
1006
|
+
* - "1. Description" / "1) Description"
|
|
1007
|
+
* - "- Description" / "* Description"
|
|
1008
|
+
* - "Task 1: Description" / "Step 1: Description"
|
|
1009
|
+
* - "- [ ] Description" / "- [x] Description" (markdown task lists)
|
|
1010
|
+
*/
|
|
1011
|
+
export function extractSubtasksFromNaturalLanguage(response) {
|
|
1012
|
+
const items = [];
|
|
1013
|
+
// Try markdown task lists first: - [ ] Task / - [x] Task
|
|
1014
|
+
const taskListPattern = /^[ \t]*[-*]\s*\[[ x]\]\s+(.+)$/gm;
|
|
1015
|
+
let match;
|
|
1016
|
+
while ((match = taskListPattern.exec(response)) !== null) {
|
|
1017
|
+
const desc = match[1].trim();
|
|
1018
|
+
if (desc.length > 5)
|
|
1019
|
+
items.push(desc);
|
|
1020
|
+
}
|
|
1021
|
+
if (items.length >= 2)
|
|
1022
|
+
return buildSubtasksFromList(items);
|
|
1023
|
+
// Try numbered lists: 1. Desc / 1) Desc / 1: Desc
|
|
1024
|
+
items.length = 0;
|
|
1025
|
+
const numberedPattern = /^[ \t]*\d+[.):\-]\s+(.+)$/gm;
|
|
1026
|
+
while ((match = numberedPattern.exec(response)) !== null) {
|
|
1027
|
+
const desc = match[1].trim();
|
|
1028
|
+
if (desc.length > 5)
|
|
1029
|
+
items.push(desc);
|
|
1030
|
+
}
|
|
1031
|
+
if (items.length >= 2)
|
|
1032
|
+
return buildSubtasksFromList(items);
|
|
1033
|
+
// Try bulleted lists: - Desc / * Desc (but not markdown task lists already tried)
|
|
1034
|
+
items.length = 0;
|
|
1035
|
+
const bulletPattern = /^[ \t]*[-*]\s+(?!\[[ x]\])(.+)$/gm;
|
|
1036
|
+
while ((match = bulletPattern.exec(response)) !== null) {
|
|
1037
|
+
const desc = match[1].trim();
|
|
1038
|
+
if (desc.length > 5)
|
|
1039
|
+
items.push(desc);
|
|
1040
|
+
}
|
|
1041
|
+
if (items.length >= 2)
|
|
1042
|
+
return buildSubtasksFromList(items);
|
|
1043
|
+
// Try "Task N:" / "Step N:" / "Subtask N:" style headers
|
|
1044
|
+
items.length = 0;
|
|
1045
|
+
const headerPattern = /^[ \t]*(?:task|step|subtask|phase)\s*\d+[:.]\s*(.+)$/gim;
|
|
1046
|
+
while ((match = headerPattern.exec(response)) !== null) {
|
|
1047
|
+
const desc = match[1].trim();
|
|
1048
|
+
if (desc.length > 5)
|
|
1049
|
+
items.push(desc);
|
|
1050
|
+
}
|
|
1051
|
+
if (items.length >= 2)
|
|
1052
|
+
return buildSubtasksFromList(items);
|
|
1053
|
+
// Try markdown headers: ## Subtask 1 / ### Step: Description
|
|
1054
|
+
items.length = 0;
|
|
1055
|
+
const mdHeaderPattern = /^#{2,4}\s+(?:(?:subtask|step|task|phase)\s*\d*[:.]*\s*)?(.+)$/gim;
|
|
1056
|
+
while ((match = mdHeaderPattern.exec(response)) !== null) {
|
|
1057
|
+
const desc = match[1].trim();
|
|
1058
|
+
// Skip generic headers like "Summary", "Strategy", "Overview"
|
|
1059
|
+
if (desc.length > 5 && !/^(summary|strategy|overview|reasoning|conclusion|notes?)$/i.test(desc)) {
|
|
1060
|
+
items.push(desc);
|
|
865
1061
|
}
|
|
866
|
-
const parsed = JSON.parse(jsonMatch[0]);
|
|
867
|
-
return {
|
|
868
|
-
subtasks: (parsed.subtasks || []).map((s) => ({
|
|
869
|
-
description: s.description || '',
|
|
870
|
-
type: s.type || 'implement',
|
|
871
|
-
complexity: s.complexity || 3,
|
|
872
|
-
dependencies: s.dependencies || [],
|
|
873
|
-
parallelizable: s.parallelizable ?? true,
|
|
874
|
-
relevantFiles: s.relevantFiles,
|
|
875
|
-
suggestedRole: s.suggestedRole,
|
|
876
|
-
})),
|
|
877
|
-
strategy: parsed.strategy || 'adaptive',
|
|
878
|
-
reasoning: parsed.reasoning || '',
|
|
879
|
-
};
|
|
880
1062
|
}
|
|
881
|
-
|
|
882
|
-
|
|
1063
|
+
if (items.length >= 2)
|
|
1064
|
+
return buildSubtasksFromList(items);
|
|
1065
|
+
return null;
|
|
1066
|
+
}
|
|
1067
|
+
/**
|
|
1068
|
+
* Build an LLMDecomposeResult from a flat list of description strings.
|
|
1069
|
+
* Assigns sequential dependencies and infers task type from keywords.
|
|
1070
|
+
*/
|
|
1071
|
+
function buildSubtasksFromList(items) {
|
|
1072
|
+
const TYPE_KEYWORDS = {
|
|
1073
|
+
research: ['research', 'investigate', 'explore', 'analyze', 'understand', 'study', 'review existing'],
|
|
1074
|
+
design: ['design', 'plan', 'architect', 'schema', 'structure'],
|
|
1075
|
+
test: ['test', 'verify', 'validate', 'assert', 'check'],
|
|
1076
|
+
refactor: ['refactor', 'clean up', 'reorganize', 'simplify'],
|
|
1077
|
+
document: ['document', 'readme', 'docs', 'comment'],
|
|
1078
|
+
integrate: ['integrate', 'wire', 'connect', 'combine', 'merge'],
|
|
1079
|
+
deploy: ['deploy', 'release', 'publish', 'ship'],
|
|
1080
|
+
};
|
|
1081
|
+
return {
|
|
1082
|
+
subtasks: items.map((desc, i) => {
|
|
1083
|
+
const lower = desc.toLowerCase();
|
|
1084
|
+
let type = 'implement';
|
|
1085
|
+
for (const [t, keywords] of Object.entries(TYPE_KEYWORDS)) {
|
|
1086
|
+
if (keywords.some(k => lower.includes(k))) {
|
|
1087
|
+
type = t;
|
|
1088
|
+
break;
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
return {
|
|
1092
|
+
description: desc,
|
|
1093
|
+
type,
|
|
1094
|
+
complexity: 3,
|
|
1095
|
+
dependencies: i > 0 ? [String(i - 1)] : [],
|
|
1096
|
+
parallelizable: i === 0 || type === 'research' || type === 'test',
|
|
1097
|
+
};
|
|
1098
|
+
}),
|
|
1099
|
+
strategy: 'sequential',
|
|
1100
|
+
reasoning: '(extracted from natural language list)',
|
|
1101
|
+
};
|
|
1102
|
+
}
|
|
1103
|
+
/**
|
|
1104
|
+
* Layer 3: Last-ditch single mega-task extraction.
|
|
1105
|
+
* If there's meaningful text but no structure could be found,
|
|
1106
|
+
* wrap the response as a single "implement" subtask so the swarm
|
|
1107
|
+
* has something to work with rather than aborting entirely.
|
|
1108
|
+
*/
|
|
1109
|
+
function extractMegaTask(response) {
|
|
1110
|
+
// Strip code blocks, JSON fragments, and whitespace to get prose content
|
|
1111
|
+
const prose = response
|
|
1112
|
+
.replace(/```[\s\S]*?```/g, '')
|
|
1113
|
+
.replace(/\{[\s\S]*?\}/g, '')
|
|
1114
|
+
.replace(/\[[\s\S]*?\]/g, '')
|
|
1115
|
+
.trim();
|
|
1116
|
+
// Only create mega-task if there's substantial text (not just JSON garbage)
|
|
1117
|
+
if (prose.length < 20)
|
|
1118
|
+
return null;
|
|
1119
|
+
const desc = prose.length > 200
|
|
1120
|
+
? prose.slice(0, 200).replace(/\s+\S*$/, '') + '...'
|
|
1121
|
+
: prose;
|
|
1122
|
+
return {
|
|
1123
|
+
subtasks: [{
|
|
1124
|
+
description: desc,
|
|
1125
|
+
type: 'implement',
|
|
1126
|
+
complexity: 5,
|
|
1127
|
+
dependencies: [],
|
|
1128
|
+
parallelizable: false,
|
|
1129
|
+
}],
|
|
1130
|
+
strategy: 'adaptive',
|
|
1131
|
+
reasoning: '(single mega-task — parser could not extract structured subtasks)',
|
|
1132
|
+
};
|
|
1133
|
+
}
|
|
1134
|
+
/**
|
|
1135
|
+
* Parse LLM response into decomposition result.
|
|
1136
|
+
*
|
|
1137
|
+
* Uses progressive fallback layers to handle messy LLM output:
|
|
1138
|
+
* 1. Standard JSON extraction (code blocks, raw JSON)
|
|
1139
|
+
* 2. Lenient JSON repair (trailing commas, comments, single quotes, unquoted keys)
|
|
1140
|
+
* 3. Truncated JSON recovery (missing closing brackets)
|
|
1141
|
+
* 4. Natural language extraction (numbered/bulleted lists, markdown task lists)
|
|
1142
|
+
* 5. Single mega-task fallback (wrap prose as one subtask)
|
|
1143
|
+
*/
|
|
1144
|
+
export function parseDecompositionResponse(response) {
|
|
1145
|
+
if (!response || response.trim().length === 0) {
|
|
883
1146
|
return {
|
|
884
1147
|
subtasks: [],
|
|
885
1148
|
strategy: 'adaptive',
|
|
886
|
-
reasoning:
|
|
1149
|
+
reasoning: '',
|
|
1150
|
+
parseError: 'Empty response from LLM',
|
|
887
1151
|
};
|
|
888
1152
|
}
|
|
1153
|
+
// ── Step 1: Extract JSON string (code block or raw) ──────────────
|
|
1154
|
+
let jsonStr;
|
|
1155
|
+
const codeBlockMatch = response.match(/```(?:json)?\s*\n?([\s\S]*?)```/);
|
|
1156
|
+
if (codeBlockMatch) {
|
|
1157
|
+
jsonStr = codeBlockMatch[1].trim();
|
|
1158
|
+
}
|
|
1159
|
+
if (!jsonStr) {
|
|
1160
|
+
// If the response starts with `[`, try array regex first to avoid
|
|
1161
|
+
// \{[\s\S]*\} greedily matching across multiple objects in the array
|
|
1162
|
+
const trimmed = response.trim();
|
|
1163
|
+
const jsonMatch = trimmed.startsWith('[')
|
|
1164
|
+
? (response.match(/\[[\s\S]*\]/) || response.match(/\{[\s\S]*\}/))
|
|
1165
|
+
: (response.match(/\{[\s\S]*\}/) || response.match(/\[[\s\S]*\]/));
|
|
1166
|
+
if (jsonMatch)
|
|
1167
|
+
jsonStr = jsonMatch[0];
|
|
1168
|
+
}
|
|
1169
|
+
// ── Step 2: Try strict JSON parse ────────────────────────────────
|
|
1170
|
+
if (jsonStr) {
|
|
1171
|
+
try {
|
|
1172
|
+
const parsed = JSON.parse(jsonStr);
|
|
1173
|
+
const result = extractSubtasksFromParsed(parsed);
|
|
1174
|
+
if (result)
|
|
1175
|
+
return result;
|
|
1176
|
+
}
|
|
1177
|
+
catch {
|
|
1178
|
+
// Strict parse failed — continue to lenient repair
|
|
1179
|
+
}
|
|
1180
|
+
// ── Step 3: Lenient JSON repair + parse ──────────────────────────
|
|
1181
|
+
try {
|
|
1182
|
+
const repaired = repairJSON(jsonStr);
|
|
1183
|
+
const parsed = JSON.parse(repaired);
|
|
1184
|
+
const result = extractSubtasksFromParsed(parsed);
|
|
1185
|
+
if (result) {
|
|
1186
|
+
result.reasoning = result.reasoning
|
|
1187
|
+
? result.reasoning + ' (repaired JSON)'
|
|
1188
|
+
: '(repaired JSON)';
|
|
1189
|
+
return result;
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
catch {
|
|
1193
|
+
// Repaired parse also failed — continue to truncation recovery
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
// ── Step 4: Truncated JSON recovery ────────────────────────────────
|
|
1197
|
+
const recovered = tryRecoverTruncatedJSON(response);
|
|
1198
|
+
if (recovered) {
|
|
1199
|
+
try {
|
|
1200
|
+
const parsed = JSON.parse(recovered);
|
|
1201
|
+
const result = extractSubtasksFromParsed(parsed);
|
|
1202
|
+
if (result) {
|
|
1203
|
+
result.reasoning = result.reasoning
|
|
1204
|
+
? result.reasoning + ' (recovered from truncated response)'
|
|
1205
|
+
: '(recovered from truncated response)';
|
|
1206
|
+
return result;
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
catch {
|
|
1210
|
+
// Truncation recovery also failed — try repaired version
|
|
1211
|
+
try {
|
|
1212
|
+
const repairedRecovered = repairJSON(recovered);
|
|
1213
|
+
const parsed = JSON.parse(repairedRecovered);
|
|
1214
|
+
const result = extractSubtasksFromParsed(parsed);
|
|
1215
|
+
if (result) {
|
|
1216
|
+
result.reasoning = '(recovered from truncated + repaired JSON)';
|
|
1217
|
+
return result;
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
catch {
|
|
1221
|
+
// All JSON approaches exhausted
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
// ── Step 5: Natural language extraction ────────────────────────────
|
|
1226
|
+
const nlResult = extractSubtasksFromNaturalLanguage(response);
|
|
1227
|
+
if (nlResult)
|
|
1228
|
+
return nlResult;
|
|
1229
|
+
// ── Step 6: Single mega-task fallback ──────────────────────────────
|
|
1230
|
+
const megaResult = extractMegaTask(response);
|
|
1231
|
+
if (megaResult)
|
|
1232
|
+
return megaResult;
|
|
1233
|
+
// ── Truly nothing worked ───────────────────────────────────────────
|
|
1234
|
+
return {
|
|
1235
|
+
subtasks: [],
|
|
1236
|
+
strategy: 'adaptive',
|
|
1237
|
+
reasoning: '',
|
|
1238
|
+
parseError: `All parse strategies failed. First 200 chars: ${response.slice(0, 200)}`,
|
|
1239
|
+
};
|
|
1240
|
+
}
|
|
1241
|
+
/**
|
|
1242
|
+
* Attempt to recover a truncated JSON response by trimming incomplete trailing
|
|
1243
|
+
* content and adding missing closing brackets/braces.
|
|
1244
|
+
*
|
|
1245
|
+
* Works for the common case where the LLM output was cut off mid-JSON-array,
|
|
1246
|
+
* e.g.: `{"subtasks": [ {...}, {...}, {"desc` → trim last incomplete object → close array & object.
|
|
1247
|
+
*/
|
|
1248
|
+
function tryRecoverTruncatedJSON(response) {
|
|
1249
|
+
// Extract JSON portion (from code block or raw)
|
|
1250
|
+
let jsonStr;
|
|
1251
|
+
const codeBlockMatch = response.match(/```(?:json)?\s*\n?([\s\S]*)/);
|
|
1252
|
+
if (codeBlockMatch) {
|
|
1253
|
+
// No closing ``` required — that's the truncation
|
|
1254
|
+
jsonStr = codeBlockMatch[1].replace(/```\s*$/, '').trim();
|
|
1255
|
+
}
|
|
1256
|
+
if (!jsonStr) {
|
|
1257
|
+
const jsonMatch = response.match(/\{[\s\S]*/);
|
|
1258
|
+
if (jsonMatch)
|
|
1259
|
+
jsonStr = jsonMatch[0].trim();
|
|
1260
|
+
}
|
|
1261
|
+
if (!jsonStr)
|
|
1262
|
+
return null;
|
|
1263
|
+
// Find the last complete JSON object in the subtasks array.
|
|
1264
|
+
// Strategy: find last `}` that closes a complete array element, trim there, close brackets.
|
|
1265
|
+
// We search backwards for `},` or `}\n` patterns that likely end a complete subtask object.
|
|
1266
|
+
let lastGoodPos = -1;
|
|
1267
|
+
let braceDepth = 0;
|
|
1268
|
+
let bracketDepth = 0;
|
|
1269
|
+
let inString = false;
|
|
1270
|
+
let escape = false;
|
|
1271
|
+
for (let i = 0; i < jsonStr.length; i++) {
|
|
1272
|
+
const ch = jsonStr[i];
|
|
1273
|
+
if (escape) {
|
|
1274
|
+
escape = false;
|
|
1275
|
+
continue;
|
|
1276
|
+
}
|
|
1277
|
+
if (ch === '\\' && inString) {
|
|
1278
|
+
escape = true;
|
|
1279
|
+
continue;
|
|
1280
|
+
}
|
|
1281
|
+
if (ch === '"') {
|
|
1282
|
+
inString = !inString;
|
|
1283
|
+
continue;
|
|
1284
|
+
}
|
|
1285
|
+
if (inString)
|
|
1286
|
+
continue;
|
|
1287
|
+
if (ch === '{')
|
|
1288
|
+
braceDepth++;
|
|
1289
|
+
else if (ch === '}') {
|
|
1290
|
+
braceDepth--;
|
|
1291
|
+
// When we close an object at brace depth 1 (inside the top-level object),
|
|
1292
|
+
// this is likely a complete subtask object inside the array
|
|
1293
|
+
if (braceDepth === 1 && bracketDepth === 1) {
|
|
1294
|
+
lastGoodPos = i;
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
else if (ch === '[')
|
|
1298
|
+
bracketDepth++;
|
|
1299
|
+
else if (ch === ']')
|
|
1300
|
+
bracketDepth--;
|
|
1301
|
+
}
|
|
1302
|
+
if (lastGoodPos === -1)
|
|
1303
|
+
return null;
|
|
1304
|
+
// Trim to last complete subtask object, then close the JSON structure
|
|
1305
|
+
let trimmed = jsonStr.slice(0, lastGoodPos + 1);
|
|
1306
|
+
// Remove trailing comma if present
|
|
1307
|
+
trimmed = trimmed.replace(/,\s*$/, '');
|
|
1308
|
+
// Close open brackets: we need to close the subtasks array and the root object
|
|
1309
|
+
// Count what's still open
|
|
1310
|
+
let openBraces = 0;
|
|
1311
|
+
let openBrackets = 0;
|
|
1312
|
+
inString = false;
|
|
1313
|
+
escape = false;
|
|
1314
|
+
for (let i = 0; i < trimmed.length; i++) {
|
|
1315
|
+
const ch = trimmed[i];
|
|
1316
|
+
if (escape) {
|
|
1317
|
+
escape = false;
|
|
1318
|
+
continue;
|
|
1319
|
+
}
|
|
1320
|
+
if (ch === '\\' && inString) {
|
|
1321
|
+
escape = true;
|
|
1322
|
+
continue;
|
|
1323
|
+
}
|
|
1324
|
+
if (ch === '"') {
|
|
1325
|
+
inString = !inString;
|
|
1326
|
+
continue;
|
|
1327
|
+
}
|
|
1328
|
+
if (inString)
|
|
1329
|
+
continue;
|
|
1330
|
+
if (ch === '{')
|
|
1331
|
+
openBraces++;
|
|
1332
|
+
else if (ch === '}')
|
|
1333
|
+
openBraces--;
|
|
1334
|
+
else if (ch === '[')
|
|
1335
|
+
openBrackets++;
|
|
1336
|
+
else if (ch === ']')
|
|
1337
|
+
openBrackets--;
|
|
1338
|
+
}
|
|
1339
|
+
// Close remaining open structures
|
|
1340
|
+
for (let i = 0; i < openBrackets; i++)
|
|
1341
|
+
trimmed += ']';
|
|
1342
|
+
for (let i = 0; i < openBraces; i++)
|
|
1343
|
+
trimmed += '}';
|
|
1344
|
+
return trimmed;
|
|
889
1345
|
}
|
|
890
1346
|
//# sourceMappingURL=smart-decomposer.js.map
|