@@ -333,80 +333,115 @@ func (s *Server) codexAlphaSearch(c *gin.Context) {
333333 }
334334 logging .SetGinCPATraceID (c , selected .EnsureIndex ())
335335
336- headers := make (http.Header )
337- headers .Set ("Content-Type" , "application/json" )
338- headers .Set ("Accept" , "application/json" )
339- headers .Set ("Originator" , "codex_cli_rs" )
336+ baseHeaders := make (http.Header )
337+ baseHeaders .Set ("Content-Type" , "application/json" )
338+ baseHeaders .Set ("Accept" , "application/json" )
339+ baseHeaders .Set ("Originator" , "codex_cli_rs" )
340340 for _ , name := range []string {"Version" , "User-Agent" , "Session_id" , "X-Client-Request-Id" } {
341341 if value := strings .TrimSpace (c .GetHeader (name )); value != "" {
342- headers .Set (name , value )
342+ baseHeaders .Set (name , value )
343343 }
344344 }
345- if accountID , ok := selected .Metadata ["account_id" ].(string ); ok && strings .TrimSpace (accountID ) != "" {
346- headers .Set ("Chatgpt-Account-Id" , accountID )
347- }
348345
349- upstreamURL := "https://chatgpt.com/backend-api/codex/alpha/search"
350- if selected . AuthKind () == auth .AuthKindAPIKey {
351- baseURL := ""
352- if selected . Attributes != nil {
353- baseURL = strings . TrimSpace ( selected . Attributes [ "base_url" ] )
346+ errMissingBaseURL := errors . New ( "Codex Alpha Search API key base URL unavailable" )
347+ performRequest := func ( current * auth.Auth ) ( * http. Response , error ) {
348+ headers := baseHeaders . Clone ()
349+ if accountID , ok := current . Metadata [ "account_id" ].( string ); ok && strings . TrimSpace ( accountID ) != "" {
350+ headers . Set ( "Chatgpt-Account-Id" , accountID )
354351 }
355- if baseURL == "" {
356- if selection != nil {
357- selection .End ("missing_base_url" )
352+ upstreamURL := "https://chatgpt.com/backend-api/codex/alpha/search"
353+ if current .AuthKind () == auth .AuthKindAPIKey {
354+ baseURL := ""
355+ if current .Attributes != nil {
356+ baseURL = strings .TrimSpace (current .Attributes ["base_url" ])
358357 }
359- c .JSON (http .StatusServiceUnavailable , gin.H {"error" : "Codex Alpha Search API key base URL unavailable" })
360- return
361- }
362- upstreamURL = strings .TrimRight (baseURL , "/" ) + "/alpha/search"
363- }
364- req , err := s .handlers .AuthManager .NewHttpRequest (
365- ctx , selected , http .MethodPost , upstreamURL , upstreamRequestBody , headers ,
366- )
367- if err != nil {
368- if selection != nil {
369- selection .End ("request_build_failed" )
370- }
371- c .JSON (http .StatusBadGateway , gin.H {"error" : err .Error ()})
372- return
358+ if baseURL == "" {
359+ return nil , errMissingBaseURL
360+ }
361+ upstreamURL = strings .TrimRight (baseURL , "/" ) + "/alpha/search"
362+ }
363+ req , errRequest := s .handlers .AuthManager .NewHttpRequest (ctx , current , http .MethodPost , upstreamURL , upstreamRequestBody , headers )
364+ if errRequest != nil {
365+ return nil , errRequest
366+ }
367+ authType , authValue := current .AccountInfo ()
368+ helps .RecordAPIRequest (ctx , s .cfg , helps.UpstreamRequestLog {
369+ URL : upstreamURL ,
370+ Method : http .MethodPost ,
371+ Headers : req .Header .Clone (),
372+ Body : upstreamRequestBody ,
373+ Provider : "codex" ,
374+ AuthID : current .ID ,
375+ AuthLabel : current .Label ,
376+ AuthType : authType ,
377+ AuthValue : authValue ,
378+ })
379+ return s .handlers .AuthManager .HttpRequest (ctx , current , req )
373380 }
374381
375- var authID , authLabel , authType , authValue string
376- if selected != nil {
377- authID = selected .ID
378- authLabel = selected .Label
379- authType , authValue = selected .AccountInfo ()
380- }
381- helpHeaders := req .Header .Clone ()
382- helps .RecordAPIRequest (ctx , s .cfg , helps.UpstreamRequestLog {
383- URL : upstreamURL ,
384- Method : http .MethodPost ,
385- Headers : helpHeaders ,
386- Body : upstreamRequestBody ,
387- Provider : "codex" ,
388- AuthID : authID ,
389- AuthLabel : authLabel ,
390- AuthType : authType ,
391- AuthValue : authValue ,
392- })
393-
394382 if errCtx := ctx .Err (); errCtx != nil {
395383 if selection != nil {
396384 selection .End ("attempt_canceled" )
397385 }
398386 c .JSON (http .StatusRequestTimeout , gin.H {"error" : errCtx .Error ()})
399387 return
400388 }
401- resp , err := s . handlers . AuthManager . HttpRequest ( ctx , selected , req )
389+ resp , err := performRequest ( selected )
402390 if err != nil {
391+ if errors .Is (err , errMissingBaseURL ) {
392+ if selection != nil {
393+ selection .End ("missing_base_url" )
394+ }
395+ c .JSON (http .StatusServiceUnavailable , gin.H {"error" : err .Error ()})
396+ return
397+ }
403398 if selection != nil {
404399 selection .End ("request_failed" )
405400 }
406401 helps .RecordAPIResponseError (ctx , s .cfg , err )
407402 c .JSON (http .StatusBadGateway , gin.H {"error" : err .Error ()})
408403 return
409404 }
405+ if selection != nil && resp .StatusCode == http .StatusUnauthorized {
406+ s .handlers .AuthManager .ReportHomeUnauthorized (ctx , selected , "codex" , selectionModel )
407+ helps .RecordAPIResponseMetadata (ctx , s .cfg , resp .StatusCode , resp .Header .Clone ())
408+ _ , _ = io .Copy (io .Discard , io .LimitReader (resp .Body , 1 << 20 ))
409+ if errClose := resp .Body .Close (); errClose != nil {
410+ log .Errorf ("codex alpha search: close unauthorized response body error: %v" , errClose )
411+ }
412+ refreshed , didRefresh , errRefresh := s .handlers .AuthManager .RefreshHomeSelectionAfterUnauthorized (ctx , selection , selected )
413+ if errRefresh != nil {
414+ selection .End ("refresh_failed" )
415+ status := http .StatusServiceUnavailable
416+ if statusError , ok := errRefresh .(interface { StatusCode () int }); ok && statusError .StatusCode () > 0 {
417+ status = statusError .StatusCode ()
418+ }
419+ c .JSON (status , gin.H {"error" : errRefresh .Error ()})
420+ return
421+ }
422+ if ! didRefresh || refreshed == nil {
423+ selection .End ("refresh_unavailable" )
424+ c .JSON (http .StatusUnauthorized , gin.H {"error" : "Codex credential unauthorized" })
425+ return
426+ }
427+ selected = refreshed
428+ logging .SetGinCPATraceID (c , selected .EnsureIndex ())
429+ resp , err = performRequest (selected )
430+ if err != nil {
431+ if errors .Is (err , errMissingBaseURL ) {
432+ selection .End ("missing_base_url" )
433+ c .JSON (http .StatusServiceUnavailable , gin.H {"error" : err .Error ()})
434+ return
435+ }
436+ selection .End ("retry_failed" )
437+ helps .RecordAPIResponseError (ctx , s .cfg , err )
438+ c .JSON (http .StatusBadGateway , gin.H {"error" : err .Error ()})
439+ return
440+ }
441+ if resp .StatusCode == http .StatusUnauthorized {
442+ s .handlers .AuthManager .ReportHomeUnauthorized (ctx , selected , "codex" , selectionModel )
443+ }
444+ }
410445 closeResponseBody := func () error {
411446 errClose := resp .Body .Close ()
412447 if errClose != nil {
0 commit comments