kap-server 与协议

REST 与三条 WS 通道、反射式调试 RPC、事件分发的三层过滤,以及新增的全局搜索与 Remote Control。

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

packages/kap-server(约 3.8 万行)把 agent 引擎暴露成网络服务,包描述是「Kimi Code server backed by the DI × Scope agent engine (agent-core-v2)」。v0.29.1 时它就已跑在 v2 上,如今 v2 成了唯一引擎。消费者是随 CLI 发布的 Web UI、apps/kimi-inspect,以及经 Remote Control 从远端接入的客户端;VS Code 插件依赖的则是 @moonshot-ai/kimi-code-sdk。

结构

packages/kap-server/src/
├── start.ts            引导入口(startServer)
├── routes/             REST 路由(/api/v1、/api/v2)
├── transport/          WS v1 / v3 / debug,反射 RPC 分发
├── services/           transcript、projection、history 等
├── protocol/           线协议 schema 与 asyncapi.ts
├── search/             全局消息搜索
├── middleware/ security/ openapi/ lib/
└── instanceRegistry.ts 实例注册表

依赖 agent-core-v2、transcript、minidb、remote-control,HTTP 用 fastify。原先独立的 packages/protocol 已不存在:v0.25.0 起 v2 服务端栈就不再用它(v1 wire schema 挪进了引擎各域与本包),现在是 src/protocol/——envelope、error-codes、pagination、ws-control、各个 rest-*.ts,以及 v3 用的 messages/。协议仍有机器可读文档:OpenAPI 由 @fastify/swagger 生成,另有 protocol/asyncapi.ts。

表面

/api/v1           REST
/api/v1/ws        WebSocket v1(session_event + transcript 帧)
/api/v2           REST v2(sessions、mcp)
/api/v3/ws        WebSocket v3(message protocol v3)
/api/v1/debug/*   反射式 RPC(需 --debug-endpoints)
/api/v1/debug/ws  调试 WS

v3 是新增的消息协议:V3_PROTOCOL_VERSION = '3',能力位 step_replay_v1,推送 assistant、thinking、tool_call 及其 delta、interaction、task、todo、session.state 这类「实体消息」,历史走 GET /api/v1/sessions/{session_id}/history。kimi-inspect 的会话视图已迁到 v3;随 CLI 发布的 Web UI 产物里能搜到 subscribe_v2 这类 v1 + transcript 协议字面量,搜不到 /api/v3/ws。/api/v2/sessions 则多了 view: 'flat' | 'by_workspace' 的分组视图。

反射式调试面

根 AGENTS.md 的说法仍然成立:/api/v1/debug/* 是对整个 scoped DI 注册表的反射分发,每个 Service 都能调,没有白名单。registerDebugRoutes() 用 resolveAnyScopedServiceId 按名字找服务,用 describeAllChannels 生成 GET /api/v1/debug/channels 的全量描述。挂载条件在 start.ts 第 166 行:

  const debugEndpoints = exposureClass === 'loopback' && opts.debugEndpoints === true;

三道锁:显式开关(kimi web --debug-endpoints)、只在回环地址生效(security/bindClassify.ts 把监听地址分成 loopback / lan / public)、全局 bearer 鉴权。非回环地址还有别的收紧:没有 TLS 就拒绝监听(除非 --insecure-no-tls),终端能力只在回环地址开放。

事件分发的三层

/api/v1/ws 的规则在 transport/ws/v1/sessionEventBroadcaster.ts:

第一层:全局 vs 会话级。 isGlobalEvent() 认定的全局事件——session.meta.updated,以及 event.session.*、event.workspace.*、event.config.*、event.model_catalog.*、event.plugin.*、event.capability.*、event.di.* 几族——广播给每个连接(addGlobalTarget);会话级事件只发给订阅了该会话的连接。

第二层:agent 过滤。 会话级事件还受 agent_filter 约束。

第三层:transcript 抑制。 第 1272 行:

function suppressedByTranscript(
  envelope: EventEnvelope,
  spec: TranscriptGradeSpec | undefined,
): boolean {
  if (spec === undefined) return false;
  if (isGlobalEvent(envelope.type)) return false;
  if (isAgentLifecycleEvent(envelope.type)) return false;
  const payload = envelope.payload;
  const agentId =
    typeof payload === 'object' && payload !== null
      ? (payload as { agentId?: unknown }).agentId
      : undefined;
  if (typeof agentId !== 'string') return false;
  if (gradeFor(spec, agentId) === 'off') return false;
  return TRANSCRIPT_PROJECTED_EVENT_TYPES.has(envelope.type);
}

订阅了 transcript 的连接,不再收到已被投影过的旧式事件,否则同一件事收两遍。它只是每连接的发送视图:实时发送与游标重放(getBufferedSince)都套这层过滤,缓冲里的事件一条不少。

会话活动的单一真相

「会话是否在忙」由引擎的 ISessionActivityView(session/sessionActivity/)拥有,state() 返回 busy、mainTurnActive、pendingInteraction(none / approval / question)与 lastTurnReason。kap-server 的 resolveSessionFacts() 直接读它,REST 会话列表、快照、v2 路由与 v3 WS 共用同一份结果——不在边缘自己折算。同一个事实若有两处计算,迟早分叉。

有界 journal 与追赶

TranscriptService.dispatchOps 给每批 op 分配 per-agent 连续 seq,存进内存 journal(TRANSCRIPT_OPS_JOURNAL_CAPACITY = 2000,超出丢最旧的一批),随实时 store 一起消亡。GET /sessions/{session_id}/transcript/ops?since_seq= 覆盖不了时回 complete: false,调用方回退全量刷新。基线帧 transcript.reset 不带历史条目(TRANSCRIPT_RESET_TAIL_TURNS = 0)——历史一律走 REST 分页。

新增:全局搜索与 Remote Control

全局搜索:POST /api/v1/search 背后是 IGlobalSearchService,索引存在 minidb 里(search-index 目录,缺省由 worker 线程维护)。响应里的 source 标明结果来自内存中的实时转录还是持久化索引,index_state 报告索引覆盖了多少会话。

Remote Control:packages/remote-control 是隧道客户端,把本机注册到 relay,再把 HTTP / WebSocket 流量转发到本地服务端,并用机器级锁保证单实例。kap-server 暴露 GET / POST /api/v1/remote-control 开关,CLI 对应 kimi web --rc(--remote-control)。两边都要求监听回环地址,CLI 还拒绝与 --dangerous-bypass-auth 同用。v0.42.0 起它不再需要实验开关。

实例注册表

instanceRegistry.ts 把运行中的实例登记在 ~/.kimi-code/server/instances(设了 KIMI_CODE_HOME 就在它下面)。kimi-inspect 的 Vite 开发服务器通过 GET /__inspect/servers 扫这个目录,实现零配置自动连接与运行时切换。

与 CLI 的关系

kimi web 在本地调用 kap-server 的 startServer(),并托管随 CLI 发布的 dist-web 预构建产物——Web UI 的源码已不在本仓库,缺了产物时服务端只提供 API。所以 Web 形态不需要单独部署,CLI 自带。

下一篇:klient、SDK 与 ACP。

本页目录