Make Codex CLI passthrough
This commit is contained in:
@@ -11,7 +11,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Wei-Shaw/sub2api/internal/config"
|
"github.com/Wei-Shaw/sub2api/internal/config"
|
||||||
"github.com/Wei-Shaw/sub2api/internal/pkg/openai"
|
|
||||||
middleware2 "github.com/Wei-Shaw/sub2api/internal/server/middleware"
|
middleware2 "github.com/Wei-Shaw/sub2api/internal/server/middleware"
|
||||||
"github.com/Wei-Shaw/sub2api/internal/service"
|
"github.com/Wei-Shaw/sub2api/internal/service"
|
||||||
|
|
||||||
@@ -92,17 +91,7 @@ func (h *OpenAIGatewayHandler) Responses(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// For non-Codex CLI requests, set default instructions
|
|
||||||
userAgent := c.GetHeader("User-Agent")
|
userAgent := c.GetHeader("User-Agent")
|
||||||
if !openai.IsCodexCLIRequest(userAgent) {
|
|
||||||
reqBody["instructions"] = openai.DefaultInstructions
|
|
||||||
// Re-serialize body
|
|
||||||
body, err = json.Marshal(reqBody)
|
|
||||||
if err != nil {
|
|
||||||
h.errorResponse(c, http.StatusInternalServerError, "api_error", "Failed to process request")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Track if we've started streaming (for error handling)
|
// Track if we've started streaming (for error handling)
|
||||||
streamStarted := false
|
streamStarted := false
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ func codexModeEnabled() bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func applyCodexOAuthTransform(reqBody map[string]any, codexMode bool) codexTransformResult {
|
func applyCodexOAuthTransform(reqBody map[string]any) codexTransformResult {
|
||||||
result := codexTransformResult{}
|
result := codexTransformResult{}
|
||||||
|
|
||||||
model := ""
|
model := ""
|
||||||
@@ -151,16 +151,13 @@ func applyCodexOAuthTransform(reqBody map[string]any, codexMode bool) codexTrans
|
|||||||
result.NormalizedModel = normalizedModel
|
result.NormalizedModel = normalizedModel
|
||||||
}
|
}
|
||||||
|
|
||||||
reqBody["store"] = false
|
if v, ok := reqBody["store"].(bool); !ok || v {
|
||||||
reqBody["stream"] = true
|
reqBody["store"] = false
|
||||||
result.Modified = true
|
result.Modified = true
|
||||||
|
}
|
||||||
instructions := getCodexInstructions(normalizedModel)
|
if v, ok := reqBody["stream"].(bool); !ok || !v {
|
||||||
if instructions != "" {
|
reqBody["stream"] = true
|
||||||
if existing, ok := reqBody["instructions"].(string); !ok || existing != instructions {
|
result.Modified = true
|
||||||
reqBody["instructions"] = instructions
|
|
||||||
result.Modified = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := reqBody["max_output_tokens"]; ok {
|
if _, ok := reqBody["max_output_tokens"]; ok {
|
||||||
@@ -180,49 +177,30 @@ func applyCodexOAuthTransform(reqBody map[string]any, codexMode bool) codexTrans
|
|||||||
result.PromptCacheKey = strings.TrimSpace(v)
|
result.PromptCacheKey = strings.TrimSpace(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
instructions := strings.TrimSpace(getCodexInstructions(normalizedModel))
|
||||||
|
existingInstructions, _ := reqBody["instructions"].(string)
|
||||||
|
existingInstructions = strings.TrimSpace(existingInstructions)
|
||||||
|
|
||||||
|
if instructions != "" {
|
||||||
|
if existingInstructions != "" && existingInstructions != instructions {
|
||||||
|
if input, ok := reqBody["input"].([]any); ok {
|
||||||
|
reqBody["input"] = prependSystemInstruction(input, existingInstructions)
|
||||||
|
result.Modified = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if existingInstructions != instructions {
|
||||||
|
reqBody["instructions"] = instructions
|
||||||
|
result.Modified = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if input, ok := reqBody["input"].([]any); ok {
|
if input, ok := reqBody["input"].([]any); ok {
|
||||||
input = filterCodexInput(input)
|
input = filterCodexInput(input)
|
||||||
if codexMode {
|
|
||||||
cachedPrompt := getOpenCodeCodexPrompt()
|
|
||||||
input = filterOpenCodeSystemPromptsWithCachedPrompt(input, cachedPrompt)
|
|
||||||
if hasTools(reqBody) {
|
|
||||||
input = addCodexBridgeMessage(input)
|
|
||||||
}
|
|
||||||
} else if hasTools(reqBody) {
|
|
||||||
input = addToolRemapMessage(input)
|
|
||||||
}
|
|
||||||
input = normalizeOrphanedToolOutputs(input)
|
input = normalizeOrphanedToolOutputs(input)
|
||||||
reqBody["input"] = input
|
reqBody["input"] = input
|
||||||
result.Modified = true
|
result.Modified = true
|
||||||
}
|
}
|
||||||
|
|
||||||
effort, summary := resolveCodexReasoning(reqBody, normalizedModel)
|
|
||||||
if effort != "" || summary != "" {
|
|
||||||
reasoning := ensureMap(reqBody["reasoning"])
|
|
||||||
if effort != "" {
|
|
||||||
reasoning["effort"] = effort
|
|
||||||
}
|
|
||||||
if summary != "" {
|
|
||||||
reasoning["summary"] = summary
|
|
||||||
}
|
|
||||||
reqBody["reasoning"] = reasoning
|
|
||||||
result.Modified = true
|
|
||||||
}
|
|
||||||
|
|
||||||
textVerbosity := resolveTextVerbosity(reqBody)
|
|
||||||
if textVerbosity != "" {
|
|
||||||
text := ensureMap(reqBody["text"])
|
|
||||||
text["verbosity"] = textVerbosity
|
|
||||||
reqBody["text"] = text
|
|
||||||
result.Modified = true
|
|
||||||
}
|
|
||||||
|
|
||||||
include := resolveInclude(reqBody)
|
|
||||||
if include != nil {
|
|
||||||
reqBody["include"] = include
|
|
||||||
result.Modified = true
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -487,6 +465,19 @@ func filterCodexInput(input []any) []any {
|
|||||||
return filtered
|
return filtered
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func prependSystemInstruction(input []any, instructions string) []any {
|
||||||
|
message := map[string]any{
|
||||||
|
"role": "system",
|
||||||
|
"content": []any{
|
||||||
|
map[string]any{
|
||||||
|
"type": "input_text",
|
||||||
|
"text": instructions,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return append([]any{message}, input...)
|
||||||
|
}
|
||||||
|
|
||||||
func filterOpenCodeSystemPromptsWithCachedPrompt(input []any, cachedPrompt string) []any {
|
func filterOpenCodeSystemPromptsWithCachedPrompt(input []any, cachedPrompt string) []any {
|
||||||
if len(input) == 0 {
|
if len(input) == 0 {
|
||||||
return input
|
return input
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Wei-Shaw/sub2api/internal/config"
|
"github.com/Wei-Shaw/sub2api/internal/config"
|
||||||
|
"github.com/Wei-Shaw/sub2api/internal/pkg/openai"
|
||||||
"github.com/Wei-Shaw/sub2api/internal/util/responseheaders"
|
"github.com/Wei-Shaw/sub2api/internal/util/responseheaders"
|
||||||
"github.com/Wei-Shaw/sub2api/internal/util/urlvalidator"
|
"github.com/Wei-Shaw/sub2api/internal/util/urlvalidator"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@@ -530,20 +531,28 @@ func (s *OpenAIGatewayService) Forward(ctx context.Context, c *gin.Context, acco
|
|||||||
reqModel, _ := reqBody["model"].(string)
|
reqModel, _ := reqBody["model"].(string)
|
||||||
reqStream, _ := reqBody["stream"].(bool)
|
reqStream, _ := reqBody["stream"].(bool)
|
||||||
promptCacheKey := ""
|
promptCacheKey := ""
|
||||||
|
if v, ok := reqBody["prompt_cache_key"].(string); ok {
|
||||||
|
promptCacheKey = strings.TrimSpace(v)
|
||||||
|
}
|
||||||
|
|
||||||
// Track if body needs re-serialization
|
// Track if body needs re-serialization
|
||||||
bodyModified := false
|
bodyModified := false
|
||||||
originalModel := reqModel
|
originalModel := reqModel
|
||||||
|
|
||||||
// Apply model mapping
|
isCodexCLI := openai.IsCodexCLIRequest(c.GetHeader("User-Agent"))
|
||||||
mappedModel := account.GetMappedModel(reqModel)
|
|
||||||
if mappedModel != reqModel {
|
// Apply model mapping (skip for Codex CLI for transparent forwarding)
|
||||||
reqBody["model"] = mappedModel
|
mappedModel := reqModel
|
||||||
bodyModified = true
|
if !isCodexCLI {
|
||||||
|
mappedModel = account.GetMappedModel(reqModel)
|
||||||
|
if mappedModel != reqModel {
|
||||||
|
reqBody["model"] = mappedModel
|
||||||
|
bodyModified = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if account.Type == AccountTypeOAuth {
|
if account.Type == AccountTypeOAuth && !isCodexCLI {
|
||||||
codexResult := applyCodexOAuthTransform(reqBody, codexModeEnabled())
|
codexResult := applyCodexOAuthTransform(reqBody)
|
||||||
if codexResult.Modified {
|
if codexResult.Modified {
|
||||||
bodyModified = true
|
bodyModified = true
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user