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, Base::DEFAULT_SMOKE_TEST_CONTRACT

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, #smoke_test, #smoke_test_contract, #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

.smoke_test_contractObject



84
85
86
# File 'lib/agent_harness/providers/anthropic.rb', line 84

def smoke_test_contract
  Base::DEFAULT_SMOKE_TEST_CONTRACT
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



221
222
223
# File 'lib/agent_harness/providers/anthropic.rb', line 221

def auth_type
  :oauth
end

#build_mcp_flags(mcp_servers, working_dir: nil) ⇒ Object



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

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



184
185
186
187
188
189
190
191
192
193
194
# File 'lib/agent_harness/providers/anthropic.rb', line 184

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

#configuration_schemaObject



167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/agent_harness/providers/anthropic.rb', line 167

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



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

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

#display_nameObject



163
164
165
# File 'lib/agent_harness/providers/anthropic.rb', line 163

def display_name
  "Anthropic Claude CLI"
end

#error_patternsObject



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
280
281
282
283
# File 'lib/agent_harness/providers/anthropic.rb', line 238

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



225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/agent_harness/providers/anthropic.rb', line 225

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



285
286
287
288
289
290
291
292
293
294
295
296
297
# File 'lib/agent_harness/providers/anthropic.rb', line 285

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



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

def name
  "anthropic"
end

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



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

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

#supported_mcp_transportsObject



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

def supported_mcp_transports
  %w[stdio http sse]
end

#supports_mcp?Boolean

Returns:

  • (Boolean)


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

def supports_mcp?
  true
end