@sema-agent/server 7.50.0 → 7.52.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/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/USAGE.md +83 -20
- package/dist/adoption/plan.d.ts +4 -4
- package/dist/adoption/plan.js +11 -0
- package/dist/approval-card.d.ts +26 -2
- package/dist/approval-card.js +9 -0
- package/dist/approval-hmac.d.ts +1 -1
- package/dist/approval-reconciler.d.ts +2 -2
- package/dist/approval-reconciler.js +1 -1
- package/dist/bench/l8/artifact.d.ts +1 -1
- package/dist/bench/s1/arms.d.ts +1 -1
- package/dist/bench/s1/live-deps.d.ts +1 -1
- package/dist/bench/s1/oracle.d.ts +1 -1
- package/dist/bench/s1/row.d.ts +1 -1
- package/dist/boot/budget-tracing.d.ts +1 -1
- package/dist/boot/budget-tracing.js +2 -5
- package/dist/boot/coordinators.js +3 -1
- package/dist/boot/deferred-sandbox-path-env.d.ts +1 -1
- package/dist/boot/device-lane.d.ts +79 -0
- package/dist/boot/device-lane.js +63 -0
- package/dist/boot/engine-lease.d.ts +1 -1
- package/dist/boot/execution-env.d.ts +48 -2
- package/dist/boot/execution-env.js +57 -5
- package/dist/boot/governance-seams.d.ts +2 -2
- package/dist/boot/leader.d.ts +1 -1
- package/dist/boot/memory-boundary.d.ts +2 -2
- package/dist/boot/memory-consolidation.d.ts +6 -6
- package/dist/boot/org-memory.d.ts +1 -1
- package/dist/boot/parked-revive-gate.d.ts +3 -3
- package/dist/boot/reapers.d.ts +2 -2
- package/dist/boot/reapers.js +17 -4
- package/dist/boot/resolve-spec.d.ts +15 -0
- package/dist/boot/resolve-spec.js +40 -15
- package/dist/boot/retention-lane.d.ts +2 -2
- package/dist/boot/runner-deps.d.ts +17 -7
- package/dist/boot/runner-deps.js +4 -2
- package/dist/boot/runtime-caps.d.ts +23 -0
- package/dist/boot/runtime-caps.js +24 -2
- package/dist/boot/session-faces.d.ts +6 -1
- package/dist/boot/session-faces.js +17 -3
- package/dist/boot/shutdown.d.ts +8 -0
- package/dist/boot/shutdown.js +3 -1
- package/dist/boot/stores.js +40 -1
- package/dist/boot/task-list-lane.d.ts +2 -2
- package/dist/brain.js +51 -31
- package/dist/budget.d.ts +2 -2
- package/dist/capabilities/center-plugins.d.ts +1 -1
- package/dist/capabilities/collab-workflows.d.ts +1 -1
- package/dist/capabilities/hands-lane.d.ts +3 -3
- package/dist/capabilities/scenarios.d.ts +3 -3
- package/dist/capabilities/skills.d.ts +1 -1
- package/dist/config-center/hot-keys-registry.js +5 -0
- package/dist/config-center/http-client.d.ts +2 -2
- package/dist/config-center/read-face.d.ts +1 -1
- package/dist/config-center/restart-signal.d.ts +1 -1
- package/dist/config-center/types.d.ts +10 -3
- package/dist/config-invariants.d.ts +2 -2
- package/dist/config-invariants.js +18 -0
- package/dist/config-types.d.ts +90 -18
- package/dist/config.js +91 -19
- package/dist/deployment-governance.d.ts +1 -1
- package/dist/device-enrollment.d.ts +125 -0
- package/dist/device-enrollment.js +156 -0
- package/dist/device-store.d.ts +385 -0
- package/dist/device-store.js +407 -0
- package/dist/device-ws-hub.d.ts +182 -0
- package/dist/device-ws-hub.js +1012 -0
- package/dist/device-ws-protocol.d.ts +429 -0
- package/dist/device-ws-protocol.js +464 -0
- package/dist/env-facts.d.ts +5 -2
- package/dist/env-facts.js +1 -0
- package/dist/execution-lane-caps.d.ts +152 -0
- package/dist/execution-lane-caps.js +166 -0
- package/dist/fleet/fleet-bus.d.ts +1 -1
- package/dist/fleet/fleet-reconciler.d.ts +1 -1
- package/dist/fleet/fleet-terminal-window.d.ts +1 -1
- package/dist/http/active-run-conflict.d.ts +2 -2
- package/dist/http/principal-gate.d.ts +1 -1
- package/dist/http/route-ctx.d.ts +24 -4
- package/dist/http/routes/admin-memory-optout.d.ts +48 -0
- package/dist/http/routes/admin-memory-optout.js +75 -0
- package/dist/http/routes/agents-roster.d.ts +1 -1
- package/dist/http/routes/approvals-assistant.js +21 -21
- package/dist/http/routes/capabilities.js +27 -11
- package/dist/http/routes/diagnostics.d.ts +1 -1
- package/dist/http/routes/leader.d.ts +1 -1
- package/dist/http/routes/memory-bundle.d.ts +1 -1
- package/dist/http/routes/memory-bundle.js +3 -1
- package/dist/http/routes/memory-compliance.d.ts +4 -4
- package/dist/http/routes/memory-origin.d.ts +4 -4
- package/dist/http/routes/memory-origin.js +3 -1
- package/dist/http/routes/memory-policy.js +6 -2
- package/dist/http/routes/retention-ops.d.ts +1 -1
- package/dist/http/routes/rules.d.ts +5 -2
- package/dist/http/routes/rules.js +84 -5
- package/dist/http/routes/run-memory-capture.d.ts +34 -0
- package/dist/http/routes/run-memory-capture.js +97 -0
- package/dist/http/routes/runs.d.ts +1 -0
- package/dist/http/routes/runs.js +212 -6
- package/dist/http/routes/session-sync.d.ts +4 -6
- package/dist/http/routes/session-sync.js +60 -47
- package/dist/http/routes/sessions.js +61 -188
- package/dist/http/routes/shared-memory.d.ts +1 -1
- package/dist/http/routes/tasks.js +1 -1
- package/dist/http/routes/workflows.js +19 -0
- package/dist/http/server.d.ts +49 -13
- package/dist/http/server.js +109 -13
- package/dist/http/verify-rounds.d.ts +1 -1
- package/dist/http/wire-types.d.ts +41 -8
- package/dist/leader/endpoint.d.ts +1 -1
- package/dist/leader/leader.d.ts +1 -1
- package/dist/leader/repair-oracle.d.ts +2 -2
- package/dist/leader/repair-oracle.js +1 -1
- package/dist/leader/wire.js +4 -2
- package/dist/main.js +23 -9
- package/dist/memory-bundle-engine.d.ts +1 -1
- package/dist/memory-operator-faces.d.ts +5 -5
- package/dist/memory-origin-fence.d.ts +50 -0
- package/dist/memory-origin-fence.js +15 -0
- package/dist/memory-posture.d.ts +13 -1
- package/dist/memory-posture.js +1 -0
- package/dist/memory-scope.d.ts +6 -1
- package/dist/memory-scope.js +3 -2
- package/dist/model-select.d.ts +2 -2
- package/dist/observability/fail-open.d.ts +17 -5
- package/dist/observability/fail-open.js +17 -5
- package/dist/orchestration/hardened-vm-runner.d.ts +9 -2
- package/dist/orchestration/hardened-vm-runner.js +11 -1
- package/dist/orchestration/hardened-vm-worker-runner.js +2 -2
- package/dist/orchestration/workflow-completion-inbox.d.ts +2 -2
- package/dist/plugins/background-shell-support.d.ts +2 -2
- package/dist/plugins/blob-backend.d.ts +7 -2
- package/dist/plugins/blob-backend.js +22 -18
- package/dist/plugins/caching-session-store.d.ts +7 -3
- package/dist/plugins/checkpoint-store-sql.d.ts +2 -2
- package/dist/plugins/device-store-sql.d.ts +130 -0
- package/dist/plugins/device-store-sql.js +574 -0
- package/dist/plugins/file-history-store-sql.d.ts +170 -0
- package/dist/plugins/file-history-store-sql.js +827 -0
- package/dist/plugins/file-run-store.d.ts +44 -5
- package/dist/plugins/file-run-store.js +85 -13
- package/dist/plugins/fork-routing-session-store.d.ts +1 -1
- package/dist/plugins/fork-routing-session-store.js +2 -2
- package/dist/plugins/leader-run-store-sql.d.ts +1 -1
- package/dist/plugins/local-session-store.d.ts +9 -1
- package/dist/plugins/memory-embedder-fingerprint.d.ts +1 -1
- package/dist/plugins/memory-optout-grant-store-sql.d.ts +139 -0
- package/dist/plugins/memory-optout-grant-store-sql.js +157 -0
- package/dist/plugins/memory-origin-law.d.ts +2 -2
- package/dist/plugins/memory-run-store.d.ts +4 -3
- package/dist/plugins/memory-run-store.js +2 -1
- package/dist/plugins/permission-rule-store-file.d.ts +16 -6
- package/dist/plugins/permission-rule-store-file.js +77 -13
- package/dist/plugins/permission-rule-store-sql.d.ts +156 -8
- package/dist/plugins/permission-rule-store-sql.js +123 -21
- package/dist/plugins/pg-pool.js +59 -0
- package/dist/plugins/pg-safe-json.d.ts +1 -1
- package/dist/plugins/remote-env-device.d.ts +271 -0
- package/dist/plugins/remote-env-device.js +727 -0
- package/dist/plugins/remote-env-k8s.d.ts +1 -1
- package/dist/plugins/remote-scratchpad.js +1 -1
- package/dist/plugins/retention-lane-store-sql.d.ts +3 -3
- package/dist/plugins/retention-store-sql.d.ts +7 -7
- package/dist/plugins/retention-store-sql.js +6 -0
- package/dist/plugins/run-store-sql.d.ts +9 -3
- package/dist/plugins/run-store-sql.js +2 -2
- package/dist/plugins/send-user-file.d.ts +1 -1
- package/dist/plugins/session-placement.d.ts +1 -1
- package/dist/plugins/sql-errors.d.ts +1 -1
- package/dist/plugins/store-backend.d.ts +68 -29
- package/dist/plugins/store-backend.js +78 -15
- package/dist/plugins/store-contracts.d.ts +5 -3
- package/dist/plugins/task-list-store-sql.d.ts +1 -1
- package/dist/plugins/tidb-pool.js +59 -0
- package/dist/plugins/web-search.d.ts +1 -1
- package/dist/prompts-domain-validate.js +1 -1
- package/dist/resource-suspend.d.ts +1 -1
- package/dist/resource-window.d.ts +3 -3
- package/dist/rules-consent.d.ts +231 -9
- package/dist/rules-consent.js +411 -13
- package/dist/run-local.js +1 -0
- package/dist/runs.d.ts +15 -1
- package/dist/runs.js +19 -0
- package/dist/runtime-caps-resolver.d.ts +36 -1
- package/dist/runtime-caps-resolver.js +25 -0
- package/dist/runtime-governance.d.ts +1 -1
- package/dist/security.d.ts +5 -5
- package/dist/security.js +1 -1
- package/dist/session-sync.d.ts +52 -37
- package/dist/session-sync.js +19 -16
- package/dist/shared-memory-scope-authorizer.d.ts +1 -1
- package/dist/sighup-idle.d.ts +1 -1
- package/dist/spec-fields.d.ts +22 -1
- package/dist/spec-fields.js +11 -0
- package/dist/store-live-probe.d.ts +2 -2
- package/dist/task-a2a.d.ts +1 -1
- package/dist/task-cwd.d.ts +25 -0
- package/dist/task-cwd.js +3 -0
- package/dist/task-mcp.d.ts +3 -3
- package/dist/task-settings.d.ts +3 -3
- package/dist/task-settings.js +3 -1
- package/dist/task-workflow.d.ts +1 -1
- package/dist/text-bidi.d.ts +2 -2
- package/dist/tool-approval.d.ts +191 -9
- package/dist/tool-approval.js +248 -29
- package/dist/trace/core-keyset-guard.d.ts +1 -1
- package/dist/trace/engine-notice-wire.d.ts +6 -4
- package/dist/trace/engine-notice-wire.js +2 -0
- package/dist/trace/ledger-events.d.ts +1 -1
- package/dist/trace/ledger-sink.d.ts +2 -2
- package/dist/trace/project.d.ts +3 -2
- package/dist/trace/project.js +1 -0
- package/dist/turn-activity.d.ts +1 -1
- package/dist/wall-clock-jump-guard.d.ts +3 -3
- package/package.json +2 -2
- package/dist/http/tar.d.ts +0 -17
- package/dist/http/tar.js +0 -53
- package/dist/http/workspace-content.d.ts +0 -11
- package/dist/http/workspace-content.js +0 -20
- package/dist/plugins/file-snapshot-store-sql.d.ts +0 -170
- package/dist/plugins/file-snapshot-store-sql.js +0 -213
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
const NO = "unsupported";
|
|
2
|
+
const YES = "supported";
|
|
3
|
+
const SU = "single-user-only";
|
|
4
|
+
export function executionLaneCaps(lane) {
|
|
5
|
+
switch (lane) {
|
|
6
|
+
case "in-process":
|
|
7
|
+
return {
|
|
8
|
+
callerCwd: NO,
|
|
9
|
+
backgroundShell: NO,
|
|
10
|
+
scheduler: NO,
|
|
11
|
+
lsp: NO,
|
|
12
|
+
sandboxSendUserFile: NO,
|
|
13
|
+
isolation: NO,
|
|
14
|
+
suspendable: NO,
|
|
15
|
+
remoteScratchpad: NO,
|
|
16
|
+
sandboxPathAdjudication: NO,
|
|
17
|
+
worktreeIsolation: NO,
|
|
18
|
+
memoryPersistenceCapable: NO,
|
|
19
|
+
hostFilePlane: YES,
|
|
20
|
+
coreRemoteExecutionEnv: NO,
|
|
21
|
+
};
|
|
22
|
+
case "host":
|
|
23
|
+
return {
|
|
24
|
+
callerCwd: SU,
|
|
25
|
+
backgroundShell: SU,
|
|
26
|
+
scheduler: SU,
|
|
27
|
+
lsp: SU,
|
|
28
|
+
sandboxSendUserFile: NO,
|
|
29
|
+
isolation: NO,
|
|
30
|
+
suspendable: NO,
|
|
31
|
+
remoteScratchpad: NO,
|
|
32
|
+
sandboxPathAdjudication: NO,
|
|
33
|
+
worktreeIsolation: YES,
|
|
34
|
+
memoryPersistenceCapable: YES,
|
|
35
|
+
hostFilePlane: YES,
|
|
36
|
+
coreRemoteExecutionEnv: YES,
|
|
37
|
+
};
|
|
38
|
+
case "e2b":
|
|
39
|
+
return {
|
|
40
|
+
callerCwd: NO,
|
|
41
|
+
backgroundShell: YES,
|
|
42
|
+
scheduler: NO,
|
|
43
|
+
lsp: YES,
|
|
44
|
+
sandboxSendUserFile: YES,
|
|
45
|
+
isolation: YES,
|
|
46
|
+
suspendable: YES,
|
|
47
|
+
remoteScratchpad: YES,
|
|
48
|
+
sandboxPathAdjudication: YES,
|
|
49
|
+
worktreeIsolation: NO,
|
|
50
|
+
memoryPersistenceCapable: NO,
|
|
51
|
+
hostFilePlane: NO,
|
|
52
|
+
coreRemoteExecutionEnv: YES,
|
|
53
|
+
};
|
|
54
|
+
case "k8s":
|
|
55
|
+
return {
|
|
56
|
+
callerCwd: NO,
|
|
57
|
+
backgroundShell: YES,
|
|
58
|
+
scheduler: NO,
|
|
59
|
+
lsp: YES,
|
|
60
|
+
sandboxSendUserFile: YES,
|
|
61
|
+
isolation: YES,
|
|
62
|
+
suspendable: YES,
|
|
63
|
+
remoteScratchpad: YES,
|
|
64
|
+
sandboxPathAdjudication: YES,
|
|
65
|
+
worktreeIsolation: NO,
|
|
66
|
+
memoryPersistenceCapable: NO,
|
|
67
|
+
hostFilePlane: NO,
|
|
68
|
+
coreRemoteExecutionEnv: YES,
|
|
69
|
+
};
|
|
70
|
+
case "ssh":
|
|
71
|
+
return {
|
|
72
|
+
callerCwd: NO,
|
|
73
|
+
backgroundShell: NO,
|
|
74
|
+
scheduler: NO,
|
|
75
|
+
lsp: NO,
|
|
76
|
+
sandboxSendUserFile: SU,
|
|
77
|
+
isolation: NO,
|
|
78
|
+
suspendable: NO,
|
|
79
|
+
remoteScratchpad: YES,
|
|
80
|
+
sandboxPathAdjudication: YES,
|
|
81
|
+
worktreeIsolation: NO,
|
|
82
|
+
memoryPersistenceCapable: NO,
|
|
83
|
+
hostFilePlane: NO,
|
|
84
|
+
coreRemoteExecutionEnv: YES,
|
|
85
|
+
};
|
|
86
|
+
case "adb":
|
|
87
|
+
return {
|
|
88
|
+
callerCwd: NO,
|
|
89
|
+
backgroundShell: NO,
|
|
90
|
+
scheduler: NO,
|
|
91
|
+
lsp: NO,
|
|
92
|
+
sandboxSendUserFile: NO,
|
|
93
|
+
isolation: NO,
|
|
94
|
+
suspendable: NO,
|
|
95
|
+
remoteScratchpad: NO,
|
|
96
|
+
sandboxPathAdjudication: YES,
|
|
97
|
+
worktreeIsolation: NO,
|
|
98
|
+
memoryPersistenceCapable: NO,
|
|
99
|
+
hostFilePlane: NO,
|
|
100
|
+
coreRemoteExecutionEnv: YES,
|
|
101
|
+
};
|
|
102
|
+
case "local-docker":
|
|
103
|
+
return {
|
|
104
|
+
callerCwd: NO,
|
|
105
|
+
backgroundShell: NO,
|
|
106
|
+
scheduler: NO,
|
|
107
|
+
lsp: NO,
|
|
108
|
+
sandboxSendUserFile: NO,
|
|
109
|
+
isolation: YES,
|
|
110
|
+
suspendable: NO,
|
|
111
|
+
remoteScratchpad: YES,
|
|
112
|
+
sandboxPathAdjudication: YES,
|
|
113
|
+
worktreeIsolation: NO,
|
|
114
|
+
memoryPersistenceCapable: NO,
|
|
115
|
+
hostFilePlane: NO,
|
|
116
|
+
coreRemoteExecutionEnv: YES,
|
|
117
|
+
};
|
|
118
|
+
case "device":
|
|
119
|
+
return {
|
|
120
|
+
callerCwd: YES,
|
|
121
|
+
backgroundShell: NO,
|
|
122
|
+
scheduler: NO,
|
|
123
|
+
lsp: NO,
|
|
124
|
+
sandboxSendUserFile: NO,
|
|
125
|
+
isolation: NO,
|
|
126
|
+
suspendable: NO,
|
|
127
|
+
remoteScratchpad: YES,
|
|
128
|
+
sandboxPathAdjudication: YES,
|
|
129
|
+
worktreeIsolation: NO,
|
|
130
|
+
memoryPersistenceCapable: NO,
|
|
131
|
+
hostFilePlane: NO,
|
|
132
|
+
coreRemoteExecutionEnv: YES,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const EXECUTION_LANE_WORDS = {
|
|
137
|
+
"in-process": true,
|
|
138
|
+
host: true,
|
|
139
|
+
e2b: true,
|
|
140
|
+
k8s: true,
|
|
141
|
+
ssh: true,
|
|
142
|
+
adb: true,
|
|
143
|
+
"local-docker": true,
|
|
144
|
+
device: true,
|
|
145
|
+
};
|
|
146
|
+
export function isExecutionLane(word) {
|
|
147
|
+
return Object.hasOwn(EXECUTION_LANE_WORDS, word);
|
|
148
|
+
}
|
|
149
|
+
export const ALL_EXECUTION_LANES = Object.freeze(Object.keys(EXECUTION_LANE_WORDS).filter(isExecutionLane));
|
|
150
|
+
export function executionLaneOf(provider) {
|
|
151
|
+
if (provider === undefined)
|
|
152
|
+
return "in-process";
|
|
153
|
+
return isExecutionLane(provider) ? provider : undefined;
|
|
154
|
+
}
|
|
155
|
+
export function laneCapabilityHolds(cap, deployment) {
|
|
156
|
+
switch (cap) {
|
|
157
|
+
case "supported":
|
|
158
|
+
return true;
|
|
159
|
+
case "unsupported":
|
|
160
|
+
return false;
|
|
161
|
+
case "single-user-only":
|
|
162
|
+
return deployment.requirePrincipal !== true;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
export const PLANNED_LANE_DIVERGENCES = Object.freeze([]);
|
|
166
|
+
//# sourceMappingURL=execution-lane-caps.js.map
|
|
@@ -102,7 +102,7 @@ export interface FleetTaskRow {
|
|
|
102
102
|
transcriptId?: string;
|
|
103
103
|
/** [1839]①/(a) 案:**终态行帧的残局键**——cli 实测裸 durable-run 完成时终态 task 帧键集只有
|
|
104
104
|
* [id,name,status,tokens,elapsedMs,description],idle 观察者(web 首屏形)从行卡拿不到终局。
|
|
105
|
-
* (b) 案(为顶层 run 造 bg_notification)
|
|
105
|
+
* (b) 案(为顶层 run 造 bg_notification)被否:那族语义=观察者眼里的**子代**,自造事件族比丰富行帧
|
|
106
106
|
* 更伤([1840]§二)。四键全部 ADDITIVE / tolerate-absent、**只在终态帧出现**:
|
|
107
107
|
* - `stoppedBy`:core open enum verbatim(与 BgNotification 同姿势);顶层 run 仅 cancel 路径有源
|
|
108
108
|
* (= "user",与 markStopSource 同源值),其余终态诚实缺席。
|
|
@@ -64,7 +64,7 @@ export declare const FLEET_RECONCILE_INTERVAL_MS = 60000;
|
|
|
64
64
|
/** 每周期的**点读上限**。超出的行留到下一周期(顺序稳定 = bus 的插入序),不把一次扫描变成全表点读风暴。 */
|
|
65
65
|
export declare const FLEET_RECONCILE_MAX_ROWS = 200;
|
|
66
66
|
/** 一个周期的 durable 读**时间预算**。超时 = 放弃这一轮(记 F 类 fail-open),行留在面板上。
|
|
67
|
-
* 与 `FLEET_SNAPSHOT_TERMINAL_READ_BUDGET_MS`
|
|
67
|
+
* 与 `FLEET_SNAPSHOT_TERMINAL_READ_BUDGET_MS` 同值同理由:慢查询不该把整条腿卡住。 */
|
|
68
68
|
export declare const FLEET_RECONCILE_READ_BUDGET_MS = 2000;
|
|
69
69
|
/** 熔断冷却:一次读失败/超预算之后,这段时间内**不再发起任何读**。`RunStore`/`WorkflowRunStore` 契约
|
|
70
70
|
* 都没有取消面(发出去的查询撤不回),挂死的后端不该被每周期继续加压。冷却一过自动重探(自愈)。 */
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* ## 为什么本模块有进程级可变状态(路由域刻意保持零状态,故不放在 `routes/fleet.ts`)
|
|
17
17
|
* 三件都长在同一个事实上——**`WorkflowRunStore` 契约没有取消面**,`Promise.race` 只结束等待、撤不回
|
|
18
18
|
* 已发出的查询:合流(重连风暴不按连接数放大,R1-H2)、合流窗有限(不把陈旧结果发给后来者、也不让
|
|
19
|
-
* 一条永不 settle
|
|
19
|
+
* 一条永不 settle 的读把后续连接全卡住,R2-H1/R3-M2)、熔断冷却(挂死的后端不被每周期继续加压,
|
|
20
20
|
* R3-H1)。真解是店侧查询超时/取消 —— 要动契约与四个后端,已作移交项。
|
|
21
21
|
*
|
|
22
22
|
* ## scope
|
|
@@ -73,7 +73,7 @@ export interface PendingGateMaterial {
|
|
|
73
73
|
* ③ **材料读取失败**:整只 `pendingGate` 都不在(那时本键连位置都没有)。
|
|
74
74
|
* ⇒ 读作「不知道这道门叫什么」,**不是**「这道门没有身份」,更**不是**「这一定是条老行」。
|
|
75
75
|
*
|
|
76
|
-
* 🔴 **它命名的是「本次 409 实际读到的那一行」,不是「activeTaskId 这条 run 的门」**(codex
|
|
76
|
+
* 🔴 **它命名的是「本次 409 实际读到的那一行」,不是「activeTaskId 这条 run 的门」**(codex 交叉复审
|
|
77
77
|
* R1-[high] 验真后如实登记):同 session 可以并存两条 pending checkpoint(表上**没有** per-session
|
|
78
78
|
* pending 唯一约束),而 `findPendingTokenBySession` 是**无序 `LIMIT 1`** —— 这个条件是本仓自己成文的
|
|
79
79
|
* 已知事实(见 `src/http/server.ts` mintFreshRun 腿 409 那段的逐字论证:「两条 pending 并存时旧
|
|
@@ -147,7 +147,7 @@ export interface ActiveRunConflictDoneResult {
|
|
|
147
147
|
/**
|
|
148
148
|
* #316(c):与 409 body 同键同语义(见 {@link ActiveRunConflictBody.stale})。
|
|
149
149
|
*
|
|
150
|
-
* 🔴 **跨仓欠账,如实登记**(codex
|
|
150
|
+
* 🔴 **跨仓欠账,如实登记**(codex 交叉复审 R1-[medium] 验真后的真形):sema-sdk 的
|
|
151
151
|
* `spec/openapi.yaml` 里 `ActiveRunConflictDoneResult` 是 `additionalProperties: false` 的**封闭**
|
|
152
152
|
* schema,今天只声明 `status/errorCode/errorMessage/activeTaskId/activeTaskStatus/pendingGate` 六键。
|
|
153
153
|
* ⚠️ 亲验后的关键修正:这**不是本键引入的新问题** —— `msSinceLastActivity`(#245 S1)早就在这条
|
|
@@ -13,7 +13,7 @@ export declare function systemFor(req: IncomingMessage, config: ServiceConfig):
|
|
|
13
13
|
export declare function bearerPresentedButUnverified(req: IncomingMessage, config: ServiceConfig): boolean;
|
|
14
14
|
export declare function gatedPrincipal(req: IncomingMessage, config: ServiceConfig): string | undefined;
|
|
15
15
|
/** The EXPLICIT operator gate (IMAGE-API-DESIGN.md §P2.4a MUST-FIX) — NOT the bare `isOperator` (whose empty-list
|
|
16
|
-
* "true-for-all" is
|
|
16
|
+
* "true-for-all" is an unrestricted-write exec door the instant OPERATOR_PRINCIPALS is empty). Requires a non-empty
|
|
17
17
|
* operator set AND a present principal IN it. The same form the preempt/resume endpoints already use.
|
|
18
18
|
* 🔴 SINGLE mint point (E1): a byte-identical twin `explicitOperator` used to live below (image-visibility lane)
|
|
19
19
|
* and two more hand-inlined copies sat in approvals-assistant — a future hardening of this judgment would have
|
package/dist/http/route-ctx.d.ts
CHANGED
|
@@ -156,18 +156,38 @@ export interface RouteLegs {
|
|
|
156
156
|
*
|
|
157
157
|
* `onTypedFailure` = 「typed 拒绝**别写响应**,交回给我」。默认(缺席)行为不变:`HttpError` 走
|
|
158
158
|
* `sendError` 连 `extra` 一起回显。DESIGN-269 车2 的 A2A 腿必须传它 —— 那些 `extra`(尤其
|
|
159
|
-
* `scenario_unknown` 的**全部场景名**)对壳是指路材料,对一个外部 peer
|
|
160
|
-
prepareSpec(req: IncomingMessage, res: ServerResponse, body?: TaskRequestBody, onTypedFailure?: (err: import("../security.js").HttpError) => void
|
|
159
|
+
* `scenario_unknown` 的**全部场景名**)对壳是指路材料,对一个外部 peer 是内部词表外泄。 */
|
|
160
|
+
prepareSpec(req: IncomingMessage, res: ServerResponse, body?: TaskRequestBody, onTypedFailure?: (err: import("../security.js").HttpError) => void,
|
|
161
|
+
/** S-46 件C:**腿身份**(不是能力表态)。`liveStream: true` 只由 `POST /v1/tasks/stream` 的装配点按
|
|
162
|
+
* URL 传 —— 那是全树唯一挂 HITL 活流投递面的腿,逐腿 `interactionPosture` 判据的第一条合取项。
|
|
163
|
+
* 缺席 ⇒ 无人腿(bg / A2A / resume),行为字节不变。 */
|
|
164
|
+
legFacts?: {
|
|
165
|
+
liveStream?: boolean;
|
|
166
|
+
}): Promise<PreparedTaskSubmission | null>;
|
|
161
167
|
/** 同步腿的终局记账(计费/配额/指标),tasks 域用。 */
|
|
162
168
|
finalizeTaskResult(result: TaskResult, principal: string | undefined, objective: string, sessionId: string | undefined): void;
|
|
163
169
|
/** approvals 决策腿:session → pending checkpoint → markResuming CAS → 驱动续跑。
|
|
164
170
|
* `settledBy` = **这次结算的出处**(core `ApprovalSettledBy`),必填:本腿有两个调用方(HTTP
|
|
165
171
|
* `/decide` = 人;内部 D-D SLA deny-sweep = 窗到期),而函数内部分辨不出谁在叫它 —— 必填参数把
|
|
166
172
|
* 「漏报出处」变成编译错,不是一条下游把「没人答」渲染成「有人拒」的静默假出处。 */
|
|
167
|
-
resumeCheckpoint(sessionId: string, decision: "approve" | "deny", reason: string | undefined, settledBy: ApprovalSettledBy, req?: IncomingMessage, answer?: QuestionAnswer, binding?: DecideBinding,
|
|
173
|
+
resumeCheckpoint(sessionId: string, decision: "approve" | "deny", reason: string | undefined, settledBy: ApprovalSettledBy, req?: IncomingMessage, answer?: QuestionAnswer, binding?: DecideBinding,
|
|
174
|
+
/** S-02 codex R4(验真后修):remember 豁免的 grant 挂点。**工具名不再由路由自己读**(那是与本函数
|
|
175
|
+
* 载入行分歧的第三次 scope-less 读,三读分歧下会给他人工具落豁免=提权)——由本函数把**已属主校验的
|
|
176
|
+
* 载入 cp** 的工具名(`validatedToolName`,非 tool_approval / AskUserQuestion / legacy null ⇒ `null`
|
|
177
|
+
* = 无可记)一并回传,路由只对这个逐字落店。`overrideSessionId` = parked 腿的 root/host 会话 grant 锚。 */
|
|
178
|
+
onResumeCommitted?: (grant: {
|
|
179
|
+
overrideSessionId?: string;
|
|
180
|
+
validatedToolName: string | null;
|
|
181
|
+
}) => Promise<void>,
|
|
168
182
|
/** #316:透传给 {@link DriveResumeArgs.acceptEarly}(200 受理语义)。HTTP `/decide` 腿传 `true`;
|
|
169
183
|
* 内部 D-D SLA deny-sweep 不传 —— 它没有在等响应的人,提前受理对它零收益而少一条同步失败面。 */
|
|
170
|
-
acceptEarly?: boolean
|
|
184
|
+
acceptEarly?: boolean,
|
|
185
|
+
/** S-02:调用方已验身份的裁定 —— stale 臂铸 `currentPending` 指路键前在被读回的行上重跑 decide 门
|
|
186
|
+
* 同一属主判(缺席 ⇒ 恒不造键;判据属主=server.ts 铸键点注)。 */
|
|
187
|
+
decider?: {
|
|
188
|
+
principal?: string;
|
|
189
|
+
explicitOperator: boolean;
|
|
190
|
+
}): Promise<{
|
|
171
191
|
status: number;
|
|
172
192
|
body: object;
|
|
173
193
|
}>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* design/383 §3.1 / S-50 §1.3(S-49 S-2)—— per-principal **memory-capture opt-out 授权表**的 operator 四口:
|
|
3
|
+
*
|
|
4
|
+
* · `GET /v1/admin/memory-optout` → `{ deploymentDefault: Row|null, overrides: Row[] }`
|
|
5
|
+
* · `PUT /v1/admin/memory-optout` body `{allow, note?}` → 部署缺省行 upsert(哨兵 `principal=''`)
|
|
6
|
+
* · `PUT /v1/admin/memory-optout/:principal` body `{allow, note?}` → per-principal 覆盖行 upsert
|
|
7
|
+
* · `DELETE /v1/admin/memory-optout/:principal` → 撤覆盖(回落部署缺省);`{ deleted: boolean }` 诚实答
|
|
8
|
+
*
|
|
9
|
+
* Row = `{ principal, allow, updatedAtMs, updatedBy, note? }`(审计行内,S-50 §1.3;`updatedBy` = 调用方 operator
|
|
10
|
+
* principal,server 铸,body 不收)。
|
|
11
|
+
*
|
|
12
|
+
* ── 稿偏离两条(如实记)────────────────────────────────────────────────────────────────────────────
|
|
13
|
+
* ① S-50 §1.1/§1.3 写的是 `orgDefault` + `(org_id, principal)`。亲读本仓(2026-08-30 侦察):server **没有 org 身份维**
|
|
14
|
+
* (租户维 = 单 principal;`org` 只是记忆 scope 目录里的词),给表/wire 铸一根没人能填的 `org_id` 是编数据。一台
|
|
15
|
+
* worker = 一个租户面 ⇒ 「org 级缺省」落成**部署级缺省**,wire 键名随实体改叫 `deploymentDefault`。折叠律不变。
|
|
16
|
+
* ② S-50 §1.3 把部署缺省写成 `PUT …/memory-optout/default`。codex R1-[medium] 验真:`default` 是一个**合法 principal
|
|
17
|
+
* 拼写**,字面路径 `/default` 与 `%64efault`(解码后同为 `default`)在第一版里分派到**两个不同的行**(哨兵行 vs
|
|
18
|
+
* 一条名叫 default 的覆盖行)—— 命名空间碰撞,而且 DELETE 侧还不对称。修法不是「解码后再保留一个词」(那只是把
|
|
19
|
+
* 碰撞改成一条不可寻址的 principal),而是**让缺省行住在集合根**:`PUT /v1/admin/memory-optout`(集合本身的
|
|
20
|
+
* 「缺省」属性),`:principal` 面从此没有任何保留词,任何合法 principal(包括字面 `default`)都可寻址。
|
|
21
|
+
*
|
|
22
|
+
* ── 族属与门序 ────────────────────────────────────────────────────────────────────────────────────
|
|
23
|
+
* 与 `/v1/admin/drain` · `/v1/admin/config/refresh` · `/v1/admin/memory/consolidation` 逐字同族(operator lane:
|
|
24
|
+
* 同一条 `explicitOperatorOk` 门;billable=false;刻意不吃 drain / roster-pending 两道 503)。门序照 operator
|
|
25
|
+
* 面既有口径:身份(401)→ 授权(403)→ **能力(501)** → 验型(400)。授权在能力之前:一个够不着任何东西
|
|
26
|
+
* 的调用方不该从「这台有没有授权表」上读出部署形态。
|
|
27
|
+
* 🔴 四口都在 `isCredentialGatedRewrite`(server.ts)门内(codex R1-[high] 验真后补):授权的**唯一**输入是
|
|
28
|
+
* principal 头 ∧ 一次调用的爆炸半径跨租户(改缺省行 = 改整台部署每个 principal 的 verdict;读面 = 全部授权行 +
|
|
29
|
+
* operator 手写的 note)—— 无 service 凭证且未开 `ALLOW_UNAUTHED_WRITES` 的 worker 上那个头**可自造**,与
|
|
30
|
+
* `/v1/memory/erase` / `POST /v1/memory/export` 同一条论证。
|
|
31
|
+
*
|
|
32
|
+
* ── 为什么缺席形是 **501 `capability.*`** 而不是 404(与 consolidation 阀门刻意分家)──────────────────
|
|
33
|
+
* consolidation 的 404 说的是「旋钮没开」(运维表态,动作=开旋钮)。本面的缺席是「**这家店在本部署上不存在**」
|
|
34
|
+
* —— local 车道刻意不给授权表一个会遗忘的 in-memory twin(接口注),动作=换部署形态(接 SQL 后端)。那正是
|
|
35
|
+
* 本仓 501 `capability.*` 族的定义(`capability.memory_engine_required` / `capability.outcome_ledger_required`
|
|
36
|
+
* 同族)。能力位 `memoryOptOutGrant`(`GET /v1/capabilities`)读同一个事实 + operator 名单非空。
|
|
37
|
+
*
|
|
38
|
+
* ── 撤销窗(S-50 §1.4)──────────────────────────────────────────────────────────────────────────
|
|
39
|
+
* 写后**零缓存**:resolver 腿(`RuntimeCaps.allowMemoryOptOut`)每次 prepare 直读同一张表 ⇒ 下一次带声明的
|
|
40
|
+
* prepare 即读到新 verdict(撤权后新声明具名拒;已声明会话 record wins,core 判,server 零码)。
|
|
41
|
+
*/
|
|
42
|
+
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
43
|
+
import type { RouteCtx } from "../route-ctx.js";
|
|
44
|
+
export declare const ADMIN_MEMORY_OPTOUT_PATH = "/v1/admin/memory-optout";
|
|
45
|
+
/** 带参口(`:principal`)⇒ 名册门走 `ROUTE_LABEL_PATTERNS`(server.ts),不是 LITERALS。 */
|
|
46
|
+
export declare const ADMIN_MEMORY_OPTOUT_OVERRIDE_RE: RegExp;
|
|
47
|
+
export declare function handleMemoryOptOut(req: IncomingMessage, res: ServerResponse, url: string, ctx: RouteCtx): Promise<boolean>;
|
|
48
|
+
//# sourceMappingURL=admin-memory-optout.d.ts.map
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { sendJson, sendError } from "../send.js";
|
|
3
|
+
import { gatedPrincipal, explicitOperatorOk } from "../principal-gate.js";
|
|
4
|
+
import { memoryOptOutPrincipalShapeProblem } from "../../plugins/memory-optout-grant-store-sql.js";
|
|
5
|
+
export const ADMIN_MEMORY_OPTOUT_PATH = "/v1/admin/memory-optout";
|
|
6
|
+
export const ADMIN_MEMORY_OPTOUT_OVERRIDE_RE = /^\/v1\/admin\/memory-optout\/([^/]+)$/;
|
|
7
|
+
const PutBodySchema = z.object({ allow: z.boolean(), note: z.string().min(1).max(500).optional() }).strict();
|
|
8
|
+
export async function handleMemoryOptOut(req, res, url, ctx) {
|
|
9
|
+
const miss = { fell: false };
|
|
10
|
+
await handleBody(req, res, url, ctx, miss);
|
|
11
|
+
return !miss.fell;
|
|
12
|
+
}
|
|
13
|
+
function decideVerb(method, path, safeDecode) {
|
|
14
|
+
if (path === ADMIN_MEMORY_OPTOUT_PATH) {
|
|
15
|
+
if (method === "GET")
|
|
16
|
+
return { kind: "list" };
|
|
17
|
+
if (method === "PUT")
|
|
18
|
+
return { kind: "putDefault" };
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
const m = ADMIN_MEMORY_OPTOUT_OVERRIDE_RE.exec(path);
|
|
22
|
+
if (m === null)
|
|
23
|
+
return undefined;
|
|
24
|
+
if (method !== "PUT" && method !== "DELETE")
|
|
25
|
+
return undefined;
|
|
26
|
+
const principal = safeDecode(m[1]);
|
|
27
|
+
if (principal === null)
|
|
28
|
+
return "malformed";
|
|
29
|
+
return method === "PUT" ? { kind: "putOverride", principal } : { kind: "deleteOverride", principal };
|
|
30
|
+
}
|
|
31
|
+
async function handleBody(req, res, url, ctx, miss) {
|
|
32
|
+
const { deps } = ctx;
|
|
33
|
+
const path = url.split("?")[0] ?? url;
|
|
34
|
+
const verb = decideVerb(req.method, path, ctx.helpers.safeDecode);
|
|
35
|
+
if (verb === undefined) {
|
|
36
|
+
miss.fell = true;
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const principal = gatedPrincipal(req, deps.config);
|
|
40
|
+
if (deps.config.requirePrincipal && !principal) {
|
|
41
|
+
sendError(res, 401, "auth.principal_required", `missing principal header '${deps.config.principalHeader}'`);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (!explicitOperatorOk(principal, deps.config.operatorPrincipals)) {
|
|
45
|
+
sendError(res, 403, "auth.operator_only", "memory opt-out grant administration is operator-only: the caller principal is not in OPERATOR_PRINCIPALS (an empty list means NO one is an operator — configure it to enable these endpoints)");
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const operator = principal;
|
|
49
|
+
const store = deps.memoryOptOutGrant;
|
|
50
|
+
if (store === undefined) {
|
|
51
|
+
sendError(res, 501, "capability.memory_optout_grant_required", "this deployment has no memory opt-out grant table: the per-principal memory-capture opt-out authorization store lives on a SQL store backend (DB_BACKEND=mysql|pg) and the local backend deliberately keeps no forgetting twin — wire a SQL backend to administer opt-out grants");
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (verb === "malformed" || ((verb.kind === "putOverride" || verb.kind === "deleteOverride") && memoryOptOutPrincipalShapeProblem(verb.principal) !== undefined)) {
|
|
55
|
+
sendError(res, 400, "request.path_malformed", "invalid memory opt-out grant principal — the path segment must percent-decode to a non-empty principal of at most 190 chars with no leading/trailing whitespace or control characters (the deployment default row is addressed by PUT on the collection root, not by a path segment)");
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (verb.kind === "list") {
|
|
59
|
+
sendJson(res, 200, await store.list());
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (verb.kind === "deleteOverride") {
|
|
63
|
+
sendJson(res, 200, { principal: verb.principal, deleted: await store.deleteOverride(verb.principal) });
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const parsed = PutBodySchema.safeParse(await ctx.helpers.readJson(req));
|
|
67
|
+
if (!parsed.success) {
|
|
68
|
+
sendError(res, 400, "request.body_shape", "invalid memory opt-out grant body — expected exactly { allow: boolean, note?: string (1..500 chars) }; unknown keys are refused (a mistyped `allow` must not silently become a no-op)");
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const input = { allow: parsed.data.allow, updatedBy: operator, ...(parsed.data.note !== undefined ? { note: parsed.data.note } : {}) };
|
|
72
|
+
const row = verb.kind === "putDefault" ? await store.putDefault(input) : await store.putOverride(verb.principal, input);
|
|
73
|
+
sendJson(res, 200, row);
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=admin-memory-optout.js.map
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*
|
|
17
17
|
* ## 三条边界(逐条对着失败形写)
|
|
18
18
|
* · **principal 门 + 反枚举**:身份判在店可用性判**之前**(否则「这台有没有装店」会先于 401 泄出去,
|
|
19
|
-
* 与 `GET /v1/sessions` 的同款注释);principal
|
|
19
|
+
* 与 `GET /v1/sessions` 的同款注释);principal 调用方**锁定自己的 scope**(`?scope=` 对它无效),
|
|
20
20
|
* 于是别的租户的行不是「403」也不是「空 200 但 total 多 1」——它在这个名册里**根本不存在**,
|
|
21
21
|
* 没有任何可判别面(`total` 同样是属主口径:一个多出来的计数就是存在性 oracle)。
|
|
22
22
|
* · **投影白名单**(照 `routes/fleet.ts` `stripT` 的姿势):逐键**显式拼**,并用
|
|
@@ -38,6 +38,8 @@ async function decideIdempotentReplay(cs, args) {
|
|
|
38
38
|
const boundCallId = binding.boundCallId;
|
|
39
39
|
if (boundCallId === undefined)
|
|
40
40
|
return undefined;
|
|
41
|
+
if (binding.checkpointToken !== undefined)
|
|
42
|
+
return undefined;
|
|
41
43
|
if (typeof cs.findDecidedApprovalsForBinding !== "function")
|
|
42
44
|
return undefined;
|
|
43
45
|
const rows = await cs.findDecidedApprovalsForBinding(sessionId, boundCallId);
|
|
@@ -463,30 +465,28 @@ async function handleApprovalsAssistantBody(req, res, url, ctx, miss) {
|
|
|
463
465
|
return;
|
|
464
466
|
}
|
|
465
467
|
}
|
|
466
|
-
let rememberToolName = null;
|
|
467
|
-
if (remember) {
|
|
468
|
-
const tok = await cs.findPendingTokenBySession(sessionId);
|
|
469
|
-
const cp0 = tok ? await cs.get(tok) : null;
|
|
470
|
-
const pa0 = cp0?.pendingAction;
|
|
471
|
-
const tn = pa0 && pa0.kind === "tool_approval" ? pa0.toolName : null;
|
|
472
|
-
rememberToolName = tn && tn !== "AskUserQuestion" ? tn : null;
|
|
473
|
-
}
|
|
474
468
|
let rememberApplied = false;
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
deps.logger?.info?.("approval_exemption_granted", { sessionId: grantSessionId, toolName: canonical, grantedBy: deciderPrincipal ?? null });
|
|
483
|
-
}
|
|
484
|
-
catch (e) {
|
|
485
|
-
deps.logger?.warn?.("approval_exemption_grant_failed", { sessionId: grantSessionId, toolName: rememberToolName, error: String(e).slice(0, 200) });
|
|
486
|
-
}
|
|
469
|
+
let pendingGrant;
|
|
470
|
+
const grantOnCommit = remember && deps.approvalExemptionStore
|
|
471
|
+
? async (grant) => {
|
|
472
|
+
const canonical = grant.validatedToolName;
|
|
473
|
+
if (!canonical)
|
|
474
|
+
return;
|
|
475
|
+
pendingGrant = { sessionId: grant.overrideSessionId ?? sessionId, toolName: canonical };
|
|
487
476
|
}
|
|
488
477
|
: undefined;
|
|
489
|
-
const out = await resumeCheckpoint(sessionId, decision, body.reason ?? undefined, "human", req, answer, binding, grantOnCommit, true);
|
|
478
|
+
const out = await resumeCheckpoint(sessionId, decision, body.reason ?? undefined, "human", req, answer, binding, grantOnCommit, true, { principal: deciderPrincipal, explicitOperator });
|
|
479
|
+
const outErrorCode = out.body.errorCode;
|
|
480
|
+
if (pendingGrant !== undefined && out.status === 200 && outErrorCode !== "cancelled" && deps.approvalExemptionStore) {
|
|
481
|
+
try {
|
|
482
|
+
await deps.approvalExemptionStore.grant(pendingGrant.sessionId, pendingGrant.toolName, deciderPrincipal ?? null);
|
|
483
|
+
rememberApplied = true;
|
|
484
|
+
deps.logger?.info?.("approval_exemption_granted", { sessionId: pendingGrant.sessionId, toolName: pendingGrant.toolName, grantedBy: deciderPrincipal ?? null });
|
|
485
|
+
}
|
|
486
|
+
catch (e) {
|
|
487
|
+
deps.logger?.warn?.("approval_exemption_grant_failed", { sessionId: pendingGrant.sessionId, toolName: pendingGrant.toolName, error: String(e).slice(0, 200) });
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
490
|
const replay = await decideIdempotentReplay(cs, {
|
|
491
491
|
sessionId,
|
|
492
492
|
out,
|
|
@@ -2,12 +2,14 @@ import { DEFAULT_EFFORT_LEVELS, expandTiers, routePairingStatus } from "@sema-ag
|
|
|
2
2
|
import { isModelAllowlisted } from "../../model-select.js";
|
|
3
3
|
import { resolveModelApiKey } from "../../key-resolver.js";
|
|
4
4
|
import { isSealedKeyPoison } from "../../sealed-key.js";
|
|
5
|
-
import { cwdHonored } from "../../task-cwd.js";
|
|
5
|
+
import { cwdHonored, deviceCwdHonored } from "../../task-cwd.js";
|
|
6
|
+
import { DEVICE_PROTOCOL_VERSION, DEVICE_WS_PATH } from "../../device-ws-protocol.js";
|
|
6
7
|
import { a2aInjectionHonored } from "../../task-a2a.js";
|
|
7
8
|
import { mcpInjectionHonored } from "../../task-mcp.js";
|
|
8
9
|
import { sendJson, sendError } from "../send.js";
|
|
9
10
|
import { resolveStreamApprovalGate } from "../../tool-approval.js";
|
|
10
11
|
import { projectMemoryEngineCapability } from "../../memory-posture.js";
|
|
12
|
+
import { workflowModelAllowlistFor } from "../../task-workflow.js";
|
|
11
13
|
import { centerEntitlementSourceWired } from "../../runtime-caps-resolver.js";
|
|
12
14
|
import { gatedPrincipal } from "../principal-gate.js";
|
|
13
15
|
function routePairingOf(deps, name, m) {
|
|
@@ -47,28 +49,28 @@ async function handleCapabilitiesBody(req, res, url, ctx, miss) {
|
|
|
47
49
|
artifacts: Boolean(deps.runStore),
|
|
48
50
|
approvals: Boolean(deps.checkpointStore),
|
|
49
51
|
sessions: Boolean(deps.sessionAudit),
|
|
52
|
+
deviceExecutor: deps.deviceHub
|
|
53
|
+
? { enabled: true, protocolVersion: DEVICE_PROTOCOL_VERSION, maxInflightPerDevice: deps.config.remoteExec?.provider === "device" ? (deps.config.remoteExec.maxInflightPerDevice ?? 4) : 4, wsPath: DEVICE_WS_PATH }
|
|
54
|
+
: false,
|
|
50
55
|
sessionEvents: Boolean(deps.sessionWatch && deps.sessionStorage?.getLeafId && deps.sessionStorage?.ownerOf),
|
|
51
56
|
fleet: deps.fleetBus
|
|
52
57
|
? { stream: true, sessionScope: true, observe: true, resume: "snapshot", bgNotifyFailClosed: true, steerPriority: "advisory", hookFailureNotice: true }
|
|
53
58
|
: false,
|
|
54
|
-
workspace:
|
|
55
|
-
const wfs = deps.fileSnapshotStore;
|
|
56
|
-
return wfs && typeof wfs.listKeys === "function" && typeof wfs.exportManifest === "function" && typeof wfs.getBlob === "function" && Boolean(deps.sessionStorage?.ownerOf)
|
|
57
|
-
? { browse: true, archive: true, maxFileBytes: deps.config.workspaceFileMaxBytes ?? 8 * 1024 * 1024 }
|
|
58
|
-
: false;
|
|
59
|
-
})(),
|
|
59
|
+
workspace: false,
|
|
60
60
|
leader: Boolean(deps.leaderEndpoint),
|
|
61
61
|
images: Boolean(deps.imageIndex),
|
|
62
62
|
memory: false,
|
|
63
63
|
memoryWrite: false,
|
|
64
64
|
memoryEngine: projectMemoryEngineCapability(deps.memoryPosture),
|
|
65
65
|
sessionBackgroundable: Boolean(deps.runStore),
|
|
66
|
+
runMemoryCaptureOptOut: Boolean(deps.runStore),
|
|
66
67
|
sharedMemory: Boolean(deps.sharedMemoryStore && deps.orgMemoryDirectory),
|
|
67
68
|
adoption: Boolean(deps.backend?.adoptionLog) && deps.config.operatorPrincipals.length > 0,
|
|
68
69
|
memoryBundle: Boolean(deps.memoryBundleExport && deps.memoryBundleImport) && deps.config.operatorPrincipals.length > 0,
|
|
69
70
|
memoryCompliance: Boolean(deps.memoryCompliance) && deps.config.operatorPrincipals.length > 0,
|
|
70
71
|
memoryOrigin: Boolean(deps.memoryOriginFace) && deps.config.operatorPrincipals.length > 0,
|
|
71
72
|
memoryConsolidationDriver: Boolean(deps.memoryConsolidation) && deps.config.operatorPrincipals.length > 0,
|
|
73
|
+
memoryOptOutGrant: Boolean(deps.memoryOptOutGrant) && deps.config.operatorPrincipals.length > 0,
|
|
72
74
|
outcomeLedger: Boolean(deps.outcomeSink?.summary) && (deps.config.requirePrincipal !== true || deps.config.operatorPrincipals.length > 0),
|
|
73
75
|
permissionRules: Boolean(deps.ruleConsent) && gatedPrincipal(req, deps.config) !== undefined,
|
|
74
76
|
permissionRulesRevoke: Boolean(deps.ruleConsent),
|
|
@@ -86,7 +88,7 @@ async function handleCapabilitiesBody(req, res, url, ctx, miss) {
|
|
|
86
88
|
scratchpadDir: true,
|
|
87
89
|
subagentSteer: Boolean(deps.subagentSteerRegistry) && Boolean(deps.runStore),
|
|
88
90
|
subagentResume: Boolean(deps.subagentSteerRegistry) && Boolean(deps.runStore),
|
|
89
|
-
taskSettings: { permissions: true, permissionMode: true, model: true, outputStyle: true, env: cwdHonored(deps.config), hooks: deps.config.requirePrincipal !== true },
|
|
91
|
+
taskSettings: { permissions: true, permissionMode: true, model: true, outputStyle: true, env: cwdHonored(deps.config) || deviceCwdHonored(deps.config), hooks: deps.config.requirePrincipal !== true },
|
|
90
92
|
modeShellGateTranslation: true,
|
|
91
93
|
permissionModeAuto: {
|
|
92
94
|
accepted: true,
|
|
@@ -103,6 +105,7 @@ async function handleCapabilitiesBody(req, res, url, ctx, miss) {
|
|
|
103
105
|
retainBackgroundProcesses: deps.config.requirePrincipal !== true,
|
|
104
106
|
interactiveTools: true,
|
|
105
107
|
projectContext: cwdHonored(deps.config),
|
|
108
|
+
callerCwd: cwdHonored(deps.config) || deviceCwdHonored(deps.config),
|
|
106
109
|
mcpInjection: mcpInjectionHonored(deps.config),
|
|
107
110
|
a2a: true,
|
|
108
111
|
a2aInjection: a2aInjectionHonored(deps.config),
|
|
@@ -130,15 +133,28 @@ async function handleCapabilitiesBody(req, res, url, ctx, miss) {
|
|
|
130
133
|
resumeAt: Boolean(deps.resumeAnchorStore && deps.sessionStorage?.getLeafId),
|
|
131
134
|
promptSuggestions: true,
|
|
132
135
|
sessionPolicy: Boolean(deps.sessionPolicyStore),
|
|
133
|
-
rewindFiles: Boolean(deps.
|
|
134
|
-
|
|
136
|
+
rewindFiles: Boolean(deps.fileHistoryStore),
|
|
137
|
+
restoreFiles: Boolean(deps.fileHistoryStore),
|
|
138
|
+
rewindFilesTo: Boolean(deps.fileHistoryStore && deps.resumeAnchorStore && deps.sessionStorage?.getLeafId),
|
|
135
139
|
scheduler: Boolean(deps.config.schedulerEnabled && deps.config.requirePrincipal !== true && deps.config.remoteExec?.provider === "host"),
|
|
136
|
-
sessionSync: Boolean(deps.backend && deps.sessionStorage?.exportEntries && deps.sessionStorage?.beginImportStaging && deps.
|
|
140
|
+
sessionSync: Boolean(deps.backend && deps.sessionStorage?.exportEntries && deps.sessionStorage?.beginImportStaging && deps.fileHistoryStore),
|
|
137
141
|
sendUserFile: Boolean(deps.sendUserFile && deps.config.sendUserFile?.publicEndpoint),
|
|
138
142
|
s3PublicEndpoint: deps.config.sendUserFile?.publicEndpoint ?? null,
|
|
139
143
|
sendUserFileLedger: Boolean(deps.sendFileLedger),
|
|
140
144
|
workflows: deps.workflowsCapable ?? Boolean(deps.workflowRunStore),
|
|
141
145
|
workflowsList: Boolean(deps.workflowRunStore),
|
|
146
|
+
workflowModels: (() => {
|
|
147
|
+
const allow = deps.workflowModelAllowlist
|
|
148
|
+
?? workflowModelAllowlistFor({
|
|
149
|
+
selfOrchestrationModels: deps.config.selfOrchestrationModels ?? [],
|
|
150
|
+
requirePrincipal: deps.config.requirePrincipal,
|
|
151
|
+
models: deps.config.models ?? {},
|
|
152
|
+
})
|
|
153
|
+
?? [];
|
|
154
|
+
const bare = deps.config.models ?? {};
|
|
155
|
+
const live = expandTiers(bare, deps.config.tiers ?? {}) ?? bare;
|
|
156
|
+
return allow.filter((n) => Object.hasOwn(live, n));
|
|
157
|
+
})(),
|
|
142
158
|
manualCompact: Boolean(deps.runStore),
|
|
143
159
|
});
|
|
144
160
|
return;
|
|
@@ -91,7 +91,7 @@ export declare function assertStaticWiringConsistent(facts: StaticWiringFacts, l
|
|
|
91
91
|
* 走认证(全局门),不进本臂。
|
|
92
92
|
*
|
|
93
93
|
* 判源=TCP 对端地址(`req.socket.remoteAddress`),**非任何头**——XFF 类头在无反代的 turnkey 形上本就
|
|
94
|
-
*
|
|
94
|
+
* 是自造面;有反代的部署必然配 token(反代后 remoteAddress 恒 loopback,门自然放行,语义仍对:该形的
|
|
95
95
|
* 边界由反代+token 承担)。`remoteAddress` 缺席(socket 已断等边缘)⇒ 判拒(fail-closed,安全轴方向)。
|
|
96
96
|
*/
|
|
97
97
|
export declare function zeroCredentialLoopbackDenied(remoteAddress: string | undefined, config: {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* design/158 A9 域模块 —— v2 leader 端点(design/50)。
|
|
3
3
|
*
|
|
4
4
|
* 路由:`POST /v1/leader`(异步,形同 `/v1/runs`)· `GET /v1/leader/:id`。整域由 `deps.leaderEndpoint`
|
|
5
|
-
* 的存在与否开关;身份层与 `/v1/runs` 同款(BL-4
|
|
5
|
+
* 的存在与否开关;身份层与 `/v1/runs` 同款(BL-4:此前整条路跳过 authorize/requirePrincipal 且不记 owner,
|
|
6
6
|
* 任何持服务令牌者能提交/读任意租户的 leader run),owner 用 crypto 验证过的 `gatedPrincipal`。本域零可变状态。
|
|
7
7
|
*/
|
|
8
8
|
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
* · 记忆引擎整个没接线(`MEMORY_ENGINE=off` / 多租 file 底座等暗态);
|
|
28
28
|
* · 引擎接了但后端没有 bundle 复合面(pg/tidb 孪生)—— 这一支在**挂载期**就判掉了
|
|
29
29
|
* (`createMemoryBundleFaces` 返回 undefined ⇒ 两口整个不挂),能力位 `memoryBundle` 因此与「路由真能用」
|
|
30
|
-
* 严格同真。🔴 首版把它当运行期事实(照常挂载、让 core 每次抛 409/422),被 codex
|
|
30
|
+
* 严格同真。🔴 首版把它当运行期事实(照常挂载、让 core 每次抛 409/422),被 codex 交叉复审驳倒并改此形:
|
|
31
31
|
* 面在不在是一次**属性检查**、boot 期判得出、且是**永久**缺席 ⇒ 照常挂着就是一个恒假的 yes,
|
|
32
32
|
* 壳会据此给用户开出一条走不通的迁移流程。
|
|
33
33
|
* ⚠️ 与**运行期**拒别混:后端**有**复合面但托管链 chain-degraded 时,core 照样抛
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { sendJson, sendError } from "../send.js";
|
|
3
|
+
import { buildOriginFence, readOriginAware } from "../../memory-origin-fence.js";
|
|
3
4
|
import { gatedPrincipal, explicitOperatorOk } from "../principal-gate.js";
|
|
4
5
|
export const MEMORY_BUNDLE_EXPORT_PATH = "/v1/memory/export";
|
|
5
6
|
export const MEMORY_BUNDLE_IMPORT_PATH = "/v1/memory/import";
|
|
@@ -93,7 +94,8 @@ async function handleMemoryBundleBody(req, res, url, ctx, miss) {
|
|
|
93
94
|
}
|
|
94
95
|
try {
|
|
95
96
|
const bundle = await engineExport(parsed.data.scopes);
|
|
96
|
-
|
|
97
|
+
const fence = buildOriginFence(bundle.entries, readOriginAware(new URL(req.url ?? "", "http://x").searchParams));
|
|
98
|
+
sendJson(res, 200, fence.withheldOriginTagged !== undefined ? { ...bundle, entries: fence.entries, withheldOriginTagged: fence.withheldOriginTagged } : bundle);
|
|
97
99
|
}
|
|
98
100
|
catch (err) {
|
|
99
101
|
if (!sentClassifiedFailure(res, ctx, "export", err))
|