fix: Codex 反代添加 chatgpt-account-id 请求头

通过 contextvars 将 OAuth 认证配置中的 account_id 从 wrap_request()传递到 extra_headers(),修复实际请求时缺少 chatgpt-account-id 头导致的错误。
This commit is contained in:
AAEE86
2026-02-08 23:51:50 +08:00
committed by fawney19
parent b34dd12863
commit 3153c60291
2 changed files with 67 additions and 2 deletions

View File

@@ -0,0 +1,44 @@
"""Codex request context using contextvars.
Similar to Kiro's context pattern, this bridges data from `CodexOAuthEnvelope.wrap_request()`
(which receives the decrypted auth_config) to `extra_headers()` which is parameterless.
"""
from __future__ import annotations
import contextvars
from dataclasses import dataclass
@dataclass(frozen=True, slots=True)
class CodexRequestContext:
"""Per-request context for the Codex adapter.
This bridges data from `CodexOAuthEnvelope.wrap_request()` (which receives the
decrypted auth_config) to other layers that only expose parameterless hooks
(extra_headers).
"""
account_id: str | None = None
user_id: str | None = None
_codex_request_context: contextvars.ContextVar[CodexRequestContext | None] = contextvars.ContextVar(
"codex_request_context",
default=None,
)
def set_codex_request_context(ctx: CodexRequestContext | None) -> None:
_codex_request_context.set(ctx)
def get_codex_request_context() -> CodexRequestContext | None:
return _codex_request_context.get()
__all__ = [
"CodexRequestContext",
"get_codex_request_context",
"set_codex_request_context",
]

View File

@@ -7,6 +7,9 @@ to avoid upstream blocks (Cloudflare, etc.).
Request/response shape quirks should live in the conversion layer as a same-format
variant (`target_variant="codex"` in the `openai:cli` normalizer). This envelope
only adds headers and keeps the rest as a no-op wrapper.
We use contextvars to pass request-scoped values (account_id) from wrap_request()
to extra_headers().
"""
from __future__ import annotations
@@ -15,6 +18,11 @@ import uuid
from typing import Any
from src.config.settings import config
from src.services.provider.adapters.codex.context import (
CodexRequestContext,
get_codex_request_context,
set_codex_request_context,
)
from src.services.provider.request_context import get_selected_base_url
@@ -38,18 +46,31 @@ class CodexOAuthEnvelope:
if ua:
headers["User-Agent"] = ua
# Add chatgpt-account-id from context (set by wrap_request)
ctx = get_codex_request_context()
if ctx and ctx.account_id:
headers["chatgpt-account-id"] = ctx.account_id
return headers
def wrap_request(
self,
request_body: dict[str, Any],
*,
model: str,
model: str, # noqa: ARG002
url_model: str | None,
decrypted_auth_config: dict[str, Any] | None,
) -> tuple[dict[str, Any], str | None]:
# Extract account_id from auth_config and set context for extra_headers()
account_id = (decrypted_auth_config or {}).get("account_id")
user_id = (decrypted_auth_config or {}).get("user_id")
set_codex_request_context(
CodexRequestContext(
account_id=str(account_id) if account_id else None,
user_id=str(user_id) if user_id else None,
)
)
# No wire envelope for Codex; keep request body as-is.
_ = model, decrypted_auth_config
return request_body, url_model
def unwrap_response(self, data: Any) -> Any: