Class: Providers::Anthropic
- Inherits:
-
Object
- Object
- Providers::Anthropic
- Includes:
- HTTParty
- Defined in:
- lib/providers/anthropic.rb
Defined Under Namespace
Classes: 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."
Instance Attribute Summary collapse
-
#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:, **options) ⇒ Hash
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.
70 71 72 |
# File 'lib/providers/anthropic.rb', line 70 def initialize(token = nil) @token = token || self.class.fetch_token end |
Instance Attribute Details
#token ⇒ Object (readonly)
Returns the value of attribute token.
68 69 70 |
# File 'lib/providers/anthropic.rb', line 68 def token @token end |
Class Method Details
.fetch_token ⇒ Object
30 31 32 33 34 35 36 37 38 39 |
# File 'lib/providers/anthropic.rb', line 30 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.
62 63 64 65 |
# File 'lib/providers/anthropic.rb', line 62 def validate_token_api!(token) provider = new(token) provider.validate_credentials! end |
.validate_token_format!(token) ⇒ Object
41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/providers/anthropic.rb', line 41 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.
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/providers/anthropic.rb', line 108 def count_tokens(model:, messages:, **) wrap_system_prompt!() 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:, **options) ⇒ Hash
Send a message to the Anthropic API and return the parsed response.
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/providers/anthropic.rb', line 84 def (model:, messages:, max_tokens:, **) 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) 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.
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/providers/anthropic.rb', line 134 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 |