summaryrefslogtreecommitdiff
path: root/internal/appconfig/config.go
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-01-29 20:23:41 +0200
committerPaul Buetow <paul@buetow.org>2026-01-29 20:23:41 +0200
commitc6bb463837ec8c41261604e416aeab023663ba09 (patch)
treeea81ab84b698c3a98fda93a9051d21f2c79708a6 /internal/appconfig/config.go
parentd088267f55c45a7ffd90a056d56e02da61b525fc (diff)
feat: add native Anthropic API provider support
- Implement new anthropicClient with full Client interface - Add Streamer interface for token-by-token streaming via SSE - Add Anthropic Messages API v1 integration with proper headers - Support claude-3-5-sonnet-20241022 as default model - Add configuration via [anthropic] TOML section - Add environment variable overrides (HEXAI_ANTHROPIC_*) - Support both HEXAI_ANTHROPIC_API_KEY and ANTHROPIC_API_KEY fallback - Integrate Anthropic key handling in LSP, CLI, and llmutils - Update provider factory to support 'anthropic' provider name - Add 11 comprehensive unit tests for Anthropic client - Update config.toml.example with [anthropic] section - Update NewFromConfig() signature to accept anthropicAPIKey parameter - All 51 internal LLM tests pass (11 new Anthropic tests + 40 existing) Anthropic models can be accessed via: [anthropic] model = "claude-3-5-sonnet-20241022" base_url = "https://api.anthropic.com/v1" temperature = 0.2 or environment: export HEXAI_PROVIDER="anthropic" export HEXAI_ANTHROPIC_API_KEY="your-key" Amp-Thread-ID: https://ampcode.com/threads/T-019c0af1-f215-72cf-9940-b014b1a9576b Co-authored-by: Amp <amp@ampcode.com>
Diffstat (limited to 'internal/appconfig/config.go')
-rw-r--r--internal/appconfig/config.go35
1 files changed, 35 insertions, 0 deletions
diff --git a/internal/appconfig/config.go b/internal/appconfig/config.go
index 59ffd89..f41d4d9 100644
--- a/internal/appconfig/config.go
+++ b/internal/appconfig/config.go
@@ -68,6 +68,10 @@ type App struct {
CopilotModel string `json:"copilot_model" toml:"copilot_model"`
// Default temperature for Copilot requests (nil means use provider default)
CopilotTemperature *float64 `json:"copilot_temperature" toml:"copilot_temperature"`
+ AnthropicBaseURL string `json:"anthropic_base_url" toml:"anthropic_base_url"`
+ AnthropicModel string `json:"anthropic_model" toml:"anthropic_model"`
+ // Default temperature for Anthropic requests (nil means use provider default)
+ AnthropicTemperature *float64 `json:"anthropic_temperature" toml:"anthropic_temperature"`
// Per-surface provider/model configurations (ordered; first entry is primary)
CompletionConfigs []SurfaceConfig `json:"-" toml:"-"`
@@ -137,6 +141,7 @@ func newDefaultConfig() App {
OpenAITemperature: &t,
OllamaTemperature: &t,
CopilotTemperature: &t,
+ AnthropicTemperature: &t,
ManualInvokeMinPrefix: 0,
CompletionDebounceMs: 800,
CompletionThrottleMs: 0,
@@ -235,6 +240,7 @@ type fileConfig struct {
OpenRouter sectionOpenRouter `toml:"openrouter"`
Copilot sectionCopilot `toml:"copilot"`
Ollama sectionOllama `toml:"ollama"`
+ Anthropic sectionAnthropic `toml:"anthropic"`
Prompts sectionPrompts `toml:"prompts"`
Tmux sectionTmux `toml:"tmux"`
Stats sectionStats `toml:"stats"`
@@ -331,6 +337,12 @@ type sectionOllama struct {
Temperature *float64 `toml:"temperature"`
}
+type sectionAnthropic struct {
+ Model string `toml:"model"`
+ BaseURL string `toml:"base_url"`
+ Temperature *float64 `toml:"temperature"`
+}
+
// Prompts sections
type sectionPrompts struct {
Completion sectionPromptsCompletion `toml:"completion"`
@@ -486,6 +498,16 @@ func (fc *fileConfig) toApp() App {
out.mergeProviderFields(&tmp)
}
+ // anthropic
+ if (fc.Anthropic != sectionAnthropic{}) || fc.Anthropic.Temperature != nil {
+ tmp := App{
+ AnthropicBaseURL: fc.Anthropic.BaseURL,
+ AnthropicModel: fc.Anthropic.Model,
+ AnthropicTemperature: fc.Anthropic.Temperature,
+ }
+ out.mergeProviderFields(&tmp)
+ }
+
// prompts
// completion
if (fc.Prompts.Completion != sectionPromptsCompletion{}) {
@@ -1292,6 +1314,19 @@ func loadFromEnv(logger *log.Logger) *App {
any = true
}
+ if s := getenv("HEXAI_ANTHROPIC_BASE_URL"); s != "" {
+ out.AnthropicBaseURL = s
+ any = true
+ }
+ if model, ok := pickModel("anthropic", getenv("HEXAI_ANTHROPIC_MODEL")); ok {
+ out.AnthropicModel = model
+ any = true
+ }
+ if f, ok := parseFloatPtr("HEXAI_ANTHROPIC_TEMPERATURE"); ok {
+ out.AnthropicTemperature = f
+ any = true
+ }
+
// Per-surface overrides
buildEntry := func(modelKey, tempKey, providerKey string) ([]SurfaceConfig, bool) {
model := getenv(modelKey)