aidp 0.25.0 → 0.27.0
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.
- checksums.yaml +4 -4
- data/README.md +45 -6
- data/lib/aidp/analyze/error_handler.rb +11 -0
- data/lib/aidp/cli/checkpoint_command.rb +198 -0
- data/lib/aidp/cli/config_command.rb +71 -0
- data/lib/aidp/cli/enhanced_input.rb +2 -0
- data/lib/aidp/cli/first_run_wizard.rb +8 -7
- data/lib/aidp/cli/harness_command.rb +102 -0
- data/lib/aidp/cli/jobs_command.rb +3 -3
- data/lib/aidp/cli/mcp_dashboard.rb +4 -3
- data/lib/aidp/cli/models_command.rb +662 -0
- data/lib/aidp/cli/providers_command.rb +223 -0
- data/lib/aidp/cli.rb +35 -456
- data/lib/aidp/daemon/runner.rb +2 -2
- data/lib/aidp/debug_mixin.rb +2 -9
- data/lib/aidp/execute/async_work_loop_runner.rb +2 -1
- data/lib/aidp/execute/checkpoint_display.rb +38 -37
- data/lib/aidp/execute/interactive_repl.rb +2 -1
- data/lib/aidp/execute/prompt_manager.rb +4 -4
- data/lib/aidp/execute/work_loop_runner.rb +253 -56
- data/lib/aidp/execute/workflow_selector.rb +2 -2
- data/lib/aidp/harness/config_loader.rb +20 -11
- data/lib/aidp/harness/config_manager.rb +5 -5
- data/lib/aidp/harness/config_schema.rb +30 -8
- data/lib/aidp/harness/configuration.rb +105 -4
- data/lib/aidp/harness/enhanced_runner.rb +24 -15
- data/lib/aidp/harness/error_handler.rb +26 -5
- data/lib/aidp/harness/filter_strategy.rb +45 -0
- data/lib/aidp/harness/generic_filter_strategy.rb +63 -0
- data/lib/aidp/harness/model_cache.rb +269 -0
- data/lib/aidp/harness/model_discovery_service.rb +259 -0
- data/lib/aidp/harness/model_registry.rb +201 -0
- data/lib/aidp/harness/output_filter.rb +136 -0
- data/lib/aidp/harness/provider_manager.rb +18 -3
- data/lib/aidp/harness/rspec_filter_strategy.rb +82 -0
- data/lib/aidp/harness/runner.rb +5 -0
- data/lib/aidp/harness/test_runner.rb +165 -27
- data/lib/aidp/harness/thinking_depth_manager.rb +223 -7
- data/lib/aidp/harness/ui/enhanced_tui.rb +4 -1
- data/lib/aidp/logger.rb +35 -5
- data/lib/aidp/providers/adapter.rb +2 -4
- data/lib/aidp/providers/anthropic.rb +141 -128
- data/lib/aidp/providers/base.rb +98 -2
- data/lib/aidp/providers/capability_registry.rb +0 -1
- data/lib/aidp/providers/codex.rb +49 -67
- data/lib/aidp/providers/cursor.rb +71 -59
- data/lib/aidp/providers/gemini.rb +44 -60
- data/lib/aidp/providers/github_copilot.rb +2 -66
- data/lib/aidp/providers/kilocode.rb +24 -80
- data/lib/aidp/providers/opencode.rb +24 -80
- data/lib/aidp/safe_directory.rb +10 -3
- data/lib/aidp/setup/wizard.rb +345 -8
- data/lib/aidp/storage/csv_storage.rb +9 -3
- data/lib/aidp/storage/file_manager.rb +8 -2
- data/lib/aidp/storage/json_storage.rb +9 -3
- data/lib/aidp/version.rb +1 -1
- data/lib/aidp/watch/build_processor.rb +40 -1
- data/lib/aidp/watch/change_request_processor.rb +659 -0
- data/lib/aidp/watch/plan_generator.rb +93 -14
- data/lib/aidp/watch/plan_processor.rb +71 -8
- data/lib/aidp/watch/repository_client.rb +85 -20
- data/lib/aidp/watch/review_processor.rb +3 -3
- data/lib/aidp/watch/runner.rb +37 -0
- data/lib/aidp/watch/state_store.rb +46 -1
- data/lib/aidp/workflows/guided_agent.rb +3 -3
- data/lib/aidp/workstream_executor.rb +5 -2
- data/lib/aidp.rb +4 -0
- data/templates/aidp-development.yml.example +2 -2
- data/templates/aidp-production.yml.example +3 -3
- data/templates/aidp.yml.example +53 -0
- metadata +14 -1
|
@@ -8,6 +8,7 @@ require_relative "work_loop_unit_scheduler"
|
|
|
8
8
|
require_relative "deterministic_unit"
|
|
9
9
|
require_relative "agent_signal_parser"
|
|
10
10
|
require_relative "../harness/test_runner"
|
|
11
|
+
require_relative "../errors"
|
|
11
12
|
|
|
12
13
|
module Aidp
|
|
13
14
|
module Execute
|
|
@@ -46,10 +47,11 @@ module Aidp
|
|
|
46
47
|
@project_dir = project_dir
|
|
47
48
|
@provider_manager = provider_manager
|
|
48
49
|
@config = config
|
|
50
|
+
@prompt = options[:prompt] || TTY::Prompt.new
|
|
49
51
|
@prompt_manager = PromptManager.new(project_dir, config: config)
|
|
50
52
|
@test_runner = Aidp::Harness::TestRunner.new(project_dir, config)
|
|
51
53
|
@checkpoint = Checkpoint.new(project_dir)
|
|
52
|
-
@checkpoint_display = CheckpointDisplay.new
|
|
54
|
+
@checkpoint_display = CheckpointDisplay.new(prompt: @prompt)
|
|
53
55
|
@guard_policy = GuardPolicy.new(project_dir, config.guards_config)
|
|
54
56
|
@persistent_tasklist = PersistentTasklist.new(project_dir)
|
|
55
57
|
@iteration_count = 0
|
|
@@ -59,6 +61,12 @@ module Aidp
|
|
|
59
61
|
@state_history = []
|
|
60
62
|
@deterministic_runner = DeterministicUnits::Runner.new(project_dir)
|
|
61
63
|
@unit_scheduler = nil
|
|
64
|
+
|
|
65
|
+
# Initialize thinking depth manager for intelligent model selection
|
|
66
|
+
require_relative "../harness/thinking_depth_manager"
|
|
67
|
+
@thinking_depth_manager = options[:thinking_depth_manager] || Aidp::Harness::ThinkingDepthManager.new(config)
|
|
68
|
+
@consecutive_failures = 0
|
|
69
|
+
@last_tier = nil
|
|
62
70
|
end
|
|
63
71
|
|
|
64
72
|
# Execute a step using fix-forward work loop pattern
|
|
@@ -154,6 +162,10 @@ module Aidp
|
|
|
154
162
|
# Wrap agent call in exception handling for true fix-forward
|
|
155
163
|
begin
|
|
156
164
|
agent_result = apply_patch
|
|
165
|
+
rescue Aidp::Errors::ConfigurationError
|
|
166
|
+
# Configuration errors should crash immediately (crash-early principle)
|
|
167
|
+
# Re-raise without catching
|
|
168
|
+
raise
|
|
157
169
|
rescue => e
|
|
158
170
|
# Convert exception to error result for fix-forward handling
|
|
159
171
|
Aidp.logger.error("work_loop", "Exception during agent call",
|
|
@@ -172,23 +184,70 @@ module Aidp
|
|
|
172
184
|
next
|
|
173
185
|
end
|
|
174
186
|
|
|
187
|
+
# Check for fatal configuration errors (crash early per LLM_STYLE_GUIDE)
|
|
188
|
+
if agent_result[:status] == "error" && agent_result[:message]&.include?("No model available")
|
|
189
|
+
tier = @thinking_depth_manager.current_tier
|
|
190
|
+
provider = @provider_manager.current_provider
|
|
191
|
+
|
|
192
|
+
error_msg = "No model configured for thinking tier '#{tier}'.\n\n" \
|
|
193
|
+
"Current provider: #{provider}\n" \
|
|
194
|
+
"Required tier: #{tier}\n\n" \
|
|
195
|
+
"To fix this, add a model to your aidp.yml:\n\n" \
|
|
196
|
+
"thinking_depth:\n" \
|
|
197
|
+
" tiers:\n" \
|
|
198
|
+
" #{tier}:\n" \
|
|
199
|
+
" models:\n" \
|
|
200
|
+
" - provider: #{provider}\n" \
|
|
201
|
+
" model: <model-name> # e.g., claude-3-5-sonnet-20241022\n\n" \
|
|
202
|
+
"Or run: aidp models list\n" \
|
|
203
|
+
"to see available models for your configured providers."
|
|
204
|
+
|
|
205
|
+
raise Aidp::Errors::ConfigurationError, error_msg
|
|
206
|
+
end
|
|
207
|
+
|
|
175
208
|
# Process agent output for task filing signals
|
|
176
209
|
process_task_filing(agent_result)
|
|
177
210
|
|
|
178
211
|
transition_to(:test)
|
|
212
|
+
# Run all configured checks
|
|
179
213
|
test_results = @test_runner.run_tests
|
|
180
214
|
lint_results = @test_runner.run_linters
|
|
215
|
+
build_results = @test_runner.run_builds
|
|
216
|
+
doc_results = @test_runner.run_documentation
|
|
217
|
+
|
|
218
|
+
# Run formatters only if agent marked work complete (per issue #234)
|
|
219
|
+
formatter_results = if agent_marked_complete?(agent_result)
|
|
220
|
+
@test_runner.run_formatters
|
|
221
|
+
else
|
|
222
|
+
{success: true, output: "Formatters: Skipped (work not complete)", failures: [], required_failures: []}
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
all_results = {
|
|
226
|
+
tests: test_results,
|
|
227
|
+
lints: lint_results,
|
|
228
|
+
formatters: formatter_results,
|
|
229
|
+
builds: build_results,
|
|
230
|
+
docs: doc_results
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
record_periodic_checkpoint(all_results)
|
|
181
234
|
|
|
182
|
-
|
|
235
|
+
# Track failures and escalate thinking tier if needed
|
|
236
|
+
track_failures_and_escalate(all_results)
|
|
183
237
|
|
|
184
|
-
|
|
238
|
+
# All required checks must pass for completion
|
|
239
|
+
all_checks_pass = test_results[:success] &&
|
|
240
|
+
lint_results[:success] &&
|
|
241
|
+
formatter_results[:success] &&
|
|
242
|
+
build_results[:success] &&
|
|
243
|
+
doc_results[:success]
|
|
185
244
|
|
|
186
|
-
if
|
|
245
|
+
if all_checks_pass
|
|
187
246
|
transition_to(:pass)
|
|
188
247
|
|
|
189
248
|
if agent_marked_complete?(agent_result)
|
|
190
249
|
transition_to(:done)
|
|
191
|
-
record_final_checkpoint(
|
|
250
|
+
record_final_checkpoint(all_results)
|
|
192
251
|
display_message("✅ Step #{@step_name} completed after #{@iteration_count} iterations", type: :success)
|
|
193
252
|
display_state_summary
|
|
194
253
|
archive_and_cleanup
|
|
@@ -201,18 +260,18 @@ module Aidp
|
|
|
201
260
|
terminate: true
|
|
202
261
|
)
|
|
203
262
|
else
|
|
204
|
-
display_message("
|
|
263
|
+
display_message(" All checks passed but work not marked complete", type: :info)
|
|
205
264
|
transition_to(:next_patch)
|
|
206
265
|
end
|
|
207
266
|
else
|
|
208
267
|
transition_to(:fail)
|
|
209
|
-
display_message("
|
|
268
|
+
display_message(" Required checks failed", type: :warning)
|
|
210
269
|
|
|
211
270
|
transition_to(:diagnose)
|
|
212
|
-
diagnostic = diagnose_failures(
|
|
271
|
+
diagnostic = diagnose_failures(all_results)
|
|
213
272
|
|
|
214
273
|
transition_to(:next_patch)
|
|
215
|
-
prepare_next_iteration(
|
|
274
|
+
prepare_next_iteration(all_results, diagnostic)
|
|
216
275
|
end
|
|
217
276
|
end
|
|
218
277
|
end
|
|
@@ -222,14 +281,18 @@ module Aidp
|
|
|
222
281
|
|
|
223
282
|
prompt = build_decider_prompt(context)
|
|
224
283
|
|
|
284
|
+
# Select model based on thinking depth tier
|
|
285
|
+
provider_name, model_name, _model_data = select_model_for_current_tier
|
|
286
|
+
|
|
225
287
|
agent_result = @provider_manager.execute_with_provider(
|
|
226
|
-
|
|
288
|
+
provider_name,
|
|
227
289
|
prompt,
|
|
228
290
|
{
|
|
229
291
|
step_name: @step_name,
|
|
230
292
|
iteration: @iteration_count,
|
|
231
293
|
project_dir: @project_dir,
|
|
232
|
-
mode: :decide_whats_next
|
|
294
|
+
mode: :decide_whats_next,
|
|
295
|
+
model: model_name
|
|
233
296
|
}
|
|
234
297
|
)
|
|
235
298
|
|
|
@@ -250,14 +313,18 @@ module Aidp
|
|
|
250
313
|
|
|
251
314
|
prompt = build_diagnose_prompt(context)
|
|
252
315
|
|
|
316
|
+
# Select model based on thinking depth tier
|
|
317
|
+
provider_name, model_name, _model_data = select_model_for_current_tier
|
|
318
|
+
|
|
253
319
|
agent_result = @provider_manager.execute_with_provider(
|
|
254
|
-
|
|
320
|
+
provider_name,
|
|
255
321
|
prompt,
|
|
256
322
|
{
|
|
257
323
|
step_name: @step_name,
|
|
258
324
|
iteration: @iteration_count,
|
|
259
325
|
project_dir: @project_dir,
|
|
260
|
-
mode: :diagnose_failures
|
|
326
|
+
mode: :diagnose_failures,
|
|
327
|
+
model: model_name
|
|
261
328
|
}
|
|
262
329
|
)
|
|
263
330
|
|
|
@@ -421,27 +488,26 @@ module Aidp
|
|
|
421
488
|
result[:status] == "completed" || prompt_marked_complete?
|
|
422
489
|
end
|
|
423
490
|
|
|
424
|
-
# Diagnose
|
|
491
|
+
# Diagnose all failures (tests, lints, formatters, builds, docs)
|
|
425
492
|
# Returns diagnostic information to help agent understand what went wrong
|
|
426
|
-
def diagnose_failures(
|
|
493
|
+
def diagnose_failures(all_results)
|
|
427
494
|
diagnostic = {
|
|
428
495
|
iteration: @iteration_count,
|
|
429
496
|
failures: []
|
|
430
497
|
}
|
|
431
498
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
499
|
+
# Check each result type for failures
|
|
500
|
+
all_results.each do |category, results|
|
|
501
|
+
next if results[:success]
|
|
502
|
+
|
|
503
|
+
# Only include required failures in diagnostic
|
|
504
|
+
required_failures = results[:required_failures] || results[:failures] || []
|
|
505
|
+
next if required_failures.empty?
|
|
439
506
|
|
|
440
|
-
unless lint_results[:success]
|
|
441
507
|
diagnostic[:failures] << {
|
|
442
|
-
type:
|
|
443
|
-
count:
|
|
444
|
-
commands:
|
|
508
|
+
type: category.to_s,
|
|
509
|
+
count: required_failures.size,
|
|
510
|
+
commands: required_failures.map { |f| f[:command] }
|
|
445
511
|
}
|
|
446
512
|
end
|
|
447
513
|
|
|
@@ -650,17 +716,36 @@ module Aidp
|
|
|
650
716
|
# Prepend work loop instructions to every iteration
|
|
651
717
|
full_prompt = build_work_loop_header(@step_name, @iteration_count) + "\n\n" + prompt_content
|
|
652
718
|
|
|
719
|
+
# Select model based on thinking depth tier
|
|
720
|
+
provider_name, model_name, _model_data = select_model_for_current_tier
|
|
721
|
+
|
|
722
|
+
if provider_name.nil? || model_name.nil?
|
|
723
|
+
Aidp.logger.error("work_loop", "Failed to select model for tier",
|
|
724
|
+
tier: @thinking_depth_manager.current_tier,
|
|
725
|
+
step: @step_name,
|
|
726
|
+
iteration: @iteration_count)
|
|
727
|
+
return {status: "error", message: "No model available for tier #{@thinking_depth_manager.current_tier}"}
|
|
728
|
+
end
|
|
729
|
+
|
|
730
|
+
# Log model selection
|
|
731
|
+
tier = @thinking_depth_manager.current_tier
|
|
732
|
+
if @last_tier != tier
|
|
733
|
+
display_message(" 💡 Using tier: #{tier} (#{provider_name}/#{model_name})", type: :info)
|
|
734
|
+
@last_tier = tier
|
|
735
|
+
end
|
|
736
|
+
|
|
653
737
|
# CRITICAL: Change to project directory before calling provider
|
|
654
738
|
# This ensures Claude CLI runs in the correct directory and can create files
|
|
655
739
|
Dir.chdir(@project_dir) do
|
|
656
|
-
# Send to provider via provider_manager
|
|
740
|
+
# Send to provider via provider_manager with selected model
|
|
657
741
|
@provider_manager.execute_with_provider(
|
|
658
|
-
|
|
742
|
+
provider_name,
|
|
659
743
|
full_prompt,
|
|
660
744
|
{
|
|
661
745
|
step_name: @step_name,
|
|
662
746
|
iteration: @iteration_count,
|
|
663
|
-
project_dir: @project_dir
|
|
747
|
+
project_dir: @project_dir,
|
|
748
|
+
model: model_name
|
|
664
749
|
}
|
|
665
750
|
)
|
|
666
751
|
end
|
|
@@ -701,7 +786,7 @@ module Aidp
|
|
|
701
786
|
prompt_content.match?(/^STATUS:\s*COMPLETE/i)
|
|
702
787
|
end
|
|
703
788
|
|
|
704
|
-
def prepare_next_iteration(
|
|
789
|
+
def prepare_next_iteration(all_results, diagnostic = nil)
|
|
705
790
|
# Only append failures to PROMPT.md for agent to see
|
|
706
791
|
# This follows fix-forward: never rollback, only add information for next patch
|
|
707
792
|
failures = []
|
|
@@ -723,25 +808,30 @@ module Aidp
|
|
|
723
808
|
failures << ""
|
|
724
809
|
end
|
|
725
810
|
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
811
|
+
# Add failure output for each category that has failures
|
|
812
|
+
category_labels = {
|
|
813
|
+
tests: "Test",
|
|
814
|
+
lints: "Linter",
|
|
815
|
+
formatters: "Formatter",
|
|
816
|
+
builds: "Build",
|
|
817
|
+
docs: "Documentation"
|
|
818
|
+
}
|
|
731
819
|
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
820
|
+
all_results.each do |category, results|
|
|
821
|
+
next if results[:success]
|
|
822
|
+
|
|
823
|
+
failures << "### #{category_labels[category]} Failures"
|
|
824
|
+
failures << results[:output]
|
|
735
825
|
failures << ""
|
|
736
826
|
end
|
|
737
827
|
|
|
738
|
-
strategy = build_failure_strategy(
|
|
828
|
+
strategy = build_failure_strategy(all_results)
|
|
739
829
|
failures.concat(strategy) unless strategy.empty?
|
|
740
830
|
|
|
741
831
|
failures << "**Fix-forward instructions**: Do not rollback changes. Build on what exists and fix the failures above."
|
|
742
832
|
failures << ""
|
|
743
833
|
|
|
744
|
-
return if
|
|
834
|
+
return if all_results.values.all? { |result| result[:success] }
|
|
745
835
|
|
|
746
836
|
# Append failures to PROMPT.md and archive immediately (issue #224)
|
|
747
837
|
current_prompt = @prompt_manager.read
|
|
@@ -832,20 +922,27 @@ module Aidp
|
|
|
832
922
|
reminder.join("\n")
|
|
833
923
|
end
|
|
834
924
|
|
|
835
|
-
def build_failure_strategy(
|
|
836
|
-
return [] if
|
|
925
|
+
def build_failure_strategy(all_results)
|
|
926
|
+
return [] if all_results.values.all? { |result| result[:success] }
|
|
837
927
|
|
|
838
928
|
lines = ["### Recovery Strategy", ""]
|
|
839
929
|
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
930
|
+
category_strategies = {
|
|
931
|
+
tests: "Re-run %s locally to reproduce the failing specs listed above. Triage the exact failures before moving on to new work.",
|
|
932
|
+
lints: "Execute %s and fix each reported offense.",
|
|
933
|
+
formatters: "Run %s to fix formatting issues.",
|
|
934
|
+
builds: "Run %s to diagnose and fix build errors.",
|
|
935
|
+
docs: "Review and update documentation using %s to meet requirements."
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
all_results.each do |category, results|
|
|
939
|
+
next if results[:success]
|
|
940
|
+
|
|
941
|
+
strategy_template = category_strategies[category]
|
|
942
|
+
next unless strategy_template
|
|
845
943
|
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
lines << "- Execute #{commands} and fix each reported offense."
|
|
944
|
+
commands = format_command_list(results[:failures])
|
|
945
|
+
lines << "- #{strategy_template % commands}"
|
|
849
946
|
end
|
|
850
947
|
|
|
851
948
|
lines << ""
|
|
@@ -926,13 +1023,16 @@ module Aidp
|
|
|
926
1023
|
end
|
|
927
1024
|
|
|
928
1025
|
# Record checkpoint at regular intervals
|
|
929
|
-
def record_periodic_checkpoint(
|
|
1026
|
+
def record_periodic_checkpoint(all_results)
|
|
930
1027
|
# Record every CHECKPOINT_INTERVAL iterations or on iteration 1
|
|
931
1028
|
return unless @iteration_count == 1 || (@iteration_count % CHECKPOINT_INTERVAL == 0)
|
|
932
1029
|
|
|
933
1030
|
metrics = {
|
|
934
|
-
tests_passing:
|
|
935
|
-
linters_passing:
|
|
1031
|
+
tests_passing: all_results[:tests][:success],
|
|
1032
|
+
linters_passing: all_results[:lints][:success],
|
|
1033
|
+
formatters_passing: all_results[:formatters][:success],
|
|
1034
|
+
builds_passing: all_results[:builds][:success],
|
|
1035
|
+
docs_passing: all_results[:docs][:success]
|
|
936
1036
|
}
|
|
937
1037
|
|
|
938
1038
|
checkpoint_data = @checkpoint.record_checkpoint(@step_name, @iteration_count, metrics)
|
|
@@ -947,10 +1047,13 @@ module Aidp
|
|
|
947
1047
|
end
|
|
948
1048
|
|
|
949
1049
|
# Record final checkpoint when step completes
|
|
950
|
-
def record_final_checkpoint(
|
|
1050
|
+
def record_final_checkpoint(all_results)
|
|
951
1051
|
metrics = {
|
|
952
|
-
tests_passing:
|
|
953
|
-
linters_passing:
|
|
1052
|
+
tests_passing: all_results[:tests][:success],
|
|
1053
|
+
linters_passing: all_results[:lints][:success],
|
|
1054
|
+
formatters_passing: all_results[:formatters][:success],
|
|
1055
|
+
builds_passing: all_results[:builds][:success],
|
|
1056
|
+
docs_passing: all_results[:docs][:success],
|
|
954
1057
|
completed: true
|
|
955
1058
|
}
|
|
956
1059
|
|
|
@@ -1114,6 +1217,100 @@ module Aidp
|
|
|
1114
1217
|
display_message(" ✓ Confirmed", type: :success)
|
|
1115
1218
|
end
|
|
1116
1219
|
end
|
|
1220
|
+
|
|
1221
|
+
# Select model based on current thinking depth tier
|
|
1222
|
+
# Returns [provider_name, model_name, model_data]
|
|
1223
|
+
def select_model_for_current_tier
|
|
1224
|
+
current_tier = @thinking_depth_manager.current_tier
|
|
1225
|
+
provider_name, model_name, model_data = @thinking_depth_manager.select_model_for_tier(
|
|
1226
|
+
current_tier,
|
|
1227
|
+
provider: @provider_manager.current_provider
|
|
1228
|
+
)
|
|
1229
|
+
|
|
1230
|
+
Aidp.logger.debug("work_loop", "Selected model for tier",
|
|
1231
|
+
tier: current_tier,
|
|
1232
|
+
provider: provider_name,
|
|
1233
|
+
model: model_name,
|
|
1234
|
+
step: @step_name,
|
|
1235
|
+
iteration: @iteration_count)
|
|
1236
|
+
|
|
1237
|
+
[provider_name, model_name, model_data]
|
|
1238
|
+
end
|
|
1239
|
+
|
|
1240
|
+
# Track test/lint/formatter/build/doc failures and escalate tier if needed
|
|
1241
|
+
def track_failures_and_escalate(all_results)
|
|
1242
|
+
all_pass = all_results.values.all? { |result| result[:success] }
|
|
1243
|
+
|
|
1244
|
+
if all_pass
|
|
1245
|
+
# Reset failure count on success
|
|
1246
|
+
@consecutive_failures = 0
|
|
1247
|
+
else
|
|
1248
|
+
# Increment failure count
|
|
1249
|
+
@consecutive_failures += 1
|
|
1250
|
+
|
|
1251
|
+
# Check if we should escalate based on consecutive failures
|
|
1252
|
+
if @thinking_depth_manager.should_escalate_on_failures?(@consecutive_failures)
|
|
1253
|
+
escalate_thinking_tier("consecutive_failures")
|
|
1254
|
+
end
|
|
1255
|
+
end
|
|
1256
|
+
|
|
1257
|
+
# Check complexity-based escalation
|
|
1258
|
+
changed_files = get_changed_files
|
|
1259
|
+
if @thinking_depth_manager.should_escalate_on_complexity?(
|
|
1260
|
+
files_changed: changed_files.size,
|
|
1261
|
+
modules_touched: estimate_modules_touched(changed_files)
|
|
1262
|
+
)
|
|
1263
|
+
escalate_thinking_tier("complexity_threshold")
|
|
1264
|
+
end
|
|
1265
|
+
end
|
|
1266
|
+
|
|
1267
|
+
# Escalate to next thinking tier
|
|
1268
|
+
def escalate_thinking_tier(reason)
|
|
1269
|
+
old_tier = @thinking_depth_manager.current_tier
|
|
1270
|
+
new_tier = @thinking_depth_manager.escalate_tier(reason: reason)
|
|
1271
|
+
|
|
1272
|
+
if new_tier
|
|
1273
|
+
display_message(" ⬆️ Escalated thinking tier: #{old_tier} → #{new_tier} (#{reason})", type: :warning)
|
|
1274
|
+
Aidp.logger.info("work_loop", "Escalated thinking tier",
|
|
1275
|
+
from: old_tier,
|
|
1276
|
+
to: new_tier,
|
|
1277
|
+
reason: reason,
|
|
1278
|
+
step: @step_name,
|
|
1279
|
+
iteration: @iteration_count,
|
|
1280
|
+
consecutive_failures: @consecutive_failures)
|
|
1281
|
+
|
|
1282
|
+
# Reset last tier to trigger display of new tier
|
|
1283
|
+
@last_tier = nil
|
|
1284
|
+
else
|
|
1285
|
+
Aidp.logger.debug("work_loop", "Cannot escalate tier further",
|
|
1286
|
+
current: old_tier,
|
|
1287
|
+
max: @thinking_depth_manager.max_tier,
|
|
1288
|
+
reason: reason)
|
|
1289
|
+
end
|
|
1290
|
+
end
|
|
1291
|
+
|
|
1292
|
+
# Estimate number of modules touched based on file paths
|
|
1293
|
+
def estimate_modules_touched(files)
|
|
1294
|
+
# Group files by their top-level directory or module
|
|
1295
|
+
modules = files.map do |file|
|
|
1296
|
+
parts = file.split("/")
|
|
1297
|
+
# Consider top 2 levels as module identifier
|
|
1298
|
+
parts.take(2).join("/")
|
|
1299
|
+
end.uniq
|
|
1300
|
+
|
|
1301
|
+
modules.size
|
|
1302
|
+
end
|
|
1303
|
+
|
|
1304
|
+
# Get thinking depth status for display
|
|
1305
|
+
def thinking_depth_status
|
|
1306
|
+
{
|
|
1307
|
+
current_tier: @thinking_depth_manager.current_tier,
|
|
1308
|
+
max_tier: @thinking_depth_manager.max_tier,
|
|
1309
|
+
can_escalate: @thinking_depth_manager.can_escalate?,
|
|
1310
|
+
consecutive_failures: @consecutive_failures,
|
|
1311
|
+
escalation_count: @thinking_depth_manager.escalation_count
|
|
1312
|
+
}
|
|
1313
|
+
end
|
|
1117
1314
|
end
|
|
1118
1315
|
end
|
|
1119
1316
|
end
|
|
@@ -10,10 +10,10 @@ module Aidp
|
|
|
10
10
|
class WorkflowSelector
|
|
11
11
|
include Aidp::MessageDisplay
|
|
12
12
|
|
|
13
|
-
def initialize(prompt: TTY::Prompt.new)
|
|
13
|
+
def initialize(prompt: TTY::Prompt.new, workflow_selector: nil)
|
|
14
14
|
@user_input = {}
|
|
15
15
|
@prompt = prompt
|
|
16
|
-
@workflow_selector = Aidp::Workflows::Selector.new(prompt: @prompt)
|
|
16
|
+
@workflow_selector = workflow_selector || Aidp::Workflows::Selector.new(prompt: @prompt)
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
# Main entry point for interactive workflow selection
|
|
@@ -316,17 +316,19 @@ module Aidp
|
|
|
316
316
|
def handle_validation_errors(errors)
|
|
317
317
|
error_message = "Configuration validation failed:\n" + errors.join("\n")
|
|
318
318
|
|
|
319
|
-
# Log error
|
|
320
|
-
|
|
321
|
-
Rails.logger
|
|
322
|
-
|
|
323
|
-
|
|
319
|
+
# Log error (suppress in test/CI environments)
|
|
320
|
+
unless suppress_config_warnings?
|
|
321
|
+
if defined?(Rails) && Rails.logger
|
|
322
|
+
Rails.logger.error(error_message)
|
|
323
|
+
else
|
|
324
|
+
warn(error_message)
|
|
325
|
+
end
|
|
324
326
|
end
|
|
325
327
|
|
|
326
328
|
# In development, try to fix common issues
|
|
327
329
|
if ENV["AIDP_ENV"] == "development" || ENV["RACK_ENV"] == "development"
|
|
328
330
|
if @validator.fix_common_issues
|
|
329
|
-
warn("Attempted to fix configuration issues. Please review the updated configuration file.")
|
|
331
|
+
warn("Attempted to fix configuration issues. Please review the updated configuration file.") unless suppress_config_warnings?
|
|
330
332
|
end
|
|
331
333
|
end
|
|
332
334
|
end
|
|
@@ -334,11 +336,13 @@ module Aidp
|
|
|
334
336
|
def log_warnings(warnings)
|
|
335
337
|
warning_message = "Configuration warnings:\n" + warnings.join("\n")
|
|
336
338
|
|
|
337
|
-
# Log warnings
|
|
338
|
-
|
|
339
|
-
Rails.logger
|
|
340
|
-
|
|
341
|
-
|
|
339
|
+
# Log warnings (suppress in test/CI environments)
|
|
340
|
+
unless suppress_config_warnings?
|
|
341
|
+
if defined?(Rails) && Rails.logger
|
|
342
|
+
Rails.logger.warn(warning_message)
|
|
343
|
+
else
|
|
344
|
+
warn(warning_message)
|
|
345
|
+
end
|
|
342
346
|
end
|
|
343
347
|
end
|
|
344
348
|
|
|
@@ -390,6 +394,11 @@ module Aidp
|
|
|
390
394
|
false
|
|
391
395
|
end
|
|
392
396
|
end
|
|
397
|
+
|
|
398
|
+
# Suppress configuration warnings in test/CI environments
|
|
399
|
+
def suppress_config_warnings?
|
|
400
|
+
ENV["RSPEC_RUNNING"] || ENV["CI"] || ENV["RAILS_ENV"] == "test" || ENV["RACK_ENV"] == "test"
|
|
401
|
+
end
|
|
393
402
|
end
|
|
394
403
|
end
|
|
395
404
|
end
|
|
@@ -359,19 +359,19 @@ module Aidp
|
|
|
359
359
|
def load_config_with_options(options)
|
|
360
360
|
# Apply different loading strategies based on options
|
|
361
361
|
if options[:mode]
|
|
362
|
-
@loader.
|
|
362
|
+
@loader.mode_config(options[:mode], options[:force_reload])
|
|
363
363
|
elsif options[:environment]
|
|
364
|
-
@loader.
|
|
364
|
+
@loader.environment_config(options[:environment], options[:force_reload])
|
|
365
365
|
elsif options[:step]
|
|
366
366
|
@loader.get_step_config(options[:step], options[:force_reload])
|
|
367
367
|
elsif options[:features]
|
|
368
|
-
@loader.
|
|
368
|
+
@loader.config_with_features(options[:features], options[:force_reload])
|
|
369
369
|
elsif options[:user]
|
|
370
370
|
@loader.get_user_config(options[:user], options[:force_reload])
|
|
371
371
|
elsif options[:time_based]
|
|
372
|
-
@loader.
|
|
372
|
+
@loader.time_based_config(options[:force_reload])
|
|
373
373
|
elsif options[:overrides]
|
|
374
|
-
@loader.
|
|
374
|
+
@loader.config_with_overrides(options[:overrides])
|
|
375
375
|
else
|
|
376
376
|
@loader.load_config(options[:force_reload])
|
|
377
377
|
end
|
|
@@ -375,6 +375,9 @@ module Aidp
|
|
|
375
375
|
max_iterations: 50,
|
|
376
376
|
test_commands: [],
|
|
377
377
|
lint_commands: [],
|
|
378
|
+
formatter_commands: [],
|
|
379
|
+
build_commands: [],
|
|
380
|
+
documentation_commands: [],
|
|
378
381
|
units: {},
|
|
379
382
|
guards: {enabled: false},
|
|
380
383
|
version_control: {tool: "git", behavior: "nothing", conventional_commits: false},
|
|
@@ -397,18 +400,37 @@ module Aidp
|
|
|
397
400
|
test_commands: {
|
|
398
401
|
type: :array,
|
|
399
402
|
required: false,
|
|
400
|
-
default: []
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
}
|
|
403
|
+
default: []
|
|
404
|
+
# Items can be strings or {command: string, required: boolean}
|
|
405
|
+
# Validation handled in Configuration class for flexibility
|
|
404
406
|
},
|
|
405
407
|
lint_commands: {
|
|
406
408
|
type: :array,
|
|
407
409
|
required: false,
|
|
408
|
-
default: []
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
410
|
+
default: []
|
|
411
|
+
# Items can be strings or {command: string, required: boolean}
|
|
412
|
+
# Validation handled in Configuration class for flexibility
|
|
413
|
+
},
|
|
414
|
+
formatter_commands: {
|
|
415
|
+
type: :array,
|
|
416
|
+
required: false,
|
|
417
|
+
default: []
|
|
418
|
+
# Items can be strings or {command: string, required: boolean}
|
|
419
|
+
# Validation handled in Configuration class for flexibility
|
|
420
|
+
},
|
|
421
|
+
build_commands: {
|
|
422
|
+
type: :array,
|
|
423
|
+
required: false,
|
|
424
|
+
default: []
|
|
425
|
+
# Items can be strings or {command: string, required: boolean}
|
|
426
|
+
# Validation handled in Configuration class for flexibility
|
|
427
|
+
},
|
|
428
|
+
documentation_commands: {
|
|
429
|
+
type: :array,
|
|
430
|
+
required: false,
|
|
431
|
+
default: []
|
|
432
|
+
# Items can be strings or {command: string, required: boolean}
|
|
433
|
+
# Validation handled in Configuration class for flexibility
|
|
412
434
|
},
|
|
413
435
|
units: {
|
|
414
436
|
type: :hash,
|