| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- package service
- import (
- "context"
- "net/http"
- "strings"
- "github.com/Wei-Shaw/sub2api/internal/pkg/logger"
- "github.com/tidwall/gjson"
- "go.uber.org/zap"
- "golang.org/x/net/http/httpguts"
- )
- const openAICodexRoutingHintHeader = "x-codex-routing-hint"
- // setOpenAICodexRoutingHint mirrors the Codex backend routing-hint contract for
- // OpenAI OAuth requests. The request model must already be the final upstream
- // slug and serviceTier must already reflect any local policy rewrite/filter.
- func setOpenAICodexRoutingHint(headers http.Header, account *Account, model string, serviceTier string) {
- if headers == nil {
- return
- }
- // The routing hint is gateway-owned. Strip every spelling before deciding
- // whether to synthesize it so API-key/provider credential paths cannot pass
- // through a caller- or account-override-supplied hint. http.Header.Del only
- // removes the canonical map key; inbound maps can contain raw lowercase keys.
- deleteOpenAIHeaderEqualFold(headers, openAICodexRoutingHintHeader)
- if account == nil || !account.IsOpenAIOAuthLike() {
- return
- }
- model = strings.TrimSpace(model)
- if model == "" || strings.ContainsAny(model, ";=") {
- return
- }
- // Codex treats "default" as an explicit standard-routing sentinel, not as a
- // service tier sent to the backend. Fast follows the gateway's existing
- // canonicalization and therefore becomes "priority"; flex and ultrafast
- // stay as themselves.
- canonicalTier := normalizedOpenAIServiceTierValue(serviceTier)
- // Keep the hint to the effective tiers Codex itself selects. default,
- // missing, auto, and scale remain model-only rather than expanding the
- // ChatGPT routing protocol here.
- switch canonicalTier {
- case OpenAIFastTierPriority, OpenAIFastTierFlex, OpenAIFastTierUltrafast:
- default:
- canonicalTier = ""
- }
- hint := "model=" + model
- if canonicalTier != "" {
- hint += ";tier=" + canonicalTier
- }
- if !httpguts.ValidHeaderFieldValue(hint) {
- return
- }
- headers.Set(openAICodexRoutingHintHeader, hint)
- }
- func deleteOpenAIHeaderEqualFold(headers http.Header, name string) {
- if headers == nil {
- return
- }
- name = strings.TrimSpace(name)
- for key := range headers {
- if strings.EqualFold(strings.TrimSpace(key), name) {
- delete(headers, key)
- }
- }
- }
- func setOpenAICodexRoutingHintFromBody(headers http.Header, account *Account, body []byte) {
- fields := gjson.GetManyBytes(body, "model", "service_tier")
- setOpenAICodexRoutingHint(headers, account, fields[0].String(), fields[1].String())
- }
- // logOpenAIRoutingDiagnostics records only gateway-derived routing state. In
- // particular, it deliberately does not include any header values, tokens, or
- // credentials because these diagnostics run on authentication-bearing paths.
- func logOpenAIRoutingDiagnostics(
- ctx context.Context,
- account *Account,
- transport string,
- model string,
- serviceTier string,
- hintGenerated bool,
- wsAffinityDecision string,
- ) {
- if ctx == nil {
- ctx = context.Background()
- }
- accountID := int64(0)
- if account != nil {
- accountID = account.ID
- }
- logger.FromContext(ctx).Debug("openai routing decision",
- zap.String("component", "service.openai_routing"),
- zap.String("transport", strings.TrimSpace(transport)),
- zap.Int64("account_id", accountID),
- zap.String("final_model", strings.TrimSpace(model)),
- zap.String("final_service_tier", normalizedOpenAIServiceTierValue(serviceTier)),
- zap.Bool("routing_hint_generated", hintGenerated),
- zap.String("ws_affinity_decision", strings.TrimSpace(wsAffinityDecision)),
- )
- }
- func logOpenAIRoutingDiagnosticsFromBody(
- ctx context.Context,
- account *Account,
- transport string,
- headers http.Header,
- body []byte,
- wsAffinityDecision string,
- ) {
- fields := gjson.GetManyBytes(body, "model", "service_tier")
- logOpenAIRoutingDiagnostics(
- ctx,
- account,
- transport,
- fields[0].String(),
- fields[1].String(),
- strings.TrimSpace(headers.Get(openAICodexRoutingHintHeader)) != "",
- wsAffinityDecision,
- )
- }
|