// Package live forwards Codex realtime WebRTC session bootstrap requests. package live import ( "bytes" "context" "encoding/json" "errors" "fmt" "io" "mime" "mime/multipart" "net/http" "path/filepath" "reflect" "strings" "sync" "github.com/gin-gonic/gin" "github.com/router-for-me/CLIProxyAPI/v7/internal/clienterror" "github.com/router-for-me/CLIProxyAPI/v7/internal/config" "github.com/router-for-me/CLIProxyAPI/v7/internal/logging" "github.com/router-for-me/CLIProxyAPI/v7/internal/runtime/executor/helps" "github.com/router-for-me/CLIProxyAPI/v7/sdk/cliproxy/auth" coreexecutor "github.com/router-for-me/CLIProxyAPI/v7/sdk/cliproxy/executor" log "github.com/sirupsen/logrus" ) const ( upstreamCallURL = "https://chatgpt.com/backend-api/codex/realtime/calls?intent=quicksilver&architecture=avas" defaultLiveModel = "gpt-live-1-codex" maxBodySize = 16 << 20 ) var liveProtocolHeaders = []string{ "OpenAI-Alpha", "X-Session-Id", "Session-Id", "Thread-Id", "Originator", "OpenAI-Safety-Identifier", "OpenAI-Organization", "OpenAI-Project", "X-Oai-Attestation", } // Handler forwards Codex live session requests through the shared auth scheduler. type Handler struct { authManager *auth.Manager cfg *config.Config sessions *sessionStore clientSecrets *clientSecretStore sidebandAPIBaseURL string mediaRelayMu sync.RWMutex mediaRelay mediaRelayFactory mediaRelayErr error mediaRelayConfig config.CodexLiveMediaRelayConfig mediaRelayConfigured bool mediaLimiter *mediaSessionLimiter } // NewHandler creates a Codex live session handler. func NewHandler(authManager *auth.Manager, cfg *config.Config) *Handler { handler := &Handler{ authManager: authManager, cfg: cfg, sessions: newSessionStore(), clientSecrets: newClientSecretStore(), sidebandAPIBaseURL: defaultSidebandAPIBaseURL, } if errUpdate := handler.UpdateConfig(cfg); errUpdate != nil { log.WithError(errUpdate).Error("failed to configure Codex Live media relay") } return handler } // UpdateConfig atomically applies Codex Live media relay settings to new sessions. func (h *Handler) UpdateConfig(cfg *config.Config) error { if h == nil { return nil } var relayConfig config.CodexLiveMediaRelayConfig if cfg != nil { relayConfig = cfg.Codex.LiveMediaRelay } h.mediaRelayMu.Lock() previousConfig := h.mediaRelayConfig previouslyConfigured := h.mediaRelayConfigured h.cfg = cfg if previouslyConfigured && reflect.DeepEqual(previousConfig, relayConfig) { currentErr := h.mediaRelayErr h.mediaRelayMu.Unlock() return currentErr } if h.mediaLimiter == nil { h.mediaLimiter = &mediaSessionLimiter{} } var relay mediaRelayFactory var relayErr error if relayConfig.Enabled { relay, relayErr = newPionMediaRelayWithLimiter(relayConfig, h.mediaLimiter) } h.mediaRelay = relay h.mediaRelayErr = relayErr h.mediaRelayConfig = relayConfig h.mediaRelayConfigured = true h.mediaRelayMu.Unlock() if relayErr == nil && (previouslyConfigured || relayConfig.Enabled) { message := "codex live media relay configured" if previouslyConfigured { message = "codex live media relay configuration reloaded; changes apply to new sessions" } log.WithFields(liveMediaConfigLogFields(relayConfig)).Info(message) } return relayErr } func liveMediaConfigLogFields(relayConfig config.CodexLiveMediaRelayConfig) log.Fields { publicIP := strings.TrimSpace(relayConfig.PublicIP) if publicIP == "" { publicIP = "auto" } return log.Fields{ "enabled": relayConfig.Enabled, "max_sessions": relayConfig.EffectiveMaxSessions(), "disable_private_remote_ips": relayConfig.DisablePrivateRemoteIPs, "public_ip": publicIP, "udp_port_min": relayConfig.UDPPortMin, "udp_port_max": relayConfig.UDPPortMax, "ice_server_count": len(relayConfig.ICEServers), } } func (h *Handler) currentRuntime() (*config.Config, mediaRelayFactory, error) { if h == nil { return nil, nil, nil } h.mediaRelayMu.RLock() cfg := h.cfg relay := h.mediaRelay relayErr := h.mediaRelayErr h.mediaRelayMu.RUnlock() return cfg, relay, relayErr } func (h *Handler) currentConfig() *config.Config { if h == nil { return nil } h.mediaRelayMu.RLock() cfg := h.cfg h.mediaRelayMu.RUnlock() return cfg } func (h *Handler) currentMediaRelay() (mediaRelayFactory, error) { if h == nil { return nil, nil } h.mediaRelayMu.RLock() relay := h.mediaRelay relayErr := h.mediaRelayErr h.mediaRelayMu.RUnlock() return relay, relayErr } // Close releases all active Codex live sessions. func (h *Handler) Close() { if h == nil { return } if h.sessions != nil { h.sessions.closeAll("server_stopped") } if h.clientSecrets != nil { h.clientSecrets.close() } } // Handle forwards a WebRTC SDP bootstrap request to the Codex realtime calls endpoint. func (h *Handler) Handle(c *gin.Context) { if h == nil || h.authManager == nil { writeLiveError(c, http.StatusServiceUnavailable, "Codex auth manager unavailable") return } body, errRead := readBody(c.Request.Body) if errRead != nil { status := clienterror.HTTPStatusFromErrorOr(errRead, http.StatusBadRequest) if errors.Is(errRead, errBodyTooLarge) { status = http.StatusRequestEntityTooLarge } writeLiveError(c, status, errRead.Error()) return } upstreamBody, upstreamContentType, model, errPayload := prepareCallRequest(body, c.GetHeader("Content-Type")) if errPayload == nil { upstreamBody, upstreamContentType, model, errPayload = applyClientSecretCallSession(upstreamBody, upstreamContentType, model, clientSecretSession(c)) } if errPayload == nil { upstreamBody, model, errPayload = rewriteCallRequestModel(upstreamBody, upstreamContentType, model) } if errPayload != nil { writeLiveError(c, http.StatusBadRequest, errPayload.Error()) return } runtimeConfig, mediaRelay, mediaRelayErr := h.currentRuntime() if mediaRelayErr != nil { writeLiveError(c, http.StatusServiceUnavailable, mediaRelayErr.Error()) return } var mediaSession mediaRelaySession mediaRetained := false ctx := context.WithValue(c.Request.Context(), "gin", c) selectionOpts := coreexecutor.Options{ Headers: liveSelectionHeaders(c), OriginalRequest: body, } selection, selected, errSelect := h.selectOAuth(ctx, model, selectionOpts) if errSelect != nil { writeSelectionError(c, errSelect) return } if selected == nil { if selection != nil { selection.End("missing_auth") } writeLiveError(c, http.StatusServiceUnavailable, "Codex auth unavailable") return } if selection != nil { attemptCtx, releaseAttempt, errAttempt := selection.AttemptContext(ctx) if errAttempt != nil { selection.End("attempt_bind_failed") writeLiveError(c, http.StatusServiceUnavailable, errAttempt.Error()) return } ctx = attemptCtx defer releaseAttempt() } selectedIndex := selected.EnsureIndex() logging.SetGinCPATraceID(c, selectedIndex) if selection != nil { defer func() { if selection.Active() && !selection.Retained() { selection.End("request_closed") } }() } if mediaRelay != nil { clientOffer, errSDP := callRequestSDP(upstreamBody, upstreamContentType) if errSDP != nil { writeLiveError(c, http.StatusBadRequest, errSDP.Error()) return } var upstreamOffer string mediaSession, upstreamOffer, errSDP = mediaRelay.NewSession(ctx, clientOffer, mediaSessionRoute{ proxyURL: proxyURLForAuth(runtimeConfig, selected), credential: mediaCredentialName(selected, selectedIndex), authIndex: selectedIndex, }) if errSDP != nil { writeLiveError(c, clienterror.HTTPStatusFromErrorOr(errSDP, http.StatusBadGateway), errSDP.Error()) return } defer func() { if !mediaRetained { if errClose := mediaSession.CloseWithReason("request_not_retained"); errClose != nil { log.WithError(errClose).Debug("codex live media: close unretained session") } } }() upstreamBody, upstreamContentType, errSDP = replaceCallRequestSDP(upstreamBody, upstreamContentType, upstreamOffer) if errSDP != nil { writeLiveError(c, http.StatusBadRequest, errSDP.Error()) return } } baseHeaders := protocolHeaders(c.Request.Header) baseHeaders.Set("Content-Type", upstreamContentType) performRequest := func(current *auth.Auth) (*http.Response, error) { headers := baseHeaders.Clone() setAccountHeader(headers, current) req, errRequest := h.authManager.NewHttpRequest(ctx, current, http.MethodPost, upstreamCallURL, upstreamBody, headers) if errRequest != nil { return nil, errRequest } authType, authValue := current.AccountInfo() helps.RecordAPIRequest(ctx, runtimeConfig, helps.UpstreamRequestLog{ URL: upstreamCallURL, Method: http.MethodPost, Headers: headersForLogging(req.Header), Body: upstreamBody, Provider: "codex", AuthID: current.ID, AuthLabel: current.Label, AuthType: authType, AuthValue: authValue, }) return h.authManager.HttpRequest(ctx, current, req) } if errContext := ctx.Err(); errContext != nil { if selection != nil { selection.End("attempt_canceled") } writeLiveError(c, clienterror.HTTPStatusFromErrorOr(errContext, http.StatusRequestTimeout), errContext.Error()) return } resp, errRequest := performRequest(selected) if errRequest != nil { if selection != nil { selection.End("request_failed") } helps.RecordAPIResponseError(ctx, runtimeConfig, errRequest) writeLiveError(c, clienterror.HTTPStatusFromErrorOr(errRequest, http.StatusBadGateway), errRequest.Error()) return } if selection != nil && resp.StatusCode == http.StatusUnauthorized { h.authManager.ReportHomeUnauthorized(ctx, selected, "codex", model) helps.RecordAPIResponseMetadata(ctx, runtimeConfig, resp.StatusCode, callResponseHeaders(resp.Header)) _, _ = io.Copy(io.Discard, io.LimitReader(resp.Body, 1<<20)) if errClose := resp.Body.Close(); errClose != nil { log.Errorf("codex live: close unauthorized response body error: %v", errClose) } refreshed, didRefresh, errRefresh := h.authManager.RefreshHomeSelectionAfterUnauthorized(ctx, selection, selected) if errRefresh != nil { selection.End("refresh_failed") writeSelectionError(c, errRefresh) return } if !didRefresh || refreshed == nil { selection.End("refresh_unavailable") writeLiveError(c, http.StatusUnauthorized, "Codex credential unauthorized") return } selected = refreshed logging.SetGinCPATraceID(c, selected.EnsureIndex()) resp, errRequest = performRequest(selected) if errRequest != nil { selection.End("retry_failed") helps.RecordAPIResponseError(ctx, runtimeConfig, errRequest) writeLiveError(c, clienterror.HTTPStatusFromErrorOr(errRequest, http.StatusBadGateway), errRequest.Error()) return } if resp.StatusCode == http.StatusUnauthorized { h.authManager.ReportHomeUnauthorized(ctx, selected, "codex", model) } } var closeResponseOnce sync.Once var closeResponseErr error closeResponseBody := func() error { closeResponseOnce.Do(func() { closeResponseErr = resp.Body.Close() if closeResponseErr != nil { log.Errorf("codex live: close response body error: %v", closeResponseErr) } }) return closeResponseErr } defer func() { _ = closeResponseBody() }() if selection != nil { if errBind := selection.Bind(closeResponseBody); errBind != nil { selection.End("response_bind_failed") writeLiveError(c, http.StatusServiceUnavailable, errBind.Error()) return } } responseHeaders := callResponseHeaders(resp.Header) helps.RecordAPIResponseMetadata(ctx, runtimeConfig, resp.StatusCode, responseHeaders) responseBody, errResponse := readLimitedBody(resp.Body) if errResponse != nil { helps.RecordAPIResponseError(ctx, runtimeConfig, errResponse) message := "Failed to read Codex live response" status := clienterror.HTTPStatusFromErrorOr(errResponse, http.StatusBadGateway) if errors.Is(errResponse, errBodyTooLarge) { message = "Codex live response body too large" status = http.StatusBadGateway } writeLiveError(c, status, message) return } helps.AppendAPIResponseChunk(ctx, runtimeConfig, responseBody) responseBodyToWrite := responseBody success := resp.StatusCode >= http.StatusOK && resp.StatusCode < http.StatusMultipleChoices callID := "" if success { callID = callIDFromLocation(resp.Header.Get("Location")) if callID == "" && mediaSession != nil { writeLiveError(c, http.StatusBadGateway, "Codex live response is missing a valid call ID") return } if mediaSession != nil { mediaSession.SetCallID(callID) } if callID != "" && strings.HasPrefix(c.Request.URL.Path, "/v1/realtime") { responseHeaders.Set("Location", "/v1/realtime/calls/"+callID) } } if success && mediaSession != nil { upstreamAnswer, errSDP := callResponseSDP(responseBody, resp.Header.Get("Content-Type")) if errSDP != nil { writeLiveError(c, http.StatusBadGateway, errSDP.Error()) return } downstreamAnswer, errAnswer := mediaSession.AcceptUpstreamAnswer(ctx, upstreamAnswer) if errAnswer != nil { writeLiveError(c, clienterror.HTTPStatusFromErrorOr(errAnswer, http.StatusBadGateway), errAnswer.Error()) return } responseBodyToWrite = []byte(downstreamAnswer) responseHeaders.Set("Content-Type", "application/sdp") } var storedSession liveSession sessionStored := false if success && h.sessions != nil { if callID != "" { session := liveSession{authID: selected.ID, model: model, media: mediaSession} session.ownerPrincipal, session.ownerProvider = requestOwner(c) if principal, ok := c.Get(ClientSecretPrincipalContextKey); ok { session.clientSecretPrincipal, _ = principal.(string) } if selection != nil { if mediaSession != nil { if errBind := selection.Bind(func() error { return mediaSession.CloseWithReason("home_selection_closed") }); errBind != nil { selection.End("media_bind_failed") writeLiveError(c, http.StatusServiceUnavailable, errBind.Error()) return } } if errBind := selection.Bind(func() error { // End outside the resource closer to avoid waiting on the closer itself. go selection.End("session_drained") return nil }); errBind != nil { selection.End("session_drain_bind_failed") writeLiveError(c, http.StatusServiceUnavailable, errBind.Error()) return } selection.Retain() session.homeSelection = selection } storedSession = h.sessions.put(callID, session) sessionStored = storedSession.callID != "" if mediaSession != nil { mediaSession.SetCloseHandler(func(reason string) { h.sessions.complete(storedSession, reason) }) mediaRetained = true } } } writeResponseHeaders(c.Writer.Header(), responseHeaders) c.Status(resp.StatusCode) if _, errWrite := c.Writer.Write(responseBodyToWrite); errWrite != nil { if sessionStored { h.sessions.complete(storedSession, "response_write_failed") } helps.RecordAPIResponseError(ctx, runtimeConfig, errWrite) log.WithError(errWrite).Warn("codex live: write response body failed") } } func mediaCredentialName(selected *auth.Auth, authIndex string) string { if selected == nil { return strings.TrimSpace(authIndex) } if label := strings.TrimSpace(selected.Label); label != "" { return label } if fileName := strings.TrimSpace(selected.FileName); fileName != "" { if baseName := strings.TrimSpace(filepath.Base(fileName)); baseName != "" && baseName != "." { return baseName } } return strings.TrimSpace(authIndex) } func (h *Handler) selectOAuth(ctx context.Context, model string, opts coreexecutor.Options) (*auth.HomeDispatchSelection, *auth.Auth, error) { var selection *auth.HomeDispatchSelection var selected *auth.Auth var errSelect error if h.authManager.HomeEnabled() { selection, errSelect = h.authManager.SelectHomeAuthByKind(ctx, "codex", model, auth.AuthKindOAuth, opts) if selection != nil { selected = selection.CloneAuth() } } else { selected, errSelect = h.authManager.SelectAuthByKind(ctx, "codex", "", auth.AuthKindOAuth, opts) } if errSelect != nil && selection != nil { selection.End("selection_failed") } return selection, selected, errSelect } var errBodyTooLarge = errors.New("Codex live request body too large") func readBody(body io.Reader) ([]byte, error) { payload, errRead := readLimitedBody(body) if errRead != nil { if errors.Is(errRead, errBodyTooLarge) { return nil, errRead } return nil, fmt.Errorf("failed to read Codex live request: %w", errRead) } return payload, nil } func readLimitedBody(body io.Reader) ([]byte, error) { if body == nil { return nil, nil } payload, errRead := io.ReadAll(io.LimitReader(body, maxBodySize+1)) if errRead != nil { return nil, errRead } if len(payload) > maxBodySize { return nil, errBodyTooLarge } return payload, nil } func prepareCallRequest(body []byte, contentType string) ([]byte, string, string, error) { mediaType, params, errMediaType := mime.ParseMediaType(contentType) if errMediaType == nil && strings.EqualFold(mediaType, "multipart/form-data") { return multipartCallRequest(body, strings.TrimSpace(params["boundary"])) } model := modelFromJSON(body) if model == "" { model = defaultLiveModel } if strings.TrimSpace(contentType) == "" { contentType = "application/json" } return body, contentType, model, nil } func applyClientSecretCallSession(body []byte, contentType, model string, session json.RawMessage) ([]byte, string, string, error) { if len(session) == 0 { return body, contentType, model, nil } mediaType, _, errMediaType := mime.ParseMediaType(contentType) if errMediaType == nil && (strings.EqualFold(mediaType, "application/sdp") || strings.EqualFold(mediaType, "text/plain")) { encoded, errEncode := encodeCallRequest(string(body), session) if errEncode != nil { return nil, "", "", errEncode } return encoded, "application/json", modelFromJSON(session), nil } if errMediaType != nil || !strings.EqualFold(mediaType, "application/json") { return nil, "", "", errors.New("Realtime client secrets require an SDP or JSON call request") } var payload map[string]json.RawMessage if errUnmarshal := json.Unmarshal(body, &payload); errUnmarshal != nil { return nil, "", "", fmt.Errorf("failed to decode Realtime call request: %w", errUnmarshal) } payload["session"] = append(json.RawMessage(nil), session...) encoded, errMarshal := json.Marshal(payload) if errMarshal != nil { return nil, "", "", fmt.Errorf("failed to encode Realtime call request: %w", errMarshal) } return encoded, "application/json", modelFromJSON(session), nil } func rewriteCallRequestModel(body []byte, contentType, model string) ([]byte, string, error) { upstreamModel := codexRealtimeModel(model) mediaType, _, errMediaType := mime.ParseMediaType(contentType) if errMediaType != nil || !strings.EqualFold(mediaType, "application/json") || len(bytes.TrimSpace(body)) == 0 { return body, upstreamModel, nil } var payload map[string]json.RawMessage if errUnmarshal := json.Unmarshal(body, &payload); errUnmarshal != nil { return nil, "", fmt.Errorf("failed to decode Realtime call request: %w", errUnmarshal) } changed := false if sessionJSON, ok := payload["session"]; ok && len(sessionJSON) > 0 { var session map[string]json.RawMessage if errUnmarshal := json.Unmarshal(sessionJSON, &session); errUnmarshal != nil { return nil, "", fmt.Errorf("failed to decode Realtime session: %w", errUnmarshal) } encodedModel, errMarshal := json.Marshal(upstreamModel) if errMarshal != nil { return nil, "", fmt.Errorf("failed to encode Realtime model: %w", errMarshal) } session["model"] = encodedModel encodedSession, errMarshal := json.Marshal(session) if errMarshal != nil { return nil, "", fmt.Errorf("failed to encode Realtime session: %w", errMarshal) } payload["session"] = encodedSession changed = true } else if _, ok := payload["model"]; ok { encodedModel, errMarshal := json.Marshal(upstreamModel) if errMarshal != nil { return nil, "", fmt.Errorf("failed to encode Realtime model: %w", errMarshal) } payload["model"] = encodedModel changed = true } if !changed { return body, upstreamModel, nil } encoded, errMarshal := json.Marshal(payload) if errMarshal != nil { return nil, "", fmt.Errorf("failed to encode Realtime call request: %w", errMarshal) } return encoded, upstreamModel, nil } func multipartCallRequest(body []byte, boundary string) ([]byte, string, string, error) { if boundary == "" { return nil, "", "", errors.New("Codex live multipart boundary is missing") } reader := multipart.NewReader(bytes.NewReader(body), boundary) var sdp *string var session json.RawMessage model := "" for { part, errPart := reader.NextPart() if errors.Is(errPart, io.EOF) { break } if errPart != nil { return nil, "", "", fmt.Errorf("failed to parse Codex live multipart body: %w", errPart) } partBody, errRead := io.ReadAll(part) errClose := part.Close() if errRead != nil { return nil, "", "", fmt.Errorf("failed to read Codex live multipart field: %w", errRead) } if errClose != nil { return nil, "", "", fmt.Errorf("failed to close Codex live multipart field: %w", errClose) } switch part.FormName() { case "sdp": value := string(partBody) sdp = &value case "session": if !json.Valid(partBody) { return nil, "", "", errors.New("Codex live session field must contain valid JSON") } session = append(json.RawMessage(nil), partBody...) model = modelFromJSON(partBody) } } if sdp == nil { return nil, "", "", errors.New("Codex live multipart body requires an sdp field") } if model == "" { model = defaultLiveModel } encoded, errEncode := encodeCallRequest(*sdp, session) if errEncode != nil { return nil, "", "", errEncode } return encoded, "application/json", model, nil } func encodeCallRequest(sdp string, session json.RawMessage) ([]byte, error) { payload := struct { SDP string `json:"sdp"` Session json.RawMessage `json:"session,omitempty"` }{ SDP: sdp, Session: session, } encoded, errMarshal := json.Marshal(payload) if errMarshal != nil { return nil, fmt.Errorf("failed to encode Codex live request: %w", errMarshal) } return encoded, nil } func callRequestSDP(body []byte, contentType string) (string, error) { mediaType, _, errMediaType := mime.ParseMediaType(contentType) if errMediaType == nil && (strings.EqualFold(mediaType, "application/sdp") || strings.EqualFold(mediaType, "text/plain")) { if strings.TrimSpace(string(body)) == "" { return "", errors.New("Codex live call request requires an SDP offer") } return string(body), nil } if errMediaType != nil || !strings.EqualFold(mediaType, "application/json") { return "", errors.New("Codex live media relay requires an SDP or JSON call request") } var payload struct { SDP string `json:"sdp"` } if errUnmarshal := json.Unmarshal(body, &payload); errUnmarshal != nil { return "", fmt.Errorf("failed to decode Codex live call request: %w", errUnmarshal) } if strings.TrimSpace(payload.SDP) == "" { return "", errors.New("Codex live call request requires an SDP offer") } return payload.SDP, nil } func replaceCallRequestSDP(body []byte, contentType, sdp string) ([]byte, string, error) { mediaType, _, errMediaType := mime.ParseMediaType(contentType) if errMediaType == nil && (strings.EqualFold(mediaType, "application/sdp") || strings.EqualFold(mediaType, "text/plain")) { encoded, errEncode := encodeCallRequest(sdp, nil) if errEncode != nil { return nil, "", errEncode } return encoded, "application/json", nil } if errMediaType != nil || !strings.EqualFold(mediaType, "application/json") { return nil, "", errors.New("Codex live media relay requires an SDP or JSON call request") } var payload map[string]json.RawMessage if errUnmarshal := json.Unmarshal(body, &payload); errUnmarshal != nil { return nil, "", fmt.Errorf("failed to decode Codex live call request: %w", errUnmarshal) } encodedSDP, errMarshal := json.Marshal(sdp) if errMarshal != nil { return nil, "", fmt.Errorf("failed to encode Codex live SDP offer: %w", errMarshal) } payload["sdp"] = encodedSDP encoded, errMarshal := json.Marshal(payload) if errMarshal != nil { return nil, "", fmt.Errorf("failed to encode Codex live call request: %w", errMarshal) } return encoded, "application/json", nil } func callResponseSDP(body []byte, contentType string) (string, error) { mediaType, _, errMediaType := mime.ParseMediaType(contentType) if errMediaType == nil && strings.EqualFold(mediaType, "application/json") { var payload struct { SDP string `json:"sdp"` } if errUnmarshal := json.Unmarshal(body, &payload); errUnmarshal != nil { return "", fmt.Errorf("failed to decode Codex live response: %w", errUnmarshal) } if strings.TrimSpace(payload.SDP) == "" { return "", errors.New("Codex live response requires an SDP answer") } return payload.SDP, nil } if strings.TrimSpace(string(body)) == "" { return "", errors.New("Codex live response requires an SDP answer") } return string(body), nil } func modelFromJSON(body []byte) string { var payload struct { Model string `json:"model"` Session struct { Model string `json:"model"` } `json:"session"` } if errUnmarshal := json.Unmarshal(body, &payload); errUnmarshal != nil { return "" } if model := strings.TrimSpace(payload.Session.Model); model != "" { return model } return strings.TrimSpace(payload.Model) } func protocolHeaders(source http.Header) http.Header { headers := make(http.Header) for _, name := range liveProtocolHeaders { for _, value := range source.Values(name) { headers.Add(name, value) } } return headers } func setAccountHeader(headers http.Header, selected *auth.Auth) { if selected == nil { return } if accountID, ok := selected.Metadata["account_id"].(string); ok && strings.TrimSpace(accountID) != "" { headers.Set("Chatgpt-Account-Id", accountID) } } func headersForLogging(source http.Header) http.Header { headers := source.Clone() if headers.Get("X-Oai-Attestation") != "" { headers.Set("X-Oai-Attestation", "[REDACTED]") } return headers } func callResponseHeaders(source http.Header) http.Header { headers := make(http.Header) for _, name := range []string{"Content-Type", "Location", "Retry-After", "X-Request-Id", "OpenAI-Request-Id"} { for _, value := range source.Values(name) { headers.Add(name, value) } } return headers } func writeResponseHeaders(destination, source http.Header) { for name, values := range source { for _, value := range values { destination.Add(name, value) } } } func writeLiveError(c *gin.Context, status int, message string) { if c != nil && c.Request != nil && c.Request.URL != nil && strings.HasPrefix(c.Request.URL.Path, "/v1/realtime") { errorType := "api_error" if status >= http.StatusBadRequest && status < http.StatusInternalServerError { errorType = "invalid_request_error" } if status == http.StatusUnauthorized { errorType = "authentication_error" } writeRealtimeError(c, status, message, errorType, "realtime_request_failed") return } c.JSON(status, gin.H{"error": message}) } func writeSelectionError(c *gin.Context, err error) { status := clienterror.HTTPStatusFromErrorOr(err, http.StatusServiceUnavailable) for _, value := range auth.SafeResponseHeaders(err).Values("Retry-After") { c.Writer.Header().Add("Retry-After", value) } writeLiveError(c, status, err.Error()) }