Repository navigation
[openai-responses] Fold role:"system" in input to top-level instructions and strip truncation parameter #2668
Description
Client or integration
VS Code / GitHub Copilot (via /v1/responses BYOK endpoint)
Provider or upstream service
ChatGPT Codex forward / openai-responses
OpenCodex version
2.33.0
Endpoint or capability
/v1/responses, OpenAI Responses adapter
Current behaviour
When VS Code / Copilot sends a standard prompt to gpt-5.6-luna (or other native OpenAI passthrough models), the client formats system prompts as { type: "message", role: "system", content: [...] } within input, and includes "truncation": "disabled".
OpenCodex forwards this payload directly to the ChatGPT Codex backend, which returns HTTP 502 with:
upstreamError: System messages are not allowed
or
Unsupported parameter: truncation
As a result, VS Code Copilot fails on turn start with generic code: 0 / "Sorry, your request failed".
Expected behaviour
The openai-responses forward adapter should automatically sanitize the incoming Responses payload before dispatching:
- Extract any
role: "system"items frominput, join their text content, and fold them into the top-levelinstructionsfield (string or text block). - Strip the unsupported
truncationparameter from the forward body.
Minimal redacted request or reproduction
- Send a request to
POST http://127.0.0.1:7861/v1/responses:
{
"model": "gpt-5.6-luna",
"store": false,
"stream": true,
"truncation": "disabled",
"input": [
{
"type": "message",
"role": "system",
"content": [{ "type": "input_text", "text": "You are a helpful assistant." }]
},
{
"type": "message",
"role": "user",
"content": [{ "type": "input_text", "text": "hi" }]
}
]
}- Request fails with HTTP 502 (
System messages are not allowed).
Actual response or error
{
"status": 502,
"errorCode": "upstream_server_error",
"upstreamError": "System messages are not allowed"
}Upstream documentation
https://platform.openai.com/docs/api-reference/responses
Suggested mapping or implementation notes
In src/adapters/openai-responses.ts:
- Add a helper
foldSystemMessagesIntoInstructions(body)that scansbody.input, movesrole === "system"contents tobody.instructions, and keeps only non-system items ininput. - Add
stripUnsupportedTruncation(body)to dropbody.truncation. - Insert them into the
sanitizedBodyprocessing pipeline increateResponsesPassthroughAdapter.
Checks
- I searched existing provider and compatibility issues.
- The request and response were redacted.
- The expected behaviour is based on an upstream specification or a concrete client requirement.
Activity
github-actions commentedon Aug 26, 2026
Issue reopened
The report now contains the information required by the automated check. Thanks for updating it.
Liang-Psych commentedon Aug 26, 2026
Updated issue report with the missing upstream documentation link (
https://platform.openai.com/docs/api-reference/responses). Requesting automated check / review.lidge-jun commentedon Aug 26, 2026
리뷰 · 우선순위 71 / 80
설명
이 이슈는 VS Code / GitHub Copilot이 OpenCodex의 /v1/responses 로 표준 Responses 요청을 보낼 때, input 배열 안의 role "system" 메시지와 맨 위 truncation 값이 ChatGPT Codex 앞단에서 HTTP 502를 내는 문제입니다. 업스트림이 돌려주는 말은 System messages are not allowed 또는 Unsupported parameter: truncation 입니다. 재현 JSON은 짧고 분명합니다. store false, stream true, truncation disabled, 그리고 system 한 줄과 user 한 줄입니다.
지금 dev 58f5a29 는 이 두 값을 받아 주기만 하고, Codex로 보내기 전에 고치지 않습니다. src/responses/schema.ts 45-49줄의 systemMessageItemSchema 는 role system 입력 항목을 허용합니다. 같은 파일 168줄은 truncation 을 아무 값이나 받게 되어 있습니다. 146줄의 instructions 는 이미 문자열 또는 null 입니다. 그래서 프록시는 400을 내지 않고, 잘못된 몸을 그대로 앞으로 넘깁니다. 그 결과 클라이언트는 code 0 과 Sorry, your request failed 만 보게 됩니다.
앞으로 보내는 살균은 src/adapters/openai-responses.ts 1714줄 createResponsesPassthroughAdapter 안에 있습니다. 1791-1792줄의 forward 경로에서 stripUnsupportedForwardParams 를 호출합니다. 그 함수는 1098-1104줄에서 max_output_tokens 와 metadata 만 빼고, truncation 은 빼지 않습니다. 캐논 ChatGPT 앞에만 쓰는 stripDeprecatedPromptCacheRetention 은 1795-1796줄에 따로 있고, 이것도 다른 필드입니다. 호환 목록 src/compatibility/openai-responses.ts 는 max_output_tokens, metadata, prompt_cache_retention 만 문서로 남겨 두었고, system 역할과 truncation 주장은 없습니다.
1862줄의 sanitizedBody 체인은 compaction 항목 청소, hosted tools 제거, 잘못된 item id 제거, 저장하지 않을 때 id 제거, Spark 호환, tool schema 정규화만 합니다. 이슈가 제안한 foldSystemMessagesIntoInstructions 나 stripUnsupportedTruncation 이라는 이름은 이 파일에 없습니다. 따라서 system 항목은 input 에 남고, truncation 도 몸에 남습니다.
공개 OpenAI Responses API 는 truncation 을 지원합니다. 모든 openai-responses 목적지에 무조건 지우면, API 키로 공개 API를 쓰는 사람은 깨집니다. 이미 같은 파일이 그 경계를 알고 있습니다. 1795줄은 isCanonicalOpenAiForwardProvider 가 참일 때만 폐기된 캐시 필드를 뺍니다. truncation 과 system 접기도 그 경계 안에 두는 것이 맞습니다. VS Code Copilot 은 이 저장소에서 github-copilot 제공자와는 다른 이야기입니다. 여기는 Copilot을 클라이언트로 써서 Codex 모델을 빌리는 경로입니다.
system 을 instructions 로 접을지, developer 역할로 바꿀지도 정해야 합니다. src/server/responses/collaboration.ts 485줄은 이미 system 과 developer 를 같은 앞머리로 봅니다. 여러 system 항목과 이미 있는 instructions 를 어떤 순서로 붙일지, 도구 이어가기 턴에서 매번 접을지도 테스트가 필요합니다. 이슈의 제안처럼 텍스트만 모아 instructions 뒤에 붙이고 input 에서 system 항목만 빼는 길이, 기존 살균 함수 스타일과 잘 맞습니다.
src/adapters/openai-responses.ts:1098 - stripUnsupportedForwardParams 는 max_output_tokens 와 metadata 만 빼서, Codex 가 모르는 truncation 이 그대로 갑니다.
src/responses/schema.ts:47 - role system 을 받아 주므로 프록시는 통과시키고, Codex 만 System messages are not allowed 로 502를 냅니다.
src/adapters/openai-responses.ts:1862 - sanitizedBody 체인에 system 접기와 truncation 제거가 없어 이슈의 최소 요청이 살균되지 않습니다.
src/compatibility/openai-responses.ts - Codex forward 비지원 목록에 truncation 과 system 역할이 없어, 이 구멍이 호환 계약에도 안 적혀 있습니다.
메인테이너의 판단이 필요한 지점
너의 추천
이 이슈는 열어 두고 구현을 진행하는 것을 추천합니다. 고침은 src/adapters/openai-responses.ts 의 forward 살균에 좁게 넣으세요. isCanonicalOpenAiForwardProvider 가 참일 때만 truncation 을 빼고, input 의 role system 텍스트를 기존 instructions 뒤에 붙인 다음 system 항목만 제거하세요. 공개 API 경로의 truncation 은 그대로 두세요. 테스트는 이슈의 최소 JSON이 Codex forward 에서 system 과 truncation 이 빠지고, API 키 경로에서는 truncation 이 남는지를 고정하세요. 호환 목록에도 같은 두 주장을 한 줄씩 추가하세요.
이 댓글은 grok-bot이 작성했습니다
Ingwannu commentedon Aug 26, 2026
Confirmed on current
dev(779b6090c): the Responses schema accepts inputrole: "system"andtruncation, but the canonical ChatGPT Codex forward sanitizer does not normalize either before dispatch.I am going to fix this with a destination-scoped transform, not a global Responses rewrite:
truncation; key-auth/public OpenAI-compatible destinations keep it;inputare folded into top-levelinstructionsin stable order and removed frominput;instructionsare preserved and combined deterministically;call_idvalues, and the rest of the request remain unchanged;I will link the implementation PR here and keep this issue open until the fix lands on
devand the exact-head checks are green.Ingwannu commentedon Aug 26, 2026
Implementation is now available as draft PR #2672 at exact head
50b50e1b9a35095ebf62fe214fef6691ab71275c.The destination boundary, public/key-auth preservation controls, atomic multimodal behavior, compatibility fixture, and public docs are included. Focused tests, the existing passthrough suite, typecheck, privacy scan, docs build, and diff check pass. The full local suite reached 14,972 pass / 16 skip with one unrelated load-sensitive Cursor executor failure that passes in isolation, so the PR remains draft pending exact-head CI and another maintainer review. This issue stays open until the PR lands on
dev.Ingwannu commentedon Aug 26, 2026
Update: draft PR #2672 exact-head CI is now fully green across all Linux shards, macOS, gates, keyring, npm-global jobs, React Doctor, and the aggregate
cicheck. The PR remains draft because I am the author and cannot self-approve;lidge-junreview has been requested. The issue stays open until the change reachesdev.Merge pull request lidge-jun#2672 from Ingwannu/ingw/fix-responses-fo…
lidge-jun commentedon Aug 27, 2026
Landed via #2720 at 2feffbd (via #2672 on L1). Fix is on
dev: canonical forward prompt envelope normalization.Merge pull request lidge-jun#2672 from Ingwannu/ingw/fix-responses-fo…
Merge pull request lidge-jun#2672 from Ingwannu/ingw/fix-responses-fo…