picoclaw/flow_diagrams.md

397 lines
21 KiB
Markdown
Raw Normal View History

# Agent Loop 流程图对比
## 1. Incoming (refactor/agent) 流程
### 整体架构
```
User Message
Message Bus (串行队列)
processMessage()
runAgentLoop()
newTurnState() → 创建 turnState
runTurn()
registerActiveTurn(ts) ← 设置 al.activeTurn = ts (单例)
[Turn 执行循环]
clearActiveTurn(ts) ← 清除 al.activeTurn = nil
```
### runTurn() 详细流程
```
┌─────────────────────────────────────────┐
│ runTurn(ctx, turnState) │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ 1. 注册 activeTurn (单例) │
│ al.registerActiveTurn(ts) │
│ defer al.clearActiveTurn(ts) │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ 2. 发送 TurnStart 事件 │
│ al.emitEvent(EventKindTurnStart) │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ 3. 加载 Session History & Summary │
│ history = Sessions.GetHistory() │
│ summary = Sessions.GetSummary() │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ 4. 构建消息 │
│ messages = BuildMessages(...) │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ 5. 检查 Context Budget │
│ if isOverContextBudget() { │
│ forceCompression() │
│ emitEvent(ContextCompress) │
│ } │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ 6. 保存用户消息到 Session │
│ Sessions.AddMessage("user", ...) │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ 7. Turn Loop (迭代执行) │
│ for iteration < MaxIterations {
│ ┌─────────────────────────────┐ │
│ │ 7.1 调用 LLM │ │
│ │ callLLM() │ │
│ │ emitEvent(LLMStart) │ │
│ └─────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────┐ │
│ │ 7.2 处理 Tool Calls │ │
│ │ for each toolCall { │ │
│ │ emitEvent(ToolStart)│ │
│ │ executeTool() │ │
│ │ emitEvent(ToolEnd) │ │
│ │ } │ │
│ └─────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────┐ │
│ │ 7.3 检查中断 │ │
│ │ if gracefulInterrupt { │ │
│ │ break │ │
│ │ } │ │
│ └─────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────┐ │
│ │ 7.4 处理 Steering Messages │ │
│ │ pollSteering() │ │
│ └─────────────────────────────┘ │
│ } │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ 8. 保存最终响应到 Session │
│ Sessions.AddMessage("assistant", ...) │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ 9. 发送 TurnEnd 事件 │
│ al.emitEvent(EventKindTurnEnd) │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ 10. 返回 turnResult │
│ {finalContent, status, followUps} │
└─────────────────────────────────────────┘
```
### 关键特点
-**事件驱动**: 每个阶段都发送事件到 EventBus
-**Hook 集成**: 在 before_llm, after_llm, before_tool, after_tool 触发 Hook
-**单 Turn**: 使用 `activeTurn` 单例,同一时间只有一个 turn
-**无并发**: 不支持多个 session 同时执行 turn
---
## 2. HEAD (feat/subturn-poc) 流程
### 整体架构
```
User Message
Message Bus
processMessage()
runAgentLoop()
检查 Context 中是否有 turnState
├─ 有 → 复用 (SubTurn 场景)
└─ 无 → 创建新的 rootTS
存储到 activeTurnStates[sessionKey]
runLLMIteration()
[并发 SubTurn 支持]
```
### runAgentLoop() 详细流程
```
┌─────────────────────────────────────────┐
│ runAgentLoop(ctx, agent, opts) │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ 1. 检查是否在 SubTurn 中 │
│ existingTS = turnStateFromContext() │
│ if existingTS != nil { │
│ rootTS = existingTS (复用) │
│ isRootTurn = false │
│ } else { │
│ rootTS = new turnState │
│ isRootTurn = true │
│ } │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ 2. 注册 Turn State (支持并发) │
│ if isRootTurn { │
│ al.activeTurnStates.Store( │
│ sessionKey, rootTS) │
│ defer activeTurnStates.Delete() │
│ } │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ 3. 记录 Last Channel │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ 4. 构建消息 │
│ messages = BuildMessages(...) │
│ messages = resolveMediaRefs(...) │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ 5. 覆盖 System Prompt (如果需要) │
│ if opts.SystemPromptOverride != "" { │
│ // 用于 SubTurn 的特殊 prompt │
│ } │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ 6. 保存用户消息 │
│ if !opts.SkipAddUserMessage { │
│ Sessions.AddMessage(...) │
│ } │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ 7. 执行 LLM 迭代 │
│ finalContent, iteration, err = │
│ runLLMIteration(ctx, agent, ...) │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ 8. 轮询 SubTurn 结果 (如果是根 turn) │
│ if isRootTurn { │
│ results = │
│ dequeuePendingSubTurnResults()│
│ // 将结果注入到最终响应 │
│ } │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ 9. 处理空响应 │
│ if finalContent == "" { │
│ finalContent = DefaultResponse │
│ } │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ 10. 保存助手响应 │
│ Sessions.AddMessage("assistant"...) │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ 11. 发送响应 (如果需要) │
│ if opts.SendResponse { │
│ bus.PublishOutbound(...) │
│ } │
└─────────────────────────────────────────┘
```
### SubTurn 执行流程
```
┌─────────────────────────────────────────┐
│ Tool: spawn │
│ args: {task: "...", label: "..."} │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ SpawnTool.Execute() │
│ if spawner != nil { │
│ // 直接 SubTurn 路径 │
│ } else { │
│ // SubagentManager 路径 │
│ } │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ spawner.SpawnSubTurn() │
│ ┌─────────────────────────────────┐ │
│ │ 1. 生成 SubTurn ID │ │
│ │ subTurnID = atomic.Add() │ │
│ └─────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────┐ │
│ │ 2. 创建 SubTurn Context │ │
│ │ subCtx = withTurnState(...) │ │
│ │ // 继承父 turnState │ │
│ └─────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────┐ │
│ │ 3. 获取并发信号量 │ │
│ │ <-rootTS.concurrencySem
│ │ defer release │ │
│ └─────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────┐ │
│ │ 4. 启动 Goroutine │ │
│ │ go func() { │ │
│ │ result = runAgentLoop( │ │
│ │ subCtx, ...) │ │
│ │ // 将结果发送到 channel │ │
│ │ rootTS.pendingResults <-
│ │ }() │ │
│ └─────────────────────────────────┘ │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ 父 Turn 继续执行 │
│ - 不等待 SubTurn 完成 │
│ - SubTurn 异步执行 │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ 父 Turn 轮询 SubTurn 结果 │
│ results = dequeuePendingSubTurnResults│
│ for each result { │
│ // 注入到响应或下一次迭代 │
│ } │
└─────────────────────────────────────────┘
```
### SubTurn 层级结构
```
Root Turn (Session A)
├─ turnState (depth=0)
│ ├─ turnID: "session-a"
│ ├─ pendingResults: chan
│ └─ concurrencySem: chan (限制并发数)
├─ SubTurn 1 (depth=1)
│ ├─ turnState (继承父 context)
│ ├─ parentTurnID: "session-a"
│ └─ 独立的 goroutine
├─ SubTurn 2 (depth=1)
│ ├─ turnState (继承父 context)
│ ├─ parentTurnID: "session-a"
│ └─ 独立的 goroutine
└─ SubTurn 3 (depth=1)
└─ SubTurn 3.1 (depth=2) ← 嵌套 SubTurn
└─ ...
Root Turn (Session B) - 并发执行
├─ turnState (depth=0)
└─ ...
```
### 关键特点
-**并发支持**: `activeTurnStates` map 支持多个 session 并发
-**SubTurn 层级**: 通过 context 传递 turnState支持嵌套
-**并发控制**: `concurrencySem` 限制 SubTurn 并发数
-**异步执行**: SubTurn 在独立 goroutine 中执行
-**结果回传**: 通过 `pendingResults` channel 传递结果
-**无事件系统**: 没有 EventBus 和 Hook 集成
---
## 3. 对比总结
| 特性 | Incoming (refactor/agent) | HEAD (feat/subturn-poc) |
|------|---------------------------|-------------------------|
| **并发模型** | 单 Turn (串行) | 多 Turn (并发) |
| **Turn 管理** | `activeTurn` (单例) | `activeTurnStates` (map) |
| **事件系统** | ✅ EventBus | ❌ 无 |
| **Hook 系统** | ✅ HookManager | ❌ 无 |
| **SubTurn** | ❓ 未实现或不同方式 | ✅ 完整实现 |
| **并发 Session** | ❌ 不支持 | ✅ 支持 |
| **嵌套 SubTurn** | ❌ 不支持 | ✅ 支持 |
| **架构复杂度** | 简单 | 复杂 |
| **可扩展性** | 高 (Hook) | 低 |
| **调试难度** | 低 | 高 (并发) |
---
## 4. 混合方案流程
结合两者优点的混合方案:
```
┌─────────────────────────────────────────┐
│ runAgentLoop(ctx, agent, opts) │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ 1. 检查 SubTurn Context │
│ existingTS = turnStateFromContext() │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ 2. 创建/复用 turnState │
│ ts = newTurnState(agent, opts, ...) │
│ if isRootTurn { │
│ activeTurnStates.Store(key, ts) │
│ } │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ 3. 执行 Turn (带事件和 Hook) │
│ result = runTurn(ctx, ts) │
│ ├─ emitEvent(TurnStart) │
│ ├─ Hook: before_llm │
│ ├─ callLLM() │
│ ├─ Hook: after_llm │
│ ├─ Hook: before_tool │
│ ├─ executeTool() │
│ │ └─ 如果是 spawn → SpawnSubTurn │
│ ├─ Hook: after_tool │
│ └─ emitEvent(TurnEnd) │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ 4. 处理 SubTurn 结果 │
│ if isRootTurn { │
│ pollSubTurnResults() │
│ } │
└─────────────────────────────────────────┘
```
### 混合方案优势
- ✅ 保留并发能力 (`activeTurnStates`)
- ✅ 获得事件系统 (`EventBus`)
- ✅ 获得扩展能力 (`HookManager`)
- ✅ 支持 SubTurn 并发
- ✅ 支持多 Session 并发