Class: Aidp::Providers::Base
- Inherits:
-
Object
- Object
- Aidp::Providers::Base
- Includes:
- MessageDisplay, Adapter
- Defined in:
- lib/aidp/providers/base.rb
Constant Summary collapse
- ACTIVITY_STATES =
Activity indicator states
{ idle: "⏳", working: "🔄", stuck: "⚠️", completed: "✅", failed: "❌" }.freeze
- DEFAULT_STUCK_TIMEOUT =
Default timeout for stuck detection (2 minutes)
120- TIMEOUT_QUICK_MODE =
Configurable timeout values (can be overridden via environment or config) These defaults provide reasonable values for different execution scenarios
120- TIMEOUT_DEFAULT =
2 minutes - for quick testing
300- TIMEOUT_REPOSITORY_ANALYSIS =
5 minutes - standard interactive timeout
180- TIMEOUT_ARCHITECTURE_ANALYSIS =
3 minutes - repository analysis
600- TIMEOUT_TEST_ANALYSIS =
10 minutes - architecture analysis
300- TIMEOUT_FUNCTIONALITY_ANALYSIS =
5 minutes - test analysis
600- TIMEOUT_DOCUMENTATION_ANALYSIS =
10 minutes - functionality analysis
300- TIMEOUT_STATIC_ANALYSIS =
5 minutes - documentation analysis
450- TIMEOUT_REFACTORING_RECOMMENDATIONS =
7.5 minutes - static analysis
600- TIMEOUT_IMPLEMENTATION =
10 minutes - refactoring
900
Constants included from MessageDisplay
Instance Attribute Summary collapse
-
#activity_state ⇒ Object
readonly
15 minutes - implementation (write files, run tests, fix issues).
-
#last_activity_time ⇒ Object
readonly
15 minutes - implementation (write files, run tests, fix issues).
-
#start_time ⇒ Object
readonly
15 minutes - implementation (write files, run tests, fix issues).
-
#step_name ⇒ Object
readonly
15 minutes - implementation (write files, run tests, fix issues).
-
#stuck_timeout ⇒ Object
readonly
Get stuck timeout for this provider.
Instance Method Summary collapse
-
#activity_summary ⇒ Object
Get activity summary for metrics.
-
#available? ⇒ Boolean
Check if provider is available (override in subclasses).
-
#display_name ⇒ Object
Human-friendly display name for UI Override in subclasses to provide a better display name.
-
#execution_time ⇒ Object
Get current execution time.
-
#fetch_mcp_servers ⇒ Object
Fetch MCP servers configured for this provider Returns an array of server hashes with keys: :name, :status, :description, :enabled Override in subclasses to provide provider-specific MCP server detection.
-
#harness_config ⇒ Object
Get provider configuration for harness.
-
#harness_health_status ⇒ Object
Get provider health status for harness.
-
#harness_healthy? ⇒ Boolean
Check if provider is healthy for harness use.
-
#harness_metrics ⇒ Object
Get harness metrics.
-
#harness_mode? ⇒ Boolean
Check if provider is operating in harness mode.
-
#initialize(output: nil, prompt: TTY::Prompt.new) ⇒ Base
constructor
A new instance of Base.
-
#mark_completed ⇒ Object
Mark as completed.
-
#mark_failed(error_message = nil) ⇒ Object
Mark as failed.
- #name ⇒ Object
-
#record_activity(message = nil) ⇒ Object
Record activity (called when provider produces output).
-
#record_harness_request(success:, tokens_used: 0, cost: 0.0, response_time: 0.0, rate_limited: false) ⇒ Object
Record harness request metrics.
- #send_message(prompt:, session: nil) ⇒ Object
-
#send_with_harness(prompt:, session: nil, _options: {}) ⇒ Object
Enhanced send method that integrates with harness.
-
#set_harness_context(harness_runner) ⇒ Object
Set harness context for provider.
-
#set_job_context(job_id:, execution_id:, job_manager:) ⇒ Object
Set job context for background execution.
-
#setup_activity_monitoring(step_name, activity_callback = nil, stuck_timeout = nil) ⇒ Object
Set up activity monitoring for a step.
-
#stuck? ⇒ Boolean
Check if provider appears to be stuck.
-
#supports_activity_monitoring? ⇒ Boolean
Check if provider supports activity monitoring.
-
#supports_mcp? ⇒ Boolean
Check if this provider supports MCP servers Override in subclasses to provide accurate MCP support detection.
-
#time_since_last_activity ⇒ Object
Get time since last activity.
-
#update_activity_state(state, message = nil) ⇒ Object
Update activity state and notify callback.
Methods included from Adapter
#capabilities, #classify_error, #dangerous_mode=, #dangerous_mode_enabled?, #dangerous_mode_flags, #error_metadata, #error_patterns, #health_status, #logging_metadata, #redact_secrets, #retryable_error?, #supports_dangerous_mode?, #validate_config
Methods included from MessageDisplay
#display_message, #in_test_environment?, included, #message_display_prompt, #suppress_display_message?
Constructor Details
#initialize(output: nil, prompt: TTY::Prompt.new) ⇒ Base
Returns a new instance of Base.
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/aidp/providers/base.rb', line 42 def initialize(output: nil, prompt: TTY::Prompt.new) @activity_state = :idle @last_activity_time = Time.now @start_time = nil @step_name = nil @activity_callback = nil @stuck_timeout = DEFAULT_STUCK_TIMEOUT @output_count = 0 @last_output_time = Time.now @job_context = nil @harness_context = nil @output = output @prompt = prompt @harness_metrics = { total_requests: 0, successful_requests: 0, failed_requests: 0, rate_limited_requests: 0, total_tokens_used: 0, total_cost: 0.0, average_response_time: 0.0, last_request_time: nil } end |
Instance Attribute Details
#activity_state ⇒ Object (readonly)
15 minutes - implementation (write files, run tests, fix issues)
40 41 42 |
# File 'lib/aidp/providers/base.rb', line 40 def activity_state @activity_state end |
#last_activity_time ⇒ Object (readonly)
15 minutes - implementation (write files, run tests, fix issues)
40 41 42 |
# File 'lib/aidp/providers/base.rb', line 40 def last_activity_time @last_activity_time end |
#start_time ⇒ Object (readonly)
15 minutes - implementation (write files, run tests, fix issues)
40 41 42 |
# File 'lib/aidp/providers/base.rb', line 40 def start_time @start_time end |
#step_name ⇒ Object (readonly)
15 minutes - implementation (write files, run tests, fix issues)
40 41 42 |
# File 'lib/aidp/providers/base.rb', line 40 def step_name @step_name end |
#stuck_timeout ⇒ Object (readonly)
Get stuck timeout for this provider
190 191 192 |
# File 'lib/aidp/providers/base.rb', line 190 def stuck_timeout @stuck_timeout end |
Instance Method Details
#activity_summary ⇒ Object
Get activity summary for metrics
171 172 173 174 175 176 177 178 179 180 181 182 |
# File 'lib/aidp/providers/base.rb', line 171 def activity_summary { provider: name, step_name: @step_name, start_time: @start_time&.iso8601, end_time: Time.now.iso8601, duration: execution_time, final_state: @activity_state, stuck_detected: stuck?, output_count: @output_count } end |
#available? ⇒ Boolean
Check if provider is available (override in subclasses)
271 272 273 |
# File 'lib/aidp/providers/base.rb', line 271 def available? true # Default to true, override in subclasses end |
#display_name ⇒ Object
Human-friendly display name for UI Override in subclasses to provide a better display name
73 74 75 |
# File 'lib/aidp/providers/base.rb', line 73 def display_name name end |
#execution_time ⇒ Object
Get current execution time
143 144 145 146 |
# File 'lib/aidp/providers/base.rb', line 143 def execution_time return 0 unless @start_time Time.now - @start_time end |
#fetch_mcp_servers ⇒ Object
Fetch MCP servers configured for this provider Returns an array of server hashes with keys: :name, :status, :description, :enabled Override in subclasses to provide provider-specific MCP server detection
84 85 86 |
# File 'lib/aidp/providers/base.rb', line 84 def fetch_mcp_servers [] end |
#harness_config ⇒ Object
Get provider configuration for harness
260 261 262 263 264 265 266 267 268 |
# File 'lib/aidp/providers/base.rb', line 260 def harness_config { name: name, supports_activity_monitoring: supports_activity_monitoring?, default_timeout: @stuck_timeout, available: available?, health_status: harness_health_status } end |
#harness_health_status ⇒ Object
Get provider health status for harness
236 237 238 239 240 241 242 243 244 245 246 247 248 |
# File 'lib/aidp/providers/base.rb', line 236 def harness_health_status { provider: name, activity_state: @activity_state, stuck: stuck?, success_rate: calculate_success_rate, average_response_time: @harness_metrics[:average_response_time], total_requests: @harness_metrics[:total_requests], rate_limit_ratio: calculate_rate_limit_ratio, last_activity: @last_activity_time, health_score: calculate_health_score } end |
#harness_healthy? ⇒ Boolean
Check if provider is healthy for harness use
251 252 253 254 255 256 257 |
# File 'lib/aidp/providers/base.rb', line 251 def harness_healthy? return false if stuck? return false if @harness_metrics[:total_requests] > 0 && calculate_success_rate < 0.5 return false if calculate_rate_limit_ratio > 0.3 true end |
#harness_metrics ⇒ Object
Get harness metrics
205 206 207 |
# File 'lib/aidp/providers/base.rb', line 205 def harness_metrics @harness_metrics.dup end |
#harness_mode? ⇒ Boolean
Check if provider is operating in harness mode
200 201 202 |
# File 'lib/aidp/providers/base.rb', line 200 def harness_mode? !@harness_context.nil? end |
#mark_completed ⇒ Object
Mark as completed
161 162 163 |
# File 'lib/aidp/providers/base.rb', line 161 def mark_completed update_activity_state(:completed) end |
#mark_failed(error_message = nil) ⇒ Object
Mark as failed
166 167 168 |
# File 'lib/aidp/providers/base.rb', line 166 def mark_failed( = nil) update_activity_state(:failed, ) end |
#name ⇒ Object
67 68 69 |
# File 'lib/aidp/providers/base.rb', line 67 def name raise NotImplementedError, "#{self.class} must implement #name" end |
#record_activity(message = nil) ⇒ Object
Record activity (called when provider produces output)
154 155 156 157 158 |
# File 'lib/aidp/providers/base.rb', line 154 def record_activity( = nil) @output_count += 1 @last_output_time = Time.now update_activity_state(:working, ) end |
#record_harness_request(success:, tokens_used: 0, cost: 0.0, response_time: 0.0, rate_limited: false) ⇒ Object
Record harness request metrics
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
# File 'lib/aidp/providers/base.rb', line 210 def record_harness_request(success:, tokens_used: 0, cost: 0.0, response_time: 0.0, rate_limited: false) @harness_metrics[:total_requests] += 1 @harness_metrics[:last_request_time] = Time.now if success @harness_metrics[:successful_requests] += 1 else @harness_metrics[:failed_requests] += 1 end if rate_limited @harness_metrics[:rate_limited_requests] += 1 end @harness_metrics[:total_tokens_used] += tokens_used @harness_metrics[:total_cost] += cost # Update average response time total_time = @harness_metrics[:average_response_time] * (@harness_metrics[:total_requests] - 1) + response_time @harness_metrics[:average_response_time] = total_time / @harness_metrics[:total_requests] # Notify harness context if available @harness_context&.record_provider_metrics(name, @harness_metrics) end |
#send_message(prompt:, session: nil) ⇒ Object
77 78 79 |
# File 'lib/aidp/providers/base.rb', line 77 def (prompt:, session: nil) raise NotImplementedError, "#{self.class} must implement #send_message" end |
#send_with_harness(prompt:, session: nil, _options: {}) ⇒ Object
Enhanced send method that integrates with harness
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 |
# File 'lib/aidp/providers/base.rb', line 276 def send_with_harness(prompt:, session: nil, _options: {}) start_time = Time.now success = false rate_limited = false tokens_used = 0 cost = 0.0 = nil begin # Call the original send_message method result = (prompt: prompt, session: session) success = true # Extract token usage and cost if available if result.is_a?(Hash) && result[:token_usage] tokens_used = result[:token_usage][:total] || 0 cost = result[:token_usage][:cost] || 0.0 end # Check for rate limiting in result if result.is_a?(Hash) && result[:rate_limited] rate_limited = true end result rescue => e = e. # Check if error is rate limiting if e..match?(/rate.?limit/i) || e..match?(/quota/i) || e..match?(/session limit/i) rate_limited = true end raise e ensure response_time = Time.now - start_time record_harness_request( success: success, tokens_used: tokens_used, cost: cost, response_time: response_time, rate_limited: rate_limited ) # Log to harness context if available if @harness_context && @harness_context.record_provider_error(name, , rate_limited) end end end |
#set_harness_context(harness_runner) ⇒ Object
Set harness context for provider
195 196 197 |
# File 'lib/aidp/providers/base.rb', line 195 def set_harness_context(harness_runner) @harness_context = harness_runner end |
#set_job_context(job_id:, execution_id:, job_manager:) ⇒ Object
Set job context for background execution
95 96 97 98 99 100 101 |
# File 'lib/aidp/providers/base.rb', line 95 def set_job_context(job_id:, execution_id:, job_manager:) @job_context = { job_id: job_id, execution_id: execution_id, job_manager: job_manager } end |
#setup_activity_monitoring(step_name, activity_callback = nil, stuck_timeout = nil) ⇒ Object
Set up activity monitoring for a step
104 105 106 107 108 109 110 111 112 113 |
# File 'lib/aidp/providers/base.rb', line 104 def setup_activity_monitoring(step_name, activity_callback = nil, stuck_timeout = nil) @step_name = step_name @activity_callback = activity_callback @stuck_timeout = stuck_timeout || DEFAULT_STUCK_TIMEOUT @start_time = Time.now @last_activity_time = @start_time @output_count = 0 @last_output_time = @start_time update_activity_state(:working) end |
#stuck? ⇒ Boolean
Check if provider appears to be stuck
135 136 137 138 139 140 |
# File 'lib/aidp/providers/base.rb', line 135 def stuck? return false unless @activity_state == :working time_since_activity = Time.now - @last_activity_time time_since_activity > @stuck_timeout end |
#supports_activity_monitoring? ⇒ Boolean
Check if provider supports activity monitoring
185 186 187 |
# File 'lib/aidp/providers/base.rb', line 185 def supports_activity_monitoring? true # Default to true, override in subclasses if needed end |
#supports_mcp? ⇒ Boolean
Check if this provider supports MCP servers Override in subclasses to provide accurate MCP support detection
90 91 92 |
# File 'lib/aidp/providers/base.rb', line 90 def supports_mcp? false end |
#time_since_last_activity ⇒ Object
Get time since last activity
149 150 151 |
# File 'lib/aidp/providers/base.rb', line 149 def time_since_last_activity Time.now - @last_activity_time end |
#update_activity_state(state, message = nil) ⇒ Object
Update activity state and notify callback
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/aidp/providers/base.rb', line 116 def update_activity_state(state, = nil) @activity_state = state @last_activity_time = Time.now if state == :working # Log state change to job if in background mode if @job_context level = case state when :completed then "info" when :failed then "error" else "debug" end log_to_job( || "Provider state changed to #{state}", level) end @activity_callback&.call(state, , self) end |