fix: use deepseek for quick start onboarding
Maintainer edit: restart the Quick Start default around a mainland-friendly provider instead of making OpenRouter the first-run dependency. Update wizard copy, default preset, focused tests, and beginner docs to use DeepSeek with the current deepseek-v4-flash model.
This commit is contained in:
@@ -304,15 +304,15 @@ Skip this step if you already configured provider and model settings in the wiza
|
||||
|
||||
`nanobot onboard --defaults` creates `~/.nanobot/config.json` and `~/.nanobot/workspace/`. Configure these **two parts** in the config file. Add or merge the following blocks into the existing file instead of replacing the whole file.
|
||||
|
||||
The example below uses [OpenRouter](https://openrouter.ai/keys) only so the JSON has concrete names. Provider examples are recipes, not rankings or endorsements. If you use another provider, replace the provider config key, API key, preset provider name, and model ID together.
|
||||
The example below uses [DeepSeek](https://platform.deepseek.com/api_keys) only so the JSON has concrete names and the compact path does not depend on OpenRouter. Provider examples are recipes, not rankings or endorsements. If you use another provider, replace the provider config key, API key, preset provider name, and model ID together.
|
||||
|
||||
*Set your API key*:
|
||||
|
||||
```json
|
||||
{
|
||||
"providers": {
|
||||
"openrouter": {
|
||||
"apiKey": "sk-or-v1-xxx"
|
||||
"deepseek": {
|
||||
"apiKey": "your-deepseek-api-key"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -325,8 +325,8 @@ The example below uses [OpenRouter](https://openrouter.ai/keys) only so the JSON
|
||||
"modelPresets": {
|
||||
"primary": {
|
||||
"label": "Primary",
|
||||
"provider": "openrouter",
|
||||
"model": "anthropic/claude-opus-4.5",
|
||||
"provider": "deepseek",
|
||||
"model": "deepseek-v4-flash",
|
||||
"maxTokens": 8192,
|
||||
"contextWindowTokens": 65536,
|
||||
"temperature": 0.1
|
||||
|
||||
+9
-9
@@ -9,7 +9,7 @@ If you have never used a terminal or edited a config file before, use [`start-wi
|
||||
You need:
|
||||
|
||||
- Python 3.11 or newer.
|
||||
- One LLM provider, company endpoint, subscription endpoint, or local model server you can call. The examples below use OpenRouter only so the snippets are concrete; any supported provider works when the key, provider name, and model ID match.
|
||||
- One LLM provider, company endpoint, subscription endpoint, or local model server you can call. The examples below use DeepSeek only so the snippets are concrete and the compact path does not depend on OpenRouter; any supported provider works when the key, provider name, and model ID match.
|
||||
- Git only if you install from source.
|
||||
- Node.js or Bun only if you are developing the WebUI itself.
|
||||
|
||||
@@ -128,8 +128,8 @@ Open `~/.nanobot/config.json`. Add or merge these blocks into the file created b
|
||||
```json
|
||||
{
|
||||
"providers": {
|
||||
"openrouter": {
|
||||
"apiKey": "sk-or-v1-xxx"
|
||||
"deepseek": {
|
||||
"apiKey": "your-deepseek-api-key"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -142,8 +142,8 @@ Open `~/.nanobot/config.json`. Add or merge these blocks into the file created b
|
||||
"modelPresets": {
|
||||
"primary": {
|
||||
"label": "Primary",
|
||||
"provider": "openrouter",
|
||||
"model": "anthropic/claude-opus-4.5",
|
||||
"provider": "deepseek",
|
||||
"model": "deepseek-v4-flash",
|
||||
"maxTokens": 8192,
|
||||
"contextWindowTokens": 65536,
|
||||
"temperature": 0.1
|
||||
@@ -161,7 +161,7 @@ The provider and model inside a preset must match. The snippet above is only an
|
||||
|
||||
| Replace | Where |
|
||||
|---|---|
|
||||
| Provider config key, such as `openrouter` | `providers.<provider>` |
|
||||
| Provider config key, such as `deepseek` | `providers.<provider>` |
|
||||
| API key or environment variable | `providers.<provider>.apiKey` |
|
||||
| Preset provider name | `modelPresets.primary.provider` |
|
||||
| Model ID | `modelPresets.primary.model` |
|
||||
@@ -207,8 +207,8 @@ If you prefer not to store secrets in `config.json`, reference an environment va
|
||||
```json
|
||||
{
|
||||
"providers": {
|
||||
"openrouter": {
|
||||
"apiKey": "${OPENROUTER_API_KEY}"
|
||||
"deepseek": {
|
||||
"apiKey": "${DEEPSEEK_API_KEY}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -260,7 +260,7 @@ Example prompt:
|
||||
|
||||
```text
|
||||
Read docs/quick-start.md, docs/providers.md, and docs/configuration.md in this checkout.
|
||||
Then update ~/.nanobot/config.json to add an OpenRouter model preset named "primary".
|
||||
Then update ~/.nanobot/config.json to add a DeepSeek model preset named "primary".
|
||||
Tell me exactly what changed and whether I need to run /restart.
|
||||
```
|
||||
|
||||
|
||||
@@ -59,15 +59,15 @@ If `python3` works but `python` does not, replace `python` with `python3` in the
|
||||
|
||||
## 3. Get a Provider API Key
|
||||
|
||||
nanobot does not create AI accounts or API keys for you. Use an AI provider account, company endpoint, subscription endpoint, or local model server that you already control. The steps below use OpenRouter because it is the recommended beginner path in the wizard; it is not a ranking or endorsement.
|
||||
nanobot does not create AI accounts or API keys for you. Use an AI provider account, company endpoint, subscription endpoint, or local model server that you already control. The steps below use DeepSeek because it is the recommended beginner path in the wizard and avoids making OpenRouter a first-run dependency; it is not a ranking or endorsement.
|
||||
|
||||
For the example path:
|
||||
|
||||
1. Open [openrouter.ai/keys](https://openrouter.ai/keys).
|
||||
1. Open [platform.deepseek.com/api_keys](https://platform.deepseek.com/api_keys).
|
||||
2. Create or copy an API key.
|
||||
3. Keep the key private.
|
||||
|
||||
An OpenRouter key usually starts with `sk-or-v1-`. Other providers use different key shapes. Keep the key nearby because the setup wizard will ask you to paste it.
|
||||
Keep the key nearby because the setup wizard will ask you to paste it.
|
||||
|
||||
## 4. Install nanobot
|
||||
|
||||
@@ -167,15 +167,15 @@ Move through the wizard like this:
|
||||
| When you see | Do this |
|
||||
|---|---|
|
||||
| A menu | Use the arrow keys to highlight an option, then press `Enter`. |
|
||||
| The OpenRouter API key field | Paste the key, then press `Enter`. |
|
||||
| The DeepSeek API key field | Paste the key, then press `Enter`. |
|
||||
| A back option in Advanced Settings | Choose it to return to the previous menu. |
|
||||
|
||||
For the first setup, choose `[Q] Quick Start (API key only)`. It configures the recommended local browser UI and default AI settings for you. Use `Advanced Settings` later only if you need a different provider, chat app, or tool setup.
|
||||
|
||||
If you are following the OpenRouter example:
|
||||
If you are following the DeepSeek example:
|
||||
|
||||
1. Choose `[Q] Quick Start (API key only)`.
|
||||
2. Paste your OpenRouter API key.
|
||||
2. Paste your DeepSeek API key.
|
||||
3. Review the Quick Start summary. The wizard saves and exits when Quick Start finishes.
|
||||
|
||||
The recommended path enables the local WebUI and default AI settings. You do not need to choose a model, endpoint, or chat channel for the first run.
|
||||
@@ -211,8 +211,8 @@ Merge them into one object:
|
||||
```json
|
||||
{
|
||||
"providers": {
|
||||
"openrouter": {
|
||||
"apiKey": "sk-or-v1-your-key-here"
|
||||
"deepseek": {
|
||||
"apiKey": "your-deepseek-api-key"
|
||||
}
|
||||
},
|
||||
"channels": {
|
||||
@@ -256,15 +256,15 @@ If this is a brand-new install and you have not configured anything else yet, re
|
||||
```json
|
||||
{
|
||||
"providers": {
|
||||
"openrouter": {
|
||||
"apiKey": "sk-or-v1-your-key-here"
|
||||
"deepseek": {
|
||||
"apiKey": "your-deepseek-api-key"
|
||||
}
|
||||
},
|
||||
"modelPresets": {
|
||||
"primary": {
|
||||
"label": "Primary",
|
||||
"provider": "openrouter",
|
||||
"model": "anthropic/claude-sonnet-4.5",
|
||||
"provider": "deepseek",
|
||||
"model": "deepseek-v4-flash",
|
||||
"maxTokens": 4096,
|
||||
"contextWindowTokens": 65536,
|
||||
"temperature": 0.1
|
||||
@@ -283,9 +283,9 @@ If this is a brand-new install and you have not configured anything else yet, re
|
||||
}
|
||||
```
|
||||
|
||||
Replace `sk-or-v1-your-key-here` with your real OpenRouter key.
|
||||
Replace `your-deepseek-api-key` with your real DeepSeek key.
|
||||
|
||||
If you use another provider, replace `openrouter`, `sk-or-v1-your-key-here`, and the `model` value with that provider's values. If the provider needs `apiBase`, add it under that provider's config block.
|
||||
If you use another provider, replace `deepseek`, `your-deepseek-api-key`, and the `model` value with that provider's values. If the provider needs `apiBase`, add it under that provider's config block.
|
||||
|
||||
Save the file.
|
||||
|
||||
|
||||
@@ -54,8 +54,8 @@ _BACK_PRESSED = object() # Sentinel value for back navigation
|
||||
# offer existing presets as choices (e.g. AgentDefaults.model_preset).
|
||||
_MODEL_PRESET_CACHE: set[str] = set()
|
||||
|
||||
_QUICK_START_RECOMMENDED_PROVIDER = "openrouter"
|
||||
_QUICK_START_RECOMMENDED_MODEL = "anthropic/claude-sonnet-4.5"
|
||||
_QUICK_START_RECOMMENDED_PROVIDER = "deepseek"
|
||||
_QUICK_START_RECOMMENDED_MODEL = "deepseek-v4-flash"
|
||||
|
||||
_QUICK_START_STEPS = ("API key", "WebUI", "Review")
|
||||
|
||||
@@ -388,7 +388,7 @@ def _show_main_menu_header() -> None:
|
||||
body = Table.grid(expand=True)
|
||||
body.add_column(ratio=1)
|
||||
body.add_row(f"{__logo__} [bold {_UI_TEXT}]nanobot[/] [{_UI_MUTED}]v{__version__}[/]")
|
||||
body.add_row(f"[{_UI_ACCENT}]Quick Start only needs an OpenRouter API key.[/]")
|
||||
body.add_row(f"[{_UI_ACCENT}]Quick Start only needs a DeepSeek API key.[/]")
|
||||
body.add_row(
|
||||
f"[{_UI_MUTED}]Use Advanced later for other providers or chat apps.[/]"
|
||||
)
|
||||
@@ -1424,14 +1424,14 @@ def _configure_recommended_provider(config: Config) -> bool:
|
||||
)
|
||||
|
||||
api_key = _input_with_existing(
|
||||
"OpenRouter API key (get one at https://openrouter.ai/keys)",
|
||||
"DeepSeek API key (get one at https://platform.deepseek.com/api_keys)",
|
||||
provider_config.api_key,
|
||||
"str",
|
||||
)
|
||||
if api_key is not None:
|
||||
provider_config.api_key = api_key.strip() or None
|
||||
if not provider_config.api_key:
|
||||
console.print("[yellow]! OpenRouter API key is required for Quick Start[/yellow]")
|
||||
console.print("[yellow]! DeepSeek API key is required for Quick Start[/yellow]")
|
||||
return False
|
||||
if default_api_base and not provider_config.api_base:
|
||||
provider_config.api_base = default_api_base
|
||||
|
||||
@@ -920,7 +920,7 @@ class TestMainMenuUpdate:
|
||||
|
||||
monkeypatch.setattr(onboard_wizard.console, "clear", lambda: None)
|
||||
monkeypatch.setattr(onboard_wizard, "_show_section_header", lambda *a, **kw: None)
|
||||
monkeypatch.setattr(onboard_wizard, "_input_with_existing", lambda *a, **kw: "sk-or-test")
|
||||
monkeypatch.setattr(onboard_wizard, "_input_with_existing", lambda *a, **kw: "sk-ds-test")
|
||||
monkeypatch.setattr(onboard_wizard, "_input_model_with_autocomplete", fail_model_input)
|
||||
monkeypatch.setattr(onboard_wizard, "_configure_pydantic_model", fail_websocket_config)
|
||||
monkeypatch.setattr(onboard_wizard, "_print_summary_panel", lambda *a, **kw: None)
|
||||
@@ -929,10 +929,10 @@ class TestMainMenuUpdate:
|
||||
assert onboard_wizard._configure_quick_start(config) is True
|
||||
|
||||
assert pause_messages == ["Press Enter to save and exit..."]
|
||||
assert config.providers.openrouter.api_key == "sk-or-test"
|
||||
assert config.providers.openrouter.api_base == "https://openrouter.ai/api/v1"
|
||||
assert config.providers.deepseek.api_key == "sk-ds-test"
|
||||
assert config.providers.deepseek.api_base == "https://api.deepseek.com"
|
||||
assert config.agents.defaults.model_preset == "primary"
|
||||
assert config.model_presets["primary"].provider == "openrouter"
|
||||
assert config.model_presets["primary"].provider == "deepseek"
|
||||
assert config.model_presets["primary"].model == onboard_wizard._QUICK_START_RECOMMENDED_MODEL
|
||||
websocket = getattr(config.channels, "websocket")
|
||||
assert websocket["enabled"] is True
|
||||
@@ -947,8 +947,8 @@ class TestMainMenuUpdate:
|
||||
|
||||
assert onboard_wizard._configure_recommended_provider(config) is False
|
||||
|
||||
assert config.providers.openrouter.api_key is None
|
||||
assert config.providers.openrouter.api_base is None
|
||||
assert config.providers.deepseek.api_key is None
|
||||
assert config.providers.deepseek.api_base is None
|
||||
assert "primary" not in config.model_presets
|
||||
|
||||
def test_quick_start_summary_calls_out_missing_api_key(self, monkeypatch):
|
||||
@@ -956,7 +956,7 @@ class TestMainMenuUpdate:
|
||||
config = Config()
|
||||
config.model_presets["primary"] = ModelPresetConfig(
|
||||
model=onboard_wizard._QUICK_START_RECOMMENDED_MODEL,
|
||||
provider="openrouter",
|
||||
provider="deepseek",
|
||||
)
|
||||
|
||||
captured: dict[str, list[tuple[str, str]]] = {}
|
||||
@@ -972,7 +972,7 @@ class TestMainMenuUpdate:
|
||||
|
||||
labels = [label for label, _value in captured["rows"]]
|
||||
rows = dict(captured["rows"])
|
||||
assert rows["Status"] == "OpenRouter API key missing"
|
||||
assert rows["Status"] == "DeepSeek API key missing"
|
||||
assert "API key" in rows["Next"]
|
||||
assert "nanobot gateway" in rows["Next"]
|
||||
assert labels.index("Next") < labels.index("Open")
|
||||
|
||||
Reference in New Issue
Block a user