Class: AgentHarness::Providers::Anthropic

Inherits:
Base
  • Object
show all
Defined in:
lib/agent_harness/providers/anthropic.rb

Overview

Anthropic Claude Code CLI provider

Provides integration with the Claude Code CLI tool for AI-powered coding assistance.

Examples:

Basic usage

provider = AgentHarness::Providers::Anthropic.new
response = provider.send_message(prompt: "Hello!")

Constant Summary collapse

MODEL_PATTERN =

Model name pattern for Anthropic Claude models

/^claude-[\d.-]+-(?:opus|sonnet|haiku)(?:-\d{8})?$/i

Constants inherited from Base

Base::COMMON_ERROR_PATTERNS

Instance Attribute Summary

Attributes inherited from Base

#config, #executor, #logger

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Base

#configure, #initialize, #sandboxed_environment?

Methods included from Adapter

#health_status, included, #parse_rate_limit_reset, #session_flags, #supports_dangerous_mode?, #supports_sessions?, #validate_config, #validate_mcp_servers!

Constructor Details

This class inherits a constructor from AgentHarness::Providers::Base

Class Method Details

.available?Boolean

Returns:

  • (Boolean)


28
29
30
31
# File 'lib/agent_harness/providers/anthropic.rb', line 28

def available?
  executor = AgentHarness.configuration.command_executor
  !!executor.which(binary_name)
end

.binary_nameObject



24
25
26
# File 'lib/agent_harness/providers/anthropic.rb', line 24

def binary_name
  "claude"
end

.discover_modelsObject



54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/agent_harness/providers/anthropic.rb', line 54

def 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
    AgentHarness.logger&.debug("[AgentHarness::Anthropic] Model discovery failed: #{e.message}")
    []
  end
end

.firewall_requirementsObject



33
34
35
36
37
38
39
40
41
42
# File 'lib/agent_harness/providers/anthropic.rb', line 33

def firewall_requirements
  {
    domains: [
      "api.anthropic.com",
      "claude.ai",
      "console.anthropic.com"
    ],
    ip_ranges: []
  }
end

.instruction_file_pathsObject



44
45
46
47
48
49
50
51
52
# File 'lib/agent_harness/providers/anthropic.rb', line 44

def instruction_file_paths
  [
    {
      path: "CLAUDE.md",
      description: "Claude Code CLI agent instructions",
      symlink: true
    }
  ]
end

.model_family(provider_model_name) ⇒ Object

Normalize a provider-specific model name to its model family



70
71
72
# File 'lib/agent_harness/providers/anthropic.rb', line 70

def model_family(provider_model_name)
  provider_model_name.sub(/-\d{8}$/, "")
end

.provider_model_name(family_name) ⇒ Object

Convert a model family name to the provider’s preferred model name



75
76
77
# File 'lib/agent_harness/providers/anthropic.rb', line 75

def provider_model_name(family_name)
  family_name
end

.provider_nameObject



20
21
22
# File 'lib/agent_harness/providers/anthropic.rb', line 20

def provider_name
  :claude
end

.supports_model_family?(family_name) ⇒ Boolean

Check if this provider supports a given model family

Returns:

  • (Boolean)


80
81
82
# File 'lib/agent_harness/providers/anthropic.rb', line 80

def supports_model_family?(family_name)
  MODEL_PATTERN.match?(family_name)
end

Instance Method Details

#auth_typeObject



217
218
219
# File 'lib/agent_harness/providers/anthropic.rb', line 217

def auth_type
  :oauth
end

#build_mcp_flags(mcp_servers, working_dir: nil) ⇒ Object



206
207
208
209
210
211
# File 'lib/agent_harness/providers/anthropic.rb', line 206

def build_mcp_flags(mcp_servers, working_dir: nil)
  return [] if mcp_servers.empty?

  config_path = write_mcp_config_file(mcp_servers, working_dir: working_dir)
  ["--mcp-config", config_path]
end

#capabilitiesObject



180
181
182
183
184
185
186
187
188
189
190
# File 'lib/agent_harness/providers/anthropic.rb', line 180

def capabilities
  {
    streaming: true,
    file_upload: true,
    vision: true,
    tool_use: true,
    json_mode: true,
    mcp: true,
    dangerous_mode: true
  }
end

#configuration_schemaObject



163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/agent_harness/providers/anthropic.rb', line 163

def configuration_schema
  {
    fields: [
      {
        name: :model,
        type: :string,
        label: "Model",
        required: false,
        hint: "Claude model to use (e.g. claude-3-5-sonnet-20241022)",
        accepts_arbitrary: false
      }
    ],
    auth_modes: [:oauth],
    openai_compatible: false
  }
end

#dangerous_mode_flagsObject



213
214
215
# File 'lib/agent_harness/providers/anthropic.rb', line 213

def dangerous_mode_flags
  ["--dangerously-skip-permissions"]
end

#display_nameObject



159
160
161
# File 'lib/agent_harness/providers/anthropic.rb', line 159

def display_name
  "Anthropic Claude CLI"
end

#error_patternsObject



234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
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
# File 'lib/agent_harness/providers/anthropic.rb', line 234

def error_patterns
  {
    rate_limited: [
      /rate.?limit/i,
      /too.?many.?requests/i,
      /429/,
      /overloaded/i,
      /session.?limit/i
    ],
    auth_expired: [
      /oauth.*token.*expired/i,
      /authentication.*error/i,
      /invalid.*api.*key/i,
      /unauthorized/i,
      /401/,
      /session.*expired/i,
      /not.*logged.*in/i,
      /login.*required/i,
      /credentials.*expired/i
    ],
    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/,
      /model.*deprecated/i,
      /end-of-life/i
    ]
  }
end

#execution_semanticsObject



221
222
223
224
225
226
227
228
229
230
231
232
# File 'lib/agent_harness/providers/anthropic.rb', line 221

def execution_semantics
  {
    prompt_delivery: :arg,
    output_format: :json,
    sandbox_aware: true,
    uses_subcommand: false,
    non_interactive_flag: "--print",
    legitimate_exit_codes: [0],
    stderr_is_diagnostic: true,
    parses_rate_limit_reset: false
  }
end

#fetch_mcp_serversObject



281
282
283
284
285
286
287
288
289
290
291
292
293
# File 'lib/agent_harness/providers/anthropic.rb', line 281

def fetch_mcp_servers
  return [] unless self.class.available?

  begin
    result = @executor.execute(["claude", "mcp", "list"], timeout: 5)
    return [] unless result.success?

    parse_claude_mcp_output(result.stdout)
  rescue => e
    log_debug("fetch_mcp_servers_failed", error: e.message)
    []
  end
end

#nameObject



155
156
157
# File 'lib/agent_harness/providers/anthropic.rb', line 155

def name
  "anthropic"
end

#send_message(prompt:, **options) ⇒ Object



192
193
194
195
196
# File 'lib/agent_harness/providers/anthropic.rb', line 192

def send_message(prompt:, **options)
  super
ensure
  cleanup_mcp_tempfiles!
end

#supported_mcp_transportsObject



202
203
204
# File 'lib/agent_harness/providers/anthropic.rb', line 202

def supported_mcp_transports
  %w[stdio http sse]
end

#supports_mcp?Boolean

Returns:

  • (Boolean)


198
199
200
# File 'lib/agent_harness/providers/anthropic.rb', line 198

def supports_mcp?
  true
end