@a9i5k4/dsh-auto-memory 2.5.3 → 3.0.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 +189 -7
- package/README.zh-CN.md +189 -7
- package/docs/CONTRIBUTORS.html +471 -0
- package/docs/FRONTEND-CO-CREATION.md +191 -0
- package/docs/GM53-HOMEPAGE-PROMPT.md +323 -0
- package/docs/HANDOFF-CRITERIA.md +92 -0
- package/docs/HOMEPAGE-CONTENT-FOR-GM53.md +299 -0
- package/docs/INTEGRATION-ANALYSIS.md +350 -348
- package/docs/PROMO-PROMPT-3.0.md +100 -0
- package/docs/USER-GUIDE.en.md +58 -3
- package/docs/USER-GUIDE.zh-CN.md +59 -4
- package/docs/WHITEPAPER.md +207 -0
- package/docs/internal/ACCEPT-35-LIVE.md +143 -0
- package/docs/internal/ACCEPTANCE-20260914.md +90 -0
- package/docs/internal/ARCH-REVIEW-BRIEF.md +411 -0
- package/docs/internal/ARCH-REVIEW-REQUEST.md +201 -0
- package/docs/internal/ARCH-REVIEW-ROUND2.md +169 -0
- package/docs/internal/ARCH-REVIEW-ROUND3.md +206 -0
- package/docs/internal/ARCHITECTURE-FOR-ZCODE-20260920.md +397 -0
- package/docs/internal/ART-DIRECTION-DEEPSEEK-20260920.md +351 -0
- package/docs/internal/ART-DIRECTION-WIREFRAME.md +191 -181
- package/docs/internal/ART-DIRECTION-WIREFRAME.md.bak-superseded +181 -0
- package/docs/internal/AUDIT-WB-GRAPH-FULL-20260916.md +314 -0
- package/docs/internal/BATTLE-PLAN-20260917.md +871 -0
- package/docs/internal/CONCURRENCY-INVESTIGATION-20260917.md +192 -0
- package/docs/internal/CROSS-SESSION-SEARCH-PATH-DECISION.md +72 -0
- package/docs/internal/CROSS-SESSION-SEARCH-RESEARCH.md +131 -0
- package/docs/internal/DECISIONS-20260914-SESSION.md +269 -0
- package/docs/internal/DESIGN-P1-STATE-COMMIT-20260915.md +219 -0
- package/docs/internal/DIRECTION-CHECK-WB-GRAPH-20260916.md +132 -0
- package/docs/internal/FEATURE-INVENTORY.md +531 -0
- package/docs/internal/FEEDBACK-TO-DSHAPI-RELAY.md +13 -0
- package/docs/internal/G-SERIES-EXECUTION-20260917.md +248 -0
- package/docs/internal/G3-DESIGN-20260918.md +82 -0
- package/docs/internal/G3-DISK-FORMAT-GAP-20260919.md +92 -0
- package/docs/internal/GH-DISCUSSION-5732-COMMENT.md +74 -0
- package/docs/internal/GPT-ACCEPTANCE-PROMPT-20260916.md +352 -0
- package/docs/internal/GPT-REVIEW-PROMPT.md +216 -0
- package/docs/internal/GROUP-WEBHOOK-SETUP.md +33 -0
- package/docs/internal/HANDOFF-TO-ZCODE-20260920.md +309 -0
- package/docs/internal/HERMES-DATA-VERIFICATION-20260919.md +120 -0
- package/docs/internal/HERMES-LEGACY-STATUS-20260919.md +74 -0
- package/docs/internal/ISSUE-55-58-VERIFICATION-20260918.md +175 -0
- package/docs/internal/ISSUE10-FIX-EXECUTION-20260919.md +389 -0
- package/docs/internal/ISSUE10-PLAN-20260919.md +254 -0
- package/docs/internal/ISSUE10B-FORENSICS-20260919.md +468 -0
- package/docs/internal/ISSUE9-PURGE-AND-R1-PLAIN-20260919.md +150 -0
- package/docs/internal/ISSUE9-RESIDUAL-FORENSICS-20260919.md +114 -0
- package/docs/internal/KICKOFF-P0.md +254 -0
- package/docs/internal/LESSON-TO-CANDIDATE-STATUS-20260919.md +79 -0
- package/docs/internal/MASTER-PLAN-3.0.md +411 -0
- package/docs/internal/MEMORY-GOVERNANCE-20260917.md +309 -0
- package/docs/internal/MEMORY-MUTATION-AND-INDEX-DESIGN.md +85 -0
- package/docs/internal/MERGE-CONFLICT-SCAN-20260914.md +222 -0
- package/docs/internal/PENDING-FIXES-20260916.md +289 -0
- package/docs/internal/PRE-FRONTEND-CHECKLIST-20260919.md +705 -0
- package/docs/internal/PRE-FRONTEND-CHECKLIST-20260919.md.bak-s10 +649 -0
- package/docs/internal/PROCEDURAL-MEMORY-AND-APPROVAL-DESIGN-20260918.md +225 -0
- package/docs/internal/PROGRESS-20260917.md +93 -0
- package/docs/internal/PROMPT-GAP-AUDIT-20260920.md +128 -0
- package/docs/internal/R1-DEGRADE-AUDIT-20260918.md +163 -0
- package/docs/internal/R1-READABILITY-FORENSICS-20260919.md +127 -0
- package/docs/internal/R2-EVIDENCE-DEEP-AUDIT-20260918.md +140 -0
- package/docs/internal/R3-DEGRADE-LEDGER-DESIGN-20260918.md +138 -0
- package/docs/internal/R4-RECALL-QUOTA-PLAN-20260918.md +218 -0
- package/docs/internal/RAG-KARPATHY-PROGRAM.md +229 -0
- package/docs/internal/REPORT-P0-NIGHTLY.md +212 -0
- package/docs/internal/REPORT-P5-ACCEPTANCE.md +31 -0
- package/docs/internal/REPORT-WB-GRAPH-NIGHTLY.md +153 -0
- package/docs/internal/RESUME-20260918.md +171 -0
- package/docs/internal/RESUME-20260919.md +104 -0
- package/docs/internal/REVIEW-WB-GRAPH-SELF.md +81 -0
- package/docs/internal/RHINELAB-TO-DEEPSEEK-FEASIBILITY.md +198 -0
- package/docs/internal/ROADMAP-20260917-WEEK.md +439 -0
- package/docs/internal/ROADMAP.md +106 -0
- package/docs/internal/RUN-P0-NIGHTLY.md +227 -0
- package/docs/internal/S10-CONSTRUCTION-HANDOFF-20260917.md +185 -0
- package/docs/internal/S10-GAP-INVENTORY-20260917.md +239 -0
- package/docs/internal/S10-GAPS-PLAIN-20260917.md +125 -0
- package/docs/internal/SEMANTIC-ARCHITECTURE-SPEC.md +360 -0
- package/docs/internal/SESSION-FILE-REPAIR-PROTOCOL.md +90 -0
- package/docs/internal/T6-EXECUTION-20260920.md +130 -0
- package/docs/internal/TELEMETRY-EFFECT-REPORT-DESIGN-20260918.md +146 -0
- package/docs/internal/THESIS-GAP-ANALYSIS-20260918.md +89 -0
- package/docs/internal/THESIS-OUTLINE-20260918.md +147 -0
- package/docs/internal/THREE-LAYER-CONTRACT.md +219 -0
- package/docs/internal/TODO-BACKLOG.md +263 -142
- package/docs/internal/TODO-GRAPH.html +715 -0
- package/docs/internal/TODO-GRAPH.html.bak-20260914-v2 +493 -0
- package/docs/internal/TODO-GRAPH.html.bak-20260915-alsfix +710 -0
- package/docs/internal/TODO-GRAPH.html.bak-20260915-p1 +710 -0
- package/docs/internal/TODO-GRAPH.html.bak-20260915-p6a-rev +703 -0
- package/docs/internal/TODO-GRAPH.html.bak-20260915-wshint +710 -0
- package/docs/internal/TODO-GRAPH.html.bak-20260916-batch +715 -0
- package/docs/internal/UPSTREAM-ISSUE-PR-TRIAGE-20260919.md +297 -0
- package/docs/internal/UPSTREAM-ISSUES-3RD-AUDIT-20260920.md +104 -0
- package/docs/internal/WB-FORMAT-CONVENTION.md +112 -0
- package/docs/internal/WB-GRAPH-DECISIONS-20260914.md +71 -0
- package/docs/internal/reviews/CLAIM-VERIFICATION-20260914.md +56 -0
- package/docs/internal/reviews/PLAN-gpt6astra-round2-20260914.md +787 -0
- package/docs/internal/reviews/REVIEW-gpt6astra-20260914.md +112 -0
- package/docs/internal/reviews/ROUND3-REVIEW-INTEGRATION-20260914.md +230 -0
- package/docs/prompts/M8-3-enable-verify.md +49 -49
- package/docs/screenshots/promo/promo-0-banner-v3.png +0 -0
- package/lib/acceptance.js +71 -0
- package/lib/activation-host.js +153 -18
- package/lib/activation-inbox.js +25 -7
- package/lib/board-mode.js +30 -0
- package/lib/client.js +1758 -90
- package/lib/config-io.js +156 -0
- package/lib/context-bridge.js +5 -2
- package/lib/context-host.js +86 -15
- package/lib/degrade.js +385 -0
- package/lib/dsh-home.js +143 -0
- package/lib/engine-identity.js +149 -0
- package/lib/engine-switch.js +247 -0
- package/lib/episodic-store.js +63 -12
- package/lib/evidence-store.js +10 -3
- package/lib/fact-store.js +22 -3
- package/lib/fs-retry.js +46 -0
- package/lib/index-sync.js +13 -1
- package/lib/index.js +3446 -263
- package/lib/intent-clean-safe.js +258 -0
- package/lib/intent-clean.js +12 -16
- package/lib/l0-extract.js +478 -149
- package/lib/l0-index-sync.js +195 -0
- package/lib/l0-index.js +349 -239
- package/lib/ledger-criteria.js +142 -0
- package/lib/m4-corpus.js +8 -2
- package/lib/m7-index-sync-host.js +73 -5
- package/lib/m7-wire.js +3 -3
- package/lib/memory-anchor.js +56 -1
- package/lib/memory-envelope.js +257 -0
- package/lib/memory-hub.js +138 -13
- package/lib/memory-index.js +4 -2
- package/lib/memory-mutation.js +246 -0
- package/lib/memory-writer.js +204 -24
- package/lib/note-status-apply.js +118 -0
- package/lib/note-status.js +196 -0
- package/lib/procedure-observation.js +48 -0
- package/lib/procedure-store.js +118 -20
- package/lib/python-setup.js +1 -1
- package/lib/python-sidecar-client.js +29 -3
- package/lib/recall-fusion.js +83 -12
- package/lib/rerank-host.js +160 -0
- package/lib/rules-edit.js +159 -0
- package/lib/rules-layer.js +261 -0
- package/lib/semantic-decide.js +41 -8
- package/lib/semantic-js.js +66 -6
- package/lib/shadow-host.js +3 -5
- package/lib/shadow-retrieval.js +3 -3
- package/lib/skill-export-host.js +153 -0
- package/lib/skill-export.js +239 -0
- package/lib/state-commit.js +245 -0
- package/lib/storage-manage.js +6 -0
- package/lib/subagent-gc.js +4 -8
- package/lib/temporal-parse.js +191 -159
- package/lib/tier-layer-inject.js +650 -0
- package/lib/tier0-catalog.js +735 -0
- package/lib/water-window.js +263 -186
- package/lib/wb-contract.js +691 -0
- package/lib/wb-sidecar.js +890 -0
- package/lib/ws-overview-rank.js +2 -2
- package/package.json +1 -1
- package/python/m7_embedding_v1.py +5 -5
- package/python/worker_semantic_v1.py +17 -6
- package/python/worker_v1.py +38 -4
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 运行时信封剥离器 —— **结构判据版**(2026-09-19 R5)。
|
|
3
|
+
*
|
|
4
|
+
* 只在未被引用/未被代码块包裹的行上剥离信封;保护字面示例与代码块。
|
|
5
|
+
*
|
|
6
|
+
* ★ 本次改动的根因(issue #30 / ③ Hermes 遗留 / H-3):
|
|
7
|
+
* 旧实现在 `:17` 用**一条字面量行首白名单** `/^(?:current runtime context\.|current dsh file policy:)/i`
|
|
8
|
+
* 识别信封 ⇒ 只能挡住两个当期已知形态。真机取证(`~/.dsh/memory/hub/procedures.json`,
|
|
9
|
+
* 10 条 procedure 里 7 条 observed、其中 4 条 title 就是运行时信封)实测漏网 4 类:
|
|
10
|
+
* · `Approval prompts are disabled in this session: …`
|
|
11
|
+
* · `{"path":"D:\\…`(工具回包的 JSON 转储)
|
|
12
|
+
* · 中文「当前运行时上下文。」
|
|
13
|
+
* · 自然语言「消息系统提醒由框架…」
|
|
14
|
+
* ⇒ 这正是本文件旧注释自己预警的风险:「注入形态会演进 ⇒ 漏判」。
|
|
15
|
+
*
|
|
16
|
+
* ★ 修法(**形态侦测,不是再添几条文法**):信封的共同**结构性质**有二,不依赖具体措辞——
|
|
17
|
+
* **F1 结构化转储**:以 `{`/`[` 开头且以 `}`/`]` 收尾的行 = 工具回包的 JSON,永不可能是人的输入;
|
|
18
|
+
* **F2 声明头 + 分隔符**:`<head noun>[::.。] <说明>` 形状,且 head noun 落在
|
|
19
|
+
* **harness 自有词汇族**内(runtime/approval/policy/sandbox/session/permission/escalation/…)。
|
|
20
|
+
* 注意判据是「**族**(family)+ 形状」,不是整句前缀 ⇒ 框架换措辞("Approval prompts…" →
|
|
21
|
+
* "Escalation is handled by…")仍能被同一个族覆盖。
|
|
22
|
+
* F2 额外加**位置约束** `leadingOnly`:仅对消息**开头的信封区**生效(一旦出现真人文本即停止),
|
|
23
|
+
* 因为 harness 一律把元数据注入在头部;这条把误伤面压到接近零(正文里写 "Policy: xxx" 不会被删)。
|
|
24
|
+
*
|
|
25
|
+
* 三条形态族之外的未知形态仍会漏 —— 这是**形态侦测的固有边界**,故本模块只保证:
|
|
26
|
+
* ①已知族全覆盖;②族内可扩展(加词族 ≠ 加整句前缀);③漏判只会让**噪音**进入 intent,
|
|
27
|
+
* 不会把真人问题删掉(真人文本一旦出现即关闭 F2 位置约束)。
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
/** 被识别的信封标签名(闭包内使用,声明必须在本文件任何使用者之前)。 */
|
|
31
|
+
const tags = new Set(['memory_system', 'system-reminder', 'long_term_memory'])
|
|
32
|
+
|
|
33
|
+
/** 行首精确信封前缀(向后兼容,任意位置生效)。 */
|
|
34
|
+
const EXACT_ENVELOPE_RE = /^(?:current runtime context\.|current dsh file policy:)/i
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* F2 英文声明头词族。
|
|
38
|
+
*
|
|
39
|
+
* ★ 2026-09-19 真机取证补第二形态:title 会被**截断到 40 字符**,
|
|
40
|
+
* 本机的 `Approval prompts are disabled in this se` 连冒号都被截掉了 ⇒ 只靠「分隔符」判据会漏。
|
|
41
|
+
* 故补 `BE_STATEMENT_RE`(词族开头 + be 动词陈述句),它同样不依赖整句字面量:
|
|
42
|
+
* 框架换措辞("Approval prompts…" → "Escalation prompts are handled…")仍在族内。
|
|
43
|
+
*/
|
|
44
|
+
const HARNESS_HEAD_RE = /^(?:current|approval|approvals|sandbox|policy|policies|runtime|session|permission|permissions|escalation|tools?|files?|memory)\b[^.!?\n]{0,90}[::.。]/i
|
|
45
|
+
|
|
46
|
+
/** F2 第二形态:词族开头 + be 动词系表结构(截断后仍成立)。 */
|
|
47
|
+
const BE_STATEMENT_RE = /^(?:current|approval|approvals|sandbox|policy|policies|runtime|session|permission|permissions|escalation)\b[^.!?\n]{0,60}\b(?:is|are|was|were|has been|have been|will be)\b/i
|
|
48
|
+
|
|
49
|
+
/** F2 中文声明头词族(对应上方英文族)。 */
|
|
50
|
+
const HARNESS_HEAD_ZH_RE = /^(?:当前|批准|沙箱|策略|运行时|会话|权限|升级|工具|文件|记忆)[^。!?\n]{0,50}[::。]/
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* F3 插件自产注入标记(★ 2026-09-19 真机取证新增)。
|
|
54
|
+
*
|
|
55
|
+
* **发现过程**:⑨ 探针逐条检验真机 `procedures.json` 的 11 条 title,
|
|
56
|
+
* 发现**时间戳最新的一条**(2026-09-19)title 是 `[Retrieved memory refe` ——
|
|
57
|
+
* 它正是**本插件自己注入的「记忆召回」块标记**
|
|
58
|
+
* (`activation-inbox.js:58` 的 `TAIL_MARKER_LINE_V1`)。
|
|
59
|
+
*
|
|
60
|
+
* ⇒ **自污染闭环**:插件注入召回块 → 召回块随 userText 进 episode →
|
|
61
|
+
* `crossFeed()` 把它当成技能 title ⇒ 又回到「技能审批队列」。
|
|
62
|
+
* ⇒ 且它**仍在持续产生**(非历史存量),故必须修,不能只清数据。
|
|
63
|
+
*
|
|
64
|
+
* **判据仍是词族 + 行首位置**(不写整句字面量,故标记措辞微调后仍成立):
|
|
65
|
+
* ① `[Retrieved memory ref…` —— 允许被 `slice(0,40)` 截断,**不要求闭合方括号**
|
|
66
|
+
* ② `Verify against the current user request…` —— 召回块尾部校验行
|
|
67
|
+
* ③ `If a reference hints at what you need…` —— 召回块尾部取用提示行
|
|
68
|
+
* ④ `Source: mem_<32hex>` —— 召回条目的来源行(结构化形态,散文不会这样起行)
|
|
69
|
+
*
|
|
70
|
+
* 位置:与 F1/`EXACT_ENVELOPE_RE` 同属**任意位置生效**(召回块可出现在文本中段)。
|
|
71
|
+
* `^` 锚定保证不误伤引用该标记的句子(如「解释一下 [Retrieved memory…」不会以它开头)。
|
|
72
|
+
*/
|
|
73
|
+
const PLUGIN_TAIL_MARKER_RE = /^\[?Retrieved memory ref|^Verify against the current user request|^If a reference hints at what you need|^Source:\s*mem_[0-9a-f]{32}|^Reason:\s*fv2 lane=|^Score:\s*[0-9.]+ \(rank \d+\/\d+\)/i
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* F3-补(★ 2026-09-19 T1-0 真机追加):召回块的**块身份锚**与**弱标记行**。
|
|
77
|
+
*
|
|
78
|
+
* **漏网根因(实测)**:`PLUGIN_TAIL_MARKER_RE` 里的 `^Source:\s*mem_[0-9a-f]{32}` 把
|
|
79
|
+
* 「前缀」与「后缀内容」**绑死** ⇒ 一旦该行被 `slice(0, N)` 截断(`Source: mem_…` → `Source: me`),
|
|
80
|
+
* 判据立即失效;且 F3 **完全没有 `^Reference:` 这一条**,而 `renderItemBlock`
|
|
81
|
+
* (`activation-inbox.js:223`)每块都会输出一行 `Reference: …` ⇒ 该行**必然幸存**并成为
|
|
82
|
+
* `extractIntent`(`episodic-store.js:167`)的输入 ⇒ 变成技能标题。
|
|
83
|
+
* 真机后果:`pipeline` 从 3 条涨回 5 条,新增 `Source: me` 与 `Reference: ## 2026-09-18 - dsh-auto-memo`。
|
|
84
|
+
*
|
|
85
|
+
* **修法(族 + 形状,不再绑死后缀)**:拆成两级,避免为堵漏而误伤真人引用句
|
|
86
|
+
* (`⑨` 套件 [4] 组用字面量锁定了「`Source: mem_xxx 这个格式对不对?` 必须保留」):
|
|
87
|
+
* ① `PLUGIN_BLOCK_ANCHOR_RE` —— **强标记**:散文不可能这样起行,单条即可确立「这是召回块」;
|
|
88
|
+
* ② `PLUGIN_BLOCK_LINE_RE` —— **弱标记**:`Source:` / `Reference:` 行的**后缀内容任意**
|
|
89
|
+
* (可能是被截断的 id、记忆正文、甚至 markdown 标题),故**只在①已确立块身份时**才生效。
|
|
90
|
+
* 这样「整块召回」被完整清空,而**孤立的 `Source:` 句子不受影响**。
|
|
91
|
+
*/
|
|
92
|
+
const PLUGIN_BLOCK_ANCHOR_RE = /^\[?Retrieved memory ref|^Verify against the current user request|^If a reference hints at what you need|^Reason:\s*fv2 lane=|^Score:\s*[0-9.]+ \(rank \d+\/\d+\)|^Source:\s*mem_[0-9a-f]{32}/i
|
|
93
|
+
|
|
94
|
+
/** F3 弱标记:仅当同一段文本已被 `PLUGIN_BLOCK_ANCHOR_RE` 确立为召回块时才参与判定。 */
|
|
95
|
+
const PLUGIN_BLOCK_LINE_RE = /^Source:\s*\S|^Reference:\s*\S/i
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* F3 截断残片:整行只剩「标签 + 单个裸 token」。
|
|
99
|
+
*
|
|
100
|
+
* `Source: me` 正是 `Source: mem_<32hex>` 被截到 10 字符的产物。真人的引用句必带后续文字
|
|
101
|
+
* (如 `Source: mem_xxx 这个格式对不对?` 含空格与整句),故用「**无块上下文也能单独判定**」这条
|
|
102
|
+
* 只需一个约束即可安全覆盖:`\S+` 后**必须直接行尾**(不允许空格续文)。
|
|
103
|
+
*/
|
|
104
|
+
const PLUGIN_TRUNCATED_FRAGMENT_RE = /^Source:\s*\S+\s*$/i
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* F3 `Reference:` + markdown 标题 —— **插件指纹,可单独判定**。
|
|
108
|
+
*
|
|
109
|
+
* `renderItemBlock`(`activation-inbox.js:223`)写的是 `'Reference: ' + refText`,
|
|
110
|
+
* 而 `refText` 来自 L0 记录正文(以 `## <标题>` 起头)⇒ 该行必然是 `Reference: ## …` 形状。
|
|
111
|
+
* 真人几乎不可能写出「`Reference:` 紧跟 `##`」,故这一条不需要块上下文。
|
|
112
|
+
* (实测漏网样本:`Reference: ## 2026-09-18 - dsh-auto-memory 项目铁律:fail-soft/降级`)
|
|
113
|
+
*/
|
|
114
|
+
const PLUGIN_REF_HEADING_RE = /^Reference:\s*#{1,6}\s+\S/i
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* F4 编码损坏行(★ 2026-09-19 真机取证新增)。
|
|
118
|
+
*
|
|
119
|
+
* 真机存在一条 title 为 `\ufffd\ufffd…正确(验证)`(U+FFFD 替换字符堆叠)——
|
|
120
|
+
* 是**编码损坏**(非 UTF-8 字节被强行解码)的产物,属结构性垃圾,不可能是有意义标题。
|
|
121
|
+
* 判据:替换字符 ≥3 个(单/双个可能出现在正常文本中,不作判据)。
|
|
122
|
+
*/
|
|
123
|
+
function looksEncodingCorruptedPre(trimmed) {
|
|
124
|
+
return (trimmed.match(/\ufffd/g) || []).length >= 3
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* F5 行内运行时残留(★ 2026-09-19 T1-3 真机追加)。
|
|
129
|
+
*
|
|
130
|
+
* **发现过程**:新套件 [6] 组跑出一条 FAIL —— 真机 fact[1] 的 object 是
|
|
131
|
+
* `现在是什么情况? Current DSH file policy: danger-full-access. The DS`
|
|
132
|
+
* └─真人话─┘└──────────────── 运行时信封 ────────────────┘
|
|
133
|
+
* 即**真人与信封挤在同一行**。
|
|
134
|
+
*
|
|
135
|
+
* **为什么清洗器处理不了它**:`stripRuntimeIntentPre` 是**按行判断**的 ——
|
|
136
|
+
* 删掉这样的整行会**连带丢掉真人话**(「现在是什么情况?」),所以它必须保留。
|
|
137
|
+
* ⇒ 「清洗后是否变化」这条判据对**行内混合**天然无效。
|
|
138
|
+
*
|
|
139
|
+
* **所以本判据是给「写入侧卫生门」用的**(`hubFlushTick`):
|
|
140
|
+
* 它不负责清洗,只负责回答「这条文本里还有没有运行时痕迹」⇒ 有则 skip。
|
|
141
|
+
* 同样用于 fact 通路:行内混信封的 subject/object 不该进正文。
|
|
142
|
+
*
|
|
143
|
+
* 判据是**标记短语**(任意位置),不要求行首 —— 这正是它区别于 F1/F2 的地方:
|
|
144
|
+
* F1/F2 判「整行是信封」,F5 判「行内夹带信封」。
|
|
145
|
+
*/
|
|
146
|
+
const RUNTIME_RESIDUE_RE = /Current DSH file policy|Current runtime context|Approval prompts are disabled in this session|\[Retrieved memory ref|Verify against the current user request|If a reference hints at what you need|Reason:\s*fv2 lane=|Score:\s*[0-9.]+ \(rank \d+\/\d+\)/i
|
|
147
|
+
|
|
148
|
+
/** F5:行内是否夹带运行时信封痕迹(不做清洗,只做判定)。 */
|
|
149
|
+
export function looksRuntimeResiduePre(text) {
|
|
150
|
+
return RUNTIME_RESIDUE_RE.test(String(text == null ? '' : text))
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** F1 结构化转储:以 { / [ 强开幕(后紧跟上引号或嵌套),可能是 JSON 转储。 */
|
|
154
|
+
function looksLikeStructuredDumpPre(trimmed) {
|
|
155
|
+
// 强开幕:`{"` / `[{` / `["` / `[ 数字` —— 人类散文几乎不会这样开头。
|
|
156
|
+
const strongOpen = /^\{"|^\[\{|^\[\s*"|^\[\s*\d/.test(trimmed)
|
|
157
|
+
if (!strongOpen) return false
|
|
158
|
+
// 已闭合 ⇒ 直接判为转储。
|
|
159
|
+
if (/[\]}]\s*$/.test(trimmed)) return true
|
|
160
|
+
// ★ 未闭合:工具回包常被**截断**(真机 title 就是 `{"path":"D:\\…` 断在半路),
|
|
161
|
+
// 故不能要求收尾符;改为要求「引号键值」特征(`"key":`),散文里不会出现这种配对。
|
|
162
|
+
return /"[^"]{0,60}"\s*:/.test(trimmed)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* 判定单行是否为信封行。
|
|
167
|
+
* @param {string} trimmed - 已 trim 的行。
|
|
168
|
+
* @param {boolean} leadingOnly - true 时只允许 F2(位置约束);false 时 F1/F2 都允许。
|
|
169
|
+
*/
|
|
170
|
+
function isEnvelopeLinePre(trimmed, leadingOnly, blockAnchored) {
|
|
171
|
+
if (!trimmed) return false
|
|
172
|
+
if (EXACT_ENVELOPE_RE.test(trimmed)) return true
|
|
173
|
+
// ★ F3/F4(2026-09-19 ⑨):插件自产标记与编码损坏行 —— **任意位置生效**
|
|
174
|
+
// 理由:召回块可能出现在 episode.intent 的**中段**(前面还有真人文本),
|
|
175
|
+
// 若沿用 F2 的「仅信封区」位置约束会再次漏网(这正是 ⑨ 的原始漏网原因之一)。
|
|
176
|
+
if (PLUGIN_TAIL_MARKER_RE.test(trimmed)) return true
|
|
177
|
+
// ★ F3-补(2026-09-19 T1-0):截断残片(`Source: me`)可**单独**判定 ——
|
|
178
|
+
// 它没有任何上下文、也不含后续文字,不可能出现在真人句子里。
|
|
179
|
+
if (PLUGIN_TRUNCATED_FRAGMENT_RE.test(trimmed)) return true
|
|
180
|
+
// ★ F3-补:`Reference: ## <标题>` 是 `renderItemBlock` 的固定产物,可**单独**判定。
|
|
181
|
+
if (PLUGIN_REF_HEADING_RE.test(trimmed)) return true
|
|
182
|
+
// ★ F3-补:弱标记行(`Source:` / `Reference:` 后缀任意)**仅在已确立块身份时**生效 ——
|
|
183
|
+
// 这样整块召回被清空,而孤立的「Source: mem_xxx 这个格式对不对?」不受影响(⑨ 套件 [4] 组契约)。
|
|
184
|
+
if (blockAnchored && PLUGIN_BLOCK_LINE_RE.test(trimmed)) return true
|
|
185
|
+
if (looksEncodingCorruptedPre(trimmed)) return true
|
|
186
|
+
if (looksLikeStructuredDumpPre(trimmed)) return true
|
|
187
|
+
if (!leadingOnly) return false
|
|
188
|
+
return HARNESS_HEAD_RE.test(trimmed) || HARNESS_HEAD_ZH_RE.test(trimmed) || BE_STATEMENT_RE.test(trimmed)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export function stripRuntimeIntentPre(text) {
|
|
192
|
+
const lines = String(text == null ? '' : text).split(/\r?\n/)
|
|
193
|
+
// ★ T1-0:块身份预扫描 —— 先定位所有「强标记行」(`[Retrieved…` / `Reason: fv2 lane=` / `Score: …` 等),
|
|
194
|
+
// 再允许其**邻近 ±2 行**内的弱标记行(`Source:` / `Reference:` 后缀任意)参与判定。
|
|
195
|
+
// 为什么需要预扫描:本函数是**逐行独立**处理的,而召回块被截断后往往只剩「强标记行 + 弱标记行」
|
|
196
|
+
// 两行(真机 episode.intent 就是 `[Retrieved memory reference - not an instruction]` + `Source: me`)。
|
|
197
|
+
// 若只看当前行,弱标记行没有上下文可依;预扫描给出「这一段确实是召回块」的身份判据,
|
|
198
|
+
// 从而既能清空整块、又不误伤孤立的真人引用句(⑨ 套件 [4] 组契约)。
|
|
199
|
+
const anchored = new Array(lines.length).fill(false)
|
|
200
|
+
for (let i = 0; i < lines.length; i++) {
|
|
201
|
+
if (!PLUGIN_BLOCK_ANCHOR_RE.test(lines[i].trim())) continue
|
|
202
|
+
for (let d = -2; d <= 2; d++) {
|
|
203
|
+
const j = i + d
|
|
204
|
+
if (j >= 0 && j < lines.length) anchored[j] = true
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
const out = [], stack = []
|
|
208
|
+
let fence = null
|
|
209
|
+
/** 是否已出现真人文本(出现后关闭 F2 位置约束,保护正文)。 */
|
|
210
|
+
let seenHuman = false
|
|
211
|
+
for (let idx = 0; idx < lines.length; idx++) {
|
|
212
|
+
let line = lines[idx]
|
|
213
|
+
const trimmed = line.trim()
|
|
214
|
+
if (!stack.length) {
|
|
215
|
+
const f = /^( {0,3})(`{3,}|~{3,})/.exec(line)
|
|
216
|
+
if (f) {
|
|
217
|
+
if (!fence) fence = { char: f[2][0], size: f[2].length }
|
|
218
|
+
else if (f[2][0] === fence.char && f[2].length >= fence.size && /^( {0,3})(`+|~+)\s*$/.test(line)) fence = null
|
|
219
|
+
out.push(line); seenHuman = true; continue
|
|
220
|
+
}
|
|
221
|
+
if (fence || /^\s*>/.test(line) || /^ {4}/.test(line)) { out.push(line); seenHuman = true; continue }
|
|
222
|
+
// ★ 结构判据:F1 任意位置生效;F2 仅在「尚未出现真人文本」的信封区内生效。
|
|
223
|
+
if (isEnvelopeLinePre(trimmed, !seenHuman, anchored[idx])) continue
|
|
224
|
+
}
|
|
225
|
+
// Consume one or more envelopes at the beginning of an unquoted line.
|
|
226
|
+
// Closing tags can end a prefix split across messages; trailing human text is retained.
|
|
227
|
+
for (;;) {
|
|
228
|
+
if (stack.length) {
|
|
229
|
+
const token = /<(\/?)(memory_system|system-reminder|long_term_memory)>/.exec(line)
|
|
230
|
+
if (!token) { line = ''; break }
|
|
231
|
+
line = line.slice(token.index + token[0].length)
|
|
232
|
+
if (!token[1]) stack.push(token[2])
|
|
233
|
+
else if (stack[stack.length - 1] === token[2]) stack.pop()
|
|
234
|
+
continue
|
|
235
|
+
}
|
|
236
|
+
const open = /^\s*<(memory_system|system-reminder|long_term_memory)>/.exec(line)
|
|
237
|
+
if (open && tags.has(open[1])) { stack.push(open[1]); line = line.slice(open[0].length); continue }
|
|
238
|
+
const close = /^\s*<\/(memory_system|system-reminder|long_term_memory)>/.exec(line)
|
|
239
|
+
if (close) { line = line.slice(close[0].length); continue }
|
|
240
|
+
break
|
|
241
|
+
}
|
|
242
|
+
if (line.trim()) { out.push(line); seenHuman = true }
|
|
243
|
+
else if (!stack.length && !trimmed) out.push('')
|
|
244
|
+
}
|
|
245
|
+
return out.join('\n')
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/** 导出判据本身,供套件直接断言(避免只能通过整串行为间接验证)。 */
|
|
249
|
+
export const RUNTIME_ENVELOPE_V1 = Object.freeze({
|
|
250
|
+
EXACT_ENVELOPE_RE,
|
|
251
|
+
HARNESS_HEAD_RE,
|
|
252
|
+
HARNESS_HEAD_ZH_RE,
|
|
253
|
+
PLUGIN_TAIL_MARKER_RE,
|
|
254
|
+
RUNTIME_RESIDUE_RE,
|
|
255
|
+
looksEncodingCorruptedPre,
|
|
256
|
+
looksRuntimeResiduePre,
|
|
257
|
+
isEnvelopeLinePre: (line) => isEnvelopeLinePre(String(line == null ? '' : line).trim(), true),
|
|
258
|
+
})
|
package/lib/intent-clean.js
CHANGED
|
@@ -24,26 +24,22 @@
|
|
|
24
24
|
* 命名空间:_pre 隔离。UTF-8 无 BOM。
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
const SNAPSHOT_BLOCK_RE = /<memory_system>[\s\S]*?<\/memory_system>/g
|
|
29
|
-
/** harness 合成前缀(剥离块后若只剩这段,说明整条都是注入)。 */
|
|
30
|
-
const RUNTIME_CONTEXT_RE = /^current runtime context\./i
|
|
27
|
+
import { stripRuntimeIntentPre } from './intent-clean-safe.js'
|
|
31
28
|
|
|
32
29
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
30
|
+
* 剥离注入内容,返回剩余的真人文本。
|
|
31
|
+
*
|
|
32
|
+
* 2026-09-16(issue #30):改为复用 `stripRuntimeIntentPre` 的**行边界**剥离器。
|
|
33
|
+
* 旧实现用两条正则(整块配对 + `^current runtime context.`)硬套,漏判面很宽:
|
|
34
|
+
* - 只认 `<memory_system>` 一种标签,新标签(如 `<system-reminder>`/`<long_term_memory>`)整条漏过;
|
|
35
|
+
* - 块被拆条时靠"取最后一个闭合标签之后"这一刀切,前真问题后快照的拼法会**丢掉真问题**;
|
|
36
|
+
* - 导语正则只匹配行首,前缀被拼到行中时不生效。
|
|
37
|
+
* 新剥离器按行处理:仅在**未被引用/未被代码块包裹**的普通行上剥离信封标签,
|
|
38
|
+
* 保留行内尾随的真人文(如 `<memory_system>…</memory_system> 我的问题` 只剩"我的问题"),
|
|
39
|
+
* 并保证代码块/引用块里的字面示例不被误删。
|
|
37
40
|
*/
|
|
38
41
|
export function stripInjectedBlockPre(text) {
|
|
39
|
-
|
|
40
|
-
s = s.replace(SNAPSHOT_BLOCK_RE, '')
|
|
41
|
-
const marker = '</memory_system>'
|
|
42
|
-
const idx = s.lastIndexOf(marker)
|
|
43
|
-
if (idx >= 0) s = s.slice(idx + marker.length)
|
|
44
|
-
// harness 的 "Current runtime context. …" 导语是整行噪声,且可能出现在任一行
|
|
45
|
-
// (快照在前真问题在后 / 真问题在前快照在后,两种拼法都要能剥干净)
|
|
46
|
-
return s.split(/\r?\n/).filter((ln) => !RUNTIME_CONTEXT_RE.test(ln.trim())).join('\n')
|
|
42
|
+
return stripRuntimeIntentPre(text)
|
|
47
43
|
}
|
|
48
44
|
|
|
49
45
|
/** 合成注入消息识别:剥离注入内容后什么都不剩 → 整条都是注入。 */
|