@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
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mcpProbeCapability — `GET /v1/capabilities.mcpProbe` 的三端共用读面(0.76.1 CC-74;能力位读器第七只,
|
|
3
|
+
* 与 sql / writeProtection / webSearch.backend / executionLane / approvalsStreamLive / deviceExecutor.management
|
|
4
|
+
* 六只兄弟同一套词汇、同一份四口实现 {@link import("./engineCapReader.js").createEngineCapReader})。
|
|
5
|
+
* sdk 9.8.1 对该位**无型** ⇒ 按契约结构读(与 device 那一位 0.74.2 同路);sdk 出键当天由能力位台账门逼一次显式处置。
|
|
6
|
+
*
|
|
7
|
+
* ── 这一位答的是哪一个问题 ────────────────────────────────────────────────────────────────
|
|
8
|
+
* 「这台引擎上**能不能发 MCP 探测请求**」(`POST /v1/capabilities/mcp/probe`)。位为 `true` ⇔ 引擎认这次注入
|
|
9
|
+
* (**单用户姿态 ∧ MCP 车道 wired**,两条合取,与探测口 200 / 501 的谓词同一个表达式);位为 `false` ⇔ 两条里
|
|
10
|
+
* 缺任一条(多租户部署,**或**单用户但车道没 wired)⇒ 探测口回 `501 {@link MCP_INJECTION_REQUIRED_CODE}`。
|
|
11
|
+
* 🔴 **`false` 不许读成「多租户」**:「单用户但车道未 wired」是同样合法的一种部署,wire 上两者不可分 ⇒
|
|
12
|
+
* 措辞与判据都只说「探测口在这台引擎上不可用」,不替引擎推因由。
|
|
13
|
+
* ⚠️ 本位只说**探测口在不在**。`GET /v1/capabilities/mcp` 详情卡的实际响应由调用那一刻决定,不从本位推 ——
|
|
14
|
+
* 本仓没有任何证据支持「本位缺席 ⇒ 详情卡 404」这类蕴含,编一条出来就是替 server 许一个它没许的诺。
|
|
15
|
+
*
|
|
16
|
+
* ── 🔴 读法(四态,不是两态)─────────────────────────────────────────────────────────────────
|
|
17
|
+
* ① `unobserved` —— 这一格**没有可用读数**:本进程一次 caps 响应都没观测到(一次性诊断命令就是这一档)、
|
|
18
|
+
* 或最后一次回体**读不懂**被删格、或引擎温切后 {@link forgetMcpProbeReading} 清过。三条路同落这一档,
|
|
19
|
+
* 它们的共同点正是这句话本身 —— 不是「探测口不在」。
|
|
20
|
+
* ② `not_reported` —— caps 观测到了,而回体上**没有** `mcpProbe` 这个键 ⇒ 老 server。🔴 **不折 `false`**:
|
|
21
|
+
* 折了就是替一台没说话的引擎断言「探测口不在」,而正确的下一步是**按 501 试探**。
|
|
22
|
+
* ③ `absent` —— 引擎**明确说** `false`。这是一个**正面事实**(明确的否),不是缺席。
|
|
23
|
+
* ④ `present` —— 引擎**明确说** `true`:探测口可用。
|
|
24
|
+
* 严格布尔:`null` / 串 / 数(含 `0` / `1`)/ 数组 / 对象 ⇒ 畸形(删格 ⇒ `unobserved`),🔴 **绝不折 `absent`** ——
|
|
25
|
+
* 一份读不懂的回体和一句「不可用」是两件事。判在场用 `hasOwn`(与 device 那一位同形):原型链上的同名键
|
|
26
|
+
* 不是这台引擎说的话。
|
|
27
|
+
* 「探测口能不能用」的判据归包:{@link mcpProbeAvailable} —— 只有 `present` 才 `'yes'`;`absent` ⇒ `'no'`;
|
|
28
|
+
* 其余 ⇒ `'unknown'`(端按 501 试探,不预判)。
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* 探测口在这台引擎上不可用时的 501 错误码(逐字)。
|
|
32
|
+
*
|
|
33
|
+
* 🔴 它与本位的 `absent` 是**同一件事的两面**(同一个谓词):端读到 `absent` 就不必发那一发请求,
|
|
34
|
+
* 读到 `unknown` 就发出去、按这个码兜。消费点按**恰等**判,绝不放宽成 `capability.` 前缀
|
|
35
|
+
* (`capability.*` 是开集,别的成员处置不同)。
|
|
36
|
+
*/
|
|
37
|
+
export declare const MCP_INJECTION_REQUIRED_CODE = "capability.mcp_injection_required";
|
|
38
|
+
/** 四态读数(见文件头)。`unobserved` 由**读口**在这一格空缺时铸,不由投影铸。 */
|
|
39
|
+
export type McpProbeReading = {
|
|
40
|
+
kind: 'unobserved';
|
|
41
|
+
} | {
|
|
42
|
+
kind: 'not_reported';
|
|
43
|
+
} | {
|
|
44
|
+
kind: 'absent';
|
|
45
|
+
} | {
|
|
46
|
+
kind: 'present';
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* caps 回体 → 本格读数;**畸形一律 `undefined`**(= 这一格不写 ⇒ 读口答 `unobserved`)。
|
|
50
|
+
*
|
|
51
|
+
* 🔴 键缺席(`hasOwn` 为假,或显式 `undefined`)⇒ `not_reported`;`false` ⇒ `absent`;`true` ⇒ `present`;
|
|
52
|
+
* 其余一切值 ⇒ `undefined`。三条路互不折叠。
|
|
53
|
+
* 🔴 值**只读一次**(校验与分臂同一次读):变化的 getter 会让校验读到布尔、分臂读到别的东西。
|
|
54
|
+
*/
|
|
55
|
+
export declare function projectMcpProbeCapability(caps: unknown): McpProbeReading | undefined;
|
|
56
|
+
/**
|
|
57
|
+
* 宿主 caps probe 的**读面 tee** 落点(与六只兄弟并列)。绝不 throw —— 读面腿不许反噬 caps 探测链。
|
|
58
|
+
* 投影 `undefined`(畸形)或投影抛出 ⇒ 这一格**被删**,不留上一台引擎的旧读数;`opts.generation` 关掉
|
|
59
|
+
* 「旧探测覆盖新读数」那条竞态(宿主在起探测那一刻 `engineCapsGeneration(baseUrl)` 抓号、在这里原样交回;
|
|
60
|
+
* 不传 ⇒ 与本位到货之前逐字节同行为)。
|
|
61
|
+
*/
|
|
62
|
+
export declare function noteEngineCapsForMcpProbe(baseUrl: string, caps: unknown, opts?: {
|
|
63
|
+
generation?: number;
|
|
64
|
+
}): void;
|
|
65
|
+
/** 本进程观测到的探测口姿态;这一格空缺 ⇒ `{kind:'unobserved'}`(**绝不**折成 `absent`)。 */
|
|
66
|
+
export declare function observedMcpProbe(baseUrl?: string | undefined): McpProbeReading;
|
|
67
|
+
/**
|
|
68
|
+
* 「MCP 探测口能不能用」的判据单源(三态):只有引擎明说在场(`present`)才 `'yes'`;明说不在(`absent`)⇒ `'no'`;
|
|
69
|
+
* 老 server / 从没观测 ⇒ `'unknown'`(端**按 501 试探,不预判** —— 把 unknown 当 no 会藏掉一台真能探测的引擎)。
|
|
70
|
+
*/
|
|
71
|
+
export declare function mcpProbeAvailable(reading: McpProbeReading): 'yes' | 'no' | 'unknown';
|
|
72
|
+
/**
|
|
73
|
+
* 四态 → doctor 那一行的 detail 串。**唯一措辞真源**(三端共用一句话;端只拼接不另写)。
|
|
74
|
+
* 🔴 四句话刻意**互不相同、也互不蕴含**:「未观测」「老引擎不报」两种「读不出」都**不等于**「探测口不在」;
|
|
75
|
+
* `absent` 那一句既要说不可用、又**不许**推因由(多租户 / 车道未 wired wire 上不可分)。
|
|
76
|
+
*/
|
|
77
|
+
export declare function mcpProbeDoctorDetail(reading: McpProbeReading): string;
|
|
78
|
+
/**
|
|
79
|
+
* **换代失效口**(与六只兄弟的同名口并列,由宿主在引擎温切成功后调):清成未观测,不是留旧值也不是铸一个
|
|
80
|
+
* `absent`。空串 / `undefined` ⇒ no-op;绝不 throw(它跑在引擎温切路径上)。
|
|
81
|
+
*/
|
|
82
|
+
export declare function forgetMcpProbeReading(baseUrl: string | undefined): void;
|
|
83
|
+
/** 测试钩子(只清本只读器的读账:不动装好的 wire 读锚、不动 caps 缓存的代际号、不动别只读器的表)。 */
|
|
84
|
+
export declare function __resetMcpProbeReadingsForTests(): void;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mcpProbeCapability — `GET /v1/capabilities.mcpProbe` 的三端共用读面(0.76.1 CC-74;能力位读器第七只,
|
|
3
|
+
* 与 sql / writeProtection / webSearch.backend / executionLane / approvalsStreamLive / deviceExecutor.management
|
|
4
|
+
* 六只兄弟同一套词汇、同一份四口实现 {@link import("./engineCapReader.js").createEngineCapReader})。
|
|
5
|
+
* sdk 9.8.1 对该位**无型** ⇒ 按契约结构读(与 device 那一位 0.74.2 同路);sdk 出键当天由能力位台账门逼一次显式处置。
|
|
6
|
+
*
|
|
7
|
+
* ── 这一位答的是哪一个问题 ────────────────────────────────────────────────────────────────
|
|
8
|
+
* 「这台引擎上**能不能发 MCP 探测请求**」(`POST /v1/capabilities/mcp/probe`)。位为 `true` ⇔ 引擎认这次注入
|
|
9
|
+
* (**单用户姿态 ∧ MCP 车道 wired**,两条合取,与探测口 200 / 501 的谓词同一个表达式);位为 `false` ⇔ 两条里
|
|
10
|
+
* 缺任一条(多租户部署,**或**单用户但车道没 wired)⇒ 探测口回 `501 {@link MCP_INJECTION_REQUIRED_CODE}`。
|
|
11
|
+
* 🔴 **`false` 不许读成「多租户」**:「单用户但车道未 wired」是同样合法的一种部署,wire 上两者不可分 ⇒
|
|
12
|
+
* 措辞与判据都只说「探测口在这台引擎上不可用」,不替引擎推因由。
|
|
13
|
+
* ⚠️ 本位只说**探测口在不在**。`GET /v1/capabilities/mcp` 详情卡的实际响应由调用那一刻决定,不从本位推 ——
|
|
14
|
+
* 本仓没有任何证据支持「本位缺席 ⇒ 详情卡 404」这类蕴含,编一条出来就是替 server 许一个它没许的诺。
|
|
15
|
+
*
|
|
16
|
+
* ── 🔴 读法(四态,不是两态)─────────────────────────────────────────────────────────────────
|
|
17
|
+
* ① `unobserved` —— 这一格**没有可用读数**:本进程一次 caps 响应都没观测到(一次性诊断命令就是这一档)、
|
|
18
|
+
* 或最后一次回体**读不懂**被删格、或引擎温切后 {@link forgetMcpProbeReading} 清过。三条路同落这一档,
|
|
19
|
+
* 它们的共同点正是这句话本身 —— 不是「探测口不在」。
|
|
20
|
+
* ② `not_reported` —— caps 观测到了,而回体上**没有** `mcpProbe` 这个键 ⇒ 老 server。🔴 **不折 `false`**:
|
|
21
|
+
* 折了就是替一台没说话的引擎断言「探测口不在」,而正确的下一步是**按 501 试探**。
|
|
22
|
+
* ③ `absent` —— 引擎**明确说** `false`。这是一个**正面事实**(明确的否),不是缺席。
|
|
23
|
+
* ④ `present` —— 引擎**明确说** `true`:探测口可用。
|
|
24
|
+
* 严格布尔:`null` / 串 / 数(含 `0` / `1`)/ 数组 / 对象 ⇒ 畸形(删格 ⇒ `unobserved`),🔴 **绝不折 `absent`** ——
|
|
25
|
+
* 一份读不懂的回体和一句「不可用」是两件事。判在场用 `hasOwn`(与 device 那一位同形):原型链上的同名键
|
|
26
|
+
* 不是这台引擎说的话。
|
|
27
|
+
* 「探测口能不能用」的判据归包:{@link mcpProbeAvailable} —— 只有 `present` 才 `'yes'`;`absent` ⇒ `'no'`;
|
|
28
|
+
* 其余 ⇒ `'unknown'`(端按 501 试探,不预判)。
|
|
29
|
+
*/
|
|
30
|
+
import { engineWireTarget } from './engineWireTarget.js';
|
|
31
|
+
import { createEngineCapReader } from './engineCapReader.js';
|
|
32
|
+
/**
|
|
33
|
+
* 探测口在这台引擎上不可用时的 501 错误码(逐字)。
|
|
34
|
+
*
|
|
35
|
+
* 🔴 它与本位的 `absent` 是**同一件事的两面**(同一个谓词):端读到 `absent` 就不必发那一发请求,
|
|
36
|
+
* 读到 `unknown` 就发出去、按这个码兜。消费点按**恰等**判,绝不放宽成 `capability.` 前缀
|
|
37
|
+
* (`capability.*` 是开集,别的成员处置不同)。
|
|
38
|
+
*/
|
|
39
|
+
export const MCP_INJECTION_REQUIRED_CODE = 'capability.mcp_injection_required';
|
|
40
|
+
/**
|
|
41
|
+
* caps 回体 → 本格读数;**畸形一律 `undefined`**(= 这一格不写 ⇒ 读口答 `unobserved`)。
|
|
42
|
+
*
|
|
43
|
+
* 🔴 键缺席(`hasOwn` 为假,或显式 `undefined`)⇒ `not_reported`;`false` ⇒ `absent`;`true` ⇒ `present`;
|
|
44
|
+
* 其余一切值 ⇒ `undefined`。三条路互不折叠。
|
|
45
|
+
* 🔴 值**只读一次**(校验与分臂同一次读):变化的 getter 会让校验读到布尔、分臂读到别的东西。
|
|
46
|
+
*/
|
|
47
|
+
export function projectMcpProbeCapability(caps) {
|
|
48
|
+
if (caps === null || typeof caps !== 'object')
|
|
49
|
+
return undefined;
|
|
50
|
+
const c = caps;
|
|
51
|
+
if (!Object.hasOwn(c, 'mcpProbe'))
|
|
52
|
+
return { kind: 'not_reported' };
|
|
53
|
+
const v = c.mcpProbe;
|
|
54
|
+
if (v === undefined)
|
|
55
|
+
return { kind: 'not_reported' };
|
|
56
|
+
if (typeof v !== 'boolean')
|
|
57
|
+
return undefined;
|
|
58
|
+
return v ? { kind: 'present' } : { kind: 'absent' };
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* 本格的 per-baseUrl 读账 + tee / 读口 / 失效口 / 测试钩四口 —— 七只能力位读器**共用同一份实现**
|
|
62
|
+
* ({@link createEngineCapReader});本文件只留这一格真正不同的部分:投影函数 {@link projectMcpProbeCapability}、doctor 措辞表,以及本位自己的判据助手(如有)。
|
|
63
|
+
* 🔴 Map 在工厂闭包里,**一只读器一张**:收到读不懂的回体只删自己这一格,绝不连坐别的能力面。
|
|
64
|
+
*/
|
|
65
|
+
const reader = createEngineCapReader({
|
|
66
|
+
name: 'mcpProbe',
|
|
67
|
+
project: projectMcpProbeCapability,
|
|
68
|
+
makeUnobserved: () => ({ kind: 'unobserved' }),
|
|
69
|
+
});
|
|
70
|
+
/**
|
|
71
|
+
* 宿主 caps probe 的**读面 tee** 落点(与六只兄弟并列)。绝不 throw —— 读面腿不许反噬 caps 探测链。
|
|
72
|
+
* 投影 `undefined`(畸形)或投影抛出 ⇒ 这一格**被删**,不留上一台引擎的旧读数;`opts.generation` 关掉
|
|
73
|
+
* 「旧探测覆盖新读数」那条竞态(宿主在起探测那一刻 `engineCapsGeneration(baseUrl)` 抓号、在这里原样交回;
|
|
74
|
+
* 不传 ⇒ 与本位到货之前逐字节同行为)。
|
|
75
|
+
*/
|
|
76
|
+
export function noteEngineCapsForMcpProbe(baseUrl, caps, opts) {
|
|
77
|
+
reader.note(baseUrl, caps, opts);
|
|
78
|
+
}
|
|
79
|
+
/** 本进程观测到的探测口姿态;这一格空缺 ⇒ `{kind:'unobserved'}`(**绝不**折成 `absent`)。 */
|
|
80
|
+
export function observedMcpProbe(baseUrl = engineWireTarget()?.baseUrl) {
|
|
81
|
+
return reader.observed(baseUrl);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* 「MCP 探测口能不能用」的判据单源(三态):只有引擎明说在场(`present`)才 `'yes'`;明说不在(`absent`)⇒ `'no'`;
|
|
85
|
+
* 老 server / 从没观测 ⇒ `'unknown'`(端**按 501 试探,不预判** —— 把 unknown 当 no 会藏掉一台真能探测的引擎)。
|
|
86
|
+
*/
|
|
87
|
+
export function mcpProbeAvailable(reading) {
|
|
88
|
+
if (reading.kind === 'present')
|
|
89
|
+
return 'yes';
|
|
90
|
+
if (reading.kind === 'absent')
|
|
91
|
+
return 'no';
|
|
92
|
+
return 'unknown';
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* 四态 → doctor 那一行的 detail 串。**唯一措辞真源**(三端共用一句话;端只拼接不另写)。
|
|
96
|
+
* 🔴 四句话刻意**互不相同、也互不蕴含**:「未观测」「老引擎不报」两种「读不出」都**不等于**「探测口不在」;
|
|
97
|
+
* `absent` 那一句既要说不可用、又**不许**推因由(多租户 / 车道未 wired wire 上不可分)。
|
|
98
|
+
*/
|
|
99
|
+
export function mcpProbeDoctorDetail(reading) {
|
|
100
|
+
switch (reading.kind) {
|
|
101
|
+
case 'unobserved':
|
|
102
|
+
return ('MCP probe face not observed — the engine reports it on /v1/capabilities (mcpProbe); ' +
|
|
103
|
+
'this process has no usable capabilities reading cached for it (none received, or the last one was unreadable)');
|
|
104
|
+
case 'not_reported':
|
|
105
|
+
return ('MCP probe face not reported by this engine — only newer engines advertise it; ' +
|
|
106
|
+
'this does not say whether the probe endpoint exists, so probe it directly');
|
|
107
|
+
case 'absent':
|
|
108
|
+
return ('MCP probe face off on this deployment — the engine refuses injected MCP servers on this lane ' +
|
|
109
|
+
`(either a multi-tenant posture or an unwired MCP lane; the wire does not say which), so the probe endpoint is unavailable and answers 501 ${MCP_INJECTION_REQUIRED_CODE}`);
|
|
110
|
+
case 'present':
|
|
111
|
+
return 'MCP probe face on — the MCP probe endpoint is available on this engine';
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* **换代失效口**(与六只兄弟的同名口并列,由宿主在引擎温切成功后调):清成未观测,不是留旧值也不是铸一个
|
|
116
|
+
* `absent`。空串 / `undefined` ⇒ no-op;绝不 throw(它跑在引擎温切路径上)。
|
|
117
|
+
*/
|
|
118
|
+
export function forgetMcpProbeReading(baseUrl) {
|
|
119
|
+
reader.forget(baseUrl);
|
|
120
|
+
}
|
|
121
|
+
/** 测试钩子(只清本只读器的读账:不动装好的 wire 读锚、不动 caps 缓存的代际号、不动别只读器的表)。 */
|
|
122
|
+
export function __resetMcpProbeReadingsForTests() {
|
|
123
|
+
reader.__resetForTests();
|
|
124
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* memoryComplianceCapability — `GET /v1/capabilities.memoryCompliance` 的三端共用读面(0.76.1 CC-97a;
|
|
3
|
+
* 与 sql / writeProtection / webSearch.backend / executionLane / approvalsStreamLive /
|
|
4
|
+
* deviceExecutor.management 诸只兄弟同一套四态词汇,四口走共用工厂 {@link createEngineCapReader})。
|
|
5
|
+
*
|
|
6
|
+
* ── 这一位答的是哪一个问题 ────────────────────────────────────────────────────────────────
|
|
7
|
+
* 「**出处问询 / 抹除**两口(`GET /v1/memory/entries/:entryId/provenance` ·
|
|
8
|
+
* `POST /v1/memory/erase`,operator 车道)在这台引擎上在不在」。引擎侧的谓词是**两项合取**:
|
|
9
|
+
* ① 合规面挂上了 —— 挂载期判后端自带引擎控制面归属,缺则整口不挂;
|
|
10
|
+
* ② 这台部署的 operator 名单**非空** —— 空名单下两口对任何身份恒 403。
|
|
11
|
+
* ⚠️ 位为真**只**保证「门能过 + 面在场」,**不**保证这一次调用成功:控制面账本损坏是**运行期**事实
|
|
12
|
+
* (typed 500),引擎刻意不把它编进部署级布尔。
|
|
13
|
+
* ⚠️ 与「治理携出 bundle」那一位**不同源**:两位的第一项查的是后端的**不同面**,一个部署可以有 bundle
|
|
14
|
+
* 复合面而没有控制面归属,反之亦然 —— 任一侧都不许拿来替另一侧作答(合成一位会对其中一半撒谎)。
|
|
15
|
+
* ⚠️ 与 `memoryOrigin`(外源标记人面三口)**同判据不同位**:两族今天查后端的同一个面,但它们是**两个
|
|
16
|
+
* 产品面**,一个部署可以只开其中一族。引擎刻意不合并,即使今天两位恒同值 ⇒ **本包也不合并**:
|
|
17
|
+
* 两只读器各持一张 per-baseUrl 表,一只收到读不懂的回体只删自己那一格
|
|
18
|
+
* ({@link observedMemoryOrigin} 的读数一字不变)。
|
|
19
|
+
*
|
|
20
|
+
* ── 🔴 读法 ─────────────────────────────────────────────────────────────────────────────────
|
|
21
|
+
* ① 引擎铸这一位时**恒在场**(一格布尔,不是条件在场)⇒ **键缺席 = 老引擎根本不报这一位** ⇒
|
|
22
|
+
* `not_reported`(判不出)。折成 `false` 就是替引擎断言「这台没有合规面」。
|
|
23
|
+
* ② `false` 是**明确的否** ⇒ `absent`。wire 上分不出「后端没有控制面归属」与「operator 名单为空」
|
|
24
|
+
* 两种成因(引擎的谓词是合取,回体只有一格布尔)⇒ 措辞**不推因由**。
|
|
25
|
+
* ③ 严格布尔;`null` / 串 / `0` / `1` / 数组 / 对象一律畸形 ⇒ 删格 ⇒ `unobserved`,🔴 绝不折 `absent`
|
|
26
|
+
* (读不懂与「明确的否」是两回事)。
|
|
27
|
+
* ③b caps 回体本身不是对象(`null` / 数组 / 串 / 数)⇒ 畸形删格,**不是** `not_reported`(那一态只说「这是
|
|
28
|
+
* 一份 caps,但没有这一格」)。
|
|
29
|
+
* ④ 判在场用 `hasOwn`:原型链上的同名键永远不会被序列化上 wire,把它读成在场就是凭空造一格读数。
|
|
30
|
+
* ⑤ 「两口能不能用」的判据归包:{@link memoryComplianceVerbsAvailable} —— 只有 `present` 才 `'yes'`,
|
|
31
|
+
* `absent` ⇒ `'no'`(明确的否),其余 ⇒ `'unknown'`(端按 501 试探,不预判)。
|
|
32
|
+
*/
|
|
33
|
+
/**
|
|
34
|
+
* 记忆治理面缺席时两族(合规两口 / 外源三口)共用的 501 码 —— **本包唯一铸点**,
|
|
35
|
+
* {@link memoryComplianceDoctorDetail} 与 {@link import('./memoryOriginCapability.js')} 的措辞表都取这一个常量,
|
|
36
|
+
* 两处不许各写一遍字面(码字面漂移时只有一处要改)。
|
|
37
|
+
*/
|
|
38
|
+
export declare const MEMORY_ENGINE_REQUIRED_CODE = "capability.memory_engine_required";
|
|
39
|
+
/** 四态读数。`unobserved` 由读口在这一格空缺时铸,不由投影铸。 */
|
|
40
|
+
export type MemoryComplianceReading = {
|
|
41
|
+
kind: 'unobserved';
|
|
42
|
+
}
|
|
43
|
+
/** 键缺席:老引擎不报这一位 ⇒ 判不出(**不是** `absent`)。 */
|
|
44
|
+
| {
|
|
45
|
+
kind: 'not_reported';
|
|
46
|
+
}
|
|
47
|
+
/** 位在场且为 `false`:这台部署上两口用不了(成因在 wire 上不可分)。 */
|
|
48
|
+
| {
|
|
49
|
+
kind: 'absent';
|
|
50
|
+
}
|
|
51
|
+
/** 位在场且为 `true`:门能过 + 面在场(不承诺这一次调用成功)。 */
|
|
52
|
+
| {
|
|
53
|
+
kind: 'present';
|
|
54
|
+
};
|
|
55
|
+
/** caps 回体 → 本格读数;畸形一律 `undefined`(= 这一格不写 ⇒ 读口答 `unobserved`)。 */
|
|
56
|
+
export declare function projectMemoryComplianceCapability(caps: unknown): MemoryComplianceReading | undefined;
|
|
57
|
+
/** 宿主 caps probe 的读面 tee 落点(与诸只兄弟并列)。绝不 throw;畸形 ⇒ 删格;`opts.generation` 关掉旧探测覆盖新读数的竞态。 */
|
|
58
|
+
export declare function noteEngineCapsForMemoryCompliance(baseUrl: string, caps: unknown, opts?: {
|
|
59
|
+
generation?: number;
|
|
60
|
+
}): void;
|
|
61
|
+
/** 本进程观测到的读数;这一格空缺 ⇒ `{kind:'unobserved'}`。 */
|
|
62
|
+
export declare function observedMemoryCompliance(baseUrl?: string | undefined): MemoryComplianceReading;
|
|
63
|
+
/**
|
|
64
|
+
* 「出处问询 / 抹除两口能不能用」的判据单源(三态):只有引擎明说在场才 `'yes'`;明说不在 ⇒ `'no'`;
|
|
65
|
+
* 老引擎不报 / 从没观测 ⇒ `'unknown'`(端按 501 试探,不预判,也不预先藏掉入口)。
|
|
66
|
+
*/
|
|
67
|
+
export declare function memoryComplianceVerbsAvailable(reading: MemoryComplianceReading): 'yes' | 'no' | 'unknown';
|
|
68
|
+
/** doctor 那一行的 detail 串,唯一措辞真源。🔴 两种「读不出」的句子都不许暗示「这台没有合规面」。 */
|
|
69
|
+
export declare function memoryComplianceDoctorDetail(reading: MemoryComplianceReading): string;
|
|
70
|
+
/** 换代失效口(引擎温切成功后调):清成未观测。空串 ⇒ no-op;绝不 throw。 */
|
|
71
|
+
export declare function forgetMemoryComplianceReading(baseUrl: string | undefined): void;
|
|
72
|
+
/** 测试钩子。 */
|
|
73
|
+
export declare function __resetMemoryComplianceReadingsForTests(): void;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* memoryComplianceCapability — `GET /v1/capabilities.memoryCompliance` 的三端共用读面(0.76.1 CC-97a;
|
|
3
|
+
* 与 sql / writeProtection / webSearch.backend / executionLane / approvalsStreamLive /
|
|
4
|
+
* deviceExecutor.management 诸只兄弟同一套四态词汇,四口走共用工厂 {@link createEngineCapReader})。
|
|
5
|
+
*
|
|
6
|
+
* ── 这一位答的是哪一个问题 ────────────────────────────────────────────────────────────────
|
|
7
|
+
* 「**出处问询 / 抹除**两口(`GET /v1/memory/entries/:entryId/provenance` ·
|
|
8
|
+
* `POST /v1/memory/erase`,operator 车道)在这台引擎上在不在」。引擎侧的谓词是**两项合取**:
|
|
9
|
+
* ① 合规面挂上了 —— 挂载期判后端自带引擎控制面归属,缺则整口不挂;
|
|
10
|
+
* ② 这台部署的 operator 名单**非空** —— 空名单下两口对任何身份恒 403。
|
|
11
|
+
* ⚠️ 位为真**只**保证「门能过 + 面在场」,**不**保证这一次调用成功:控制面账本损坏是**运行期**事实
|
|
12
|
+
* (typed 500),引擎刻意不把它编进部署级布尔。
|
|
13
|
+
* ⚠️ 与「治理携出 bundle」那一位**不同源**:两位的第一项查的是后端的**不同面**,一个部署可以有 bundle
|
|
14
|
+
* 复合面而没有控制面归属,反之亦然 —— 任一侧都不许拿来替另一侧作答(合成一位会对其中一半撒谎)。
|
|
15
|
+
* ⚠️ 与 `memoryOrigin`(外源标记人面三口)**同判据不同位**:两族今天查后端的同一个面,但它们是**两个
|
|
16
|
+
* 产品面**,一个部署可以只开其中一族。引擎刻意不合并,即使今天两位恒同值 ⇒ **本包也不合并**:
|
|
17
|
+
* 两只读器各持一张 per-baseUrl 表,一只收到读不懂的回体只删自己那一格
|
|
18
|
+
* ({@link observedMemoryOrigin} 的读数一字不变)。
|
|
19
|
+
*
|
|
20
|
+
* ── 🔴 读法 ─────────────────────────────────────────────────────────────────────────────────
|
|
21
|
+
* ① 引擎铸这一位时**恒在场**(一格布尔,不是条件在场)⇒ **键缺席 = 老引擎根本不报这一位** ⇒
|
|
22
|
+
* `not_reported`(判不出)。折成 `false` 就是替引擎断言「这台没有合规面」。
|
|
23
|
+
* ② `false` 是**明确的否** ⇒ `absent`。wire 上分不出「后端没有控制面归属」与「operator 名单为空」
|
|
24
|
+
* 两种成因(引擎的谓词是合取,回体只有一格布尔)⇒ 措辞**不推因由**。
|
|
25
|
+
* ③ 严格布尔;`null` / 串 / `0` / `1` / 数组 / 对象一律畸形 ⇒ 删格 ⇒ `unobserved`,🔴 绝不折 `absent`
|
|
26
|
+
* (读不懂与「明确的否」是两回事)。
|
|
27
|
+
* ③b caps 回体本身不是对象(`null` / 数组 / 串 / 数)⇒ 畸形删格,**不是** `not_reported`(那一态只说「这是
|
|
28
|
+
* 一份 caps,但没有这一格」)。
|
|
29
|
+
* ④ 判在场用 `hasOwn`:原型链上的同名键永远不会被序列化上 wire,把它读成在场就是凭空造一格读数。
|
|
30
|
+
* ⑤ 「两口能不能用」的判据归包:{@link memoryComplianceVerbsAvailable} —— 只有 `present` 才 `'yes'`,
|
|
31
|
+
* `absent` ⇒ `'no'`(明确的否),其余 ⇒ `'unknown'`(端按 501 试探,不预判)。
|
|
32
|
+
*/
|
|
33
|
+
import { engineWireTarget } from './engineWireTarget.js';
|
|
34
|
+
import { createEngineCapReader } from './engineCapReader.js';
|
|
35
|
+
/**
|
|
36
|
+
* 记忆治理面缺席时两族(合规两口 / 外源三口)共用的 501 码 —— **本包唯一铸点**,
|
|
37
|
+
* {@link memoryComplianceDoctorDetail} 与 {@link import('./memoryOriginCapability.js')} 的措辞表都取这一个常量,
|
|
38
|
+
* 两处不许各写一遍字面(码字面漂移时只有一处要改)。
|
|
39
|
+
*/
|
|
40
|
+
export const MEMORY_ENGINE_REQUIRED_CODE = 'capability.memory_engine_required';
|
|
41
|
+
/** caps 回体 → 本格读数;畸形一律 `undefined`(= 这一格不写 ⇒ 读口答 `unobserved`)。 */
|
|
42
|
+
export function projectMemoryComplianceCapability(caps) {
|
|
43
|
+
// 🔴 数组也是畸形:一个数组回体**不是**引擎对 caps 的回答,从它上面读出「老引擎不报这一位」是替引擎
|
|
44
|
+
// 编了一句它没说的话。`not_reported` 只留给**真的是 caps 对象、但这一格不在**那一形。
|
|
45
|
+
if (caps === null || typeof caps !== 'object' || Array.isArray(caps))
|
|
46
|
+
return undefined;
|
|
47
|
+
const c = caps;
|
|
48
|
+
if (!Object.hasOwn(c, 'memoryCompliance'))
|
|
49
|
+
return { kind: 'not_reported' };
|
|
50
|
+
// 🔴 只读一次:校验与分臂若各读一次,变化的 getter 能让校验读到布尔、分臂读到别的东西。
|
|
51
|
+
const v = c.memoryCompliance;
|
|
52
|
+
if (v === undefined)
|
|
53
|
+
return { kind: 'not_reported' };
|
|
54
|
+
if (typeof v !== 'boolean')
|
|
55
|
+
return undefined;
|
|
56
|
+
return v ? { kind: 'present' } : { kind: 'absent' };
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* 本格的 per-baseUrl 读账 + tee / 读口 / 失效口 / 测试钩四口 —— 能力位读器**共用同一份实现**
|
|
60
|
+
* ({@link createEngineCapReader});本文件只留这一格真正不同的部分:投影函数
|
|
61
|
+
* {@link projectMemoryComplianceCapability}、doctor 措辞表与本位的判据助手。
|
|
62
|
+
* 🔴 Map 在工厂闭包里,**一只读器一张**:收到读不懂的回体只删自己这一格,绝不连坐别的能力面
|
|
63
|
+
* (尤其不连坐同判据的 `memoryOrigin`)。
|
|
64
|
+
*/
|
|
65
|
+
const reader = createEngineCapReader({
|
|
66
|
+
name: 'memoryCompliance',
|
|
67
|
+
project: projectMemoryComplianceCapability,
|
|
68
|
+
makeUnobserved: () => ({ kind: 'unobserved' }),
|
|
69
|
+
});
|
|
70
|
+
/** 宿主 caps probe 的读面 tee 落点(与诸只兄弟并列)。绝不 throw;畸形 ⇒ 删格;`opts.generation` 关掉旧探测覆盖新读数的竞态。 */
|
|
71
|
+
export function noteEngineCapsForMemoryCompliance(baseUrl, caps, opts) {
|
|
72
|
+
reader.note(baseUrl, caps, opts);
|
|
73
|
+
}
|
|
74
|
+
/** 本进程观测到的读数;这一格空缺 ⇒ `{kind:'unobserved'}`。 */
|
|
75
|
+
export function observedMemoryCompliance(baseUrl = engineWireTarget()?.baseUrl) {
|
|
76
|
+
return reader.observed(baseUrl);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* 「出处问询 / 抹除两口能不能用」的判据单源(三态):只有引擎明说在场才 `'yes'`;明说不在 ⇒ `'no'`;
|
|
80
|
+
* 老引擎不报 / 从没观测 ⇒ `'unknown'`(端按 501 试探,不预判,也不预先藏掉入口)。
|
|
81
|
+
*/
|
|
82
|
+
export function memoryComplianceVerbsAvailable(reading) {
|
|
83
|
+
if (reading.kind === 'present')
|
|
84
|
+
return 'yes';
|
|
85
|
+
if (reading.kind === 'absent')
|
|
86
|
+
return 'no';
|
|
87
|
+
return 'unknown';
|
|
88
|
+
}
|
|
89
|
+
/** doctor 那一行的 detail 串,唯一措辞真源。🔴 两种「读不出」的句子都不许暗示「这台没有合规面」。 */
|
|
90
|
+
export function memoryComplianceDoctorDetail(reading) {
|
|
91
|
+
switch (reading.kind) {
|
|
92
|
+
case 'unobserved':
|
|
93
|
+
return 'memory compliance face not observed — the engine reports it on /v1/capabilities (memoryCompliance); this process has no usable capabilities reading cached for it (none received, or the last one was unreadable)';
|
|
94
|
+
case 'not_reported':
|
|
95
|
+
return 'memory compliance face not reported by this engine — only newer engines advertise it; this does not say whether the provenance and erasure endpoints exist, probe them directly';
|
|
96
|
+
case 'absent':
|
|
97
|
+
return `memory compliance face off on this deployment — the entry-provenance and erasure endpoints are unavailable (${MEMORY_ENGINE_REQUIRED_CODE}); the engine does not say which half is missing (a memory backend that does not own the engine control plane, or an empty operator roster), so do not guess`;
|
|
98
|
+
case 'present':
|
|
99
|
+
return 'memory compliance face on — the entry-provenance and erasure endpoints are mounted and the operator roster is non-empty on this engine; this says the door opens, not that any one call succeeds (a damaged control-plane ledger is a runtime fact and arrives as a typed 500)';
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/** 换代失效口(引擎温切成功后调):清成未观测。空串 ⇒ no-op;绝不 throw。 */
|
|
103
|
+
export function forgetMemoryComplianceReading(baseUrl) {
|
|
104
|
+
reader.forget(baseUrl);
|
|
105
|
+
}
|
|
106
|
+
/** 测试钩子。 */
|
|
107
|
+
export function __resetMemoryComplianceReadingsForTests() {
|
|
108
|
+
reader.__resetForTests();
|
|
109
|
+
}
|