Run 生命周期

Run 是 wescode 中一次完整的 Agent 执行过程。本文介绍 Run 的创建、执行、事件流和终止路径。


Run 概念

一次 Run 是从用户发送消息到 AI 完成响应的完整过程:

用户发送消息
    ↓
cell.Runtime().Run(ctx, AppRunRequest{...})
    ↓
Agent Loop(工具调用循环)
    ↓
CognitiveSettlement(认知结算)
    ↓
Run 结束

每次 Run 返回一个事件流(<-chan engine.Event),消费方通过流式接收事件来呈现 AI 响应。


AppRunRequest 必填字段

字段类型必填说明
Actorstring✅请求主体(SD-15,空 → ErrActorRequired)
Modelstring✅模型名(INV-MODEL-01,空 → ErrModelRequired)
SessionIDstring✅会话 ID
AgentIDstring推荐Agent ID
Messages[]Message✅消息列表

示例

events, err := cell.Runtime().Run(ctx, wesgine.AppRunRequest{
    Actor:     "local",                    // ★ 必填
    Model:     "claude-sonnet-4-20250514", // ★ 必填
    SessionID: "s-abc123",
    AgentID:   "code-assistant",
    Messages:  []wesgine.Message{
        {Role: "user", Content: "帮我重构这个函数"},
    },
})

Run 事件流

Run 通过事件流返回进展信息:

核心事件

事件类型说明
EventStreamDeltaLLM 流式输出片段
EventToolCall工具调用开始
EventToolResult工具调用结果
EventDoneRun 正常完成
EventErrorRun 错误
EventInterruptedRun 被中断

Plan 事件

事件类型说明
EventPlanCreatedPlan 创建
EventPlanUpdatedPlan 步骤更新
EventPlanCompletedPlan 完成
EventPlanInterruptedPlan 中断
EventPlanNudgePlan Nudge 提醒

其他事件

事件类型说明
EventBudgetStatus预算状态更新
EventCycleWarningCycleDetector 警告
EventHITLRequestHITL 审批请求

Run 终止路径

Run 有 11 种终止原因:

终止原因类型说明
end_turn正常AI 主动结束
interrupted用户用户中断(/stop)
context_cancelled用户context 取消(窗口关闭)
cycle_detected引擎检测到死循环
budget_exhausted外部预算耗尽
error_streak引擎连续错误(伪进展)
quality_revision_limit引擎质量修订上限
cognitive_error引擎认知内部错误
execute_error引擎执行错误
panic_stop引擎崩溃停止
missing_terminal_event保底缺少终端事件(异常)

Run 与 SSE 解耦(INV-RUN-DETACH)

Run 生命周期始终与传输层(SSE / HTTP 连接)解耦:

SSE 连接建立 → Run 开始
SSE 连接断开 → Run 继续执行(不取消!)
Run 完成 → 事件存入 RunEventBuffer
SSE 重连 → 从 RunEventBuffer 续播

取消 Run 的唯一途径

途径说明
POST /sessions/{sid}/interrupt用户主动中断
CycleDetector HITL 超时真循环检测后用户无响应
ErrorStreakDetector HITL 超时伪进展检测后用户无响应
BudgetCheckFn Exhausted外部预算检查返回耗尽
Cell StopCell 生命周期结束

引擎不因 counter 阈值主动终止(INV-TERM-01)。


CognitiveSettlement

Run 终态必须包含 CognitiveSettlement 产物(INV-CTX-40 / INV-COORD-13):

Run 终止(任何路径)
    ↓
CognitiveSettlement 执行
    ├── 产出 SessionState
    ├── 产出 Memory entries
    ├── 产出 Reflections
    └── 产出 Learnings
    ↓
Run 完成

覆盖所有终止路径

终止路径Settlement
end_turn✅ 执行
interrupted✅ 执行
cycle_detected✅ 执行
budget_exhausted✅ 执行
error_streak✅ 执行
context_cancelled✅ 执行
panic_stop❌ 唯一例外

Run 终端事件保证(INV-TERM-04)

runLoop 的每个 return 路径必须在返回前发出终端事件:


wescode 中的 Run

chatInFlight 锁(INV-WS-11)

wescode 中,每个 workspace 同时最多一个 Chat Run:

用户发送消息
    ↓
chatInFlight 加锁(per workspace key)
    ↓
Run 执行
    ↓
收到终端事件(done/error/interrupted)
    ↓
chatInFlight 解锁

锁的生命周期 = 用户可见生成轮次,不是 chat/send RPC。RPC 返回后的收尾(Settlement、SaveExplorationPaths、CKG 写库)是后台整理,不占用发送权。

Run 后台整理

Run 终端事件发出后,还有后台工作:

EventDone 发出(chatInFlight 解锁,用户可发新消息)
    ↓  ← 后台 goroutine
SaveExplorationPaths(CKG 更新)
CognitiveSettlement(认知结算)
CKG WriterDB 写入

这些后台任务不阻塞用户交互。


事件消费示例

events, err := cell.Runtime().Run(ctx, req)
if err != nil {
    return err
}

for evt := range events {
    switch evt.Type {
    case engine.EventStreamDelta:
        // 流式输出
        fmt.Print(evt.Delta)
    case engine.EventToolCall:
        // 工具调用
        log.Info("tool call", "name", evt.ToolName)
    case engine.EventDone:
        // 完成
        log.Info("done", "reason", evt.DoneReason)
    case engine.EventError:
        // 错误
        log.Error("error", "kind", evt.ErrorKind)
    }
}

常见问题

Q:为什么关闭浏览器后 AI 还在执行?

Run 与 SSE 连接解耦(INV-RUN-DETACH)。关闭连接不取消 Run。使用 /stop 或 POST /sessions/{sid}/interrupt 显式中断。

Q:Run 终端事件缺失怎么办?

terminal guard 会合成 EventError(missing_terminal_event)。检查 Go 后端日志中是否有 phaseReturn 路径未发出终端事件的问题。