@sema-agent/client-core 0.72.7 → 0.72.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/README.md +2 -1
- package/dist/adapter/activeRunSelfHeal.d.ts +8 -0
- package/dist/adapter/activeRunSelfHeal.js +43 -15
- package/dist/adapter/runStream.d.ts +18 -0
- package/dist/adapter/runStream.js +32 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -0
- package/dist/mcpReconnect.d.ts +131 -0
- package/dist/mcpReconnect.js +235 -0
- package/dist/request/taskRequest.d.ts +30 -0
- package/dist/request/taskRequest.js +79 -3
- package/dist/resumeRefusalCopy.d.ts +2 -2
- package/dist/resumeRefusalCopy.js +10 -4
- package/dist/sessionMemoryStatus.d.ts +15 -1
- package/dist/sessionMemoryStatus.js +18 -0
- package/docs/INTEGRATION-CLIENTS.md +73 -8
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -49,6 +49,31 @@
|
|
|
49
49
|
> 挡住 ⇒ 本批把它机械化——④a0 对 `pending` 行**要求段头已是日期形**(`(未发布)` 直接红),阶段一
|
|
50
50
|
> commit 漏转在发布前就红,不再靠人记。
|
|
51
51
|
|
|
52
|
+
## 0.72.9(2026-09-18)
|
|
53
|
+
|
|
54
|
+
> 主题:**server 7.85.0 提货批**(发车帖 [7522] @client-core;CC-30 会话内 MCP re-dial 消费口 / CC-39② memory-status `autoConsolidationArmed` 读数)+ **CC-45 resume 补充句渲保留秒数**(cli L-383 / test [7516] N-G10)+ **CC-47 / CC-48**(test 0.72.8 验收 sema-internal#56 / #57)。**patch**:型面纯 additive(+2 常量 +6 函数,公面 977 → 985;`MemoryStatusFacts` 加一可选键;零 wire 新键 —— 端点 / 能力位 / 新键由 server 7.85.0 铸,本包只读;peer 不动)。接入面 §56。
|
|
55
|
+
|
|
56
|
+
### Added
|
|
57
|
+
|
|
58
|
+
- **`src/mcpReconnect.ts`(CC-30;server ≥7.85.0 S-381 / core 7.22.0 #857;契约 §G.7c)**:`reconnectMcpServer(client, sessionId, server, { signal? })` 消费口(**永不抛**;duck-typed 注入 `sessions.mcpReconnect`,sdk 9.6.0 未声明;本地体门 `server` 非空 ≤190 不发注定 400 的请求;🔴 `signal` 已 abort ⇒ 动词零调用直接 `failed`(破坏性动词不在用户说停之后再发,不依赖壳传输看不看 signal);回声 `sessionId` / `server` 与请求逐字相等否则 `failed`)⇒ `McpReconnectVerdict`(`ok` / `invalid` / `not_running` / `unsupported{capability|route}` / `not_found` / `failed`,按 `errorCode` 分诊、无码不猜);`projectMcpReconnectResult(body)` 按 `outcome` 三词(`MCP_RECONNECT_OUTCOMES`)分形:🔴 `unsupported` **恒五键**(`prefix` / `toolCount` / `added` / `removed` 不编 `0` / `[]`),`accepted` / `refused` 四座必填缺一整只畸形;🔴 名册按 `toolNames` **在场性**(缺席 = 名册原样不动;`[]` = 工具被撤走);`status` 八键 `errorCode` **开集**透传(core 十词 server 不枚举,消费端 switch 必带 default),`error` / `serverInfo` / `reason` UNTRUSTED 消毒封长,`transportClosed` 在场即 true;`listingIncomplete` 原样。`projectMcpReconnectCapability(caps)` 能力位三态(`available` / `unavailable` / `not_reported` = 老 server 判不了);`mcpReconnectOutcomeDetail(view)` 措辞单源(`refused` 按 `toolNames` 在场性分三句:缺席 = 连接未动工具未撤 / `[]` = 工具撤走 / 非空 = 如实报名册);**`MCP_RECONNECT_TRANSACTION_NOTICE`** = 契约 🔴 必进 UI 的那句(健康 server 上重连 = 一次交易,不是刷新:旧连接先关、失败则工具撤走)。🔴 「在场但坏形 ≠ 缺席」:`toolNames` / `listingIncomplete` 在契约上缺席各是一条正面指令(名册别动 / 名册走完了),在场但读不懂 ⇒ 整只畸形,不折成缺席;`listingIncomplete.pages` 必填;`status.name` 是身份键不封长;`unsupported` 的 `reason` 可缺席(判别键是 `outcome`);501 按 `capability.*` / `feature.*` 前缀族分诊(server 本路由真发两道 501)。⚠️ `McpReconnectVerdict.kind:'unsupported'`(面 / 部署不存在)与 `result.outcome:'unsupported'`(这条 run 未声明 MCP)是**两个词两件事**,端别并成一句。门 `run-mcp-reconnect-test.mjs` 51 格(红先绿后;两路异源复审四条真修:分诊器在 catch 里读 Proxy 属性抛穿「永不抛」—— 登 `docs/DISEASE-SHAPES.md` DS-05 / refused 无条件说撤工具 / 坏形折缺席 / 501 第二码漏诊);singleton +1;typeshape `unknownExport` 349 → 354(负控锚同批);portability index 闭包 167。
|
|
59
|
+
- **memory-status `autoConsolidationArmed: boolean`(CC-39②;server 7.85.0 S-403;core #863 W1 唯一读法组)**:`MemoryStatusFacts = SessionMemoryStatus & { autoConsolidationArmed?: boolean }`,`readSessionMemoryStatus` 逐键条件拷贝(非布尔 / 老 server 缺席 ⇒ 键不在场,不铸 false);读器 **`readAutoConsolidationArmed(facts)`** ⇒ `armed` / `unarmed` / `indeterminate`(🔴 缺席 = 老 server <7.85.0 判不了,不折 unarmed;与 manifest `autoConsolidation` 段「缺席 = indeterminate」同律)。memory-status 门 G2c 段 +8 格(红先绿后)。
|
|
60
|
+
|
|
61
|
+
### Changed
|
|
62
|
+
|
|
63
|
+
- **`resumeContextUnavailableContent` 第三句带保留秒数**(CC-45;cli L-383 / test [7516] N-G10 / sema-internal#54):`staleAfterSec` 在场 ⇒ 第三句尾加「(本部署的会话保留时长为 N 秒)」(N 原数,读口已窄读为整数 ≥1);缺席 ⇒ 逐字同 0.72.1。0.72.1 曾把秒数留给端「单独渲」而端没渲 ⇒ 补充句永无保留秒数;归层改为**有数必渲、无数不编**。resume-refusal 门 ⑧ 段改钉五格(在场恰一次原数 / 缺席零数字 / runId 缺席时同样带数 / 缺席两形逐字节 = 0.72.1 基线串 / 措辞铸点自复核 `0` · 非整数 · 巨数不渲)。
|
|
64
|
+
- **注入形 steer 失败按 `delivery` 分句 + 已中止不 steer**(CC-47;test 0.72.8 验收 sema-internal#56):`running-steer-failed` 注入形不再落默认「NOT delivered … could not put a decision on screen」句 —— `unknown`(5xx / 断连,可能已注入)说「可能已送达、未重试(steer 不可安全重发)、请观察」并带上游真因;`rejected` 说引擎拒收、未重试、模型未收到;`deps.signal` 已 abort ⇒ 注入形不发那枪不可撤回的 steer(零动作 `not-parked`)。reopen 门 ③z +4 格。
|
|
65
|
+
- **`isModelOutputErrorText` 按位置认锚**(CC-48;test #57):真实 provider HTTP 400 的错误体引用了锚句(`offending text: "tool call argument(s) …"`)曾被子串命中改标为模型输出错误 ⇒ 锚**只认消息开头**(`trimStart` 后 `startsWith`;core 铸点两句都出现时用 ` | ` 连、第一句仍在开头);引用形 / 加前缀形 / `<上游错误> | <引用锚句>` 形一律不命中,仍 `API Error:`。identity-copy 门 G1c +5 格。
|
|
66
|
+
|
|
67
|
+
## 0.72.8(2026-09-18)
|
|
68
|
+
|
|
69
|
+
> 主题:**清账三票**(CC-39③ server 7.84.0 S-405 `memory:"off"` 请求键 / CC-43 cli L-372 ③ `Model output error:` 中性臂 / CC-44 cli L-380 注入件撞活 run 自动 steer 零卡)。**patch**:型面纯 additive(+2 常量 +4 函数,公面 971 → 977;`ActiveRunSelfHealDeps.submissionOrigin?` 可选席;零 wire 新键 —— `memory` 键由 server 7.84.0 铸,本包只发;peer 不动)。接入面 §55。
|
|
70
|
+
|
|
71
|
+
### Added
|
|
72
|
+
|
|
73
|
+
- **`memory: "off"` 请求键**(CC-39③;server [7506] S-405 / 契约 §12.7 / core #863 W3):`REQUEST_FIELD_MATRIX` 加 `memory` 行(interactive + print,live 门),`TaskRequestInput.memory?: 'off'`,`buildTaskRequest` stamp;常量 **`MEMORY_OFF`** + 意图位片段 **`memoryOffDeclarationField(declared)`**(`false` ⇒ 整键缺席 = 记忆照常挂的唯一写法)+ 入口投影 **`memoryOffDeclared({ flag?, settingsMemory? })`**(cli [7510]:`--memory off` 旗恰 `'off'` ∨ settings CC 形 `memory: { enabled: false }` 严格 false ⇒ true;三端同判,壳零自判;🔴 旗在场非 `'off'` / `enabled` 在场非布尔 / 段非对象 ⇒ 响亮拒 `TypeError` —— 异源对抗复审一轮 [medium] 真修:入口投影不把打错字的收紧声明降级成缺席,否则片段函数删键、`buildTaskRequest` 无从校验)。🔴 与 `memoryCapture`(会话级采集面关)**同形、不同轴、可并存**:`memory` = 「这一次别给我记忆」(请求级整面关,零记录,终局状态词 `disabled`);坏拼写(含 `{ enabled: false }` 对象形)本层**响亮拒** `TypeError`,与 server 400 `request.field_invalid` 同律,不静默删键。两键同发时 capture 的单向记录不落 —— 不许拿 `memory:"off"` 当隐私声明。无能力位,老 server 400 / 更老 worker 静默忽略 ⇒ 本层不预判版本。pure 门 ⑤b 段 +70 格(红先绿后)。异源对抗复审第二轮两条 [medium] 真修:`buildTaskRequest` 对 `memory` / `memoryCapture` **只读一次**(校验与 stamp 共用同一次读取;带 getter 的入参第一次 `'off'` 第二次 `'OFF'` 曾让收紧声明静默丢失);memory 一族拒绝文本改用**粗分类**(`typeof` / null / array,不读 `Symbol.toStringTag` 与构造器名 —— 调用方可控的串不进错误展示)。typeshape `unknownExport` 347 → 349(`memoryOffDeclared` 两只 `unknown` 入参,负控锚同批)。
|
|
74
|
+
- **`runStream` 第二条中性臂 `Model output error:`**(CC-43;cli L-372 ③ 包侧正位):core 三 brain 的 malformed tool-call 一族(`tool call argument(s) not valid JSON …` / `tool call(s) arrived with no tool name and cannot be executed …`,brain 用 ` | ` 连)以 `done{status:'failed', errorMessage}` 收口时,行身份从 `API Error:` 换成 **`Model output error:`**(这一族零 provider 请求失败,该做的是调小请求 / 抬 output cap / 换说法重问,不是查网络);`isApiErrorMessage` 行类旗不变;busy / 治理两臂优先(结构位赢过文本锚);**只锚 core 原句共同前缀**,近似词不改身份(误报方向相反、代价一样)。导出 **`MODEL_OUTPUT_ERROR_PREFIX`** / **`isModelOutputErrorText(text)`** / **`isModelOutputErrorRowText(text)`**(与 `isGovernanceStopRowText` 互斥)。identity-copy 门 G1c 段 +10 格(红先绿后)。cli 1.0.119 归约器 `retagModelOutputErrorRow` 到货即退成直通。
|
|
75
|
+
- **`ActiveRunSelfHealDeps.submissionOrigin?: 'user' | 'injected'`**(CC-44;cli L-380):`'injected'`(plan-review 回执 / cron 唤醒 / task 通知等系统件)撞活 run 时**不呈三选卡、直接 steer 恰一次**(零卡)⇒ `running-steered` ⇒ 宿主按 `steerFollowIntent` 续听(L-379 闭环);不依赖 `offerRunningChoice` 口;没有正文 / 没有 steer 动词 ⇒ 零卡零动作 `not-parked`(注入行渲 not-delivered);cancel 永不自动打;**不碰**「用户选过 Do nothing」登记表;缺席 / `'user'` ⇒ 逐字节同旧。与 `activeRunSelfHealRow` 的 `origin` 是同一个词,宿主两处传同值。reopen 门 ③z 段 +7 格(红先绿后)。
|
|
76
|
+
|
|
52
77
|
## 0.72.7(2026-09-18)
|
|
53
78
|
|
|
54
79
|
> 主题:**core 7.22.0 提货**(发车帖 [7502] / 提货单 [7503] @client-core 三条;CC-42)。**patch**:型面纯 additive(一个 `_sema_` 超集键 + 通告闭集 +1 + 读器 +1 + 三词闭集 +1;公面 969 → 971;peer 不动;devDep core `~7.22.0`)。接入面 §54。
|
package/README.md
CHANGED
|
@@ -35,7 +35,7 @@ Renamed from **`@sema-agent/wire-cc-adapter`** (0.1.x, deprecated — see *Migra
|
|
|
35
35
|
|
|
36
36
|
## Scope
|
|
37
37
|
|
|
38
|
-
**Version:** 0.72.
|
|
38
|
+
**Version:** 0.72.9
|
|
39
39
|
|
|
40
40
|
- **Today** — the adapter seam, the whole `adapt()` pipeline (all 14 A-layer arms plus the
|
|
41
41
|
B/D/E tool-card layers), the notification/caps/model families, the adapter kernel (stream driver
|
|
@@ -311,6 +311,7 @@ public-surface guard checks that last one).
|
|
|
311
311
|
| `scripts/run-export-liveness-test.mjs` | Every runtime export in the public baseline must be **alive**: referenced by some gate, or explicitly registered in `scripts/export-liveness.json` as `contract` (consumed by a client with no gate yet), `internal` (an internal helper amplified onto the public surface by `export *`), `candidate` (with ticket + retire-by) or `retire` (dead; retire-by version). Registration is accounting, not exemption: a row for a name a gate already references is stale and must go, a row for a name no longer exported is red, `retire`/`candidate` rows go red the moment `package.json` reaches their retire-by version, and the row count only ratchets down. When the sibling client trees are on disk the consumption evidence is checked by name — a `contract` row's claimed consumers must equal the real set, and a `retire` name must not be imported by any client. Names that have already left the surface are kept in a per-version `removed` ledger: they must never reappear in the baseline or the registry, and the ledger's versions must not run ahead of the changelog. |
|
|
312
312
|
| `scripts/run-tool-disclosure-progress-projection-test.mjs` | The two wire arms sdk 9.6.0 adds — `tool_disclosure` (name-only tool census: open-set `policy`, `thresholdPercent` absent ≠ default, `deferred`/`activated` full snapshots) and `tool_progress` (one frame, two beats: Bash ticks carry an output tail with `totalLines`/`totalBytes` that come and go together; other tools carry only `elapsedSeconds`) — project to neutral internal arms plus chrome arms. Required keys missing ⇒ `malformed`; bad optional keys drop only themselves; the sub-flow three-key gate keeps child frames off the leader lane; both arms are `required: false` in the arm table with duties stated (the output tail is untrusted raw and must never be fed back to the model). |
|
|
313
313
|
| `scripts/run-mcp-panel-projection-test.mjs` | The `GET /v1/sessions/:id/mcp` panel reader (`projectMcpPanel`; server >=7.77.0 adds the optional `lastLegMcp` key) and the single wording mint for its "last leg" line. Absence of `lastLegMcp` is one literal sentence that never blames the engine version (a new session, a leg outside the retention window, a leg without a manifest and an older engine all look the same on the wire); a key that is present but unreadable is a different sentence plus a `lastLegMcpUnreadable: true` mark, never folded into absence. The `mcp[]` roster goes through the same reader as the live `wiring_manifest` third section, so a replayed roster and a live one have one shape. The two faces of the panel (`servers[]` and the last-leg roster) may legitimately differ, so the view carries no agreement flag and none of the five sentences mentions `servers`. Required keys are pinned to the SDK `openapi.yaml` component bytes **0.69.0:** `fetchMcpPanel` fetches the panel through the SDK client's own `sessions.mcp` call (same transport and auth as every other read) and projects it; transport failure, an unreadable body and an empty session id all come back as `undefined`, never as a fabricated empty panel 0.71.0 adds section K: `mcpEngineLegPresence(view)` — the engine-side MCP presence tri-state read only off the panel view (`unknown` when the view could not be read, never rendered as "no MCP configured") |
|
|
314
|
+
| `scripts/run-mcp-reconnect-test.mjs` | The in-session MCP re-dial verb (`POST /v1/sessions/:id/mcp/reconnect`, engine ≥7.85.0), consumed. The single discriminant is `outcome` and all three answers are HTTP 200, so the reader branches on the word and never on the status; the `unsupported` answer carries exactly five keys and the reader refuses to invent a zero or an empty list for the four fields the engine did not produce, while `accepted` / `refused` treat those four as required and go malformed when one is missing. The tool roster follows the **presence** of `toolNames` (absent = untouched, empty = withdrawn), the connection record passes `errorCode` through as an open set, and every remote-authored string is sanitised and bounded before display. Failures are classified by `errorCode` alone, a missing code is reported as unknown rather than guessed, the verb never throws, and the request-side guard (non-empty name, ≤190 chars) stops a call that the contract would reject anyway. The capability bit reads absent as "cannot tell" rather than "unavailable", and the one sentence the contract insists every UI carries — that re-dialing is a transaction, not a refresh — is minted here once |
|
|
314
315
|
| `scripts/run-core-value-ports-test.mjs` | The port-injection seam for ten **engine value-level** facilities (autonomous-loop prompt assembly, permission-rule loosening, tool-policy composition, protocol/retired-name/grammar lookups, rule compilation, the discussion workflow name). This package cannot re-export them (the engine barrel drags Node built-ins into the browser bundle), so it declares the ports and honest-absence readers; a Node host installs the engine's own functions verbatim. The guard pins: every reader returns `undefined` when nothing is installed (never a fabricated empty array or default policy), arguments and results pass through by reference, engine errors propagate unchanged, partial installs read partially, restore functions unwind to the previous bag, and the module source has zero engine imports |
|
|
315
316
|
| `scripts/run-read-face-posture-projection-test.mjs` | The operator-face `readFace: ReadFacePosture` reader (server >=7.65.0). Three ways of "can't say" are pinned to three different, literal sentences, and none of them may read as "nothing is pinned" — that statement belongs to exactly one case, `face: null`, which is a positive fact reported by the engine, not an absence: not having read an operator response yet, having read one from an engine too old to report the key, and the engine actually saying nothing is pinned are three different next steps for an operator and must not collapse into each other. `source` is read as an open set (the server's closed four words plus an escape hatch) rather than narrowed to an enum, so a new word added upstream is not silently turned into a bad reading. The free-text `note` is sanitized and length-capped before it is ever rendered. A companion pure function flags disagreement between this face and the tenant-facing `capabilities.readFace` — silent only when the two actually agree, honest-absent when either side cannot be read at all, never asserting agreement as a fact. The gate's last leg reads the installed SDK's own `openapi.yaml` directly rather than restating the schema in prose, so the package's leniency cannot quietly drift from the real contract |
|
|
316
317
|
| `scripts/run-display-cap-order-test.mjs` | The order in which untrusted text is sanitised and length-capped, across every mint point that puts an engine- or database-supplied string on a screen. The sanitiser rewrites each invisible character as a six-character escape, so capping the **raw** string first and escaping afterwards hands the screen six times the width that was budgeted — a forty-character allowance becomes two hundred and forty. The guard does not hardcode that allowance, because each mint point wraps its field in different fixed prose and the prose moves: it anchors on the deciding quantity instead, feeding one benign and one control-character input of the same length through the same mint and requiring the second not to come out longer. That criterion is immune to wording changes and stays sensitive to the expansion, and it is `<=` rather than `==` on purpose — a correct escape-then-cap backs the cut off a partially-consumed escape token, so the control-character line is legitimately the shorter of the two, and demanding equality would score that avoidance as a regression. Each mint is bracketed by two positive controls (the input really reaches the screen; the cap really engages) and the expansion predicate is shown to turn red against a deliberately cap-then-escape reference, so an all-green run cannot mean the guard simply measured nothing. The shared mint point is checked directly for the two avoidances it owes — never splitting an escape token in half, which would leave something on screen that looks like the beginning of a complete answer, and never splitting a legal surrogate pair, which would manufacture the very lone surrogate the sanitiser exists to catch |
|
|
@@ -274,6 +274,14 @@ export interface ActiveRunSelfHealDeps {
|
|
|
274
274
|
signal?: AbortSignal;
|
|
275
275
|
/** cancel 之后等 claim 释放的窗口(ms,缺省 {@link CANCEL_RELEASE_WAIT_MS});测试用它把窗调小。 */
|
|
276
276
|
cancelReleaseWaitMs?: number;
|
|
277
|
+
/**
|
|
278
|
+
* 被拒提交的**出身**(0.72.8 CC-44;cli L-380)。`'injected'` = 系统注入件(plan-review 回执 / cron 唤醒 / task 通知),
|
|
279
|
+
* **不是人写的、也不该问人**:撞活 run 时不呈三选卡,直接 steer(零卡)⇒ 结局 `running-steered` ⇒ 宿主按
|
|
280
|
+
* {@link steerFollowIntent} 续听(L-379)。没有正文 / 没有 steer 动词 ⇒ 零动作 `not-parked`(注入行渲 not-delivered)。
|
|
281
|
+
* 缺席 / `'user'` ⇒ 逐字节同旧(三选卡照呈)。与 {@link activeRunSelfHealRow} 的 `origin` 是同一个词,宿主两处传同一个值。
|
|
282
|
+
* 🔴 注入形**不碰**「用户选过 Do nothing」的登记表:那张表记的是人的决定,系统件不替他改、也不被它挡。
|
|
283
|
+
*/
|
|
284
|
+
submissionOrigin?: RejectedSubmissionOrigin;
|
|
277
285
|
/** 本会话的引擎 sessionId —— durable run 动词逐次透传(见 {@link DurableRunCallOpts.session})。
|
|
278
286
|
* 缺席 = 退化成今天的「server 记一条迁移告警后放行」,enforcement 到站后那条腿会整体 404。 */
|
|
279
287
|
sessionId?: string;
|
|
@@ -897,7 +897,9 @@ async function cancelAndConfirmRelease(taskId, durable, durableGet, deps) {
|
|
|
897
897
|
async function runningChoiceArm(taskId, status, busy, statusFromWire, runs, deps) {
|
|
898
898
|
const notParked = { kind: 'not-parked', taskId, status };
|
|
899
899
|
const offer = deps?.offerRunningChoice;
|
|
900
|
-
|
|
900
|
+
// CC-44(0.72.8):系统注入件不问人 —— 不需要呈卡口;canSteer 不成立时零卡零动作。
|
|
901
|
+
const injected = deps?.submissionOrigin === 'injected';
|
|
902
|
+
if (typeof offer !== 'function' && !injected)
|
|
901
903
|
return notParked;
|
|
902
904
|
const text = typeof deps?.deniedMessage === 'string' ? deps.deniedMessage : '';
|
|
903
905
|
// 🔴 **只取来判在场,绝不裸调**(二次评审 R7 [high]):真 SDK 的 `RunsResource` 方法体走
|
|
@@ -909,6 +911,8 @@ async function runningChoiceArm(taskId, status, busy, statusFromWire, runs, deps
|
|
|
909
911
|
const canCancel = typeof runs?.cancel === 'function' && typeof runs?.get === 'function';
|
|
910
912
|
if (!canSteer && !canCancel)
|
|
911
913
|
return notParked;
|
|
914
|
+
if (injected && !canSteer)
|
|
915
|
+
return notParked;
|
|
912
916
|
// ── 存活对账腿(Inkglow-1085 P0b②):出卡前对 wire 直供的 running 补一发 runs.get 真查 ────────
|
|
913
917
|
// 409 终帧的 `activeTaskStatus` 是引擎 claim/store 的 best-effort 投影 —— claim 指着一条早已终结
|
|
914
918
|
// 甚至已不存在的 run 时,它会**每次都**回送同一个错的 running(幽灵),用户按 wire 读数拿到的
|
|
@@ -954,28 +958,41 @@ async function runningChoiceArm(taskId, status, busy, statusFromWire, runs, deps
|
|
|
954
958
|
// ── 已呈现登记(Inkglow-1085 P0b①):同 (sessionKey,taskId) 用户选过「Do nothing」⇒ 不再整卡
|
|
955
959
|
// 重弹,给 `alreadyOffered` 判别位让端降级渲一行(登记语义与清口见 runningChoiceDeclined 顶注)。
|
|
956
960
|
const declineKey = runningChoiceDeclineKey(deps?.sessionId, taskId);
|
|
957
|
-
if (runningChoiceDeclined.has(declineKey)) {
|
|
961
|
+
if (!injected && runningChoiceDeclined.has(declineKey)) {
|
|
958
962
|
return { kind: 'not-parked', taskId, status, alreadyOffered: true };
|
|
959
963
|
}
|
|
960
964
|
let choice = 'wait';
|
|
961
965
|
let offerDelivered = false;
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
966
|
+
if (injected) {
|
|
967
|
+
// CC-44:系统件不问人 —— canSteer 已在上面证过(动词在场 ∧ 有正文)。cancel 永不自动打(反钉纪律不变)。
|
|
968
|
+
// 🔴 CC-47(test 0.72.8 验收 #56 ②):用户已按 Esc(`deps.signal` 已 abort)⇒ **不发**这枪不可撤回的 steer,零动作现状行
|
|
969
|
+
// 收口 —— 用户说停之后系统件还往 run 里注入 = 「UI 显示已停、后台还在动」那一形。
|
|
970
|
+
if (probeCallerAborted())
|
|
971
|
+
return notParked;
|
|
972
|
+
choice = 'steer';
|
|
965
973
|
}
|
|
966
|
-
|
|
967
|
-
|
|
974
|
+
else if (typeof offer === 'function') {
|
|
975
|
+
try {
|
|
976
|
+
choice = (await offer({ taskId, status, canSteer, canCancel })) ?? 'wait';
|
|
977
|
+
offerDelivered = true;
|
|
978
|
+
}
|
|
979
|
+
catch {
|
|
980
|
+
choice = 'wait'; // 呈卡腿出意外 = 用户没做决定 ⇒ 零动作(绝不掉进破坏性分支)
|
|
981
|
+
}
|
|
968
982
|
}
|
|
969
983
|
// wait = 用户看过卡并选择留着它(呈现层把 Esc/空答也收口成 wait —— 同样是「这次不动它」的表态);
|
|
970
984
|
// steer/cancel = 用户重新表了态 ⇒ 清登记。呈卡腿抛错那次**不**登记(用户没看到卡)。
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
rememberDeclinedOffer
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
985
|
+
// 注入形不碰这张表(它记的是人的决定)。
|
|
986
|
+
if (!injected) {
|
|
987
|
+
if (choice === 'wait') {
|
|
988
|
+
// (对抗复审 [medium] 轻形采纳)FIFO 有界:长命桌面/多会话宿主不许无界长住(叶
|
|
989
|
+
// {@link rememberDeclinedOffer},与 L-93 两选卡共用同一条上界)。
|
|
990
|
+
if (offerDelivered)
|
|
991
|
+
rememberDeclinedOffer(declineKey);
|
|
992
|
+
}
|
|
993
|
+
else {
|
|
994
|
+
runningChoiceDeclined.delete(declineKey);
|
|
995
|
+
}
|
|
979
996
|
}
|
|
980
997
|
if (choice === 'steer' && canSteer && runs?.steer !== undefined) {
|
|
981
998
|
try {
|
|
@@ -1130,6 +1147,17 @@ export function activeRunSelfHealRow(outcome, signal, copy, origin, follow) {
|
|
|
1130
1147
|
*/
|
|
1131
1148
|
function injectedSubmissionRow(outcome, following = false) {
|
|
1132
1149
|
const handle = 'taskId' in outcome && outcome.taskId ? ` (run ${outcome.taskId})` : '';
|
|
1150
|
+
// 0.72.9 CC-47(test 0.72.8 验收 #56):steer 失败**按 delivery 分句**,不落默认 not-delivered 句 —— 那句说「could not put a
|
|
1151
|
+
// decision on screen」与真因不符,且对 `unknown`(5xx / 断连,可能已注入)断言「未送达、模型不知道」是替引擎编一句安全声明;
|
|
1152
|
+
// 用户据此手动补发 = 重复注入。与用户形同一条律:明确拒收才说没送到;送达未知只说「未知、未重试、请观察」。
|
|
1153
|
+
if (outcome.kind === 'running-steer-failed') {
|
|
1154
|
+
return outcome.delivery === 'unknown'
|
|
1155
|
+
? `A system notification was handed to the run that is already working${handle}, but the engine did not confirm delivery ` +
|
|
1156
|
+
`(${outcome.detail}) — that run may or may not have received it; sema did not retry (a steer cannot be re-sent safely). ` +
|
|
1157
|
+
`Watch that run for what it does next.`
|
|
1158
|
+
: `A system notification was NOT delivered: the engine refused it for the run that is already working${handle} ` +
|
|
1159
|
+
`(${outcome.detail}); sema did not retry. The model was not told about it.`;
|
|
1160
|
+
}
|
|
1133
1161
|
switch (selfHealSubmissionDisposition(outcome)) {
|
|
1134
1162
|
case 'held-for-decision':
|
|
1135
1163
|
return (`A system notification could not be delivered while an earlier turn${handle} is waiting on a ` +
|
|
@@ -157,6 +157,24 @@ export declare const RUN_BLOCKED_MESSAGE_PREFIX = "Run blocked";
|
|
|
157
157
|
* 各写一份正则必漂(记忆 `machine-readable-signal-not-visual-anchor`)。
|
|
158
158
|
*/
|
|
159
159
|
export declare function isGovernanceStopRowText(text: string): boolean;
|
|
160
|
+
/**
|
|
161
|
+
* 第二条中性臂的前缀(0.72.8 CC-43;cli L-372 ③ 包侧正位):**模型这一轮的输出**坏了 —— core 三个 brain
|
|
162
|
+
* (anthropic / openai / open-responses)把 `tool_use` 参数不是合法 JSON(最常见成因 = 输出被 max_tokens
|
|
163
|
+
* 截断在参数中间)/ tool call 没带工具名 收成一句错误、run 以 `done{status:'failed', errorMessage}` 收口。
|
|
164
|
+
* 这一族**没有一个 provider 请求失败过**:渲成 `API Error:` 把人指去查网络 / key / 配额,而该做的是调小请求、
|
|
165
|
+
* 抬 output cap 或换个说法重问。与治理臂同律:身份换,行类旗(`isApiErrorMessage`)不换。
|
|
166
|
+
*/
|
|
167
|
+
export declare const MODEL_OUTPUT_ERROR_PREFIX = "Model output error";
|
|
168
|
+
/**
|
|
169
|
+
* 这条终态错误文本是不是「模型输出问题」(⇒ 中性行 `Model output error:`)。
|
|
170
|
+
* 🔴 **只锚 core 原句的共同前缀,不做模糊匹配**:三个 brain 各带各的终止原因字段名(`stop_reason` /
|
|
171
|
+
* `finish_reason` / `status`)⇒ 只锚括号前那一段;`JSON` / `not valid` 这类词在别的错误里到处都是,放宽一个字
|
|
172
|
+
* 就会把真的传输 / 服务端错误改渲成「模型输出问题」—— 方向相反、代价一样大。core 换句子 ⇒ 本锚当场失效 ⇒
|
|
173
|
+
* 行回落 `API Error:`(开集兜底,不误报)。两句锚 = 同一铸点的两个分支(参数非 JSON / 无工具名),brain 用 ` | ` 连。
|
|
174
|
+
*/
|
|
175
|
+
export declare function isModelOutputErrorText(text: string): boolean;
|
|
176
|
+
/** 这一行是不是「模型输出问题」行(渲染面 / 归约面的谓词;与铸点同源,端别自抄前缀字面)。与 {@link isGovernanceStopRowText} 互斥。 */
|
|
177
|
+
export declare function isModelOutputErrorRowText(text: string): boolean;
|
|
160
178
|
/**
|
|
161
179
|
* 终态是不是治理/契约面的(⇒ 中性行),而不是 provider/HTTP 面的(⇒ 保留 `API Error:`)。
|
|
162
180
|
*
|
|
@@ -169,6 +169,34 @@ export function isGovernanceStopRowText(text) {
|
|
|
169
169
|
const t = text.trimStart();
|
|
170
170
|
return t.startsWith(`${RUN_STOPPED_MESSAGE_PREFIX}:`) || t.startsWith(`${RUN_BLOCKED_MESSAGE_PREFIX}`);
|
|
171
171
|
}
|
|
172
|
+
/**
|
|
173
|
+
* 第二条中性臂的前缀(0.72.8 CC-43;cli L-372 ③ 包侧正位):**模型这一轮的输出**坏了 —— core 三个 brain
|
|
174
|
+
* (anthropic / openai / open-responses)把 `tool_use` 参数不是合法 JSON(最常见成因 = 输出被 max_tokens
|
|
175
|
+
* 截断在参数中间)/ tool call 没带工具名 收成一句错误、run 以 `done{status:'failed', errorMessage}` 收口。
|
|
176
|
+
* 这一族**没有一个 provider 请求失败过**:渲成 `API Error:` 把人指去查网络 / key / 配额,而该做的是调小请求、
|
|
177
|
+
* 抬 output cap 或换个说法重问。与治理臂同律:身份换,行类旗(`isApiErrorMessage`)不换。
|
|
178
|
+
*/
|
|
179
|
+
export const MODEL_OUTPUT_ERROR_PREFIX = 'Model output error';
|
|
180
|
+
/**
|
|
181
|
+
* 这条终态错误文本是不是「模型输出问题」(⇒ 中性行 `Model output error:`)。
|
|
182
|
+
* 🔴 **只锚 core 原句的共同前缀,不做模糊匹配**:三个 brain 各带各的终止原因字段名(`stop_reason` /
|
|
183
|
+
* `finish_reason` / `status`)⇒ 只锚括号前那一段;`JSON` / `not valid` 这类词在别的错误里到处都是,放宽一个字
|
|
184
|
+
* 就会把真的传输 / 服务端错误改渲成「模型输出问题」—— 方向相反、代价一样大。core 换句子 ⇒ 本锚当场失效 ⇒
|
|
185
|
+
* 行回落 `API Error:`(开集兜底,不误报)。两句锚 = 同一铸点的两个分支(参数非 JSON / 无工具名),brain 用 ` | ` 连。
|
|
186
|
+
*/
|
|
187
|
+
export function isModelOutputErrorText(text) {
|
|
188
|
+
// 🔴 0.72.9 CC-48(test 0.72.8 验收 #57):**按位置**认锚,不按子串 —— 真实 provider HTTP 400 的错误体会引用这句
|
|
189
|
+
// (`offending text: "tool call argument(s) not valid JSON …"`),子串命中就把 API 侧拒请求说成模型输出坏了。
|
|
190
|
+
// core 的铸点把这两句放在 errorMessage **开头**(两句都出现时 brain 用 " | " 连,第一句仍在开头)⇒ **只认消息开头**;
|
|
191
|
+
// 引用形、加前缀形、`<上游错误> | <引用锚句>` 形(异源复审第二轮抓出:任意段首也是子串匹配的变体)一律不命中。
|
|
192
|
+
const anchors = ['tool call argument(s) not valid JSON', 'tool call(s) arrived with no tool name and cannot be executed'];
|
|
193
|
+
const t = text.trimStart();
|
|
194
|
+
return anchors.some((a) => t.startsWith(a));
|
|
195
|
+
}
|
|
196
|
+
/** 这一行是不是「模型输出问题」行(渲染面 / 归约面的谓词;与铸点同源,端别自抄前缀字面)。与 {@link isGovernanceStopRowText} 互斥。 */
|
|
197
|
+
export function isModelOutputErrorRowText(text) {
|
|
198
|
+
return text.trimStart().startsWith(`${MODEL_OUTPUT_ERROR_PREFIX}:`);
|
|
199
|
+
}
|
|
172
200
|
/**
|
|
173
201
|
* 终态是不是治理/契约面的(⇒ 中性行),而不是 provider/HTTP 面的(⇒ 保留 `API Error:`)。
|
|
174
202
|
*
|
|
@@ -801,7 +829,10 @@ async function* runStreamInner(events, ctx, handle = {}) {
|
|
|
801
829
|
? // blocked 的 errText 自己就以 `Run blocked` 开头(见上方 errText 构造),再套一层
|
|
802
830
|
// `Run stopped:` 会变成两个前缀叠字;其余治理码用中性前缀 + 引擎原话。
|
|
803
831
|
`${isGovernanceStopRowText(errText) ? errText : `${RUN_STOPPED_MESSAGE_PREFIX}: ${errText}`}${maxTokHint}`
|
|
804
|
-
:
|
|
832
|
+
: isModelOutputErrorText(errText)
|
|
833
|
+
? // 0.72.8 CC-43:第二条中性臂 —— 模型输出坏了(core 原句锚),不是 API 错误;busy / 治理两臂优先(结构位赢过文本锚)。
|
|
834
|
+
`${MODEL_OUTPUT_ERROR_PREFIX}: ${errText}${maxTokHint}`
|
|
835
|
+
: `API Error: ${errText}${maxTokHint}`;
|
|
805
836
|
yield {
|
|
806
837
|
session_id: ctx.sessionId ?? '',
|
|
807
838
|
uuid: `err-${Date.now().toString(36)}`,
|
package/dist/index.d.ts
CHANGED
|
@@ -155,6 +155,7 @@ export * from './engineCapsCache.js';
|
|
|
155
155
|
export * from './sqlEngineCapability.js';
|
|
156
156
|
export * from './writeProtectionCapability.js';
|
|
157
157
|
export * from './webSearchBackendCapability.js';
|
|
158
|
+
export * from './mcpReconnect.js';
|
|
158
159
|
export * from './runTerminal.js';
|
|
159
160
|
export * from './readFacePosture.js';
|
|
160
161
|
export * from './mcpPanel.js';
|
package/dist/index.js
CHANGED
|
@@ -187,6 +187,9 @@ export * from './writeProtectionCapability.js';
|
|
|
187
187
|
// S-382(0.72.5;server ≥7.82.1,sdk 尚未声明):`Capabilities.webSearch.backend` 的四态窄读器 ——
|
|
188
188
|
// 部署默认 WebSearch 后端(`none` = 正面事实 / 键缺席 = 老引擎判不了,两者处置相反)。与上两只同构同纪律。
|
|
189
189
|
export * from './webSearchBackendCapability.js';
|
|
190
|
+
// S-381 / core 7.22.0 #857(0.72.9 CC-30;server ≥7.85.0,sdk 尚未声明):会话内 MCP re-dial 的消费口 —— 200 三态按 outcome 分形读、
|
|
191
|
+
// unsupported 恒五键、名册按 toolNames 在场性、失败按 errorCode 分诊、「重连 = 一次交易」措辞单源;能力位 mcpReconnect 三态读。
|
|
192
|
+
export * from './mcpReconnect.js';
|
|
190
193
|
// 0.60.0(engine ≥7.64.0 / sdk 8.4.0):终局因由与门记录两只**判定归包**的读器。
|
|
191
194
|
export * from './runTerminal.js';
|
|
192
195
|
// 0.61.0(engine ≥7.65.0 / sdk 8.5.0 / S-167):READ 容纳面档位 + 来源的 operator 面窄读器
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mcpReconnect — 会话内 MCP re-dial 的**三端共用消费口**(0.72.9 CC-30;server ≥7.85.0 S-381 / core 7.22.0 #857;
|
|
3
|
+
* 契约 §G.7c / 附录 B.1 `mcpReconnect`;sdk 9.6.0 尚未声明端点与体,读口 duck-typed 注入,与 `sessionMemoryStatus` 同款)。
|
|
4
|
+
*
|
|
5
|
+
* ── 这一口答的是哪件事 ────────────────────────────────────────────────────────────────────
|
|
6
|
+
* 传输断了的 stdio MCP server 在不结束任务的前提下**重拨一台具名 server**:`POST /v1/sessions/:id/mcp/reconnect { server }`。
|
|
7
|
+
* 壳只有「重连这台」按钮与结果渲染;判定(三态分臂 / 名册在场性 / 失败分诊 / 交易文案)三端各写一遍必各错一遍 ⇒ 归包。
|
|
8
|
+
*
|
|
9
|
+
* ── 🔴 五条契约读法(§G.7c 逐字)──────────────────────────────────────────────────────────
|
|
10
|
+
* ① `outcome` 是**唯一判别键**,三态全部走 200:`accepted`(core reconnected)/ `refused`(core refused **或** not_declared,
|
|
11
|
+
* wire 上刻意不可区分,子理由骑 `reason`)/ `unsupported`(server 自己的词:这条 run 一台 MCP 都没声明;不是 409、不是 refused)。
|
|
12
|
+
* ② `unsupported` **恒五键**(taskId / sessionId / server / outcome / reason):那条臂没有 core 结果,`prefix` / `toolCount` / `added` /
|
|
13
|
+
* `removed` 编成 `0` / `[]` = 替 core 说一句它没说过的话 ⇒ 本读器**按 outcome 分支再读**;accepted / refused 四座缺一 ⇒ 整只畸形。
|
|
14
|
+
* ③ **名册按 `toolNames` 的在场性**:在场非空 = 对该 `prefix` 域断言的名册(**超集**:core 挂载前还滤一道);在场 `[]` = 拨号失败、
|
|
15
|
+
* 这台的工具被撤走(空数组是一句话);整键缺席 = 这条臂从未碰过连接,挂载名册原样不动。真挂上了什么读 `wiring_manifest.tools`。
|
|
16
|
+
* ④ **下一步动作读 `status.errorCode` / `httpStatus`,不解析 `reason`**:`errorCode` 是 core 十词闭集但 server 不枚举 ⇒ 本读器按**开集**
|
|
17
|
+
* 透传(消费端 switch 必带 default);`delivered` 三词 / `transportClosed` 在场即 true(缺席 = 没观察到关闭,**不是**还活着);
|
|
18
|
+
* `error` / `serverInfo` / `reason` 是远端自由文本 —— UNTRUSTED-for-display,呈前消毒封长。
|
|
19
|
+
* ⑤ **交易,不是刷新**(core 原话,契约 🔴 必进 UI):旧连接在拨新号**之前**就被关 ⇒ 一次失败的重拨花掉一条能用的连接。
|
|
20
|
+
* 壳不许只写「重连」—— 措辞单源 {@link MCP_RECONNECT_TRANSACTION_NOTICE}。
|
|
21
|
+
*
|
|
22
|
+
* ── 失败分诊按 `errorCode` 不按 status(与 `classifyMemoryStatusFailure` 同律)────────────────
|
|
23
|
+
* 422 `steering.invalid_content` ⇒ invalid · 409 `steering.not_running` ⇒ not_running(parked / 终态 / 他副本 / 无活流四臂一码)·
|
|
24
|
+
* 501 `capability.run_store_required` ⇒ unsupported/capability · 404 `not_found.route` ⇒ unsupported/route(老 server 无此路由)·
|
|
25
|
+
* 404 `not_found.session` ⇒ not_found(未知 / 非属主同码同串)· 无码 ⇒ failed(**不猜**)。
|
|
26
|
+
*/
|
|
27
|
+
/** `outcome` 三词(契约 §G.7c;`unsupported` 是 server 的词,core 没有它)。 */
|
|
28
|
+
export declare const MCP_RECONNECT_OUTCOMES: readonly string[];
|
|
29
|
+
/**
|
|
30
|
+
* 「重连 = 一次交易」的**唯一措辞铸点**(三端共用;契约 🔴 这句必须进 UI,壳不许只写「重连」)。
|
|
31
|
+
* 零内部车道词;只说用户能据以决策的事实:旧连接先关、失败则工具撤走、直到再拨成功。
|
|
32
|
+
*/
|
|
33
|
+
export declare const MCP_RECONNECT_TRANSACTION_NOTICE: string;
|
|
34
|
+
/** `status`(这一次拨号的新连接时记录)的八键投影;`errorCode` 开集透传。UNTRUSTED 座已消毒封长。 */
|
|
35
|
+
export interface McpReconnectStatusView {
|
|
36
|
+
name: string;
|
|
37
|
+
status: string;
|
|
38
|
+
errorCode?: string;
|
|
39
|
+
httpStatus?: number;
|
|
40
|
+
delivered?: string;
|
|
41
|
+
serverInfo?: {
|
|
42
|
+
name: string;
|
|
43
|
+
version: string;
|
|
44
|
+
};
|
|
45
|
+
error?: string;
|
|
46
|
+
/** 在场即 `true`(core 永不写 false);缺席 = 没观察到关闭,**不是**「还活着」。 */
|
|
47
|
+
transportClosed?: true;
|
|
48
|
+
}
|
|
49
|
+
/** `listingIncomplete`:这次 `tools/list` 没走完 ⇒ 名册不许当全集(缺的一条是未证明缺席,不是被撤走)。 */
|
|
50
|
+
export interface McpReconnectListingIncompleteView {
|
|
51
|
+
reason: string;
|
|
52
|
+
/** 这次 `tools/list` 走到第几页(server 无条件投;非整数 ⇒ 整只畸形)。 */
|
|
53
|
+
pages: number;
|
|
54
|
+
budgetMs?: number;
|
|
55
|
+
error?: string;
|
|
56
|
+
}
|
|
57
|
+
/** 200 体的读视图 —— **按 `outcome` 分形**(`unsupported` 五键 / 其余四座必填)。 */
|
|
58
|
+
export type McpReconnectResultView = {
|
|
59
|
+
outcome: 'unsupported';
|
|
60
|
+
taskId: string;
|
|
61
|
+
sessionId: string;
|
|
62
|
+
server: string;
|
|
63
|
+
reason?: string;
|
|
64
|
+
} | {
|
|
65
|
+
outcome: 'accepted' | 'refused';
|
|
66
|
+
taskId: string;
|
|
67
|
+
sessionId: string;
|
|
68
|
+
server: string;
|
|
69
|
+
prefix: string;
|
|
70
|
+
toolCount: number;
|
|
71
|
+
/** 带命名空间的工具名(相对「一刻之前它挂载了什么」;失败的拨号移除它原有的全部)。**不是**通告 `mcp.server_redialed` 的计数。 */
|
|
72
|
+
added: string[];
|
|
73
|
+
removed: string[];
|
|
74
|
+
/** present-iff 这次结果对自己的 `prefix` 域做了名册断言(见文件头 ③);缺席 ⇒ 名册原样不动。 */
|
|
75
|
+
toolNames?: string[];
|
|
76
|
+
reason?: string;
|
|
77
|
+
status?: McpReconnectStatusView;
|
|
78
|
+
listingIncomplete?: McpReconnectListingIncompleteView;
|
|
79
|
+
};
|
|
80
|
+
/** 消费口的判决。`ok` 之外五档各是一条不同的下一步;`failed` 原错误带出(端要能看到真因)。 */
|
|
81
|
+
export type McpReconnectVerdict = {
|
|
82
|
+
readonly kind: 'ok';
|
|
83
|
+
readonly result: McpReconnectResultView;
|
|
84
|
+
} | {
|
|
85
|
+
readonly kind: 'invalid';
|
|
86
|
+
} | {
|
|
87
|
+
readonly kind: 'not_running';
|
|
88
|
+
} | {
|
|
89
|
+
readonly kind: 'unsupported';
|
|
90
|
+
readonly reason: 'capability' | 'route' | 'feature';
|
|
91
|
+
} | {
|
|
92
|
+
readonly kind: 'not_found';
|
|
93
|
+
} | {
|
|
94
|
+
readonly kind: 'failed';
|
|
95
|
+
readonly error: unknown;
|
|
96
|
+
};
|
|
97
|
+
/** 宿主注入的读口切片(duck-typed;sdk 9.6.0 没有本方法,壳用自己的传输层接 `POST /v1/sessions/:id/mcp/reconnect`)。 */
|
|
98
|
+
export interface McpReconnectClientLike {
|
|
99
|
+
sessions: {
|
|
100
|
+
mcpReconnect?: (sessionId: string, body: {
|
|
101
|
+
server: string;
|
|
102
|
+
}, opts?: {
|
|
103
|
+
signal?: AbortSignal;
|
|
104
|
+
}) => Promise<unknown>;
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* 200 体 → 读视图;**畸形一律 `undefined`**(不编、不猜)。按 `outcome` 分形读键(文件头 ①②③④)。
|
|
109
|
+
*/
|
|
110
|
+
export declare function projectMcpReconnectResult(body: unknown): McpReconnectResultView | undefined;
|
|
111
|
+
/** 抛出物 → 判决(按 `errorCode`;与 `classifyMemoryStatusFailure` 同律:无码不猜)。 */
|
|
112
|
+
export declare function classifyMcpReconnectFailure(e: unknown): McpReconnectVerdict;
|
|
113
|
+
/**
|
|
114
|
+
* 「重连这台 MCP」的消费口:**永不抛**。本地先按契约把体门(`server` 非空 ≤ 190)判掉,不发一条注定 400 的请求;
|
|
115
|
+
* 回体经 {@link projectMcpReconnectResult} 投影;**回声身份**(`sessionId` / `server`)与请求逐字相等,否则 `failed`(宁缺席不串台,
|
|
116
|
+
* 与 `readSessionMemoryStatus` 同律)。注入口没有方法 ⇒ `unsupported/route`(壳没接线 = 面不存在)。
|
|
117
|
+
*/
|
|
118
|
+
export declare function reconnectMcpServer(client: McpReconnectClientLike, sessionId: string, server: string, opts?: {
|
|
119
|
+
signal?: AbortSignal;
|
|
120
|
+
}): Promise<McpReconnectVerdict>;
|
|
121
|
+
/**
|
|
122
|
+
* 能力位 `GET /v1/capabilities.mcpReconnect`(设施依赖 = runStore ∧ sessionStorage.ownerOf)的三态读:
|
|
123
|
+
* `available` / `unavailable` / `not_reported`(键缺席 = 老 server <7.85.0 **判不了**,不折 unavailable);坏形 ⇒ `undefined`。
|
|
124
|
+
* 纯投影(caps 体由宿主交,本包不另开 tee:这一位只在按钮亮不亮时读一次)。
|
|
125
|
+
*/
|
|
126
|
+
export declare function projectMcpReconnectCapability(caps: unknown): 'available' | 'unavailable' | 'not_reported' | undefined;
|
|
127
|
+
/**
|
|
128
|
+
* 三态 → 一句结果(**唯一措辞铸点**;三端共用;零内部车道词)。`accepted` 带工具计数;`refused` 说清工具已撤走(交易的代价)并带 reason;
|
|
129
|
+
* `unsupported` 说清是这条 run 的装配(未声明 MCP),不是 refused。
|
|
130
|
+
*/
|
|
131
|
+
export declare function mcpReconnectOutcomeDetail(view: McpReconnectResultView): string;
|