@sema-agent/server 7.144.0 → 7.145.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 +129 -0
- package/README.md +3 -0
- package/README.zh-CN.md +1 -0
- package/USAGE.md +16 -8
- package/dist/audit.d.ts +2 -21
- package/dist/audit.js +0 -9
- package/dist/boot/session-faces.d.ts +1 -1
- package/dist/boot/session-faces.js +3 -3
- package/dist/boot/stage-09-leader.d.ts +1 -1
- package/dist/boot/stage-10-http-server.d.ts +1 -1
- package/dist/boot/stage-10-http-server.js +2 -2
- package/dist/config-d-migration.d.ts +3 -2
- package/dist/fleet/fleet-bus.d.ts +13 -3
- package/dist/fleet/fleet-bus.js +17 -3
- package/dist/http/admission.js +2 -1
- package/dist/http/checkpoint-ctx.d.ts +1 -0
- package/dist/http/checkpoint-ctx.js +1 -0
- package/dist/http/durable-run-leg.js +7 -6
- package/dist/http/resume-legs.js +5 -3
- package/dist/http/route-ctx.d.ts +15 -0
- package/dist/http/routes/approvals-assistant.d.ts +20 -1
- package/dist/http/routes/approvals-assistant.js +27 -6
- package/dist/http/routes/rules.d.ts +1 -1
- package/dist/http/routes/rules.js +5 -2
- package/dist/http/routes/session-sync.js +12 -0
- package/dist/http/routes/tasks.js +12 -9
- package/dist/http/run-meta.d.ts +14 -7
- package/dist/http/run-meta.js +5 -2
- package/dist/http/server.d.ts +13 -5
- package/dist/http/server.js +3 -0
- package/dist/http/submit-ctx.d.ts +12 -0
- package/dist/http/submit-ctx.js +23 -0
- package/dist/observability/fail-open.d.ts +15 -3
- package/dist/observability/fail-open.js +15 -3
- package/dist/plugins/approval-ask-store-file.d.ts +16 -2
- package/dist/plugins/approval-ask-store-file.js +21 -1
- package/dist/plugins/approval-ask-store-memory.d.ts +8 -2
- package/dist/plugins/approval-ask-store-memory.js +11 -8
- package/dist/plugins/caching-session-store.d.ts +3 -0
- package/dist/plugins/caching-session-store.js +3 -0
- package/dist/plugins/checkpoint-store-sql.d.ts +29 -11
- package/dist/plugins/checkpoint-store-sql.js +38 -16
- package/dist/plugins/file-run-store.d.ts +13 -1
- package/dist/plugins/file-run-store.js +11 -1
- package/dist/plugins/local-checkpoint-store.d.ts +14 -3
- package/dist/plugins/local-checkpoint-store.js +23 -5
- package/dist/plugins/local-session-store.d.ts +52 -16
- package/dist/plugins/local-session-store.js +47 -14
- package/dist/plugins/memory-run-store.d.ts +2 -0
- package/dist/plugins/memory-run-store.js +6 -0
- package/dist/plugins/one-time-migrations.js +2 -2
- package/dist/plugins/run-store-sql.d.ts +4 -0
- package/dist/plugins/run-store-sql.js +3 -0
- package/dist/plugins/session-store.d.ts +1 -1
- package/dist/prompt-screen.d.ts +21 -0
- package/dist/prompt-screen.js +8 -0
- package/dist/rules-consent.d.ts +63 -51
- package/dist/rules-consent.js +6 -10
- package/dist/run-acceptance.d.ts +40 -10
- package/dist/run-acceptance.js +38 -5
- package/dist/runs.js +1 -1
- package/dist/security.d.ts +10 -3
- package/dist/session-agent.d.ts +39 -0
- package/dist/session-agent.js +16 -0
- package/dist/session-error-wire.d.ts +4 -4
- package/dist/trace/model-segment.d.ts +3 -2
- package/dist/trace/model-segment.js +16 -8
- package/dist/trace/redact.d.ts +66 -2
- package/dist/trace/redact.js +220 -101
- package/dist/trace/self-minted-wire.d.ts +73 -1
- package/dist/trace/self-minted-wire.js +27 -0
- package/package.json +2 -2
- package/wire-changes/server@7.145.0.json +146 -0
package/MIGRATION.md
CHANGED
|
@@ -7,6 +7,135 @@
|
|
|
7
7
|
> ⚠️ 完整清单在仓库根 `CHANGELOG.md`——它**不随 npm tarball 出包**(本文件随包)。看完整迁移窗的
|
|
8
8
|
> 权威姿势是源码 tag diff:`git diff v<旧>..v<新>`(每版都推 `v<版本>` tag);npm 包页也镜像 CHANGELOG。
|
|
9
9
|
|
|
10
|
+
## 7.145.0 —— ① 🔴 `DB_BACKEND=local`:带戳存档上会话同步导入的第一阶段也答 `conflict.session_archive_stamped`(wire 加性:多一口答该码;行为修复;部署零动作) ② 运维审批队列的停驻行带它那只会话的 `agent`(委派子代在委派树里的位置;与会话视图同一只读口):后台委派子代停驻的那一行能连回发起委派的会话(wire 加性;行为修复;部署零动作) ③ 订正 7.144.0 节第 12 条「远端五车道不变」一句:k8s / local-docker / ssh / adb / e2b 上家目录主张证不了时,第一句拒是哪一形按命令形、执行面与会话分(文字订正;零行为变更) ④ 🔴 `DB_BACKEND=local`:委派子代转录的建行先记属主、再建存档,进程崩在两笔之间不再留下无主的子代转录(行为修复;持久面;部署零动作) ⑤ 🔴 规则导入:cc-import 兑付时成员表里有引擎拒的成员 ⇒ 落定 200 + 回执逐成员交出,不再 503 `state.rule_import_retry` 到票过期;cc-import 口的 200 体换成与 local-import 口同一张回执 `{ members, rev }`(wire BREAKING;行为修复;部署零动作) ⑥ 🔴 `CONFIG_PROVIDER=local`:配置根里的悬空符号链接(链接在、目标不在)不再读成「缺席」—— `config.d/remote-exec.json` 或 `config.d` 目录链接悬空 ⇒ 起服拒(此前无声落宿主车道),`config.d/<域>.json` 悬空 ⇒ 整份本地候选被判官拒、回落 env(此前读成域缺省);提货 settings-schema 17.0.0;更正 7.144.0 及更早(行为收紧,fail-closed;升级前先查链接) ⑦ 🔴 装着 prompt 屏(`prompt.submit` / `classic.UserPromptSubmit`)的腿:run 行预览、会话自动标题、fleet 行名只取引擎原样交付的目标,屏判完之前不落盘,续跑输入不存目标;屏改写 / 丢弃 / 抛错 ⇒ 这些面缺席(行为修复;机密;wire 值变化:预览可缺席;嵌入方类型面 BREAKING:`ServiceDeps.deploymentMods` 必填) ⑧ 停驻行一行坏字节只坏它自己那一行:SQL 后端的收件箱照列它、带 `rowVerdict`,收件箱与任务视图不再整张 500 / 503;`DB_BACKEND=local` 上别的卡的决断不再被一张坏卡拖成 500,local 的列表面候引擎(行为修复;wire 加性;部署零动作;更正 7.144.0 节第 5 条两句) ⑨ `DB_BACKEND=local`:审批账本里任何真删了行的调用(留存清扫的两只动词与 `deleteByTask`)的那一拍,问账日志 `approval-asks/asks.jsonl` 同拍整本重写成存活行的快照 —— 被删的问的字节(含工具实参字面)当拍离开活文件;订正 7.133.0 节第 14 条 local 一句(行为修复;持久面;部署零动作)
|
|
11
|
+
|
|
12
|
+
1. **🔴 `DB_BACKEND=local`:仍带属主戳的存档上,会话同步导入的第一阶段(`POST /v1/sessions/:id/sync/import`)按 id 分类出 fork / stale 且没带同意时,直接答 409 `conflict.session_archive_stamped` + 带出路句,不再先答通用的 `conflict`(wire 加性:这一口多答一个已在册的码;行为修复;部署零动作)**:
|
|
13
|
+
旧形(7.144.0 节第 10 条「范围」一句):带戳存档上,第一阶段按 id 分类出 fork / stale 且没带同意(`resolution: "overwrite-dst"`)时,仍先答通用的 `409 conflict`(`sync conflict` + `relation`)——
|
|
14
|
+
那一口只按 id 分类、不经提交里的带戳判,所以这两形的推送要到带同意的第二轮才读到出路句,而它指的出路(带同意重来)在带戳存档上是死路。
|
|
15
|
+
新形:第一阶段对这两形先问带戳判的唯一读口(店里「这份存档带不带戳」只有这一只读口,fork 的源与提交里的带戳判问的是同一只),带戳 ⇒ 直接答 `409` + `errorCode:"conflict.session_archive_stamped"` + 同一句固定句
|
|
16
|
+
(体只有 `error` / `errorCode` 两键,不带 `relation`),不开暂存、不拿租约、不写存档(存档原样带戳),重发同答;请求前的门读口照旧可能为从没被读过的旧会话补铸一格只有化身的行格(既有的读时补铸)。
|
|
17
|
+
其余各形不变:`fast_forward`(干净追加 / 载荷分叉)与带同意的 fork / stale,第一阶段照旧受理 200,带戳判仍在提交里、答同一码同一句;匿名存档和 SQL 后端上第一阶段的应答不变(它们没有带戳存档这一形)。
|
|
18
|
+
**谁需要**:壳 / SDK 等对迁移留着的带戳存档(起服 warn `local_archive_kept_stamped` 点名)推送的客户端 —— fork / stale 形的推送在第一阶段就读到「删掉会话后重推」,不再先去试带同意重来。
|
|
19
|
+
**谁受伤**:在第一阶段按 `errorCode == "conflict"` 或体里 `relation` 键判「要解决冲突、带同意重来」的客户端 —— local 部署的带戳存档上,fork / stale 无同意这两形它们不再读到(这两形在带戳存档上本来就解决不了)。
|
|
20
|
+
**补偿**:改读新码 `conflict.session_archive_stamped`(读体的 `error` 即出路:删掉会话 `DELETE /v1/sessions/:id` 后重推);按状态 `409` 分支的不受影响。**升级前做**:无。**回滚**:回到上一版即恢复旧形(本版不写任何新形,落盘数据不受影响)。
|
|
21
|
+
|
|
22
|
+
2. **运维审批队列的停驻行带它那只会话的 `agent`:`{ id?, parentSessionId?, rootSessionId? }`,与 `GET /v1/sessions/:id` 体顶层的同名键同一只读口、逐值同答(wire 加性;行为修复;部署零动作)**:
|
|
23
|
+
旧形:后台委派子代撞审批门停驻后,它那一行在 `GET /v1/approvals` 的 `pending[]` 与 `/v1/approvals/stream` 的 `pending` 帧上 `taskId` 空、`sessionId` = 子代自己的会话,行上没有一位能连回发起委派的那只会话 ——
|
|
24
|
+
只认「本端提交的 run」或「行的会话 = 当前会话」的归属判官认不领这一行,非交互(`-p`)的壳上这张卡没有入口。
|
|
25
|
+
新形:停驻行(`kind: "checkpoint"`)带 `agent` = 行的 `sessionId` 那只会话在会话视图上的 `agent`(`id` = 耐久 agent 行的 `a…` 键;`parentSessionId` = 派它的会话;`rootSessionId` = 委派树的根会话;
|
|
26
|
+
会话行上存的委派元组缺哪一格缺哪一格)。`/stream` 的 `pending` 帧同键同值(新订阅首拍补给的帧与之后推出的帧都带);`resolved` 帧不带。不回填:读的是会话行,升级前停驻的行升级后即带。
|
|
27
|
+
缺席 = 这台 server 没有说,不是「不是子代」:宿主会话自己的停驻行、同步委派的子代、`subagent_type: "fork"` 的后台子代(它的会话是父会话的一只普通分叉,没有委派元组 —— 这一形的停驻行本版仍连不回发起会话)、
|
|
28
|
+
不存元组的店(`DB_BACKEND=memory`)、`DB_BACKEND=local` 在 7.140.x 及以前拷进宿主店的子代转录、那一读没读成(只这一行缺键,列表照出,计 `fail_open_total{tag="server.approvals.queue-row-agent-unreadable"}`)。
|
|
29
|
+
**谁需要**:非交互(`-p`)与交互车道的壳、按「行上的父 / 根会话 = 本会话」认领停驻行的归属判官(一只判官,不另铸)。**谁受伤**:无(加性键)。
|
|
30
|
+
**补偿**:老 server 不带这个键 ⇒ 按原读法(本端提交的 run / 行的会话 = 当前会话)。**升级前做**:无。**回滚**:回到上一版即不带这个键;落盘数据不受影响(本版不写任何新形)。
|
|
31
|
+
|
|
32
|
+
3. **订正 7.144.0 节第 12 条「远端五车道不变」一句:k8s / local-docker / ssh / adb / e2b 上家目录主张证不了时,第一句拒是哪一形按命令形、执行面与会话分(文字订正;零行为变更)**:
|
|
33
|
+
7.144.0 节第 12 条(与契约附录 A 的 `env.home_unconfirmed` 行、USAGE §9 的同一行、DEPLOY-PREREQS 的 `REMOTE_EXEC_HOME_DIR` 节)写这些车道「照旧在开环境那一拍拒、拒句落在工具结果里;递归读形与 adb 上连带路径的普通读先被读边界拦下」。
|
|
34
|
+
7.144.0 发出后的复跑(真引擎 Runner,五条车道的供方换成假的;每格另跑一遍主张 = 实测的负控,只记两遍不同的形)读到的形比这句多,读法以本条为准(已发节原文不改):
|
|
35
|
+
① **环境在开跑前就被打开**:新提交腿上,引擎拿到执行环境后的第一件事是把任务根读成规范路径,这一读就让车道建连、问 `$HOME`、判出拒;引擎把这次失败读作「任务根读不成规范形」,照样开跑(模型照常被调),拒句要等模型的第一条工具调用才再被答出来。模型要跑的命令一条都没进环境(车道自己建根、探 shell、问 `$HOME` 的命令照跑)。
|
|
36
|
+
② **全 shell 面**:不带路径的命令(`echo hi`、`ls`)⇒ 工具结果 `shell_unavailable` + 判官的拒句(点名声明值、实测值与改法)。带路径的命令(路径不在读拒表上 —— 读拒表命中的路径照旧先答读拒表的拒)先撞引擎的读边界(要人批,句子「could not establish what is read」,不点名家目录)的范围:
|
|
37
|
+
`~/` 下的递归读(`grep -r … ~/…`)五条车道都是(ssh 上这一形家目录对得上也先要人批);`~/` 下的普通读(`cat ~/x`)在 ssh、adb 上是(k8s / local-docker / e2b 答判官的拒句);工作区内相对路径的普通读(`cat x`)只在 adb 上是。
|
|
38
|
+
③ **只读面**(`AUTONOMY=read-only`):不带路径的命令同 ②;adb 上工作区内相对路径的读先被读边界拒(句子不点名家目录;家目录对得上时照读)。只读面的读边界不展开 `~`,`~/` 下路径的读在那里不论家目录对不对都被拒 —— 不是这一因。
|
|
39
|
+
④ **ssh / adb 上会话绑了附件**:附件在建执行环境时写进工作目录,写入撞拒 ⇒ run 在开跑前 `failed`、模型零调用,终局**不带码**,句子以 `attachment materialization failed (createDir attachments/): ` 起头、后接判官的拒句;同步提交腿答 200 + `failed` 体(不落零工作拒档)。
|
|
40
|
+
⑤ **从快照恢复的续跑腿**(e2b;配了快照存储的 k8s):恢复出来的沙箱 / pod 对不上 ⇒ 准备期 `resume.env_failed`,句子里带判官的拒句。e2b 会尝试把沙箱重新挂起 —— 挂起成功快照留着,挂起失败只记一行 warn `remote_env_home_refused_repause_failed`、沙箱按自己的寿命到期。
|
|
41
|
+
不从快照恢复的续跑腿(local-docker / ssh / adb,没配快照存储的 k8s:只停驻、不打包)不经恢复,形同 ①–④。
|
|
42
|
+
本版这些车道的行为不变,改法也不变:把 `REMOTE_EXEC_HOME_DIR` 设成环境里 `echo $HOME` 的结果,或让环境的 `HOME` 读声明那个值;删掉声明只在没有出厂答案的车道(k8s / local-docker / ssh / adb)上是一条路 —— e2b 删掉后主张回落 `/home/user`,仍要与 `$HOME` 一致。
|
|
43
|
+
读边界拦下的那几形(② 后半、③)句子里没有家目录,④ 的终局不带码 —— 远端车道上看到这几形时先核一次声明与环境的 `$HOME`。
|
|
44
|
+
**谁需要**:远端车道上排查「为什么这条 run 一读 `~/` 就要人批」「为什么带附件的会话开跑就失败」的运维。**谁受伤**:无(行为不变)。**补偿**:不需要(改法照旧:把 `REMOTE_EXEC_HOME_DIR` 设成环境里 `echo $HOME` 的结果,或让环境的 `HOME` 读声明那个值)。**升级前做**:无。**回滚**:不适用(文字订正,零行为变更)。
|
|
45
|
+
|
|
46
|
+
4. **🔴 `DB_BACKEND=local`:委派子代转录的建行改为先记属主、再建存档 —— 进程崩在两笔之间不再留下属主从没被记下的子代转录(行为修复;持久面;部署零动作)**:
|
|
47
|
+
旧形:local 后端建一只后台子代的转录先建存档(行头带委派元组)、再写会话元数据那一格(属主);进程崩在两笔之间 ⇒ 存档在而属主格缺,重启后这只转录读作无主,
|
|
48
|
+
具名委派树的停驻每次被否决、不自愈。另外存档行头的委派元组里多带了一份属主(引擎不声明这一成员,无人读)。
|
|
49
|
+
新形:先写属主格、再建存档(与登记 / fork / 导入同一写序);崩在两笔之间留下的是一只没有转录的属主格 —— 不是子代转录(不进会话列表、不进委派分区枚举),复活那只子代读到「转录不在」、
|
|
50
|
+
同 id 再建子代转录被拒。建存档失败 ⇒ 盘上不是本次的子代转录(别的写者抢先建了同 id 的存档 / 根本没建成)就撤回刚写的格;引擎写完行头之后才报错 ⇒ 格留着(它就是那只转录的属主);撤不回 ⇒ 响亮报两只故障。新写的元组不再带属主(存档匿名,属主只在会话元数据那一格)。
|
|
51
|
+
**存量**:升级前(7.144.x 及更早)崩在两笔之间留下的无主子代转录不迁移、不回填 —— 照旧读作无主,具名树停驻被否决(响亮)。出路:取消 / 删掉那只后台子代(联合收割随后删它的转录)。
|
|
52
|
+
7.144.x 写下的元组里那一份属主留在盘上、不被读。
|
|
53
|
+
**谁需要**:local 上带身份(具名委派树)的部署。**谁受伤**:崩溃之后同一 id 再建子代转录被拒(引擎新起的子代每次用新 id,复活不重建同 id);残留的属主格不被收割(惰性,不上列表)。
|
|
54
|
+
**补偿**:存量行按上面的出路处置。**升级前做**:无。**回滚**:回到上一版即恢复旧写序;本版写下的子代转录(元组不带属主、属主在格里)上一版照常读。
|
|
55
|
+
|
|
56
|
+
5. **🔴 规则导入:`POST /v1/rules/cc-import/redeem` 兑付时成员表里有引擎拒的成员 ⇒ 这次兑付落定,`200` + 回执逐成员交出,不再 503 `state.rule_import_retry` 到票过期;cc-import 口的 200 体换成与 `POST /v1/rules/local-import/redeem` 同一张回执 `{ members, rev }`(wire BREAKING;行为修复;部署零动作)**:
|
|
57
|
+
旧形:cc-import 口拿到引擎的完整成员表后,只要其中一行被拒,整次兑付就放回认领、答 `503 state.rule_import_retry`(「票还能用,重试」)。引擎的成员拒只带自由文本,永久的裁定也在里面 ——
|
|
58
|
+
引擎对旧导入记录里从 `/` 写起的全局规则(7.142.0 及更早在用户层收下的,如 `Edit(/notes/**)`)兑付期答 `unsupported.layer_root:`。这样一条成员让同票重试一直 503 到票过期(10 分钟),临期答 `404 not_found.rule_ticket`;
|
|
59
|
+
同一记录里已落的成员不撤、被拒的那条永不落。200 体是 `{ result: { members: [{ candidateIndex, behavior, rule, scope: {kind, root?}, status: "persisted" | "deduped", alreadyRedeemed, dot }], rev } }`。
|
|
60
|
+
新形:两只 redeem 口一条规则 —— 兑付走完、拿到完整成员表 ⇒ 落定:`200 { members, rev }`(两键),每个成员一行 `{ key: { behavior, rule, scope }, outcome, reason?, detail? }`,`scope` 是与 `GET /v1/rules` 列举行同形的判别式串(`global` / `project:<root>`),行序是引擎的走序;
|
|
61
|
+
`outcome` = `persisted`(这次写了)/ `no-op`(等价规则已在店)/ `indeterminate`(引擎在这一条上答了拒,带 `reason: "store_refused"` 与 `detail` = 引擎原话;拒因只有自由文本,本服务不猜它是裁定还是瞬时,所以不说落了、也不担保没落)。
|
|
62
|
+
票不放回:cc-import 的票照旧一次性(同票再兑 `404`);local-import 照旧先把回执落进票行(SETTLED)再答 200、同票重放逐字回放,落定这一跳答不成(落定写抛 / 认领被租约接管而新持有者还没落定)时照旧答 `409 conflict.rule_import_in_flight`、同票再来读权威的那份回执。同一个引擎成员拒,两口回执逐字节相同。
|
|
63
|
+
`503 state.rule_import_retry` 只剩**没有完整成员表**的兑付:引擎在走之前整批拒、成员循环走到一半抛、confirm 输给并发写者、店在走之前抛 —— 认领已放回,同一张票重来就是重走一遍;中途抛时此前的成员可能已落,重走交出完整表、那几条读 `no-op`。
|
|
64
|
+
local-import 回执 `reason` 的词表收成一词 `store_refused`(契约此前还列着 `walk_failed`,它从未被铸过:没走完的兑付不落定,没有那一行)。
|
|
65
|
+
**谁需要**:兑付旧导入记录的部署(7.142.0 及更早铸、10 分钟票寿内在本版兑付的导入 —— 滚动升级窗)、任何成员表里含永久被拒成员的 cc 导入。
|
|
66
|
+
**谁受伤**:① 收到 `503 state.rule_import_retry` 就原样重发同一张票的客户端 —— 瞬时的成员拒(店写抖动)不再按票重试,那一行在回执里是 `indeterminate`,票已用掉;
|
|
67
|
+
② 读 cc-import 200 体 `result.members[].status`(或 `candidateIndex` / `alreadyRedeemed` / `dot`)的客户端 —— 那一形退出 wire,体里不再有 `result` 键,只读那一形的计数读口会读出「看不懂的结局形」。
|
|
68
|
+
**补偿**:按回执的成员行读结局 —— `persisted` / `no-op` 是落了;`indeterminate` 读 `detail`(引擎的话即出路,`unsupported.layer_root:` 那句自己写着「重新 prepare,这一条会披露在 skipped」),
|
|
69
|
+
对账读 `GET /v1/rules`(按 `key` 的三格比),要补就重新走一次导入(幂等,已落的读 `no-op`);cc-import 与 local-import 同一只读口。`503 state.rule_import_retry` 的读法不变(拿同一张票重试)。滚动升级窗里 7.144.x 与本版的副本并存时,同一个客户端可能先后读到两种 200 形(`{ result: { members, rev } }` / `{ members, rev }`):读口两形都认,旧形那一支在客户端自己的下个版本里删。
|
|
70
|
+
**升级前做**:无。**回滚**:回到上一版即恢复旧形(成员拒 503 到票过期、cc-import 体 `{ result: … }`);local-import 票行里写下的回执形不变,上一版读得回。
|
|
71
|
+
|
|
72
|
+
6. **🔴 `CONFIG_PROVIDER=local`:配置根里的悬空符号链接(链接在、目标不在)不再读成「缺席」—— `config.d/remote-exec.json` 或 `config.d` 目录链接悬空 ⇒ 起服拒(`run-local` 退 2);`config.d/<域>.json` 悬空 ⇒ 整份本地候选被判官拒、回落 env,`config_candidate_rejected` 与 `GET /v1/models` 的 `candidateRejected` 点名(行为收紧,fail-closed;提货 `@sema-agent/settings-schema` 17.0.0;更正 7.144.0 及更早;升级前先查链接)**:
|
|
73
|
+
旧形(7.144.0 及更早,发车时作为已知限制披露过的那一形):悬空链接上读文件得 `ENOENT`,本服务读 `config.d` 的契约读者把它读成「文档缺席」。`config.d/remote-exec.json` 悬空 ⇒ 执行车道合成步当文件缺席,引擎落缺省车道
|
|
74
|
+
(`CONFIG_PROVIDER=local` ⇒ host),文件里写的是 `local-docker` 也一样 —— 链接一断(卷没挂上 / NFS 掉了 / 目标被删),隔离车道无声降成宿主车道;`config.d/<域>.json` 悬空 ⇒ 域缺省(`governance.json` 里的护栏不生效);
|
|
75
|
+
`config.d` 目录链接悬空 ⇒ 整个 `config.d` 读成不存在。起服日志上唯一的信号是一次性迁移那一行 `config_dir_migration_failed`,而且只对文档链接出(目录链接悬空连它都没有)。
|
|
76
|
+
新形:契约 17.0.0 起「缺席 = 路径上没有任何条目」,悬空链接是「在场却读不出」,读它拒,句子点名链接、目标与出路:`<链接> is a dangling symbolic link (it points at <目标>, which does not exist) — nothing is read or written through it; repair or remove the link`
|
|
77
|
+
(与一次性迁移的读口同一句)。三处读点各走既有的拒路,本服务零改码:
|
|
78
|
+
① `config.d/remote-exec.json` 悬空、或 `config.d` 目录链接悬空 ⇒ 起服拒:一行 `remote_exec_file_invalid`,fatal 句 `config.d/remote-exec.json under <配置根> is invalid: <悬空句>`,进程非零退出,不进入服务、不落宿主车道(`run-local` 同一读点:退出码 2、同一句);
|
|
79
|
+
② `config.d/<域>.json` 悬空 ⇒ 本地读腿交出的拒单里多一条 `{ document, reason: "io", error: <悬空句> }`,候选判官整拒这份本地候选(`config.d` 里别的域也一个不应用,起服回落 env —— 与同一份文档写坏 JSON 同形):
|
|
80
|
+
一行 `config_candidate_rejected`(`domains` 点名这份文档、`errors[].reason` = `io`、悬空句),`GET /v1/models` 顶层 `candidateRejected`(域名 + 源 `local`)在场;刷新拍保持当前已应用的配置并原样重判,修好链接即落地。回落 env 之后起服的缺省模型检查照常:有 `MODEL_ID` ⇒ 照常起服、服务 env 表;没设 `MODEL_ID`、模型只配在 `config.d/models.json` ⇒ 起服拒 `config.default_model_missing`(拒句不点名链接 —— 先出的 `config_candidate_rejected` 行点名);
|
|
81
|
+
③ 一次性迁移对悬空的 `config.d` 目录链接仍答「没有 `config.d`」、不出声(迁移的读口先 `stat`)—— 读者的拒(①)是目录链接悬空这件事唯一的信号,也是够用的信号;对悬空的文档链接,迁移那一行 `config_dir_migration_failed` 照出,读者的拒是它之外的第二行(同一句)。
|
|
82
|
+
不在本条范围:配置根自己(或更上层)是悬空链接 —— 读法不变(读成缺席);`<配置根>/.env`:本服务不读(契约的 `loadEnvFile` / `loadLocalConfig` 本仓零调用),悬空的 `.env` 对本服务无影响。
|
|
83
|
+
**谁需要**:`CONFIG_PROVIDER=local` 且把 `config.d`、其下的文档(尤其 `remote-exec.json`)链到卷 / NFS / 部署工具链管理路径的部署 —— 要的是「链接断了 ⇒ 起服响亮」,断链不许悄悄把隔离车道变成宿主车道。
|
|
84
|
+
**谁受伤**:今天带着悬空链接静默跑缺省的部署(升级前它们没有任何一行错误):`remote-exec.json` / `config.d` 目录链接悬空的升级后起不来;域文档悬空的整份本地候选被拒(`config.d` 里别的设置也不生效,直到修好):有 `MODEL_ID` 兜底的照常起服、服务 env 表;**没有 `MODEL_ID`、模型只配在 `config.d/models.json` 的部署也起不来**(缺省模型检查拒启,见 ②)。
|
|
85
|
+
**补偿**:拒句自带出路 —— 修好链接(挂上卷 / 恢复目标)或删掉它(删掉 = 回到缺席时的缺省:`remote-exec.json` 缺席 ⇒ 缺省车道)。**升级前做**:在每个本地配置根(`CONFIG_LOCAL_DIR` → `AGENT_DATA_DIR` → `~/.ai-agent`)上跑
|
|
86
|
+
`find -L <配置根> -maxdepth 2 -type l`(`-L` 之下只有悬空的链接还显示为链接;空输出且退出码 0、stderr 无报错 = 无事可做,权限不够时 `find` 会漏列);命中 `config.d` 目录链接本身、或 `config.d/` 下的 `*.json`(本服务读的就是这一集:便携域文档、退役域的墓碑文件、`remote-exec.json`)的先修好或删掉;配置根上的根级文档 `config.env-models.json` 悬空的读法本版不变(契约的根级文档读者一直把它读成读不出、不读成缺席);其余命中与本服务无关。**回滚**:回到上一版即恢复旧形(读成缺席);本条不改任何落盘数据。
|
|
87
|
+
|
|
88
|
+
7. **🔴 装着 prompt 屏的腿:本服务存 / 转目标的面只取引擎原样交付的那一份,屏判完之前不落盘;屏改写 / 丢弃 / 抛错 ⇒ 这些面缺席(行为修复;机密;wire 值变化;嵌入方类型面 BREAKING)**:
|
|
89
|
+
旧形:一次提交的目标有三处早于部署的 prompt 屏(扩展站 `prompt.submit` 的改写 / 丢弃 / 抛错,`classic.UserPromptSubmit` 的拦截)落盘或外送:建 run 行时写预览列(`GET /v1/tasks` 行的 `objectivePreview`、`GET /v1/assistant/tasks` 的行名、助手收件箱行的 `objective`、会话列表的回退与 fleet 行的 `name` 同读这一列);
|
|
90
|
+
续跑输入(checkpoint ctx)存整份请求体;屏改写过的目标仍拿请求原文去起会话标题(原文进标题模型的请求)。模型与会话转录只见屏后文本,屏前文本却留在这几处。
|
|
91
|
+
新形:一条律 —— 本服务的目标副本 = 引擎交付的那一份,屏判完之前一个字节都不存。这条腿的部署座(交给 Runner 的 `mods`)或任务座(`settings.hooks` 的 `UserPromptSubmit` 那一张)声明了这两站之一(含 `prompt.*` / `classic.*` 通配)⇒
|
|
92
|
+
提交时预览列 NULL、fleet 行不带名、续跑输入里的目标留空串;目标的受理帧(`human_input{ carrier: "objective", delivery: "applied" }`)不带 `rewrittenBy`(原样送达)⇒ 这一拍补上预览、给 fleet 行补名、起标题;
|
|
93
|
+
受理帧带 `rewrittenBy`,或没有受理帧(丢弃 / 抛错 / 受理前取消或失败)⇒ 这些面一直缺席、标题器不起。引擎今天不把屏后文本交给宿主,所以改写过的那一臂是缺席,不显示屏后文本(引擎交出之后改读它,律不变)。
|
|
94
|
+
只回结果的腿(`verify` / `cascade` 形)看不到受理帧 ⇒ 有屏时预览、标题、fleet 行名缺席。**例外(已知债)**:`verify` 形提交的续跑输入照旧存请求原文(停驻后的续跑把它交给验证器当任务陈述),每次计 `fail_open_total{tag="server.objective-delivery.verify-replay-copy"}`。
|
|
95
|
+
**不在本条覆盖**:leader 车道 durable worker 的子目标续跑输入(`src/leader/wire.ts` 每只 worker 铸续跑上下文的写序)不经受理座、不打标记,屏前原文照旧落盘 —— 另票。
|
|
96
|
+
续跑输入里的目标在有屏的腿上一直留空(交付之后也不补:续跑期间还有别的写者改写这一行 —— 权限模式切档口的回写 —— 交付时的补写会与它抢写);读它的只有两处展示:wake 腿新建的 run 行预览与续跑腿的 fleet 行名,
|
|
97
|
+
这类腿写下的续跑输入一律缺席(`verify` 形那份照存的原文也不进这两处 —— 它只给验证器)。目标里的内联 `@名`(用户点模型)随目标一起留空 ⇒ 请求没带 `model` 时,续跑输入的 `model` 记下这次选中的那只模型,续跑腿照旧跑它。没有声明这两站的腿逐字不变(提交时照写)。补写失败(店抖动)⇒ 那张面保持空、run 照跑,计 `fail_open_total{tag="server.objective-delivery.face-fill-failed"}`。
|
|
98
|
+
嵌入方:`createHttpServer` 的 `ServiceDeps` 多一只必填件 `deploymentMods`(交给 Runner 当 `mods` 的同一只数组;没有 mod 传 `[]`)—— 省掉是编译错;绕过类型省掉 ⇒ 构造期拒启,句子以 `createHttpServer: the deploymentMods seat is required` 起头。
|
|
99
|
+
**谁需要**:装 prompt 屏做内容过滤 / 改写的部署 —— 屏拦下或改写的原文不再留在 run 行、续跑输入里,也不再送进标题模型的请求。
|
|
100
|
+
**谁受伤**:① 这类部署上,被屏改写 / 拦下的 run 在任务列表、收件箱、fleet 面板上不显示「这是什么任务」(预览缺席,客户端渲占位),也不自动起会话标题;有屏的 `cascade` 提交同样缺席;订 `prompt.*` / `classic.*` 通配的只观察型运维 mod 也被算成屏(判据读声明,与引擎的通配语义一致):这类部署上只回结果的腿(`verify` / `cascade`)的预览 / 标题 / fleet 行名同样缺席,wake 新建的 run 行与续跑腿的 fleet 行名同样缺席,其余腿按 ② 在受理那一拍补上;
|
|
101
|
+
② 原样交下的 run,预览在受理那一拍才出现(建行到受理之间读列表读不到预览);有屏的腿上 wake 新建的 run 行没有预览、续跑腿的 fleet 行不带名(原样交下也一样);③ 嵌入方 tsc 红 / 起服拒;④ 升级前写下的续跑输入与 run 行不改写 —— 那些行里的屏前文本留到它们被收割或会话被删。
|
|
102
|
+
**补偿**:① 预览缺席时行上其余键照旧,会话标题可手工设;要预览的部署可让屏原样交下(只加上下文、不改写);② 无;③ 把交给 Runner 的同一只 `mods` 数组传进 `deploymentMods`(没有 mod 传 `[]`);④ 要清旧行的部署按既有留存窗收割或删会话。
|
|
103
|
+
**升级前做**:嵌入方补 `deploymentMods`;其余零动作(零 DDL)。**回滚**:回到上一版即恢复旧形;本版留空的续跑输入在上一版上续跑时目标是空串(只影响 wake 腿新行的预览与 fleet 行名的显示);本版有屏的 `verify` 形续跑输入在上一版上续跑时,那份原文会进 wake 新行的预览与 fleet 行名(上一版不读这类行上的标记)。
|
|
104
|
+
|
|
105
|
+
8. **停驻行一行坏字节只坏它自己那一行:SQL 后端的助手收件箱照列它、带引擎判官的 `rowVerdict`,收件箱与任务视图不再整张 500 / 503;`DB_BACKEND=local` 上别的卡的决断不再被一张坏卡拖成 500;local 的列表面候引擎;更正 7.144.0 节第 5 条两句(行为修复;wire 加性:坏行在场、`rowVerdict` 在场面放宽;部署零动作)**:
|
|
106
|
+
旧形:同库一张停驻行的存储体被手改坏(`{}`;整段缺 `state` / `pendingAction` / `gate`;非 JSON / JSON 字面 `null` / 标量 / 数组)。
|
|
107
|
+
SQL 后端:助手收件箱 `GET /v1/assistant/inbox` 与任务视图 `GET /v1/assistant/tasks` 整张拒 —— `{}` / 缺 `state` 落 `503 approvals.read_unavailable`(「稍后重试」,而坏行不修同一请求恒失败)、
|
|
108
|
+
存储体非 JSON / 字面 `null` 落 `500 approvals.read_corrupt`;同一张卡在运维队列 `GET /v1/approvals` 上照列(同一张坏行两个读者两个方向),队列上存储体读不成检查点的那一行不带 `rowVerdict`。
|
|
109
|
+
`DB_BACKEND=local`:一张缺 `state` 的卡让运维队列与收件箱对所有调用 `503 approvals.read_unavailable`,另一张好卡的决断 `500 internal.error`,坏卡自己的决断同样 500。
|
|
110
|
+
新形:店的每一个停驻行读者一种失败方向 —— 逐行隔离,同一只判官(引擎的 `judgeCheckpointRow`)判坏行。
|
|
111
|
+
① SQL 后端的收件箱照列那一行:`rowVerdict` = 判官对这份字节的判决(上面这些形今天答 `damaged` · `checkpoint.invalid_outcome` · `requirements_damaged`;例外:只缺 `pendingAction` 的行判官答 `ok` —— 引擎判官的已知缺口,这张卡的决断会失败),其余只带列事实
|
|
112
|
+
(`sessionId` / `scope` / `createdAt` / `gateKind` / `deadline` / `checkpointId`),摘要派生的键缺席、`input` 为 `null`;门型列读不出的行照旧不列。任务视图不再整张拒:那条 run 照列,`gate` 的 `severity` / `spentMicroUsd` 为 `null`(任务视图的行不带 `rowVerdict`,7.144.0 起就如此 —— 判决读收件箱或运维队列)。
|
|
113
|
+
② 运维队列行上存储体读不成检查点的那一行也带 `rowVerdict`(判官对原样字节作答,恒 `damaged`)。两种读者同计 `fail_open_total{tag="server.approvals.park-row-blob-unreadable"}`(每次列表各计一次)。
|
|
114
|
+
③ 决断只读自己那一行:local 后端按会话的三个读口(决断选行 / 属主门的 scope 预读 / 会话删除)改经引擎店的按会话读,一行读不出只坏它自己 —— 别的卡的决断照常 200;
|
|
115
|
+
坏卡自己的决断答 409 带码拒、卡仍待决、字节不动(续跑第一级判官的拒:今天落 `approval_binding_mismatch` + 体顶层 `reason: "requirements_damaged"`、`retriable: true`)。
|
|
116
|
+
SQL 后端的决断本来就按会话选行(别的卡不受影响);它上面坏卡自己的决断:缺 `state` 这类同上,存储体 `{}` 落 `gate_not_tool_approval`(决断口的门型守卫读存储体的门)。坏卡的决断码与行上 `rowVerdict.code` 尚未收成同一个码。
|
|
117
|
+
**local 列表面本版未收**:local 后端的列举经引擎店的按 scope 列举,一行摘要读不动整只抛 ⇒ 运维队列 / 订阅流 / 收件箱 / 任务视图照旧整张 `503 approvals.read_unavailable`,候引擎对这种行答一行(带判决);
|
|
118
|
+
local 上存储体 `{}` 的行在引擎店重放时即被丢弃并披露,读作「这一行不在」(列表只列别的行、它的决断 404)。
|
|
119
|
+
**更正 7.144.0 节第 5 条(文书)**:那一条的「缺席(存储体解不出 / …)不是 `ok`」与「存储体解不出的行照列、不带 `rowVerdict`」两句,自本版起 SQL 后端上存储体解不出的行带 `rowVerdict`;缺席只剩「两次读之间行离开待决或字节变了」。7.144.0 节原文不改(已发节字节不动)。
|
|
120
|
+
**谁需要**:运维与助手壳 —— 一张手改坏 / 迁移残留的停驻行不再让整张收件箱、任务视图打不开,local 上也不再让别人的卡决不掉;坏行本身在列表上看得见(人要知道它停在哪)。
|
|
121
|
+
**谁受伤**:① 把收件箱 / 任务视图的 503 读作「店在抖、稍后重试」的监控:坏行这一形不再出 503;② 假设收件箱行恒有 `severity` 等摘要键、`input` 恒有内容的客户端:坏行上它们缺席(`input` 为 `null`)—— 契约本来就把它们标为可缺席;
|
|
122
|
+
③ 把运维队列行 `rowVerdict` 缺席读作「存储体坏」的看板:那一形改为在场的 `damaged`。
|
|
123
|
+
**补偿**:按 `rowVerdict.kind !== "ok"` 把行呈成不可批的卡、把 `sentence` 原句给人;找坏行看计数 `server.approvals.park-row-blob-unreadable`,按会话查那一行修或删。**升级前做**:无。**回滚**:回到上一版即恢复整张拒形;落盘数据不受影响(本版不写任何新形)。
|
|
124
|
+
|
|
125
|
+
9. **`DB_BACKEND=local`:审批账本里任何真删了行的调用(留存清扫的两只动词与 `deleteByTask`)的那一拍,问账日志 `approval-asks/asks.jsonl` 同拍整本重写成存活行的快照 —— 被删的问的字节(含工具实参字面)当拍离开活文件;订正 7.133.0 节第 14 条 local 一句(行为修复;持久面;部署零动作)**:
|
|
126
|
+
旧形:7.133.0 起的留存清扫(和删一个 run 名下全部问行与批行的 `deleteByTask`)在 local 上把每次真删当一条写调用追加进 `asks.jsonl`,被删的问行 —— 连同卡上的工具实参(`Write` / `Edit` 的内容字面)—— 的字节仍留在文件里,
|
|
127
|
+
直到记录数过阈(≥ 2000 条且 ≥ 存活行数的两倍)才整本重写;写得少的部署上,「整问删掉」之后的字节可以在盘上留很久(要等记录数过阈)。
|
|
128
|
+
而 7.133.0 节第 14 条与 USAGE「审批账本保留多久」一段对运维写的是「它在三本账里的全部记录由维护 tick 整问删掉」,没有 local 的限定:SQL 两方言的 `DELETE` 当即成真,审计账的轮转本来就整文件原子重写,只有 local 问账日志不是。
|
|
129
|
+
新形:任何删行的调用(留存清扫的问行 / 批行两只动词与 `deleteByTask`)真删了 ≥ 1 行 ⇒ 同一拍把整本账原子重写成存活行的快照(既有的压实动作;没有新阈值、没有新旋钮),活文件里只剩存活行;没删东西的调用不落记录、不重写(`deleteByTask` 零删原先会落一条无用的记录,现在同样不落);普通写的压实阈值(≥ 2000 条且 ≥ 存活行数的两倍)不变。
|
|
130
|
+
压实失败(盘满 / 只读挂载 / 压实落点不可写)不影响删行的调用:行照删,计 `fail_open_total{tag="server.approval-ask-journal.compaction-failed"}`,账本里留着那条删行记录,下一次写(任何写)或下一次起服再压实 —— 到那时字节才离盘。
|
|
131
|
+
升级前删过行的账本:起服重放到账本里的删行记录(升级前的清扫或 `deleteByTask`,或上面失败的那一次)⇒ 起服压实一次(信封 1 的老账本同一次压实顺带写成信封 2,迁移的 local 腿读数照报、不再重写第二次),此后活文件里没有被删的问的字节;账本里没有删行记录的部署,起服不因删行而重写(撕尾 / 坏行收拢、信封升级、车道回填各自的重写照旧)。
|
|
132
|
+
**边界(如实)**:① 留存清扫的问行、批行动词各按批删(每批至多 500 行),每个真删了行的调用重写一次整本 —— 一次清扫的重写次数 = ⌈删掉的问数 / 500⌉ + ⌈删掉的批数 / 500⌉(删掉的问与批各不到 500 只的清扫至多两次;积压的头几次清扫更多);写的是存活行的快照,同步跑在事件循环上,
|
|
133
|
+
量级(本机单次读数,合成账本):1 万行 × 2 KB 的存活账本约 0.15 s,3 万行 × 5 KB(约 160 MB)约 1 s;② 压实是原子换文件,不是文件系统层的安全擦除(空闲块、备份、快照不在本服务手里);
|
|
134
|
+
③ 起服时因撕尾 / 坏行隔离出去的原件 `asks.jsonl.corrupt-<ts>` 没有清扫腿,里面仍有当时的字节 —— 取证材料,要清由人来(正常部署恒零)。
|
|
135
|
+
**订正 7.133.0 节第 14 条(文书)**:那一条「从三本账里整问删掉」在 `DB_BACKEND=local` 的问账日志上,7.144.0 及更早是「读不到了」—— 字节要等记录数过阈的压实才离盘;自本版起与 SQL 同拍。7.133.0 节原文不改(已发节字节不动)。
|
|
136
|
+
**谁需要**:把审批账本的留存窗当机密 / 取证边界的 local 部署(过窗的问里有 `Write` / `Edit` 实参这类内容,按窗期待它离盘)。**谁受伤**:无 —— 每次真删了行的调用多一次整本重写(留存清扫每小时至多一次、通常问行与批行各一次;`deleteByTask` 本服务自己的路径不调用它;体量随窗内存活的问走),读数 / 日志形不变。
|
|
137
|
+
**补偿**:不需要。**升级前做**:无。**回滚**:回到上一版(7.144.0)⇒ 账本照读(存活行快照是既有的压实形,上一版认这三只删行动词);删行回到「追加记录、过阈才重写」。
|
|
138
|
+
|
|
10
139
|
## 7.144.0 —— 🔴 会话日志回放丢了记录:用户面通告只剩引擎的 `session.lineage_rerooted`(`session.records_skipped` 退役)、丢了分支上祖先的会话从断点续上、走不成一棵树的已存日志答 `corrupt_session`(打开面 `invalid_session` 退役)(wire BREAKING:一个通告码与一个错误码退出;行为修复;部署零动作) · 跨会话来信有序关停:info 行字段改为 `{ queues, cards }`、回执没落进发信方的箱每条一行 warn(运维面;日志形变更) · 引擎在没有自己席的地方说的话落结构化 `engine_notice` 日志行,不再是裸 `console.warn` 句(运维面;日志形变更) · 🔴 `DB_BACKEND=local`:数据根里的会话元数据边档本构建读不出(更新的引擎写下 / 损坏 / 读不了)⇒ `ensureSchema()` 拒启 `config.schema_mismatch`,开始服务之前判(行为修复;fail-closed;持久面;零 DDL) · SQL 后端:更新引擎停驻的行续跑 / 决断答 409 `checkpoint.unsupported_version`(不再答 `conflict.checkpoint_unreadable`)、运维队列行与助手收件箱行带 `rowVerdict`(wire 拒码改答 + 加性;部署零动作) · 持久问店车道上同一只审批问被另一腿再问时,「这一问要人」取行上那张卡与这一腿请求的并集(安全;行为收紧;wire 零形变;部署零动作) · 🔴 引擎 7.62.0:部署的 mod 包按内核契约 8 重建(部署面;BREAKING) · 远端五车道的私有暂存目录多一道 ACL 核:继承来的 ACL 条目去不掉 / 读不出 / 目标机系统不在闭集里 ⇒ 不暂存,退回就地写目标(行为收紧,fail-closed;安全;部署零动作) · 🔴 活流文字段的脱敏单位收成段(与账本 `text` 行同一个):引擎的 `text_end` 是文字块的交付点、不收段,锚与值分在同一段两块时 `text_delta` / `text_end` 照样遮;更正 7.143.0 节第 11 条「文字段的单位是引擎的文字块」一句(wire 值语义;安全;部署零动作) · 🔴 `DB_BACKEND=local`:仍带属主戳的存档的拒有了自己的码 `conflict.session_archive_stamped`,fork 与改日志的各形推送(含载荷分叉的 fast_forward)同码同句(wire BREAKING:这两扇写口上带戳存档的拒由 `conflict` 改新码;行为修复;部署零动作) · 更正 7.143.0 节五处说法:退役工具名写进 deny / ask 规则时按名单的来源各答各码(请求体 422 `request.unprocessable` · 部署名单拒启 · `config.legacy_tool_name` 只来自存量会话规则)、`decidedVia` 在直连门部署上哪几口不收、续跑门 `/resume` 的真路由、user 层要根的 allow 免不了配置根下写保护表上的写、被拒的个人层抹除与点名个人层的只读也会在盘上留下一只从没写过的个人店(文书;零行为变化) · host 车道:执行环境的家目录主张证不了 ⇒ 环境在开跑前就不铸,run 失败终局码 `env.home_unconfirmed`(同步提交腿 409),命令带不带路径同一首拒;worktree 的 git 基环境不再带家目录主张;更正 7.140.0 节第 12 条 ③(wire 新码;行为修复;部署零动作)
|
|
11
140
|
|
|
12
141
|
1. **🔴 `DB_BACKEND=local`:会话日志回放丢了读不出的记录 —— 用户面只剩一只帧 `session.lineage_rerooted`(引擎铸),本服务自铸的 `session.records_skipped` 退役;丢了分支上祖先的会话从断点续上;走不成一棵树的已存日志答 `corrupt_session`,打开面不再出现 `invalid_session`(wire BREAKING;行为修复;部署零动作)**:
|
package/README.md
CHANGED
|
@@ -136,6 +136,9 @@ curl -s localhost:8090/v1/tasks -H "Authorization: Bearer <SERVICE_AUTH_TOKEN>"
|
|
|
136
136
|
`createHttpServer` requires the `authorize` seat — the only resolver of a submission's root session (the server stamps
|
|
137
137
|
that root onto every spec it runs; `resolveSpec` returns no `sessionId` and reads `opts.execution.root` when it needs it).
|
|
138
138
|
A single-user embedding passes `createAuthorizer(config, runner.sessions)` (package root); omitting the seat refuses at construction.
|
|
139
|
+
Since 7.145.0 it also requires `deploymentMods` — the very array the Runners carry as `mods` (`[]` for an embedding without mods): the server reads it to
|
|
140
|
+
learn whether a prompt screen runs on a leg, and on such a leg stores objective text only once the engine delivered it unchanged (two paths sit outside that: a `verify`
|
|
141
|
+
submission's resume input keeps the request text for its verifier, and that copy is never shown; and the leader lane's durable-worker sub-goal resume inputs, which do not go through that seat and are still stored as submitted — tracked separately); omitting it refuses at construction.
|
|
139
142
|
Build-time tools (e.g. a catalog editor) read two allowlists from the package root instead of hand-copying them: `RETIRED_ENVS` (the retired-env
|
|
140
143
|
tombstones) and, since 7.110.0, `CATALOG_ENTRY_HEADER_LANES` / `CATALOG_ENTRY_HEADER_NAMES` (+ type `CatalogEntryHeaderName`) — the closed allowlist of
|
|
141
144
|
model-catalog entry `headers` and the API line that reads each name. Both are frozen, the very objects the server judges with.
|
package/README.zh-CN.md
CHANGED
|
@@ -117,6 +117,7 @@ curl -s localhost:8090/v1/tasks -H "Authorization: Bearer <SERVICE_AUTH_TOKEN>"
|
|
|
117
117
|
`assertExecutionLaneInvariants(config)` 是同一份判据,不做 `config.d/remote-exec.json` 覆写。
|
|
118
118
|
`createHttpServer` 的 `authorize` 席是必填:它是一次提交的根会话唯一的来源(server 把这只根盖进它执行的每一只 spec;`resolveSpec`
|
|
119
119
|
不返回 `sessionId`,要用根时读 `opts.execution.root`)。单用户嵌入传 `createAuthorizer(config, runner.sessions)`(包根导出);省掉即构造期拒。
|
|
120
|
+
7.145.0 起它还要 `deploymentMods`:交给 Runner 当 `mods` 的同一只数组(没有 mod 传 `[]`)—— server 从它读这条腿上有没有 prompt 屏,有屏的腿只在引擎原样交付之后才存目标文本(有两处在此之外:`verify` 形提交的续跑输入为验证器留着请求原文,那一份从不展示;leader 车道 durable worker 的子目标续跑输入不经这一座,屏前原文照旧落盘 —— 另票);省掉即构造期拒。
|
|
120
121
|
构建期工具(如目录编辑页)从包根取两张表、不手抄:`RETIRED_ENVS`(退役 env 墓碑)与 7.110.0 起的 `CATALOG_ENTRY_HEADER_LANES` /
|
|
121
122
|
`CATALOG_ENTRY_HEADER_NAMES`(+ 型 `CatalogEntryHeaderName`)—— 模型目录条目 `headers` 的闭集白名单及读每个名字的线路。两者都冻结,就是服务端自己判据用的那一只。
|
|
122
123
|
壳要知道一台在跑的引擎服务的是哪张模型表、目录采纳了没有、起服路由判官怎么说,读 `GET /v1/models` 的 `modelPlane`
|
package/USAGE.md
CHANGED
|
@@ -173,6 +173,11 @@ ANTHROPIC_API_KEY=sk-ant-… # 可选:ANTHROPIC_BASE_URL / ANTHROPIC_VERSION /
|
|
|
173
173
|
引擎注入的 `<system-reminder>` / `<task-notification>` / `<attachment>` 块,以及壳铸进用户轮的**本地命令回显**(`<command-name>` / `<command-message>` / `<command-args>`、`<local-command-stdout>` / `<local-command-stderr>` / `<local-command-caveat>`、
|
|
174
174
|
`<bash-input>` / `<bash-stdout>` / `<bash-stderr>` / `<bash-exit-code>`、`<user-memory-input>`)都不算你写的:`/compact` 一类本地命令之后的下一条提交,预览与标题取的是随后那句话,不再是回显;只有回显、没有你的话 ⇒ run / leader 行的预览是空串(任务名折成 `(notification turn)`),会话列表的预览回落到更早的一句、都没有则缺席(`null`)。
|
|
175
175
|
代价:正文里真的写了这些开标签字面的那一段在预览 / 标题里被剥(只是**提到**这些词的原样保留),原文在会话历史读面完整可见。
|
|
176
|
+
- **装了 prompt 屏的部署,预览与标题只取引擎原样交付的目标**(7.145.0+):部署座的 mod 包或请求的 `settings.hooks` 声明了 `prompt.submit` / `classic.UserPromptSubmit` 的腿,建 run 行时不写预览、续跑输入里的目标留空、fleet 行不带名;
|
|
177
|
+
目标的受理帧原样送达(不带 `rewrittenBy`)⇒ 那一拍补上预览、fleet 行名并起标题;屏改写过 / 丢弃 / 抛错 ⇒ 这些面一直缺席,标题不自动起 —— 屏前文本不落进 run 行、续跑输入,也不送进标题模型。
|
|
178
|
+
续跑输入里的目标在这类腿上一直留空,所以 wake 新建的 run 行没有预览、续跑腿的 fleet 行不带名(原样交下也一样)。订 `prompt.*` / `classic.*` 通配的只观察型运维 mod 也被算成屏(判据读声明、与引擎的通配语义一致),这类部署上只回结果的腿(`verify` / `cascade`)与 wake / 续跑腿同样缺席,其余腿在受理那一拍补上。
|
|
179
|
+
leader 车道 durable worker 的子目标续跑输入不在这条律内:它不经受理座,屏前原文照旧落盘(另票)。
|
|
180
|
+
`verify` 形提交的续跑输入照旧存请求原文(停驻续跑要把它交给验证器;不进 wake 新行的预览与 fleet 行名);目标里的内联 `@名` 选中的模型(请求没带 `model` 时)记在续跑输入里,续跑照旧跑它;只回结果的 `cascade` 提交有屏时预览与标题缺席。嵌入方:`createHttpServer` 的 `deploymentMods` 必填,传交给 Runner 的同一只 `mods` 数组(没有传 `[]`)。
|
|
176
181
|
- **缺省推断**:`MODEL_PROVIDER` **未设**、但显式配了 Anthropic 协议 base URL(`ANTHROPIC_BASE_URL`)**和**对应凭证(`ANTHROPIC_API_KEY` / `ANTHROPIC_AUTH_TOKEN`)时,缺省自动判 `anthropic` 并打一行启动 warn(`model_provider_inferred`)——纯净机直连 Anthropic 兼容上游不再需要显式第七个键。显式 `MODEL_PROVIDER` 恒赢;只给 base URL 或只给凭证不推断;两者皆无 = `gateway`,与以前逐字节一致。
|
|
177
182
|
- 启动日志的 `brain` 字段会回显当前组合(`failover` / `anthropicRoute` / `anthropicCacheBreakpoints`)。
|
|
178
183
|
- **在服务进程之外读同一套 env 路由**(子路径 `@sema-agent/server/model-route-env`;纯数据 + 纯函数,import 无副作用,值依赖只有 `@sema-agent/core` 与 `@sema-agent/settings-schema`):
|
|
@@ -652,7 +657,7 @@ MODEL_CASCADE_LADDER=deepseek-flash,deepseek-pro # 目录里的模型名,cheap
|
|
|
652
657
|
行与编号高水位一并抹掉(同 anchors/附件/快照的级联)——会话 id 可被重新认领,残留就等于把上一位
|
|
653
658
|
主人的任务标题与编号进度交给下一个化身。
|
|
654
659
|
- **会话的行事实只住在数据根的 `session-incarnations.json`**(每只会话一格:属主 / 化身 / 执行放置 / 建档时刻 / fork 谱系);`sessions/*.jsonl` 是匿名的对话内容。
|
|
655
|
-
备份 / 迁数据根时两样一起搬;更早版本写下的带属主戳的存档由起服一次性迁移改写(改不了的点名,fork 与改日志推送答 409 `conflict.session_archive_stamped
|
|
660
|
+
备份 / 迁数据根时两样一起搬;更早版本写下的带属主戳的存档由起服一次性迁移改写(改不了的点名,fork 与改日志推送答 409 `conflict.session_archive_stamped`;会话同步导入的第一阶段对 fork / stale 且没带同意的推送也直接答它),快照目录 `session-archive-m33/` 非空且消化不了 ⇒ 拒启(MIGRATION 写了出路)。
|
|
656
661
|
`session-incarnations.json` 本构建读不出(更新的引擎写过、格里多出不认得的键;或文件坏了 / 读不了)⇒ 起服拒 `config.schema_mismatch`(与 SQL 后端列册对账同一个码,拒句点名文件与键;
|
|
657
662
|
出路 = 部署写下它的那一版,或恢复升级前的数据根备份;读不了 ⇒ 修好权限 / 盘再起);起服之后才读不出(跳过了 `ensureSchema()` 的嵌入方;或违规共享的数据根上另一只引擎写了它)⇒ 同码拒,
|
|
658
663
|
形读不出则那只边档的每一读每一写拒到重启,盘上字节不被盖掉。
|
|
@@ -1094,6 +1099,9 @@ UNREACHED_ASK_TTL_MS=3600000
|
|
|
1094
1099
|
非终态的问行(`STREAM_PENDING` / `PARKING`)永不按龄删 —— 它们归对账器与起服收敛。节律:首拍即清扫一次,之后每小时至多一次;每次先从 run 账、后台子代账与 checkpoint 店列出还能动的东西(任一读不出 ⇒ 这次不删),
|
|
1095
1100
|
问账一批至多 500 行、一次清扫删到不满一批为止。读数:起服一行 `approval_ask_retention`(`windowMs`;`0` = 关),真删了东西时一行 `approval_ask_retention_swept`
|
|
1096
1101
|
(`cutoffMs` / `asks` / `batches` / `auditAsks` / `auditRecords`;半途失败时已经删掉的照样打,带 `incomplete: true`)+ 计数器 `approval_ask_retention_rows_deleted_total{ledger=asks|batches|audit}`。
|
|
1102
|
+
local 的问账日志上,任何真删了行的调用(留存清扫的两只动词与 `deleteByTask`)的那一拍,同步把整本原子重写成存活行的快照 —— `asks.jsonl` 里同拍不再有被删的问的字节(含 `Write` / `Edit` 这类工具实参的字面);没删东西的调用不落记录、不重写;
|
|
1103
|
+
压实失败不影响调用(行照删,计 `fail_open_total{tag="server.approval-ask-journal.compaction-failed"}`,日志里留着删行记录,下一次写或下一次起服再压实)。
|
|
1104
|
+
起服时因撕尾 / 坏行隔离出去的原件 `asks.jsonl.corrupt-<ts>` 是取证材料,**没有清扫腿**,里面仍有当时的字节,要清由人来(正常部署恒零)。
|
|
1097
1105
|
**关法**:`APPROVAL_ASK_RETENTION_MS=0` = 永久保留(要在升级后的第一次清扫之前设 —— 首拍即扫);正值低于 1 天钳到 1 天并在启动告警里点名(刚结束的 run 的客户端还可能对它的卡重试 / 晚答,
|
|
1098
1106
|
一天吸收这一段);负值 / 非整数 / 非数拒启。run 结束超过窗之后才对它的卡作答 ⇒ 决断口与流内审批口答 404。
|
|
1099
1107
|
|
|
@@ -1992,9 +2000,9 @@ curl -N http://<host>:8090/v1/tasks/stream -H 'content-type: application/json' \
|
|
|
1992
2000
|
## 7. 其它接口(按需)
|
|
1993
2001
|
| 端点 | 用途 |
|
|
1994
2002
|
|---|---|
|
|
1995
|
-
| `GET /v1/sessions/<id>` | 审计回溯:当前上下文 + 摘要(owner 校验);消息里模型 / 工具产出的文本与 live 帧、账本帧同一只脱敏(密钥形换占位,其余字节不变);Read 图像 / PDF 的媒体卡(工具结果消息的 `details`)的 `file.base64` 是字节编码,逐字。**委派子代的转录**也走这一口:`<id>` = 子代帧 / fleet 子代行上的 `transcriptId`(未压缩过的子代首条用户消息是委派 prompt;子代跑过的工具是 assistant 消息里的 `toolCall` 段 + 同 `toolCallId` 的 `toolResult` 行;整段逐字条目走 `…/sync/entries`)。体顶层加性键 `agent: { id?, parentSessionId?, rootSessionId? }`(**7.133.0+**)说这是哪只子代:只投影会话行上存下来的委派元组,`id` 与 fleet 行的 `id`、`GET /v1/agents/roster` 的 `handle` 同一个串;键缺席 = 普通会话 / 老 server(`DB_BACKEND=local` 到 7.140.x 也是)/ 会话店不存元组(`DB_BACKEND=memory`;嵌入方自建、不声明委派分区的店),读作「没存」、回落 fleet 行 / 名册上的 id。子代会话的属主是引擎判的委派树属主(**7.144.0+**:没人派生的 run 读自己那一行的属主、按化身绑一次,原样带给每一层子代;三只持久会话店〔MySQL 协议 / PostgreSQL / local〕建行那一笔原样记引擎交来的属主,`null` = 根匿名;停驻挂点只比对宿主行属主与引擎交来的属主,不认领、不推断。**7.133.0–7.143.x** 是本服务在建行那一笔按根 / 父推断:根会话的行在 ⇒ 它的属主,根行已不在 ⇒ 它记录的父会话的,都不在 ⇒ 哨兵 `_orphan:<id>`;7.132.x 及更早的 SQL 后端上子代会话无主、谁都读得到)⇒ 用发起子代的那位主体读;别的主体与不存在的 id 同一个 `404 not_found.session`。属主为空的委派子代行(根会话本就无主,或升级前写下、还没回填)只有 fleet 调用方读得到(出示 service 凭据、不带主体头;dev-open 部署不钉人),任何具名主体、没有 service 凭据的无身份调用方同样 404(存量无主会话互认臂 —— 单用户形下 `default` 主对无主的普通会话放行,fork / 删除 / `/sync/*`(同步族自 7.134.0 起)同走这一只 —— 对这些 placed 行同样不放行,审批豁免、notify 同样不放行;fork / 删除 / `/sync/*` 的 fleet 调用方与此处同一个判据:出示 service 凭据、不带主体头,带主体头的 service 凭据请求是那位主体,7.134.0 起);SQL 后端两店每次起服由一次性迁移 M23 在它的窗内回填升级前写下的无主 placed 行(按 7.133.0 起的读法:根的属主,根行不在取记录的父的,都不在写 `_orphan:<id>`;起服读数行 `placedSessionOwnersRemaining` 非零 = 还有没定下的,再起直到为 0),local
|
|
1996
|
-
| `GET /v1/approvals?owner=user:42` | 高危写审批(durable,需 `DURABLE_APPROVAL=true`):**operator** 看待办队列(可按 owner 过滤);非 operator 只看自己的。队列里某一行的存储体读不出来、重试不会好时,答 `500` + `errorCode:"approvals.read_corrupt"`(**7.134.0+**;与订阅流同码、同一只判官;运维处置那一行后再读,别原样重试);此刻读不出队列(连接 / 超时 / 店抖动)⇒ `503` + `errorCode:"approvals.read_unavailable"`(**7.135.0+**,此前 500 `internal.error`;稍后重发,这一答不表示队列为空)。`GET /v1/assistant/inbox` / `GET /v1/assistant/tasks` 读同一个队列,两种读失败同码同状态(**7.135.0+**)。停驻的**技能卡**(对引擎 `Skill` 工具的调用)的行带 `boundGrantDigest` / `boundGrants`(批准它还授予的东西:技能名 + 两只工具清单;清单只在哈希等于摘要时才有,是部署文本,渲染要按上下文转义),分类器没给判词的卡带 `classifierNoRuling`(`error` / `timeout` / `parse_error`)—— **7.136.0+**,与 `GET /v1/assistant/inbox` 行逐字同值(此前只有收件箱行与活卡帧带);普通卡三位都缺席。`GET /v1/assistant/inbox` 行的 `objective` 是门所属 run 的**目标预览**(写入时已脱敏、截到约 120 字符,与 `GET /v1/assistant/tasks` 读同一列;委派子代的门读派它的那条 run;没有 run 账本 ⇒ `null`;**7.136.0+**,此前原样回显存着的任务目标,运维 `?owner=` 跨看也是原文) |
|
|
1997
|
-
| `GET /v1/approvals/stream` | 同一队列的 SSE 推送(范围同上):首拍快照 → `pending` / `resolved` 增量(开了工具审批时另有 `live_pending` / `live_resolved`),空闲时心跳,15 分钟上限(`STREAM_MAX_DURATION` 帧后重连)。**心跳只表示流活着,不表示这一拍读过队列**:队列读不出时每次读失败发一帧 `error`(`approvals.read_unavailable`,流留着、下一拍再读,恢复后同一条流继续);某一行的存储体读不出来、重试不会好时发 `approvals.read_corrupt` 并收流(运维处置那一行后再重连)。15 分钟上限对读失败的拍同样算数。`pending` 帧带的行与 `GET /v1/approvals` 同一只投影(含上面的技能卡三位,**7.136.0+**) |
|
|
2003
|
+
| `GET /v1/sessions/<id>` | 审计回溯:当前上下文 + 摘要(owner 校验);消息里模型 / 工具产出的文本与 live 帧、账本帧同一只脱敏(密钥形换占位,其余字节不变);Read 图像 / PDF 的媒体卡(工具结果消息的 `details`)的 `file.base64` 是字节编码,逐字。**委派子代的转录**也走这一口:`<id>` = 子代帧 / fleet 子代行上的 `transcriptId`(未压缩过的子代首条用户消息是委派 prompt;子代跑过的工具是 assistant 消息里的 `toolCall` 段 + 同 `toolCallId` 的 `toolResult` 行;整段逐字条目走 `…/sync/entries`)。体顶层加性键 `agent: { id?, parentSessionId?, rootSessionId? }`(**7.133.0+**)说这是哪只子代:只投影会话行上存下来的委派元组,`id` 与 fleet 行的 `id`、`GET /v1/agents/roster` 的 `handle` 同一个串;键缺席 = 普通会话 / 老 server(`DB_BACKEND=local` 到 7.140.x 也是)/ 会话店不存元组(`DB_BACKEND=memory`;嵌入方自建、不声明委派分区的店),读作「没存」、回落 fleet 行 / 名册上的 id。子代会话的属主是引擎判的委派树属主(**7.144.0+**:没人派生的 run 读自己那一行的属主、按化身绑一次,原样带给每一层子代;三只持久会话店〔MySQL 协议 / PostgreSQL / local〕建行那一笔原样记引擎交来的属主,`null` = 根匿名;停驻挂点只比对宿主行属主与引擎交来的属主,不认领、不推断。**7.133.0–7.143.x** 是本服务在建行那一笔按根 / 父推断:根会话的行在 ⇒ 它的属主,根行已不在 ⇒ 它记录的父会话的,都不在 ⇒ 哨兵 `_orphan:<id>`;7.132.x 及更早的 SQL 后端上子代会话无主、谁都读得到)⇒ 用发起子代的那位主体读;别的主体与不存在的 id 同一个 `404 not_found.session`。属主为空的委派子代行(根会话本就无主,或升级前写下、还没回填)只有 fleet 调用方读得到(出示 service 凭据、不带主体头;dev-open 部署不钉人),任何具名主体、没有 service 凭据的无身份调用方同样 404(存量无主会话互认臂 —— 单用户形下 `default` 主对无主的普通会话放行,fork / 删除 / `/sync/*`(同步族自 7.134.0 起)同走这一只 —— 对这些 placed 行同样不放行,审批豁免、notify 同样不放行;fork / 删除 / `/sync/*` 的 fleet 调用方与此处同一个判据:出示 service 凭据、不带主体头,带主体头的 service 凭据请求是那位主体,7.134.0 起);SQL 后端两店每次起服由一次性迁移 M23 在它的窗内回填升级前写下的无主 placed 行(按 7.133.0 起的读法:根的属主,根行不在取记录的父的,都不在写 `_orphan:<id>`;起服读数行 `placedSessionOwnersRemaining` 非零 = 还有没定下的,再起直到为 0),local 后端没有回填臂(**7.145.0+** local 后端建子代行先记属主、再建转录存档,进程崩在两笔之间留下的是一只没有转录的属主格 —— 不是子代行,不再新生无主子代行;更早版本崩在两笔之间留下的无主子代行照旧无主、不回填,出路是取消 / 删掉那只后台子代)。属主 `_orphan:<id>` 由 7.133.0–7.143.x 的建行推断与 M23 回填写下(7.144.0 起本服务不再推哨兵,建行原样记引擎交来的属主 —— 已有的哨兵属主随引擎的树属主原样带到它下面新建的子代行上):任何主体都不匹配,只有 fleet-wide / operator 读得到,前缀永久保留。停驻时宿主行属主与引擎交来的不等 ⇒ 停驻否决(那张待批卡作废、那一只子代以失败收尾) |
|
|
2004
|
+
| `GET /v1/approvals?owner=user:42` | 高危写审批(durable,需 `DURABLE_APPROVAL=true`):**operator** 看待办队列(可按 owner 过滤);非 operator 只看自己的。队列里某一行的存储体读不出来、重试不会好时,答 `500` + `errorCode:"approvals.read_corrupt"`(**7.134.0+**;与订阅流同码、同一只判官;运维处置那一行后再读,别原样重试);此刻读不出队列(连接 / 超时 / 店抖动)⇒ `503` + `errorCode:"approvals.read_unavailable"`(**7.135.0+**,此前 500 `internal.error`;稍后重发,这一答不表示队列为空)。`GET /v1/assistant/inbox` / `GET /v1/assistant/tasks` 读同一个队列,两种读失败同码同状态(**7.135.0+**)。一张停驻行的存储体读不出摘要(手改成 `{}`、整段缺 `state` 等)只坏它自己那一行(**7.145.0+**,MySQL 协议 / PostgreSQL 后端):收件箱与运维队列照列它、带引擎判官的 `rowVerdict`(只缺 `pendingAction` 的行判官答 `ok`,引擎侧已知缺口),任务视图照列那条 run,三个面都不再整张答 500 / 503;别的卡的决断照常,这张卡自己的决断答 409 带码拒;`DB_BACKEND=local` 上列表面本版仍整张 503(决断已逐行)。停驻的**技能卡**(对引擎 `Skill` 工具的调用)的行带 `boundGrantDigest` / `boundGrants`(批准它还授予的东西:技能名 + 两只工具清单;清单只在哈希等于摘要时才有,是部署文本,渲染要按上下文转义),分类器没给判词的卡带 `classifierNoRuling`(`error` / `timeout` / `parse_error`)—— **7.136.0+**,与 `GET /v1/assistant/inbox` 行逐字同值(此前只有收件箱行与活卡帧带);普通卡三位都缺席。`GET /v1/assistant/inbox` 行的 `objective` 是门所属 run 的**目标预览**(写入时已脱敏、截到约 120 字符,与 `GET /v1/assistant/tasks` 读同一列;委派子代的门读派它的那条 run;没有 run 账本 ⇒ `null`;**7.136.0+**,此前原样回显存着的任务目标,运维 `?owner=` 跨看也是原文)。停驻行带 `agent`(**7.145.0+**):行的会话在委派树里的位置 `{ id?, parentSessionId?, rootSessionId? }`,与 `GET /v1/sessions/<sessionId>` 体顶层的 `agent` 同一只读口、逐值同答 —— 后台委派子代停驻的行(`taskId` 为 `null`、`sessionId` 是子代自己的会话)凭它连回发起委派的会话(`rootSessionId` / `parentSessionId` = 本端会话 ⇒ 本端的卡);缺席 = 这台 server 没有说(宿主会话自己的停驻、同步委派的子代、`subagent_type: "fork"` 的后台子代、不存委派元组的店、那一读没读成 —— 只这一行缺键、列表照出),按原读法判,不读作「不是子代」 |
|
|
2005
|
+
| `GET /v1/approvals/stream` | 同一队列的 SSE 推送(范围同上):首拍快照 → `pending` / `resolved` 增量(开了工具审批时另有 `live_pending` / `live_resolved`),空闲时心跳,15 分钟上限(`STREAM_MAX_DURATION` 帧后重连)。**心跳只表示流活着,不表示这一拍读过队列**:队列读不出时每次读失败发一帧 `error`(`approvals.read_unavailable`,流留着、下一拍再读,恢复后同一条流继续);某一行的存储体读不出来、重试不会好时发 `approvals.read_corrupt` 并收流(运维处置那一行后再重连)。15 分钟上限对读失败的拍同样算数。`pending` 帧带的行与 `GET /v1/approvals` 同一只投影(含上面的技能卡三位,**7.136.0+**;含 `agent`,新订阅首拍补给的帧与之后推出的帧同值,**7.145.0+**) |
|
|
1998
2006
|
| `POST /v1/approvals/<sessionId>/decide` `{"decision":"approve"|"deny","reason":"…"}` | 批/否并恢复挂起任务(CAS,重复决议 409);**仅 operator**(非 operator → 403)。5.0.0 起旧轮询腿 `POST /v1/approvals/<id>` 已退役。停驻的后台子代**复活不了**(行上没有根会话锚;未起名的后台子代不在此列 —— 引擎 7.57.0 起每只子代都有名字,升级前的无名行读作派生名,照常复活)⇒ `deny` 作废这张卡:`200 {taskId, status:"failed", decision:"deny"}`,卡离开待决队列、子代终局 `failed`;`approve` 答 `409 decide.row_unrevivable`、拒句指路 deny(**7.136.0+**;此前两个决定都 409,卡处理不掉)。有根会话锚的停驻子代卡上,`decide` 与删根会话 / 卡作废并发:写口放行之后卡已被作废 ⇒ `422 parked_resume.startup_failed`(卡已作废、什么都没复活;与 `409 decide.gate_moved` 并列为并发终局码,调用方须同时处理 409 / 422) |
|
|
1999
2007
|
| `GET /v1/tool-approvals/<approvalId>` | 按问读口(**7.133.0+**;与 `POST …/respond` 同门同身份,不是你的 ask 与查无同形 404;**7.136.0+** 两扇决议口 —— `POST …/respond` 与耐久决断口 `POST /v1/tasks/<taskId>/asks/<askId>/decision` —— 与本口同一只属主判据:有行的问读行上当下的属主,收编之后新属主三口都认、前属主三口都 404;本口在店读不出时只对本副本自己铸的活登记回落登记(登记属主认你 ⇒ `pending`),起服接管的登记不回落、答 404 —— 与同一刻的应答口同答,此前本副本上的活卡读的是铸卡那一刻记下的属主):一只审批问此刻在哪一态,`state` ∈ `pending` / `decided` / `parked` / `void`(闭集)。停驻卡被答过 ⇒ `decided`、停驻 run 被取消 ⇒ `void`(**7.134.0+**;7.133.x 恒答 `parked`);停驻行的门已结算却读不出可用的决议(含坏行:状态词 / 种类 / 当事方不在闭集、结算记录过不了引擎的不变量筛、缺必填成员、时刻 / 方向读不出)⇒ 404 `tool_approval.not_pending`,运维日志一行 error(`defect` 首条缺陷句 · `defectCount`)。停驻行的 `decided` 可回到 `parked`:续跑腿在被批准的动作开跑前失败时,引擎重开同一张门 —— 读口答 `parked` + `decidePath` 并另带 `reopened`(**7.135.0+**):`reason` 是引擎的重开因由词(`env_failed` 按原决议经 `decidePath` 再交一次 —— 本副本还留着首次受理回执时(缺省 1 小时内)`…/respond` 回放那张回执、不驱续跑;`tool_unavailable` / `constraint_rejected` 重新决;`config_refused` 改好配置再交或重新决),`decision` / `decidedAtMs` / `decisionNote?` 是重开之前的那次决议(读不出 ⇒ 只带 `reason`);再决之后回到 `decided`。续跑被取消 ⇒ 重开的门被收掉,读作 `void`。全文见契约 §4a-bis-read |
|
|
2000
2008
|
| `GET /v1/agents/roster` | 后台 agent **名册**(7.29 起,需 durable background-agent store,否则 501 `capability.background_agent_store_required`):调用方自己 scope 的 `a…` 行,新→旧。行只带 `handle`/`name`/`agentType`/`status`/`spawnedAt`/`updatedAt`/`settledAt`(content-free;子代产物正文走 `GET /v1/runs/<id>/subagents/<handle>/output`)。查询:`?limit=`(1..100,默认 20)、`?before=`(上一页的 `nextBefore` 游标)、`?status=`(running\|parked\|completed\|failed\|killed)、`?session=`(按会话树窄化)、`?scope=`(**仅** fleet 调用方:不带主体头的 service 凭据 / 只读 `TRACE_TOKEN`(只在没配 service 凭据的部署上够得着这一口)/ dev-open;带主体头的调用方 —— 含带 service 凭据的 —— 锁定自己)。回体 `{agents,total,nextBefore?,truncated?}`;`truncated:true` = 租户行数超过名册窗(500),`total` 此时是窗内数。非属主的行**不出现也不计数**(无存在性 oracle) |
|
|
@@ -2266,8 +2274,8 @@ curl -N http://<host>:8090/v1/tasks/stream -H 'content-type: application/json' \
|
|
|
2266
2274
|
> adb 经设备 shell、e2b 是建 / 恢复沙箱时的一次 `commands.run`),host 读它自己组合给子进程的那份 env 里的 `HOME`(会话 `settings.env` 改了 `HOME` 也算);
|
|
2267
2275
|
> 与主张(`REMOTE_EXEC_HOME_DIR`,或 host 的本进程家目录 / e2b 的 `/home/user`)不一致(去掉尾斜杠后逐字比)或问不出 ⇒ 那只执行环境不开,拒句点名两个值与改法
|
|
2268
2276
|
> (把 `REMOTE_EXEC_HOME_DIR` 设成实测值、删掉错的声明,或让环境的 `HOME` 读主张那个值)。host 车道的读数在铸环境时就到手 ⇒ 环境不铸,run 在开跑前失败
|
|
2269
|
-
> (码 `env.home_unconfirmed`,同步腿 409;一条命令没跑、模型一次没调,命令带不带路径都是这一句;7.144.0 起,此前拒句落在工具结果里)
|
|
2270
|
-
>
|
|
2277
|
+
> (码 `env.home_unconfirmed`,同步腿 409;一条命令没跑、模型一次没调,命令带不带路径都是这一句;7.144.0 起,此前拒句落在工具结果里);远端五车道的环境也在开跑前打开、拒在那一拍判出,但 run 照样开跑 ⇒
|
|
2278
|
+
> 拒句落在工具结果里(带路径的命令可能先撞读边界、ssh / adb 上带附件的会话开跑前就失败、从快照恢复的续跑腿答 `resume.env_failed`,逐形见 §9 的 `env.home_unconfirmed` 行),环境答了的不一致记在那只环境上(此后每次回同一句,不再起容器 / pod / 沙箱、不再问),问不出的那一次不记、下一次重问。e2b 恢复出来的沙箱对不上时尝试重新挂起(挂起成功快照留着;挂起失败只记一行 warn,沙箱按自己的寿命到期),不杀。
|
|
2271
2279
|
> e2b 的出厂答案 `/home/user` 已于 2026-10-29 在真沙箱上实测一致(缺省模板:用户 `user`、`$HOME` = `/home/user`);自定义模板换了用户的,`$HOME` 若不是它,没声明 `REMOTE_EXEC_HOME_DIR` 的 e2b 部署的每只沙箱建起来就拒,把声明设成沙箱里 `echo $HOME` 的结果(声明同样被对证)。
|
|
2272
2280
|
> device 车道读不了家目录:声明即座,起服响一行 `execution_lane_home_unmeasured`(点名声明值与「未实测」)。
|
|
2273
2281
|
>
|
|
@@ -2387,7 +2395,7 @@ curl -N http://<host>:8090/v1/tasks/stream -H 'content-type: application/json' \
|
|
|
2387
2395
|
| HTTP `409`(`/v1/runs`) | 同 session 已有活跃 run | 等它完成 / 用返回的 `activeTaskId` |
|
|
2388
2396
|
| HTTP `409` + `errorCode:"conflict.idempotency_payload_mismatch"`(7.126.0 起;`POST /v1/tasks` · `/v1/tasks/stream` · `/v1/runs`) | `Idempotency-Key` 已绑定在一条你读得到的 run 上,而绑定它的那次请求的体与这次不同(规范化:按键排序、去掉 `taskId`;契约 §0.7「同一请求 = 同一份体」)—— 不回放、不新建、那一条不动,体不回显键与那一行;流式腿在开流之后才撞上时,是终帧 `done.result` 带同一 `errorCode` 的 `failed`。A2A 不会遇到 | 重试就重发同一份体;不同的请求换一把新键。与 `conflict.run_exists` 不同:后者是那一行你读不到、或带的 `taskId` 不是那一行 |
|
|
2389
2397
|
| HTTP `429` | 限流 | 看 `Retry-After` 退避 |
|
|
2390
|
-
| HTTP `409` + `errorCode:"conflict.session_archive_stamped"`(7.144.0 起;`DB_BACKEND=local`;`POST /v1/sessions/:id/fork` 与会话同步导入的提交 `POST …/sync/import/:stagingId/entries`;7.141.0–7.143.0 答的码是 `conflict`) | 这只会话的存档仍带更早版本写下的属主戳(一次性迁移改写不了的,或跳过带迁移的版本升上来的数据根;起服 warn `local_archive_kept_stamped` 点名):不在它上面造新存档、不原地换它的日志(干净追加 / 载荷分叉 / fork / stale 各形的推送同答),什么都没写;读 / 续跑 / 拉取照常,「id 与内容都相同」的重推照常落定 | 按体里的固定句办:删掉这只会话(`DELETE /v1/sessions/:id`)再推。与暂存提交时属主变了的 `errorCode:"conflict"`(出路相反:从第一阶段重来)按码分开 |
|
|
2398
|
+
| HTTP `409` + `errorCode:"conflict.session_archive_stamped"`(7.144.0 起;`DB_BACKEND=local`;`POST /v1/sessions/:id/fork` 与会话同步导入的提交 `POST …/sync/import/:stagingId/entries`;7.145.0 起第一阶段 `POST …/sync/import` 对按 id 分类出 fork / stale 且没带同意的推送也直接答它,此前先答通用 `conflict`;7.141.0–7.143.0 答的码是 `conflict`) | 这只会话的存档仍带更早版本写下的属主戳(一次性迁移改写不了的,或跳过带迁移的版本升上来的数据根;起服 warn `local_archive_kept_stamped` 点名):不在它上面造新存档、不原地换它的日志(干净追加 / 载荷分叉 / fork / stale 各形的推送同答),什么都没写;读 / 续跑 / 拉取照常,「id 与内容都相同」的重推照常落定 | 按体里的固定句办:删掉这只会话(`DELETE /v1/sessions/:id`)再推。与暂存提交时属主变了的 `errorCode:"conflict"`(出路相反:从第一阶段重来)按码分开 |
|
|
2391
2399
|
| HTTP `429` + `errorCode:"limit.cost_quota_exceeded"` | per-principal 累计成本配额越顶(`MAX_PRINCIPAL_COST_USD`;**进场门**,不打断在跑的 run) | 看 `Retry-After` / 体 `retryAfterSec` 退避(体 `windowResetsAt` = 当代窗滚过的时刻);窗滚过或调高上限后放行 |
|
|
2392
2400
|
| HTTP `400` + `errorCode:"request.id_invalid"` | 调用方给的 id 形不对。**会话 id 的形门只有一只** = 任意版本 canonical uuid(壳预设的 v4 也过门):会话口 `:id`(fork / 抹除 / 会话策略 / 2c 同步)与提交口(`POST /v1/tasks` / `/v1/tasks/stream` / `/v1/runs` 体里的 `sessionId`,A2A 的 `contextId` 同)同判,提交口的句子在句首之后点名「改用 uuid、自己记映射」;`GET /v1/sendfile-links?before=` 游标与 `body.taskId` 幂等键要求 uuidv7(时间序 / 幂等键契约) | 按 `errorCode` 分支;句子各自点名要求的形(`must be a canonical uuid` / `must be a uuidv7 …`),只作展示、别锚文案 |
|
|
2393
2401
|
| HTTP `400` + `errorCode:"request.invalid_json"` + `reason:"not_json"` \| `"not_object"`(`reason` 7.133.0 起) | 请求体不是合法 JSON(`not_json`;所有读体的口同一个体 —— 含 `notify` / `wake` / 权限规则这几口,它们 7.132.x 及以前答 `request.body_shape`,其余多数口答 `request.rejected`),或合法 JSON 却不是这一口要的对象(`not_object`,`POST /v1/runs/:id/compact`)。读体超 8 MiB 是 `413 request.payload_too_large`(`field:"body"` / `reason:"too_large"` / `cap`,没有 `count`),不是本码 | 修请求体;按 `errorCode` + `reason` 分支,句子只作展示 |
|
|
@@ -2404,7 +2412,7 @@ curl -N http://<host>:8090/v1/tasks/stream -H 'content-type: application/json' \
|
|
|
2404
2412
|
| 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 |
|
|
2405
2413
|
| HTTP `429` + `errorCode:"usage.window_exhausted"` | 部署级治理窗耗尽(`USAGE_WINDOWS`,token 或 $ 天花板先满者) | 看响应体 `retryAfterSec` 退避;窗滑动/桶到期后放行 |
|
|
2406
2414
|
| `terminal:{kind:"failed", code:"usage.window_exhausted"}` | 已受理的 run 在 **turn 边界**撞上治理窗且无法 durable 挂起 | 同上退避后重投;配好 checkpoint 基建则改为 `suspended` 等窗自动续跑 |
|
|
2407
|
-
| HTTP `409` + `errorCode:"env.home_unconfirmed"`(同步 `POST /v1/tasks`;流式 / 后台腿是 `terminal:{kind:"failed", code:"env.home_unconfirmed"}`;7.144.0 起) | 执行环境的家目录主张证不了:部署给环境的家目录(`REMOTE_EXEC_HOME_DIR`,没设时 host 车道 = 服务进程的家目录)与环境里命令看到的 `HOME`(含会话 `settings.env` 里写的 `HOME`)对不上 / 读不出 / 不是绝对路径 ⇒ 环境在开跑前就不铸:一条命令没跑、模型一次没调、一个 token 没烧,不管模型要跑的命令带不带路径都是这一句(句子点名两个家目录与改法)。今天只有 host 车道(含 `run-local`)
|
|
2415
|
+
| HTTP `409` + `errorCode:"env.home_unconfirmed"`(同步 `POST /v1/tasks`;流式 / 后台腿是 `terminal:{kind:"failed", code:"env.home_unconfirmed"}`;7.144.0 起) | 执行环境的家目录主张证不了:部署给环境的家目录(`REMOTE_EXEC_HOME_DIR`,没设时 host 车道 = 服务进程的家目录)与环境里命令看到的 `HOME`(含会话 `settings.env` 里写的 `HOME`)对不上 / 读不出 / 不是绝对路径 ⇒ 环境在开跑前就不铸:一条命令没跑、模型一次没调、一个 token 没烧,不管模型要跑的命令带不带路径都是这一句(句子点名两个家目录与改法)。今天只有 host 车道(含 `run-local`)这样答;远端五车道的环境也在开跑前打开、拒在那一拍判出,但 run 照样开跑:不带路径的命令拿到同一句(工具结果里);读边界要先读环境才判得了的命令先被读边界拦下、句子不点名家目录(路径不在读拒表上时;全 shell 面要人批:`~/` 下的递归读五条车道都是,`~/` 下的普通读在 ssh / adb,工作区内相对路径的普通读在 adb;`AUTONOMY=read-only` 上 adb 的工作区相对路径读被拒);ssh / adb 上会话绑了附件 ⇒ 开跑前 `failed`、终局不带码(句子以 `attachment materialization failed` 起头);从快照恢复的续跑腿(e2b;配了快照存储的 k8s)⇒ `resume.env_failed` | 把 `REMOTE_EXEC_HOME_DIR` 设成环境里 `echo $HOME` 的结果(或删掉它 —— host / e2b 删掉后主张回落车道的出厂答案,仍要与 `HOME` 一致),或让环境的 `HOME` 等于声明,或去掉会话 `settings.env` 里的 `HOME`;原样重试不改判 |
|
|
2408
2416
|
| HTTP `501`(`/v1/runs`) | 内存模式不支持异步 | 配持久存储(`DB_BACKEND=mysql` / `pg` + 坐标;7.106.0 起给了坐标必须点名 `DB_BACKEND`) |
|
|
2409
2417
|
| HTTP `500` + `errorCode:"corrupt_session"`(7.104.0 起;流式口在应答头之后则是 `done` 帧的 `result.terminal.code`,后台 run 是 run 行的 `errorCode`) | 这只会话的**存档读不出**、唤不醒(文件后端:会话日志没有会话头;SQL 后端:一行事件读不出);或(7.144.0 起)存着的日志读得出、**走不成一棵树**:某条目的父不在日志里而回放没丢记录(悬空)、条目是自己的祖先(自指 / 成环)、叶子不在日志里(7.137.0–7.143.0 这一形答 `invalid_session`;句子点名条目 id,读整条分支的口 —— 会话视图 `GET /v1/sessions/:id` / `…/memory-status` —— 同答,事件订阅与头探针只读会话头的叶子,照旧 200 / 起流)。这一轮没跑,一个 token 没烧。直接读这只会话的口(头探针 / 事件订阅 / 会话视图 / 改名 / 导出 / 分叉 / 2c 同步)同答(契约 §17;文件后端上事件订阅与改名 7.136.0 起同答,此前一个 200 起流却零帧、一个 404)。会话列表 `GET /v1/sessions` 里它仍是一行,行带 `unreadable: { errorCode }`,码就是这些口对它答的那一个(文件后端,7.142.0 起;此前它从列表里消失;存档文件本身读不出 —— 权限 / I/O —— 时码是 `internal.error`) | **别重试**(确定性失败)。**文件后端**:运维看 `fail_open_total{tag="server.session-repo.corrupt-record-skipped"}` 的计数、stderr 契约行 `[sema] fail-open: server.session-repo.corrupt-record-skipped` 与随带的一条 `fail_open` warn(后两者每进程每 tag 只一次,warn 带首条明细);逐条明细(文件路径、会话 id、行号、成因)每命中一行进探针文件 —— 起服前设 `SEMA_FAILOPEN_PROBE=<文件路径>`(会话头那一行本身读不出时,它就是其中一条);修或移开那份存档。**SQL 后端**不经这只座:坏的那一行由错误句子点名(`session_event.payload` + 会话 id + 序号 `seq`)。要继续工作就换一个新会话 |
|
|
2410
2418
|
| 流里一帧 `engine_notice` `code:"session.lineage_rerooted"`,`detail:{ break, recordsDropped, recordsTotal, leaf, entriesOnPath, sessionId, runId }`(7.144.0 起,只在文件后端;7.104.0–7.143.0 这件事由 `session.records_skipped` 说,已退役) | 这只会话的日志回放时有 `recordsDropped` 条记录读不出、被跳过了;这一轮**照跑**,模型读到的历史是 `entriesOnPath` 条。`break: true` = 被跳过的是分支上的祖先(`missingParentId`),这一轮从点名它作父的那一条(`rootedAt`)续上、`entriesCut` 条更早的条目不在上下文里(7.143.0 及以前这一形整轮失败);`break: false` = 分支完整,从 `leaf` 续上(`leaf: null` = 一条都没剩,从空对话起跑)。日志没修好之前每一轮都会再说一次(会话缓存命中的轮次照样说);进程已持有这只会话时盘上才坏的行,这一轮读的是内存里那份完整历史、不说,重启后的第一轮才说 | 告诉用户「这段对话的一部分历史丢了」;运维按 `fail_open_total{tag="server.session-repo.corrupt-record-skipped"}` 的计数与探针文件(`SEMA_FAILOPEN_PROBE=<文件路径>`,每命中一行)里的逐条明细(文件路径、会话 id、行号、成因)查那份文件。非流式 `POST /v1/tasks` 收不到通告帧(只有运维面的计数与探针) |
|
package/dist/audit.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type StoredPromptEpoch } from "@sema-agent/core";
|
|
2
2
|
import type { Pool } from "mysql2/promise";
|
|
3
3
|
import type { Pool as PgPool } from "pg";
|
|
4
4
|
import { type LocalSessionRows } from "./plugins/local-session-window.js";
|
|
@@ -30,31 +30,12 @@ export interface SessionAudit {
|
|
|
30
30
|
* the key entirely (undefined). */
|
|
31
31
|
promptEpoch?: StoredPromptEpoch;
|
|
32
32
|
}
|
|
33
|
-
/**
|
|
34
|
-
* 会话视图体顶层 additive 键 `agent` —— **这只会话是哪只委派子代的转录**(`GET /v1/sessions/:id`;读法:终端侧链投影方按 fleet 帧的 `transcriptId`
|
|
35
|
-
* 读同一只会话读面,从体上拿到子代身份,不必再回头翻 fleet 行 —— 行一离场就没有了)。
|
|
36
|
-
*
|
|
37
|
-
* 只投影**存下来的 placement 元组**(`session_meta` 的 `placement_*` 列,首写不可变;店的 `placementOf` 一行 PK 探针),**不另铸**:
|
|
38
|
-
* · `id` = 元组里的 `handle` —— 耐久 agent 行的 `a…` 键,与 fleet 行的 `id`、`GET /v1/agents/roster` 的 `handle` 是同一个串(core 铸元组时 `handle: taskId`);
|
|
39
|
-
* · `parentSessionId` / `rootSessionId` = 元组里的同名格(派它的会话 / 委派树的根会话);
|
|
40
|
-
* · 元组缺哪一格这里就缺哪一格(present-iff;不铸空串);元组的 `scope`(租户键)/ `placedAt` / `kind` 不上 wire。
|
|
41
|
-
* 键在场 = 这是一只委派子代的转录(哪怕元组只存了 `kind`,那时 `agent` 是 `{}`);键缺席 = 普通会话,**或这台部署的店不存 placement 元组**
|
|
42
|
-
* (local 后端:子代转录停驻前住私有短 TTL 店、停驻时拷进来的那一份是普通会话行 —— 事实没存就不报,消费方在 fleet 行 / `GET /v1/agents/roster` 上本就有 `id`)。
|
|
43
|
-
* 元组由引擎在**后台**委派子代(带耐久 agent 行、店声明了 placements)建会话时铸;同步委派的子代转录不落宿主店,没有元组。
|
|
44
|
-
*/
|
|
45
|
-
export interface SessionAgent {
|
|
46
|
-
id?: string;
|
|
47
|
-
parentSessionId?: string;
|
|
48
|
-
rootSessionId?: string;
|
|
49
|
-
}
|
|
50
|
-
/** {@link SessionAgent} 的唯一投影:店答出的 placement 元组 → 体上的 `agent` 值;`undefined`(普通会话 / 店没有这一面)⇒ 调用方不铸键。 */
|
|
51
|
-
export declare function sessionAgentOf(placement: SessionPlacementRecord | undefined): SessionAgent | undefined;
|
|
52
33
|
/**
|
|
53
34
|
* 用户消息行的**回退手柄**表:用户条目 id → 回退时交给 `resumeAt` 的那个 `event_id`(R8 用户消息锚按 run 的 taskId 键入)。
|
|
54
35
|
* 真源 = `resume_anchor`(锚店 `listBySession` 的读数),本表只是它对**一位读者**的一次投影。
|
|
55
36
|
*/
|
|
56
37
|
export type RewindHandles = ReadonlyMap<string, string>;
|
|
57
|
-
/** 会话视图读口(`ServiceDeps.sessionAudit`)的读者参数:`reader` = 读这张视图的**已验身份**(无身份 = `null`)。给了 ⇒ 这是一次**视图读**:用户消息行投回退手柄、体顶层投 `agent`(
|
|
38
|
+
/** 会话视图读口(`ServiceDeps.sessionAudit`)的读者参数:`reader` = 读这张视图的**已验身份**(无身份 = `null`)。给了 ⇒ 这是一次**视图读**:用户消息行投回退手柄、体顶层投 `agent`(`session-agent.ts` 的 `readSessionAgent`);
|
|
58
39
|
* 不给(只要归属的调用方:memory-status / 自助抹除)⇒ 两样投影的读都不付。 */
|
|
59
40
|
export interface SessionAuditReadOpts {
|
|
60
41
|
readonly reader: string | null;
|
package/dist/audit.js
CHANGED
|
@@ -6,15 +6,6 @@ import { redactModelText } from "./observability/run-terminal.js";
|
|
|
6
6
|
import { redactDeepWith } from "./trace/redact.js";
|
|
7
7
|
import { projectToolStructured } from "./trace/tool-output-media.js";
|
|
8
8
|
import { INJECTED_BLOCK_RE, isAttachmentFrame } from "./user-authored-text.js";
|
|
9
|
-
export function sessionAgentOf(placement) {
|
|
10
|
-
if (placement === undefined)
|
|
11
|
-
return undefined;
|
|
12
|
-
return {
|
|
13
|
-
...(placement.handle !== undefined ? { id: placement.handle } : {}),
|
|
14
|
-
...(placement.parentSessionId !== undefined ? { parentSessionId: placement.parentSessionId } : {}),
|
|
15
|
-
...(placement.rootSessionId !== undefined ? { rootSessionId: placement.rootSessionId } : {}),
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
9
|
export function buildRewindHandles(anchors, reader) {
|
|
19
10
|
const byEntry = new Map();
|
|
20
11
|
for (const a of anchors) {
|
|
@@ -66,7 +66,7 @@ export interface SessionFacesCtx {
|
|
|
66
66
|
export declare function createSessionFaces(ctx: SessionFacesCtx): {
|
|
67
67
|
ownerAware: OwnerAwareSessionStore;
|
|
68
68
|
sessionAudit: ((sessionId: string, opts?: SessionAuditReadOpts) => Promise<{
|
|
69
|
-
agent?: import("../
|
|
69
|
+
agent?: import("../session-agent.js").SessionAgent | undefined;
|
|
70
70
|
owner: string | null;
|
|
71
71
|
sessionId: string;
|
|
72
72
|
createdAt: string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { buildRewindHandles, buildSessionAudit, buildSessionAuditLocal, buildSessionAuditPg
|
|
1
|
+
import { buildRewindHandles, buildSessionAudit, buildSessionAuditLocal, buildSessionAuditPg } from "../audit.js";
|
|
2
|
+
import { readSessionAgent } from "../session-agent.js";
|
|
2
3
|
import { makeDegenerateInstrument } from "../degenerate-instrument.js";
|
|
3
4
|
import { PlanCacheProbe } from "../plan-cache-probe.js";
|
|
4
5
|
import { purgeScratchpadDir } from "../env-facts.js";
|
|
@@ -29,9 +30,8 @@ export function createSessionFaces(ctx) {
|
|
|
29
30
|
: await buildSessionAuditLocal(auditLocalRows, sessionId, handles);
|
|
30
31
|
if (!audit)
|
|
31
32
|
return undefined;
|
|
32
|
-
const [head,
|
|
33
|
+
const [head, agent] = await Promise.all([headOf?.(sessionId), opts !== undefined ? readSessionAgent(ownerAware, sessionId) : undefined]);
|
|
33
34
|
const owner = head?.owner;
|
|
34
|
-
const agent = sessionAgentOf(placement);
|
|
35
35
|
return { ...audit, owner: owner ?? null, ...(agent !== undefined ? { agent } : {}) };
|
|
36
36
|
}
|
|
37
37
|
: undefined;
|
|
@@ -18,7 +18,7 @@ export declare function runStage09(ctx: Awaited<ReturnType<typeof runStage08>>):
|
|
|
18
18
|
}>) | undefined;
|
|
19
19
|
webAdminJwtVerifier: import("../auth-bridge.js").WebAdminJwtVerifier | undefined;
|
|
20
20
|
sessionAudit: ((sessionId: string, opts?: import("../audit.js").SessionAuditReadOpts) => Promise<{
|
|
21
|
-
agent?: import("../
|
|
21
|
+
agent?: import("../session-agent.js").SessionAgent | undefined;
|
|
22
22
|
owner: string | null;
|
|
23
23
|
sessionId: string;
|
|
24
24
|
createdAt: string;
|
|
@@ -17,7 +17,7 @@ export declare function runStage10(ctx: Awaited<ReturnType<typeof runStage09>>):
|
|
|
17
17
|
}>) | undefined;
|
|
18
18
|
webAdminJwtVerifier: import("../auth-bridge.js").WebAdminJwtVerifier | undefined;
|
|
19
19
|
sessionAudit: ((sessionId: string, opts?: import("../audit.js").SessionAuditReadOpts) => Promise<{
|
|
20
|
-
agent?: import("../
|
|
20
|
+
agent?: import("../session-agent.js").SessionAgent | undefined;
|
|
21
21
|
owner: string | null;
|
|
22
22
|
sessionId: string;
|
|
23
23
|
createdAt: string;
|
|
@@ -32,7 +32,7 @@ import { serviceVersion } from "../service-version.js";
|
|
|
32
32
|
import { buildDisplaySafeUrl } from "../trace/redact.js";
|
|
33
33
|
import { seatText } from "../trace/exit-seat.js";
|
|
34
34
|
export async function runStage10(ctx) {
|
|
35
|
-
const { peerDesk, approvalAskAudit, approvalExemptionStore, approvalNonceStore, authorize, backend, backgroundAgentStore, brain, breakerState, centerRuntimeCapsResolver, checkpointStore, checkpointCtxSealing, parkCommits, config, webAdmin, consolidationValve, costQuota, deploymentModsLoaded, deviceLane, drainState, durableEnabled, elicitation, fenceSessionOwner, fileHistoryStore, fleetBus, fleetLease, fleetUsage, governanceSeams, handslessRunner, hookAgent, hookLlm, hookWakeBus, imageBakes, imageIndex, instanceId, instrumentDegenerate, leaderEndpoint, loadedSkills, localRoot, logger, lspManager, mcpRevocations, memoryBundleFaces, memoryComplianceFaces, memoryConsolidationFaces, memoryEngine, memoryExportStores, memoryOptOutGrantStore, memoryOriginFaces, memoryPosture, memorySyncCursors, memorySyncRunner, metrics, modelUsageTracker, orgMemoryAdmission, otelExporter, outcomeSink, ownerAware, parkedReviveInheritedGate, parkedReviveSurface, perSessionCwd, perTaskImage, planCacheProbe, pricing, principalCaps, promptManifestTracker, purgeSession, question, rateLimiter, reaper, webAdminJwtVerifier, resumeAnchorStore, retentionLaneStarted, retentionLaneStore, ruleConsent, runStore, runner, runnerDeps, runtimeCapsPeekResolver, sandboxGitPlane, scenarioDetails, scenarios, selectEnvTool, sendFileLedger, sendUserFileEmitter, sendUserFileToolSpec, sessionAudit, sessionEnvSelection, sessionMemoryStatusFace, sessionPolicyStore, sessionTitler, sessionWatchRegistry, setSessionCwd, setSessionInheritEnv, setSessionShellEnv, sharedMemoryStore, sideQueryAccounting, sqlEngine, sqlWorkflowRunStore, staticWiring, storePosture, subRunner, subagentSteerRegistry, taskAttachmentStore, taskLimitCaps, taskTimeoutSec, toolApproval, toolResultStore, usageWindowStore, userInputLedger, webSearchProvider, workflowAgentRegistry, workflowAgentSessionIndex, workflowParkDecisions, workflowCompletionInbox, workflowJournalStore, workflowModelAllowlistSnapshot, workflowNotifyGate, workflowNotifyJournal, workflowRecoverOpts, workflowRunStore, workflowsCapable, orgDeliveryGate } = ctx;
|
|
35
|
+
const { peerDesk, approvalAskAudit, approvalExemptionStore, approvalNonceStore, authorize, backend, backgroundAgentStore, brain, breakerState, centerRuntimeCapsResolver, checkpointStore, checkpointCtxSealing, parkCommits, config, webAdmin, consolidationValve, costQuota, deploymentMods, deploymentModsLoaded, deviceLane, drainState, durableEnabled, elicitation, fenceSessionOwner, fileHistoryStore, fleetBus, fleetLease, fleetUsage, governanceSeams, handslessRunner, hookAgent, hookLlm, hookWakeBus, imageBakes, imageIndex, instanceId, instrumentDegenerate, leaderEndpoint, loadedSkills, localRoot, logger, lspManager, mcpRevocations, memoryBundleFaces, memoryComplianceFaces, memoryConsolidationFaces, memoryEngine, memoryExportStores, memoryOptOutGrantStore, memoryOriginFaces, memoryPosture, memorySyncCursors, memorySyncRunner, metrics, modelUsageTracker, orgMemoryAdmission, otelExporter, outcomeSink, ownerAware, parkedReviveInheritedGate, parkedReviveSurface, perSessionCwd, perTaskImage, planCacheProbe, pricing, principalCaps, promptManifestTracker, purgeSession, question, rateLimiter, reaper, webAdminJwtVerifier, resumeAnchorStore, retentionLaneStarted, retentionLaneStore, ruleConsent, runStore, runner, runnerDeps, runtimeCapsPeekResolver, sandboxGitPlane, scenarioDetails, scenarios, selectEnvTool, sendFileLedger, sendUserFileEmitter, sendUserFileToolSpec, sessionAudit, sessionEnvSelection, sessionMemoryStatusFace, sessionPolicyStore, sessionTitler, sessionWatchRegistry, setSessionCwd, setSessionInheritEnv, setSessionShellEnv, sharedMemoryStore, sideQueryAccounting, sqlEngine, sqlWorkflowRunStore, staticWiring, storePosture, subRunner, subagentSteerRegistry, taskAttachmentStore, taskLimitCaps, taskTimeoutSec, toolApproval, toolResultStore, usageWindowStore, userInputLedger, webSearchProvider, workflowAgentRegistry, workflowAgentSessionIndex, workflowParkDecisions, workflowCompletionInbox, workflowJournalStore, workflowModelAllowlistSnapshot, workflowNotifyGate, workflowNotifyJournal, workflowRecoverOpts, workflowRunStore, workflowsCapable, orgDeliveryGate } = ctx;
|
|
36
36
|
const stores = {
|
|
37
37
|
runStore,
|
|
38
38
|
resumeAnchorStore: resumeAnchorStore ? resumeAnchorStore : undefined,
|
|
@@ -219,7 +219,7 @@ export async function runStage10(ctx) {
|
|
|
219
219
|
const runnerFor = createHandsRunnerSelector({ full: runner, handsless: handslessRunner });
|
|
220
220
|
const sideQuery = createSideQueryLane({ brain, config, getKeyResolver: () => webAdmin.getKeyResolver() });
|
|
221
221
|
const scenarioGate = createScenarioGate({ config, scenarios, principalCaps, logger }, "peek");
|
|
222
|
-
const server = createHttpServer({ runner, runnerFor, sideQuery, scenarioGate, peerDesk, config, authorize, resolveSpec, stores, coordinators, seams, observability, governance, deployment, knobs });
|
|
222
|
+
const server = createHttpServer({ runner, runnerFor, sideQuery, scenarioGate, peerDesk, deploymentMods, config, authorize, resolveSpec, stores, coordinators, seams, observability, governance, deployment, knobs });
|
|
223
223
|
bindServerLateSeats({ config, logger, server });
|
|
224
224
|
const fleetReconcile = startFleetReconciler({
|
|
225
225
|
bus: fleetBus,
|
|
@@ -28,8 +28,9 @@ export interface ConfigDirMigrationLog {
|
|
|
28
28
|
* · `noop` / `no-documents` / 目录不在 ⇒ 不出声(没有东西可迁);
|
|
29
29
|
* · `refused` ⇒ warn `config_dir_migration_refused`(一字未写;逐条点名迁移 id、坐标与契约的拒句 —— 读侧随后对这些旧形照旧响亮拒);
|
|
30
30
|
* · `unreadable` / 调用抛 ⇒ warn `config_dir_migration_failed`(一字未写或写到一半;原因 —— 坏文件的句子与读腿同一只判官)。
|
|
31
|
-
* 契约的 `unreadable` 不带成因,本仓分不出两类:①
|
|
32
|
-
*
|
|
31
|
+
* 契约的 `unreadable` 不带成因,本仓分不出两类:① 读腿同一拍也会拒的(坏文本:空 / 坏 JSON / 不是对象 / 嵌得过深〔根下 199 层〕,同一只文本判官;悬空的文档符号链接:契约 17.0.0 起读腿同样拒、同一句悬空句,此前读腿读成缺席)
|
|
32
|
+
* —— 读腿随后另有一行 `config_candidate_rejected`(`remote-exec.json` 则是执行车道合成步先拒启,读腿到不了),同一件事两行;
|
|
33
|
+
* ② 只有迁移读不了的(目录列不了:`config.d` 有 x 无 r —— 读腿按名逐份打开,读得进,这一行是唯一的信号)。静默 ① 就会连 ② 一起吞,所以两类同一行;契约交出成因后 ① 改为只留读腿那一行(待契约)。
|
|
33
34
|
* · `pending` 只在契约的 `check: true` 下出现,本仓从不传 ⇒ 撞上即是接线错,响亮抛。
|
|
34
35
|
*/
|
|
35
36
|
export declare function logConfigDirMigration(log: ConfigDirMigrationLog, m: ConfigDirMigration): void;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { TerminalCause, WorkflowRun } from "@sema-agent/core";
|
|
2
2
|
import type { RunRecord } from "../plugins/store-contracts.js";
|
|
3
|
+
import type { RunAcceptance } from "../run-acceptance.js";
|
|
3
4
|
/** The fleet vocabulary the shell renders (MF-Fleet `FleetTask.status`). The service maps its run/workflow status
|
|
4
5
|
* onto this neutral set; `awaiting approval` = a needs-review/plan-approval park, `waiting` = a durable suspend.
|
|
5
6
|
*
|
|
@@ -642,7 +643,8 @@ export declare class FleetEventBus {
|
|
|
642
643
|
export declare function fleetRunPublisher(bus: FleetEventBus | undefined, run: {
|
|
643
644
|
runId: string;
|
|
644
645
|
scope: string;
|
|
645
|
-
|
|
646
|
+
/** 行名 = 本服务持有的交付文本的预览({@link fleetRunLabels});缺席 = 腿上装着 prompt 屏、提交时还没有交付的文本 ⇒ 建行不带名,交付之后经 `onNamed` 补。 */
|
|
647
|
+
name?: string;
|
|
646
648
|
description?: string;
|
|
647
649
|
/** 嵌子代树的根:这条腿的 canonical core taskId(`spec.taskId ?? sessionId`)。转发子代的 `parentTaskId` 与它相等
|
|
648
650
|
* ⇒ 挂在 run 行下,否则挂在那个子代的行下。**只管嵌套**,不是行的会话键。 */
|
|
@@ -679,6 +681,9 @@ export declare function fleetRunPublisher(bus: FleetEventBus | undefined, run: {
|
|
|
679
681
|
* 只有**真终态**(completed/failed/killed)帧带残局——parked(suspended/needs_review)的行还活着,
|
|
680
682
|
* 没有「终局」可言,误传也不上帧。 */
|
|
681
683
|
onTerminal: (status: RunStatusForFleet, residuals?: FleetRunResiduals) => void;
|
|
684
|
+
/** 建行时没有名(腿上有屏)的行,引擎交付之后补上名(受理座的补写口调)。只改**还在 bus 上**的那一行:收场之后、或行已被别的路径收走(对账腿退场)⇒ 不发 ——
|
|
685
|
+
* 名不是活着的信号,一帧只带名的 delta 不许铸行(铸出来的行没有 scope / 会话键)。 */
|
|
686
|
+
onNamed: (name: string) => void;
|
|
682
687
|
};
|
|
683
688
|
/** The run-scoped publisher handle (returned by `fleetRunPublisher`). Threaded into `runInBackground` so a
|
|
684
689
|
* background run TRANSITIONS its fleet row exactly like the sync POST /v1/runs leg does. */
|
|
@@ -738,10 +743,15 @@ export declare function buildRunName(preview: string): string;
|
|
|
738
743
|
* shows `name`=objective + `description`=current activity (two DISTINCT things, killing the earlier "objective shown
|
|
739
744
|
* twice" dup). (A subagent CHILD row's name = its agent-type — BC-2.)
|
|
740
745
|
* 一只折法({@link buildRunName}),输入 = 与 run 行同一只预览(用户写的那段 → 脱敏 → 截):`GET /v1/assistant/tasks`
|
|
741
|
-
* 读 run 行上存的预览、过同一只折法 ⇒ 同一个 run 两面同名。剥完没有用户正文 ⇒ `(notification turn)`;闭集外的 XML 头当普通正文标。
|
|
746
|
+
* 读 run 行上存的预览、过同一只折法 ⇒ 同一个 run 两面同名。剥完没有用户正文 ⇒ `(notification turn)`;闭集外的 XML 头当普通正文标。
|
|
747
|
+
* 入参 = 本服务持有的交付文本(受理座的 `objectiveAtSubmit` / 交付之后的那一份;律的属主 = `run-acceptance.ts`),缺席(腿上有屏、还没有可写的那一份)⇒ 不带名 ——
|
|
748
|
+
* 与运维任务视图对 NULL 预览的处置同(展示位缺席即缺席,客户端渲占位)。 */
|
|
742
749
|
export declare function fleetRunLabels(objective: string | undefined): {
|
|
743
|
-
name
|
|
750
|
+
name?: string;
|
|
744
751
|
};
|
|
752
|
+
/** 腿上有屏时 fleet 行名的补写口(开 fleet 行之后、起跑之前登记;律的属主 = `run-acceptance.ts`):交付的那一份 → {@link fleetRunLabels} 同一只折法 → `onNamed`。
|
|
753
|
+
* 腿上没有屏 ⇒ 受理座永不调它(行名在开行时已按提交时的交付文本写好)。 */
|
|
754
|
+
export declare function nameFleetRowOnDelivery(acceptance: Pick<RunAcceptance, "onDelivered">, publisher: Pick<FleetRunPublisher, "onNamed">): void;
|
|
745
755
|
/**
|
|
746
756
|
* `runStatusToFleet` 的入参**闭集**([ref] P1-④)。两段:
|
|
747
757
|
* · `RunRecord["status"]` = `"running" | core.TaskStatus` —— run **行**状态词表,属主
|