# PicoBot 配置说明 配置文件加载顺序:`~/.picobot/config.json` → 当前目录 `./config.json`。 占位符 `` 从启动环境替换。PicoBot 依次加载 `config.json` 同目录的 `.env`、`workspace_dir/.env`,最后保留启动进程已有环境变量作为最高优先级;workspace 层覆盖配置目录层。合并值也会进入进程环境,供 MCP 和工具子进程继承。workspace `.env` 不能修改用于定位自身的 `workspace_dir`。 Gateway WebUI 的“配置”页可以编辑实际加载的配置文件。读取时 API Key、secret、password 和 token 会显示为 `********`,保持掩码不变再保存会保留原值;写入采用同目录临时文件替换。Gateway 会忽略可恢复的历史未知字段、类型不匹配字段和失效的非核心命名条目,在配置页按 JSON Pointer 显示诊断,但不会自动改写原始文件;“一键清除”由后端校验文件 revision 后原子删除已诊断项,普通保存仍严格拒绝无效配置。JSON 损坏、不可用的 `default` Agent 链路和无法安全构造运行代的错误不会被忽略。运行配置保存或清理后可执行 `picobot reload`、发送 `/reload`,或由根交互 Agent 在用户明确要求时调用 `reload_config` 工具。Gateway 会先校验候选配置,停止接收新工作并等待交互 Turn、Scheduler job 和后台子 Agent 到达安全边界后切换;失败时继续使用旧配置。`GET /api/config/reload/status` 可查询 generation、相位与最近错误。`gateway.host`、`gateway.port`、`workspace_dir` 和 `gateway.session_db_path` 的有效路径必须通过完整重启变更。`USER.md` 与 `AGENTS.md` 的修改用于后续构建的 Agent 上下文。 ## config.json 结构 ```jsonc { "providers": {}, // LLM 提供商配置 "models": {}, // 模型配置 "agents": {}, // Provider/Model profile "context_compaction": {}, // 上下文 reserve 预算与近期保留量 "agent_orchestration": {}, // 具名子 Agent Definition 与编排上限 "gateway": {}, // 网关配置 "client": {}, // 客户端配置 "channels": {}, // 渠道配置 "memory": {}, // 记忆系统配置 "workspace_dir": "", // 工作目录,默认 ~/.picobot/workspace "mcp": {}, // MCP 服务器配置 "browser": {} // 可选浏览器自动化配置 } ``` 完整示例见 `assets/config.example.json`。 ## providers 字段 | 字段 | 说明 | |------|------| | `type` | 提供商类型: `openai`(兼容 OpenAI API)、`anthropic` | | `base_url` | API 端点地址 | | `api_key` | API 密钥,支持 `` 占位符 | | `extra_headers` | 额外 HTTP 头 | ## models 字段 | 字段 | 说明 | |------|------| | `model_id` | 模型标识名称 | | `temperature` | 采样温度,可选 | | `max_tokens` | 最大输出 token 数,可选 | | `token_limit` | 模型上下文窗口硬上限,可选;未配置时默认为 128000,Agent 只能进一步收紧 | | `input_type` | 模型支持的输入类型,如 `["text"]` 或 `["text", "image"]`,默认 `["text"]`. 纯内部使用,不会传递给 LLM API | ## agents 字段 | 字段 | 类型 | 默认 | 说明 | |------|------|------|------| | `provider` | string | - | 提供商名称(对应 providers key) | | `model` | string | - | 模型名称(对应 models key) | | `max_tool_iterations` | int | 99 | 最大工具调用轮数 | | `token_limit` | int | 使用模型上限 | 可选的 Agent 上限;有效窗口取 Agent 与模型(模型未配置时为 128000)的最小值 | ## context_compaction 字段 自动压缩只使用 reserve 公式 `context_tokens > context_window - effective_reserve`。小窗口下 `effective_reserve = min(reserve_tokens, context_window / 2)`,近期原样保留量最多为有效阈值的一半。 | 字段 | 默认 | 说明 | |------|------|------| | `enabled` | true | 只控制 Turn 前自动压缩;不禁用 `/compact` 或 overflow 恢复 | | `reserve_tokens` | 16384 | 为输出、工具迭代和估算误差预留的输入窗口 | | `keep_recent_tokens` | 20000 | checkpoint 后尽量原样保留的近期历史 token | ## agent_orchestration 字段 子 Agent 编排是 PicoBot 的内在机制,始终启用、不可关闭;该配置块只控制定义目录与各类上限。`definitions_dir` 相对 `config.json` 所在目录解析,且不得通过绝对路径或 symlink 逃逸该受信任配置目录。Gateway 启动和热重载会严格校验全部 Markdown Definition;任一无效 Provider profile、工具、Skill 或委托目标会拒绝整个候选运行代。 | 字段 | 默认 | 说明 | |------|------|------| | `definitions_dir` | agents | 第一层 `*.md` Definition 目录 | | `max_tree_depth` | 4 | Root-relative 委托深度硬上限 | | `max_runs_per_tree` | 16 | 单任务树 run 预算(树级原子计数强制) | | `max_concurrent_runs` / `max_concurrent_runs_per_session` | 6 / 4 | background run 接纳配额(global→session 顺序获取,runner 持有至 terminal commit;foreground 不占) | | `max_concurrent_provider_steps` / `..._per_session` | 8 / 4 | Provider step 上限(global→session) | | `max_concurrent_tool_steps` / `..._per_session` | 16 / 8 | 普通工具 step 上限(global→session) | | `max_pending_inbox_events_per_session` | 128 | durable inbox 容量(条件更新,预留槽不可被信号挤占) | | `inbox_event_ttl_hours` | 168 | inbox 事件 TTL(已预留配置;TTL 清理尚未实现) | | `max_inbox_delivery_attempts` | 8 | inbox 最大投递次数,超限 dead-letter | | `max_user_turn_burst_before_inbox` | 4 | 用户 Turn 公平调度阈值 | | `max_inbox_wait_secs` | 30 | inbox 最大等待阈值 | 已实现:具名 foreground 与 background(Root 单任务或批量)、内联 `provider`/`model` 或 `llm_profile`、工具集由定义文件 `tools` 决定、批量并发、父子委托边校验、durable inbox continuation(空闲时完成即返回)、`emit_signal`(queue/steer)、run quota 与 step gate、内置 general-purpose 定义与 WebUI「子 Agent」管理页。未开放:子 Agent 发起的 background、`idempotency_key` 工具入口。旧匿名 general 兼容路径已移除,委托必须指定具名 `target`。 ## gateway 字段 | 字段 | 类型 | 默认 | 说明 | |------|------|------|------| | `host` | string | 127.0.0.1 | 监听地址 | | `port` | int | 19876 | 监听端口 | | `require_pairing` | bool | true | 是否要求 WebUI 与 CLI 设备先使用一次性代码配对 | | `session_ttl_hours` | int | - | 兼容/预留字段;当前没有会话 TTL 清理循环 | | `session_db_path` | string | - | SQLite 数据库路径,默认在配置目录 `data/` 下 | | `cleanup_interval_minutes` | int | - | 兼容/预留字段;当前没有按此间隔运行的 session 清理任务 | | `scheduler` | object | - | 调度器配置 | ### gateway.scheduler 字段 | 字段 | 类型 | 默认 | 说明 | |------|------|------|------| | `enabled` | bool | true | 是否启动调度器并注册 cron 工具 | | `poll_interval_secs` | int | 60 | 检查到期任务的轮询间隔 | | `max_concurrent` | int | 1 | 同时执行的 Scheduled Run 上限,运行时限制在 1–256;投递使用独立有界并发 | | `execution_timeout_secs` | int | 900 | 单个定时任务 Agent 执行的硬超时;Job 执行租约额外覆盖关停宽限,投递由持久化 outbox 独立恢复 | ## memory 字段 | 字段 | 类型 | 默认 | 说明 | |------|------|------|------| | `consolidation_provider` | string | 主 Agent provider | 当前记录在 MemoryManager 中供后续归并使用;压缩摘要仍使用 Session provider | | `consolidation_model` | string | 主 Agent model | 当前记录在 MemoryManager 中供后续归并使用;压缩摘要仍使用 Session model | | `recall_limit` | int | 5 | 每轮自动注入上下文的知识记忆条数上限 | | `recall_min_relevance` | float | 0.25 | 自动召回的相关性硬门槛(命中词项占比低于此值则丢弃) | | `recall_min_score` | float | 0.25 | 自动召回的综合分门槛(相关度+重要度+时效加权) | | `recall_recency_half_life_days` | int | 30 | 自动召回时效衰减的半衰期(天) | | `recall_timeout_ms` | int | 1000 | 自动召回搜索的硬超时;超时本轮不注入记忆 | | `idle_consolidation_minutes` | int | 10 | 预留的空闲归并阈值;当前无对应循环 | | `timeline_retention_days` | int | 90 | 默认日常维护巡检删除超过该期限的 Timeline;Knowledge 不受影响 | | `max_failures_before_degrade` | int | 3 | 预留的归并失败阈值;当前无失败降级循环 | 自动召回每轮用当前用户输入做关键词检索(jieba 分词 + FTS5),按「词项相关度 0.5 + 重要度 0.3 + 时效 0.2」加权,通过相关性/综合分双门槛后才注入;搜索有硬超时保证不拖慢 Turn。Timeline 不自动召回,需显式 `timeline_recall`。idle consolidation 和失败降级循环尚未接入。Timeline 清理由默认启用的 `picobot-routine-maintenance` Scheduled Run 执行;该任务使用 `never` 策略,结构化结果只进入运行审计和 Health。 ## channels.feishu 字段 | 字段 | 类型 | 默认 | 说明 | |------|------|------|------| | `enabled` | bool | false | 是否启用 | | `app_id` | string | - | 飞书应用 ID | | `app_secret` | string | - | 飞书应用密钥 | | `allow_from` | []string | ["*"] | 允许交互的用户列表 | | `require_mention` | bool | true | 群聊中是否必须明确 @ 机器人;无法解析机器人身份时安全地忽略群消息 | | `agent` | string | - | 使用的 agent 名称 | | `media_dir` | string | ~/.picobot/media/feishu | 配置默认值;Gateway 注册渠道时会覆盖为 `{workspace}/media/feishu` | | `reaction_emoji` | string | "Typing" | 回复意向表达的表情 | | `live_updates` | bool | false | 是否用单张卡片实时编辑活动 Turn;关闭时只发送终态 | | `live_update_interval_ms` | int | 500 | 卡片更新最小间隔,运行时限制在 250–5000ms | | `max_image_bytes` | int | 10485760 | 单个入站/出站图片的最大字节数 | | `max_file_bytes` | int | 26214400 | 单个入站/出站文件、音频或视频的最大字节数 | | `media_dir_max_bytes` | int | 536870912 | 飞书媒体目录容量上限;达到上限后拒绝新下载,不自动删除旧文件 | | `request_timeout_secs` | int | 30 | 单次飞书 HTTP 请求及响应体读取的硬超时,运行时限制在 5–120 秒 | 飞书属于外部渠道:无论是否开启实时卡片,都不会接收模型 reasoning;工具只显示紧凑状态。渠道配置可通过 Gateway 配置重载生效。 ## mcp 字段 | 字段 | 类型 | 默认 | 说明 | |------|------|------|------| | `servers` | array | [] | MCP 服务器列表 | | `tool_timeout_secs` | int | 180 | 工具调用超时秒数 | MCP 服务器单条配置: | 字段 | 说明 | |------|------| | `name` | 服务器名称 | | `enabled` | 是否启用,默认 true;关闭后启动/重载时不连接该服务器 | | `transport` | 传输方式: `stdio`、`sse`、`streamable-http` | | `command` | 启动命令(stdio 模式) | | `args` | 命令参数 | | `env` | 子进程环境变量 | | `url` | URL(sse / streamable-http 模式) | | `headers` | HTTP 传输额外请求头 | | `tool_timeout_secs` | 单独的超时设置 | | `tool_settings` | 按 MCP 原始工具名索引的本地执行属性声明;每项可设 `read_only` 与 `exclusive`,均默认 false | `tool_settings` 示例: ```json { "tool_settings": { "read_file": { "read_only": true }, "refresh_index": { "exclusive": true } } } ``` `可并发` 不需要也不能单独配置:它始终等于 `read_only && !exclusive`。未声明的 MCP 工具按可能有副作用且顺序执行处理。WebUI「工具 → MCP」展开服务器后可编辑这些复选框;编辑先暂存,可跨多个工具一次“保存并应用”并热重载,离开 MCP 标签或刷新页面会丢弃未保存草稿。 ## browser 字段 浏览器工具默认开启并注册 `browser` 与 `browser_profiles` 工具。缺少外部依赖不会阻止 Gateway 启动,但实际调用会返回安装错误,`picobot health` 会提前判定。上层由 PicoBot 管理浏览器生命周期与媒体,底层调用 agent-browser JSON CLI;不再依赖 Fantoccini、ChromeDriver 或 WebDriver。 | 字段 | 类型 | 默认 | 说明 | |------|------|------|------| | `enabled` | bool | true | 是否启用浏览器工具;关闭后不注册 `browser` | | `command` | string | agent-browser | CLI 名称或绝对路径 | | `headless` | bool | true | 是否无头运行 | | `browser_executable_path` | string | - | 自定义 Chrome/Chromium 可执行文件路径 | | `max_sessions` | int | 4 | 同时保留的普通 dialog 临时浏览器会话上限;持久身份不计入 | | `idle_timeout_secs` | int | 3600 | 大于零;普通 dialog 临时浏览器的空闲退出及 Manager 回收时间;持久浏览器不使用该超时 | | `command_timeout_secs` | int | 120 | 单次 CLI 调用硬超时 | | `max_output_chars` | int | 50000 | 页面来源文本输出上限 | | `content_boundaries` | bool | true | 启用 agent-browser 不可信页面边界元数据 | | `allowed_domains` | []string | [] | 可选域名白名单;空数组表示不启用域名限制 | | `allow_private_hosts` | bool | false | 是否允许回环、私网和本地域名 | | `artifact_dir` | string | ~/.picobot/media/browser | 截图产物目录 | | `persistence.profile_dir` | string | ~/.picobot/browser/profiles | 持久 ID、语义标签和 Profile 目录的受控根目录 | 持久化不是配置模式。`browser` 调用省略 `persistent_id` 时使用当前 dialog 的普通临时浏览器,并在达到 `idle_timeout_secs` 后自动退出;长期工作需要保持浏览器进程或保留登录和站点状态时,Agent 可自主调用 `browser_profiles(create,label=...)` 生成 `picobot-profile-`,对应数据位于 `profile_dir/`,然后在该工作的后续每个 action 中持续传入同一个 ID。持久浏览器禁用 daemon 空闲自动退出,只通过显式 `browser(close)` 或 Profile 删除关闭。没有默认 ID,也不会按 dialog 自动选择持久身份。同一 ID 跨 dialog 共享底层 session 与串行锁,不同 ID 各自独立并可并发。`browser_profiles` 还支持 `set_label`、`list` 和使用精确 ID 的 `delete`;标签可重命名,但选择浏览器始终使用不可变 ID。 agent-browser 0.33.0 不允许持久 Profile 与 `allowed_domains` 同时使用。配置域名限制后普通临时浏览器仍可用,创建或使用持久身份会被拒绝,health 会提示该可选能力受限。Profile 包含登录凭据,应把目录视为敏感数据,不得提交到版本控制、跨用户共享或放在不受信任的网络文件系统中。 旧字段 `webdriver_url`、`chrome_path` 不再接受。推荐安装 `agent-browser@0.33.0` 后运行 `agent-browser install`;Linux 可运行 `agent-browser install --with-deps`。使用前用 `picobot health` 检查 CLI、浏览器安装和真实 headless 启动环境。 ### 浏览器依赖故障处置 | health / 工具错误 | 处置 | |---|---| | `agent-browser` 未找到 | 运行 `npm install -g agent-browser@0.33.0`,或 `cargo install agent-browser --version 0.33.0 --locked` | | CLI 已安装但找不到 Chrome/Chromium | 运行 `agent-browser install`;已有浏览器则设置 `browser_executable_path` 或 `AGENT_BROWSER_EXECUTABLE_PATH` | | Linux 缺少共享库/系统包 | 运行 `agent-browser install --with-deps`,然后再运行 `agent-browser doctor` | | 安装状态不明确 | 先运行 `picobot health` 获取 PicoBot 视角的结果,再运行 `agent-browser doctor` 查看完整上游诊断 | 不得在 Agent 工具调用中自动安装或执行 `doctor --fix`;安装会修改系统且可能需要管理员权限,应把命令报告给用户,由用户确认后执行。临时不需要浏览器时可设置 `browser.enabled=false`,此时 health 不要求 agent-browser/Chrome。