-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdetection.go
More file actions
141 lines (115 loc) · 3.74 KB
/
detection.go
File metadata and controls
141 lines (115 loc) · 3.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package llmproxy
import (
"net/http"
"strings"
)
// ProviderHint contains information that can be used to detect the provider.
type ProviderHint struct {
Model string
Headers http.Header
}
// ProviderDetector determines the upstream provider based on request characteristics.
type ProviderDetector interface {
Detect(hint ProviderHint) string
}
// ProviderDetectorFunc is a function that implements ProviderDetector.
type ProviderDetectorFunc func(hint ProviderHint) string
func (f ProviderDetectorFunc) Detect(hint ProviderHint) string {
return f(hint)
}
// ModelProviderLookup is a function that finds the provider for a given model name.
// This can be backed by models.dev or another model registry.
type ModelProviderLookup func(model string) string
// DefaultProviderDetector detects the provider from model name patterns and headers.
// Precedence: X-Provider header > model pattern > other header heuristics
var DefaultProviderDetector = ProviderDetectorFunc(func(hint ProviderHint) string {
// X-Provider header is always an explicit override
if hint.Headers != nil {
if provider := hint.Headers.Get("X-Provider"); provider != "" {
return provider
}
}
// Model-based detection takes precedence over header heuristics
if hint.Model != "" {
if provider := DetectProviderFromModel(hint.Model); provider != "" {
return provider
}
}
// Header heuristics as fallback
if hint.Headers != nil {
return detectProviderFromHeaderHeuristics(hint.Headers)
}
return ""
})
func detectProviderFromHeaderHeuristics(headers http.Header) string {
if headers.Get("anthropic-version") != "" || strings.HasPrefix(headers.Get("X-API-Key"), "sk-ant-") {
return "anthropic"
}
if strings.HasPrefix(headers.Get("Authorization"), "Bearer sk-") {
if strings.Contains(headers.Get("Authorization"), "sk-proj-") {
return "openai"
}
}
if headers.Get("api-key") != "" {
return "azure"
}
if strings.HasPrefix(headers.Get("Authorization"), "Bearer gsk_") {
return "groq"
}
return ""
}
// DetectProviderFromModel returns the provider name based on model naming patterns.
func DetectProviderFromModel(model string) string {
if model == "" {
return ""
}
// Check for explicit provider prefix (e.g., "openai/gpt-4", "anthropic/claude-3-opus")
if idx := strings.Index(model, "/"); idx >= 0 {
prefix := model[:idx]
switch prefix {
case "openai", "anthropic", "googleai", "groq", "fireworks", "xai", "perplexity", "bedrock", "azure", "mistral":
return prefix
}
}
switch {
case strings.HasPrefix(model, "gpt-"),
strings.HasPrefix(model, "o1-"),
strings.HasPrefix(model, "o3-"),
strings.HasPrefix(model, "o4-"),
strings.HasPrefix(model, "chatgpt-"),
strings.HasPrefix(model, "text-"),
strings.HasPrefix(model, "davinci-"),
strings.HasPrefix(model, "curie-"),
strings.HasPrefix(model, "babbage-"),
strings.HasPrefix(model, "ada-"):
return "openai"
case strings.HasPrefix(model, "claude-"),
strings.HasPrefix(model, "claude"):
return "anthropic"
case strings.HasPrefix(model, "gemini-"),
strings.HasPrefix(model, "gemma-"),
strings.HasPrefix(model, "palm-"):
return "googleai"
case strings.HasPrefix(model, "grok-"):
return "xai"
case strings.HasPrefix(model, "llama-"),
strings.HasPrefix(model, "mixtral-"),
strings.HasPrefix(model, "mistral-"):
if strings.Contains(model, "groq") {
return "groq"
}
return "openai_compatible"
case strings.HasPrefix(model, "accounts/fireworks/"),
strings.HasPrefix(model, "fireworks"):
return "fireworks"
case strings.Contains(model, "sonar"):
return "perplexity"
case strings.HasPrefix(model, "amazon."),
strings.HasPrefix(model, "anthropic.claude-"),
strings.HasPrefix(model, "meta."),
strings.HasPrefix(model, "cohere."):
return "bedrock"
default:
return ""
}
}