Class: RubynCode::LLM::Adapters::Anthropic

Inherits:
Base
  • Object
show all
Includes:
JsonParsing, PromptCaching, TokenCaching
Defined in:
lib/rubyn_code/llm/adapters/anthropic.rb

Overview

rubocop:disable Metrics/ClassLength – auth helpers + streaming + finalize are all needed

Direct Known Subclasses

AnthropicCompatible

Constant Summary collapse

API_URL =
'https://api.anthropic.com/v1/messages'
ANTHROPIC_VERSION =
'2023-06-01'
MAX_RETRIES =
3
RETRY_DELAYS =
[2, 5, 10].freeze
AVAILABLE_MODELS =
%w[
  claude-fable-5
  claude-opus-4-8
  claude-sonnet-4-20250514
  claude-haiku-4-20250506
].freeze

Constants included from PromptCaching

PromptCaching::CACHE_EPHEMERAL, PromptCaching::OAUTH_GATE

Instance Method Summary collapse

Instance Method Details

#access_tokenString?

Returns the access token in use. Accepts either a raw String token or a Hash like { access_token: “…”, expires_at: …, source: :keychain }. Memoized per-instance so that repeated calls during one request don’t re-hit the token store.

Returns:

  • (String, nil)

    the access token in use. Accepts either a raw String token or a Hash like { access_token: “…”, expires_at: …, source: :keychain }. Memoized per-instance so that repeated calls during one request don’t re-hit the token store.



81
82
83
84
85
86
87
88
89
90
91
# File 'lib/rubyn_code/llm/adapters/anthropic.rb', line 81

def access_token
  return @access_token if defined?(@access_token)

  token = raw_access_token
  @access_token =
    case token
    when nil    then nil
    when String then token.empty? ? nil : token
    when Hash   then token[:access_token] || token['access_token']
    end
end

#api_keyString?

Returns the API key (ANTHROPIC_API_KEY), or nil.

Returns:

  • (String, nil)

    the API key (ANTHROPIC_API_KEY), or nil



94
95
96
# File 'lib/rubyn_code/llm/adapters/anthropic.rb', line 94

def api_key
  ENV.fetch('ANTHROPIC_API_KEY', nil)
end

#chat(messages:, model:, max_tokens:, tools: nil, system: nil, on_text: nil, task_budget: nil) ⇒ Object

rubocop:disable Metrics/ParameterLists – mirrors LLM adapter interface



36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/rubyn_code/llm/adapters/anthropic.rb', line 36

def chat(messages:, model:, max_tokens:, tools: nil, system: nil, on_text: nil, task_budget: nil) # rubocop:disable Metrics/ParameterLists -- mirrors LLM adapter interface
  ensure_valid_token!
  use_streaming = on_text && oauth_token?

  body = build_request_body(
    messages: messages, tools: tools, system: system,
    model: model, max_tokens: max_tokens,
    stream: use_streaming, task_budget: task_budget
  )

  return stream_request(body, on_text) if use_streaming

  execute_with_retries(body, on_text)
end

#ensure_valid_token!Object

Validate the active auth path before sending the request. Raises Client::AuthExpiredError with a clear message instead of letting the HTTP request fail with a 401.



56
57
58
59
60
61
62
# File 'lib/rubyn_code/llm/adapters/anthropic.rb', line 56

def ensure_valid_token!
  return if token_valid? && access_token && !access_token.empty?

  return if !oauth_token? && api_key && !api_key.empty?

  raise Client::AuthExpiredError, 'No valid authentication configured'
end

#modelsObject



32
33
34
# File 'lib/rubyn_code/llm/adapters/anthropic.rb', line 32

def models
  AVAILABLE_MODELS
end

#oauth_token?Boolean

Returns true when using the OAuth token (vs API key). A token from the keychain (or marked source: :keychain / :oauth) is treated as OAuth; a token from :env or :tokens_file is treated as a long-lived API key.

Returns:

  • (Boolean)

    true when using the OAuth token (vs API key). A token from the keychain (or marked source: :keychain / :oauth) is treated as OAuth; a token from :env or :tokens_file is treated as a long-lived API key.



68
69
70
71
72
73
74
# File 'lib/rubyn_code/llm/adapters/anthropic.rb', line 68

def oauth_token?
  token = raw_access_token
  return false unless token.is_a?(Hash)

  source = token[:source] || token['source']
  [:keychain, 'keychain', :oauth].include?(source)
end

#provider_nameObject



28
29
30
# File 'lib/rubyn_code/llm/adapters/anthropic.rb', line 28

def provider_name
  'anthropic'
end

#raw_access_tokenObject



107
108
109
110
111
112
# File 'lib/rubyn_code/llm/adapters/anthropic.rb', line 107

def raw_access_token
  return @raw_access_token if defined?(@raw_access_token)

  @raw_access_token =
    (Auth::TokenStore.load if defined?(Auth::TokenStore) && Auth::TokenStore.respond_to?(:load))
end

#token_valid?Boolean

Returns true if the token store says the active credential is still valid.

Returns:

  • (Boolean)

    true if the token store says the active credential is still valid



100
101
102
103
104
105
# File 'lib/rubyn_code/llm/adapters/anthropic.rb', line 100

def token_valid?
  return true unless defined?(Auth::TokenStore)
  return true unless Auth::TokenStore.respond_to?(:valid?)

  Auth::TokenStore.valid?
end