feat(providers): support Codex fast mode
This commit is contained in:
@@ -676,6 +676,25 @@ Then run:
|
||||
nanobot agent -m "Hello!"
|
||||
```
|
||||
|
||||
To opt in to Codex Fast mode, merge this provider setting into `config.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"providers": {
|
||||
"openaiCodex": {
|
||||
"extraBody": {
|
||||
"service_tier": "priority"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`priority` is the Responses API request value used by Codex Fast mode. The setting only works
|
||||
for models and accounts that support Fast mode; remove `service_tier` to return to standard
|
||||
processing. Fast mode consumes Codex credits at a higher rate. See the
|
||||
[OpenAI Codex rate card](https://help.openai.com/en/articles/20001106) for current details.
|
||||
|
||||
For proxy, remote/headless login, model-name, or config-key errors, see [`troubleshooting.md`](./troubleshooting.md#provider-and-model-problems).
|
||||
|
||||
</details>
|
||||
|
||||
@@ -88,6 +88,7 @@ def _make_provider_core(
|
||||
provider = OpenAICodexProvider(
|
||||
default_model=model,
|
||||
proxy=getattr(p, "proxy", None) if p else None,
|
||||
extra_body=p.extra_body if p else None,
|
||||
)
|
||||
elif backend == "azure_openai":
|
||||
from nanobot.providers.azure_openai_provider import AzureOpenAIProvider
|
||||
|
||||
@@ -37,10 +37,12 @@ class OpenAICodexProvider(LLMProvider):
|
||||
self,
|
||||
default_model: str = "openai-codex/gpt-5.6-sol",
|
||||
proxy: str | None = None,
|
||||
extra_body: dict[str, Any] | None = None,
|
||||
):
|
||||
super().__init__(api_key=None, api_base=None)
|
||||
self.default_model = default_model
|
||||
self.proxy = proxy or None
|
||||
self._extra_body = dict(extra_body or {})
|
||||
|
||||
async def _call_codex(
|
||||
self,
|
||||
@@ -74,6 +76,9 @@ class OpenAICodexProvider(LLMProvider):
|
||||
body["reasoning"] = reasoning_options
|
||||
if tools:
|
||||
body["tools"] = convert_tools(tools)
|
||||
if self._extra_body:
|
||||
# Apply explicit provider overrides last, matching other provider backends.
|
||||
body.update(self._extra_body)
|
||||
|
||||
stage = "oauth_token"
|
||||
try:
|
||||
|
||||
@@ -9,6 +9,8 @@ import pytest
|
||||
from loguru import logger
|
||||
|
||||
import nanobot.providers.base as provider_base
|
||||
from nanobot.config.schema import Config
|
||||
from nanobot.providers.factory import make_provider
|
||||
from nanobot.providers.openai_codex_provider import (
|
||||
OpenAICodexProvider,
|
||||
_build_reasoning_options,
|
||||
@@ -220,6 +222,38 @@ async def test_codex_prompt_cache_key_uses_stable_conversation_prefix(monkeypatc
|
||||
|
||||
assert bodies[0]["prompt_cache_key"] == bodies[1]["prompt_cache_key"]
|
||||
assert bodies[0]["prompt_cache_key"] != bodies[2]["prompt_cache_key"]
|
||||
assert all("service_tier" not in body for body in bodies)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_codex_provider_applies_extra_body_from_config(monkeypatch) -> None:
|
||||
bodies: list[dict[str, Any]] = []
|
||||
_mock_codex_token(monkeypatch)
|
||||
|
||||
async def fake_request(_url, _headers, body, **_kwargs):
|
||||
bodies.append(body)
|
||||
return "ok", [], "stop", {}, None
|
||||
|
||||
monkeypatch.setattr("nanobot.providers.openai_codex_provider._request_codex", fake_request)
|
||||
config = Config.model_validate({
|
||||
"agents": {
|
||||
"defaults": {
|
||||
"model": "openai-codex/gpt-5.6-sol",
|
||||
"provider": "openai_codex",
|
||||
},
|
||||
},
|
||||
"providers": {
|
||||
"openaiCodex": {
|
||||
"extraBody": {"service_tier": "priority"},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
provider = make_provider(config)
|
||||
response = await provider.chat([{"role": "user", "content": "hello"}])
|
||||
|
||||
assert response.content == "ok"
|
||||
assert bodies[0]["service_tier"] == "priority"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
||||
Reference in New Issue
Block a user