fix: sync codex field (#6018)
This commit is contained in:
@@ -874,6 +874,9 @@ type OpenAIResponsesRequest struct {
|
||||
User json.RawMessage `json:"user,omitempty"`
|
||||
MaxToolCalls *uint `json:"max_tool_calls,omitempty"`
|
||||
Prompt json.RawMessage `json:"prompt,omitempty"`
|
||||
// Codex Responses metadata/client_metadata:
|
||||
// https://github.com/openai/codex/commit/14df0e8833aad0d6d78287954b61ffac67af936c
|
||||
ClientMetadata json.RawMessage `json:"client_metadata,omitempty"`
|
||||
// qwen
|
||||
EnableThinking json.RawMessage `json:"enable_thinking,omitempty"`
|
||||
// perplexity
|
||||
@@ -958,8 +961,10 @@ func (r *OpenAIResponsesRequest) GetToolsMap() []map[string]any {
|
||||
}
|
||||
|
||||
type Reasoning struct {
|
||||
Effort string `json:"effort,omitempty"`
|
||||
Summary string `json:"summary,omitempty"`
|
||||
Effort string `json:"effort,omitempty"`
|
||||
Summary string `json:"summary,omitempty"`
|
||||
Mode json.RawMessage `json:"mode,omitempty"`
|
||||
Context json.RawMessage `json:"context,omitempty"`
|
||||
}
|
||||
|
||||
type Input struct {
|
||||
|
||||
@@ -14,6 +14,15 @@ type OpenAIResponsesCompactionRequest struct {
|
||||
Input json.RawMessage `json:"input,omitempty"`
|
||||
Instructions json.RawMessage `json:"instructions,omitempty"`
|
||||
PreviousResponseID string `json:"previous_response_id,omitempty"`
|
||||
// Codex compact request parity:
|
||||
// https://github.com/openai/codex/commit/53d59722268dde82fb93c1f37964ce196c2a86d7
|
||||
// https://github.com/openai/codex/commit/5d6f23a27bf9c90709af527a7108c1c2eadf5123
|
||||
Tools json.RawMessage `json:"tools,omitempty"`
|
||||
ParallelToolCalls json.RawMessage `json:"parallel_tool_calls,omitempty"`
|
||||
Reasoning *Reasoning `json:"reasoning,omitempty"`
|
||||
ServiceTier string `json:"service_tier,omitempty"`
|
||||
PromptCacheKey json.RawMessage `json:"prompt_cache_key,omitempty"`
|
||||
Text json.RawMessage `json:"text,omitempty"`
|
||||
}
|
||||
|
||||
func (r *OpenAIResponsesCompactionRequest) GetTokenCountMeta() *types.TokenCountMeta {
|
||||
|
||||
@@ -9,7 +9,7 @@ var baseModelList = []string{
|
||||
"gpt-5", "gpt-5-codex", "gpt-5-codex-mini",
|
||||
"gpt-5.1", "gpt-5.1-codex", "gpt-5.1-codex-max", "gpt-5.1-codex-mini",
|
||||
"gpt-5.2", "gpt-5.2-codex", "gpt-5.3-codex", "gpt-5.3-codex-spark",
|
||||
"gpt-5.4",
|
||||
"gpt-5.4", "gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna",
|
||||
}
|
||||
|
||||
var ModelList = withCompactModelSuffix(baseModelList)
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/QuantumNous/new-api/constant"
|
||||
"github.com/QuantumNous/new-api/logger"
|
||||
relaycommon "github.com/QuantumNous/new-api/relay/common"
|
||||
"github.com/QuantumNous/new-api/service"
|
||||
"github.com/QuantumNous/new-api/setting/operation_setting"
|
||||
|
||||
"github.com/bytedance/gopkg/util/gopool"
|
||||
@@ -45,6 +46,24 @@ func NewStreamScanner(reader io.Reader) *bufio.Scanner {
|
||||
return scanner
|
||||
}
|
||||
|
||||
func copyCodexSSEHeaders(c *gin.Context, resp *http.Response) {
|
||||
if c == nil || c.Writer == nil || resp == nil {
|
||||
return
|
||||
}
|
||||
// codex
|
||||
for _, name := range []string{"X-Reasoning-Included", "X-Codex-Turn-State"} {
|
||||
values := resp.Header.Values(name)
|
||||
if !service.ShouldCopyUpstreamHeader(c, name, values) {
|
||||
continue
|
||||
}
|
||||
for _, value := range values {
|
||||
if value != "" {
|
||||
c.Writer.Header().Add(name, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ExtendWriteDeadline pushes the connection write deadline forward before each
|
||||
// stream write. Best-effort: writers that don't support deadlines (e.g.
|
||||
// httptest recorders) are silently ignored.
|
||||
@@ -122,6 +141,7 @@ func StreamScannerHandler(c *gin.Context, resp *http.Response, info *relaycommon
|
||||
defer cleanup()
|
||||
|
||||
scanner.Split(bufio.ScanLines)
|
||||
copyCodexSSEHeaders(c, resp)
|
||||
SetEventStreamHeaders(c)
|
||||
|
||||
ctx = context.WithValue(ctx, "stop_chan", stopChan)
|
||||
|
||||
@@ -45,6 +45,8 @@ func ResponsesHelper(c *gin.Context, info *relaycommon.RelayInfo) (newAPIError *
|
||||
Input: req.Input,
|
||||
Instructions: req.Instructions,
|
||||
PreviousResponseID: req.PreviousResponseID,
|
||||
ParallelToolCalls: req.ParallelToolCalls,
|
||||
ServiceTier: req.ServiceTier,
|
||||
}
|
||||
default:
|
||||
return types.NewErrorWithStatusCode(
|
||||
|
||||
@@ -36,12 +36,33 @@ type ChannelAffinitySetting struct {
|
||||
Rules []ChannelAffinityRule `json:"rules"`
|
||||
}
|
||||
|
||||
// Keep Codex CLI passthrough aligned with upstream. Codex uses lower-case
|
||||
// header names, while HTTP matching here is case-insensitive.
|
||||
// Request session/thread headers:
|
||||
// https://github.com/openai/codex/commit/7c7b4861d88960f7e3bd5b7f30f8351be666dd84
|
||||
// Responses metadata headers/client_metadata:
|
||||
// https://github.com/openai/codex/commit/14df0e8833aad0d6d78287954b61ffac67af936c
|
||||
// x-codex-turn-state response/request round trip:
|
||||
// https://github.com/openai/codex/commit/ebdd8795e924a8149b616e46ca2ed7848c207a4b
|
||||
var codexCliPassThroughHeaders = []string{
|
||||
"Originator",
|
||||
"Session_id",
|
||||
"Thread_id",
|
||||
"Session-Id",
|
||||
"Thread-Id",
|
||||
"X-Client-Request-Id",
|
||||
"User-Agent",
|
||||
"X-Codex-Beta-Features",
|
||||
"X-Codex-Turn-State",
|
||||
"X-Codex-Turn-Metadata",
|
||||
"X-Codex-Window-Id",
|
||||
"X-Codex-Parent-Thread-Id",
|
||||
//"X-Codex-Installation-Id",
|
||||
"X-OpenAI-Subagent",
|
||||
"X-OpenAI-Memgen-Request",
|
||||
//"X-OAI-Attestation",
|
||||
"X-ResponsesAPI-Include-Timing-Metrics",
|
||||
"X-OpenAI-Internal-Codex-Responses-Lite",
|
||||
}
|
||||
|
||||
var claudeCliPassThroughHeaders = []string{
|
||||
@@ -74,6 +95,20 @@ func buildPassHeaderTemplate(headers []string) map[string]interface{} {
|
||||
}
|
||||
}
|
||||
|
||||
func buildCodexPassHeaderTemplate() map[string]interface{} {
|
||||
requestHeaders := make([]string, 0, len(codexCliPassThroughHeaders))
|
||||
requestHeaders = append(requestHeaders, codexCliPassThroughHeaders...)
|
||||
return map[string]interface{}{
|
||||
"operations": []map[string]interface{}{
|
||||
{
|
||||
"mode": "pass_headers",
|
||||
"value": requestHeaders,
|
||||
"keep_origin": true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
var channelAffinitySetting = ChannelAffinitySetting{
|
||||
Enabled: true,
|
||||
SwitchOnSuccess: true,
|
||||
@@ -90,7 +125,7 @@ var channelAffinitySetting = ChannelAffinitySetting{
|
||||
},
|
||||
ValueRegex: "",
|
||||
TTLSeconds: 0,
|
||||
ParamOverrideTemplate: buildPassHeaderTemplate(codexCliPassThroughHeaders),
|
||||
ParamOverrideTemplate: buildCodexPassHeaderTemplate(),
|
||||
SkipRetryOnFailure: true,
|
||||
IncludeUsingGroup: true,
|
||||
IncludeRuleName: true,
|
||||
|
||||
@@ -27,12 +27,39 @@ const buildPassHeadersTemplate = (headers) => ({
|
||||
],
|
||||
});
|
||||
|
||||
const buildCodexPassHeadersTemplate = () => ({
|
||||
operations: [
|
||||
{
|
||||
mode: 'pass_headers',
|
||||
value: [...CODEX_CLI_HEADER_PASSTHROUGH_HEADERS],
|
||||
keep_origin: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// Keep in sync with upstream Codex request headers:
|
||||
// https://github.com/openai/codex/commit/7c7b4861d88960f7e3bd5b7f30f8351be666dd84
|
||||
// https://github.com/openai/codex/commit/14df0e8833aad0d6d78287954b61ffac67af936c
|
||||
// https://github.com/openai/codex/commit/ebdd8795e924a8149b616e46ca2ed7848c207a4b
|
||||
export const CODEX_CLI_HEADER_PASSTHROUGH_HEADERS = [
|
||||
'Originator',
|
||||
'Session_id',
|
||||
'Thread_id',
|
||||
'Session-Id',
|
||||
'Thread-Id',
|
||||
'X-Client-Request-Id',
|
||||
'User-Agent',
|
||||
'X-Codex-Beta-Features',
|
||||
'X-Codex-Turn-State',
|
||||
'X-Codex-Turn-Metadata',
|
||||
'X-Codex-Window-Id',
|
||||
'X-Codex-Parent-Thread-Id',
|
||||
// 'X-Codex-Installation-Id',
|
||||
'X-OpenAI-Subagent',
|
||||
'X-OpenAI-Memgen-Request',
|
||||
// 'X-OAI-Attestation',
|
||||
'X-ResponsesAPI-Include-Timing-Metrics',
|
||||
'X-OpenAI-Internal-Codex-Responses-Lite',
|
||||
];
|
||||
|
||||
export const CLAUDE_CLI_HEADER_PASSTHROUGH_HEADERS = [
|
||||
@@ -51,9 +78,8 @@ export const CLAUDE_CLI_HEADER_PASSTHROUGH_HEADERS = [
|
||||
'Anthropic-Version',
|
||||
];
|
||||
|
||||
export const CODEX_CLI_HEADER_PASSTHROUGH_TEMPLATE = buildPassHeadersTemplate(
|
||||
CODEX_CLI_HEADER_PASSTHROUGH_HEADERS,
|
||||
);
|
||||
export const CODEX_CLI_HEADER_PASSTHROUGH_TEMPLATE =
|
||||
buildCodexPassHeadersTemplate();
|
||||
|
||||
export const CLAUDE_CLI_HEADER_PASSTHROUGH_TEMPLATE = buildPassHeadersTemplate(
|
||||
CLAUDE_CLI_HEADER_PASSTHROUGH_HEADERS,
|
||||
@@ -65,7 +91,7 @@ export const CHANNEL_AFFINITY_RULE_TEMPLATES = {
|
||||
model_regex: ['^gpt-.*$'],
|
||||
path_regex: ['/v1/responses'],
|
||||
key_sources: [{ type: 'gjson', path: 'prompt_cache_key' }],
|
||||
param_override_template: CODEX_CLI_HEADER_PASSTHROUGH_TEMPLATE,
|
||||
param_override_template: buildCodexPassHeadersTemplate(),
|
||||
value_regex: '',
|
||||
ttl_seconds: 0,
|
||||
skip_retry_on_failure: true,
|
||||
|
||||
+27
-3
@@ -291,12 +291,29 @@ const GEMINI_IMAGE_4K_TEMPLATE = {
|
||||
],
|
||||
}
|
||||
|
||||
// Keep in sync with upstream Codex request headers:
|
||||
// https://github.com/openai/codex/commit/7c7b4861d88960f7e3bd5b7f30f8351be666dd84
|
||||
// https://github.com/openai/codex/commit/14df0e8833aad0d6d78287954b61ffac67af936c
|
||||
// https://github.com/openai/codex/commit/ebdd8795e924a8149b616e46ca2ed7848c207a4b
|
||||
const CODEX_CLI_HEADER_PASSTHROUGH_HEADERS = [
|
||||
'Originator',
|
||||
'Session_id',
|
||||
'Thread_id',
|
||||
'Session-Id',
|
||||
'Thread-Id',
|
||||
'X-Client-Request-Id',
|
||||
'User-Agent',
|
||||
'X-Codex-Beta-Features',
|
||||
'X-Codex-Turn-State',
|
||||
'X-Codex-Turn-Metadata',
|
||||
'X-Codex-Window-Id',
|
||||
'X-Codex-Parent-Thread-Id',
|
||||
// 'X-Codex-Installation-Id',
|
||||
'X-OpenAI-Subagent',
|
||||
'X-OpenAI-Memgen-Request',
|
||||
// 'X-OAI-Attestation',
|
||||
'X-ResponsesAPI-Include-Timing-Metrics',
|
||||
'X-OpenAI-Internal-Codex-Responses-Lite',
|
||||
]
|
||||
|
||||
const CLAUDE_CLI_HEADER_PASSTHROUGH_HEADERS = [
|
||||
@@ -321,9 +338,15 @@ const buildPassHeadersTemplate = (headers: string[]) => ({
|
||||
],
|
||||
})
|
||||
|
||||
const CODEX_CLI_HEADER_PASSTHROUGH_TEMPLATE = buildPassHeadersTemplate(
|
||||
CODEX_CLI_HEADER_PASSTHROUGH_HEADERS
|
||||
)
|
||||
const CODEX_CLI_HEADER_PASSTHROUGH_TEMPLATE = {
|
||||
operations: [
|
||||
{
|
||||
mode: 'pass_headers',
|
||||
value: [...CODEX_CLI_HEADER_PASSTHROUGH_HEADERS],
|
||||
keep_origin: true,
|
||||
},
|
||||
],
|
||||
}
|
||||
const CLAUDE_CLI_HEADER_PASSTHROUGH_TEMPLATE = buildPassHeadersTemplate(
|
||||
CLAUDE_CLI_HEADER_PASSTHROUGH_HEADERS
|
||||
)
|
||||
@@ -941,6 +964,7 @@ const validateOperations = (
|
||||
if (headers.length === 0)
|
||||
return t('Rule {{line}} pass_headers format is invalid', { line })
|
||||
}
|
||||
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
+30
-3
@@ -18,12 +18,29 @@ For commercial licensing, please contact support@quantumnous.com
|
||||
*/
|
||||
import type { AffinityRule } from './types'
|
||||
|
||||
// Keep in sync with upstream Codex request headers:
|
||||
// https://github.com/openai/codex/commit/7c7b4861d88960f7e3bd5b7f30f8351be666dd84
|
||||
// https://github.com/openai/codex/commit/14df0e8833aad0d6d78287954b61ffac67af936c
|
||||
// https://github.com/openai/codex/commit/ebdd8795e924a8149b616e46ca2ed7848c207a4b
|
||||
const CODEX_CLI_HEADER_PASSTHROUGH_HEADERS = [
|
||||
'Originator',
|
||||
'Session_id',
|
||||
'Thread_id',
|
||||
'Session-Id',
|
||||
'Thread-Id',
|
||||
'X-Client-Request-Id',
|
||||
'User-Agent',
|
||||
'X-Codex-Beta-Features',
|
||||
'X-Codex-Turn-State',
|
||||
'X-Codex-Turn-Metadata',
|
||||
'X-Codex-Window-Id',
|
||||
'X-Codex-Parent-Thread-Id',
|
||||
// 'X-Codex-Installation-Id',
|
||||
'X-OpenAI-Subagent',
|
||||
'X-OpenAI-Memgen-Request',
|
||||
// 'X-OAI-Attestation',
|
||||
'X-ResponsesAPI-Include-Timing-Metrics',
|
||||
'X-OpenAI-Internal-Codex-Responses-Lite',
|
||||
]
|
||||
|
||||
const CLAUDE_CLI_HEADER_PASSTHROUGH_HEADERS = [
|
||||
@@ -54,6 +71,18 @@ function buildPassHeadersTemplate(headers: string[]) {
|
||||
}
|
||||
}
|
||||
|
||||
function buildCodexPassHeadersTemplate() {
|
||||
return {
|
||||
operations: [
|
||||
{
|
||||
mode: 'pass_headers',
|
||||
value: [...CODEX_CLI_HEADER_PASSTHROUGH_HEADERS],
|
||||
keep_origin: true,
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
export type RuleTemplate = Omit<AffinityRule, 'id'>
|
||||
|
||||
export const RULE_TEMPLATES: Record<string, RuleTemplate> = {
|
||||
@@ -62,9 +91,7 @@ export const RULE_TEMPLATES: Record<string, RuleTemplate> = {
|
||||
model_regex: ['^gpt-.*$'],
|
||||
path_regex: ['/v1/responses'],
|
||||
key_sources: [{ type: 'gjson', path: 'prompt_cache_key' }],
|
||||
param_override_template: buildPassHeadersTemplate(
|
||||
CODEX_CLI_HEADER_PASSTHROUGH_HEADERS
|
||||
),
|
||||
param_override_template: buildCodexPassHeadersTemplate(),
|
||||
value_regex: '',
|
||||
ttl_seconds: 0,
|
||||
skip_retry_on_failure: true,
|
||||
|
||||
Reference in New Issue
Block a user