aidp 0.32.0 → 0.33.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/lib/aidp/analyze/feature_analyzer.rb +322 -320
- data/lib/aidp/auto_update/coordinator.rb +97 -7
- data/lib/aidp/auto_update.rb +0 -12
- data/lib/aidp/cli/devcontainer_commands.rb +0 -5
- data/lib/aidp/cli.rb +2 -1
- data/lib/aidp/comment_consolidator.rb +78 -0
- data/lib/aidp/concurrency.rb +0 -3
- data/lib/aidp/config.rb +0 -1
- data/lib/aidp/config_paths.rb +71 -0
- data/lib/aidp/execute/work_loop_runner.rb +324 -15
- data/lib/aidp/harness/ai_filter_factory.rb +285 -0
- data/lib/aidp/harness/config_schema.rb +97 -1
- data/lib/aidp/harness/config_validator.rb +1 -1
- data/lib/aidp/harness/configuration.rb +61 -5
- data/lib/aidp/harness/filter_definition.rb +212 -0
- data/lib/aidp/harness/generated_filter_strategy.rb +197 -0
- data/lib/aidp/harness/output_filter.rb +50 -25
- data/lib/aidp/harness/output_filter_config.rb +129 -0
- data/lib/aidp/harness/provider_manager.rb +90 -2
- data/lib/aidp/harness/runner.rb +0 -11
- data/lib/aidp/harness/test_runner.rb +179 -41
- data/lib/aidp/harness/thinking_depth_manager.rb +16 -0
- data/lib/aidp/harness/ui/navigation/submenu.rb +0 -2
- data/lib/aidp/loader.rb +195 -0
- data/lib/aidp/metadata/compiler.rb +29 -17
- data/lib/aidp/metadata/query.rb +1 -1
- data/lib/aidp/metadata/scanner.rb +8 -1
- data/lib/aidp/metadata/tool_metadata.rb +13 -13
- data/lib/aidp/metadata/validator.rb +10 -0
- data/lib/aidp/metadata.rb +16 -0
- data/lib/aidp/pr_worktree_manager.rb +2 -2
- data/lib/aidp/provider_manager.rb +1 -7
- data/lib/aidp/setup/wizard.rb +279 -9
- data/lib/aidp/skills.rb +0 -5
- data/lib/aidp/storage/csv_storage.rb +3 -0
- data/lib/aidp/style_guide/selector.rb +360 -0
- data/lib/aidp/tooling_detector.rb +283 -16
- data/lib/aidp/version.rb +1 -1
- data/lib/aidp/watch/change_request_processor.rb +152 -14
- data/lib/aidp/watch/repository_client.rb +41 -0
- data/lib/aidp/watch/runner.rb +29 -18
- data/lib/aidp/watch.rb +5 -7
- data/lib/aidp/workstream_cleanup.rb +0 -2
- data/lib/aidp/workstream_executor.rb +0 -4
- data/lib/aidp/worktree.rb +0 -1
- data/lib/aidp.rb +21 -106
- metadata +72 -36
- data/lib/aidp/config/paths.rb +0 -131
|
@@ -1240,6 +1240,11 @@ module Aidp
|
|
|
1240
1240
|
total_tokens: m[:total_tokens] || 0,
|
|
1241
1241
|
last_used: m[:last_used]
|
|
1242
1242
|
}
|
|
1243
|
+
|
|
1244
|
+
# Set reason if currently rate limited (for display in Reason column)
|
|
1245
|
+
if rl && reset_in && reset_in > 0
|
|
1246
|
+
row[:unhealthy_reason] ||= "rate_limited"
|
|
1247
|
+
end
|
|
1243
1248
|
# Incorporate CLI check outcome into reason/availability if failing
|
|
1244
1249
|
unless cli_ok_prefetch
|
|
1245
1250
|
row[:available] = false
|
|
@@ -1416,9 +1421,43 @@ module Aidp
|
|
|
1416
1421
|
|
|
1417
1422
|
# Execute a prompt with a specific provider
|
|
1418
1423
|
def execute_with_provider(provider_type, prompt, options = {})
|
|
1424
|
+
options = options.dup
|
|
1425
|
+
|
|
1419
1426
|
# Extract model from options if provided
|
|
1420
1427
|
model_name = options.delete(:model)
|
|
1421
|
-
retry_on_rate_limit = options.
|
|
1428
|
+
retry_on_rate_limit = if options.key?(:retry_on_rate_limit)
|
|
1429
|
+
options.delete(:retry_on_rate_limit) != false
|
|
1430
|
+
else
|
|
1431
|
+
true
|
|
1432
|
+
end
|
|
1433
|
+
retry_on_unsupported = if options.key?(:retry_on_unsupported)
|
|
1434
|
+
options.delete(:retry_on_unsupported) != false
|
|
1435
|
+
else
|
|
1436
|
+
true
|
|
1437
|
+
end
|
|
1438
|
+
tier = options[:tier]
|
|
1439
|
+
base_options = options.dup
|
|
1440
|
+
|
|
1441
|
+
if model_name && model_denied?(provider_type, model_name)
|
|
1442
|
+
alternate_model = select_alternate_model(provider_type, tier: tier, current_model: model_name)
|
|
1443
|
+
if alternate_model
|
|
1444
|
+
Aidp.logger.warn("provider_manager", "Model is denylisted, selecting alternate",
|
|
1445
|
+
provider: provider_type,
|
|
1446
|
+
model: model_name,
|
|
1447
|
+
alternate_model: alternate_model,
|
|
1448
|
+
tier: tier)
|
|
1449
|
+
|
|
1450
|
+
return execute_with_provider(
|
|
1451
|
+
provider_type,
|
|
1452
|
+
prompt,
|
|
1453
|
+
base_options.merge(
|
|
1454
|
+
model: alternate_model,
|
|
1455
|
+
retry_on_rate_limit: retry_on_rate_limit,
|
|
1456
|
+
retry_on_unsupported: false
|
|
1457
|
+
)
|
|
1458
|
+
)
|
|
1459
|
+
end
|
|
1460
|
+
end
|
|
1422
1461
|
|
|
1423
1462
|
# Create provider factory instance
|
|
1424
1463
|
provider_factory = ProviderFactory.new
|
|
@@ -1440,7 +1479,7 @@ module Aidp
|
|
|
1440
1479
|
prompt_length: prompt.length)
|
|
1441
1480
|
|
|
1442
1481
|
# Execute the prompt with the provider
|
|
1443
|
-
result = provider.send_message(prompt: prompt, session: nil)
|
|
1482
|
+
result = provider.send_message(prompt: prompt, session: nil, options: options)
|
|
1444
1483
|
|
|
1445
1484
|
# Return structured result
|
|
1446
1485
|
{
|
|
@@ -1460,6 +1499,28 @@ module Aidp
|
|
|
1460
1499
|
|
|
1461
1500
|
if unsupported_model_error?(e, model_name)
|
|
1462
1501
|
deny_model(provider_type, model_name, error: e)
|
|
1502
|
+
|
|
1503
|
+
if retry_on_unsupported
|
|
1504
|
+
alternate_model = select_alternate_model(provider_type, tier: tier, current_model: model_name)
|
|
1505
|
+
|
|
1506
|
+
if alternate_model
|
|
1507
|
+
Aidp.logger.info("provider_manager", "Retrying with alternate model after unsupported model error",
|
|
1508
|
+
provider: provider_type,
|
|
1509
|
+
original_model: model_name,
|
|
1510
|
+
alternate_model: alternate_model,
|
|
1511
|
+
tier: tier)
|
|
1512
|
+
|
|
1513
|
+
return execute_with_provider(
|
|
1514
|
+
provider_type,
|
|
1515
|
+
prompt,
|
|
1516
|
+
base_options.merge(
|
|
1517
|
+
model: alternate_model,
|
|
1518
|
+
retry_on_rate_limit: retry_on_rate_limit,
|
|
1519
|
+
retry_on_unsupported: false
|
|
1520
|
+
)
|
|
1521
|
+
)
|
|
1522
|
+
end
|
|
1523
|
+
end
|
|
1463
1524
|
end
|
|
1464
1525
|
|
|
1465
1526
|
# Detect rate limit / quota errors and attempt fallback
|
|
@@ -1615,12 +1676,39 @@ module Aidp
|
|
|
1615
1676
|
|
|
1616
1677
|
message = error&.message.to_s.downcase
|
|
1617
1678
|
return false if message.empty?
|
|
1679
|
+
return false unless message.include?(model_name.to_s.downcase)
|
|
1618
1680
|
|
|
1619
1681
|
(message.include?("unsupported") && message.include?("model")) ||
|
|
1620
1682
|
(message.include?("model") && message.include?("not supported")) ||
|
|
1621
1683
|
message.include?("invalid model")
|
|
1622
1684
|
end
|
|
1623
1685
|
|
|
1686
|
+
# Select an alternate model for the provider and tier, excluding denylisted/current models
|
|
1687
|
+
def select_alternate_model(provider_name, tier:, current_model: nil)
|
|
1688
|
+
candidates = []
|
|
1689
|
+
|
|
1690
|
+
if tier && @configuration.respond_to?(:models_for_tier)
|
|
1691
|
+
tier_models = Array(@configuration.models_for_tier(tier, provider_name)).map(&:to_s)
|
|
1692
|
+
candidates.concat(tier_models)
|
|
1693
|
+
end
|
|
1694
|
+
|
|
1695
|
+
if candidates.empty? && @configuration.respond_to?(:provider_models)
|
|
1696
|
+
provider_models = Array(@configuration.provider_models(provider_name)).map(&:to_s)
|
|
1697
|
+
candidates.concat(provider_models)
|
|
1698
|
+
end
|
|
1699
|
+
|
|
1700
|
+
candidates = candidates.uniq
|
|
1701
|
+
return nil if candidates.empty?
|
|
1702
|
+
|
|
1703
|
+
excluded = Array(current_model).compact + Array(@model_denylist[provider_name])
|
|
1704
|
+
candidates.reject! { |model| excluded.include?(model) }
|
|
1705
|
+
candidates.first
|
|
1706
|
+
rescue => e
|
|
1707
|
+
log_rescue(e, component: "provider_manager", action: "select_alternate_model", fallback: nil,
|
|
1708
|
+
provider: provider_name, tier: tier, current_model: current_model)
|
|
1709
|
+
nil
|
|
1710
|
+
end
|
|
1711
|
+
|
|
1624
1712
|
public
|
|
1625
1713
|
|
|
1626
1714
|
# Log provider switch
|
data/lib/aidp/harness/runner.rb
CHANGED
|
@@ -2,16 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
require "timeout"
|
|
4
4
|
require "json"
|
|
5
|
-
require_relative "configuration"
|
|
6
|
-
require_relative "state_manager"
|
|
7
|
-
require_relative "condition_detector"
|
|
8
|
-
require_relative "provider_manager"
|
|
9
|
-
require_relative "simple_user_interface"
|
|
10
|
-
require_relative "error_handler"
|
|
11
|
-
require_relative "status_display"
|
|
12
|
-
require_relative "completion_checker"
|
|
13
|
-
require_relative "../concurrency"
|
|
14
|
-
require_relative "../errors"
|
|
15
5
|
|
|
16
6
|
module Aidp
|
|
17
7
|
module Harness
|
|
@@ -61,7 +51,6 @@ module Aidp
|
|
|
61
51
|
# Use ZFC-enabled condition detector
|
|
62
52
|
# ZfcConditionDetector will create its own ProviderFactory if needed
|
|
63
53
|
# Falls back to legacy pattern matching when ZFC is disabled
|
|
64
|
-
require_relative "zfc_condition_detector"
|
|
65
54
|
@condition_detector = ZfcConditionDetector.new(@configuration)
|
|
66
55
|
|
|
67
56
|
@user_interface = SimpleUserInterface.new
|
|
@@ -3,16 +3,19 @@
|
|
|
3
3
|
require "open3"
|
|
4
4
|
require_relative "../tooling_detector"
|
|
5
5
|
require_relative "output_filter"
|
|
6
|
+
require_relative "output_filter_config"
|
|
6
7
|
|
|
7
8
|
module Aidp
|
|
8
9
|
module Harness
|
|
9
10
|
# Executes test and linter commands configured in aidp.yml
|
|
10
11
|
# Returns results with exit status and output
|
|
12
|
+
# Applies intelligent output filtering to reduce token consumption
|
|
11
13
|
class TestRunner
|
|
12
14
|
def initialize(project_dir, config)
|
|
13
15
|
@project_dir = project_dir
|
|
14
16
|
@config = config
|
|
15
17
|
@iteration_count = 0
|
|
18
|
+
@filter_stats = {total_input_bytes: 0, total_output_bytes: 0}
|
|
16
19
|
end
|
|
17
20
|
|
|
18
21
|
# Run all configured tests
|
|
@@ -47,6 +50,29 @@ module Aidp
|
|
|
47
50
|
run_command_category(:documentation, "Documentation")
|
|
48
51
|
end
|
|
49
52
|
|
|
53
|
+
# Preview the commands that will run for each category so callers can log intent
|
|
54
|
+
# Returns a hash of category => array of normalized command entries
|
|
55
|
+
def planned_commands
|
|
56
|
+
{
|
|
57
|
+
tests: resolved_commands(:test),
|
|
58
|
+
lints: resolved_commands(:lint),
|
|
59
|
+
formatters: resolved_commands(:formatter),
|
|
60
|
+
builds: resolved_commands(:build),
|
|
61
|
+
docs: resolved_commands(:documentation)
|
|
62
|
+
}
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Get current iteration count
|
|
66
|
+
attr_reader :iteration_count
|
|
67
|
+
|
|
68
|
+
# Get filtering statistics
|
|
69
|
+
attr_reader :filter_stats
|
|
70
|
+
|
|
71
|
+
# Reset iteration counter (useful for testing)
|
|
72
|
+
def reset_iteration_count
|
|
73
|
+
@iteration_count = 0
|
|
74
|
+
end
|
|
75
|
+
|
|
50
76
|
private
|
|
51
77
|
|
|
52
78
|
# Run commands for a specific category (test, lint, formatter, build, documentation)
|
|
@@ -59,6 +85,12 @@ module Aidp
|
|
|
59
85
|
# Determine output mode based on category
|
|
60
86
|
mode = determine_output_mode(category)
|
|
61
87
|
|
|
88
|
+
Aidp.log_debug("test_runner", "running_category",
|
|
89
|
+
category: category,
|
|
90
|
+
command_count: commands.length,
|
|
91
|
+
iteration: @iteration_count,
|
|
92
|
+
output_mode: mode)
|
|
93
|
+
|
|
62
94
|
# Execute all commands
|
|
63
95
|
results = commands.map do |cmd_config|
|
|
64
96
|
# Handle both string commands (legacy) and hash format (new)
|
|
@@ -71,6 +103,23 @@ module Aidp
|
|
|
71
103
|
end
|
|
72
104
|
end
|
|
73
105
|
|
|
106
|
+
aggregate_results(results, display_name, mode: mode)
|
|
107
|
+
rescue NameError
|
|
108
|
+
# Logging not available
|
|
109
|
+
commands = resolved_commands(category)
|
|
110
|
+
return {success: true, output: "", failures: [], required_failures: []} if commands.empty?
|
|
111
|
+
|
|
112
|
+
mode = determine_output_mode(category)
|
|
113
|
+
results = commands.map do |cmd_config|
|
|
114
|
+
if cmd_config.is_a?(String)
|
|
115
|
+
result = execute_command(cmd_config, category.to_s)
|
|
116
|
+
result.merge(required: true)
|
|
117
|
+
else
|
|
118
|
+
result = execute_command(cmd_config[:command], category.to_s)
|
|
119
|
+
result.merge(required: cmd_config[:required])
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
74
123
|
aggregate_results(results, display_name, mode: mode)
|
|
75
124
|
end
|
|
76
125
|
|
|
@@ -107,6 +156,11 @@ module Aidp
|
|
|
107
156
|
(optional_failures.any? ? "\n" + format_failures(optional_failures, "#{category} - Optional", mode: mode) : "")
|
|
108
157
|
end
|
|
109
158
|
|
|
159
|
+
# Add filtering summary if filtering was applied
|
|
160
|
+
if mode != :full && all_failures.any?
|
|
161
|
+
output += "\n[Output filtered: mode=#{mode}]"
|
|
162
|
+
end
|
|
163
|
+
|
|
110
164
|
{
|
|
111
165
|
success: success,
|
|
112
166
|
output: output,
|
|
@@ -124,9 +178,12 @@ module Aidp
|
|
|
124
178
|
output << "Exit Code: #{failure[:exit_code]}"
|
|
125
179
|
output << "--- Output ---"
|
|
126
180
|
|
|
181
|
+
# Detect framework for filtering
|
|
182
|
+
framework = detect_framework_from_command(failure[:command])
|
|
183
|
+
|
|
127
184
|
# Apply filtering based on mode and framework
|
|
128
|
-
filtered_stdout = filter_output(failure[:stdout], mode,
|
|
129
|
-
filtered_stderr = filter_output(failure[:stderr], mode, :unknown)
|
|
185
|
+
filtered_stdout = filter_output(failure[:stdout], mode, framework, :test)
|
|
186
|
+
filtered_stderr = filter_output(failure[:stderr], mode, :unknown, :lint)
|
|
130
187
|
|
|
131
188
|
output << filtered_stdout unless filtered_stdout.strip.empty?
|
|
132
189
|
output << filtered_stderr unless filtered_stderr.strip.empty?
|
|
@@ -136,67 +193,139 @@ module Aidp
|
|
|
136
193
|
output.join("\n")
|
|
137
194
|
end
|
|
138
195
|
|
|
139
|
-
def filter_output(raw_output, mode, framework)
|
|
196
|
+
def filter_output(raw_output, mode, framework, category)
|
|
140
197
|
return raw_output if mode == :full || raw_output.nil? || raw_output.empty?
|
|
141
198
|
|
|
142
|
-
|
|
199
|
+
# Build filter config from configuration or defaults
|
|
200
|
+
filter_config = build_filter_config(mode, category)
|
|
201
|
+
|
|
202
|
+
# Load AI-generated filter definition if available (AGD pattern)
|
|
203
|
+
filter_definition = load_filter_definition_for(category)
|
|
204
|
+
|
|
205
|
+
# Track input size for stats
|
|
206
|
+
@filter_stats[:total_input_bytes] += raw_output.bytesize
|
|
207
|
+
|
|
208
|
+
filter = OutputFilter.new(filter_config, filter_definition: filter_definition)
|
|
209
|
+
filtered = filter.filter(raw_output, framework: framework)
|
|
210
|
+
|
|
211
|
+
# Track output size for stats
|
|
212
|
+
@filter_stats[:total_output_bytes] += filtered.bytesize
|
|
213
|
+
|
|
214
|
+
Aidp.log_debug("test_runner", "output_filtered",
|
|
215
|
+
framework: framework,
|
|
143
216
|
mode: mode,
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
217
|
+
input_size: raw_output.bytesize,
|
|
218
|
+
output_size: filtered.bytesize,
|
|
219
|
+
has_custom_definition: !filter_definition.nil?)
|
|
148
220
|
|
|
149
|
-
|
|
150
|
-
filter.filter(raw_output, framework: framework)
|
|
221
|
+
filtered
|
|
151
222
|
rescue NameError
|
|
152
223
|
# Logging infrastructure not available
|
|
153
224
|
raw_output
|
|
154
225
|
rescue => e
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
226
|
+
begin
|
|
227
|
+
Aidp.log_warn("test_runner", "filter_failed",
|
|
228
|
+
error: e.message,
|
|
229
|
+
framework: framework)
|
|
230
|
+
rescue NameError
|
|
231
|
+
# Logging not available
|
|
232
|
+
end
|
|
158
233
|
raw_output # Fallback to unfiltered on error
|
|
159
234
|
end
|
|
160
235
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
when
|
|
170
|
-
|
|
171
|
-
else
|
|
172
|
-
:unknown
|
|
236
|
+
# Load AI-generated filter definition for a category
|
|
237
|
+
# @param category [Symbol] :test or :lint
|
|
238
|
+
# @return [FilterDefinition, nil]
|
|
239
|
+
def load_filter_definition_for(category)
|
|
240
|
+
return nil unless @config.respond_to?(:filter_definition_for)
|
|
241
|
+
|
|
242
|
+
# Map category to definition key (matches setup wizard keys)
|
|
243
|
+
definition_key = case category
|
|
244
|
+
when :test then "unit_test"
|
|
245
|
+
when :lint then "lint"
|
|
246
|
+
else category.to_s
|
|
173
247
|
end
|
|
248
|
+
|
|
249
|
+
@config.filter_definition_for(definition_key)
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def build_filter_config(mode, category)
|
|
253
|
+
config_hash = {
|
|
254
|
+
mode: mode,
|
|
255
|
+
include_context: output_filtering_include_context,
|
|
256
|
+
context_lines: output_filtering_context_lines,
|
|
257
|
+
max_lines: max_output_lines_for_category(category)
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
OutputFilterConfig.from_hash(config_hash)
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
def detect_framework_from_command(command)
|
|
264
|
+
# Use ToolingDetector's enhanced framework detection
|
|
265
|
+
Aidp::ToolingDetector.framework_from_command(command)
|
|
174
266
|
end
|
|
175
267
|
|
|
176
268
|
def determine_output_mode(category)
|
|
177
269
|
# Check config for category-specific mode
|
|
178
270
|
case category
|
|
179
271
|
when :test
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
:full
|
|
186
|
-
end
|
|
272
|
+
configured_mode = test_output_mode_from_config
|
|
273
|
+
return configured_mode if configured_mode
|
|
274
|
+
|
|
275
|
+
# Default: full on first iteration, failures_only after
|
|
276
|
+
(@iteration_count > 1) ? :failures_only : :full
|
|
187
277
|
when :lint
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
:full
|
|
194
|
-
end
|
|
278
|
+
configured_mode = lint_output_mode_from_config
|
|
279
|
+
return configured_mode if configured_mode
|
|
280
|
+
|
|
281
|
+
# Default: full on first iteration, failures_only after
|
|
282
|
+
(@iteration_count > 1) ? :failures_only : :full
|
|
195
283
|
else
|
|
196
284
|
:full
|
|
197
285
|
end
|
|
198
286
|
end
|
|
199
287
|
|
|
288
|
+
def test_output_mode_from_config
|
|
289
|
+
return nil unless @config.respond_to?(:test_output_mode)
|
|
290
|
+
mode = @config.test_output_mode
|
|
291
|
+
return nil if mode.nil?
|
|
292
|
+
mode.to_sym
|
|
293
|
+
rescue
|
|
294
|
+
nil
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def lint_output_mode_from_config
|
|
298
|
+
return nil unless @config.respond_to?(:lint_output_mode)
|
|
299
|
+
mode = @config.lint_output_mode
|
|
300
|
+
return nil if mode.nil?
|
|
301
|
+
mode.to_sym
|
|
302
|
+
rescue
|
|
303
|
+
nil
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
def max_output_lines_for_category(category)
|
|
307
|
+
case category
|
|
308
|
+
when :test
|
|
309
|
+
return @config.test_max_output_lines if @config.respond_to?(:test_max_output_lines) && @config.test_max_output_lines
|
|
310
|
+
OutputFilterConfig::DEFAULT_MAX_LINES
|
|
311
|
+
when :lint
|
|
312
|
+
return @config.lint_max_output_lines if @config.respond_to?(:lint_max_output_lines) && @config.lint_max_output_lines
|
|
313
|
+
300 # Default smaller for lint output
|
|
314
|
+
else
|
|
315
|
+
OutputFilterConfig::DEFAULT_MAX_LINES
|
|
316
|
+
end
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
def output_filtering_include_context
|
|
320
|
+
return @config.output_filtering_include_context if @config.respond_to?(:output_filtering_include_context)
|
|
321
|
+
OutputFilterConfig::DEFAULT_INCLUDE_CONTEXT
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
def output_filtering_context_lines
|
|
325
|
+
return @config.output_filtering_context_lines if @config.respond_to?(:output_filtering_context_lines)
|
|
326
|
+
OutputFilterConfig::DEFAULT_CONTEXT_LINES
|
|
327
|
+
end
|
|
328
|
+
|
|
200
329
|
# Resolve commands for a specific category
|
|
201
330
|
# Returns normalized command configs (array of {command:, required:} hashes)
|
|
202
331
|
def resolved_commands(category)
|
|
@@ -239,8 +368,17 @@ module Aidp
|
|
|
239
368
|
def detected_tooling
|
|
240
369
|
@detected_tooling ||= Aidp::ToolingDetector.detect(@project_dir)
|
|
241
370
|
rescue => e
|
|
242
|
-
|
|
243
|
-
|
|
371
|
+
begin
|
|
372
|
+
Aidp.log_warn("test_runner", "tooling_detection_failed", error: e.message)
|
|
373
|
+
rescue NameError
|
|
374
|
+
# Logging not available
|
|
375
|
+
end
|
|
376
|
+
Aidp::ToolingDetector::Result.new(
|
|
377
|
+
test_commands: [],
|
|
378
|
+
lint_commands: [],
|
|
379
|
+
formatter_commands: [],
|
|
380
|
+
frameworks: {}
|
|
381
|
+
)
|
|
244
382
|
end
|
|
245
383
|
|
|
246
384
|
def log_fallback(type, commands)
|
|
@@ -152,6 +152,15 @@ module Aidp
|
|
|
152
152
|
def select_model_for_tier(tier = nil, provider: nil)
|
|
153
153
|
tier ||= current_tier
|
|
154
154
|
validate_tier!(tier)
|
|
155
|
+
provider_has_no_tiers = provider && configuration.configured_tiers(provider).empty?
|
|
156
|
+
provider_has_catalog_models = provider && !@registry.models_for_provider(provider).empty?
|
|
157
|
+
|
|
158
|
+
if provider_has_no_tiers && !provider_has_catalog_models
|
|
159
|
+
Aidp.log_info("thinking_depth_manager", "No configured tiers for provider, deferring to provider auto model selection",
|
|
160
|
+
requested_tier: tier,
|
|
161
|
+
provider: provider)
|
|
162
|
+
return [provider, nil, {auto_model: true, reason: "provider_has_no_tiers"}]
|
|
163
|
+
end
|
|
155
164
|
|
|
156
165
|
# First, try to get models from user's configuration for this tier and provider
|
|
157
166
|
if provider
|
|
@@ -270,6 +279,13 @@ module Aidp
|
|
|
270
279
|
|
|
271
280
|
result = try_fallback_tiers(tier, provider)
|
|
272
281
|
|
|
282
|
+
if provider_has_no_tiers && result.nil? && provider
|
|
283
|
+
Aidp.log_info("thinking_depth_manager", "No configured tiers for provider, deferring to provider auto model selection",
|
|
284
|
+
requested_tier: tier,
|
|
285
|
+
provider: provider)
|
|
286
|
+
return [provider, nil, {auto_model: true, reason: "provider_has_no_tiers"}]
|
|
287
|
+
end
|
|
288
|
+
|
|
273
289
|
unless result
|
|
274
290
|
# Enhanced error message with discovery hints
|
|
275
291
|
display_enhanced_tier_error(tier, provider)
|