dsh-prime-memory 0.26.9 → 0.26.11
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.de.md +1638 -0
- package/CHANGELOG.en.md +15 -0
- package/CHANGELOG.es.md +1641 -0
- package/CHANGELOG.fr.md +1643 -0
- package/CHANGELOG.it.md +1643 -0
- package/CHANGELOG.ja.md +15 -0
- package/CHANGELOG.ko.md +15 -0
- package/CHANGELOG.md +62 -0
- package/CHANGELOG.ru.md +1640 -0
- package/README.de.md +1 -1
- package/README.en.md +3 -3
- package/README.es.md +1 -1
- package/README.fr.md +1 -1
- package/README.it.md +1 -1
- package/README.ja.md +1 -1
- package/README.ko.md +1 -1
- package/README.md +17 -4
- package/README.ru.md +1 -1
- package/dist/bench-control.js +3 -1
- package/dist/client.js +121 -12
- package/dist/clients/drsc.d.ts +34 -0
- package/dist/clients/drsc.js +56 -11
- package/dist/config.d.ts +10 -1
- package/dist/config.js +37 -18
- package/dist/contract.d.ts +48 -1
- package/dist/graph/gate.d.ts +17 -0
- package/dist/graph/gate.js +11 -0
- package/dist/graph/preview.d.ts +5 -0
- package/dist/graph/preview.js +2 -0
- package/dist/index.js +1 -1
- package/dist/pipeline/fact-source.d.ts +127 -0
- package/dist/pipeline/fact-source.js +192 -0
- package/dist/pipeline/rebuild-preserve.d.ts +31 -2
- package/dist/pipeline/rebuild-preserve.js +40 -14
- package/dist/pipeline/rebuild.d.ts +47 -13
- package/dist/pipeline/rebuild.js +153 -57
- package/dist/pipeline/runner.d.ts +4 -1
- package/dist/pipeline/runner.js +58 -21
- package/dist/pipeline/workspace-relink.js +7 -2
- package/dist/room-review.d.ts +1 -1
- package/dist/room-review.js +10 -5
- package/dist/settings.js +4 -0
- package/dist/stats.js +10 -3
- package/dist/store/graph-store.d.ts +20 -0
- package/dist/store/graph-store.js +50 -1
- package/dist/store/sqlite.d.ts +42 -0
- package/dist/store/sqlite.js +98 -0
- package/dist/tools/index.js +4 -3
- package/dsh.plugin.json +2 -2
- package/package.json +26 -21
package/README.de.md
CHANGED
|
@@ -61,7 +61,7 @@ alt="DeepSeek Harness Hero-Banner: Unterhaltungen werden automatisch zu mehrschi
|
|
|
61
61
|
> Kompatibilitätsmechanismus: Die Settings-Registrierung durchläuft zur Laufzeit drei Zweige
|
|
62
62
|
> (`register` → `installSection`-Brücke → Dauerein-Notbetrieb), siehe Eintrag 0.11.0 im
|
|
63
63
|
> [CHANGELOG.md](./CHANGELOG.md). `dsh.plugin.json` deklariert
|
|
64
|
-
> `engines.dsh` 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.
|
|
64
|
+
> `engines.dsh` 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.3,18 rc).
|
|
65
65
|
|
|
66
66
|
## Schnellstart
|
|
67
67
|
|
package/README.en.md
CHANGED
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
> Compatibility mechanism: settings registration uses a three-way runtime branch
|
|
62
62
|
> (`register` → `installSection` bridge → always-on degradation); see the 0.11.0 entry
|
|
63
63
|
> in [CHANGELOG.md](./CHANGELOG.md). `dsh.plugin.json` declares
|
|
64
|
-
> `engines.dsh` 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.
|
|
64
|
+
> `engines.dsh` 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.3,18 rc).
|
|
65
65
|
|
|
66
66
|
## Getting Started
|
|
67
67
|
|
|
@@ -565,9 +565,9 @@ directly ("zero source-less facts" invariant: every edge traces back to live L1
|
|
|
565
565
|
| Action | Tool | Preconditions | Notes |
|
|
566
566
|
| --- | --- | --- | --- |
|
|
567
567
|
| Revise one memory | `memory_update` | high-privilege mode | Read old → create new (`version+1`, new id) → old row retires via the shared soft-delete confluence with a `superseded` marker (restorable) → new version enters retrieval; then both [old, new] ids are force-reprojected so graph edges follow (edges supported only by the old source get tombstoned). Not a physical delete; the JSONL fact source is append-only and never rewritten |
|
|
568
|
-
| Force reprojection | `memory_reproject` | `graph.enabled` | Erases the "already projected at current version" receipts and re-enqueues at top priority, bypassing the permanent `projector_version` skip. Idempotent: in-flight jobs never pile up. **Manually added/imported memories that never showed up in the graph: this is the back-fill projection channel** (non-distilled writes now auto-enqueue; the tool remains the correction path for legacy rows and post-edit freshness) |
|
|
568
|
+
| Force reprojection | `memory_reproject` | Overview → Knowledge graph switch, or `graph.enabled` | Erases the "already projected at current version" receipts and re-enqueues at top priority, bypassing the permanent `projector_version` skip. Idempotent: in-flight jobs never pile up. **Manually added/imported memories that never showed up in the graph: this is the back-fill projection channel** (non-distilled writes now auto-enqueue; the tool remains the correction path for legacy rows and post-edit freshness) |
|
|
569
569
|
| Migrate one relation | `memory_migrate_relation` | high-privilege mode | Source-derived semantics: hard-validate that every `source_record_ids` is live and un-retired → the new relation lands through the deterministic projection branch (same (from, relation) with a new target closes the old edge) → a new L1 carrier record is written as the traceable basis (tagged `proposal_source=tool` plus a decision receipt). Old edges are not flipped back by later rejections: the reprojection batch pulls only the carrier, not sources whose text still describes the old relation |
|
|
570
|
-
| Non-distilled writes auto-enqueue | `memory_add` / `memory_import` | `graph.enabled` | After a successful write, records join the projection queue at the same priority as distillation output (`GRAPH_PRIORITY_NEW`) — the "only distillation projects" bypass is closed |
|
|
570
|
+
| Non-distilled writes auto-enqueue | `memory_add` / `memory_import` | Overview → Knowledge graph switch, or `graph.enabled` | After a successful write, records join the projection queue at the same priority as distillation output (`GRAPH_PRIORITY_NEW`) — the "only distillation projects" bypass is closed |
|
|
571
571
|
|
|
572
572
|
Two boundaries worth knowing:
|
|
573
573
|
|
package/README.es.md
CHANGED
|
@@ -61,7 +61,7 @@ alt="Banner hero de DeepSeek Harness: las conversaciones se destilan automática
|
|
|
61
61
|
> Mecanismo de compatibilidad: el registro de ajustes pasa en tiempo de ejecución por tres ramas
|
|
62
62
|
> (`register` → puente `installSection` → degradación a siempre activado),
|
|
63
63
|
> ver la entrada 0.11.0 del [CHANGELOG.md](./CHANGELOG.md). `dsh.plugin.json` declara
|
|
64
|
-
> `engines.dsh` 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.
|
|
64
|
+
> `engines.dsh` 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.3,18 rc).
|
|
65
65
|
|
|
66
66
|
## Inicio rápido
|
|
67
67
|
|
package/README.fr.md
CHANGED
|
@@ -61,7 +61,7 @@ alt="Bannière hero de DeepSeek Harness : les conversations sont automatiquement
|
|
|
61
61
|
> Mécanisme de compatibilité : l'enregistrement settings passe par trois branches à l'exécution
|
|
62
62
|
> (`register` → pont `installSection` → dégradation en mode toujours actif),
|
|
63
63
|
> voir l'entrée 0.11.0 du [CHANGELOG.md](./CHANGELOG.md). `dsh.plugin.json` déclare
|
|
64
|
-
> `engines.dsh` 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.
|
|
64
|
+
> `engines.dsh` 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.3,18 rc).
|
|
65
65
|
|
|
66
66
|
## Démarrage rapide
|
|
67
67
|
|
package/README.it.md
CHANGED
|
@@ -61,7 +61,7 @@ alt="Banner hero di DeepSeek Harness: le conversazioni vengono distillate automa
|
|
|
61
61
|
> Meccanismo di compatibilità: la registrazione delle impostazioni passa per tre rami a runtime
|
|
62
62
|
> (`register` → ponte `installSection` → degrado a sempre-attivo),
|
|
63
63
|
> vedi la voce 0.11.0 del [CHANGELOG.md](./CHANGELOG.md). `dsh.plugin.json` dichiara
|
|
64
|
-
> `engines.dsh` 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.
|
|
64
|
+
> `engines.dsh` 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.3,18 rc).
|
|
65
65
|
|
|
66
66
|
## Avvio rapido
|
|
67
67
|
|
package/README.ja.md
CHANGED
|
@@ -62,7 +62,7 @@ alt="DeepSeek Harness ヒーロー画像:会話がバックグラウンドで
|
|
|
62
62
|
|
|
63
63
|
> 互換メカニズム:settings 登録は 3 分岐のランタイム判定(`register` → `installSection` ブリッジ → 常時オン縮退)。
|
|
64
64
|
> 詳細は [CHANGELOG.md](./CHANGELOG.md) の 0.11.0 エントリ参照。`dsh.plugin.json` は
|
|
65
|
-
> `engines.dsh` 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.
|
|
65
|
+
> `engines.dsh` 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.3,18 rc) を宣言。
|
|
66
66
|
|
|
67
67
|
## クイックスタート
|
|
68
68
|
|
package/README.ko.md
CHANGED
|
@@ -62,7 +62,7 @@ alt="DeepSeek Harness 히어로 이미지: 대화가 백그라운드에서 계
|
|
|
62
62
|
|
|
63
63
|
> 호환 메커니즘: settings 등록은 3분기 런타임 분기(`register` → `installSection` 브리지 → 상시 온 강등).
|
|
64
64
|
> 자세한 내용은 [CHANGELOG.md](./CHANGELOG.md)의 0.11.0 항목 참조. `dsh.plugin.json`은
|
|
65
|
-
> `engines.dsh` 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.
|
|
65
|
+
> `engines.dsh` 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.3,18 rc) 선언.
|
|
66
66
|
|
|
67
67
|
## 빠른 시작
|
|
68
68
|
|
package/README.md
CHANGED
|
@@ -60,7 +60,7 @@ alt="DeepSeek Harness hero 横幅:对话自动分层蒸馏成记忆,模型
|
|
|
60
60
|
|
|
61
61
|
> 兼容机制:settings 注册走运行时三分支(`register` → `installSection` 桥接 → 恒开降级),
|
|
62
62
|
> 详见 [CHANGELOG.md](./CHANGELOG.md) 的 0.11.0 条目。`dsh.plugin.json` 声明
|
|
63
|
-
> `engines.dsh` 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.
|
|
63
|
+
> `engines.dsh` 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.3,18 rc)。
|
|
64
64
|
|
|
65
65
|
## 快速开始
|
|
66
66
|
|
|
@@ -353,7 +353,12 @@ ONNX 量化 **CPU 推理**——无需 API Key,数据不出本机)。本地
|
|
|
353
353
|
| `llm.reasoningEffort` | 空 | 蒸馏思考档位:空串 = **自动**(按模型能力解析:模型默认档 → `high`);显式值(`off`/`none`/`minimal`/`low`/`medium`/`high`/`xhigh`/`max`)仅在该模型声明支持时发送——跨供应商 effort 词汇表不同(deepseek 认 `off`,OpenAI 系是 `none`,未声明档位的模型不传),不支持的档位自动降级为不传并告警一次;思考档 high/xhigh/max 时输出预算自动 ×4。运行时可在设置页路由链编辑器里**逐路由**覆盖档位(行内下拉,词表按各模型声明的能力实时显示,缺省跟随本值) |
|
|
354
354
|
| `llm.temperature` | `0.3` | 蒸馏温度 |
|
|
355
355
|
| `llm.maxInputChars` | `200000` | 单次蒸馏调用输入闸门(超限截断);默认 200k 适配本地/免费模型窗口,上限 256k,可再往下调。L1 抽取/L2 另有 24k 分块硬顶,不受此值影响;运行时可在设置页 → 蒸馏参数 → 输入预算调整(留空/0 = 跟随本值) |
|
|
356
|
-
| `llm.timeoutMs` | `120000` | 单次蒸馏调用超时(ms
|
|
356
|
+
| `llm.timeoutMs` | `120000` | 单次蒸馏调用超时(ms);运行时可在设置页 → 蒸馏参数 → 蒸馏超时(ms) 覆盖(仅治"慢但未被网关掐"的路由,供应商网关侧固定掐断抬此值无效) |
|
|
357
|
+
| `llm.extractTimeBudgetMs` | `0` | 整轮抽取墙钟预算(ms):`0` = 不限(旧行为);`>0` 时多块抽取累计超此预算即把剩余块留待重试、下轮续跑,防一个慢模型独占后台串行泵([ADR-0023](./docs/adr/0023-distill-load-balance-and-secondary-route.md)) |
|
|
358
|
+
| `llm.modelMaxInputChars` | `0` | 蒸馏模型真实输入上限(字符):`0` = 未声明(回退保守口径 `min(24k, maxInputChars−42k)`);声明后抽取/L2 块大小取 `min(24k, 本值−42k)`,避免默认值撞本地模型硬限 |
|
|
359
|
+
| `llm.secondary` | 关 | 二线大容量兜底 `{provider,model,reasoningEffort,triggerChars}`:单次调用输入 ≥ `triggerChars`(默认 20000)才前置二线(肥调用走能吞大输入的二线、小调用走一线);未配则不启用、绝不静默改选任意模型 |
|
|
360
|
+
| `llm.requireExplicitRoute` | `false` | 显式路由闸(灰度):`true` 时一线+二线+回退链皆空 → 蒸馏顺延并告警(`NoDistillRouteError`、不记退避),不再蹭宿主默认模型;`false` 保持旧行为 |
|
|
361
|
+
| `llm.chunkShrink*` 等(预留) | — | ⚠ `llm.chunkShrinkFactor` / `chunkShrinkMaxSteps` / `adaptiveChunk` 为**预留配置,当前版本未接线生效**(同轮内超时 ×0.6 缩块尚未实现)——设了不影响行为,请勿依赖 |
|
|
357
362
|
| `tokenCost.retentionDays` | `365` | 蒸馏成本明细(token\_cost 表)保留天数,写入时滚动清理更早行;`0` = 永久保留。成本看板「近 N 天」窗口上限同此值 |
|
|
358
363
|
| `tools` | `true` | 是否注册模型可调用的记忆工具 |
|
|
359
364
|
| `benchControl` | `false` | 注册 bench 控制服务(进程内 rebuild 触发/会话档位设置/蒸馏用量快照,供基准 lifecycle 赛道)。默认关——生产部署零表面积,勿随意开启 |
|
|
@@ -421,6 +426,7 @@ ONNX 量化 **CPU 推理**——无需 API Key,数据不出本机)。本地
|
|
|
421
426
|
- **二线模型(大容量兜底)**:`llm.secondary{provider,model,triggerChars}`——单次调用输入 ≥ `triggerChars` 才走二线(小调用走便宜快的一线、肥调用走能吞大输入的二线)。未配则不启用、绝不静默改选任意模型。
|
|
422
427
|
- **分块分载与容错**:L1 抽取 / L2 场景整合按字符预算分块,单块超时/崩只丢该块、留待重试,不再"一块崩整批丢"(待重试不再被整片回滚)。`llm.extractTimeBudgetMs`(默认 0=不限)可给整轮抽取设墙钟预算,防一个慢模型独占后台;`llm.modelMaxInputChars` 声明模型真实输入上限,块大小据此收紧。
|
|
423
428
|
- **显式路由(灰度)**:`llm.requireExplicitRoute=true` 时,未显式配一线/二线/回退链 → 蒸馏顺延并告警,不再蹭宿主默认模型(默认 false 保持旧行为)。
|
|
429
|
+
- **预留未生效的配置**:`llm.chunkShrinkFactor` / `llm.chunkShrinkMaxSteps` / `llm.adaptiveChunk` 已在 schema 声明但**尚未接线**(同轮内超时自动缩块未实现)——设了不影响行为;跨轮自适应已由 R9 路由健康学习承担。
|
|
424
430
|
|
|
425
431
|
## 日志与故障排查
|
|
426
432
|
|
|
@@ -430,6 +436,13 @@ dsh 宿主把插件日志打到控制台;插件另把 info 级以上镜像到
|
|
|
430
436
|
前 400 字符;所有失败告警带堆栈首帧。JSONL 事实源按轮次追加、依赖操作系统写回(不做逐条
|
|
431
437
|
fsync),断电等极端崩溃最多丢最后一小段尾部,检索库可用「重建记忆」从事实源全量重导。
|
|
432
438
|
|
|
439
|
+
> **重建的事实源边界(0.26.11 起要说清楚)**:重建只能重蒸**事实源覆盖到的那一刻之前**的记忆。L0 正文自 T8.4 起已停写(历史面由 DRSC 供给),所以水位之后新增的记忆**不会被重新蒸馏**——它们会被**原样保留**(保留理由 `post-watermark`:来源消息不在本次快照内),不会丢。确认弹窗会直接写出「事实源覆盖到 X」与「可重造 N 条 / 原样保留 M 条」;若晚于水位的记录超过一半,启动需要二次确认(`force`)——这是**提示**而非永久拒绝(否则停写的库上重建会被永久锁死)。
|
|
440
|
+
|
|
441
|
+
> **重建的事实源可切换(`rebuild.factSource`,默认 `local`)**:
|
|
442
|
+
> - `local`:本地 `l0_conversations`(已停写的冻结存量),**按会话流式读**——峰值只占单会话,不再把全量正文(3 万条量级约 88MB)驻留整个重建期;
|
|
443
|
+
> - `drsc`(实验性):`reference-session-collector` 的投影——先枚举会话、再逐会话拉全量,**恒带 `redact=1`**(collector 的 `session` 缺省是原文臂,而捕获侧是写前脱敏)。选了 drsc 但 collector 未装配会**显式报错中止**,不静默回退本地表。
|
|
444
|
+
> - 注意:DRSC 无法枚举消息 id(`drsc:<sid>:<seq>` 与事实源的 `source_message_ids` 不同域),所以 `drsc` 模式下所有有来源的记忆都会被判为**不可重蒸并原样保留**(保守侧失败,不丢数据)。
|
|
445
|
+
|
|
433
446
|
## 与 MemoryCore 的差异
|
|
434
447
|
|
|
435
448
|
- 内嵌完整管线(不依赖外部 Gateway),蒸馏复用 DSH 自己的 LLM;
|
|
@@ -507,9 +520,9 @@ fsync),断电等极端崩溃最多丢最后一小段尾部,检索库可用
|
|
|
507
520
|
| 动作 | 工具 | 前提 | 说明 |
|
|
508
521
|
| --- | --- | --- | --- |
|
|
509
522
|
| 修订一条记忆 | `memory_update` | 高权限模式 | 读旧 → 造新(`version+1`,新 id)→ 旧行经退场汇流口 `superseded` 软删(可恢复)→ 新版进检索面;随后对 [旧,新] 强制重投,图谱边跟随(旧源支撑的边自动标墓碑)。不是物理删,也不覆写 JSONL 事实源 |
|
|
510
|
-
| 强制重投 | `memory_reproject` |
|
|
523
|
+
| 强制重投 | `memory_reproject` | 概览「知识图谱」开关 或 部署 `graph.enabled` | 抹掉"已按当前版本投影"凭证、按高优先级重新入队——绕开 `projector_version` 的永久跳过。幂等:在途任务不堆重。**手加/导入的记忆长期不出现在图谱里,用它补投影**(非蒸馏写入现已自动入队,此工具是给存量与改后保鲜的纠正通道) |
|
|
511
524
|
| 迁移一条关系 | `memory_migrate_relation` | 高权限模式 | 源导语义:先硬校验 `source_record_ids` 全部"现存未退场" → 新关系经确定性投影支路落库(同 (起点,关系) 换目标自动闭旧边出新边)→ 新增一条承载新关系的 L1 源记录留可回溯根据(带 `proposal_source=tool` 审计标记与决策凭证)。旧边不会因后续重投被翻回:重投批只拉载体记录,不拉描述旧关系的旧源 |
|
|
512
|
-
| 非蒸馏写入自动入队 | `memory_add` / `memory_import` |
|
|
525
|
+
| 非蒸馏写入自动入队 | `memory_add` / `memory_import` | 概览「知识图谱」开关 或 部署 `graph.enabled` | 落库成功后与蒸馏产出同优先级(`GRAPH_PRIORITY_NEW`)进投影队——"只有蒸馏才投影"的旁路缺口已闭合 |
|
|
513
526
|
|
|
514
527
|
两条必须知道的边界:
|
|
515
528
|
|
package/README.ru.md
CHANGED
|
@@ -61,7 +61,7 @@ alt="Баннер hero DeepSeek Harness: диалоги автоматическ
|
|
|
61
61
|
> Механизм совместимости: регистрация настроек на этапе исполнения идёт по трём ветвям
|
|
62
62
|
> (`register` → мост `installSection` → деградация в режим «всегда включено»),
|
|
63
63
|
> подробнее — запись 0.11.0 в [CHANGELOG.md](./CHANGELOG.md). `dsh.plugin.json` объявляет
|
|
64
|
-
> `engines.dsh` 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.
|
|
64
|
+
> `engines.dsh` 为逐 rc 精确枚举串(0.1.0-rc.2 → 0.2.1-rc.3,18 rc).
|
|
65
65
|
|
|
66
66
|
## Быстрый старт
|
|
67
67
|
|
package/dist/bench-control.js
CHANGED
|
@@ -4,7 +4,9 @@ export const BENCH_CONTROL_SERVICE = 'dsh-memory-bench';
|
|
|
4
4
|
/** 注册控制服务,返回注销函数(调用方在插件 dispose 时执行)。 */
|
|
5
5
|
export function registerBenchControl(ctx, rebuild, modes, logger) {
|
|
6
6
|
const surface = {
|
|
7
|
-
|
|
7
|
+
// bench 场景自带可控数据集,需要确定性重建:水位落差的“二次确认”
|
|
8
|
+
// 属于人机交互护栏,不该阻断自动化赛道,故显式 force。
|
|
9
|
+
rebuildStart: () => rebuild.start(true),
|
|
8
10
|
rebuildStatus: () => rebuild.getStatus(),
|
|
9
11
|
setSessionMode: (sessionId, mode) => modes.set(sessionId, mode),
|
|
10
12
|
getSessionMode: (sessionId) => modes.get(sessionId),
|
package/dist/client.js
CHANGED
|
@@ -49,9 +49,9 @@ var __create = Object.create;
|
|
|
49
49
|
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
|
|
50
50
|
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
|
51
51
|
|
|
52
|
-
// node_modules/@antv/g6/dist/g6.min.js
|
|
52
|
+
// node_modules/.pnpm/@antv+g6@5.1.1/node_modules/@antv/g6/dist/g6.min.js
|
|
53
53
|
var require_g6_min = __commonJS({
|
|
54
|
-
"node_modules/@antv/g6/dist/g6.min.js"(exports, module2) {
|
|
54
|
+
"node_modules/.pnpm/@antv+g6@5.1.1/node_modules/@antv/g6/dist/g6.min.js"(exports, module2) {
|
|
55
55
|
!(function(t, e) {
|
|
56
56
|
"object" == typeof exports && "undefined" != typeof module2 ? e(exports) : "function" == typeof define && define.amd ? define(["exports"], e) : e((t = "undefined" != typeof globalThis ? globalThis : t || self).G6 = {});
|
|
57
57
|
})(exports, function(t) {
|
|
@@ -37508,6 +37508,17 @@ var __create = Object.create;
|
|
|
37508
37508
|
return "关闭";
|
|
37509
37509
|
}
|
|
37510
37510
|
|
|
37511
|
+
// client/src/copy.ts
|
|
37512
|
+
var GRAPH_FEATURE_LABEL = "知识图谱";
|
|
37513
|
+
var GRAPH_TOOL_LABEL = "图谱读工具";
|
|
37514
|
+
var GRAPH_BUDGET_LABEL = "图谱投影预算";
|
|
37515
|
+
function graphEnableHint() {
|
|
37516
|
+
return `在设置页「概览 → ${GRAPH_FEATURE_LABEL}」打开开关后,存量记忆会逐批投影成实体与关系。`;
|
|
37517
|
+
}
|
|
37518
|
+
function graphSwitchDesc(on) {
|
|
37519
|
+
return on ? "已开启:L1 记忆会投影成实体与关系,存量在启动/开启后逐批补齐(可与「图谱读工具」独立开关)" : "默认关闭:开启后才会生成知识图谱;这一步会逐条走 LLM,首次开启前会先给出预计耗时";
|
|
37520
|
+
}
|
|
37521
|
+
|
|
37511
37522
|
// client/src/tabs/ArchiveSection.tsx
|
|
37512
37523
|
var import_react7 = require("react");
|
|
37513
37524
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
@@ -37788,7 +37799,9 @@ var __create = Object.create;
|
|
|
37788
37799
|
["dedup", "去重"],
|
|
37789
37800
|
["l2", "L2 场景"],
|
|
37790
37801
|
["l3", "L3 画像"],
|
|
37791
|
-
|
|
37802
|
+
// 这不是“投影开关”,是投影这一步的**输出预算**(issue #16:旧标签就叫“图谱投影”,
|
|
37803
|
+
// 与概览页那个功能开关撞名,用户点了以为开了投影,实际只是改了 token 预算)。
|
|
37804
|
+
["graph", GRAPH_BUDGET_LABEL]
|
|
37792
37805
|
];
|
|
37793
37806
|
var SCOPE_KEYS = {
|
|
37794
37807
|
l1: ["extract", "dedup"],
|
|
@@ -39314,6 +39327,7 @@ var __create = Object.create;
|
|
|
39314
39327
|
const [confirmOpen, setConfirmOpen] = (0, import_react14.useState)(false);
|
|
39315
39328
|
const [busy, setBusy] = (0, import_react14.useState)(false);
|
|
39316
39329
|
const [rbError, setRbError] = (0, import_react14.useState)(null);
|
|
39330
|
+
const [canForce, setCanForce] = (0, import_react14.useState)(false);
|
|
39317
39331
|
const refresh = (0, import_react14.useCallback)(() => {
|
|
39318
39332
|
rpc("dsh-memory/rebuild-status", {}).then((r) => {
|
|
39319
39333
|
if (r && r.ok) setRb(r.value);
|
|
@@ -39334,20 +39348,25 @@ var __create = Object.create;
|
|
|
39334
39348
|
if (!rbRaw || rbRaw.supported === false) return null;
|
|
39335
39349
|
const rb = rbRaw;
|
|
39336
39350
|
ensureThemeStyle();
|
|
39337
|
-
const start = () => {
|
|
39351
|
+
const start = (force = false) => {
|
|
39338
39352
|
setBusy(true);
|
|
39339
39353
|
setRbError(null);
|
|
39340
|
-
|
|
39354
|
+
setCanForce(false);
|
|
39355
|
+
rpc("dsh-memory/rebuild-start", force ? { force: true } : {}).then((r) => {
|
|
39341
39356
|
setBusy(false);
|
|
39342
39357
|
if (r && r.ok) {
|
|
39343
39358
|
setConfirmOpen(false);
|
|
39344
39359
|
setRb(r.value);
|
|
39345
39360
|
} else {
|
|
39346
|
-
|
|
39361
|
+
const msg = r && r.error ? r.error.message : "启动失败";
|
|
39362
|
+
setRbError(msg);
|
|
39363
|
+
setCanForce(/force/.test(msg));
|
|
39347
39364
|
}
|
|
39348
39365
|
}).catch((e) => {
|
|
39349
39366
|
setBusy(false);
|
|
39350
|
-
|
|
39367
|
+
const msg = String(e && e.message || e);
|
|
39368
|
+
setRbError(msg);
|
|
39369
|
+
setCanForce(/force/.test(msg));
|
|
39351
39370
|
});
|
|
39352
39371
|
};
|
|
39353
39372
|
const cancel = () => {
|
|
@@ -39391,7 +39410,13 @@ var __create = Object.create;
|
|
|
39391
39410
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "dsh-mem-rb-muted", style: { whiteSpace: "nowrap" }, children: "产出 " + rb.recordsBuilt + " 条" })
|
|
39392
39411
|
] }) : null,
|
|
39393
39412
|
lastNote ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 8 }, children: lastNote }) : null,
|
|
39394
|
-
|
|
39413
|
+
rb.rederivableCount !== null || rb.preserveCount !== null ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 6 }, children: "本次计划:可重造 " + (rb.rederivableCount ?? 0) + " 条 · 原样保留 " + (rb.preserveCount ?? 0) + " 条(无来源或来源不在本次快照)" }) : null,
|
|
39414
|
+
rbError ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { marginTop: 8, fontSize: 12, color: "var(--dsh-mem-danger)" }, children: [
|
|
39415
|
+
rbError,
|
|
39416
|
+
canForce ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { marginTop: 6 }, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(NButton, { disabled: busy, onClick: () => {
|
|
39417
|
+
start(true);
|
|
39418
|
+
}, children: busy ? "启动中…" : "我已了解,仍要继续(不重蒸水位后的记录)" }) }) : null
|
|
39419
|
+
] }) : null,
|
|
39395
39420
|
confirmOpen ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
39396
39421
|
NModal,
|
|
39397
39422
|
{
|
|
@@ -39411,7 +39436,9 @@ var __create = Object.create;
|
|
|
39411
39436
|
},
|
|
39412
39437
|
"cancel"
|
|
39413
39438
|
),
|
|
39414
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(NButton, { variant: "primary", disabled: busy, onClick:
|
|
39439
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(NButton, { variant: "primary", disabled: busy, onClick: () => {
|
|
39440
|
+
start();
|
|
39441
|
+
}, children: busy ? "启动中…" : "开始重建" }, "confirm")
|
|
39415
39442
|
],
|
|
39416
39443
|
children: [
|
|
39417
39444
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { children: [
|
|
@@ -39419,6 +39446,11 @@ var __create = Object.create;
|
|
|
39419
39446
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("b", { children: rb.sessionCount + " 个会话 · " + rb.messageCount + " 条消息" }),
|
|
39420
39447
|
",预计 ≥" + rb.estCalls + " 次蒸馏调用。"
|
|
39421
39448
|
] }),
|
|
39449
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { marginTop: 8 }, children: [
|
|
39450
|
+
"事实源覆盖到:",
|
|
39451
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("b", { children: rb.factWatermark ? fmtTime(rb.factWatermark) : "无(本地 L0 没有任何正文)" }),
|
|
39452
|
+
rb.factWatermark ? ";晚于此时刻的记忆会被原样保留、不重新蒸馏(不会丢)。" : "。"
|
|
39453
|
+
] }),
|
|
39422
39454
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { marginTop: 8 }, children: "现有 L1 记忆 / L2 场景 / L3 画像会整体归档(*.bak.时间戳,可手工找回),随后清空重建;重建期间可正常对话,新对话的蒸馏优先进行;中途可取消,已重建部分保留。" })
|
|
39423
39455
|
]
|
|
39424
39456
|
}
|
|
@@ -39929,6 +39961,7 @@ var __create = Object.create;
|
|
|
39929
39961
|
const [stats, setStats] = (0, import_react17.useState)(null);
|
|
39930
39962
|
const [settingsData, setSettingsData] = (0, import_react17.useState)(null);
|
|
39931
39963
|
const [error, setError] = (0, import_react17.useState)(null);
|
|
39964
|
+
const [graphConfirm, setGraphConfirm] = (0, import_react17.useState)(null);
|
|
39932
39965
|
const load = (0, import_react17.useCallback)(() => {
|
|
39933
39966
|
rpc("dsh-memory/stats", {}).then((r) => {
|
|
39934
39967
|
if (r && r.ok) setStats(r.value);
|
|
@@ -39966,6 +39999,14 @@ var __create = Object.create;
|
|
|
39966
39999
|
setError("开关写入失败:" + String(e && e.message || e));
|
|
39967
40000
|
});
|
|
39968
40001
|
};
|
|
40002
|
+
const requestGraphOn = () => {
|
|
40003
|
+
rpc("dsh-memory/graph-preview", {}).then((r) => {
|
|
40004
|
+
const missing = r && r.ok ? r.value.stats?.missing ?? 0 : 0;
|
|
40005
|
+
setGraphConfirm({ missing });
|
|
40006
|
+
}).catch(() => {
|
|
40007
|
+
setGraphConfirm({ missing: 0 });
|
|
40008
|
+
});
|
|
40009
|
+
};
|
|
39969
40010
|
const setNum = (key, value) => {
|
|
39970
40011
|
if (!settingsData) return;
|
|
39971
40012
|
const prev = settingsData;
|
|
@@ -40021,6 +40062,7 @@ var __create = Object.create;
|
|
|
40021
40062
|
const toolMutate = settingsData && settingsData.settings ? settingsData.settings.toolMutate !== false : true;
|
|
40022
40063
|
const toolSkills = settingsData && settingsData.settings ? settingsData.settings.toolSkills !== false : true;
|
|
40023
40064
|
const skillsEnabled = settingsData && settingsData.settings ? settingsData.settings.skillsEnabled === true : false;
|
|
40065
|
+
const graphEnabled = settingsData && settingsData.settings ? settingsData.settings.graphEnabled === true : false;
|
|
40024
40066
|
const keywordEnabled = settingsData && settingsData.settings ? settingsData.settings.keywordEnabled === true : false;
|
|
40025
40067
|
const redistillEnabled = settingsData && settingsData.settings ? settingsData.settings.redistillEnabled === true : false;
|
|
40026
40068
|
const mdSyncEnabled = settingsData && settingsData.settings ? settingsData.settings.mdSyncEnabled === true : false;
|
|
@@ -40100,6 +40142,23 @@ var __create = Object.create;
|
|
|
40100
40142
|
}
|
|
40101
40143
|
}
|
|
40102
40144
|
),
|
|
40145
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.panelLabel, children: GRAPH_FEATURE_LABEL }),
|
|
40146
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
40147
|
+
SwitchRow,
|
|
40148
|
+
{
|
|
40149
|
+
label: `${GRAPH_FEATURE_LABEL}投影`,
|
|
40150
|
+
desc: graphSwitchDesc(graphEnabled),
|
|
40151
|
+
checked: graphEnabled,
|
|
40152
|
+
disabled: !master,
|
|
40153
|
+
onChange: (v) => {
|
|
40154
|
+
if (v) {
|
|
40155
|
+
requestGraphOn();
|
|
40156
|
+
} else {
|
|
40157
|
+
toggle("graphEnabled", false);
|
|
40158
|
+
}
|
|
40159
|
+
}
|
|
40160
|
+
}
|
|
40161
|
+
),
|
|
40103
40162
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.panelLabel, children: "工具封印" }),
|
|
40104
40163
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
40105
40164
|
SwitchRow,
|
|
@@ -40115,7 +40174,7 @@ var __create = Object.create;
|
|
|
40115
40174
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
40116
40175
|
SwitchRow,
|
|
40117
40176
|
{
|
|
40118
|
-
label:
|
|
40177
|
+
label: GRAPH_TOOL_LABEL,
|
|
40119
40178
|
desc: toolGraph ? "已注册:memory_search_graph / memory_expand_graph_node" : "已封印:图谱读工具从模型工具列表移除",
|
|
40120
40179
|
checked: toolGraph,
|
|
40121
40180
|
onChange: (v) => {
|
|
@@ -40271,7 +40330,53 @@ var __create = Object.create;
|
|
|
40271
40330
|
})
|
|
40272
40331
|
] }),
|
|
40273
40332
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ArchiveSection, { rpc }),
|
|
40274
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { style: S.hint, children: "浏览各层记忆内容请切换上方 Tab;原始对话(L0)不入浏览器,可由模型侧 conversation_search 工具查询。" })
|
|
40333
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { style: S.hint, children: "浏览各层记忆内容请切换上方 Tab;原始对话(L0)不入浏览器,可由模型侧 conversation_search 工具查询。" }),
|
|
40334
|
+
graphConfirm ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
40335
|
+
NModal,
|
|
40336
|
+
{
|
|
40337
|
+
open: true,
|
|
40338
|
+
onClose: () => {
|
|
40339
|
+
setGraphConfirm(null);
|
|
40340
|
+
},
|
|
40341
|
+
title: `开启${GRAPH_FEATURE_LABEL}投影?`,
|
|
40342
|
+
footer: [
|
|
40343
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
40344
|
+
NButton,
|
|
40345
|
+
{
|
|
40346
|
+
onClick: () => {
|
|
40347
|
+
setGraphConfirm(null);
|
|
40348
|
+
},
|
|
40349
|
+
children: "取消"
|
|
40350
|
+
},
|
|
40351
|
+
"cancel"
|
|
40352
|
+
),
|
|
40353
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
40354
|
+
NButton,
|
|
40355
|
+
{
|
|
40356
|
+
variant: "primary",
|
|
40357
|
+
onClick: () => {
|
|
40358
|
+
setGraphConfirm(null);
|
|
40359
|
+
toggle("graphEnabled", true);
|
|
40360
|
+
},
|
|
40361
|
+
children: "开启"
|
|
40362
|
+
},
|
|
40363
|
+
"confirm"
|
|
40364
|
+
)
|
|
40365
|
+
],
|
|
40366
|
+
children: [
|
|
40367
|
+
graphConfirm.missing > 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { children: [
|
|
40368
|
+
"待投影记忆 ",
|
|
40369
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("b", { children: graphConfirm.missing }),
|
|
40370
|
+
" 条,按每批 8 条约 ",
|
|
40371
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("b", { children: Math.ceil(graphConfirm.missing / 8) }),
|
|
40372
|
+
" 个作业;每个作业一次 LLM 抽取(单批约 2 分钟),预计总计 ",
|
|
40373
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("b", { children: Math.max(1, Math.round(Math.ceil(graphConfirm.missing / 8) * 2 / 60)) }),
|
|
40374
|
+
" 小时量级。"
|
|
40375
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { children: "当前没有待投影的记忆,开启后新蒸馏的记忆会陆续进图。" }),
|
|
40376
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: { marginTop: 8 }, children: "投影在后台串行跑,不会阻断对话(新蒸馏的记录优先级恒高于存量补投影);进度可在「图谱」页看,随时可关开关停下来。" })
|
|
40377
|
+
]
|
|
40378
|
+
}
|
|
40379
|
+
) : null
|
|
40275
40380
|
] });
|
|
40276
40381
|
}
|
|
40277
40382
|
|
|
@@ -42711,7 +42816,11 @@ var __create = Object.create;
|
|
|
42711
42816
|
" ",
|
|
42712
42817
|
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(NButton, { onClick: loadBoard, children: "重试" })
|
|
42713
42818
|
] }) : null,
|
|
42714
|
-
stats && stats.nodes === 0 && !error ? /* @__PURE__ */ (0, import_jsx_runtime23.
|
|
42819
|
+
stats && stats.nodes === 0 && !error ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("p", { style: S.intro, children: [
|
|
42820
|
+
"图谱还没有内容。",
|
|
42821
|
+
graphEnableHint(),
|
|
42822
|
+
`(注意:这里指的是「${GRAPH_FEATURE_LABEL}」开关,不是「${GRAPH_TOOL_LABEL}」——后者只管模型能不能读图)`
|
|
42823
|
+
] }) : null,
|
|
42715
42824
|
board && board.seeds.length > 1 && view === "full" ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { style: { ...S.flexRow, marginBottom: 8, flexWrap: "wrap", gap: 6 }, children: board.seeds.map((s) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
42716
42825
|
"button",
|
|
42717
42826
|
{
|
package/dist/clients/drsc.d.ts
CHANGED
|
@@ -8,6 +8,10 @@
|
|
|
8
8
|
* - 工具面 conversation_search → `op=search&redact=1`(命中基于原文 fts,
|
|
9
9
|
* 返回 snippet 取脱敏锚定文本)。
|
|
10
10
|
*
|
|
11
|
+
* 加上 issue #14-B 的**重建事实源**:`op=sessions` 枚举 + `op=session`(**不带 tail**)
|
|
12
|
+
* 逐会话拉全量——对全量重建来说“尾窗”不够用,而 collector 侧不带 tail 即 `ORDER BY seq ASC`
|
|
13
|
+
* 无 LIMIT。此路径同样恒带 `redact=1`。
|
|
14
|
+
*
|
|
11
15
|
* 硬依赖纪律(对齐 T7.3 裁定):collector 缺席/超时/非 2xx/ok=false 一律抛
|
|
12
16
|
* {@link DrscClientError}——**绝不回退本地 l0**(表已退役,无退路);调用方
|
|
13
17
|
* 分口径处理:蒸馏背景窗空窗降级(runner),工具面显式报错(tools)。
|
|
@@ -55,6 +59,16 @@ export interface DrscSearchHit {
|
|
|
55
59
|
on_surface: number;
|
|
56
60
|
turn: number;
|
|
57
61
|
}
|
|
62
|
+
/** `op=sessions` 的一个会话摘要行(分页枚举用;wire 蛇形直取)。 */
|
|
63
|
+
export interface DrscSessionSummary {
|
|
64
|
+
session_id: string;
|
|
65
|
+
title: string;
|
|
66
|
+
cwd: string;
|
|
67
|
+
event_count: number;
|
|
68
|
+
turn_count: number;
|
|
69
|
+
/** 末条消息时间(ms)—— collector 按它降序排,客户端用时注意反转。 */
|
|
70
|
+
last_time_ms: number;
|
|
71
|
+
}
|
|
58
72
|
/** kind → L0 角色词表(memory 只收 user/assistant 两类,其余(tool/* 等)不映射)。 */
|
|
59
73
|
export declare function drscRoleOf(kind: string): 'user' | 'assistant' | undefined;
|
|
60
74
|
/**
|
|
@@ -88,6 +102,26 @@ export declare class DrscClient {
|
|
|
88
102
|
* collector 无此会话(session:null)返回空数组(新会话首轮的常态,非错误)。
|
|
89
103
|
*/
|
|
90
104
|
sessionTail(sessionId: string, tail: number): Promise<DrscSessionRow[]>;
|
|
105
|
+
/**
|
|
106
|
+
* **整会话**正文(issue #14-B 重建事实源):`op=session&session=<id>&redact=1`,
|
|
107
|
+
* **不带 `tail`** —— collector 侧 `tail` 未给时走 `ORDER BY s.seq ASC` 无 LIMIT,即全量。
|
|
108
|
+
*
|
|
109
|
+
* `redact=1` 是**硬要求**,不是可选项:collector 的 `session` 缺省是原文臂,
|
|
110
|
+
* 而 memory 捕获侧是写前单点脱敏;重建若走原文臂,产出的 L1 会比正常蒸馏「更脏」,
|
|
111
|
+
* 而且会经 md 投射落盘。
|
|
112
|
+
*/
|
|
113
|
+
sessionAll(sessionId: string): Promise<DrscSessionRow[]>;
|
|
114
|
+
/**
|
|
115
|
+
* 会话枚举:`op=sessions&offset&limit`(collector 侧 limit 钳到 1..500)。
|
|
116
|
+
*
|
|
117
|
+
* 重建的事实源没有“全量导出”单口(也不应该有:一个响应装不下几万条正文),
|
|
118
|
+
* 所以走「枚举会话 → 逐会话拉全量」的 N+1 组合。采集端分页是 0-SQL 的内存切片,
|
|
119
|
+
* 代价仅在于请求数。
|
|
120
|
+
*/
|
|
121
|
+
listSessions(offset: number, limit: number): Promise<{
|
|
122
|
+
total: number;
|
|
123
|
+
rows: DrscSessionSummary[];
|
|
124
|
+
}>;
|
|
91
125
|
/** 原史检索:`op=search&q=<query>&limit=N&redact=1` → 脱敏 snippet 命中。 */
|
|
92
126
|
search(query: string, limit: number): Promise<DrscSearchHit[]>;
|
|
93
127
|
}
|
package/dist/clients/drsc.js
CHANGED
|
@@ -51,6 +51,26 @@ export function drscRowToConversationMessage(row, sessionId) {
|
|
|
51
51
|
}
|
|
52
52
|
return msg;
|
|
53
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* `op=session` 包络 → 行数组。
|
|
56
|
+
*
|
|
57
|
+
* `session:null` = collector 没有这个会话 —— 新会话首轮的常态,**不是错误**
|
|
58
|
+
* (“没有内容”与“没拿到”必须分开:前者空窗降级,后者抛 DrscClientError)。
|
|
59
|
+
*/
|
|
60
|
+
function parseSessionRows(body) {
|
|
61
|
+
if (body['session'] === null || body['session'] === undefined)
|
|
62
|
+
return [];
|
|
63
|
+
const rows = Array.isArray(body['rows']) ? body['rows'] : [];
|
|
64
|
+
return rows.map((r) => ({
|
|
65
|
+
seq: Number(r['seq'] ?? 0),
|
|
66
|
+
turn: Number(r['turn'] ?? 0),
|
|
67
|
+
step: Number(r['step'] ?? 0),
|
|
68
|
+
kind: String(r['kind'] ?? ''),
|
|
69
|
+
role: String(r['role'] ?? ''),
|
|
70
|
+
time: Number(r['time'] ?? 0),
|
|
71
|
+
text: String(r['text'] ?? ''),
|
|
72
|
+
}));
|
|
73
|
+
}
|
|
54
74
|
export class DrscClient {
|
|
55
75
|
options;
|
|
56
76
|
fetchImpl;
|
|
@@ -108,18 +128,43 @@ export class DrscClient {
|
|
|
108
128
|
*/
|
|
109
129
|
async sessionTail(sessionId, tail) {
|
|
110
130
|
const body = await this.getJson(`?op=session&session=${encodeURIComponent(sessionId)}&tail=${Math.max(0, Math.floor(tail))}&redact=1`);
|
|
111
|
-
|
|
112
|
-
|
|
131
|
+
return parseSessionRows(body);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* **整会话**正文(issue #14-B 重建事实源):`op=session&session=<id>&redact=1`,
|
|
135
|
+
* **不带 `tail`** —— collector 侧 `tail` 未给时走 `ORDER BY s.seq ASC` 无 LIMIT,即全量。
|
|
136
|
+
*
|
|
137
|
+
* `redact=1` 是**硬要求**,不是可选项:collector 的 `session` 缺省是原文臂,
|
|
138
|
+
* 而 memory 捕获侧是写前单点脱敏;重建若走原文臂,产出的 L1 会比正常蒸馏「更脏」,
|
|
139
|
+
* 而且会经 md 投射落盘。
|
|
140
|
+
*/
|
|
141
|
+
async sessionAll(sessionId) {
|
|
142
|
+
const body = await this.getJson(`?op=session&session=${encodeURIComponent(sessionId)}&redact=1`);
|
|
143
|
+
return parseSessionRows(body);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* 会话枚举:`op=sessions&offset&limit`(collector 侧 limit 钳到 1..500)。
|
|
147
|
+
*
|
|
148
|
+
* 重建的事实源没有“全量导出”单口(也不应该有:一个响应装不下几万条正文),
|
|
149
|
+
* 所以走「枚举会话 → 逐会话拉全量」的 N+1 组合。采集端分页是 0-SQL 的内存切片,
|
|
150
|
+
* 代价仅在于请求数。
|
|
151
|
+
*/
|
|
152
|
+
async listSessions(offset, limit) {
|
|
153
|
+
const from = Math.max(0, Math.floor(offset));
|
|
154
|
+
const size = Math.max(1, Math.min(500, Math.floor(limit)));
|
|
155
|
+
const body = await this.getJson(`?op=sessions&offset=${from}&limit=${size}`);
|
|
113
156
|
const rows = Array.isArray(body['rows']) ? body['rows'] : [];
|
|
114
|
-
return
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
157
|
+
return {
|
|
158
|
+
total: Number(body['total'] ?? rows.length),
|
|
159
|
+
rows: rows.map((r) => ({
|
|
160
|
+
session_id: String(r['session_id'] ?? ''),
|
|
161
|
+
title: String(r['title'] ?? ''),
|
|
162
|
+
cwd: String(r['cwd'] ?? ''),
|
|
163
|
+
event_count: Number(r['event_count'] ?? 0),
|
|
164
|
+
turn_count: Number(r['turn_count'] ?? 0),
|
|
165
|
+
last_time_ms: Number(r['last_time_ms'] ?? 0),
|
|
166
|
+
})),
|
|
167
|
+
};
|
|
123
168
|
}
|
|
124
169
|
/** 原史检索:`op=search&q=<query>&limit=N&redact=1` → 脱敏 snippet 命中。 */
|
|
125
170
|
async search(query, limit) {
|
package/dist/config.d.ts
CHANGED
|
@@ -117,6 +117,15 @@ export interface MemoryConfig {
|
|
|
117
117
|
/** 单源扫描记录上限(0 = 不限;仍受总护栏)。 */
|
|
118
118
|
scanMaxRecords: number;
|
|
119
119
|
};
|
|
120
|
+
/**
|
|
121
|
+
* 重建事实源(issue #14-B)。
|
|
122
|
+
*
|
|
123
|
+
* - `local`(默认):本地 `l0_conversations` —— 已停写的冻结存量;
|
|
124
|
+
* - `drsc`(实验性):`dsh-reference-session-collector` 的投影,枚举会话后逐会话拉全量。
|
|
125
|
+
*/
|
|
126
|
+
rebuild: {
|
|
127
|
+
factSource: 'local' | 'drsc';
|
|
128
|
+
};
|
|
120
129
|
/** 轨2 技能结晶(程序性记忆)。**默认关**:allowPromote 也默认关(上线先只计数不晋升,
|
|
121
130
|
* distinct-session 达阈后才开);injectionTier 不用 union,消费侧归一。 */
|
|
122
131
|
skills: {
|
|
@@ -193,7 +202,7 @@ export interface MemoryConfig {
|
|
|
193
202
|
*/
|
|
194
203
|
workspaceSource: {
|
|
195
204
|
enabled: boolean;
|
|
196
|
-
/**
|
|
205
|
+
/** 路由表:按数组序取首个命中;**默认为空**,需按自己的项目自行配置(issue #13)。 */
|
|
197
206
|
routes: WorkspaceRoute[];
|
|
198
207
|
/** 存量 re-link 的单次护栏。 */
|
|
199
208
|
maxRecords: number;
|