@sema-agent/client-core 0.75.1 → 0.76.1
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 +53 -0
- package/README.md +11 -1
- package/dist/adapt/arms.js +137 -35
- package/dist/adapt/ids.d.ts +29 -2
- package/dist/adapt/ids.js +29 -2
- package/dist/adapt/panelTasks.d.ts +4 -3
- package/dist/adapt/panelTasks.js +29 -11
- package/dist/adapt/textStream.js +5 -5
- package/dist/adapt/toolCards.js +2 -2
- package/dist/adapt/turnFlags.js +5 -5
- package/dist/adapt.d.ts +1 -1
- package/dist/adapt.js +8 -8
- package/dist/adapter/downstream/eventToSdkMessage.d.ts +57 -0
- package/dist/adapter/downstream/eventToSdkMessage.js +125 -17
- package/dist/adapter/runStream.js +14 -5
- package/dist/adapter/types.d.ts +12 -0
- package/dist/adapter/types.js +30 -0
- package/dist/agentsWireCaps.d.ts +15 -2
- package/dist/approvalsStreamLiveCapability.js +15 -35
- package/dist/deviceExecutorManagementCapability.js +15 -35
- package/dist/engineAgentPanelStore.js +13 -1
- package/dist/engineCapReader.d.ts +77 -0
- package/dist/engineCapReader.js +87 -0
- package/dist/engineErrorCodes.d.ts +4 -0
- package/dist/engineErrorCodes.js +14 -0
- package/dist/executionLaneCapability.js +15 -38
- package/dist/fleet/fleetRowAgentType.js +1 -1
- package/dist/hitl/approvalOutcomeNote.d.ts +0 -10
- package/dist/hitl/approvalOutcomeNote.js +35 -8
- package/dist/hitl/approvalResolution.d.ts +148 -0
- package/dist/hitl/approvalResolution.js +199 -0
- package/dist/hitl/approvalsFeed.d.ts +100 -2
- package/dist/hitl/approvalsFeed.js +234 -18
- package/dist/hitl/livePendingAsk.d.ts +26 -6
- package/dist/hitl/livePendingAsk.js +52 -12
- package/dist/hitl/persistedRulesWire.d.ts +20 -0
- package/dist/hitl/persistedRulesWire.js +23 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +25 -1
- package/dist/mcpLiveness.d.ts +179 -0
- package/dist/mcpLiveness.js +218 -0
- package/dist/mcpPanel.d.ts +17 -0
- package/dist/mcpPanel.js +21 -0
- package/dist/mcpProbeCapability.d.ts +84 -0
- package/dist/mcpProbeCapability.js +124 -0
- package/dist/memoryComplianceCapability.d.ts +73 -0
- package/dist/memoryComplianceCapability.js +109 -0
- package/dist/memoryEntriesWire.d.ts +302 -0
- package/dist/memoryEntriesWire.js +595 -0
- package/dist/memoryOriginCapability.d.ts +68 -0
- package/dist/memoryOriginCapability.js +102 -0
- package/dist/memorySpecWire.d.ts +175 -0
- package/dist/memorySpecWire.js +320 -0
- package/dist/peerLaneCapability.d.ts +62 -0
- package/dist/peerLaneCapability.js +100 -0
- package/dist/permissionRulesWriteCapability.d.ts +64 -0
- package/dist/permissionRulesWriteCapability.js +98 -0
- package/dist/seam.d.ts +53 -5
- package/dist/seam.js +10 -1
- package/dist/selfOrchestrationDenial.js +7 -2
- package/dist/sqlEngineCapability.js +15 -35
- package/dist/webSearchBackendCapability.js +15 -35
- package/dist/writeProtectionCapability.js +15 -35
- package/docs/INTEGRATION-CLIENTS.md +148 -15
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -140,6 +140,7 @@ export * from './steering.js';
|
|
|
140
140
|
export * from './diagnostics.js';
|
|
141
141
|
export * from './retryStatus.js';
|
|
142
142
|
export * from './sessionMemoryStatus.js';
|
|
143
|
+
export * from './memorySpecWire.js';
|
|
143
144
|
export * from './adapt.js';
|
|
144
145
|
export * from './adapt/textSegmentAuthority.js';
|
|
145
146
|
export * from './engineHttpTools.js';
|
|
@@ -157,6 +158,11 @@ export * from './writeProtectionCapability.js';
|
|
|
157
158
|
export * from './webSearchBackendCapability.js';
|
|
158
159
|
export * from './executionLaneCapability.js';
|
|
159
160
|
export * from './approvalsStreamLiveCapability.js';
|
|
161
|
+
export * from './peerLaneCapability.js';
|
|
162
|
+
export * from './permissionRulesWriteCapability.js';
|
|
163
|
+
export * from './memoryComplianceCapability.js';
|
|
164
|
+
export * from './memoryOriginCapability.js';
|
|
165
|
+
export * from './memoryEntriesWire.js';
|
|
160
166
|
export * from './deviceExecutorManagementCapability.js';
|
|
161
167
|
export * from './mcpReconnect.js';
|
|
162
168
|
export * from './leaderConflict.js';
|
|
@@ -165,6 +171,7 @@ export * from './runCancelContext.js';
|
|
|
165
171
|
export * from './argvFlagValue.js';
|
|
166
172
|
export * from './readFacePosture.js';
|
|
167
173
|
export * from './mcpPanel.js';
|
|
174
|
+
export * from './mcpLiveness.js';
|
|
168
175
|
export * from './effectiveFacts.js';
|
|
169
176
|
export * from './gateOutcome.js';
|
|
170
177
|
export * from './postureKnob.js';
|
|
@@ -257,6 +264,7 @@ export * from './model/providerPresets.js';
|
|
|
257
264
|
export * from './hitl/hitlBridge.js';
|
|
258
265
|
export * from './hitl/suspendedReopen.js';
|
|
259
266
|
export * from './hitl/approvalOutcomeNote.js';
|
|
267
|
+
export * from './hitl/approvalResolution.js';
|
|
260
268
|
export { toolEndOutputText, ENGINE_ABORT_TOOL_RESULT } from './hitl/frameRouter.js';
|
|
261
269
|
export { isAskTool } from './hitl/frameRouter.js';
|
|
262
270
|
export * from './hitl/hitlHostSurface.js';
|
package/dist/index.js
CHANGED
|
@@ -151,6 +151,7 @@ export * from './retryStatus.js';
|
|
|
151
151
|
// 把「部署没这个面」说成「你这个会话不存在」;② 五键缺席语义**逐键不同**,健康会话上就有两键
|
|
152
152
|
// 合法缺席,一律读成「没有/关着/0」就是对用户下一个证不出的断言。
|
|
153
153
|
export * from './sessionMemoryStatus.js';
|
|
154
|
+
export * from './memorySpecWire.js';
|
|
154
155
|
export * from './adapt.js';
|
|
155
156
|
// ── L-318(0.68.2):`text_end` 权威段替换的**判决单源** + print 形车道的段账状态机 ──────────
|
|
156
157
|
// 修前这套六形判据有两份实现:本包 `adapt/textStream.replaceAnswerSegment`(交互车道)与 cli
|
|
@@ -193,6 +194,23 @@ export * from './executionLaneCapability.js';
|
|
|
193
194
|
// · approvalsStreamLiveCapability(0.73.3 CC-61):capabilities.approvalsStreamLive 四态读面 + feed 消费方「要不要靠对账拉」的判据单源。
|
|
194
195
|
export * from './approvalsStreamLiveCapability.js';
|
|
195
196
|
// · deviceExecutorManagementCapability(0.74.2 CC-69):capabilities.deviceExecutor.management 四态读面 + 管理动词可用性判据单源。
|
|
197
|
+
// 各只能力位读器的 tee / 读口 / 失效口 / 测试钩共用 `engineCapReader`(0.76.1 CC-75;包内叶,不出 barrel)。
|
|
198
|
+
// · peerLaneCapability(0.76.1 CC-102):capabilities.peerLane 四态读面 —— 键缺席 = 老 worker 判不出、`false` = 明确没挂跨会话目录席(正面事实);
|
|
199
|
+
// 非 HTTP 面,消费方式是渲染/预期,不 gate 某个动词。「要不要露出跨会话入口」三态判据单源 peerLaneAvailable。
|
|
200
|
+
export * from './peerLaneCapability.js';
|
|
201
|
+
// · permissionRulesWriteCapability(0.76.1 CC-102):capabilities.permissionRulesWrite 四态读面 —— 键缺席 = 这份二进制比单步写口老(藏入口)、
|
|
202
|
+
// 键在场按值判「这次调用够不够得着」(与撤销面那只部署级存在性信号刻意不同源,别互相套用读法)。布尔便利口 permissionRulesWriteAvailable 是本位唯一派生点。
|
|
203
|
+
export * from './permissionRulesWriteCapability.js';
|
|
204
|
+
// · memoryComplianceCapability(0.76.1 CC-97a):capabilities.memoryCompliance 四态读面(出处问询 / 抹除两口)——
|
|
205
|
+
// 键缺席 = 老引擎判不出、`false` = 明确的否、畸形删格绝不折否;两口可用性三态判据 + 记忆治理面 501 码单源。
|
|
206
|
+
export * from './memoryComplianceCapability.js';
|
|
207
|
+
// · memoryOriginCapability(0.76.1 CC-97a):capabilities.memoryOrigin 四态读面(外源标记人面三口)——
|
|
208
|
+
// 与上一只**同判据不同位**,刻意各持一张表、不合并(引擎刻意不合并,今天恒同值也不许折)。
|
|
209
|
+
export * from './memoryOriginCapability.js';
|
|
210
|
+
// · memoryEntriesWire(0.76.1 CC-97a):记忆条目面三个 200 回体的窄读口(导出条目行 / 抹除证明 / 外源清标回执)——
|
|
211
|
+
// 逐行窄读三向边界(空数组 = 真 0 / 非空全坏 = malformed / 半坏 = present + dropped)、`historyUnknown` 三态原样过境、
|
|
212
|
+
// 「抹了 0 条」与「200 空体」与「读不懂」判成三回事,以及「空答绝不读作本店干净」的代码落点(判词口的 originAware 必填形参)。
|
|
213
|
+
export * from './memoryEntriesWire.js';
|
|
196
214
|
export * from './deviceExecutorManagementCapability.js';
|
|
197
215
|
// S-381 / core 7.22.0 #857(0.72.9 CC-30;server ≥7.85.0,sdk 尚未声明):会话内 MCP re-dial 的消费口 —— 200 三态按 outcome 分形读、
|
|
198
216
|
// unsupported 恒五键、名册按 toolNames 在场性、失败按 errorCode 分诊、「重连 = 一次交易」措辞单源;能力位 mcpReconnect 三态读。
|
|
@@ -213,6 +231,9 @@ export * from './argvFlagValue.js';
|
|
|
213
231
|
export * from './readFacePosture.js';
|
|
214
232
|
// CC-03(0.68.2):`GET /v1/sessions/:id/mcp` 面板体的防御读视图 + lastLegMcp 一行措辞铸点(三端共用)。
|
|
215
233
|
export * from './mcpPanel.js';
|
|
234
|
+
// CC-36(0.76.1):引擎托管 MCP 服务器的**活性观察**(`wiring_manifest.mcp[].liveness`)结构读口 ——
|
|
235
|
+
// 三词闭集词表 + 行级三向读数(缺席 / 在场读不出 / 一次观察)+ 腿级四读数判词与它的唯一措辞铸点。
|
|
236
|
+
export * from './mcpLiveness.js';
|
|
216
237
|
export * from './effectiveFacts.js';
|
|
217
238
|
export * from './gateOutcome.js';
|
|
218
239
|
// 0.63.0(sdk 8.8.0 / engine ≥7.67.0 / S-178):`serverGates` 三根 posture 旋钮的读数窄读器
|
|
@@ -446,6 +467,8 @@ export * from './hitl/hitlBridge.js';
|
|
|
446
467
|
export * from './hitl/suspendedReopen.js';
|
|
447
468
|
// 0.74.5 CC-88:流内帧腿审批结局 → 宿主便签的单源映射(三端手拼退役)
|
|
448
469
|
export * from './hitl/approvalOutcomeNote.js';
|
|
470
|
+
// CC-77 ①:「一次审批决断最后怎么了」的单源判别联合 + 唯一映射口(additive;既有结局型面一字不动)
|
|
471
|
+
export * from './hitl/approvalResolution.js';
|
|
449
472
|
// [C93] P0 直讨(0.17.1):toolEndOutputText 单一真源导出——web/desktop 被点名「两端务必接」的
|
|
450
473
|
// 6.0.0 output content-block 归一,此前 frameRouter 内私有,两端手抄=漂移温床。frameRouter 只
|
|
451
474
|
// 挑名导出这一件(整星导出会把路由内部面全泄进公面)。
|
|
@@ -498,7 +521,8 @@ export * from './hitl/resumeRunningCard.js';
|
|
|
498
521
|
// RulesFailure 处置分类(404 两支绝不共用一格)、keyset 翻页收口(游标失效重列 + 页数硬帽)、
|
|
499
522
|
// skipped.reason 前缀分类、persist-ack 三态读口 —— 读口与 `readToolApprovalRespondAck`
|
|
500
523
|
// **合成一处**(census top-08 #1 的双份台账收口本体);CC settings 三层 fs 读、SDK facade
|
|
501
|
-
// 装配、通知呈现留宿主。
|
|
524
|
+
// 装配、通知呈现留宿主。0.76.1 CC-102 补 persistedRulesWriteAvailable:单步写入口便利口,
|
|
525
|
+
// 只派生自 permissionRulesWriteCapability 的四态读数,与撤销面那只合取式刻意不同源。
|
|
502
526
|
// · localAllowRule:parseLocalAllowRule 窄化五步(①整工具拒/②工具名对齐/③字面锚/⑤裸解释器
|
|
503
527
|
// 前缀/⑤b canonical 危险谓词)骨架;危险谓词与规则语法经 `LocalAllowRuleDeps` 注入
|
|
504
528
|
// (parkOwnership deps 同形)—— 谓词表本体(BARE_SHELL_PREFIXES / dangerousPatterns)留宿主,
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mcpLiveness.ts — 引擎托管的 MCP 服务器**活性观察**(`wiring_manifest.mcp[].liveness`)的三端共用
|
|
3
|
+
* **结构读口** + 三词闭集词表 + 腿级判词(CC-36,0.76.1)。引擎内核自 7.24.3 起铸这一格,服务端的转发层自 7.91.2 起把它送上 wire ——
|
|
4
|
+
* 更老的服务端上这一格**恒缺席**(读数 = `indeterminate`,正是缺席语义要兜的那一档,不是故障)。
|
|
5
|
+
*
|
|
6
|
+
* ── 这一格答的是哪一个问题 ────────────────────────────────────────────────────────────────────
|
|
7
|
+
* 「这台服务器**还够得着吗**」。引擎不为它发任何自己的流量 —— 每条记录都是那条腿**已经做过的工作**
|
|
8
|
+
* (拨号、re-dial、传输关闭、一次发现传输没了的请求)顺带盖的章,自带盖章时刻 `observedAt`。
|
|
9
|
+
* ⇒ 它是**每条腿的一张快照**,不是心跳、不是轮询、更不是「此刻」。
|
|
10
|
+
*
|
|
11
|
+
* 🔴 **同一行上的三个位各说各的,谁都不许顶替谁、不许互相校验、不许据其一推另一个**:
|
|
12
|
+
* · `status`(申报 / 连接时判决)—— 这条腿**拨号那一刻**的判词,引擎**有意冻结**它(服务器中途死了这一格
|
|
13
|
+
* 仍读 `connected`);
|
|
14
|
+
* · re-dial 回执的 `outcome`(动作判决)—— **一次动作**的判词,过去式;
|
|
15
|
+
* · `liveness`(本件)—— 连接层**最后学到的那件事**,自带时戳。
|
|
16
|
+
* 最直白的一格:`status: 'failed'` 与 `liveness.state: 'reachable'` **同一行并存是真行** —— 服务器答了
|
|
17
|
+
* 握手、答的是协议错(**活着,且配错了**)。判据是「两格都在」,不是「两格一致」。
|
|
18
|
+
*
|
|
19
|
+
* ── 🔴 四种读数(三个词 + 缺席),缺席**不是**其中任何一个词 ────────────────────────────────────
|
|
20
|
+
* · `reachable` —— **一次交换完成了**(连上并列出了,或服务器自己答了 —— MCP 级的拒绝**也是答**,所以
|
|
21
|
+
* 它证明够得着,即便那次调用失败);
|
|
22
|
+
* · `unreachable` —— 试过,丢在传输或时钟上(拒连 / 重置 / 关闭 / 起不来 / 超时);
|
|
23
|
+
* · `unknown` —— **试过,而回来的东西答不了这个问题**(服务器前面那台网关写的 HTTP 状态、非 MCP 载荷、
|
|
24
|
+
* 没有结构的抛出值)。它是一句**更强**的断言:引擎看了,看不出来。
|
|
25
|
+
* · **缺席 = indeterminate** —— 这一行**没有可用的观察记录**。四个来源在 wire 上**同形**,消费端分不出也
|
|
26
|
+
* 不需要分:① 这条腿没走到那台服务器(`status: 'skipped'`);② 那份声明从来没被拨过(`invalid_config`);
|
|
27
|
+
* ③ 这是一条老引擎 / 老服务端的帧;④ 上游判形没过、那一格被摘掉了。
|
|
28
|
+
* 🔴 **不许据缺席反推「这条腿拨没拨过号」**,也不许把它折进 `unknown`、折成「健康」、折成「关着」。
|
|
29
|
+
* 这四句话在本包里是四句不同的话,任何折叠都是「把不知道说成没有 / 说成好着呢」的变体。
|
|
30
|
+
*
|
|
31
|
+
* ── 为什么是结构读(不靠型面) ─────────────────────────────────────────────────────────────────
|
|
32
|
+
* 本包 peer 地板上的 wire 型面里**还没有这一格**(键形是引擎侧先出、型面后出的常态)。所以本件按契约
|
|
33
|
+
* **结构读**:从 `unknown` 起按键路径窄化,判据自带(见下),**不抬 peer 地板、不等型面**。安全性不靠型
|
|
34
|
+
* 而靠三条:① 三词按**闭集恰等**判,认不得的词一律畸形(词表属主在上游,本包**不放宽**成开集 —— 放宽了
|
|
35
|
+
* 就会把一个没人定义过的词当成一句真话往屏上送);② `observedAt` 按**有限数**判;③ 判形没过 ⇒ 这一格
|
|
36
|
+
* 摘掉、那一行照读(与上游同判),而摘掉的**理由**留在 {@link McpLivenessCell} 的 `unreadable` 臂上,
|
|
37
|
+
* 与「引擎没报」分开。型面出键那天由包侧门逼一次显式处置(见 `run-mcp-liveness-test.mjs` 的上游见证臂)。
|
|
38
|
+
*
|
|
39
|
+
* ── `errorCode` 只随 `unreachable` ────────────────────────────────────────────────────────────
|
|
40
|
+
* 它是那句话的**注脚**(为什么够不着),不是那句话本身。上游的单点铸造保证它**只随 `unreachable`** 出现,
|
|
41
|
+
* 理由逐字可查:`unknown` 的全部意思就是「那次失败并没有决定可达性」,把失败类别挂在那个词上等于请消费端
|
|
42
|
+
* 拿一份说明不了可达性的证据去决定下一步动作。⇒ 本读口在**非 `unreachable`** 臂上**丢掉这只注脚**
|
|
43
|
+
* (整格仍在、`state` 仍读):去掉的恰是上游点名要防的那条误读路,而 `state` 那句话一个字没动。
|
|
44
|
+
* 注脚自己形坏(空串 / 非串)同样**只丢它自己不拆整格** —— 代价如实:此时读到的是「够不着,原因没说」,
|
|
45
|
+
* **不是**「这条记录坏了」。词按**开集**读(十词闭集的属主在上游,抄一张会把新词吞成缺席)。
|
|
46
|
+
*/
|
|
47
|
+
/**
|
|
48
|
+
* 活性词的**三词闭集**(与上游同序:能完成交换 / 完不成 / 答不了)。
|
|
49
|
+
*
|
|
50
|
+
* 🔴 **它只有三个词**。腿级判词的第四个读数 `indeterminate`(见 {@link McpLegLivenessReading})**不是**
|
|
51
|
+
* 本表成员,也绝不许被加进来:本表是**上游的词表**,那第四个读数是**缺席**在本包里的名字。
|
|
52
|
+
* 🔴 消费端按本表写的 `switch` 判**恰等**(不 trim、不折大小写、不按前缀猜);上游加词的唯一处置是
|
|
53
|
+
* **本表同批加一格 + 补一条读数格**,而不是在消费点放宽判据。
|
|
54
|
+
*/
|
|
55
|
+
export declare const MCP_LIVENESS_STATES: readonly ["reachable", "unreachable", "unknown"];
|
|
56
|
+
/** {@link MCP_LIVENESS_STATES} 的三个词 —— **由那张表派生**,不另手写一份(两份手写迟早各说一套;本包不依赖上游型面,见文件顶注)。 */
|
|
57
|
+
export type McpLivenessState = (typeof MCP_LIVENESS_STATES)[number];
|
|
58
|
+
/** 一台服务器的**一次**活性观察(读视图;逐键挑,开集键不透传)。 */
|
|
59
|
+
export interface McpLivenessView {
|
|
60
|
+
/** 三词闭集(见 {@link MCP_LIVENESS_STATES});认不得的词不到这里(整格判畸形)。 */
|
|
61
|
+
state: McpLivenessState;
|
|
62
|
+
/** 盖章时刻(epoch 毫秒,有限数)。🔴 它是**那条腿**的观察时刻 —— 不是「此刻」,也不与面板的
|
|
63
|
+
* `asOf` 同源,两者**不比**。 */
|
|
64
|
+
observedAt: number;
|
|
65
|
+
/** 够不着的**类别注脚**(开集,上游十词;**只随 `unreachable`** 在场)。缺席 = 原因没说,
|
|
66
|
+
* **不是**「这条记录坏了」,更不是第四态。 */
|
|
67
|
+
errorCode?: string;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* 一行上这一格的三向读数(**缺席 / 在场读不出 / 一次观察**三句话分开,任何两句都不折)。
|
|
71
|
+
* · `absent` —— 键不在场 = 没有可用的观察记录(四源同形,见文件顶注);
|
|
72
|
+
* · `unreadable` —— 键**在场**而读不出(整格不是对象 / 词出闭集 / `observedAt` 非有限数)。它与 `absent`
|
|
73
|
+
* **不是**一句话:「引擎送了一份我读不懂的」与「引擎没报」对运维是两件事;
|
|
74
|
+
* · `observation` —— 读得出的那一次观察。
|
|
75
|
+
*/
|
|
76
|
+
export type McpLivenessCell = {
|
|
77
|
+
kind: 'absent';
|
|
78
|
+
} | {
|
|
79
|
+
kind: 'unreadable';
|
|
80
|
+
} | {
|
|
81
|
+
kind: 'observation';
|
|
82
|
+
liveness: McpLivenessView;
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* 从**一行** MCP 名册条目里读这一格(结构读;单一铸点,别在消费点再写一遍判据)。
|
|
86
|
+
*
|
|
87
|
+
* 缺席答什么:`{kind:'absent'}` —— 判据是**自有键在不在**(`Object.hasOwn`),不按真值判。原型链上的
|
|
88
|
+
* 同名键**永远不会**上 wire,拿它当在场 = 把本进程对象的形状当成引擎说过的话;`null` / `undefined`
|
|
89
|
+
* 显式在场是**坏形**(走 `unreadable`),不是缺席形。
|
|
90
|
+
* 畸形答什么:`{kind:'unreadable'}` —— 整行不是对象、整格不是对象(含 `null` / 数组 / 串 / 数)、
|
|
91
|
+
* `state` 不是三词之一(含空串、近形拼法、大小写变体)、`observedAt` 非有限数(含缺席 / 串 / `NaN`)。
|
|
92
|
+
* 🔴 **绝不**折成 `{kind:'absent'}`(会把「送来一份读不懂的」说成「引擎没报」),更**绝不**折成
|
|
93
|
+
* `reachable` 或任何一个词(那是把读不出说成好着呢)。
|
|
94
|
+
* 为什么不折:这三句话在本包下游各对一种不同的处置 —— 缺席 = 什么都不渲(**不许**渲「一台都够不着」也
|
|
95
|
+
* **不许**渲「都好着」);读不出 = 渲「这一格读不出」并让运维去看引擎版本与投影层;观察 = 渲那个词
|
|
96
|
+
* + 那个时刻。折任何一对,渲出来的都是一句谁都没说过的话。
|
|
97
|
+
*
|
|
98
|
+
* ⚠️ 本口**只读这一格**:同行的 `status` / `errorCode` / `delivered` 一个字节都不碰,也不拿它们互相校验
|
|
99
|
+
* (三个位各说各的,见文件顶注)。
|
|
100
|
+
*/
|
|
101
|
+
export declare function readMcpLiveness(row: unknown): McpLivenessCell;
|
|
102
|
+
/**
|
|
103
|
+
* 腿级判词能吃的**最小行形**(结构型入参:凡带这两格的行视图都喂得进来,本口刻意不与某一张具体的
|
|
104
|
+
* 行视图型耦合 —— 活体腿的名册与面板上那条腿的回放是**同一只读器**的产物,判词也只该有一份)。
|
|
105
|
+
*/
|
|
106
|
+
export interface McpLivenessBearingRow {
|
|
107
|
+
/** 读得出的那次观察(缺席 = 这一行没有可用观察,或那一格读不出 —— 后者看 {@link livenessUnreadable})。 */
|
|
108
|
+
liveness?: McpLivenessView;
|
|
109
|
+
/** never false:这一行的活性格**在场而读不出**(与整格缺席不是一句话)。 */
|
|
110
|
+
livenessUnreadable?: true;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* 一条腿的活性读数:三个词 + `indeterminate`(= 这条腿上**没有任何在场的活性格**)。
|
|
114
|
+
*
|
|
115
|
+
* 🔴 `indeterminate` **不是**上游词表的成员(词表仍是三词,见 {@link MCP_LIVENESS_STATES})——
|
|
116
|
+
* 它是**缺席**在本包里的名字,存在的全部理由就是不让缺席借用那三个词里的任何一个。
|
|
117
|
+
*/
|
|
118
|
+
export type McpLegLivenessReading = McpLivenessState | 'indeterminate';
|
|
119
|
+
/** 一条腿的活性判词 + 它的两条诚实附注。 */
|
|
120
|
+
export interface McpEngineLegHealth {
|
|
121
|
+
/** 判词(四读数;合成规则见 {@link mcpLivenessRollupOf})。 */
|
|
122
|
+
reading: McpLegLivenessReading;
|
|
123
|
+
/** never false:这条腿上**至少有一行**的活性格在场而读不出(判词为什么退到 `unknown` 的分辨位)。 */
|
|
124
|
+
unreadableCells?: true;
|
|
125
|
+
/**
|
|
126
|
+
* **判词那个词自己的**观察时刻(epoch 毫秒)= 带着决定 {@link reading} 那个词的那些行里**最新的**一格。
|
|
127
|
+
*
|
|
128
|
+
* 🔴 刻意**不是**「这条腿上所有观察里最新的那一格」(异源对抗复审 r1 [medium] 采纳,真病):一行在
|
|
129
|
+
* t=1000 观察到 `unreachable`、另一行在 t=900000 观察到 `reachable` 时,跨行取最大会让「至少有一台
|
|
130
|
+
* 够不着」这句判词后面跟上一个**属于那次成功观察**的时刻 —— 运维会把一次旧故障读成刚刚又被确认一次。
|
|
131
|
+
* ⇒ 时刻与判词**同源**:判词说 `unreachable`,这一格就是最新那次 `unreachable` 的时刻。
|
|
132
|
+
* 🔴 在场 iff 有**读得出的观察**决定了判词:`indeterminate` 上永不在场;判词是 `unknown` 而**只**由
|
|
133
|
+
* 「在场读不出」的格决定(没有一格读得出)时同样不在场 —— 读不出的格没有可用时刻,编一个就是造读数。
|
|
134
|
+
* ⚠️ 它是**那条腿**的观察时刻,不是「此刻」,也与面板的 materialize 时刻不同源、**不比**。
|
|
135
|
+
* 别的词那些行的时刻本口不铸(要逐行时刻就读行视图,不要从一个聚合值反推某一行)。
|
|
136
|
+
*/
|
|
137
|
+
observedAt?: number;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* 一条腿的名册 → 活性判词(**唯一铸点**:别在各端的状态行装配里另写一遍这套合成规则)。
|
|
141
|
+
*
|
|
142
|
+
* 合成规则 = **最坏事实优先**,不是多数票、不是取最新一格:
|
|
143
|
+
* ① 任一行 `unreachable` ⇒ `unreachable`(有一台**可证**打不通时说「够得着」,就是把坏消息折成健康);
|
|
144
|
+
* ② 否则任一行 `unknown` **或任一行的格读不出**(`livenessUnreadable`,或入参自带一格形坏的 `liveness`)
|
|
145
|
+
* ⇒ `unknown`。在**腿**这一层,`unknown` 的意思恰是
|
|
146
|
+
* 「有观察在场而答不了这个问题」,而一份读不懂的格**同样答不了** ⇒ 🔴 **读不出的格绝不作可达的证据**
|
|
147
|
+
* (否则「一行读不出 + 一行 reachable」会合成一句「这条腿够得着」,而那行读不出的格完全可能本来写着
|
|
148
|
+
* `unreachable`)。为什么答不了,由 {@link McpEngineLegHealth.unreadableCells} 分辨;
|
|
149
|
+
* ③ 否则任一行 `reachable` ⇒ `reachable`(其余行缺席 = 没观察,不是反证);
|
|
150
|
+
* ④ 否则 ⇒ `indeterminate`。
|
|
151
|
+
*
|
|
152
|
+
* 缺席答什么:`{reading:'indeterminate'}` —— 三种入参落这一档且**刻意同形**:段读不出(`undefined`)、
|
|
153
|
+
* 零申报(`[]`,这条腿一台服务器都没申报 ⇒ 没有服务器就没有观察)、每一行的活性格都缺席(老引擎 /
|
|
154
|
+
* 都没走到)。要分「一台都没申报」与「有服务器但没报活性」,问名册本身(行数)或在场判词,**不要**
|
|
155
|
+
* 让本口替那一问答话。
|
|
156
|
+
* 畸形答什么:整个入参不是数组 ⇒ `indeterminate`;行本身不是对象 ⇒ **那一行什么都不贡献**(连「有没有
|
|
157
|
+
* 这一格」都没读出来,不替它认领一格);行在而那一格形坏 ⇒ 按上面的 ② 算「读不出」。**永不抛**。
|
|
158
|
+
* 为什么不折:`indeterminate` 与三个词之间**没有**默认值可回落 —— 回落到 `reachable` 是谎、回落到
|
|
159
|
+
* `unreachable` 是恐慌、回落到 `unknown` 是替引擎认领一次它没做过的观察。
|
|
160
|
+
*/
|
|
161
|
+
export declare function mcpLivenessRollupOf(rows: readonly McpLivenessBearingRow[] | undefined): McpEngineLegHealth;
|
|
162
|
+
/**
|
|
163
|
+
* 活性那一行措辞的**唯一铸点**(三端共用;别在各端的行装配里另写一遍)。
|
|
164
|
+
*
|
|
165
|
+
* 🔴 四句刻意逐字互异,且**没有一句**把 `indeterminate` 说成「都好着」或「一台都够不着」:
|
|
166
|
+
* ① `reachable` —— 上次交换完成了(这条腿的观察,带时刻);
|
|
167
|
+
* ② `unreachable` —— 至少一台**可证**够不着;
|
|
168
|
+
* ③ `unknown` —— 看过了,答不了(读不出的格同落这一档,附注多一句);
|
|
169
|
+
* ③′ `unknown` 且**只**由读不出的格决定(判词无时刻 ∧ `unreadableCells`)—— 另一句:记录在场而**本端读不出**。
|
|
170
|
+
* ③ 那句的主语是「回来的东西」(引擎看了、看不出来),③′ 的主语是本端的读器 —— 上游哪天加了第四个词,
|
|
171
|
+
* 老客户端落的正是 ③′;把它说成 ③ 等于替引擎认领一次它没做过的「看不出来」。
|
|
172
|
+
* ④ `indeterminate` —— **没报**:这条腿上没有可用的观察记录,**不武断咎为引擎版本**(四源同形)。
|
|
173
|
+
* 🔴 句子里**不出现**服务器台数与「健康 / 正常」这类词:台数在名册上,而「健康」是本格答不了的问题
|
|
174
|
+
* (它只答「还够得着吗」)。
|
|
175
|
+
* 🔴 句尾那个时刻**属于句子里那个判词**(见 {@link McpEngineLegHealth.observedAt}):说「至少有一台够不着」
|
|
176
|
+
* 时它是最新那次**够不着**的观察时刻,不是这条腿上任何一次观察的最大值 —— 否则一句旧故障的判词会跟上
|
|
177
|
+
* 一个属于别的词的新时刻,读起来像刚刚又确认了一次。时刻缺席时句子里就没有时刻,不编「刚刚」。
|
|
178
|
+
*/
|
|
179
|
+
export declare function mcpEngineLegHealthDetail(health: McpEngineLegHealth | undefined): string;
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mcpLiveness.ts — 引擎托管的 MCP 服务器**活性观察**(`wiring_manifest.mcp[].liveness`)的三端共用
|
|
3
|
+
* **结构读口** + 三词闭集词表 + 腿级判词(CC-36,0.76.1)。引擎内核自 7.24.3 起铸这一格,服务端的转发层自 7.91.2 起把它送上 wire ——
|
|
4
|
+
* 更老的服务端上这一格**恒缺席**(读数 = `indeterminate`,正是缺席语义要兜的那一档,不是故障)。
|
|
5
|
+
*
|
|
6
|
+
* ── 这一格答的是哪一个问题 ────────────────────────────────────────────────────────────────────
|
|
7
|
+
* 「这台服务器**还够得着吗**」。引擎不为它发任何自己的流量 —— 每条记录都是那条腿**已经做过的工作**
|
|
8
|
+
* (拨号、re-dial、传输关闭、一次发现传输没了的请求)顺带盖的章,自带盖章时刻 `observedAt`。
|
|
9
|
+
* ⇒ 它是**每条腿的一张快照**,不是心跳、不是轮询、更不是「此刻」。
|
|
10
|
+
*
|
|
11
|
+
* 🔴 **同一行上的三个位各说各的,谁都不许顶替谁、不许互相校验、不许据其一推另一个**:
|
|
12
|
+
* · `status`(申报 / 连接时判决)—— 这条腿**拨号那一刻**的判词,引擎**有意冻结**它(服务器中途死了这一格
|
|
13
|
+
* 仍读 `connected`);
|
|
14
|
+
* · re-dial 回执的 `outcome`(动作判决)—— **一次动作**的判词,过去式;
|
|
15
|
+
* · `liveness`(本件)—— 连接层**最后学到的那件事**,自带时戳。
|
|
16
|
+
* 最直白的一格:`status: 'failed'` 与 `liveness.state: 'reachable'` **同一行并存是真行** —— 服务器答了
|
|
17
|
+
* 握手、答的是协议错(**活着,且配错了**)。判据是「两格都在」,不是「两格一致」。
|
|
18
|
+
*
|
|
19
|
+
* ── 🔴 四种读数(三个词 + 缺席),缺席**不是**其中任何一个词 ────────────────────────────────────
|
|
20
|
+
* · `reachable` —— **一次交换完成了**(连上并列出了,或服务器自己答了 —— MCP 级的拒绝**也是答**,所以
|
|
21
|
+
* 它证明够得着,即便那次调用失败);
|
|
22
|
+
* · `unreachable` —— 试过,丢在传输或时钟上(拒连 / 重置 / 关闭 / 起不来 / 超时);
|
|
23
|
+
* · `unknown` —— **试过,而回来的东西答不了这个问题**(服务器前面那台网关写的 HTTP 状态、非 MCP 载荷、
|
|
24
|
+
* 没有结构的抛出值)。它是一句**更强**的断言:引擎看了,看不出来。
|
|
25
|
+
* · **缺席 = indeterminate** —— 这一行**没有可用的观察记录**。四个来源在 wire 上**同形**,消费端分不出也
|
|
26
|
+
* 不需要分:① 这条腿没走到那台服务器(`status: 'skipped'`);② 那份声明从来没被拨过(`invalid_config`);
|
|
27
|
+
* ③ 这是一条老引擎 / 老服务端的帧;④ 上游判形没过、那一格被摘掉了。
|
|
28
|
+
* 🔴 **不许据缺席反推「这条腿拨没拨过号」**,也不许把它折进 `unknown`、折成「健康」、折成「关着」。
|
|
29
|
+
* 这四句话在本包里是四句不同的话,任何折叠都是「把不知道说成没有 / 说成好着呢」的变体。
|
|
30
|
+
*
|
|
31
|
+
* ── 为什么是结构读(不靠型面) ─────────────────────────────────────────────────────────────────
|
|
32
|
+
* 本包 peer 地板上的 wire 型面里**还没有这一格**(键形是引擎侧先出、型面后出的常态)。所以本件按契约
|
|
33
|
+
* **结构读**:从 `unknown` 起按键路径窄化,判据自带(见下),**不抬 peer 地板、不等型面**。安全性不靠型
|
|
34
|
+
* 而靠三条:① 三词按**闭集恰等**判,认不得的词一律畸形(词表属主在上游,本包**不放宽**成开集 —— 放宽了
|
|
35
|
+
* 就会把一个没人定义过的词当成一句真话往屏上送);② `observedAt` 按**有限数**判;③ 判形没过 ⇒ 这一格
|
|
36
|
+
* 摘掉、那一行照读(与上游同判),而摘掉的**理由**留在 {@link McpLivenessCell} 的 `unreadable` 臂上,
|
|
37
|
+
* 与「引擎没报」分开。型面出键那天由包侧门逼一次显式处置(见 `run-mcp-liveness-test.mjs` 的上游见证臂)。
|
|
38
|
+
*
|
|
39
|
+
* ── `errorCode` 只随 `unreachable` ────────────────────────────────────────────────────────────
|
|
40
|
+
* 它是那句话的**注脚**(为什么够不着),不是那句话本身。上游的单点铸造保证它**只随 `unreachable`** 出现,
|
|
41
|
+
* 理由逐字可查:`unknown` 的全部意思就是「那次失败并没有决定可达性」,把失败类别挂在那个词上等于请消费端
|
|
42
|
+
* 拿一份说明不了可达性的证据去决定下一步动作。⇒ 本读口在**非 `unreachable`** 臂上**丢掉这只注脚**
|
|
43
|
+
* (整格仍在、`state` 仍读):去掉的恰是上游点名要防的那条误读路,而 `state` 那句话一个字没动。
|
|
44
|
+
* 注脚自己形坏(空串 / 非串)同样**只丢它自己不拆整格** —— 代价如实:此时读到的是「够不着,原因没说」,
|
|
45
|
+
* **不是**「这条记录坏了」。词按**开集**读(十词闭集的属主在上游,抄一张会把新词吞成缺席)。
|
|
46
|
+
*/
|
|
47
|
+
/**
|
|
48
|
+
* 活性词的**三词闭集**(与上游同序:能完成交换 / 完不成 / 答不了)。
|
|
49
|
+
*
|
|
50
|
+
* 🔴 **它只有三个词**。腿级判词的第四个读数 `indeterminate`(见 {@link McpLegLivenessReading})**不是**
|
|
51
|
+
* 本表成员,也绝不许被加进来:本表是**上游的词表**,那第四个读数是**缺席**在本包里的名字。
|
|
52
|
+
* 🔴 消费端按本表写的 `switch` 判**恰等**(不 trim、不折大小写、不按前缀猜);上游加词的唯一处置是
|
|
53
|
+
* **本表同批加一格 + 补一条读数格**,而不是在消费点放宽判据。
|
|
54
|
+
*/
|
|
55
|
+
export const MCP_LIVENESS_STATES = Object.freeze(['reachable', 'unreachable', 'unknown']);
|
|
56
|
+
/** 三词闭集的**唯一**判据(恰等;行级读口与腿级判词共用这一只,不各写一遍)。 */
|
|
57
|
+
const isLivenessState = (v) => typeof v === 'string' && MCP_LIVENESS_STATES.includes(v);
|
|
58
|
+
const isRecord = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
59
|
+
/**
|
|
60
|
+
* 从**一行** MCP 名册条目里读这一格(结构读;单一铸点,别在消费点再写一遍判据)。
|
|
61
|
+
*
|
|
62
|
+
* 缺席答什么:`{kind:'absent'}` —— 判据是**自有键在不在**(`Object.hasOwn`),不按真值判。原型链上的
|
|
63
|
+
* 同名键**永远不会**上 wire,拿它当在场 = 把本进程对象的形状当成引擎说过的话;`null` / `undefined`
|
|
64
|
+
* 显式在场是**坏形**(走 `unreadable`),不是缺席形。
|
|
65
|
+
* 畸形答什么:`{kind:'unreadable'}` —— 整行不是对象、整格不是对象(含 `null` / 数组 / 串 / 数)、
|
|
66
|
+
* `state` 不是三词之一(含空串、近形拼法、大小写变体)、`observedAt` 非有限数(含缺席 / 串 / `NaN`)。
|
|
67
|
+
* 🔴 **绝不**折成 `{kind:'absent'}`(会把「送来一份读不懂的」说成「引擎没报」),更**绝不**折成
|
|
68
|
+
* `reachable` 或任何一个词(那是把读不出说成好着呢)。
|
|
69
|
+
* 为什么不折:这三句话在本包下游各对一种不同的处置 —— 缺席 = 什么都不渲(**不许**渲「一台都够不着」也
|
|
70
|
+
* **不许**渲「都好着」);读不出 = 渲「这一格读不出」并让运维去看引擎版本与投影层;观察 = 渲那个词
|
|
71
|
+
* + 那个时刻。折任何一对,渲出来的都是一句谁都没说过的话。
|
|
72
|
+
*
|
|
73
|
+
* ⚠️ 本口**只读这一格**:同行的 `status` / `errorCode` / `delivered` 一个字节都不碰,也不拿它们互相校验
|
|
74
|
+
* (三个位各说各的,见文件顶注)。
|
|
75
|
+
*/
|
|
76
|
+
export function readMcpLiveness(row) {
|
|
77
|
+
// 整行不是对象:说「引擎没报」就是替引擎发言 —— 我们连有没有这一行都没读出来。
|
|
78
|
+
if (!isRecord(row))
|
|
79
|
+
return { kind: 'unreadable' };
|
|
80
|
+
if (!Object.hasOwn(row, 'liveness'))
|
|
81
|
+
return { kind: 'absent' };
|
|
82
|
+
const cell = row.liveness;
|
|
83
|
+
if (!isRecord(cell))
|
|
84
|
+
return { kind: 'unreadable' };
|
|
85
|
+
const state = cell.state;
|
|
86
|
+
if (!isLivenessState(state))
|
|
87
|
+
return { kind: 'unreadable' };
|
|
88
|
+
const observedAt = cell.observedAt;
|
|
89
|
+
if (typeof observedAt !== 'number' || !Number.isFinite(observedAt))
|
|
90
|
+
return { kind: 'unreadable' };
|
|
91
|
+
const liveness = { state, observedAt };
|
|
92
|
+
// 注脚:只随 unreachable 收,且形坏只丢它自己(见文件顶注最后一段)。
|
|
93
|
+
if (state === 'unreachable' && typeof cell.errorCode === 'string' && cell.errorCode.length > 0) {
|
|
94
|
+
liveness.errorCode = cell.errorCode;
|
|
95
|
+
}
|
|
96
|
+
return { kind: 'observation', liveness };
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* 一条腿的名册 → 活性判词(**唯一铸点**:别在各端的状态行装配里另写一遍这套合成规则)。
|
|
100
|
+
*
|
|
101
|
+
* 合成规则 = **最坏事实优先**,不是多数票、不是取最新一格:
|
|
102
|
+
* ① 任一行 `unreachable` ⇒ `unreachable`(有一台**可证**打不通时说「够得着」,就是把坏消息折成健康);
|
|
103
|
+
* ② 否则任一行 `unknown` **或任一行的格读不出**(`livenessUnreadable`,或入参自带一格形坏的 `liveness`)
|
|
104
|
+
* ⇒ `unknown`。在**腿**这一层,`unknown` 的意思恰是
|
|
105
|
+
* 「有观察在场而答不了这个问题」,而一份读不懂的格**同样答不了** ⇒ 🔴 **读不出的格绝不作可达的证据**
|
|
106
|
+
* (否则「一行读不出 + 一行 reachable」会合成一句「这条腿够得着」,而那行读不出的格完全可能本来写着
|
|
107
|
+
* `unreachable`)。为什么答不了,由 {@link McpEngineLegHealth.unreadableCells} 分辨;
|
|
108
|
+
* ③ 否则任一行 `reachable` ⇒ `reachable`(其余行缺席 = 没观察,不是反证);
|
|
109
|
+
* ④ 否则 ⇒ `indeterminate`。
|
|
110
|
+
*
|
|
111
|
+
* 缺席答什么:`{reading:'indeterminate'}` —— 三种入参落这一档且**刻意同形**:段读不出(`undefined`)、
|
|
112
|
+
* 零申报(`[]`,这条腿一台服务器都没申报 ⇒ 没有服务器就没有观察)、每一行的活性格都缺席(老引擎 /
|
|
113
|
+
* 都没走到)。要分「一台都没申报」与「有服务器但没报活性」,问名册本身(行数)或在场判词,**不要**
|
|
114
|
+
* 让本口替那一问答话。
|
|
115
|
+
* 畸形答什么:整个入参不是数组 ⇒ `indeterminate`;行本身不是对象 ⇒ **那一行什么都不贡献**(连「有没有
|
|
116
|
+
* 这一格」都没读出来,不替它认领一格);行在而那一格形坏 ⇒ 按上面的 ② 算「读不出」。**永不抛**。
|
|
117
|
+
* 为什么不折:`indeterminate` 与三个词之间**没有**默认值可回落 —— 回落到 `reachable` 是谎、回落到
|
|
118
|
+
* `unreachable` 是恐慌、回落到 `unknown` 是替引擎认领一次它没做过的观察。
|
|
119
|
+
*/
|
|
120
|
+
export function mcpLivenessRollupOf(rows) {
|
|
121
|
+
if (!Array.isArray(rows))
|
|
122
|
+
return { reading: 'indeterminate' };
|
|
123
|
+
let unreachable = false;
|
|
124
|
+
let unknown = false;
|
|
125
|
+
let reachable = false;
|
|
126
|
+
let unreadable = false;
|
|
127
|
+
// 按**词**分别记最新时刻:判词定下来之后只取那个词自己的(见 McpEngineLegHealth.observedAt 的理由)。
|
|
128
|
+
const newestByWord = {};
|
|
129
|
+
for (const row of rows) {
|
|
130
|
+
if (row === null || typeof row !== 'object')
|
|
131
|
+
continue;
|
|
132
|
+
if (row.livenessUnreadable === true)
|
|
133
|
+
unreadable = true;
|
|
134
|
+
const lv = row.liveness;
|
|
135
|
+
// `undefined` = 这一格不在 = 没有观察(JSON 上根本没有这一键):什么都不贡献,也不算「读不出」。
|
|
136
|
+
if (lv === undefined)
|
|
137
|
+
continue;
|
|
138
|
+
// 形再核一次(本口是公面,入参可能来自宿主自建管线而不是本包的读器):整格不是对象、词出闭集、
|
|
139
|
+
// 时刻非有限数 ⇒ 与 `livenessUnreadable` **同判**(算「在场而读不出」)。🔴 刻意不让它「什么都不贡献」:
|
|
140
|
+
// 那样一行读不懂的格会被另一行的 `reachable` 盖过去,合成一句「这条腿够得着」—— 正是本件要防的那一折。
|
|
141
|
+
if (lv === null || typeof lv !== 'object' || Array.isArray(lv)) {
|
|
142
|
+
unreadable = true;
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
const word = lv.state;
|
|
146
|
+
if (!isLivenessState(word)) {
|
|
147
|
+
unreadable = true;
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
if (typeof lv.observedAt !== 'number' || !Number.isFinite(lv.observedAt)) {
|
|
151
|
+
unreadable = true;
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
if (word === 'unreachable')
|
|
155
|
+
unreachable = true;
|
|
156
|
+
else if (word === 'unknown')
|
|
157
|
+
unknown = true;
|
|
158
|
+
else
|
|
159
|
+
reachable = true;
|
|
160
|
+
const seen = newestByWord[word];
|
|
161
|
+
if (seen === undefined || lv.observedAt > seen)
|
|
162
|
+
newestByWord[word] = lv.observedAt;
|
|
163
|
+
}
|
|
164
|
+
const reading = unreachable
|
|
165
|
+
? 'unreachable'
|
|
166
|
+
: unknown || unreadable
|
|
167
|
+
? 'unknown'
|
|
168
|
+
: reachable
|
|
169
|
+
? 'reachable'
|
|
170
|
+
: 'indeterminate';
|
|
171
|
+
// 时刻与判词同源:`indeterminate` 没有时刻;`unknown` 若只由读不出的格决定,那个词一格可读观察都没有 ⇒ 同样没有时刻。
|
|
172
|
+
const at = reading === 'indeterminate' ? undefined : newestByWord[reading];
|
|
173
|
+
return {
|
|
174
|
+
reading,
|
|
175
|
+
...(unreadable ? { unreadableCells: true } : {}),
|
|
176
|
+
...(at !== undefined ? { observedAt: at } : {}),
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
/** 观察时刻的呈前写法:ISO(与本包其余时刻面同形)。🔴 **超出 `Date` 可表示区间的有限数原样印数字,
|
|
180
|
+
* 绝不抛、也绝不回落到一个编出来的时刻** —— 那一格是引擎给的读数,不是本包的时钟。 */
|
|
181
|
+
const epochLabel = (ms) => Math.abs(ms) <= 8.64e15 ? new Date(ms).toISOString() : String(ms);
|
|
182
|
+
/**
|
|
183
|
+
* 活性那一行措辞的**唯一铸点**(三端共用;别在各端的行装配里另写一遍)。
|
|
184
|
+
*
|
|
185
|
+
* 🔴 四句刻意逐字互异,且**没有一句**把 `indeterminate` 说成「都好着」或「一台都够不着」:
|
|
186
|
+
* ① `reachable` —— 上次交换完成了(这条腿的观察,带时刻);
|
|
187
|
+
* ② `unreachable` —— 至少一台**可证**够不着;
|
|
188
|
+
* ③ `unknown` —— 看过了,答不了(读不出的格同落这一档,附注多一句);
|
|
189
|
+
* ③′ `unknown` 且**只**由读不出的格决定(判词无时刻 ∧ `unreadableCells`)—— 另一句:记录在场而**本端读不出**。
|
|
190
|
+
* ③ 那句的主语是「回来的东西」(引擎看了、看不出来),③′ 的主语是本端的读器 —— 上游哪天加了第四个词,
|
|
191
|
+
* 老客户端落的正是 ③′;把它说成 ③ 等于替引擎认领一次它没做过的「看不出来」。
|
|
192
|
+
* ④ `indeterminate` —— **没报**:这条腿上没有可用的观察记录,**不武断咎为引擎版本**(四源同形)。
|
|
193
|
+
* 🔴 句子里**不出现**服务器台数与「健康 / 正常」这类词:台数在名册上,而「健康」是本格答不了的问题
|
|
194
|
+
* (它只答「还够得着吗」)。
|
|
195
|
+
* 🔴 句尾那个时刻**属于句子里那个判词**(见 {@link McpEngineLegHealth.observedAt}):说「至少有一台够不着」
|
|
196
|
+
* 时它是最新那次**够不着**的观察时刻,不是这条腿上任何一次观察的最大值 —— 否则一句旧故障的判词会跟上
|
|
197
|
+
* 一个属于别的词的新时刻,读起来像刚刚又确认了一次。时刻缺席时句子里就没有时刻,不编「刚刚」。
|
|
198
|
+
*/
|
|
199
|
+
export function mcpEngineLegHealthDetail(health) {
|
|
200
|
+
if (health === undefined)
|
|
201
|
+
return 'mcp liveness not reported (no liveness observation is available to this client)';
|
|
202
|
+
const unreadable = health.unreadableCells === true ? ' (one or more liveness records could not be read)' : '';
|
|
203
|
+
const at = health.observedAt !== undefined ? `, last observed at ${epochLabel(health.observedAt)}` : '';
|
|
204
|
+
switch (health.reading) {
|
|
205
|
+
case 'reachable':
|
|
206
|
+
return `mcp liveness: an exchange completed for every server that was observed on this leg${at}${unreadable}`;
|
|
207
|
+
case 'unreachable':
|
|
208
|
+
return `mcp liveness: at least one server was observed unreachable on this leg${at}${unreadable}`;
|
|
209
|
+
case 'unknown':
|
|
210
|
+
// ③′:时刻缺席 ∧ 有读不出的格 ⇒ 这个 unknown 一格可读观察都没有(时刻与判词同源,见 McpEngineLegHealth.observedAt)。
|
|
211
|
+
if (health.observedAt === undefined && health.unreadableCells === true) {
|
|
212
|
+
return 'mcp liveness: liveness records are present on this leg, but this client could not read them';
|
|
213
|
+
}
|
|
214
|
+
return `mcp liveness: observed on this leg, but what came back does not answer whether the server can be reached${at}${unreadable}`;
|
|
215
|
+
default:
|
|
216
|
+
return `mcp liveness not reported (no observation record on this leg's roster)${unreadable}`;
|
|
217
|
+
}
|
|
218
|
+
}
|
package/dist/mcpPanel.d.ts
CHANGED
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
*/
|
|
37
37
|
import type { AgentClient } from '@sema-agent/sdk';
|
|
38
38
|
import { type WiringManifestMcpEntryView } from './adapter/downstream/eventToSdkMessage.js';
|
|
39
|
+
import { type McpEngineLegHealth } from './mcpLiveness.js';
|
|
39
40
|
/** 面板 `servers[]` 一行(sdk `McpServerStatus` 的窄读;开集键不透传,逐键挑)。 */
|
|
40
41
|
export interface McpPanelServerView {
|
|
41
42
|
/** 配置名(引擎产的标识,非用户内容)。 */
|
|
@@ -120,3 +121,19 @@ export declare function mcpPanelLastLegDetail(view: McpPanelView | undefined, op
|
|
|
120
121
|
*/
|
|
121
122
|
export type McpEngineLegPresence = 'present' | 'absent' | 'unknown';
|
|
122
123
|
export declare function mcpEngineLegPresence(view: McpPanelView | undefined): McpEngineLegPresence;
|
|
124
|
+
/**
|
|
125
|
+
* CC-36(0.76.1):**这条腿的 MCP 活性判词**,只从本包的面板视图求(不自拼第二份判据、不发第二次请求)。
|
|
126
|
+
* 合成规则、四个读数与「缺席 ≠ unknown」那几句话的单一铸点在 {@link mcpLivenessRollupOf};本口只做一件事 ——
|
|
127
|
+
* 把面板上**带活性格的那一面**交给它。
|
|
128
|
+
*
|
|
129
|
+
* 🔴 **活性只在「最近那条腿的名册」这一面上**(`lastLegMcp.mcp[]`)。面板自己的 `servers[]` 半场**没有**
|
|
130
|
+
* 这一格:那一面是**部署缺省场景**此刻按需物化出来的台账,它的投影是逐键挑的白名单,今天不带活性位 ——
|
|
131
|
+
* 所以本口读不到它**不是漏读,是那一面今天没有这句话**。哪天它带上了,处置是同批补一格读数 + 判据,
|
|
132
|
+
* 而**不是**拿这一面的词去顶另一面(两面合法可不同,视图上从来没有、也不会有「一致/不一致」位)。
|
|
133
|
+
* 🔴 **判词说的是「那条腿」,不是「此刻」**:`observedAt` 属于那条腿的观察时刻,与面板的 `asOf` 不同源、
|
|
134
|
+
* **不比**。壳渲这一行必须带腿的时刻,别渲成一个实时健康灯。
|
|
135
|
+
* 🔴 `view === undefined`(传输失败 / 体读不出 / 空 sessionId,三形同形)与「面板读到了但没有那条腿的
|
|
136
|
+
* 名册」**都答 `indeterminate`**:两者的共同点正是这句话本身 —— 本包**说不出**这条腿的活性。
|
|
137
|
+
* 要分辨「这次读没读到面板」问 {@link mcpPanelLastLegDetail} 的 `reachable` 位,**不要**让本口替它答。
|
|
138
|
+
*/
|
|
139
|
+
export declare function mcpEngineLegHealthOf(view: McpPanelView | undefined): McpEngineLegHealth;
|
package/dist/mcpPanel.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { hostLog } from './host.js';
|
|
2
2
|
import { projectMcpSection } from './adapter/downstream/eventToSdkMessage.js';
|
|
3
3
|
import { capForDisplay } from './fleetTaskDesc.js';
|
|
4
|
+
import { mcpLivenessRollupOf } from './mcpLiveness.js';
|
|
4
5
|
/** `error` 上屏前的封长(server 侧 `slice(200)`,同值)。 */
|
|
5
6
|
const MCP_PANEL_ERROR_MAX = 200;
|
|
6
7
|
/** 名字类词形的封长(与本包其余 detail 铸点同值同理由)。 */
|
|
@@ -140,3 +141,23 @@ export function mcpEngineLegPresence(view) {
|
|
|
140
141
|
return 'present';
|
|
141
142
|
return 'absent';
|
|
142
143
|
}
|
|
144
|
+
/**
|
|
145
|
+
* CC-36(0.76.1):**这条腿的 MCP 活性判词**,只从本包的面板视图求(不自拼第二份判据、不发第二次请求)。
|
|
146
|
+
* 合成规则、四个读数与「缺席 ≠ unknown」那几句话的单一铸点在 {@link mcpLivenessRollupOf};本口只做一件事 ——
|
|
147
|
+
* 把面板上**带活性格的那一面**交给它。
|
|
148
|
+
*
|
|
149
|
+
* 🔴 **活性只在「最近那条腿的名册」这一面上**(`lastLegMcp.mcp[]`)。面板自己的 `servers[]` 半场**没有**
|
|
150
|
+
* 这一格:那一面是**部署缺省场景**此刻按需物化出来的台账,它的投影是逐键挑的白名单,今天不带活性位 ——
|
|
151
|
+
* 所以本口读不到它**不是漏读,是那一面今天没有这句话**。哪天它带上了,处置是同批补一格读数 + 判据,
|
|
152
|
+
* 而**不是**拿这一面的词去顶另一面(两面合法可不同,视图上从来没有、也不会有「一致/不一致」位)。
|
|
153
|
+
* 🔴 **判词说的是「那条腿」,不是「此刻」**:`observedAt` 属于那条腿的观察时刻,与面板的 `asOf` 不同源、
|
|
154
|
+
* **不比**。壳渲这一行必须带腿的时刻,别渲成一个实时健康灯。
|
|
155
|
+
* 🔴 `view === undefined`(传输失败 / 体读不出 / 空 sessionId,三形同形)与「面板读到了但没有那条腿的
|
|
156
|
+
* 名册」**都答 `indeterminate`**:两者的共同点正是这句话本身 —— 本包**说不出**这条腿的活性。
|
|
157
|
+
* 要分辨「这次读没读到面板」问 {@link mcpPanelLastLegDetail} 的 `reachable` 位,**不要**让本口替它答。
|
|
158
|
+
*/
|
|
159
|
+
export function mcpEngineLegHealthOf(view) {
|
|
160
|
+
if (view === undefined)
|
|
161
|
+
return { reading: 'indeterminate' };
|
|
162
|
+
return mcpLivenessRollupOf(view.lastLegMcp?.mcp);
|
|
163
|
+
}
|