Keep quick start channels opt-in

This commit is contained in:
chengyongru
2026-06-22 13:04:05 +08:00
committed by Xubin Ren
parent fc7971b3b6
commit 0097488eed
3 changed files with 36 additions and 18 deletions
+3 -1
View File
@@ -190,13 +190,15 @@ For the first setup, choose `[Q] Quick Start (recommended)`. It asks for the mod
If you are following the OpenRouter example:
1. Choose `[Q] Quick Start (recommended)`.
2. Choose `WebUI only (recommended)` unless you already have a Telegram, Feishu/Lark, Slack, or Discord bot token ready.
2. Choose `No chat channel yet (recommended)` unless you already have a Telegram, Feishu/Lark, Slack, or Discord bot token ready.
3. Select OpenRouter.
4. Paste your OpenRouter API key.
5. Enter a model ID, for example `anthropic/claude-sonnet-4.5`.
6. Review the Quick Start summary.
7. Choose `[S] Save and Exit`.
Enable WebUI later from `[C] Chat Channel` -> `WebSocket` after the first local reply works.
If OpenRouter says your account cannot use that model, use another OpenRouter model ID that your account can access.
If you are using another provider, use the same wizard choices but substitute that provider's values:
+18 -11
View File
@@ -54,7 +54,7 @@ _BACK_PRESSED = object() # Sentinel value for back navigation
_MODEL_PRESET_CACHE: set[str] = set()
_QUICK_START_TARGETS = {
"WebUI only (recommended)": "websocket",
"No chat channel yet (recommended)": None,
"Telegram": "telegram",
"Feishu / Lark": "feishu",
"Slack": "slack",
@@ -414,11 +414,9 @@ 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 configures one AI model first.[/]")
body.add_row(
f"[{_UI_ACCENT}]Quick Start configures a model and enables WebUI by default.[/]"
)
body.add_row(
f"[{_UI_MUTED}]Chat channels and advanced settings stay available when you need them.[/]"
f"[{_UI_MUTED}]WebUI, chat channels, and advanced settings stay available when you need them.[/]"
)
console.print(
Panel(
@@ -1445,13 +1443,21 @@ def _configure_quick_start_channel(config: Config, channel_name: str | None) ->
current = getattr(config.channels, channel_name, None) or {}
model = config_cls.model_validate(current)
if channel_name == "websocket":
console.print("[dim]WebUI uses the built-in local WebSocket channel. No token is needed now.[/dim]")
for field_name, prompt in _QUICK_START_CHANNEL_FIELDS.get(channel_name, ()):
required_fields = _QUICK_START_CHANNEL_FIELDS.get(channel_name, ())
for field_name, prompt in required_fields:
value = _input_with_existing(prompt, getattr(model, field_name, ""), "str")
if value is not None:
setattr(model, field_name, value)
missing = [
prompt
for field_name, prompt in required_fields
if not str(getattr(model, field_name, "") or "").strip()
]
if missing:
console.print(f"[yellow]! {missing[0]} is required; channel was not enabled[/yellow]")
return False
if hasattr(model, "enabled"):
setattr(model, "enabled", True)
setattr(config.channels, channel_name, model.model_dump(by_alias=True, exclude_none=True))
@@ -1465,8 +1471,9 @@ def _show_quick_start_summary(config: Config, channel_name: str | None) -> None:
rows = [
("Provider", preset.provider if preset else "[not set]"),
("Model", preset.model if preset else "[not set]"),
("Entry point", "WebUI" if channel_name in {None, "websocket"} else channel_name),
("Next", "Save, then run `nanobot gateway`"),
("Entry point", "Not enabled yet" if channel_name is None else channel_name),
("Next", "Save, then run `nanobot agent -m \"Hello!\"`"),
("WebUI", "Use [C] Chat Channel -> WebSocket when you are ready"),
]
_print_summary_panel(rows, "Quick Start")
@@ -1482,7 +1489,7 @@ def _configure_quick_start(config: Config) -> None:
answer = _select_with_back(
"How do you want to use nanobot first?",
list(_QUICK_START_TARGETS) + ["<- Back"],
default="WebUI only (recommended)",
default="No chat channel yet (recommended)",
)
if answer is _BACK_PRESSED or answer is None or answer == "<- Back":
return
+15 -6
View File
@@ -926,10 +926,10 @@ class TestMainMenuUpdate:
assert telegram["enabled"] is True
assert telegram["token"] == "123:abc"
def test_quick_start_webui_enables_websocket(self, monkeypatch):
"""The recommended Quick Start target should create a working WebUI channel."""
def test_quick_start_recommended_path_does_not_enable_channel(self, monkeypatch):
"""The recommended Quick Start target should leave chat surfaces as explicit opt-ins."""
config = Config()
selections = iter(["WebUI only (recommended)", "OpenRouter"])
selections = iter(["No chat channel yet (recommended)", "OpenRouter"])
def fake_select_with_back(*_args, **_kwargs):
return next(selections)
@@ -948,9 +948,18 @@ class TestMainMenuUpdate:
onboard_wizard._configure_quick_start(config)
websocket = getattr(config.channels, "websocket")
assert websocket["enabled"] is True
assert websocket["allowFrom"] == ["*"]
assert getattr(config.channels, "websocket", None) is None
assert config.agents.defaults.model_preset == "primary"
def test_quick_start_channel_requires_token_before_enable(self, monkeypatch):
"""Quick Start should not enable token-based channels with blank credentials."""
config = Config()
monkeypatch.setattr(onboard_wizard, "_show_quick_start_progress", lambda *_args: None)
monkeypatch.setattr(onboard_wizard, "_input_with_existing", lambda *a, **kw: "")
assert onboard_wizard._configure_quick_start_channel(config, "telegram") is False
assert getattr(config.channels, "telegram", None) is None
def test_main_menu_dispatch_includes_channel_common(self):
"""Main menu dispatch should route [H] to Channel Common."""