dsh-prime-memory 0.11.0 → 0.12.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.
Files changed (47) hide show
  1. package/CHANGELOG.en.md +36 -1
  2. package/CHANGELOG.ja.md +36 -1
  3. package/CHANGELOG.ko.md +36 -1
  4. package/CHANGELOG.md +40 -0
  5. package/README.en.md +28 -0
  6. package/README.ja.md +25 -0
  7. package/README.ko.md +25 -0
  8. package/README.md +22 -0
  9. package/dist/client.js +54 -30
  10. package/dist/config.d.ts +39 -1
  11. package/dist/config.js +16 -0
  12. package/dist/conflict-service.d.ts +38 -0
  13. package/dist/conflict-service.js +65 -0
  14. package/dist/graph/search.d.ts +15 -0
  15. package/dist/graph/search.js +54 -1
  16. package/dist/hooks/recall.js +4 -0
  17. package/dist/index.d.ts +28 -1
  18. package/dist/index.js +12 -3
  19. package/dist/pipeline/l1.d.ts +7 -1
  20. package/dist/pipeline/l1.js +165 -20
  21. package/dist/pipeline/runner.js +6 -1
  22. package/dist/prompts/l1-dedup.d.ts +22 -1
  23. package/dist/prompts/l1-dedup.js +61 -4
  24. package/dist/stats.d.ts +12 -0
  25. package/dist/stats.js +222 -33
  26. package/dist/store/conflicts.d.ts +62 -0
  27. package/dist/store/conflicts.js +69 -0
  28. package/dist/store/graph-store.d.ts +72 -1
  29. package/dist/store/graph-store.js +165 -1
  30. package/dist/store/l1.d.ts +97 -4
  31. package/dist/store/l1.js +163 -21
  32. package/dist/store/receipts.d.ts +157 -0
  33. package/dist/store/receipts.js +139 -0
  34. package/dist/store/search-utils.d.ts +15 -0
  35. package/dist/store/search-utils.js +20 -0
  36. package/dist/store/session-modes.d.ts +7 -0
  37. package/dist/store/session-modes.js +9 -0
  38. package/dist/store/sqlite.d.ts +116 -8
  39. package/dist/store/sqlite.js +366 -46
  40. package/dist/store/vec-utils.d.ts +16 -0
  41. package/dist/store/vec-utils.js +24 -0
  42. package/dist/tools/index.js +204 -31
  43. package/dist/types.d.ts +48 -0
  44. package/dist/types.js +40 -0
  45. package/dist/workspace.d.ts +46 -0
  46. package/dist/workspace.js +105 -0
  47. package/package.json +9 -3
@@ -8,9 +8,11 @@
8
8
  */
9
9
  import { randomBytes } from 'node:crypto';
10
10
  import { callLLM, parseJsonLogged, resolveLayerTokens } from '../llm.js';
11
+ import { buildReceipts, newRunId, persistReceiptsSafely } from '../store/receipts.js';
12
+ import { buildConflictPair, validateConflictPair } from '../store/conflicts.js';
11
13
  import { formatExtractionPrompt, getExtractMemoriesSystemPrompt } from '../prompts/l1-extraction.js';
12
14
  import { formatBatchConflictPrompt, getConflictDetectionSystemPrompt } from '../prompts/l1-dedup.js';
13
- import { familyForType, normPersistence, resolveRecordFamily } from '../types.js';
15
+ import { familyForType, normPersistence, normScope, resolveRecordFamily, resolveRecordScope } from '../types.js';
14
16
  /** 解析 ISO/epoch 时间证据,非法或非正值一律 undefined——不猜测。 */
15
17
  function parseTimeEvidence(raw) {
16
18
  const t = typeof raw === 'string' ? Date.parse(raw) : typeof raw === 'number' ? raw : Number.NaN;
@@ -45,6 +47,30 @@ function mergeTemporal(self, targets) {
45
47
  persistence: self.persistence ?? targets.find((r) => r.persistence)?.persistence,
46
48
  };
47
49
  }
50
+ /**
51
+ * 构造一条**全新**L1 记录(store 语义)。§C 冻结复用同一构造:
52
+ * "新记忆照常入 L1"必须与既有 store 路径**逐字段一致**,否则冻结会引入
53
+ * 一种只在开启开关时才出现的新记录形状。
54
+ */
55
+ function toStoreRecord(m, now, ts) {
56
+ return {
57
+ id: m.record_id,
58
+ content: m.content,
59
+ type: m.type,
60
+ priority: Number(m.priority) || 60,
61
+ scene_name: m.scene_name,
62
+ timestamps: [Number.isNaN(ts) ? now : ts],
63
+ createdAt: now,
64
+ updatedAt: now,
65
+ version: 0,
66
+ source_message_ids: m.source_message_ids ?? [],
67
+ metadata: m.metadata ?? {},
68
+ family: m.family,
69
+ scope: m.scope,
70
+ workspaceId: m.workspaceId,
71
+ ...temporalOf(m.metadata),
72
+ };
73
+ }
48
74
  function newId(prefix) {
49
75
  return `${prefix}_${Date.now()}_${randomBytes(3).toString('hex')}`;
50
76
  }
@@ -72,15 +98,54 @@ export function chunkByCharBudget(messages, budgetChars) {
72
98
  chunks.push(cur);
73
99
  return chunks;
74
100
  }
