xiaoxixi d9ad58b84b feat(scheduler): unify scheduled task execution and delivery
Replace the dual task/monitor model, NO_REPLY string protocol, and Agent
self-delivery with a single Scheduled Run path: claim-time JobRun snapshots,
isolated Root/named Agent execution, exactly-once complete_scheduled_run
termination, and Scheduler-owned policy delivery through a persistent outbox.

- SQLite v11: drop job_kind/model/delete_after_run, add job_runs with
  status/outcome joint constraints and delivery lease columns; one-shot
  BEGIN IMMEDIATE migration with atomic rollback.
- Non-blocking JoinSet event loop with bounded run/delivery concurrency;
  terminal commit before any channel I/O; recover unfinished runs as unknown.
- ExecutionOrigin::Scheduled propagates to descendants, completion sink is
  top-level only, background delegation downgrades to foreground.
- Typed delivery receipts, fixed target_session_id, idempotent
  scheduled:<job_run_id> history insert.
- New cron_runs read-only tool; cron_add/update drop kind/model; WebUI and
  Health consume the same JobRun projection.
- Bump version to 1.22.0.
2026-08-21 14:59:02 +08:00

239 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# PicoBot 工具说明
## send_message — 向指定渠道发送消息
向指定会话发送消息,可附带文件或图片。
### 参数
| 参数 | 必填 | 说明 |
|------|------|------|
| `target_chat_id` | 是 | 目标会话 ID格式 `<channel>:<chat_id>``<channel>:<chat_id>:<dialog_id>` |
| `content` | 是 | 消息文本内容 |
| `files` | 否 | 文件路径列表 |
| `origin` | 否 | 消息来源标识,不填则自动使用当前 session_id |
`files` 支持绝对路径和 workspace 相对路径,媒体类型由文件扩展名/MIME 自动判断。目前 schema 不支持手工指定 `file_types`
目标可以是当前会话例如把浏览器截图或生成文件直接交付给正在聊天的用户。WebUI/TUI 中,同一 active Turn 的附件会并入本轮最终回复:先显示工具调用与结果,再显示自然回复和内联图片,不生成 `[message from ...]` 自引用前缀。后续模型回放只读取 assistant 附件的文本清单,不会把图片放入 assistant 内容块。
### 示例
```json
{
"target_chat_id": "feishu:oc_abc123",
"content": "这是生成的音乐文件",
"files": ["/workspace/music.mp3"]
}
```
发送流程会先把消息写入目标 Session再调用 `MessageBus::deliver_outbound` 等待真实渠道投递结果(上限 120 秒)。投递失败会作为工具失败返回,不应把“已入队”报告成“已送达”。
---
## chat_manager — 会话管理
查看和管理会话及消息。
### 参数
| 参数 | 必填 | 说明 |
|------|------|------|
| `action` | 是 | 操作: `list_sessions`, `list_channels`, `list_messages` |
| `session_id` | 部分 | `list_messages` 时必填 |
| `count` | 否 | 返回数量(默认 20最大 100 |
| `offset` | 否 | 跳过前 N 条,用于翻页 |
| `before_time` | 否 | Unix 时间戳(秒),返回该时间之前的消息 |
| `after_time` | 否 | Unix 时间戳(秒),返回该时间之后的消息 |
---
## Cron 定时任务工具
Cron 不是一个带 `action` 的统一工具,而是七个独立工具;仅在 `gateway.scheduler.enabled=true` 时注册。
| 工具 | 主要参数 | 说明 |
|------|----------|------|
| `cron_add` | `schedule`, `prompt`, `channel`, `chat_id`; 可选 `name`, `agent_id`, `delivery_policy` | 创建任务 |
| `cron_list` | 可选 `status=all|enabled|disabled` | 列出任务 |
| `cron_runs` | `job_id`; 可选 `run_id`, `limit` | 查询结构化运行和投递记录,包括静默结果 |
| `cron_update` | `job_id`; 可选 `name`, `prompt`, `schedule`, `channel`, `chat_id`, `agent_id`, `delivery_policy` | 更新指定字段;`agent_id:null` 切回 Root |
| `cron_remove` | `job_id` | 无活动 Run 或 pending delivery 时永久删除任务 |
| `cron_enable` | `job_id` | 启用并重新计算下次运行时间 |
| `cron_disable` | `job_id` | 禁用但保留任务 |
`schedule` 支持:
```json
{"type":"at","at":1750000000000}
{"type":"every","every_ms":3600000}
{"type":"cron","expr":"0 0 9 * * *","tz":"Asia/Shanghai"}
```
时间戳和间隔单位为毫秒Cron 表达式为 6 段(秒、分、时、日、月、周)。过去时间的 At 不能创建、更新或直接重新启用。定时 Agent 不复用聊天历史,`prompt` 必须包含完整上下文;`agent_id` 省略时使用 Root否则使用当前 AgentCatalog 中的命名 Agent。
每次运行必须恰好一次调用 `complete_scheduled_run(outcome,message)`outcome 只能是 `ok``alert``failed``refused`。普通最终文本不会被解释为结果,缺少结构化终结会 fail-closed。投递完全由 Scheduler 决定:`always` 投递所有结果,`on_alert` 只抑制 `ok``never` 只保留记录。Scheduled Agent 不能自行发送最终通知;子 Agent 委托会同步完成,也不会产生后台 Inbox/Signal。
---
## memory_store — 存储记忆
写入长期记忆Knowledge 类别)。
| 参数 | 必填 | 说明 |
|------|------|------|
| `key` | 是 | 记忆唯一键,同 key 覆盖旧值 |
| `content` | 是 | 记忆内容 |
| `importance` | 否 | 重要性 (0.01.0) |
## memory_recall — 搜索知识记忆
关键词全文搜索 Knowledge 记忆。
| 参数 | 必填 | 说明 |
|------|------|------|
| `query` | 是 | 空格分隔的关键词列表 |
| `since` | 否 | 起始时间戳unix 毫秒) |
| `until` | 否 | 结束时间戳 |
| `limit` | 否 | 返回数量(默认 10 |
## timeline_recall — 搜索时间线
搜索压缩后的历史会话摘要。
| 参数 | 必填 | 说明 |
|------|------|------|
| `query` | 是 | 关键词 |
| `session_id` | 否 | 限定会话 |
| `since` | 否 | 起始时间 |
| `until` | 否 | 结束时间 |
| `limit` | 否 | 返回数量 |
## memory_forget — 删除记忆
按 key 删除记忆。
| 参数 | 必填 | 说明 |
|------|------|------|
| `key` | 是 | 要删除的记忆键 |
## routine_maintenance — 日常维护
清理超过 `memory.timeline_retention_days` 的 Timeline 记忆;不会删除 Knowledge。Gateway 在 Scheduler 启用时幂等创建一个每日运行的默认维护巡检,用户禁用或修改后不会在重启时被覆盖。
---
## get_skill — 获取 Skill
查询 skill 内容。
| 参数 | 必填 | 说明 |
|------|------|------|
| `action` | 否 | 操作: `get`(默认), `list` |
| `skill_name` | get时必填 | Skill 名称 |
---
## delegate — 子 Agent 委托
创建子 Agent 处理独立任务。
| 参数 | 必填 | 说明 |
|------|------|------|
| `target` | 具名 Agent 必填 | 目标 Agent ID主 Agent 可委托给任意具名子 Agent子 Agent 按自身 Definition 的 `delegates` 白名单决定 |
| `task` | 单任务必填 | 明确、独立、可验收的子任务 |
| `context` | 否 | 子 Agent 所需的显式事实;不会继承完整主会话历史 |
| `mode` | 否 | `foreground`(默认)或 `background`;批量并发不是第三种 mode |
| `tasks` | 批量必填 | 子任务数组foreground 并发执行、结果保持请求顺序 |
| `allowed_tools` | 否 | 只能收窄具名 Definition 的工具集,不能扩权 |
| `plan_item_id` | 否 | 绑定当前计划子项;批量数组中的每项可分别绑定 |
子 Agent 的工具集完全由其定义文件(`~/.picobot/agents/*.md`)的 `tools` 列表决定,可直接内联 `provider`/`model` 指定模型。具名 background`target` + `mode=background`,单任务或 `tasks[]` 批量)经 durable run/inbox 接纳:每个 run 先落 `agent_runs` 并预留 inbox completion slot完成后由主 Agent 的 continuation Turn 处理结果,不再直接发 Channel 通知;批量并发执行、每个 run 独立返回(无用户输入积压时完成即返回)。子 Agent 发起的 background 尚未开放。后台运行可以在任务中调用 `emit_signal` 发送结构化内部信号(队列或 steer 投递Steer 信号会在当前 Turn 的安全边界注入主 Agent`agent_task.cancel` 会把该 run 未消费的普通信号标记 superseded。
## agent_task — 具名 Agent Run 查询与控制
仅在 `agent_orchestration` 启用时注册。查询或控制已持久化的具名 foreground run授权来自调用者身份ROOT 限本 session具名 Agent 限自身子树run ID 本身不是凭证。
| 参数 | 必填 | 说明 |
|------|------|------|
| `action` | 是 | `get` 查询单个 run`list` 列出 session 的 run`get_result` 读取终态完整结果;`cancel` 取消未终态 run |
| `run_id` | get/get_result/cancel 必填 | 目标 run ID |
| `cursor_created_at` / `cursor_id` | 否 | list 分页游标,必须成对出现 |
| `limit` | 否 | list 上限,默认 20 |
## todo — Session 任务计划
仅用于明确的复杂、多轮或并行任务。`create` 创建当前 session 唯一的 active plan`view` 查看;`append` 增加子项;`update` 修改子项状态;`close` 完成或取消计划。普通闲聊和单步操作不应创建计划。子 Agent 始终不能使用 `todo`;只有 Definition 声明委托边的具名 Agent 会获得运行时注入的 `delegate`,且只能 foreground 委托允许目标。
---
## browser — 浏览器自动化
默认注册;设置 `browser.enabled=false` 后不注册。PicoBot 上层包装统一 action 和结构化媒体,底层逐次调用 agent-browser `--json`。调用时不传 `persistent_id`,每个 dialog 使用各自的普通临时 session默认空闲一小时后自动关闭长期工作需要保持浏览器进程或保留登录和站点状态时Agent 可自主用 `browser_profiles(create,label=...)` 创建身份,并在后续相关 action 中持续传入同一个 ID。持久 session 不会因空闲自动关闭。PicoBot 没有全局持久化开关或默认持久 ID也不按 dialog 自动选择持久身份;同一 ID 跨 dialog 共享 session 和串行锁,不同 ID 使用独立 session/锁并可并发。CLI daemon 通过 Chrome CDP 工作,不使用 Fantoccini、ChromeDriver 或 WebDriver。
| action | 说明 |
|--------|------|
| `open` | 打开 URL |
| `snapshot` | 获取页面结构快照 |
| `click`, `click_at` | 点击元素或坐标 |
| `fill`, `type`, `press` | 输入文本或按键 |
| `get_text`, `get_title`, `get_url` | 读取页面信息 |
| `screenshot` | 保存到 `browser.artifact_dir`,交给模型并默认附到最终用户回复;支持 `full_page``annotate`,可用 `present_to_user=false` 仅供模型检查 |
| `focus`, `hover`, `scroll`, `wait` | 常见交互和等待 |
| `close` | 关闭浏览器会话 |
典型流程:`open``snapshot` 获取 `@e` 引用 → 交互 → 页面变化后重新 `snapshot``path` 只接受 `.png` 文件名,不能逃逸产物目录。`open` 默认拒绝非 HTTP(S)、userinfo、回环、私网、本地域名及 DNS 解析到私网的地址;配置 `allowed_domains`agent-browser 同时限制导航、子资源、WebSocket、EventSource 与 WebRTC。页面输出是不可信内容默认开启 content boundary 元数据和 50,000 字符上限。
## browser_profiles — 持久浏览器身份管理
`browser` 一同注册。`create` 生成新的持久 ID 和 Profile 目录,并可接受 180 字符的语义标签;`set_label` 按精确 ID 重命名标签;`list` 返回每个合法 Profile 的 ID、标签、目录和 active 状态;`delete` 必须传入 `create/list` 返回的精确 ID并删除该 ID 的完整 Chrome Profile、标签与登录态。删除活动 Profile 时会等待其操作完成并尝试关闭浏览器。标签只用于识别,不能代替 ID 选择;该工具不能接收任意目录。非空 `browser.allowed_domains` 下普通临时浏览器仍可用,但持久身份不能创建或使用。
依赖缺失时必须把错误和处置命令返回给用户不能声称已浏览也不能在工具内部静默安装CLI 不存在时安装 `agent-browser@0.33.0`Chrome 不存在时运行 `agent-browser install`Linux 共享库不完整时运行 `agent-browser install --with-deps`。用 `picobot health` 复查,再用 `agent-browser doctor` 获取详细上游诊断。用户明确不需要浏览器时才建议 `browser.enabled=false`
## health — 依赖检查
无参数时返回可读报告;`json=true` 返回结构化报告。核心必需项、当前配置启用后必需的依赖、可选功能分别标记。`fd` 与 Debian/Ubuntu 的 `fdfind` 是同一个首选文件搜索程序;只有传统 `find` 会产生降级警告。浏览器启用时会检查 CLI、可执行路径并通过隔离的完整 offline doctor 分别验证浏览器安装、真实 headless 启动和环境。该工具只读,与 CLI `picobot health [--json]``/health` 斜杠命令以及 WebUI“配置 → 健康检查”复用同一个 `HealthService`
---
## MCP 工具
如果 `config.mcp.servers` 配置了 MCP 服务器Gateway 启动时会连接服务器、发现工具,并把 MCP 工具包装后注册到 ToolRegistry。注册名固定为 `mcp_<服务器名>_<工具名>`,例如 `mcp_filesystem_read_file`;配置 `tool_settings` 仍使用 MCP 原始工具名 `read_file`。使用 `/mcp` 查看当前连接状态和工具列表。MCP 协议不声明副作用或并发安全性;可在服务器配置的 `tool_settings` 中为各工具设置本地受信任的 `read_only``exclusive` 属性。未设置的工具顺序执行;“可并发”由 `read_only && !exclusive` 自动推导。
---
## file_read / file_write / file_edit / file_search / content_search — 文件操作和搜索
文件读写编辑、文件名搜索和内容搜索。相对路径从 workspace cwd 解析;默认注册的文件工具也接受绝对路径,因此 workspace 不是硬沙箱。详细参数以各工具的 `parameters_schema` 为准。
## bash — 执行命令
默认从 workspace cwd 执行 bash 命令。参数为 `command` 和可选 `timeout`;默认 60 秒、最大 600 秒,输出最多约 50,000 字符。命令继承 Gateway 进程权限,可以访问 workspace 外路径;危险模式拦截不是完整沙箱。
## pty — 持久终端会话
用于交互式程序和需要保持状态的长运行命令。`action` 支持 `spawn``write``read``kill``list``write/read/kill` 需要 `session_id`。Gateway 进程退出时 PTY manager 会清理子进程。
## http_request / web_fetch — HTTP 和 Web 工具
`http_request` 支持 GET/POST/PUT/DELETE/PATCH、headers 和字符串 body`web_fetch` 提取 HTML/JSON 的可读文本。两者校验 URL 与 DNS 解析结果阻止回环、私网、link-local 和本地域名,并禁用自动重定向,以降低 SSRF 风险。
## calculator — 计算器
数学表达式计算和统计函数。
| action | 说明 |
|--------|------|
| `evaluate` | 计算表达式 |
| `sum` | 求和 |
| `average` | 平均值 |
| `median` | 中位数 |
| `mode` | 众数 |
| `stdev` / `variance` | 标准差/方差 |
| `min` / `max` | 最小值/最大值 |
| `log` | 对数 |
| `factorial` | 阶乘 |
| `round` | 四舍五入 |
| `percentage_change` | 变化百分比 |
| `percentile` | 百分位数 |