From 36b817d008e7ad719a892424bc8b0529bb8b9d2c Mon Sep 17 00:00:00 2001 From: cyhhao Date: Sat, 10 Jan 2026 20:53:16 +0800 Subject: [PATCH] Align OAuth transform with OpenCode instructions --- .../service/openai_codex_transform.go | 29 ++++++++++++------- .../service/openai_gateway_service.go | 10 +++++-- .../service/openai_gateway_service_test.go | 2 +- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/backend/internal/service/openai_codex_transform.go b/backend/internal/service/openai_codex_transform.go index e6c71775..fc9d30cd 100644 --- a/backend/internal/service/openai_codex_transform.go +++ b/backend/internal/service/openai_codex_transform.go @@ -13,11 +13,12 @@ import ( ) const ( - codexReleaseAPIURL = "https://api.github.com/repos/openai/codex/releases/latest" - codexReleaseHTMLURL = "https://github.com/openai/codex/releases/latest" - codexPromptURLFmt = "https://raw.githubusercontent.com/openai/codex/%s/codex-rs/core/%s" - opencodeCodexURL = "https://raw.githubusercontent.com/anomalyco/opencode/dev/packages/opencode/src/session/prompt/codex.txt" - codexCacheTTL = 15 * time.Minute + codexReleaseAPIURL = "https://api.github.com/repos/openai/codex/releases/latest" + codexReleaseHTMLURL = "https://github.com/openai/codex/releases/latest" + codexPromptURLFmt = "https://raw.githubusercontent.com/openai/codex/%s/codex-rs/core/%s" + opencodeCodexURL = "https://raw.githubusercontent.com/anomalyco/opencode/dev/packages/opencode/src/session/prompt/codex.txt" + opencodeCodexHeaderURL = "https://raw.githubusercontent.com/anomalyco/opencode/dev/packages/opencode/src/session/prompt/codex_header.txt" + codexCacheTTL = 15 * time.Minute ) type codexModelFamily string @@ -177,7 +178,7 @@ func applyCodexOAuthTransform(reqBody map[string]any) codexTransformResult { result.PromptCacheKey = strings.TrimSpace(v) } - instructions := strings.TrimSpace(getCodexInstructions(normalizedModel)) + instructions := strings.TrimSpace(getOpenCodeCodexHeader()) existingInstructions, _ := reqBody["instructions"].(string) existingInstructions = strings.TrimSpace(existingInstructions) @@ -408,13 +409,13 @@ func parseReleaseTagFromHTML(html string) (string, error) { return "", fmt.Errorf("release tag not found") } -func getOpenCodeCodexPrompt() string { +func getOpenCodeCachedPrompt(url, cacheFileName, metaFileName string) string { cacheDir := codexCachePath("") if cacheDir == "" { return "" } - cacheFile := filepath.Join(cacheDir, "opencode-codex.txt") - metaFile := filepath.Join(cacheDir, "opencode-codex-meta.json") + cacheFile := filepath.Join(cacheDir, cacheFileName) + metaFile := filepath.Join(cacheDir, metaFileName) var cachedContent string if content, ok := readFile(cacheFile); ok { @@ -428,7 +429,7 @@ func getOpenCodeCodexPrompt() string { } } - content, etag, status, err := fetchWithETag(opencodeCodexURL, meta.ETag) + content, etag, status, err := fetchWithETag(url, meta.ETag) if err == nil && status == http.StatusNotModified && cachedContent != "" { return cachedContent } @@ -446,6 +447,14 @@ func getOpenCodeCodexPrompt() string { return cachedContent } +func getOpenCodeCodexPrompt() string { + return getOpenCodeCachedPrompt(opencodeCodexURL, "opencode-codex.txt", "opencode-codex-meta.json") +} + +func getOpenCodeCodexHeader() string { + return getOpenCodeCachedPrompt(opencodeCodexHeaderURL, "opencode-codex-header.txt", "opencode-codex-header-meta.json") +} + func filterCodexInput(input []any) []any { filtered := make([]any, 0, len(input)) for _, item := range input { diff --git a/backend/internal/service/openai_gateway_service.go b/backend/internal/service/openai_gateway_service.go index 33244330..76aaa6cd 100644 --- a/backend/internal/service/openai_gateway_service.go +++ b/backend/internal/service/openai_gateway_service.go @@ -580,7 +580,7 @@ func (s *OpenAIGatewayService) Forward(ctx context.Context, c *gin.Context, acco } // Build upstream request - upstreamReq, err := s.buildUpstreamRequest(ctx, c, account, body, token, reqStream, promptCacheKey) + upstreamReq, err := s.buildUpstreamRequest(ctx, c, account, body, token, reqStream, promptCacheKey, isCodexCLI) if err != nil { return nil, err } @@ -641,7 +641,7 @@ func (s *OpenAIGatewayService) Forward(ctx context.Context, c *gin.Context, acco }, nil } -func (s *OpenAIGatewayService) buildUpstreamRequest(ctx context.Context, c *gin.Context, account *Account, body []byte, token string, isStream bool, promptCacheKey string) (*http.Request, error) { +func (s *OpenAIGatewayService) buildUpstreamRequest(ctx context.Context, c *gin.Context, account *Account, body []byte, token string, isStream bool, promptCacheKey string, isCodexCLI bool) (*http.Request, error) { // Determine target URL based on account type var targetURL string switch account.Type { @@ -694,7 +694,11 @@ func (s *OpenAIGatewayService) buildUpstreamRequest(ctx context.Context, c *gin. } if account.Type == AccountTypeOAuth { req.Header.Set("OpenAI-Beta", "responses=experimental") - req.Header.Set("originator", "codex_cli_rs") + if isCodexCLI { + req.Header.Set("originator", "codex_cli_rs") + } else { + req.Header.Set("originator", "opencode") + } req.Header.Set("accept", "text/event-stream") if promptCacheKey != "" { req.Header.Set("conversation_id", promptCacheKey) diff --git a/backend/internal/service/openai_gateway_service_test.go b/backend/internal/service/openai_gateway_service_test.go index c30fba7e..55e11b30 100644 --- a/backend/internal/service/openai_gateway_service_test.go +++ b/backend/internal/service/openai_gateway_service_test.go @@ -220,7 +220,7 @@ func TestOpenAIInvalidBaseURLWhenAllowlistDisabled(t *testing.T) { Credentials: map[string]any{"base_url": "://invalid-url"}, } - _, err := svc.buildUpstreamRequest(c.Request.Context(), c, account, []byte("{}"), "token", false, "") + _, err := svc.buildUpstreamRequest(c.Request.Context(), c, account, []byte("{}"), "token", false, "", false) if err == nil { t.Fatalf("expected error for invalid base_url when allowlist disabled") }