Power 生命周期

理解 City 持有的 Power 实例、动态调用上下文与执行租约。

Power 的所有权属于 City。city.powers.add(new MyPower()) 登记一个唯一实例;同一 Power ID 不能在一个 City 中重复注册,Agent 也不保存 Power 实例或 Registry。

两个生命周期节点

  • initialize(context):Power 加入 City 时执行一次,用于注册宿主 Action,并初始化 Power 自己拥有的长期资源。
  • dispose(context):Power 被移除或 City 关闭时执行一次,用于释放这些长期资源。
class ProviderPower extends Power {
  readonly name = "provider";

  async initialize({ storage }: PowerLifecycleContext) {
    await this.provider.open(storage.path);
  }

  async dispose() {
    await this.provider.close();
  }
}

两个节点使用同一个稳定的 PowerLifecycleContext。Agent 加入或离开 City、Session 创建或结束、 Workspace 进入或离开都不会触发 Power 生命周期,也不存在通用的 connect/disconnect。

city.powers.add() 会明确返回初始化失败。失败实例不会进入执行 Registry,因此不能贡献 Action、Hook 或 System;City 同时在 city.powers.snapshots() 中保留 status: "error" 和 last_error。 宿主应隔离单个 Power 的失败并继续启动其他主体,而不是把可选 Power 当成整个应用的启动条件。成功重试 同一 Power ID 后,错误快照会被新的 ready 状态替换。

调用上下文

Action、Hook、System 和 Availability 每次调用都会获得 City 即时投影的 PowerContext。其中的 agent、workspace、可选 session/turn 都是当前调用可以直接使用的受限对象;Workspace 是本次 调用的项目资源,不是 Power 的生命周期或默认资源隔离键。

需要长期连接、Timer、调度器或后台 Worker 时,Power 应按真实领域所有权管理它们。例如浏览器 Provider 可以在首次 Action 时按 Agent 惰性创建,聊天渠道可以按账号管理,任务调度器 可以按任务定义管理。所有这些资源最终都必须由 dispose 收口。

执行租约

Session 在每个 Step 捕获不可变的 Power 执行视图。Power 被移除后,新 Step 立即不可见;已开始的 Step 可以继续使用捕获的实例,City 会等最后一个 execution lease 释放后再调用 dispose。

city.close() 会先停止 Session,再释放 Power 和 Workspace,并汇总释放错误。一个 Power 的 dispose 失败不会阻止其他 Power 清理。