背景
在之前的文章中Nanobot 轻量级的个人AI助手,我们提到了两个命令
一个是nanobot onboard,另一个是nanobot gateway,
从整理上来看,该 nanobot用到了Typer,Rich,Questionary,prompt_toolkit这种现代、美观且交互式命令行界面 (CLI) 的强大工具组合。
Typer 用于定义 CLI 结构和参数;Rich 负责文本样式、表格、面板和 Markdown 渲染;Questionary 用于创建交互式问答界面
其中 Rich中的Console,Markdown,Table,Text用来进行渲染,支持颜色、表格、面板、语法高亮和 Markdown ,以更好的进行个性化的展示。
nanobot onboard命令
onboard 是 Typer 子命令,用于 首次或再次初始化 nanobot:处理配置文件路径、创建/更新 config.json、可选交互向导、合并channel插件默认配置、创建工作区并同步模板,最后打印下一步提示。
@app.command()
def onboard(
workspace: str | None = typer.Option(None, "--workspace", "-w", help="Workspace directory"),
config: str | None = typer.Option(None, "--config", "-c", help="Path to config file"),
wizard: bool = typer.Option(False, "--wizard", help="Use interactive wizard"),
):
"""Initialize nanobot configuration and workspace."""
...
| 参数 | 说明 |
|---|---|
-c / --config |
指定配置文件路径;若给出,会调用 set_config_path,后续读写均针对该文件。 |
-w / --workspace |
覆盖配置中的 agents.defaults.workspace(在内存中的 Config 上生效,保存时写入)。 |
--wizard |
启用交互式向导(nanobot.cli.onboard.run_onboard),由向导决定是否保存。 |
- 第一步便是配置文件的路径,如果指定了--config,就从这里进行查找,否则默认为
~/.nanbot/.config.json:
python
if config:
config_path = Path(config).expanduser().resolve()
set_config_path(config_path)
console.print(f"[dim]Using config: {config_path}[/dim]")
else:
config_path = get_config_path()
- 创建或者更新
config.json文件
-
配置文件已存在
- 如果是wizard: 只 load_config + 工作区覆盖,不在这里做覆盖/刷新的交互;后面交给向导统一保存。
- 非 wizard:
提示:已存在,用typer.confirm("Overwrite?")问是否 Overwrite。
确认覆盖:Config() 全新默认 + 工作区覆盖 → save_config,相当于重置为默认。
不覆盖:load_config + 工作区覆盖 → save_config,保留已有字段值,同时用 save_config 把结构写回到config路径下。
-
配置文件不存在
Config() 默认 + 工作区覆盖。
非 wizard:立刻 save_config
wizard:先不保存,等向导结束再决定是否写盘。
注意这里json配置转换为python Config配置用到了
pydantic 的 BaseSettings Field(default_factory=...)以及model_validate用于将数据(如字典)转换并验证为模型实例的方法。
python
if config_path.exists():
if wizard:
config = _apply_workspace_override(load_config(config_path))
else:
console.print(f"[yellow]Config already exists at {config_path}[/yellow]")
console.print(" [bold]y[/bold] = overwrite with defaults (existing values will be lost)")
console.print(" [bold]N[/bold] = refresh config, keeping existing values and adding new fields")
if typer.confirm("Overwrite?"):
config = _apply_workspace_override(Config())
save_config(config, config_path)
console.print(f"[green]✓[/green] Config reset to defaults at {config_path}")
else:
config = _apply_workspace_override(load_config(config_path))
save_config(config, config_path)
console.print(f"[green]✓[/green] Config refreshed at {config_path} (existing values preserved)")
else:
config = _apply_workspace_override(Config())
# In wizard mode, don't save yet - the wizard will handle saving if should_save=True
if not wizard:
save_config(config, config_path)
console.print(f"[green]✓[/green] Created config at {config_path}")
- 进行向导式的配置
如果配置了进行了向导式的操作,则利用questionary包进行引导式的操作,并且借助于prompt_toolkit这个强大、交互式命令行界面(CLI)的纯 Python 库,
具体见onboard.py中的_select_with_back方法,使用KeyBindings捕获键盘的操作,用来锁定选择的配置,之后在利用python的getattr和setattr以及_configure_pydantic_model方法进行对应的配置
并且会根据返回的值,判断是否进行持久化配置操作。
python
try:
answer = _get_questionary().select(
"What would you like to configure?",
choices=[
"[P] LLM Provider",
"[C] Chat Channel",
"[A] Agent Settings",
"[G] Gateway",
"[T] Tools",
"[V] View Configuration Summary",
"[S] Save and Exit",
"[X] Exit Without Saving",
],
qmark=">",
).ask()
except KeyboardInterrupt:
answer = None
if answer is None:
action = _prompt_main_menu_exit(_has_unsaved_changes(original_config, config))
if action == "save":
return OnboardResult(config=config, should_save=True)
if action == "discard":
return OnboardResult(config=original_config, should_save=False)
continue
_MENU_DISPATCH = {
"[P] LLM Provider": lambda: _configure_providers(config),
"[C] Chat Channel": lambda: _configure_channels(config),
"[A] Agent Settings": lambda: _configure_general_settings(config, "Agent Settings"),
"[G] Gateway": lambda: _configure_general_settings(config, "Gateway"),
"[T] Tools": lambda: _configure_general_settings(config, "Tools"),
"[V] View Configuration Summary": lambda: _show_summary(config),
}
-
同步配置channel
对于已经配置好,或者没有配置的channel,都会写入到config.json文件中,
没有配置的会写入默认值,配置的则覆盖默认值。 -
同步工作区配置
把templates目录下的AGENTS.md,HEARTBEAT.md,SOUL.md,TOOLS.md,USER.md等文件拷贝到工作目录下.
形成如下的目录结构:shell├── AGENTS.md ├── HEARTBEAT.md ├── memory │ ├── HISTORY.md │ └── MEMORY.md ├── skills ├── SOUL.md ├── TOOLS.md └── USER.md