fix: make quick start rollback on websocket failure
maintainer edit: stage Quick Start edits on a draft config so declining WebSocket/password setup cannot leave saveable provider defaults behind. Align beginner WebUI docs with the password-protected setup.
This commit is contained in:
@@ -400,7 +400,15 @@ The WebUI ships **inside the published wheel** — no extra build step. It is th
|
||||
Merge this block into your existing config:
|
||||
|
||||
```json
|
||||
{ "channels": { "websocket": { "enabled": true } } }
|
||||
{
|
||||
"channels": {
|
||||
"websocket": {
|
||||
"enabled": true,
|
||||
"tokenIssueSecret": "your-webui-password",
|
||||
"websocketRequiresToken": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**2. Start the gateway**
|
||||
|
||||
+1
-1
@@ -280,7 +280,7 @@ Tell me exactly what changed and whether I need to run /restart.
|
||||
|
||||
Exit interactive mode with `exit`, `quit`, `/exit`, `/quit`, `:q`, or `Ctrl+D`.
|
||||
|
||||
## 6. Choose Your Next Step
|
||||
## 7. Choose Your Next Step
|
||||
|
||||
| Want to... | Go to |
|
||||
|---|---|
|
||||
|
||||
@@ -225,7 +225,9 @@ Merge them into one object:
|
||||
},
|
||||
"channels": {
|
||||
"websocket": {
|
||||
"enabled": true
|
||||
"enabled": true,
|
||||
"tokenIssueSecret": "your-webui-password",
|
||||
"websocketRequiresToken": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -286,13 +288,15 @@ If this is a brand-new install and you have not configured anything else yet, re
|
||||
},
|
||||
"channels": {
|
||||
"websocket": {
|
||||
"enabled": true
|
||||
"enabled": true,
|
||||
"tokenIssueSecret": "your-webui-password",
|
||||
"websocketRequiresToken": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Replace `your-api-key`, `https://api.example.com/v1`, and `model-id-from-your-provider` with values from your provider.
|
||||
Replace `your-api-key`, `https://api.example.com/v1`, `model-id-from-your-provider`, and `your-webui-password` with your own values.
|
||||
|
||||
For copyable provider-specific examples, use [`provider-cookbook.md`](./provider-cookbook.md).
|
||||
|
||||
@@ -316,7 +320,7 @@ Start the local browser UI:
|
||||
nanobot gateway
|
||||
```
|
||||
|
||||
Leave that terminal open, then open `http://127.0.0.1:8765` in your browser. If Quick Start enabled the WebSocket channel, enter the WebUI password you set in the wizard.
|
||||
Leave that terminal open, then open `http://127.0.0.1:8765` in your browser. Enter the WebUI password you set in the wizard or the `tokenIssueSecret` value from your manual config.
|
||||
|
||||
Send this first message in the browser:
|
||||
|
||||
|
||||
@@ -1700,14 +1700,17 @@ def _configure_quick_start(config: Config) -> bool:
|
||||
"Quick Start",
|
||||
"Choose provider endpoint, add credentials and model, then enable the local WebUI channel.",
|
||||
)
|
||||
if not _configure_quick_start_provider(config):
|
||||
draft = config.model_copy(deep=True)
|
||||
if not _configure_quick_start_provider(draft):
|
||||
_pause()
|
||||
return False
|
||||
if not _enable_quick_start_websocket_defaults(config):
|
||||
if not _enable_quick_start_websocket_defaults(draft):
|
||||
_pause()
|
||||
return False
|
||||
_show_quick_start_summary(config)
|
||||
_show_quick_start_summary(draft)
|
||||
_pause("Press Enter to save and exit...")
|
||||
for field_name in type(config).model_fields:
|
||||
setattr(config, field_name, getattr(draft, field_name))
|
||||
return True
|
||||
|
||||
|
||||
|
||||
@@ -983,6 +983,41 @@ class TestMainMenuUpdate:
|
||||
assert websocket["websocketRequiresToken"] is True
|
||||
assert websocket["tokenIssueSecret"] == "webui-secret"
|
||||
|
||||
def test_quick_start_websocket_decline_rolls_back_provider_defaults(self, monkeypatch):
|
||||
"""A failed WebSocket step should not leave saveable Quick Start defaults behind."""
|
||||
config = Config()
|
||||
original = config.model_dump(by_alias=True)
|
||||
|
||||
class FakePrompt:
|
||||
def __init__(self, response):
|
||||
self.response = response
|
||||
|
||||
def ask(self):
|
||||
return self.response
|
||||
|
||||
monkeypatch.setattr(onboard_wizard.console, "clear", lambda: None)
|
||||
monkeypatch.setattr(onboard_wizard.console, "print", lambda *a, **kw: None)
|
||||
monkeypatch.setattr(onboard_wizard, "_show_section_header", lambda *a, **kw: None)
|
||||
monkeypatch.setattr(onboard_wizard, "_show_quick_start_progress", lambda *a, **kw: None)
|
||||
monkeypatch.setattr(onboard_wizard, "_select_with_back", lambda *a, **kw: "DeepSeek")
|
||||
monkeypatch.setattr(onboard_wizard, "_input_text", lambda *a, **kw: "sk-ds-test")
|
||||
monkeypatch.setattr(
|
||||
onboard_wizard,
|
||||
"_input_model_with_autocomplete",
|
||||
lambda *a, **kw: "deepseek-v4-flash",
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
onboard_wizard,
|
||||
"questionary",
|
||||
SimpleNamespace(confirm=lambda *a, **kw: FakePrompt(False)),
|
||||
)
|
||||
monkeypatch.setattr(onboard_wizard, "_pause", lambda message="": None)
|
||||
|
||||
assert onboard_wizard._configure_quick_start(config) is False
|
||||
|
||||
assert config.model_dump(by_alias=True) == original
|
||||
assert getattr(config.channels, "websocket", None) is None
|
||||
|
||||
def test_quick_start_provider_choice_asks_for_model_id(self, monkeypatch):
|
||||
"""Known providers should ask users for the model instead of fetching one."""
|
||||
config = Config()
|
||||
|
||||
Reference in New Issue
Block a user