dsh-prime-memory 0.25.0 → 0.26.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 +37 -0
- package/CHANGELOG.ja.md +38 -0
- package/CHANGELOG.ko.md +38 -0
- package/CHANGELOG.md +39 -0
- package/dist/client.js +991 -665
- package/dist/config.d.ts +44 -2
- package/dist/config.js +32 -2
- package/dist/contract.d.ts +108 -2
- package/dist/index.js +3 -3
- package/dist/keyword-backfill.d.ts +52 -7
- package/dist/keyword-backfill.js +204 -62
- package/dist/llm.d.ts +9 -0
- package/dist/llm.js +7 -4
- package/dist/pipeline/relabel.d.ts +11 -12
- package/dist/pipeline/relabel.js +54 -66
- package/dist/pipeline/runner.js +24 -1
- package/dist/projection/recall.d.ts +3 -2
- package/dist/projection/recall.js +26 -5
- package/dist/projection/slots.d.ts +11 -0
- package/dist/projection/slots.js +13 -3
- package/dist/redistill-backfill.d.ts +148 -0
- package/dist/redistill-backfill.js +420 -0
- package/dist/room-review.d.ts +12 -13
- package/dist/room-review.js +39 -29
- package/dist/settings.js +15 -0
- package/dist/stats.js +138 -21
- package/dist/store/l1.d.ts +12 -0
- package/dist/store/l1.js +9 -0
- package/dist/store/memory-md.d.ts +8 -0
- package/dist/store/memory-md.js +13 -2
- package/dist/store/sqlite.d.ts +17 -0
- package/dist/store/sqlite.js +33 -0
- package/dist/tools/index.d.ts +10 -1
- package/dist/tools/index.js +7 -1
- package/dist/tools/skills.d.ts +7 -4
- package/dist/tools/skills.js +9 -11
- package/dist/wing-backfill.d.ts +25 -14
- package/dist/wing-backfill.js +133 -96
- package/dsh.plugin.json +1 -1
- package/package.json +1 -1
package/dist/pipeline/runner.js
CHANGED
|
@@ -121,17 +121,40 @@ export function effectiveCfg(cfg, live) {
|
|
|
121
121
|
const cfOverride = s?.conflictFreeze !== undefined
|
|
122
122
|
? { conflictFreeze: { ...(cfg.conflictFreeze ?? {}), enabled: s.conflictFreeze } }
|
|
123
123
|
: null;
|
|
124
|
+
// 存量回填/进阶功能启用开关:live 与部署 cfg.<x>.enabled 取或(部署强制开、live 追加开,
|
|
125
|
+
// 任一为真即放行)。关关关时保持逐字 false(零漂移不破)。
|
|
126
|
+
const kwOverride = s?.keywordEnabled !== undefined
|
|
127
|
+
? { keyword: { ...(cfg.keyword ?? {}), enabled: cfg.keyword?.enabled === true || s.keywordEnabled === true } }
|
|
128
|
+
: null;
|
|
129
|
+
const rdOverride = s?.redistillEnabled !== undefined
|
|
130
|
+
? { redistill: { ...(cfg.redistill ?? {}), enabled: cfg.redistill?.enabled === true || s.redistillEnabled === true } }
|
|
131
|
+
: null;
|
|
132
|
+
const mdsOverride = s?.mdSyncEnabled !== undefined
|
|
133
|
+
? { mdSync: { ...(cfg.mdSync ?? {}), enabled: cfg.mdSync?.enabled === true || s.mdSyncEnabled === true } }
|
|
134
|
+
: null;
|
|
135
|
+
const mpOverride = s?.memportEnabled !== undefined
|
|
136
|
+
? { memport: { ...(cfg.memport ?? {}), enabled: cfg.memport?.enabled === true || s.memportEnabled === true } }
|
|
137
|
+
: null;
|
|
124
138
|
// md 投射/后缀收敛的单次动作护栏运行时覆盖(0 = 跟随部署 cfg.memExport.maxRecords)。
|
|
125
139
|
// 只覆盖条数护栏,不动 enabled/root——开关与根路径仍属部署配置。
|
|
126
140
|
const mdx = s?.mdExportMaxRecords ?? 0;
|
|
127
141
|
const memExportOverride = mdx > 0 ? { memExport: { ...(cfg.memExport ?? {}), maxRecords: mdx } } : null;
|
|
128
|
-
|
|
142
|
+
// 回填并行度运行时覆盖(0 = 跟随部署 cfg.backfill.concurrency):只改并发度,
|
|
143
|
+
// 不动 maxRecords/timeBudgetMs/callTimeoutMs——那三个仍属部署护栏,要改得改 YAML。
|
|
144
|
+
const bf = s?.backfillConcurrency ?? 0;
|
|
145
|
+
const backfillOverride = bf > 0 ? { backfill: { ...(cfg.backfill ?? {}), concurrency: bf } } : null;
|
|
146
|
+
if (!override && !budgets && !maxInput && !fallbacksTakeover && !chainEffort && !chainFallbacks && !effortInject && !layerChains && !hasChannel && !embedOverride && !cfOverride && !memExportOverride && !backfillOverride && !kwOverride && !rdOverride && !mdsOverride && !mpOverride)
|
|
129
147
|
return cfg;
|
|
130
148
|
return {
|
|
131
149
|
...cfg,
|
|
132
150
|
...(embedOverride ?? {}),
|
|
133
151
|
...(cfOverride ?? {}),
|
|
152
|
+
...(kwOverride ?? {}),
|
|
153
|
+
...(rdOverride ?? {}),
|
|
154
|
+
...(mdsOverride ?? {}),
|
|
155
|
+
...(mpOverride ?? {}),
|
|
134
156
|
...(memExportOverride ?? {}),
|
|
157
|
+
...(backfillOverride ?? {}),
|
|
135
158
|
llm: {
|
|
136
159
|
...cfg.llm,
|
|
137
160
|
...(effortInject ?? {}),
|
|
@@ -92,9 +92,10 @@ export declare const stateSchema: SchemaLike<RecallProjectionState>;
|
|
|
92
92
|
/** view 校验(出网前调用;未知键容忍,同 slots 投影的语义边界)。 */
|
|
93
93
|
export declare const viewSchema: SchemaLike<RecallView>;
|
|
94
94
|
/** 投影需要的 L1 只读面(结构化声明,避免跨模块类型耦合)。
|
|
95
|
-
* 判退场要 `validTo`/`metadata`,故直接 Pick 自 MemoryRecord,不在投影里自写时间比较。
|
|
95
|
+
* 判退场要 `validTo`/`metadata`,故直接 Pick 自 MemoryRecord,不在投影里自写时间比较。
|
|
96
|
+
* `name` 是名称蒸馏产出的短标题,优先作为展示标题。 */
|
|
96
97
|
export interface RecallL1Face {
|
|
97
|
-
getByIds(ids: string[]): Array<Pick<MemoryRecord, 'id' | 'type' | 'content' | 'priority' | 'metadata' | 'validTo'>>;
|
|
98
|
+
getByIds(ids: string[]): Array<Pick<MemoryRecord, 'id' | 'type' | 'content' | 'priority' | 'metadata' | 'validTo' | 'name'>>;
|
|
98
99
|
}
|
|
99
100
|
/** 投影需要的反馈只读面(缺席 = view 不带 rating,旧行为)。 */
|
|
100
101
|
export interface RecallFeedbackFace {
|
|
@@ -77,11 +77,32 @@ export const viewSchema = {
|
|
|
77
77
|
return value;
|
|
78
78
|
},
|
|
79
79
|
};
|
|
80
|
-
/**
|
|
80
|
+
/**
|
|
81
|
+
* 正文首行 → 标题(投影内不引 client 的 format 工具,保持服务端自足)。
|
|
82
|
+
* 按 markdown 语义解析:
|
|
83
|
+
* - H1(`# xxx`)是文档标题,直接作为记忆名称;
|
|
84
|
+
* - H2+(`## xxx`)是正文分节标记,跳过它取第一个实质文本行。
|
|
85
|
+
* 全部行都是 heading 时回落到第一个非空行。
|
|
86
|
+
*/
|
|
81
87
|
function firstLine(content) {
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
88
|
+
const lines = content.split('\n');
|
|
89
|
+
// 优先取 H1(文档级标题)
|
|
90
|
+
const h1 = lines.find((l) => /^#\s/.test(l.trim()));
|
|
91
|
+
if (h1)
|
|
92
|
+
return clampTitle(h1.trim());
|
|
93
|
+
// 无 H1 时跳过 H2+ 分节 heading,取第一个实质文本行
|
|
94
|
+
const body = lines.find((l) => {
|
|
95
|
+
const t = l.trim();
|
|
96
|
+
return t.length > 0 && !/^#{2,6}\s/.test(t);
|
|
97
|
+
});
|
|
98
|
+
if (body)
|
|
99
|
+
return clampTitle(body.trim());
|
|
100
|
+
// 全是 heading 的极端情况:回落第一个非空行
|
|
101
|
+
const fallback = lines.find((l) => l.trim().length > 0) ?? content;
|
|
102
|
+
return clampTitle(fallback.trim());
|
|
103
|
+
}
|
|
104
|
+
function clampTitle(s) {
|
|
105
|
+
return s.length > TITLE_MAX ? s.slice(0, TITLE_MAX) : s;
|
|
85
106
|
}
|
|
86
107
|
/** 正文全文 → 泡泡用(去首尾空白,超长截断补省略号)。 */
|
|
87
108
|
function clampBody(content) {
|
|
@@ -132,7 +153,7 @@ function makeView(state, l1, feedback) {
|
|
|
132
153
|
items.push({
|
|
133
154
|
id: r.id,
|
|
134
155
|
type: r.type,
|
|
135
|
-
title: firstLine(r.content),
|
|
156
|
+
title: r.name || firstLine(r.content),
|
|
136
157
|
priority: r.priority,
|
|
137
158
|
body: clampBody(r.content),
|
|
138
159
|
...(scenario !== undefined && scenario.length > 0 ? { scenario } : {}),
|
|
@@ -36,6 +36,15 @@ export interface SlotsViewSlot {
|
|
|
36
36
|
export interface SlotRefView {
|
|
37
37
|
ref: string;
|
|
38
38
|
title: string;
|
|
39
|
+
/**
|
|
40
|
+
* 记忆文件相对路径(`<type>/<name>.memory.md`)。
|
|
41
|
+
* 拼接绝对地址:
|
|
42
|
+
* - 有 workspaceId → `<workspaceId>/.agents/memory/<filePath>`
|
|
43
|
+
* - 无 workspaceId → `<memoriesRoot>/<filePath>`(由消费方自行解析根目录)
|
|
44
|
+
*/
|
|
45
|
+
filePath?: string;
|
|
46
|
+
/** 记忆归属的工作区绝对路径;空串/undefined = global(无 workspace)。 */
|
|
47
|
+
workspaceId?: string;
|
|
39
48
|
}
|
|
40
49
|
export interface SlotsProjectionState {
|
|
41
50
|
rev: number;
|
|
@@ -76,6 +85,8 @@ export interface L1LookupFace {
|
|
|
76
85
|
id: string;
|
|
77
86
|
content: string;
|
|
78
87
|
type: string;
|
|
88
|
+
name?: string;
|
|
89
|
+
workspaceId?: string;
|
|
79
90
|
}>;
|
|
80
91
|
}
|
|
81
92
|
export declare function registerSlotsProjection(ctx: Context, store: SlotStore, l1?: L1LookupFace): void;
|
package/dist/projection/slots.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { SLOT_KINDS, SLOT_STATUSES } from '../store/slots.js';
|
|
2
|
+
import { relPathFor } from '../store/memory-md.js';
|
|
2
3
|
export const MEMORY_SLOTS_KEY = 'memorySlots';
|
|
3
4
|
function invalid(what, detail) {
|
|
4
5
|
throw new Error(`${what}: ${detail}`);
|
|
@@ -100,9 +101,18 @@ function resolveRefViewsUnsafe(recordRefs, l1) {
|
|
|
100
101
|
const record = byId.get(ref);
|
|
101
102
|
if (record === undefined)
|
|
102
103
|
continue;
|
|
103
|
-
|
|
104
|
-
const
|
|
105
|
-
|
|
104
|
+
// 优先用 name 字段(名称蒸馏产出的短标题),无 name 时回落 content 首行截断。
|
|
105
|
+
const raw = record.name || (record.content.split('\n', 1)[0] ?? '');
|
|
106
|
+
const summary = raw.length > REF_TITLE_MAX ? raw.slice(0, REF_TITLE_MAX) + '…' : raw;
|
|
107
|
+
// 投射相对路径走单一事实源 `relPathFor`,与写盘/records-meta 端点同算法。
|
|
108
|
+
const filePath = relPathFor(record);
|
|
109
|
+
const ws = (record.workspaceId ?? '').trim();
|
|
110
|
+
views.push({
|
|
111
|
+
ref,
|
|
112
|
+
title: '[' + record.type + '] ' + summary,
|
|
113
|
+
filePath,
|
|
114
|
+
...(ws.length > 0 ? { workspaceId: ws } : {}),
|
|
115
|
+
});
|
|
106
116
|
}
|
|
107
117
|
return views.length > 0 ? views : undefined;
|
|
108
118
|
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 存量记忆重蒸馏整形回填(redistill)。
|
|
3
|
+
*
|
|
4
|
+
* 职责:对**活跃**且 `scoreSkeleton` 判「骨架不齐备」的 L1 记录,**一条一个请求**送 LLM
|
|
5
|
+
* 把正文重排成 G2 分类型的 `## 节名` 分节骨架,并顺带产 `dsh_keywords` / `dsh_usage_scenario`;
|
|
6
|
+
* 只有**整形后骨架分严格更优且无空心标题**才写回(并盖当前整形版本戳),否则留原文**不打标记**——
|
|
7
|
+
* 下轮仍可再试(用户定:「成功替换的」才不再进入重蒸馏)。
|
|
8
|
+
*
|
|
9
|
+
* 与 keyword-backfill 的关键差异(为什么它更重一档):
|
|
10
|
+
* - **改 content** ⇒ 写回必须走 `L1Store.appendNew`(追加 JSONL 事实源 + upsertL1 重嵌+FTS +
|
|
11
|
+
* fireFileSync 重导出),**不能**走 `MemoryBackend.patchMetadata*`(只改元数据、不动正文),
|
|
12
|
+
* 也**不能**走 worker backend(`memory-backend.ts` 明示 upsert 会重嵌、worker 拿不到
|
|
13
|
+
* embedding service 会写零向量毁数据)。故本模块 deps 直取 `l1: L1Store`(进程内)。
|
|
14
|
+
* - **入口 `vectorsReady()` 守卫**:`upsertL1InTx` 先删向量行、仅非零 embedding 才插回;
|
|
15
|
+
* embed 未就绪时改正文会静默丢该记录向量。故向量未就绪 ⇒ 整轮回跳过(整形是可选优化,不抢这个险)。
|
|
16
|
+
*
|
|
17
|
+
* 安全边界(继承 keyword/wing 回填):
|
|
18
|
+
* - 单飞:同时最多一个任务,重复触发返回 running(不排队不叠加)
|
|
19
|
+
* - 后台执行:端点立即返回,逐条推进并**每条即时提交**,不阻塞 RPC/管线
|
|
20
|
+
* - 失败可退:LLM 失败/输出非法/质量闸不过 ⇒ 原记录零改动(写回只发生在严格更优且 embed 就绪时)
|
|
21
|
+
* - 有界:单次最多 cfg.backfill.maxRecords 条 + timeBudgetMs 墙钟;其余计入 deferred 可再触发
|
|
22
|
+
* - 排除靠**版本戳**:成功写回盖 `dsh_reshape_ver = RESHAPE_SCHEMA_VERSION`;扫描只排「当前版本
|
|
23
|
+
* 已整过」的(存量兼容:只有旧布尔 `dsh_reshape_tried` 且正文确为 `## 分节`式也算已整)。
|
|
24
|
+
* 整形规则/提示词改变时把 `RESHAPE_SCHEMA_VERSION` 递增,旧产物即自动重新入列。
|
|
25
|
+
* - 门控关(`cfg.redistill.enabled = false`):入口立即跳过——不动 content、FTS、投射逐字不变
|
|
26
|
+
*
|
|
27
|
+
* 形状约定(用户定):**按单元、串行、不合并**——一个请求只装一条记忆,跑完一条再发下一条。
|
|
28
|
+
* 扫描期就用 SQL 退场判据 + 骨架判据筛出真目标(旧实现收 1221 条候选、每批 20 条只命中 ~4 条)。
|
|
29
|
+
* `cfg.backfill.concurrency` 默认 1(串行);拖高概览页滑块可临时多路在飞(上限 8)。
|
|
30
|
+
* 注意:本任务直接调 `callLLM`、不进 runner 队列,拿不到“live 优先”的让位保护。
|
|
31
|
+
*/
|
|
32
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
33
|
+
import type { L1Store } from './store/l1.js';
|
|
34
|
+
import type { MemoryConfig } from './config.js';
|
|
35
|
+
import type { MemoryLogger, MemoryRecord } from './types.js';
|
|
36
|
+
/**
|
|
37
|
+
* 整形**版本戳**:只在**成功替换**时写入,值为当前整形规则版本(`RESHAPE_SCHEMA_VERSION`)。
|
|
38
|
+
* 扫描阶段据此排除「已按当前规则整过形」的记录——见 `isReshapedAtCurrentVersion`。
|
|
39
|
+
*/
|
|
40
|
+
export declare const RESHAPE_VER_KEY = "dsh_reshape_ver";
|
|
41
|
+
/**
|
|
42
|
+
* 当前整形规则版本。**改动整形骨架/提示词/输出契约时必须 +1**,否则旧产物不会重跑。
|
|
43
|
+
* v1 = 行内标签式(`规则:/触发时机:`,已废);v2 = `## 节名` 分节 + 空心标题闸。
|
|
44
|
+
*/
|
|
45
|
+
export declare const RESHAPE_SCHEMA_VERSION = 2;
|
|
46
|
+
export interface RedistillBackfillDeps {
|
|
47
|
+
ctx: Context;
|
|
48
|
+
cfg: MemoryConfig;
|
|
49
|
+
/** 直取 L1Store(进程内):改 content 要 appendNew 重嵌 + 追加 JSONL + 投射点火,不经 worker backend。 */
|
|
50
|
+
l1: L1Store;
|
|
51
|
+
logger: MemoryLogger;
|
|
52
|
+
/**
|
|
53
|
+
* 运行时**生效并发**读取器(可选):给正在跑的任务即时改并发用——池子每完成一条重读一次。
|
|
54
|
+
* 缺省 = 启动时读一次 `cfg.backfill.concurrency`(旧行为)。
|
|
55
|
+
*/
|
|
56
|
+
concurrency?: () => number | undefined;
|
|
57
|
+
}
|
|
58
|
+
export interface RedistillBackfillState {
|
|
59
|
+
running: boolean;
|
|
60
|
+
/** 整形成功写回条数。 */
|
|
61
|
+
updated: number;
|
|
62
|
+
/** 质量闸判不写(留原文)条数。 */
|
|
63
|
+
skipped: number;
|
|
64
|
+
/** 失败/跳过(LLM 失败、id 配不上、embed 掉线)条数。 */
|
|
65
|
+
failed: number;
|
|
66
|
+
/** 分批进度(UI 轮询据此显示「扫描中 / 第几条」,否则运行期只有一个「整形中…」): */
|
|
67
|
+
/** 每个请求处理的条数——本任务已改成逐条,永远为 1(保留字段与 keyword 同形状)。 */
|
|
68
|
+
chunk: number;
|
|
69
|
+
/** 扫描阶段确定的**真目标**总数(骨架不齐备且未试过;扫描未完成时为已发现数)。 */
|
|
70
|
+
candidates: number;
|
|
71
|
+
/** 本次已完成(送过 LLM 且已提交结果)条数。**在请求完成时才自增**——
|
|
72
|
+
* 在开始处加会让“全部超时失败”跟“全部成功”长得一模一样。 */
|
|
73
|
+
processed: number;
|
|
74
|
+
/** 仍在扫描阶段(此阶段 candidates 还在动,UI 应报「扫描中」而非「第 N 条」)。 */
|
|
75
|
+
scanning: boolean;
|
|
76
|
+
/** 已完成条数(与 processed 同值,保留为与 keyword 共用的进度形状)。 */
|
|
77
|
+
batchesDone: number;
|
|
78
|
+
/** 本次要处理的总条数。 */
|
|
79
|
+
batchTotal: number;
|
|
80
|
+
/** LLM 批调用并行度。 */
|
|
81
|
+
concurrency: number;
|
|
82
|
+
/** 预算/上限用尽未处理、留下次的条数。 */
|
|
83
|
+
deferred: number;
|
|
84
|
+
/** 本轮被人工中止(进端点 cancel)——与“预算用尽”分开报文案。 */
|
|
85
|
+
cancelled: boolean;
|
|
86
|
+
/**
|
|
87
|
+
* 扫描期已扫行数(活跃集逐页扫)/ 总行数(本模块拿不到总数,恒 0 = 未知)。
|
|
88
|
+
* 为何要暴露:扫描段原本在面板上只是一个静态「正在扫描…」,分不清在跑还是卡死。
|
|
89
|
+
*/
|
|
90
|
+
scanned: number;
|
|
91
|
+
scanTotal: number;
|
|
92
|
+
}
|
|
93
|
+
/** 请求中止本轮(空闲时无副作用);返回后中止是**有界**的:最多等 graceMs(≤60s)。 */
|
|
94
|
+
export declare function cancelRedistillBackfill(): {
|
|
95
|
+
cancelled: boolean;
|
|
96
|
+
running: boolean;
|
|
97
|
+
};
|
|
98
|
+
export declare function redistillBackfillState(): RedistillBackfillState;
|
|
99
|
+
/**
|
|
100
|
+
* 空心标题检测:某个 `## 节名` 到下一标题之间没有实质文字。
|
|
101
|
+
*
|
|
102
|
+
* 为什么需要它:判定器(`scoreSkeleton`)按子串命中认骨架,而标题词本身就是那个子串——
|
|
103
|
+
* 只写 `## 触发时机` 不写内容就能白得一个命中。不堵这个闸,“加分才写回”会退化成
|
|
104
|
+
* “加空标题就写回”,正文反而被掏空了。
|
|
105
|
+
*/
|
|
106
|
+
export declare function hasHollowHeading(content: string): boolean;
|
|
107
|
+
/** 质量闸:整形后骨架命中数严格上升(或旧不齐备且新齐备)且正文非空、无空心标题 → 判可写。 */
|
|
108
|
+
export declare function reshapePassesGate(type: string, oldContent: string, newContent: string): boolean;
|
|
109
|
+
/**
|
|
110
|
+
* 是否已按**当前版本**整理过 → 扫描阶段排除(用户定:「成功替换的」才不再进入)。
|
|
111
|
+
*
|
|
112
|
+
* 判据:
|
|
113
|
+
* - 带当前版本戳(`dsh_reshape_ver === RESHAPE_SCHEMA_VERSION`)⇒ 已成功替换,排除;
|
|
114
|
+
* - 旧存量兼容:只有布尔 `dsh_reshape_tried`(成功与留原文都打过,无法区分)+ 正文确实是
|
|
115
|
+
* `## 分节`式 ⇒ 视为已整形排除;**不带标题的则重新入列**(它们是「试过但没改成」的,
|
|
116
|
+
* 或首轮行内标签式产物,都该重跑)。
|
|
117
|
+
*/
|
|
118
|
+
export declare function isReshapedAtCurrentVersion(meta: Record<string, unknown> | undefined, content: string): boolean;
|
|
119
|
+
/** 启动后台重蒸馏回填;已在运行返回 false(单飞)。 */
|
|
120
|
+
export declare function startRedistillBackfill(deps: RedistillBackfillDeps): {
|
|
121
|
+
started: boolean;
|
|
122
|
+
running: boolean;
|
|
123
|
+
};
|
|
124
|
+
/**
|
|
125
|
+
* 回填主体(导出供单测 await 到完成;生产走 `startRedistillBackfill` 的单飞后台包装)。
|
|
126
|
+
* 门控关或向量未就绪 ⇒ 入口即返回,不碰任何记录、FTS、投射。
|
|
127
|
+
*
|
|
128
|
+
* 阶段划分对齐反刍重标定(`pipeline/relabel.ts`):**机械扫描期把筛子下推到底**,
|
|
129
|
+
* LLM 期只吃真目标、逐条推进、**每条即时提交**、条间受墙钟预算约束。
|
|
130
|
+
* 形状约定(用户定):**按单元、串行、不合并**——`concurrency` 默认 1(跑完一条再发下一条),
|
|
131
|
+
* 拖高概览页滑块只是临时提速。旧形状(20 条一批)真机把单请求拖到 200s+ 并在超时线上被掐。
|
|
132
|
+
*/
|
|
133
|
+
export declare function runRedistillBackfillOnce(deps: RedistillBackfillDeps): Promise<void>;
|
|
134
|
+
/** 单条整形结果。 */
|
|
135
|
+
export interface ReshapeOneResult {
|
|
136
|
+
content: string;
|
|
137
|
+
keywords: string[];
|
|
138
|
+
usageScenario: string[];
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* 整形**一条**记忆(一个请求只装一条)。失败/输出非法返回 null(原记录不动)。
|
|
142
|
+
*
|
|
143
|
+
* 导出不带 ctx/cfg 以外的参数,供单测注入桩 LLM。旧名 `reshapeChunk`(多条一次)已废:
|
|
144
|
+
* 合并请求把爆炸半径从 1 条放大到 20 条,而实测逐条只花 2.6s,合并毫无收益。
|
|
145
|
+
*/
|
|
146
|
+
export declare function reshapeOne(ctx: Context, cfg: MemoryConfig, logger: MemoryLogger, rec: MemoryRecord, callTimeoutMs?: number,
|
|
147
|
+
/** 本轮中止信号(可选):与单次超时**取或**,宽限到期后由它当场掐断请求。 */
|
|
148
|
+
externalSignal?: AbortSignal): Promise<ReshapeOneResult | null>;
|