@sema-agent/server 7.140.0 → 7.141.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MIGRATION.md +290 -0
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/USAGE.md +75 -13
- package/dist/approval-batch-census.d.ts +27 -0
- package/dist/approval-batch-census.js +27 -0
- package/dist/approval-card.d.ts +31 -16
- package/dist/approval-card.js +6 -3
- package/dist/approval.d.ts +15 -0
- package/dist/approval.js +10 -0
- package/dist/audit.d.ts +4 -2
- package/dist/audit.js +2 -2
- package/dist/boot/device-lane.d.ts +11 -0
- package/dist/boot/device-lane.js +16 -0
- package/dist/boot/engine-lease.d.ts +24 -3
- package/dist/boot/engine-lease.js +9 -2
- package/dist/boot/execution-env.js +8 -4
- package/dist/boot/memory-boundary.d.ts +2 -2
- package/dist/boot/memory-consolidation.d.ts +1 -1
- package/dist/boot/memory-consolidation.js +1 -1
- package/dist/boot/reapers.d.ts +2 -2
- package/dist/boot/resolve-spec.js +7 -4
- package/dist/boot/session-faces.d.ts +1 -1
- package/dist/boot/session-faces.js +4 -3
- package/dist/boot/shutdown.js +5 -0
- package/dist/boot/stage-05-execution-env.js +3 -1
- package/dist/boot/stage-06-runners.d.ts +0 -2
- package/dist/boot/stage-06-runners.js +1 -1
- package/dist/boot/stage-07-capability-layer.d.ts +0 -1
- package/dist/boot/stage-07-capability-layer.js +8 -10
- package/dist/boot/stage-08-reapers.d.ts +0 -1
- package/dist/boot/stage-09-leader.d.ts +0 -1
- package/dist/boot/stage-10-http-server.d.ts +0 -1
- package/dist/boot/stage-10-http-server.js +1 -0
- package/dist/boot/stores.js +10 -4
- package/dist/boot/web-admin.js +1 -0
- package/dist/capabilities/scenarios.d.ts +1 -1
- package/dist/capability-facts.d.ts +9 -0
- package/dist/capability-facts.js +9 -0
- package/dist/card-void.d.ts +38 -0
- package/dist/card-void.js +23 -0
- package/dist/config-catalog.js +11 -8
- package/dist/config-provider.d.ts +13 -13
- package/dist/config-provider.js +19 -33
- package/dist/config-types.d.ts +26 -8
- package/dist/config.js +55 -46
- package/dist/delegated-session-owner.d.ts +21 -19
- package/dist/delegated-session-owner.js +1 -1
- package/dist/device-store.d.ts +7 -0
- package/dist/device-store.js +3 -0
- package/dist/execution-config-root.d.ts +22 -0
- package/dist/execution-config-root.js +35 -0
- package/dist/execution-lane-caps.d.ts +49 -2
- package/dist/execution-lane-caps.js +90 -13
- package/dist/execution-placement.d.ts +3 -0
- package/dist/execution-placement.js +7 -0
- package/dist/fleet/drain-entry.d.ts +3 -0
- package/dist/hosted-posture.d.ts +8 -0
- package/dist/hosted-posture.js +4 -0
- package/dist/http/admission.js +3 -3
- package/dist/http/caller-trust.d.ts +3 -2
- package/dist/http/caller-trust.js +2 -1
- package/dist/http/dispatch.js +4 -0
- package/dist/http/live-frame.d.ts +24 -0
- package/dist/http/live-frame.js +16 -0
- package/dist/http/resume-legs.js +37 -20
- package/dist/http/route-table.js +2 -0
- package/dist/http/routes/approvals-assistant.js +1 -0
- package/dist/http/routes/capabilities.js +5 -4
- package/dist/http/routes/diagnostics.d.ts +0 -19
- package/dist/http/routes/diagnostics.js +16 -2
- package/dist/http/routes/memory-bundle.d.ts +2 -2
- package/dist/http/routes/memory-bundle.js +1 -1
- package/dist/http/routes/memory-compliance.js +1 -1
- package/dist/http/routes/memory-policy.js +2 -2
- package/dist/http/routes/run-permission-mode.d.ts +75 -0
- package/dist/http/routes/run-permission-mode.js +170 -0
- package/dist/http/routes/session-sync.d.ts +3 -6
- package/dist/http/routes/session-sync.js +7 -2
- package/dist/http/routes/sessions.js +5 -4
- package/dist/http/routes/tasks.js +63 -66
- package/dist/http/run-read-face.js +3 -3
- package/dist/http/send.d.ts +1 -1
- package/dist/http/send.js +2 -2
- package/dist/http/server.d.ts +9 -2
- package/dist/http/sse-log.d.ts +3 -8
- package/dist/http/stored-body-replay.d.ts +3 -3
- package/dist/http/stored-body-replay.js +3 -1
- package/dist/instruction-source-notice.d.ts +7 -0
- package/dist/instruction-source-notice.js +6 -6
- package/dist/mcp-assertion-header.d.ts +4 -0
- package/dist/mcp-assertion-header.js +5 -0
- package/dist/memory-posture.d.ts +1 -1
- package/dist/memory-scope.d.ts +4 -4
- package/dist/memory-scope.js +1 -1
- package/dist/memory-sync-client.d.ts +14 -2
- package/dist/memory-sync-client.js +80 -18
- package/dist/observability/fail-open.d.ts +30 -2
- package/dist/observability/fail-open.js +30 -2
- package/dist/observability/metrics.js +0 -1
- package/dist/observability/run-terminal.d.ts +6 -2
- package/dist/observability/run-terminal.js +25 -26
- package/dist/observability/secret-env-scrub.d.ts +20 -1
- package/dist/observability/secret-env-scrub.js +14 -0
- package/dist/orchestration/workflow-completion-inbox.d.ts +5 -2
- package/dist/orchestration/workflow-completion-inbox.js +13 -5
- package/dist/orchestration/workflow-notify-journal.d.ts +5 -3
- package/dist/orchestration/workflow-notify-journal.js +2 -1
- package/dist/permission-mode-admission.d.ts +68 -0
- package/dist/permission-mode-admission.js +23 -0
- package/dist/permission-rule-list.d.ts +55 -6
- package/dist/permission-rule-list.js +52 -5
- package/dist/plugins/caching-session-store.d.ts +6 -0
- package/dist/plugins/caching-session-store.js +3 -0
- package/dist/plugins/checkpoint-store-sql.d.ts +65 -17
- package/dist/plugins/checkpoint-store-sql.js +74 -3
- package/dist/plugins/device-store-sql.d.ts +5 -2
- package/dist/plugins/device-store-sql.js +4 -1
- package/dist/plugins/execution-placement-sql.d.ts +11 -1
- package/dist/plugins/execution-placement-sql.js +12 -1
- package/dist/plugins/file-run-store.d.ts +2 -2
- package/dist/plugins/file-run-store.js +1 -1
- package/dist/plugins/fork-routing-session-store.d.ts +10 -32
- package/dist/plugins/fork-routing-session-store.js +2 -61
- package/dist/plugins/k8s-exec-protocol.d.ts +4 -1
- package/dist/plugins/k8s-exec-protocol.js +6 -1
- package/dist/plugins/local-checkpoint-store.d.ts +10 -1
- package/dist/plugins/local-checkpoint-store.js +22 -0
- package/dist/plugins/local-session-store.d.ts +227 -35
- package/dist/plugins/local-session-store.js +518 -37
- package/dist/plugins/local-session-window.d.ts +17 -3
- package/dist/plugins/local-session-window.js +7 -13
- package/dist/plugins/memory-run-store.d.ts +2 -2
- package/dist/plugins/memory-run-store.js +1 -1
- package/dist/plugins/one-time-migrations.d.ts +42 -2
- package/dist/plugins/one-time-migrations.js +65 -3
- package/dist/plugins/pg-pool.js +3 -2
- package/dist/plugins/pg-session-storage.d.ts +2 -0
- package/dist/plugins/pg-session-storage.js +3 -2
- package/dist/plugins/remote-env-e2b.d.ts +24 -3
- package/dist/plugins/remote-env-e2b.js +131 -18
- package/dist/plugins/remote-env-k8s.d.ts +20 -1
- package/dist/plugins/remote-env-k8s.js +148 -25
- package/dist/plugins/remote-env-local-docker.d.ts +25 -11
- package/dist/plugins/remote-env-local-docker.js +87 -21
- package/dist/plugins/run-store-sql.d.ts +3 -3
- package/dist/plugins/run-store-sql.js +4 -3
- package/dist/plugins/sandbox-read-floor.d.ts +273 -0
- package/dist/plugins/sandbox-read-floor.js +608 -0
- package/dist/plugins/session-ownership.d.ts +2 -1
- package/dist/plugins/session-placement.d.ts +17 -4
- package/dist/plugins/session-placement.js +2 -1
- package/dist/plugins/session-store.d.ts +18 -20
- package/dist/plugins/session-store.js +4 -12
- package/dist/plugins/store-backend.d.ts +31 -0
- package/dist/plugins/store-backend.js +21 -4
- package/dist/plugins/store-contracts.d.ts +9 -2
- package/dist/plugins/tidb-pool.js +2 -1
- package/dist/plugins/tidb-session-store.d.ts +4 -1
- package/dist/plugins/tidb-session-store.js +3 -2
- package/dist/run-cancel-context.d.ts +34 -0
- package/dist/run-cancel-context.js +7 -0
- package/dist/runs.d.ts +39 -12
- package/dist/runs.js +68 -53
- package/dist/security.d.ts +2 -2
- package/dist/server-secret-env.d.ts +2 -1
- package/dist/server-secret-env.js +2 -4
- package/dist/session-error-wire.d.ts +22 -4
- package/dist/session-error-wire.js +16 -0
- package/dist/session-incarnation.d.ts +9 -3
- package/dist/session-sync-kernel.d.ts +42 -1
- package/dist/session-sync-kernel.js +17 -0
- package/dist/session-sync.js +16 -4
- package/dist/sql-engine-coordinates.d.ts +49 -0
- package/dist/sql-engine-coordinates.js +27 -0
- package/dist/standing-answer-grant.d.ts +31 -2
- package/dist/standing-answer-grant.js +14 -2
- package/dist/store-posture.d.ts +1 -1
- package/dist/task-a2a.d.ts +1 -1
- package/dist/task-mcp.d.ts +1 -1
- package/dist/task-settings.d.ts +52 -25
- package/dist/task-settings.js +91 -28
- package/dist/terminal.d.ts +77 -20
- package/dist/terminal.js +66 -20
- package/dist/trace/core-keyset-guard.d.ts +79 -2
- package/dist/trace/exit-seat.d.ts +7 -0
- package/dist/trace/exit-seat.js +1 -0
- package/dist/trace/model-segment.d.ts +2 -2
- package/dist/trace/redact.js +323 -90
- package/dist/trace/self-minted-wire.d.ts +168 -2
- package/dist/trace/self-minted-wire.js +63 -0
- package/dist/verifier-pause-card.d.ts +8 -0
- package/dist/verifier-pause-card.js +19 -0
- package/dist/web-admin-client/apply-effective.d.ts +5 -7
- package/dist/web-admin-client/apply-effective.js +2 -2
- package/dist/web-admin-client/candidate-gate.d.ts +1 -1
- package/dist/web-admin-client/read-warnings.d.ts +2 -2
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +3 -2
- package/package.json +2 -2
- package/wire-changes/server@7.141.0.json +367 -0
package/USAGE.md
CHANGED
|
@@ -57,9 +57,12 @@ docker compose up --build --scale service=4 # 4 个无状态 worker,nginx
|
|
|
57
57
|
> 显式带 `DB_BACKEND=mysql`。同版:`DB_BACKEND=mysql|pg` 显式而店打不开,拒句点名 `DB_BACKEND=<引擎>`(修前只有驱动的一句 `connect ECONNREFUSED …`)。
|
|
58
58
|
> 🔴 **7.119.0 起 `SESSION_BACKEND=auto` 配了坐标而库连不上同样拒启,不再有「auto 内存起服」这条出路**:`auto` = 「配了该引擎的坐标就是那只库(boot 期窗内重试、到窗拒启),没配就是内存」,
|
|
59
59
|
> 由配置决定、不由起库成败决定;内存部署写 `DB_BACKEND=memory` 或 `SESSION_BACKEND=memory`。`GET /health` 的 `sessionBackend` 如实说装好的后端(`durable(pg)` / `memory`)。持久化姿态读面:caps `store`(附录 B)。
|
|
60
|
+
> 🔴 **显式 `DB_BACKEND=mysql|pg` 而该引擎的坐标一个都没配 ⇒ 配置期拒启,与 `SESSION_BACKEND` 怎么写无关**(未设 / `auto` / `mysql` / `memory` 同一句拒句,`REQUIRE_PRINCIPAL=true` 亦然):写下 `DB_BACKEND=pg` 就是要这只持久引擎,没有坐标它开不了店。修前 `SESSION_BACKEND=auto`(「坐标不在就不探测」)下这一形静默跑内存、`/health` 照样 200、姿态位照报 `declared: "pg"`。拒句点名缺的坐标键名(`PG_HOST` / `PG_USER` / `PG_DATABASE`;`MYSQL_*` 同形),不回显任何值;出路:补齐坐标;或要无 SQL 的部署写 `DB_BACKEND=local`(单用户文件店)/ `DB_BACKEND=memory`。坐标齐、`DB_BACKEND=local|memory`、不写 `DB_BACKEND` 的形零变化。同族:`MEMORY_ENGINE_BACKEND=pg|mysql` 要绑的池没开而 `DB_BACKEND` 已点名该引擎时,拒句改点名真正开店的条件(持久会话后端 + 必需坐标键),不再说「要 `DB_BACKEND=…`」。
|
|
60
61
|
|
|
61
62
|
> 🔴 7.96.0 起根 `docker-compose.yml` 的 `REMOTE_EXEC`(执行车道)是**必填**:不设 ⇒ `docker compose config` 当场失败(此前静默起成一个没有手的 worker)。单人自用 `REMOTE_EXEC=host`(手落在 worker 容器里);多人 / 生产选隔离车道 `e2b`(配 `E2B_API_KEY`)或 `k8s`(`K8S_SANDBOX_IMAGE`、`K8S_NAMESPACE`〔没有内置缺省〕都是必需件,未设、空串或只含空白一律按缺 ⇒ 起服拒;`K8S_API_URL` 与 `K8S_TOKEN` 也要设;根 compose 透传前两名〔空串透传 = 按缺,要填〕,后两名要在 compose override 里加进服务的 `environment`,或改走随包 chart `deploy/sema-up`)。
|
|
62
63
|
|
|
64
|
+
> 🔴 **`REMOTE_EXEC` 的形是部署声明的有序车道表**(契约 `runtime.execution.lanes` 渲成 env 的形:逗号分隔、首项是缺省车道;单词 = 一条车道的表,读法与以前逐字同)。每段逐字是一个车道词(不 trim、不折大小写),不许空段、不许同一车道出现两次;写着契约退役车道值(如 `remote-docker`)⇒ 拒句给出去向。**本引擎每个进程只装一条车道的执行座**:表里不止一条(`REMOTE_EXEC=k8s,device`)⇒ 起服拒,拒句点名全部声明的车道与出路(一台引擎一条车道:`REMOTE_EXEC=k8s`,其余车道各起一台)—— 不只服务首项而让其余车道无声地什么都不跑。
|
|
65
|
+
|
|
63
66
|
> 🔴 **7.104.0 起多租户姿态不许跑不分租户的执行车道**:`REQUIRE_PRINCIPAL=true` ∧ 最终生效的车道在执行车道能力表上不分租户 ⇒ **拒启**。按表不按词,今天覆盖 `host` / `ssh` / `adb`(所有任务落同一个共享目标:worker 宿主 / 一台 SSH 对端 / 一台 ADB 设备)。判的是合成后的车道(env 的 `REMOTE_EXEC`、`CONFIG_PROVIDER=local` 而 `REMOTE_EXEC` 未设的隐式 host、local 形 `config.d/remote-exec.json` 的覆写,在中心拉取与任何配置应用之前合成)。拒因(逐字,以 host 为例):`REQUIRE_PRINCIPAL=true (multi-tenant posture) with the "host" execution lane runs every tenant's Bash on one shared target — this lane does not separate tenants; set REMOTE_EXEC to e2b / k8s / local-docker / device, or unset REQUIRE_PRINCIPAL for a single-user box`。车道 × 租户形:
|
|
64
67
|
>
|
|
65
68
|
> | 车道 | 单用户 | 多租户(`REQUIRE_PRINCIPAL=true`) | `READ_FACE` 缺席时的读面缺省(7.133.0 起车道行声明) |
|
|
@@ -71,6 +74,8 @@ docker compose up --build --scale service=4 # 4 个无状态 worker,nginx
|
|
|
71
74
|
> | `device`(每人自己的设备) | ✅ | ✅ | 单用户 `open`(来源 `posture`);多租户 不铸 = 引擎默认 `roots` |
|
|
72
75
|
> | 未点名(云形进程内 stub,零手带工具、非手带工具照常执行) | ✅(`REQUIRE_EXECUTION_LANE=true` 可改成拒启) | ✅(同左) | 单用户 `open`(来源 `posture`);多租户 不铸 = 引擎默认 `roots` |
|
|
73
76
|
|
|
77
|
+
> 🔴 **`REMOTE_EXEC=device` 必须声明设备入口 `DEVICE_RELAY_URL`(无缺省)**。两种合法值:设备连不到引擎自己的地址(引擎在中继 / 网关之后)时设备该拨的那一个 `ws://` / `wss://` 绝对地址(逐字上 `GET /v1/capabilities` 的 `deviceExecutor.relayUrl`);或字面 `none`(没有中继,设备按引擎地址 + `deviceExecutor.wsPath` 拨号,能力面不带 `relayUrl`)。缺席 / 空串 / 只含空白 ⇒ 起服拒,拒在车道必需 env 门(与 `K8S_NAMESPACE` 等其余车道必需键同一句:`required env DEVICE_RELAY_URL is unset, empty or whitespace-only`);写了却不合文法 ⇒ 起服拒,拒句点名两种合法值(规则文字取自契约包)。`none` 而根会话上还有设备绑定 ⇒ 起服 warn `device_relay_withdrawn_with_bindings`(`bindings` = 绑定条数,不带会话 id)。撤中继声明的回滚序:先恢复引擎自己的入口,再把值改成 `none`。
|
|
78
|
+
|
|
74
79
|
> 🔴 **7.104.0 起 `CONFIG_PROVIDER` 是闭集**:只认 `local` / `remote` / 不设(空串 = 不设),**逐字**比较 —— `Local`、` local`、`remote ` 这类写法**拒启**,拒因句点名旋钮并列出合法词。此前认不出的词照起,却被配置源当成 `local`、被隐式 host 车道当成「不是 local」,local 配置源的根还落回进程 cwd(与车道文件覆写读的本地根分家)。本地配置根只有一条链:`CONFIG_LOCAL_DIR` → `AGENT_DATA_DIR` → `~/.ai-agent`,配置源与 `config.d/remote-exec.json` 读同一个。
|
|
75
80
|
|
|
76
81
|
> 🔴 **`CONFIG_PROVIDER=remote` 要中心地址**:`remote` 说的是「这台 worker 的配置来自中心」,中心就是 `SEMA_WEB_ADMIN_URL` 那一只 —— 写了 `remote` 而没设 `SEMA_WEB_ADMIN_URL` ⇒ **拒启**,
|
|
@@ -449,16 +454,16 @@ MODEL_CODE_ROLES=default,subagent # 不设=全中立;仅这些角色在「
|
|
|
449
454
|
- **记忆(文件记忆引擎,2026-07-08 起唯一记忆面)**:core 注入式文件引擎——任务开始时 materialize 记忆目录(`MEMORY_ENGINE_DIR`,默认 `~/.ai-agent`),模型用**普通文件技能**读写记忆(CC `# Memory` 指令 + 派生索引;无 remember/recall 工具),任务边界 harvest 门(secret/cap 扫描)提交。单用户默认开,`MEMORY_ENGINE=off` 显式关;多租户恒关(文件基座无租户隔离,fail-closed)。旧 SQL 记忆面(`MEMORY_BACKEND`/`EMBEDDING_*`/`MEMORY_READ_LIMIT`/去重/向量检索、`GET/DELETE /v1/memory` 与 session memory 写 verb)已退役,数据不迁移——升级后对库跑一次 `scripts/drop-memory-tables.sql`。`body.memoryWrite:false` 仍是每请求只读开关(harvest 不提交)。
|
|
450
455
|
**`MEMORY_PERSISTENCE_CAPABLE`(三态,7.14.0 起)**=**部署自述**「本机能不能把用户的『记住 X』落到持久处」,与请求键 `memoryWrite` 两轴正交(后者收紧本次运行,前者是 operator 声明;任一取否即只读方向)。缺省不设=引擎按 roster 自行推断;`true`=本部署有推断看不见的持久通道(自定义 writer / 记忆 MCP / 远程执行车道与记忆根共享挂载);`false`=强制只读披露并关掉文件工具往记忆根的写通道。不认得的词拒启。
|
|
451
456
|
🔴 **`false` 自 core 5.27.0(7.14.0 提货)起还多一层——但只在 file 记忆引擎上**(`MEMORY_ENGINE_BACKEND` 未设 = 默认单机形):该会话是**受限会话**——materialize/搜索/harvest 一律按**已提交账**供给,记忆根下无事务背书的磁盘分歧既不收编也不供给,而是留盘 + 响亮点名(`restricted_divergence`,本服务把它计进 `memory_harvest_rejections_total{code}` 并 warn 一条),等下一次**非受限**会话走正常门收编。合法流程不受影响:用户手改、`git pull` 落下的删除照旧(延后,不销毁),并发的可写会话提交的变更算有事务背书。
|
|
452
|
-
⚠️ **`MEMORY_ENGINE_BACKEND=pg|
|
|
453
|
-
🔴 **降级前必须先停写排空(core 5.33.0 / server 7.21.0 起,运维 BREAKING)**:file 记忆后端的账本升到 **schema v2**(slug/scope rebind 与跨 scope transfer 改成 journaled 事务),而 **v2 journal 被 ≤5.32 的旧读者响亮拒**——这是**有意的 fail-closed**(拒启比静默读半张账好)。⇒ 要把服务降回 <5.33 的镜像:①**先停写、把在跑的记忆写排空**;②按 core 设计稿 §3.6 用 `transfers.jsonl` + journal 回放清账;③**再**降版。**排空这一步没做就降级 = 数据面响亮拒,不是静默丢**。`MEMORY_ENGINE_BACKEND=pg|
|
|
457
|
+
⚠️ **`MEMORY_ENGINE_BACKEND=pg|mysql` 上没有这一层**(引擎的受限视图是 file 后端的实装):那两条腿的读侧本来就走库、盘上目录只是每任务的投影工作区,不存在「读磁盘即收编」的通道,所以也无洞可堵——`false` 在它们上仍然照常买到披露、写门与零收编 harvest 三件(与后端无关)。
|
|
458
|
+
🔴 **降级前必须先停写排空(core 5.33.0 / server 7.21.0 起,运维 BREAKING)**:file 记忆后端的账本升到 **schema v2**(slug/scope rebind 与跨 scope transfer 改成 journaled 事务),而 **v2 journal 被 ≤5.32 的旧读者响亮拒**——这是**有意的 fail-closed**(拒启比静默读半张账好)。⇒ 要把服务降回 <5.33 的镜像:①**先停写、把在跑的记忆写排空**;②按 core 设计稿 §3.6 用 `transfers.jsonl` + journal 回放清账;③**再**降版。**排空这一步没做就降级 = 数据面响亮拒,不是静默丢**。`MEMORY_ENGINE_BACKEND=pg|mysql` 的部署不受此条约束(账本在库里,不走 file journal)。
|
|
454
459
|
⚠️ **口径别混**:「受限」是**会话级的这一个声明**;请求键 `memoryWrite:false` 铸出的只读**平面**(以及 org 层默认只读、双根非写面)**保持原样的 adopt-on-read**——它只是不 harvest,照旧看得见盘上的新内容。
|
|
455
|
-
⚠️ **core 5.26.0 起,remote 执行车道上的 `# Memory` 写指令被撤**(沙箱手带够不着 host 记忆根;读与注入不变)。**判据是「`REMOTE_EXEC` 有没有设」,不是那个旗**——凡设了 `REMOTE_EXEC`(含 `host`)且这次任务真有记忆面,写指令就被撤。因此被打到的**不止**显式 `MEMORY_ENGINE_REMOTE_LANE=allow` 的部署,还包括:① `MEMORY_ENGINE_BACKEND=pg|
|
|
456
|
-
另:记忆**没有写工具**,模型是用普通文件工具往记忆根写的——所以记忆根必须落在任务的 fs 授权边界内。结构性够不着时启动会 warn 并给出三条改法(把根挪进 workspace / 经 `additionalDirectories` 授权 / 声明 `MEMORY_PERSISTENCE_CAPABLE=false` 让披露诚实)。⚠️ **「挪根」用哪个旋钮按记忆后端分腿**:file 引擎是 `MEMORY_ENGINE_DIR`;`MEMORY_ENGINE_BACKEND=pg|
|
|
460
|
+
⚠️ **core 5.26.0 起,remote 执行车道上的 `# Memory` 写指令被撤**(沙箱手带够不着 host 记忆根;读与注入不变)。**判据是「`REMOTE_EXEC` 有没有设」,不是那个旗**——凡设了 `REMOTE_EXEC`(含 `host`)且这次任务真有记忆面,写指令就被撤。因此被打到的**不止**显式 `MEMORY_ENGINE_REMOTE_LANE=allow` 的部署,还包括:① `MEMORY_ENGINE_BACKEND=pg|mysql` 的 DB 记忆面(它不受那个旗管辖——旗只管 file 引擎,库是持久真身,任何车道上都照常点亮)= 最常见的云形;② `REMOTE_EXEC=host` + file 引擎(文件平面就在本机,但 core 的执行环境判决仍是 remote)。若该车道确实够得着记忆根,`MEMORY_PERSISTENCE_CAPABLE=true` 是官方恢复路径(启动日志 `memory_remote_lane_write_instruction_dropped` 会点名这一条);够不着就表 `false`,让只读状态对模型说明白。
|
|
461
|
+
另:记忆**没有写工具**,模型是用普通文件工具往记忆根写的——所以记忆根必须落在任务的 fs 授权边界内。结构性够不着时启动会 warn 并给出三条改法(把根挪进 workspace / 经 `additionalDirectories` 授权 / 声明 `MEMORY_PERSISTENCE_CAPABLE=false` 让披露诚实)。⚠️ **「挪根」用哪个旋钮按记忆后端分腿**:file 引擎是 `MEMORY_ENGINE_DIR`;`MEMORY_ENGINE_BACKEND=pg|mysql` 的根是 `<数据根>/memory-work`(数据根 = `LOCAL_DATA_ROOT`/`AGENT_DATA_DIR` 族),那两条腿**不读** `MEMORY_ENGINE_DIR`——启动 warn 的文案自己会按腿指对旋钮。
|
|
457
462
|
- **记忆店根搬了家 ⇒ 拒启(7.126.0 / 引擎 7.49.0 起,file 记忆后端)**:店根的物理路径记在店的控制面里(`root-anchor.json`),每次打开都比对。目录被搬走、
|
|
458
463
|
或换成指向别处的链接之后,起服**拒**(码 `memory.target_outside_store`;不降级成「记忆暗」—— 店还在,只是搬了家,静默降级会让这台部署在没人知道的情况下丢掉全部记忆)。
|
|
459
464
|
拒句点名控制面记下的路径与现在解析到的路径,并给出两条出路:**① 把目录放回原处**;**② 在本服务的目录里跑一次重锚**:
|
|
460
465
|
`node --input-type=module -e 'import("@sema-agent/core").then(m => m.reanchorMemoryStoreRoot("<path>", { controlDir: "<controlDir>" }))'`
|
|
461
|
-
(两个坐标拒句里逐字给出),然后再起服。`MEMORY_ENGINE_BACKEND=pg|
|
|
466
|
+
(两个坐标拒句里逐字给出),然后再起服。`MEMORY_ENGINE_BACKEND=pg|mysql` 与 `MEMORY_ENGINE=off` 的部署不经这一判。
|
|
462
467
|
- **数据根的写豁免只有一个来源(7.126.0 / 引擎 7.49.0 起)**:路径守卫对「本服务自己的数据根」的豁免,只读引擎的 `memoryEngineDir` 一处 —— 本服务把记忆引擎根
|
|
463
468
|
**恒**交给它,**`MEMORY_ENGINE=off` 的部署也交**(否则豁免根缺席,数据根下的写会被当成普通受保护路径拒)。运维零动作。
|
|
464
469
|
- **写目标的真落点读不出 ⇒ 有守卫行的面拒这次写(7.126.0 / 引擎 7.49.0 起,所有权限模式含 `bypassPermissions`)**:`Write` / `Edit` / `NotebookEdit` 的目标
|
|
@@ -468,7 +473,7 @@ MODEL_CODE_ROLES=default,subagent # 不设=全中立;仅这些角色在「
|
|
|
468
473
|
读落点(代理不转发链接链 ⇒ 部署守卫表在这些车道上只判落点,不逐跳;始终在岗的写保护表读适配器本身);`device` —— 设备协议必答 `canonicalPath`,
|
|
469
474
|
不答链接链(只判落点)。这些车道上一次瞬时失败(pod exec 超时、设备掉线、写门代理还没绑定本任务的沙箱)就是一次「读不出」⇒ 受守的写被拒,
|
|
470
475
|
重试那一次写即可(本服务不提供关掉始终在岗写保护表的旋钮)。
|
|
471
|
-
- **记忆检索的向量面(embedder,7.14.0 起)**:记忆检索有三档——`lexical`(词面 jaccard)/ `portable`(库内存向量,进程内算余弦)/ `native`(库侧向量算子)。⚠️ **没有档位旋钮**:档位是「记忆后端上限 × embedder 在不在场」**推断**出来的结果(显式选档只会造出「选了 native 却没 embedder」这类矛盾态)。**配上 embedder = 唯一的开法**,而且只在 `MEMORY_ENGINE_BACKEND=pg` 上有意义(
|
|
476
|
+
- **记忆检索的向量面(embedder,7.14.0 起)**:记忆检索有三档——`lexical`(词面 jaccard)/ `portable`(库内存向量,进程内算余弦)/ `native`(库侧向量算子)。⚠️ **没有档位旋钮**:档位是「记忆后端上限 × embedder 在不在场」**推断**出来的结果(显式选档只会造出「选了 native 却没 embedder」这类矛盾态)。**配上 embedder = 唯一的开法**,而且只在 `MEMORY_ENGINE_BACKEND=pg` 上有意义(mysql 记忆后端 v1 是词面档,file 引擎没有 embedder 接缝——两者配了 `MEMORY_EMBEDDER_*` 一律**拒启**点名)。不配 = 保持 `lexical`(默认姿态,零 warn)。
|
|
472
477
|
|
|
473
478
|
| env | 缺省 | 说明 |
|
|
474
479
|
|---|---|---|
|
|
@@ -490,7 +495,7 @@ MODEL_CODE_ROLES=default,subagent # 不设=全中立;仅这些角色在「
|
|
|
490
495
|
- ⚠️ **换 embedder 请停机换:先 `scale 0`,再起**。指纹门管的是 **boot 面**;**滚动升级窗**里新副本清完列之后,仍在服役的旧副本还在按**旧**模型写向量,滚动结束后表里混着两个空间而元表已是新指纹 ⇒ 此后恒判「相等」,门再也不会复检。这是纪律面的残余,不假装根治(行级 embedder 记账列可结构性根治,超出本件射程)。滚动事故后的补救 = 手动清一次:`UPDATE agent_memory_engine_entry SET embedding = NULL WHERE embedding IS NOT NULL;`(同一条也可用于「误配后立刻重置」)。
|
|
491
496
|
🔴 **同族的第二格:回滚到指纹门之前的版本**(7.14.x / 7.15.x —— 有 embedder、无指纹门)。那些版本照写 `embedding` 列却**根本不认识这张元表**,所以「装本版(元表记 B)→ 回滚到旧版跑一段(往列里写 A 空间向量,元表纹丝不动)→ 再升回本版、配置仍是 B」这条路走完,元表与配置都说 B 而列里躺着 A 空间向量 ⇒ 此后恒判「相等」,门再也不会复检。**跨门回滚与滚动窗要做同一件事**:回滚之前(或重新升级之后)手动跑上面那条清列 SQL,或干脆 `DELETE FROM agent_memory_engine_meta WHERE meta_key = 'embedder_identity';` 让下次启动按「无主向量」保守清一次。
|
|
492
497
|
- **没配 `MEMORY_EMBEDDER_*` 时门整个不装**(元表不动,旧指纹保留),启动日志 `memory_embedder_identity_absent` 说明:缺席期间**被改写过**的行,其 embedding 本来就被写成 NULL,所以「配置回归同一 identity 后向量续用」只对缺席期间**未被触碰**的行成立。
|
|
493
|
-
- 残余:同名模型在不同供应商若其实是不同实现(自托管 finetune 撞名),指纹辨不出——明知异实现时改 `MEMORY_EMBEDDER_MODEL` 名,或手动跑上面那条清列 SQL。`MEMORY_ENGINE_BACKEND=
|
|
498
|
+
- 残余:同名模型在不同供应商若其实是不同实现(自托管 finetune 撞名),指纹辨不出——明知异实现时改 `MEMORY_EMBEDDER_MODEL` 名,或手动跑上面那条清列 SQL。`MEMORY_ENGINE_BACKEND=mysql` 无向量面(v1 词面档),没有这张元表也没有这道门。
|
|
494
499
|
📋 **档位对运维可见**:启动日志 `memory_engine_enabled` 行带 `vectorMode` 字段(取自后端实例的真值,不是配置推断)——`lexical` 在跑就必须看得见;配了 embedder 时同行还带 `embedderModel`/`embedderDim`,换模型这件事在日志里留痕。
|
|
495
500
|
- **org 记忆准入(7.0.0 起 BREAKING)**:`org:*` 记忆 scope 分**两个来源**——部署自证
|
|
496
501
|
(env `MEMORY_SCOPE` 的 org 形 + **单用户部署**的 `projects[].defaultScopes` org 键)直通;**多租户**
|
|
@@ -608,6 +613,19 @@ MODEL_CASCADE_LADDER=deepseek-flash,deepseek-pro # 目录里的模型名,cheap
|
|
|
608
613
|
- 数据驻留提示:`DB_BACKEND=local` 下显式 `SESSION_BACKEND=memory` 会被收编为 **durable(local)**
|
|
609
614
|
(1.292+ 裸 boot 默认 durable;/health 的 `sessionBackend` 报 `durable(local)`)——session 行落盘在
|
|
610
615
|
数据根下,清数据/隐私预期要按「sessions 在 engine-data 里」来做,不要按「只在内存」。
|
|
616
|
+
- **后台子代的转录住哪、活多久(按车道)**:规则一条 —— 一只后台子代的持久记录在,它的转录就是宿主会话店委派分区里的一只分区会话:活过重启、随记录同亡;
|
|
617
|
+
进程内短 TTL 店只装没有持久记录指着的会话(普通子任务、前台子代)。`subagent_type: "fork"` 的后台子代不在这条规则里(各车道同):它的转录是从父会话分叉出来、
|
|
618
|
+
住宿主会话店的一只普通会话,记录被收割时保留(归会话留存管),也不能经 `SendMessage` 复活(工具结果是错误,`revive.fork_unsupported`)—— 下表的居所与续话两列不适用于它。
|
|
619
|
+
|
|
620
|
+
| 车道 | 后台子代转录的居所 | 接线清单 `fleet.subagentTranscripts` | 重启后对已结束的子代 `SendMessage` |
|
|
621
|
+
| --- | --- | --- | --- |
|
|
622
|
+
| `DB_BACKEND=mysql` / `pg` | 会话表里的分区行(`session_meta` 的委派元组列) | `full` | 续上(带原上下文复活) |
|
|
623
|
+
| `DB_BACKEND=local` | `<数据根>/sessions/<id>.jsonl`(存档行头记着委派元组) | `full` | 续上(带原上下文复活) |
|
|
624
|
+
| `DB_BACKEND=memory` | 进程内(没有后台记录店) | `none` | 不可续(记录与转录都随进程走) |
|
|
625
|
+
|
|
626
|
+
分区会话不进会话列表(`GET /v1/sessions`、`/resume`);属主按帧上的 `transcriptId` 读 `GET /v1/sessions/<transcriptId>`(体上带 `agent` 键)。记录被收割时转录一并删除(`BG_AGENT_RETENTION_MS`,缺省 7 天;
|
|
627
|
+
记录已不在的分区会话由分区孤儿腿按同一视界收);删根会话不连带删子代转录。会话同步往子代 id 上写 ⇒ `409 conflict.session_placed`。
|
|
628
|
+
本机形升级前停驻时被拷进宿主店的旧子代转录是普通会话(进列表、不随记录删),要清就 `DELETE /v1/sessions/<id>`。
|
|
611
629
|
- **任务清单(TaskCreate/TaskList 家族)的持久边界**:清单按**会话**分区,同一会话
|
|
612
630
|
跨 turn/跨 resume 连续,跨会话互不可见。配了 SQL 后端(`SESSION_BACKEND=mysql` / `DB_BACKEND=pg`)
|
|
613
631
|
时落 `task_list_meta`/`task_list_item` 两表 ⇒ **跨副本、跨重启都续得上**;**没有 SQL 后端的形态
|
|
@@ -616,6 +634,8 @@ MODEL_CASCADE_LADDER=deepseek-flash,deepseek-pro # 目录里的模型名,cheap
|
|
|
616
634
|
条边界,不为它自造持久性。**删除权**:`DELETE /v1/sessions/:id` 与托管留存 sweep 两条腿都把清单
|
|
617
635
|
行与编号高水位一并抹掉(同 anchors/附件/快照的级联)——会话 id 可被重新认领,残留就等于把上一位
|
|
618
636
|
主人的任务标题与编号进度交给下一个化身。
|
|
637
|
+
- **会话的行事实只住在数据根的 `session-incarnations.json`**(每只会话一格:属主 / 化身 / 执行放置 / 建档时刻 / fork 谱系);`sessions/*.jsonl` 是匿名的对话内容。
|
|
638
|
+
备份 / 迁数据根时两样一起搬;更早版本写下的带属主戳的存档由起服一次性迁移改写(改不了的点名,fork 与改日志推送答 409),快照目录 `session-archive-m33/` 非空且消化不了 ⇒ 拒启(MIGRATION 写了出路)。
|
|
619
639
|
- 多实例边界:同一数据根同时只允许一个实例(BootLock 独占,第二个进程拒启;死主自愈含 SIGKILL)。
|
|
620
640
|
core 5.54.0 起拒启错误带**可分派 code**(`FileStoreLockError`,message 点名占用方 pid),运维按码
|
|
621
641
|
三动作:`store.dir_in_use`=另一个活进程持有该目录 → 停掉它(或换数据根/迁 SQL 后端);
|
|
@@ -728,6 +748,7 @@ MODEL_CASCADE_LADDER=deepseek-flash,deepseek-pro # 目录里的模型名,cheap
|
|
|
728
748
|
host 车道 = 引擎的整文件替换(同目录暂存 + fsync + rename);ssh / adb / local-docker / k8s / e2b = 先在目标目录下建一只生来 0700 的私有目录
|
|
729
749
|
`.<名>.stage-<12 位十六进制>/`,整份传进去,再在目标机上一次 `mv -f` 换上去;device = 设备侧执行器在同一步里暂存再换上。
|
|
730
750
|
传输中途断、取消、写到一半出错 ⇒ 目标逐字是旧内容,私有目录被删(删不掉 ⇒ 错误句点名残留的目录)。修前 host 与五条远端车道是就地截断写:中途中断留下新内容的前半截,原件找不回。
|
|
751
|
+
- **服务进程被 `SIGKILL` 时,暂存目录会留在目标旁(可直接删)**:上一条的清理是服务进程自己做的 —— `kill -9`、内存杀手、容器被强停这类**没有机会跑清理**的退出,正在传输的那一次写留下 `.<名>.stage-<12 位十六进制>/`,里面是在传的新内容(上传途中被杀只有前半截,传完才被杀则是整份);**目标逐字是旧内容**,整文件替换的保证不受影响,多出来的只是这只目录。ssh 车道实测(被强杀的写都留下了);其余四条远端车道走同一段暂存脚本,同形。取消(Ctrl-C 中断那一次写)不留 —— 取消路径上清理那一往返照跑。**本版不自动清**:下一次对同一目标的写不会去扫陈旧的暂存目录,它会一直留着,确认没有另一个进程正在写同一个目标之后 `rm -rf` 即可(名字里的十六进制每次写都不同,在写的那一只和陈旧的那一只光看名字分不出)。host 车道的暂存是引擎的,同形的残留名是 `<目标>.tmp.<进程号>.<十六进制>`,同样可以删。
|
|
731
752
|
- 暂存自创建起不比目标更可读:远端五车道的暂存只在私有目录里(别的用户进不去;替换 0600 的文件时新内容在传输期间只有写入方与 root 读得到),device 的暂存件以 0600 打开;
|
|
732
753
|
host 车道的这一保证在引擎原语里:引擎 7.60.0 起目标存在时暂存件以 0600 打开。新建的文件是写入方身份的 umask 形(local-docker = 容器内镜像用户的)。
|
|
733
754
|
私有目录建出后要读回核实是 0700 且属写入方;**核不过(`chmod` 被拒、文件系统不认权限位、缺省 ACL 的掩码收不下来、目标机没有 `stat`)⇒ 不暂存,退回就地写目标**
|
|
@@ -1275,7 +1296,9 @@ READ_DENY_PATTERNS='[{"pattern":"**/secrets/**"},{"pattern":".ssh","caseSensitiv
|
|
|
1275
1296
|
`neverAuto` 在策略折叠里),本服务不另合一份并集。
|
|
1276
1297
|
- **`neverAuto`** 与部署的 `APPROVAL_NEVER_AUTO` 同级:命中的调用必须由真人在**这一次**答 —— `bypassPermissions`、请求自己的 `allow`、持久规则、「本会话放行」、auto 分类器都放不掉;无人可问时按无审批面的终局拒。
|
|
1277
1298
|
名字文法与永不匹配的名字(退役名、无前缀短名……)的判决与 env 腿同一只判官:有这类名字 ⇒ 整请求 422。审批卡的问句是 `human approval required to run "<工具名>"`;出处串(`settings.permissions.neverAuto(<命中的工具名>)`)只在引擎闸内部消费、不上卡(部署的 `APPROVAL_NEVER_AUTO` 同样)。
|
|
1278
|
-
- **合规禁项是「拒而不是收窄」**:请求禁了某能力而任务自己带着它 ⇒ 整个任务以 `config.compliance_denied` 失败(`workflows` + `selfOrchestration`;`
|
|
1299
|
+
- **合规禁项是「拒而不是收窄」**:请求禁了某能力而任务自己带着它 ⇒ 整个任务以 `config.compliance_denied` 失败(`workflows` + `selfOrchestration`;`web_fetch` + 花名册挂着 `WebFetch`)。
|
|
1300
|
+
`mcp_servers` 分两形:请求自带的 MCP 条目在本部署本就挂不上时(多租户姿态、`mcp` 锁、部署合规档禁了 `mcp_servers`),它们在受理时被否决 —— 用户面一条 `mcp.injection_dropped` 通告,任务照跑;
|
|
1301
|
+
条目挂得上(单用户部署)或部署自带 MCP 服务器时,任务真带着 MCP 服务器 ⇒ 同样整个任务 `config.compliance_denied`。
|
|
1279
1302
|
⚠️ 单用户部署的默认工具面恒挂 `WebFetch`,请求的 `excludeTools` 补偿不了(引擎先查花名册、后卸载),所以 `web_fetch` 这个词今天只在多租户部署的请求座上可用。不需要部署配 `COMPLIANCE_PROFILE`(env 腿需要)。
|
|
1280
1303
|
- **`readDenyPatterns` 的请求侧界**:请求里**一段最多 2 颗 `*`**(每一颗都算,相邻的也逐颗算;`**` 整段、`a**b`、`id_rsa*`、`*.pem`、`*secret*` 都在内)、**整张列表合计最多 16 颗**、**最多 32 条**;超了 ⇒ 400,句子点名坐标与上限。这是请求面的受理口径(请求是不可信的写者);引擎 7.55.0 起路径段按 `*` glob 匹配,星的个数不再影响匹配代价。进任务的就是写下的那一份(不改写模式)。需要更复杂或更多的行,合并成更宽的模式、改用不带星的字面形,或让运维写进 `READ_DENY_PATTERNS`(部署表不受此界)。
|
|
1281
1304
|
- **坏值不静默丢**:不是数组 / 超帽(读拒模式 32 条,其余三座 1000 条)/ 坏条目 ⇒ 400 `request.field_invalid` + `{ field, reason: "bad_entry" | "over_cap", index | count + cap }`;续跑重放存体时同判(409 `resume_blocked_by_policy`)。
|
|
@@ -1573,6 +1596,7 @@ ENGINE_ORPHAN_LINGER_MS=2000 # 可选,默认 2s(父没了之后的窗;见上一
|
|
|
1573
1596
|
`inflight` / `idleForMs` / `lingerMs`,孤儿还带 `orphanedForMs`),随后就是那条 `draining_started`。
|
|
1574
1597
|
`reason` 是闭集:`"idle"`(没人用了)/ `"reparented"` / `"esrch"`(后两者 = 父没了那一路,`orphan:true`)。
|
|
1575
1598
|
同一份读数会写进 `<数据根>/exit-last.json`(见上一节)。
|
|
1599
|
+
- **租约窗可读(`GET /health` 的 `engineLease`,7.141.0 起)**:装了自退腿的引擎在 `/health`(无鉴权)上多一个对象键 `engineLease: { lingerMs, tickMs }` —— `lingerMs` = 自退腿会执行的**最短**静默窗(`ENGINE_LINGER_MS` 与 `ENGINE_ORPHAN_LINGER_MS`〔装了父监视才有〕取小),`tickMs` = 采样拍(自退发生在**生效窗**满之后、至多再晚一拍;父还活着时生效的是较长的父活着的窗,所以实际自退可以比 `lingerMs` 晚得多 —— `lingerMs` 是安全节拍的上界(触点比它密,在任何状态下都先于自退),不是自退时刻的预言)。壳持租约的触点节拍据此定:比 `lingerMs` 密,在任何状态下都留得住引擎(附着着 SSE 流时本来就留得住,约束的是没有 SSE 的纯轮询壳),不必再按交给 spawn 的那份推 —— 别处起的短窗引擎、父死之后只剩孤儿窗的引擎也读得到。**取最短、不取「此刻生效」**:此刻生效的窗在父死那一拍从长窗掉到孤儿窗,按旧读数定节拍的壳会在下一次读 `/health` 之前被拆台。两个数与上一条 `engine_lease_armed` 日志是同一组窗。没装自退腿(两键都没设)、或腿已因排空 / 自退触发而收摊 ⇒ 键缺席(不补 0)。
|
|
1576
1600
|
- **坏值拒启**:`ENGINE_LINGER_MS` 必须是落在 **`[1000, 86400000]`(1s…24h)** 的整数毫秒,**两端都承重**:
|
|
1577
1601
|
下界防 `ENGINE_LINGER_MS=60`(以为单位是秒)—— 60ms 的窗等于把整条防误杀腿静默摘掉;上界防 `1e100`
|
|
1578
1602
|
这类值 —— 它能过朴素的「是正整数吗」检查,而计时**永远追不上它**,于是配置看着好好的、自退其实整件
|
|
@@ -1674,7 +1698,9 @@ invalid_using_default` 警告 + 退回缺省值」这条臂随词表放宽一并
|
|
|
1674
1698
|
继承整份用户环境(CC 交互形,用户自己的凭据形变量在内)—— 🔴 **但不含本服务自己的凭据**(7.129.0 起,引擎 7.51.1):配置目录全部 `type:"secret"` 名
|
|
1675
1699
|
(`SERVICE_AUTH_TOKEN(S)` / `APPROVAL_HMAC_KEYS` / `MODEL_API_KEY` …)与名单型旋钮名起服已向引擎声明为本进程自有凭据,生效配置里每条模型条目的 `apiKeyEnv` 也在名单里
|
|
1676
1700
|
(中心热应用新增 / 改名条目时在模型目录换代前重声明,名单只随落地的世代增长 —— 改名后旧名照扣到重启,没落地的候选不留痕;条目的 `apiKeyEnv` 是引擎扣不住的名,或它点到的名正被某只名单型旋钮交给沙箱 / 语言服务器(见下文沙箱名单段)⇒ 该候选整拒),`"all"` = 整份环境**减**它们,任何继承词都不把它们
|
|
1677
|
-
交给模型 shell(能力位 `inherit_env.own_credentials_withheld` = 最近一次声明 ⊇ 当前生效配置应声明的集合;真要让模型 shell 持某枚令牌 ⇒ 另放一个不在配置目录、也不是任何模型条目 `apiKeyEnv` 的名,或经 `settings.env` 显式授予)
|
|
1701
|
+
交给模型 shell(能力位 `inherit_env.own_credentials_withheld` = 最近一次声明 ⊇ 当前生效配置应声明的集合;真要让模型 shell 持某枚令牌 ⇒ 另放一个不在配置目录、也不是任何模型条目 `apiKeyEnv` 的名,或经 `settings.env` 显式授予);这些变量此刻的**值**也交给引擎按值扣(同值换名的副本同样进不了模型 shell),引擎判某个值「不是凭据值」(空白 / 占位词 / 一个字符重复 / 不足 8 字符)⇒
|
|
1702
|
+
那一个值不按值扣(名照扣、不拒启,能力位 `inherit_env.own_credential_values_withheld` 答 false),起服与模型目录换代时每个这样的变量出**一条** warn 结构化行 `own_credential_value_not_withheld { name, reason }`
|
|
1703
|
+
(`reason` 是引擎的拒句原文,从不回显值;起服第一步 logger 还没建时,这一行当拍以同一行形写 stderr,不缓冲)—— 按事件名告警,给该变量一个真值即可;`"scrub"` / 缺席 = 上面的缺省剥除。🔴 **`"all"` 只在单用户部署兑现**:`REQUIRE_PRINCIPAL=true`
|
|
1678
1704
|
⇒ 422 `request.host_posture_refused`(射程与写容纳面那条腿同一只谓词,`TASK_WRITE_FACE_ESCALATION` 不管它);非 host 车道带 `"all"` ⇒ 400。词表外的值(`"ALL"` · `""` · 名单 `["PATH"]` · 布尔 · `null` …)、非 host 车道带 `"all"`、部署不接 authorizer 时带 `"all"` 这三只都是 `400 request.field_invalid`,7.137.0 起体另带 `field: "inheritEnv"` 与 `reason`(`"unknown_word"` = 是字符串但不在词表;`"not_a_string"` = 根本不是字符串;`"lane_not_host"` = `"all"` 落在非 host 车道;`"no_authorizer_session"` = `"all"` 而部署不接 authorizer),壳按这两位认拒因、不解析句子(句子 / 码 / 状态不变;续跑腿同判,折叠 409 随体带同一组)。托管部署的 `422 request.host_posture_refused` 不在这组:它说的是「这台部署的姿态不给」,不是这个键写错,按 `errorCode` 认、不带这两位。部署方
|
|
1679
1705
|
**没有**旋钮能替调用方打开它,也没有旋钮能在单用户部署上关掉它(单用户部署的用户把他自己的环境交给他自己驱动的 shell);起服一行 info
|
|
1680
1706
|
`task_inherit_env_honored {honored}` 告诉你这台机器认不认。上面「部署级名单不给模型驱动 shell」那条不变 —— 两件事是两条轴(部署名单 vs 调用方 × 单用户射程)。
|
|
@@ -1716,7 +1742,7 @@ bake-runner 要用 ⇒ `LSP_ENV_ALLOW` / `BAKE_ENV_ALLOW` 点名放回。
|
|
|
1716
1742
|
(`A,,B`、尾逗号)、非变量名形(`1BAD`、带空格、`NAME=value` 整段贴进来)、点名名单型旋钮(`E2B_SANDBOX_ENV=E2B_SANDBOX_ENV`,
|
|
1717
1743
|
或 `LSP_ENV_ALLOW` / 另一只沙箱名单)⇒ 起服失败,拒句点名键与第几段,**不回显原值**。**点名本服务自有凭据名** —— 配置目录里的 secret 型变量(如
|
|
1718
1744
|
`SERVICE_AUTH_TOKEN(S)` / `APPROVAL_HMAC_KEYS` / `MODEL_API_KEY` / `E2B_API_KEY` / `K8S_TOKEN` / `GIT_API_TOKEN`)—— 同样起服失败:名单会把这枚凭据原样装进模型读得到的沙箱;
|
|
1719
|
-
与 `LSP_ENV_ALLOW` 同一条律、同一只判官(引擎拒白名单的那一只,按平台比名),拒句同一个开头 `this deployment's own credential —
|
|
1745
|
+
与 `LSP_ENV_ALLOW` 同一条律、同一只判官(引擎拒白名单的那一只,按平台比名),拒句同一个开头 `this deployment's own credential — `,点名键与第几段(`entry #k of n`,k 从 1 起,就是你写的名单里的第 k 项;一句话里只有这一套序号),不回显名也不回显值。
|
|
1720
1746
|
沙箱要凭据 ⇒ 给它铸一把自己的(名与值都不同于本服务的任何凭据),放进服务进程环境再点那个名;判的是名字,把同一个值换个名字再点,起服认不出、值照样进沙箱 ——
|
|
1721
1747
|
所以「值也不同」是出路的一半。**中心 / config.d 模型条目后来点到同一个名**:条目的 `apiKeyEnv` 在模型目录换代时才并进本服务自有凭据名,那一刻对本表三只与
|
|
1722
1748
|
`LSP_ENV_ALLOW` 此刻交出去的名用同一只判官重判 —— 新并进的名正被某只名单交出去 ⇒ 那份候选整拒、上一代照常服务,拒句点名旋钮、名与条目;出路二选一:给沙箱另铸一把并改名单
|
|
@@ -1917,7 +1943,8 @@ curl -s http://<host>:8090/v1/runs/<taskId> -H 'x-agent-principal: user:42' #
|
|
|
1917
1943
|
```bash
|
|
1918
1944
|
curl -N http://<host>:8090/v1/tasks/stream -H 'content-type: application/json' \
|
|
1919
1945
|
-H 'x-agent-principal: user:42' -d '{"objective":"…"}'
|
|
1920
|
-
# → SSE
|
|
1946
|
+
# → SSE,每条两行:event: <type> + data: <原始 TaskEvent>,如 event: text_delta / data: {"type":"text_delta","delta":"…"} … event: done / data: {"type":"done","result":{…}}
|
|
1947
|
+
# (带 eventId 的帧在最前面多一行 id: <eventId>;心跳 = event: heartbeat + data: {}。7.141.0 起每帧都具名,此前引擎帧与 done 只有 data 行)
|
|
1921
1948
|
# 注意:这是「同实例逐 token」;跨 worker 断线重连用 §4 的 /v1/runs(turn 粒度)。
|
|
1922
1949
|
```
|
|
1923
1950
|
> **7.127.0 起两处帧形(引擎 7.50.0)**:
|
|
@@ -2043,7 +2070,7 @@ curl -N http://<host>:8090/v1/tasks/stream -H 'content-type: application/json' \
|
|
|
2043
2070
|
> - **未设 + 没有便宜模型**(`MODEL_CHEAP_ID` 未设时 summarize 落主模型)⇒ **关** + 起服一行 warn
|
|
2044
2071
|
> `memory_consolidation_default_off_no_cheap_model`(点名 `MODEL_CHEAP_ID`;显式写 `off` 即静音)。理由:一轮整库
|
|
2045
2072
|
> 折叠读 ~1e5 prompt tokens,落主模型就是按最贵的价记账。
|
|
2046
|
-
> - **未设 + 结构上跑不起来**(下面 ①②③ 三形:多租户 / `MEMORY_ENGINE=off` / pg·
|
|
2073
|
+
> - **未设 + 结构上跑不起来**(下面 ①②③ 三形:多租户 / `MEMORY_ENGINE=off` / pg·mysql 记忆后端 / `MEMORY_PROVENANCE=off`)
|
|
2047
2074
|
> ⇒ **恒关、零提示**(配不配便宜模型它都开不了;缺省不造新拒启)。
|
|
2048
2075
|
> - **显式 `on` / `off` 恒赢**。显式 `on` 而座落主模型 ⇒ 照开,起服一行 warn `memory_consolidation_on_main_model`
|
|
2049
2076
|
> 说清按主模型计费(部署方显式承担)。
|
|
@@ -2345,6 +2372,7 @@ curl -N http://<host>:8090/v1/tasks/stream -H 'content-type: application/json' \
|
|
|
2345
2372
|
| HTTP `200` / `202` 应答里的 `warnings`(7.133.0 起;同步腿 200 体 · 流式腿 `meta` 帧 · 异步腿 202 回执;**有话说才在场**) | 请求的放行侧选择器清单(根 `allowTools`、子代定义的 `allowTools`)里有什么也不放的条目,而受理口没拒(放行侧只拒近似名,其余交引擎):`reason` 是引擎条目读法的原因词(`tool_name` · `grammar` · …)或 `not_in_roster`(读得出、却不在名册 —— 引擎目录 ∪ 本服务自铸工具 ∪ 本请求挂的调用方工具(主名 · 别名 · 子代工具池);协议命名空间名 `mcp__*` / `a2a__*` 懒挂载、`*` 是「不设名单」,都不判)。每条 `{ code, field, entry, reason }`,形同上一行。这不是拒:请求照常受理、照跑,引擎对这些条目的既有处置不变 | 把 `warnings` 当提示给用户看(「这几条什么也没放」);同一 `Idempotency-Key` 的重放从 run 记录答,不重判、不带;在飞合流回放的是首发那一腿铸的应答 |
|
|
2346
2373
|
| HTTP `422`(`request settings cannot be applied as written: …`)/ HTTP `400` + `errorCode:"request.field_invalid"`(7.131.0 起的读成空) | 请求体 `settings.permissions.deny` / `ask` 里的孪生与退役名 ⇒ 422、句子点名带内容的现名(`BASH(*)` ⇒ 写 `Bash(*)`);同两桶里参数不属于该工具的规则(`WebFetch(foo:…)`、`WebSearch(domain:…)`)⇒ 422 `unsupported.param_unknown`,句子列出该工具能写的参数(7.135.0 起;此前受理、永不命中);`settings.permissions.allow` 与技能 `allowedTools` 里的**近似名**(`BASH`)⇒ 400(退役名 · 内容形 · 文法读不出(带空白 / 括号不配 / 规则内容文法不成立,如 `Bash(echo $HOME)`)· 对端段通配照 7.130.0 受理,引擎通告)—— 全部读**同一张名册**(引擎目录 ∪ 本服务自铸的工具名)。运维 `APPROVAL_REQUIRE` / `APPROVAL_DENY` / `APPROVAL_NEVER_AUTO` / `APPROVAL_GRANT` 里的孪生 **拒启**,中心下发的 `governance.approvalRequire` 里的孪生整组被拒、保前值。续跑:停驻在升级前的任务,超 1000 条的清单(任一方向)与限制方向的存量孪生 `409 resume_blocked_by_policy`,放行方向的存量近似名照旧续跑 + 一行 warn `stored_allow_list_inert_resumed` | 改成句子里 `write` 后的现名(或删掉条目);超帽的合并成更宽的条目 |
|
|
2347
2374
|
| HTTP `400` + `errorCode:"request.field_invalid"` + `detail.problems[].reason:"below_trust_floor"`(7.133.0 起) | 多租部署(`REQUIRE_PRINCIPAL=true`)上调用方的信任档低于 `settings.permissions.allow`(或 `userInvokedSkills` 点用的自带技能的 `allowedTools`,`field: skills[i].allowedTools`)要的 `global`:档只由这次请求验过的凭据推 —— 部署的 service 凭据、或中心登录令牌在活动 scope 里的角色 ≥ `editor`(settings-schema 的治理写角色)⇒ `global`;角色更低 / 令牌不带角色 / 直连门 principal 令牌 / 没有验过的凭据 ⇒ `project`(`detail.callerTrust`)。`deny` / `ask` 与空 `allow` 照收;单用户部署任何调用方都是 `global` | 去掉 `allow`、开跑时答卡;请运维把规则放进 `APPROVAL_GRANT`;或请 scope 管理员把成员角色抬到 `editor` 及以上。提交前可读 `GET /v1/capabilities` 的 `settings.permissions.callerTrust` |
|
|
2375
|
+
| HTTP `422`(`request settings cannot be applied as written: …`)+ `detail.problems[].reason:"home_unresolvable"`,句子说 `user-settings path rule rooted at the configuration directory`(7.141.0 起) | 请求 `settings.permissions.deny` / `ask` 里一条 `layer:"userSettings"` 的 `/` 形路径规则,而这条沙箱车道既没把 `SEMA_CONFIG_DIR` 转进沙箱、也没有可知的 home(k8s / local-docker / ssh / adb / device 且未声明 `REMOTE_EXEC_HOME_DIR`)—— 配置根读不出,不猜目录(续跑同体 409 同句) | 往沙箱 env 名单里加 `SEMA_CONFIG_DIR`,或声明 `REMOTE_EXEC_HOME_DIR`,或把规则写成 `//` 绝对形 / 放进项目层(读在任务根);见 9.4d |
|
|
2348
2376
|
| HTTP `429` + `errorCode:"usage.window_exhausted"` | 部署级治理窗耗尽(`USAGE_WINDOWS`,token 或 $ 天花板先满者) | 看响应体 `retryAfterSec` 退避;窗滑动/桶到期后放行 |
|
|
2349
2377
|
| `terminal:{kind:"failed", code:"usage.window_exhausted"}` | 已受理的 run 在 **turn 边界**撞上治理窗且无法 durable 挂起 | 同上退避后重投;配好 checkpoint 基建则改为 `suspended` 等窗自动续跑 |
|
|
2350
2378
|
| HTTP `501`(`/v1/runs`) | 内存模式不支持异步 | 配持久存储(`DB_BACKEND=mysql` / `pg` + 坐标;7.106.0 起给了坐标必须点名 `DB_BACKEND`) |
|
|
@@ -2688,6 +2716,18 @@ ssh / adb / local-docker 三条车道的流式调用同读这一条律:没有车
|
|
|
2688
2716
|
run 行的身份来源不是接线点:读的是受理时记在 run 行上的那一份身份。本节写的是组件的行为与边界;
|
|
2689
2717
|
打开平面的那一版会在本节补上取值与续期。
|
|
2690
2718
|
|
|
2719
|
+
### 9.3i 沙箱三车道的读拒表字节地板:`SANDBOX_READ_FLOOR`(7.141.0 起;本版模块不服务任何车道)
|
|
2720
|
+
|
|
2721
|
+
读拒表(`READ_DENY_PATTERNS` / 出厂读拒档)判拒的路径,读工具会拒;「字节地板」说的是更强的一件:**命令跑的每个程序**都打不开这些路径(或这只沙箱拒起这条命令)。车道守不守它,看能力块的 `keepsReadFloor`。
|
|
2722
|
+
|
|
2723
|
+
- **判据只有一条**:沙箱车道(e2b / k8s / local-docker)守地板 ⇔ 读地板模块服务这条车道 ∧ `SANDBOX_READ_FLOOR` 不是 `off`。主机 / ssh / adb / device 恒不守(这些环境约束不了进程)。
|
|
2724
|
+
**本版模块不服务任何车道** ⇒ 三条沙箱车道的 `keepsReadFloor` 仍是 `false`,沙箱里的起动与上一版逐字同。
|
|
2725
|
+
- **看一处**:起服行 `remote_exec_enabled` 的 `keepsReadFloor`,沙箱车道上再加 `sandboxReadFloor`:`unserved`(模块还没服务这条车道)/ `off`(部署关了)/ `kept`(守)。
|
|
2726
|
+
- **守地板的车道上会多出的两种拒起**(都是 `spawn_error`,命令一个进程都不起):① 这只沙箱守不住整张表 —— 首句 `read floor unavailable on this sandbox (<原因词>)`,原因词九选一
|
|
2727
|
+
(`arch` / `user_notif` / `addfd_send` / `uid_zero` / `writable_system_path` / `binary_digest` / `relay_silent` / `relay_identity` / `provenance`),句中点名表首行与 `SANDBOX_READ_FLOOR=off`;
|
|
2728
|
+
② 一次不带地板的引擎起动(流式执行面,以及本服务里几处替引擎干活的内部调用方今天都不带)—— 句子点名车道与 `SANDBOX_READ_FLOOR=off`。
|
|
2729
|
+
- **不想守**:`SANDBOX_READ_FLOOR=off`。块如实答 `false`;读拒表非空的 run 照旧每 run 一条运维通告 `config.read_deny_floor_unkept`,部署设了 `READ_DENY_FLOOR_REQUIRED=true` 时准备期拒(同码)。
|
|
2730
|
+
|
|
2691
2731
|
### 9.4 auto 模式(`permissionMode:"auto"`):武装三态、本地 org deny、自查(与 core 的意图武装式合修)
|
|
2692
2732
|
|
|
2693
2733
|
**背景**:此前引擎只在「组织授予」(web-admin 解出的 per-principal `runtimeCaps.autoMode === true`)时武装
|
|
@@ -2780,6 +2820,27 @@ plan 起步的任务把计划交给人之后停在 `plan_review` 门上。`POST
|
|
|
2780
2820
|
机读两桶逐字点名,**不再静默丢** —— 与 `/v1/approvals/:id/decide` 同一只机器、同码同串。
|
|
2781
2821
|
逐字契约见 `docs/ASSISTANT-WIRE-CONTRACT.md` §4c。
|
|
2782
2822
|
|
|
2823
|
+
### 9.4c 两层「放行 / 拒绝」别读混:单用户 allow-all 基线与敏感路径守卫集(7.141.0 起成文)
|
|
2824
|
+
|
|
2825
|
+
- **起服行 `tool_policy_single_user_default`(info)说的是部署工具策略层的 allow-all 基线,不是逐调用放行**:单用户 turnkey 且没有任何门意图(没有审批名单、没有显式启用 `DURABLE_APPROVAL`)时,部署层铺一条在场的、看效果的 allow-all 基线,
|
|
2826
|
+
好让引擎的「写手无裁决」告警不再响;这一层自己不问也不拒。每次调用仍由本次运行的权限模式与引擎写门裁(例如 `auto` 下 shell 的写 / 删照样出问、交分类器)。要收紧用 `APPROVAL_REQUIRE` / `AUTONOMY` / `commandPolicy`(起服行的 `tighten` 键同一句)。
|
|
2827
|
+
- **`SENSITIVE_WRITE_PATTERNS` 拒的是文件工具,shell 写同一路径不被它拒绝,走普通审批问**:守卫集对 Write / Edit / NotebookEdit 按路径做 deny;shell 命令写同一条路径(重定向、`tee`、`cp` …)是一条普通审批问,和这次运行里别的 shell 写同一条出路(人答;`auto` 下交分类器),不会因为命中这个集而被拒。
|
|
2828
|
+
要让某类 shell 写在你的部署里被问或被拒,管 shell 本身:`commandPolicy` / `AUTONOMY` / `APPROVAL_REQUIRE`。
|
|
2829
|
+
|
|
2830
|
+
### 9.4d 设置层的路径规则读在它那一层的根:`settings.permissions.deny` / `ask` 的带层条目(7.141.0 起)
|
|
2831
|
+
|
|
2832
|
+
- **一句规则**:一条路径规则的 `/` 读在它所在那一层的根上;`~/`、`//`、相对形在每一层读法相同。端从设置文件读规则时可以把出处层一起发:
|
|
2833
|
+
`"deny": ["Read(/secret/**)", { "rule": "Read(/secret/**)", "layer": "userSettings" }]` —— 纯串是请求自己写的规则(读在任务根,读法不变);带层条目的 `layer` 是设置来源词
|
|
2834
|
+
(`userSettings` · `projectSettings` · `localSettings` · `flagSettings` · `policySettings` · `foreignProjectSettings`)。能力位 `settings.permissions.layers` 为真才发。
|
|
2835
|
+
- **只有 user 层的 `/` 形随层变**:`userSettings` 里的 `Read(/secret/**)` 守的是**执行环境的配置根**下的 `secret`(host 车道 = 本服务的 `SEMA_CONFIG_DIR`,缺省 `~/.sema`),
|
|
2836
|
+
不再守任务根下的 `secret` —— 与参照实现读 user 层 `/` 的位置相同。别的来源与纯串读在任务根。要守每个项目自己的目录:把规则放进项目层,或写相对形 `secret/**`(任务根下任意深度);固定位置写 `//` 绝对形。
|
|
2837
|
+
- **沙箱车道的配置根**:运维把 `SEMA_CONFIG_DIR` 列进 `E2B_SANDBOX_ENV` / `K8S_SANDBOX_ENV` / `DOCKER_SANDBOX_ENV` 转进沙箱 ⇒ 读那个值;没转 ⇒ 执行环境 home 下的 `.sema`
|
|
2838
|
+
(e2b = `/home/user/.sema`;k8s / local-docker / ssh / adb / device 要 `REMOTE_EXEC_HOME_DIR` 声明 home)。两样都没有 ⇒ 这样的条目 422,`detail.problems[].reason:"home_unresolvable"`(与 `~/` 缺 home 同一个词);
|
|
2839
|
+
出路:转 `SEMA_CONFIG_DIR`、声明 `REMOTE_EXEC_HOME_DIR`,或把规则写成 `//` 绝对形。转进去的值不是绝对路径 ⇒ 422 `unsupported.path_base`。
|
|
2840
|
+
- **层不改准入**:多租部署上的准入档只按这次请求验过的凭据推(9 节速查 `below_trust_floor` 一行);条目上的层只决定规则读在哪。
|
|
2841
|
+
- **回滚 / 混版副本**:本版之前的服务对带层条目是桶门 `bad_entry`(新提交 400,续跑 409),不会静默读丢;端见位才发,所以没升级的服务上它照旧只收到纯串。
|
|
2842
|
+
- **已知限制**:`allow` 桶只收纯串(带层条目 400 `bad_entry`);user 层的 `/` 形 allow 今天仍按任务根放行。
|
|
2843
|
+
|
|
2783
2844
|
### 9.5 Web search:两车道优先级、per-request `settings.webSearch`、错误形
|
|
2784
2845
|
|
|
2785
2846
|
**两车道,整段整取(不是逐键 merge)**:部署 env(`WEB_SEARCH_*`,§0)与 per-request `body.settings.webSearch`
|
|
@@ -2947,6 +3008,7 @@ WebSearch 工具的 `tool_result` 错误文本,回到模型的对话里,**不是
|
|
|
2947
3008
|
- **`transport.url` 不得带凭据(7.135.0 起)**:http 传输的 `url` 带 userinfo(`https://user:pass@host/mcp`,只有用户名也算),或带名字在凭据名表里的 query / fragment 参数(`?api_key=` · `?key=` · `?token=` · `#access_token=` …;表 = 本服务日志脱敏器认作凭据名的那一张,全表见契约附录 A `request.field_invalid` 行;名字大小写不敏感,按解一次百分号编码读)⇒ 新提交 `400 request.field_invalid`,体另带 `field: "mcpServers[i].transport.url"` 与 `reason`(`url_userinfo` | `url_credential_param`),原因句点名出路:**凭据改写进 `transport.headers`**(如 `"Authorization": "Bearer …"`)。为什么:任务停驻时提交体整份进续跑上下文,`transport.headers` 的值在那里只以封签存在,`url` 照原样存(日志与读面同理)。值从不回显;解析不了的 url 不在这一问里判(拨号时失败)。7.134.x 及以前照收、原样落停驻上下文;带 userinfo 的 url 本就连不上(fetch 对带凭据的 URL 构造即抛),带名表参数的升级后要改。同一条规则在 A2A 对端 / http 钩子 / 搜索后端 / 图片 URL 上的几座见 9.5g。
|
|
2948
3009
|
- **耐久 resume 重放存量请求**:不拒(拒会把升级前 park 的任务永久卡死;`transport.url` 带凭据的存量条目照挂、url 逐字交引擎)。写坏的 `name` · `transport` 的 `kind`/`command`/`url` · `allowTools` · `toolAxes` · `toolFaces` · `sessionMetaKey` ⇒ 这一条 server 整条不进,运维 warn `mcp_injection_dropped`(`reason: malformed_entry`,`field` 点名)并投用户面通告 `mcp.injection_dropped`(其中 `toolAxes` 在一次性迁移 M19 的窗开着时先按升级前读法重读一次,过了就挂,见上文 `toolAxes` 一节);写坏的 `contentOrigin` · `elicitation` · `source` · `transport` 的 `args`/`principalHeader` 与词表外的键 ⇒ 丢掉那一个键、server 照挂;`transport` 的 `env`/`headers`(名 → 串记录)对 JSON 存体按 7.131.x 的读法交:有值不是串的成员 ⇒ 整键不交,只有 `__proto__` 名的成员坏 ⇒ 剔掉它、其余照交;server 照挂,一行运维 warn `mcp_transport_members_dropped` 点名(见 9.5c-bis 同段);条目不是对象 ⇒ 这一条不进(`malformed_entry`);超过 32 条 ⇒ 第 33 条起只记 `over_cap`;整只不是数组 ⇒ 整只忽略 + 运维 warn `mcp_injection_ignored`。
|
|
2949
3010
|
- `POST /v1/capabilities/mcp/probe` 问的是新提交那**同一只判官**:上面每一形同码同句(含 `unknownKeys`,与 url 带凭据那一形的 `field` / `reason`),拒之前零拨号;判官受理的申报,探测口拨的就是一条任务提交会交给引擎的那一份(判官的合法归一照收)。它多出的两形:本口的体就是这份列表,`mcpServers` 缺席或为 `null` ⇒ `400 request.body_shape`(缺必需字段);声明了 `transport.assertionHeader` 的条目 ⇒ `400 request.field_invalid`(见 9.5d:本版承载、不发送,新提交照挂,探测不拨一份少了断言头的配置 —— 同一只谓词,后果按门分)。7.131.x 上本口另有一只判法(申报原文与读器产物逐字比),列表不是数组 / 条目不是对象答 `request.body_shape`。
|
|
3011
|
+
- **`transport.kind` 的词表可读(7.141.0 起)**:`GET /v1/capabilities` 的 `mcpTransportKinds`(`["stdio","http"]`,书写序,每种部署形都在场、不随部署形变)= 请求面读器与引擎今天能拨的传输种类。客户端在投影 `mcpServers` 条目之前据此判目标传输读不读得了(只拒那一台、其余照投),不必靠整次提交挨 400 去试。**位不是放行单**:位外的词(引擎的 `host`、别家的 `sse` / `sdk` / `websocket`)在新提交与探测口上照旧整次 400;本部署收不收自带的 `mcpServers` 读 `mcpInjection`,「端到端可达」没有任何位承诺。键缺席 = 老 server,读作 `["stdio","http"]`;位里出现不认识的词按「不支持该种类」处理。
|
|
2950
3012
|
- **`toolFaces` 的判官是引擎的 `readToolFaces`(7.134.0 起;此前本服务自带一只只判 JSON 形的读器)**:它在门口就判声明本身能说的一切 —— 成员与类型、五张闭词表、上界、跨成员律 ——
|
|
2951
3013
|
所以下面几形 7.133.x 受理、7.134.0 起 400(重放腿整条 server 不进、中心 / `config.d` 腿跳过该 server 并点名 warn):空工具名;保留审批卡(`renderHints.approvalCard: "question"` / `"plan"`);
|
|
2952
3014
|
🔴 **`pathTarget.access` 是闭集 `read` / `create` / `edit`** —— 写成 `"write"`(或任何别的词)整条拒;**`pathTarget.base: "root"` 要求 `access: "read"`**(写面落根基底整条拒);
|
|
@@ -3098,7 +3160,7 @@ docker 推送的鉴权走构建宿主上的 docker 凭据存储(`docker login`),
|
|
|
3098
3160
|
`git fetch` 的 askpass 读 `GIT_TOKEN`)⇒ 点名它,runner 把该键从本进程 env **原样**放回给每一只子进程组(部署方显式承担)。
|
|
3099
3161
|
与服务侧 `LSP_ENV_ALLOW` 同一只解析器、同一只放行谓词:
|
|
3100
3162
|
- 形错(空段 / 尾逗号 / 非变量名形,如 `$NPM_TOKEN`、`a b`、`NAME=value` 整段贴入 / 点名任一只名单型旋钮 / 点名本服务自有凭据名,7.132.0 起)⇒ runner **拒启**,
|
|
3101
|
-
`bake_runner_fatal`
|
|
3163
|
+
`bake_runner_fatal` 那一行点名旋钮与第几段(`entry #k of n`,一句话只有这一套序号),**不回显值**(自有凭据那一形与服务侧同一句:说明这是本部署自己的凭据、给出路,并说明引擎拒它进任何名单);
|
|
3102
3164
|
- 本进程环境里没有的名 ⇒ 起服一行 `config_env_entry_rejected`(只报序号)、不放行;
|
|
3103
3165
|
- 旋钮原文本身按凭据类对待,不进子进程;
|
|
3104
3166
|
- 生效名单(点到且环境里真有的名)见起服行 `bake_runner_start.envAllow`(只键名);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Logger } from "./observability/logger.js";
|
|
2
|
+
/** 载体名(闭集;进探针行的 detail,不含任何行内容)。 */
|
|
3
|
+
export declare const KINDLESS_BATCH_CARRIERS: readonly ["rule_suggestions", "pendingAction.ruleOffers"];
|
|
4
|
+
export type KindlessBatchCarrier = (typeof KINDLESS_BATCH_CARRIERS)[number];
|
|
5
|
+
/** 一行带旧形成员的存量行:`ref` 是非机密的行指纹(checkpoint 的 token 是机密,只出指纹),`carriers` 是哪几个载体带着它。 */
|
|
6
|
+
export interface KindlessBatchRow {
|
|
7
|
+
readonly ref: string;
|
|
8
|
+
readonly carriers: readonly KindlessBatchCarrier[];
|
|
9
|
+
}
|
|
10
|
+
/** 一次扫描的读数:带旧形的行,与「读不出形所以没法判」的 cell 数(坏 JSON / 形不对 —— 到不了读者,不计入 `rows`,但不静默:普查另出一行 warn)。 */
|
|
11
|
+
export interface KindlessBatchScan {
|
|
12
|
+
readonly rows: readonly KindlessBatchRow[];
|
|
13
|
+
readonly unreadableCells: number;
|
|
14
|
+
}
|
|
15
|
+
/** 一只可被普查的店:SQL 孪生同一份实现(`SqlCheckpointStore`)。 */
|
|
16
|
+
export interface KindlessBatchRowSource {
|
|
17
|
+
scanKindlessBatchRows(): Promise<KindlessBatchScan>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* 跑一次普查并落痕。返回数到的行数(扫失败 ⇒ `undefined`)。**永不 reject**(起服处不 await 它 —— 见 `boot/stores.ts`):整段在一只 try 里,
|
|
21
|
+
* 任何失败(扫描抛、落痕抛)都收成一行 warn `approval_batch_kindless_census_failed`,不让一个观测面变成未处理的 rejection。
|
|
22
|
+
*
|
|
23
|
+
* **扫失败不拒启、也不装成「零」**:普查是观测面(它不判任何门),读不出就响亮 warn 并**不出** info —— 一行 `count: 0` 是「已扫完且为零」的正面证据,
|
|
24
|
+
* 半途失败的读数不得冒充它。
|
|
25
|
+
*/
|
|
26
|
+
export declare function runApprovalBatchKindlessCensus(source: KindlessBatchRowSource | undefined, logger: Pick<Logger, "info" | "warn">): Promise<number | undefined>;
|
|
27
|
+
//# sourceMappingURL=approval-batch-census.d.ts.map
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { recordFailOpen } from "./observability/fail-open.js";
|
|
2
|
+
export const KINDLESS_BATCH_CARRIERS = ["rule_suggestions", "pendingAction.ruleOffers"];
|
|
3
|
+
export async function runApprovalBatchKindlessCensus(source, logger) {
|
|
4
|
+
if (source === undefined)
|
|
5
|
+
return undefined;
|
|
6
|
+
try {
|
|
7
|
+
const scan = await source.scanKindlessBatchRows();
|
|
8
|
+
for (const row of scan.rows)
|
|
9
|
+
recordFailOpen("server.approval-batch.kindless-row", `row=${row.ref} carriers=${row.carriers.join("+")}`);
|
|
10
|
+
if (scan.unreadableCells > 0) {
|
|
11
|
+
logger.warn("approval_batch_kindless_census_unreadable_cells", {
|
|
12
|
+
cells: scan.unreadableCells,
|
|
13
|
+
note: "stored approval-row cells whose body could not be read as JSON of the expected shape were not judged (they never reach the rule-offer reader either); the reported count covers the readable cells only",
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
logger.info("approval_batch_kindless_rows", { count: scan.rows.length });
|
|
17
|
+
return scan.rows.length;
|
|
18
|
+
}
|
|
19
|
+
catch (err) {
|
|
20
|
+
logger.warn("approval_batch_kindless_census_failed", {
|
|
21
|
+
error: err instanceof Error ? err.message : String(err),
|
|
22
|
+
note: "the startup census of stored approval rows holding kind-less batch members did not complete, so no count is reported (an unfinished scan is not a zero); restart to retry",
|
|
23
|
+
});
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=approval-batch-census.js.map
|
package/dist/approval-card.d.ts
CHANGED
|
@@ -149,6 +149,15 @@ export interface ReadRuleOffer {
|
|
|
149
149
|
* 缺席(`undefined`)= 没有提议,答空、不计。展示帽(条数、成员前缀、扫描窗)、脱敏与截长归调用方 —— 它们是各腿的展示纪律,不是读法。
|
|
150
150
|
*/
|
|
151
151
|
export declare function readRuleOfferList(raw: unknown): readonly ReadRuleOffer[];
|
|
152
|
+
/**
|
|
153
|
+
* 一份(已解码的)规则提议列表里,**带着无 `kind` 存量成员**的 batch offer 有几只 —— 判官是 core `readRuleOffers` 给每只读出的 offer 打的 `kindlessForm` 记号
|
|
154
|
+
* (「这一只 batch 里至少一个成员是经无 `kind` 的存量形读的」;与 {@link readRuleOfferList} 同一只读者,不是本仓自己再写一遍「成员没有 `kind` 键」)。
|
|
155
|
+
* 起服普查(`approval-batch-census.ts`)用它给存量行记数:读者那条存量臂退役的前提是「零行还靠它读」。
|
|
156
|
+
*
|
|
157
|
+
* **只数,不落任何痕迹**:读不出的元素(`dropped`)与整只值不是列表(`problem`)是 {@link readRuleOfferList} 的计数口径(`server.rule-offers.offer-dropped`),这里不重复记,
|
|
158
|
+
* 它们也不是「靠存量臂读出来」的 —— 一个读不出的无 `kind` 成员(缺文本键)退役前后同样被丢,不改变任何一行的读法,所以不计入。
|
|
159
|
+
*/
|
|
160
|
+
export declare function countKindlessBatchOffers(raw: unknown): number;
|
|
152
161
|
/**
|
|
153
162
|
* 卡面/帧面共用的 offer **投影型**(= {@link RuleOfferSchema} 的输出形)。判别位 `kind` 上闭集,
|
|
154
163
|
* 消费端(SDK/cli 渲染)按 core 契约分臂;`batch.rules` 成员是判别联合(`command` | `directoryRead`),
|
|
@@ -441,11 +450,13 @@ export interface AskClassPair {
|
|
|
441
450
|
* bypass 姿态下按 `ask_rule` / `hook` 照问的那条壳规则无从落地。缺席 = 老行(core 7.5.0 之前 park 的)/ 集外词(计 [ref] tag)。
|
|
442
451
|
* [ref] ②(core 7.37.0 [ref])第六 / 七位 `askClass` / `classes`:这一问的类对(经 {@link readAskClassPair};两位同在同缺,与活卡帧 / 呈卡帧的卡
|
|
443
452
|
* 同名同义同值)—— durable 审批席按类答的依据。缺席 = 老行(core 7.37.0 之前 park 的,续跑不补)/ 读不出(计 [ref] tag)。
|
|
444
|
-
* [ref](core 7.51.0 [ref])第八位 `boundGrantAbsence
|
|
445
|
-
* `
|
|
446
|
-
*
|
|
453
|
+
* [ref](core 7.51.0 [ref])第八位 `boundGrantAbsence` / [ref] 起与 `boundGrantDigest` 合成**一臂**:这张卡的授予绑定 —— `tool_approval` 行**恰带**两者之一,
|
|
454
|
+
* 经本仓唯一读口 `grantBindingOf` 读停驻行、`grantBindingArm` 投回(`standing-answer-grant.ts`;与 core 投 inbox 行的那一臂逐形同值):摘要是串 ⇒ 摘要;
|
|
455
|
+
* 否则摘要键不在且行上的词是闭集成员 ⇒ 那个词;否则(7.51.0 之前停驻的行两者都不说 / 集外词 / 摘要在却不是串)⇒ `unreadable`。`not_bindable` = 这一问不绑任何授予
|
|
456
|
+
* (「本会话放行」可按工具记)。摘要读自停驻行本身 —— 不靠整行的检查点摘要,所以 SQL 腿那一次整行读失败也不丢这一臂;要 core 校验的清单与成因词走
|
|
457
|
+
* 另一只投影 {@link skillCardFacts}。
|
|
447
458
|
*/
|
|
448
|
-
export type ParkRowFacts = Pick<ToolApprovalPark, "requiresRealApproval" | "ruleOffersAbsence" | "mandated" | "mandate" | "origin" | "askClass" | "classes" | "boundGrantAbsence">;
|
|
459
|
+
export type ParkRowFacts = Pick<ToolApprovalPark, "requiresRealApproval" | "ruleOffersAbsence" | "mandated" | "mandate" | "origin" | "askClass" | "classes" | "boundGrantDigest" | "boundGrantAbsence">;
|
|
449
460
|
/**
|
|
450
461
|
* [ref] —— park 行事实的**唯一投影**(`pendingAction` 是寄存行上 core 铸的那一只,读自持久层 ⇒ `unknown`)。
|
|
451
462
|
*
|
|
@@ -465,7 +476,8 @@ export type ParkRowFacts = Pick<ToolApprovalPark, "requiresRealApproval" | "rule
|
|
|
465
476
|
* park 孪生座与同步座是 core 同一个 factory 铸的同一闭集,不另起第二份词表;
|
|
466
477
|
* · `mandate` / `origin` —— 经 {@link readClosedWordSeat}(一座一只 core 成员筛 `isPersistedRuleMandate` / `isAskOrigin`,与 core
|
|
467
478
|
* `summarizeCheckpoint` 投 inbox 行时是同一只筛 ⇒ 两条耐久读面对同一张行同答;集外词读作缺席 + 计同一个集外 tag);
|
|
468
|
-
* ·
|
|
479
|
+
* · 授予绑定([ref])—— 不是「在场才带」的一位,是恰一臂:`grantBindingArm(grantBindingOf(行))`,读法见 {@link ParkRowFacts} 顶注;
|
|
480
|
+
* · 缺席 ≠ false:其余各位都只在「真 / 有词」时在场,消费端读**在场**。
|
|
469
481
|
*
|
|
470
482
|
* 🔴 **这是展示/分诊投影,不是权限判据**(core 对两位的定性都是 display metadata:「the resume belts keep reading
|
|
471
483
|
* the gate's own bit」)。本投影对「在场却读不出」的方向是**缺席**(卡上少一行 ≪ 卡上出现生词);一条要从
|
|
@@ -474,28 +486,31 @@ export type ParkRowFacts = Pick<ToolApprovalPark, "requiresRealApproval" | "rule
|
|
|
474
486
|
*/
|
|
475
487
|
export declare function parkRowFacts(stored: unknown): ParkRowFacts;
|
|
476
488
|
/**
|
|
477
|
-
* 🔴
|
|
489
|
+
* 🔴 **技能卡两位的唯一投影**:授予绑定摘要哈希的那一份清单 `boundGrants`、分类器没给判词的成因 `classifierNoRuling` ——
|
|
478
490
|
* 助手收件箱行(`GET /v1/assistant/inbox`)、运维队列行(`GET /v1/approvals` 的 `pending[]`)、`/v1/approvals/stream` 的 `pending` 帧三张停驻读面
|
|
479
491
|
* **经这一只函数**投它们。同一张停驻的技能卡于是三面同一份字节:运维从队列决这张卡时,看得到批准它还授予了什么。
|
|
492
|
+
* (摘要本身 `boundGrantDigest` 不在这里:它是授予绑定那一臂的一半,队列两面经 {@link parkRowFacts} 从停驻行读 —— core 对串摘要也是原样回显,值相同;
|
|
493
|
+
* [ref] 起这样分,是为了那一臂不依赖整行的检查点摘要读得到读不到。)
|
|
480
494
|
*
|
|
481
|
-
* **输入恒是 core 的检查点摘要**({@link CoreCheckpointSummary},`summarizeCheckpoint` 的产物)——
|
|
495
|
+
* **输入恒是 core 的检查点摘要**({@link CoreCheckpointSummary},`summarizeCheckpoint` 的产物)—— 两位的校验点单点在 core:清单**只在哈希等于摘要时**才发布
|
|
482
496
|
* (「never a list beside a digest that binds another」—— 一份与摘要对不上的清单会让批准人看着一份清单、批的却是另一份绑定);成因词只在闭集成员时回显。
|
|
483
|
-
* 本仓**不重算哈希**(core 的 `boundInputHashOf` 不在公开导出面上,清单校验读口 `readBoundBinding` 同样不导出),所以**不许**拿寄存行 `pendingAction`
|
|
484
|
-
* 原值上的清单是未经哈希校验的(
|
|
485
|
-
* (LOCAL 孪生本来就握着 core 对同一行投的摘要;SQL
|
|
497
|
+
* 本仓**不重算哈希**(core 的 `boundInputHashOf` 不在公开导出面上,清单校验读口 `readBoundBinding` 同样不导出),所以**不许**拿寄存行 `pendingAction` 上的原清单直接投 ——
|
|
498
|
+
* 原值上的清单是未经哈希校验的(这正是它此前不上队列行的原因,见 `trace/core-keyset-guard.ts` ⑧b 记账的旧注)。两只店各自拿到「这一行的摘要」的办法不同
|
|
499
|
+
* (LOCAL 孪生本来就握着 core 对同一行投的摘要;SQL 孪生对可能带两位之一的行读一次该行再调 core 的 `summarizeCheckpoint`,见 `plugins/checkpoint-store-sql.ts`),
|
|
486
500
|
* 但投影只有这一只:OMIT 契约 —— 缺席即缺席,恒不铸 `undefined` 值的键。
|
|
487
501
|
*
|
|
488
502
|
* `boundGrants` 是**部署文本**(技能名、清单条目):本函数不脱敏、不转义,与收件箱行逐字同口径 —— 渲染按上下文转义是客户端的事(契约同句)。
|
|
489
|
-
*
|
|
503
|
+
* 两位都不进 `card_json`(同步路铸点,另一条纪律)。
|
|
490
504
|
*
|
|
491
|
-
* 🚧 清单校验读口 `readBoundBinding` 若成为 core 的公开导出,SQL 孪生那一次整行读与 {@link parkRowCarriesSkillCardFacts} 一并退役:`parkRowFacts` 直接读寄存行原值经 core
|
|
505
|
+
* 🚧 清单校验读口 `readBoundBinding` 若成为 core 的公开导出,SQL 孪生那一次整行读与 {@link parkRowCarriesSkillCardFacts} 一并退役:`parkRowFacts` 直接读寄存行原值经 core 的读口投两位
|
|
506
|
+
* (`grantBindingOf` 也改成它的薄包装 —— 那时 core 是绑定读法的唯一属主)。
|
|
492
507
|
*/
|
|
493
|
-
export type SkillCardFacts = Pick<CoreCheckpointSummary, "
|
|
508
|
+
export type SkillCardFacts = Pick<CoreCheckpointSummary, "boundGrants" | "classifierNoRuling">;
|
|
494
509
|
export declare function skillCardFacts(summary: SkillCardFacts): SkillCardFacts;
|
|
495
510
|
/**
|
|
496
|
-
* 这一行的寄存行(`pendingAction`,读自持久层 ⇒ `unknown`)**有没有可能**让 core
|
|
497
|
-
* `tool_approval` 臂上摘要字段是串(core
|
|
498
|
-
* 绝不漏取:摘要字段不是串 ⇒ core
|
|
511
|
+
* 这一行的寄存行(`pendingAction`,读自持久层 ⇒ `unknown`)**有没有可能**让 core 的摘要投出两位里的任何一位 —— 只回答「值不值得为它取一次摘要」,**不投值**:
|
|
512
|
+
* `tool_approval` 臂上摘要字段是串(core 只在这时回显清单),或成因词键在场(是不是闭集成员由 core 的摘要判)。判错的方向只有一个 —— 多取一次摘要(摘要读数为空),
|
|
513
|
+
* 绝不漏取:摘要字段不是串 ⇒ core 的摘要没有清单;成因词键不在 ⇒ 无成因词 —— 两者都不满足的行,摘要里这两位恒空。普通卡(绝大多数行)因此零额外读。
|
|
499
514
|
* 只读键在不在 / 是不是串,不读值的内容,所以不需要 {@link readClosedWordSeat} 那样的计数。
|
|
500
515
|
*/
|
|
501
516
|
export declare function parkRowCarriesSkillCardFacts(stored: unknown): boolean;
|
package/dist/approval-card.js
CHANGED
|
@@ -4,6 +4,7 @@ import { redactSecrets } from "./trace/redact.js";
|
|
|
4
4
|
import { recordFailOpen } from "./observability/fail-open.js";
|
|
5
5
|
import { readApprovalCard } from "./approval-content-kind.js";
|
|
6
6
|
import { capText } from "./caller-text-echo.js";
|
|
7
|
+
import { grantBindingArm, grantBindingOf } from "./standing-answer-grant.js";
|
|
7
8
|
import { retireParkArmWords, retireStoredCardWords } from "./retired-card-words.js";
|
|
8
9
|
export const MAX_AGENT_NAME = 200;
|
|
9
10
|
const MAX_IDENT = 200;
|
|
@@ -61,6 +62,10 @@ export function readRuleOfferList(raw) {
|
|
|
61
62
|
reading.dropped.forEach((d) => recordOfferDropped(d.problem, d.index));
|
|
62
63
|
return reading.offers.map(withDetailSeatBounded);
|
|
63
64
|
}
|
|
65
|
+
export function countKindlessBatchOffers(raw) {
|
|
66
|
+
const reading = readRuleOffers(raw);
|
|
67
|
+
return "problem" in reading ? 0 : reading.offers.filter((o) => o.kindlessForm === true).length;
|
|
68
|
+
}
|
|
64
69
|
function withoutOverCapDetailSeat(item, index) {
|
|
65
70
|
if (typeof item !== "object" || item === null)
|
|
66
71
|
return item;
|
|
@@ -335,7 +340,6 @@ export function parkRowFacts(stored) {
|
|
|
335
340
|
const mandate = readClosedWordSeat(pendingAction, "mandate");
|
|
336
341
|
const origin = readClosedWordSeat(pendingAction, "origin");
|
|
337
342
|
const askClassPair = readAskClassPair(pendingAction);
|
|
338
|
-
const boundGrantAbsence = readClosedWordSeat(pendingAction, "boundGrantAbsence");
|
|
339
343
|
return {
|
|
340
344
|
...(readParkRowTrueSeat(pendingAction, "requiresRealApproval") ? { requiresRealApproval: true } : {}),
|
|
341
345
|
...(readParkRowTrueSeat(pendingAction, "mandated") ? { mandated: true } : {}),
|
|
@@ -343,12 +347,11 @@ export function parkRowFacts(stored) {
|
|
|
343
347
|
...(origin !== undefined ? { origin } : {}),
|
|
344
348
|
...(ruleOffersAbsence !== undefined ? { ruleOffersAbsence } : {}),
|
|
345
349
|
...(askClassPair ?? {}),
|
|
346
|
-
...(
|
|
350
|
+
...grantBindingArm(grantBindingOf(pendingAction)),
|
|
347
351
|
};
|
|
348
352
|
}
|
|
349
353
|
export function skillCardFacts(summary) {
|
|
350
354
|
return {
|
|
351
|
-
...(summary.boundGrantDigest !== undefined ? { boundGrantDigest: summary.boundGrantDigest } : {}),
|
|
352
355
|
...(summary.boundGrants !== undefined ? { boundGrants: summary.boundGrants } : {}),
|
|
353
356
|
...(summary.classifierNoRuling !== undefined ? { classifierNoRuling: summary.classifierNoRuling } : {}),
|
|
354
357
|
};
|
package/dist/approval.d.ts
CHANGED
|
@@ -95,6 +95,21 @@ export declare function buildNoResponderBootWarns(input: {
|
|
|
95
95
|
hint: string;
|
|
96
96
|
};
|
|
97
97
|
}>;
|
|
98
|
+
/**
|
|
99
|
+
* 单用户 turnkey 起服行 `tool_policy_single_user_default` 的**载荷**(纯数据 ⇒ `build*`;打不打、用哪只 logger 归 stage-07 的调用点,
|
|
100
|
+
* 打的判据是 {@link singleUserAutoAcceptBaselineApplies})。文案只此一处。
|
|
101
|
+
*
|
|
102
|
+
* 它说的是**部署工具策略层**的姿势:这一层铺的是一条在场的、看效果的 allow-all 基线(`createApprovalBaselinePolicy(config, { kind: "absent" })`),
|
|
103
|
+
* 好让引擎的「写手无裁决」告警不再响 —— 这一层自己不问也不拒。它**不是逐调用的放行**:每次调用仍由本次运行的权限模式与引擎写门裁(`auto` 下 shell 的写 / 删
|
|
104
|
+
* 照样出问并交分类器)。修前这一句写成「ALL write/hand/MCP tool surfaces auto-allowed」,读者(含取证)把它读成逐调用放行,与运行期读数相反。
|
|
105
|
+
*/
|
|
106
|
+
export declare function buildSingleUserDefaultPostureNotice(): {
|
|
107
|
+
event: "tool_policy_single_user_default";
|
|
108
|
+
fields: {
|
|
109
|
+
posture: string;
|
|
110
|
+
tighten: string;
|
|
111
|
+
};
|
|
112
|
+
};
|
|
98
113
|
/**
|
|
99
114
|
* [ref] 件⑩ —— **center 的 `forceDurableGate` 在无 checkpoint 店的部署上会静默 inert**,补一条 boot 披露。
|
|
100
115
|
*
|
package/dist/approval.js
CHANGED
|
@@ -53,6 +53,16 @@ export function buildNoResponderBootWarns(input) {
|
|
|
53
53
|
}
|
|
54
54
|
return out;
|
|
55
55
|
}
|
|
56
|
+
export function buildSingleUserDefaultPostureNotice() {
|
|
57
|
+
return {
|
|
58
|
+
event: "tool_policy_single_user_default",
|
|
59
|
+
fields: {
|
|
60
|
+
posture: "deployment tool-policy baseline is allow-all — this layer asks no question and refuses nothing of its own (core's per-surface UNGATED enumeration is suppressed for single-user turnkey). " +
|
|
61
|
+
"It is not a per-call verdict: each call is still judged by the run's permission mode and the engine's write gate — a shell write or delete can still be asked, or handed to the classifier under auto",
|
|
62
|
+
tighten: "APPROVAL_REQUIRE / AUTONOMY / commandPolicy (re-surfaces + gates specific surfaces)",
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
|
56
66
|
export function buildForceDurableGateInertNotice(input) {
|
|
57
67
|
if (!input.entitlementSourceWired || input.checkpointStorePresent)
|
|
58
68
|
return undefined;
|
package/dist/audit.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type SessionPlacementRecord, type StoredPromptEpoch } from "@sema-agent/core";
|
|
2
2
|
import type { Pool } from "mysql2/promise";
|
|
3
3
|
import type { Pool as PgPool } from "pg";
|
|
4
|
+
import { type LocalSessionRows } from "./plugins/local-session-window.js";
|
|
4
5
|
/**
|
|
5
6
|
* Audit view of a session = its **current context** (the live messages + the last compaction's
|
|
6
7
|
* summary), i.e. the floor-bounded window — never the full raw transcript. This matches the
|
|
@@ -76,10 +77,11 @@ export declare function buildSessionAudit(pool: Pool, sessionId: string, handles
|
|
|
76
77
|
* audit face was TiDB-only and a PG/local deployment 404'd the whole web session area. */
|
|
77
78
|
export declare function buildSessionAuditPg(pool: PgPool, sessionId: string, handles?: RewindHandles): Promise<SessionAudit | undefined>;
|
|
78
79
|
/** The LOCAL (File) leg — web session area on DB_BACKEND=local: the same view over `LocalSessionWindow.wake`
|
|
79
|
-
* (`plugins/local-session-window.ts`)
|
|
80
|
+
* (`plugins/local-session-window.ts`), read from the local session store's rows (its row projection and its log export — the view's
|
|
81
|
+
* `createdAt` is the row's, as on the SQL twins). All three legs read one way — a bounded window that carries the epoch anchor below its
|
|
80
82
|
* floor — and on every backend that is what the run reads: the SQL twins' run wakes the same window; the local run wakes the whole
|
|
81
83
|
* tree, and the local window is cut from that tree's branch, with the anchor walking the branch below the floor. */
|
|
82
|
-
export declare function buildSessionAuditLocal(
|
|
84
|
+
export declare function buildSessionAuditLocal(rows: LocalSessionRows, sessionId: string, handles?: RewindHandles): Promise<SessionAudit | undefined>;
|
|
83
85
|
/**
|
|
84
86
|
* 🔴 **会话视图的读面口 —— `GET /v1/sessions/:id` 的全部取法(整读 / `?tail` / `?before` / `?blobCap` / `?message=N`)共用这一只**。
|
|
85
87
|
* 次序 = **选 → 脱 → 截**(路由 `http/routes/sessions.ts`):整条消息的选窗不切字符串,先选窗不改任何一条的脱敏读数、只把脱敏的量降到选中的那几条;
|
package/dist/audit.js
CHANGED
|
@@ -34,8 +34,8 @@ export async function buildSessionAudit(pool, sessionId, handles) {
|
|
|
34
34
|
export async function buildSessionAuditPg(pool, sessionId, handles) {
|
|
35
35
|
return auditFromStorage(await PgSessionStorage.wake(pool, sessionId), sessionId, handles);
|
|
36
36
|
}
|
|
37
|
-
export async function buildSessionAuditLocal(
|
|
38
|
-
return auditFromStorage(await LocalSessionWindow.wake(
|
|
37
|
+
export async function buildSessionAuditLocal(rows, sessionId, handles) {
|
|
38
|
+
return auditFromStorage(await LocalSessionWindow.wake(rows, sessionId), sessionId, handles);
|
|
39
39
|
}
|
|
40
40
|
async function auditFromStorage(storage, sessionId, handles) {
|
|
41
41
|
if (!storage)
|
|
@@ -18,6 +18,7 @@ import type { DeviceStore } from "../device-store.js";
|
|
|
18
18
|
import type { ExecutionPlacementSeat } from "../execution-placement.js";
|
|
19
19
|
import { type DeviceWsHub } from "../device-ws-hub.js";
|
|
20
20
|
import type { ServiceConfig } from "../config.js";
|
|
21
|
+
import type { DeviceRelayDeclaration } from "../config-types.js";
|
|
21
22
|
import type { Logger } from "../observability/logger.js";
|
|
22
23
|
import type { Metrics } from "../observability/metrics.js";
|
|
23
24
|
import type { StoreBackend } from "../plugins/store-backend.js";
|
|
@@ -75,4 +76,14 @@ export declare function createDeviceLane(ctx: DeviceLaneCtx): DeviceLane | undef
|
|
|
75
76
|
* 抛而不是 warn:降级的代价由用户承担(他以为命令跑在自己机器上、看到的却是云上一个空目录的结果)。
|
|
76
77
|
*/
|
|
77
78
|
export declare function assertDeviceLaneWired(isDeviceLane: boolean, lane: DeviceLane | undefined, hasFactory: boolean): void;
|
|
79
|
+
/**
|
|
80
|
+
* 设备入口 × 已绑设备的起服一行(拒的那一半在配置期:device 车道上 `DEVICE_RELAY_URL` 必填,缺席拒起 —— `config.ts` `parseDeviceRelayUrlEnv`;
|
|
81
|
+
* 起不起服不随表里有几条绑定变)。
|
|
82
|
+
*
|
|
83
|
+
* 字面 `none` = 运维声明「设备拨本引擎自己的地址 + `wsPath`」。此刻根会话行上若有设备绑定(writer(device, D) 的格),这些会话的设备从此只能拨那个入口 ——
|
|
84
|
+
* 撤中继声明的回滚序是先恢复引擎自己的入口、再写 `none`,本行让运维看见押在那个入口上的绑定有几条:`device_relay_withdrawn_with_bindings { bindings }`
|
|
85
|
+
* (只交数,不交会话 id)。绑定 0 ⇒ 不响。URL ⇒ 不读表(设备读能力面拨它,与绑定数无关)。
|
|
86
|
+
* 读数 = 设备店的绑定数(唯一读法 `boundDeviceOf` 的聚合);读故障原样抛 ⇒ 起服失败(不折成 0 —— 折 0 就是在有绑定时不响)。
|
|
87
|
+
*/
|
|
88
|
+
export declare function noteDeviceRelayBindings(relay: DeviceRelayDeclaration, store: Pick<DeviceStore, "countDeviceBindings">, logger: Pick<Logger, "warn">): Promise<void>;
|
|
78
89
|
//# sourceMappingURL=device-lane.d.ts.map
|