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.
14 KiB
PicoBot 数据库表结构
数据库为 SQLite,默认位于配置目录(~/.picobot)data/ 下的 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 ID;NULL 表示使用全部原始消息 |
context_generation |
INTEGER | checkpoint CAS 提交代;历史清空/改写时递增并清除活动指针 |
delivery_context |
TEXT | 渠道声明的可跨 Turn 复用投递上下文 JSON(如飞书 thread/root 身份);一次性 reply/reaction ID 永不写入 |
delivery_context_updated_at |
INTEGER | delivery_context 最后更新时间 |
session_turn_usage 以 turn_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,默认 visible;hidden 只供模型回放(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 v8,Agent 编排)
每次具名委托(foreground 与 background 一致)先落库再执行;execution_id 条件更新保证迟到结果丢弃。批量委托只是多个 run 的集合,不再存在组头(schema v7 的 agent_run_groups 表已删除)。
| 字段 | 类型 | 说明 |
|---|---|---|
id |
TEXT PK | run ID |
root_session_id |
TEXT | 根会话 |
parent_run_id |
TEXT FK | 父 run(RESTRICT),NULL 表示 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 信号契约快照与投递 lane(queue/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 v8,Agent 编排)
每根会话一行,inbox 容量与客户端 revision 的权威计数:
| 字段 | 说明 |
|---|---|
root_session_id |
TEXT PK |
revision |
单调客户端投影修订号 |
pending_event_count |
未消费事件数(容量条件更新) |
reserved_completion_slots |
已接纳 background run 预留的完成槽 |
updated_at |
最后更新时间 |
容量判断在同一写事务内做条件 UPDATE(pending + reserved + 新增 <= 上限),杜绝并发 COUNT(*) 漂移。
agent_inbox_events 表(schema v8,Agent 编排)
background 完成/信号投递的唯一事实源:pending → leased → admitted → consumed,失败按 token 释放回 pending,超限进 dead-letter,崩溃靠 lease 过期恢复。
| 字段 | 说明 |
|---|---|
id |
TEXT PK |
root_session_id |
TEXT |
run_id |
TEXT FK NOT NULL(RESTRICT) |
event_type |
signal / completion |
event_key |
去重键(signal 含冷却窗口 id) |
delivery |
queue / steer |
requires_continuation |
是否反向启动 continuation Turn(cancel 产物为 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) 为复合主键,因此每个计划都可使用 T1、T2 等稳定显示 ID。子项状态为 pending、in_progress、completed 或 blocked;executor_kind 和 execution_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 | 调度规则 JSON(at/every/cron) |
prompt |
TEXT | 任务提示词 |
agent_id |
TEXT | 可选命名 Agent;NULL 表示 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 标志等摘要;错误响应仍可能包含服务端回显内容。