diff --git a/docs/cli-reference.md b/docs/cli-reference.md index 3056e920..b9a4899e 100644 --- a/docs/cli-reference.md +++ b/docs/cli-reference.md @@ -286,8 +286,8 @@ remain accepted as no-op compatibility aliases. | Command | Description | |---|---| -| `nanobot provider login openai-codex` | Authenticate OpenAI Codex provider | -| `nanobot provider login github-copilot` | Authenticate GitHub Copilot provider | +| `nanobot provider login openai-codex --set-main` | Authenticate Codex and select its current default model | +| `nanobot provider login github-copilot --set-main` | Authenticate GitHub Copilot and select its current default model | | `nanobot provider logout openai-codex` | Remove OpenAI Codex OAuth state | | `nanobot provider logout github-copilot` | Remove GitHub Copilot OAuth state | diff --git a/docs/configuration.md b/docs/configuration.md index cae55e6a..b347e8e2 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -298,7 +298,7 @@ Tracing covers the providers that go through nanobot's OpenAI-compatible client | `ovms` | LLM (local, OpenVINO Model Server) | [docs.openvino.ai](https://docs.openvino.ai/2026/model-server/ovms_docs_llm_quickstart.html) | | `vllm` | LLM (local, any OpenAI-compatible server) | — | | `nvidia` | LLM (NVIDIA NIM) | [build.nvidia.com](https://build.nvidia.com/) | -| `openai_codex` | LLM (Codex, OAuth) | `nanobot provider login openai-codex` | +| `openai_codex` | LLM (Codex, OAuth) | `nanobot provider login openai-codex --set-main` | | `github_copilot` | LLM (GitHub Copilot, OAuth) | `nanobot provider login github-copilot` | | `qianfan` | LLM (Baidu Qianfan) | [cloud.baidu.com](https://cloud.baidu.com/doc/qianfan/s/Hmh4suq26) | @@ -660,61 +660,19 @@ nanobot agent -m "Reply with one short sentence."
OpenAI Codex (OAuth) -Codex uses OAuth instead of API keys. Requires a ChatGPT Plus or Pro account. `nanobot provider login` stores the OAuth session outside config. A `providers.openai_codex` block is optional and is only needed for provider-specific settings such as a proxy. +Codex uses OAuth instead of API keys and requires a ChatGPT Plus or Pro account. Authenticate it and make the current flagship model the active agent model with one command: -**1. Login:** ```bash -nanobot provider login openai-codex +nanobot provider login openai-codex --set-main ``` -If the machine running nanobot cannot open a graphical browser, copy the printed URL into a real browser. For remote SSH login, open the URL locally, then paste the final `http://localhost:1455/auth/callback?...` redirect URL back into the terminal when prompted. +Then run: -**2. Optional proxy** (merge into `~/.nanobot/config.json` if Codex OAuth or Codex API traffic must use a proxy): - -```json -{ - "providers": { - "openai_codex": { - "proxy": "http://127.0.0.1:7890" - } - } -} -``` - -The proxy applies to Codex OAuth token refresh, interactive token exchange, and Codex Responses API requests. It does not affect other providers; configure `proxy` separately on each supported provider that needs it. - -**3. Set model** (merge into `~/.nanobot/config.json`): -```json -{ - "modelPresets": { - "codex": { - "provider": "openai_codex", - "model": "gpt-5.1-codex", - "reasoningEffort": "high" - } - }, - "agents": { - "defaults": { - "modelPreset": "codex" - } - } -} -``` - -Use `reasoningEffort` in the preset to send a Codex reasoning effort such as `"low"`, `"medium"`, `"high"`, or another value supported by the selected model. When `provider` is explicitly `openai_codex`, the model name does not need the `openai-codex/` prefix. - -**4. Chat:** ```bash nanobot agent -m "Hello!" - -# Target a specific workspace/config locally -nanobot agent -c ~/.nanobot-telegram/config.json -m "Hello!" - -# One-off workspace override on top of that config -nanobot agent -c ~/.nanobot-telegram/config.json -w /tmp/nanobot-telegram-test -m "Hello!" ``` -> Docker users: use `docker run -it` for interactive OAuth login. +For proxy, remote/headless login, model-name, or config-key errors, see [`troubleshooting.md`](./troubleshooting.md#provider-and-model-problems).
diff --git a/docs/providers.md b/docs/providers.md index 028d92b2..141b7e5c 100644 --- a/docs/providers.md +++ b/docs/providers.md @@ -418,38 +418,19 @@ See [`configuration.md#providers`](./configuration.md#providers) for Bedrock-spe Some providers do not use API keys in `config.json`. +For OpenAI Codex: + ```bash -nanobot provider login openai-codex -nanobot provider login github-copilot +nanobot provider login openai-codex --set-main ``` -Then explicitly select the provider and model in a preset. OAuth providers are not valid automatic fallbacks. +For GitHub Copilot: -For OpenAI Codex, add `providers.openai_codex.proxy` only when Codex OAuth/token refresh or Codex API requests must use a proxy: - -```json -{ - "providers": { - "openai_codex": { - "proxy": "http://127.0.0.1:7890" - } - }, - "modelPresets": { - "codex": { - "provider": "openai_codex", - "model": "gpt-5.1-codex", - "reasoningEffort": "high" - } - }, - "agents": { - "defaults": { - "modelPreset": "codex" - } - } -} +```bash +nanobot provider login github-copilot --set-main ``` -If you run the login command on a remote/headless machine and open the authorization URL in a local browser, paste the final `http://localhost:1455/auth/callback?...` redirect URL back into the terminal when prompted. See [`configuration.md#providers`](./configuration.md#providers) for the full OAuth provider notes. +Each command authenticates the selected provider and makes its current default model active. OAuth providers are not valid automatic fallbacks. See [`troubleshooting.md`](./troubleshooting.md#provider-and-model-problems) for proxy, headless-login, model-name, and config-key errors. ## Provider Resolution diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 70b940e8..ba89dadc 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -135,7 +135,12 @@ If you need a known-good snippet instead of diagnosis, use [`provider-cookbook.m | Provider cannot be inferred | Pin `modelPresets..provider` in the active preset instead of using `"auto"`. For legacy direct configs, pin `agents.defaults.provider`. | | Local model connection refused | Ollama, vLLM, LM Studio, or another local server is not running, or `apiBase` points to the wrong port. | | Bedrock validation error | Check AWS region, credentials, model access, model ID, and whether the model supports Converse. | -| OAuth provider fails | Run `nanobot provider login openai-codex` or `nanobot provider login github-copilot`, then select the provider explicitly. | +| OAuth provider fails | Run `nanobot provider login openai-codex --set-main` or `nanobot provider login github-copilot --set-main`. | +| Codex OAuth needs a proxy | Set `providers.openaiCodex.proxy` before running the login command. The proxy applies to login, token refresh, and Codex API requests. | +| Codex login runs on a remote/headless machine | Open the printed URL in a local browser, then paste the final `http://localhost:1455/auth/callback?...` URL back into the terminal. | +| Codex login runs in Docker | Start the container with `docker run -it` so the OAuth flow has an interactive terminal. | +| Codex says a model is not supported with a ChatGPT account | Use provider `openai_codex` with a Codex model such as `openai-codex/gpt-5.6-sol`. Do not use the direct-API `openai/...` prefix with Codex OAuth. | +| Config says `providers.openai_codex` conflicts with the built-in provider | Under `providers`, keep only the canonical `openaiCodex` settings key and remove a duplicate `openai_codex` key. A model preset's `provider` value remains `openai_codex`. | ## Langfuse Problems diff --git a/nanobot/cli/commands.py b/nanobot/cli/commands.py index 9c3609df..5900d7e4 100644 --- a/nanobot/cli/commands.py +++ b/nanobot/cli/commands.py @@ -2646,7 +2646,7 @@ _PROVIDER_DISPLAY: dict[str, str] = { } _OAUTH_PROVIDER_DEFAULT_MODELS: dict[str, str] = { - "openai_codex": "openai-codex/gpt-5.4-mini", + "openai_codex": "openai-codex/gpt-5.6-sol", "github_copilot": "github-copilot/gpt-5.4-mini", } diff --git a/nanobot/providers/openai_codex_provider.py b/nanobot/providers/openai_codex_provider.py index b544bad4..a89e3cac 100644 --- a/nanobot/providers/openai_codex_provider.py +++ b/nanobot/providers/openai_codex_provider.py @@ -35,7 +35,7 @@ class OpenAICodexProvider(LLMProvider): def __init__( self, - default_model: str = "openai-codex/gpt-5.1-codex", + default_model: str = "openai-codex/gpt-5.6-sol", proxy: str | None = None, ): super().__init__(api_key=None, api_base=None) diff --git a/tests/cli/test_commands.py b/tests/cli/test_commands.py index dce93986..0ec0b582 100644 --- a/tests/cli/test_commands.py +++ b/tests/cli/test_commands.py @@ -450,11 +450,21 @@ def test_config_matches_github_copilot_codex_with_hyphen_prefix(): def test_config_matches_openai_codex_with_hyphen_prefix(): config = Config() - config.agents.defaults.model = "openai-codex/gpt-5.1-codex" + config.agents.defaults.model = "openai-codex/gpt-5.6-sol" assert config.get_provider_name() == "openai_codex" +def test_openai_codex_oauth_default_matches_curated_flagship(): + spec = find_by_name("openai_codex") + + assert spec is not None + assert spec.builtin_models + assert cli_commands._OAUTH_PROVIDER_DEFAULT_MODELS["openai_codex"] == ( + spec.builtin_models[0].id + ) + + def test_config_dump_excludes_oauth_provider_blocks(): config = Config() @@ -605,7 +615,7 @@ def test_provider_login_can_set_openai_codex_as_main_provider(tmp_path): saved = Config.model_validate(json.loads(config_path.read_text(encoding="utf-8"))) assert saved.agents.defaults.provider == "openai_codex" - assert saved.agents.defaults.model == "openai-codex/gpt-5.4-mini" + assert saved.agents.defaults.model == "openai-codex/gpt-5.6-sol" assert saved.agents.defaults.model_preset is None assert make_provider(saved).__class__.__name__ == "OpenAICodexProvider" @@ -1071,8 +1081,8 @@ async def test_github_copilot_provider_refreshes_client_api_key_before_chat(): def test_openai_codex_strip_prefix_supports_hyphen_and_underscore(): - assert _strip_model_prefix("openai-codex/gpt-5.1-codex") == "gpt-5.1-codex" - assert _strip_model_prefix("openai_codex/gpt-5.1-codex") == "gpt-5.1-codex" + assert _strip_model_prefix("openai-codex/gpt-5.6-sol") == "gpt-5.6-sol" + assert _strip_model_prefix("openai_codex/gpt-5.6-sol") == "gpt-5.6-sol" def test_make_provider_passes_extra_headers_to_custom_provider(): diff --git a/tests/providers/test_openai_codex_provider.py b/tests/providers/test_openai_codex_provider.py index 8cba9df0..560b25e7 100644 --- a/tests/providers/test_openai_codex_provider.py +++ b/tests/providers/test_openai_codex_provider.py @@ -18,6 +18,7 @@ from nanobot.providers.openai_codex_provider import ( _request_codex, _should_retry_status, ) +from nanobot.providers.registry import find_by_name def _mock_codex_token(monkeypatch: pytest.MonkeyPatch) -> None: @@ -30,6 +31,14 @@ def _mock_codex_token(monkeypatch: pytest.MonkeyPatch) -> None: ) +def test_codex_default_model_matches_curated_flagship() -> None: + spec = find_by_name("openai_codex") + + assert spec is not None + assert spec.builtin_models + assert OpenAICodexProvider().get_default_model() == spec.builtin_models[0].id + + class _WarningCaptureLogger: def __init__(self) -> None: self.calls: list[tuple[str, tuple[Any, ...]]] = [] diff --git a/tests/webui/test_settings_api.py b/tests/webui/test_settings_api.py index 3e91ca30..299b4af2 100644 --- a/tests/webui/test_settings_api.py +++ b/tests/webui/test_settings_api.py @@ -1220,7 +1220,7 @@ def test_create_model_configuration_accepts_configured_oauth_provider( { "label": ["Codex"], "provider": ["openai_codex"], - "model": ["openai-codex/gpt-5.1-codex"], + "model": ["openai-codex/gpt-5.6-sol"], } )