package openai import "strings" // CodexCLIUserAgentPrefixes matches Codex CLI User-Agent patterns // Examples: "codex_vscode/1.0.0", "codex_cli_rs/0.1.2" var CodexCLIUserAgentPrefixes = []string{ "codex_vscode/", "codex_cli_rs/", } // CodexOfficialClientUserAgentPrefixes matches Codex 官方客户端家族 User-Agent 前缀。 // 该列表仅用于 OpenAI OAuth `codex_cli_only` 访问限制判定。 var CodexOfficialClientUserAgentPrefixes = []string{ "codex_cli_rs/", "codex_vscode/", "codex_app/", "codex_chatgpt_desktop/", "codex_atlas/", "codex_exec/", "codex_sdk_ts/", "codex ", } // CodexOfficialClientOriginatorPrefixes matches Codex 官方客户端家族 originator 前缀。 // 说明:OpenAI 官方 Codex 客户端并不只使用固定的 codex_app 标识。 // 例如 codex_cli_rs、codex_vscode、codex_chatgpt_desktop、codex_atlas、codex_exec、codex_sdk_ts 等。 var CodexOfficialClientOriginatorPrefixes = []string{ "codex_", "codex ", } // IsCodexCLIRequest checks if the User-Agent indicates a Codex CLI request func IsCodexCLIRequest(userAgent string) bool { ua := normalizeCodexClientHeader(userAgent) if ua == "" { return false } return matchCodexClientHeaderPrefixes(ua, CodexCLIUserAgentPrefixes) } // IsCodexOfficialClientRequest checks if the User-Agent indicates a Codex 官方客户端请求。 // 与 IsCodexCLIRequest 解耦,避免影响历史兼容逻辑。 func IsCodexOfficialClientRequest(userAgent string) bool { ua := normalizeCodexClientHeader(userAgent) if ua == "" { return false } return matchCodexClientHeaderPrefixes(ua, CodexOfficialClientUserAgentPrefixes) } // IsCodexOfficialClientOriginator checks if originator indicates a Codex 官方客户端请求。 func IsCodexOfficialClientOriginator(originator string) bool { v := normalizeCodexClientHeader(originator) if v == "" { return false } return matchCodexClientHeaderPrefixes(v, CodexOfficialClientOriginatorPrefixes) } func normalizeCodexClientHeader(value string) string { return strings.ToLower(strings.TrimSpace(value)) } func matchCodexClientHeaderPrefixes(value string, prefixes []string) bool { for _, prefix := range prefixes { normalizedPrefix := normalizeCodexClientHeader(prefix) if normalizedPrefix == "" { continue } // 优先前缀匹配;若 UA/Originator 被网关拼接为复合字符串时,退化为包含匹配。 if strings.HasPrefix(value, normalizedPrefix) || strings.Contains(value, normalizedPrefix) { return true } } return false }