aidp 0.34.0 → 0.39.3
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 +14 -14
- data/lib/aidp/agent_harness_adapter.rb +309 -0
- data/lib/aidp/cli/issue_importer.rb +20 -6
- data/lib/aidp/cli/jobs_command.rb +1 -1
- data/lib/aidp/cli/models_command.rb +9 -16
- data/lib/aidp/cli/prompts_command.rb +253 -0
- data/lib/aidp/cli/security_command.rb +4 -10
- data/lib/aidp/cli/storage_command.rb +277 -0
- data/lib/aidp/cli/temporal_command.rb +460 -0
- data/lib/aidp/cli.rb +24 -2
- data/lib/aidp/config.rb +15 -0
- data/lib/aidp/config_paths.rb +12 -2
- data/lib/aidp/database/migrations.rb +114 -0
- data/lib/aidp/database/repositories/checkpoint_repository.rb +174 -0
- data/lib/aidp/database/repositories/deprecated_models_repository.rb +206 -0
- data/lib/aidp/database/repositories/evaluation_repository.rb +208 -0
- data/lib/aidp/database/repositories/harness_state_repository.rb +140 -0
- data/lib/aidp/database/repositories/job_repository.rb +278 -0
- data/lib/aidp/database/repositories/model_cache_repository.rb +194 -0
- data/lib/aidp/database/repositories/progress_repository.rb +210 -0
- data/lib/aidp/database/repositories/prompt_archive_repository.rb +195 -0
- data/lib/aidp/database/repositories/prompt_feedback_repository.rb +266 -0
- data/lib/aidp/database/repositories/provider_info_cache_repository.rb +208 -0
- data/lib/aidp/database/repositories/provider_metrics_repository.rb +245 -0
- data/lib/aidp/database/repositories/secrets_repository.rb +187 -0
- data/lib/aidp/database/repositories/task_repository.rb +231 -0
- data/lib/aidp/database/repositories/template_version_repository.rb +383 -0
- data/lib/aidp/database/repositories/watch_state_repository.rb +472 -0
- data/lib/aidp/database/repositories/workstream_repository.rb +310 -0
- data/lib/aidp/database/repositories/worktree_repository.rb +240 -0
- data/lib/aidp/database/repository.rb +166 -0
- data/lib/aidp/database/schema.rb +347 -0
- data/lib/aidp/database/storage_migrator.rb +693 -0
- data/lib/aidp/database.rb +139 -0
- data/lib/aidp/debug_mixin.rb +2 -2
- data/lib/aidp/execute/checkpoint.rb +26 -0
- data/lib/aidp/execute/checkpoint_display.rb +16 -0
- data/lib/aidp/execute/prompt_evaluator.rb +30 -57
- data/lib/aidp/execute/work_loop_runner.rb +294 -46
- data/lib/aidp/firewall/provider_requirements_collector.rb +7 -23
- data/lib/aidp/harness/agent_harness_provider_manager.rb +275 -0
- data/lib/aidp/harness/ai_decision_engine.rb +78 -296
- data/lib/aidp/harness/config_schema.rb +59 -0
- data/lib/aidp/harness/configuration.rb +229 -10
- data/lib/aidp/harness/deprecation_cache.rb +53 -11
- data/lib/aidp/harness/enhanced_runner.rb +1 -1
- data/lib/aidp/harness/error_handler.rb +11 -5
- data/lib/aidp/harness/provider_config.rb +36 -0
- data/lib/aidp/harness/provider_factory.rb +26 -24
- data/lib/aidp/harness/provider_info.rb +9 -5
- data/lib/aidp/harness/provider_manager.rb +2 -2
- data/lib/aidp/harness/provider_metrics.rb +103 -1
- data/lib/aidp/harness/rspec_command_optimizer.rb +166 -0
- data/lib/aidp/harness/ruby_llm_registry.rb +97 -8
- data/lib/aidp/harness/runner.rb +7 -2
- data/lib/aidp/harness/state_manager.rb +1 -1
- data/lib/aidp/harness/test_runner.rb +167 -11
- data/lib/aidp/harness/thinking_depth_manager.rb +564 -5
- data/lib/aidp/harness/ui.rb +11 -0
- data/lib/aidp/harness/usage_limit.rb +179 -0
- data/lib/aidp/harness/usage_limit_enforcer.rb +240 -0
- data/lib/aidp/harness/usage_limit_tracker.rb +308 -0
- data/lib/aidp/harness/usage_period.rb +234 -0
- data/lib/aidp/init/agent_instructions_generator.rb +317 -0
- data/lib/aidp/init/runner.rb +25 -4
- data/lib/aidp/interfaces/activity_monitor_interface.rb +234 -0
- data/lib/aidp/interfaces/binary_checker_interface.rb +232 -0
- data/lib/aidp/interfaces/command_executor_interface.rb +216 -0
- data/lib/aidp/interfaces/logger_interface.rb +150 -0
- data/lib/aidp/interfaces/ui_interface.rb +254 -0
- data/lib/aidp/logger.rb +25 -7
- data/lib/aidp/orchestration_adapter.rb +279 -0
- data/lib/aidp/pr_worktree_manager.rb +4 -15
- data/lib/aidp/prompts/feedback_collector.rb +198 -0
- data/lib/aidp/prompts/prompt_template_manager.rb +415 -0
- data/lib/aidp/prompts/template_evolver.rb +305 -0
- data/lib/aidp/prompts/template_version_manager.rb +325 -0
- data/lib/aidp/setup/in_memory_config_adapter.rb +257 -0
- data/lib/aidp/setup/in_memory_config_manager.rb +262 -0
- data/lib/aidp/setup/wizard.rb +616 -176
- data/lib/aidp/shell_executor.rb +58 -0
- data/lib/aidp/style_guide/selector.rb +56 -1
- data/lib/aidp/temporal/activities/analyze_issue_activity.rb +198 -0
- data/lib/aidp/temporal/activities/analyze_sub_task_activity.rb +163 -0
- data/lib/aidp/temporal/activities/base_activity.rb +78 -0
- data/lib/aidp/temporal/activities/create_plan_activity.rb +115 -0
- data/lib/aidp/temporal/activities/create_pr_activity.rb +193 -0
- data/lib/aidp/temporal/activities/create_prompt_activity.rb +118 -0
- data/lib/aidp/temporal/activities/diagnose_failure_activity.rb +228 -0
- data/lib/aidp/temporal/activities/prepare_next_iteration_activity.rb +147 -0
- data/lib/aidp/temporal/activities/record_checkpoint_activity.rb +81 -0
- data/lib/aidp/temporal/activities/run_agent_activity.rb +139 -0
- data/lib/aidp/temporal/activities/run_tests_activity.rb +114 -0
- data/lib/aidp/temporal/activities/run_work_loop_iteration_activity.rb +249 -0
- data/lib/aidp/temporal/configuration.rb +169 -0
- data/lib/aidp/temporal/connection.rb +93 -0
- data/lib/aidp/temporal/worker.rb +119 -0
- data/lib/aidp/temporal/workflow_client.rb +171 -0
- data/lib/aidp/temporal/workflows/base_workflow.rb +73 -0
- data/lib/aidp/temporal/workflows/issue_to_pr_workflow.rb +278 -0
- data/lib/aidp/temporal/workflows/sub_issue_workflow.rb +253 -0
- data/lib/aidp/temporal/workflows/work_loop_workflow.rb +321 -0
- data/lib/aidp/temporal.rb +120 -0
- data/lib/aidp/version.rb +1 -1
- data/lib/aidp/watch/base_processor.rb +35 -0
- data/lib/aidp/watch/build_processor.rb +132 -0
- data/lib/aidp/watch/github_state_extractor.rb +0 -8
- data/lib/aidp/watch/rebase_processor.rb +245 -0
- data/lib/aidp/watch/round_robin_scheduler.rb +150 -0
- data/lib/aidp/watch/runner.rb +366 -285
- data/lib/aidp/watch/state_store.rb +80 -0
- data/lib/aidp/watch/work_item.rb +96 -0
- data/lib/aidp/watch/worktree_cleanup_job.rb +226 -0
- data/lib/aidp/watch/worktree_reconciler.rb +643 -0
- data/lib/aidp/workflows/guided_agent.rb +1 -1
- data/lib/aidp/worktree.rb +62 -0
- data/templates/aidp.yml.example +70 -0
- metadata +118 -16
- data/lib/aidp/analyze/json_file_storage.rb +0 -292
- data/lib/aidp/execute/future_work_backlog.rb +0 -411
- data/lib/aidp/providers/adapter.rb +0 -239
- data/lib/aidp/providers/aider.rb +0 -264
- data/lib/aidp/providers/anthropic.rb +0 -614
- data/lib/aidp/providers/base.rb +0 -617
- data/lib/aidp/providers/capability_registry.rb +0 -204
- data/lib/aidp/providers/codex.rb +0 -267
- data/lib/aidp/providers/cursor.rb +0 -304
- data/lib/aidp/providers/error_taxonomy.rb +0 -195
- data/lib/aidp/providers/gemini.rb +0 -110
- data/lib/aidp/providers/github_copilot.rb +0 -227
- data/lib/aidp/providers/kilocode.rb +0 -157
- data/lib/aidp/providers/opencode.rb +0 -139
|
@@ -71,10 +71,16 @@ module Aidp
|
|
|
71
71
|
@unit_scheduler = nil
|
|
72
72
|
|
|
73
73
|
# Initialize thinking depth manager for intelligent model selection
|
|
74
|
+
# Issue #375: Enable autonomous mode by default for work loops
|
|
74
75
|
require_relative "../harness/thinking_depth_manager"
|
|
75
|
-
@thinking_depth_manager = options[:thinking_depth_manager] || Aidp::Harness::ThinkingDepthManager.new(
|
|
76
|
+
@thinking_depth_manager = options[:thinking_depth_manager] || Aidp::Harness::ThinkingDepthManager.new(
|
|
77
|
+
config,
|
|
78
|
+
root_dir: @project_dir,
|
|
79
|
+
autonomous_mode: true # Issue #375: Work loops use autonomous mode
|
|
80
|
+
)
|
|
76
81
|
@consecutive_failures = 0
|
|
77
82
|
@last_tier = nil
|
|
83
|
+
@last_model = nil # Issue #375: Track last used model
|
|
78
84
|
|
|
79
85
|
# Initialize style guide selector for intelligent section selection
|
|
80
86
|
@style_guide_selector = options[:style_guide_selector] || Aidp::StyleGuide::Selector.new(project_dir: project_dir)
|
|
@@ -281,26 +287,9 @@ module Aidp
|
|
|
281
287
|
process_task_filing(agent_result)
|
|
282
288
|
|
|
283
289
|
transition_to(:test)
|
|
284
|
-
# Run all configured checks
|
|
285
|
-
test_results = @test_runner.run_tests
|
|
286
|
-
lint_results = @test_runner.run_linters
|
|
287
|
-
build_results = @test_runner.run_builds
|
|
288
|
-
doc_results = @test_runner.run_documentation
|
|
289
|
-
|
|
290
|
-
# Run formatters only if agent marked work complete (per issue #234)
|
|
291
|
-
formatter_results = if agent_marked_complete?(agent_result)
|
|
292
|
-
@test_runner.run_formatters
|
|
293
|
-
else
|
|
294
|
-
{success: true, output: "Formatters: Skipped (work not complete)", failures: [], required_failures: []}
|
|
295
|
-
end
|
|
296
290
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
lints: lint_results,
|
|
300
|
-
formatters: formatter_results,
|
|
301
|
-
builds: build_results,
|
|
302
|
-
docs: doc_results
|
|
303
|
-
}
|
|
291
|
+
# Run all configured checks using phase-based execution
|
|
292
|
+
all_results = run_phase_based_commands(agent_result)
|
|
304
293
|
|
|
305
294
|
record_periodic_checkpoint(all_results)
|
|
306
295
|
|
|
@@ -308,28 +297,21 @@ module Aidp
|
|
|
308
297
|
track_failures_and_escalate(all_results)
|
|
309
298
|
|
|
310
299
|
# All required checks must pass for completion
|
|
311
|
-
all_checks_pass =
|
|
312
|
-
lint_results[:success] &&
|
|
313
|
-
formatter_results[:success] &&
|
|
314
|
-
build_results[:success] &&
|
|
315
|
-
doc_results[:success]
|
|
300
|
+
all_checks_pass = all_results.values.all? { |r| r[:success] }
|
|
316
301
|
|
|
317
302
|
# Check task completion status
|
|
318
303
|
task_completion_result = check_task_completion
|
|
319
304
|
agent_completed = agent_marked_complete?(agent_result)
|
|
320
305
|
|
|
321
306
|
# FIX for issue #391: Comprehensive logging at completion decision point
|
|
307
|
+
results_summary = all_results.transform_values { |r| r[:success] }
|
|
322
308
|
Aidp.log_debug("work_loop", "completion_decision_point",
|
|
323
309
|
iteration: @iteration_count,
|
|
324
310
|
all_checks_pass: all_checks_pass,
|
|
325
311
|
agent_marked_complete: agent_completed,
|
|
326
312
|
task_completion_complete: task_completion_result[:complete],
|
|
327
313
|
task_completion_reason: task_completion_result[:reason],
|
|
328
|
-
|
|
329
|
-
lint_success: lint_results[:success],
|
|
330
|
-
formatter_success: formatter_results[:success],
|
|
331
|
-
build_success: build_results[:success],
|
|
332
|
-
doc_success: doc_results[:success])
|
|
314
|
+
phase_results: results_summary)
|
|
333
315
|
|
|
334
316
|
if all_checks_pass
|
|
335
317
|
transition_to(:pass)
|
|
@@ -341,6 +323,16 @@ module Aidp
|
|
|
341
323
|
iteration: @iteration_count,
|
|
342
324
|
reason: task_completion_result[:reason])
|
|
343
325
|
|
|
326
|
+
# Run full_loop phase commands before final completion
|
|
327
|
+
full_loop_results = run_full_loop_commands
|
|
328
|
+
unless full_loop_results[:success]
|
|
329
|
+
# Full loop commands failed - continue iterating
|
|
330
|
+
display_message(" Full loop commands failed, continuing work loop", type: :warning)
|
|
331
|
+
all_results[:full_loop] = full_loop_results
|
|
332
|
+
transition_to(:fail)
|
|
333
|
+
next
|
|
334
|
+
end
|
|
335
|
+
|
|
344
336
|
transition_to(:done)
|
|
345
337
|
record_final_checkpoint(all_results)
|
|
346
338
|
display_task_summary
|
|
@@ -510,8 +502,9 @@ module Aidp
|
|
|
510
502
|
|
|
511
503
|
def append_evaluation_feedback_to_prompt(evaluation)
|
|
512
504
|
feedback_section = build_evaluation_feedback_section(evaluation)
|
|
513
|
-
|
|
514
|
-
|
|
505
|
+
current_prompt = @prompt_manager.read || ""
|
|
506
|
+
updated_prompt = current_prompt + "\n\n---\n\n" + feedback_section
|
|
507
|
+
@prompt_manager.write(updated_prompt, step_name: @step_name)
|
|
515
508
|
|
|
516
509
|
Aidp.log_debug("work_loop", "appended_evaluation_feedback",
|
|
517
510
|
iteration: @iteration_count,
|
|
@@ -771,6 +764,81 @@ module Aidp
|
|
|
771
764
|
result[:status] == "completed" || prompt_marked_complete?
|
|
772
765
|
end
|
|
773
766
|
|
|
767
|
+
# Run commands using the new phase-based execution model
|
|
768
|
+
# This method supports both the new generic commands and legacy category-specific commands
|
|
769
|
+
#
|
|
770
|
+
# @param agent_result [Hash] Result from the agent (used to determine if on_completion should run)
|
|
771
|
+
# @return [Hash] Results keyed by phase/category
|
|
772
|
+
def run_phase_based_commands(agent_result)
|
|
773
|
+
all_results = {}
|
|
774
|
+
|
|
775
|
+
# Check if we're using the new generic commands or legacy category commands
|
|
776
|
+
if @config.respond_to?(:commands) && @config.commands.any?
|
|
777
|
+
# New phase-based execution
|
|
778
|
+
each_unit_results = @test_runner.run_commands_for_phase(:each_unit)
|
|
779
|
+
all_results[:each_unit] = each_unit_results
|
|
780
|
+
|
|
781
|
+
# Run on_completion commands only if agent marked work complete
|
|
782
|
+
if agent_marked_complete?(agent_result)
|
|
783
|
+
on_completion_results = @test_runner.run_commands_for_phase(:on_completion)
|
|
784
|
+
all_results[:on_completion] = on_completion_results
|
|
785
|
+
else
|
|
786
|
+
all_results[:on_completion] = {
|
|
787
|
+
success: true,
|
|
788
|
+
output: "On-completion commands: Skipped (work not complete)",
|
|
789
|
+
failures: [],
|
|
790
|
+
required_failures: []
|
|
791
|
+
}
|
|
792
|
+
end
|
|
793
|
+
|
|
794
|
+
Aidp.log_debug("work_loop", "ran_phase_based_commands",
|
|
795
|
+
each_unit_success: each_unit_results[:success],
|
|
796
|
+
on_completion_success: all_results[:on_completion][:success],
|
|
797
|
+
agent_completed: agent_marked_complete?(agent_result))
|
|
798
|
+
else
|
|
799
|
+
# Legacy category-based execution for backwards compatibility
|
|
800
|
+
all_results = run_legacy_category_commands(agent_result)
|
|
801
|
+
end
|
|
802
|
+
|
|
803
|
+
all_results
|
|
804
|
+
end
|
|
805
|
+
|
|
806
|
+
# Run full_loop phase commands (only at end of entire work loop)
|
|
807
|
+
def run_full_loop_commands
|
|
808
|
+
return {success: true, output: "", failures: [], required_failures: []} unless @config.respond_to?(:commands)
|
|
809
|
+
|
|
810
|
+
full_loop_results = @test_runner.run_commands_for_phase(:full_loop)
|
|
811
|
+
|
|
812
|
+
Aidp.log_debug("work_loop", "ran_full_loop_commands",
|
|
813
|
+
success: full_loop_results[:success],
|
|
814
|
+
command_count: full_loop_results[:results_by_command]&.size || 0)
|
|
815
|
+
|
|
816
|
+
full_loop_results
|
|
817
|
+
end
|
|
818
|
+
|
|
819
|
+
# Run commands using legacy category-based approach (backwards compatibility)
|
|
820
|
+
def run_legacy_category_commands(agent_result)
|
|
821
|
+
test_results = @test_runner.run_tests
|
|
822
|
+
lint_results = @test_runner.run_linters
|
|
823
|
+
build_results = @test_runner.run_builds
|
|
824
|
+
doc_results = @test_runner.run_documentation
|
|
825
|
+
|
|
826
|
+
# Run formatters only if agent marked work complete (per issue #234)
|
|
827
|
+
formatter_results = if agent_marked_complete?(agent_result)
|
|
828
|
+
@test_runner.run_formatters
|
|
829
|
+
else
|
|
830
|
+
{success: true, output: "Formatters: Skipped (work not complete)", failures: [], required_failures: []}
|
|
831
|
+
end
|
|
832
|
+
|
|
833
|
+
{
|
|
834
|
+
tests: test_results,
|
|
835
|
+
lints: lint_results,
|
|
836
|
+
formatters: formatter_results,
|
|
837
|
+
builds: build_results,
|
|
838
|
+
docs: doc_results
|
|
839
|
+
}
|
|
840
|
+
end
|
|
841
|
+
|
|
774
842
|
# Diagnose all failures (tests, lints, formatters, builds, docs)
|
|
775
843
|
# Returns diagnostic information to help agent understand what went wrong
|
|
776
844
|
def diagnose_failures(all_results)
|
|
@@ -818,6 +886,8 @@ module Aidp
|
|
|
818
886
|
user_input = format_user_input(context[:user_input])
|
|
819
887
|
deterministic_outputs = Array(context[:deterministic_outputs])
|
|
820
888
|
previous_summary = context[:previous_agent_summary]
|
|
889
|
+
task_description = format_task_description(user_input, previous_summary)
|
|
890
|
+
additional_context = format_additional_context(context[:additional_context])
|
|
821
891
|
|
|
822
892
|
initial_prompt = build_initial_prompt_content(
|
|
823
893
|
template: template_content,
|
|
@@ -826,7 +896,9 @@ module Aidp
|
|
|
826
896
|
user_input: user_input,
|
|
827
897
|
step_name: @step_name,
|
|
828
898
|
deterministic_outputs: deterministic_outputs,
|
|
829
|
-
previous_agent_summary: previous_summary
|
|
899
|
+
previous_agent_summary: previous_summary,
|
|
900
|
+
task_description: task_description,
|
|
901
|
+
additional_context: additional_context
|
|
830
902
|
)
|
|
831
903
|
|
|
832
904
|
@prompt_manager.write(initial_prompt, step_name: @step_name)
|
|
@@ -910,6 +982,42 @@ module Aidp
|
|
|
910
982
|
parts.join("\n\n")
|
|
911
983
|
end
|
|
912
984
|
|
|
985
|
+
def format_task_description(user_input, previous_agent_summary)
|
|
986
|
+
description = build_task_description(user_input, {previous_agent_summary: previous_agent_summary}).to_s.strip
|
|
987
|
+
description.empty? ? "_No task description provided._" : description
|
|
988
|
+
end
|
|
989
|
+
|
|
990
|
+
def format_additional_context(additional_context)
|
|
991
|
+
return "_No additional context._" if additional_context.nil?
|
|
992
|
+
|
|
993
|
+
formatted = case additional_context
|
|
994
|
+
when String
|
|
995
|
+
additional_context.strip
|
|
996
|
+
when Array
|
|
997
|
+
additional_context.map do |entry|
|
|
998
|
+
if entry.is_a?(Hash)
|
|
999
|
+
entry.map { |key, value| "#{key}: #{value}" }.join(", ")
|
|
1000
|
+
else
|
|
1001
|
+
entry.to_s
|
|
1002
|
+
end
|
|
1003
|
+
end.reject(&:empty?).map { |line| "- #{line}" }.join("\n")
|
|
1004
|
+
when Hash
|
|
1005
|
+
additional_context.map { |key, value| "- #{key}: #{value}" }.join("\n")
|
|
1006
|
+
else
|
|
1007
|
+
additional_context.to_s
|
|
1008
|
+
end
|
|
1009
|
+
|
|
1010
|
+
formatted.empty? ? "_No additional context._" : formatted
|
|
1011
|
+
end
|
|
1012
|
+
|
|
1013
|
+
def interpolate_task_template(template, task_description:, additional_context:)
|
|
1014
|
+
return "" if template.nil?
|
|
1015
|
+
|
|
1016
|
+
template
|
|
1017
|
+
.gsub("{{task_description}}", task_description.to_s)
|
|
1018
|
+
.gsub("{{additional_context}}", additional_context.to_s)
|
|
1019
|
+
end
|
|
1020
|
+
|
|
913
1021
|
# Extract relevant tags from input and spec
|
|
914
1022
|
def extract_tags(user_input, step_spec)
|
|
915
1023
|
tags = []
|
|
@@ -930,16 +1038,16 @@ module Aidp
|
|
|
930
1038
|
tags.uniq
|
|
931
1039
|
end
|
|
932
1040
|
|
|
933
|
-
def build_initial_prompt_content(template:, prd:, style_guide:, user_input:, step_name:, deterministic_outputs:, previous_agent_summary:)
|
|
1041
|
+
def build_initial_prompt_content(template:, prd:, style_guide:, user_input:, step_name:, deterministic_outputs:, previous_agent_summary:, task_description:, additional_context:)
|
|
934
1042
|
parts = []
|
|
935
1043
|
|
|
936
1044
|
parts << "# Work Loop: #{step_name}"
|
|
937
1045
|
parts << ""
|
|
938
1046
|
parts << "## Instructions"
|
|
939
1047
|
parts << "You are working in a work loop. Your responsibilities:"
|
|
940
|
-
parts << "1. Read this PROMPT.md
|
|
1048
|
+
parts << "1. Read this file (`.aidp/PROMPT.md`) to understand what needs to be done"
|
|
941
1049
|
parts << "2. Complete the work described below"
|
|
942
|
-
parts << "3. **IMPORTANT**: Edit this PROMPT.md file
|
|
1050
|
+
parts << "3. **IMPORTANT**: Edit this `.aidp/PROMPT.md` file to:"
|
|
943
1051
|
parts << " - Remove completed items"
|
|
944
1052
|
parts << " - Update with current status"
|
|
945
1053
|
parts << " - Keep it concise (remove unnecessary context)"
|
|
@@ -948,7 +1056,7 @@ module Aidp
|
|
|
948
1056
|
parts << "5. If tests/linters fail, you'll see the errors in the next iteration"
|
|
949
1057
|
parts << ""
|
|
950
1058
|
parts << "## Completion Criteria"
|
|
951
|
-
parts << "Mark this step COMPLETE by adding this line to PROMPT.md
|
|
1059
|
+
parts << "Mark this step COMPLETE by adding this line to `.aidp/PROMPT.md`:"
|
|
952
1060
|
parts << "```"
|
|
953
1061
|
parts << "STATUS: COMPLETE"
|
|
954
1062
|
parts << "```"
|
|
@@ -988,7 +1096,11 @@ module Aidp
|
|
|
988
1096
|
end
|
|
989
1097
|
|
|
990
1098
|
parts << "## Task Template"
|
|
991
|
-
parts <<
|
|
1099
|
+
parts << interpolate_task_template(
|
|
1100
|
+
template,
|
|
1101
|
+
task_description: task_description,
|
|
1102
|
+
additional_context: additional_context
|
|
1103
|
+
)
|
|
992
1104
|
parts << ""
|
|
993
1105
|
|
|
994
1106
|
parts.join("\n")
|
|
@@ -1261,7 +1373,7 @@ module Aidp
|
|
|
1261
1373
|
parts << "### Step 3: Complete the Work Loop"
|
|
1262
1374
|
parts << "Only after ALL tasks are done:"
|
|
1263
1375
|
parts << "- Verify tests pass"
|
|
1264
|
-
parts << "- Add STATUS: COMPLETE to PROMPT.md"
|
|
1376
|
+
parts << "- Add STATUS: COMPLETE to `.aidp/PROMPT.md`"
|
|
1265
1377
|
parts << ""
|
|
1266
1378
|
parts << "### Task Rules"
|
|
1267
1379
|
parts << "- **At least ONE task must be filed** - completion blocked without tasks"
|
|
@@ -1285,7 +1397,7 @@ module Aidp
|
|
|
1285
1397
|
end
|
|
1286
1398
|
|
|
1287
1399
|
parts << "## Completion Criteria"
|
|
1288
|
-
parts << "Mark this step COMPLETE by adding these lines to PROMPT.md
|
|
1400
|
+
parts << "Mark this step COMPLETE by adding these lines to `.aidp/PROMPT.md`:"
|
|
1289
1401
|
parts << "```"
|
|
1290
1402
|
parts << "STATUS: COMPLETE"
|
|
1291
1403
|
if @config.task_completion_required?
|
|
@@ -2144,15 +2256,83 @@ module Aidp
|
|
|
2144
2256
|
end
|
|
2145
2257
|
end
|
|
2146
2258
|
|
|
2259
|
+
# Maximum escalation depth to prevent infinite recursion
|
|
2260
|
+
MAX_ESCALATION_DEPTH = 5
|
|
2261
|
+
|
|
2147
2262
|
# Select model based on current thinking depth tier
|
|
2148
2263
|
# Returns [provider_name, model_name, model_data]
|
|
2149
|
-
|
|
2264
|
+
# Issue #375: Uses intelligent model selection in autonomous mode
|
|
2265
|
+
# @param escalation_depth [Integer] Current recursion depth (prevents infinite loops)
|
|
2266
|
+
def select_model_for_current_tier(escalation_depth: 0)
|
|
2150
2267
|
current_tier = @thinking_depth_manager.current_tier
|
|
2268
|
+
provider = @provider_manager.current_provider
|
|
2269
|
+
|
|
2270
|
+
# Issue #375: In autonomous mode, use intelligent model selection
|
|
2271
|
+
# that considers previous attempts and prefers untested models
|
|
2272
|
+
if @thinking_depth_manager.autonomous_mode?
|
|
2273
|
+
model_name = @thinking_depth_manager.select_next_model(provider: provider)
|
|
2274
|
+
if model_name
|
|
2275
|
+
@last_model = model_name
|
|
2276
|
+
Aidp.logger.debug("work_loop", "Selected model intelligently",
|
|
2277
|
+
tier: current_tier,
|
|
2278
|
+
provider: provider,
|
|
2279
|
+
model: model_name,
|
|
2280
|
+
step: @step_name,
|
|
2281
|
+
iteration: @iteration_count)
|
|
2282
|
+
return [provider, model_name, {}]
|
|
2283
|
+
end
|
|
2284
|
+
|
|
2285
|
+
# No model from intelligent selection - check if we should escalate
|
|
2286
|
+
escalation_check = @thinking_depth_manager.should_escalate_tier?(provider: provider)
|
|
2287
|
+
if escalation_check[:should_escalate] && escalation_depth < MAX_ESCALATION_DEPTH
|
|
2288
|
+
# Attempt escalation to get access to higher-tier models
|
|
2289
|
+
new_tier = @thinking_depth_manager.escalate_tier_intelligent(provider: provider)
|
|
2290
|
+
if new_tier
|
|
2291
|
+
Aidp.logger.info("work_loop", "Escalated tier after exhausting models",
|
|
2292
|
+
from: current_tier,
|
|
2293
|
+
to: new_tier,
|
|
2294
|
+
reason: escalation_check[:reason])
|
|
2295
|
+
# Retry selection with new tier (increment depth to prevent infinite recursion)
|
|
2296
|
+
return select_model_for_current_tier(escalation_depth: escalation_depth + 1)
|
|
2297
|
+
else
|
|
2298
|
+
Aidp.logger.warn("work_loop", "Escalation recommended but not possible",
|
|
2299
|
+
tier: current_tier,
|
|
2300
|
+
reason: "at_max_tier_or_blocked")
|
|
2301
|
+
# Fall through to standard selection as last resort
|
|
2302
|
+
end
|
|
2303
|
+
elsif escalation_depth >= MAX_ESCALATION_DEPTH
|
|
2304
|
+
Aidp.logger.error("work_loop", "Max escalation depth reached - model selection exhausted",
|
|
2305
|
+
depth: escalation_depth,
|
|
2306
|
+
tier: current_tier,
|
|
2307
|
+
provider: provider)
|
|
2308
|
+
raise Aidp::Harness::NoModelAvailableError.new(
|
|
2309
|
+
tier: current_tier,
|
|
2310
|
+
provider: provider
|
|
2311
|
+
)
|
|
2312
|
+
end
|
|
2313
|
+
# Fall through to standard selection if escalation not recommended or not possible
|
|
2314
|
+
end
|
|
2315
|
+
|
|
2316
|
+
# Standard model selection (non-autonomous or fallback)
|
|
2151
2317
|
provider_name, model_name, model_data = @thinking_depth_manager.select_model_for_tier(
|
|
2152
2318
|
current_tier,
|
|
2153
|
-
provider:
|
|
2319
|
+
provider: provider
|
|
2154
2320
|
)
|
|
2155
2321
|
|
|
2322
|
+
# Validate that we got a usable model
|
|
2323
|
+
if model_name.nil?
|
|
2324
|
+
Aidp.logger.error("work_loop", "No model available after standard selection",
|
|
2325
|
+
tier: current_tier,
|
|
2326
|
+
provider: provider_name)
|
|
2327
|
+
raise Aidp::Harness::NoModelAvailableError.new(
|
|
2328
|
+
tier: current_tier,
|
|
2329
|
+
provider: provider_name || provider
|
|
2330
|
+
)
|
|
2331
|
+
end
|
|
2332
|
+
|
|
2333
|
+
# Track the selected model for attempt recording
|
|
2334
|
+
@last_model = model_name
|
|
2335
|
+
|
|
2156
2336
|
Aidp.logger.debug("work_loop", "Selected model for tier",
|
|
2157
2337
|
tier: current_tier,
|
|
2158
2338
|
provider: provider_name,
|
|
@@ -2164,8 +2344,20 @@ module Aidp
|
|
|
2164
2344
|
end
|
|
2165
2345
|
|
|
2166
2346
|
# Track test/lint/formatter/build/doc failures and escalate tier if needed
|
|
2347
|
+
# Issue #375: Uses intelligent escalation that tries all models in tier first
|
|
2167
2348
|
def track_failures_and_escalate(all_results)
|
|
2168
2349
|
all_pass = all_results.values.all? { |result| result[:success] }
|
|
2350
|
+
provider = @provider_manager.current_provider
|
|
2351
|
+
model = @last_model
|
|
2352
|
+
|
|
2353
|
+
# Record model attempt with success/failure
|
|
2354
|
+
if model
|
|
2355
|
+
@thinking_depth_manager.record_model_attempt(
|
|
2356
|
+
provider: provider,
|
|
2357
|
+
model: model,
|
|
2358
|
+
success: all_pass
|
|
2359
|
+
)
|
|
2360
|
+
end
|
|
2169
2361
|
|
|
2170
2362
|
if all_pass
|
|
2171
2363
|
# Reset failure count on success
|
|
@@ -2174,19 +2366,75 @@ module Aidp
|
|
|
2174
2366
|
# Increment failure count
|
|
2175
2367
|
@consecutive_failures += 1
|
|
2176
2368
|
|
|
2177
|
-
#
|
|
2178
|
-
if @thinking_depth_manager.
|
|
2369
|
+
# Issue #375: Use intelligent escalation in autonomous mode
|
|
2370
|
+
if @thinking_depth_manager.autonomous_mode?
|
|
2371
|
+
intelligent_escalate_thinking_tier(provider)
|
|
2372
|
+
elsif @thinking_depth_manager.should_escalate_on_failures?(@consecutive_failures)
|
|
2373
|
+
# Legacy behavior for non-autonomous mode
|
|
2179
2374
|
escalate_thinking_tier("consecutive_failures")
|
|
2180
2375
|
end
|
|
2181
2376
|
end
|
|
2182
2377
|
|
|
2183
|
-
# Check complexity-based escalation
|
|
2378
|
+
# Check complexity-based escalation (applies to both modes)
|
|
2184
2379
|
changed_files = get_changed_files
|
|
2185
2380
|
if @thinking_depth_manager.should_escalate_on_complexity?(
|
|
2186
2381
|
files_changed: changed_files.size,
|
|
2187
2382
|
modules_touched: estimate_modules_touched(changed_files)
|
|
2188
2383
|
)
|
|
2189
|
-
|
|
2384
|
+
# In autonomous mode, only escalate if intelligent check allows
|
|
2385
|
+
if @thinking_depth_manager.autonomous_mode?
|
|
2386
|
+
intelligent_escalate_thinking_tier(provider, reason: "complexity_threshold")
|
|
2387
|
+
else
|
|
2388
|
+
escalate_thinking_tier("complexity_threshold")
|
|
2389
|
+
end
|
|
2390
|
+
end
|
|
2391
|
+
end
|
|
2392
|
+
|
|
2393
|
+
# Issue #375: Intelligent tier escalation that tries all models in current tier first
|
|
2394
|
+
def intelligent_escalate_thinking_tier(provider, reason: nil)
|
|
2395
|
+
escalation_check = @thinking_depth_manager.should_escalate_tier?(provider: provider)
|
|
2396
|
+
|
|
2397
|
+
unless escalation_check[:should_escalate]
|
|
2398
|
+
# Log why we're not escalating yet
|
|
2399
|
+
case escalation_check[:reason]
|
|
2400
|
+
when "untested_models_remain"
|
|
2401
|
+
display_message(" ℹ️ Not escalating tier: #{escalation_check[:untested_count]} untested models remain", type: :info)
|
|
2402
|
+
when "below_min_attempts"
|
|
2403
|
+
display_message(" ℹ️ Not escalating tier: #{escalation_check[:current]}/#{escalation_check[:required]} attempts made", type: :info)
|
|
2404
|
+
end
|
|
2405
|
+
|
|
2406
|
+
Aidp.log_debug("work_loop", "Intelligent escalation blocked",
|
|
2407
|
+
reason: escalation_check[:reason],
|
|
2408
|
+
details: escalation_check)
|
|
2409
|
+
return
|
|
2410
|
+
end
|
|
2411
|
+
|
|
2412
|
+
# Proceed with escalation
|
|
2413
|
+
old_tier = @thinking_depth_manager.current_tier
|
|
2414
|
+
new_tier = @thinking_depth_manager.escalate_tier_intelligent(
|
|
2415
|
+
provider: provider,
|
|
2416
|
+
reason: reason || escalation_check[:reason]
|
|
2417
|
+
)
|
|
2418
|
+
|
|
2419
|
+
if new_tier
|
|
2420
|
+
display_message(" ⬆️ Escalated thinking tier: #{old_tier} → #{new_tier} (#{reason || escalation_check[:reason]})", type: :warning)
|
|
2421
|
+
display_message(" Total attempts in #{old_tier}: #{escalation_check[:total_attempts]}", type: :info)
|
|
2422
|
+
|
|
2423
|
+
Aidp.logger.info("work_loop", "Intelligent tier escalation",
|
|
2424
|
+
from: old_tier,
|
|
2425
|
+
to: new_tier,
|
|
2426
|
+
reason: reason || escalation_check[:reason],
|
|
2427
|
+
step: @step_name,
|
|
2428
|
+
iteration: @iteration_count,
|
|
2429
|
+
model_attempts_summary: @thinking_depth_manager.model_attempts_summary)
|
|
2430
|
+
|
|
2431
|
+
# Reset last tier to trigger display of new tier
|
|
2432
|
+
@last_tier = nil
|
|
2433
|
+
else
|
|
2434
|
+
Aidp.logger.debug("work_loop", "Cannot escalate tier further",
|
|
2435
|
+
current: @thinking_depth_manager.current_tier,
|
|
2436
|
+
max: @thinking_depth_manager.max_tier,
|
|
2437
|
+
reason: reason)
|
|
2190
2438
|
end
|
|
2191
2439
|
end
|
|
2192
2440
|
|
|
@@ -2,15 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require "yaml"
|
|
4
4
|
require "fileutils"
|
|
5
|
-
|
|
6
|
-
require_relative "../providers/anthropic"
|
|
7
|
-
require_relative "../providers/cursor"
|
|
8
|
-
require_relative "../providers/github_copilot"
|
|
9
|
-
require_relative "../providers/gemini"
|
|
10
|
-
require_relative "../providers/kilocode"
|
|
11
|
-
require_relative "../providers/opencode"
|
|
12
|
-
require_relative "../providers/codex"
|
|
13
|
-
require_relative "../providers/aider"
|
|
5
|
+
require "agent_harness"
|
|
14
6
|
|
|
15
7
|
module Aidp
|
|
16
8
|
module Firewall
|
|
@@ -233,24 +225,16 @@ module Aidp
|
|
|
233
225
|
|
|
234
226
|
private
|
|
235
227
|
|
|
236
|
-
# Get list of all provider classes
|
|
228
|
+
# Get list of all provider classes from AgentHarness registry
|
|
237
229
|
def provider_classes
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
Aidp::Providers::Cursor,
|
|
241
|
-
Aidp::Providers::GithubCopilot,
|
|
242
|
-
Aidp::Providers::Gemini,
|
|
243
|
-
Aidp::Providers::Kilocode,
|
|
244
|
-
Aidp::Providers::Opencode,
|
|
245
|
-
Aidp::Providers::Codex,
|
|
246
|
-
Aidp::Providers::Aider
|
|
247
|
-
]
|
|
230
|
+
registry = AgentHarness::Providers::Registry.instance
|
|
231
|
+
registry.all.map { |name| registry.get(name) }
|
|
248
232
|
end
|
|
249
233
|
|
|
250
|
-
# Extract provider name from class
|
|
234
|
+
# Extract provider name from provider class
|
|
251
235
|
def extract_provider_name(provider_class)
|
|
252
|
-
#
|
|
253
|
-
provider_class.
|
|
236
|
+
# AgentHarness providers have provider_name class method
|
|
237
|
+
provider_class.provider_name.to_s
|
|
254
238
|
end
|
|
255
239
|
|
|
256
240
|
# Default path to firewall config file
|