Class: Providers::Anthropic
- Inherits:
-
Object
- Object
- Providers::Anthropic
- Includes:
- HTTParty
- Defined in:
- lib/providers/anthropic.rb
Defined Under Namespace
Classes: ApiResponse, AuthenticationError, Error, RateLimitError, ServerError, TokenFormatError, TransientError
Constant Summary collapse
- TOKEN_PREFIX =
"sk-ant-oat01-"- TOKEN_MIN_LENGTH =
80- API_VERSION =
"2023-06-01"- REQUIRED_BETA =
"oauth-2025-04-20"- OAUTH_PASSPHRASE =
Anthropic requires this exact string as the first system block for OAuth subscription tokens on Sonnet/Opus. Without it, /v1/messages returns 400.
"You are Claude Code, Anthropic's official CLI for Claude."- RATE_LIMIT_HEADERS =
Rate limit header names for extraction
{ "5h_status" => "Anthropic-Ratelimit-Unified-5h-Status", "5h_reset" => "Anthropic-Ratelimit-Unified-5h-Reset", "5h_utilization" => "Anthropic-Ratelimit-Unified-5h-Utilization", "7d_status" => "Anthropic-Ratelimit-Unified-7d-Status", "7d_reset" => "Anthropic-Ratelimit-Unified-7d-Reset", "7d_utilization" => "Anthropic-Ratelimit-Unified-7d-Utilization" }.freeze
Instance Attribute Summary collapse
-
#api_metrics ⇒ Hash?
readonly
Rate limits and usage data.
-
#body ⇒ Hash
readonly
Parsed API response.
-
#token ⇒ Object
readonly
Returns the value of attribute token.
Class Method Summary collapse
- .fetch_token ⇒ Object
-
.validate_token_api!(token) ⇒ true
Validate a token against the live Anthropic API.
- .validate_token_format!(token) ⇒ Object
Instance Method Summary collapse
-
#count_tokens(model:, messages:, **options) ⇒ Integer
Count tokens in a message payload without creating a message.
-
#create_message(model:, messages:, max_tokens:, include_metrics: false, **options) ⇒ Hash, ApiResponse
Send a message to the Anthropic API and return the parsed response.
-
#initialize(token = nil) ⇒ Anthropic
constructor
A new instance of Anthropic.
-
#validate_credentials! ⇒ true
Verify the token is accepted by Anthropic using the free models endpoint.
Constructor Details
#initialize(token = nil) ⇒ Anthropic
Returns a new instance of Anthropic.
98 99 100 |
# File 'lib/providers/anthropic.rb', line 98 def initialize(token = nil) @token = token || self.class.fetch_token end |
Instance Attribute Details
#api_metrics ⇒ Hash? (readonly)
Returns rate limits and usage data.
37 38 39 40 41 42 43 44 45 46 |
# File 'lib/providers/anthropic.rb', line 37 ApiResponse = Data.define(:body, :api_metrics) do # Delegate Hash methods to body for backward compatibility. # Callers using response["content"] continue to work unchanged. def [](key) = body[key] def dig(...) = body.dig(...) def fetch(...) = body.fetch(...) def key?(key) = body.key?(key) def to_h = body def to_json(...) = body.to_json(...) end |
#body ⇒ Hash (readonly)
Returns parsed API response.
37 38 39 40 41 42 43 44 45 46 |
# File 'lib/providers/anthropic.rb', line 37 ApiResponse = Data.define(:body, :api_metrics) do # Delegate Hash methods to body for backward compatibility. # Callers using response["content"] continue to work unchanged. def [](key) = body[key] def dig(...) = body.dig(...) def fetch(...) = body.fetch(...) def key?(key) = body.key?(key) def to_h = body def to_json(...) = body.to_json(...) end |
#token ⇒ Object (readonly)
Returns the value of attribute token.
96 97 98 |
# File 'lib/providers/anthropic.rb', line 96 def token @token end |
Class Method Details
.fetch_token ⇒ Object
58 59 60 61 62 63 64 65 66 67 |
# File 'lib/providers/anthropic.rb', line 58 def fetch_token token = CredentialStore.read("anthropic", "subscription_token") return token if token.present? return "sk-ant-oat01-#{"0" * 68}" if ENV["CI"] raise AuthenticationError, <<~MSG.strip No Anthropic subscription token found in credentials. Use the TUI token setup (Ctrl+a → a) to configure your token. MSG end |
.validate_token_api!(token) ⇒ true
Validate a token against the live Anthropic API. Delegates to #validate_credentials! on a throwaway instance.
90 91 92 93 |
# File 'lib/providers/anthropic.rb', line 90 def validate_token_api!(token) provider = new(token) provider.validate_credentials! end |
.validate_token_format!(token) ⇒ Object
69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/providers/anthropic.rb', line 69 def validate_token_format!(token) unless token.start_with?(TOKEN_PREFIX) raise TokenFormatError, "Token must start with '#{TOKEN_PREFIX}'. Got: '#{token[0..12]}...'" end unless token.length >= TOKEN_MIN_LENGTH raise TokenFormatError, "Token must be at least #{TOKEN_MIN_LENGTH} characters (got #{token.length})" end true end |
Instance Method Details
#count_tokens(model:, messages:, **options) ⇒ Integer
Count tokens in a message payload without creating a message. Uses the free Anthropic token counting endpoint.
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/providers/anthropic.rb', line 140 def count_tokens(model:, messages:, **) body = {model: model, messages: }.merge() response = self.class.post( "/v1/messages/count_tokens", body: body.to_json, headers: request_headers, timeout: Anima::Settings.api_timeout ) result = handle_response(response) result["input_tokens"] rescue Errno::ECONNRESET, Net::ReadTimeout, Net::OpenTimeout, SocketError, EOFError => network_error raise TransientError, "#{network_error.class}: #{network_error.}" end |
#create_message(model:, messages:, max_tokens:, include_metrics: false, **options) ⇒ Hash, ApiResponse
Send a message to the Anthropic API and return the parsed response.
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/providers/anthropic.rb', line 115 def (model:, messages:, max_tokens:, include_metrics: false, **) wrap_system_prompt!() () body = {model: model, messages: , max_tokens: max_tokens}.merge() response = self.class.post( "/v1/messages", body: body.to_json, headers: request_headers, timeout: Anima::Settings.api_timeout ) handle_response(response, include_metrics: include_metrics) rescue Errno::ECONNRESET, Net::ReadTimeout, Net::OpenTimeout, SocketError, EOFError => network_error raise TransientError, "#{network_error.class}: #{network_error.}" end |
#validate_credentials! ⇒ true
Verify the token is accepted by Anthropic using the free models endpoint. Returns true on success; raises typed exceptions on failure so callers can distinguish permanent auth problems from transient outages.
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
# File 'lib/providers/anthropic.rb', line 165 def validate_credentials! response = self.class.get( "/v1/models", headers: request_headers, timeout: Anima::Settings.api_timeout ) case response.code when 200 true when 401 raise AuthenticationError, "Token rejected by Anthropic API (401). Re-run `claude setup-token` and use the TUI token setup (Ctrl+a → a)." when 403 raise AuthenticationError, "Token not authorized for API access (403). This credential may be restricted to Claude Code only." else handle_response(response) end rescue Errno::ECONNRESET, Net::ReadTimeout, Net::OpenTimeout, SocketError, EOFError => network_error raise TransientError, "#{network_error.class}: #{network_error.}" end |