agent-core-v2:唯一的引擎

v1 退场、v2 接管的时间线,三层作用域与工作区实例,Service/Fiber 单元层与 Feature 接缝,以及 human 内核的边界。

作者 David更新于 第 31 篇(共 33 篇)

packages/agent-core-v2(约 13.6 万行)的包描述没变:

The unified agent engine for Kimi (v2 — DI Scope architecture)

变的是地位。v0.29.1 时本文讲的是「正在进行的 v2 重构」:v1 agent-core 仍是 CLI 主路径,v2 只在服务端落地。到 v0.43.0,packages/agent-core 目录已经不存在,代码里也搜不到回退开关 KIMI_CODE_LEGACY_FLAG——v2 是唯一的引擎,kap-server、acp-server、klient、node-sdk、migration-legacy、remote-control 都建在它上面。

v1 退场的时间线

CHANGELOG 里能找到的节点:

版本变化
0.24.0kimi server run / kimi web 默认跑 v2,v1 服务端包删除(#1617)
0.25.0服务端 v1 wire schema 挪进引擎各域与服务端包,共享 schema 包退出 v2 服务端栈(#1755)
0.33.0TUI、kimi -p、kimi acp、kimi export、kimi provider 默认跑 v2,KIMI_CODE_LEGACY_FLAG=1 可回退(#2627)
0.40.0kimi acp 不再理会 KIMI_CODE_LEGACY_FLAG(#3434)

packages/agent-core 本身在哪个版本删除,CHANGELOG 没有记。按 monorepo 全景的口径,v0.29.1 时 v1 约 6.6 万行、v2 已约 9.8 万行。

路线很典型:新架构先在服务端落地,再切 CLI 默认值并保留回退开关,最后撤掉开关、删掉旧代码。每一步都可观察、可回退。

三层作用域,外加工作区实例

作用域枚举从 _base/di/scope.ts 挪到了 app/scopes.ts,改成字符串值,并向 DI 内核声明拓扑:

export enum LifecycleScope {
  App = 'app',
  Session = 'session',
  Agent = 'agent',
}

export const SCOPE_TOPOLOGY: readonly LifecycleScope[] = [
  LifecycleScope.App,
  LifecycleScope.Session,
  LifecycleScope.Agent,
];

setScopeTopology(SCOPE_TOPOLOGY);

_base/di 只把作用域当字符串(ScopeKind = string),Scope.createChild() 按声明的拓扑拒绝「子级不高于父级」的建法。服务用 registerScopedService(scope, id, ctor, activation, domain) 注册,直接调用的有 App 级 75 处、Session 级 18 处、Agent 级 45 处;ScopeActivation 决定作用域一建就实例化还是首次解析时再建,重复注册直接报错,有意替换要用 overrideScopedService。

DI 作用域就这三层。工作区那一层在代码里不是作用域,而是 WorkspaceInstance(workspace/workspaceInstance/):App 级的 IWorkspaceInstanceManager 为每个工作区创建一个实例,它有 materializing / active / closing / disposed 四态,持有运行时注册表、单元宿主与 Program,后者按工作区装配 WorkspaceFsService、WorkspaceGitService、WorkspaceTrustService 等服务。

以恢复会话为例:App 级 ISessionManager 的 controllerForSession() 先查 ISessionIndex 拿到会话所属工作区,经 IWorkspaceInstanceManager.getOrCreate() 物化工作区实例,交给它的 SessionLifecycleService,后者用 createScopedChildHandle(…, LifecycleScope.Session, …) 建出 Session 作用域;Agent 作用域同理由 agentLifecycleService.ts 建出。

需要提醒一句:根 AGENTS.md 的项目地图写的是四层 LifecycleScope(App / Workspace / Session / Agent),还说调用方组合 ISessionIndex → IWorkspaceLifecycleService.handlerFor → handler、没有 App 级会话门面。这与 v0.43.0 的代码不符:全仓没有 LifecycleScope.Workspace,IWorkspaceLifecycleService 只出现在 node-sdk 与 kimi-inspect 的注释里,ISessionManager 仍注册在 App 级——文档走在了代码前面,读源码时以代码为准。

单元层:Service、Fiber 与贡献点

根 AGENTS.md 称之为 L3 单元层。_base/di/service.ts 的 Service 是抽象基类,同时实现 Fiber 接口:一个服务单元可以在运行时 provide() 子单元(类、函数或对象形式的 recipe,可声明 inject 与 Config),单元有 Pending / Activating / Active / Unloading / Failed 五态。

collection<T>(name) 定义集合贡献点:多方贡献、统一消费。ScopeUnits(kind) 就是其中之一,贡献进来的单元会在对应作用域创建时由 watchScopeUnits() 物化。单元的增删改由 cascadeEngine.ts 沿依赖图级联(provide / unprovide / update),并记下每次级联拆了谁、重建了谁;循环依赖仍抛 CyclicDependencyError。App 级 IFeatureManager 暴露 provideUnit / unprovideUnit / updateUnit,单元因此能在运行时热插拔。src/debug/ 的 ledger、graph、cascade 调试服务,就是 kimi-inspect 里 DI 视图的数据源。

Feature 接缝

features/ 是功能挂进引擎的统一入口。Feature 继承 Service,提供一组声明式的 contribute*():contributeService、contributeAgentService、contributeTool、contributeCommand、contributeConfig、contributeSessionModel、contributeAgentModel 等。最短的例子是 features/btw/btwFeature.ts:

export class BtwFeature extends Feature {
  static override readonly name = 'btw';

  constructor() {
    super();
    this.contributeService(LifecycleScope.Session, ISessionBtwService, SessionBtwService);
  }
}

registerFeature(BtwFeature);

contributeService 内部就是往 ScopeUnits(scope) 贡献一个单元。registerFeature() 只做登记,App 级的 FeatureAssemblyService 启动时把登记过的 recipe 逐个交给 IFeatureManager.provideUnit()。目前登记了 17 个:btw、cron、dateChange、debugEvents、externalHooks、fileHistory、goal、notify、plan、reminder、sessionInit、skill、swarm、todo、tokenCounting、tower、usage。

human 内核与导入边界

src/human/ 是另一块值得注意的区域。packages/agent-core-v2/scripts/check-import-boundaries.mjs(lint:imports)这样定位它:

human is the pure LLM/agent kernel: it never imports llm-adapter or v2 domains

反过来,只有 llm-adapter、agent/loop/machine、session/agentLifecycle 三处能 import human 的实现,其余代码只能用少数「词汇」模块(llm/message、llm/usage 等)。同一个脚本还宣告「the kosong kernel is deleted」。所以 v2 的 package.json 既不声明 @moonshot-ai/kosong,也不声明 @moonshot-ai/kaos:模型请求层是 src/human/llm 与 src/llm-adapter,执行与文件 / 进程访问走自己的 src/os/(IHostProcessService 等,见 kaos)。

另外,agent-core-v2、kap-server、transcript 是零注释区(scripts/check-no-comments.mjs 随 pnpm lint 检查),v0.29.1 时本文引用的文件头注释都已删除。

这次接管解决了什么

v1 的问题v2 的解法
服务全是单例,会话 / agent 级状态靠手工传递作用域树,容器管生命周期
功能散落在引擎各处Feature 接缝,contribute*() 声明式挂载
PermissionManager 一个类多职责permissionGate / permissionMode / permissionPolicy / permissionRules 四个域
会话活动状态在多处折算ISessionActivityView 单一真相
两代引擎长期并存服务端先行、CLI 跟进、回退开关兜底、最后删除

代价也真实:规模是 v0.29.1 时 v1 的两倍多,概念层次(作用域、工作区实例、单元、贡献点、Feature、human 边界)也更多。好在关键边界都有脚本检查,而不是靠口头约定。

下一篇:kaos 执行环境抽象。

本页目录