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

14 KiB
Raw Blame History

PicoBot 数据库表结构

数据库为 SQLite默认位于配置目录~/.picobotdata/ 下的 picobot.db,与 workspace 相互独立。

连接启用 WAL、synchronous=NORMAL、foreign keys、5 秒 busy timeout连接池最多 8 个连接。当前 PRAGMA user_version=11;启动时会在单个事务内迁移旧库,遇到比程序更新的 schema version 会拒绝启动。

sessions 表

会话表,一个 session 对应一个 (channel, chat_id, dialog_id) 组合。

字段 类型 说明
id TEXT PK session ID格式 <channel>:<chat_id>:<dialog_id>
channel TEXT 渠道名称
chat_id TEXT 聊天/群组标识
dialog_id TEXT 对话标识
title TEXT 会话标题(默认 "新对话"
created_at INTEGER 创建时间Unix 毫秒)
last_active_at INTEGER 最后活跃时间Unix 毫秒)
message_count INTEGER 消息计数
routing_info TEXT 路由信息
archived_at INTEGER 归档时间Unix 毫秒NULL 表示未归档
deleted_at INTEGER 软删除时间戳
last_consolidated_at INTEGER 上次记忆归并时间
last_compressed_message_at INTEGER 最近 checkpoint 时间戳(兼容/诊断字段,不作为恢复边界)
active_context_checkpoint_id TEXT 当前 Provider 历史投影使用的 checkpoint IDNULL 表示使用全部原始消息
context_generation INTEGER checkpoint CAS 提交代;历史清空/改写时递增并清除活动指针
delivery_context TEXT 渠道声明的可跨 Turn 复用投递上下文 JSON如飞书 thread/root 身份);一次性 reply/reaction ID 永不写入
delivery_context_updated_at INTEGER delivery_context 最后更新时间

session_turn_usageturn_id 幂等保存已提交 Turn 的 Provider usage包括累计输入、输出、缓存输入、请求数和最后一次请求的 prompt tokens。它与 Turn 消息批次在同一事务中提交,供 WebUI 状态栏和 /info 使用;升级前历史无法可靠回填,因此统计起点以首条 usage 记录为准。

(channel, chat_id, dialog_id) 唯一。普通列表排除 deleted_at;是否包含归档记录由查询参数决定。

messages 表

字段 类型 说明
id TEXT PK 消息 UUID
session_id TEXT FK 所属会话,外键关联 sessions(id)
seq INTEGER 消息序号
role TEXT 角色: user / assistant / tool / system
content TEXT 消息内容
media_refs TEXT 多媒体引用 JSON
tool_call_id TEXT 工具调用 ID
tool_name TEXT 工具名称
tool_calls TEXT 工具调用参数 JSON
source TEXT 消息来源(跨会话消息时标记来源 session_id
created_at INTEGER 创建时间Unix 毫秒)
reasoning_content TEXT 可展示的模型 reasoning如有
provider_state TEXT Provider 私有回放状态 JSON只回放给匹配 Provider不下发客户端或 Channel
turn_id TEXT 产生该消息的活动 Turn ID
iteration INTEGER Agent 工具循环中的迭代序号
completion_status TEXT completed / cancelled / interrupted,旧数据默认 completed
client_visibility TEXT visible / hidden,默认 visiblehidden 只供模型回放continuation 内部触发),客户端历史/投影/投递一律过滤
turn_origin TEXT user / agent_continuation / scheduled,默认 user客户端据此渲染"后台结果处理"标签而不创建用户气泡

(session_id, seq) 有唯一索引,防止并发写入重复序号。物理删除 session 会通过外键级联删除 messages普通对话删除使用 deleted_at 软删除,因此保留关联行。索引 (session_id, client_visibility, seq) 支撑按可见性分层查询。

context_checkpoints 表schema v10

checkpoint 只保存累计摘要和精确 raw-tail 边界,不复制或删除原始消息。每个 Session 的 active_context_checkpoint_id 最多指向其中一行;历史行保留用于审计。

