dsh-prime-memory 0.18.5 → 0.18.6
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.md +11 -28
- package/dist/contract.d.ts +1 -109
- package/dist/hooks/recall.d.ts +1 -4
- package/dist/hooks/recall.js +1 -7
- package/dist/hooks/slot-recall.js +24 -1
- package/dist/index.js +4 -14
- package/dist/metadata-validators.d.ts +0 -5
- package/dist/metadata-validators.js +1 -11
- package/dist/pipeline/ruminate.d.ts +1 -11
- package/dist/pipeline/ruminate.js +1 -18
- package/dist/projection/slots.js +9 -14
- package/dist/stats.d.ts +2 -26
- package/dist/stats.js +13 -261
- package/dist/store/l1.d.ts +0 -34
- package/dist/store/l1.js +1 -68
- package/dist/store/sqlite.d.ts +0 -4
- package/dist/store/sqlite.js +0 -20
- package/dist/tools/index.d.ts +1 -4
- package/dist/tools/index.js +2 -224
- package/dist/types.d.ts +0 -4
- package/package.json +1 -1
- package/dist/client.js +0 -6274
- package/dist/config.d.ts +0 -1407
- package/dist/embedding-worker.cjs +0 -176
- package/dist/index.d.ts +0 -999
- package/dist/room-review.d.ts +0 -196
- package/dist/room-review.js +0 -281
- package/dist/runtime-package-lock.json +0 -982
- package/dist/store/recall-usage.d.ts +0 -43
- package/dist/store/recall-usage.js +0 -149
- package/dist/store/rooms-registry.d.ts +0 -66
- package/dist/store/rooms-registry.js +0 -250
package/CHANGELOG.md
CHANGED
|
@@ -6,34 +6,6 @@
|
|
|
6
6
|
> **UI 截图约定**:带界面变化的条目在 `assets/changelog/<版本号>/<两位编号>-<简述>.png`
|
|
7
7
|
> 存真机截图,并在条目内以相对路径引用,读者可在更新日志里直接看到新版本 UI 的样子。
|
|
8
8
|
|
|
9
|
-
## [0.18.5] — 2026-10-03(0.2.0 Hall·Room 功能下放)
|
|
10
|
-
|
|
11
|
-
### 新增(自 0.2.0-beta.4–beta.25 下放;对应 main 6037ebc..847c3f7 链)
|
|
12
|
-
|
|
13
|
-
- **Hall·Room 分类管理**:两级制 Room slug(`major` / `major/minor`)注册表 sidecar
|
|
14
|
-
(`rooms-registry.json`,损坏只读降级)、`memory_room_admin` 工具与
|
|
15
|
-
`room-admin`/`room-register`/`rooms-export`(rooms|orphans|records) RPC 面、
|
|
16
|
-
merge/rename/retire/update 破坏性面(预览→备份→游标重写,含已退场行)、
|
|
17
|
-
自生长 Room 一步收编(source=grown)、未注册 slug 退场自动补 retired 条目。
|
|
18
|
-
- **面板**:Hall 管理标签页(指针自制拖拽归类、全局 sticky 操作栏、子 room 仅显示 active)、
|
|
19
|
-
Room 独立标签页(存在/名称/条目管理、退场筛选 chips)、记忆页孤儿筛选与
|
|
20
|
-
「导出孤儿」回迁。
|
|
21
|
-
- **标注器词表接入注册表**:候选标注与 tags 标注优先把记忆挂到注册表 Room。
|
|
22
|
-
- **老化权重展示 + 召回使用统计**:`agingWeightOf` 半衰期权重、卡片「老化 N%」chip、
|
|
23
|
-
`RecallUsageStore`(进 topN 才算 used;损坏只读降级)。
|
|
24
|
-
- **测试**:Hall·Room HTTP 面集成测试(25 用例)、rooms-registry/room-review/
|
|
25
|
-
room-merge/room-admin-endpoint/recall-usage 单测,endpoint 契约计数 43→46。
|
|
26
|
-
- **Hall/Room 名称搜索过滤 + Hall 分组默认折叠**(0.20.0-beta.26 同步):
|
|
27
|
-
Hall 页搜索框(slug/显示名/别名,匹配组自动展开)、hall 头折叠默认收起 +
|
|
28
|
-
展开全部/收起全部 + localStorage 记忆;Room 页同款搜索框与退场筛选叠加。
|
|
29
|
-
|
|
30
|
-
### 适配差异(相对 0.2.0 线)
|
|
31
|
-
|
|
32
|
-
- 不含 longtask 全族(main 上已净零)、ADR-0015 repo 软围栏/治理权重/场景重聚类
|
|
33
|
-
队列(0.2.0 线专属);merge/rename 的「场景重算入队」随之省略(备份/重写/收别名
|
|
34
|
-
语义不变)。
|
|
35
|
-
- `agent/session-start` 仍并入 `agent/created`(0.1.7-rc.2 宿主适配保留)。
|
|
36
|
-
|
|
37
9
|
## [0.18.4] — 2026-09-28
|
|
38
10
|
|
|
39
11
|
### 新增
|
|
@@ -56,6 +28,17 @@
|
|
|
56
28
|
- **读侧双形状兼容**:召回份额估算的署名判据 `isOwnRecallSource` 同时接受新署名与 v3 旧行——只改写侧会让占用面板"记忆召回份额"静默归零(无异常无报错)。`MessageSourceMap` 经模块增强登记 `plugin:memory`(dsh-llm 0.1.7 的 map 为 `user|model|tool|'system-prompt'`,无 plugin catch-all,merge-extensible per-producer)。
|
|
57
29
|
- **tool-result v4 native 适配(N1)**:`store/evidence-source.ts` 的取证文本读取新增 native 分支(v4 一等 `role:'tool'` 消息:content 直接为 text/reasoning 块、`isError` 在 message 顶层;宿主 `assertBlock` 硬拒旧 `tool-result` wrapper 块),旧块下钻路径保留作历史兼容——否则 v4 下取证文本静默恒空。`projection/slots.ts` 的 isError 守卫同步 native 化。
|
|
58
30
|
|
|
31
|
+
## [0.18.6] — 2026-10-04
|
|
32
|
+
|
|
33
|
+
### 修复
|
|
34
|
+
|
|
35
|
+
- **投影 `memorySlots` 判脏放宽到任意事件**(同步主线 v0.20.2):不再仅 tool/result 时按 store rev 判脏,任意已提交事件 O(1) 比较,写入后下一条任意事件即刷新侧栏帧。
|
|
36
|
+
- **常驻注入改 `<system-reminder>` 标签帧**(同步主线 v0.20.2,对齐 dsh-agent-instructions house style):免回应/勿复述权威声明 + 正文闭合标签转义,修掉弱模型复读槽位内容的问题。
|
|
37
|
+
|
|
38
|
+
### 新增
|
|
39
|
+
|
|
40
|
+
- **`memory_search` 结果透出 `id`**(schema/映射/渲染文本三处,同步主线 v0.20.3):解除检索拿不到 record_id 的死锁。
|
|
41
|
+
|
|
59
42
|
## [Unreleased]
|
|
60
43
|
|
|
61
44
|
### 新增
|
package/dist/contract.d.ts
CHANGED
|
@@ -507,91 +507,10 @@ export interface WingOverviewResponse {
|
|
|
507
507
|
* 降级/无 tags 时 `rooms` 为空数组(面板显示"暂无"),不报错。
|
|
508
508
|
*/
|
|
509
509
|
export interface RoomsGetResponse {
|
|
510
|
-
/** Room 列表(
|
|
511
|
-
* 条目可选字段 source/label 由端点层合并注册表后附带(客户端可选读,零断裂)。 */
|
|
510
|
+
/** Room 列表(按记录数降序,同数按名升序)。 */
|
|
512
511
|
rooms: RoomCount[];
|
|
513
512
|
/** Room 总数(= rooms.length,冗余只为前端少写一次 .length)。 */
|
|
514
513
|
total: number;
|
|
515
|
-
/** 孤儿记忆数:没有任何 Room(tags 为空/缺失)的记录条数(与 rooms 同口径含已退场)。 */
|
|
516
|
-
orphanCount: number;
|
|
517
|
-
/** 注册表条目(全量含 retired;分类管理面板用;未装配 = undefined)。 */
|
|
518
|
-
registry?: Array<{
|
|
519
|
-
slug: string;
|
|
520
|
-
label?: string;
|
|
521
|
-
description?: string;
|
|
522
|
-
source: 'pre-registered' | 'grown';
|
|
523
|
-
aliases?: string[];
|
|
524
|
-
status: 'active' | 'retired';
|
|
525
|
-
}>;
|
|
526
|
-
}
|
|
527
|
-
/** dsh-memory/room-register(预注册 Room;高权限:面板 memoryMutate 开启才生效)。 */
|
|
528
|
-
export interface RoomRegisterRequest {
|
|
529
|
-
slug: string;
|
|
530
|
-
label?: string;
|
|
531
|
-
description?: string;
|
|
532
|
-
/** 收编自生长 slug 时传 grown(缺省 pre-registered;已存在条目忽略此字段)。 */
|
|
533
|
-
source?: 'pre-registered' | 'grown';
|
|
534
|
-
}
|
|
535
|
-
export interface RoomRegisterResponse {
|
|
536
|
-
slug: string;
|
|
537
|
-
created: boolean;
|
|
538
|
-
/** 幂等补全时的提示(如「已存在,只补全缺失字段」)。 */
|
|
539
|
-
notice?: string;
|
|
540
|
-
}
|
|
541
|
-
/** dsh-memory/rooms-export(分类数据导出,CSV 直出)。 */
|
|
542
|
-
export interface RoomsExportRequest {
|
|
543
|
-
/** rooms = 词表+计数;orphans = 无 Room 绑定的记录清单;records = 按 Room 的记录清单(tag 必传)。 */
|
|
544
|
-
kind: 'rooms' | 'orphans' | 'records';
|
|
545
|
-
/** 各 kind 通用上限(1..10000,默认 2000)。 */
|
|
546
|
-
limit?: number;
|
|
547
|
-
/** kind=records 的目标 Room slug。 */
|
|
548
|
-
tag?: string;
|
|
549
|
-
}
|
|
550
|
-
export interface RoomsExportResponse {
|
|
551
|
-
kind: 'rooms' | 'orphans' | 'records';
|
|
552
|
-
/** CSV 文本(首行表头;
|
|
553
|
-
行尾;RFC 4180 转义)。 */
|
|
554
|
-
csv: string;
|
|
555
|
-
/** 数据行数(不含表头)。 */
|
|
556
|
-
total: number;
|
|
557
|
-
/** truncated = 达到 limit 上限,结果可能不完整。 */
|
|
558
|
-
truncated: boolean;
|
|
559
|
-
}
|
|
560
|
-
/** dsh-memory/room-admin(Room 破坏性面管理;高权限:面板 memoryMutate 开启才生效)。 */
|
|
561
|
-
export interface RoomAdminRequest {
|
|
562
|
-
/** merge/rename:from→to(mergeRoom/renameRoom 编排:预览→实跑+自动备份+入队场景重算);retire:slug 退役/恢复;update:改写 label/description。 */
|
|
563
|
-
action: 'merge' | 'rename' | 'retire' | 'update';
|
|
564
|
-
/** update 的显示名(可中文;非空才改写)。 */
|
|
565
|
-
label?: string;
|
|
566
|
-
/** update 的归类说明(喂标注器;非空才改写)。 */
|
|
567
|
-
description?: string;
|
|
568
|
-
/** merge/rename 的源 Room slug。 */
|
|
569
|
-
from?: string;
|
|
570
|
-
/** merge/rename 的目标 Room slug。 */
|
|
571
|
-
to?: string;
|
|
572
|
-
/** retire 的目标 Room slug。 */
|
|
573
|
-
slug?: string;
|
|
574
|
-
/** retire:true=恢复 active;缺省/false=退役。 */
|
|
575
|
-
active?: boolean;
|
|
576
|
-
/** retire:同时把该 room 下全部**活跃**记录退场(软删,可在「已退场」区恢复)。 */
|
|
577
|
-
withRecords?: boolean;
|
|
578
|
-
/** merge/rename:缺省 true 只返预览;实跑需显式 false。 */
|
|
579
|
-
dryRun?: boolean;
|
|
580
|
-
}
|
|
581
|
-
export interface RoomAdminResponse {
|
|
582
|
-
notice: string;
|
|
583
|
-
/** merge/rename 本次是否 dryRun(预览)。 */
|
|
584
|
-
dryRun?: boolean;
|
|
585
|
-
/** merge/rename 影响的记录条数(实跑 = 已改写条数)。 */
|
|
586
|
-
affected?: number;
|
|
587
|
-
/** 预览样例(受影响记录 id 的前几条)。 */
|
|
588
|
-
preview?: string[];
|
|
589
|
-
/** true = 超过单次上限,需续跑。 */
|
|
590
|
-
hasMore?: boolean;
|
|
591
|
-
/** 实跑时改写前备份文件名(rooms-merge-backups/)。 */
|
|
592
|
-
backupFile?: string;
|
|
593
|
-
/** retire withRecords 实际退场的记录条数(软删,可恢复)。 */
|
|
594
|
-
retiredRecords?: number;
|
|
595
514
|
}
|
|
596
515
|
/** dsh-memory/wing-backfill(一键回填,后台任务;端点立即返回,进度以 wing-overview 轮询)。 */
|
|
597
516
|
export interface WingBackfillResponse {
|
|
@@ -731,11 +650,6 @@ export interface ListRecordsRequest {
|
|
|
731
650
|
* Room 由 tags 派生(自生长),故这里传的是**具体 tag 名**而非枚举 id。
|
|
732
651
|
*/
|
|
733
652
|
tag?: string;
|
|
734
|
-
/**
|
|
735
|
-
* 孤儿记忆筛选:true = 只列**没有任何 Room(tags 为空/缺失)**的记录。
|
|
736
|
-
* 与 `tag` 互斥;同传时 `tag` 优先(客户端保证不同传)。
|
|
737
|
-
*/
|
|
738
|
-
untagged?: boolean;
|
|
739
653
|
/**
|
|
740
654
|
* 退场(软删)筛查:三态。省略 = 全部(活跃+已退场混排,靠 `UiRecord.retired`
|
|
741
655
|
* 徽标区分);`false` = 仅活跃;`true` = 仅已退场。
|
|
@@ -772,15 +686,6 @@ export interface UiRecord {
|
|
|
772
686
|
sourceAnchors: string[];
|
|
773
687
|
/** 检索相关度(列表路径无 score → null)。 */
|
|
774
688
|
score: number | null;
|
|
775
|
-
/** 老化权重:读路径衰减系数 max(0.5, 0.5^(Δ天/半衰期))(Δ=updatedAt;半衰期 0=关 → null)。 */
|
|
776
|
-
agingWeight?: number | null;
|
|
777
|
-
/** 召回使用统计:**进 topN(被注入)才算 used**;参与尝试未进 = 仅 attempts。缺省 = 未装配。 */
|
|
778
|
-
usage?: {
|
|
779
|
-
attempts: number;
|
|
780
|
-
used: number;
|
|
781
|
-
lastAttemptAt: number | null;
|
|
782
|
-
lastUsedAt: number | null;
|
|
783
|
-
} | null;
|
|
784
689
|
/**
|
|
785
690
|
* 是否已退场(软删)。`true` 时该记录在活动列表里仍以「已退场」态呈现(置灰 + 徽标),
|
|
786
691
|
* 可被 `records-restore` 找回——这正是设计要的「不静默消失、可恢复」,而非真删。
|
|
@@ -799,13 +704,6 @@ export interface ListRecordsResponse {
|
|
|
799
704
|
truncated: boolean;
|
|
800
705
|
/** 场景筛选下拉选项(仅 offset===0 时附带)。 */
|
|
801
706
|
scenes?: string[];
|
|
802
|
-
/** 召回使用汇总(老化权重效果口径:进 topN 才算 used)。未装配 = undefined。 */
|
|
803
|
-
usageSummary?: {
|
|
804
|
-
tracked: number;
|
|
805
|
-
attempted: number;
|
|
806
|
-
used: number;
|
|
807
|
-
rate: number;
|
|
808
|
-
} | null;
|
|
809
707
|
/**
|
|
810
708
|
* Wing 词表(R8 单一事实源:服务端随 list-records 下发,client 不再手抄;仅 offset===0 时附带)。
|
|
811
709
|
* 含 8 角 + `general`(跨域兜底,存量大 reserved 值仍可筛)。缺省(旧服务端)时 client
|
|
@@ -1303,9 +1201,6 @@ export interface DshMemoryRequestMap {
|
|
|
1303
1201
|
'dsh-memory/session-mode-set': SessionModeSetRequest;
|
|
1304
1202
|
'dsh-memory/wing-overview': Record<string, never>;
|
|
1305
1203
|
'dsh-memory/rooms-get': Record<string, never>;
|
|
1306
|
-
'dsh-memory/rooms-export': RoomsExportRequest;
|
|
1307
|
-
'dsh-memory/room-register': RoomRegisterRequest;
|
|
1308
|
-
'dsh-memory/room-admin': RoomAdminRequest;
|
|
1309
1204
|
'dsh-memory/wing-backfill': Record<string, never>;
|
|
1310
1205
|
'dsh-memory/session-stats': SessionStatsRequest;
|
|
1311
1206
|
'dsh-memory/settings-get': Record<string, never>;
|
|
@@ -1351,9 +1246,6 @@ export interface DshMemoryResponseMap {
|
|
|
1351
1246
|
'dsh-memory/session-mode-set': SessionModeSetResponse;
|
|
1352
1247
|
'dsh-memory/wing-overview': WingOverviewResponse;
|
|
1353
1248
|
'dsh-memory/rooms-get': RoomsGetResponse;
|
|
1354
|
-
'dsh-memory/rooms-export': RoomsExportResponse;
|
|
1355
|
-
'dsh-memory/room-register': RoomRegisterResponse;
|
|
1356
|
-
'dsh-memory/room-admin': RoomAdminResponse;
|
|
1357
1249
|
'dsh-memory/wing-backfill': WingBackfillResponse;
|
|
1358
1250
|
'dsh-memory/session-stats': SessionStatsResponse;
|
|
1359
1251
|
'dsh-memory/settings-get': SettingsGetResponse;
|
package/dist/hooks/recall.d.ts
CHANGED
|
@@ -22,7 +22,6 @@ import type { L1Store } from '../store/l1.js';
|
|
|
22
22
|
import type { PersonaStore } from '../store/persona.js';
|
|
23
23
|
import type { SceneStore } from '../store/scenes.js';
|
|
24
24
|
import type { SessionModeStore } from '../store/session-modes.js';
|
|
25
|
-
import type { RecallUsageStore } from '../store/recall-usage.js';
|
|
26
25
|
import type { MemoryLogger } from '../types.js';
|
|
27
26
|
import { type OccupancyLedger } from '../util/context-occupancy.js';
|
|
28
27
|
/**
|
|
@@ -90,6 +89,4 @@ export declare function registerRecall(ctx: Context, cfg: MemoryConfig, stores:
|
|
|
90
89
|
l1: L1Store;
|
|
91
90
|
scenes: Record<'chat' | 'work', SceneStore>;
|
|
92
91
|
persona: Record<'chat' | 'work', PersonaStore>;
|
|
93
|
-
}, logger: MemoryLogger, live: LiveSettingsHandle, modes: SessionModeStore, dataDir: string
|
|
94
|
-
/** 召回使用统计(可选;未装配 = 零成本旁路):进 topN(注入)才算 used。 */
|
|
95
|
-
usage?: RecallUsageStore): RecallHooks;
|
|
92
|
+
}, logger: MemoryLogger, live: LiveSettingsHandle, modes: SessionModeStore, dataDir: string): RecallHooks;
|
package/dist/hooks/recall.js
CHANGED
|
@@ -112,9 +112,7 @@ export function emptyRecallStats(now = Date.now()) {
|
|
|
112
112
|
updatedAt: now,
|
|
113
113
|
};
|
|
114
114
|
}
|
|
115
|
-
export function registerRecall(ctx, cfg, stores, logger, live, modes, dataDir
|
|
116
|
-
/** 召回使用统计(可选;未装配 = 零成本旁路):进 topN(注入)才算 used。 */
|
|
117
|
-
usage) {
|
|
115
|
+
export function registerRecall(ctx, cfg, stores, logger, live, modes, dataDir) {
|
|
118
116
|
/** 召回去重存储(同会话已注入的记忆不再重复注入;写穿持久化,重启不丢)。 */
|
|
119
117
|
const dedupe = new RecallDedupeStore(dataDir, logger);
|
|
120
118
|
/** 记忆占用流水(账本迁移写穿;重启后历史会话账目由此复生)。 */
|
|
@@ -381,7 +379,6 @@ usage) {
|
|
|
381
379
|
injectedIds: [], suppressedCount: scoped.length - fresh.length,
|
|
382
380
|
durationMs: Date.now() - searchStart, outcome: 'suppressed',
|
|
383
381
|
});
|
|
384
|
-
usage?.recordAttempt(scoped.map((h) => h.id), []);
|
|
385
382
|
return decision;
|
|
386
383
|
}
|
|
387
384
|
const lines = applyRecallBudget(fresh.map((h) => `- [${h.scene_name ? `${h.type}|${h.scene_name}` : h.type}] ${h.content}`), { maxCharsPerMemory: cfg.recall.maxCharsPerMemory, maxTotalRecallChars: cfg.recall.maxTotalRecallChars });
|
|
@@ -393,7 +390,6 @@ usage) {
|
|
|
393
390
|
injectedIds: [], suppressedCount: scoped.length - fresh.length,
|
|
394
391
|
durationMs: Date.now() - searchStart, outcome: 'suppressed',
|
|
395
392
|
});
|
|
396
|
-
usage?.recordAttempt(fresh.map((h) => h.id), []);
|
|
397
393
|
return decision;
|
|
398
394
|
}
|
|
399
395
|
st.lastHits = lines.length;
|
|
@@ -426,8 +422,6 @@ usage) {
|
|
|
426
422
|
injectedIds: fresh.slice(0, lines.length).map((h) => h.id), suppressedCount: scoped.length - fresh.length,
|
|
427
423
|
durationMs: Date.now() - searchStart, outcome: 'injected',
|
|
428
424
|
});
|
|
429
|
-
// 使用统计:候选=scoped(尝试),进 topN(注入)=used
|
|
430
|
-
usage?.recordAttempt(scoped.map((h) => h.id), fresh.slice(0, lines.length).map((h) => h.id));
|
|
431
425
|
// 入账在成功构造注入消息之后、返回 enter 之前——任何前置抛错路径账目零扰动
|
|
432
426
|
const led = ledgerFor(payload.agent.id);
|
|
433
427
|
recordRecallInjection(led, text.length);
|
|
@@ -1,4 +1,22 @@
|
|
|
1
1
|
import { createUserMessage } from '@deepseek-ai/dsh-llm';
|
|
2
|
+
/**
|
|
3
|
+
* 对齐宿主 house style(dsh-agent-instructions 的 AGENTS.md 注入):user 角色
|
|
4
|
+
* 承载 + `<system-reminder>` 标签框。宿主对自家指令刻意**不用** system 角色——
|
|
5
|
+
* 会话中段的 system 消息会破坏部分聊天模板(qwen-chat-template 等),标签框即可
|
|
6
|
+
* 让模型把它识别为系统级元信息(Claude Code 同款语义)。
|
|
7
|
+
*/
|
|
8
|
+
const SYSTEM_REMINDER_OPEN = '<system-reminder>';
|
|
9
|
+
const SYSTEM_REMINDER_CLOSE = '</system-reminder>';
|
|
10
|
+
const SLOTS_INTRO = '以下是本环境的常驻记忆槽位(激活槽位):跨会话持续生效的背景约定,仅在与之相关时作为指引遵循。' +
|
|
11
|
+
'它们是系统注入的元信息,不是用户发言——无需回应,请勿在回复中复述本节内容;' +
|
|
12
|
+
'且不覆盖系统提示与用户的直接指令,更具体的指令优先于更一般的约定。';
|
|
13
|
+
/**
|
|
14
|
+
* 槽位标题/正文来自模型工具调用,可能含有闭合标签;不转义会让槽位内容伪造
|
|
15
|
+
* 帧边界(宿主对指令文件正文做同样的转义)。
|
|
16
|
+
*/
|
|
17
|
+
function escapeFrameBody(body) {
|
|
18
|
+
return body.replaceAll(SYSTEM_REMINDER_CLOSE, '<\\/system-reminder>');
|
|
19
|
+
}
|
|
2
20
|
export function registerSlotRecall(ctx, cfg, slots, logger, _live) {
|
|
3
21
|
const buildInjection = () => {
|
|
4
22
|
if (!cfg.slots.enabled || !cfg.slots.inject)
|
|
@@ -13,7 +31,12 @@ export function registerSlotRecall(ctx, cfg, slots, logger, _live) {
|
|
|
13
31
|
if (truncatedCount > 0) {
|
|
14
32
|
lines.push(`… 另有 ${truncatedCount} 个常驻槽位因预算未显示,可用 memory_slot_list 查看`);
|
|
15
33
|
}
|
|
16
|
-
return
|
|
34
|
+
return [
|
|
35
|
+
SYSTEM_REMINDER_OPEN,
|
|
36
|
+
SLOTS_INTRO,
|
|
37
|
+
escapeFrameBody(lines.join('\n')),
|
|
38
|
+
SYSTEM_REMINDER_CLOSE,
|
|
39
|
+
].join('\n');
|
|
17
40
|
};
|
|
18
41
|
ctx.on('agent/pre-step', async (payload, next) => {
|
|
19
42
|
const decision = await next();
|
package/dist/index.js
CHANGED
|
@@ -36,8 +36,6 @@ import { SlotStore } from './store/slots.js';
|
|
|
36
36
|
import { registerMemoryTools } from './tools/index.js';
|
|
37
37
|
import { registerSlotTools } from './tools/slots.js';
|
|
38
38
|
import { registerSlotRecall } from './hooks/slot-recall.js';
|
|
39
|
-
import { RoomRegistryStore } from './store/rooms-registry.js';
|
|
40
|
-
import { RecallUsageStore } from './store/recall-usage.js';
|
|
41
39
|
import { registerSlotsProjection } from './projection/slots.js';
|
|
42
40
|
import { errDetail, withFileLog } from './util/filelog.js';
|
|
43
41
|
import { buildRouteChain, resolveModelRoute, invalidateEffortCache } from './llm.js';
|
|
@@ -160,7 +158,6 @@ export async function apply(ctx, config) {
|
|
|
160
158
|
}
|
|
161
159
|
}
|
|
162
160
|
const stores = {
|
|
163
|
-
usage: undefined, // 装配于下方(依赖 dataDir 就绪)
|
|
164
161
|
l0: new L0Store(dataDir, db, embed, logger),
|
|
165
162
|
l1: new L1Store(dataDir, db, embed, config.recall.strategy, logger, config.recall.decayHalfLifeDays,
|
|
166
163
|
// §D 第 3 路:图谱回链。图谱不可用时 searchNodes 自带 no-op,不影响双路。
|
|
@@ -353,23 +350,16 @@ export async function apply(ctx, config) {
|
|
|
353
350
|
backend = await createMemoryBackend({ dbPath: path.join(dataDir, 'memory.db'), dimensions: initial.dims, logger }, backend);
|
|
354
351
|
}
|
|
355
352
|
stores.backend = backend;
|
|
356
|
-
// Room 注册表(分类管理 beta.4;损坏降级为纯自生长目录)
|
|
357
|
-
const roomRegistry = new RoomRegistryStore(dataDir, logger);
|
|
358
|
-
await roomRegistry.init();
|
|
359
353
|
const ruminate = storageOk && !db.isDegraded() && ruminateFile
|
|
360
|
-
? new RuminateController(ctx, config, runner, stores, logger, live, ruminateFile
|
|
354
|
+
? new RuminateController(ctx, config, runner, stores, logger, live, ruminateFile)
|
|
361
355
|
: undefined;
|
|
362
356
|
let flushL0;
|
|
363
357
|
if (storageOk) {
|
|
364
358
|
flushL0 = registerCapture(ctx, config, runner, stores.l0, logger, live, modes);
|
|
365
359
|
}
|
|
366
|
-
|
|
367
|
-
const recallUsage = new RecallUsageStore(dataDir, logger);
|
|
368
|
-
await recallUsage.init();
|
|
369
|
-
stores.usage = recallUsage;
|
|
370
|
-
const recall = registerRecall(ctx, config, stores, logger, live, modes, dataDir, recallUsage);
|
|
360
|
+
const recall = registerRecall(ctx, config, stores, logger, live, modes, dataDir);
|
|
371
361
|
runner.setAfterRun(recall.invalidateProfile);
|
|
372
|
-
registerMemoryTools(ctx, config, stores, logger, modes, live, ruminate
|
|
362
|
+
registerMemoryTools(ctx, config, stores, logger, modes, live, ruminate);
|
|
373
363
|
// 激活槽位(active slot):工具面 + 常驻注入 + 服务端投影(均走 ctx.effect,可撤销)
|
|
374
364
|
registerSlotTools(ctx, config, stores.slots, logger, modes, live, stores.l1);
|
|
375
365
|
const slotRecall = registerSlotRecall(ctx, config, stores.slots, logger, live);
|
|
@@ -388,7 +378,7 @@ export async function apply(ctx, config) {
|
|
|
388
378
|
runnerView: (sid, mode) => runner.sessionView(sid, mode),
|
|
389
379
|
l0Count: (sid) => stores.l0.countBySession(sid),
|
|
390
380
|
capabilities: () => db.getCapabilities(),
|
|
391
|
-
}, ruminate
|
|
381
|
+
}, ruminate);
|
|
392
382
|
// bench 控制服务(config.benchControl 门控,默认关):仅基准/调试部署注册,
|
|
393
383
|
// 供同进程的 bench-runner lifecycle 赛道触发 rebuild / 设置会话档位
|
|
394
384
|
// (宿主侧 RPC 无 call(),见 bench-control.ts)
|
|
@@ -10,11 +10,6 @@
|
|
|
10
10
|
* 已是 string 的变量收窄成 `never`(该分支内无法再 `.slice`,已在 wing-backfill 踩过)。
|
|
11
11
|
*/
|
|
12
12
|
export declare function isWingId(v: unknown): boolean;
|
|
13
|
-
/**
|
|
14
|
-
* 两级 Room slug(`major` 或 `major/minor`,各段满足 isTag;至多一个 slash)。
|
|
15
|
-
* Room 注册表/归类写回的 tags 域;与 rooms-registry.ts 同一事实源(就近定义避免依赖环)。
|
|
16
|
-
*/
|
|
17
|
-
export declare function isRoomSlug(v: unknown): boolean;
|
|
18
13
|
/** 同为布尔谓词(理由见 isWingId 注释)。 */
|
|
19
14
|
export declare function isTag(v: unknown): boolean;
|
|
20
15
|
/**
|
|
@@ -31,16 +31,6 @@ export function isWingId(v) {
|
|
|
31
31
|
}
|
|
32
32
|
/** 标签(Room 的构成单元)校验:小写字母数字连字符,1-32 字符。 */
|
|
33
33
|
const TAG_RE = /^[a-z0-9][a-z0-9-]{0,31}$/;
|
|
34
|
-
/**
|
|
35
|
-
* 两级 Room slug(`major` 或 `major/minor`,各段满足 isTag;至多一个 slash)。
|
|
36
|
-
* Room 注册表/归类写回的 tags 域;与 rooms-registry.ts 同一事实源(就近定义避免依赖环)。
|
|
37
|
-
*/
|
|
38
|
-
export function isRoomSlug(v) {
|
|
39
|
-
if (typeof v !== 'string')
|
|
40
|
-
return false;
|
|
41
|
-
const parts = v.split('/');
|
|
42
|
-
return parts.length <= 2 && parts.every((p) => TAG_RE.test(p));
|
|
43
|
-
}
|
|
44
34
|
/** 同为布尔谓词(理由见 isWingId 注释)。 */
|
|
45
35
|
export function isTag(v) {
|
|
46
36
|
return typeof v === 'string' && TAG_RE.test(v);
|
|
@@ -57,7 +47,7 @@ export function normTags(v, max = 3) {
|
|
|
57
47
|
if (typeof raw !== 'string')
|
|
58
48
|
continue;
|
|
59
49
|
const t = raw.trim().toLowerCase();
|
|
60
|
-
if (!
|
|
50
|
+
if (!isTag(t) || out.includes(t))
|
|
61
51
|
continue;
|
|
62
52
|
out.push(t);
|
|
63
53
|
if (out.length >= max)
|
|
@@ -66,8 +66,6 @@ export declare class RuminateController {
|
|
|
66
66
|
private sessions;
|
|
67
67
|
private totalL1;
|
|
68
68
|
private pendingFile;
|
|
69
|
-
/** Room 注册表(可选;孤儿候选预标记的合并词表来源)。 */
|
|
70
|
-
private readonly roomRegistry;
|
|
71
69
|
/** 记忆后端:未注入时包 l1(进程内,行为与改造前等价)。 */
|
|
72
70
|
private backend;
|
|
73
71
|
constructor(ctx: Context, cfg: MemoryConfig, runner: Pick<MemoryRunner, 'enqueue' | 'states'>, stores: {
|
|
@@ -77,15 +75,7 @@ export declare class RuminateController {
|
|
|
77
75
|
scenes: Record<MemoryFamily, SceneStore>;
|
|
78
76
|
persona: Record<MemoryFamily, PersonaStore>;
|
|
79
77
|
state: StateStore;
|
|
80
|
-
}, logger: MemoryLogger, live: LiveSettingsHandle, pendingFile: string
|
|
81
|
-
/** Room 注册表(可选;孤儿候选预标记的合并词表来源)。 */
|
|
82
|
-
roomRegistry?: {
|
|
83
|
-
listActive(): Array<{
|
|
84
|
-
slug: string;
|
|
85
|
-
label?: string;
|
|
86
|
-
description?: string;
|
|
87
|
-
}>;
|
|
88
|
-
});
|
|
78
|
+
}, logger: MemoryLogger, live: LiveSettingsHandle, pendingFile: string);
|
|
89
79
|
/** 状态快照 */
|
|
90
80
|
getStatus(): RuminateStatus;
|
|
91
81
|
/**
|
|
@@ -3,7 +3,6 @@ import { groupPendingBySession, loadPending, } from '../store/pending.js';
|
|
|
3
3
|
import { errDetail } from '../util/filelog.js';
|
|
4
4
|
import { runSceneConsolidation } from './l2.js';
|
|
5
5
|
import { relabelPass } from './relabel.js';
|
|
6
|
-
import { annotateOrphanCandidates } from '../room-review.js';
|
|
7
6
|
import { runPersona } from './l3.js';
|
|
8
7
|
const IDLE_STATUS = {
|
|
9
8
|
running: false,
|
|
@@ -45,15 +44,11 @@ export class RuminateController {
|
|
|
45
44
|
sessions = [];
|
|
46
45
|
totalL1 = 0;
|
|
47
46
|
pendingFile;
|
|
48
|
-
/** Room 注册表(可选;孤儿候选预标记的合并词表来源)。 */
|
|
49
|
-
roomRegistry;
|
|
50
47
|
/** 记忆后端:未注入时包 l1(进程内,行为与改造前等价)。 */
|
|
51
48
|
backend() {
|
|
52
49
|
return this.stores.backend ?? new InProcMemoryBackend(this.stores.l1);
|
|
53
50
|
}
|
|
54
|
-
constructor(ctx, cfg, runner, stores, logger, live, pendingFile
|
|
55
|
-
/** Room 注册表(可选;孤儿候选预标记的合并词表来源)。 */
|
|
56
|
-
roomRegistry) {
|
|
51
|
+
constructor(ctx, cfg, runner, stores, logger, live, pendingFile) {
|
|
57
52
|
this.ctx = ctx;
|
|
58
53
|
this.cfg = cfg;
|
|
59
54
|
this.runner = runner;
|
|
@@ -61,7 +56,6 @@ export class RuminateController {
|
|
|
61
56
|
this.logger = logger;
|
|
62
57
|
this.live = live;
|
|
63
58
|
this.pendingFile = pendingFile;
|
|
64
|
-
this.roomRegistry = roomRegistry;
|
|
65
59
|
}
|
|
66
60
|
/** 状态快照 */
|
|
67
61
|
getStatus() {
|
|
@@ -228,17 +222,6 @@ export class RuminateController {
|
|
|
228
222
|
// 重标定失败不拖垮反刍整体(蒸馏/L2/L3 产物保留)
|
|
229
223
|
this.logger.warn(`[memory] 反刍重标定失败(不影响本次产物): ${errDetail(err)}`);
|
|
230
224
|
}
|
|
231
|
-
// 孤儿候选预标记(长尾治理):无 Room 的活跃孤儿对照现有 Room 词表产出
|
|
232
|
-
// 候选(roomReview='pending'),由 agent 用 memory_room_review 逐个复查;
|
|
233
|
-
// 每轮至多 40 条,吞错不拖垮反刍。
|
|
234
|
-
try {
|
|
235
|
-
const r = await annotateOrphanCandidates(this.ctx, this.cfg, { l1: this.stores.l1, logger: this.logger, registry: this.roomRegistry }, 40);
|
|
236
|
-
if (r.written > 0)
|
|
237
|
-
this.status.detail = `孤儿候选预标记 ${r.written} 条(待 agent 复查,工具 memory_room_review)`;
|
|
238
|
-
}
|
|
239
|
-
catch (err) {
|
|
240
|
-
this.logger.warn(`[memory] 孤儿候选预标记失败(忽略): ${errDetail(err)}`);
|
|
241
|
-
}
|
|
242
225
|
this.status.phase = 'done';
|
|
243
226
|
this.finish(null);
|
|
244
227
|
}
|
package/dist/projection/slots.js
CHANGED
|
@@ -75,22 +75,17 @@ function view(state) {
|
|
|
75
75
|
}
|
|
76
76
|
/**
|
|
77
77
|
* apply(state, event):同步。
|
|
78
|
-
* -
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
* (
|
|
82
|
-
*
|
|
78
|
+
* - **任意已提交事件都判脏**(v0.18.4 起):此前仅在 tool/result(settled、非 error)
|
|
79
|
+
* 时检查,实际运行中暴露出脆弱性——写入后的投影帧依赖"该会话恰好再来一条
|
|
80
|
+
* tool/result"才刷新;跨会话场景(会话 A 写、会话 B 看)更是要等 B 自己的下一次
|
|
81
|
+
* 工具调用。改为对所有事件做 O(1) revision 比较:rev 未变 → 同引用(满足 I1b,
|
|
82
|
+
* 无 republish thrash);rev 变 → 立即重建。写入后的下一条任意事件(用户消息、
|
|
83
|
+
* turn 边界、其他工具结果)都会把新帧推给客户端。
|
|
84
|
+
* - isError 守卫一并移除:rev 只在 store 真实变更后递增(persist 内联 RMW),
|
|
85
|
+
* 事件成败与否不影响"store 是否变了"这一事实;错误事件后重建读到的仍是
|
|
86
|
+
* 当前真实快照,不会引入错误数据。
|
|
83
87
|
*/
|
|
84
88
|
function applySlotsEvent(state, event, store) {
|
|
85
|
-
if (event.type !== 'tool/result')
|
|
86
|
-
return state;
|
|
87
|
-
const data = event.data;
|
|
88
|
-
// v4 native(宿主 ≥0.1.7-rc.1):isError 在 message 顶层;v3 wrapper:块上 isError(历史兼容)。
|
|
89
|
-
const isError = data?.message?.isError === true ||
|
|
90
|
-
(Array.isArray(data?.message?.content) &&
|
|
91
|
-
data.message.content.some((c) => c.isError === true));
|
|
92
|
-
if (isError)
|
|
93
|
-
return state;
|
|
94
89
|
if (store.revision() === state.rev)
|
|
95
90
|
return state;
|
|
96
91
|
return buildState(store);
|
package/dist/stats.d.ts
CHANGED
|
@@ -3,8 +3,6 @@ import { type MemoryConfig } from './config.js';
|
|
|
3
3
|
import { type RecallSessionStats } from './hooks/recall.js';
|
|
4
4
|
import type { RebuildController } from './pipeline/rebuild.js';
|
|
5
5
|
import type { RuminateController } from './pipeline/ruminate.js';
|
|
6
|
-
import type { RoomRegistryStore } from './store/rooms-registry.js';
|
|
7
|
-
import type { RecallUsageStore } from './store/recall-usage.js';
|
|
8
6
|
import { type LiveSettingsHandle } from './settings.js';
|
|
9
7
|
import type { GraphStore } from './store/graph-store.js';
|
|
10
8
|
import type { L0Store } from './store/l0.js';
|
|
@@ -25,7 +23,7 @@ export interface MemoryStatusSource {
|
|
|
25
23
|
pending(): number;
|
|
26
24
|
}
|
|
27
25
|
/**
|
|
28
|
-
* 端点全集运行时清单(
|
|
26
|
+
* 端点全集运行时清单(36 个,与 tests/contract-keys.test.ts 的 ENDPOINTS 及
|
|
29
27
|
* contract.ts 类型映射表三方对齐,漂移由键集 diff 测试暴露)。
|
|
30
28
|
* 注意:本清单同时是 HTTP 前缀路由 `/dsh-memory/rpc/<短名>` 的**放行白名单**
|
|
31
29
|
* (见下方 SHORT_ENDPOINTS),漏一条 = 该端点在面板里静默消失(404 被客户端
|
|
@@ -79,9 +77,6 @@ interface MemoryRpcSources {
|
|
|
79
77
|
rebuild?: RebuildController;
|
|
80
78
|
embedManager?: EmbeddingManager;
|
|
81
79
|
sessionInfo?: SessionInfoSource;
|
|
82
|
-
/** 长任务端点依赖(未装配 = 端点恒 disabled,面板不挂载)。 */
|
|
83
|
-
/** Room 注册表(未装配 = rooms-get 不带 registry,rooms-export 不可用)。 */
|
|
84
|
-
roomRegistry?: RoomRegistryStore;
|
|
85
80
|
}
|
|
86
81
|
/** 端点 deps 的注入面(ctx/cfg/stores/logger 由调用方绑定,其余由此处决定)。 */
|
|
87
82
|
export type EndpointDepsInput = Omit<EndpointDeps, 'ctx' | 'cfg' | 'stores' | 'logger'>;
|
|
@@ -97,25 +92,19 @@ export declare function registerMemoryRpc(ctx: Context, cfg: MemoryConfig, store
|
|
|
97
92
|
scenes: Record<MemoryFamily, SceneStore>;
|
|
98
93
|
persona: Record<MemoryFamily, PersonaStore>;
|
|
99
94
|
state: StateStore;
|
|
100
|
-
/** 召回使用统计(可选)。 */
|
|
101
|
-
usage?: RecallUsageStore;
|
|
102
95
|
/** 记忆后端(后台边界);未装配时回退为包 l1 的进程内实现。 */
|
|
103
96
|
backend?: MemoryBackend;
|
|
104
97
|
/** 图谱存储(可选:未装配时图谱端点返空,不报错)。 */
|
|
105
98
|
graph?: GraphStore;
|
|
106
99
|
}, logger: MemoryLogger, status?: MemoryStatusSource, live?: LiveSettingsHandle, modes?: SessionModeStore, dataDir?: string, rebuild?: RebuildController, embedManager?: EmbeddingManager, sessionInfo?: SessionInfoSource,
|
|
107
100
|
/** 反刍控制器(存储降级时为 undefined):经 buildEndpointDeps 落入 deps.ruminate。 */
|
|
108
|
-
ruminate?: RuminateController
|
|
109
|
-
/** Room 分类管理依赖(注册表;缺省 = rooms-get 不带 registry、rooms-export 恒 404 语义)。 */
|
|
110
|
-
roomRegistry?: RoomRegistryStore): void;
|
|
101
|
+
ruminate?: RuminateController): void;
|
|
111
102
|
export interface EndpointDeps {
|
|
112
103
|
ctx: Context;
|
|
113
104
|
cfg: MemoryConfig;
|
|
114
105
|
stores: {
|
|
115
106
|
l0: L0Store;
|
|
116
107
|
l1: L1Store;
|
|
117
|
-
/** 召回使用统计(可选:未装配 = 列表不带 usage/usageSummary)。 */
|
|
118
|
-
usage?: RecallUsageStore;
|
|
119
108
|
scenes: Record<MemoryFamily, SceneStore>;
|
|
120
109
|
persona: Record<MemoryFamily, PersonaStore>;
|
|
121
110
|
state: StateStore;
|
|
@@ -132,15 +121,10 @@ export interface EndpointDeps {
|
|
|
132
121
|
ruminate?: RuminateController;
|
|
133
122
|
embedManager?: EmbeddingManager;
|
|
134
123
|
sessionInfo?: SessionInfoSource;
|
|
135
|
-
/** 长任务端点依赖(未装配 = 端点恒 disabled,面板不挂载)。 */
|
|
136
|
-
/** Room 注册表(未装配 = rooms-get 不带 registry,rooms-export 不可用)。 */
|
|
137
|
-
roomRegistry?: RoomRegistryStore;
|
|
138
124
|
}
|
|
139
125
|
/** 端点分发表(导出供测试直调:可精确注入 rebuild/ruminate 等可选控制器,验证 deps 接线)。 */
|
|
140
126
|
export declare function handleEndpoint(endpoint: string, payload: unknown, deps: EndpointDeps): Promise<unknown>;
|
|
141
127
|
/** 浏览器卡片字段(比 MemoryRecord 精简,去掉大 metadata;Hall 从 metadata 提取)。 */
|
|
142
|
-
/** 老化权重(与读路径 applyDecayWeight 同式):max(0.5, 0.5^(Δ天/半衰期));半衰期 ≤0 = 关 → null。 */
|
|
143
|
-
export declare function agingWeightOf(updatedAtMs: number | undefined, halfLifeDays: number, now?: number): number | null;
|
|
144
128
|
export declare function hitToUiRecord(r: {
|
|
145
129
|
id: string;
|
|
146
130
|
content: string;
|
|
@@ -157,12 +141,4 @@ export declare function hitToUiRecord(r: {
|
|
|
157
141
|
family?: string;
|
|
158
142
|
/** 退场判据:`valid_to` 闭合即已退场(软删)。由 `listL1`/`getByIds` 透传。 */
|
|
159
143
|
validTo?: number;
|
|
160
|
-
}, extra?: {
|
|
161
|
-
agingWeight?: number | null;
|
|
162
|
-
usage?: {
|
|
163
|
-
attempts: number;
|
|
164
|
-
used: number;
|
|
165
|
-
lastAttemptAt: number | null;
|
|
166
|
-
lastUsedAt: number | null;
|
|
167
|
-
} | null;
|
|
168
144
|
}): UiRecord;
|