ScuttleBot

scuttlebot / internal / llm / anthropic.go
Source Blame History 100 lines
5ac549c… lmata 1 package llm
5ac549c… lmata 2
5ac549c… lmata 3 import (
5ac549c… lmata 4 "bytes"
5ac549c… lmata 5 "context"
5ac549c… lmata 6 "encoding/json"
5ac549c… lmata 7 "fmt"
5ac549c… lmata 8 "io"
5ac549c… lmata 9 "net/http"
5ac549c… lmata 10 )
5ac549c… lmata 11
5ac549c… lmata 12 const anthropicAPIBase = "https://api.anthropic.com"
5ac549c… lmata 13 const anthropicVersion = "2023-06-01"
5ac549c… lmata 14
5ac549c… lmata 15 // anthropicModels is a curated static list — Anthropic has no public list API.
5ac549c… lmata 16 var anthropicModels = []ModelInfo{
5ac549c… lmata 17 {ID: "claude-opus-4-6", Name: "Claude Opus 4.6"},
5ac549c… lmata 18 {ID: "claude-sonnet-4-6", Name: "Claude Sonnet 4.6"},
5ac549c… lmata 19 {ID: "claude-haiku-4-5-20251001", Name: "Claude Haiku 4.5"},
5ac549c… lmata 20 {ID: "claude-3-5-sonnet-20241022", Name: "Claude 3.5 Sonnet"},
5ac549c… lmata 21 {ID: "claude-3-5-haiku-20241022", Name: "Claude 3.5 Haiku"},
5ac549c… lmata 22 {ID: "claude-3-opus-20240229", Name: "Claude 3 Opus"},
5ac549c… lmata 23 {ID: "claude-3-sonnet-20240229", Name: "Claude 3 Sonnet"},
5ac549c… lmata 24 {ID: "claude-3-haiku-20240307", Name: "Claude 3 Haiku"},
5ac549c… lmata 25 }
5ac549c… lmata 26
5ac549c… lmata 27 type anthropicProvider struct {
5ac549c… lmata 28 apiKey string
5ac549c… lmata 29 model string
5ac549c… lmata 30 baseURL string
5ac549c… lmata 31 http *http.Client
5ac549c… lmata 32 }
5ac549c… lmata 33
5ac549c… lmata 34 func newAnthropicProvider(cfg BackendConfig, hc *http.Client) *anthropicProvider {
5ac549c… lmata 35 model := cfg.Model
5ac549c… lmata 36 if model == "" {
5ac549c… lmata 37 model = "claude-3-5-sonnet-20241022"
5ac549c… lmata 38 }
5ac549c… lmata 39 baseURL := cfg.BaseURL
5ac549c… lmata 40 if baseURL == "" {
5ac549c… lmata 41 baseURL = anthropicAPIBase
5ac549c… lmata 42 }
5ac549c… lmata 43 return &anthropicProvider{
5ac549c… lmata 44 apiKey: cfg.APIKey,
5ac549c… lmata 45 model: model,
5ac549c… lmata 46 baseURL: baseURL,
5ac549c… lmata 47 http: hc,
5ac549c… lmata 48 }
5ac549c… lmata 49 }
5ac549c… lmata 50
5ac549c… lmata 51 func (p *anthropicProvider) Summarize(ctx context.Context, prompt string) (string, error) {
5ac549c… lmata 52 body, _ := json.Marshal(map[string]any{
5ac549c… lmata 53 "model": p.model,
5ac549c… lmata 54 "max_tokens": 512,
5ac549c… lmata 55 "messages": []map[string]string{
5ac549c… lmata 56 {"role": "user", "content": prompt},
5ac549c… lmata 57 },
5ac549c… lmata 58 })
5ac549c… lmata 59 req, err := http.NewRequestWithContext(ctx, "POST", p.baseURL+"/v1/messages", bytes.NewReader(body))
5ac549c… lmata 60 if err != nil {
5ac549c… lmata 61 return "", err
5ac549c… lmata 62 }
5ac549c… lmata 63 req.Header.Set("x-api-key", p.apiKey)
5ac549c… lmata 64 req.Header.Set("anthropic-version", anthropicVersion)
5ac549c… lmata 65 req.Header.Set("Content-Type", "application/json")
5ac549c… lmata 66
5ac549c… lmata 67 resp, err := p.http.Do(req)
5ac549c… lmata 68 if err != nil {
5ac549c… lmata 69 return "", fmt.Errorf("anthropic request: %w", err)
5ac549c… lmata 70 }
5ac549c… lmata 71 defer resp.Body.Close()
5ac549c… lmata 72
5ac549c… lmata 73 data, _ := io.ReadAll(resp.Body)
5ac549c… lmata 74 if resp.StatusCode != http.StatusOK {
5ac549c… lmata 75 return "", fmt.Errorf("anthropic error %d: %s", resp.StatusCode, string(data))
5ac549c… lmata 76 }
5ac549c… lmata 77
5ac549c… lmata 78 var result struct {
5ac549c… lmata 79 Content []struct {
5ac549c… lmata 80 Type string `json:"type"`
5ac549c… lmata 81 Text string `json:"text"`
5ac549c… lmata 82 } `json:"content"`
5ac549c… lmata 83 }
5ac549c… lmata 84 if err := json.Unmarshal(data, &result); err != nil {
5ac549c… lmata 85 return "", fmt.Errorf("anthropic parse: %w", err)
5ac549c… lmata 86 }
5ac549c… lmata 87 for _, c := range result.Content {
5ac549c… lmata 88 if c.Type == "text" {
5ac549c… lmata 89 return c.Text, nil
5ac549c… lmata 90 }
5ac549c… lmata 91 }
5ac549c… lmata 92 return "", fmt.Errorf("anthropic returned no text content")
5ac549c… lmata 93 }
5ac549c… lmata 94
5ac549c… lmata 95 // DiscoverModels returns a curated static list (Anthropic has no public list API).
5ac549c… lmata 96 func (p *anthropicProvider) DiscoverModels(_ context.Context) ([]ModelInfo, error) {
5ac549c… lmata 97 models := make([]ModelInfo, len(anthropicModels))
5ac549c… lmata 98 copy(models, anthropicModels)
5ac549c… lmata 99 return models, nil
5ac549c… lmata 100 }

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button