feat: add Anthropic provider adapter

Streaming, tool use (with InputJSONDelta assembly), thinking blocks,
cache token tracking, system prompt separation. Tool name sanitization
(fs.read → fs_read) for Anthropic's naming constraints with reverse
translation on tool call responses.

Hardcoded model list with capabilities (Opus 4, Sonnet 4, Haiku 4.5).
Wired into CLI with ANTHROPIC_API_KEY + ANTHROPICS_API_KEY env support.

Also: migrated Mistral SDK to github.com/VikingOwl91/mistral-go-sdk.

Live verified: text streaming + tool calling with claude-sonnet-4.
126 tests across 9 packages.
This commit is contained in:
2026-04-03 13:11:00 +02:00
parent 625f807cd5
commit b0fc4bbbc7
7 changed files with 710 additions and 7 deletions
+22 -6
View File
@@ -12,6 +12,7 @@ import (
"somegit.dev/Owlibou/gnoma/internal/engine"
"somegit.dev/Owlibou/gnoma/internal/provider"
anthropicprov "somegit.dev/Owlibou/gnoma/internal/provider/anthropic"
"somegit.dev/Owlibou/gnoma/internal/provider/mistral"
"somegit.dev/Owlibou/gnoma/internal/stream"
"somegit.dev/Owlibou/gnoma/internal/tool"
@@ -146,11 +147,6 @@ func readInput(args []string) (string, error) {
return "", nil
}
func resolveAPIKey(providerName string) string {
envVar := envKeyFor(providerName)
return os.Getenv(envVar)
}
func envKeyFor(providerName string) string {
switch providerName {
case "mistral":
@@ -166,6 +162,24 @@ func envKeyFor(providerName string) string {
}
}
func resolveAPIKey(providerName string) string {
// Try primary env var
primary := envKeyFor(providerName)
if key := os.Getenv(primary); key != "" {
return key
}
// Try common alternatives
alternatives := map[string][]string{
"anthropic": {"ANTHROPICS_API_KEY"},
}
for _, alt := range alternatives[providerName] {
if key := os.Getenv(alt); key != "" {
return key
}
}
return ""
}
func createProvider(name, apiKey, model string) (provider.Provider, error) {
cfg := provider.ProviderConfig{
APIKey: apiKey,
@@ -175,8 +189,10 @@ func createProvider(name, apiKey, model string) (provider.Provider, error) {
switch name {
case "mistral":
return mistral.New(cfg)
case "anthropic":
return anthropicprov.New(cfg)
default:
return nil, fmt.Errorf("unknown provider %q (M1 supports: mistral)", name)
return nil, fmt.Errorf("unknown provider %q (supports: mistral, anthropic)", name)
}
}