dsh-prime-memory 0.22.2 → 0.24.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/CHANGELOG.en.md +421 -0
- package/CHANGELOG.ja.md +416 -0
- package/CHANGELOG.ko.md +416 -0
- package/CHANGELOG.md +120 -0
- package/dist/client.js +1266 -845
- package/dist/config.d.ts +131 -1341
- package/dist/config.js +89 -4
- package/dist/conflict-service.d.ts +7 -1
- package/dist/conflict-service.js +7 -1
- package/dist/contract.d.ts +211 -0
- package/dist/domain-gate.d.ts +11 -0
- package/dist/domain-gate.js +15 -0
- package/dist/hooks/obsolete-notice.d.ts +26 -0
- package/dist/hooks/obsolete-notice.js +64 -0
- package/dist/hooks/recall.d.ts +39 -0
- package/dist/hooks/recall.js +110 -30
- package/dist/index.d.ts +1 -1127
- package/dist/index.js +52 -2
- package/dist/memory-types.d.ts +69 -0
- package/dist/memory-types.js +165 -0
- package/dist/memport/format.d.ts +6 -1
- package/dist/memport/format.js +42 -2
- package/dist/pipeline/l1.d.ts +44 -2
- package/dist/pipeline/l1.js +163 -9
- package/dist/pipeline/md-sync.d.ts +65 -0
- package/dist/pipeline/md-sync.js +456 -0
- package/dist/pipeline/ruminate.d.ts +46 -1
- package/dist/pipeline/ruminate.js +109 -0
- package/dist/pipeline/runner.d.ts +10 -0
- package/dist/pipeline/runner.js +13 -2
- package/dist/pipeline/workspace-relink.d.ts +60 -0
- package/dist/pipeline/workspace-relink.js +73 -0
- package/dist/projection/recall.d.ts +51 -13
- package/dist/projection/recall.js +47 -12
- package/dist/prompts/examples.d.ts +73 -0
- package/dist/prompts/examples.js +178 -0
- package/dist/prompts/l1-dedup.d.ts +9 -3
- package/dist/prompts/l1-dedup.js +34 -13
- package/dist/prompts/l1-extraction.d.ts +5 -3
- package/dist/prompts/l1-extraction.js +49 -4
- package/dist/settings.d.ts +8 -0
- package/dist/settings.js +16 -1
- package/dist/stats.d.ts +12 -0
- package/dist/stats.js +352 -17
- package/dist/store/embedding-source.d.ts +8 -0
- package/dist/store/embedding-source.js +39 -2
- package/dist/store/file-versions.d.ts +2 -0
- package/dist/store/file-versions.js +2 -0
- package/dist/store/graph-store.d.ts +14 -0
- package/dist/store/graph-store.js +35 -0
- package/dist/store/l1-snapshot.d.ts +26 -1
- package/dist/store/l1-snapshot.js +53 -8
- package/dist/store/l1.d.ts +94 -3
- package/dist/store/l1.js +169 -4
- package/dist/store/memory-md-archive.d.ts +84 -0
- package/dist/store/memory-md-archive.js +155 -0
- package/dist/store/memory-md-disable.d.ts +74 -0
- package/dist/store/memory-md-disable.js +302 -0
- package/dist/store/memory-md-export.d.ts +50 -0
- package/dist/store/memory-md-export.js +227 -0
- package/dist/store/memory-md-ledger.d.ts +94 -0
- package/dist/store/memory-md-ledger.js +243 -0
- package/dist/store/memory-md-orphan.d.ts +27 -0
- package/dist/store/memory-md-orphan.js +153 -0
- package/dist/store/memory-md-parse.d.ts +35 -0
- package/dist/store/memory-md-parse.js +85 -0
- package/dist/store/memory-md-run.d.ts +48 -0
- package/dist/store/memory-md-run.js +151 -0
- package/dist/store/memory-md-skeleton.d.ts +18 -0
- package/dist/store/memory-md-skeleton.js +61 -0
- package/dist/store/memory-md-sync.d.ts +59 -0
- package/dist/store/memory-md-sync.js +152 -0
- package/dist/store/memory-md-types.d.ts +243 -0
- package/dist/store/memory-md-types.js +10 -0
- package/dist/store/memory-md.d.ts +117 -0
- package/dist/store/memory-md.js +230 -0
- package/dist/store/obsolete-notices.d.ts +39 -0
- package/dist/store/obsolete-notices.js +153 -0
- package/dist/store/recall-feedback.d.ts +75 -0
- package/dist/store/recall-feedback.js +213 -0
- package/dist/store/recall-usage.d.ts +11 -0
- package/dist/store/recall-usage.js +29 -0
- package/dist/store/session-recalled.d.ts +38 -3
- package/dist/store/session-recalled.js +156 -9
- package/dist/store/sqlite.d.ts +66 -0
- package/dist/store/sqlite.js +233 -15
- package/dist/store/supersede.d.ts +1 -1
- package/dist/store/supersede.js +1 -1
- package/dist/tools/index.d.ts +4 -0
- package/dist/tools/index.js +26 -7
- package/dist/tools/slots.d.ts +2 -1
- package/dist/tools/slots.js +2 -1
- package/dist/types.d.ts +24 -7
- package/dist/types.js +10 -2
- package/dist/util/maturity.d.ts +20 -3
- package/dist/util/maturity.js +18 -1
- package/dist/util/md-name.d.ts +129 -0
- package/dist/util/md-name.js +366 -0
- package/dist/util/md-normalize.d.ts +23 -0
- package/dist/util/md-normalize.js +131 -0
- package/dist/workspace-route.d.ts +22 -0
- package/dist/workspace-route.js +66 -0
- package/dsh.plugin.json +1 -1
- package/package.json +6 -5
package/dist/index.js
CHANGED
|
@@ -37,12 +37,17 @@ import { SlotStore } from './store/slots.js';
|
|
|
37
37
|
import { registerMemoryTools } from './tools/index.js';
|
|
38
38
|
import { registerSlotTools } from './tools/slots.js';
|
|
39
39
|
import { registerSlotRecall } from './hooks/slot-recall.js';
|
|
40
|
+
import { registerObsoleteNotice } from './hooks/obsolete-notice.js';
|
|
40
41
|
import { RoomRegistryStore } from './store/rooms-registry.js';
|
|
41
42
|
import { MemorySourceStore } from './store/memory-sources.js';
|
|
42
43
|
import { SkillStore } from './store/skill-store.js';
|
|
43
44
|
import { registerSkillRecall } from './hooks/skill-recall.js';
|
|
44
45
|
import { registerSkillTools } from './tools/skills.js';
|
|
45
46
|
import { RecallUsageStore } from './store/recall-usage.js';
|
|
47
|
+
import { RecallFeedbackStore } from './store/recall-feedback.js';
|
|
48
|
+
import { MdLedgerStore } from './store/memory-md-ledger.js';
|
|
49
|
+
import { makeFileSyncHook } from './store/memory-md-sync.js';
|
|
50
|
+
import { ObsoleteNoticeStore } from './store/obsolete-notices.js';
|
|
46
51
|
import { registerSlotsProjection } from './projection/slots.js';
|
|
47
52
|
import { registerRecallProjection } from './projection/recall.js';
|
|
48
53
|
import { errDetail, withFileLog } from './util/filelog.js';
|
|
@@ -170,7 +175,10 @@ export async function apply(ctx, config) {
|
|
|
170
175
|
l0: new L0Store(dataDir, db, embed, logger),
|
|
171
176
|
l1: new L1Store(dataDir, db, embed, config.recall.strategy, logger, config.recall.decayHalfLifeDays,
|
|
172
177
|
// §D 第 3 路:图谱回链。图谱不可用时 searchNodes 自带 no-op,不影响双路。
|
|
173
|
-
(query, limit, family) => db.graphStore.searchNodes(query, limit, family ? [family] : undefined)
|
|
178
|
+
(query, limit, family) => db.graphStore.searchNodes(query, limit, family ? [family] : undefined),
|
|
179
|
+
// 投射开着才给没名字的新记录起名(“关时零动作”这条承诺不改)。
|
|
180
|
+
// 传函数而不是布尔:读的是当前配置对象,不把启动那一刻的值钉进 store。
|
|
181
|
+
() => config.memExport?.enabled === true),
|
|
174
182
|
// L2/L3 分族隔离:各自目录与文件(scenes/chat|work、persona-chat|work.md)
|
|
175
183
|
scenes: {
|
|
176
184
|
chat: new SceneStore(dataDir, 'chat', logger),
|
|
@@ -183,6 +191,11 @@ export async function apply(ctx, config) {
|
|
|
183
191
|
state: new StateStore(StateStore.pathFor(dataDir), logger),
|
|
184
192
|
// 会话“活召回集”(G-live):sessionKey → 本会话已注入未压缩的记录 id;持久化,旧会话重开载回。
|
|
185
193
|
recalled: new SessionRecalledStore(dataDir, logger),
|
|
194
|
+
// 召回相关度反馈与过时播报队列(装配于下方,需 await init)。
|
|
195
|
+
feedback: undefined,
|
|
196
|
+
notices: undefined,
|
|
197
|
+
// md 投射指纹账本(N9;装配于下方,需 await init)。
|
|
198
|
+
mdLedger: undefined,
|
|
186
199
|
// 激活槽位(active slot):独立 slots.json,高频小改不拖累 checkpoint 原子写
|
|
187
200
|
slots: new SlotStore(SlotStore.pathFor(dataDir), logger, {
|
|
188
201
|
maxSlots: config.slots.maxSlots,
|
|
@@ -381,6 +394,40 @@ export async function apply(ctx, config) {
|
|
|
381
394
|
const recallUsage = new RecallUsageStore(dataDir, logger);
|
|
382
395
|
await recallUsage.init();
|
|
383
396
|
stores.usage = recallUsage;
|
|
397
|
+
// 召回相关度反馈(人在召回卡上打 -1..5)与「已声明过时」待播报队列。
|
|
398
|
+
// 两个都是低频用户动作 → 立即落盘;sidecar 缺席/损坏只降级为只读,不阻断任何读路径。
|
|
399
|
+
const recallFeedback = new RecallFeedbackStore(dataDir, logger);
|
|
400
|
+
await recallFeedback.init();
|
|
401
|
+
stores.feedback = recallFeedback;
|
|
402
|
+
const obsoleteNotices = new ObsoleteNoticeStore(dataDir, logger);
|
|
403
|
+
await obsoleteNotices.init();
|
|
404
|
+
stores.notices = obsoleteNotices;
|
|
405
|
+
// md 投射指纹账本(N9):派生态,缺席/损坏只降级为只读,不弄挂任何读路径。
|
|
406
|
+
// 它与 feedback/notices 同属“库外 sidecar”,不进快照哈希投影。
|
|
407
|
+
const mdLedger = new MdLedgerStore(dataDir, logger);
|
|
408
|
+
await mdLedger.init();
|
|
409
|
+
stores.mdLedger = mdLedger;
|
|
410
|
+
// 库→文件投射的跟随钩子:**收口在 `L1Store` 的四个汇流口**(appendNew / retire / restore / rename),
|
|
411
|
+
// 不在这里往调用方分发。不变式本体在 `store/memory-md-sync.ts`。
|
|
412
|
+
// 为什么只能装配层建:工具面/冲突裁决各自看不到 cfg + ledger + dataDir 的完整视野。
|
|
413
|
+
const fileSync = makeFileSyncHook({
|
|
414
|
+
getByIds: (list) => stores.l1.getByIds([...list]),
|
|
415
|
+
// 现读生效配置(volatile 热更后不必重启):与 RPC 分发用同一个 `effectiveCfg` 口径。
|
|
416
|
+
exportCfg: () => {
|
|
417
|
+
const exp = effectiveCfg(config, live).memExport;
|
|
418
|
+
return {
|
|
419
|
+
enabled: exp?.enabled === true,
|
|
420
|
+
root: exp?.root,
|
|
421
|
+
maxRecords: exp?.maxRecords ?? 2000,
|
|
422
|
+
timeBudgetMs: exp?.timeBudgetMs ?? 120_000,
|
|
423
|
+
};
|
|
424
|
+
},
|
|
425
|
+
dataDir,
|
|
426
|
+
ledger: () => stores.mdLedger,
|
|
427
|
+
logger,
|
|
428
|
+
});
|
|
429
|
+
// 晚绑定:`stores.l1` 在 md 账本之前就建好了,这里只把钩子接上去。
|
|
430
|
+
stores.l1.setFileSyncHook(fileSync);
|
|
384
431
|
const recall = registerRecall(ctx, config, stores, logger, live, modes, dataDir, recallUsage);
|
|
385
432
|
runner.setAfterRun(recall.invalidateProfile);
|
|
386
433
|
registerMemoryTools(ctx, config, stores, logger, modes, live, ruminate, storageOk ? roomRegistry : undefined);
|
|
@@ -398,7 +445,10 @@ export async function apply(ctx, config) {
|
|
|
398
445
|
registerSlotsProjection(ctx, stores.slots, stores.l1);
|
|
399
446
|
// memoryRecall 投影:本会话“已注入且未被压缩覆盖”的召回集(会话感知,init 取 header.id),
|
|
400
447
|
// 与常驻槽位是两条轴:那个是手动 pin 的硬注入约定,这个是非常驻的相关性浮现结果。
|
|
401
|
-
|
|
448
|
+
// 带上反馈面:条目要显示人已经打过的那一笔(rating)。
|
|
449
|
+
registerRecallProjection(ctx, stores.recalled, stores.l1, recallFeedback);
|
|
450
|
+
// 人打 -1 声明过时后,下一轮向模型一次性播报“这条已退场、别再依据它作答”。
|
|
451
|
+
registerObsoleteNotice(ctx, config, obsoleteNotices, logger);
|
|
402
452
|
void slotRecall;
|
|
403
453
|
registerMemoryRpc(ctx, config, stores, logger, {
|
|
404
454
|
degraded: () => !storageOk || db.isDegraded(),
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 记忆类型词表的**唯一事实源**(pm-name-distill A 节)。
|
|
3
|
+
*
|
|
4
|
+
* 在此之前,"类型全集"手抄在四处:`MEMORY_TYPE_DIRS`(投射目录)、`ADD_TYPES`(写入白名单)、
|
|
5
|
+
* `TYPE_LABELS`(面板标签)、抽取/去重 prompt 的枚举串。四处各自演化过——宿主记忆分类
|
|
6
|
+
* (29 类)与插件 7 类字面交集为空,`memory_add` 把外部分类**静默改写**成 `episodic`,
|
|
7
|
+
* 而 memport 的警告文案却承诺"按原样透传"。同一件事两套口径,漂移只是时间问题。
|
|
8
|
+
*
|
|
9
|
+
* 词表内容 = **宿主 29 类原名**(与 memport 导入的分类字面一致,不再造 `dev_*`/`exp_*`
|
|
10
|
+
* 那层映射——映射层每多一处就多一处漂移)+ 插件旧 7 类(库里 1166 条正带着它们,
|
|
11
|
+
* 不许一夜之间全变 `unclassified`)+ `unclassified` 兜底目录。
|
|
12
|
+
*
|
|
13
|
+
* 本文件必须**零依赖运行**(不引 node: 模块):client 侧与 server 侧同源消费,
|
|
14
|
+
* prompt 渲染也从这里派生。
|
|
15
|
+
*/
|
|
16
|
+
/** 类型族(与 `types.ts` 的 `MemoryFamily` 同域;这里重述字面量以免运行时循环引用)。 */
|
|
17
|
+
export type TypeFamily = 'chat' | 'work';
|
|
18
|
+
/** 宿主记忆分类的 29 类原名(实测自宿主记忆目录树,条数分布见计划 findings 第一节)。 */
|
|
19
|
+
export declare const HOST_MEMORY_TYPES: readonly string[];
|
|
20
|
+
/** 插件早期 7 类(蒸馏管线现役词表;库里存量正带着,永久保留)。 */
|
|
21
|
+
export declare const LEGACY_MEMORY_TYPES: readonly string[];
|
|
22
|
+
/**
|
|
23
|
+
* 兜底目录名(不是可赋值类型):不在词表的 `type` 原值照旧写进 frontmatter,
|
|
24
|
+
* 只在**目录层**归这里。归进某个 `work_*` 会静默把这批记录的 family 挑到 work 侧
|
|
25
|
+
* (family 决定共享面),所以它自成一桶、族取 chat。
|
|
26
|
+
*/
|
|
27
|
+
export declare const UNCLASSIFIED_DIR = "unclassified";
|
|
28
|
+
/**
|
|
29
|
+
* 非词表 type 进入写路径时的降级目标。旧代码在 `tools/index.ts` 里把 `'episodic'`
|
|
30
|
+
* 当字面量散写;集中到这里,降级行为至少有一个可 grep 的名字。
|
|
31
|
+
*/
|
|
32
|
+
export declare const DOWNGRADE_TARGET = "episodic";
|
|
33
|
+
/** 可赋值类型全集(宿主 29 + 旧 7 = 36;`unclassified` 不在其中——它是目录,不是类型)。 */
|
|
34
|
+
export declare const MEMORY_TYPE_VOCABULARY: ReadonlySet<string>;
|
|
35
|
+
/**
|
|
36
|
+
* 族映射(新旧同放)。旧 `familyForType` 靠 `type.startsWith('work')` 前缀猜族,
|
|
37
|
+
* 新词表里 `project_*`/`development_*`/`*_experience` 都是 work 族却不带 work 前缀——
|
|
38
|
+
* 前缀判定会把它们静默归进 chat,而 family 决定召回/浏览/去重的共享面。
|
|
39
|
+
*/
|
|
40
|
+
export declare const TYPE_FAMILY_MAP: Readonly<Record<string, TypeFamily>>;
|
|
41
|
+
/** 类型 → 面板中文标签(真源;client 侧经 `list-records` 的 `typeCatalog` 下发消费)。 */
|
|
42
|
+
export declare const MEMORY_TYPE_LABELS: Readonly<Record<string, string>>;
|
|
43
|
+
/** 投射目录全集 = 可赋值类型 + 兜底桶(37 个)。`memory-md.ts` 的白名单从这里派生。 */
|
|
44
|
+
export declare function memoryTypeDirs(): ReadonlySet<string>;
|
|
45
|
+
/** 是否为词表内类型(写路径白名单判据;`unclassified` 不算——没人该主动赋它)。 */
|
|
46
|
+
export declare function isKnownType(type: string): boolean;
|
|
47
|
+
/** 族查询:查表;未知值回落旧前缀规则并交给 `onUnknownFamily` 提醒一次。 */
|
|
48
|
+
export declare function familyOf(type: string): TypeFamily;
|
|
49
|
+
/**
|
|
50
|
+
* CSS 类名用的 slug(`work_fact` → `work-fact`)。
|
|
51
|
+
*
|
|
52
|
+
* 面板标签类名以前直接拼 `type` 原值(下划线),而主题 CSS 定义的是连字符类——
|
|
53
|
+
* `dsh-mem-tag-work_fact` 匹配不上 `.dsh-mem-tag-work-fact`,标签无色(F11 既有断裂)。
|
|
54
|
+
* 拼接点统一走这里,判据只有一份。
|
|
55
|
+
*/
|
|
56
|
+
export declare function slugOf(type: string): string;
|
|
57
|
+
/** 面板词表目录(下发给 client 的 `typeCatalog`;含兜底桶,顺序 = 旧 7 → 宿主 29 → 兜底)。 */
|
|
58
|
+
export declare function typeCatalogEntries(): Array<{
|
|
59
|
+
id: string;
|
|
60
|
+
label: string;
|
|
61
|
+
}>;
|
|
62
|
+
/** chat / work 族的可赋值类型(prompt 枚举串从这里渲染,不再手抄)。 */
|
|
63
|
+
export declare function typesOfFamily(family: TypeFamily): string[];
|
|
64
|
+
/** prompt/工具描述用的枚举串(`|` 或 `/` 连接,顺序稳定:旧 7 在前)。 */
|
|
65
|
+
export declare function typeEnumSep(sep: string, family?: TypeFamily): string;
|
|
66
|
+
/** 测试/宿主接线用:替换未知族的提醒出口(传 undefined 恢复 console)。 */
|
|
67
|
+
export declare function setFamilyWarnSink(sink?: (msg: string) => void): void;
|
|
68
|
+
/** 清空"已提醒"集(用例要能反复断言只 warn 一次)。 */
|
|
69
|
+
export declare function resetFamilyWarned(): void;
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 记忆类型词表的**唯一事实源**(pm-name-distill A 节)。
|
|
3
|
+
*
|
|
4
|
+
* 在此之前,"类型全集"手抄在四处:`MEMORY_TYPE_DIRS`(投射目录)、`ADD_TYPES`(写入白名单)、
|
|
5
|
+
* `TYPE_LABELS`(面板标签)、抽取/去重 prompt 的枚举串。四处各自演化过——宿主记忆分类
|
|
6
|
+
* (29 类)与插件 7 类字面交集为空,`memory_add` 把外部分类**静默改写**成 `episodic`,
|
|
7
|
+
* 而 memport 的警告文案却承诺"按原样透传"。同一件事两套口径,漂移只是时间问题。
|
|
8
|
+
*
|
|
9
|
+
* 词表内容 = **宿主 29 类原名**(与 memport 导入的分类字面一致,不再造 `dev_*`/`exp_*`
|
|
10
|
+
* 那层映射——映射层每多一处就多一处漂移)+ 插件旧 7 类(库里 1166 条正带着它们,
|
|
11
|
+
* 不许一夜之间全变 `unclassified`)+ `unclassified` 兜底目录。
|
|
12
|
+
*
|
|
13
|
+
* 本文件必须**零依赖运行**(不引 node: 模块):client 侧与 server 侧同源消费,
|
|
14
|
+
* prompt 渲染也从这里派生。
|
|
15
|
+
*/
|
|
16
|
+
/** 宿主记忆分类的 29 类原名(实测自宿主记忆目录树,条数分布见计划 findings 第一节)。 */
|
|
17
|
+
export const HOST_MEMORY_TYPES = [
|
|
18
|
+
// —— 个人可见(chat 族):用户画像的四类 ——
|
|
19
|
+
'user_info', 'user_hobby', 'user_communication', 'user_behavior',
|
|
20
|
+
// —— 项目轴(work 族)——
|
|
21
|
+
'project_introduction', 'project_tech_stack', 'project_architecture',
|
|
22
|
+
'project_build_configuration', 'project_dependency_configuration', 'project_ide_configuration',
|
|
23
|
+
'project_scm_configuration', 'project_environment_configuration', 'project_rule',
|
|
24
|
+
// —— 开发规范轴(work 族)——
|
|
25
|
+
'development_code_specification', 'development_practice_specification',
|
|
26
|
+
'development_test_specification', 'development_comment_specification',
|
|
27
|
+
// —— 经验轴(work 族)——
|
|
28
|
+
'task_summary_experience', 'task_breakdown_experience', 'task_flow_experience', 'task_experience',
|
|
29
|
+
'tool_experience', 'mcp_experience', 'skill_experience', 'learned_skill_experience',
|
|
30
|
+
'expert_experience', 'important_decision_experience', 'common_pitfalls_experience',
|
|
31
|
+
'history_task_reference_files',
|
|
32
|
+
];
|
|
33
|
+
/** 插件早期 7 类(蒸馏管线现役词表;库里存量正带着,永久保留)。 */
|
|
34
|
+
export const LEGACY_MEMORY_TYPES = [
|
|
35
|
+
'persona', 'episodic', 'instruction', 'work_fact', 'work_task', 'work_method', 'work_artifact',
|
|
36
|
+
];
|
|
37
|
+
/**
|
|
38
|
+
* 兜底目录名(不是可赋值类型):不在词表的 `type` 原值照旧写进 frontmatter,
|
|
39
|
+
* 只在**目录层**归这里。归进某个 `work_*` 会静默把这批记录的 family 挑到 work 侧
|
|
40
|
+
* (family 决定共享面),所以它自成一桶、族取 chat。
|
|
41
|
+
*/
|
|
42
|
+
export const UNCLASSIFIED_DIR = 'unclassified';
|
|
43
|
+
/**
|
|
44
|
+
* 非词表 type 进入写路径时的降级目标。旧代码在 `tools/index.ts` 里把 `'episodic'`
|
|
45
|
+
* 当字面量散写;集中到这里,降级行为至少有一个可 grep 的名字。
|
|
46
|
+
*/
|
|
47
|
+
export const DOWNGRADE_TARGET = 'episodic';
|
|
48
|
+
/** 可赋值类型全集(宿主 29 + 旧 7 = 36;`unclassified` 不在其中——它是目录,不是类型)。 */
|
|
49
|
+
export const MEMORY_TYPE_VOCABULARY = new Set([
|
|
50
|
+
...LEGACY_MEMORY_TYPES, ...HOST_MEMORY_TYPES,
|
|
51
|
+
]);
|
|
52
|
+
/**
|
|
53
|
+
* 族映射(新旧同放)。旧 `familyForType` 靠 `type.startsWith('work')` 前缀猜族,
|
|
54
|
+
* 新词表里 `project_*`/`development_*`/`*_experience` 都是 work 族却不带 work 前缀——
|
|
55
|
+
* 前缀判定会把它们静默归进 chat,而 family 决定召回/浏览/去重的共享面。
|
|
56
|
+
*/
|
|
57
|
+
export const TYPE_FAMILY_MAP = Object.freeze((() => {
|
|
58
|
+
const map = {};
|
|
59
|
+
for (const t of LEGACY_MEMORY_TYPES)
|
|
60
|
+
map[t] = t.startsWith('work') ? 'work' : 'chat';
|
|
61
|
+
for (const t of HOST_MEMORY_TYPES)
|
|
62
|
+
map[t] = t.startsWith('user_') ? 'chat' : 'work';
|
|
63
|
+
map[UNCLASSIFIED_DIR] = 'chat';
|
|
64
|
+
return map;
|
|
65
|
+
})());
|
|
66
|
+
/** 类型 → 面板中文标签(真源;client 侧经 `list-records` 的 `typeCatalog` 下发消费)。 */
|
|
67
|
+
export const MEMORY_TYPE_LABELS = Object.freeze({
|
|
68
|
+
persona: '画像偏好',
|
|
69
|
+
episodic: '客观事件',
|
|
70
|
+
instruction: '全局指令',
|
|
71
|
+
work_fact: '工作事实',
|
|
72
|
+
work_task: '工作任务',
|
|
73
|
+
work_method: '工作方法',
|
|
74
|
+
work_artifact: '工作资产',
|
|
75
|
+
user_info: '用户信息',
|
|
76
|
+
user_hobby: '用户爱好',
|
|
77
|
+
user_communication: '沟通风格',
|
|
78
|
+
user_behavior: '行为规范',
|
|
79
|
+
project_introduction: '项目介绍',
|
|
80
|
+
project_tech_stack: '技术栈',
|
|
81
|
+
project_architecture: '架构设计',
|
|
82
|
+
project_build_configuration: '构建配置',
|
|
83
|
+
project_dependency_configuration: '依赖配置',
|
|
84
|
+
project_ide_configuration: 'IDE 配置',
|
|
85
|
+
project_scm_configuration: '版本控制配置',
|
|
86
|
+
project_environment_configuration: '环境配置',
|
|
87
|
+
project_rule: '项目规则',
|
|
88
|
+
development_code_specification: '代码规范',
|
|
89
|
+
development_practice_specification: '实践规范',
|
|
90
|
+
development_test_specification: '测试规范',
|
|
91
|
+
development_comment_specification: '注释规范',
|
|
92
|
+
task_summary_experience: '任务总结',
|
|
93
|
+
task_breakdown_experience: '任务拆解',
|
|
94
|
+
task_flow_experience: '任务流程',
|
|
95
|
+
task_experience: '任务经验',
|
|
96
|
+
tool_experience: '工具经验',
|
|
97
|
+
mcp_experience: 'MCP 经验',
|
|
98
|
+
skill_experience: '技能经验',
|
|
99
|
+
learned_skill_experience: '习得技能',
|
|
100
|
+
expert_experience: '专家经验',
|
|
101
|
+
important_decision_experience: '重要决策',
|
|
102
|
+
common_pitfalls_experience: '常见陷阱',
|
|
103
|
+
history_task_reference_files: '历史参考文件',
|
|
104
|
+
[UNCLASSIFIED_DIR]: '未分类',
|
|
105
|
+
});
|
|
106
|
+
/** 投射目录全集 = 可赋值类型 + 兜底桶(37 个)。`memory-md.ts` 的白名单从这里派生。 */
|
|
107
|
+
export function memoryTypeDirs() {
|
|
108
|
+
return new Set([...MEMORY_TYPE_VOCABULARY, UNCLASSIFIED_DIR]);
|
|
109
|
+
}
|
|
110
|
+
/** 是否为词表内类型(写路径白名单判据;`unclassified` 不算——没人该主动赋它)。 */
|
|
111
|
+
export function isKnownType(type) {
|
|
112
|
+
return MEMORY_TYPE_VOCABULARY.has(type);
|
|
113
|
+
}
|
|
114
|
+
/** 族查询:查表;未知值回落旧前缀规则并交给 `onUnknownFamily` 提醒一次。 */
|
|
115
|
+
export function familyOf(type) {
|
|
116
|
+
const f = TYPE_FAMILY_MAP[type];
|
|
117
|
+
if (f !== undefined)
|
|
118
|
+
return f;
|
|
119
|
+
noteUnknown(type);
|
|
120
|
+
return type.startsWith('work') ? 'work' : 'chat';
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* CSS 类名用的 slug(`work_fact` → `work-fact`)。
|
|
124
|
+
*
|
|
125
|
+
* 面板标签类名以前直接拼 `type` 原值(下划线),而主题 CSS 定义的是连字符类——
|
|
126
|
+
* `dsh-mem-tag-work_fact` 匹配不上 `.dsh-mem-tag-work-fact`,标签无色(F11 既有断裂)。
|
|
127
|
+
* 拼接点统一走这里,判据只有一份。
|
|
128
|
+
*/
|
|
129
|
+
export function slugOf(type) {
|
|
130
|
+
return type.replace(/_/g, '-');
|
|
131
|
+
}
|
|
132
|
+
/** 面板词表目录(下发给 client 的 `typeCatalog`;含兜底桶,顺序 = 旧 7 → 宿主 29 → 兜底)。 */
|
|
133
|
+
export function typeCatalogEntries() {
|
|
134
|
+
return [...LEGACY_MEMORY_TYPES, ...HOST_MEMORY_TYPES, UNCLASSIFIED_DIR].map((id) => ({
|
|
135
|
+
id,
|
|
136
|
+
label: MEMORY_TYPE_LABELS[id] ?? id,
|
|
137
|
+
}));
|
|
138
|
+
}
|
|
139
|
+
/** chat / work 族的可赋值类型(prompt 枚举串从这里渲染,不再手抄)。 */
|
|
140
|
+
export function typesOfFamily(family) {
|
|
141
|
+
return [...MEMORY_TYPE_VOCABULARY].filter((t) => TYPE_FAMILY_MAP[t] === family);
|
|
142
|
+
}
|
|
143
|
+
/** prompt/工具描述用的枚举串(`|` 或 `/` 连接,顺序稳定:旧 7 在前)。 */
|
|
144
|
+
export function typeEnumSep(sep, family) {
|
|
145
|
+
const list = family === undefined ? [...LEGACY_MEMORY_TYPES, ...HOST_MEMORY_TYPES] : typesOfFamily(family);
|
|
146
|
+
return list.join(sep);
|
|
147
|
+
}
|
|
148
|
+
// —— 未知类型的"只提醒一次":诊断集封到 64 个就不再记录(宁可漏提醒,不让集合无限吃内存)。
|
|
149
|
+
const warnedUnknownFamilies = new Set();
|
|
150
|
+
let warnSink = (msg) => console.warn(msg);
|
|
151
|
+
/** 测试/宿主接线用:替换未知族的提醒出口(传 undefined 恢复 console)。 */
|
|
152
|
+
export function setFamilyWarnSink(sink) {
|
|
153
|
+
warnSink = sink ?? ((msg) => console.warn(msg));
|
|
154
|
+
}
|
|
155
|
+
/** 清空"已提醒"集(用例要能反复断言只 warn 一次)。 */
|
|
156
|
+
export function resetFamilyWarned() {
|
|
157
|
+
warnedUnknownFamilies.clear();
|
|
158
|
+
}
|
|
159
|
+
function noteUnknown(type) {
|
|
160
|
+
if (warnedUnknownFamilies.has(type))
|
|
161
|
+
return;
|
|
162
|
+
if (warnedUnknownFamilies.size < 64)
|
|
163
|
+
warnedUnknownFamilies.add(type);
|
|
164
|
+
warnSink(`[memory] type '${type}' 不在词表,family 按旧前缀规则回落(请核对来源)`);
|
|
165
|
+
}
|
package/dist/memport/format.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
/** MMF v1.1 默认列序(缺 `#cols=` 时按此解析;v1 包缺 vf/vt/st 列按 -/-/? 补齐)。 */
|
|
2
2
|
export declare const DEFAULT_COLS: readonly ["type", "created", "updated", "vf", "vt", "st", "cf", "rw", "tags", "content"];
|
|
3
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* 类型码 → 运行时 type(与 memport.py TYPE_CODES 一字不差)。
|
|
5
|
+
*
|
|
6
|
+
* 旧码(插件 7 类)不变;pm-name-distill task_1.7 补进宿主 29 类的新码,使外部包
|
|
7
|
+
* 带来的宿主分类不再被写侧抹平——两实现同表是 `memport-ts-consistency` 的前提。
|
|
8
|
+
*/
|
|
4
9
|
export declare const TYPE_CODES: Record<string, string>;
|
|
5
10
|
/** 持续性取值域:p 时点 / s 已结束区间 / o 仍在持续 / t 无时间性 / ? 未判定。 */
|
|
6
11
|
export declare const PERSISTENCE: readonly ["p", "s", "o", "t", "?"];
|
package/dist/memport/format.js
CHANGED
|
@@ -13,7 +13,12 @@
|
|
|
13
13
|
import { createHash } from 'node:crypto';
|
|
14
14
|
/** MMF v1.1 默认列序(缺 `#cols=` 时按此解析;v1 包缺 vf/vt/st 列按 -/-/? 补齐)。 */
|
|
15
15
|
export const DEFAULT_COLS = ['type', 'created', 'updated', 'vf', 'vt', 'st', 'cf', 'rw', 'tags', 'content'];
|
|
16
|
-
/**
|
|
16
|
+
/**
|
|
17
|
+
* 类型码 → 运行时 type(与 memport.py TYPE_CODES 一字不差)。
|
|
18
|
+
*
|
|
19
|
+
* 旧码(插件 7 类)不变;pm-name-distill task_1.7 补进宿主 29 类的新码,使外部包
|
|
20
|
+
* 带来的宿主分类不再被写侧抹平——两实现同表是 `memport-ts-consistency` 的前提。
|
|
21
|
+
*/
|
|
17
22
|
export const TYPE_CODES = {
|
|
18
23
|
pe: 'persona',
|
|
19
24
|
ep: 'episodic',
|
|
@@ -22,6 +27,39 @@ export const TYPE_CODES = {
|
|
|
22
27
|
wt: 'work_task',
|
|
23
28
|
wm: 'work_method',
|
|
24
29
|
wa: 'work_artifact',
|
|
30
|
+
// —— 宿主分类·个人轴 ——
|
|
31
|
+
ui: 'user_info',
|
|
32
|
+
uh: 'user_hobby',
|
|
33
|
+
uc: 'user_communication',
|
|
34
|
+
ub: 'user_behavior',
|
|
35
|
+
// —— 宿主分类·项目轴 ——
|
|
36
|
+
pi: 'project_introduction',
|
|
37
|
+
pt: 'project_tech_stack',
|
|
38
|
+
pg: 'project_architecture',
|
|
39
|
+
pb: 'project_build_configuration',
|
|
40
|
+
pq: 'project_dependency_configuration',
|
|
41
|
+
po: 'project_ide_configuration',
|
|
42
|
+
ps: 'project_scm_configuration',
|
|
43
|
+
pw: 'project_environment_configuration',
|
|
44
|
+
pl: 'project_rule',
|
|
45
|
+
// —— 宿主分类·规范轴 ——
|
|
46
|
+
ds: 'development_code_specification',
|
|
47
|
+
dp: 'development_practice_specification',
|
|
48
|
+
dv: 'development_test_specification',
|
|
49
|
+
dn: 'development_comment_specification',
|
|
50
|
+
// —— 宿主分类·经验轴 ——
|
|
51
|
+
tm: 'task_summary_experience',
|
|
52
|
+
dk: 'task_breakdown_experience',
|
|
53
|
+
df: 'task_flow_experience',
|
|
54
|
+
td: 'task_experience',
|
|
55
|
+
tl: 'tool_experience',
|
|
56
|
+
mp: 'mcp_experience',
|
|
57
|
+
sl: 'skill_experience',
|
|
58
|
+
lk: 'learned_skill_experience',
|
|
59
|
+
ek: 'expert_experience',
|
|
60
|
+
im: 'important_decision_experience',
|
|
61
|
+
cp: 'common_pitfalls_experience',
|
|
62
|
+
hf: 'history_task_reference_files',
|
|
25
63
|
};
|
|
26
64
|
const TYPE_FULL = Object.fromEntries(Object.entries(TYPE_CODES).map(([k, v]) => [v, k]));
|
|
27
65
|
/** 持续性取值域:p 时点 / s 已结束区间 / o 仍在持续 / t 无时间性 / ? 未判定。 */
|
|
@@ -269,8 +307,10 @@ export function parseBundle(text) {
|
|
|
269
307
|
if (!(rec.type in TYPE_CODES) && !(rec.type in TYPE_FULL)) {
|
|
270
308
|
if (rec.type === '' || rec.type === '?')
|
|
271
309
|
b.warnings.push(`${p}: 类型缺失,导入时将回落 episodic`);
|
|
310
|
+
// 口径与写侧 `memory_add` 一致(旧文案承诺“按原样透传”,写侧却静默抹平——
|
|
311
|
+
// 同一件事两套说法)。非词表值现在会被降级并留痕,不能再说是“透传”。
|
|
272
312
|
else
|
|
273
|
-
b.warnings.push(`${p}:
|
|
313
|
+
b.warnings.push(`${p}: 非词表类型 ${rec.type},导入时将降级为 episodic(服务端记 warn)`);
|
|
274
314
|
}
|
|
275
315
|
for (const [fld, val] of [
|
|
276
316
|
['cf', rec.cf],
|
package/dist/pipeline/l1.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { Context } from '@deepseek-ai/cordis';
|
|
|
2
2
|
import type { MemoryConfig } from '../config.js';
|
|
3
3
|
import type { L1Store } from '../store/l1.js';
|
|
4
4
|
import type { MemoryState } from '../store/state.js';
|
|
5
|
-
import type { ConversationAnchor, ConversationMessage, ExtractMode, MemoryFamily, MemoryLogger, MemoryRecord } from '../types.js';
|
|
5
|
+
import type { ConversationAnchor, ConversationMessage, ExtractedMemory, ExtractMode, MemoryFamily, MemoryLogger, MemoryRecord, MemoryScope } from '../types.js';
|
|
6
6
|
export interface ExtractionResult {
|
|
7
7
|
stored: number;
|
|
8
8
|
skipped: boolean;
|
|
@@ -15,6 +15,42 @@ export interface ExtractionResult {
|
|
|
15
15
|
}
|
|
16
16
|
/** 分族 checkpoint 桶(活引用,改动由调用方 save 落盘)。 */
|
|
17
17
|
export type FamilyStates = Record<MemoryFamily, MemoryState>;
|
|
18
|
+
/** 抽取产出 + 管线补上的五个字段(与 Step 1 的 `extracted` 元素同形)。 */
|
|
19
|
+
export type PendingMemory = ExtractedMemory & {
|
|
20
|
+
record_id: string;
|
|
21
|
+
scene_name: string;
|
|
22
|
+
family: MemoryFamily;
|
|
23
|
+
/** §E 归属:write 侧已按 `resolveRecordScope` 算好,`toStoreRecord` 原样带出 */
|
|
24
|
+
scope: MemoryScope;
|
|
25
|
+
workspaceId: string;
|
|
26
|
+
/** 治理归属(ADR-0015 T1.9/T1.10):进管线时一次算定(I-21),写时随 store 行落盘。 */
|
|
27
|
+
repoKeyName: string;
|
|
28
|
+
repoKeyOwner: string;
|
|
29
|
+
applicability: string;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* 合并时的检索轴并集(P0-c)。
|
|
33
|
+
*
|
|
34
|
+
* 此前合并产物只带新记忆的 metadata,targets 的 tags/hall/cogHall/使用场景全丢——
|
|
35
|
+
* 一次合并就把这条记忆从它原来的 Room/Wing 里摘出去,而面板上看不出任何异常(F2)。
|
|
36
|
+
* 这里只并**检索轴**:派生评价(maturity/usage/rating)与内容层字段不在其列。
|
|
37
|
+
*
|
|
38
|
+
* 单值轴(hall/cogHall)两侧互斥时**保留新记忆侧并留痕**,不拼成 `"a,b"`——那会
|
|
39
|
+
* 造出一个不存在的域(与 `isWingId` 的值域约束相冲)。
|
|
40
|
+
*
|
|
41
|
+
* @param self - 新记忆自己的 metadata(可为 undefined)。
|
|
42
|
+
* @param targets - 被合并掉的旧记录们的 metadata。
|
|
43
|
+
* @returns 并集后的 metadata 与若干条“丢了什么”的留痕文案。
|
|
44
|
+
*/
|
|
45
|
+
export declare function mergeAxes(self: Record<string, unknown> | undefined, targets: ReadonlyArray<Record<string, unknown> | undefined>): {
|
|
46
|
+
metadata: Record<string, unknown>;
|
|
47
|
+
notes: string[];
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* 导出仅供用例:`title → name` 这一跳是本计划的风隙(模型给的名字能不能落成合法身份名),
|
|
51
|
+
* 而驱动整条 LLM 管线会把断言埋进抽取/去重两段的噪声里。与 `mergeAxes` 同一先例。
|
|
52
|
+
*/
|
|
53
|
+
export declare function toStoreRecord(m: PendingMemory, now: number, ts: number, anchorMap?: ReadonlyMap<string, ConversationAnchor>): MemoryRecord;
|
|
18
54
|
/**
|
|
19
55
|
* 按字符预算把消息切成多块(保持顺序,单条超预算独占一块,由 callLLM 兜底截断)。
|
|
20
56
|
* 每条消息按 content 长度 + 64 字符脚手架开销(id/时间戳行)计。
|
|
@@ -32,4 +68,10 @@ workspaceId?: string,
|
|
|
32
68
|
* **缺省时行为与改动前逐字一致**——传入的 `pending` 消息若不带锚点(老数据、
|
|
33
69
|
* 未启用捕获侧打戳),`resolveSourceAnchors` 一律返回 undefined,不写 metadata 键。
|
|
34
70
|
*/
|
|
35
|
-
anchorMap?: ReadonlyMap<string, ConversationAnchor
|
|
71
|
+
anchorMap?: ReadonlyMap<string, ConversationAnchor>,
|
|
72
|
+
/**
|
|
73
|
+
* 合并后的**派生数据搬运钩子**(P0-d):旧 id → 新 id。使用史与人工标注存在
|
|
74
|
+
* 另两个 sidecar 里,而 merge 每次新铸 id——不搬就等于每次合并把这条记忆的
|
|
75
|
+
* `used`/人工打分清零,它会被当成“没用过”而沉底。缺省不搬(行为与改动前一致)。
|
|
76
|
+
*/
|
|
77
|
+
mergeRekey?: (oldId: string, newId: string) => void): Promise<ExtractionResult>;
|