/** * #A1([ref] 窗三件批 件3;[ref] 链的 server 前置)—— 后台 agent **名册读面** * `GET /v1/agents/roster`。 * * ## 读的是哪个店(两个「名册」概念的定界) * 树上有两个:core 的 `RosterStore`(name→agentId 绑定,agent-teams 的按名解析)与 * `BackgroundAgentStore`(durable 后台子代行)。壳要渲的是「我有哪些后台 agent、各自什么状态」—— * `RosterEntry` 身上**没有** status / spawnedAt / settledAt 这些轴,答不了;而 * `BackgroundAgentRowSummary`(store 的 content-free 列投影)恰好就是它。故本面读后者的两只既有只读口 * (`listByScope` / `listBySession`),**零 SQL schema 面**。 * * ## 路径为什么是顶层 `/v1/agents/roster` * 名册的价值正在**跨会话**(agent-teams 的按名寻址要能越过单次 run);挂进 `/v1/sessions/:id/…` 会把 * 跨会话形从 wire 上抹掉,只剩「这一次会话派了谁」。会话维不是没有,是降为**可选窄化** `?session=` * (与 `/v1/fleet/stream` 的 `?session=` 同姿势)。 * * ## 三条边界(逐条对着失败形写) * · **principal 门 + 反枚举**:身份判在店可用性判**之前**(否则「这台有没有装店」会先于 401 泄出去, * 与 `GET /v1/sessions` 的同款注释);principal 调用方**锁定自己的 scope**(`?scope=` 对它无效), * 于是别的租户的行不是「403」也不是「空 200 但 total 多 1」——它在这个名册里**根本不存在**, * 没有任何可判别面(`total` 同样是属主口径:一个多出来的计数就是存在性 oracle)。 * · **投影白名单**(照 `routes/fleet.ts` `stripT` 的姿势):逐键**显式拼**,并用 * `satisfies Record` 的处置表把「行上新增键」变成**编译错误** —— * 黑名单形在 fleet 那边被击穿过两次(currentTool / editedFiles),同一条信任边界不再靠人记全。 * · **能力位同源**:`capabilities.agentRoster` 与这里的 501 谓词是同一个 `deps.backgroundAgentStore`。 */ import type { IncomingMessage, ServerResponse } from "node:http"; import type { RouteCtx, RouteMatch, RouteIdsOf } from "../route-ctx.js"; /** 名册窗的扫描上限(与 fleet 的终态窗同姿势:读面要有界)。窗满时回体带 `truncated:true`, * `total` 于是诚实地是「窗内行数」而不是租户全量 —— 一个悄悄封顶的 total 比没有 total 更坏。 */ export declare const ROSTER_SCAN_LIMIT = 500; export declare function handleAgentRoster(req: IncomingMessage, res: ServerResponse, match: RouteMatch, ctx: RouteCtx): Promise; export declare const AGENT_ROSTER_ROUTES: readonly [{ readonly id: "agents-roster"; readonly path: "/v1/agents/roster"; readonly methods: readonly ["GET"]; }]; /** 本域可分派行的 `id` 闭集 —— handler 的 `switch` 按它判穷尽(漏一口 = 编译红)。 */ export type AgentRosterRouteId = RouteIdsOf; //# sourceMappingURL=agents-roster.d.ts.map