콘텐츠로 이동

작동 방식

Codex는 정확히 하나의 프로토콜만 사용합니다: OpenAI Responses API(POST /v1/responses, Server-Sent Events). opencodex는 이 요청을 받아 프로바이더의 wire 포맷으로 변환하고, 스트리밍되는 응답을 다시 Responses 이벤트로 변환합니다 — 그래서 Codex는 자신이 OpenAI와 통신하고 있지 않다는 사실을 전혀 알지 못합니다.

┌──────────────────────────── opencodex ────────────────────────────┐
│ │
Codex ──▶ │ parser ──▶ router ──▶ [vision] ──▶ adapter ──▶ provider │ ──▶ Codex
(/v1/ │ │ │ │ │ │ │ (SSE)
responses)│ OcxParsed provider describe buildRequest parseStream │
│ Request +adapter images + fetch AdapterEvent[] │
│ │ │ │
│ [web-search loop] bridge ─▶ SSE │
└─────────────────────────────────────────────────────────────────────┘
  1. Parseresponses/parser.ts가 Zod 스키마(responses/schema.ts)로 요청을 검증하고 이를 내부 OcxParsedRequest로 변환합니다: 시스템 프롬프트, 정규화된 메시지 목록 (텍스트, 이미지, tool call, tool result), tool 정의, 생성 옵션, 그리고 _webSearch(호스팅 웹 검색 요청됨)와 _structuredOutput(JSON 스키마 / JSON-object text.format이 설정됨) 같은 기능 플래그. 이미지는 실제 콘텐츠 파트로 보존되며, 절대 base64 텍스트로 인라인되지 않습니다.

  2. Routerouter.ts가 고정된 우선순위에 따라 요청된 모델 id를 설정된 프로바이더로 매핑합니다: 명시적 provider/model → 프로바이더의 defaultModel → 프로바이더의 models[] → 내장 prefix 패턴(claude-, gpt-, o1-/o3-/o4-, llama-/mixtral-/gemma-) → defaultProvider 폴백. 모델 라우팅을 참고하세요.

  3. Authenticateoauth 프로바이더의 경우, opencodex가 새로 자동 갱신된 access 토큰을 bearer 키로 교체하므로, 기존 adapter들은 변경 없이 인증됩니다.

  4. Vision sidecar(선택) — 라우팅된 모델이 provider.noVisionModels에 나열되어 있고 요청에 이미지가 포함된 경우, opencodex는 ChatGPT 로그인을 통한 gpt-5.4-mini vision 모델로 각 이미지를 설명한 뒤 텍스트로 치환합니다. 덕분에 텍스트 전용 모델도 해당 이미지에 대해 추론할 수 있습니다. Sidecar를 참고하세요.

  5. Passthrough 빠른 경로 — adapter가 패스스루(forward 모드의 openai-responses, 또는 azure)인 경우, 원본 요청 본문이 프로바이더로 그대로 전달되고 응답도 변환 없이 그대로 스트리밍됩니다. 어떤 변환도 일어나지 않습니다.

  6. Web-search sidecar(선택) — Codex가 호스팅 web_search를 활성화했지만 라우팅된 모델이 OpenAI가 아닌 경우, opencodex는 합성 web_search function tool을 노출하고 모델을 작은 에이전트 루프로 실행하면서, ChatGPT 로그인을 통한 gpt-5.4-mini로 실제 검색을 수행해 그 결과를 tool result로 다시 주입합니다.

  7. Adapt — 그 외의 경우, 선택된 adapter의 buildRequest()가 프로바이더의 네이티브 포맷으로 업스트림 HTTP 요청(URL, 헤더, 본문)을 생성하고, opencodex가 이를 fetch합니다.

  8. Bridge — adapter의 parseStream()(또는 parseResponse())이 내부 AdapterEvent를 생성합니다(텍스트, reasoning, tool-call start/delta/end, done, error). bridge.ts는 그 스트림을 다시 Responses SSE 이벤트로 변환합니다 — response.output_text.delta, response.reasoning_summary_text.delta, response.function_call_arguments.delta, response.completed 등 — 그리고 Codex가 이를 소비합니다.

왜 Codex 포크가 아니라 프록시인가?

섹션 제목: “왜 Codex 포크가 아니라 프록시인가?”

Codex는 Responses API를 하드코딩하고 있습니다. opencodex는 프로토콜 경계에서 변환을 수행함으로써 Codex CLI, App, SDK를 변경 없이 그대로 지원하고, Codex 업데이트에도 영향을 받지 않으며, Codex 자체를 건드리지 않고 요청마다 프로바이더를 전환할 수 있게 합니다. 이 변환은 양방향이며 스트리밍에 충실합니다: reasoning 요약, MCP tool 네임스페이스, freeform(apply_patch) tool, tool_search 발견이 모두 정확히 왕복합니다. 이벤트별 매핑은 아키텍처 레퍼런스를 참고하세요.