Nanobot 从onboard启动命令来看个人助理Agent的实现

背景

在之前的文章中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命令

onboardTyper 子命令,用于 首次或再次初始化 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),由向导决定是否保存。
  1. 第一步便是配置文件的路径,如果指定了--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()
  1. 创建或者更新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}")
  1. 进行向导式的配置
    如果配置了进行了向导式的操作,则利用 questionary包 进行引导式的操作,并且借助于prompt_toolkit 这个强大、交互式命令行界面(CLI)的纯 Python 库,
    具体见 onboard.py中的_select_with_back方法,使用KeyBindings捕获键盘的操作,用来锁定选择的配置,之后在利用python的 getattrsetattr以及_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),
      }
  1. 同步配置channel
    对于已经配置好,或者没有配置的channel,都会写入到config.json文件中,
    没有配置的会写入默认值,配置的则覆盖默认值。

  2. 同步工作区配置
    把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
相关推荐
魔术师Grace1 天前
从传统企业架构到 OPC 模式,AI 到底改变了什么?
人工智能·程序员
沪漂阿龙1 天前
LangGraph 持久化完全指南:从零搭建永不丢失状态的 AI Agent 系统
人工智能·流程图
杨浦老苏1 天前
大模型安全接入网关LinkAI
人工智能·docker·ai·群晖·隐私保护
档案宝档案管理1 天前
权限分级管控,全程可追溯,筑牢会计档案安全防线
运维·网络·人工智能
Chat_zhanggong3451 天前
主推RK3567J作用有哪些?
人工智能·嵌入式硬件
qq_411262421 天前
四博 AI 机械臂台灯智能音箱方案:让台灯具备视觉、语音、动作和学习陪伴能力
人工智能·语音识别
AI+程序员在路上1 天前
VS Code 完全使用指南:下载、安装、核心功能与 内置AI 编程助手实战
开发语言·人工智能·windows·开源
coderyi1 天前
Agent协作简析
人工智能
霍小毛1 天前
破局工业数据孤岛!数字孪生+AI智慧设备资产管理平台,重构智能运维新范式
人工智能·重构
向量引擎1 天前
向量引擎的新时代:从OpenClaw、Hermes到GPT Image 2与龙虾(Lobster)模型的深度对比与应用
人工智能·gpt·aigc·api·ai编程·key·api调用