字段 说明
id checkpoint ID主键
session_id / generation 所属 Session 与单调提交代;组合唯一
parent_checkpoint_id 上一个累计 checkpoint审计链
summary 不含 Provider 私有 reasoning 的累计摘要
first_retained_seq Provider 原样保留尾部的第一条 durable seq
source_max_seq 生成候选时快照的最大 seq
trigger_reason manual / auto / overflow
provider_kind / model 生成摘要的 Provider/model
tokens_before / tokens_after 候选验证和诊断数据
degraded 是否为 Provider overflow 或发送前硬超限的确定性无语义降级
created_at 创建时间

checkpoint 插入、Session 活动指针更新与 context_generation 递增在同一事务内完成。/clear 原子删除 messages 并使活动 checkpoint 失效;只有物理删除 Session 才会通过外键级联删除全部 checkpoint普通 /delete 软删除会保留 checkpoint 行。

agent_runs 表schema v8Agent 编排)

每次具名委托foreground 与 background 一致)先落库再执行;execution_id 条件更新保证迟到结果丢弃。批量委托只是多个 run 的集合不再存在组头schema v7 的 agent_run_groups 表已删除)。

字段 类型 说明
id TEXT PK run ID
root_session_id TEXT 根会话
parent_run_id TEXT FK 父 runRESTRICTNULL 表示 Root 直接委托
caller_agent_id / caller_scope_id TEXT 调用方身份Root 的 caller_scope_id 固定 "ROOT"
agent_id / definition_hash / provider_profile TEXT Definition 快照(绑定运行代,运行中不热切换)
provider_name / model_id TEXT Provider 与模型
mode TEXT foreground / background
depth INTEGER 委托深度(>=1
plan_item_id TEXT 绑定计划子项(接纳时原子领取)
execution_id TEXT 执行尝试 ID唯一索引
task / context_json TEXT 任务与调用方上下文
budget_json TEXT 树级剩余预算
signal_contract_json / signal_delivery TEXT Definition 信号契约快照与投递 lanequeue/steer
status TEXT queued / running / waiting_children / completed / failed / timed_out / cancelled / interrupted
result / error TEXT 终态完整结果/错误get_result 与 tool 结果同源)
prompt_tokens / completion_tokens / cost INTEGER/REAL Provider usage
tool_calls_count / iterations INTEGER 执行统计
runtime_generation / attempt INTEGER 运行代与重试次数
completion_slot_reserved INTEGER background 完成槽预留
deadline_at / started_at / finished_at / created_at / updated_at INTEGER 时间线
revision INTEGER 客户端投影修订号

索引:execution_id 唯一、(root_session_id, caller_scope_id, idempotency_key) 部分唯一、(root_session_id, created_at DESC)(parent_run_id, created_at)(runtime_generation, status, deadline_at)(恢复扫描)。

agent_session_state 表schema v8Agent 编排)

每根会话一行inbox 容量与客户端 revision 的权威计数:

字段 说明
root_session_id TEXT PK
revision 单调客户端投影修订号
pending_event_count 未消费事件数(容量条件更新)
reserved_completion_slots 已接纳 background run 预留的完成槽
updated_at 最后更新时间

容量判断在同一写事务内做条件 UPDATEpending + reserved + 新增 <= 上限),杜绝并发 COUNT(*) 漂移。

agent_inbox_events 表schema v8Agent 编排)

background 完成/信号投递的唯一事实源:pending → leased → admitted → consumed,失败按 token 释放回 pending超限进 dead-letter崩溃靠 lease 过期恢复。

字段 说明
id TEXT PK
root_session_id TEXT
run_id TEXT FK NOT NULLRESTRICT
event_type signal / completion
event_key 去重键signal 含冷却窗口 id
delivery queue / steer
requires_continuation 是否反向启动 continuation Turncancel 产物为 false
severity / payload_json 信号级别与结构化载荷completion 含 signal_ids
status pending / leased / admitted / consumed / superseded / dead_letter
attempt_count / lease_token / lease_until / next_attempt_at 投递尝试与租约
admitted_turn_id steer 事件接纳的 Turn/stop 按此条件释放)
last_error 最近失败原因
revision 投影修订号
updated_at 最后更新时间
created_at / consumed_at / superseded_at / dead_lettered_at / fallback_notified_at / fallback_suppressed_reason 状态时间线

(run_id, event_type, event_key) 唯一signal 冷却窗去重)。消费/死信会同步递减 agent_session_state.pending_event_count

task_plans / task_items 表

