MaxHu-xuan / task-state-guard
git clone https://github.com/MaxHu-xuan/task-state-guard.git
v0.1.0 · 1mo ago
Reconcile stuck AI-agent tasks after restarts and timeouts. Preview SQLite changes, close stale delivery states, and never guess success.
+19
stars, 24h · #1,900
+~56
stars, 7 days · #3,589
+~240
stars, 30 days · #3,296
968
★ total · +6% this week
8
forks · 0 open issues
Star history (as recorded here)
LanguagePython
LicenseApache-2.0
Created2026-08-23 (2mo ago)
Last push1mo ago
Watchers5
OwnerUser
GitHub topics
agent-runtimeai-agentsdelivery-stateidempotencyjob-recoverypythonrestart-reconciliationsqlitestale-taskstask-statetask-state-machinetimeout-reconciliationworkflow-observability
Links
README excerpt
# TaskStateGuard(任务状态守护) 中文 · English · 运行合成演示 · Technical reference ## 中文 服务重启后,`running` 任务和 `pending` 投递很容易继续留在界面里,却没人能确认它们 是否真的还在工作。TaskStateGuard 是面向 AI 智能体、后台 worker 和本地工作流的 嵌入式 SQLite 状态对账护栏。它把任务终态与投递终态分开,按明确的截止时间和 宽限期收敛遗留状态;你可以先看只含汇总数字的预览,再决定是否应用,`doctor` 健康检查同样不会列出任务明细。 它解决的是任务状态对账(task state reconciliation)和重启后卡住任务的状态收敛 (stuck task recovery)。它不是队列、执行器或计算续跑工具,也不承诺恰好一次;系统没有 观测到成功或投递回执时,TaskStateGuard 不会把未知结果猜成成功或已送达。 ### 三个工具怎么选 | 你需要解决的问题 | 选择 | |---|---| | 重启后核对卡住任务、超时与待投递状态,不把未知结果猜成成功 | TaskStateGuard(任务状态守护),当前项目 | | 分享或迁移聊天导出前,本地检查疑似秘密、个人信息形态、格式、SQLite 与扫描盲区 | ChatArchiveGuard(聊天归档守护) | | 确认最终 PPTX 及随附验收证据仍匹配结构检查后生成的 HMAC 签名收据 | ArtifactProof(PPTX 交付物验真) | 三个项目都可以独立使用;它们分别守护状态、聊天归档和 PPTX 交付物,不会互相读取数据。 ### 它能带来什么 | 你遇到的问题 | TaskStateGuard 给出的结果 | |---|---| | 服务重启后,一批任务一直显示 `running` | 超过截止时间或活跃宽限期的任务转为 `timed_out`;仍然新鲜的任务保持不变 | | 任务已经结束,但用户是否收到结果并不确定 | 投递状态继续保持 `pending`,直到真实回执或投递宽限期到期 | | 内部子任务完成后不应单独向用户投递 | 终态内部任务在宽限期后转为 `not_applicable`,不会伪装成已送达 | | 收敛遗留状态前需要知道会改动多少记录 | `reconcile --dry-run` 返回同一时刻将发生的聚合计数,不修改任务、事件或数据库 | | 运维需要判断工作流账本是否可信 | `doctor` 检查数据库、schema、状态、时间戳和事件链,只返回聚合计数 | | Linux、macOS 和 Windows 需要共用一套状态语义 | 状态机一致;文件保护按 POSIX 权限或外部管理的 Windows DACL 分别处理 | 适合以下场景: - AI 智能体运行时在重启后需要识别失联任务; - worker 服务需要区分任务终态和投递状态; - 本地工作流需要处理超时与重启,并使用可审计的宽限期; - 运维希望增加工作流可观测性(workflow observability),但不想把提示词或任务正文 写入诊断账本。 ### 状态模型 任务状态: [code] 任务可以从 `queued` 或 `running` 进入终态。终态不可改写;重复写入相同终态是幂等的, 写入冲突终态会被拒绝。 投递状态: [code] 投递状态只能在任务进入终态后关闭。外部投递任务只有收到真实传输回执后才能标记为 `delivered`;无需直接投递的内部任务只能标记为 `not_applicable`。 这两套状态机回答不同问题: - 任务终态回答工作是否结束、以什么结果结束; - 投递状态回答结果是否真实送达,或是否根本不需要直接送达。 ### 快速开始 #### 1. 安装 TaskStateGuard 对于已经发布到 PyPI 的版本,普通用户建议在虚拟环境中安装 TaskStateGuard。 Linux 或 macOS: [code] Windows PowerShell: [code] 如需审阅尚未发布的修改或参与开发,请先确认源码来源和目标提交,再在已核对的源码仓库 根目录创建独立虚拟环境,并将最后一条安装命令改为 `python -m pip install .` (Windows 使用 `.\.venv\Scripts\python.exe -m pip install .`)。 支持 CPython 3.11 至 3.14。运行时代码只使用 Python 标准库,不包含网络请求或遥测。 #### 2. 运行完全合成的演示 演示脚本随源码仓库提供,不包含在 wheel 中。请从仓库根目录运行;它只使用固定的公开 样例状态,在系统临时目录创建 SQLite,调用真实 CLI 完成 preview、apply、幂等复查和 `doctor`,结束后自动删除临时数据库。它不读取本机任务数据, 也不包含提示词、消息、任务正文或真实标识。 Linux 或 macOS: [code] Windows PowerShell: [code] 真实演示中的前三个聚合结果如下;` ` 是刻意使用的、不包含本机信息的 路径占位符: [code] 第三次没有再次改写已经闭合的记录;仍保留的 `queued` 和刚刚进入 `timed_out` 的投递解释了 两个 retained 计数。完整命令与只含汇总数字的 `doctor` 输出由脚本直接打印,并在测试中 连续运行两次验证一致性。 #### 3. 只记录真实发生的状态变化 [code] 在 Windows 上,数据库父目录必须提前存在,并由管理员或部署系统设置为仅服务账户可访问的 私有 DACL。只有确认该边界已经建立后,才传入 `allow_external_acl=True`。 #### 4. 先预览,再执行重启收敛 [code] `--dry-run` 使用与实际执行相同的判断规则,但不会修改任务、事件或数据库。时间会继续前进, 并发 worker 也可能更新状态,因此预览只代表预览时刻;执行前应核对返回的 `dry_run` 和 `applied` 字段。 CLI 的 dry-run 会以只读模式打开一个已经存在、已经采用 WAL 且权限边界合格的账本;它 不会创建数据库、收紧文件权限或迁移 schema。安全的 schema v1 可以直接预览并保持为 v1;普通执行仍按原有默认行为迁移到 v2。嵌入 Python 时,如果连构造阶段也必须只读,请 使用 `Ledger(path, read_only=True)`,并只调用读取操作或 `dry_run=True` 的收敛。 数据库已干净关闭且没有 WAL/SHM 时,TaskStateGuard 会对不超过 64 MiB 的主库做两次 身份、时间和 SHA-256 一致性读取,再把私有副本载入内存;不会用 SQLite 的 immutable 模式直接读取可能并发变化的源文件,也不会创建临时副本。读取期间出现 writer 或 ch