Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 16 additions & 10 deletions src/adapter/adapters/anthropic/adapter_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,19 +97,25 @@ impl Adapter for AnthropicAdapter {
) -> Result<WebRequestData> {
let ServiceTarget { endpoint, auth, model } = target;

// -- api_key
let api_key = get_api_key(auth, &model)?;

// -- url
let url = Self::get_service_url(&model, service_type, endpoint)?;

// -- headers
let headers = Headers::from(vec![
// headers
("x-api-key".to_string(), api_key),
("anthropic-beta".to_string(), "effort-2025-11-24".to_string()),
("anthropic-version".to_string(), ANTHROPIC_VERSION.to_string()),
]);
// -- headers (Bearer token uses Authorization header, otherwise x-api-key)
let headers = match &auth {
AuthData::BearerToken(token) => Headers::from(vec![
("Authorization".to_string(), format!("Bearer {}", token)),
("anthropic-beta".to_string(), "effort-2025-11-24".to_string()),
("anthropic-version".to_string(), ANTHROPIC_VERSION.to_string()),
]),
_ => {
let api_key = get_api_key(auth, &model)?;
Headers::from(vec![
("x-api-key".to_string(), api_key),
("anthropic-beta".to_string(), "effort-2025-11-24".to_string()),
("anthropic-version".to_string(), ANTHROPIC_VERSION.to_string()),
])
}
};

// -- Parts
let AnthropicRequestParts {
Expand Down
47 changes: 47 additions & 0 deletions src/resolver/auth_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ pub enum AuthData {
/// The key value itself.
Key(String),

/// OAuth Bearer token for providers that support `Authorization: Bearer` auth.
BearerToken(String),

/// Override headers and request url for unorthodox authentication schemes
RequestOverride { url: String, headers: Headers },

Expand Down Expand Up @@ -44,6 +47,8 @@ impl AuthData {
match self {
// Overrides don't use an api key
AuthData::RequestOverride { .. } => Ok(String::new()),
// Bearer tokens return the token value
AuthData::BearerToken(value) => Ok(value.to_string()),
AuthData::FromEnv(env_name) => {
// Get value from the environment name.
let value = std::env::var(env_name).map_err(|_| Error::ApiKeyEnvNotFound {
Expand All @@ -66,6 +71,7 @@ impl std::fmt::Debug for AuthData {
// NOTE: Here we also redact for `FromEnv` in case the developer confuses this with a key.
AuthData::FromEnv(_env_name) => write!(f, "AuthData::FromEnv(REDACTED)"),
AuthData::Key(_) => write!(f, "AuthData::Single(REDACTED)"),
AuthData::BearerToken(_) => write!(f, "AuthData::BearerToken(REDACTED)"),
AuthData::MultiKeys(_) => write!(f, "AuthData::Multi(REDACTED)"),
AuthData::RequestOverride { .. } => {
write!(f, "AuthData::RequestOverride {{ url: REDACTED, headers: REDACTED }}")
Expand All @@ -75,3 +81,44 @@ impl std::fmt::Debug for AuthData {
}

// endregion: --- AuthData Std Impls

// region: --- Tests

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_bearer_token_single_key_value() {
let auth = AuthData::BearerToken("sk-ant-oat01-test-token".to_string());
let value = auth.single_key_value().unwrap();
assert_eq!(value, "sk-ant-oat01-test-token");
}

#[test]
fn test_bearer_token_debug_redacted() {
let auth = AuthData::BearerToken("secret-token".to_string());
let debug = format!("{:?}", auth);
assert_eq!(debug, "AuthData::BearerToken(REDACTED)");
assert!(!debug.contains("secret-token"));
}

#[test]
fn test_key_single_key_value() {
let auth = AuthData::Key("test-api-key".to_string());
let value = auth.single_key_value().unwrap();
assert_eq!(value, "test-api-key");
}

#[test]
fn test_request_override_returns_empty() {
let auth = AuthData::RequestOverride {
url: "https://example.com".to_string(),
headers: Headers::default(),
};
let value = auth.single_key_value().unwrap();
assert_eq!(value, "");
}
}

// endregion: --- Tests
Loading