/** * S-381(core 7.22.0 [ref] 的 server 半场;提货单 [ref] ⓪ @server 第 3 条 / 判据帖 [ref] G1)—— * **会话内 MCP re-dial** 的 wire 面: * * `POST /v1/sessions/:id/mcp/reconnect` body `{ server: string }` * → 200 `{ taskId, sessionId, server, outcome: "accepted" | "refused" | "unsupported", … }` * * 语义 = core `TaskStream.reconnectMcpServer(server)`:传输断了的那台 MCP server,在**不结束任务**的前提下 * 重拨一次号。**一台具名 server,必需,没有全部形**(core 原话:全体形会 CLOSE 掉健康连接,而拥有设备/端口的 * stdio server 恰恰是这个动词存在的理由)。 * * ── 🔴 一次交易,不是一个「刷新」按钮(core 原话,必须进 UI 文案与契约)─────────────────────────────── * **失败的重拨让 server 留在断线状态** —— 旧连接在拨新号**之前**就被关(对拥有设备/端口的 stdio server 没有 * 别的顺序可用),所以一次失败的拨号花掉了一条能用的连接:server 保持断开、**它的工具从模型名册撤走**,在飞 * 调用随之失败。**在一台健康的 server 上提供「重连」按钮 = 提供一次交易**。契约 §G.7 与本面的 `outcome` * 三词都按这句话写;壳不许把它渲成无代价的刷新。 * * ── 三态映射(`unsupported` 是**本仓自己的词**,core 无此词)────────────────────────────────────── * · core `reconnected` → `accepted` * · core `refused` → `refused` * · core `not_declared` → `refused`(未知 server 名是**名册事实**,不是引擎能力事实) * · core **抛** `mcp.reconnect_unavailable`(本 run 未声明任何 MCP)→ `unsupported` * 🔴 **`outcome` 是唯一判别键**:三态**全部走 200**。HTTP 状态只回答「动词有没有到达引擎」——与 steer 回执的 * 「branch on `delivery`, not the status」同一条律。把 `refused` 挂到 4xx 会让同一件事有两个判别键,而 * `unsupported` 挂 409 更会把「这条 run 没有 MCP 面」谎报成一个活性问题。 * * ── 下一步动作按 `status`,不解析 `reason`(core [ref] 键表逐字)──────────────────────────────── * `status.errorCode` / `status.httpStatus` 是机器面(`http_status` 401 是一扇重新授权的门,`spawn_failed` 是 * 缺二进制);`reason` 是**人读**的一句话,经本仓 `redactSecrets` + 定长截断后投出(它可能嵌远端文本), * 消费端**不许**解析它。名册**按 `tools` 的在场性**投成 `toolNames`(present-iff),**不按 `outcome`**。 * * ── 查找与拒绝形(与 steer / capture-optout **同一只**,不新造)─────────────────────────────────── * 路径是 session,动词挂在 **run 句柄**上 ⇒ 会话属主门(`sessionStorage.ownerOf`,未知与他人**同码同串** * 404 无 oracle,与 `POST /v1/sessions/:id/notify` 逐字同形)→ `getActiveTaskId` 取本会话的活 run → * `steerableRuns` 取本副本活流。非 live 的四臂一码 409 `steering.not_running`,判据取词表属主 * (`isParkedRunStatus` / `isTerminalRunStatus`)与 `runProvenElsewhere`(手抄已收编成一只谓词,S-430 起同住 `plugins/store-contracts.ts`)。 * 显式 operator 可重拨任何租户的会话(监督动作,与 notify / steer 同臂;**不是** bare `isOperator`)。 * * ── 计费/门 ───────────────────────────────────────────────────────────────────────────────────── * 零模型工作(不进 billable;不吃 drain / roster-pending);mutating ⇒ `rateLimited`。能力位 `mcpReconnect` * = 持久 run 账面 ∧ 会话属主面(两道 501 的同一批 deps 推导出来,「说 yes 但 501」结构上不可能)。 */ import type { IncomingMessage, ServerResponse } from "node:http"; import { type RouteCtx, type RouteMatch, type RouteIdsOf } from "../route-ctx.js"; /** 本面的三词闭集 —— **`unsupported` 是本仓的词**(core 的三词是 `reconnected`/`refused`/`not_declared`)。 */ export type McpReconnectOutcome = "accepted" | "refused" | "unsupported"; export declare function handleMcpReconnect(req: IncomingMessage, res: ServerResponse, match: RouteMatch, ctx: RouteCtx): Promise; export declare const MCP_RECONNECT_ROUTES: readonly [{ readonly id: "mcp-reconnect"; readonly pattern: RegExp; readonly label: "/v1/sessions/:id/mcp/reconnect"; readonly methods: readonly ["POST"]; }]; /** 本域可分派行的 `id` 闭集 —— handler 的 `switch` 按它判穷尽(漏一口 = 编译红)。 */ export type McpReconnectRouteId = RouteIdsOf; //# sourceMappingURL=mcp-reconnect.d.ts.map