Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions internal/adapter/provider/cliproxyapi_codex/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/awsl-project/maxx/internal/domain"
"github.com/awsl-project/maxx/internal/flow"
"github.com/awsl-project/maxx/internal/usage"
"github.com/tidwall/sjson"
"github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/auth"
"github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/executor"
"github.com/router-for-me/CLIProxyAPI/v6/sdk/exec"
Expand Down Expand Up @@ -212,6 +213,19 @@ func (a *CLIProxyAPICodexAdapter) Execute(c *flow.Ctx, p *domain.Provider) error
stream := flow.GetIsStream(c)
model := flow.GetMappedModel(c)

// Apply provider-level overrides for reasoning and service_tier
cfg := a.codexConfig()
if cfg.Reasoning != "" {
if updated, err := sjson.SetBytes(requestBody, "reasoning.effort", cfg.Reasoning); err == nil {
requestBody = updated
}
}
if cfg.ServiceTier != "" {
if updated, err := sjson.SetBytes(requestBody, "service_tier", cfg.ServiceTier); err == nil {
requestBody = updated
}
}

// Codex CLI 请求体本质是 OpenAI Responses schema;保持与 CLIProxyAPI 一致。
sourceFormat := translator.FormatOpenAIResponse

Expand Down
22 changes: 19 additions & 3 deletions internal/adapter/provider/codex/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,11 +121,28 @@ func (a *CodexAdapter) Execute(c *flow.Ctx, provider *domain.Provider) error {
cacheID, updatedBody := applyCodexRequestTuning(c, requestBody)
requestBody = updatedBody

// Apply provider-level overrides for reasoning and service_tier
config := provider.Config.Codex
if config.Reasoning != "" {
if updated, err := sjson.SetBytes(requestBody, "reasoning.effort", config.Reasoning); err == nil {
requestBody = updated
}
}
if config.ServiceTier != "" {
if updated, err := sjson.SetBytes(requestBody, "service_tier", config.ServiceTier); err == nil {
requestBody = updated
}
}

// Build upstream URL and stream mode
upstreamURL := CodexBaseURL + "/responses"
baseURL := CodexBaseURL
if config.BaseURL != "" {
baseURL = strings.TrimRight(config.BaseURL, "/")
}
upstreamURL := baseURL + "/responses"
upstreamStream := true
if !clientWantsStream {
upstreamURL = CodexBaseURL + "/responses/compact"
upstreamURL = baseURL + "/responses/compact"
upstreamStream = false
}
if len(requestBody) > 0 {
Expand All @@ -141,7 +158,6 @@ func (a *CodexAdapter) Execute(c *flow.Ctx, provider *domain.Provider) error {
}

// Apply headers with passthrough support (client headers take priority)
config := provider.Config.Codex
a.applyCodexHeaders(upstreamReq, request, accessToken, config.AccountID, upstreamStream, cacheID)

// Send request info via EventChannel
Expand Down
7 changes: 7 additions & 0 deletions internal/converter/codex_to_claude.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ func (c *codexToClaudeRequest) Transform(body []byte, model string, stream bool)
TopP: req.TopP,
}

// Convert reasoning effort to Claude output_config
if req.Reasoning != nil && req.Reasoning.Effort != "" {
claudeReq.OutputConfig = &ClaudeOutputConfig{
Effort: req.Reasoning.Effort,
}
}

// Convert instructions to system prompt
if req.Instructions != "" {
claudeReq.System = req.Instructions
Expand Down
3 changes: 3 additions & 0 deletions internal/converter/codex_to_openai.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ func (c *codexToOpenAIRequest) Transform(body []byte, model string, stream bool)
if req.Reasoning != nil && req.Reasoning.Effort != "" {
openaiReq.ReasoningEffort = req.Reasoning.Effort
}
if req.ServiceTier != "" {
openaiReq.ServiceTier = req.ServiceTier
}

// Convert instructions to system message
if req.Instructions != "" {
Expand Down
4 changes: 4 additions & 0 deletions internal/converter/openai_to_codex.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ func (c *openaiToCodexRequest) Transform(body []byte, model string, stream bool)
} else {
out, _ = sjson.Set(out, "reasoning.effort", "medium")
}
if v := gjson.GetBytes(rawJSON, "service_tier"); v.Exists() {
out, _ = sjson.Set(out, "service_tier", v.Value())
}
out, _ = sjson.Set(out, "parallel_tool_calls", true)
out, _ = sjson.Set(out, "reasoning.summary", "auto")
out, _ = sjson.Set(out, "include", []string{"reasoning.encrypted_content"})
Expand Down Expand Up @@ -901,6 +904,7 @@ func applyRequestEchoToResponse(responseJSON string, prefix string, requestRaw [
"previous_response_id",
"text",
"truncation",
"service_tier",
}
for _, path := range paths {
val := req.Get(path)
Expand Down
1 change: 1 addition & 0 deletions internal/converter/types_codex.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type CodexRequest struct {
Tools []CodexTool `json:"tools,omitempty"`
ToolChoice interface{} `json:"tool_choice,omitempty"`
Reasoning *CodexReasoning `json:"reasoning,omitempty"`
ServiceTier string `json:"service_tier,omitempty"`
ParallelToolCalls *bool `json:"parallel_tool_calls,omitempty"`
Include []string `json:"include,omitempty"`
Metadata map[string]interface{} `json:"metadata,omitempty"`
Expand Down
1 change: 1 addition & 0 deletions internal/converter/types_openai.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ type OpenAIRequest struct {
MaxTokens int `json:"max_tokens,omitempty"`
MaxCompletionTokens int `json:"max_completion_tokens,omitempty"`
ReasoningEffort string `json:"reasoning_effort,omitempty"`
ServiceTier string `json:"service_tier,omitempty"`
Temperature *float64 `json:"temperature,omitempty"`
TopP *float64 `json:"top_p,omitempty"`
N int `json:"n,omitempty"`
Expand Down
11 changes: 11 additions & 0 deletions internal/domain/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,17 @@ type ProviderConfigCodex struct {

// 使用 CLIProxyAPI 转发
UseCLIProxyAPI bool `json:"useCLIProxyAPI,omitempty"`

// 自定义 Codex API Base URL(默认使用官方地址)
BaseURL string `json:"baseURL,omitempty"`

// 强制 reasoning effort(覆盖请求中的值)
// 可选值: "low", "medium", "high"
Reasoning string `json:"reasoning,omitempty"`

// 强制 service_tier(覆盖请求中的值)
// 可选值: "auto", "default", "flex", "priority"
ServiceTier string `json:"serviceTier,omitempty"`
}

// ProviderConfigCLIProxyAPIAntigravity CLIProxyAPI Antigravity 内部配置
Expand Down
3 changes: 2 additions & 1 deletion tests/e2e/playwright/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"private": true,
"type": "module",
"scripts": {
"test": "node test-passkey-discoverable.mjs && node test-requests-project-filter.mjs && node test-stats-chart-resize.mjs",
"test": "node test-passkey-discoverable.mjs && node test-requests-project-filter.mjs && node test-stats-chart-resize.mjs && node test-codex-reasoning-servicetier.mjs",
"test:codex-overrides": "node test-codex-reasoning-servicetier.mjs",
"test:passkey": "node test-passkey-discoverable.mjs",
"test:project-filter": "node test-requests-project-filter.mjs",
"test:stats-chart": "node test-stats-chart-resize.mjs",
Expand Down
Loading