@sema-ai/core 1.277.0 → 1.277.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -5
- package/dist/bench/metrics.js +1 -1
- package/dist/bench/metrics.js.map +1 -1
- package/dist/core/cache-break-detector.js +0 -0
- package/dist/core/cache-break-detector.js.map +1 -1
- package/dist/tools/gitea-issue.d.ts +1 -1
- package/dist/tools/gitea-issue.d.ts.map +1 -1
- package/package.json +1 -6
- package/CHANGELOG.md +0 -5455
- package/docs/A1-ATTRIBUTION-ROUND1-2026-07-09.md +0 -181
- package/docs/AB-ORACLE-GATE-VERDICT-2026-07-10.md +0 -100
- package/docs/ANCHOR-GAP-INVENTORY-2026-07-09.md +0 -143
- package/docs/ARCHITECTURE.md +0 -125
- package/docs/BUGHUNT-2026-07-05-NIGHT.md +0 -98
- package/docs/BUILD.md +0 -63
- package/docs/CANCEL-ASYNC-ATTRIBUTION-2026-07-09.md +0 -98
- package/docs/CC-198-VS-201-DRIFT-2026-07-09.md +0 -70
- package/docs/CC-BASELINE-FAKE-ZERO-AUDIT-2026-07-09.md +0 -51
- package/docs/CC-DRIFT-198-206-AGENT-TYPES-2026-07-10.md +0 -82
- package/docs/CC-DRIFT-198-206-CHANGELOG-2026-07-10.md +0 -82
- package/docs/CC-DRIFT-198-206-REMINDERS-2026-07-10.md +0 -96
- package/docs/CC-DRIFT-198-206-ROADMAP-2026-07-10.md +0 -110
- package/docs/CC-DRIFT-198-206-TOOL-INVENTORY-2026-07-10.md +0 -53
- package/docs/CC-DRIFT-198-206-USAGE-CONSTANTS-2026-07-10.md +0 -64
- package/docs/CC-DRIFT-198-206-WORKFLOW-2026-07-10.md +0 -83
- package/docs/CC-PARITY-CHECKLIST.md +0 -220
- package/docs/CC-PARITY-DEEP-SWEEP-2026-07-07.md +0 -149
- package/docs/CC-SUBAGENT-PROMPT-STUDY-2026-07-09.md +0 -219
- package/docs/CC-TASK-REMINDER-CADENCE-STUDY-2026-07-09.md +0 -396
- package/docs/CC-TOOL-PARITY-SWEEP-2026-07.md +0 -56
- package/docs/CC-TOOL-PROMPT-DEEP-DIFF-2026-07-08.md +0 -274
- package/docs/CC-TOOLSURFACE-DEEP-DIVE-2026-07-07.md +0 -197
- package/docs/CC206-OBSERVER-ANCHORS-2026-07-11.md +0 -463
- package/docs/CC207-CORE-SWEEP-BACKLOG-2026-07-12.md +0 -155
- package/docs/CENTER-CONTROL-PLANE-SEAM.md +0 -86
- package/docs/CLEANUP-CONTRACT-ANCHOR-2026-07-09.md +0 -83
- package/docs/COLD-START-RSI-2026-07-09.md +0 -72
- package/docs/COMPACTION-LIVE-AUDIT-2026-07-09.md +0 -114
- package/docs/CONTEXT-lifecycle-extension-points-and-stop-attribution.md +0 -71
- package/docs/COREWARS-POLYGLOT-TRIAGE-2026-07-09.md +0 -85
- package/docs/DEADTARGET-OVERFULL-HBOX-2026-07-10.md +0 -92
- package/docs/DEADTARGET-PATH-TRACING-REVERSE-2026-07-10.md +0 -87
- package/docs/DEADTARGET-WINNING-AVG-COREWARS-2026-07-10.md +0 -96
- package/docs/DEEPSEEK-API-LIMITS-PROBE-2026-07-09.md +0 -118
- package/docs/DESIGN-140-MOCK-VERIFY-2026-07-11.md +0 -79
- package/docs/DESIGN-140-VERIFICATION-2026-07-11.md +0 -43
- package/docs/DESIGN-DRAFT-workflow-collab-2026-07-11.md +0 -56
- package/docs/DESIGN-ORACLE-GROUNDING-GATE-2026-07-10.md +0 -167
- package/docs/DESIGN-TFRAG-RECONCILE-SCAFFOLD-2026-07-09.md +0 -102
- package/docs/EXP-PA2-PE-DESIGN-2026-07-11.md +0 -220
- package/docs/EXT-DOGFOOD-2026-07-12.md +0 -50
- package/docs/FINAL-VERIFY-SURFACE-AUDIT-2026-07-09.md +0 -44
- package/docs/FRAG-RECON-INVESTIGATION-2026-07-09.md +0 -183
- package/docs/HANDOFF.md +0 -121
- package/docs/KNOWN-ISSUES.md +0 -96
- package/docs/LEGW-WINDOW-TAX-2026-07-10.md +0 -82
- package/docs/LIVE-PROBE-BATCH-2026-07-11.md +0 -207
- package/docs/M2-CERT-ATTRIBUTION-2026-07-10.md +0 -61
- package/docs/M25-LEG-VARIANCE-ATTRIBUTION-2026-07-10.md +0 -81
- package/docs/MAILMAN-TIMEOUT-ATTRIBUTION-2026-07-10.md +0 -88
- package/docs/MEMORY-BACKEND-DIALECT-NOTES.md +0 -69
- package/docs/MTEB-ESCAPE-HATCH-ATTRIBUTION-2026-07-09.md +0 -57
- package/docs/MTEB-LEADERBOARD-ATTRIBUTION-2026-07-10.md +0 -134
- package/docs/ORACLE-GATE-NEGATIVE-SAMPLE-2026-07-11.md +0 -28
- package/docs/PARITY-CONTEXT-TRANSACTIONS-2026-07-10.md +0 -67
- package/docs/PARITY-PROGRESS-MATRIX-2026-07-10.md +0 -37
- package/docs/PARITY-SPOT-AGENT-TYPES-2026-07-10.md +0 -70
- package/docs/PARITY-SPOT-REMINDERS-2026-07-10.md +0 -144
- package/docs/PARITY-SPOT-TOOL-INVENTORY-2026-07-10.md +0 -61
- package/docs/PARITY-SPOT-USAGE-CONSTANTS-2026-07-10.md +0 -95
- package/docs/PARITY-SPOT-WORKFLOW-2026-07-10.md +0 -93
- package/docs/PASSWORD-RECOVERY-PANEL-VERDICT-2026-07-10.md +0 -62
- package/docs/R8-R9-FINALIZE-COORDINATION-2026-07-09.md +0 -124
- package/docs/REPL-CODE-MODE-EVALUATION-2026-07-10.md +0 -187
- package/docs/REPORT-1249-TARGETED.md +0 -48
- package/docs/RESEARCH-3P-MEMORY-SWAP-2026-07-12.md +0 -273
- package/docs/ROADMAP.md +0 -111
- package/docs/RSI-CLOUD-DEPLOY-2026-07-06.md +0 -289
- package/docs/RSI-PROCESS-AI-COLDSTART-2026-07-11.md +0 -68
- package/docs/S18-THOROUGHNESS-AUDIT-2026-07-09.md +0 -113
- package/docs/SERVICE-INTEGRATION-GUIDE.md +0 -298
- package/docs/SUBAGENT-STREAM-RESILIENCE-PARITY-2026-07-10.md +0 -118
- package/docs/SWEBENCH-PRO-RECON-2026-07-11.md +0 -31
- package/docs/TB-EFFICIENCY-TELEMETRY-2026-07-08.md +0 -114
- package/docs/TB-FAILURE-AUTOPSY-2026-07-05-RERUN.md +0 -67
- package/docs/TB-FAIRNESS-AUDIT-2026-07-08.md +0 -141
- package/docs/TB-FULL-1257-2026-07-08.md +0 -77
- package/docs/TB-LEG-GAP-ATTRIBUTION-1261-1263-2026-07-11.md +0 -154
- package/docs/TB-REGRESSION-DAEMON-KILL-2026-07-08.md +0 -58
- package/docs/TB-RSI-CROSSCHECK-2026-07-06.md +0 -68
- package/docs/TB-RSI-LEDGER.md +0 -30
- package/docs/TB-STABLE-SET-2026-07-08.md +0 -127
- package/docs/TB21-RECON-2026-07-11.md +0 -28
- package/docs/TEST-DESIGN-BATCH-1-2-3.md +0 -97
- package/docs/THIRD-PARTY-INTEGRATION.md +0 -45
- package/docs/TOKEN-ESTIMATE-CALIBRATION-LIVE-2026-07-09.md +0 -102
- package/docs/audit-2026-06-10-/347/254/254/344/272/214/350/275/256-/347/251/272/347/231/275/345/214/272/344/270/216/345/277/230/346/216/245/347/272/277.md +0 -147
- package/docs/audit-2026-06-10-/350/256/241/347/256/227bug/346/211/253/346/217/217.md +0 -163
- package/docs/audit-2026-06-11-/344/277/256/345/244/215/345/244/215/345/256/241/344/270/216/345/233/236/345/275/222/344/270/223/346/211/253.md +0 -95
- package/docs/audit-2026-06-12-design71-P1/346/275/234/344/274/217/351/235/242/350/243/201/345/206/263/344/270/216/345/220/236/351/224/231/345/256/241/350/256/241.md +0 -45
- package/docs/audit-2026-06-12-/345/205/254/345/274/200/346/227/213/351/222/256/346/264/273/346/200/247/344/270/216vendored/346/255/273/350/267/257.md +0 -63
- package/docs/audit-2026-06-15/ADDENDUM-second-pass.md +0 -88
- package/docs/audit-2026-06-15/ARCHITECTURE-AND-ROADMAP.md +0 -187
- package/docs/audit-2026-06-15/DOC-CORRECTIONS.md +0 -105
- package/docs/audit-2026-06-15/INDEX.md +0 -49
- package/docs/audit-2026-06-15/ORCHESTRATION-STATUS.md +0 -98
- package/docs/audit-2026-06-15/PRODUCTION-ISSUES.md +0 -189
- package/docs/audit-2026-06-15/REFERENCES-literature.md +0 -139
- package/docs/audit-2026-06-15/VENDOR-REFACTOR-PLAN.md +0 -96
- package/docs/cc-probe-198/README.md +0 -72
- package/docs/cc-probe-198/STABILITY-AUDIT.md +0 -118
- package/docs/cc-probe-198/live-schema-monitor-worktree-2026-07-09.json +0 -56
- package/docs/cc-probe-198/mount-variants.json +0 -536
- package/docs/cc-probe-198/plan-mode-run.json +0 -1
- package/docs/cc-probe-198/probe-bash-bg.json +0 -224
- package/docs/cc-probe-198/probe-edit-mismatch.json +0 -120
- package/docs/cc-probe-198/probe-read-missing.json +0 -62
- package/docs/cc-probe-198/probe-search-empty.json +0 -127
- package/docs/cc-probe-198/probe-task-family.json +0 -227
- package/docs/cc-probe-198/probes.status +0 -6
- package/docs/cc-probe-198/raw-capture-interactive.json +0 -948
- package/docs/cc-probe-198/raw-capture-print.json +0 -787
- package/docs/cc-probe-198/raw-capture2-interactive.json +0 -948
- package/docs/cc-probe-198/raw-capture2-print.json +0 -787
- package/docs/cc-probe-198/system-prompt.txt +0 -135
- package/docs/cc-probe-198/tools-array.json +0 -962
- package/docs/durability-boundary.md +0 -63
- package/docs/fix-2026-06-10-/350/256/241/347/256/227bug/344/277/256/345/244/215-search/346/211/271.md +0 -75
- package/docs/fix-2026-06-11-/347/254/254/344/272/214/350/275/256-/344/277/256/345/244/215-search/346/211/271.md +0 -62
- package/docs/parity-sweep/REPORT-DYNAMIC.md +0 -97
- package/docs/parity-sweep/REPORT-STATIC-GGB.md +0 -127
- package/docs/parity-sweep/REPORT-STATIC-RWE.md +0 -133
- package/docs/vendor-history.md +0 -385
- package/docs/vendored-upstream-diff-2026-07.md +0 -83
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
# 批①②③ 测试设计(设计者主刀,2026-07-07)
|
|
2
|
-
|
|
3
|
-
> 用途:**验收标准**——实现 agent 的测试面对照此表,缺项由主会话补齐或打回。原则:从行为契约反推(不看实现怎么写);每条给【构造】【断言】;⚠️ 标注 = 实现者顺着自己实现写测试时最可能漏的对抗面。
|
|
4
|
-
> 状态标记:D/E/C agent 交付后逐条填 ✅(已覆盖,文件:测试名)/ ➕(主会话补)/ ⏸(honest skip 带理由)。
|
|
5
|
-
|
|
6
|
-
## 一、批② WebFetch/WebSearch(src/tools/web.ts)
|
|
7
|
-
|
|
8
|
-
### W1 href 保真(P1)
|
|
9
|
-
| # | 行为 | 构造 | 断言 |
|
|
10
|
-
|---|---|---|---|
|
|
11
|
-
| W1.1 | 绝对链接 | `<a href="https://x.com/doc">Docs</a>` | 输出含 `[Docs](https://x.com/doc)` |
|
|
12
|
-
| W1.2 | 相对链接 | `<a href="/download">DL</a>`(页 URL 已知) | 按 CC turndown 行为定(不解析→保留原样);断言与 CC 对齐并注释 |
|
|
13
|
-
| W1.3 | 嵌套标记 | `<a href=u><b>bold</b> text</a>` | `[bold text](u)`(内层标签剥、文本留) |
|
|
14
|
-
| W1.4 | 无 href 锚 | `<a>text</a>` | 只留文本,无 `[]()` 空壳 |
|
|
15
|
-
| W1.5 | 标题层级 | h1/h3/h6 | `#`/`###`/`######` |
|
|
16
|
-
| W1.6 | 代码 | `<pre><code>` 与内联 `<code>` | fenced 与 backtick;pre 内 `<a>` **不**转链接(代码原样)⚠️ |
|
|
17
|
-
| W1.7 | 列表 | ul/li 嵌套两层 | `- ` 前缀;嵌套至少不丢文本 |
|
|
18
|
-
| W1.8 | 表格 | 2×2 table | cell 文本全保留(分隔符形式自定) |
|
|
19
|
-
| W1.9 | script/style 剥离 | 含两者的页 | 内容不出现(现行为不回归) |
|
|
20
|
-
| ⚠️ W1.10 | **协议注入** | `<a href="javascript:alert(1)">x</a>`、`data:` URI | 不渲染为 markdown 链接(纯文本或剥 href)——转换器给了攻击者「构造可点链接」的新能力,必须收口 |
|
|
21
|
-
| ⚠️ W1.11 | **围栏不回归** | 页面 body 含 `</untrusted>`、伪 `<system-reminder>` | delimitUntrusted 围栏语义完好(1.242 反注入面不因转换器换代而破) |
|
|
22
|
-
| W1.12 | 截断×链接 | 截断点精确落在 `[text](ur…` 中间 | 无悬空半链接或无害(截断标记在,内容不炸 markdown 渲染) |
|
|
23
|
-
|
|
24
|
-
### W2 summarize 兜底(P1)
|
|
25
|
-
| # | 行为 | 构造 | 断言 |
|
|
26
|
-
|---|---|---|---|
|
|
27
|
-
| W2.1 | 无 summarize+有 prompt | config 空 | 头部 note 含「summarization unavailable」+ prompt 前段回显 + 「NOT applied」 |
|
|
28
|
-
| W2.2 | 无 summarize+无 prompt | | 无 note(现行为) |
|
|
29
|
-
| W2.3 | 有 summarize+prompt | mock summarize | 走摘要,note 不出现 |
|
|
30
|
-
| W2.4 | sema-tb 接线 | 若 D 实现了主 brain 复用 | 摘要调用发生(mock brain 记录);逃生门(若有)两态 |
|
|
31
|
-
| ⚠️ W2.5 | note 位置 | | note 在**围栏外**(是我们的框架文本,进围栏会被当不可信内容打折) |
|
|
32
|
-
|
|
33
|
-
### W3 请求头(P2)
|
|
34
|
-
| W3.1 | fetchImpl spy 断言 UA/Accept 具体值(对 CC utils.ts:278-281) | W3.2 | 既有自定义 header 路径(若有)不被覆盖 |
|
|
35
|
-
|
|
36
|
-
### W4 二进制/PDF 检测(P2)
|
|
37
|
-
| # | 构造 | 断言 |
|
|
38
|
-
|---|---|---|
|
|
39
|
-
| W4.1 | content-type: application/pdf | 结构化拒绝(类型/大小/建议 bash) |
|
|
40
|
-
| ⚠️ W4.2 | content-type 谎报 text/html,body=PNG magic | 嗅探拒(headers 不可信) |
|
|
41
|
-
| W4.3 | 正常 UTF-8 长文含中文/emoji | 不误伤 |
|
|
42
|
-
| ⚠️ W4.4 | **UTF-8 BOM 开头的 HTML** | 不误判二进制(1.247 编码批同款陷阱) |
|
|
43
|
-
|
|
44
|
-
### W5 跨主机重定向(P2)
|
|
45
|
-
| # | 构造 | 断言 |
|
|
46
|
-
|---|---|---|
|
|
47
|
-
| W5.1 | 302 同主机 | 跟随 |
|
|
48
|
-
| W5.2 | 302 跨主机 | 不请求目标;返回 REDIRECT DETECTED + 目标 URL |
|
|
49
|
-
| W5.3 | 链 A→B(同)→C(跨) | 在 C 停 |
|
|
50
|
-
| W5.4 | 相对 Location 头 | 正确解析后再判主机 |
|
|
51
|
-
| ⚠️ W5.5 | **SSRF 不回归** | 同主机 302 的目标解析出私网 IP → 现有 SSRF floor 仍拒(重定向不是绕私网检查的旁路);跨主机模式因不请求天然安全,但要有测试钉住「确实没发第二个请求」(fetchImpl 调用计数=1) |
|
|
52
|
-
|
|
53
|
-
### W6 加固与回归
|
|
54
|
-
W6.1 `user:pass@` URL 拒 · W6.2 >2048 URL 拒 · W6.3 WebSearch allowed+blocked 同传报错 · ⚠️ W6.4 **1.250 details 不回归**(web-fetch 各字段 + result 8K 预览截断仍工作;新转换器改变 result 内容形态——details.result 应是转换后文本的预览,断言两者一致性)
|
|
55
|
-
|
|
56
|
-
## 二、批③ Read 图像管线(src/tools/fs/index.ts + mcp resizer)
|
|
57
|
-
|
|
58
|
-
### I1 resizer 接线(P1)
|
|
59
|
-
| # | 构造 | 断言 |
|
|
60
|
-
|---|---|---|
|
|
61
|
-
| I1.1 | 有 sharp:3000×3000 PNG(脚本生成) | 输出图 ≤2000×2000;base64 显著小于原图 |
|
|
62
|
-
| ⚠️ I1.2 | **无 sharp**(mock import 失败) | 行为=现状路径,不 throw,注释记档 optional 语义——CI 环境可能没 sharp,这条决定测试策略本身 |
|
|
63
|
-
| I1.3 | 100×100 小图 | 不动(字节等价,无损通道) |
|
|
64
|
-
| I1.4 | 超 token 预算 | 最终产物 ≤ 预算(阶梯至少走一层) |
|
|
65
|
-
|
|
66
|
-
### I2 base64 上限(P1,立案根因=「打断下一整个请求」)
|
|
67
|
-
| # | 构造 | 断言 |
|
|
68
|
-
|---|---|---|
|
|
69
|
-
| ⚠️ I2.1 | **精确边界窗口**:raw ∈ (3.75MB, 5MB](构造 4.2MB 字节) | 新逻辑处理(resize 或拒);产出 base64 严格 ≤ 上限——这是洞本体,必须字节级 |
|
|
70
|
-
| I2.2 | raw ≤3.75MB | 照常通过 |
|
|
71
|
-
| I2.3 | 与 mcp.ts:277 口径统一 | 常数/口径同源断言(import 同一常数或数值相等测试) |
|
|
72
|
-
| ⚠️ I2.4 | **端到端**:Read 大图后下一请求构造(convertToLlm 消息序列) | image block 尺寸合规——防 1.244 P1 同款「单工具产物毒化下一请求」,单元层断言不能替代这条 |
|
|
73
|
-
| I2.5 | 1.250 details 48K 条件不回归 | 大图 details 无 base64 有 metadata |
|
|
74
|
-
|
|
75
|
-
### I3/I4 估值与元数据(P2)
|
|
76
|
-
I3.1 compaction 图像常数=2000 断言(定义处) · I4.1 resize 时 content 增 meta 块(original/displayed/multiply N)+ details width/height · ⚠️ I4.2 **无 resize/无 sharp 不伪造 meta**(诚实缺席) · I4.3 multiply 系数数学正确(3000→2000 ⇒ N=1.5,坐标映射用)
|
|
77
|
-
|
|
78
|
-
### I5 交互回归
|
|
79
|
-
I5.1 伪装 .txt 的 PNG 仍走 text 分支拒(1.247 sniff 不回归) · I5.2 .png 真图不过 text sniff(分支序不回归)
|
|
80
|
-
|
|
81
|
-
## 三、批① 设计者补充盲区(C agent 派单之外)
|
|
82
|
-
|
|
83
|
-
| # | 行为 | 为什么 C 可能漏 |
|
|
84
|
-
|---|---|---|
|
|
85
|
-
| ⚠️ A1 | **resume 后 attachment 不轰炸**:resume leg 的 AttachmentState 归零,断言 resume 首边界不立刻注入(lastWriteTurn 语义在新 leg 从头算)且不 crash | known limitation 记了档,但「记档」≠「有回归网」;resume 是 133 生命周期最脆的面 |
|
|
86
|
-
| ⚠️ A2 | **三 producer 同边界**:todo+changedFiles+plan 同时到期 → 单条 steer 含三段、≤8KB、顺序=证据强度(todo 最前) | C 的派单按单 producer 组织,组合态易漏 |
|
|
87
|
-
| A3 | **窗口不累积**:15 turn 不更新 → 只发 1 次(下个窗口 20 turn 才第二次),断言两次注入的 turn 间隔 ≥ TURNS_BETWEEN | 「到期后每边界都发」是最容易写错的实现,测试要钉频率不只钉存在 |
|
|
88
|
-
| A4 | steering_injected 帧数(N producer=N 帧)vs steer 条数(1)的一对多 wire 断言 | A 线注释写了,但没测试钉 |
|
|
89
|
-
| ⚠️ A5 | **changedFiles maxFiles 配置形态**:`changedFiles:{maxFiles:5}` 真的只 stat/列 5 个 | 对象形态参数常只测 true 形态 |
|
|
90
|
-
| A6 | attachment 文本进入下一请求的**模型可见性端到端**:scriptedBrain 断言下一 call 的 context 里含 `<system-reminder>` 包裹的 reminder(不只断言 steering_injected 事件) | 事件面绿≠模型真看到;A 线冒烟只锁了事件 |
|
|
91
|
-
|
|
92
|
-
## 四、执行规则
|
|
93
|
-
|
|
94
|
-
1. D/E/C 交付后,主会话按本表逐条对照填状态;➕ 项主会话亲自补(不再派)。
|
|
95
|
-
2. ⚠️ 项缺失 = 打回/必补,不进发版。
|
|
96
|
-
3. Live 层(133 矩阵 8/9)已在 C 派单;批②③ 无 Live 需求(mock fetchImpl/本地图像即真实行为)。
|
|
97
|
-
4. 全表绿后才进 codex+opus 双轨终审。
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
# 第三方集成指引(@sema-ai/core)
|
|
2
|
-
|
|
3
|
-
> 面向零内部知识的第三方:装包→选扩展面→照 example 抄。实证背景见 docs/EXT-DOGFOOD-2026-07-12.md
|
|
4
|
-
> (纯外部视角 dogfood:~20 分钟过存储契约,~40 分钟跑通 memory+自定义工具+observer live 全链)。
|
|
5
|
-
|
|
6
|
-
## 1. 装包
|
|
7
|
-
|
|
8
|
-
用 **sema-release 腿(匿名可装)**:
|
|
9
|
-
|
|
10
|
-
```bash
|
|
11
|
-
npm install @sema-ai/core --registry=http://git.zhenbs.com:9999/api/packages/sema-release/npm/
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
或写进项目 `.npmrc`:
|
|
15
|
-
|
|
16
|
-
```
|
|
17
|
-
@sema-ai:registry=http://git.zhenbs.com:9999/api/packages/sema-release/npm/
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
另一条 AI-Only 腿(`.../api/packages/AI-Only/npm/`)需要 token,匿名装会 401——第三方一律走 sema-release。
|
|
21
|
-
|
|
22
|
-
## 2. 扩展面地图
|
|
23
|
-
|
|
24
|
-
所有扩展面都只用公开导出(package 根入口),不需要 fork 或 patch 引擎。每面一个可跑的 example(仓内 `src/examples/`,也随包发布在 dist):
|
|
25
|
-
|
|
26
|
-
| 扩展面 | 一句话 | Example |
|
|
27
|
-
|---|---|---|
|
|
28
|
-
| **MemoryBackend + 契约套件** | 实现 6 方法存储 seam,用公开的 `memoryBackendContract`(16 案,零测试框架,裸 `tsx` 可跑)认证;16 案即实现路线图 | `src/examples/third-party-memory-backend.ts` |
|
|
29
|
-
| **Brain**(model provider) | 接任意 OpenAI 兼容端点:stream 契约两种姿势(工厂式/手写 yield)+ 错误编码进流(post-invocation 永不 throw)+ failover/routing wrapper 组合 | `src/examples/custom-brain-provider.ts` |
|
|
30
|
-
| **ExecutionEnv**(文件面+exec 面) | 实现公开 `ExecutionEnv` 接口(FileSystem+Shell,`Result` 编码永不 throw),注入 `RunnerDeps.executionEnv` 即让 hands 工具带跑在你的执行环境上 | `src/examples/custom-execution-env.ts` |
|
|
31
|
-
| **agents + hands** | `RunnerDeps.agents` 部署目录(`defineAgent` 全字段,Agent-tool 与 workflow 双 lane 单源)+ `hands.beforeWrite` 写门(与引擎门 COMPOSE、tighten-only:只能收紧,不能放宽) | `src/examples/deployment-agents-and-hands.ts` |
|
|
32
|
-
| **caps 四轴** | `RunnerDeps.runtimeCapsResolver` per-principal 运行时授权(allowWorkflows / allowFork / allowObservers / 工具面),调用方永远不能自授 | `src/examples/settings-and-caps.ts` |
|
|
33
|
-
| **observer 双开关** | 观察者需两开关同开:`AgentDefinition.observer` 声明 + `RuntimeCaps.allowObservers === true` 显式 opt-in(⚠️ 极性与其他轴相反,`undefined` ≠ 放行,声明会静默解析为 unobserved) | `settings-and-caps.ts` §3 + `third-party-memory-backend.ts` live C 幕 |
|
|
34
|
-
|
|
35
|
-
## 3. workflow 沙箱注意
|
|
36
|
-
|
|
37
|
-
core **不 ship 硬沙箱**。`allowWorkflows` 走三段闸(task opt-in ∧ 部署能力 ∧ principal 授权),其中"部署能力"要求你自备满足 `safeForUntrustedScripts === true` 的 `WorkflowScriptRunner`(自证的硬沙箱)。仓内 `devWorkflowScriptRunner` 明确**不是**安全边界,只供开发调试——生产开启 workflows 前必须接自己的沙箱实现,否则保持 fail-closed(工具不挂载,理由见 `selfOrchestrationFailClosedReason`)。
|
|
38
|
-
|
|
39
|
-
## 4. memory description 写法建议
|
|
40
|
-
|
|
41
|
-
召回注入面 = index(name + description),条目 body 要模型主动 Read 才可见。因此 **description 要写成可独立回答问题的一行摘要**(answer-bearing):弱模型往往只凭 index 作答,模糊的 description 意味着多一轮 read 往返甚至直接答错(dogfood F5 实测:B 幕首跑 FAIL,补提示后过)。
|
|
42
|
-
|
|
43
|
-
## 5. 已知 ergonomics
|
|
44
|
-
|
|
45
|
-
- **Brain.stream 双 await**:`brain.stream(...)` 返回类型是联合 `Stream | Promise<Stream>`。直连调用(不经 Runner)先归一——`const s = await brain.stream(...)`——再迭代或取 `s.result()`,否则 TS 在联合类型上报 TS2339。Runner 内部已处理,仅影响直接探测 brain 的第三方代码。
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
# Token 估算器活体精度标定 — A1 腿真实轨迹逐点对齐
|
|
2
|
-
|
|
3
|
-
日期:2026-07-09 · 数据:海外机 `~/sema-tb/jobs/a1-ccdiff-1258-fb/{short,long}` · 模型:deepseek-v4-pro
|
|
4
|
-
状态:不 commit,量化报告。所有比值/分布均在海外机用 python 对全量 `brain.call` 逐点算出,非目测。
|
|
5
|
-
|
|
6
|
-
## 0. 数据模型(实测坐标)
|
|
7
|
-
|
|
8
|
-
每题 `agent/events.jsonl`。两条流对齐:
|
|
9
|
-
|
|
10
|
-
- **API 真值** — `kind:"brain.call"`(trace):每次 LLM call 的 `promptTokens`(=真实输入上下文总量,含 cacheRead)、`completionTokens`、`cacheRead`、`cacheWrite`。`promptTokens = cacheRead + fresh`,即它**就是**该 call 的真实上下文大小。
|
|
11
|
-
- **引擎估算** — `type:"compacted"` 的 `triggerTokensBefore`(压缩触发时的估算)、`kind:"compaction.suppressed"` 的 `estTokens`(被防抖 `floor` 抑制时的估算)。二者都是 `estimateContextTokens(messages, cpt).tokens`(compaction.ts:259)。
|
|
12
|
-
- 辅助:`context.trim`(请求层丢消息数)、`compaction.input_truncated`(`keptChars`/`droppedChars`)。
|
|
13
|
-
|
|
14
|
-
引擎公式(**以实际跑腿的 bundled dist 为准**——从任务目录 `agent/sema-core.tgz` 解包核实,版本 **1.258.2**):
|
|
15
|
-
- `charsPerToken=3`(deepseek),结构估算 `Math.ceil(chars/3)`(compaction.ts:307-396),图像固定 `IMAGE_TOKEN_ESTIMATE=2000`(:179)。
|
|
16
|
-
- 锚定混合:`estimateContextTokens` 取**最后一个带 usage 的 assistant** 为锚,锚点 usage tokens + 其后每条消息的结构外推(compaction.ts:259-290)。
|
|
17
|
-
- 压缩阈值:**1.258.2 dist 里 deepseek `contextWindow=64_000`**(dist/bin/sema-tb.js:79 实核),`reserveTokens=16384` → **自然阈值 = 47616 tokens**(`shouldCompact`,compaction.ts:293-302)。⚠️ 口径警示:本地 devendor src 已于 07-09 改为 200k("TB budget-ceiling fix",src/bin/sema-tb.ts:133 注释),**不适用于本批 07-08 轨迹**;初稿曾用 183616 复盘历史轨迹 = 口径错位,本版已修订。防抖 `minTokens` floor 随压缩效果浮动(实测 66189→75375,**高于阈值 47616、甚至高于 64k 窗口本身** = 病态,见 §3)。
|
|
18
|
-
- 强制腿:`forceUnderThreshold`(trim 压力 D4)与 floor 抑制,与自然阈值交织(auto-compaction.ts:339-352)。
|
|
19
|
-
|
|
20
|
-
取样:8 题(circuit-fibsqrt/path-tracing/path-tracing-reverse/mteb-retrieve = 压缩多;portfolio-optimization/chess-best-move/largest-eigenval/db-wal-recovery = 压缩少),逐 call。
|
|
21
|
-
|
|
22
|
-
## 1. 逐点误差:est/usage 比值分布
|
|
23
|
-
|
|
24
|
-
比值 r = 引擎估算 / 真实 promptTokens。分两个锚:
|
|
25
|
-
|
|
26
|
-
| 桶 | 定义 | n | P10 | P50 | P90 | mean |
|
|
27
|
-
|---|---|---|---|---|---|---|
|
|
28
|
-
| **est / realPREV** | 估算 vs 它所描述的那次 call(估算事件前最近的真实 call) | 86 | 1.004 | **1.03** | 4.90 | 2.11 |
|
|
29
|
-
| **est / realNEXT** | 估算 vs 压缩后下一次 call(post-trim 视角) | 85 | 0.997 | 1.18 | 2.43 | 1.41 |
|
|
30
|
-
|
|
31
|
-
读法:
|
|
32
|
-
- **中位数近乎完美**(P50=1.03):锚新鲜、trailing 外推短时,charsPerToken=3 + usage 锚混合是准的。
|
|
33
|
-
- **但高侧长尾极重**(P90=4.9,mean=2.11):约 1/10 的门控时刻,估算跑到真实的 ~5x。长尾全部落在压缩/抑制这些门控点上——即最需要准的地方最不准。
|
|
34
|
-
- 方向**系统性偏高**(mean≫1,尾巴单边朝上),不是对称噪声。
|
|
35
|
-
- 双轨交叉验证:独立第二腿(不同配对脚本)算得 est/realNEXT n=85 P10=0.998 P50=1.177 P90=2.383 mean=1.412,与本表第二行逐位吻合。
|
|
36
|
-
|
|
37
|
-
## 2. 系统性偏差 + charsPerToken 真值
|
|
38
|
-
|
|
39
|
-
**方向:门控点系统性偏高(over-estimate)。** mean 2.11、P90 4.9、无对称低尾。主含义 = **过早压缩 / 浪费窗口**;同时存在被 floor 抑制造成的"真实值越阈值却不压"的晚压缩面(见 §3,两面同根:估算/floor 与真实脱钩)。
|
|
40
|
-
|
|
41
|
-
**charsPerToken 真值(usage/chars 反推):**
|
|
42
|
-
- 纯结构文本:`compaction.input_truncated` keptChars=106512 → 其后 call promptTokens=48929 ⇒ **真实 ≈ 2.18 chars/token**。
|
|
43
|
-
- reasoning 内容更密:某 turn reasoning_delta 30395 chars / completionTokens 10583 ⇒ **≈ 2.87 chars/token**。
|
|
44
|
-
- 起始拼装提示词:`prompt.assembled.totalChars`/首 call promptTokens ≈ 0.93(8 题一致)——但该比值分母含工具 schema 等 totalChars 未计的部分,非干净 tokenizer 度量,仅作参考;2.18 为主口径。
|
|
45
|
-
|
|
46
|
-
即 deepseek tokenizer 真实约 **2.2 chars/token**,`charsPerToken=3` 在**纯结构路径上系统性偏低 ~27%**(3/2.18=1.38 → 结构估算只有真值 0.72x)。这与第 1 节的整体偏高不矛盾:整体偏高由 **usage 锚陈旧**(§4 第三形态)主导,量级远超结构系数的 -27%;当锚新鲜、以纯结构外推为主时,方向反转为偏低。两个偏差符号相反,charsPerToken=3 的 -27% 结构偏低被陈旧锚的大幅偏高盖过。
|
|
47
|
-
|
|
48
|
-
## 3. 压缩决策错误率(真实 usage 复盘,阈值=47616)
|
|
49
|
-
|
|
50
|
-
以真实 promptTokens 复盘全部 23 次压缩(8 题,含 db-wal-recovery 1 次):
|
|
51
|
-
|
|
52
|
-
**过早(realBefore < 47616):21/23。合理(realBefore ≥ 47616):2/23**(circuit-fibsqrt est=77525/real=48929;path-tracing est=58509/real=57601)。**过早触发率 = 91%。** 极端条目:
|
|
53
|
-
|
|
54
|
-
| 题 | est(触发估算) | realBefore(压缩前真实) | est/real |
|
|
55
|
-
|---|---|---|---|
|
|
56
|
-
| path-tracing | 52925 | **2888** | 18x |
|
|
57
|
-
| path-tracing | 58509* | 7824 | 7.5x |
|
|
58
|
-
| circuit-fibsqrt | 69067 | 18200 | 3.8x |
|
|
59
|
-
| path-tracing-reverse | 60357 | 16341 | 3.7x |
|
|
60
|
-
| circuit-fibsqrt | 51595 | 17734 | 2.9x |
|
|
61
|
-
|
|
62
|
-
(*同题另一次;est−real 最大差 +56453。)
|
|
63
|
-
|
|
64
|
-
机制:估算(44907~77525)普遍在阈值 47616 之上 → 自然门"想压";但真实值大多远在阈值下。这些误触是**估算侧的错**(陈旧锚偏高,§4),不是阈值本身错。防抖 floor(66k~75k)又叠加病态:floor 高于阈值、甚至高于 64k 窗口本身 → 压缩后估算永远降不到 floor 下 → **压缩风暴**(path-tracing 8 次、circuit-fibsqrt 6 次、63 次 suppressed 事件),真实上下文被反复打到数千 token 空转。
|
|
65
|
-
|
|
66
|
-
**晚压缩面(初稿误判"无",修订):存在。** 55 次 brain.call 的真实 promptTokens ≥ 47616 而其后未立即压缩(circuit-fibsqrt 32 次、path-tracing-reverse 11 次、path-tracing 10 次;峰值 70720/67829——**真实值甚至越过 64k 窗口声明本身**,endpoint 真限 ~1M 所以未炸,纯靠 provider 宽容兜底)。这些点位压缩被 floor 抑制(suppressed est 51997~61607 < floor 66189~75375)。即:**floor 同时制造两面错——该停的压缩停不下来(过早风暴),该压的时刻被它抑制(过晚)。**
|
|
67
|
-
|
|
68
|
-
## 4. 欺骗形态穷举
|
|
69
|
-
|
|
70
|
-
除已知 **D-1(trim 使估算偏低触发负收益压缩)**,活体逮到 **第三种系统性欺骗形态**:
|
|
71
|
-
|
|
72
|
-
### 新形态:陈旧 usage 锚 → 估算暴高(与 D-1 反向)
|
|
73
|
-
|
|
74
|
-
**证据链**(path-tracing tMs 850323→879081):
|
|
75
|
-
```
|
|
76
|
-
850323 promptTokens=44325 cacheRead=36608 ← 大上下文,建立 ~44k usage 锚
|
|
77
|
-
864950 promptTokens= 7646 cacheRead=0 ← 前缀缓存断,上下文塌缩
|
|
78
|
-
879081 promptTokens= 2888 cacheRead=0 ← 真实上下文仅 2888
|
|
79
|
-
879081 compacted est=52925 → after=37553 ← 引擎估算 52925,真实 2888(18x)
|
|
80
|
-
```
|
|
81
|
-
机制:`estimateContextTokens`(compaction.ts:259)的 `getLastAssistantUsageInfo` 扫到一个**压缩/trim 前**的大 usage 锚(~44k),加 trailing 外推,报 52925;但真实上下文已被 cache-break + 请求层 trim 打到 2888。**锚描述的上下文已不存在。** 这正是 compaction.ts:210-217 与 auto-compaction.ts:563-567 记档的 stale-anchor 危害在生产中发火:锚"应被视作 STALE,它高估 post-compaction 上下文"。后果 = floor 门被虚高估算长期满足不了 → 压缩风暴 + 浪费窗口。
|
|
82
|
-
|
|
83
|
-
**与 D-1 的关系:同一个 trim/锚脱钩根因的两个符号。** D-1:trim 拆掉锚 → 估算跌破真实 → 该压不压。新形态:trim 后锚残留高位 → 估算高于真实 → 不该压狂压。两者都是"锚与 trim 后真实上下文脱钩"。
|
|
84
|
-
|
|
85
|
-
### 其余四条穷举(均已被现有机制堵住,非活体欺骗)
|
|
86
|
-
|
|
87
|
-
- **图像**:固定 pin `IMAGE_TOKEN_ESTIMATE=2000`(compaction.ts:179),coefficient-invariant,user+toolResult 双分支对称(:331-342 已修 0-计 bug)。A1 腿纯代码题无图像,本腿无暴露面。**无欺骗。**
|
|
88
|
-
- **长工具结果**:走 `capAggregateToolResults`(200K 字符门)+ `clearStaleToolResults`,estimateTokens 按现存字符算,offload 后估算随之降。结构一致。**无欺骗。**
|
|
89
|
-
- **reasoning token 计不计入**:`completionTokens` **含** reasoning(10583 ≈ 30395 reasoning chars / 2.87)。估算侧 assistant 分支计 `thinking` block 字符(compaction.ts:349)。若 deepseek 不把 reasoning_content 回灌进下轮上下文(deepseek 标准行为=不回灌),而历史里持久化了 thinking → 估算会**高计**上一轮 reasoning。这条与陈旧锚叠加,是高侧尾巴的次要放大因子。**潜在小幅偏高,非独立欺骗——建议核 deepseek 是否持久化 thinking 到 session 再定。**
|
|
90
|
-
- **attachment 重复计量**:压缩重注 working-file(auto-compaction.ts:527-561,预算 `window*0.15*cpt` 自缩),每压缩注一次入 summary;A1 腿见 `attachedFiles` 每压缩 3 文件(gen.py/gates.txt/sim.c)反复注入。真实 promptTokens 复盘未见异常膨胀(峰值仍 <70k),estimateTokens 对 summary 按字符算,无双计。**无欺骗**,但注意 attachment 每次压缩重读磁盘现值,压缩越频重复 IO 越多(成本面非估算面)。
|
|
91
|
-
|
|
92
|
-
## 5. 结论(机制面)
|
|
93
|
-
|
|
94
|
-
1. **P50 误差比 = 1.03**(est/realPREV;post-trim 视角 1.18,双轨独立复算吻合)——中位数准。但 **P90=4.9 / mean=2.11**,门控点长尾极重。
|
|
95
|
-
2. **系统性方向 = 偏高**(over-estimate → 过早压缩 / 浪费窗口),由陈旧 usage 锚主导;纯结构路径反向偏低 ~27%(charsPerToken=3 vs 真实 ~2.18)。
|
|
96
|
-
3. **压缩误触率 = 91%(21/23 过早,真实值 < 47616 阈值)**,触发估算是真实的 2.9x~18x;另有 **55 个 call 真实值越阈值(最高越过 64k 窗口本身)而压缩被 floor 抑制 = 过晚面**。floor(66k~75k)高于阈值甚至窗口,两面错同根。
|
|
97
|
-
4. **发现新欺骗形态:是。** 第三种 = **陈旧 usage 锚**(与 D-1 trim-偏低反向的偏高),path-tracing 逮到 18x 实例;根因与 D-1 同源(trim/锚脱钩),代码注释已预警(compaction.ts:210-217)但门控前无失效判定。
|
|
98
|
-
|
|
99
|
-
**修向建议(供后续,非本腿动作):**
|
|
100
|
-
- 门控前对 usage 锚做新鲜度校验——锚点消息若已被本轮 trim/cache-break 移出请求视图,降级纯结构估算或用最近一次真实 promptTokens 重锚。
|
|
101
|
-
- floor 与阈值/窗口失去序关系(floor > threshold 甚至 > window)时钳制或重置——floor 本意防抖,现为两面错的放大器。
|
|
102
|
-
- (已在做)deepseek 窗口 64k 自缚已由 07-09 "TB budget-ceiling fix" 改 200k,本报告的压缩风暴/越窗数据即该修的活体依据。
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
# 第二轮 blocker 扫描:第一轮空白区 + 无用代码/忘接线 — 2026-06-10
|
|
2
|
-
|
|
3
|
-
- **背景**:第一轮(`audit-2026-06-10-计算bug扫描.md`)覆盖压缩/定价/runner/brain/fs/vendor 主循环。本轮补扫第一轮**未分配**的模块,并新增一类视角:**无用代码 = 可能忘了接线**(AI 迭代开发,design/ 有 68 篇编号文档,"写了没人用"可能是设计要求接线但漏挂)。
|
|
4
|
-
- **范围(本轮新覆盖)**:记忆系统(memory/memory-recall/strategy-store/roles/ask-question/untrusted-text/prompts)、权限与门(tool-policy/exec-gate/hooks/tools/runtime/property-harness/push-queue/trace/tool-filter)、外设工具与服务面(sql/web/gitea/mcp/lsp/remote-env/http)、vendor 余下(messages/skills/prompt-templates/nodejs env/kill-tree/shell-output/validation/internal)、全仓导出面的语义死代码分析。
|
|
5
|
-
- **方法**:5 个 fable subagent 并行分片 + 主会话对 S/A 与核心忘接线逐条读源码复核。
|
|
6
|
-
- **基线**:commit `73f341d`(注:工作树有并发 agent 正在修第一轮 bug,teacher/anthropic/pricing/fs/index.ts 已改;本轮发现均独立于那批修复,行号取自当前工作树可能漂移)。
|
|
7
|
-
|
|
8
|
-
总计本轮新增:**S×0、A×8、忘接线 B×3、其他 B×16**。S/A 与 3 条忘接线全部主会话读码核实(标 ✅)。
|
|
9
|
-
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
## A 级(8 条,全部核实)
|
|
13
|
-
|
|
14
|
-
### A-1 ✅ `combinePolicies` 静默丢弃 policy 的 `allow{updatedInput}` 重写 — 1.65 runToolGate 修复的孪生漏网
|
|
15
|
-
|
|
16
|
-
- **位置**:`src/core/tool-policy.ts:181-197`
|
|
17
|
-
- **代码**:fold 循环只看 `deny`/`ask`,任何 policy 返回 `allow{updatedInput}` 时最终返回裸 `ALLOW` 常量。
|
|
18
|
-
- **问题**:`PermissionResult` 契约(同文件 :14-16)明确 `allow.updatedInput` = "替换模型 args 的重写值"(脱敏 secret、钳路径)。组合路径把它丢了 → 工具以**未脱敏原始 args 执行**;且重写不在 policy 间级联(后续 policy 审的是 stale args)。`message`/`decisionReason` 审计信息同样丢。这正是 1.65 在单 policy 路径 `runToolGate` 修过的 bug 的孪生体,组合路径没修。`combinePolicies` 是根导出(index.ts),存在的唯一目的就是"审批 policy + 脱敏 policy"组合——触发即命中。
|
|
19
|
-
- **修法**:fold 时若 `allow` 带 `updatedInput`,用重写后的 req 喂后续 policy,并把最终重写带出。
|
|
20
|
-
- **置信度**:高。
|
|
21
|
-
|
|
22
|
-
### A-2 ✅ SQL `allowTables` 可被逗号连接(comma-join)绕过 — 表级隔离失效
|
|
23
|
-
|
|
24
|
-
- **位置**:`src/tools/sql.ts:40-51`(`extractReferencedTables`),enforced at `:86-92`
|
|
25
|
-
- **代码**:`const re = /\b(?:from|join)\s+([a-zA-Z_][\w.$"`[\]]*)/gi;` 只捕获 `FROM`/`JOIN` 紧跟的标识符。
|
|
26
|
-
- **问题**:ANSI 逗号连接 `FROM a, b` 的第二+张表前面是逗号不是关键字,永不被捕获、永不查 allowlist。`allowTables:["orders"]` 下 `SELECT * FROM orders, secret_users WHERE ...` 中 `secret_users` 直接放行。子查询里的逗号表列表同理。
|
|
27
|
-
- **后果**:表限制(隐藏 secrets 表/其他租户表的文档用途)在一个完全普通的 SQL 形态上被彻底绕过 = 信息泄露。只读凭证层仍挡写,但表级隔离形同虚设。多租户部署里实质是 S 级。
|
|
28
|
-
- **修法**:用真 SQL 解析器,或扩展提取覆盖逗号列表 + 拒绝无法可靠解析的查询(fail-closed)。
|
|
29
|
-
- **置信度**:高。
|
|
30
|
-
|
|
31
|
-
### A-3 ✅ exec 把"被信号中止"翻译成 exitCode 0(成功)— vendored
|
|
32
|
-
|
|
33
|
-
- **位置**:`src/vendor/agent-core/src/harness/env/nodejs.ts:377-390`
|
|
34
|
-
- **代码**:`child.on("close", (code) => { ... settle(ok({ stdout, stderr, exitCode: code ?? 0 })); });` —— 回调连 `signal` 参数都没接,`code===null` 一律 `?? 0`。
|
|
35
|
-
- **问题**:子进程被信号中止(OOM 内存回收 SIGKILL、SIGSEGV、外部 SIGKILL 信号)时 Node 的 close 回调收到 `(code=null, signal=...)`。代码只判别自身的 timeout/abort,其余 null 当 exit 0。
|
|
36
|
-
- **后果**:bash 工具向模型报"命令成功、exit 0"附半截输出,模型基于假成功推进(以为测试跑通)。长任务/E2B/内存受限容器里 OOM 回收不罕见。
|
|
37
|
-
- **修法**:close 回调接 `(code, signal)`,`signal != null` 时返回非零/失败(如 `exitCode: 128 + signalNum` 或显式 ExecutionError)。
|
|
38
|
-
- **置信度**:高。
|
|
39
|
-
|
|
40
|
-
### A-4 ✅ shell-output 满载竞态:full-output 文件静默缺块 + 泄漏孤儿 temp 文件 — vendored
|
|
41
|
-
|
|
42
|
-
- **位置**:`src/vendor/agent-core/src/harness/utils/shell-output.ts:85-130`
|
|
43
|
-
- **问题**:输出超 50KB(`DEFAULT_MAX_BYTES`)且流速快时,`ensureFullOutputFile` 只在**同步调用点**检查 `fullOutputPath`,排进 `writeChain` 的异步任务内不重检。`createTempFile`(mkdtemp+writeFile)在途时又来 data 事件 → 第二次 `ensureFullOutputFile` 创建第二个 temp 并覆盖 `fullOutputPath`;file1 建成到 file2 建成之间的 chunk 按当时值追加到 file1,而最终返回模型的是 file2。
|
|
44
|
-
- **后果**:消息称 `[Output truncated. Full output: <file2>]`,模型读 file2 时中/尾段 chunk 静默缺失(数据丢失),并泄漏 N-1 个孤儿 temp 文件。`cat 大文件`/构建日志即触发。
|
|
45
|
-
- **修法**:writeChain 任务开头重检 `fullOutputPath`,已建则复用。
|
|
46
|
-
- **置信度**:高(逻辑确定)。
|
|
47
|
-
|
|
48
|
-
### A-5 ✅ `checkInvariants` 把"不变量求值抛错"当 pass — 验证门对最粗的结构违例静默放行
|
|
49
|
-
|
|
50
|
-
- **位置**:`src/core/property-harness.ts:225-231`
|
|
51
|
-
- **代码**:`try { if (!iv.check(fn, input)) found.set(...) } catch { /* skip this input */ }`
|
|
52
|
-
- **问题**:集合类不变量直接对输出 `.map`/`.length`/`.every`/spread。实现若返回 `undefined`/`null`/数字/对象(worker 写错返回类型——最常见的结构性 bug),check 抛 TypeError 被吞 → 该输入记为"未违例"。类型错是确定性的(每个 trial 必抛),结果 `{ok:true, violations:[], trials:200}` 零信号。模块头宣称"structural-contract bug class deterministically caught (16/16)",对"输出根本不是集合"这种最粗违例静默放行;soundness(0 FP) 保住但 completeness 静默坍塌,无 skipped 计数暴露。
|
|
53
|
-
- **修法**:check 抛错记为该 kind 违例(输出不符合契约隐含结构即违例),或至少在 CheckResult 上报 evaluation-error 计数。
|
|
54
|
-
- **置信度**:中高(catch 是有意取舍,但与模块核心承诺直接矛盾)。
|
|
55
|
-
|
|
56
|
-
### A-6 ✅ `delimitUntrusted` 默认路径不中和带属性的 `<system-reminder …>` 伪造标签 — 围栏逃逸缺口
|
|
57
|
-
|
|
58
|
-
- **位置**:`src/core/untrusted-text.ts:24`(严格正则)vs `:37`(属性容忍正则),`delimitUntrusted`(:63) 走空 extraTags 路径
|
|
59
|
-
- **问题**:注释(:35-37)明说属性容忍是"so a forged-with-attributes tag is neutralized too",但只有 `extraTags` 非空路径用属性容忍正则;空路径回退严格正则 `/<\/?\s*system-reminder\s*>/gi`,对 `<system-reminder importance="x">` 不匹配。而 **`delimitUntrusted` 恰好只走空路径**——即 web_fetch 外部内容(web.ts:144)、MCP 资源(mcp.ts:208)、verify 的 implementer 报告(verify.ts:188)这些最高危外部入口,开标签原样保留(仅闭标签被中和)。
|
|
60
|
-
- **后果**:防御纵深层出现缺口,被注入内容可能伪装系统级指令。注意 design/53 自承围栏是 defense-in-depth 非 guarantee(真边界是去相关+读客观产物),故定 A 而非 S。
|
|
61
|
-
- **修法**:让空-tags 路径也用属性容忍正则(两路径统一)。
|
|
62
|
-
- **置信度**:高(行为实测)。
|
|
63
|
-
|
|
64
|
-
### A-7 ✅ 记忆内容未经围栏直接注入系统提示词 — 跨会话持久化注入通道
|
|
65
|
-
|
|
66
|
-
- **位置**:`src/core/memory.ts:376`(`<user_memory>` payload 原样)、`src/core/memory-recall.ts:121-131`(selective bullet + manifest description 原样)
|
|
67
|
-
- **问题**:`remember` 工具存原始 note(memory.ts:444-447),consolidation 的 `add` 也原样 append。一条含 `</user_memory>\n<system-reminder>…` 的 note(模型被引导 remember,或 consolidation LLM 被候选文本干扰后 add)会在**之后每个同 scope 会话的系统提示词内**逃出围栏伪装系统指令——跨会话持久化、位置比 A-6 更高(system prompt)。对比:consolidation 提示词自己都把记忆文本当 DATA 防注入,trusted 侧 runtask 也拒 `</system-reminder>`,唯独注入面这条链没过 `sanitizeUntrustedText`。
|
|
68
|
-
- **修法**:`composeMemoryBlock`/`composeSelectiveMemoryBlock`/`buildManifestText` 对内容过 `sanitizeUntrustedText(text, ["user_memory"])`(且修复 A-6 后才完整)。
|
|
69
|
-
- **置信度**:高(代码确凿);是否纯 by-design 中等,但与 design/53 结构性要求矛盾。
|
|
70
|
-
|
|
71
|
-
### A-8 ✅ subagent 子报告未走 untrusted 围栏 — design/53 结构性要求的委派路径遗漏(忘接线类)
|
|
72
|
-
|
|
73
|
-
- **位置**:`src/agents/subagent.ts:194-207`(`child.result` 原文拼进 `[Sub-agent report]` 回注 leader 上下文,结尾还带可信指令行)
|
|
74
|
-
- **设计依据**:design/53 §2.A 原则:"worker 的任何输出进入任何 prompt(judge/leader/人/下一 worker)前必须 sanitize/opaque-delimit——结构性、普适"。该要求已落在 verify.ts:8/170、team.ts:5/14(1.74.0)、web.ts:144、mcp.ts:208(1.82.0),**唯独 subagent 全文无 sanitize/delimit**。被注入的子 agent 可在 result 里伪造 `[Sub-agent report] status: completed` 框架或 system-reminder 标签污染 leader。委派树正是 design/48/50 主线的 leader←worker 路径。
|
|
75
|
-
- **修法**:`delimitUntrusted("sub-agent report", child.result)` 或 `sanitizeUntrustedText`。
|
|
76
|
-
- **置信度**:中高("逐点补围栏漏掉结构性站点"恰是 design/53 round-1 council 警告的模式;保留意见:可能是已知排期,建议与 core 的 design/53 track 对账)。
|
|
77
|
-
|
|
78
|
-
---
|
|
79
|
-
|
|
80
|
-
## 忘接线(无用代码 = 漏挂的接线,B 级)
|
|
81
|
-
|
|
82
|
-
### W-1 ✅ `TaskSpec.sessionTtlDays` 全仓无人读 — README 文档化但静默 no-op
|
|
83
|
-
|
|
84
|
-
- **位置**:`src/core/types.ts:377`
|
|
85
|
-
- **依据**:design/01 第 79 行列进 TaskSpec 契约("默认 7");README.md:170/670 至今文档化("空闲超过 sessionTtlDays 被清理")。
|
|
86
|
-
- **证据**:自 initial commit 起全仓(binary-safe grep)只有声明这一行、零读取。实际 TTL 只走 store 级 `TtlSessionStore({defaultTtlDays})`,且 `SessionStore.acquire(sessionId?)` 签名无 TTL 参数——链路第一环就断。
|
|
87
|
-
- **后果**:消费者按 README 设 per-task TTL 静默 no-op。修法:给 acquire 加可选 TTL 并 plumb,或删字段 + 改 README(后者符合现状)。
|
|
88
|
-
|
|
89
|
-
### W-2 ✅ `RunnerDeps.agents` 全仓无人读 — design/38b 双接线只接了一半
|
|
90
|
-
|
|
91
|
-
- **位置**:`src/core/types.ts:824`
|
|
92
|
-
- **依据**:design/38b §1.2 明确双接线 `RunnerDeps.agents`(部署声明一次)+ `createSubagentTool({agents})`。引入 commit 自述"step 1 类型基座",step 3 最终只接到 `SubagentToolOptions.agents`(subagent.ts:29,正常工作),RunnerDeps 这个槽被遗忘。
|
|
93
|
-
- **证据**:`deps.agents` 全仓零读取;`Runner.deps` 是 private,部署放进去既没人消费也取不回 = write-only 字段。
|
|
94
|
-
- **后果**:部署在 deps 声明 agents 期望委派工具看到 → 静默 no-op。修法:删字段,或 prepare-task 在 `deps.agents` 存在时自动挂委派工具(更大变更需 council)。
|
|
95
|
-
|
|
96
|
-
### W-3 ✅ `FILE_TOOL_NAMES` 死代码 — 建议删
|
|
97
|
-
|
|
98
|
-
- **位置**:`src/tools/fs/index.ts`(`FILE_TOOL_NAMES`)
|
|
99
|
-
- **依据**:引入注释"for tool-filter / docs"(design/44 §6/§9),但 design/38 tool-filter 收的是调用方给的名字串,core 内部不需要这个常量。
|
|
100
|
-
- **证据**:src/test 全仓零引用,且**没**从 index.ts 导出(下游够不着)。用途已被 `HAND_TOOL_EFFECTS`(已根导出、prepare-task 在用)完全覆盖(`Object.keys(HAND_TOOL_EFFECTS)` 即全集)。
|
|
101
|
-
- **修法**:删除;若 service 确需"纯文件工具子集"再像 HAND_TOOL_EFFECTS 一样根导出。
|
|
102
|
-
|
|
103
|
-
---
|
|
104
|
-
|
|
105
|
-
## 其他 B 级(16 条)
|
|
106
|
-
|
|
107
|
-
复核:✅=主会话读码核实;◐=分片证据充分抽查通过;○=分片报告未独立复核。
|
|
108
|
-
|
|
109
|
-
| # | 发现 | 位置 | 状态 |
|
|
110
|
-
|---|------|------|------|
|
|
111
|
-
| B-1 | `runToolGate` hook-ask 提升整体覆盖 policy 的 `allow{updatedInput}` → 审批通过后重写丢失(hook-ask + 重写 policy + 批准三者叠加触发)。A-1 的同族第三处 | `src/core/hooks.ts:172-174,199-201` | ✅ |
|
|
112
|
-
| B-2 | `validateSelectedIds` off-by-one:push 后才查 `>= max`,`maxSelected:0` 实测返回 1 条 | `src/core/memory-recall.ts:103-108` | ◐ |
|
|
113
|
-
| B-3 | selective 路径选中 note 正文**无字节上限**(manifest 有 200 行/25KB 帽、inject-all 有 100KB 帽,唯独选中正文无帽),一条超大 note 被选中即无限进系统提示词 | `src/core/memory-recall.ts:114-134` | ◐ |
|
|
114
|
-
| B-4 | manifest 写 "call recall to fetch by id",但 `recall` 是关键词搜索、渲染不含 id → 模型照 id 调必返 "No memory matches",逃生通道名存实亡 | `src/core/memory-recall.ts:130` + `memory.ts:153` | ◐ |
|
|
115
|
-
| B-5 | selector:外层 signal 已 aborted 时 `addEventListener("abort")` 永不触发 → 照常烧 20s API;应先查 `signal?.aborted` | `src/core/memory-recall.ts:154-155` | ○ |
|
|
116
|
-
| B-6 | selector:`runner.runTask` 在 try/finally 外,throw 时 `release(sessionId)` 不执行 → 会话泄漏 | `src/core/memory-recall.ts:200,228` | ○ |
|
|
117
|
-
| B-7 | `roles.ts` 显式 `spec.model` 直接 return,丢请求 role 的 `systemPrompt` 预设——与 :164-166 自述不变量矛盾(`modelRole:"coder"`+显式 model 静默退回中性提示词);可能设计取舍 | `src/core/roles.ts:159-161` | ◐ |
|
|
118
|
-
| B-8 | 词法分词只认 `[a-z0-9]`:**纯中文** note/objective 的 termSet 为空 → InMemory `searchScored` 永空(consolidation 把每条 CJK note 当全新永不去重)、`InMemoryStrategyStore.find` 对中文 query 永远 `[]`(teacher 策略零召回)。memory store 自认 dev 替身,strategy store 无此免责 | `src/core/memory.ts:157-164` + `strategy-store.ts:47` | ◐ |
|
|
119
|
-
| B-9 | web_fetch `maxBytes` 既不限内存也不数字节:`res.text()` 先把整个响应缓进内存(多 GB 体可 OOM),`raw.length`/`slice` 按 UTF-16 码元非字节(多字节内容偏) | `src/tools/web.ts:132-133` | ◐ |
|
|
120
|
-
| B-10 | HTTP body-too-large 与 bad-JSON 都映射成 500(应为 413/400),客户端无法区分真服务端故障 | `src/server/http.ts:37-45,75-81` | ◐ |
|
|
121
|
-
| B-11 | `substituteArgs` 多 pass 顺序替换:①pass 1 插入的参数内容被后续 pass 二次展开(参数含 `$@`/`$ARGUMENTS` 被再展开);②后两 `replace` 用字符串值,参数里 `$$`→`$`/`$&` 等被吞(shell `$$` 常见)→ 注入 prompt 的指令失真 | vendor `prompt-template-arguments.ts:42-77` | ◐ |
|
|
122
|
-
| B-12 | skills ignore 规则前缀化破坏 gitignore 锚定:根 `/foo`(仅锚根)变 `foo`(任意深度)过度忽略;子目录 `build` 被前缀成 `sub/build`(含斜杠即锚定)漏忽略 | vendor `skills.ts:269-291` | ○ |
|
|
123
|
-
| B-13 | degrading `terminalOf` 在内层流违约且 stopReason 为 aborted 时铸造协议非法事件 `{type:"done", reason:"aborted"}`(防御兜底路径的兜底铸型错,可达性低) | `src/brain/degrading.ts:112-116` | ◐ |
|
|
124
|
-
| B-14 | exec 等 `close` 而非 `exit`:`bash -c "server &"` 孙进程持有 pipe 时,无 timeout 的调用永不 settle(与 CC 上游同病,上层 bash 工具有默认 timeout 则缓解) | vendor `nodejs.ts:377` | ◐ |
|
|
125
|
-
| B-15 | SQL `stripStringLiterals` 只懂双引号转义(`''`)不懂反斜杠转义(`\'`,MySQL/TiDB 默认开)→ `'a\''` 误解析留悬空引号 → **过度拒绝**(合法单语句被 `;`/关键字检查误判),非欠拒绝;适配器明确针对 TiDB | `src/tools/sql.ts:36-38` | ◐ |
|
|
126
|
-
| B-16 | `abortFallback` 的 10s setTimeout 在 settled 先到时不清理/未 unref(teacher,第一轮 B-7 同源已记,此处再确认) | `src/agents/teacher.ts` | ○ |
|
|
127
|
-
|
|
128
|
-
---
|
|
129
|
-
|
|
130
|
-
## 修复优先级建议
|
|
131
|
-
|
|
132
|
-
1. **安全门(高优)**:A-1(combinePolicies)+ B-1(hooks hook-ask)——同一族重写丢失,应一起修;A-2(SQL comma-join)。
|
|
133
|
-
2. **正确性 blocker**:A-3(exec signal→0,vendored)、A-4(shell-output 竞态,vendored)、A-5(property-harness 假阴性)。
|
|
134
|
-
3. **注入纵深**:A-6 + A-7 + A-8 应一起做(A-6 修好围栏函数,A-7/A-8 再把记忆/委派两条链接上)——与 core 的 design/53 track 对账。
|
|
135
|
-
4. **忘接线**:W-1/W-2 二选一(删字段+改文档 或 真接线),W-3 删除。建议先和 service 确认 README 契约预期。
|
|
136
|
-
5. B 级随模块顺修;B-8(中文分词零召回)若生产用 InMemory store 处理中文负载,影响升级。
|
|
137
|
-
|
|
138
|
-
## 本轮验证过成立的不变量(避免重复挖)
|
|
139
|
-
|
|
140
|
-
- **权限层叠**:deny>ask>allow 不可绕(hook deny 短路、policy 跑在 post-hook args 上、policy deny 终局);`combinePolicies` deny 短路正确(只丢 rewrite 不丢 deny);resolveAsk/approval fail-closed(headless auto-deny、abort→deny、timeout 单次 settle+unref);suspendAsk 不双解析。
|
|
141
|
-
- **exec-gate**:空 suite `passed:false` 非 vacuous;null exitCode 永不 ok;`clampBytes` UTF-8 回退正确无死循环;timeoutSec→秒 单位与 vendored 契约一致无 1000×。
|
|
142
|
-
- **web SSRF/重定向**:allowlist 下每跳 `redirect:"manual"` + 跳前 re-validate host+scheme,跨 host 重定向请求前被拒;exact-host 匹配 IP/localhost 别名 fail-closed;重定向上限 5。
|
|
143
|
-
- **MCP**:未知 content 类型 fallthrough 到 JSON.stringify 不丢;inputSchema 原样透传;per-server fail-open + 原子 staging;CR/LF 头注入守卫。LSP 1-based 行/0-based 列约定一致无 off-by-one。gitea token 只在 header、owner/repo encodeURIComponent。
|
|
144
|
-
- **PushQueue** 无丢消息/重复消费;**trace** emit 吞 throw、lazy;**tool-filter** 精确名 Set 无子串误判、deny 恒胜;**defineTool** schema 预校验、AbortError 包装不破坏 abort 语义。
|
|
145
|
-
- **messages.ts convertToLlm** 零字段丢失(thinking/ToolCall/thoughtSignature/image 透传);**validation.ts** `Value.Convert` in-place 变异对对象 args 成立(核过 typebox 源码)、union/required 路径正确;**kill-tree** 进程组终止链自洽;**internal/** 纯 re-export 零语义偏移;**degrading** hold-start/abort 不降级/terminal 必发逐条干净。
|
|
146
|
-
- **consolidation** band 方向正确、id 白名单防幻觉、fail-open 不丢数据;**composeMemoryBlock** 100KB UTF-8 边界回退正确;ZWSP 中和幂等;selector 软失败 throw→degrade(§80)逻辑正确。
|
|
147
|
-
- 排除的"零引用导出"约 50 个(withRetry/deriveInvariants/runExecGate/parseModelMention/boundedTail/leafIdAfterEntry/policy 工厂/prompt 常量等)均为文档化的下游 service 消费侧 API;`ExecStreamOptions.sandboxTier` 是 design/48 拍的 v2 预留字段非忘接线。
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
# 全仓 blocker 级 bug 扫描(计算类重点)— 2026-06-10
|
|
2
|
-
|
|
3
|
-
- **范围**:src/ 全量(不含 examples),重点为各类计算代码:token 估算/压缩、预算/定价、runner/编排统计聚合、brain 流式解析与 usage、文件工具偏移/截断/路径、vendored 主循环与会话层。
|
|
4
|
-
- **方法**:5 个并行分片审计(fable 模型 subagent 整文件精读)→ 主会话对全部 S/A 级逐条读源码复核裁决(剔除/降级误报后成稿)。B 级保留分片原始发现并标注复核状态。
|
|
5
|
-
- **基线**:commit `33fcdb9`(1.89.2)。
|
|
6
|
-
- **严重度**:S=数据丢失/死循环/会话永久不可用/静默失败的 blocker;A=明确正确性错误、常见路径触发;B=边界条件错误或可观测计算偏差。
|
|
7
|
-
|
|
8
|
-
总计:**S×1、A×8、B×18**。S/A 全部经主会话亲自复核源码确认(标 ✅核实)。
|
|
9
|
-
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
## S 级
|
|
13
|
-
|
|
14
|
-
### S-1 ✅核实 `edit_file` 单次替换走 `String.replace(string, string)` — `$` 替换模式静默腐坏文件
|
|
15
|
-
|
|
16
|
-
- **位置**:`src/tools/fs/index.ts:198`
|
|
17
|
-
- **代码**:
|
|
18
|
-
```ts
|
|
19
|
-
const updated = replace_all === true ? content.split(old_string).join(new_string) : content.replace(old_string, new_string);
|
|
20
|
-
```
|
|
21
|
-
- **问题**:JS `String.prototype.replace` 在 searchValue 为字符串时,replacement 仍解释 `$$`/`$&`/`` $` ``/`$'` 等替换模式。`replace_all` 路径用 split/join(安全),单次替换路径不安全——两路径不一致本身即证据。
|
|
22
|
-
- **触发**:模型编辑 Makefile(`$$` 被吞成 `$`)、bash 的 `$'\n'`(`$'` = "匹配点之后的整个文件后缀",把文件后半段整段复制进替换点)、JS 正则代码里的 `$&`。全是日常编辑负载。
|
|
23
|
-
- **后果**:**静默腐坏**——写回后 `state.set` 用腐坏内容的 hash 记账(:202),staleness 检查抓不到;工具返回 "Edited (1 replacement)" 成功,但文件内容 ≠ 模型给的 `new_string`。
|
|
24
|
-
- **修法**:单次替换也改 split-once-join,或 `content.replace(old_string, () => new_string)`(函数式 replacement 不解释 `$`)。
|
|
25
|
-
- **置信度**:高(JS 语义确定)。
|
|
26
|
-
|
|
27
|
-
---
|
|
28
|
-
|
|
29
|
-
## A 级
|
|
30
|
-
|
|
31
|
-
### A-1 ✅核实 live-interrupt 对账把合成 toolResult 追加在 aborted assistant 消息之后 → 会话被永久污染为 API 非法序列(严格 provider 上等效 S)
|
|
32
|
-
|
|
33
|
-
- **位置**:
|
|
34
|
-
- `src/vendor/agent-core/src/agent-loop.ts:534`(sequential batch 中途 abort `break` → 余下 tool_call 成孤儿)、`:597`(parallel 同构)
|
|
35
|
-
- `src/vendor/agent-core/src/agent-loop.ts:233-258`(内层循环**无 abort 检查**就再次 `streamAssistantResponse`)
|
|
36
|
-
- `src/vendor/agent-core/src/harness/agent-harness.ts:630-645`(`emitRunFailure` 把 stopReason:"aborted" 的空 assistant 消息经 message_start/end **持久化进 session**)
|
|
37
|
-
- `src/core/session-reconcile.ts:101-112`(合成 toolResult append 在当前 leaf,非孤儿相邻位)+ `src/core/runner/runtask.ts:875-887`(调用点,在 run 完全 settle 之后)
|
|
38
|
-
- **触发链**(逐环核实):interrupt/timeout/budget-cancel 打断多工具 batch 中段 → ① assistant(tu1..tu3) 已持久化、TR1/TR2 落盘、tu3 成孤儿;② 内层循环不查 abort 再发流式请求,带 aborted signal 失败 → `emitRunFailure` 持久化一条 aborted 空 assistant 消息;③ 之后 runtask 的对账才跑,合成 TR3 追加在 leaf。最终序列:`A(tu×3), TR1, TR2, A(aborted,""), TR3`。
|
|
39
|
-
- **后果**:`convertToLlm` 与 `toOpenAIMessages` 都保序直通、无配对修复。OpenAI/DeepSeek 等强校验端点对该序列直接 400(assistant 的 3 个 tool_calls 未应答完就出现下一条 assistant;TR3 跟在无 tool_calls 的消息后)。wake 路径 reconcile 此时找不到孤儿(已被"闭合"),**没有任何机制能自愈**——该 session 永久不可复用。自家宽松模板(vLLM/Qwen)可能掩盖,严格端点必炸。对比:suspend 路径明确先回卷 leaf 再对账(prepare-task 注释),interrupt 路径缺等价回卷。
|
|
40
|
-
- **修法**:interrupt 对账前先把 leaf 回卷到孤儿批次最后一条真实 toolResult(镜像 suspend 路径),或对账时移除/跳过尾部 failure 消息。
|
|
41
|
-
- **置信度**:高(四层链全部读码核实);现有测试只覆盖"孤儿在尾部"形态。
|
|
42
|
-
|
|
43
|
-
### A-2 ✅核实 压缩 `findCutPoint` 裁剪预算在尾部 toolResult 批内越界时回落到**最早**切点 → 空摘要 + 上下文不降反升 + 本任务压缩永久关闭
|
|
44
|
-
|
|
45
|
-
- **位置**:`src/vendor/agent-core/src/harness/compaction/compaction.ts:403-421`(回落)、`:817`(非 split 分支无条件 `generateSummary(messagesToSummarize)`,对比 split 分支 :782 有 `length > 0` 守卫)、`src/core/runner/runtask.ts:750`(floor 放大)
|
|
46
|
-
- **代码**:
|
|
47
|
-
```ts
|
|
48
|
-
let cutIndex = cutPoints[0]; // 初值 = 最早切点
|
|
49
|
-
for (let i = endIndex - 1; i >= startIndex; i--) {
|
|
50
|
-
...
|
|
51
|
-
if (accumulatedTokens >= keepRecentTokens) {
|
|
52
|
-
for (const cutPoint of cutPoints) {
|
|
53
|
-
if (cutPoint >= i) { cutIndex = cutPoint; break; } // 只向后找
|
|
54
|
-
}
|
|
55
|
-
break;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
```
|
|
59
|
-
- **问题**:toolResult 不是合法切点(正确)。within-task turn_boundary 触发时 session 总以最后一批 toolResult 结尾;若该批自身估算 ≥ `keepRecentTokens`(默认 20000≈80KB——两个 50KB 截断上限的并行 read/grep 即达;小窗口 sanitize 后更低),反向累计在最后一个合法切点**之后**就越界,`cutPoint >= i` 找不到任何切点,回落 `cutPoints[0]`(最早)。正确语义应是「≤ i 的最大切点」。
|
|
60
|
-
- **后果链**:`firstKeptEntryIndex≈0` → `messagesToSummarize=[]` → 空 `<conversation>` 喂模型产出幻觉摘要 → 摘要 append 但全部原历史保留 → 上下文不降反升 → `freedTokens=0` → floor = `tokensBefore × 1.5` 可超窗口 → **本任务内 within-task 压缩永久关闭**,退化为 trimToBudget 丢最老消息(恰是 design/64 §25 要消灭的行为),观测面只见一次"成功" compacted 事件。
|
|
61
|
-
- **修法**:回落改为「≤ i 的最大 cutPoint」;并给非 split 分支补 `messagesToSummarize.length === 0` 短路(防御纵深)。
|
|
62
|
-
- **置信度**:高。
|
|
63
|
-
|
|
64
|
-
### A-3 ✅核实 Anthropic brain `totalTokens` 漏算 cache token → usage 锚定的上下文估算大幅低估 → 压缩不触发
|
|
65
|
-
|
|
66
|
-
- **位置**:`src/brain/anthropic.ts:189`
|
|
67
|
-
- **代码**:`totalTokens: input + output,`
|
|
68
|
-
- **问题**:Anthropic API 的 `input_tokens` **不含** `cache_read_input_tokens`/`cache_creation_input_tokens`。下游 `calculateContextTokens`(vendor compaction.ts:147)是 `usage.totalTokens || input + output + cacheRead + cacheWrite`——fallback 公式自证 `totalTokens` 预期语义为"含 cache 的全上下文",但非零时短路取它,cache token 全丢。本 brain 默认开 cacheBreakpoints,长任务里绝大部分 prompt 是 cacheRead(100k 上下文 input_tokens 可能只有几百)。
|
|
69
|
-
- **后果**:auto-compaction 的 usage 锚严重低估 → 压缩永不触发 → 长任务被 provider context overflow 硬拒;`stats.tokens` 同样少计。OpenAI brain 无此问题(`total_tokens` 全量)——跨 brain 语义不一致坐实。
|
|
70
|
-
- **修法**:`totalTokens: input + output + cacheRead + cacheWrite`。
|
|
71
|
-
- **置信度**:高。
|
|
72
|
-
|
|
73
|
-
### A-4 ✅核实 定价表缺 `cacheReadPer1M`/`cacheWritePer1M` 时缓存 token 计为**免费**,与文档承诺的"按全价入账"相反 → 成本系统性少算、预算钳失效
|
|
74
|
-
|
|
75
|
-
- **位置**:`src/core/pricing.ts:12-17`(文档)vs `:46-56`(实现)。两个分片独立发现。
|
|
76
|
-
- **问题**:`per1M(tokens, undefined)` 返回 0,而 `fullInput` 已**无条件**把 cache 子集从总输入减掉。结果:定价表只配 `cost:{input,output}`(漏 cacheRead 字段,OpenAI 系自动缓存下很常见)时,缓存命中 token 既不按缓存价也不按全价——直接免费。接口注释明示 "absent ⇒ treated as full-price input"(保守多算),实现是 "absent ⇒ free"(激进少算),方向相反。
|
|
77
|
-
- **后果**:暖循环 80–95% 输入是 cacheRead,账面成本可少算到真实的 ~1/5 以下;`overBudget()`/cascade/verify 的 `costCeilingMicroUsd` 全基于该低估值——预算钳形同虚设。`cacheWrite`(Anthropic 1.25×)同理。
|
|
78
|
-
- **修法**:price 缺失时该子集不从 `fullInput` 扣(落回全价);显式 0 仍可表示免费。`modelCostToPricing` 已保留 undefined 区分,无需动。
|
|
79
|
-
- **置信度**:高。
|
|
80
|
-
|
|
81
|
-
### A-5 ✅核实 OpenAI brain finalize 丢弃 thinking 块 → `replayThinking` 端到端死路
|
|
82
|
-
|
|
83
|
-
- **位置**:`src/brain/openai.ts:414-491`(`finalContent` 只 push text/toolCall,`accumReasoning` 只用于错误文案);回放条件 `:173-179`(filter `m.content` 中 `type==="thinking"`);对照 anthropic.ts thinking 块进 final。
|
|
84
|
-
- **问题**:harness 存进 session 的是最终消息(agent-loop message_update 的 partial 被 final 整体替换)。本 brain 产出的最终消息永远没有 thinking 块 → 回放条件对自产消息**恒空** → `reasoning_content` 永不回放。文件头注释自己声明 "DeepSeek 在 tool-call 轮 **requires** it — else it errors/degrades"。现有测试用手工构造的含 thinking 消息测回放,从未测"本 brain 产出 → session → 回放"闭环,测试绿但功能死。
|
|
85
|
-
- **后果**:DeepSeek V4 类 provider 工具调用后续轮报错/降质,或特性整体静默失效。
|
|
86
|
-
- **修法**:finalize 时把 `accumReasoning` 作为 `{type:"thinking"}` 块放进 finalContent(放 text 之前,保持与 anthropic 一致)。
|
|
87
|
-
- **置信度**:高(机制确定);provider 实际报错程度依部署。
|
|
88
|
-
|
|
89
|
-
### A-6 ✅核实 grep/glob 的 `path` 参数无 root 包含性检查 — 文件工具读边界可被绕穿
|
|
90
|
-
|
|
91
|
-
- **位置**:`src/tools/fs/search.ts:170`(jsGrep)、`:239-241`(rgGrep:`rg ... -- <path>` cwd=root 原样执行)、`:268`(runGlob)
|
|
92
|
-
- **代码**:
|
|
93
|
-
```ts
|
|
94
|
-
const start = p.path ? (p.path.startsWith("/") ? p.path : `${rootPrefix}${p.path}`) : root;
|
|
95
|
-
```
|
|
96
|
-
- **问题**:read/edit/write 全走 `resolveKey`(canonicalize + `within`),但 grep/glob 的 `path` 直接拼接:绝对路径 `/etc` 或相对 `../../..` 直接走出 root。`grep pattern="." path="/etc" context=5` 即可整段倒出 root 外文件内容。工具描述自己承诺 "within the root",design/44 §4 inv 5/6/7 声明文件工具有 rootPath 包含性。
|
|
97
|
-
- **后果**:普通模式因 bash 本就不沙箱、实际增量有限;但 **verifier readOnly 模式(无 bash、只挂 read/grep/glob)下这是该模式声明边界的真实逃逸**。
|
|
98
|
-
- **修法**:`path` 参数过 canonicalize+`within`(与 read 同路径),拒绝越界。
|
|
99
|
-
- **置信度**:高。
|
|
100
|
-
|
|
101
|
-
### A-7 ✅核实 teacher `finalize` 的累计 stats 漏掉权威成本字段 `costMicroUsd` 等 → 聚合自相矛盾
|
|
102
|
-
|
|
103
|
-
- **位置**:`src/agents/teacher.ts:544-553`
|
|
104
|
-
- **代码**:
|
|
105
|
-
```ts
|
|
106
|
-
stats: { ...result.stats, tokens: studentTokens, turns: studentTurns, costUsd: studentCost || undefined },
|
|
107
|
-
```
|
|
108
|
-
- **问题**:多次学生/helper 运行后,`tokens/turns/costUsd` 替换为累计值,但展开保留的 `costMicroUsd`、`promptTokens`、`cachedTokens`、`outputTokens`、`nested` 全是**末次** runTask 的值。types.ts 明确标注 `costMicroUsd` 是 authoritative、`costUsd` 已 `@deprecated`——按推荐字段读成本的消费者,在每次发生 escalation 的 teacher run(stuck/verify-fail 必然多 run)都拿到只含末次尝试的成本、token 却是累计值,同一对象内部互相矛盾。注释自称 "coherent" 不成立。附带:`addStudent`(:318-322) 不计 `nested`(学生用 subagent 时 spendCap 比率与最终 stats 漏计委派成本),`addTeacher`(:323-327) 计——不对称。
|
|
109
|
-
- **修法**:累计并回写 `costMicroUsd/promptTokens/cachedTokens/outputTokens`(或显式删除无法累计的字段);`addStudent` 补 nested;`teacherStats` 补 `costMicroUsd`。
|
|
110
|
-
- **置信度**:高。
|
|
111
|
-
|
|
112
|
-
### A-8 ✅核实 JS fallback grep 静默忽略 `glob` 与 `multiline` 参数 → 误导性 "No matches"
|
|
113
|
-
|
|
114
|
-
- **位置**:`src/tools/fs/search.ts:161-208`(`jsGrep` 全函数未引用 `p.glob`/`p.multiline`;`compilePattern` 纯按行)
|
|
115
|
-
- **触发**:无 rg 的环境(远端 E2B/SSH——正是主线执行面场景)或 rg exec 失败/exit≥2 回退(:242/:245)。
|
|
116
|
-
- **后果**:①带 `glob:"*.ts"` 的搜索扫**所有**文件,无关匹配先填满 200 条 cap,目标结果被挤掉;②`multiline:true` 按行匹配跨行 pattern 必然 0 命中,返回 "No matches."——模型据此得出"代码里没有 X"的错误结论。两者均无"参数未生效"提示。
|
|
117
|
-
- **修法**:jsGrep 实现 glob 过滤(已有 `globTokenToRegExp`)与 multiline(整文件匹配再映射行号);至少对不支持的参数返回显式提示而非静默忽略。
|
|
118
|
-
- **置信度**:高(行为确定)。定 A 的理由:远端无 rg 是主线部署形态,触发即产出错误结论。
|
|
119
|
-
|
|
120
|
-
---
|
|
121
|
-
|
|
122
|
-
## B 级
|
|
123
|
-
|
|
124
|
-
复核标记:✅=主会话读码核实;◐=分片证据充分、主会话抽查通过;○=分片报告,逻辑成立但未独立复核(建议修前自查)。
|
|
125
|
-
|
|
126
|
-
| # | 严重度 | 发现 | 位置 | 状态 |
|
|
127
|
-
|---|--------|------|------|------|
|
|
128
|
-
| B-1 | B | §25.2 反 thrash floor 与触发估算单位不一致:anchor-less 下触发量含 `overheadTokens` 而 `tokensBefore/freedTokens` 不含 → overhead > 0.5×postChars 时 floor 永远拦不住,每 boundary 烧一次真摘要(floor 要防的正是这个)。anchored 下 `tokensBefore`(usage 真值) vs `freedTokens`(chars/4) 坐标系混用,floor 系统性偏高 | `src/core/auto-compaction.ts:137,204-213` + `runtask.ts:750-752` | ◐(数学推演成立;anchor-less+大 overhead 是该参数的目标场景) |
|
|
129
|
-
| B-2 | B | `estimateTokens` 对 user 消息 image 块计 0、对 toolResult/custom 的 image 计 4800 — 不对称漏计;anchor-less+`spec.images` 时系统性低估 | vendor `compaction.ts:260-273` vs `:288-301` | ◐ |
|
|
130
|
-
| B-3 | B | `prefer:"premium"` 把缺 cost 元数据的模型(`costOf`→Infinity 哨兵)当"最贵=最强"确定性选中 → 静默错误路由 | `src/core/select-model.ts:27-32,64-68` | ◐ |
|
|
131
|
-
| B-4 | B | 成功的 resume 任务可被 `unpin` 异常(自定义 durable store reject、无 try/catch)改写为零统计 failed 结果 → 调用方重发=重复副作用 | `runtask.ts:987-992` | ○ |
|
|
132
|
-
| B-5 | B | cascade stats 内部不一致:`costMicroUsd` 跨梯级求和而 `tokens/turns/costUsd` 只取末级;`rungCost` 不含 `nested.costMicroUsd`(梯级用 subagent 时钳子漏计)。同族:team.ts:228、verify.ts:249/284 的 spend 均不含 nested | `src/agents/cascade.ts:142,202` | ◐(与 A-7 镜像) |
|
|
133
|
-
| B-6 | B | subagent 对子结果无 suspended 守卫(五编排器唯一缺失;今天不可达、透传 durableApproval 即触发=孤儿化 checkpoint)且 `release` 无 catch:flaky release 使已完成子任务报告对父模型丢失、`reportUsage` 不执行 | `src/agents/subagent.ts:166-182` | ○ |
|
|
134
|
-
| B-7 | B | teacher stuck-abort 竞速失败时用零统计合成结果顶替真实运行 → 该次学生运行的 token/成本从累计消失、`teacherSpendRatioCap` 分母失真;附 `abortFallback` 的 10s setTimeout 不清理/未 unref | `src/agents/teacher.ts:380-397` | ○ |
|
|
135
|
-
| B-8 | B | team 对 suspended 成员丢弃 checkpointToken(只拼文本标记),`TeamResult` 无承载字段 → 成员可挂起后审批被消费却永远无法 resume(潜伏:成员 spec 今天不带 durableApproval) | `src/agents/team.ts:233-236` | ○ |
|
|
136
|
-
| B-9 | B | 任务内/任务末压缩的 LLM 调用走 brain 旁路,token/成本不进 `stats`、不参与 `overBudget()`、trace 无记录 → 1.88+ 长任务每 boundary 可能一次,真实成本系统性低估且不可见 | `runtask.ts:729-741,1338-1349` | ◐ |
|
|
137
|
-
| B-10 | B | repetition 阈值可误判正常输出:60 字符同字符 run(代码 banner `====…` 70-80 字符常见)触发 check 1;精确重复短单元×6 覆盖 120 字符(测试 fixture 数组元素)触发 check 2 → 整轮标 error(文本有 salvage 兜底)。原报 A,主会话降 B:启发式阈值取舍、注释已声明 conservative、salvage 限损 | `src/brain/repetition.ts:23-25` | ✅(机制核实;误判率依输出分布) |
|
|
138
|
-
| B-11 | B | anthropic `lastDegenCheck` 跨 content block 共享(parser 级变量 vs block 级 `acc.text`)→ 第二个及以后 text block 的重复检测窗口整体错位 | `src/brain/anthropic.ts:269,318` | ○ |
|
|
139
|
-
| B-12 | B | openai tool_call delta `index ?? 0`:网关不发 index 且并发多工具时合并进槽 0 → args 拼接成非法 JSON → 本可成功的轮变失败轮(有 malformed 防线、非静默错参) | `src/brain/openai.ts:404` | ✅(代码核实;触发依赖网关行为) |
|
|
140
|
-
| B-13 | B | openai `computeUsage`:`prompt_tokens` 含 cached 但 `costInput = input × c.input` 全价计,cacheRead 传了 token 数不参与成本 → brain 级成本**高估**(与 A-4 的 core 级少算方向相反;权威路径在 core,影响仅 brain 自报 cost 可观测性) | `src/brain/openai.ts:241-249` | ◐ |
|
|
141
|
-
| B-14 | B | `runGlob` 非锚定匹配放宽语义:`*.ts` 等价 `**/*.ts`、`src/*.json` 命中 `a/src/x.json`;brace `*.{ts,tsx}` 在 JS 路径被当字面量永不匹配(与 grep 文档示例矛盾,rg 路径支持) | `src/tools/fs/search.ts:270-273` | ◐ |
|
|
142
|
-
| B-15 | B | JSONL 尾行撕裂写(crash/断电/磁盘满 mid-append)→ `parseEntryLine` 抛错 → 整个会话(含全部完好历史)永久拒绝加载,无截断恢复(CC 同类存储可容错)。fail-loud 非静默,但属数据不可达 | vendor `jsonl-storage.ts:161-174` | ◐ |
|
|
143
|
-
| B-16 | B | `TtlSessionStore` 与其文档点名支持的 vendored `JsonlSessionRepo` 运行时不兼容:`open` 不给 path、`create` 不给 cwd(`encodeCwd(undefined)` TypeError);另 `sweep()` 的 `void this.repo.delete(...)` reject 即 unhandled rejection | `src/core/session-store.ts:108,121,167` vs vendor `jsonl-repo.ts:98-109` | ○ |
|
|
144
|
-
| B-17 | B | reconcile 冲突重试调 `release`,默认 in-memory repo 的 evictPolicy="delete" → 会话整删 → `openOrCreate` 同 id 新建**空会话**继续跑(静默全量上下文丢失)。前提:并发任务共享同一 sessionId | `src/core/session-store.ts:70,136-145` + `prepare-task.ts:310` | ○(触发条件苛刻) |
|
|
145
|
-
| B-18 | B | `getPathToRoot` 对 parentId 环无防护:损坏/外改 JSONL 两行互指即 `open` 后首次 `buildContext` 死循环(`unshift` O(n²) 放大) | vendor `storage-base.ts:173-189` | ◐ |
|
|
146
|
-
|
|
147
|
-
---
|
|
148
|
-
|
|
149
|
-
## 修复优先级建议
|
|
150
|
-
|
|
151
|
-
1. **立即**(一行级修复、爆炸半径大):S-1(edit_file `$`)、A-3(anthropic totalTokens)、A-4(pricing cache 免费)。
|
|
152
|
-
2. **高优**(需小重构、影响主线长任务/会话复用):A-1(interrupt 回卷)、A-2(findCutPoint 回落 + 空摘要守卫)、A-6(grep/glob path 包含检查)。
|
|
153
|
-
3. **随版**:A-5(thinking 进 finalContent)、A-7(teacher stats)、A-8(jsGrep glob/multiline)。
|
|
154
|
-
4. B 级按触碰相应模块时顺修;B-1/B-9 与 1.88-1.89 压缩主线直接相关,建议并入 design/64 收尾。
|
|
155
|
-
|
|
156
|
-
## 验证过成立的不变量(扫描中确认无问题,避免重复挖)
|
|
157
|
-
|
|
158
|
-
- 嵌套统计上报无重复计数(subagent 上报 own+nested、父侧只累计上报值);轮次计数无 off-by-one;超时单位 ms/s 一致;`overBudget` 方向正确;cacheHitRate 除零守卫。
|
|
159
|
-
- 压缩多轮链不双计不漏计(boundaryStart/previousSummary/entry 排除);空摘要 THROW 在 append 之前;`sanitizeCompactionSettings` 三段算术正确;truncate.ts 字节记账与 surrogate 处理正确。
|
|
160
|
-
- fs safety:`within` 分段比较无 `/root` vs `/root2` 误判;read-before-edit/hash staleness/唯一匹配链自洽(read/edit/write 路径;grep/glob 例外见 A-6);walk 有 visited-Set 防环。
|
|
161
|
-
- stream-engine 行切分/UTF-8 跨 chunk/重试边界正确;两 brain 工具调用按 index 累积无串台(带 index 时);usage 取最后一帧语义正确。
|
|
162
|
-
- leaf-CAS 乐观锁语义正确(误报方向安全);Checkpoint 全字段 JSON-safe 往返保真;steering drain 无重复消费/丢失。
|
|
163
|
-
- tool-result-budget 批边界扫描无重叠;context-guard 尾扫 off-by-one 验过;cache-break-detector 方向正确且防除零;with-retry 退避参数正确。
|