From b04a17beb2707db64f260fdc30b0b15f98c5eb42 Mon Sep 17 00:00:00 2001 From: Kaushik Iska Date: Wed, 19 Aug 2026 12:36:00 -0500 Subject: [PATCH] Add a retry-config overload to Anthropic create_client The OpenAI factory already accepts a retry::RetryConfig so callers can tune retry behavior for unreliable networks, but the Anthropic factory offered no equivalent, leaving its clients pinned to the default policy. Add the matching create_client(api_key, base_url, retry_config) overload. The two public AnthropicClient constructors now delegate to one private constructor taking std::optional rather than duplicating the ProviderConfig block. --- README.md | 3 +++ include/ai/anthropic.h | 10 ++++++++++ src/providers/anthropic/anthropic_client.cpp | 19 ++++++++++++++++--- src/providers/anthropic/anthropic_client.h | 11 +++++++++++ src/providers/anthropic/anthropic_factory.cpp | 8 ++++++++ tests/unit/anthropic_client_test.cpp | 11 +++++++++++ 6 files changed, 59 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4db55d7..daf536f 100644 --- a/README.md +++ b/README.md @@ -251,6 +251,9 @@ int main() { } ``` +The same retry-config overload is available from +`ai::anthropic::create_client` for Anthropic requests. + #### Using OpenAI-Compatible APIs (OpenRouter, etc.) The OpenAI client can be used with any OpenAI-compatible API by specifying a custom base URL. This allows you to use alternative providers like OpenRouter, which offers access to multiple models through a unified API. diff --git a/include/ai/anthropic.h b/include/ai/anthropic.h index 91a55e3..0a10da7 100644 --- a/include/ai/anthropic.h +++ b/include/ai/anthropic.h @@ -5,6 +5,7 @@ "Anthropic component not available. Link with ai::anthropic or ai::sdk to use Anthropic functionality." #endif +#include "retry/retry_policy.h" #include "types/client.h" #include @@ -57,6 +58,15 @@ Client create_client(const std::string& api_key); /// @return Configured Anthropic client Client create_client(const std::string& api_key, const std::string& base_url); +/// Create an Anthropic client with custom configuration and retry settings +/// @param api_key Anthropic API key +/// @param base_url Custom base URL (for Anthropic-compatible APIs) +/// @param retry_config Custom retry configuration +/// @return Configured Anthropic client +Client create_client(const std::string& api_key, + const std::string& base_url, + const retry::RetryConfig& retry_config); + /// Try to create an Anthropic client using environment variables /// Reads API key from ANTHROPIC_API_KEY environment variable /// @return Optional client - has value if environment variable is set, empty diff --git a/src/providers/anthropic/anthropic_client.cpp b/src/providers/anthropic/anthropic_client.cpp index 042a9d2..4516235 100644 --- a/src/providers/anthropic/anthropic_client.cpp +++ b/src/providers/anthropic/anthropic_client.cpp @@ -14,6 +14,18 @@ namespace anthropic { AnthropicClient::AnthropicClient(const std::string& api_key, const std::string& base_url) + : AnthropicClient(api_key, base_url, std::optional{}) {} + +AnthropicClient::AnthropicClient(const std::string& api_key, + const std::string& base_url, + const retry::RetryConfig& retry_config) + : AnthropicClient(api_key, + base_url, + std::optional(retry_config)) {} + +AnthropicClient::AnthropicClient(const std::string& api_key, + const std::string& base_url, + std::optional retry_config) : BaseProviderClient( providers::ProviderConfig{ .api_key = api_key, @@ -23,11 +35,12 @@ AnthropicClient::AnthropicClient(const std::string& api_key, .auth_header_name = "x-api-key", .auth_header_prefix = "", .extra_headers = {{"anthropic-version", "2023-06-01"}}, - .retry_config = std::nullopt}, + .retry_config = retry_config}, std::make_unique(), std::make_unique()) { - ai::logger::log_debug("Anthropic client initialized with base_url: {}", - base_url); + ai::logger::log_debug("Anthropic client initialized with base_url: {}{}", + base_url, + config_.retry_config ? " and custom retry config" : ""); } StreamResult AnthropicClient::stream_text(const StreamOptions& options) { diff --git a/src/providers/anthropic/anthropic_client.h b/src/providers/anthropic/anthropic_client.h index f66e432..509f861 100644 --- a/src/providers/anthropic/anthropic_client.h +++ b/src/providers/anthropic/anthropic_client.h @@ -1,8 +1,10 @@ #pragma once +#include "ai/retry/retry_policy.h" #include "ai/types/stream_options.h" #include "providers/base_provider_client.h" +#include #include #include @@ -15,6 +17,10 @@ class AnthropicClient : public providers::BaseProviderClient { const std::string& api_key, const std::string& base_url = "https://api.anthropic.com"); + AnthropicClient(const std::string& api_key, + const std::string& base_url, + const retry::RetryConfig& retry_config); + // Override only what's specific to Anthropic StreamResult stream_text(const StreamOptions& options) override; std::string provider_name() const override; @@ -26,6 +32,11 @@ class AnthropicClient : public providers::BaseProviderClient { // Member access for testing const std::string& get_api_key() const { return config_.api_key; } const std::string& get_base_url() const { return config_.base_url; } + + private: + AnthropicClient(const std::string& api_key, + const std::string& base_url, + std::optional retry_config); }; } // namespace anthropic diff --git a/src/providers/anthropic/anthropic_factory.cpp b/src/providers/anthropic/anthropic_factory.cpp index 9fae17b..4c358b0 100644 --- a/src/providers/anthropic/anthropic_factory.cpp +++ b/src/providers/anthropic/anthropic_factory.cpp @@ -47,6 +47,14 @@ Client create_client(const std::string& api_key, const std::string& base_url) { get_api_key_or_default(api_key), get_base_url_or_default(base_url))); } +Client create_client(const std::string& api_key, + const std::string& base_url, + const retry::RetryConfig& retry_config) { + return Client(std::make_unique( + get_api_key_or_default(api_key), get_base_url_or_default(base_url), + retry_config)); +} + std::optional try_create_client() { auto api_key = utils::non_empty_env("ANTHROPIC_API_KEY"); if (!api_key) { diff --git a/tests/unit/anthropic_client_test.cpp b/tests/unit/anthropic_client_test.cpp index 109751d..aeab3da 100644 --- a/tests/unit/anthropic_client_test.cpp +++ b/tests/unit/anthropic_client_test.cpp @@ -79,6 +79,17 @@ TEST_F(AnthropicClientTest, ConstructorWithHttpUrl) { // EXPECT_FALSE(client.get_use_ssl()); } +TEST_F(AnthropicClientTest, ConstructorWithCustomRetryConfig) { + retry::RetryConfig retry_config; + retry_config.max_retries = 5; + + ai::anthropic::AnthropicClient client( + "sk-ant-test", "https://api.anthropic.com", retry_config); + + EXPECT_TRUE(client.is_valid()); + EXPECT_EQ(client.get_base_url(), "https://api.anthropic.com"); +} + // Model Support Tests TEST_F(AnthropicClientTest, SupportedModelsContainsExpectedModels) { auto models = client_->supported_models();