agim-cli 1.4.2 → 1.4.5
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/dist/cli-ui/tui/app.d.ts +7 -1
- package/dist/cli-ui/tui/app.d.ts.map +1 -1
- package/dist/cli-ui/tui/app.js +41 -31
- package/dist/cli-ui/tui/app.js.map +1 -1
- package/dist/cli-ui/tui/index.d.ts.map +1 -1
- package/dist/cli-ui/tui/index.js +32 -18
- package/dist/cli-ui/tui/index.js.map +1 -1
- package/dist/cli-ui/tui/mouse-stdin.d.ts.map +1 -1
- package/dist/cli-ui/tui/mouse-stdin.js +23 -4
- package/dist/cli-ui/tui/mouse-stdin.js.map +1 -1
- package/dist/cli.js +10 -0
- package/dist/cli.js.map +1 -1
- package/dist/core/llm/registry.d.ts +1 -1
- package/dist/core/llm/registry.d.ts.map +1 -1
- package/dist/core/memory-distill.d.ts +22 -5
- package/dist/core/memory-distill.d.ts.map +1 -1
- package/dist/core/memory-distill.js +153 -133
- package/dist/core/memory-distill.js.map +1 -1
- package/dist/core/memory-distiller.d.ts +11 -0
- package/dist/core/memory-distiller.d.ts.map +1 -0
- package/dist/core/memory-distiller.js +105 -0
- package/dist/core/memory-distiller.js.map +1 -0
- package/dist/core/memory.d.ts +31 -0
- package/dist/core/memory.d.ts.map +1 -1
- package/dist/core/memory.js +102 -3
- package/dist/core/memory.js.map +1 -1
- package/package.json +2 -1
|
@@ -24,47 +24,42 @@
|
|
|
24
24
|
// extraction surfaces "user lives in 杭州" three times in three turns,
|
|
25
25
|
// we'll have three rows. Consolidation cron will dedupe.
|
|
26
26
|
import { logger as rootLogger } from './logger.js';
|
|
27
|
-
import { saveFact, findFactIdByWhat, touchFact, userKey } from './memory.js';
|
|
27
|
+
import { saveFact, findFactIdByWhat, touchFact, userKey, enqueuePendingTurn } from './memory.js';
|
|
28
28
|
import { isMemoryEnabled } from './persona.js';
|
|
29
29
|
import { logInvocation } from './audit-log.js';
|
|
30
30
|
import { tryIntrospect } from './llm/index.js';
|
|
31
|
+
import { registry } from './registry.js';
|
|
31
32
|
const log = rootLogger.child({ component: 'memory-distill' });
|
|
32
33
|
const DEFAULT_MIN_LEN = 20;
|
|
33
|
-
// Prompt
|
|
34
|
-
// defensively (the LLM occasionally wraps in markdown fences).
|
|
35
|
-
|
|
34
|
+
// Prompt for BATCH fact extraction across N buffered turns. Returns JSON; we
|
|
35
|
+
// parse defensively (the LLM occasionally wraps in markdown fences). Batching
|
|
36
|
+
// lets the model dedup / resolve contradictions across the whole session.
|
|
37
|
+
function buildBatchExtractionPrompt(turns) {
|
|
38
|
+
const convo = [];
|
|
39
|
+
turns.forEach((t, i) => {
|
|
40
|
+
convo.push(`### 第 ${i + 1} 轮`);
|
|
41
|
+
convo.push('用户:' + t.user_message.slice(0, 2000));
|
|
42
|
+
convo.push('Agent:' + t.agent_reply.slice(0, 2000));
|
|
43
|
+
convo.push('');
|
|
44
|
+
});
|
|
36
45
|
return [
|
|
37
|
-
|
|
38
|
-
'
|
|
46
|
+
`你是一个事实抽取器。下面是与同一个用户的 ${turns.length} 轮对话。`,
|
|
47
|
+
'从【整段对话】中提取最多 8 条**值得长期记住的事实**:跨轮去重、合并相似项、矛盾时保留最新。',
|
|
48
|
+
'输出严格的 JSON,**不要任何额外文字 / markdown / 解释**:',
|
|
49
|
+
'',
|
|
50
|
+
'{"facts":[{"what":"用户偏好早 8 点喝咖啡","category":"preference","confidence":0.8,"who":"user","when_text":"","where_label":"","why":""}]}',
|
|
39
51
|
'',
|
|
40
|
-
'
|
|
41
|
-
'{',
|
|
42
|
-
' "facts": [',
|
|
43
|
-
' {',
|
|
44
|
-
' "what": "用户偏好早 8 点喝咖啡", // 必填,1 句话,主语写 user/我/...都行',
|
|
45
|
-
' "category": "preference", // fact|preference|goal|history|profile',
|
|
46
|
-
' "confidence": 0.8, // 0-1,根据语境强弱',
|
|
47
|
-
' "who": "user", // 可选,事实涉及的主体',
|
|
48
|
-
' "when_text": "", // 可选',
|
|
49
|
-
' "where_label": "", // 可选',
|
|
50
|
-
' "why": "" // 可选',
|
|
51
|
-
' }',
|
|
52
|
-
' ]',
|
|
53
|
-
'}',
|
|
54
|
-
'```',
|
|
52
|
+
'字段:what 必填(1 句话) · category ∈ fact|preference|goal|history|profile · confidence 0-1 · who/when_text/where_label/why 可选。',
|
|
55
53
|
'',
|
|
56
54
|
'严格执行:',
|
|
57
55
|
'- **跳过寒暄 / 测试消息 / 临时性信息**(如"在不在"、"明天再说")',
|
|
58
|
-
'-
|
|
56
|
+
'- 只挑可在未来对话里**复用**的事实;不要总结整段对话',
|
|
59
57
|
'- 用户没说的事**不要编造**(confidence 必须基于实际证据)',
|
|
60
|
-
'-
|
|
58
|
+
'- 没有值得记的就**返回 `{"facts": []}`**',
|
|
61
59
|
'- 输出**纯 JSON,不要 markdown 围栏**',
|
|
62
60
|
'',
|
|
63
|
-
'##
|
|
64
|
-
|
|
65
|
-
'',
|
|
66
|
-
'## Agent 回复',
|
|
67
|
-
agentReply.slice(0, 4000),
|
|
61
|
+
'## 对话',
|
|
62
|
+
...convo,
|
|
68
63
|
].join('\n');
|
|
69
64
|
}
|
|
70
65
|
function tryParseFactsJson(raw) {
|
|
@@ -99,103 +94,64 @@ function clampConfidence(c) {
|
|
|
99
94
|
return 0.6;
|
|
100
95
|
return Math.max(0, Math.min(1, n));
|
|
101
96
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
97
|
+
function distillSource() {
|
|
98
|
+
const v = (process.env.IMHUB_MEMORY_DISTILL_SOURCE || 'auto').toLowerCase();
|
|
99
|
+
return v === 'agent' || v === 'llm' ? v : 'auto';
|
|
100
|
+
}
|
|
101
|
+
// Resolve + run the extraction LLM per the configured source:
|
|
102
|
+
// auto → the batch's representative agent (zero-config default)
|
|
103
|
+
// agent → IMHUB_MEMORY_DISTILL_AGENT (a chosen, already-enabled agent)
|
|
104
|
+
// llm → the `distill` LLM role (direct HTTP, no CLI spawn)
|
|
105
|
+
// Returns raw model output + an audit name, or null when no usable LLM is
|
|
106
|
+
// available (caller then keeps the turns buffered to retry next pass).
|
|
107
|
+
async function runExtractionLlm(prompt, representativeAgent) {
|
|
108
|
+
const src = distillSource();
|
|
109
|
+
if (src === 'llm') {
|
|
110
|
+
const r = await tryIntrospect({ role: 'distill', prompt, timeoutMs: 30_000, temperature: 0.2 });
|
|
111
|
+
if (!r) {
|
|
112
|
+
log.warn({ event: 'memory.distill.no_distill_backend' });
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
return { text: r.text, usedName: `llm:${r.backendName}`, costUsd: typeof r.usage.costUsd === 'number' ? r.usage.costUsd : 0 };
|
|
114
116
|
}
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
// 1. Preferred (D+ Stage 1): native LLM backend configured for the
|
|
120
|
-
// 'cheap' role — direct HTTP call, no CLI spawn, completes in
|
|
121
|
-
// ~200ms instead of seconds.
|
|
122
|
-
// 2. Fallback: the agent that just produced the reply. Keeps
|
|
123
|
-
// behaviour identical to pre-D+ deployments and operators who
|
|
124
|
-
// run agim without any LLM backend configured.
|
|
125
|
-
//
|
|
126
|
-
// We use a synthetic session id so the agent doesn't pollute the
|
|
127
|
-
// user's real conversation history.
|
|
128
|
-
const extractionPrompt = buildExtractionPrompt(input.userMessage, input.agentReply);
|
|
129
|
-
let raw = '';
|
|
130
|
-
let costAccum = 0;
|
|
131
|
-
const startedAt = Date.now();
|
|
132
|
-
let agentFailed = null;
|
|
133
|
-
let usedAgentName = input.agent.name;
|
|
134
|
-
const nativeResult = await tryIntrospect({
|
|
135
|
-
role: 'cheap',
|
|
136
|
-
prompt: extractionPrompt,
|
|
137
|
-
timeoutMs: 30_000,
|
|
138
|
-
temperature: 0.2,
|
|
139
|
-
});
|
|
140
|
-
if (nativeResult) {
|
|
141
|
-
raw = nativeResult.text;
|
|
142
|
-
if (typeof nativeResult.usage.costUsd === 'number')
|
|
143
|
-
costAccum = nativeResult.usage.costUsd;
|
|
144
|
-
usedAgentName = `llm:${nativeResult.backendName}`;
|
|
117
|
+
const agentName = (src === 'agent' ? (process.env.IMHUB_MEMORY_DISTILL_AGENT || '') : representativeAgent).trim();
|
|
118
|
+
if (!agentName) {
|
|
119
|
+
log.warn({ event: 'memory.distill.no_agent', src });
|
|
120
|
+
return null;
|
|
145
121
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
// turns in the audit view (and in Cost & Health pivots).
|
|
151
|
-
platform: 'memory-distill',
|
|
152
|
-
userId: input.userId,
|
|
153
|
-
// P1-5: account for distill cost so Cost & Health reports the true
|
|
154
|
-
// operator spend, not just user-facing turns.
|
|
155
|
-
onUsage: (delta) => {
|
|
156
|
-
if (typeof delta.costUsd === 'number' && Number.isFinite(delta.costUsd)) {
|
|
157
|
-
costAccum += delta.costUsd;
|
|
158
|
-
}
|
|
159
|
-
},
|
|
160
|
-
});
|
|
161
|
-
for await (const chunk of gen) {
|
|
162
|
-
raw += chunk;
|
|
163
|
-
if (raw.length > 8000)
|
|
164
|
-
break; // safety cap; extraction output is small
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
catch (err) {
|
|
168
|
-
agentFailed = err instanceof Error ? err : new Error(String(err));
|
|
169
|
-
log.warn({ event: 'memory.distill.agent_failed', err: String(err) });
|
|
170
|
-
}
|
|
122
|
+
const agent = registry.getAgent(agentName);
|
|
123
|
+
if (!agent) {
|
|
124
|
+
log.warn({ event: 'memory.distill.agent_missing', agentName });
|
|
125
|
+
return null;
|
|
171
126
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
// intent='memory.distill' makes it filterable in the dashboard.
|
|
175
|
-
// The agent field uses `llm:<backend>` for native calls so the cost
|
|
176
|
-
// dashboard can pivot CLI vs LLM spend.
|
|
127
|
+
let raw = '';
|
|
128
|
+
let cost = 0;
|
|
177
129
|
try {
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
userId
|
|
130
|
+
const gen = agent.sendPrompt(`memory-distill-${Date.now()}`, prompt, [], {
|
|
131
|
+
// platform='memory-distill' keeps distill rows out of real IM history /
|
|
132
|
+
// audit pivots; userId is synthetic so it never pollutes a user thread.
|
|
181
133
|
platform: 'memory-distill',
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
responseLen: raw.length,
|
|
186
|
-
durationMs: Date.now() - startedAt,
|
|
187
|
-
cost: costAccum,
|
|
188
|
-
success: agentFailed === null,
|
|
189
|
-
error: agentFailed?.message,
|
|
134
|
+
userId: 'distill',
|
|
135
|
+
onUsage: (d) => { if (typeof d.costUsd === 'number' && Number.isFinite(d.costUsd))
|
|
136
|
+
cost += d.costUsd; },
|
|
190
137
|
});
|
|
138
|
+
const cap = Date.now() + 30_000;
|
|
139
|
+
for await (const chunk of gen) {
|
|
140
|
+
raw += chunk;
|
|
141
|
+
if (raw.length > 8000 || Date.now() > cap)
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
191
144
|
}
|
|
192
|
-
catch {
|
|
193
|
-
|
|
194
|
-
return
|
|
195
|
-
if (!raw.trim()) {
|
|
196
|
-
log.debug({ event: 'memory.distill.empty_output' });
|
|
197
|
-
return 0;
|
|
145
|
+
catch (err) {
|
|
146
|
+
log.warn({ event: 'memory.distill.agent_failed', agentName, err: String(err) });
|
|
147
|
+
return null;
|
|
198
148
|
}
|
|
149
|
+
return { text: raw, usedName: agentName, costUsd: cost };
|
|
150
|
+
}
|
|
151
|
+
/** Parse the model's JSON output and persist facts, with write-time dedup by
|
|
152
|
+
* exact `what` (re-confirmed facts are touched, not duplicated). Returns the
|
|
153
|
+
* count of NEW facts saved. */
|
|
154
|
+
function parseAndSaveFacts(raw, key, source) {
|
|
199
155
|
const extracted = tryParseFactsJson(raw);
|
|
200
156
|
if (extracted.length === 0) {
|
|
201
157
|
log.debug({ event: 'memory.distill.no_facts', rawPreview: raw.slice(0, 200) });
|
|
@@ -207,13 +163,6 @@ export async function runDistillation(input) {
|
|
|
207
163
|
if (typeof ef.what !== 'string' || !ef.what.trim())
|
|
208
164
|
continue;
|
|
209
165
|
const what = ef.what.trim().slice(0, 500);
|
|
210
|
-
// v1.6 — write-time dedup. Distillation runs every turn, so a fact the
|
|
211
|
-
// user keeps mentioning ("我住在杭州") would otherwise be re-inserted each
|
|
212
|
-
// time, bloating memory and skewing persona / query results. If an exact
|
|
213
|
-
// `what` already exists for this user, reinforce it (touch
|
|
214
|
-
// last_referenced_at so LRU retention keeps it) instead of appending a
|
|
215
|
-
// duplicate row. This also covers a single batch that repeats a `what`,
|
|
216
|
-
// since saveFact commits synchronously before the next iteration.
|
|
217
166
|
const existingId = findFactIdByWhat(key, what);
|
|
218
167
|
if (existingId !== null) {
|
|
219
168
|
touchFact(existingId);
|
|
@@ -234,21 +183,92 @@ export async function runDistillation(input) {
|
|
|
234
183
|
if (id !== null)
|
|
235
184
|
saved++;
|
|
236
185
|
}
|
|
237
|
-
log.info({ event: 'memory.distill.
|
|
186
|
+
log.info({ event: 'memory.distill.saved', saved, deduped, attempted: extracted.length, user_key: key });
|
|
238
187
|
return saved;
|
|
239
188
|
}
|
|
240
189
|
/**
|
|
241
|
-
*
|
|
242
|
-
* the
|
|
243
|
-
*
|
|
190
|
+
* Extract + save facts from a batch of buffered turns for one user.
|
|
191
|
+
* `ok=true` means the LLM ran and its output parsed — safe to clear the buffer
|
|
192
|
+
* even if 0 facts were worth keeping. `ok=false` means no usable LLM, so the
|
|
193
|
+
* caller should keep the turns and retry on the next pass.
|
|
194
|
+
*/
|
|
195
|
+
export async function runBatchDistillation(key, turns, representativeAgent) {
|
|
196
|
+
if (!isMemoryEnabled() || turns.length === 0)
|
|
197
|
+
return { ok: false, saved: 0 };
|
|
198
|
+
const prompt = buildBatchExtractionPrompt(turns);
|
|
199
|
+
const startedAt = Date.now();
|
|
200
|
+
const res = await runExtractionLlm(prompt, representativeAgent);
|
|
201
|
+
// Audit every attempt (success or "no LLM") for the Cost & Health dashboard.
|
|
202
|
+
try {
|
|
203
|
+
logInvocation({
|
|
204
|
+
traceId: `distill-${startedAt}`,
|
|
205
|
+
userId: key,
|
|
206
|
+
platform: 'memory-distill',
|
|
207
|
+
agent: res?.usedName ?? 'none',
|
|
208
|
+
intent: 'memory.distill',
|
|
209
|
+
promptLen: prompt.length,
|
|
210
|
+
responseLen: res?.text.length ?? 0,
|
|
211
|
+
durationMs: Date.now() - startedAt,
|
|
212
|
+
cost: res?.costUsd ?? 0,
|
|
213
|
+
success: res !== null,
|
|
214
|
+
error: res ? undefined : 'no usable distill LLM',
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
catch { /* audit best-effort */ }
|
|
218
|
+
if (!res)
|
|
219
|
+
return { ok: false, saved: 0 };
|
|
220
|
+
if (!res.text.trim())
|
|
221
|
+
return { ok: true, saved: 0 };
|
|
222
|
+
return { ok: true, saved: parseAndSaveFacts(res.text, key, 'distill') };
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Single-turn distillation (direct/legacy entry). Delegates to the batch path
|
|
226
|
+
* with a one-turn batch. The hot path no longer calls this — it buffers via
|
|
227
|
+
* scheduleDistillation and the background distiller batches.
|
|
228
|
+
*/
|
|
229
|
+
export async function runDistillation(input) {
|
|
230
|
+
if (!isMemoryEnabled())
|
|
231
|
+
return 0;
|
|
232
|
+
if (!input.platform || !input.userId)
|
|
233
|
+
return 0;
|
|
234
|
+
const min = input.minLen ?? DEFAULT_MIN_LEN;
|
|
235
|
+
if (input.userMessage.trim().length < min && input.agentReply.trim().length < min)
|
|
236
|
+
return 0;
|
|
237
|
+
const key = userKey(input.platform, input.userId);
|
|
238
|
+
const r = await runBatchDistillation(key, [{ user_message: input.userMessage, agent_reply: input.agentReply }], input.agent?.name ?? '');
|
|
239
|
+
return r.saved;
|
|
240
|
+
}
|
|
241
|
+
function maxPending() {
|
|
242
|
+
const raw = process.env.IMHUB_MEMORY_DISTILL_MAX_PENDING;
|
|
243
|
+
const n = raw ? Number(raw) : NaN;
|
|
244
|
+
return Number.isFinite(n) && n > 0 ? Math.floor(n) : 200;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Post-reply hook (router.ts). Dream distillation: just BUFFER the turn on the
|
|
248
|
+
* hot path (a single SQLite insert, zero LLM). The background distiller
|
|
249
|
+
* (memory-distiller.ts) batch-extracts buffered turns when the system is idle.
|
|
250
|
+
* Trivial exchanges ("ok" / "thanks") are skipped. Returns immediately.
|
|
244
251
|
*/
|
|
245
252
|
export function scheduleDistillation(input) {
|
|
246
253
|
if (!isMemoryEnabled())
|
|
247
254
|
return;
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
255
|
+
if (!input.platform || !input.userId)
|
|
256
|
+
return;
|
|
257
|
+
const min = input.minLen ?? DEFAULT_MIN_LEN;
|
|
258
|
+
if (input.userMessage.trim().length < min && input.agentReply.trim().length < min)
|
|
259
|
+
return;
|
|
260
|
+
try {
|
|
261
|
+
enqueuePendingTurn({
|
|
262
|
+
user_key: userKey(input.platform, input.userId),
|
|
263
|
+
platform: input.platform,
|
|
264
|
+
user_message: input.userMessage,
|
|
265
|
+
agent_reply: input.agentReply,
|
|
266
|
+
agent_name: input.agent?.name ?? '',
|
|
267
|
+
trace_id: input.traceId,
|
|
268
|
+
}, maxPending());
|
|
269
|
+
}
|
|
270
|
+
catch (err) {
|
|
271
|
+
log.debug({ event: 'memory.distill.enqueue_failed', err: String(err) });
|
|
272
|
+
}
|
|
253
273
|
}
|
|
254
274
|
//# sourceMappingURL=memory-distill.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-distill.js","sourceRoot":"","sources":["../../src/core/memory-distill.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,0EAA0E;AAC1E,8DAA8D;AAC9D,EAAE;AACF,yDAAyD;AACzD,EAAE;AACF,8EAA8E;AAC9E,6EAA6E;AAC7E,kEAAkE;AAClE,mDAAmD;AACnD,EAAE;AACF,0EAA0E;AAC1E,gDAAgD;AAChD,EAAE;AACF,0EAA0E;AAC1E,4EAA4E;AAC5E,2BAA2B;AAC3B,EAAE;AACF,wEAAwE;AACxE,0EAA0E;AAC1E,mEAAmE;AACnE,EAAE;AACF,oEAAoE;AACpE,yEAAyE;AACzE,6DAA6D;AAG7D,OAAO,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,aAAa,CAAA;AAClD,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,SAAS,EAAE,OAAO,EAAqB,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"memory-distill.js","sourceRoot":"","sources":["../../src/core/memory-distill.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One distiller pass. When idle (no active agent jobs) processes every user
|
|
3
|
+
* with buffered turns; when busy, only users whose oldest pending turn has
|
|
4
|
+
* crossed the staleness floor. Returns the number of users processed.
|
|
5
|
+
*/
|
|
6
|
+
export declare function runDistillerOnce(): Promise<number>;
|
|
7
|
+
/** Start the periodic distiller. No-op if already running. */
|
|
8
|
+
export declare function startMemoryDistiller(): void;
|
|
9
|
+
/** Stop the periodic distiller (tests + graceful shutdown). */
|
|
10
|
+
export declare function stopMemoryDistiller(): void;
|
|
11
|
+
//# sourceMappingURL=memory-distiller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-distiller.d.ts","sourceRoot":"","sources":["../../src/core/memory-distiller.ts"],"names":[],"mappings":"AA6CA;;;;GAIG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC,CAiCxD;AAED,8DAA8D;AAC9D,wBAAgB,oBAAoB,IAAI,IAAI,CAW3C;AAED,+DAA+D;AAC/D,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// memory-distiller — "dream distillation" scheduler.
|
|
2
|
+
//
|
|
3
|
+
// Instead of extracting facts after every reply (per-turn LLM cost on the hot
|
|
4
|
+
// path), the router now just BUFFERS each turn into pending_distill. This
|
|
5
|
+
// background pass batch-extracts those buffered turns when the system is idle
|
|
6
|
+
// (no active agent jobs) — or, on a continuously-busy bot, once a user's
|
|
7
|
+
// oldest buffered turn passes the staleness floor so facts never lag forever.
|
|
8
|
+
//
|
|
9
|
+
// Independent of the 24h persona consolidator (memory-consolidate.ts): this
|
|
10
|
+
// only writes raw facts; consolidation rolls them into the summary on its own
|
|
11
|
+
// cadence.
|
|
12
|
+
//
|
|
13
|
+
// Tunables (env):
|
|
14
|
+
// IMHUB_MEMORY_DISTILL_ENABLED master toggle (default on when memory on)
|
|
15
|
+
// IMHUB_MEMORY_DISTILL_INTERVAL_MS tick interval (default 300000 = 5 min)
|
|
16
|
+
// IMHUB_MEMORY_DISTILL_FLOOR_MIN force-flush staleness floor (default 30)
|
|
17
|
+
// IMHUB_MEMORY_DISTILL_BATCH_MAX turns per extraction call (default 20)
|
|
18
|
+
import { logger as rootLogger } from './logger.js';
|
|
19
|
+
import { isMemoryEnabled } from './persona.js';
|
|
20
|
+
import { _activeJobCount } from './job-board.js';
|
|
21
|
+
import { listPendingUserKeys, listPendingForUser, deletePendingByIds } from './memory.js';
|
|
22
|
+
import { runBatchDistillation } from './memory-distill.js';
|
|
23
|
+
const log = rootLogger.child({ component: 'memory-distiller' });
|
|
24
|
+
let timer = null;
|
|
25
|
+
function intervalMs() {
|
|
26
|
+
const n = Number(process.env.IMHUB_MEMORY_DISTILL_INTERVAL_MS);
|
|
27
|
+
return Number.isFinite(n) && n >= 10_000 ? n : 300_000;
|
|
28
|
+
}
|
|
29
|
+
function floorSec() {
|
|
30
|
+
const n = Number(process.env.IMHUB_MEMORY_DISTILL_FLOOR_MIN);
|
|
31
|
+
return (Number.isFinite(n) && n >= 0 ? n : 30) * 60;
|
|
32
|
+
}
|
|
33
|
+
function batchMax() {
|
|
34
|
+
const n = Number(process.env.IMHUB_MEMORY_DISTILL_BATCH_MAX);
|
|
35
|
+
return Number.isFinite(n) && n >= 1 ? Math.floor(n) : 20;
|
|
36
|
+
}
|
|
37
|
+
function isDistillerEnabled() {
|
|
38
|
+
if (!isMemoryEnabled())
|
|
39
|
+
return false;
|
|
40
|
+
const raw = (process.env.IMHUB_MEMORY_DISTILL_ENABLED || '1').toLowerCase();
|
|
41
|
+
return raw !== '0' && raw !== 'false' && raw !== 'no';
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* One distiller pass. When idle (no active agent jobs) processes every user
|
|
45
|
+
* with buffered turns; when busy, only users whose oldest pending turn has
|
|
46
|
+
* crossed the staleness floor. Returns the number of users processed.
|
|
47
|
+
*/
|
|
48
|
+
export async function runDistillerOnce() {
|
|
49
|
+
if (!isDistillerEnabled())
|
|
50
|
+
return 0;
|
|
51
|
+
const idle = _activeJobCount() === 0;
|
|
52
|
+
const users = idle ? listPendingUserKeys() : listPendingUserKeys({ olderThanSec: floorSec() });
|
|
53
|
+
if (users.length === 0)
|
|
54
|
+
return 0;
|
|
55
|
+
let processed = 0;
|
|
56
|
+
for (const userKey of users) {
|
|
57
|
+
const turns = listPendingForUser(userKey, batchMax());
|
|
58
|
+
if (turns.length === 0)
|
|
59
|
+
continue;
|
|
60
|
+
// Representative agent = the newest turn's agent (turns are id-ASC, so the
|
|
61
|
+
// last one). Used by the zero-config 'auto' source.
|
|
62
|
+
const representativeAgent = turns[turns.length - 1].agent_name || '';
|
|
63
|
+
try {
|
|
64
|
+
const r = await runBatchDistillation(userKey, turns.map((t) => ({ user_message: t.user_message, agent_reply: t.agent_reply })), representativeAgent);
|
|
65
|
+
if (r.ok) {
|
|
66
|
+
// Processed (even if 0 facts were worth keeping) → clear these rows.
|
|
67
|
+
deletePendingByIds(turns.map((t) => t.id));
|
|
68
|
+
processed++;
|
|
69
|
+
log.info({ event: 'memory.distill.batch_done', userKey, turns: turns.length, saved: r.saved });
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
// No usable LLM — leave buffered, retry next pass (bounded by the
|
|
73
|
+
// per-user cap enforced at enqueue time).
|
|
74
|
+
log.debug({ event: 'memory.distill.batch_skipped', userKey, turns: turns.length });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
log.warn({ event: 'memory.distill.batch_failed', userKey, err: String(err) });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return processed;
|
|
82
|
+
}
|
|
83
|
+
/** Start the periodic distiller. No-op if already running. */
|
|
84
|
+
export function startMemoryDistiller() {
|
|
85
|
+
if (timer)
|
|
86
|
+
return;
|
|
87
|
+
const period = intervalMs();
|
|
88
|
+
log.info({ event: 'memory.distill.scheduler_start', periodMs: period });
|
|
89
|
+
timer = setInterval(() => {
|
|
90
|
+
if (!isDistillerEnabled())
|
|
91
|
+
return;
|
|
92
|
+
void runDistillerOnce().catch((err) => log.warn({ event: 'memory.distill.tick_failed', err: String(err) }));
|
|
93
|
+
}, period);
|
|
94
|
+
if (typeof timer === 'object' && timer && 'unref' in timer) {
|
|
95
|
+
timer.unref();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/** Stop the periodic distiller (tests + graceful shutdown). */
|
|
99
|
+
export function stopMemoryDistiller() {
|
|
100
|
+
if (timer) {
|
|
101
|
+
clearInterval(timer);
|
|
102
|
+
timer = null;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=memory-distiller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-distiller.js","sourceRoot":"","sources":["../../src/core/memory-distiller.ts"],"names":[],"mappings":"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"}
|
package/dist/core/memory.d.ts
CHANGED
|
@@ -152,6 +152,37 @@ export declare function exportUserMemory(user_key: string): {
|
|
|
152
152
|
/** Public retention API — useful for /api/memory/prune endpoint + tests. */
|
|
153
153
|
export declare function pruneExpiredFacts(): number;
|
|
154
154
|
export declare function pruneExpiredPersona(): number;
|
|
155
|
+
export interface PendingTurnInput {
|
|
156
|
+
user_key: string;
|
|
157
|
+
platform: string;
|
|
158
|
+
user_message: string;
|
|
159
|
+
agent_reply: string;
|
|
160
|
+
agent_name?: string;
|
|
161
|
+
trace_id?: string;
|
|
162
|
+
}
|
|
163
|
+
export interface PendingTurn {
|
|
164
|
+
id: number;
|
|
165
|
+
user_key: string;
|
|
166
|
+
platform: string;
|
|
167
|
+
user_message: string;
|
|
168
|
+
agent_reply: string;
|
|
169
|
+
agent_name: string;
|
|
170
|
+
trace_id: string;
|
|
171
|
+
created_at: number;
|
|
172
|
+
}
|
|
173
|
+
/** Buffer one (user msg, agent reply) turn for later batch distillation.
|
|
174
|
+
* Best-effort (a write failure / disabled sqlite is swallowed). Enforces a
|
|
175
|
+
* per-user cap by dropping the oldest rows beyond `maxPerUser` (backpressure). */
|
|
176
|
+
export declare function enqueuePendingTurn(input: PendingTurnInput, maxPerUser?: number): void;
|
|
177
|
+
/** Distinct user_keys with buffered turns. When `olderThanSec` is set, only
|
|
178
|
+
* users whose OLDEST pending turn is at least that old (the staleness floor). */
|
|
179
|
+
export declare function listPendingUserKeys(opts?: {
|
|
180
|
+
olderThanSec?: number;
|
|
181
|
+
}): string[];
|
|
182
|
+
/** Oldest-first buffered turns for a user, capped at `limit`. */
|
|
183
|
+
export declare function listPendingForUser(user_key: string, limit: number): PendingTurn[];
|
|
184
|
+
export declare function deletePendingByIds(ids: number[]): void;
|
|
185
|
+
export declare function countPendingTotal(): number;
|
|
155
186
|
/** Stop the periodic retention sweep (tests + graceful shutdown). */
|
|
156
187
|
export declare function stopMemoryRetentionSweep(): void;
|
|
157
188
|
export declare function closeMemoryDb(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/core/memory.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/core/memory.ts"],"names":[],"mappings":"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"}
|