Class: Aidp::Providers::Anthropic
- Includes:
- DebugMixin
- Defined in:
- lib/aidp/providers/anthropic.rb
Constant Summary collapse
- MODEL_PATTERN =
Model name pattern for Anthropic Claude models
/^claude-[\d.-]+-(?:opus|sonnet|haiku)(?:-\d{8})?$/i
Constants included from DebugMixin
DebugMixin::DEBUG_BASIC, DebugMixin::DEBUG_OFF, DebugMixin::DEBUG_VERBOSE
Constants inherited from Base
Base::ACTIVITY_STATES, Base::DEFAULT_STUCK_TIMEOUT, Base::TIMEOUT_ARCHITECTURE_ANALYSIS, Base::TIMEOUT_DEFAULT, Base::TIMEOUT_DOCUMENTATION_ANALYSIS, Base::TIMEOUT_FUNCTIONALITY_ANALYSIS, Base::TIMEOUT_IMPLEMENTATION, Base::TIMEOUT_QUICK_MODE, Base::TIMEOUT_REFACTORING_RECOMMENDATIONS, Base::TIMEOUT_REPOSITORY_ANALYSIS, Base::TIMEOUT_STATIC_ANALYSIS, Base::TIMEOUT_TEST_ANALYSIS
Constants included from MessageDisplay
Instance Attribute Summary
Attributes inherited from Base
#activity_state, #last_activity_time, #model, #start_time, #step_name, #stuck_timeout
Class Method Summary collapse
- .available? ⇒ Boolean
-
.discover_models ⇒ Array<Hash>
Discover available models from Claude CLI.
-
.firewall_requirements ⇒ Object
Get firewall requirements for Anthropic provider.
-
.model_family(provider_model_name) ⇒ String
Normalize a provider-specific model name to its model family.
-
.provider_model_name(family_name) ⇒ String
Convert a model family name to the provider’s preferred model name.
-
.supports_model_family?(family_name) ⇒ Boolean
Check if this provider supports a given model family.
Instance Method Summary collapse
- #available? ⇒ Boolean
-
#capabilities ⇒ Object
ProviderAdapter interface methods.
- #dangerous_mode_flags ⇒ Object
- #display_name ⇒ Object
- #error_patterns ⇒ Object
- #fetch_mcp_servers ⇒ Object
- #name ⇒ Object
- #send_message(prompt:, session: nil) ⇒ Object
- #supports_dangerous_mode? ⇒ Boolean
- #supports_mcp? ⇒ Boolean
Methods included from DebugMixin
#debug_basic?, #debug_command, #debug_enabled?, #debug_error, #debug_execute_command, #debug_level, #debug_log, #debug_logger, #debug_provider, #debug_step, #debug_timing, #debug_verbose?, included, shared_logger
Methods inherited from Base
#activity_summary, #configure, discover_models_from_registry, #execution_time, #harness_config, #harness_health_status, #harness_healthy?, #harness_metrics, #harness_mode?, #initialize, #mark_completed, #mark_failed, #record_activity, #record_harness_request, #send_with_harness, #set_harness_context, #set_job_context, #setup_activity_monitoring, #stuck?, #supports_activity_monitoring?, #time_since_last_activity, #update_activity_state
Methods included from Adapter
#classify_error, #dangerous_mode=, #dangerous_mode_enabled?, #error_metadata, #health_status, #logging_metadata, #redact_secrets, #retryable_error?, #validate_config
Methods included from MessageDisplay
#display_message, included, #message_display_prompt
Constructor Details
This class inherits a constructor from Aidp::Providers::Base
Class Method Details
.available? ⇒ Boolean
15 16 17 |
# File 'lib/aidp/providers/anthropic.rb', line 15 def self.available? !!Aidp::Util.which("claude") end |
.discover_models ⇒ Array<Hash>
Discover available models from Claude CLI
52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/aidp/providers/anthropic.rb', line 52 def self.discover_models return [] unless available? begin require "open3" output, _, status = Open3.capture3("claude", "models", "list", {timeout: 10}) return [] unless status.success? parse_models_list(output) rescue => e Aidp.log_debug("anthropic_provider", "discovery failed", error: e.) [] end end |
.firewall_requirements ⇒ Object
Get firewall requirements for Anthropic provider
68 69 70 71 72 73 74 75 76 77 |
# File 'lib/aidp/providers/anthropic.rb', line 68 def self.firewall_requirements { domains: [ "api.anthropic.com", "claude.ai", "console.anthropic.com" ], ip_ranges: [] } end |
.model_family(provider_model_name) ⇒ String
Normalize a provider-specific model name to its model family
Anthropic uses date-versioned models (e.g., “claude-3-5-sonnet-20241022”). This method strips the date suffix to get the family name.
26 27 28 29 |
# File 'lib/aidp/providers/anthropic.rb', line 26 def self.model_family(provider_model_name) # Strip date suffix: "claude-3-5-sonnet-20241022" → "claude-3-5-sonnet" provider_model_name.sub(/-\d{8}$/, "") end |
.provider_model_name(family_name) ⇒ String
Convert a model family name to the provider’s preferred model name
Returns the family name as-is. Users can configure specific versions in aidp.yml.
37 38 39 |
# File 'lib/aidp/providers/anthropic.rb', line 37 def self.provider_model_name(family_name) family_name end |
.supports_model_family?(family_name) ⇒ Boolean
Check if this provider supports a given model family
45 46 47 |
# File 'lib/aidp/providers/anthropic.rb', line 45 def self.supports_model_family?(family_name) MODEL_PATTERN.match?(family_name) end |
Instance Method Details
#available? ⇒ Boolean
188 189 190 |
# File 'lib/aidp/providers/anthropic.rb', line 188 def available? self.class.available? end |
#capabilities ⇒ Object
ProviderAdapter interface methods
194 195 196 197 198 199 200 201 202 203 |
# File 'lib/aidp/providers/anthropic.rb', line 194 def capabilities { reasoning_tiers: ["mini", "standard", "thinking"], context_window: 200_000, supports_json_mode: true, supports_tool_use: true, supports_vision: false, supports_file_upload: true } end |
#dangerous_mode_flags ⇒ Object
209 210 211 |
# File 'lib/aidp/providers/anthropic.rb', line 209 def dangerous_mode_flags ["--dangerously-skip-permissions"] end |
#display_name ⇒ Object
165 166 167 |
# File 'lib/aidp/providers/anthropic.rb', line 165 def display_name "Anthropic Claude CLI" end |
#error_patterns ⇒ Object
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 |
# File 'lib/aidp/providers/anthropic.rb', line 213 def error_patterns { rate_limited: [ /rate.?limit/i, /too.?many.?requests/i, /429/, /overloaded/i ], auth_expired: [ /oauth.*token.*expired/i, /authentication.*error/i, /invalid.*api.*key/i, /unauthorized/i, /401/ ], quota_exceeded: [ /quota.*exceeded/i, /usage.*limit/i, /credit.*exhausted/i ], transient: [ /timeout/i, /connection.*reset/i, /temporary.*error/i, /service.*unavailable/i, /503/, /502/, /504/ ], permanent: [ /invalid.*model/i, /unsupported.*operation/i, /not.*found/i, /404/, /bad.*request/i, /400/ ] } end |
#fetch_mcp_servers ⇒ Object
173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
# File 'lib/aidp/providers/anthropic.rb', line 173 def fetch_mcp_servers return [] unless self.class.available? begin # Use claude mcp list command result = debug_execute_command("claude", args: ["mcp", "list"], timeout: 5) return [] unless result.exit_status == 0 parse_claude_mcp_output(result.out) rescue => e debug_log("Failed to fetch MCP servers via Claude CLI: #{e.message}", level: :debug) [] end end |
#name ⇒ Object
161 162 163 |
# File 'lib/aidp/providers/anthropic.rb', line 161 def name "anthropic" end |
#send_message(prompt:, session: nil) ⇒ Object
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 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 |
# File 'lib/aidp/providers/anthropic.rb', line 253 def (prompt:, session: nil) raise "claude CLI not available" unless self.class.available? # Smart timeout calculation timeout_seconds = calculate_timeout debug_provider("claude", "Starting execution", {timeout: timeout_seconds}) debug_log("📝 Sending prompt to claude...", level: :info) # Build command arguments args = ["--print", "--output-format=text"] # Add model if specified if @model && !@model.empty? args << "--model" << @model end # Check if we should skip permissions (devcontainer support) if args << "--dangerously-skip-permissions" debug_log("🔓 Running with elevated permissions (devcontainer mode)", level: :info) end begin result = debug_execute_command("claude", args: args, input: prompt, timeout: timeout_seconds) # Log the results debug_command("claude", args: args, input: prompt, output: result.out, error: result.err, exit_code: result.exit_status) if result.exit_status == 0 result.out else # Detect issues in stdout/stderr (Claude sometimes prints to stdout) combined = [result.out, result.err].compact.join("\n") # Check for rate limit (Session limit reached) if combined.match?(/session limit reached/i) Aidp.log_debug("anthropic_provider", "rate_limit_detected", exit_code: result.exit_status, message: combined) notify_rate_limit(combined) = "Rate limit reached for Claude CLI.\n#{combined}" debug_error(StandardError.new(), {exit_code: result.exit_status, stdout: result.out, stderr: result.err}) raise end # Check for auth issues if combined.downcase.include?("oauth token has expired") || combined.downcase.include?("authentication_error") = "Authentication error from Claude CLI: token expired or invalid.\n" \ "Run 'claude /login' or refresh credentials.\n" \ "Note: Model discovery requires valid authentication." debug_error(StandardError.new(), {exit_code: result.exit_status, stdout: result.out, stderr: result.err}) raise end debug_error(StandardError.new("claude failed"), {exit_code: result.exit_status, stderr: result.err}) raise "claude failed with exit code #{result.exit_status}: #{result.err}" end rescue => e debug_error(e, {provider: "claude", prompt_length: prompt.length}) raise end end |
#supports_dangerous_mode? ⇒ Boolean
205 206 207 |
# File 'lib/aidp/providers/anthropic.rb', line 205 def supports_dangerous_mode? true end |
#supports_mcp? ⇒ Boolean
169 170 171 |
# File 'lib/aidp/providers/anthropic.rb', line 169 def supports_mcp? true end |