mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-06-15 15:24:06 +00:00
fix(provider): honor NANOBOT_STREAM_IDLE_TIMEOUT_S in Codex provider
Every other streaming provider (anthropic, bedrock, openai_compat, litellm) reads NANOBOT_STREAM_IDLE_TIMEOUT_S with a 90s default. The Codex provider hardcoded 60s in _request_codex, so it could not be tuned the same way and aborted streams sooner than its peers. Read the same env var with the same default and pass it as the httpx client timeout. The variable name and int parsing match anthropic / openai_compat / bedrock verbatim. #4009 normalized the error response when the timeout fires; this PR fixes the timeout knob itself.
This commit is contained in:
parent
1cfc3ef165
commit
ac8bef76f6
@ -5,6 +5,7 @@ from __future__ import annotations
|
|||||||
import asyncio
|
import asyncio
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
|
import os
|
||||||
from collections.abc import Awaitable, Callable
|
from collections.abc import Awaitable, Callable
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
@ -177,7 +178,8 @@ async def _request_codex(
|
|||||||
on_content_delta: Callable[[str], Awaitable[None]] | None = None,
|
on_content_delta: Callable[[str], Awaitable[None]] | None = None,
|
||||||
on_tool_call_delta: Callable[[dict[str, Any]], Awaitable[None]] | None = None,
|
on_tool_call_delta: Callable[[dict[str, Any]], Awaitable[None]] | None = None,
|
||||||
) -> tuple[str, list[ToolCallRequest], str]:
|
) -> tuple[str, list[ToolCallRequest], str]:
|
||||||
async with httpx.AsyncClient(timeout=60.0, verify=verify) as client:
|
idle_timeout_s = int(os.environ.get("NANOBOT_STREAM_IDLE_TIMEOUT_S", "90"))
|
||||||
|
async with httpx.AsyncClient(timeout=idle_timeout_s, verify=verify) as client:
|
||||||
async with client.stream("POST", url, headers=headers, json=body) as response:
|
async with client.stream("POST", url, headers=headers, json=body) as response:
|
||||||
if response.status_code != 200:
|
if response.status_code != 200:
|
||||||
text = await response.aread()
|
text = await response.aread()
|
||||||
|
|||||||
@ -76,8 +76,8 @@ async def test_codex_request_non_200_populates_http_metadata(monkeypatch) -> Non
|
|||||||
request=request,
|
request=request,
|
||||||
)
|
)
|
||||||
|
|
||||||
def fake_client(*, timeout: float, verify: bool) -> httpx.AsyncClient:
|
def fake_client(*, timeout: int, verify: bool) -> httpx.AsyncClient:
|
||||||
assert timeout == 60.0
|
assert timeout == 90
|
||||||
assert verify is True
|
assert verify is True
|
||||||
return original_client(transport=httpx.MockTransport(handler), timeout=timeout)
|
return original_client(transport=httpx.MockTransport(handler), timeout=timeout)
|
||||||
|
|
||||||
@ -95,6 +95,27 @@ async def test_codex_request_non_200_populates_http_metadata(monkeypatch) -> Non
|
|||||||
assert error.should_retry is True
|
assert error.should_retry is True
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_codex_request_honors_stream_idle_timeout_env(monkeypatch) -> None:
|
||||||
|
"""NANOBOT_STREAM_IDLE_TIMEOUT_S overrides the default Codex stream timeout."""
|
||||||
|
monkeypatch.setenv("NANOBOT_STREAM_IDLE_TIMEOUT_S", "5")
|
||||||
|
original_client = httpx.AsyncClient
|
||||||
|
seen: dict[str, int] = {}
|
||||||
|
|
||||||
|
def handler(request: httpx.Request) -> httpx.Response:
|
||||||
|
return httpx.Response(200, request=request)
|
||||||
|
|
||||||
|
def fake_client(*, timeout: int, verify: bool) -> httpx.AsyncClient:
|
||||||
|
seen["timeout"] = timeout
|
||||||
|
return original_client(transport=httpx.MockTransport(handler), timeout=timeout)
|
||||||
|
|
||||||
|
monkeypatch.setattr("nanobot.providers.openai_codex_provider.httpx.AsyncClient", fake_client)
|
||||||
|
|
||||||
|
await _request_codex("https://codex.example/responses", {}, {"input": []}, verify=True)
|
||||||
|
|
||||||
|
assert seen["timeout"] == 5
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_codex_prompt_cache_key_uses_stable_conversation_prefix(monkeypatch) -> None:
|
async def test_codex_prompt_cache_key_uses_stable_conversation_prefix(monkeypatch) -> None:
|
||||||
bodies: list[dict] = []
|
bodies: list[dict] = []
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user