fix(providers): honor Codex proxy config consistently

This commit is contained in:
chengyongru
2026-07-15 20:01:48 +08:00
committed by chengyongru
parent ba86dccc8d
commit 681edfa6f3
6 changed files with 145 additions and 3 deletions
+46
View File
@@ -711,6 +711,52 @@ def test_provider_login_openai_codex_passes_configured_proxy(monkeypatch):
assert captured["proxy"] == proxy
def test_provider_login_openai_codex_uses_explicit_config_proxy(tmp_path, monkeypatch):
from nanobot.config import loader
proxy = "http://127.0.0.1:23458"
config_path = tmp_path / "config.json"
config_path.write_text(
json.dumps({"providers": {"openaiCodex": {"proxy": proxy}}}),
encoding="utf-8",
)
active_path: dict[str, Path] = {}
real_load_config = loader.load_config
def fake_set_config_path(path: Path) -> None:
active_path["path"] = path
def fake_load_config(config_path: Path | None = None) -> Config:
path = config_path or active_path.get("path")
if path is None:
return Config.model_validate(
{"providers": {"openaiCodex": {"proxy": "http://default-proxy:8080"}}}
)
return real_load_config(path)
monkeypatch.setattr(loader, "set_config_path", fake_set_config_path)
monkeypatch.setattr(loader, "load_config", fake_load_config)
import oauth_cli_kit
captured: dict[str, str | None] = {}
def fake_get_token(*, proxy=None):
captured["proxy"] = proxy
return SimpleNamespace(access="access-token", account_id="acct-test")
monkeypatch.setattr(oauth_cli_kit, "get_token", fake_get_token)
result = runner.invoke(
app,
["provider", "login", "openai-codex", "--config", str(config_path)],
)
assert result.exit_code == 0
assert active_path["path"] == config_path.resolve()
assert captured["proxy"] == proxy
def test_provider_login_openai_codex_resolves_proxy_env_ref(monkeypatch):
proxy = "http://127.0.0.1:23458"
monkeypatch.setenv("CODEX_PROXY_FOR_TEST", proxy)
+55
View File
@@ -1181,6 +1181,61 @@ async def test_codex_payload_and_response(monkeypatch) -> None:
assert body["stream"] is True
@pytest.mark.asyncio
async def test_codex_proxy_applies_to_oauth_and_http(monkeypatch) -> None:
import sys
from types import SimpleNamespace
proxy = "http://127.0.0.1:23458"
captured: dict[str, Any] = {}
async def fake_to_thread(fn, *args, **kwargs):
return fn(*args, **kwargs)
def fake_get_token(*, proxy=None):
captured["token_proxy"] = proxy
return SimpleNamespace(account_id="acct-123", access="oauth-token")
fake_oauth = SimpleNamespace(get_token=fake_get_token)
monkeypatch.setattr("asyncio.to_thread", fake_to_thread)
monkeypatch.setitem(sys.modules, "oauth_cli_kit", fake_oauth)
class FakeAsyncClient:
def __init__(self, **kwargs: Any) -> None:
captured["client_kwargs"] = kwargs
async def __aenter__(self):
return self
async def __aexit__(self, exc_type, exc, tb) -> None:
return None
async def post(self, url: str, **kwargs: Any) -> FakeResponse:
captured["request"] = {"url": url, **kwargs}
return FakeResponse(
{},
sse_lines=[
f'data: {{"type":"response.output_item.done","item":{{"type":"image_generation_call","result":"{PNG_DATA_URL}"}}}}',
"",
"data: [DONE]",
"",
],
)
monkeypatch.setattr(
"nanobot.providers.image_generation.httpx.AsyncClient",
FakeAsyncClient,
)
client = CodexImageGenerationClient(api_key=None, proxy=proxy)
response = await client.generate(prompt="draw", model="gpt-5.4")
assert response.images == [PNG_DATA_URL]
assert captured["token_proxy"] == proxy
assert captured["client_kwargs"]["proxy"] == proxy
assert captured["client_kwargs"]["trust_env"] is False
@pytest.mark.asyncio
async def test_codex_stops_reading_after_completed_event(monkeypatch) -> None:
import sys
+26
View File
@@ -125,6 +125,32 @@ async def test_generate_image_tool_selects_aihubmix_provider(
assert fake.calls[0]["aspect_ratio"] == "3:4"
def test_image_generation_tool_passes_provider_proxy_to_client(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
FakeImageClient.instances = []
monkeypatch.setattr(
"nanobot.agent.tools.image_generation.get_image_gen_provider",
lambda name: FakeImageClient if name == "openai_codex" else None,
)
proxy = "http://127.0.0.1:23458"
tool = ImageGenerationTool(
workspace=tmp_path,
config=ImageGenerationToolConfig(
enabled=True,
provider="openai_codex",
model="openai-codex/gpt-5.4",
),
provider_configs={"openai_codex": ProviderConfig(proxy=proxy)},
)
client = tool._provider_client()
assert client is not None
assert FakeImageClient.instances[0].kwargs["proxy"] == proxy
@pytest.mark.asyncio
async def test_generate_image_tool_reports_missing_aihubmix_key(tmp_path: Path) -> None:
tool = ImageGenerationTool(