fix(llm): make gpt-5.x usable through ccproxy Codex OAuth (#324)
* fix(llm): make gpt-5.x usable through ccproxy Codex OAuth
Two independent blockers made current OpenAI models fail when routed
through ccproxy's Codex OAuth endpoint:
1. ccproxy's default Codex model mappings rewrite any gpt-*/o1-*/o3-*/
claude-* model to gpt-5.3-codex before forwarding, silently overriding
the configured model and failing outright on accounts where
gpt-5.3-codex is not served ("The 'gpt-5.3-codex' model is not
supported when using Codex with a ChatGPT account").
start_ccproxy() now generates a config with empty codex model
mappings and passes it via 'ccproxy serve --config'.
2. ccproxy forwards the client's own User-Agent upstream and only
gap-fills its Codex headers, so the backend gates current models on
the client identity ("The '<model>' model requires a newer version
of Codex"). get_chat_model() now sends Codex-CLI-shaped
originator/version/User-Agent headers when the ccproxy Codex adapter
is detected, overridable via EVOSCIENTIST_CODEX_CLIENT_VERSION.
Verified live: gpt-5.5 and gpt-5.4 complete successfully through
ccproxy Codex OAuth on a ChatGPT Plus account with both fixes; each
fails without them.
* fix(ccproxy): harden Codex client routing
* fix(llm): keep Codex client identity consistent
* docs: clarify Codex version floor
* style: ruff format models.py after merge
---------
Co-authored-by: Xi Zhang <106144707+X-iZhang@users.noreply.github.com>
Co-authored-by: X-iZhang <zacharyzhang2022@gmail.com>
This commit is contained in:
committed by
GitHub
parent
da6ca38d53
commit
2b28c46caf
@@ -17,6 +17,7 @@ from EvoScientist.ccproxy_manager import (
|
||||
setup_codex_env,
|
||||
start_ccproxy,
|
||||
stop_ccproxy,
|
||||
write_ccproxy_config,
|
||||
)
|
||||
|
||||
# =============================================================================
|
||||
@@ -168,6 +169,54 @@ class TestStartCcproxy:
|
||||
with pytest.raises(FileNotFoundError):
|
||||
start_ccproxy(8000)
|
||||
|
||||
@patch("EvoScientist.ccproxy_manager.is_ccproxy_running")
|
||||
@patch("subprocess.Popen")
|
||||
def test_passes_generated_config(self, mock_popen, mock_running, tmp_path):
|
||||
proc = MagicMock()
|
||||
proc.poll.return_value = None
|
||||
mock_popen.return_value = proc
|
||||
mock_running.side_effect = [True]
|
||||
|
||||
with patch("EvoScientist.config.get_config_dir", return_value=tmp_path):
|
||||
start_ccproxy(8000)
|
||||
|
||||
cmd = mock_popen.call_args[0][0]
|
||||
assert "--config" in cmd
|
||||
assert cmd[cmd.index("--config") + 1] == str(tmp_path / "ccproxy.toml")
|
||||
|
||||
@patch("EvoScientist.ccproxy_manager.is_ccproxy_running")
|
||||
@patch("EvoScientist.ccproxy_manager.write_ccproxy_config", side_effect=OSError)
|
||||
@patch("subprocess.Popen")
|
||||
def test_config_write_failure_starts_without_config(
|
||||
self, mock_popen, mock_write, mock_running
|
||||
):
|
||||
proc = MagicMock()
|
||||
proc.poll.return_value = None
|
||||
mock_popen.return_value = proc
|
||||
mock_running.side_effect = [True]
|
||||
|
||||
start_ccproxy(8000)
|
||||
|
||||
cmd = mock_popen.call_args[0][0]
|
||||
assert "--config" not in cmd
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# write_ccproxy_config
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class TestWriteCcproxyConfig:
|
||||
def test_writes_codex_mapping_override(self, tmp_path):
|
||||
config_dir = tmp_path / "missing" / "config"
|
||||
with patch("EvoScientist.config.get_config_dir", return_value=config_dir):
|
||||
path = write_ccproxy_config()
|
||||
|
||||
assert path == str(config_dir / "ccproxy.toml")
|
||||
content = (config_dir / "ccproxy.toml").read_text(encoding="utf-8")
|
||||
assert "[plugins.codex]" in content
|
||||
assert "model_mappings = []" in content
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# ensure_ccproxy
|
||||
|
||||
Reference in New Issue
Block a user