@sema-agent/server 7.139.0 → 7.140.0
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/MIGRATION.md +181 -0
- package/USAGE.md +19 -13
- package/dist/adoption/runner.js +1 -1
- package/dist/adoption/sql.js +1 -1
- package/dist/approval-card.d.ts +6 -6
- package/dist/bench/s1/live-deps.js +3 -2
- package/dist/bench/s1/row.d.ts +5 -2
- package/dist/bench/s1/row.js +2 -22
- package/dist/boot/adoption.js +1 -1
- package/dist/boot/execution-env.js +12 -10
- package/dist/boot/execution-lane.d.ts +8 -0
- package/dist/boot/execution-lane.js +6 -1
- package/dist/boot/memory-boundary.d.ts +14 -51
- package/dist/boot/memory-boundary.js +10 -20
- package/dist/boot/memory-consolidation.d.ts +15 -11
- package/dist/boot/memory-consolidation.js +23 -12
- package/dist/boot/resolve-spec.d.ts +3 -5
- package/dist/boot/resolve-spec.js +2 -4
- package/dist/boot/runner-deps.d.ts +3 -3
- package/dist/boot/runner-deps.js +1 -0
- package/dist/boot/stage-03-store-backend.d.ts +2 -6
- package/dist/boot/stage-03-store-backend.js +2 -3
- package/dist/boot/stage-04-stores.d.ts +2 -6
- package/dist/boot/stage-04-stores.js +5 -5
- package/dist/boot/stage-05-execution-env.d.ts +2 -6
- package/dist/boot/stage-06-runners.d.ts +2 -6
- package/dist/boot/stage-06-runners.js +2 -2
- package/dist/boot/stage-07-capability-layer.d.ts +2 -6
- package/dist/boot/stage-08-reapers.d.ts +2 -6
- package/dist/boot/stage-09-leader.d.ts +2 -6
- package/dist/boot/stage-10-http-server.d.ts +2 -6
- package/dist/boot/stage-10-http-server.js +5 -4
- package/dist/boot/stores.d.ts +3 -6
- package/dist/boot/stores.js +27 -40
- package/dist/boot/task-list-lane.d.ts +1 -1
- package/dist/boot/task-list-lane.js +1 -1
- package/dist/boot/web-admin.js +35 -9
- package/dist/capabilities/execution-lane.d.ts +2 -2
- package/dist/config-catalog.js +2 -1
- package/dist/config-provider.d.ts +14 -13
- package/dist/config-provider.js +24 -18
- package/dist/config-types.d.ts +11 -2
- package/dist/config.js +2 -1
- package/dist/delegated-session-owner.d.ts +2 -1
- package/dist/delegated-session-owner.js +1 -1
- package/dist/deployment-shape.d.ts +9 -8
- package/dist/deployment-shape.js +4 -4
- package/dist/execution-lane-caps.d.ts +97 -106
- package/dist/execution-lane-caps.js +67 -83
- package/dist/http/memory-compliance-failure-reply.d.ts +3 -1
- package/dist/http/memory-compliance-failure-reply.js +5 -0
- package/dist/http/memory-layer-reply.d.ts +30 -0
- package/dist/http/memory-layer-reply.js +24 -0
- package/dist/http/resume-legs.js +13 -16
- package/dist/http/retired-service-deps.d.ts +1 -1
- package/dist/http/retired-service-deps.js +1 -1
- package/dist/http/routes/adoption.js +1 -1
- package/dist/http/routes/memory-bundle.js +3 -0
- package/dist/http/routes/memory-compliance.js +8 -1
- package/dist/http/routes/memory-consolidation.js +12 -1
- package/dist/http/routes/memory-origin.js +14 -2
- package/dist/http/routes/memory-policy.js +5 -0
- package/dist/http/routes/sessions.js +28 -11
- package/dist/http/routes/tasks.js +4 -2
- package/dist/http/server.d.ts +5 -25
- package/dist/http/server.js +2 -2
- package/dist/identity-source.d.ts +1 -1
- package/dist/identity-source.js +1 -1
- package/dist/lane-home-probe.d.ts +68 -42
- package/dist/lane-home-probe.js +53 -30
- package/dist/leader/wire.js +5 -4
- package/dist/memory-bundle-engine.d.ts +16 -9
- package/dist/memory-bundle-engine.js +29 -6
- package/dist/memory-operator-faces.d.ts +85 -30
- package/dist/memory-operator-faces.js +136 -30
- package/dist/memory-project-layer.d.ts +3 -21
- package/dist/memory-project-layer.js +11 -8
- package/dist/memory-scope-stores.d.ts +73 -0
- package/dist/memory-scope-stores.js +86 -0
- package/dist/memory-scope.d.ts +29 -5
- package/dist/memory-scope.js +16 -4
- package/dist/memory-sync-client.d.ts +20 -7
- package/dist/memory-sync-client.js +31 -13
- package/dist/plugins/adoption-log-sql.js +4 -4
- package/dist/plugins/approval-ask-store-sql.js +14 -14
- package/dist/plugins/approval-nonce-store.js +4 -4
- package/dist/plugins/blob-backend.d.ts +4 -4
- package/dist/plugins/blob-backend.js +7 -7
- package/dist/plugins/breaker-state-sql.js +2 -2
- package/dist/plugins/checkpoint-index-columns.js +2 -2
- package/dist/plugins/checkpoint-store-sql.js +16 -16
- package/dist/plugins/device-store-sql.js +19 -19
- package/dist/plugins/ensure-index.d.ts +1 -2
- package/dist/plugins/execution-placement-sql.d.ts +8 -8
- package/dist/plugins/execution-placement-sql.js +8 -8
- package/dist/plugins/file-history-store-sql.d.ts +2 -2
- package/dist/plugins/file-history-store-sql.js +4 -4
- package/dist/plugins/image-bake-store-sql.js +9 -9
- package/dist/plugins/image-index-sql.js +11 -11
- package/dist/plugins/leader-run-store-sql.js +4 -4
- package/dist/plugins/mailbox-store-sql.d.ts +2 -1
- package/dist/plugins/mailbox-store-sql.js +4 -4
- package/dist/plugins/memory-engine-tidb.js +5 -5
- package/dist/plugins/memory-optout-grant-store-sql.js +1 -1
- package/dist/plugins/memory-sync-store-tidb.js +3 -3
- package/dist/plugins/one-time-migrations.d.ts +10 -9
- package/dist/plugins/one-time-migrations.js +36 -36
- package/dist/plugins/org-delivery-quota-store.js +2 -2
- package/dist/plugins/outcome-ledger-sql.js +2 -2
- package/dist/plugins/permission-rule-store-sql.d.ts +4 -4
- package/dist/plugins/permission-rule-store-sql.js +16 -16
- package/dist/plugins/remote-env-adb.d.ts +7 -24
- package/dist/plugins/remote-env-adb.js +22 -5
- package/dist/plugins/remote-env-device.d.ts +2 -28
- package/dist/plugins/remote-env-device.js +2 -1
- package/dist/plugins/remote-env-e2b.d.ts +18 -26
- package/dist/plugins/remote-env-e2b.js +51 -4
- package/dist/plugins/remote-env-file-error.d.ts +1 -1
- package/dist/plugins/remote-env-file-error.js +8 -2
- package/dist/plugins/remote-env-host.d.ts +19 -35
- package/dist/plugins/remote-env-host.js +26 -3
- package/dist/plugins/remote-env-k8s.d.ts +3 -14
- package/dist/plugins/remote-env-k8s.js +3 -2
- package/dist/plugins/remote-env-local-docker.d.ts +4 -15
- package/dist/plugins/remote-env-local-docker.js +5 -4
- package/dist/plugins/remote-env-ssh.d.ts +4 -24
- package/dist/plugins/remote-env-ssh.js +4 -3
- package/dist/plugins/resume-anchor-store-sql.js +2 -2
- package/dist/plugins/retention-lane-store-sql.d.ts +1 -1
- package/dist/plugins/retention-lane-store-sql.js +2 -2
- package/dist/plugins/retention-store-sql.d.ts +1 -1
- package/dist/plugins/retention-store-sql.js +6 -6
- package/dist/plugins/run-store-sql.js +15 -15
- package/dist/plugins/schema-consistency.d.ts +6 -6
- package/dist/plugins/schema-consistency.js +1 -1
- package/dist/plugins/schema-ensure-legs.d.ts +2 -3
- package/dist/plugins/schema-ensure-legs.js +2 -2
- package/dist/plugins/schema-live-columns.d.ts +1 -1
- package/dist/plugins/session-capture-record-store-sql.js +1 -1
- package/dist/plugins/session-rules-column.d.ts +1 -1
- package/dist/plugins/session-rules-column.js +1 -1
- package/dist/plugins/session-workspace-cell.d.ts +1 -1
- package/dist/plugins/session-workspace-cell.js +1 -1
- package/dist/plugins/shared-memory-store-sql.js +2 -2
- package/dist/plugins/sql-driver.d.ts +10 -5
- package/dist/plugins/sql-driver.js +6 -6
- package/dist/plugins/sql-errors.js +1 -1
- package/dist/plugins/store-backend.d.ts +4 -6
- package/dist/plugins/store-backend.js +6 -6
- package/dist/plugins/task-list-store-sql.js +11 -11
- package/dist/plugins/tidb-pool.js +5 -5
- package/dist/plugins/tidb-session-storage.js +4 -4
- package/dist/plugins/tidb-session-store.js +13 -13
- package/dist/plugins/tool-result-store-sql.d.ts +2 -2
- package/dist/plugins/tool-result-store-sql.js +3 -3
- package/dist/plugins/user-input-ledger-sql.js +2 -2
- package/dist/plugins/workflow-journal-store-sql.js +5 -5
- package/dist/plugins/workflow-run-store-sql.js +19 -19
- package/dist/plugins/write-behind-counter.d.ts +2 -3
- package/dist/plugins/write-behind-counter.js +5 -5
- package/dist/resource-suspend.d.ts +14 -12
- package/dist/resource-suspend.js +1 -1
- package/dist/resource-window.d.ts +4 -3
- package/dist/run-local.js +14 -19
- package/dist/runs.d.ts +8 -4
- package/dist/runs.js +49 -65
- package/dist/session-incarnation.d.ts +1 -1
- package/dist/session-incarnation.js +1 -1
- package/dist/session-policy-wire.d.ts +1 -1
- package/dist/sql-engine-posture.d.ts +1 -1
- package/dist/sql-engine-posture.js +1 -1
- package/dist/{plugins → stores-sql}/background-agent-store-sql.d.ts +2 -2
- package/dist/{plugins → stores-sql}/background-agent-store-sql.js +8 -8
- package/dist/{plugins → stores-sql}/session-policy-store-sql.d.ts +7 -5
- package/dist/{plugins → stores-sql}/session-policy-store-sql.js +12 -12
- package/dist/{plugins → stores-sql}/usage-window-store-sql.d.ts +1 -1
- package/dist/{plugins → stores-sql}/usage-window-store-sql.js +3 -3
- package/dist/task-a2a.js +5 -6
- package/dist/task-mcp.d.ts +20 -7
- package/dist/task-mcp.js +17 -9
- package/dist/terminal.d.ts +27 -0
- package/dist/terminal.js +6 -0
- package/dist/trace/redact.d.ts +3 -1
- package/dist/trace/redact.js +80 -28
- package/dist/trace/self-minted-wire.d.ts +58 -0
- package/dist/trace/self-minted-wire.js +16 -0
- package/dist/web-admin-client/candidate-gate.d.ts +11 -7
- package/dist/web-admin-client/candidate-gate.js +1 -1
- package/dist/web-admin-client/http-client.d.ts +5 -4
- package/dist/web-admin-client/http-client.js +2 -2
- package/dist/web-admin-client/read-warnings.d.ts +7 -17
- package/dist/web-admin-client/read-warnings.js +5 -9
- package/package.json +2 -2
- package/wire-changes/server@7.140.0.json +184 -0
|
@@ -5,9 +5,26 @@
|
|
|
5
5
|
* ## 为什么是一个模块而不是 main.ts 里直接 new
|
|
6
6
|
*
|
|
7
7
|
* 同 `memory-bundle-engine.ts` 的那句话:本仓**没有**一个长命的 `MemoryEngine` 实例 —— `boot/stores.ts`
|
|
8
|
-
* 装配出来的 `memoryEngine`
|
|
9
|
-
* (按任务的 scope
|
|
10
|
-
* 只调用与转接。
|
|
8
|
+
* 装配出来的 `memoryEngine` 是记忆作用域店(`memory-scope-stores.ts`:部署的店 + 引擎根 + 「一层住哪只店」的唯一读者),
|
|
9
|
+
* 真引擎由 core 的 Runner **每任务现构**(按任务的 scope 平面决定店与 `memoryDir`)。HTTP 面若要一个引擎,必须自己构;构的判断写在这里,
|
|
10
|
+
* main.ts 只调用与转接。
|
|
11
|
+
*
|
|
12
|
+
* ## 引擎建在哪只店上:动词点名的层住的那只(一层的店只问记忆作用域店)
|
|
13
|
+
* 每个动词先定店,再在那只店上建(或复用)一只引擎 —— 一只店一只引擎,`memoryDir` = 那只店的挂载平面、控制面 = 那只店自带的。
|
|
14
|
+
* 店怎么定只有一条规则({@link memoryStoreForRequest}):请求点名的层(`select.scope`、`expectedScopes`、外源列表的 `scopes`、
|
|
15
|
+
* 不点名层的动词的层座 `{ layer }`)共住的那一只;不点名层 ⇒ 本部署点名的层与部署的店共处的那一只,分住两只就拒(`request.memory_layer`)。
|
|
16
|
+
* 修前三只工厂各在**部署的店**上建一只引擎 —— 目录钉住的部署上,类型化个人层(`user:` / `userproj:` / `org:`)的会话条目在个人挂载上的
|
|
17
|
+
* 另一只店里,擦的、查的、清标的都是会话不读的那只店。
|
|
18
|
+
*
|
|
19
|
+
* 会话 id 的两只动词不点名层(会话的写家在哪只店由它各条腿的任务根定,服务端没有存;一只会话可以跨两只店):
|
|
20
|
+
* · 会话记忆状态读**本部署的每一只店**(`memoryStoresOfDeployment`,至多两只),逐店的答案按 {@link foldPlaneStatuses} 折成一份;
|
|
21
|
+
* · 按会话抹除(`{ sessionId }` 选择子)落部署的店,见下一节的护栏。
|
|
22
|
+
*
|
|
23
|
+
* ## 抹除只在部署的店上执行({@link MemoryErasureStoreUnjudged})
|
|
24
|
+
* 抹除 `requestId` 的幂等判(重放收敛、同 id 换了选择子 ⇒ `memory.erasure_selector_mismatch`)记在**每只店自己的**证据链上,引擎今天没有
|
|
25
|
+
* 跨店的请求身份、也没有按 `requestId` 读锚的公开面;本层不另记一本请求账(第二真源)。所以本服务只在**一只**店上执行抹除 —— 部署的店,
|
|
26
|
+
* 它的证据链就是本部署唯一的判官:请求落到别的店(点名的层住在个人挂载那只店),或按会话抹除而这只会话在别的店里有贡献(或那只店的账读不出)
|
|
27
|
+
* ⇒ 409 拒,什么都不删。🚧 引擎给出部署级的抹除请求身份后,这条护栏删除、各店照常执行(钉在 `test/memory-project-scope.test.ts` ⑩)。
|
|
11
28
|
*
|
|
12
29
|
* ## 控制面归属:为什么 `controlPlaneRoot` 缺席就整口不挂(F-9 裁)
|
|
13
30
|
*
|
|
@@ -46,6 +63,8 @@
|
|
|
46
63
|
* 不是一回事(附录 A 两条分列)。
|
|
47
64
|
*/
|
|
48
65
|
import { type EntryProvenanceAccount, type MemoryBackend, type MemoryEntryOrigin, type MemoryErasureAttestation, type OriginClearanceRow, type SessionCaptureRecordStore, type SessionMemoryStatus } from "@sema-agent/core";
|
|
66
|
+
import { type MemoryScopeStores } from "./memory-scope-stores.js";
|
|
67
|
+
import type { SessionCaptureRecordSource } from "./plugins/store-backend.js";
|
|
49
68
|
/**
|
|
50
69
|
* 控制面归属判据 —— 三个记忆操作面(合规两口 / 外源标记三口 / consolidation 阀门的 D1 拒启门)共用的
|
|
51
70
|
* **同一只**谓词:backend 的面上带**非空** `controlPlaneRoot` 才算归属在案。空串与缺席同判「不归属」:
|
|
@@ -54,11 +73,22 @@ import { type EntryProvenanceAccount, type MemoryBackend, type MemoryEntryOrigin
|
|
|
54
73
|
* 「逐字同源」成为结构事实而不是手抄承诺(merge-rescan 746 C-1:main.ts 手抄版漏了空串臂)。
|
|
55
74
|
*/
|
|
56
75
|
export declare function backendOwnsControlPlane(backend: unknown): boolean;
|
|
76
|
+
/**
|
|
77
|
+
* 一只店的 capture opt-out 记录店 —— 按**这只店的控制面**向记录源取(`StoreBackend.sessionCaptureRecords()` 的按平面取用;
|
|
78
|
+
* 会话装配向同一只源问的也是它那只平面的控制面,core `prepare-memory` 的 `memoryCaptureRecordStore({ controlDir })`)。
|
|
79
|
+
* 店带控制面归属 ⇒ 问那一只控制面(个人店 ⇒ 个人平面的记录,部署的店 ⇒ 部署那一只);不带(SQL 孪生)⇒ 不指名(SQL 源本就不按平面分)。
|
|
80
|
+
* 修前操作面引擎一律拿部署平面那一只:个人店上的整理会读错名册(看不见只在个人平面登记 opt-out 的会话)。
|
|
81
|
+
*/
|
|
82
|
+
export declare function captureRecordStoreOf(source: SessionCaptureRecordSource | undefined, store: MemoryBackend): SessionCaptureRecordStore | undefined;
|
|
83
|
+
/** 不点名层的动词(条目 id / 会话 id / 店级账本)的**层座**:点名一层 ⇒ 动词答在这一层住的那只店上(这一层只用来定店)。 */
|
|
84
|
+
export interface MemoryLayerSeat {
|
|
85
|
+
readonly layer: string;
|
|
86
|
+
}
|
|
57
87
|
/** 两口 HTTP 面消费的窄能力面(`ServiceDeps.memoryCompliance` 的实参来源)。 */
|
|
58
88
|
export interface MemoryComplianceFaces {
|
|
59
89
|
/** 单条出处账。core 的失败姿态原样穿过:控制面损坏 ⇒ `ControlPlaneCorruptError`(fail-closed,
|
|
60
90
|
* 绝不在一个完整性未知的账上拼一个答案);能力缺席 ⇒ 三值 `capability-absent`,**不是**抛。 */
|
|
61
|
-
provenanceOf: (entryId: string) => Promise<EntryProvenanceAccount>;
|
|
91
|
+
provenanceOf: (entryId: string, at?: MemoryLayerSeat) => Promise<EntryProvenanceAccount>;
|
|
62
92
|
/**
|
|
63
93
|
* 抹除。入参 `unknown`:调用方递交的是未校验的对象,三选一选择子的整体判决归 core
|
|
64
94
|
* (`erasureRequestInvalid` 是它的单一属主面)—— 在本层抄一遍就是第二真源。
|
|
@@ -69,14 +99,23 @@ export interface MemoryComplianceFaces {
|
|
|
69
99
|
* 都得是集内成员,判在解析之后、店锁之内;违者整单拒 `config.memory_erasure_scope`,拒句不带数、不带 id、不带 scope(集外 id
|
|
70
100
|
* 与从没存在过的 id 同句,不是存在性神谕)。本层不另设信封:一只只读得到 `{ scope }` 选择子字面量的信封判不了 `ids` /
|
|
71
101
|
* `sessionId` 两腿、只能整拒,而且让「哪些 scope 能删」有两个答者。集随**入参**走(与 `requestId` / `select` 同一个对象),
|
|
72
|
-
*
|
|
102
|
+
* 授权集也是定店的那一只读数之一(选择子不点名 scope 时,集里的层共住的那只店;见文件头「引擎建在哪只店上」)。
|
|
73
103
|
*
|
|
74
104
|
* 今天谁传集:operator 面原样递交调用方的体(调用方自己写的 `expectedScopes` = 它自己收窄自己);路由不替 operator 铸集 ——
|
|
75
105
|
* 本仓没有任何授权源能对一个 operator 说「你只能动这些 scope」(`routes/memory-policy.ts` 的 `gateMemoryScope`:operator 支在查
|
|
76
106
|
* 目录之前就 allow;`org-memory-admission.ts`:v1 不中央收窄 operator 声明的 scope)。拿 org 目录的 grant 集去凑一个集就是在本层
|
|
77
107
|
* 发明第二套授权语义,与 `gateMemoryScope` 对同一个身份给出相反答案。会话自助面的选择子由路径铸,不带集。
|
|
78
108
|
*/
|
|
79
|
-
erase: (input: unknown) => Promise<MemoryErasureAttestation>;
|
|
109
|
+
erase: (input: unknown, at?: MemoryLayerSeat) => Promise<MemoryErasureAttestation>;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* 本服务的「这次抹除不在本版受理的那只店上」拒(409 `memory.erasure_store_unjudged`):请求本身合法,是本部署此刻判不了同一个 `requestId`
|
|
113
|
+
* 跨店的幂等(见文件头「抹除只在部署的店上执行」)。什么都没删、什么都没记。句子不带层键、路径或任何值(两受众同一句;会话所有者受众另有固定句)。
|
|
114
|
+
* 🚧 引擎的部署级抹除请求身份到货后,本类连同抛它的两处删除。
|
|
115
|
+
*/
|
|
116
|
+
export declare class MemoryErasureStoreUnjudged extends Error {
|
|
117
|
+
readonly code: "memory.erasure_store_unjudged";
|
|
118
|
+
constructor();
|
|
80
119
|
}
|
|
81
120
|
/**
|
|
82
121
|
* **选择子替身**的拦截谓词(codex 交叉复审 [critical],亲验复现后修 —— 复现器与结论逐条在
|
|
@@ -111,10 +150,11 @@ export interface MemoryComplianceFaces {
|
|
|
111
150
|
*/
|
|
112
151
|
export declare function erasureInputSmugglesPrototypeKey(input: unknown): boolean;
|
|
113
152
|
/**
|
|
114
|
-
*
|
|
153
|
+
* 在**记忆作用域店**上建合规两面。命名照 CLAUDE.md 工厂律:返回的是带行为的活对象 ⇒ `create*`。
|
|
115
154
|
*
|
|
116
|
-
* `
|
|
117
|
-
*
|
|
155
|
+
* 店:出处按层座定;抹除按选择子的 `scope` / `expectedScopes` 定(会话自助面由路径铸选择子,用层座)—— 见文件头。
|
|
156
|
+
* `memoryDir` = 那只店的**挂载平面**(`memoryMountRootOf(store, root)` 单铸点:店钉了 `directoryRoot`
|
|
157
|
+
* 就是它 —— file 腿 = `<配置根>/memory`,个人店 = 个人挂载;两只 SQL 孪生不钉 ⇒ 回到配置根,读数逐字节不变)。
|
|
118
158
|
*
|
|
119
159
|
* 🔴 **不是 `memoryEngine.root`**(2026 提货批订正,亲读 core 推翻旧注):旧注写着「这两条路径不读它」,
|
|
120
160
|
* 而实装里 `erase` 的派生索引清扫(`engine.js` 的 `sweepErasedIndexLines`)与 `clearEntryOrigin` 的
|
|
@@ -123,10 +163,7 @@ export declare function erasureInputSmugglesPrototypeKey(input: unknown): boolea
|
|
|
123
163
|
* **静默**:扫一棵不存在的树 ⇒ ENOENT ⇒ 跳过 ⇒ 零残留可报,而真正的 `MEMORY.md` 里还留着被抹条目的
|
|
124
164
|
* 名字,收执却显示干净。机器钉:`test/memory-operator-faces.test.ts` 的「[ref] 提货」两格。
|
|
125
165
|
*/
|
|
126
|
-
export declare function createMemoryComplianceFaces(
|
|
127
|
-
backend: MemoryBackend;
|
|
128
|
-
root: string;
|
|
129
|
-
},
|
|
166
|
+
export declare function createMemoryComplianceFaces(stores: MemoryScopeStores,
|
|
130
167
|
/**
|
|
131
168
|
* 引擎的 **advisory incident 座**(core `MemoryEngineOptions.onIncident`)。接它不是锦上添花:
|
|
132
169
|
* 抹除腿上有一条**只走这个座**的码 —— `memory.erasure_index_residue`(engine.js)。它说的是
|
|
@@ -143,7 +180,7 @@ opts?: {
|
|
|
143
180
|
onIncident?: (err: Error & {
|
|
144
181
|
code?: string;
|
|
145
182
|
}) => void;
|
|
146
|
-
|
|
183
|
+
captureRecords?: SessionCaptureRecordSource;
|
|
147
184
|
}): MemoryComplianceFaces | undefined;
|
|
148
185
|
/** 件② 三口 HTTP 面消费的窄能力面(`ServiceDeps.memoryOriginFace` 的实参来源)。 */
|
|
149
186
|
export interface MemoryOriginFaces {
|
|
@@ -164,12 +201,12 @@ export interface MemoryOriginFaces {
|
|
|
164
201
|
}>>;
|
|
165
202
|
/** §13-4② 读半场:清标审计账(**同步** —— core 的 `listOriginClearances` 就是一次严格 sidecar 读;
|
|
166
203
|
* 账本损坏 ⇒ `ControlPlaneCorruptError`,fail-closed,绝不回半张表)。 */
|
|
167
|
-
listClearances: () => OriginClearanceRow[];
|
|
204
|
+
listClearances: (at?: MemoryLayerSeat) => OriginClearanceRow[];
|
|
168
205
|
/** §13-4② 写半场:审计化的 UN-MARK 阀门。拒因族是 core 的**闭集码**,本层零翻译原样上抛。 */
|
|
169
206
|
clear: (entryId: string, input: {
|
|
170
207
|
requestId: string;
|
|
171
208
|
reason: string;
|
|
172
|
-
}) => Promise<{
|
|
209
|
+
}, at?: MemoryLayerSeat) => Promise<{
|
|
173
210
|
entryId: string;
|
|
174
211
|
clearanceId: string;
|
|
175
212
|
origin: MemoryEntryOrigin;
|
|
@@ -208,10 +245,7 @@ export interface MemoryOriginFaces {
|
|
|
208
245
|
* ⚠️ **不在 seam 里翻译拒因码**:core 的 origin-clear 族是**闭集**,翻译点只有一个(路由的 switch),
|
|
209
246
|
* 在这里再翻一遍就是第二真源。seam 原样抛,路由逐码字面量转发。
|
|
210
247
|
*/
|
|
211
|
-
export declare function createMemoryOriginFaces(
|
|
212
|
-
backend: MemoryBackend;
|
|
213
|
-
root: string;
|
|
214
|
-
},
|
|
248
|
+
export declare function createMemoryOriginFaces(stores: MemoryScopeStores,
|
|
215
249
|
/**
|
|
216
250
|
* 引擎的 advisory incident 座(core `MemoryEngineOptions.onIncident`)。
|
|
217
251
|
* 🔴 与合规面的同名座**理由不同,如实写**:亲读 core 5.59.0 的这三条动词路径(engine.js)
|
|
@@ -223,12 +257,34 @@ opts?: {
|
|
|
223
257
|
onIncident?: (err: Error & {
|
|
224
258
|
code?: string;
|
|
225
259
|
}) => void;
|
|
226
|
-
|
|
260
|
+
captureRecords?: SessionCaptureRecordSource;
|
|
227
261
|
}): MemoryOriginFaces | undefined;
|
|
228
262
|
/** [ref] seam① 的窄能力面(`ServiceDeps.sessionMemoryStatus` 的实参来源)。 */
|
|
229
263
|
export interface SessionMemoryStatusFace {
|
|
264
|
+
/**
|
|
265
|
+
* 这次状态请求读的店:层座点名 ⇒ 那一层住的那一只;不带 ⇒ 本部署的每一只店(部署的店在前,至多两只;单店部署恰一只)——
|
|
266
|
+
* 路由逐店读,再按 {@link foldPlaneStatuses} 折成一份(会话 id 不点名层,一只会话可以跨两只店,见文件头)。每次请求都现定 ——
|
|
267
|
+
* 登记簿热换当场生效,路由的短窗缓存只缓存逐店的扫描,不缓存定店。唯一的拒:点名的层 / 本部署点名的层引擎读不出 ⇒ 同步抛 `request.memory_layer`。
|
|
268
|
+
*/
|
|
269
|
+
storesAt: (at?: MemoryLayerSeat) => readonly SessionMemoryStatusStore[];
|
|
270
|
+
}
|
|
271
|
+
/** 一只店上的会话记忆状态读。 */
|
|
272
|
+
export interface SessionMemoryStatusStore {
|
|
273
|
+
/** 这只店的控制面根(引擎自己的读数)—— 状态读扫的就是它;路由的短窗缓存按(会话, 它)分:落同一只店的层键别名是同一格。 */
|
|
274
|
+
readonly controlPlane: string;
|
|
230
275
|
status: (sessionId: string) => Promise<SessionMemoryStatus>;
|
|
231
276
|
}
|
|
277
|
+
/** 状态面上 wire 的五键(引擎答案里其余的键不上 wire,也就不折)。 */
|
|
278
|
+
export type FoldedSessionMemoryStatus = Pick<SessionMemoryStatus, "captureOptedOut" | "committedCount" | "foldedCount" | "optOutSource" | "lastCaptureAt">;
|
|
279
|
+
/**
|
|
280
|
+
* 逐店的会话记忆状态 → 一份(**折叠律在代码里只写这一处**;契约 §9 开头同句)。每只店的答案都来自引擎,本函数只按键合,不补任何替身值:
|
|
281
|
+
* · `committedCount` / `foldedCount`:各店相加;任一店缺席(那只店的账读不出)⇒ 缺席。
|
|
282
|
+
* · `lastCaptureAt`:各店取最大;任一店的 `committedCount` 缺席(同一次账读失败)⇒ 缺席;都没有贡献 ⇒ 缺席(与引擎单店同义)。
|
|
283
|
+
* · `captureOptedOut` / `optOutSource`:任一店有记录 ⇒ `true`,带那只店的 `optOutSource`(引擎恒是 `"record"`;一只店上的单向记录就是这只会话的记录);否则全部店答 `false` ⇒ `false`;
|
|
284
|
+
* 否则(有店故障)⇒ `captureOptedOut` 缺席,有店说 `"fault"` 就带 `optOutSource: "fault"`。
|
|
285
|
+
* 一只店 ⇒ 逐键与那只店的答案同(单店部署的应答字节不变)。🚧 引擎的部署级会话记忆状态到货后,本函数删除、路由直接投那一份。
|
|
286
|
+
*/
|
|
287
|
+
export declare function foldPlaneStatuses(statuses: readonly SessionMemoryStatus[]): FoldedSessionMemoryStatus;
|
|
232
288
|
/**
|
|
233
289
|
* [ref] seam①([ref] §S-7,core 7.0.2 [ref] 件1)—— `GET /v1/sessions/:id/memory-status` 的引擎面。
|
|
234
290
|
* 命名照 CLAUDE.md 工厂律:返回带行为的活对象 ⇒ `create*`。
|
|
@@ -240,17 +296,16 @@ export interface SessionMemoryStatusFace {
|
|
|
240
296
|
* 那是**说谎的 0**,比缺席更坏(S-7 的诚实键律:可读零必须是真零)。⇒ 归属缺席 ⇒ 工厂返 undefined,
|
|
241
297
|
* HTTP 面诚实 501,与 erase/origin 同码同分支。
|
|
242
298
|
*
|
|
243
|
-
* `
|
|
244
|
-
* 机器钉 capture-optout-lane
|
|
245
|
-
*
|
|
299
|
+
* `captureRecords` = [ref]② 的按平面取用源(main.ts 取一次,与 Runner/其余引擎同源 —— 全站同批注入律,
|
|
300
|
+
* 机器钉 capture-optout-lane ②;引擎按它那只店的控制面取,{@link captureRecordStoreOf}):`captureOptedOut` / `optOutSource`
|
|
301
|
+
* 两键经它读,多副本部署上答的才是跨副本的真记录。[ref] 起 local 车道在引擎接线时也供(core 文件三腿);缺席 ⇒ 记忆面暗。
|
|
246
302
|
*
|
|
247
|
-
*
|
|
303
|
+
* 引擎**不抛**(core 契约:sessionMemoryStatus never throws —— 每个事实源各自 catch 折缺席键);面唯一的拒是定店那一步的
|
|
304
|
+
* `request.memory_layer`(点名的层 / 本部署点名的层读不出)。不点名层 ⇒ 读本部署的每一只店、路由按 {@link foldPlaneStatuses} 折
|
|
305
|
+
* (只读一只店而它不装这只会话,答出来的就是一个说谎的 0)。
|
|
248
306
|
* 不接 onIncident:这条只读路径上今天零 sink 站点,而且缺席键本身就是它的披露形。
|
|
249
307
|
*/
|
|
250
|
-
export declare function createSessionMemoryStatusFace(
|
|
251
|
-
|
|
252
|
-
root: string;
|
|
253
|
-
}, opts?: {
|
|
254
|
-
captureRecordStore?: SessionCaptureRecordStore;
|
|
308
|
+
export declare function createSessionMemoryStatusFace(stores: MemoryScopeStores, opts?: {
|
|
309
|
+
captureRecords?: SessionCaptureRecordSource;
|
|
255
310
|
}): SessionMemoryStatusFace | undefined;
|
|
256
311
|
//# sourceMappingURL=memory-operator-faces.d.ts.map
|
|
@@ -1,8 +1,59 @@
|
|
|
1
1
|
import { MemoryEngine, } from "@sema-agent/core";
|
|
2
2
|
import { memoryMountRootOf } from "./memory-scope.js";
|
|
3
|
+
import { memoryStoreForRequest, memoryStoresOfDeployment } from "./memory-scope-stores.js";
|
|
3
4
|
export function backendOwnsControlPlane(backend) {
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
return controlPlaneRootOf(backend) !== undefined;
|
|
6
|
+
}
|
|
7
|
+
function controlPlaneRootOf(backend) {
|
|
8
|
+
const root = backend?.controlPlaneRoot;
|
|
9
|
+
return typeof root === "string" && root !== "" ? root : undefined;
|
|
10
|
+
}
|
|
11
|
+
export function captureRecordStoreOf(source, store) {
|
|
12
|
+
if (source === undefined)
|
|
13
|
+
return undefined;
|
|
14
|
+
const root = controlPlaneRootOf(store);
|
|
15
|
+
return source(root !== undefined ? { controlDir: root } : undefined);
|
|
16
|
+
}
|
|
17
|
+
const seatLayers = (at) => (at !== undefined ? [at.layer] : []);
|
|
18
|
+
function createEngineSeat(build) {
|
|
19
|
+
const engines = new Map();
|
|
20
|
+
return (store) => {
|
|
21
|
+
const known = engines.get(store);
|
|
22
|
+
if (known !== undefined)
|
|
23
|
+
return known;
|
|
24
|
+
if (!backendOwnsControlPlane(store))
|
|
25
|
+
throw new Error("the memory store that holds this layer owns no engine control plane (controlPlaneRoot) — the operator faces never answer over a store without one");
|
|
26
|
+
const engine = build(store);
|
|
27
|
+
engines.set(store, engine);
|
|
28
|
+
return engine;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function erasureLayersOf(input) {
|
|
32
|
+
if (typeof input !== "object" || input === null)
|
|
33
|
+
return [];
|
|
34
|
+
const { select, expectedScopes } = input;
|
|
35
|
+
const scope = typeof select === "object" && select !== null ? select.scope : undefined;
|
|
36
|
+
if (typeof scope === "string" && scope.length > 0)
|
|
37
|
+
return [scope];
|
|
38
|
+
if (Array.isArray(expectedScopes) && expectedScopes.length > 0 && expectedScopes.every((s) => typeof s === "string" && s.length > 0))
|
|
39
|
+
return expectedScopes;
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
function erasureSessionOf(input) {
|
|
43
|
+
if (typeof input !== "object" || input === null)
|
|
44
|
+
return undefined;
|
|
45
|
+
const { select } = input;
|
|
46
|
+
const sessionId = typeof select === "object" && select !== null ? select.sessionId : undefined;
|
|
47
|
+
return typeof sessionId === "string" && sessionId.length > 0 ? sessionId : undefined;
|
|
48
|
+
}
|
|
49
|
+
export class MemoryErasureStoreUnjudged extends Error {
|
|
50
|
+
code = "memory.erasure_store_unjudged";
|
|
51
|
+
constructor() {
|
|
52
|
+
super("memory erasure refused: this erasure reaches a memory store other than the deployment's store (this deployment keeps the typed personal memory layers in a second store), " +
|
|
53
|
+
"and this build judges an erasure requestId on the deployment's store only, so it cannot tell whether the same requestId already erased under another selector there — " +
|
|
54
|
+
"erasures that reach the second store are not taken in this build, and nothing was erased; the way out is the engine's deployment-wide erasure request identity, due with the next engine update");
|
|
55
|
+
this.name = "MemoryErasureStoreUnjudged";
|
|
56
|
+
}
|
|
6
57
|
}
|
|
7
58
|
export function erasureInputSmugglesPrototypeKey(input) {
|
|
8
59
|
const stack = [input];
|
|
@@ -24,50 +75,105 @@ export function erasureInputSmugglesPrototypeKey(input) {
|
|
|
24
75
|
}
|
|
25
76
|
return false;
|
|
26
77
|
}
|
|
27
|
-
export function createMemoryComplianceFaces(
|
|
28
|
-
if (!backendOwnsControlPlane(
|
|
78
|
+
export function createMemoryComplianceFaces(stores, opts) {
|
|
79
|
+
if (!backendOwnsControlPlane(stores.backend))
|
|
29
80
|
return undefined;
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
81
|
+
const engineOf = createEngineSeat((store) => {
|
|
82
|
+
const records = captureRecordStoreOf(opts?.captureRecords, store);
|
|
83
|
+
return new MemoryEngine({
|
|
84
|
+
backend: store,
|
|
85
|
+
memoryDir: memoryMountRootOf(store, stores.root),
|
|
86
|
+
...(opts?.onIncident !== undefined ? { onIncident: opts.onIncident } : {}),
|
|
87
|
+
...(records !== undefined ? { captureRecordStore: records } : {}),
|
|
88
|
+
});
|
|
35
89
|
});
|
|
90
|
+
const erasureStoreOf = async (input, at) => {
|
|
91
|
+
const seat = at !== undefined ? "`scope`" : "`select.scope`, or `expectedScopes` next to `select.ids` / `select.sessionId`";
|
|
92
|
+
const layers = at !== undefined ? seatLayers(at) : erasureLayersOf(input);
|
|
93
|
+
const sessionId = layers.length === 0 ? erasureSessionOf(input) : undefined;
|
|
94
|
+
if (sessionId === undefined) {
|
|
95
|
+
const store = memoryStoreForRequest(stores, layers, seat);
|
|
96
|
+
if (store !== stores.backend)
|
|
97
|
+
throw new MemoryErasureStoreUnjudged();
|
|
98
|
+
return store;
|
|
99
|
+
}
|
|
100
|
+
for (const other of memoryStoresOfDeployment(stores, seat)) {
|
|
101
|
+
if (other === stores.backend)
|
|
102
|
+
continue;
|
|
103
|
+
if ((await engineOf(other).sessionMemoryStatus(sessionId)).committedCount !== 0)
|
|
104
|
+
throw new MemoryErasureStoreUnjudged();
|
|
105
|
+
}
|
|
106
|
+
return stores.backend;
|
|
107
|
+
};
|
|
36
108
|
return {
|
|
37
|
-
provenanceOf: (entryId) =>
|
|
38
|
-
erase: (input) => {
|
|
109
|
+
provenanceOf: async (entryId, at) => engineOf(memoryStoreForRequest(stores, seatLayers(at))).provenanceOf(entryId),
|
|
110
|
+
erase: async (input, at) => {
|
|
39
111
|
if (erasureInputSmugglesPrototypeKey(input)) {
|
|
40
112
|
const e = new Error("memory erasure refused: the request carries a key that rewrites an object's prototype — such a key is not a selector, and core's selector dispatch would read it in preference to the declared one");
|
|
41
113
|
e.code = "memory.erasure_selector_unsafe";
|
|
42
|
-
|
|
114
|
+
throw e;
|
|
43
115
|
}
|
|
44
|
-
|
|
116
|
+
const store = await erasureStoreOf(input, at);
|
|
117
|
+
return engineOf(store).eraseMemoryEntries(input);
|
|
45
118
|
},
|
|
46
119
|
};
|
|
47
120
|
}
|
|
48
|
-
export function createMemoryOriginFaces(
|
|
49
|
-
if (!backendOwnsControlPlane(
|
|
121
|
+
export function createMemoryOriginFaces(stores, opts) {
|
|
122
|
+
if (!backendOwnsControlPlane(stores.backend))
|
|
50
123
|
return undefined;
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
124
|
+
const engineOf = createEngineSeat((store) => {
|
|
125
|
+
const records = captureRecordStoreOf(opts?.captureRecords, store);
|
|
126
|
+
return new MemoryEngine({
|
|
127
|
+
backend: store,
|
|
128
|
+
memoryDir: memoryMountRootOf(store, stores.root),
|
|
129
|
+
...(opts?.onIncident !== undefined ? { onIncident: opts.onIncident } : {}),
|
|
130
|
+
...(records !== undefined ? { captureRecordStore: records } : {}),
|
|
131
|
+
});
|
|
56
132
|
});
|
|
57
133
|
return {
|
|
58
|
-
listExternal: (scopes) =>
|
|
59
|
-
listClearances: () =>
|
|
60
|
-
clear: (entryId, input) =>
|
|
134
|
+
listExternal: async (scopes) => engineOf(memoryStoreForRequest(stores, scopes)).listExternalOriginEntries(scopes),
|
|
135
|
+
listClearances: (at) => engineOf(memoryStoreForRequest(stores, seatLayers(at))).listOriginClearances(),
|
|
136
|
+
clear: async (entryId, input, at) => engineOf(memoryStoreForRequest(stores, seatLayers(at))).clearEntryOrigin(entryId, input),
|
|
61
137
|
};
|
|
62
138
|
}
|
|
63
|
-
export function
|
|
64
|
-
|
|
139
|
+
export function foldPlaneStatuses(statuses) {
|
|
140
|
+
const sum = (key) => statuses.every((s) => s[key] !== undefined) ? statuses.reduce((n, s) => n + s[key], 0) : undefined;
|
|
141
|
+
const committedCount = sum("committedCount");
|
|
142
|
+
const foldedCount = sum("foldedCount");
|
|
143
|
+
const captures = statuses.flatMap((s) => (s.lastCaptureAt !== undefined ? [s.lastCaptureAt] : []));
|
|
144
|
+
const lastCaptureAt = committedCount !== undefined && captures.length > 0 ? Math.max(...captures) : undefined;
|
|
145
|
+
const recorded = statuses.find((s) => s.captureOptedOut === true);
|
|
146
|
+
const capture = recorded !== undefined
|
|
147
|
+
? { captureOptedOut: true, ...(recorded.optOutSource !== undefined ? { optOutSource: recorded.optOutSource } : {}) }
|
|
148
|
+
: statuses.every((s) => s.captureOptedOut === false)
|
|
149
|
+
? { captureOptedOut: false }
|
|
150
|
+
: statuses.some((s) => s.optOutSource === "fault")
|
|
151
|
+
? { optOutSource: "fault" }
|
|
152
|
+
: {};
|
|
153
|
+
return {
|
|
154
|
+
...capture,
|
|
155
|
+
...(committedCount !== undefined ? { committedCount } : {}),
|
|
156
|
+
...(foldedCount !== undefined ? { foldedCount } : {}),
|
|
157
|
+
...(lastCaptureAt !== undefined ? { lastCaptureAt } : {}),
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
export function createSessionMemoryStatusFace(stores, opts) {
|
|
161
|
+
if (!backendOwnsControlPlane(stores.backend))
|
|
65
162
|
return undefined;
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
163
|
+
const engineOf = createEngineSeat((store) => {
|
|
164
|
+
const records = captureRecordStoreOf(opts?.captureRecords, store);
|
|
165
|
+
return new MemoryEngine({
|
|
166
|
+
backend: store,
|
|
167
|
+
memoryDir: memoryMountRootOf(store, stores.root),
|
|
168
|
+
...(records !== undefined ? { captureRecordStore: records } : {}),
|
|
169
|
+
});
|
|
70
170
|
});
|
|
71
|
-
|
|
171
|
+
const storeOf = (store) => {
|
|
172
|
+
const engine = engineOf(store);
|
|
173
|
+
return { controlPlane: engine.controlPlaneRoot, status: (sessionId) => engine.sessionMemoryStatus(sessionId) };
|
|
174
|
+
};
|
|
175
|
+
return {
|
|
176
|
+
storesAt: (at) => (at !== undefined ? [storeOf(memoryStoreForRequest(stores, seatLayers(at)))] : memoryStoresOfDeployment(stores).map(storeOf)),
|
|
177
|
+
};
|
|
72
178
|
}
|
|
73
179
|
//# sourceMappingURL=memory-operator-faces.js.map
|
|
@@ -1,23 +1,5 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* [ref]([ref] 片二)—— 一个任务的**项目层准备一步**:求键 → 把同一 checkout 的旧层折进当前层 → 交给同步腿跟踪。
|
|
3
|
-
* HTTP 腿(`boot/resolve-spec.ts`)与 run-local 腿共用这一只;键的规则只在 `memory-scope.ts` `memoryProjectLayerFor`(本模块不判让位、不铸键)。
|
|
4
|
-
*
|
|
5
|
-
* ## 折叠(`foldFrom`,由 `project-identity.ts` `projectLayerForTaskRoot` 给出,按序)
|
|
6
|
-
* · 退役 `repo:<sha256(根)[:24]>` 层 —— **一次性迁移**(7.98.0–7.132.x 的项目键;窗、删法见 `plugins/one-time-migrations.ts` 登记表 M25);
|
|
7
|
-
* · 当前档为 `r`(origin 远端)时本 checkout 的 `p` 档 —— **常设律**(先 `git init` 后加远端的项目,加远端那一刻不丢项目记忆)。
|
|
8
|
-
* 折 = core `migrateScope`(id 保留、rev 按新 scope 重算、逐条 CAS;冲突留原地,下一个任务再折)。**不记「已折」**:每个任务先读一眼旧层
|
|
9
|
-
* (`listHeaders`,空就不动),旧层之后又来了条目(仍在跑的旧任务 harvest、同步把别处的改动拉回旧层)下一个任务照折。
|
|
10
|
-
* 🔴 **与同步轮串行**:旧层若是被同步的层(`p` 档),在飞的那一轮的应答(拉回的改动 / 删除)按 id 落盘 —— 折在它前面,应答会把刚折走的条目改回旧层
|
|
11
|
-
* 或在新层上删掉它。所以有东西要折时,折叠排进同步腿的串行链(`MemorySyncRunner.exclusive`):等在飞的那一轮落定再折,折的时候没有轮在飞。
|
|
12
|
-
* 折在 spec 返回之前完成(`await`)⇒ 这一任务挂载时就看得见折进来的条目(代价如实:有东西要折又恰有一轮在飞时,任务起步等那一轮)。
|
|
13
|
-
* 折叠失败不挡任务(响亮 warn,条目原地不动、下次再折):项目层记忆暂时少了旧层那几条,比任务起不来更接近用户要的东西。
|
|
14
|
-
*
|
|
15
|
-
* ## 跟踪
|
|
16
|
-
* 当前层在复制覆盖面里(否则规则已让位、根本走不到这里)且有同步腿 ⇒ `track(scope)`:本地还没有条目也每轮拉它 —— 第二台设备第一次进这个项目
|
|
17
|
-
* 就拉得到第一台写的(拉回来可能晚于本任务挂载:第一个任务看不见,下一个任务看得见,如实)。
|
|
18
|
-
*/
|
|
19
|
-
import { type MemoryBackend } from "@sema-agent/core";
|
|
20
1
|
import type { ServiceConfig } from "./config-types.js";
|
|
2
|
+
import type { MemoryScopeStores } from "./memory-scope-stores.js";
|
|
21
3
|
import type { MemorySyncRunner } from "./memory-sync-client.js";
|
|
22
4
|
import type { MemoryProjectKey } from "./project-identity.js";
|
|
23
5
|
export interface MemoryProjectLayers {
|
|
@@ -25,8 +7,8 @@ export interface MemoryProjectLayers {
|
|
|
25
7
|
prepare(config: Pick<ServiceConfig, "requirePrincipal" | "memorySync">, scope: string | undefined, taskRoot: string | undefined): Promise<MemoryProjectKey | undefined>;
|
|
26
8
|
}
|
|
27
9
|
export declare function createMemoryProjectLayers(deps: {
|
|
28
|
-
/**
|
|
29
|
-
|
|
10
|
+
/** 本部署的记忆作用域店(= 入口装配出的记忆引擎对象);缺席 ⇒ 没有可折的盘(记忆暗时调用方根本不会问)。 */
|
|
11
|
+
stores: MemoryScopeStores | undefined;
|
|
30
12
|
/** 同步腿(开同步时在场):跟踪当前层;有东西要折时折叠排进它的串行链。 */
|
|
31
13
|
syncRunner: Pick<MemorySyncRunner, "track" | "exclusive"> | undefined;
|
|
32
14
|
log: {
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { migrateScope } from "@sema-agent/core";
|
|
2
2
|
import { memoryProjectLayerFor } from "./memory-scope.js";
|
|
3
3
|
export function createMemoryProjectLayers(deps) {
|
|
4
|
-
const fold = async (
|
|
4
|
+
const fold = async (stores, from, to) => {
|
|
5
5
|
let report;
|
|
6
6
|
try {
|
|
7
|
-
|
|
7
|
+
const store = stores.storeOf(to);
|
|
8
|
+
if (stores.storeOf(from) !== store)
|
|
9
|
+
throw new Error(`the layers ${JSON.stringify(from)} and ${JSON.stringify(to)} live in two different memory stores — a fold moves entries inside one store`);
|
|
10
|
+
report = await migrateScope(store, from, to);
|
|
8
11
|
}
|
|
9
12
|
catch (err) {
|
|
10
13
|
deps.log.warn("memory_project_layer_fold_failed", { from, to, err: String(err), note: "entries stay where they are; the next task in this project retries" });
|
|
@@ -16,10 +19,10 @@ export function createMemoryProjectLayers(deps) {
|
|
|
16
19
|
deps.log.warn("memory_project_layer_fold_conflicts", { from, to, conflicts: report.conflicts.length, note: "conflicting entries stay in the old layer; the next task in this project retries" });
|
|
17
20
|
}
|
|
18
21
|
};
|
|
19
|
-
const occupied = async (
|
|
22
|
+
const occupied = async (stores, sources) => {
|
|
20
23
|
const out = [];
|
|
21
24
|
for (const from of sources) {
|
|
22
|
-
if ((await
|
|
25
|
+
if ((await stores.storeOf(from).listHeaders([from])).some((h) => h.scope === from))
|
|
23
26
|
out.push(from);
|
|
24
27
|
}
|
|
25
28
|
return out;
|
|
@@ -30,11 +33,11 @@ export function createMemoryProjectLayers(deps) {
|
|
|
30
33
|
const current = layer?.key.scope;
|
|
31
34
|
if (layer === undefined || current === undefined)
|
|
32
35
|
return layer?.key;
|
|
33
|
-
const
|
|
34
|
-
if (
|
|
36
|
+
const stores = deps.stores;
|
|
37
|
+
if (stores !== undefined && (await occupied(stores, layer.foldFrom)).length > 0) {
|
|
35
38
|
const foldAll = async () => {
|
|
36
|
-
for (const from of await occupied(
|
|
37
|
-
await fold(
|
|
39
|
+
for (const from of await occupied(stores, layer.foldFrom))
|
|
40
|
+
await fold(stores, from, current);
|
|
38
41
|
};
|
|
39
42
|
await (deps.syncRunner !== undefined ? deps.syncRunner.exclusive(foldAll) : foldAll());
|
|
40
43
|
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 记忆作用域店 —— 「一层住在哪只店」在本宿主的**唯一读者**。
|
|
3
|
+
*
|
|
4
|
+
* ## 规则(一条)
|
|
5
|
+
* 一层(scope)的条目住哪只店,只有引擎的 `resolveMemoryScopeStore` 答;本服务在会话之外读写某一层的每一条腿(同步执行器、项目层折叠、
|
|
6
|
+
* 中心侧导出 / 同步、bundle 导出导入、合规抹除 / 出处、外源标记、会话记忆状态、整理)一律问**本对象**,不再自持「部署的店」当某一层的答案。
|
|
7
|
+
* 本对象就是起服装配出来的那只记忆引擎对象(`boot/stores.ts` 的 `memoryEngine`、`run-local.ts` 的同名量):它的 `backend` / `root`
|
|
8
|
+
* 正是交给 Runner 的两件事实(`RunnerDeps.memoryBackend` / `RunnerDeps.memoryEngineDir`),会话装配解析一层的店读的也是这两件 ——
|
|
9
|
+
* 所以宿主腿与会话对同一层答同一只店。每进程一只,所有腿共用(引擎的话:每层解析一次、留着用)。
|
|
10
|
+
*
|
|
11
|
+
* ## 喂给引擎的契约
|
|
12
|
+
* `scopeContract` = 本服务铸 spec 时给会话盖的同一只判据 {@link memoryScopeContractOf}(按层问与按会话问答同一只店,理由见该函数注)。
|
|
13
|
+
*
|
|
14
|
+
* ## 先判平面,再建店;一只平面一只实例
|
|
15
|
+
* 目录钉住的部署上,引擎对个人平面的答案是在个人挂载上**新开**的一只 File 店(契约原话:一只挂载;打开 = 建目录、收尾中断的事务、读台账)。
|
|
16
|
+
* 层键是调用方给的串,所以本对象**先**问平面、**再**按平面取店:
|
|
17
|
+
* · 平面 = 引擎同一只读法 `resolveMemoryScopeStore` 在一只**不钉目录**的探针店上的答案。引擎契约:不钉目录的店对个人平面原样答回
|
|
18
|
+
* 入参店(「the personal plane shares a backend without a directory」)、项目平面恒答部署的店 ⇒ 这一问只得平面、零建店零读盘,
|
|
19
|
+
* 层键读不出照样抛引擎的 `config.memory_scope_key`(同一只校验)。不在本层另写分类(另写就是第二个读者)。
|
|
20
|
+
* · 店 = 每个平面第一次用到时问引擎一次(真店入参),留下这一只;同平面的后来层复用它 —— 每个本对象至多两只店(项目 / 个人),
|
|
21
|
+
* 「两层同店」按实例判(下面的路由读它)。不按层键缓存:任意多把新层键不建店、不读盘、本对象不长。
|
|
22
|
+
* 🚧 平面的读法待引擎导出纯分类函数(`classifyScopePlanes` / `scopePlanesOf`)后改读它、删探针店;钉在 `test/memory-layer-seat-http.test.ts`。
|
|
23
|
+
*
|
|
24
|
+
* ## 请求的店({@link memoryStoreForRequest})
|
|
25
|
+
* 动词按它的请求**点名的层**取店;点名的几层不在同一只店 ⇒ 响亮拒(一次请求只落一只店)。请求不点名层的动词(条目 id、店级账本)
|
|
26
|
+
* 答在**本部署点名的层与部署的店共处的那一只店**上(`memoryLayersNamedBy`:全局层 / 同步层 / 登记簿种子 / 整理层);它们分住两只店时
|
|
27
|
+
* 不猜,响亮拒并指路「在请求里点名层」。单店部署(缺省 `local`、SQL 记忆后端、配置不点名个人平面键)上无层请求的答法与上一版逐字同。
|
|
28
|
+
*
|
|
29
|
+
* ## 本部署的店({@link memoryStoresOfDeployment})
|
|
30
|
+
* 部署的店 + 本部署点名的每一层住的店,去重、部署的店在前 —— 至多两只。会话 id 的动词读它:一只会话的记忆事实住在它各条腿写进的那只店
|
|
31
|
+
* (写家所在的平面),而单用户部署上会话的写家只会是项目层(部署的店)或全局层(点名的层),所以这张表就是「这只会话可能住的店」的全集。
|
|
32
|
+
*/
|
|
33
|
+
import { type MemoryBackend } from "@sema-agent/core";
|
|
34
|
+
export interface MemoryScopeStores {
|
|
35
|
+
/** 部署的记忆后端 —— 交给 Runner 的那一只(`RunnerDeps.memoryBackend`)。它是「层在哪只店」那只读法的输入、项目平面的店本身,
|
|
36
|
+
* 不是任何一层的答案(层的答案只出自 {@link MemoryScopeStores.storeOf})。 */
|
|
37
|
+
readonly backend: MemoryBackend;
|
|
38
|
+
/** 引擎根 —— 交给 Runner 的那一个值(`RunnerDeps.memoryEngineDir`):读法的另一件输入(个人挂载在它下面),也是同步游标的根。 */
|
|
39
|
+
readonly root: string;
|
|
40
|
+
/** 层 `layer` 住的那只店(引擎的唯一读法;先判平面、每个平面一只实例)。引擎读不出的层键 ⇒ 抛引擎的 `config.memory_scope_key`,原样。 */
|
|
41
|
+
storeOf(layer: string): MemoryBackend;
|
|
42
|
+
/** 本部署配置点名的层(每次现读 —— 登记簿热换)。 */
|
|
43
|
+
namedLayers(): readonly string[];
|
|
44
|
+
}
|
|
45
|
+
/** 命名照工厂律:返回带行为的活对象 ⇒ `create*`。 */
|
|
46
|
+
export declare function createMemoryScopeStores(input: {
|
|
47
|
+
backend: MemoryBackend;
|
|
48
|
+
root: string;
|
|
49
|
+
namedLayers: () => readonly string[];
|
|
50
|
+
/** 本对象为一层开出的店(个人平面的 File 店)的构造期 incident 座(与部署的店那只同一只汇点;缺席合法)。 */
|
|
51
|
+
onIncident?: (err: Error & {
|
|
52
|
+
code?: string;
|
|
53
|
+
}) => void;
|
|
54
|
+
}): MemoryScopeStores;
|
|
55
|
+
/** 本服务的「这次请求落不到一只记忆店」拒(400 `request.memory_layer`):点名的层读不出 / 点名的几层分住两只店 / 两店部署上没点名层。 */
|
|
56
|
+
export declare class MemoryLayerRefusal extends Error {
|
|
57
|
+
readonly code: "request.memory_layer";
|
|
58
|
+
constructor(message: string, cause?: unknown);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* 一次请求的记忆店。`layers` = 请求点名的层(空 = 没点名):
|
|
62
|
+
* · 点名 ⇒ 它们共住的那一只店;分住两只 ⇒ 拒(一次请求只落一只店,按店拆成几次请求)。
|
|
63
|
+
* · 没点名 ⇒ 本部署点名的层与部署的店共处的那一只(= 部署的店);它们分住两只 ⇒ 拒,指路在请求里点名层。
|
|
64
|
+
* `seat` = 这个动词点名层的那一处(拒句里指路用,如 `` `scope` ``;缺省 = 层座 `scope`)。
|
|
65
|
+
* 拒一律 {@link MemoryLayerRefusal}(读不出的层键同码,引擎原句随句)。
|
|
66
|
+
*/
|
|
67
|
+
export declare function memoryStoreForRequest(stores: MemoryScopeStores, layers: readonly string[], seat?: string): MemoryBackend;
|
|
68
|
+
/**
|
|
69
|
+
* 本部署的店:部署的店在前,其后是本部署点名的层住的其余店(去重)—— 单店部署恰一只(部署的店本身)。点名的层读不出 ⇒ {@link MemoryLayerRefusal}(同无层那一臂)。
|
|
70
|
+
* 每次现算(登记簿热换当场生效);只问平面与每平面一只的店,不建多余的店。
|
|
71
|
+
*/
|
|
72
|
+
export declare function memoryStoresOfDeployment(stores: MemoryScopeStores, seat?: string): readonly MemoryBackend[];
|
|
73
|
+
//# sourceMappingURL=memory-scope-stores.d.ts.map
|