task_plans 保存 session 级任务计划,通过部分唯一索引保证每个 session 最多一个 status='active' 的计划。version 在任何子项变化时递增,用于 WebSocket 快照排序和乐观并发检查。

task_items(plan_id, id) 为复合主键,因此每个计划都可使用 T1T2 等稳定显示 ID。子项状态为 pendingin_progresscompletedblockedexecutor_kindexecution_id 将并行子 Agent 执行绑定到具体子项。只有 active plan 且 execution ID 匹配时,异步结果才能提交。

memories 表

长期记忆存储。

字段 类型 说明
id TEXT PK 记忆 UUID
key TEXT UNIQUE 记忆唯一键
content TEXT 记忆内容
category TEXT 类别: knowledge / timeline
importance REAL 重要性权重 (0-1)
session_id TEXT 关联会话
created_at TEXT 创建时间
updated_at TEXT 更新时间

配套 FTS5 全文索引虚拟表 memory_fts(key, content),用于关键词搜索,通过触发器自动同步。

scheduled_jobs 表

字段 类型 说明
id TEXT PK 任务 UUID
name TEXT 任务名称
schedule TEXT 调度规则 JSONat/every/cron
prompt TEXT 任务提示词
agent_id TEXT 可选命名 AgentNULL 表示 Root
channel TEXT 目标渠道
chat_id TEXT 目标对话
delivery_policy TEXT always / on_alert / never
enabled INTEGER 是否启用 (1/0)
next_run_at INTEGER 下次执行时间
last_run_at INTEGER 上次执行时间
last_outcome TEXT 最近结构化结果ok/alert/failed/refused/unknown
locked_at INTEGER 本次领取时间
lock_owner TEXT 本次 occurrence 的唯一 owner token
lease_until INTEGER 租约到期时间
created_at INTEGER 创建时间Unix 毫秒)
updated_at INTEGER 更新时间Unix 毫秒)

Scheduler 在领取事务中插入 JobRun、快照执行/投递字段并推进下次时间。At 在领取时立即禁用;执行失败或崩溃不重放同一个 occurrence。

job_runs 表

字段 类型 说明
id INTEGER PK 自增 ID
job_id TEXT FK 关联任务,外键关联 scheduled_jobs(id)
scheduled_for INTEGER 本 occurrence 原计划时间
agent_run_id TEXT FK 顶层 AgentRun 审计记录
agent_id TEXT claim-time Agent 快照
delivery_policy TEXT claim-time 投递策略快照
target_channel / target_chat_id TEXT claim-time 目标快照
target_session_id TEXT 首次投递时固定的目标 dialog
started_at INTEGER 开始时间
finished_at INTEGER 结束时间
status TEXT claimed/running/completed/failed/timed_out/cancelled/interrupted/unknown
outcome TEXT ok/alert/failed/refused/unknown与 status 有联合约束
message TEXT 面向用户的结构化结果
diagnostic TEXT 有界内部诊断
duration_ms INTEGER 耗时(毫秒)
delivery_status TEXT awaiting_result/not_requested/suppressed/pending/delivering/delivered/failed
delivery_attempts INTEGER 持久化投递尝试次数,最多 3 次
delivery_next_attempt_at INTEGER 瞬态失败后的退避时间
delivery_lease_owner / delivery_lease_until TEXT / INTEGER outbox 领取租约
delivery_error TEXT 清洗后的投递失败摘要

JobRun 是执行结果和投递状态的唯一权威。顶层 AgentRun 与 JobRun 终态、Job 最近摘要和租约释放原子提交;启动恢复将遗留运行归为 unknown,不会自动重跑。

llm_calls 表

记录所有 LLM API 调用的请求/响应详情,自动保留最近 1000 条。

字段 类型 说明
id INTEGER PK 自增 ID
created_at INTEGER 调用时间
provider TEXT 提供商类型
model TEXT 模型名称
request_body TEXT 请求摘要 JSON旧记录可能是完整请求体
response_body TEXT 响应体 JSON
error TEXT 错误信息
duration_ms INTEGER 耗时(毫秒)

旧数据中的 request_body/response_body 可能包含用户内容,排障和导出数据库时应按敏感数据处理。新 Provider 请求的 request_body 只保存模型、消息数、工具数和 stream 标志等摘要;错误响应仍可能包含服务端回显内容。