75
- export async function runExtraction(ctx, cfg, store, states, pending, background, logger, mode) {
101
+ export async function runExtraction(ctx, cfg, store, states, pending, background, logger, mode,
102
+ /**
103
+ * §E 当前工作区标识(由调用方经 `sessionWorkspaceIdOf` 解析;拿不到传 undefined)。
104
+ * 传 undefined 时行为与改动前**逐字一致**——`cfg.scope='global'` 的既有部署
105
+ * 永远走这条分支,这是零漂移的构造性保证。
106
+ */
107
+ workspaceId) {
76
108
  if (!cfg.extract.enabled)
77
109
  return { stored: 0, skipped: true, sceneName: chainHead(states, mode), newRecords: [] };
78
110
  // 触发阈值(渐进爬坡 + 按会话切片计数)由 runner 判定(trigger.ts);
79
111
  // 此处不再重复 gate——重建轮 force 与 warmup 早期轮次都会传入小于稳态值的切片。
80
112
  // 纯档强制族 = 档位族;auto 档抽取后的记录族按 type 前缀判定
81
113
  const forcedFamily = mode === 'auto' ? undefined : mode;
114
+ // §E 归属模式(归一:非法/缺省值 → global,ADR-0008 条 4)
115
+ const scopeMode = normScope(cfg.scope);
116
+ // 候选池过滤值**只在 workspace 模式生效**——判断收在这一处,调用方无需自己判。
117
+ // 若让它漏出去(比如调用方无条件传),`scope='global'` 的部署会被误过滤而破坏零漂移。
118
+ const wsFilter = scopeMode === 'workspace' ? workspaceId : undefined;
82
119
  // 情境链锚点桶:纯档用本族;auto 用最近活跃的族(chainHead 同源)
83
120
  const chainState = mode === 'auto' ? activeState(states) : states[mode];
121
+ // ── §C 安全阀(task_24):队列上限 + 超时降级 ──
122
+ // 冻结的代价是消耗人的注意力。没有安全阀,队列会无界增长,且"新记忆与旧记忆
123
+ // 长期并列召回"的状态会**永久**留在库里——比它想解决的问题更糟。
124
+ // 语义是**回落自动裁决**(按 LLM 给出的 winner/loser 了结),而**不是**丢掉
125
+ // 待裁决对:被自动了结的对仍写进 conflict_pending,只是 resolved_at 非空、
126
+ // resolution='auto'。痕迹必须留下,否则"机器替人裁决"会以"悄悄发生"的形式回来。
127
+ const freezeEnabled = cfg.conflictFreeze?.enabled === true;
128
+ const maxPending = cfg.conflictFreeze?.maxPending ?? 0;
129
+ const timeoutDays = cfg.conflictFreeze?.timeoutDays ?? 0;
130
+ /** LLM 的 loser,将在新增记录写完后从检索库退场(自动裁决的执行面)。 */
131
+ const autoLosers = new Set();
132
+ if (freezeEnabled && timeoutDays > 0) {
133
+ const cutoff = new Date(Date.now() - timeoutDays * 86_400_000).toISOString();
134
+ try {
135
+ const stale = store.listConflictPending({ createdBefore: cutoff });
136
+ for (const p of stale) {
137
+ if (store.resolveConflictPending(p.pairId, 'auto', new Date().toISOString()) > 0) {
138
+ autoLosers.add(p.loserId);
139
+ }
140
+ }
141
+ if (stale.length > 0) {
142
+ logger.info(`[memory] 矛盾冻结:${stale.length} 对待裁决对超时 ${timeoutDays} 天,已自动了结`);
143
+ }
144
+ }
145
+ catch (err) {
146
+ logger.warn(`[memory] 矛盾冻结:超时扫描失败(忽略): ${err instanceof Error ? err.message : String(err)}`);
147
+ }
148
+ }
84
149
  // ── Step 1: 抽取(输入按 llm.maxInputChars 预算分块,情境链式衔接,不丢消息) ──
85
150
  const backgroundMsgs = background.slice(-cfg.extract.backgroundMessages);
86
151
  // 预留:背景消息(≤10 条 ×4000 字)+ prompt 脚手架
@@ -117,11 +182,15 @@ export async function runExtraction(ctx, cfg, store, states, pending, background
117
182
  for (const m of scene.memories ?? []) {
118
183
  if (!m || typeof m.content !== 'string' || !m.content.trim())
119
184
  continue;
185
+ const family = resolveRecordFamily(forcedFamily, m.family, m.type ?? '');
120
186
  extracted.push({
121
187
  ...m,
122
188
  record_id: newId('mem'),
123
189
  scene_name: scene.scene_name,
124
- family: resolveRecordFamily(forcedFamily, m.family, m.type ?? ''),
190
+ family,
191
+ // §E 归属在**进管线时**一次算定,下游(store / conflict / update / merge 各分支)
192
+ // 一律复用它——四个分支各算一次是漏判的温床。
193
+ ...resolveRecordScope(scopeMode, family, workspaceId),
125
194
  });
126
195
  }
127
196
  }
@@ -135,11 +204,11 @@ export async function runExtraction(ctx, cfg, store, states, pending, background
135
204
  // ── Step 2: 去重(batch 冲突检测;候选只在本族内召回,去重永不跨族) ──
136
205
  const matches = await Promise.all(extracted.map(async (m) => ({
137
206
  newMemory: m,
138
- candidates: await store.searchCandidates(m.content, cfg.extract.candidatePool, m.family),
207
+ candidates: await store.searchCandidates(m.content, cfg.extract.candidatePool, m.family, wsFilter),
139
208
  })));
140
209
  const dedupPrompt = formatBatchConflictPrompt(matches);
141
210
  const dedupRaw = await callLLM(ctx, cfg, {
142
- system: getConflictDetectionSystemPrompt(mode),
211
+ system: getConflictDetectionSystemPrompt(mode, { conflictFreeze: cfg.conflictFreeze.enabled }),
143
212
  user: dedupPrompt,
144
213
  maxTokens: resolveLayerTokens(cfg, 'dedup'),
145
214
  layer: 'l1-dedup',
@@ -161,6 +230,24 @@ export async function runExtraction(ctx, cfg, store, states, pending, background
161
230
  logger.info(`[memory] L1 去重判定:${extracted.length} 条候选记忆召回 ${candidateTotal} 条已有记录,决策 ${Object.entries(actionCount)
162
231
  .map(([k, v]) => `${k}=${v}`)
163
232
  .join(' ')}`);
233
+ // ── §B 决策凭证:在应用决策前留痕(旁路设施,写失败绝不中断蒸馏) ──
234
+ // 覆盖**全部** extracted:包括 skip 与"模型没返回决策"——回溯"这条为什么没进记忆"
235
+ // 与"为什么进了"同等重要,而 skip 恰好是现有代码里唯一完全不留痕的分支
236
+ // (下方应用循环 `if (!decision || action === 'skip') continue` 直接跳过)。
237
+ // matches 与 extracted 同长同序(Promise.all 按数组序),故按下标取候选池。
238
+ // 注:本轮不开配置开关——新增开关要连带改 config schema / contract / 设置页,
239
+ // 属范围蔓延;凭证本身是纯旁路且幂等,先落地,需要时再加 kill-switch。
240
+ // runId 提到块外:§C 冻结对要沿用同一批次 id,使「这一轮判了什么」与
241
+ // 「这一轮冻结了哪一对」在记忆库侧可交叉审计(findings.md §3 / §9)。
242
+ const runId = newRunId();
243
+ {
244
+ const items = extracted.map((m, i) => ({
245
+ recordId: m.record_id,
246
+ candidateIds: (matches[i]?.candidates ?? []).map((c) => c.id),
247
+ action: byRecord.get(m.record_id)?.action,
248
+ }));
249
+ persistReceiptsSafely((rows) => store.recordReceipts(rows), buildReceipts(runId, new Date().toISOString(), items), logger);
250
+ }
164
251
  // ── Step 3: 应用决策(官方语义:新记录追加进事实源,被替换目标只从检索库删除) ──
165
252
  // 只按需取决策涉及的记录(候选 + 目标 id 并集),避免每轮全表扫描
166
253
  const relatedIds = new Set();
@@ -175,6 +262,8 @@ export async function runExtraction(ctx, cfg, store, states, pending, background
175
262
  const byId = new Map(store.getByIds([...relatedIds]).map((r) => [r.id, r]));
176
263
  const deletedIds = new Set();
177
264
  const added = [];
265
+ /** §C 本轮新冻结的冲突对(应用完新增记录后统一落盘)。 */
266
+ const frozen = [];
178
267
  const now = Date.now();
179
268
  for (const m of extracted) {
180
269
  const decision = byRecord.get(m.record_id);
@@ -183,21 +272,43 @@ export async function runExtraction(ctx, cfg, store, states, pending, background
183
272
  const action = decision.action;
184
273
  const ts = m.metadata?.activity_start_time ? Date.parse(String(m.metadata.activity_start_time)) : now;
185
274
  if (action === 'store') {
186
- added.push({
187
- id: m.record_id,
188
- content: m.content,
189
- type: m.type,
190
- priority: Number(m.priority) || 60,
191
- scene_name: m.scene_name,
192
- timestamps: [Number.isNaN(ts) ? now : ts],
193
- createdAt: now,
194
- updatedAt: now,
195
- version: 0,
196
- source_message_ids: m.source_message_ids ?? [],
197
- metadata: m.metadata ?? {},
198
- family: m.family,
199
- ...temporalOf(m.metadata),
200
- });
275
+ added.push(toStoreRecord(m, now, ts));
276
+ continue;
277
+ }
278
+ // ── §C 矛盾冻结:不自动裁决 ──
279
+ // 走这里意味着**不覆盖、不合并、不删除**——新记忆按 store 语义照常入 L1,
280
+ // 旧记忆原样留下,两者作为**一对**停放待人工裁决。
281
+ // 开关关闭时 prompt 里根本没有 conflict 动作(零漂移见 task_23),但模型仍可能
282
+ // 凭惯性输出它。此时**回落 store 而非落到下面的 update/merge 分支**:
283
+ // 一个显式声明了"拿不准"的决策,绝不能被静默当成"新记忆更优"去覆盖旧记忆。
284
+ if (action === 'conflict') {
285
+ const pair = freezeEnabled
286
+ ? validateConflictPair(m.record_id, decision.winner, decision.loser, new Set(byId.keys()))
287
+ : null;
288
+ if (pair) {
289
+ added.push(toStoreRecord(m, now, ts));
290
+ const built = buildConflictPair({
291
+ runId,
292
+ winnerId: pair.winnerId,
293
+ loserId: pair.loserId,
294
+ createdAt: new Date(now).toISOString(),
295
+ });
296
+ // 队列上限:达上限即**不再停放**,改为当场按 LLM 的 winner/loser 了结。
297
+ // 判据含 frozen 中本轮已停放的未裁决数,否则同一轮内多条冲突会一起越界。
298
+ const pendingNow = store.countConflictPendingUnresolved() + frozen.filter((p) => p.resolvedAt === '').length;
299
+ if (pendingNow >= maxPending) {
300
+ built.resolvedAt = new Date(now).toISOString();
301
+ built.resolution = 'auto';
302
+ autoLosers.add(pair.loserId);
303
+ logger.warn(`[memory] 矛盾冻结:待裁决队列已满(${pendingNow}/${maxPending}),第 ${m.record_id} 条改为自动了结`);
304
+ }
305
+ frozen.push(built);
306
+ }
307
+ else {
308
+ logger.warn(`[memory] 矛盾冻结:第 ${m.record_id} 条的 conflict 决策无法构成冻结对` +
309
+ `(winner=${String(decision.winner)} loser=${String(decision.loser)}),已回落 store`);
310
+ added.push(toStoreRecord(m, now, ts));
311
+ }
201
312
  continue;
202
313
  }
203
314
  // update / merge:目标记录从检索库删除,合并结果作为新记录追加(版本 +1)
@@ -232,6 +343,40 @@ export async function runExtraction(ctx, cfg, store, states, pending, background
232
343
  await store.appendNew(added);
233
344
  if (deletedIds.size > 0)
234
345
  await store.deleteBatch([...deletedIds]);
346
+ // §C 自动裁决的执行面:LLM 的 loser 从检索库退场(winner 存活)。
347
+ // 排在 appendNew 之后——若 loser 恰是**本轮新记忆**(LLM 判定新记忆更差),
348
+ // 也必须先让它进库再退场,以保证"本轮新增"与"本轮删除"的账面一致。
349
+ if (autoLosers.size > 0)
350
+ await store.deleteBatch([...autoLosers]);
351
+ // ── §C 冻结对落盘(排在 appendNew 之后) ──
352
+ // 顺序有讲究:先让新记忆真正进 L1,再登记"它和谁构成待裁决对"。反过来的话,
353
+ // 落盘失败会留下一条指向**不存在记录**的裁决请求,人工打开队列只会看到悬空 id。
354
+ // 写失败与 §B 凭证同策略:记 warn、不中断蒸馏——冻结是旁路设施,
355
+ // 让它有权打断一轮蒸馏是本末倒置。
356
+ if (frozen.length > 0) {
357
+ try {
358
+ store.recordConflictPending(frozen);
359
+ }
360
+ catch (err) {
361
+ logger.warn(`[memory] 矛盾冻结:${frozen.length} 对落盘失败(忽略): ${err instanceof Error ? err.message : String(err)}`);
362
+ }
363
+ // 图谱侧:`disputed` 是"照常召回、但状态可见"的中间态(graph/search.ts 仍在候选内)。
364
+ // **重算**而非增量标记:队列里现在还剩哪些未裁决对,就是此刻的争议集;
365
+ // 本轮之前已被裁决的节点因此会**自动复原 active**(派生字段由当前事实重算)。
366
+ // 图谱是可选派生投影,未启用时 syncGraphDisputed 内部即 no-op。
367
+ try {
368
+ const ids = new Set();
369
+ for (const p of store.listConflictPending()) {
370
+ ids.add(p.winnerId);
371
+ ids.add(p.loserId);
372
+ }
373
+ store.syncGraphDisputed([...ids]);
374
+ }
375
+ catch (err) {
376
+ logger.warn(`[memory] 矛盾冻结:图谱 disputed 同步失败(忽略): ${err instanceof Error ? err.message : String(err)}`);
377
+ }
378
+ logger.info(`[memory] 矛盾冻结:本轮停放 ${frozen.length} 对待人工裁决(run_id=${runId})`);
379
+ }
235
380
  // 状态按记录族分桶推进(阈值计数各自独立)
236
381
  const addedByFamily = { chat: 0, work: 0 };
237
382
  for (const r of added)
@@ -2,6 +2,7 @@ import { resolveDataDir } from '../config.js';
2
2
  import { GRAPH_PRIORITY_NEW } from '../graph/types.js';
3
3
  import { emptyPending, freshWarmup, groupPendingBySession, loadPending, PENDING_MODES, pendingPathFor, savePending, } from '../store/pending.js';
4
4
  import { errDetail } from '../util/filelog.js';
5
+ import { sessionWorkspaceIdOf } from '../workspace.js';
5
6
  import { advanceWarmupThreshold, effectiveExtractThreshold, extractionBackoffMs, idleSessionsToFlush, modeSwitchAction, pickSessionBackground, } from './trigger.js';
6
7
  import { runExtraction } from './l1.js';
7
8
  import { runGraphProjection } from './graph.js';
@@ -599,7 +600,11 @@ export class MemoryRunner {
599
600
  ? pickSessionBackground(await this.stores.l0.recentBySession(sessionId, cfg.extract.backgroundMessages + slice.length), new Set(slice.map((m) => m.id)), cfg.extract.backgroundMessages)
600
601
  : [];
601
602
  const t = Date.now();
602
- const result = await runExtraction(this.ctx, cfg, this.stores.l1, this.states, slice, background, this.logger, mode);
603
+ const result = await runExtraction(this.ctx, cfg, this.stores.l1, this.states, slice, background, this.logger, mode,
604
+ // §E 写入侧工作区:后台蒸馏手上只有 sessionId(没有 exec),经
605
+ // `ctx.get('agents')` 宽容解析——与 §A 的多级父链解析同一招。
606
+ // 拿不到 → undefined → 归属回落 global(pipeline 侧 `resolveRecordScope` 兜底)。
607
+ sessionWorkspaceIdOf(this.ctx, sessionId));
603
608
  if (!result.skipped) {
604
609
  this.pending[mode] = rest;
605
610
  // 重建轮(force)不是有机对话,不推进爬坡
@@ -1,6 +1,9 @@
1
1
  /**
2
2
  * 去重 prompt(批量冲突检测:store/update/merge/skip 决策词表)。
3
3
  *
4
+ * §C 矛盾冻结(task_20):`conflictFreeze` 开启时额外注入 `conflict` 动作
5
+ * (要求 winner/loser 两个不同 id),关闭时三份变体逐字不变。
6
+ *
4
7
  * 净室重写说明:本文件的 prompt 文案按重写规格(Phase 2 决策)逐字沿用——
5
8
  * prompt 内容直接决定蒸馏质量,是已发布行为的一部分,不属于可自由重写文本;
6
9
  * 代码结构与注释随实现重写。
@@ -9,7 +12,25 @@ import type { ExtractedMemory, ExtractMode, MemoryRecord } from '../types.js';
9
12
  export declare const CONFLICT_DETECTION_SYSTEM_PROMPT = "\u4F60\u662F\u8BB0\u5FC6\u51B2\u7A81\u68C0\u6D4B\u5668\u3002\u6279\u91CF\u6BD4\u8F83\u591A\u6761\u3010\u65B0\u8BB0\u5FC6\u3011\u4E0E\u3010\u7EDF\u4E00\u5019\u9009\u8BB0\u5FC6\u6C60\u3011\u4E2D\u7684\u5DF2\u6709\u8BB0\u5FC6\uFF0C\u9010\u6761\u51B3\u5B9A\u5982\u4F55\u5904\u7406\u3002\n\n**\u8F93\u51FA\u8BED\u8A00**\uFF1A`merged_content` \u4F7F\u7528\u4E0E\u5019\u9009\u6C60\u4E2D\u5DF2\u6709\u8BB0\u5FC6\u76F8\u540C\u7684\u8BED\u8A00\uFF1BJSON \u5B57\u6BB5\u540D\u3001\u679A\u4E3E\u503C\u3001record_id\u3001ISO \u65F6\u95F4\u6233\u4FDD\u6301\u82F1\u6587\u3002\n\n## \u6838\u5FC3\u89C4\u5219\n\n- **\u8DE8 type \u5408\u5E76**\uFF1A\u4E0D\u540C type\uFF08persona / episodic / instruction / work_fact / work_task / work_method / work_artifact\uFF09\u7684\u8BB0\u5FC6\u5982\u679C\u8BED\u4E49\u4E0A\u63CF\u8FF0\u540C\u4E00\u4E8B\u5B9E/\u4E8B\u4EF6\uFF0C**\u53EF\u4EE5\u5408\u5E76**\u3002\n- **\u591A\u5BF9\u591A\u5408\u5E76**\uFF1A\u4E00\u6761\u65B0\u8BB0\u5FC6\u53EF\u4EE5\u540C\u65F6\u66FF\u6362/\u5408\u5E76\u5019\u9009\u6C60\u4E2D\u7684**\u591A\u6761**\u5DF2\u6709\u8BB0\u5FC6\uFF08\u901A\u8FC7 target_ids \u6570\u7EC4\u6307\u5B9A\uFF09\u3002\n- \u5408\u5E76\u540E\u4F60\u5FC5\u987B\u5224\u65AD\u65B0\u8BB0\u5FC6\u7684\u6700\u4F73 type\uFF08merged_type\uFF09\u3002\n\n## \u5224\u65AD\u903B\u8F91\n\n1. **\u5206\u8FA8\u8BB0\u5FC6\u6027\u8D28**\uFF1A\n - **\u72B6\u6001\u7C7B**\uFF08persona/instruction\uFF09\uFF1A\u504F\u597D\u3001\u7279\u8D28\u3001\u957F\u671F\u8BBE\u5B9A\u3001\u76F8\u5BF9\u7A33\u5B9A\u7684\u4E8B\u5B9E\u3001\u884C\u4E3A\u89C4\u5219\n - **\u4E8B\u4EF6\u7C7B**\uFF08episodic\uFF09\uFF1A\u4E00\u6B21\u6027\u7ECF\u5386\u3001\u5E26\u65F6\u95F4\u70B9\u7684\u5BA2\u89C2\u8BB0\u5F55\uFF0C\u5EFA\u8BAE\u5408\u5E76\u540C\u4E00\u4EF6\u4E8B\u7684\u524D\u56E0\u540E\u679C\n\n2. **\u5224\u65AD\u662F\u5426\u540C\u4E00\u4E8B\u5B9E/\u4E8B\u4EF6**\uFF1A\u4E3B\u4F53\u76F8\u540C\u3001\u4E3B\u9898\u4E00\u81F4\u3001\u65F6\u95F4\u63A5\u8FD1\u3001scene_name \u76F8\u4F3C\n\n3. **\u9009\u62E9\u52A8\u4F5C**\uFF1A\n - \"store\"\uFF1A\u89C6\u4E3A\u65B0\u4FE1\u606F\uFF0C\u65B0\u589E\u5F53\u524D\u8BB0\u5FC6\u3002\n - \"skip\"\uFF1A\u5DF2\u6709\u8BB0\u5FC6\u66F4\u597D\uFF0C\u65B0\u8BB0\u5FC6\u65E0\u589E\u91CF\u6216\u66F4\u6A21\u7CCA\uFF0C\u5FFD\u7565\u5F53\u524D\u8BB0\u5FC6\u3002\n - \"update\"\uFF1A\u540C\u4E00\u4E8B\u5B9E/\u4E8B\u4EF6\uFF0C\u65B0\u8BB0\u5FC6\u5728\u5185\u5BB9\u6216\u65F6\u95F4\u4E0A\u66F4\u4F18\uFF08\u66F4\u5177\u4F53\u3001\u66F4\u665A\u6216\u7EA0\u9519\uFF09\uFF0C\u4EE5\u65B0\u8BB0\u5FC6\u4E3A\u4E3B\u8986\u76D6\u65E7\u8BB0\u5FC6\uFF0C\u53EF\u4FDD\u7559\u65E7\u8BB0\u5FC6\u4E2D\u4ECD\u6B63\u786E\u7684\u7EC6\u8282\u3002\n - \"merge\"\uFF1A\u540C\u4E00\u4E8B\u5B9E\u6216\u540C\u4E00\u6F14\u5316\u8FC7\u7A0B\uFF0C\u591A\u6761\u8BB0\u5FC6\u4FE1\u606F\u4E92\u8865\u4E14\u4E0D\u77DB\u76FE\uFF0C\u5408\u5E76\u6210\u4E00\u6761\u66F4\u5B8C\u6574\u8BB0\u5FC6\uFF0C\u4FE1\u606F\u5C3D\u91CF\u4E0D\u5197\u4F59\u3002\n\n4. **\u7B56\u7565\u503E\u5411**\uFF1A\n - \u72B6\u6001\u7C7B\uFF1A\u591A\u6761\u63CF\u8FF0\u540C\u4E00\u504F\u597D/\u7279\u8D28 \u2192 \u503E\u5411 merge\uFF1B\u65E0\u589E\u91CF \u2192 skip\uFF1B\u660E\u786E\u66F4\u65B0 \u2192 update\n - \u4E8B\u4EF6\u7C7B\uFF1A\u540C\u4E00\u4E8B\u4EF6\u7684\u524D\u56E0\u540E\u679C\u3001\u4E0D\u540C\u9636\u6BB5 \u2192 \u503E\u5411 merge \u4E3A\u4E00\u6761\u5B8C\u6574\u53D9\u8FF0\uFF1B\u5B8C\u5168\u76F8\u540C \u2192 skip\n - \u8DE8\u7C7B\u578B\u793A\u4F8B\uFF1A\u4E00\u6761 episodic \"\u7528\u6237\u5728 2018 \u5E74\u5F00\u59CB\u505A\u64AD\u5BA2\" + \u4E00\u6761 persona \"\u7528\u6237\u6709\u64AD\u5BA2\u5236\u4F5C\u7ECF\u9A8C\" \u2192 \u53EF merge \u4E3A\u4E00\u6761 persona \u6216 episodic\uFF08\u53D6\u51B3\u4E8E\u4FE1\u606F\u4FA7\u91CD\uFF09\n\n5. **timestamp \u5904\u7406**\uFF1A\n - merge / update \u65F6\uFF0Cmerged_timestamps \u5E94\u5305\u542B**\u6240\u6709\u76F8\u5173\u8BB0\u5FC6\u7684\u65F6\u95F4\u6233\u5E76\u96C6**\uFF08\u53BB\u91CD\u6392\u5E8F\uFF09\n - \u8FD9\u6837\u53EF\u4EE5\u4FDD\u7559\u4E8B\u4EF6\u53D1\u751F\u7684\u5B8C\u6574\u65F6\u95F4\u7EBF\n\n## \u8F93\u51FA\u683C\u5F0F\n\n\u4E25\u683C\u8F93\u51FA JSON \u6570\u7EC4\uFF0C\u6BCF\u4E2A\u5143\u7D20\u5BF9\u5E94\u4E00\u6761\u65B0\u8BB0\u5FC6\u7684\u51B3\u7B56\u3002\u4E0D\u8F93\u51FA\u4EFB\u4F55\u5176\u4ED6\u5185\u5BB9\uFF1A\n\n[\n {\n \"record_id\": \"\u65B0\u8BB0\u5FC6\u7684 record_id\",\n \"action\": \"store|update|skip|merge\",\n \"target_ids\": [\"\u8981\u5220\u9664\u7684\u5019\u9009\u8BB0\u5FC6 record_id 1\", \"record_id 2\"],\n \"merged_content\": \"\u5408\u5E76/\u66F4\u65B0\u540E\u7684\u8BB0\u5FC6\u5185\u5BB9\uFF08merge/update \u65F6\u5FC5\u586B\uFF09\",\n \"merged_type\": \"\u5408\u5E76\u540E\u7684\u6700\u4F73 type\uFF1Apersona|episodic|instruction|work_fact|work_task|work_method|work_artifact\uFF08merge/update \u65F6\u5FC5\u586B\uFF09\",\n \"merged_priority\": 85,\n \"merged_timestamps\": [\"\u5408\u5E76\u540E\u7684\u65F6\u95F4\u6233\u6570\u7EC4\uFF0C\u5305\u542B\u6240\u6709\u65B0\u65E7\u8BB0\u5FC6\u65F6\u95F4\u6233\u7684\u5E76\u96C6\uFF08merge/update \u65F6\u5FC5\u586B\uFF09\"]\n }\n]\n\n\u5B57\u6BB5\u8BF4\u660E\uFF1A\n- target_ids\uFF1A\u8981\u5220\u9664\u66FF\u6362\u7684\u65E7\u8BB0\u5FC6 ID **\u6570\u7EC4**\uFF08\u53EF\u4EE5 1 \u6761\u6216\u591A\u6761\uFF09\u3002store/skip \u65F6\u7701\u7565\u6216\u4E3A\u7A7A\u3002\n- merged_content\uFF1Amerge/update \u65F6\u7684\u6700\u7EC8\u8BB0\u5FC6\u6587\u672C\u3002store/skip \u65F6\u7701\u7565\u3002\n- merged_type\uFF1Amerge/update \u540E\u8BB0\u5FC6\u5E94\u5F52\u5C5E\u7684 type\u3002\u6839\u636E\u5408\u5E76\u540E\u5185\u5BB9\u672C\u8D28\u5224\u65AD\u3002\n- merged_priority\uFF1Amerge/update \u540E\u7684\u65B0\u4F18\u5148\u7EA7\uFF080-100 \u6574\u6570\uFF0Cmerge/update \u65F6\u5FC5\u586B\uFF09\u3002\u5408\u5E76\u540E\u4FE1\u606F\u66F4\u5B8C\u6574\u3001\u66F4\u786E\u5B9A\uFF0C\u901A\u5E38\u5E94**\u914C\u60C5\u63D0\u5347** priority\uFF08\u4F8B\u5982\u4E24\u6761 priority 70 \u7684\u8BB0\u5FC6\u5408\u5E76\u540E\u53EF\u63D0\u5347\u5230 80\uFF09\u3002\u53C2\u8003\u6807\u51C6\uFF1A80-100\uFF08\u6838\u5FC3\u7279\u8D28/\u91CD\u8981\u4E8B\u4EF6\uFF09\uFF0C60-79\uFF08\u4E00\u822C\u504F\u597D/\u666E\u901A\u6D3B\u52A8\uFF09\uFF0C<60\uFF08\u6B21\u8981\u4FE1\u606F\uFF09\u3002\n- merged_timestamps\uFF1A\u5408\u5E76\u540E\u7684\u65F6\u95F4\u6233\u6570\u7EC4\u3002\u6536\u96C6\u65B0\u8BB0\u5FC6 + \u6240\u6709\u88AB\u5408\u5E76\u65E7\u8BB0\u5FC6\u7684\u65F6\u95F4\u6233\uFF0C\u53BB\u91CD\u6392\u5E8F\u3002";
10
13
  export declare const WORK_CONFLICT_DETECTION_SYSTEM_PROMPT = "\u4F60\u662F\u56E2\u961F\u5DE5\u4F5C\u8BB0\u5FC6\u51B2\u7A81\u68C0\u6D4B\u5668\u3002\u6279\u91CF\u6BD4\u8F83\u591A\u6761\u3010\u65B0\u8BB0\u5FC6\u3011\u4E0E\u3010\u7EDF\u4E00\u5019\u9009\u8BB0\u5FC6\u6C60\u3011\u4E2D\u7684\u5DF2\u6709\u8BB0\u5FC6\uFF0C\u9010\u6761\u51B3\u5B9A\u5982\u4F55\u5904\u7406\u3002\n\n**\u8F93\u51FA\u8BED\u8A00**\uFF1A`merged_content` \u4F7F\u7528\u4E0E\u5019\u9009\u6C60\u4E2D\u5DF2\u6709\u8BB0\u5FC6\u76F8\u540C\u7684\u8BED\u8A00\uFF1BJSON \u5B57\u6BB5\u540D\u3001\u679A\u4E3E\u503C\u3001record_id\u3001ISO \u65F6\u95F4\u6233\u4FDD\u6301\u82F1\u6587\u3002\n\n## \u6838\u5FC3\u89C4\u5219\n\n- **\u8DE8 type \u5408\u5E76**\uFF1A\u4E0D\u540C type\uFF08work_fact / work_task / work_method / work_artifact\uFF09\u7684\u8BB0\u5FC6\u5982\u679C\u8BED\u4E49\u4E0A\u63CF\u8FF0\u540C\u4E00\u5DE5\u4F5C\u5BF9\u8C61\u3001\u4EFB\u52A1\u3001\u65B9\u6CD5\u6216\u8D44\u4EA7\uFF0C**\u53EF\u4EE5\u5408\u5E76**\u3002\n- **\u591A\u5BF9\u591A\u5408\u5E76**\uFF1A\u4E00\u6761\u65B0\u8BB0\u5FC6\u53EF\u4EE5\u540C\u65F6\u66FF\u6362/\u5408\u5E76\u5019\u9009\u6C60\u4E2D\u7684**\u591A\u6761**\u5DF2\u6709\u8BB0\u5FC6\uFF08\u901A\u8FC7 target_ids \u6570\u7EC4\u6307\u5B9A\uFF09\u3002\n- \u5408\u5E76\u540E\u4F60\u5FC5\u987B\u5224\u65AD\u65B0\u8BB0\u5FC6\u7684\u6700\u4F73 type\uFF08merged_type\uFF09\u3002\n- \u8BB0\u5FC6\u9ED8\u8BA4\u4F1A\u5728\u9879\u76EE\u56E2\u961F\u5185\u5171\u4EAB\uFF0C\u5408\u5E76\u5185\u5BB9\u5E94\u53EA\u4FDD\u7559\u5DE5\u4F5C\u76F8\u5173\u4FE1\u606F\u3002\n\n## \u5224\u65AD\u903B\u8F91\n\n1. **\u5206\u8FA8\u8BB0\u5FC6\u6027\u8D28**\uFF1A\n - **\u5DE5\u4F5C\u4E8B\u5B9E\u7C7B\uFF08work_fact\uFF09**\uFF1A\u9879\u76EE\u4E8B\u5B9E\u3001\u9700\u6C42\u3001\u51B3\u7B56\u3001\u72B6\u6001\u3001\u98CE\u9669\u3001\u7EA6\u675F\u3001\u5B9E\u9A8C\u7ED3\u679C\u3001\u5BA2\u6237\u53CD\u9988\u3002\n - **\u5DE5\u4F5C\u4EFB\u52A1\u7C7B\uFF08work_task\uFF09**\uFF1A\u5F85\u529E\u3001owner\u3001deadline\u3001\u4E0B\u4E00\u6B65\u8BA1\u5212\u3001\u4EFB\u52A1\u72B6\u6001\u53D8\u5316\u3002\n - **\u5DE5\u4F5C\u65B9\u6CD5\u7C7B\uFF08work_method\uFF09**\uFF1ASOP\u3001\u7981\u5FCC\u3001\u539F\u5219\u3001\u7ECF\u9A8C\u3001\u8BBE\u8BA1\u601D\u8DEF\u3001\u5224\u65AD\u6807\u51C6\u3001Agent \u884C\u4E3A\u89C4\u5219\u3002\n - **\u5DE5\u4F5C\u8D44\u4EA7\u7C7B\uFF08work_artifact\uFF09**\uFF1A\u6587\u6863\u3001PR\u3001Issue\u3001Prompt\u3001\u62A5\u544A\u3001\u4EE3\u7801\u5206\u652F\u3001\u8BBE\u8BA1\u7A3F\u3001\u94FE\u63A5\u7B49\u3002\n\n2. **\u5224\u65AD\u662F\u5426\u540C\u4E00\u5DE5\u4F5C\u5BF9\u8C61/\u6F14\u5316\u8FC7\u7A0B**\uFF1A\n - \u540C\u4E00\u9879\u76EE\u3001\u6A21\u5757\u3001\u9700\u6C42\u3001\u4EFB\u52A1\u3001\u98CE\u9669\u3001\u51B3\u7B56\u3001\u65B9\u6CD5\u3001\u8D44\u4EA7\uFF0C\u4E14 scene_name \u6216\u8BED\u4E49\u9AD8\u5EA6\u76F8\u4F3C\u3002\n - \u540C\u4E00\u4EFB\u52A1\u7684\u4E0D\u540C\u9636\u6BB5\u3001\u540C\u4E00\u65B9\u6CD5\u7684\u8865\u5145\u3001\u540C\u4E00\u8D44\u4EA7\u7684\u7248\u672C\u6216\u7528\u9014\u53D8\u5316\uFF0C\u901A\u5E38\u53EF\u4EE5\u5408\u5E76\u3002\n - \u4EC5\u5C5E\u4E8E\u540C\u4E00\u5927\u9879\u76EE\u4F46\u8BA8\u8BBA\u5BF9\u8C61\u4E0D\u540C\uFF0C\u4E0D\u5E94\u5F3A\u884C\u5408\u5E76\u3002\n\n3. **\u9009\u62E9\u52A8\u4F5C**\uFF1A\n - \"store\"\uFF1A\u89C6\u4E3A\u65B0\u4FE1\u606F\uFF0C\u65B0\u589E\u5F53\u524D\u8BB0\u5FC6\u3002\n - \"skip\"\uFF1A\u5DF2\u6709\u8BB0\u5FC6\u66F4\u597D\uFF0C\u65B0\u8BB0\u5FC6\u65E0\u589E\u91CF\u6216\u66F4\u6A21\u7CCA\uFF0C\u5FFD\u7565\u5F53\u524D\u8BB0\u5FC6\u3002\n - \"update\"\uFF1A\u540C\u4E00\u5DE5\u4F5C\u5BF9\u8C61\uFF0C\u65B0\u8BB0\u5FC6\u66F4\u5177\u4F53\u3001\u66F4\u65B0\u3001\u66F4\u6743\u5A01\u6216\u7EA0\u6B63\u65E7\u4FE1\u606F\uFF0C\u4EE5\u65B0\u8BB0\u5FC6\u4E3A\u4E3B\u8986\u76D6\u65E7\u8BB0\u5FC6\uFF0C\u53EF\u4FDD\u7559\u65E7\u8BB0\u5FC6\u4E2D\u4ECD\u6B63\u786E\u7684\u7EC6\u8282\u3002\n - \"merge\"\uFF1A\u540C\u4E00\u5DE5\u4F5C\u5BF9\u8C61\u6216\u540C\u4E00\u6F14\u5316\u8FC7\u7A0B\uFF0C\u65B0\u65E7\u8BB0\u5FC6\u4E92\u8865\u4E14\u4E0D\u77DB\u76FE\uFF0C\u5408\u5E76\u6210\u4E00\u6761\u66F4\u5B8C\u6574\u8BB0\u5FC6\uFF0C\u4FE1\u606F\u5C3D\u91CF\u4E0D\u5197\u4F59\u3002\n\n4. **\u7B56\u7565\u503E\u5411**\uFF1A\n - work_fact\uFF1A\u540C\u4E00\u4E8B\u5B9E/\u51B3\u7B56/\u72B6\u6001\u7684\u8865\u5145\u6216\u4FEE\u6B63 \u2192 \u503E\u5411 update \u6216 merge\u3002\n - work_task\uFF1A\u540C\u4E00\u4EFB\u52A1\u7684 owner\u3001deadline\u3001\u72B6\u6001\u53D8\u5316 \u2192 \u503E\u5411 update\uFF1B\u8865\u5145\u4F9D\u8D56\u6216\u9A8C\u6536\u6807\u51C6 \u2192 \u503E\u5411 merge\u3002\n - work_method\uFF1A\u540C\u4E00 SOP\u3001\u7981\u5FCC\u3001\u539F\u5219\u3001\u7ECF\u9A8C\u7684\u8865\u5145 \u2192 \u503E\u5411 merge\uFF1B\u66F4\u6E05\u6670\u901A\u7528\u7684\u8868\u8FF0 \u2192 \u503E\u5411 update\u3002\n - work_artifact\uFF1A\u540C\u4E00\u6587\u6863\u3001PR\u3001Prompt\u3001\u62A5\u544A\u7B49\u8D44\u4EA7\u7684\u7528\u9014\u3001\u7248\u672C\u3001\u94FE\u63A5\u8865\u5145 \u2192 \u503E\u5411 merge \u6216 update\u3002\n - \u8DE8\u7C7B\u578B\u793A\u4F8B\uFF1A\u4E00\u6761 work_fact \"\u56E2\u961F\u51B3\u5B9A L1 type \u4FDD\u6301\u5C11\u91CF\u9AD8\u5C42\u5206\u7C7B\" + \u4E00\u6761 work_method \"L1 type \u4E0D\u5B9C\u8FC7\u7EC6\uFF0C\u5426\u5219\u5F71\u54CD L2/L3 \u805A\u5408\" \u2192 \u53EF merge \u4E3A work_method\u3002\n\n5. **timestamp \u5904\u7406**\uFF1A\n - merge / update \u65F6\uFF0Cmerged_timestamps \u5E94\u5305\u542B**\u6240\u6709\u76F8\u5173\u8BB0\u5FC6\u7684\u65F6\u95F4\u6233\u5E76\u96C6**\uFF08\u53BB\u91CD\u6392\u5E8F\uFF09\u3002\n - \u8FD9\u6837\u53EF\u4EE5\u4FDD\u7559\u5DE5\u4F5C\u4E8B\u5B9E\u3001\u4EFB\u52A1\u6216\u65B9\u6CD5\u6F14\u5316\u7684\u5B8C\u6574\u65F6\u95F4\u7EBF\u3002\n\n## \u8F93\u51FA\u683C\u5F0F\n\n\u4E25\u683C\u8F93\u51FA JSON \u6570\u7EC4\uFF0C\u6BCF\u4E2A\u5143\u7D20\u5BF9\u5E94\u4E00\u6761\u65B0\u8BB0\u5FC6\u7684\u51B3\u7B56\u3002\u4E0D\u8F93\u51FA\u4EFB\u4F55\u5176\u4ED6\u5185\u5BB9\uFF1A\n\n[\n {\n \"record_id\": \"\u65B0\u8BB0\u5FC6\u7684 record_id\",\n \"action\": \"store|update|skip|merge\",\n \"target_ids\": [\"\u8981\u5220\u9664\u7684\u5019\u9009\u8BB0\u5FC6 record_id 1\", \"record_id 2\"],\n \"merged_content\": \"\u5408\u5E76/\u66F4\u65B0\u540E\u7684\u8BB0\u5FC6\u5185\u5BB9\uFF08merge/update \u65F6\u5FC5\u586B\uFF09\",\n \"merged_type\": \"\u5408\u5E76\u540E\u7684\u6700\u4F73 type\uFF1Awork_fact|work_task|work_method|work_artifact\uFF08merge/update \u65F6\u5FC5\u586B\uFF09\",\n \"merged_priority\": 85,\n \"merged_timestamps\": [\"\u5408\u5E76\u540E\u7684\u65F6\u95F4\u6233\u6570\u7EC4\uFF0C\u5305\u542B\u6240\u6709\u65B0\u65E7\u8BB0\u5FC6\u65F6\u95F4\u6233\u7684\u5E76\u96C6\uFF08merge/update \u65F6\u5FC5\u586B\uFF09\"]\n }\n]\n\n\u5B57\u6BB5\u8BF4\u660E\uFF1A\n- target_ids\uFF1A\u8981\u5220\u9664\u66FF\u6362\u7684\u65E7\u8BB0\u5FC6 ID **\u6570\u7EC4**\uFF08\u53EF\u4EE5 1 \u6761\u6216\u591A\u6761\uFF09\u3002store/skip \u65F6\u7701\u7565\u6216\u4E3A\u7A7A\u3002\n- merged_content\uFF1Amerge/update \u65F6\u7684\u6700\u7EC8\u8BB0\u5FC6\u6587\u672C\u3002store/skip \u65F6\u7701\u7565\u3002\n- merged_type\uFF1Amerge/update \u540E\u8BB0\u5FC6\u5E94\u5F52\u5C5E\u7684 type\u3002\u6839\u636E\u5408\u5E76\u540E\u5185\u5BB9\u672C\u8D28\u5224\u65AD\u3002\n- merged_priority\uFF1Amerge/update \u540E\u7684\u65B0\u4F18\u5148\u7EA7\uFF080-100 \u6574\u6570\uFF0Cmerge/update \u65F6\u5FC5\u586B\uFF09\u3002\u5408\u5E76\u540E\u4FE1\u606F\u66F4\u5B8C\u6574\u3001\u66F4\u786E\u5B9A\uFF0C\u901A\u5E38\u5E94**\u914C\u60C5\u63D0\u5347** priority\u3002\u53C2\u8003\u6807\u51C6\uFF1A80-100\uFF08\u5173\u952E\u4E8B\u5B9E/\u91CD\u8981\u4EFB\u52A1/\u6838\u5FC3\u65B9\u6CD5/\u91CD\u8981\u8D44\u4EA7\uFF09\uFF0C60-79\uFF08\u4E00\u822C\u5DE5\u4F5C\u4FE1\u606F\uFF09\uFF0C<60\uFF08\u6B21\u8981\u4FE1\u606F\uFF09\u3002\n- merged_timestamps\uFF1A\u5408\u5E76\u540E\u7684\u65F6\u95F4\u6233\u6570\u7EC4\u3002\u6536\u96C6\u65B0\u8BB0\u5FC6 + \u6240\u6709\u88AB\u5408\u5E76\u65E7\u8BB0\u5FC6\u7684\u65F6\u95F4\u6233\uFF0C\u53BB\u91CD\u6392\u5E8F\u3002";
11
14
  export declare const ALL_CONFLICT_DETECTION_SYSTEM_PROMPT = "\u4F60\u662F\u8BB0\u5FC6\u51B2\u7A81\u68C0\u6D4B\u5668\u3002\u6279\u91CF\u6BD4\u8F83\u591A\u6761\u3010\u65B0\u8BB0\u5FC6\u3011\u4E0E\u3010\u7EDF\u4E00\u5019\u9009\u8BB0\u5FC6\u6C60\u3011\u4E2D\u7684\u5DF2\u6709\u8BB0\u5FC6\uFF0C\u9010\u6761\u51B3\u5B9A\u5982\u4F55\u5904\u7406\u3002\u5019\u9009\u6C60\u540C\u65F6\u5305\u542B\u4E2A\u4EBA\u8BB0\u5FC6\uFF08persona/episodic/instruction\uFF09\u4E0E\u56E2\u961F\u5DE5\u4F5C\u8BB0\u5FC6\uFF08work_fact/work_task/work_method/work_artifact\uFF09\uFF0C\u5224\u65AD\u65F6\u6309\u5404\u81EA\u8BED\u4E49\u5904\u7406\u3002\n\n**\u8F93\u51FA\u8BED\u8A00**\uFF1A`merged_content` \u4F7F\u7528\u4E0E\u5019\u9009\u6C60\u4E2D\u5DF2\u6709\u8BB0\u5FC6\u76F8\u540C\u7684\u8BED\u8A00\uFF1BJSON \u5B57\u6BB5\u540D\u3001\u679A\u4E3E\u503C\u3001record_id\u3001ISO \u65F6\u95F4\u6233\u4FDD\u6301\u82F1\u6587\u3002\n\n## \u6838\u5FC3\u89C4\u5219\n\n- **\u8DE8 type \u5408\u5E76**\uFF1A\u4E0D\u540C type\uFF08persona / episodic / instruction / work_fact / work_task / work_method / work_artifact\uFF09\u7684\u8BB0\u5FC6\u5982\u679C\u8BED\u4E49\u4E0A\u63CF\u8FF0\u540C\u4E00\u4E8B\u5B9E/\u4E8B\u4EF6/\u5DE5\u4F5C\u5BF9\u8C61\uFF0C**\u53EF\u4EE5\u5408\u5E76**\u3002\n- **\u591A\u5BF9\u591A\u5408\u5E76**\uFF1A\u4E00\u6761\u65B0\u8BB0\u5FC6\u53EF\u4EE5\u540C\u65F6\u66FF\u6362/\u5408\u5E76\u5019\u9009\u6C60\u4E2D\u7684**\u591A\u6761**\u5DF2\u6709\u8BB0\u5FC6\uFF08\u901A\u8FC7 target_ids \u6570\u7EC4\u6307\u5B9A\uFF09\u3002\n- \u5408\u5E76\u540E\u4F60\u5FC5\u987B\u5224\u65AD\u65B0\u8BB0\u5FC6\u7684\u6700\u4F73 type\uFF08merged_type\uFF09\u3002\n- \u5DE5\u4F5C\u8BB0\u5FC6\u9ED8\u8BA4\u4F1A\u5728\u9879\u76EE\u56E2\u961F\u5185\u5171\u4EAB\uFF0C\u5408\u5E76\u5185\u5BB9\u5E94\u53EA\u4FDD\u7559\u76F8\u5173\u4FE1\u606F\uFF1B\u4E2A\u4EBA\u8BB0\u5FC6\u4E0E\u5DE5\u4F5C\u8BB0\u5FC6\u63CF\u8FF0\u540C\u4E00\u5E95\u5C42\u4E8B\u5B9E\u65F6\u53EF\u4EE5\u5408\u5E76\uFF0C\u6309\u5408\u5E76\u540E\u5185\u5BB9\u672C\u8D28\u9009\u62E9\u5F52\u5C5E type\u3002\n\n## \u5224\u65AD\u903B\u8F91\n\n1. **\u5206\u8FA8\u8BB0\u5FC6\u6027\u8D28**\uFF1A\n - **\u72B6\u6001\u7C7B**\uFF08persona/instruction\uFF09\uFF1A\u504F\u597D\u3001\u7279\u8D28\u3001\u957F\u671F\u8BBE\u5B9A\u3001\u76F8\u5BF9\u7A33\u5B9A\u7684\u4E8B\u5B9E\u3001\u884C\u4E3A\u89C4\u5219\n - **\u4E8B\u4EF6\u7C7B**\uFF08episodic\uFF09\uFF1A\u4E00\u6B21\u6027\u7ECF\u5386\u3001\u5E26\u65F6\u95F4\u70B9\u7684\u5BA2\u89C2\u8BB0\u5F55\uFF0C\u5EFA\u8BAE\u5408\u5E76\u540C\u4E00\u4EF6\u4E8B\u7684\u524D\u56E0\u540E\u679C\n - **\u5DE5\u4F5C\u4E8B\u5B9E\u7C7B**\uFF08work_fact\uFF09\uFF1A\u9879\u76EE\u4E8B\u5B9E\u3001\u9700\u6C42\u3001\u51B3\u7B56\u3001\u72B6\u6001\u3001\u98CE\u9669\u3001\u7EA6\u675F\u3001\u5B9E\u9A8C\u7ED3\u679C\n - **\u5DE5\u4F5C\u4EFB\u52A1\u7C7B**\uFF08work_task\uFF09\uFF1A\u5F85\u529E\u3001owner\u3001deadline\u3001\u4E0B\u4E00\u6B65\u8BA1\u5212\u3001\u4EFB\u52A1\u72B6\u6001\u53D8\u5316\n - **\u5DE5\u4F5C\u65B9\u6CD5\u7C7B**\uFF08work_method\uFF09\uFF1ASOP\u3001\u7981\u5FCC\u3001\u539F\u5219\u3001\u7ECF\u9A8C\u3001\u8BBE\u8BA1\u601D\u8DEF\u3001\u5224\u65AD\u6807\u51C6\u3001Agent \u884C\u4E3A\u89C4\u5219\n - **\u5DE5\u4F5C\u8D44\u4EA7\u7C7B**\uFF08work_artifact\uFF09\uFF1A\u6587\u6863\u3001PR\u3001Issue\u3001Prompt\u3001\u62A5\u544A\u3001\u4EE3\u7801\u5206\u652F\u3001\u8BBE\u8BA1\u7A3F\u3001\u94FE\u63A5\u7B49\n\n2. **\u5224\u65AD\u662F\u5426\u540C\u4E00\u4E8B\u5B9E/\u4E8B\u4EF6/\u5DE5\u4F5C\u5BF9\u8C61**\uFF1A\n - \u4E2A\u4EBA\u8BB0\u5FC6\uFF1A\u4E3B\u4F53\u76F8\u540C\u3001\u4E3B\u9898\u4E00\u81F4\u3001\u65F6\u95F4\u63A5\u8FD1\u3001scene_name \u76F8\u4F3C\n - \u5DE5\u4F5C\u8BB0\u5FC6\uFF1A\u540C\u4E00\u9879\u76EE\u3001\u6A21\u5757\u3001\u9700\u6C42\u3001\u4EFB\u52A1\u3001\u98CE\u9669\u3001\u51B3\u7B56\u3001\u65B9\u6CD5\u3001\u8D44\u4EA7\uFF0C\u6216\u540C\u4E00\u4EFB\u52A1\u7684\u4E0D\u540C\u9636\u6BB5\u3001\u540C\u4E00\u65B9\u6CD5\u7684\u8865\u5145\u3001\u540C\u4E00\u8D44\u4EA7\u7684\u7248\u672C\u53D8\u5316\uFF0C\u901A\u5E38\u53EF\u4EE5\u5408\u5E76\uFF1B\u4EC5\u540C\u5C5E\u4E00\u4E2A\u5927\u9879\u76EE\u4F46\u8BA8\u8BBA\u5BF9\u8C61\u4E0D\u540C\uFF0C\u4E0D\u5E94\u5F3A\u884C\u5408\u5E76\n\n3. **\u9009\u62E9\u52A8\u4F5C**\uFF1A\n - \"store\"\uFF1A\u89C6\u4E3A\u65B0\u4FE1\u606F\uFF0C\u65B0\u589E\u5F53\u524D\u8BB0\u5FC6\u3002\n - \"skip\"\uFF1A\u5DF2\u6709\u8BB0\u5FC6\u66F4\u597D\uFF0C\u65B0\u8BB0\u5FC6\u65E0\u589E\u91CF\u6216\u66F4\u6A21\u7CCA\uFF0C\u5FFD\u7565\u5F53\u524D\u8BB0\u5FC6\u3002\n - \"update\"\uFF1A\u540C\u4E00\u4E8B\u5B9E/\u4E8B\u4EF6/\u5DE5\u4F5C\u5BF9\u8C61\uFF0C\u65B0\u8BB0\u5FC6\u5728\u5185\u5BB9\u6216\u65F6\u95F4\u4E0A\u66F4\u4F18\uFF08\u66F4\u5177\u4F53\u3001\u66F4\u665A\u3001\u66F4\u6743\u5A01\u6216\u7EA0\u9519\uFF09\uFF0C\u4EE5\u65B0\u8BB0\u5FC6\u4E3A\u4E3B\u8986\u76D6\u65E7\u8BB0\u5FC6\uFF0C\u53EF\u4FDD\u7559\u65E7\u8BB0\u5FC6\u4E2D\u4ECD\u6B63\u786E\u7684\u7EC6\u8282\u3002\n - \"merge\"\uFF1A\u540C\u4E00\u4E8B\u5B9E\u3001\u540C\u4E00\u6F14\u5316\u8FC7\u7A0B\u6216\u4FE1\u606F\u4E92\u8865\u4E14\u4E0D\u77DB\u76FE\u7684\u591A\u6761\u8BB0\u5FC6\uFF0C\u5408\u5E76\u6210\u4E00\u6761\u66F4\u5B8C\u6574\u8BB0\u5FC6\uFF0C\u4FE1\u606F\u5C3D\u91CF\u4E0D\u5197\u4F59\u3002\n\n4. **\u7B56\u7565\u503E\u5411**\uFF1A\n - \u72B6\u6001\u7C7B\uFF1A\u591A\u6761\u63CF\u8FF0\u540C\u4E00\u504F\u597D/\u7279\u8D28 \u2192 \u503E\u5411 merge\uFF1B\u65E0\u589E\u91CF \u2192 skip\uFF1B\u660E\u786E\u66F4\u65B0 \u2192 update\n - \u4E8B\u4EF6\u7C7B\uFF1A\u540C\u4E00\u4E8B\u4EF6\u7684\u524D\u56E0\u540E\u679C\u3001\u4E0D\u540C\u9636\u6BB5 \u2192 \u503E\u5411 merge \u4E3A\u4E00\u6761\u5B8C\u6574\u53D9\u8FF0\uFF1B\u5B8C\u5168\u76F8\u540C \u2192 skip\n - work_task\uFF1A\u540C\u4E00\u4EFB\u52A1\u7684 owner\u3001deadline\u3001\u72B6\u6001\u53D8\u5316 \u2192 \u503E\u5411 update\uFF1B\u8865\u5145\u4F9D\u8D56\u6216\u9A8C\u6536\u6807\u51C6 \u2192 \u503E\u5411 merge\n - work_method\uFF1A\u540C\u4E00 SOP\u3001\u7981\u5FCC\u3001\u539F\u5219\u3001\u7ECF\u9A8C\u7684\u8865\u5145 \u2192 \u503E\u5411 merge\uFF1B\u66F4\u6E05\u6670\u901A\u7528\u7684\u8868\u8FF0 \u2192 \u503E\u5411 update\n - work_artifact\uFF1A\u540C\u4E00\u8D44\u4EA7\u7684\u7528\u9014\u3001\u7248\u672C\u3001\u94FE\u63A5\u8865\u5145 \u2192 \u503E\u5411 merge \u6216 update\n - \u8DE8\u7C7B\u578B\u793A\u4F8B\uFF1A\u4E00\u6761 episodic \"\u7528\u6237\u5728 2018 \u5E74\u5F00\u59CB\u505A\u64AD\u5BA2\" + \u4E00\u6761 persona \"\u7528\u6237\u6709\u64AD\u5BA2\u5236\u4F5C\u7ECF\u9A8C\" \u2192 \u53EF merge \u4E3A\u4E00\u6761 persona \u6216 episodic\uFF08\u53D6\u51B3\u4E8E\u4FE1\u606F\u4FA7\u91CD\uFF09\n\n5. **timestamp \u5904\u7406**\uFF1A\n - merge / update \u65F6\uFF0Cmerged_timestamps \u5E94\u5305\u542B**\u6240\u6709\u76F8\u5173\u8BB0\u5FC6\u7684\u65F6\u95F4\u6233\u5E76\u96C6**\uFF08\u53BB\u91CD\u6392\u5E8F\uFF09\n - \u8FD9\u6837\u53EF\u4EE5\u4FDD\u7559\u4E8B\u4EF6\u4E0E\u5DE5\u4F5C\u5BF9\u8C61\u6F14\u5316\u7684\u5B8C\u6574\u65F6\u95F4\u7EBF\n\n## \u8F93\u51FA\u683C\u5F0F\n\n\u4E25\u683C\u8F93\u51FA JSON \u6570\u7EC4\uFF0C\u6BCF\u4E2A\u5143\u7D20\u5BF9\u5E94\u4E00\u6761\u65B0\u8BB0\u5FC6\u7684\u51B3\u7B56\u3002\u4E0D\u8F93\u51FA\u4EFB\u4F55\u5176\u4ED6\u5185\u5BB9\uFF1A\n\n[\n {\n \"record_id\": \"\u65B0\u8BB0\u5FC6\u7684 record_id\",\n \"action\": \"store|update|skip|merge\",\n \"target_ids\": [\"\u8981\u5220\u9664\u7684\u5019\u9009\u8BB0\u5FC6 record_id 1\", \"record_id 2\"],\n \"merged_content\": \"\u5408\u5E76/\u66F4\u65B0\u540E\u7684\u8BB0\u5FC6\u5185\u5BB9\uFF08merge/update \u65F6\u5FC5\u586B\uFF09\",\n \"merged_type\": \"\u5408\u5E76\u540E\u7684\u6700\u4F73 type\uFF1Apersona|episodic|instruction|work_fact|work_task|work_method|work_artifact\uFF08merge/update \u65F6\u5FC5\u586B\uFF09\",\n \"merged_priority\": 85,\n \"merged_timestamps\": [\"\u5408\u5E76\u540E\u7684\u65F6\u95F4\u6233\u6570\u7EC4\uFF0C\u5305\u542B\u6240\u6709\u65B0\u65E7\u8BB0\u5FC6\u65F6\u95F4\u6233\u7684\u5E76\u96C6\uFF08merge/update \u65F6\u5FC5\u586B\uFF09\"]\n }\n]\n\n\u5B57\u6BB5\u8BF4\u660E\uFF1A\n- target_ids\uFF1A\u8981\u5220\u9664\u66FF\u6362\u7684\u65E7\u8BB0\u5FC6 ID **\u6570\u7EC4**\uFF08\u53EF\u4EE5 1 \u6761\u6216\u591A\u6761\uFF09\u3002store/skip \u65F6\u7701\u7565\u6216\u4E3A\u7A7A\u3002\n- merged_content\uFF1Amerge/update \u65F6\u7684\u6700\u7EC8\u8BB0\u5FC6\u6587\u672C\u3002store/skip \u65F6\u7701\u7565\u3002\n- merged_type\uFF1Amerge/update \u540E\u8BB0\u5FC6\u5E94\u5F52\u5C5E\u7684 type\u3002\u6839\u636E\u5408\u5E76\u540E\u5185\u5BB9\u672C\u8D28\u5224\u65AD\u3002\n- merged_priority\uFF1Amerge/update \u540E\u7684\u65B0\u4F18\u5148\u7EA7\uFF080-100 \u6574\u6570\uFF0Cmerge/update \u65F6\u5FC5\u586B\uFF09\u3002\u5408\u5E76\u540E\u4FE1\u606F\u66F4\u5B8C\u6574\u3001\u66F4\u786E\u5B9A\uFF0C\u901A\u5E38\u5E94**\u914C\u60C5\u63D0\u5347** priority\u3002\u53C2\u8003\u6807\u51C6\uFF1A80-100\uFF08\u6838\u5FC3\u7279\u8D28/\u91CD\u8981\u4E8B\u4EF6/\u5173\u952E\u4E8B\u5B9E/\u91CD\u8981\u4EFB\u52A1/\u6838\u5FC3\u65B9\u6CD5/\u91CD\u8981\u8D44\u4EA7\uFF09\uFF0C60-79\uFF08\u4E00\u822C\u4FE1\u606F\uFF09\uFF0C<60\uFF08\u6B21\u8981\u4FE1\u606F\uFF09\u3002\n- merged_timestamps\uFF1A\u5408\u5E76\u540E\u7684\u65F6\u95F4\u6233\u6570\u7EC4\u3002\u6536\u96C6\u65B0\u8BB0\u5FC6 + \u6240\u6709\u88AB\u5408\u5E76\u65E7\u8BB0\u5FC6\u7684\u65F6\u95F4\u6233\uFF0C\u53BB\u91CD\u6392\u5E8F\u3002";
12
- export declare function getConflictDetectionSystemPrompt(mode: ExtractMode): string;
15
+ /**
16
+ * §C 矛盾冻结追加的决策词表条款(与档位无关,三份变体共用)。
17
+ *
18
+ * 语义承自 mneme(dream layer **不**自动裁决 winner/loser):检测到矛盾后
19
+ * 不是"拦住写入",而是"不自动裁决"——把冲突对停放到待审区。
20
+ */
21
+ export declare const CONFLICT_ACTION_CLAUSE = "## \u77DB\u76FE\u51BB\u7ED3\u52A8\u4F5C\uFF08\"conflict\"\uFF09\n\n\u4E0A\u9762\u56DB\u6761\u52A8\u4F5C\u5728**\u5224\u5B9A\u51B2\u7A81**\u65F6\u90FD\u4E0D\u53EF\u7528\u2014\u2014\"update\" \u4E0E \"merge\" \u90FD\u4F1A\u7531\u4F60\u76F4\u63A5\u6539\u5199\u8BB0\u5FC6\uFF0C**\u6CA1\u6709\"\u505C\u4E0B\u6765\u7B49\u4EBA\u88C1\u51B3\"\u8FD9\u4E2A\u9009\u9879**\u3002\u6545\u65B0\u589E\u7B2C\u4E94\u6761\u52A8\u4F5C\uFF1A\n\n- \"conflict\"\uFF1A\u65B0\u8BB0\u5FC6\u4E0E\u5019\u9009\u6C60\u4E2D\u67D0\u6761\u5DF2\u6709\u8BB0\u5FC6**\u63CF\u8FF0\u540C\u4E00\u4E8B\u5B9E/\u4E8B\u4EF6/\u5DE5\u4F5C\u5BF9\u8C61\uFF0C\u4F46\u5185\u5BB9\u4E92\u76F8\u77DB\u76FE**\uFF0C\u4E14\u4F60**\u65E0\u6CD5\u4F9D\u636E\u73B0\u6709\u4FE1\u606F\u5224\u5B9A\u54EA\u4E00\u65B9\u66F4\u53EF\u4FE1**\u65F6\u4F7F\u7528\u3002**\u4E0D\u8986\u76D6\u3001\u4E0D\u5408\u5E76**\uFF1A\u8BE5\u6761\u65B0\u8BB0\u5FC6\u7167\u5E38\u5199\u5165\uFF0C\u4E0E\u51B2\u7A81\u7684\u5DF2\u6709\u8BB0\u5FC6\u4F5C\u4E3A**\u4E00\u5BF9**\u505C\u653E\u5230\u5F85\u4EBA\u5DE5\u88C1\u51B3\u533A\uFF0C\u53CC\u65B9\u5185\u5BB9\u90FD\u4E0D\u88AB\u6539\u5199\u3002\n\n### conflict \u7684\u8FFD\u52A0\u8F93\u51FA\u5B57\u6BB5\n\n{\n \"record_id\": \"\u672C\u6761\u65B0\u8BB0\u5FC6\u7684 record_id\",\n \"action\": \"conflict\",\n \"winner\": \"\u5176\u4E2D\u4E00\u65B9\u7684 record_id\",\n \"loser\": \"\u53E6\u4E00\u65B9\u7684 record_id\"\n}\n\n- \"winner\" / \"loser\"\uFF1A**\u4E8C\u8005\u5FC5\u987B\u4E0D\u540C**\u3002\u53D6\u503C\u5747\u4E3A record_id\uFF0C\u6765\u81EA\u300C\u672C\u6761\u65B0\u8BB0\u5FC6\u7684 record_id\u300D\u6216\u300C\u5019\u9009\u6C60\u4E2D\u7684 record_id\u300D\u3002\n- \"winner\" \u53EA\u8868\u793A\u8FDB\u5165\u5F85\u88C1\u51B3\u5BF9\u65F6\u7684\u6392\u5E8F\u4F4D\uFF0C**\u4E0D\u4EE3\u8868\u6700\u7EC8\u7ED3\u8BBA**\uFF1B\u6700\u7EC8\u7ED3\u8BBA\u7531\u4EBA\u5DE5\u88C1\u51B3\u5199\u5165\u3002\n- action \u4E3A \"conflict\" \u65F6**\u4E0D\u8981**\u8F93\u51FA merged_content / merged_type / merged_priority / merged_timestamps\u2014\u2014\u5B83\u4EEC\u53EA\u5C5E\u4E8E update / merge\u3002\n\n### \u4EC0\u4E48\u65F6\u5019**\u4E0D**\u7528 conflict\n\n- \u65B0\u8BB0\u5FC6\u66F4\u5177\u4F53\u3001\u66F4\u65B0\u3001\u66F4\u6743\u5A01\uFF0C\u6216\u80FD\u660E\u786E\u7EA0\u6B63\u65E7\u8BB0\u5FC6\u7684\u9519\u8BEF \u2192 \u4ECD\u7528 \"update\"\u3002\n- \u65B0\u65E7\u8BB0\u5FC6\u4FE1\u606F\u4E92\u8865\u4E14**\u4E0D\u77DB\u76FE** \u2192 \u4ECD\u7528 \"merge\"\u3002\n- \u53EA\u662F\u540C\u5C5E\u4E00\u4E2A\u4E3B\u9898\u4F46\u63CF\u8FF0\u5BF9\u8C61\u4E0D\u540C \u2192 \u4ECD\u7528 \"store\"\u3002\n\nconflict \u53EA\u7559\u7ED9\"\u4E24\u8FB9\u90FD\u50CF\u662F\u5BF9\u7684\u3001\u673A\u5668\u5224\u4E0D\u4E86\"\u7684\u60C5\u51B5\u2014\u2014\u5B83\u6D88\u8017\u4EBA\u7684\u6CE8\u610F\u529B\uFF0C\u4E0D\u53EF\u6EE5\u7528\u3002";
22
+ export interface DedupPromptOptions {
23
+ /** §C 矛盾冻结总开关。**默认关**:关闭时 prompt 与改动前逐字一致。 */
24
+ conflictFreeze?: boolean;
25
+ }
26
+ /**
27
+ * 把注入词表后的 prompt 交给调用方。
28
+ *
29
+ * 关闭态直接返回 base(逐字不变);开启态先换掉 action 枚举行、再追加条款。
30
+ * 枚举行未被找到时**不抛错**——条款自身也重述了完整输出契约,退化为
31
+ * "只靠追加段覆盖",属安全降级而非静默错误(回归由 task_20 的枚举行用例守住)。
32
+ */
33
+ export declare function getConflictDetectionSystemPrompt(mode: ExtractMode, opts?: DedupPromptOptions): string;
13
34
  export interface CandidateMatch {
14
35
  newMemory: ExtractedMemory & {
15
36
  record_id: string;
@@ -1,6 +1,9 @@
1
1
  /**
2
2
  * 去重 prompt(批量冲突检测:store/update/merge/skip 决策词表)。
3
3
  *
4
+ * §C 矛盾冻结(task_20):`conflictFreeze` 开启时额外注入 `conflict` 动作
5
+ * (要求 winner/loser 两个不同 id),关闭时三份变体逐字不变。
6
+ *
4
7
  * 净室重写说明:本文件的 prompt 文案按重写规格(Phase 2 决策)逐字沿用——
5
8
  * prompt 内容直接决定蒸馏质量,是已发布行为的一部分,不属于可自由重写文本;
6
9
  * 代码结构与注释随实现重写。
@@ -188,10 +191,64 @@ export const ALL_CONFLICT_DETECTION_SYSTEM_PROMPT = `你是记忆冲突检测器
188
191
  - merged_type:merge/update 后记忆应归属的 type。根据合并后内容本质判断。
189
192
  - merged_priority:merge/update 后的新优先级(0-100 整数,merge/update 时必填)。合并后信息更完整、更确定,通常应**酌情提升** priority。参考标准:80-100(核心特质/重要事件/关键事实/重要任务/核心方法/重要资产),60-79(一般信息),<60(次要信息)。
190
193
  - merged_timestamps:合并后的时间戳数组。收集新记忆 + 所有被合并旧记忆的时间戳,去重排序。`;
191
- export function getConflictDetectionSystemPrompt(mode) {
192
- if (mode === 'auto')
193
- return ALL_CONFLICT_DETECTION_SYSTEM_PROMPT;
194
- return mode === 'work' ? WORK_CONFLICT_DETECTION_SYSTEM_PROMPT : CONFLICT_DETECTION_SYSTEM_PROMPT;
194
+ /**
195
+ * §C 矛盾冻结:注入 `conflict` 动作后,三份变体输出契约里的 action 枚举。
196
+ * 用**字面量替换**而非把三份 base 改成函数——base 是已发布行为的一部分,
197
+ * 关闭态必须逐字不变(见 task_23 的零漂移判据)。
198
+ */
199
+ const ACTION_ENUM_BASE = '"action": "store|update|skip|merge"';
200
+ const ACTION_ENUM_FROZEN = '"action": "store|update|skip|merge|conflict"';
201
+ /**
202
+ * §C 矛盾冻结追加的决策词表条款(与档位无关,三份变体共用)。
203
+ *
204
+ * 语义承自 mneme(dream layer **不**自动裁决 winner/loser):检测到矛盾后
205
+ * 不是"拦住写入",而是"不自动裁决"——把冲突对停放到待审区。
206
+ */
207
+ export const CONFLICT_ACTION_CLAUSE = `## 矛盾冻结动作("conflict")
208
+
209
+ 上面四条动作在**判定冲突**时都不可用——"update" 与 "merge" 都会由你直接改写记忆,**没有"停下来等人裁决"这个选项**。故新增第五条动作:
210
+
211
+ - "conflict":新记忆与候选池中某条已有记忆**描述同一事实/事件/工作对象,但内容互相矛盾**,且你**无法依据现有信息判定哪一方更可信**时使用。**不覆盖、不合并**:该条新记忆照常写入,与冲突的已有记忆作为**一对**停放到待人工裁决区,双方内容都不被改写。
212
+
213
+ ### conflict 的追加输出字段
214
+
215
+ {
216
+ "record_id": "本条新记忆的 record_id",
217
+ "action": "conflict",
218
+ "winner": "其中一方的 record_id",
219
+ "loser": "另一方的 record_id"
220
+ }
221
+
222
+ - "winner" / "loser":**二者必须不同**。取值均为 record_id,来自「本条新记忆的 record_id」或「候选池中的 record_id」。
223
+ - "winner" 只表示进入待裁决对时的排序位,**不代表最终结论**;最终结论由人工裁决写入。
224
+ - action 为 "conflict" 时**不要**输出 merged_content / merged_type / merged_priority / merged_timestamps——它们只属于 update / merge。
225
+
226
+ ### 什么时候**不**用 conflict
227
+
228
+ - 新记忆更具体、更新、更权威,或能明确纠正旧记忆的错误 → 仍用 "update"。
229
+ - 新旧记忆信息互补且**不矛盾** → 仍用 "merge"。
230
+ - 只是同属一个主题但描述对象不同 → 仍用 "store"。
231
+
232
+ conflict 只留给"两边都像是对的、机器判不了"的情况——它消耗人的注意力,不可滥用。`;
233
+ /**
234
+ * 把注入词表后的 prompt 交给调用方。
235
+ *
236
+ * 关闭态直接返回 base(逐字不变);开启态先换掉 action 枚举行、再追加条款。
237
+ * 枚举行未被找到时**不抛错**——条款自身也重述了完整输出契约,退化为
238
+ * "只靠追加段覆盖",属安全降级而非静默错误(回归由 task_20 的枚举行用例守住)。
239
+ */
240
+ export function getConflictDetectionSystemPrompt(mode, opts) {
241
+ const base = mode === 'auto'
242
+ ? ALL_CONFLICT_DETECTION_SYSTEM_PROMPT
243
+ : mode === 'work'
244
+ ? WORK_CONFLICT_DETECTION_SYSTEM_PROMPT
245
+ : CONFLICT_DETECTION_SYSTEM_PROMPT;
246
+ if (!opts?.conflictFreeze)
247
+ return base;
248
+ const withEnum = base.includes(ACTION_ENUM_BASE)
249
+ ? base.replace(ACTION_ENUM_BASE, ACTION_ENUM_FROZEN)
250
+ : base;
251
+ return `${withEnum}\n\n${CONFLICT_ACTION_CLAUSE}`;
195
252
  }
196
253
  /**
197
254
  * 格式化批量冲突检测 prompt(统一候选池)。
package/dist/stats.d.ts CHANGED
@@ -21,6 +21,18 @@ export interface MemoryStatusSource {
21
21
  /** L1 抽取待重试的消息条数。 */
22
22
  pending(): number;
23
23
  }
24
+ /**
25
+ * 端点全集运行时清单(31 个,与 tests/contract-keys.test.ts 的 ENDPOINTS 及
26
+ * contract.ts 类型映射表三方对齐,漂移由键集 diff 测试暴露)。
27
+ * 注意:本清单同时是 HTTP 前缀路由 `/dsh-memory/rpc/<短名>` 的**放行白名单**
28
+ * (见下方 SHORT_ENDPOINTS),漏一条 = 该端点在面板里静默消失(404 被客户端
29
+ * rpc 的 catch 吞掉,无任何报错),故必须与 contract.ts 的 DshMemoryRequestMap
30
+ * 严格逐项一致。
31
+ * 用途:0.1.5 共享通道 /api 的 interceptor 是单槽(多插件会抛 already has an
32
+ * interceptor),精确 Fetch 路由按路径 key 可共存且分发优先于 interceptor——
33
+ * 因此逐端点注册 `POST /api/<endpoint>` 精确路由,彻底绕开槽位竞争。
34
+ */
35
+ export declare const MEMORY_ENDPOINTS: readonly string[];
24
36
  /**
25
37
  * 会话级统计数据源(悬浮卡信息区;index.ts 注入)。
26
38
  * 硬规则:本端点按"打开期间 2~5s 轮询"设计,实现只允许内存注册表读取与