mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
0db49a7e6a
## Why
`AppServerConfig` is exported as part of the ergonomic Python SDK
surface and passed to `Codex(...)` and `AsyncCodex(...)`. That name
exposes the underlying app-server transport at the same layer where
users are configuring the Codex client. `CodexConfig` makes the common
callsite read naturally and names the object it configures.
## What changed
- Renamed the public configuration dataclass from `AppServerConfig` to
`CodexConfig`.
- Updated `Codex`, `AsyncCodex`, and the transport clients to accept
`CodexConfig`.
- Updated binary-resolution messages, package exports, docs, examples,
and related coverage to use the new public name.
## API impact
```python
from openai_codex import Codex, CodexConfig
with Codex(config=CodexConfig(codex_bin="/path/to/codex")) as codex:
...
```
Callers should now import and construct `CodexConfig`; `AppServerConfig`
is no longer part of the Python SDK surface.
## Validation
- `uv run --frozen --extra dev ruff check src/openai_codex scripts
examples tests`
- Tests are deferred to online CI for this PR.
91 lines
3.3 KiB
Python
91 lines
3.3 KiB
Python
from __future__ import annotations
|
|
|
|
import base64
|
|
import json
|
|
|
|
from app_server_harness import AppServerHarness
|
|
|
|
from openai_codex import Codex, CodexConfig
|
|
from openai_codex.generated.v2_all import (
|
|
ChatgptAuthTokensLoginAccountParams,
|
|
LoginAccountParams,
|
|
)
|
|
|
|
|
|
def _app_server_config(harness: AppServerHarness) -> CodexConfig:
|
|
"""Build an isolated login config without inheriting ambient API-key auth."""
|
|
config = harness.app_server_config()
|
|
config.env = {**(config.env or {}), "OPENAI_API_KEY": ""}
|
|
return config
|
|
|
|
|
|
def test_api_key_login_authenticates_follow_up_model_requests(tmp_path) -> None:
|
|
"""API-key login should authorize the next Responses request with that key."""
|
|
with AppServerHarness(tmp_path, requires_openai_auth=True) as harness:
|
|
harness.responses.enqueue_assistant_message("api key auth", response_id="api-key-auth")
|
|
|
|
with Codex(config=_app_server_config(harness)) as codex:
|
|
codex.login_api_key("sk-sdk-login-test")
|
|
result = codex.thread_start().run("prove api key auth")
|
|
request = harness.responses.single_request()
|
|
|
|
assert {
|
|
"final_response": result.final_response,
|
|
"authorization": request.header("authorization"),
|
|
} == {
|
|
"final_response": "api key auth",
|
|
"authorization": "Bearer sk-sdk-login-test",
|
|
}
|
|
|
|
|
|
def test_chatgpt_token_login_authenticates_follow_up_model_requests(tmp_path) -> None:
|
|
"""ChatGPT token handoff should authorize later Responses requests with that token."""
|
|
account_id = "workspace-sdk-chatgpt"
|
|
|
|
def _encode(payload: dict[str, object]) -> str:
|
|
raw = json.dumps(payload, separators=(",", ":"), sort_keys=True).encode("utf-8")
|
|
return base64.urlsafe_b64encode(raw).rstrip(b"=").decode("ascii")
|
|
|
|
# App-server parses claims from the access token before persisting external ChatGPT auth.
|
|
header = _encode({"alg": "none", "typ": "JWT"})
|
|
claims = _encode(
|
|
{
|
|
"email": "sdk-chatgpt@example.com",
|
|
"https://api.openai.com/auth": {
|
|
"chatgpt_account_id": account_id,
|
|
"chatgpt_plan_type": "pro",
|
|
},
|
|
}
|
|
)
|
|
access_token = f"{header}.{claims}.sig"
|
|
|
|
with AppServerHarness(tmp_path, requires_openai_auth=True) as harness:
|
|
harness.responses.enqueue_assistant_message(
|
|
"chatgpt token auth",
|
|
response_id="chatgpt-token-auth",
|
|
)
|
|
|
|
with Codex(config=_app_server_config(harness)) as codex:
|
|
login = codex._client.account_login_start(
|
|
LoginAccountParams(
|
|
root=ChatgptAuthTokensLoginAccountParams(
|
|
access_token=access_token,
|
|
chatgpt_account_id=account_id,
|
|
chatgpt_plan_type="pro",
|
|
type="chatgptAuthTokens",
|
|
)
|
|
)
|
|
)
|
|
result = codex.thread_start().run("prove chatgpt token auth")
|
|
request = harness.responses.single_request()
|
|
|
|
assert {
|
|
"login_type": login.root.type,
|
|
"final_response": result.final_response,
|
|
"authorization": request.header("authorization"),
|
|
} == {
|
|
"login_type": "chatgptAuthTokens",
|
|
"final_response": "chatgpt token auth",
|
|
"authorization": f"Bearer {access_token}",
|
|
}
|