From b5f21f385ae1ba644eaafdcf06bfd33deb6ac549 Mon Sep 17 00:00:00 2001 From: Anibal Angulo Date: Sun, 1 Mar 2026 19:00:03 +0000 Subject: [PATCH] Add Azure Anthropic support --- config.example.yaml | 5 +++++ internal/config/config.go | 27 +++++++++++++++++++---- internal/providers/anthropic/anthropic.go | 27 ++++++++++++++++++++++- internal/providers/providers.go | 4 +++- 4 files changed, 57 insertions(+), 6 deletions(-) diff --git a/config.example.yaml b/config.example.yaml index 8344896..f16ae20 100644 --- a/config.example.yaml +++ b/config.example.yaml @@ -14,3 +14,8 @@ providers: api_key: "YOUR_OPENAI_API_KEY" model: "gpt-4o-mini" endpoint: "https://api.openai.com" + # Azure-hosted Anthropic (Microsoft Foundry) - optional, overrides anthropic if set + # azureanthropic: + # api_key: "YOUR_AZURE_ANTHROPIC_API_KEY" + # endpoint: "https://your-resource.services.ai.azure.com/anthropic" + # model: "claude-sonnet-4-5-20250514" diff --git a/internal/config/config.go b/internal/config/config.go index eafdc44..470f6eb 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -28,10 +28,18 @@ type ServerConfig struct { // ProvidersConfig wraps supported provider settings. type ProvidersConfig struct { - Google ProviderConfig `yaml:"google"` - Anthropic ProviderConfig `yaml:"anthropic"` - OpenAI ProviderConfig `yaml:"openai"` - AzureOpenAI AzureOpenAIConfig `yaml:"azureopenai"` + Google ProviderConfig `yaml:"google"` + Anthropic ProviderConfig `yaml:"anthropic"` + OpenAI ProviderConfig `yaml:"openai"` + AzureOpenAI AzureOpenAIConfig `yaml:"azureopenai"` + AzureAnthropic AzureAnthropicConfig `yaml:"azureanthropic"` +} + +// AzureAnthropicConfig contains Azure-specific settings for Anthropic (Microsoft Foundry). +type AzureAnthropicConfig struct { + APIKey string `yaml:"api_key"` + Endpoint string `yaml:"endpoint"` + Model string `yaml:"model"` } // ProviderConfig contains shared provider configuration fields. @@ -83,6 +91,17 @@ func (cfg *Config) applyEnvOverrides() { if v := os.Getenv("AZURE_OPENAI_API_VERSION"); v != "" { cfg.Providers.AzureOpenAI.APIVersion = v } + + // Azure Anthropic (Microsoft Foundry) overrides + if v := os.Getenv("AZURE_ANTHROPIC_API_KEY"); v != "" { + cfg.Providers.AzureAnthropic.APIKey = v + } + if v := os.Getenv("AZURE_ANTHROPIC_ENDPOINT"); v != "" { + cfg.Providers.AzureAnthropic.Endpoint = v + } + if v := os.Getenv("AZURE_ANTHROPIC_MODEL"); v != "" { + cfg.Providers.AzureAnthropic.Model = v + } } func overrideAPIKey(cfg *ProviderConfig, envKey string) { diff --git a/internal/providers/anthropic/anthropic.go b/internal/providers/anthropic/anthropic.go index b0dc3c4..44e6ce4 100644 --- a/internal/providers/anthropic/anthropic.go +++ b/internal/providers/anthropic/anthropic.go @@ -15,12 +15,14 @@ import ( const Name = "anthropic" // Provider implements the Anthropic SDK integration. +// It supports both direct Anthropic API and Azure-hosted (Microsoft Foundry) endpoints. type Provider struct { cfg config.ProviderConfig client *anthropic.Client + azure bool } -// New constructs a Provider from configuration. +// New constructs a Provider for the direct Anthropic API. func New(cfg config.ProviderConfig) *Provider { var client *anthropic.Client if cfg.APIKey != "" { @@ -33,6 +35,29 @@ func New(cfg config.ProviderConfig) *Provider { } } +// NewAzure constructs a Provider targeting Azure-hosted Anthropic (Microsoft Foundry). +// The Azure endpoint uses api-key header auth and a base URL like +// https://.services.ai.azure.com/anthropic. +func NewAzure(azureCfg config.AzureAnthropicConfig) *Provider { + var client *anthropic.Client + if azureCfg.APIKey != "" && azureCfg.Endpoint != "" { + c := anthropic.NewClient( + option.WithBaseURL(azureCfg.Endpoint), + option.WithAPIKey("unused"), + option.WithAuthToken(azureCfg.APIKey), + ) + client = &c + } + return &Provider{ + cfg: config.ProviderConfig{ + APIKey: azureCfg.APIKey, + Model: azureCfg.Model, + }, + client: client, + azure: true, + } +} + func (p *Provider) Name() string { return Name } // Generate routes the Open Responses request to Anthropic's API. diff --git a/internal/providers/providers.go b/internal/providers/providers.go index f8a6f29..3cf2a68 100644 --- a/internal/providers/providers.go +++ b/internal/providers/providers.go @@ -31,7 +31,9 @@ func NewRegistry(cfg config.ProvidersConfig) (*Registry, error) { if cfg.Google.APIKey != "" { reg.providers[googleprovider.Name] = googleprovider.New(cfg.Google) } - if cfg.Anthropic.APIKey != "" { + if cfg.AzureAnthropic.APIKey != "" && cfg.AzureAnthropic.Endpoint != "" { + reg.providers[anthropicprovider.Name] = anthropicprovider.NewAzure(cfg.AzureAnthropic) + } else if cfg.Anthropic.APIKey != "" { reg.providers[anthropicprovider.Name] = anthropicprovider.New(cfg.Anthropic) } if cfg.AzureOpenAI.APIKey != "" && cfg.AzureOpenAI.Endpoint != "" {