refactor(providers): hide oauth-only providers from config setup

Exclude openai_codex alongside github_copilot from generated config,
filter OAuth-only providers out of the onboarding wizard, and clarify in
README that OAuth login stores session state outside config. Also unify
the GitHub Copilot login command spelling and add regression tests.

Made-with: Cursor
This commit is contained in:
Xubin Ren
2026-03-20 19:19:02 +00:00
committed by Xubin Ren
parent e029d52e70
commit 32f4e60145
5 changed files with 18 additions and 4 deletions

View File

@@ -811,6 +811,7 @@ Config file: `~/.nanobot/config.json`
<summary><b>OpenAI Codex (OAuth)</b></summary> <summary><b>OpenAI Codex (OAuth)</b></summary>
Codex uses OAuth instead of API keys. Requires a ChatGPT Plus or Pro account. Codex uses OAuth instead of API keys. Requires a ChatGPT Plus or Pro account.
No `providers.openaiCodex` block is needed in `config.json`; `nanobot provider login` stores the OAuth session outside config.
**1. Login:** **1. Login:**
```bash ```bash
@@ -845,13 +846,14 @@ nanobot agent -c ~/.nanobot-telegram/config.json -w /tmp/nanobot-telegram-test -
<details> <details>
<summary><b>Github Copilot (OAuth)</b></summary> <summary><b>GitHub Copilot (OAuth)</b></summary>
Github Copilot uses OAuth instead of API keys. Requires a [Github account with a plan](https://github.com/features/copilot/plans) configured. GitHub Copilot uses OAuth instead of API keys. Requires a [GitHub account with a plan](https://github.com/features/copilot/plans) configured.
No `providers.githubCopilot` block is needed in `config.json`; `nanobot provider login` stores the OAuth session outside config.
**1. Login:** **1. Login:**
```bash ```bash
nanobot provider login github_copilot nanobot provider login github-copilot
``` ```
**2. Set model** (merge into `~/.nanobot/config.json`): **2. Set model** (merge into `~/.nanobot/config.json`):

View File

@@ -664,6 +664,7 @@ def _get_provider_info() -> dict[str, tuple[str, bool, bool, str]]:
spec.default_api_base, spec.default_api_base,
) )
for spec in PROVIDERS for spec in PROVIDERS
if not spec.is_oauth
} }

View File

@@ -78,7 +78,7 @@ class ProvidersConfig(Base):
volcengine_coding_plan: ProviderConfig = Field(default_factory=ProviderConfig) # VolcEngine Coding Plan volcengine_coding_plan: ProviderConfig = Field(default_factory=ProviderConfig) # VolcEngine Coding Plan
byteplus: ProviderConfig = Field(default_factory=ProviderConfig) # BytePlus (VolcEngine international) byteplus: ProviderConfig = Field(default_factory=ProviderConfig) # BytePlus (VolcEngine international)
byteplus_coding_plan: ProviderConfig = Field(default_factory=ProviderConfig) # BytePlus Coding Plan byteplus_coding_plan: ProviderConfig = Field(default_factory=ProviderConfig) # BytePlus Coding Plan
openai_codex: ProviderConfig = Field(default_factory=ProviderConfig) # OpenAI Codex (OAuth) openai_codex: ProviderConfig = Field(default_factory=ProviderConfig, exclude=True) # OpenAI Codex (OAuth)
github_copilot: ProviderConfig = Field(default_factory=ProviderConfig, exclude=True) # Github Copilot (OAuth) github_copilot: ProviderConfig = Field(default_factory=ProviderConfig, exclude=True) # Github Copilot (OAuth)

View File

@@ -213,6 +213,15 @@ def test_config_matches_openai_codex_with_hyphen_prefix():
assert config.get_provider_name() == "openai_codex" assert config.get_provider_name() == "openai_codex"
def test_config_dump_excludes_oauth_provider_blocks():
config = Config()
providers = config.model_dump(by_alias=True)["providers"]
assert "openaiCodex" not in providers
assert "githubCopilot" not in providers
def test_config_matches_explicit_ollama_prefix_without_api_key(): def test_config_matches_explicit_ollama_prefix_without_api_key():
config = Config() config = Config()
config.agents.defaults.model = "ollama/llama3.2" config.agents.defaults.model = "ollama/llama3.2"

View File

@@ -359,6 +359,8 @@ class TestProviderChannelInfo:
assert len(names) > 0 assert len(names) > 0
# Should include common providers # Should include common providers
assert "openai" in names or "anthropic" in names assert "openai" in names or "anthropic" in names
assert "openai_codex" not in names
assert "github_copilot" not in names
def test_get_channel_names_returns_dict(self): def test_get_channel_names_returns_dict(self):
from nanobot.cli.onboard_wizard import _get_channel_names from nanobot.cli.onboard_wizard import _get_channel_names