Skip to content
Closed
Changes from all 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
9 changes: 9 additions & 0 deletions relay/channel/codex/adaptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
relaycommon "github.com/QuantumNous/new-api/relay/common"
relayconstant "github.com/QuantumNous/new-api/relay/constant"
"github.com/QuantumNous/new-api/types"
"github.com/samber/lo"

"github.com/gin-gonic/gin"
)
Expand Down Expand Up @@ -99,6 +100,14 @@ func (a *Adaptor) ConvertOpenAIResponsesRequest(c *gin.Context, info *relaycommo
if isCompact {
return request, nil
}
// Codex upstream (chatgpt.com/backend-api/codex/responses) only accepts
// streaming requests and rejects with 400 "Stream must be set to true"
// otherwise. Force it here so every call path (manual test, batch test,
// playground, third-party clients) honors the upstream contract.
request.Stream = lo.ToPtr(true)
if info != nil {
info.IsStream = true
}
Comment on lines +103 to +110

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect how IsStream is initially derived and whether the stream handler
# accounts for a client that requested non-streaming.
rg -nP --type=go 'func OaiResponsesStreamHandler' -A 40
echo '--- where IsStream is initialized ---'
rg -nP --type=go '\.IsStream\s*=' -C2

Repository: QuantumNous/new-api

Length of output: 157


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file list =="
git ls-files | rg '^(relay/channel/codex/adaptor\.go|.*openai.*\.go|.*responses.*\.go|.*stream.*\.go)$' || true

echo
echo "== locate DoResponse / OaiResponsesStreamHandler / IsStream assignments =="
rg -n --hidden --glob '*.go' 'DoResponse|OaiResponsesStreamHandler|IsStream|StreamHandler' relay . || true

Repository: QuantumNous/new-api

Length of output: 50375


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== relay/channel/codex/adaptor.go (lines 90-170) =="
sed -n '90,170p' relay/channel/codex/adaptor.go | cat -n

echo
echo "== relay/channel/openai/relay_responses.go (lines 1-220) =="
sed -n '1,220p' relay/channel/openai/relay_responses.go | cat -n

echo
echo "== relay/channel/openai/chat_via_responses.go (lines 1-240) =="
sed -n '1,240p' relay/channel/openai/chat_via_responses.go | cat -n

echo
echo "== relay/common/relay_info.go (lines 430-500) =="
sed -n '430,500p' relay/common/relay_info.go | cat -n

echo
echo "== relay/chat_completions_via_responses.go (lines 130-175) =="
sed -n '130,175p' relay/chat_completions_via_responses.go | cat -n

Repository: QuantumNous/new-api

Length of output: 25086


Preserve the caller's stream preference here

Force request.Stream = true for Codex, but keep info.IsStream unchanged. DoResponse routes through OaiResponsesStreamHandler, which always emits SSE; overwriting info.IsStream makes stream: false callers receive a streamed body instead of the JSON response they asked for. Add a buffered non-stream fallback for those callers.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@relay/channel/codex/adaptor.go` around lines 103 - 110, The Codex adaptor is
forcing the upstream request to stream correctly, but it also overwrites the
caller’s stream preference by setting info.IsStream to true. Update the adaptor
logic around request.Stream and info.IsStream so the request is always sent as
streaming to Codex while preserving the original info.IsStream value, and add a
non-stream buffered fallback in DoResponse/OaiResponsesStreamHandler for callers
that requested stream=false so they still receive a JSON response instead of
SSE.

// codex: store must be false
request.Store = json.RawMessage("false")
// rm max_output_tokens
Expand Down