# 任务计划实际执行原理

## 核心设计思想

**任务计划没有专用执行引擎。** 计划的执行完全依赖 **system prompt 注入驱动 LLM 自主调用工具**——本质上是通过 prompt engineering 让主代理按照计划逐步执行。

## 一、完整生命周期

```
创建 → 等待审批 → 执行（LLM 驱动）→ 逐步完成 → 归档
 │        │            │                │
 子代理    Web/外部     system prompt     task_plan_step_done
 生成      批准         注入指令
```

## 二、阶段一：计划创建

### 触发

主代理 LLM 判断任务复杂，调用 `task_plan_create(description)` 工具。

### 执行过程

```
task_plan_create("下载分析报告")
  │
  ▼
检查: config.json → task_plan.accept_task == true?
  │  否 → 拒绝
  │
  ▼
检查: 是否已有 in_progress 计划?
  │  是 → 拒绝: "请先完成或中止"
  │
  ▼
调用子代理 generate_plan()
  │
  │  输入:
  │    · chat.messages → 当前对话
  │    · chat.system_prompt → 完整 prompt (截断 3000 字)
  │    · load_tool_schemas() → 所有已注册工具
  │    · get_cached_skills_info() → 技能摘要
  │    · AGENT.md → 子代理专用 prompt
  │
  │  子代理返回 JSON:
  │    {
  │      "title": "下载分析报告",
  │      "steps": [
  │        {"id":"step_1", "description":"下载文件", "tool_calls":[...]}
  │      ]
  │    }
  │
  ▼
_validate_plan()
  · title 和 steps 必填
  · steps 不超过 max_steps (10)
  · 每个 tool_call 的 action 必须在已注册工具中
  · 步骤 ID 不重复
  │
  ▼
保存到 users/<name>/task-plan/plan_xxxx.json
  初始状态: status="pending", current_step=0
  │
  ▼
返回给主代理: "OK: 已创建计划... ⚠ 请告知用户点击「批准」按钮"
```

## 三、阶段二：审批

### Web UI 批准

```
POST /api/task-plan/<plan_id>/resume
  → plan["status"] = "in_progress"
  → invalidate_prompt_cache(user_dir)
```

### 外部消息批准（QQ/Telegram）

```
用户: "/plan approve plan_xxxx"
  → agent.approve_plan() → status = "in_progress"
  → agent.chat("任务计划已批准，请继续执行该计划。")
  → 这条消息触发主代理开始执行！
```

### Web API 端点

| 端点 | 方法 | 功能 |
|------|------|------|
| `/api/task-plan` | GET | 列出所有计划 |
| `/api/task-plan/<id>` | GET | 查看单个计划 |
| `/api/task-plan/<id>/resume` | POST | 恢复/批准 → in_progress |
| `/api/task-plan/<id>/pause` | POST | 暂停 → paused |
| `/api/task-plan/<id>/abort` | POST | 中止 → aborted |
| `/api/task-plan/<id>/reject` | POST | 拒绝 → aborted |
| `/api/task-plan/<id>/edit-step` | POST | 编辑步骤 |
| `/api/task-plan/clear-completed` | DELETE | 清理已完成计划 |

每个端点都调用 `invalidate_prompt_cache()` 确保 LLM 看到最新状态。

## 四、阶段三：执行（核心机制）

### System Prompt 注入

计划状态变更后，`build_system_prompt()` 在末尾注入：

```
## 活跃任务计划 [plan_xxxx]
**下载分析报告** — 执行中
  ✅ step_1: 下载文件
      结果: 已保存到 xxx.mp4
  🔄 step_2: 分析内容
  ⬜ step_3: 生成报告

**请连续执行所有待完成的步骤，不要中断。完成每步后立即调用
task_plan_step_done(plan_id, step_id, result) 并接着执行下一步，
直到全部步骤完成（计划自动标记为 completed）。
如遇失败调用 task_plan_step_fail。不要在步骤之间停下来询问用户。**
```

### 执行循环

```
LLM 读到 system prompt 中的计划指令
  │
  ▼
LLM 执行 step_2: 调用 read_file(path="xxx.mp4")
  │
  ▼
run_chat_turn() 工具调用循环:
  │  LLM 返回 tool_calls → 执行工具 → 结果返回 LLM
  │  LLM 继续推理 → 调用 task_plan_step_done("plan_xxxx", "step_2", "内容已分析...")
  │
  ▼
task_plan_step_done():
  │  step["status"] = "completed"
  │  step["result"] = "内容已分析..."
  │  plan["current_step"] = 2
  │  _save_plan()
  │  invalidate_prompt_cache()
  │
  ▼
下一轮 build_messages() → system prompt 更新 (step_2 ✅, step_3 🔄)
  │
  ▼
LLM 继续执行 step_3...
  │
  ▼
全部完成 → plan.status = "completed"
```

## 五、状态机

```
pending ──(批准)──→ in_progress ──(全部完成)──→ completed
                       │    ↑
                       │    │ (恢复)
                       ▼    │
                     paused ←──(单步失败)── task_plan_step_fail
                       │
                       ▼ (中止)
                    aborted
```

### 不同状态的 System Prompt 指令

| 状态 | 注入指令 |
|------|----------|
| `pending` | "**等待用户审批，请勿执行。** 告知用户点击「批准」。" |
| `in_progress` | "**请连续执行所有待完成的步骤，不要中断...**" |
| `paused` | "**此计划已暂停。不要主动执行步骤，等待用户确认继续。**" |

## 六、关键设计要点

### 1. 没有专用执行引擎
计划执行完全依赖主代理的 `run_chat_turn()` 工具调用循环。计划只是 system prompt 中的一段指令文本。

### 2. 缓存失效驱动状态同步
```
状态变更 → _save_plan() → invalidate_prompt_cache()
  → 下一次 build_messages() → build_system_prompt() 重建
  → LLM 读到最新状态 → 决定下一步行为
```

### 3. 步骤结果截断
```python
if s.get("result"):
    result_text = s["result"][:200]   # 只保留前 200 字
```

### 4. 防竞态保护
```python
def _save_plan(user_name, plan_id, plan):
    if plan_path.exists():
        current = json.loads(plan_path.read_text())
        if current.get("status") == "aborted":
            return   # 用户已中止，不再覆写
```

### 5. 计划存储
```
users/<name>/task-plan/plan_xxxx.json
{
  "id": "plan_xxxx",
  "title": "下载分析报告",
  "description": "...",
  "status": "in_progress",
  "current_step": 1,
  "steps": [
    {"id":"step_1", "description":"下载文件", "status":"completed", "result":"..."},
    {"id":"step_2", "description":"分析内容", "status":"in_progress", "tool_calls":[...]}
  ],
  "created_at": "2026-05-17T12:00:00"
}
```
