@sema-agent/server 7.51.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/engine-lease.d.ts +1 -1
- package/dist/boot/execution-env.d.ts +1 -1
- 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 +12 -0
- package/dist/boot/resolve-spec.js +29 -7
- 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 +1 -1
- package/dist/boot/session-faces.js +14 -3
- package/dist/boot/stores.js +31 -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-types.d.ts +78 -18
- package/dist/config.js +45 -10
- package/dist/deployment-governance.d.ts +1 -1
- package/dist/device-enrollment.d.ts +2 -2
- package/dist/device-store.d.ts +3 -3
- package/dist/device-ws-protocol.d.ts +2 -2
- package/dist/env-facts.d.ts +1 -1
- package/dist/execution-lane-caps.d.ts +1 -1
- 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 +20 -9
- 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 +35 -13
- package/dist/http/server.js +105 -12
- 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/main.js +13 -6
- 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 +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/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 +1 -1
- package/dist/plugins/remote-env-k8s.d.ts +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 +59 -29
- package/dist/plugins/store-backend.js +75 -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 +1 -1
- package/dist/task-mcp.d.ts +3 -3
- package/dist/task-settings.d.ts +3 -3
- 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
|
@@ -15,7 +15,7 @@ import { type TaskAttachmentStore } from "../plugins/task-attachment-store.js";
|
|
|
15
15
|
* ── 为什么围栏不是可选的(codex R1-F1,判真)────────────────────────────────────────────────────
|
|
16
16
|
* 这两张表只按 `sessionId` 键控。在 host lane 上那是安全的:那条车道的闸带 `requirePrincipal !== true`,
|
|
17
17
|
* 整台机器就一个用户。**device lane 把这个前提撤掉了** —— 它的闸(`deviceCwdHonored`)刻意不要求单用户
|
|
18
|
-
* (员工各连各的设备)
|
|
18
|
+
* (员工各连各的设备)。于是一条真实的超范围路径出现了:
|
|
19
19
|
* ① sessionId 由**调用方自选**,而且 `DELETE /v1/sessions/:id` 之后可以被**别人** `register` 重新登记
|
|
20
20
|
* (`boot/session-faces.ts` 的化身围栏注逐字写着这件事);
|
|
21
21
|
* ② 会话删除的级联删的是库里的行,**够不着这两张进程内的表**;
|
|
@@ -75,7 +75,7 @@ export interface GovernanceSeamsCtx {
|
|
|
75
75
|
* #270 车1 —— **本 build 是否真的接了留存执行器**(sweep lane;车2 的 `startRetentionLane()`)。
|
|
76
76
|
* 缺席 = `false`。
|
|
77
77
|
*
|
|
78
|
-
* 🔴 为什么这一位必须存在(codex
|
|
78
|
+
* 🔴 为什么这一位必须存在(codex 交叉复审 R2-[critical],验真后修):core 的
|
|
79
79
|
* `assertRetentionCapability` 只读**店的声明位**。#270 车1 让三只 SQL 店如实声明了 `"managed"`
|
|
80
80
|
* (它们的行确实由托管留存删),于是那道门从此**放行** locked policy —— 可执行器还在车2 手里。
|
|
81
81
|
* 两者之间的窗口如果什么都不做,后果正是本仓最忌的那种:部署自述「策略已受管」、审计与能力面
|
|
@@ -96,7 +96,7 @@ export declare function assertLockAssemblable(input: {
|
|
|
96
96
|
deploymentMcpConfigured: boolean;
|
|
97
97
|
}): void;
|
|
98
98
|
/**
|
|
99
|
-
* 治理面的**装配相容性**总判据(codex
|
|
99
|
+
* 治理面的**装配相容性**总判据(codex 交叉复审 R2-F2 起扩面)——锁与合规档位在这条轴上是同一件事:
|
|
100
100
|
* 两者都可能把「本部署自己的装配」判成 core 门口的违规,而那不是「配得更严」,是**这台从此每条腿必失败**。
|
|
101
101
|
*
|
|
102
102
|
* 合规半场的判据来自亲核 core 的 prepare 门(`prepare-task` 的 compliance 段):被否决的能力若**已在
|
package/dist/boot/leader.d.ts
CHANGED
|
@@ -40,7 +40,7 @@ export interface LeaderCtx {
|
|
|
40
40
|
*/
|
|
41
41
|
export declare function leaderK8sMinioGap(leaderEnabled: boolean, leaderProvider: string | undefined, hasS3: boolean): string[] | null;
|
|
42
42
|
/**
|
|
43
|
-
* #193 车4 件2 的**能力面**门(codex
|
|
43
|
+
* #193 车4 件2 的**能力面**门(codex 交叉复审 R1-high①,验真后修)。
|
|
44
44
|
*
|
|
45
45
|
* config 层的门②判的是 `DB_BACKEND` 的字面值 —— 那句话回答的是「运维要没要 durable」。它回答不了
|
|
46
46
|
* 「这次启动**真的拿到**了 durable 吗」:`openStoreBackendWithFallback` 在 `SESSION_BACKEND=auto`
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* #214 记忆边界不变式(板 [3492]② 立案,[3521] 裁1 与 core #151 同窗)—— 启动期把「结构性写不进的记忆
|
|
3
3
|
* 部署形」说出来。
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* 根本问题(test 仓 [3479] 实测,[3490]② 定位):core 的记忆工具面是 `memory_search`/`memory_get`/
|
|
6
|
+
* `memory_index`(#493 第五单起第三只,枚举面,仍只读)三只**只读**工具;**写**记忆没有专用工具 —— 模型用 fs 工具往记忆根写文件,harvest 再从那里收编。于是整条链的成立
|
|
7
7
|
* 条件是「记忆根落在该次任务的 fs 授权边界之内」。server 把根交给 core(`RunnerDeps.memoryEngineDir`)
|
|
8
8
|
* 之后,没有任何一处保证这一点,也没有任何一处说过「这台部署的记忆写面够不着」。默认根是
|
|
9
9
|
* `~/.ai-agent`(或 `AGENT_DATA_DIR`),默认围栏是任务 cwd —— 两者天然不相交:用户说「记住 X」,模型照
|
|
@@ -31,7 +31,7 @@ export interface ConsolidationDriverSeat {
|
|
|
31
31
|
*/
|
|
32
32
|
export declare function resolveConsolidationDriverSeat(deps: MemoryConsolidationDriverDeps): ConsolidationDriverSeat;
|
|
33
33
|
/**
|
|
34
|
-
* **每 scope 单飞**(codex
|
|
34
|
+
* **每 scope 单飞**(codex 交叉复审 [high],验真后修)—— 同一 scope 上在飞的那一轮被后来者**并入**,
|
|
35
35
|
* 而不是各起一轮。`create*`:返回带状态的活对象。
|
|
36
36
|
*
|
|
37
37
|
* ## 病(不是理论)
|
|
@@ -47,7 +47,7 @@ export declare function resolveConsolidationDriverSeat(deps: MemoryConsolidation
|
|
|
47
47
|
* 本仓没有 —— 同 §遗留 遗-1 的那条基建缺口)。今天够得着这条阀门的部署形态是 file 记忆后端,那种部署
|
|
48
48
|
* 实际上是单副本,所以进程内单飞覆盖了真实的失败形;但话按**它真正保证的**说,不按它常常够用说。
|
|
49
49
|
*
|
|
50
|
-
* 单飞**不是缓存**:那一轮落定(无论成败)即刻放行下一轮 —— 否则一次失败会把这个 scope
|
|
50
|
+
* 单飞**不是缓存**:那一轮落定(无论成败)即刻放行下一轮 —— 否则一次失败会把这个 scope 永久卡住。
|
|
51
51
|
*/
|
|
52
52
|
export declare function createPerScopeSingleFlight<T>(): (scope: string, run: () => Promise<T>) => Promise<T>;
|
|
53
53
|
/**
|
|
@@ -80,7 +80,7 @@ export declare function assertConsolidationDriverWirable(input: {
|
|
|
80
80
|
provenance?: "off" | "carry";
|
|
81
81
|
}): void;
|
|
82
82
|
/**
|
|
83
|
-
* 阀门上了场之后的**可达性**告警两条(自查 + codex
|
|
83
|
+
* 阀门上了场之后的**可达性**告警两条(自查 + codex 交叉复审;姿态=warn 不拒启)。
|
|
84
84
|
*
|
|
85
85
|
* ## 病(结构性,而且**只在**这条阀门够得着的那种部署上成立)
|
|
86
86
|
*
|
|
@@ -114,11 +114,11 @@ export declare function buildConsolidationValveAudit(input: {
|
|
|
114
114
|
}>;
|
|
115
115
|
};
|
|
116
116
|
/**
|
|
117
|
-
* 停因诊断行的**运维日志**投影(codex
|
|
117
|
+
* 停因诊断行的**运维日志**投影(codex 交叉复审 R2-[medium],验真后修)。`build*`:纯数据。
|
|
118
118
|
*
|
|
119
119
|
* `stopDetail` 已经不上 wire(`routes/memory-consolidation.ts` 的同名段:core 的 `driver_failed` 支把
|
|
120
120
|
* 模型座抛出的 `Error.message` 逐字拼进去)。但**落日志同样要有信任边界** —— 集中式日志是人读的,
|
|
121
|
-
*
|
|
121
|
+
* 而一段来路不明的文本混在自家诊断里,既可能夹带凭据,也可能把不当调用方写的"操作建议"摆成本服务的口吻。
|
|
122
122
|
* 三件:
|
|
123
123
|
* ① 字段名 `untrustedDetail` **自陈**(一个叫 `detail` 的键会被下一个读日志的人当成本服务自己的诊断);
|
|
124
124
|
* ② `redactSecrets` 脱敏(与审批卡片面同一只属主函数,不在本层另写一份模式表);
|
|
@@ -159,7 +159,7 @@ export interface MemoryConsolidationFaces {
|
|
|
159
159
|
*
|
|
160
160
|
* 本仓**没有**一个长命的 `MemoryEngine` 实例:`boot/stores.ts` 装配出来的 `memoryEngine` 是
|
|
161
161
|
* `{ backend, root }` 二元组,真引擎由 core 的 Runner **每任务现构**。HTTP 面要一个引擎就得自己构。
|
|
162
|
-
*
|
|
162
|
+
* 两只引擎不会各说各话:控制面由后端写死(`backend.controlPlaneRoot`),gate / run 账 / plan 归档
|
|
163
163
|
* 全住在那里,所以操作面引擎与每任务引擎看的是**同一本**账。
|
|
164
164
|
*
|
|
165
165
|
* ## `consolidation: {}` = 出厂缺省,**显式在场**
|
|
@@ -35,7 +35,7 @@ export interface OrgMemoryAdmissionWiring {
|
|
|
35
35
|
* 🔴 A-057.40:这一席**故意**留快照,不跟 `config.projects` 的热应用走,理由是 core 根本不优先吃它:
|
|
36
36
|
* 本仓每个请求都在 `boot/resolve-spec.ts` 现读 `config.projects[...].defaultScopes`(热加的项目当场
|
|
37
37
|
* 进 spec),并在 `memory-scope.ts` 按 `originPolicy.multiTenant` 给每个 `org:` 键**盖章**;core 的
|
|
38
|
-
* `memory-admission` 先看盖章、只有没盖章时才查这张表 ⇒ 单用户部署下热注册项目的 org
|
|
38
|
+
* `memory-admission` 先看盖章、只有没盖章时才查这张表 ⇒ 单用户部署下热注册项目的 org 键恒被覆盖为
|
|
39
39
|
* `deployment`,这张表陈旧只会让 `governed` / `orgGovernedProvenance` 两个布尔偏保守,**不产生拒绝**。
|
|
40
40
|
* 需要跟着热应用走的是另一个消费点(共享记忆读面)—— 见 {@link deploymentMemoryScopesLive}。
|
|
41
41
|
*/
|
|
@@ -23,7 +23,7 @@ export interface ParkedReviveGateDeps {
|
|
|
23
23
|
* 部署级活体审批席 —— `RunnerDeps.onAsk` 的**同源铸法**(main.ts 递 `createRunnerDepsOnAsk(toolApproval)`,
|
|
24
24
|
* 单一属主同 boot/runner-deps.ts)。
|
|
25
25
|
*
|
|
26
|
-
* ⚠️ **本仓确有 per-task `spec.onAsk` 装配点**(codex
|
|
26
|
+
* ⚠️ **本仓确有 per-task `spec.onAsk` 装配点**(codex 交叉复审 R1-中1 验真纠正 —— 别照抄
|
|
27
27
|
* `createRunnerDepsOnAsk` 头注那句「bg/resume 两条腿没有 per-task 装配点」,那句话的射程只是那两条腿):
|
|
28
28
|
* `http/routes/tasks.ts` 的宿主 sync/stream 腿在装配点写 `spec.onAsk = toolApproval.boundAsk({owner,
|
|
29
29
|
* taskId, sessionId, legKey…})`(windowZero 形则写一个恒返 `"unavailable"` 的闭包)。core 冻的是
|
|
@@ -72,7 +72,7 @@ export interface ParkedReviveGateDeps {
|
|
|
72
72
|
/**
|
|
73
73
|
* core 1.396 的父约束席位形(`parkedResume.inheritedGate`)—— 从**载体自己的签名位推导**,绝不手写。
|
|
74
74
|
*
|
|
75
|
-
* 🔴 手写这个形状会**藏住轴**(codex
|
|
75
|
+
* 🔴 手写这个形状会**藏住轴**(codex 交叉复审 R1-高2 的真回归):第一版在这里手抄了一个只有
|
|
76
76
|
* `parentConstraints` 的接口,于是 core 载体上那个 `shellGate` 槽在类型层面根本看不见,「shellGate 轴
|
|
77
77
|
* 也要交回」这件事就无声地漏了一整刀。推导形让「core 又加了一条能收紧的轴」变成本仓的编译期/钉子面
|
|
78
78
|
* 事件(载体键集钉见 test/parked-revive-gate-wiring.test.ts)。
|
|
@@ -124,7 +124,7 @@ export type RebuiltParentConstraint = NonNullable<RebuiltInheritedGate["parentCo
|
|
|
124
124
|
* (test/parked-revive-e2e.test.ts);真 settings→park→赎回的端到端钉未建(候件,随收口件一起)。
|
|
125
125
|
*/
|
|
126
126
|
/**
|
|
127
|
-
* 🔴 A-057.44 第二半(codex
|
|
127
|
+
* 🔴 A-057.44 第二半(codex 交叉复审 medium,验真后采纳)—— 席位多收一位**权威 principal**。
|
|
128
128
|
*
|
|
129
129
|
* 为什么不能只看 `row.scope`:`principal ?? "default"` 这套约定在那一列上是**有损**的(匿名与一个真名叫
|
|
130
130
|
* `default` 的租户同形),而匿名别名匹配(见 `parked-decide.ts` 的 `backgroundScopesForCheckpointScope`)
|
package/dist/boot/reapers.d.ts
CHANGED
|
@@ -69,7 +69,7 @@ export interface ReapersCtx {
|
|
|
69
69
|
rateLimiter: RateLimiter | RateLimiterStore | undefined;
|
|
70
70
|
costQuota: CostQuota | CostQuotaStore | undefined;
|
|
71
71
|
toolResultStore: ToolResultStoreFull | undefined;
|
|
72
|
-
|
|
72
|
+
fileHistoryStore: ReturnType<StoreBackend["fileHistory"]> | undefined;
|
|
73
73
|
taskAttachmentStore: TaskAttachmentStore | undefined;
|
|
74
74
|
imageBakes: ImageBake | undefined;
|
|
75
75
|
worktreeReap: (() => Promise<void>) | undefined;
|
|
@@ -154,7 +154,7 @@ interface ReapSessionsInputs {
|
|
|
154
154
|
* 的 id 会回落 transient(进程内 no-op),那会让 core 数出一次**从未发生**的 release
|
|
155
155
|
* (`orphanPlacedReleased` 当场变成谎)而字节还在库里。故先按**持久化元组**判(一次 PK 探针),
|
|
156
156
|
* placed 走 host 店的真删除;其余 id 原样保留 [1522] 裁定的双店语义。
|
|
157
|
-
* · 🔴 探针本身失败 ⇒ **响亮抛**(codex
|
|
157
|
+
* · 🔴 探针本身失败 ⇒ **响亮抛**(codex 交叉复审 R1-[medium],验真后修:本函数的初版把探针错误
|
|
158
158
|
* 改写成 `undefined` 再落路由店 —— 而重启后路由店不认识 placed id ⇒ transient no-op,core 却因为
|
|
159
159
|
* release 正常 resolve 而 `orphanPlacedReleased++`。间歇性 DB 故障于是被**伪装成 GC 成功**:监控
|
|
160
160
|
* 报着「收掉了 N 条孤儿」,durable 字节一条没动。这正是本函数顶注要防的那个形,初版自己踩了。
|
package/dist/boot/reapers.js
CHANGED
|
@@ -56,7 +56,7 @@ export function createPlacementAwareReapSessions(deps) {
|
|
|
56
56
|
};
|
|
57
57
|
}
|
|
58
58
|
export function startReapers(ctx) {
|
|
59
|
-
const { config, logger, metrics, localRoot, backend, subRunner, runStore, checkpointStore, rateLimiter, costQuota, toolResultStore,
|
|
59
|
+
const { config, logger, metrics, localRoot, backend, subRunner, runStore, checkpointStore, rateLimiter, costQuota, toolResultStore, fileHistoryStore, taskAttachmentStore, imageBakes, worktreeReap, workflowNotifyGate, workflowRecoverOpts, workflowJournalStore, sqlWorkflowRunStore, workflowNotifyJournal, rosterStore, backgroundAgentStore, mailboxStore, toolApproval, permissionRuleStores, getRunDenySweep, } = ctx;
|
|
60
60
|
const leg = (p) => {
|
|
61
61
|
if (p !== undefined)
|
|
62
62
|
trackMaintenanceLeg(p);
|
|
@@ -85,7 +85,8 @@ export function startReapers(ctx) {
|
|
|
85
85
|
const runsReapSuspendedGuard = createThrottledReaperCatch("runs_reap_suspended", logger);
|
|
86
86
|
const checkpointReapCtxGuard = createThrottledReaperCatch("checkpoint_reap_ctx", logger);
|
|
87
87
|
const toolResultReapOlderThanGuard = createThrottledReaperCatch("tool_result_reap_older_than", logger);
|
|
88
|
-
const
|
|
88
|
+
const fileHistorySweepOrphanBlobsGuard = createThrottledReaperCatch("file_history_sweep_orphan_blobs", logger);
|
|
89
|
+
const legacySnapshotBlobSweepGuard = createThrottledReaperCatch("legacy_snapshot_blob_sweep", logger);
|
|
89
90
|
const attachmentReapUnboundGuard = createThrottledReaperCatch("attachment_reap_unbound", logger);
|
|
90
91
|
const sessionSweepStagingGuard = createThrottledReaperCatch("session_sweep_staging", logger);
|
|
91
92
|
const imageBakesReapStaleGuard = createThrottledReaperCatch("image_bakes_reap_stale", logger);
|
|
@@ -100,6 +101,8 @@ export function startReapers(ctx) {
|
|
|
100
101
|
const leaderRunStore = config.leaderEnabled ? backend?.leaderRun?.() : undefined;
|
|
101
102
|
const scratchpadSweepStaleGuard = createThrottledReaperCatch("scratchpad_sweep_stale", logger);
|
|
102
103
|
const approvalReconcileGuard = createThrottledReaperCatch("approval_reconcile", logger);
|
|
104
|
+
const approvalSuspendedPollGuard = createThrottledReaperCatch("approval_suspended_poll", logger);
|
|
105
|
+
let approvalSuspendedPollInFlight = false;
|
|
103
106
|
const permissionRuleReapGuard = createThrottledReaperCatch("permission_rule_reap_expired", logger);
|
|
104
107
|
let permissionRuleReapInFlight = false;
|
|
105
108
|
let approvalReconcileInFlight = false;
|
|
@@ -220,9 +223,12 @@ export function startReapers(ctx) {
|
|
|
220
223
|
leg(toolResultStore
|
|
221
224
|
?.reapOlderThan?.(Date.now() - config.toolResultTtlSec * 1000)
|
|
222
225
|
?.then(() => toolResultReapOlderThanGuard.onSuccess(), toolResultReapOlderThanGuard.onError));
|
|
223
|
-
leg(
|
|
226
|
+
leg(fileHistoryStore
|
|
224
227
|
?.sweepOrphanBlobs?.()
|
|
225
|
-
.then(() =>
|
|
228
|
+
.then(() => fileHistorySweepOrphanBlobsGuard.onSuccess(), fileHistorySweepOrphanBlobsGuard.onError));
|
|
229
|
+
leg(backend?.legacySnapshotBlobSweep?.()
|
|
230
|
+
.then(reapCount("legacy_snapshot_blobs_swept_total", {}))
|
|
231
|
+
.then(() => legacySnapshotBlobSweepGuard.onSuccess(), legacySnapshotBlobSweepGuard.onError));
|
|
226
232
|
leg(taskAttachmentStore
|
|
227
233
|
?.reapUnbound(Date.now() - config.attachmentUnboundTtlMs)
|
|
228
234
|
.then(reapCount("attachments_reaped_total", {}))
|
|
@@ -295,6 +301,13 @@ export function startReapers(ctx) {
|
|
|
295
301
|
.then(() => approvalReconcileGuard.onSuccess(), approvalReconcileGuard.onError)
|
|
296
302
|
.finally(() => (approvalReconcileInFlight = false)));
|
|
297
303
|
}
|
|
304
|
+
if (toolApproval && !approvalSuspendedPollInFlight) {
|
|
305
|
+
approvalSuspendedPollInFlight = true;
|
|
306
|
+
leg(toolApproval
|
|
307
|
+
.pollSuspendedDecisions()
|
|
308
|
+
.then(() => approvalSuspendedPollGuard.onSuccess(), approvalSuspendedPollGuard.onError)
|
|
309
|
+
.finally(() => (approvalSuspendedPollInFlight = false)));
|
|
310
|
+
}
|
|
298
311
|
if (!permissionRuleReapInFlight) {
|
|
299
312
|
permissionRuleReapInFlight = true;
|
|
300
313
|
leg(permissionRuleStores
|
|
@@ -18,6 +18,7 @@ import type { StoreBackend } from "../plugins/store-backend.js";
|
|
|
18
18
|
import { type TaskAttachmentStore } from "../plugins/task-attachment-store.js";
|
|
19
19
|
import { type createPrincipalEntitlementsClient } from "../runtime-caps-resolver.js";
|
|
20
20
|
import { type OwnerAwareSessionStore } from "../security.js";
|
|
21
|
+
import type { RunnerDepsOnAsk } from "./runner-deps.js";
|
|
21
22
|
type PrincipalCaps = ReturnType<typeof createPrincipalEntitlementsClient>;
|
|
22
23
|
/** `resolveSpec` 原先从 `main()` 闭包里拿到的全部 boot 局部量。 */
|
|
23
24
|
export interface ResolveSpecCtx {
|
|
@@ -68,6 +69,17 @@ export interface ResolveSpecCtx {
|
|
|
68
69
|
* ASK_QUESTION_ENABLED)时 durable question 门按活流上下文分腿、spec 不再 stamp QUESTION_AWAITS_RESUME
|
|
69
70
|
* (否则 spec.onQuestion 恒遮蔽 RunnerDeps.onQuestion 的活人腿);缺席时行为与旧形逐字一致。 */
|
|
70
71
|
liveQuestionFace: LiveQuestionFace | undefined;
|
|
72
|
+
/**
|
|
73
|
+
* S-46 件C —— 部署级**活体审批席**(`RunnerDeps.onAsk` 的同源铸法,main.ts 递
|
|
74
|
+
* `createRunnerDepsOnAsk(toolApproval)`;单一属主同 `boot/runner-deps.ts`,与 `parked-revive-gate.ts`
|
|
75
|
+
* 的 `approverSeat` 是同一格)。
|
|
76
|
+
*
|
|
77
|
+
* 本域**只**用于逐腿 `interactionPosture` 判据(见下方 `declaresInteractivePosture`),不参与任何
|
|
78
|
+
* 装配 —— spec 上的 per-task `onAsk` 由 `http/routes/tasks.ts` 在 resolveSpec **之后**写(bound 席),
|
|
79
|
+
* 而 core 的 posture 门读的是 `spec.onAsk ?? deps.onAsk`,两个装配点是**同一个条件**的两种表达
|
|
80
|
+
* (spec 位只在 `deps.toolApproval` 在场时才写,且写的也是函数)⇒ 拿 deps 位判「席位形」恒等。
|
|
81
|
+
*/
|
|
82
|
+
approverSeat: RunnerDepsOnAsk | undefined;
|
|
71
83
|
approvalExemptionStore: ReturnType<StoreBackend["approvalExemption"]> | undefined;
|
|
72
84
|
singleUserAutoAcceptBaseline: boolean;
|
|
73
85
|
checkpointStore: ReturnType<NonNullable<StoreBackend["checkpoint"]>> | undefined;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { realpathSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
-
import { NodeExecutionEnv, QUESTION_AWAITS_RESUME, expandTiers, tightenTaskSpec } from "@sema-agent/core";
|
|
3
|
+
import { NodeExecutionEnv, QUESTION_AWAITS_RESUME, deriveAskEffective, expandTiers, resolveAskSeamForm, tightenTaskSpec } from "@sema-agent/core";
|
|
4
4
|
import { cappedCeiling } from "../budget.js";
|
|
5
5
|
import { centerPromptProvider, centerIdentityAssembled } from "../capabilities/center-prompts.js";
|
|
6
6
|
import { SessionEnvironmentSelection, selectEnvironmentTool } from "../capabilities/select-environment-tool.js";
|
|
@@ -13,6 +13,7 @@ import { assertGuardPatternsUsable, buildOnlySensitiveBaselineWarning, createApp
|
|
|
13
13
|
import { acceptShellScratchpadDir, buildEnvFacts, egressForRemoteExec, ensureScratchpadDir, resumeFactsForLane } from "../env-facts.js";
|
|
14
14
|
import { FleetEventBus } from "../fleet/fleet-bus.js";
|
|
15
15
|
import { composeHooks, createTaskHooks } from "../hooks/hook-runner.js";
|
|
16
|
+
import { headerStr } from "../http/principal-gate.js";
|
|
16
17
|
import { explicitOperatorOk } from "../http/server.js";
|
|
17
18
|
import { isModelAllowlisted, matchCatalogModel, modelSupportsImages, resolveTaskModel, terminalCatalogName } from "../model-select.js";
|
|
18
19
|
import { PerTaskImageRegistry, resolveSandboxImageRef } from "../per-task-image.js";
|
|
@@ -35,21 +36,25 @@ import { redactSecrets } from "../trace/redact.js";
|
|
|
35
36
|
import { DeferredSandboxPathEnv, isSandboxPathAdjudicationLane, sandboxPathEnvSlots } from "./deferred-sandbox-path-env.js";
|
|
36
37
|
import { effectiveMemoryPersistenceCapable } from "./memory-boundary.js";
|
|
37
38
|
export function createResolveSpec(ctx) {
|
|
38
|
-
const { config, logger, metrics, localRoot, scenarios, principalCaps, centerRuntimeCapsResolver, handsLanes, getCenterPrompts, getKeyResolver, taskAttachmentStore, perSessionCwd, setSessionCwd, setSessionShellEnv, fenceSessionOwner, hookLlm, hookAgent, fleetBus, hookWakeBus, resumeAnchorStore, ownerAware, taskLimitCaps, taskTimeoutSec, selectEnvTool, sendUserFileToolSpec, memoryEngine, durableEnabled, approvalExemptionStore, singleUserAutoAcceptBaseline, checkpointStore, deploymentHooks, imageIndex, perTaskImage, sessionEnvSelection, liveQuestionFace, lockedKeys, } = ctx;
|
|
39
|
+
const { config, logger, metrics, localRoot, scenarios, principalCaps, centerRuntimeCapsResolver, handsLanes, getCenterPrompts, getKeyResolver, taskAttachmentStore, perSessionCwd, setSessionCwd, setSessionShellEnv, fenceSessionOwner, hookLlm, hookAgent, fleetBus, hookWakeBus, resumeAnchorStore, ownerAware, taskLimitCaps, taskTimeoutSec, selectEnvTool, sendUserFileToolSpec, memoryEngine, durableEnabled, approvalExemptionStore, singleUserAutoAcceptBaseline, checkpointStore, deploymentHooks, imageIndex, perTaskImage, sessionEnvSelection, liveQuestionFace, approverSeat, lockedKeys, } = ctx;
|
|
39
40
|
assertGuardPatternsUsable(config);
|
|
40
41
|
const onlySensitiveBaseline = buildOnlySensitiveBaselineWarning(config, { durableEnabled, singleUserAutoAcceptBaseline });
|
|
41
42
|
if (onlySensitiveBaseline)
|
|
42
43
|
logger.warn(onlySensitiveBaseline.event, onlySensitiveBaseline.fields);
|
|
43
|
-
const resolveSpec = async (body,
|
|
44
|
+
const resolveSpec = async (body, req, auth, opts) => {
|
|
44
45
|
assertRequestMcpUnlocked(body.mcpServers, lockedKeys);
|
|
45
46
|
if (opts?.leg === "fresh")
|
|
46
47
|
assertRequestMcpContentOrigin(body.mcpServers);
|
|
48
|
+
const rawMemoryCapture = body.memoryCapture;
|
|
49
|
+
if (rawMemoryCapture !== undefined && rawMemoryCapture !== "off") {
|
|
50
|
+
throw new HttpError(400, "memoryCapture must be the string 'off' when present (the session-level memory-capture opt-out declaration; absent = capture as usual — there is no 'on' spelling)", { code: "request.field_invalid" });
|
|
51
|
+
}
|
|
47
52
|
assertRequestA2aUnlocked(body.a2aPeers, lockedKeys);
|
|
48
53
|
const gated = await gateScenarioAndAppend(body, auth, opts);
|
|
49
54
|
const effMode = effectivePermissionMode(body, gated.parsedSettings.settings);
|
|
50
55
|
const lane = bindSettingsCwdEnvAndModel(body, auth, gated, effMode, opts);
|
|
51
56
|
const anchors = await resolveHistoryAnchors(body, auth);
|
|
52
|
-
const spec = assembleSpecLiteral(body, auth, opts, { ...gated, ...lane, ...anchors }, effMode);
|
|
57
|
+
const spec = assembleSpecLiteral(body, auth, req, opts, { ...gated, ...lane, ...anchors }, effMode);
|
|
53
58
|
const folded = await foldGovernanceAndSettings(body, auth, spec, gated, effMode);
|
|
54
59
|
const final = await applyImageFactsAndRouting(body, auth, folded.governed, {
|
|
55
60
|
scenarioName: gated.scenarioName,
|
|
@@ -228,7 +233,21 @@ export function createResolveSpec(ctx) {
|
|
|
228
233
|
const s4DefaultScopes = s4ProjectId ? config.projects[s4ProjectId]?.defaultScopes : undefined;
|
|
229
234
|
return { resumeAtEntryId, rewindFilesToEntryId, s4DefaultScopes };
|
|
230
235
|
};
|
|
231
|
-
const
|
|
236
|
+
const declaresInteractivePosture = (body, req, opts) => {
|
|
237
|
+
if (opts?.liveStream !== true)
|
|
238
|
+
return false;
|
|
239
|
+
if (body.verify === true || body.cascade === true)
|
|
240
|
+
return false;
|
|
241
|
+
if (liveQuestionFace === undefined)
|
|
242
|
+
return false;
|
|
243
|
+
if (body.interactiveTools === false)
|
|
244
|
+
return false;
|
|
245
|
+
if (headerStr(req?.headers["x-detach-on-disconnect"]) === "true")
|
|
246
|
+
return false;
|
|
247
|
+
const askForm = resolveAskSeamForm({}, approverSeat !== undefined ? { onAsk: approverSeat } : {});
|
|
248
|
+
return deriveAskEffective(askForm.form, "unresolved") === "human_reachable";
|
|
249
|
+
};
|
|
250
|
+
const assembleSpecLiteral = (body, auth, req, opts, parts, effMode) => {
|
|
232
251
|
const { scenarioName, cap, hands, centerDecls, acceptedAppend, parsedSettings, attachmentNotice, taskHooks, additionalDirectories, additionalReadDirectories, wireCatalog, picked, resumeAtEntryId, rewindFilesToEntryId, s4DefaultScopes, } = parts;
|
|
233
252
|
const spec = {
|
|
234
253
|
objective: attachmentNotice ? `${picked.cleanedObjective}\n\n${attachmentNotice}` : picked.cleanedObjective,
|
|
@@ -251,7 +270,9 @@ export function createResolveSpec(ctx) {
|
|
|
251
270
|
requireExistingSession: body.requireExistingSession === true ? true : undefined,
|
|
252
271
|
enableFork: enableForkFromBody(body, config, Boolean(centerRuntimeCapsResolver)),
|
|
253
272
|
suggestNextPrompts: normalizeSuggestNextPrompts(body.suggestNextPrompts),
|
|
254
|
-
|
|
273
|
+
restoreFiles: body.restoreFiles === true ? true : undefined,
|
|
274
|
+
acceptPartialRestore: body.acceptPartialRestore === true ? true : undefined,
|
|
275
|
+
...(body.rewindFiles === true ? { rewindFiles: true } : {}),
|
|
255
276
|
rewindFilesTo: rewindFilesToEntryId,
|
|
256
277
|
additionalDirectories,
|
|
257
278
|
additionalReadDirectories,
|
|
@@ -271,6 +292,7 @@ export function createResolveSpec(ctx) {
|
|
|
271
292
|
...(typeof body.interactiveTools === "boolean"
|
|
272
293
|
? { interactiveTools: body.interactiveTools }
|
|
273
294
|
: {}),
|
|
295
|
+
...(declaresInteractivePosture(body, req, opts) ? { interactionPosture: "interactive" } : {}),
|
|
274
296
|
...(typeof body.oneShot === "boolean" ? { oneShot: body.oneShot } : {}),
|
|
275
297
|
resilience: normalizeResilience(body.resilience, explicitOperatorOk(auth?.principal, config.operatorPrincipals)),
|
|
276
298
|
finalVerification: cap.finalVerification === true || body.finalVerification === true ? true : undefined,
|
|
@@ -337,7 +359,7 @@ export function createResolveSpec(ctx) {
|
|
|
337
359
|
return { ...(Object.keys(merged).length > 0 ? { limits: merged } : {}), ...(declarations.length > 0 ? { configOverrides: declarations } : {}) };
|
|
338
360
|
})(),
|
|
339
361
|
...(config.requirePrincipal !== true ? { backgroundScope: "session" } : {}),
|
|
340
|
-
memory: memoryEngine ? memorySpecForRequest(auth?.memoryScope, body.memoryWrite, s4DefaultScopes, { multiTenant: config.requirePrincipal === true }) : undefined,
|
|
362
|
+
memory: memoryEngine ? memorySpecForRequest(auth?.memoryScope, body.memoryWrite, s4DefaultScopes, { multiTenant: config.requirePrincipal === true }, body.memoryCapture) : undefined,
|
|
341
363
|
...((v) => (v !== undefined ? { memoryPersistenceCapable: v } : {}))(effectiveMemoryPersistenceCapable(config)),
|
|
342
364
|
tools: ((base) => {
|
|
343
365
|
const extra = [...(selectEnvTool ? [selectEnvTool] : []), ...(sendUserFileToolSpec ? [sendUserFileToolSpec] : [])];
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* ③ 模式分家(§4):`audit-only` 只调 `previewRetention` 记 `audit_only` 行,**一条破坏性方法都不调**;
|
|
22
22
|
* `enforce` 才调三方法。两支在代码里**物理分开**(不是同一段带 `if` 的调用序)—— 自审判据「grep 三个
|
|
23
23
|
* 方法名只出现在 enforce 臂」靠的就是这个形。
|
|
24
|
-
* ④ 单 domain 失败 ⇒ 记 `failed` 行 + **继续下一 domain**(
|
|
24
|
+
* ④ 单 domain 失败 ⇒ 记 `failed` 行 + **继续下一 domain**(一个坏租户不卡住整轮);同 domain 连败
|
|
25
25
|
* ≥ {@link RETENTION_SWEEP_STUCK_THRESHOLD} ⇒ `retention_sweep_stuck` 指标 + **一次性** warn。
|
|
26
26
|
*
|
|
27
27
|
* ── 破坏性审计行的属主(§6 F5)────────────────────────────────────────────────────────────────
|
|
@@ -181,7 +181,7 @@ export interface RetentionLaneCtx extends RetentionSweepCtx {
|
|
|
181
181
|
/**
|
|
182
182
|
* 起飞后的 lane 控制器(`create*` 形:有行为有状态)。
|
|
183
183
|
*
|
|
184
|
-
* 🔴 `stop()` 为什么必须**可等**(codex
|
|
184
|
+
* 🔴 `stop()` 为什么必须**可等**(codex 交叉复审 R1-[high],验真后加):`clearInterval` 只挡住**新** tick,
|
|
185
185
|
* 它不等当前这一轮。旧形的收尾链停表之后紧跟着就让租 ⇒ 新副本立刻接租,而旧副本还在删同一个域的
|
|
186
186
|
* 数据 —— 一个由**正常** SIGTERM/SIGINT 稳定触发的双执行者窗口(比任何竞态都好复现)。
|
|
187
187
|
* 正确的次序是:停表 → **等在飞那一轮落地** → 让租 → 关连接池。
|
|
@@ -29,10 +29,14 @@ import type { MemorySyncRunner } from "../memory-sync-client.js";
|
|
|
29
29
|
/**
|
|
30
30
|
* `RunnerDeps.onAsk` 的装配(#168 件4:从内联闭包提为具名导出,**纯 testability 重构、零行为变化**)。
|
|
31
31
|
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
32
|
+
* 为什么值得有名字(历史理由,#168 当时):bg / resume 两条腿彼时没有 per-task `spec.onAsk` 装配点,
|
|
33
|
+
* 它们唯一的审批接缝就是这一格。端到端测试此前只能把这一行**照抄**一份,再靠一条读源码
|
|
34
34
|
* 的正则当漂移告警 —— 那种锚只抓得到「这一行没了/改名了」,抓不到任何语义变化,而且抄件与真件从此是两
|
|
35
35
|
* 份实现。提成导出之后,测试直接取本函数,接缝与 production 是**同一个符号**。
|
|
36
|
+
* ⚠️ S-52 起**三腿都装** per-task `spec.onAsk = boundAsk`(sync=routes/tasks.ts、bg=runs.ts、
|
|
37
|
+
* resume=server.ts driveResumeLeg;core `resolveAsk` 取 `spec.onAsk ?? deps.onAsk` ⇒ 这三条腿及其继承链
|
|
38
|
+
* 子代不再落到本格)—— 本格现役的到达面 = 没有 per-task 装配的腿(headless/durable-submit、协调器在场
|
|
39
|
+
* 但 taskId 缺席的退化 resume 腿)与任何未来新腿的缺省兜底,fail-direction 不变(零 ctx ⇒ 政策口)。
|
|
36
40
|
*
|
|
37
41
|
* 命名(CLAUDE.md 工厂命名律):返回的是一个闭包(活对象)⇒ `create*`。
|
|
38
42
|
*
|
|
@@ -74,11 +78,11 @@ export interface RunnerDepsCtx {
|
|
|
74
78
|
memorySyncRunner: MemorySyncRunner | undefined;
|
|
75
79
|
/** design/170 件A(#148 件3③):org 记忆准入两 seam 的装配产物(boot/org-memory.ts)。进**共享
|
|
76
80
|
* 基座**——主/sub 两 Runner 必须同源:委托子代的 prepare 同样跑准入(委托冻结的重判腿),漏挂
|
|
77
|
-
* subRunner
|
|
81
|
+
* subRunner=子代平面跳过目录判决。 */
|
|
78
82
|
orgMemoryAdmission: import("./org-memory.js").OrgMemoryAdmissionWiring;
|
|
79
83
|
/** design/170 件B/C/D(#252 件1):三个部署治理座席的装配产物(boot/governance-seams.ts)。进**共享
|
|
80
84
|
* 基座** —— 合规否决与锁定层必须同样管住委托子代那条腿(子代 prepare 走同一套 preflight;漏挂
|
|
81
|
-
* subRunner =
|
|
85
|
+
* subRunner = 子代平面跳过档位与锁,与件A 同一个理由)。`retentionPolicy` 是纯声明,同源携带。 */
|
|
82
86
|
governanceSeams: import("./governance-seams.js").GovernanceSeams;
|
|
83
87
|
/** design/177 —— org 共享记忆库的供给面(core `RunnerDeps.sharedMemoryStores`)。在场即挂载
|
|
84
88
|
* `memory_list`/`memory_read` 两只工具(core 没有 TaskSpec 伴生旋钮:dep 的在场**就是**部署意图);
|
|
@@ -88,7 +92,13 @@ export interface RunnerDepsCtx {
|
|
|
88
92
|
toolResultStore: ToolResultStoreFull | undefined;
|
|
89
93
|
sessionPolicyStore: ReturnType<StoreBackend["sessionPolicy"]> | undefined;
|
|
90
94
|
runtimeCapsResolver: RunnerDeps["runtimeCapsResolver"];
|
|
91
|
-
|
|
95
|
+
/** S-15 per-edited-file rewind history (core `RunnerDeps.fileHistoryStore`; replaces the retired E19
|
|
96
|
+
* whole-tree snapshot seat — core 94632197 renamed the seat, not a coexistence). WIRING IS THE OPT-IN. */
|
|
97
|
+
fileHistoryStore: ReturnType<StoreBackend["fileHistory"]> | undefined;
|
|
98
|
+
/** S-1 legacy-epoch discriminant (core `RunnerDeps.legacyRewindBoundaryProbe`): lets the rewind refusal
|
|
99
|
+
* distinguish "never existed / reaped" from "exists in the RETIRED whole-tree epoch". Consulted only on
|
|
100
|
+
* the refusal path; diagnostic input, never a control input (a bad probe cannot change the outcome). */
|
|
101
|
+
legacyRewindBoundaryProbe: RunnerDeps["legacyRewindBoundaryProbe"];
|
|
92
102
|
/** #154 车二:持久化权限规则店 provider(core `RunnerDeps.permissionRuleStore`)。缺席 ⇒ 引擎的
|
|
93
103
|
* `permissionRules.storeWired` 如实报 false、`AskRequest.ruleOffers` 不铸(诚实缺席)。 */
|
|
94
104
|
permissionRuleStore: RunnerDeps["permissionRuleStore"];
|
|
@@ -126,7 +136,7 @@ export interface RunnerDepsCtx {
|
|
|
126
136
|
}
|
|
127
137
|
/** design/158 A10 留档发现②:main runner `RunnerDeps` 与 main.ts subRunner 字面量之间此前手工重复
|
|
128
138
|
* 的 ~15 个键,类型标注见 {@link createSharedRunnerDeps} 头注。 */
|
|
129
|
-
export type SharedRunnerDeps = Pick<RunnerDeps, "brain" | "readFace" | "readDenyPatterns" | "readDenyBuiltinTiers" | "readDenyBuiltinExclude" | "memoryDelegationEvidence" | "memoryProvenance" | "delegationEntryCaps" | "models" | "roles" | "tiers" | "pricing" | "tracer" | "promptSource" | "executionEnvFactory" | "lspManager" | "backgroundAgentStore" | "mailboxStore" | "rosterStore" | "hooks" | "toolResultStore" | "hands" | "sessionPolicyStore" | "usageWindows" | "usageWindowStore" | "memoryScopeAdmission" | "deploymentMemoryScopes" | "sharedMemoryStores" | "compliancePostureResolver" | "lockedConfig" | "retentionPolicy" | "onNotice" | "mcpRevocations">;
|
|
139
|
+
export type SharedRunnerDeps = Pick<RunnerDeps, "brain" | "readFace" | "readDenyPatterns" | "readDenyBuiltinTiers" | "readDenyBuiltinExclude" | "memoryDelegationEvidence" | "memoryProvenance" | "memoryCapturePolicy" | "delegationEntryCaps" | "models" | "roles" | "tiers" | "pricing" | "tracer" | "promptSource" | "executionEnvFactory" | "lspManager" | "backgroundAgentStore" | "mailboxStore" | "rosterStore" | "hooks" | "toolResultStore" | "hands" | "sessionPolicyStore" | "usageWindows" | "usageWindowStore" | "memoryScopeAdmission" | "deploymentMemoryScopes" | "sharedMemoryStores" | "compliancePostureResolver" | "lockedConfig" | "retentionPolicy" | "onNotice" | "mcpRevocations">;
|
|
130
140
|
/**
|
|
131
141
|
* design/158 A10 留档发现②(review 2026-07-29,[1543]§三族A 同源修补的延续):main runner 的
|
|
132
142
|
* `RunnerDeps` 字面量(下方 `createRunnerDeps`)与 `main.ts` 里 subRunner 的 `new Runner({...})`
|
|
@@ -194,7 +204,7 @@ export declare function createEngineNoticeForwarder(logger: {
|
|
|
194
204
|
}, router?: EngineNoticeRouter): NonNullable<RunnerDeps["onNotice"]>;
|
|
195
205
|
/**
|
|
196
206
|
* `onNotice` **席**的装配判据本身 —— 「`warn` 真在场才铸席」这一条从此是**一个可直接调用的函数**,
|
|
197
|
-
* 不是散在装配点、只能靠扫源码文本去猜的一行三元(codex
|
|
207
|
+
* 不是散在装配点、只能靠扫源码文本去猜的一行三元(codex 交叉复审 R1-[medium],验真后修)。
|
|
198
208
|
*
|
|
199
209
|
* 病(实测):把 leader 的门写成 `cfg.logger ? ((m, x) => cfg.logger?.warn?.(m, x)) : undefined` 时,
|
|
200
210
|
* 「装配点切片里出现过 `warn` 这个词」这类**源码文本**判据一律照绿 —— 而只装了 `info` 的部署会拿到一个
|
package/dist/boot/runner-deps.js
CHANGED
|
@@ -41,6 +41,7 @@ export function createSharedRunnerDeps(ctx) {
|
|
|
41
41
|
readDenyBuiltinExclude: ctx.config.readDenyBuiltinExclude ?? undefined,
|
|
42
42
|
memoryDelegationEvidence: ctx.config.memoryDelegationEvidence ?? undefined,
|
|
43
43
|
memoryProvenance: ctx.config.memoryProvenance ?? undefined,
|
|
44
|
+
memoryCapturePolicy: ctx.config.memoryCapturePolicy ?? undefined,
|
|
44
45
|
delegationEntryCaps: ctx.config.delegationEntryCaps ?? undefined,
|
|
45
46
|
executionEnvFactory: ctx.executionEnvFactory ? ctx.executionEnvFactory : undefined,
|
|
46
47
|
lspManager: ctx.lspManager ? ctx.lspManager : undefined,
|
|
@@ -64,7 +65,7 @@ export function createSharedRunnerDeps(ctx) {
|
|
|
64
65
|
return shared;
|
|
65
66
|
}
|
|
66
67
|
export function createRunnerDeps(ctx) {
|
|
67
|
-
const { config, logger, metrics, localRoot, outcomeSink, elicitation, question, toolApproval, sessionStore, memoryEngine, memorySyncRunner, runtimeCapsResolver,
|
|
68
|
+
const { config, logger, metrics, localRoot, outcomeSink, elicitation, question, toolApproval, sessionStore, memoryEngine, memorySyncRunner, runtimeCapsResolver, fileHistoryStore, legacyRewindBoundaryProbe, permissionRuleStore, fleetBus, workflowRunStore, workflowJournalStore, workflowAgentRegistry, workflowNotifyGate, workflowCompletionInbox, deliverWorkflowCompletion, getRunStore, } = ctx;
|
|
68
69
|
const sharedRunnerDeps = createSharedRunnerDeps(ctx);
|
|
69
70
|
const workflowModelAllowlist = workflowModelAllowlistFor(config);
|
|
70
71
|
const selfOrchestrationDeps = config.selfOrchestrationEnabled
|
|
@@ -160,7 +161,8 @@ export function createRunnerDeps(ctx) {
|
|
|
160
161
|
}
|
|
161
162
|
: undefined,
|
|
162
163
|
runtimeCapsResolver: runtimeCapsResolver ? runtimeCapsResolver : undefined,
|
|
163
|
-
|
|
164
|
+
fileHistoryStore: fileHistoryStore ? fileHistoryStore : undefined,
|
|
165
|
+
legacyRewindBoundaryProbe: legacyRewindBoundaryProbe ? legacyRewindBoundaryProbe : undefined,
|
|
164
166
|
permissionRuleStore: permissionRuleStore ? permissionRuleStore : undefined,
|
|
165
167
|
onBackgroundChildEvent: fleetBackgroundChildPublisher(fleetBus, (msg, fields) => logger.info(msg, fields)),
|
|
166
168
|
loadProjectMemory: config.requirePrincipal !== true && config.projectMemoryEnabled ? makeLoadProjectMemory({ logger }) : undefined,
|
|
@@ -9,10 +9,33 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import type { ServiceConfig } from "../config.js";
|
|
11
11
|
import type { Logger } from "../observability/logger.js";
|
|
12
|
+
import { type MemoryOptOutVerdictSource } from "../runtime-caps-resolver.js";
|
|
12
13
|
export interface RuntimeCapsCtx {
|
|
13
14
|
config: ServiceConfig;
|
|
14
15
|
logger: Logger;
|
|
16
|
+
/** design/383 S-2:`RuntimeCaps.allowMemoryOptOut` 的本地 verdict 源(`backend.memoryOptOutGrant()`;
|
|
17
|
+
* SQL 后端在场才有,local 车道 undefined)。缺席 ⇒ 本键不合成(零行为差)。 */
|
|
18
|
+
memoryOptOutGrant?: MemoryOptOutVerdictSource | undefined;
|
|
15
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* design/383 §3.1(S-49 S-1b)—— `MEMORY_CAPTURE_POLICY=governed` 的**半配置拒启**(`boot/memory-consolidation.ts`
|
|
22
|
+
* D1 / `boot/retention-lane.ts` 同姿态:安全/合规控件不得半开)。
|
|
23
|
+
*
|
|
24
|
+
* governed 的语义是「per-principal verdict **必答**」:core 对 verdict 缺席一律**拒跑**(fail-closed,部署显式
|
|
25
|
+
* 选的方向)。而 verdict 只能来自一个源 —— 本批唯一源 = SQL 后端上的 `memory_optout_grant` 表(三层折叠后
|
|
26
|
+
* 恒答显式 boolean)。governed 而无源 ⇒ 每一个 `capture:"off"` 声明都被 core 以
|
|
27
|
+
* `memory.capture_optout_denied` 拒掉,而运维看到的只是一台「启动成功、opt-out 全拒」的机器 —— 正是
|
|
28
|
+
* 「阀门开着而配不出来 ⇒ 悄悄读成别的」那一形。所以在**启动期**点名:要么接 SQL 后端(表随中央
|
|
29
|
+
* ensureSchema 建),要么改姿态。`open`/`capture-required`/缺席 不依赖源(前者故障放行、后者全拒,
|
|
30
|
+
* 都不问 verdict)。
|
|
31
|
+
*
|
|
32
|
+
* ⚠️ center 键 `EntitlementRuntimeCaps.allowMemoryOptOut` 是 settings-schema 的独立小件(S-50 §四 开放问题①),
|
|
33
|
+
* 到货前**不算源**;到货后本断言加一条「center 在场」析取臂即可,判据不变。
|
|
34
|
+
*/
|
|
35
|
+
export declare function assertMemoryCapturePolicyWirable(input: {
|
|
36
|
+
policy: ServiceConfig["memoryCapturePolicy"];
|
|
37
|
+
grantSourceWired: boolean;
|
|
38
|
+
}): void;
|
|
16
39
|
export declare function createRuntimeCaps(ctx: RuntimeCapsCtx): {
|
|
17
40
|
principalCaps: import("../runtime-caps-resolver.js").PrincipalEntitlementsClient | undefined;
|
|
18
41
|
centerRuntimeCapsResolver: ((principal: string | undefined) => Promise<import("@sema-agent/core").RuntimeCaps | undefined>) | undefined;
|
|
@@ -1,6 +1,21 @@
|
|
|
1
|
-
import { applyObserverEnvOptIn, centerEntitlementSourceWired, createPrincipalEntitlementsClient, scopedTokenNeedsWorker } from "../runtime-caps-resolver.js";
|
|
1
|
+
import { applyMemoryOptOutGrant, applyObserverEnvOptIn, centerEntitlementSourceWired, createPrincipalEntitlementsClient, scopedTokenNeedsWorker, } from "../runtime-caps-resolver.js";
|
|
2
|
+
export function assertMemoryCapturePolicyWirable(input) {
|
|
3
|
+
if (input.policy !== "governed")
|
|
4
|
+
return;
|
|
5
|
+
if (input.grantSourceWired)
|
|
6
|
+
return;
|
|
7
|
+
throw new Error(`MEMORY_CAPTURE_POLICY=governed requires a per-principal memory opt-out verdict source, and this deployment wires NONE ` +
|
|
8
|
+
`— under "governed" core REFUSES every session memory-capture opt-out whose verdict is absent (fail-closed, the posture's ` +
|
|
9
|
+
`own contract), so a governed worker without a source would refuse every \`memory.capture:"off"\` declaration and the ` +
|
|
10
|
+
`refusal would read as an entitlement denial rather than the misconfiguration it is. The only verdict source in this ` +
|
|
11
|
+
`version is the \`memory_optout_grant\` table on a SQL store backend (DB_BACKEND=mysql|pg; the table is created by the ` +
|
|
12
|
+
`central ensureSchema and administered through /v1/admin/memory-optout). Wire a SQL backend, or set ` +
|
|
13
|
+
`MEMORY_CAPTURE_POLICY=open (opt-outs take effect; only an explicit per-principal false denies) or ` +
|
|
14
|
+
`MEMORY_CAPTURE_POLICY=capture-required (every opt-out declaration refused, no source consulted).`);
|
|
15
|
+
}
|
|
2
16
|
export function createRuntimeCaps(ctx) {
|
|
3
17
|
const { config, logger } = ctx;
|
|
18
|
+
assertMemoryCapturePolicyWirable({ policy: config.memoryCapturePolicy, grantSourceWired: ctx.memoryOptOutGrant !== undefined });
|
|
4
19
|
if (config.configCenter && !config.configCenter.dryRun && scopedTokenNeedsWorker(config.configCenter.token, config.configCenter.worker)) {
|
|
5
20
|
logger.warn("runtime_caps_scoped_token_no_worker", {
|
|
6
21
|
reason: "SEMA_REGISTRY_TOKEN is a worker-scoped wpt_ token but SEMA_REGISTRY_WORKER is unset → center 403s per-principal caps → ALL workflow self-orchestration will be fail-closed denied. Set SEMA_REGISTRY_WORKER (the orchestrator normally injects it) or use the full SERVICE_PULL_TOKEN.",
|
|
@@ -15,11 +30,18 @@ export function createRuntimeCaps(ctx) {
|
|
|
15
30
|
})
|
|
16
31
|
: undefined;
|
|
17
32
|
const centerRuntimeCapsResolver = principalCaps?.resolveRuntimeCaps;
|
|
18
|
-
const
|
|
33
|
+
const withObservers = applyObserverEnvOptIn(centerRuntimeCapsResolver, {
|
|
19
34
|
experimentalObserverAgents: config.experimentalObserverAgents,
|
|
20
35
|
requirePrincipal: config.requirePrincipal,
|
|
21
36
|
warn: (msg, fields) => logger.warn(msg, fields),
|
|
22
37
|
});
|
|
38
|
+
const runtimeCapsResolver = applyMemoryOptOutGrant(withObservers, ctx.memoryOptOutGrant, {
|
|
39
|
+
onFault: (err, principal) => logger.warn("memory_optout_grant_resolve_failed", {
|
|
40
|
+
principal,
|
|
41
|
+
err: String(err),
|
|
42
|
+
effect: "allowMemoryOptOut left ABSENT for this resolve (never coined as false): open posture ⇒ the opt-out takes effect; governed ⇒ core refuses the run (verdict absent)",
|
|
43
|
+
}),
|
|
44
|
+
});
|
|
23
45
|
return { principalCaps, centerRuntimeCapsResolver, runtimeCapsResolver };
|
|
24
46
|
}
|
|
25
47
|
//# sourceMappingURL=runtime-caps.js.map
|
|
@@ -23,7 +23,7 @@ export interface SessionFacesCtx {
|
|
|
23
23
|
approvalExemptionStore: ReturnType<StoreBackend["approvalExemption"]> | undefined;
|
|
24
24
|
sessionPolicyStore: ReturnType<StoreBackend["sessionPolicy"]> | undefined;
|
|
25
25
|
taskAttachmentStore: TaskAttachmentStore | undefined;
|
|
26
|
-
|
|
26
|
+
fileHistoryStore: ReturnType<StoreBackend["fileHistory"]> | undefined;
|
|
27
27
|
workflowCompletionInbox: WorkflowCompletionInbox | undefined;
|
|
28
28
|
/** #318:会话级任务清单车道(E21 级联的一条腿)。缺席 = 装配未接本车道 ⇒ 无清单可删。 */
|
|
29
29
|
taskListLane: TaskListLane | undefined;
|
|
@@ -6,7 +6,7 @@ import { setLeafAdvanceListener } from "../session-leaf-bus.js";
|
|
|
6
6
|
import { SessionWatchRegistry, posIntEnv } from "../session-watch.js";
|
|
7
7
|
import { defaultTaskRegistry } from "@sema-agent/core";
|
|
8
8
|
export function createSessionFaces(ctx) {
|
|
9
|
-
const { config, logger, metrics, localRoot, backend, sessionStore, runStore, checkpointStore, toolResultStore, resumeAnchorStore, approvalExemptionStore, sessionPolicyStore, taskAttachmentStore,
|
|
9
|
+
const { config, logger, metrics, localRoot, backend, sessionStore, runStore, checkpointStore, toolResultStore, resumeAnchorStore, approvalExemptionStore, sessionPolicyStore, taskAttachmentStore, fileHistoryStore, workflowCompletionInbox, taskListLane, deviceStore, dropSessionScoped, } = ctx;
|
|
10
10
|
const mysqlPool = backend?.mysqlPool();
|
|
11
11
|
const auditPgPool = backend?.pgPool();
|
|
12
12
|
const auditLocalRoot = backend?.kind === "local" ? (config.localDataRoot ?? localRoot) : undefined;
|
|
@@ -66,8 +66,19 @@ export function createSessionFaces(ctx) {
|
|
|
66
66
|
if (deviceStore)
|
|
67
67
|
await deviceStore.deleteByRootSession(sessionId);
|
|
68
68
|
dropSessionScoped?.(sessionId);
|
|
69
|
-
if (
|
|
70
|
-
|
|
69
|
+
if (fileHistoryStore) {
|
|
70
|
+
if (typeof fileHistoryStore.deleteBySession === "function")
|
|
71
|
+
await fileHistoryStore.deleteBySession(sessionId);
|
|
72
|
+
else {
|
|
73
|
+
await fileHistoryStore.reap(sessionId, []);
|
|
74
|
+
logger.warn("session_file_history_baselines_retained", {
|
|
75
|
+
sessionId,
|
|
76
|
+
note: "the local file-history store has no whole-scope purge verb; boundaries were reaped but v1 baselines (original file bytes) remain under the data root until the upstream purge seam lands — recorded as an open deletion-rights gap, not silent",
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (backend?.legacySnapshotPurge)
|
|
81
|
+
await backend.legacySnapshotPurge(sessionId);
|
|
71
82
|
if (workflowCompletionInbox)
|
|
72
83
|
await workflowCompletionInbox.purge(sessionId, owner ?? null).catch((err) => logger.warn("workflow_completion_inbox_purge_failed", { sessionId, err: String(err) }));
|
|
73
84
|
await purgeScratchpadDir(config.localDataRoot ?? localRoot, sessionId);
|