Repository navigation
Feature: opt-in plaintext V2 collaboration rewrite for native-to-routed sub-agents #2495
Description
Area
Proxy and routing
What are you trying to accomplish?
I want a native ChatGPT MultiAgentV2 parent to delegate spawn_agent, send_message, and followup_task messages to a routed third-party child without first producing backend ciphertext that the child cannot read.
The requested feature is an experimental configuration option that is unset in a fresh config and runs only when explicitly set to true. It changes eligible collaboration tool declarations before ChatGPT generates a call, so Codex can receive the message through its supported plaintext collaboration path. It does not decrypt an existing task, make an authenticated recovery request, change the default encrypted behavior, or claim to fix the upstream limitation tracked in #92.
What prevents this today?
Codex MultiAgentV2 declares message.encrypted: true on spawn_agent, send_message, and followup_task. A native ChatGPT parent can therefore return the assignment as backend ciphertext. OpenCodex cannot make that ciphertext readable to a third-party routed child.
The available alternatives have different costs:
- V1 keeps heterogeneous delegation readable but gives up the V2 collaboration workflow.
- The opt-in recovery path from fix(agents): add opt-in encrypted v2 recovery #1540 and fix(agents): reroute recovered tasks through healthy fallback #1556 can recover some unreadable tasks, but it adds an authenticated ChatGPT request, quota use, latency, backend coupling, and a plaintext-in-process boundary.
- The trusted ciphertext passthrough proposed in feat(providers): allow trusted encrypted V2 task passthrough #2113 helps only Responses providers that have been explicitly verified to consume or relay the opaque payload.
- Changing the reserved
collaborationschema while retaining reserved child-tool names can still cause ChatGPT to return ciphertext.
OpenAI Codex has a receiving path for plaintext collaboration calls when encrypted_function_args: [] is present, added by openai/codex#35845. OpenCodex needs a narrowly limited request rewrite that selects that path before ciphertext exists and restores every client-facing identity before Codex receives the response.
What should OpenCodex do?
Add a boolean plaintextV2AgentMessages field. A fresh config should omit the field, and only the explicit value true should enable it.
- Apply only when the caller uses the Responses wire, the final destination uses
adapter: "openai-responses",authMode: "forward", and base URLhttps://chatgpt.com/backend-api/codex, and the request contains the default top-levelcollaborationMultiAgentV2 catalog. - Leave OpenAI API-key providers, custom compatible gateways, routes whose final parent destination is another provider, Anthropic-protocol callers, V1 tools, custom collaboration namespaces, and disabled configurations unchanged.
- For an eligible request, assign fixed request-scoped aliases to the namespace and the
spawn_agent,send_message, andfollowup_taskfunction names. Remove onlyparameters.properties.message.encrypted: truefrom those declarations. Preserve every other schema field and leave the caller's object unchanged. - Refuse the entire rewrite if a fixed alias already appears in any top-level or nested declaration,
additional_tools, tool-search result, tool choice, allowed-tool entry, or replayed function/custom call. - Restore the namespace and only the aliases that this request generated before JSON, SSE, WebSocket, snapshot, continuation state, or Codex history can consume the response. A fixed alias under a foreign namespace must remain unchanged. Preserve
encrypted_function_args: []so current Codex clients select structured plaintext delivery. - Keep all rewrite and restoration state within the request. An incremental WebSocket turn, a later option change, or a concurrent request must not reuse another request's alias metadata.
- If a conflict, malformed payload, byte limit, 10,000-identity limit, or unsupported response type prevents safe restoration, do not retry the model request. Bounded JSON should return HTTP 502, streams should emit
response.failed, private aliases should not reach Codex, and the refused response should not be cached forprevious_response_id. - Emit a startup warning and document that task text can remain in Codex history, OpenCodex response state or debug files, and the selected provider. HTTPS transport encryption does not make the task application-layer ciphertext.
- Keep the first version configuration-only. Dashboard controls and the separate recovery UX in [UX] Explain native-to-routed V2 compatibility and recovery state for preferred sub-agents #1533 remain separate work.
Example usage or interface
ocx config set plaintextV2AgentMessages true
ocx service restartAn eligible ChatGPT request would use a private namespace and a private name for a declared message tool:
{
"type": "namespace",
"name": "collaboration-optimize",
"tools": [
{
"type": "function",
"name": "start_delegated_task",
"parameters": {
"properties": {
"message": { "type": "string" }
}
}
}
]
}Before Codex receives the response, OpenCodex restores the client-facing identity and retains the plaintext marker:
{
"type": "function_call",
"namespace": "collaboration",
"name": "spawn_agent",
"encrypted_function_args": [],
"arguments": "{...}"
}Disabling the option for later requests is explicit:
ocx config set plaintextV2AgentMessages false
ocx service restartAlternatives or workarounds
- Use V1 for native-parent to routed-child delegation.
- Enable the encrypted-task recovery introduced by fix(agents): add opt-in encrypted v2 recovery #1540 and fix(agents): reroute recovered tasks through healthy fallback #1556 when its authentication, quota, latency, and fidelity limits are acceptable.
- Use trusted encrypted V2 passthrough as proposed in feat(providers): allow trusted encrypted V2 task passthrough #2113 when the selected Responses provider has been verified to handle the opaque payload.
- Wait for an upstream provider-aware plaintext sending policy.
0.147.0-alpha.4: OpenAI parent still sends encrypted V2 task to non-OpenAI child after #35845 openai/codex#36376 reproduces the encrypted native-parent case after plaintext receiving support, and MultiAgentV2 plaintext support in 0.147.0-alpha.1 does not complete cross-provider task delivery openai/codex#37197 describes the missing sending policy.
Additional context
This proposal follows the prevention approach discussed in #92. Issue #92 later closed as an upstream tracker after recovery mitigations shipped. This proposal does not request reopening it and does not replace #1540, #1556, #1533, or #2113.
Relevant upstream and prior-art references:
- Support plaintext collaboration tool messages openai/codex#35845 added client support for plaintext collaboration messages marked by
encrypted_function_args: []. 0.147.0-alpha.4: OpenAI parent still sends encrypted V2 task to non-OpenAI child after #35845 openai/codex#36376 confirms that an OpenAI parent can still emit ciphertext for a third-party child.- MultiAgentV2 plaintext support in 0.147.0-alpha.1 does not complete cross-provider task delivery openai/codex#37197 proposes an upstream plaintext sending policy and a non-reserved namespace.
- Handle encrypted collaboration message schemas router-for-me/CLIProxyAPI#4748 implemented a disabled-by-default schema rewrite for the same three message tools.
- codex: optimize-multi-agent-v2 leaks collaboration-optimize across incremental WebSocket turns router-for-me/CLIProxyAPI#4909 shows why namespace restoration must survive incremental WebSocket turns.
- fix(openai-chat): strip the Responses-only encrypted tool annotation #1779 removes the Responses-only encryption annotation when converting schemas for non-Responses providers. This proposal is a separate explicit exception for canonical ChatGPT forwarding.
PR #2496 implements this scope on current dev:
- Fork branch: Sigurd-git/opencodex:feat/plaintext-v2-collaboration
- Tested commit:
1a4cb4aab
Current verification:
Feature and adjacent tests: 270 pass, 0 fail
Capacity regression tests: 128 pass, 0 fail
Capability registry tests: 16 pass, 0 fail
TypeScript typecheck: pass
Privacy scan: pass
git diff --check: pass
An earlier complete single-worker suite ran on c17bc94c2: 17,272 passed, 16 skipped, and 0 failed. After replaying onto current dev commit f84dbf91e, all 414 feature, adjacent, capacity, and capability tests passed with typecheck, privacy scan, and git diff --check. The only rebase conflict was tests/provider-quota.test.ts; current dev already contained the same #3198 expectation, so the redundant test-only commit was skipped and the file disappeared from the PR diff. GitHub reports the new head as mergeable and created exact-head Cross-platform CI and React Doctor runs for 1a4cb4aab; both require upstream maintainer approval before fork code can execute.
The last successful documentation build produced 409 pages before the conflict-only rebase. The final local attempt stopped before Astro loaded because the available Node runtime is 20.19.4 and current Astro requires >=22.12.0.
A captured rollout showed that namespace aliasing plus schema-marker removal was insufficient. ChatGPT still returned a Fernet-shaped gAAAA… value in spawn_agent.arguments.message, and the routed Fable task received an empty Payload:. The implementation now aliases all three reserved message-tool names and restores only identities authenticated by request-scoped metadata.
A post-fix isolated canary used Codex CLI 0.149.1, a source-built proxy on a separate port, temporary OpenCodex and Codex homes, a native gpt-5.5 parent, and a combo/fable child. The child returned the exact marker FABLE_ALIAS_CANARY_20260826. The available account did not advertise gpt-5.6-sol, so this evidence does not claim a GPT-5.6 run. The issue should remain open until PR #2496 is reviewed and merged.
Checks
- I searched existing issues and documentation.
- This request describes a concrete OpenCodex workflow rather than merely naming a desired technology.
- I removed secrets and personal data.
Activity
lidge-jun commentedon Aug 24, 2026
리뷰 · 우선순위 65 / 80
설명: 이 이슈는 실험 기능 요청이다. 작성자는 Sigurd-git 이다. 네이티브 챗지피티 멀티에이전트 브이투 부모가 spawn_agent, send_message, followup_task 를 라우트된 자식에게 맡길 때, 백엔드 암호문이 먼저 생기지 않게 하고 싶다. 설정 칸 하나로만 켜고, 기본값은 꺼짐이다. 이미 있는 암호문을 풀지 않고, 회복 요청도 하지 않고, 92 의 업스트림 한계를 고친다고 말하지 않는다. 후속 구현은 2496 이다. 2496 이 개발 가지에 착지하기 전에는 이 이슈를 닫지 말 것.
지금 CURRENT
devHEAD 는 a60d517 이다. 이번 시간에 origin/dev 는 그대로다. 새 머지는 없다. package.json 은 2.32.0 이다. src/config.ts 는 3238줄이다. src/responses/plaintext-v2-agent-messages.ts 는 지금 HEAD 에 없다. keepNativeChatGptOnV1 과 agentTaskRecovery 는 이미 설정에 있다. 1779 는 라우트된 비 리스폰스 제공자에서 암호화 표시만 뺀다. 이 이슈가 원하는 것은 그와 다르다. 정식 챗지피티 전달 앞에서 예약된 collaboration 스키마를 비예약 이름으로 바꾸고, 응답에서 다시 collaboration 으로 되돌리자는 것이다. 코덱스 0.149.1 은 encrypted_function_args 빈 배열이 있으면 평문 수신을 고른다.이 글은 범위가 좁다. 리스폰스이고 정식 챗지피티이고 기본 브이투 카탈로그일 때만 적용한다. 에이피아이 키 제공자, 라우트된 부모, 브이원 도구, 커스텀 네임스페이스, 이름 충돌은 그대로 둔다. 충돌이나 깨진 본문이나 크기 한계면 실험 길을 쓰지 않는다. 시작 경고와 히스토리 남음도 적혀 있다. 대시보드 칸과 1533 회복 화면은 이번이 아니다. 92 를 다시 열지 말라고 본문이 직접 적었다. 1540 과 1556 과 1533 과 2113 도 대체하지 않는다.
라이브 카나리는 코덱스 0.149.1 과 따로 포트의 소스 프록시로, 네이티브 gpt-5.6-sol 부모가 anthropic/claude-opus-5 자식을 불렀고 자식 마커가 돌아왔다고 한다. 임시 홈을 지웠고 설치된 서비스는 안 건드렸다. 그래도 문서화되지 않은 챗지피티와 코덱스 행동에 기대므로, 다음 업스트림이 바꾸면 또 깨질 수 있다. types.ts 와 config.ts 가르기는 이 이슈 자체와는 무관하다. 구현 풀이 config.ts 와 types/config.ts 를 만진다. 프리뷰 배포가 아니다.
HEAD 부재 src/responses/plaintext-v2-agent-messages.ts - 지금 개발 가지에는 이 파일이 없다. 기능은 아직 안 착지했다
src/types/config.ts keepNativeChatGptOnV1 - 브이원으로 남는 기존 우회다. 이 이슈가 원하는 평문 브이투와는 다른 길이다
src/config.ts agentTaskRecovery - 1540 과 1556 의 암호문 회복이다. 인증과 쿼터와 지연이 있다. 이 이슈는 그 길을 대체하지 말라고 한다
이슈 92 - 업스트림 추적기로 이미 닫혔다. 다시 열지 말 것
이슈 2113 - 신뢰된 암호문 통과다. 이 이슈와 섞지 말 것
이슈 1779 - 라우트된 비 리스폰스 스키마에서 암호화 표시를 뺀다. 정식 챗지피티 전달 예외가 아니다
풀 2496 - 이 이슈의 참조 구현이다. 초안이고 점검 2/4 다. 착지 전에 이 이슈를 닫지 말 것
openai/codex 35845 / 36376 / 37197 - 평문 수신은 있고, 네이티브 부모의 암호문 송신 정책은 아직 없다. 그래서 프록시 쪽 예방 길이 나온 것이다
메인테이너의 판단이 필요한 지점
너의 추천
이 이슈는 연다. 요청이 구체적이고 HEAD 에 구현이 없다. 2496 이 착지한 뒤에만 닫는다. 지금 닫지 말 것. 92 와 1540 과 1556 과 1533 과 2113 은 이 글로 닫지 않는다. 합치지도 말 것. 호출 길을 넓히지 말 것. 프리뷰 배포가 아니다.
이 댓글은 grok-bot이 작성했습니다
Sigurd-git commentedon Aug 26, 2026
The reported plaintext-prevention gap was reproduced and fixed in PR #2496, commit 7fde8eb.
Captured evidence showed
spawn_agent.arguments.messageremained agAAAA…ciphertext after only the namespace and schema marker were changed, leaving the routed Fable task with an emptyPayload:. The implementation now aliases the three reserved message-tool names as well as the namespace and restores them before Codex receives the response.A post-fix isolated
gpt-5.5MultiAgentV2 →combo/fablecanary returned the exact markerFABLE_ALIAS_CANARY_20260826. The available account did not advertisegpt-5.6-sol, so GPT-5.6 still needs a later canary on an entitled account. The issue stays open until PR #2496 is reviewed and merged.github-actions commentedon Sep 1, 2026
Automated translation bookkeeping — detected language: English.
Sigurd-git commentedon Sep 1, 2026
Implementation PR #2496 has been updated to exact head
1a4cb4aabon currentdevbasef84dbf91e.The update makes the 10,000-identity limit fail closed across JSON, SSE, and WebSocket delivery, covers fixed-alias collisions in every request declaration and reference location, restores only aliases generated by the current request, and corrects the English and Simplified Chinese contract for the unset default and canonical ChatGPT forward-only scope.
The rebase conflict in
tests/provider-quota.test.tswas removed by keeping the equivalent expectation already present ondevand skipping the redundant test-only commit. GitHub now reports the PR as mergeable. Exact-head feature, adjacent, capacity, capability, typecheck, privacy, and whitespace checks are recorded in the PR body. The Cross-platform CI and React Doctor runs are waiting for upstream maintainer approval before fork code can execute. This issue remains open until #2496 is reviewed and merged.lidge-jun commentedon Sep 1, 2026
Status after the backlog pass: PR #2496 is closed (see the rationale there) and this issue stays open as the tracking item. The design is still the right shape — opt-in, default off, canonical ChatGPT forward route only, fail-closed identity cap — but it rides on undocumented upstream behavior (reserved-namespace encryption trigger,
encrypted_function_args: []receive path), so it needs a maintainer-owned rebase, an exact-head green cross-platform run, and a security pass on plaintext retention before it can land. Operators who need this today keep the V1 path (keepNativeChatGptOnV1) and the recovery work from #1540/#1556.lidge-jun commentedon Sep 13, 2026
Landed via #4351 at
17da84f89adf0db78852f1f13e7e74c14d5a317e.maintainer adaptation of #2496 (
plaintextV2AgentMessagesopt-in) is now ondev. Tracking issue closes as completed.