# 三行速读

  1. 这章把工作目标从会话内 todo 升级成持久任务图。
  2. 关键是依赖关系:谁阻塞谁、谁解锁谁。
  3. 任务状态能跨会话延续,是后续运行时与团队协作基础。

# 先修知识

  • 已理解 s03 todo 的会话内边界。
  • 知道 JSON 持久化与状态同步基本逻辑。

# 读完后你应该能做到(可检验清单)

# 本篇要解决什么

s03 的 todo 只适合会话内计划。s12 要解决的是跨会话、跨阶段的工作协调:任务需要持久化,并且要有依赖关系。

核心变化:从 “临时清单” 升级为 “持久任务图”。

# 用一个类比先理解

把 todo 当便签,把 task 当项目管理系统:

  • 便签能提醒你现在做什么;
  • 项目系统能记录谁依赖谁、谁完成后解锁谁。

这就是 s12 的定位。

# 为什么这一步必须现在做

后续要做后台执行、调度、多 Agent 认领,没有持久任务图就无法稳定协作。s12 是运行时阶段的基座。

# 关键代码怎么读

# 1) TaskManager 落盘模型

1
2
3
class TaskManager:
def _load(self, task_id: int) -> dict: ...
def _save(self, task: dict): ...

任务状态写入 .tasks/task_*.json ,会话结束也不会丢。

# 2) 任务字段设计

1
2
3
4
5
6
7
8
task = {
"id": self._next_id,
"subject": subject,
"status": "pending",
"blockedBy": [],
"blocks": [],
"owner": "",
}

blockedBy/blocks 是依赖图关键字段,不是装饰。

# 3) 完成任务触发解锁

1
2
if status == "completed":
self._clear_dependency(task_id)

完成不是只改自己状态,还会影响下游节点是否可执行。

# 4) 任务工具接入统一 loop

1
2
3
4
5
6
7
TOOL_HANDLERS = {
...,
"task_create": ...,
"task_update": ...,
"task_list": ...,
"task_get": ...,
}

任务系统与基础文件工具共用一个调用管道,架构一致性很好。

# 你可以怎么复现

  1. 建三个有依赖的任务(A -> B -> C)。
  2. 完成 A,观察 B 是否自动解除阻塞。
  3. 重启会话,检查任务图是否仍在。

# 常见误区

  • 误区 1:把 task 当会话临时计划。
  • 误区 2:只记录状态,不维护依赖。
  • 误区 3:完成任务后不清理下游阻塞。

# 一句话总结

s12 让系统从 “会话驱动” 走向 “工作图驱动”,这是长期执行能力的关键转折。

# 补充解读:任务图的细节行为

# A. _max_id() 保证 ID 连续增长

1
2
ids = [int(f.stem.split("_")[1]) for f in self.dir.glob("task_*.json")]
return max(ids) if ids else 0

这让任务 ID 在重启后仍然连续,不会重号。

# B. update() 同时维护双向依赖

1
2
3
4
5
6
if add_blocks:
task["blocks"] = list(set(task["blocks"] + add_blocks))
for blocked_id in add_blocks:
blocked = self._load(blocked_id)
if task_id not in blocked["blockedBy"]:
blocked["blockedBy"].append(task_id)

这是容易忽略的点:依赖关系要双向同步,不能只改一侧。

# C. list_all() 的可读输出

1
marker = {"pending": "[ ]", "in_progress": "[>]", "completed": "[x]", "deleted": "[-]"}

标记化输出虽然简单,但极大提升了任务面板可读性。

# D. task 工具作为 “统一入口”

任务创建、查询、更新都通过工具调用进入 loop,说明任务系统不是旁路模块。

# 进阶练习

  1. 为任务加 due_date 字段,并扩展 list 输出。
  2. 增加 “循环依赖检测”,防止 A->B->A。
  3. 增加 “批量解锁报告”,显示一次完成解锁了哪些任务。

# 再补一层:任务图建模的实践建议

# 1) 任务粒度怎么定

一个实用原则:单个任务应当在一次稳定工作块里可完成(比如 30~120 分钟)。过大难追踪,过小会产生大量管理噪音。

# 2) 依赖字段怎么用才不会乱

  • blockedBy 表示 “我依赖谁”。
  • blocks 表示 “我解锁谁”。

两者要么双向维护,要么只存一边并动态计算。教学版选择双向,读起来更直观。

# 3) owner 字段什么时候写

建议在 “认领” 那一刻写入,而不是创建时就填。否则任务可能长期显示归属错误。

# 4) deleted 与 completed 的区别

  • completed : 目标达成。
  • deleted : 目标取消或失效。

这两个状态在统计报表里意义完全不同,别混用。

# 统一术语口径(本章)

  • Task Record :持久化任务节点(目标对象)。
  • blockedBy :当前任务依赖的前置任务集合。
  • blocks :当前任务完成后可解锁的后置任务集合。

# 章节衔接(从易到难)

  • 本章解决 “任务目标持久化”。
  • 下一章 s13 进入 “运行时执行槽位与后台任务机制”。