73 lines
1.9 KiB
Go
73 lines
1.9 KiB
Go
package schemas
|
|
|
|
import "strings"
|
|
|
|
// UserAgentIdentifiers lists substrings that may appear in User-Agent for a given integration.
|
|
// Versions of the same client may use different strings; Matches checks any of them.
|
|
type UserAgentIdentifiers []string
|
|
|
|
var (
|
|
// ClaudeCLI — Anthropic Claude Code / Claude CLI (identifiers vary by release).
|
|
ClaudeCLI = UserAgentIdentifiers{"claude-cli", "claude-code", "claude-vscode"}
|
|
GeminiCLI = UserAgentIdentifiers{"geminicli"}
|
|
CodexCLI = UserAgentIdentifiers{"codex-tui"}
|
|
QwenCodeCLI = UserAgentIdentifiers{"qwencode"}
|
|
OpenCode = UserAgentIdentifiers{"opencode"}
|
|
Cursor = UserAgentIdentifiers{"cursor"}
|
|
)
|
|
|
|
// integrationUserAgents is the set of known client User-Agent patterns we persist on the context.
|
|
var integrationUserAgents = []UserAgentIdentifiers{
|
|
ClaudeCLI, GeminiCLI, CodexCLI, QwenCodeCLI, OpenCode, Cursor,
|
|
}
|
|
|
|
// Matches reports whether userAgent contains any identifier (case-insensitive substring match).
|
|
func (ids UserAgentIdentifiers) Matches(userAgent string) bool {
|
|
if len(ids) == 0 || userAgent == "" {
|
|
return false
|
|
}
|
|
ua := strings.ToLower(userAgent)
|
|
for _, id := range ids {
|
|
if id == "" {
|
|
continue
|
|
}
|
|
if strings.Contains(ua, strings.ToLower(id)) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// String returns the first identifier for logging and tests that need a canonical sample value.
|
|
func (ids UserAgentIdentifiers) String() string {
|
|
if len(ids) == 0 {
|
|
return ""
|
|
}
|
|
return ids[0]
|
|
}
|
|
|
|
func ExtractAndSetUserAgentFromHeaders(headers map[string][]string, bifrostCtx *BifrostContext) {
|
|
if len(headers) == 0 {
|
|
return
|
|
}
|
|
if bifrostCtx == nil {
|
|
return
|
|
}
|
|
var userAgent []string
|
|
for key, value := range headers {
|
|
if strings.EqualFold(key, "user-agent") {
|
|
userAgent = value
|
|
break
|
|
}
|
|
}
|
|
if len(userAgent) > 0 {
|
|
ua := userAgent[0]
|
|
for _, ids := range integrationUserAgents {
|
|
if ids.Matches(ua) {
|
|
bifrostCtx.SetValue(BifrostContextKeyUserAgent, ua)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|