@yeaft/webchat-agent 0.1.665 → 0.1.667
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/connection/message-router.js +1 -24
- package/package.json +1 -1
- package/unify/cli.js +5 -84
- package/unify/config.js +2 -2
- package/unify/dream-v2/apply.js +1 -1
- package/unify/dream-v2/limits.js +1 -1
- package/unify/dream-v2/merge.js +1 -1
- package/unify/dream-v2/runner.js +2 -2
- package/unify/dream-v2/schedule.js +2 -2
- package/unify/dream-v2/segment.js +1 -1
- package/unify/dream-v2/session-wiring.js +2 -3
- package/unify/dream-v2/snapshot.js +1 -1
- package/unify/dream-v2/state.js +1 -1
- package/unify/dream-v2/triage.js +1 -1
- package/unify/engine.js +23 -133
- package/unify/eval/cases/memory.js +9 -142
- package/unify/features/summary.js +15 -98
- package/unify/index.js +0 -2
- package/unify/memory/ams.js +1 -1
- package/unify/memory/consolidate.js +10 -125
- package/unify/memory/segment-store.js +1 -1
- package/unify/memory/store-v2.js +6 -9
- package/unify/prompts.js +8 -50
- package/unify/session.js +2 -22
- package/unify/stop-hooks.js +8 -44
- package/unify/tools/index.js +0 -11
- package/unify/web-bridge.js +0 -98
- package/unify/memory/dream-shard.js +0 -722
- package/unify/memory/extract.js +0 -101
- package/unify/memory/layout.js +0 -358
- package/unify/memory/schema.js +0 -166
- package/unify/memory/shard-store.js +0 -373
- package/unify/memory/store.js +0 -578
- package/unify/memory/types.js +0 -139
- package/unify/memory/user-memory-store.js +0 -452
- package/unify/tools/memory-query.js +0 -134
- package/unify/tools/memory-read.js +0 -90
- package/unify/tools/memory-search.js +0 -140
- package/unify/tools/memory-trace.js +0 -135
- package/unify/tools/memory-write.js +0 -113
- package/unify/user-memory.js +0 -107
|
@@ -36,7 +36,7 @@ import { sendToServer, flushMessageBuffer } from './buffer.js';
|
|
|
36
36
|
import { handleRestartAgent, handleUpgradeAgent } from './upgrade.js';
|
|
37
37
|
import { loadMcpServers, updateMcpConfig } from '../mcp.js';
|
|
38
38
|
import { getLlmConfig, updateLlmConfig, getUnifySettings, updateUnifySettings } from '../unify/config-api.js';
|
|
39
|
-
import { handleUnifyChat, handleUnifyGroupChat, handleUnifyModeSwitch, handleUnifyModelSwitch, resetUnifySession, handleUnifyLoadHistory, handleUnifyAbortThread, handleUnifyAbortAll, handleUnifyVpSubscribe, handleUnifyVpCreate, handleUnifyVpUpdate, handleUnifyVpDelete, handleUnifyVpRead, handleUnifyFeatureMessage,
|
|
39
|
+
import { handleUnifyChat, handleUnifyGroupChat, handleUnifyModeSwitch, handleUnifyModelSwitch, resetUnifySession, handleUnifyLoadHistory, handleUnifyAbortThread, handleUnifyAbortAll, handleUnifyVpSubscribe, handleUnifyVpCreate, handleUnifyVpUpdate, handleUnifyVpDelete, handleUnifyVpRead, handleUnifyFeatureMessage, handleUnifyFetchSummaryHistory, handleUnifyFeatureCrud, handleUnifyListGroups, handleUnifyCreateGroup, handleUnifyRenameGroup, handleUnifyArchiveGroup, handleUnifyDeleteGroup, handleUnifyAddMember, handleUnifyRemoveMember, handleUnifySetDefaultVp, handleUnifyDreamTrigger } from '../unify/web-bridge.js';
|
|
40
40
|
|
|
41
41
|
export async function handleMessage(msg) {
|
|
42
42
|
switch (msg.type) {
|
|
@@ -424,29 +424,6 @@ export async function handleMessage(msg) {
|
|
|
424
424
|
handleUnifyFeatureMessage(msg);
|
|
425
425
|
break;
|
|
426
426
|
|
|
427
|
-
// task-334h (R6 §Δ29): user-memory skeleton. Payload schema + event
|
|
428
|
-
// names are wire-frozen here; real ingestion lands in task-334l.
|
|
429
|
-
case 'unify_user_memory_write':
|
|
430
|
-
handleUnifyUserMemoryWrite(msg);
|
|
431
|
-
break;
|
|
432
|
-
case 'unify_user_memory_remove':
|
|
433
|
-
handleUnifyUserMemoryRemove(msg);
|
|
434
|
-
break;
|
|
435
|
-
// task-fix: list MemoryStore entries (scope-tree folder view) for the
|
|
436
|
-
// Unify "User Memory" page. Replies with `memory_scope_snapshot`.
|
|
437
|
-
case 'unify_memory_scope_list':
|
|
438
|
-
handleUnifyMemoryScopeList(msg);
|
|
439
|
-
break;
|
|
440
|
-
|
|
441
|
-
// R6 G2 — VP/Task memory browser (read-only). Replies with
|
|
442
|
-
// unify_memory_query_result / unify_memory_trace_result.
|
|
443
|
-
case 'unify_memory_query':
|
|
444
|
-
handleUnifyMemoryQuery(msg);
|
|
445
|
-
break;
|
|
446
|
-
case 'unify_memory_trace':
|
|
447
|
-
handleUnifyMemoryTrace(msg);
|
|
448
|
-
break;
|
|
449
|
-
|
|
450
427
|
// R6 G1a — feature summary history + feature affiliation CRUD.
|
|
451
428
|
case 'unify_fetch_summary_history':
|
|
452
429
|
await handleUnifyFetchSummaryHistory(msg);
|
package/package.json
CHANGED
package/unify/cli.js
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* --skip-skills — Skip skill loading
|
|
15
15
|
*
|
|
16
16
|
* REPL commands:
|
|
17
|
-
* /
|
|
17
|
+
* /history — Show conversation history
|
|
18
18
|
* /history [n] — Show last N messages from conversation
|
|
19
19
|
* /search <keyword> — Search conversation history
|
|
20
20
|
* /compact — Trigger manual consolidation
|
|
@@ -31,7 +31,6 @@ import { loadSession } from './session.js';
|
|
|
31
31
|
import { listModels, resolveModel, parseModelRef } from './models.js';
|
|
32
32
|
import { buildSystemPrompt } from './prompts.js';
|
|
33
33
|
import { searchMessages } from './conversation/search.js';
|
|
34
|
-
import { consolidate } from './memory/consolidate.js';
|
|
35
34
|
|
|
36
35
|
// ─── Argument parsing ──────────────────────────────────────────
|
|
37
36
|
|
|
@@ -211,7 +210,7 @@ async function runREPL(config, args) {
|
|
|
211
210
|
skipSkills: args.skipSkills,
|
|
212
211
|
});
|
|
213
212
|
|
|
214
|
-
const { engine, conversationStore,
|
|
213
|
+
const { engine, conversationStore, trace, skillManager, mcpManager, toolRegistry } = session;
|
|
215
214
|
|
|
216
215
|
// Load persisted conversation as initial messages
|
|
217
216
|
let conversationMessages = conversationStore.loadRecent(50).map(m => ({
|
|
@@ -223,10 +222,9 @@ async function runREPL(config, args) {
|
|
|
223
222
|
|
|
224
223
|
const hotCount = conversationStore.countHot();
|
|
225
224
|
const coldCount = conversationStore.countCold();
|
|
226
|
-
const memStats = memoryStore.stats();
|
|
227
225
|
|
|
228
226
|
console.log(`Yeaft Unify REPL (model: ${session.config.model})`);
|
|
229
|
-
console.log(`Conversation: ${hotCount} hot, ${coldCount} cold
|
|
227
|
+
console.log(`Conversation: ${hotCount} hot, ${coldCount} cold`);
|
|
230
228
|
console.log(`Tools: ${session.status.tools} | Skills: ${session.status.skills}`);
|
|
231
229
|
if (session.status.mcpServers.length > 0) {
|
|
232
230
|
console.log(`MCP: ${session.status.mcpServers.join(', ')}`);
|
|
@@ -260,7 +258,6 @@ async function runREPL(config, args) {
|
|
|
260
258
|
console.log('Commands:');
|
|
261
259
|
console.log(' /debug — Toggle debug mode');
|
|
262
260
|
console.log(' /trace <stats|recent> — Query debug trace');
|
|
263
|
-
console.log(' /memory [add|clear|stats] — Memory management');
|
|
264
261
|
console.log(' /history [n] — Show last N messages');
|
|
265
262
|
console.log(' /search <keyword> — Search conversation history');
|
|
266
263
|
console.log(' /compact — Trigger consolidation');
|
|
@@ -293,55 +290,7 @@ async function runREPL(config, args) {
|
|
|
293
290
|
}
|
|
294
291
|
|
|
295
292
|
case 'memory': {
|
|
296
|
-
|
|
297
|
-
if (subcmd === 'add') {
|
|
298
|
-
// /memory add <section> <entry text>
|
|
299
|
-
const section = cmdArgs[1];
|
|
300
|
-
const entryText = cmdArgs.slice(2).join(' ');
|
|
301
|
-
if (!section || !entryText) {
|
|
302
|
-
console.log('Usage: /memory add <section> <entry text>');
|
|
303
|
-
} else {
|
|
304
|
-
memoryStore.addToSection(section, `- ${entryText}`);
|
|
305
|
-
console.log(`Added to MEMORY.md [${section}]: ${entryText}`);
|
|
306
|
-
}
|
|
307
|
-
} else if (subcmd === 'clear') {
|
|
308
|
-
memoryStore.clear();
|
|
309
|
-
console.log('All memory cleared.');
|
|
310
|
-
} else if (subcmd === 'stats') {
|
|
311
|
-
const s = memoryStore.stats();
|
|
312
|
-
console.log('Memory stats:');
|
|
313
|
-
console.log(` Entries: ${s.entryCount}`);
|
|
314
|
-
console.log(` Scopes: ${s.scopes.join(', ') || '(none)'}`);
|
|
315
|
-
console.log(` Kinds: ${Object.entries(s.kinds).map(([k, v]) => `${k}=${v}`).join(', ') || '(none)'}`);
|
|
316
|
-
} else if (subcmd === 'search') {
|
|
317
|
-
const keyword = cmdArgs.slice(1).join(' ');
|
|
318
|
-
if (!keyword) {
|
|
319
|
-
console.log('Usage: /memory search <keyword>');
|
|
320
|
-
} else {
|
|
321
|
-
const results = memoryStore.search(keyword);
|
|
322
|
-
if (results.length === 0) {
|
|
323
|
-
console.log(`No memory entries matching "${keyword}".`);
|
|
324
|
-
} else {
|
|
325
|
-
console.log(`Found ${results.length} entries:`);
|
|
326
|
-
for (const e of results) {
|
|
327
|
-
console.log(` [${e.kind}] ${e.name} (scope: ${e.scope})`);
|
|
328
|
-
console.log(` ${(e.content || '').slice(0, 100)}`);
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
} else {
|
|
333
|
-
// Default: show MEMORY.md content
|
|
334
|
-
const profile = memoryStore.readProfile();
|
|
335
|
-
const s = memoryStore.stats();
|
|
336
|
-
if (profile) {
|
|
337
|
-
console.log('--- MEMORY.md ---');
|
|
338
|
-
console.log(profile.slice(0, 1000));
|
|
339
|
-
if (profile.length > 1000) console.log('... (truncated)');
|
|
340
|
-
} else {
|
|
341
|
-
console.log('MEMORY.md is empty.');
|
|
342
|
-
}
|
|
343
|
-
console.log(`\nEntries: ${s.entryCount} | Scopes: ${s.scopes.length}`);
|
|
344
|
-
}
|
|
293
|
+
console.log('Memory commands have been retired. Memory is now managed by Dream V2; use the in-app FTS recall.');
|
|
345
294
|
break;
|
|
346
295
|
}
|
|
347
296
|
|
|
@@ -382,33 +331,7 @@ async function runREPL(config, args) {
|
|
|
382
331
|
}
|
|
383
332
|
|
|
384
333
|
case 'compact': {
|
|
385
|
-
|
|
386
|
-
const budget = session.config.messageTokenBudget || 8192;
|
|
387
|
-
const hotTokens = conversationStore.hotTokens();
|
|
388
|
-
console.log(`Hot tokens: ${hotTokens} / budget: ${budget}`);
|
|
389
|
-
|
|
390
|
-
if (hotTokens <= 0) {
|
|
391
|
-
console.log('No messages to compact.');
|
|
392
|
-
break;
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
console.log('Running consolidation...');
|
|
396
|
-
const result = await consolidate({
|
|
397
|
-
conversationStore,
|
|
398
|
-
memoryStore,
|
|
399
|
-
adapter: session.adapter,
|
|
400
|
-
config: session.config,
|
|
401
|
-
budget: Math.min(budget, hotTokens), // force trigger
|
|
402
|
-
});
|
|
403
|
-
console.log(`Consolidation complete:`);
|
|
404
|
-
console.log(` Archived: ${result.archivedCount} messages`);
|
|
405
|
-
console.log(` Extracted: ${result.extractedEntries.length} memory entries`);
|
|
406
|
-
if (result.compactSummary) {
|
|
407
|
-
console.log(` Summary: ${result.compactSummary.slice(0, 200)}...`);
|
|
408
|
-
}
|
|
409
|
-
} catch (e) {
|
|
410
|
-
console.error(`Consolidation error: ${e.message}`);
|
|
411
|
-
}
|
|
334
|
+
console.log('The /compact REPL command is retired. Compaction is driven automatically by the engine when the hot-window budget is exceeded.');
|
|
412
335
|
break;
|
|
413
336
|
}
|
|
414
337
|
|
|
@@ -421,7 +344,6 @@ async function runREPL(config, args) {
|
|
|
421
344
|
console.log(` Hot messages: ${conversationStore.countHot()}`);
|
|
422
345
|
console.log(` Hot tokens: ${conversationStore.hotTokens()}`);
|
|
423
346
|
console.log(` Cold messages: ${conversationStore.countCold()}`);
|
|
424
|
-
console.log(` Memory entries: ${memoryStore.stats().entryCount}`);
|
|
425
347
|
console.log(` Tools: ${toolRegistry.size}`);
|
|
426
348
|
console.log(` Skills: ${skillManager.size}`);
|
|
427
349
|
break;
|
|
@@ -438,7 +360,6 @@ async function runREPL(config, args) {
|
|
|
438
360
|
console.log(` Tools: ${s.toolCount}`);
|
|
439
361
|
console.log(` Hot messages: ${conversationStore.countHot()}`);
|
|
440
362
|
console.log(` Cold messages: ${conversationStore.countCold()}`);
|
|
441
|
-
console.log(` Memory entries: ${memoryStore.stats().entryCount}`);
|
|
442
363
|
console.log(` Registered tools: ${toolRegistry.size}`);
|
|
443
364
|
console.log(` Loaded skills: ${skillManager.size}`);
|
|
444
365
|
break;
|
package/unify/config.js
CHANGED
|
@@ -217,7 +217,7 @@ function loadLegacyConfig(dir, overrides) {
|
|
|
217
217
|
maxContinueTurns: overrides.maxContinueTurns ?? fileConfig.maxContinueTurns ?? DEFAULTS.maxContinueTurns,
|
|
218
218
|
// task-318: legacy path never had the `unify` section — defaults.
|
|
219
219
|
unify: normaliseUnifySection(null),
|
|
220
|
-
//
|
|
220
|
+
// H2-AMS feature flag. Default true. Override wins.
|
|
221
221
|
memoryV2: overrides.memoryV2 !== undefined ? !!overrides.memoryV2 : true,
|
|
222
222
|
providers: null,
|
|
223
223
|
primaryModel: null,
|
|
@@ -315,7 +315,7 @@ export function loadConfig(overrides = {}) {
|
|
|
315
315
|
// don't pollute the flat config namespace used by chat/crew code.
|
|
316
316
|
unify: normaliseUnifySection(jsonConfig.unify),
|
|
317
317
|
|
|
318
|
-
//
|
|
318
|
+
// H2-AMS feature flag. When true the session opens the FTS5
|
|
319
319
|
// SegmentIndex (used by groups/pre-flow.js → memory/preflow.js
|
|
320
320
|
// for pre-turn recall) and wires the v2 dream pipeline
|
|
321
321
|
// (dream-v2/runner.js). When false both are skipped — no recall,
|
package/unify/dream-v2/apply.js
CHANGED
package/unify/dream-v2/limits.js
CHANGED
package/unify/dream-v2/merge.js
CHANGED
package/unify/dream-v2/runner.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* dream-v2/runner.js
|
|
2
|
+
* dream-v2/runner.js.
|
|
3
3
|
*
|
|
4
4
|
* Orchestrates one full dream pass:
|
|
5
5
|
*
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
*
|
|
30
30
|
* onProgress emits dream_progress events that the web bridge forwards
|
|
31
31
|
* as `unify_output` messages so the debug panel can render live state
|
|
32
|
-
*
|
|
32
|
+
* . All events flow through the same channel; no new
|
|
33
33
|
* WebSocket message type is introduced.
|
|
34
34
|
*
|
|
35
35
|
* Everything that touches a shell of the system (LLM, message store,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* dream-v2/schedule.js
|
|
2
|
+
* dream-v2/schedule.js.
|
|
3
3
|
*
|
|
4
4
|
* Two trigger paths:
|
|
5
5
|
*
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*
|
|
11
11
|
* The scheduler is a thin wrapper around `runDream()` that prevents
|
|
12
12
|
* concurrent passes (a second tick while the previous is still running
|
|
13
|
-
* is dropped, not queued
|
|
13
|
+
* is dropped, not queued: "slow is OK, doesn't
|
|
14
14
|
* compete with user latency").
|
|
15
15
|
*/
|
|
16
16
|
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* dream-v2/session-wiring.js
|
|
2
|
+
* dream-v2/session-wiring.js wire-up for session.js.
|
|
3
3
|
*
|
|
4
4
|
* Bridges the framework-agnostic `runDream` orchestrator (dream-v2/runner.js)
|
|
5
5
|
* to the live yeaft session: groups store, conversation log, LLM adapter,
|
|
6
6
|
* and the engine's progress event sink.
|
|
7
7
|
*
|
|
8
8
|
* The dream pipeline only activates when `config.memoryV2 === true`. When
|
|
9
|
-
* the flag is off, this module is a no-op
|
|
10
|
-
* keeps running as before (session.js still wires it).
|
|
9
|
+
* the flag is off, this module is a no-op.
|
|
11
10
|
*/
|
|
12
11
|
|
|
13
12
|
import { join } from 'path';
|
package/unify/dream-v2/state.js
CHANGED
package/unify/dream-v2/triage.js
CHANGED
package/unify/engine.js
CHANGED
|
@@ -21,13 +21,11 @@ import { randomUUID } from 'crypto';
|
|
|
21
21
|
import { buildSystemPrompt, buildWorkerPrompt } from './prompts.js';
|
|
22
22
|
import { LLMContextError, LLMAbortError } from './llm/adapter.js';
|
|
23
23
|
import { runMemoryPreflow, buildRelevantScopes } from './groups/pre-flow.js';
|
|
24
|
-
import { shouldConsolidate,
|
|
25
|
-
import { extractMemories } from './memory/extract.js';
|
|
24
|
+
import { shouldConsolidate, partitionMessages } from './memory/consolidate.js';
|
|
26
25
|
import { runCompact as runCompactOrchestrator } from './compact/orchestrator.js';
|
|
27
26
|
import { evaluateCompactTriggers } from './compact/triggers.js';
|
|
28
27
|
import { archiveTurn } from './archive/turn-archive.js';
|
|
29
28
|
import { archiveToolResults } from './archive/tool-results.js';
|
|
30
|
-
import { buildMemoryInjection } from './memory/layout.js';
|
|
31
29
|
import { readSummary as readScopeSummary } from './memory/store-v2.js';
|
|
32
30
|
import { runAdjust } from './memory/adjust.js';
|
|
33
31
|
import { runStopHooks } from './stop-hooks.js';
|
|
@@ -145,12 +143,6 @@ export class Engine {
|
|
|
145
143
|
/** @type {import('./conversation/persist.js').ConversationStore|null} */
|
|
146
144
|
#conversationStore;
|
|
147
145
|
|
|
148
|
-
/** @type {import('./memory/store.js').MemoryStore|null} */
|
|
149
|
-
#memoryStore;
|
|
150
|
-
|
|
151
|
-
/** @type {object|null} — R6 memory shard store (task-334f) */
|
|
152
|
-
#memoryShardStore;
|
|
153
|
-
|
|
154
146
|
/** @type {import('./memory/index-db.js').SegmentIndex|null} — GC.1: SQLite FTS5 segment index */
|
|
155
147
|
#memoryIndex;
|
|
156
148
|
|
|
@@ -235,7 +227,6 @@ export class Engine {
|
|
|
235
227
|
* trace: object,
|
|
236
228
|
* config: object,
|
|
237
229
|
* conversationStore?: import('./conversation/persist.js').ConversationStore,
|
|
238
|
-
* memoryStore?: import('./memory/store.js').MemoryStore,
|
|
239
230
|
* memoryIndex?: import('./memory/index-db.js').SegmentIndex,
|
|
240
231
|
* toolRegistry?: import('./tools/registry.js').ToolRegistry,
|
|
241
232
|
* skillManager?: import('./skills.js').SkillManager,
|
|
@@ -243,15 +234,13 @@ export class Engine {
|
|
|
243
234
|
* yeaftDir?: string,
|
|
244
235
|
* }} params
|
|
245
236
|
*/
|
|
246
|
-
constructor({ adapter, trace, config, conversationStore,
|
|
237
|
+
constructor({ adapter, trace, config, conversationStore, memoryIndex, amsRegistry, toolRegistry, skillManager, mcpManager, yeaftDir }) {
|
|
247
238
|
this.#adapter = adapter;
|
|
248
239
|
this.#trace = trace;
|
|
249
240
|
this.#config = config;
|
|
250
241
|
this.#tools = new Map();
|
|
251
242
|
this.#traceId = randomUUID();
|
|
252
243
|
this.#conversationStore = conversationStore || null;
|
|
253
|
-
this.#memoryStore = memoryStore || null;
|
|
254
|
-
this.#memoryShardStore = memoryShardStore || null;
|
|
255
244
|
this.#memoryIndex = memoryIndex || null;
|
|
256
245
|
this.#amsRegistry = amsRegistry || null;
|
|
257
246
|
this.#toolRegistry = toolRegistry || null;
|
|
@@ -568,8 +557,8 @@ export class Engine {
|
|
|
568
557
|
* @param {{ profile?: string, entries?: object[] }} [memory]
|
|
569
558
|
* @param {string} [compactSummary]
|
|
570
559
|
* @param {string} [prompt] — user prompt (for skill relevance matching)
|
|
571
|
-
* @param {string} [memoryInjection] —
|
|
572
|
-
* @param {string} [userProfile] — user profile
|
|
560
|
+
* @param {string} [memoryInjection] — prebuilt memory block from preflow
|
|
561
|
+
* @param {string} [userProfile] — user profile string
|
|
573
562
|
* @param {object} [vpPersona]
|
|
574
563
|
* @param {{user?:string, group?:string, vp?:string}} [summaries]
|
|
575
564
|
* @returns {string}
|
|
@@ -619,8 +608,6 @@ export class Engine {
|
|
|
619
608
|
cwd: process.cwd(),
|
|
620
609
|
mcpManager: this.#mcpManager,
|
|
621
610
|
skillManager: this.#skillManager,
|
|
622
|
-
memoryStore: this.#memoryStore,
|
|
623
|
-
memoryShardStore: this.#memoryShardStore,
|
|
624
611
|
conversationStore: this.#conversationStore,
|
|
625
612
|
adapter: this.#adapter,
|
|
626
613
|
config: this.#config,
|
|
@@ -644,8 +631,6 @@ export class Engine {
|
|
|
644
631
|
adapter: this.#adapter,
|
|
645
632
|
trace: this.#trace,
|
|
646
633
|
config: this.#config,
|
|
647
|
-
memoryStore: this.#memoryStore,
|
|
648
|
-
memoryShardStore: this.#memoryShardStore,
|
|
649
634
|
parentToolRegistry: this.#toolRegistry,
|
|
650
635
|
skillManager: this.#skillManager,
|
|
651
636
|
mcpManager: this.#mcpManager,
|
|
@@ -759,64 +744,21 @@ export class Engine {
|
|
|
759
744
|
* @returns {Promise<{ archivedCount: number, extractedCount: number }|null>}
|
|
760
745
|
*/
|
|
761
746
|
async #maybeConsolidate() {
|
|
762
|
-
if (!this.#conversationStore
|
|
747
|
+
if (!this.#conversationStore) return null;
|
|
763
748
|
if (this.#config._readOnly) return null;
|
|
764
749
|
|
|
765
750
|
const budget = this.#config.messageTokenBudget || 8192;
|
|
766
751
|
const compactCfg = (this.#config && this.#config.compact) || {};
|
|
767
|
-
|
|
768
|
-
// Phase 8 PR-H: orchestrator is now the default. The legacy
|
|
769
|
-
// shouldConsolidate / consolidate path remains reachable as an
|
|
770
|
-
// explicit fallback via `config.compact.useLegacy=true` for parity
|
|
771
|
-
// testing during migration. evaluateCompactTriggers (DESIGN §4.1)
|
|
772
|
-
// and runCompact (DESIGN §4.2) own the live path.
|
|
773
|
-
const useLegacy = compactCfg.useLegacy === true || compactCfg.useOrchestrator === false;
|
|
774
|
-
if (!useLegacy) {
|
|
775
|
-
return this.#runOrchestratorCompact(budget, compactCfg);
|
|
776
|
-
}
|
|
777
|
-
|
|
778
|
-
// Default path — surface trigger reasons via trace for observability
|
|
779
|
-
// even when we still fall through to the legacy consolidate.
|
|
780
|
-
try {
|
|
781
|
-
const messages = this.#conversationStore.loadAll();
|
|
782
|
-
const tokenCount = this.#conversationStore.hotTokens();
|
|
783
|
-
const trig = evaluateCompactTriggers({
|
|
784
|
-
messages,
|
|
785
|
-
tokenCount,
|
|
786
|
-
contextLimit: this.#config.maxContextTokens || 200000,
|
|
787
|
-
tokenRatio: compactCfg.tokenRatio,
|
|
788
|
-
maxMessages: compactCfg.maxMessages,
|
|
789
|
-
});
|
|
790
|
-
this.#trace.logEvent && this.#trace.logEvent({
|
|
791
|
-
traceId: 'compact_triggers_eval',
|
|
792
|
-
eventType: 'compact_triggers_eval',
|
|
793
|
-
eventData: { trigger: trig.trigger, reasons: trig.reasons },
|
|
794
|
-
});
|
|
795
|
-
} catch { /* observability only */ }
|
|
796
|
-
|
|
797
|
-
if (!shouldConsolidate(this.#conversationStore, budget)) return null;
|
|
798
|
-
|
|
799
|
-
try {
|
|
800
|
-
const result = await consolidate({
|
|
801
|
-
conversationStore: this.#conversationStore,
|
|
802
|
-
memoryStore: this.#memoryStore,
|
|
803
|
-
adapter: this.#adapter,
|
|
804
|
-
config: this.#fastConfig,
|
|
805
|
-
budget,
|
|
806
|
-
});
|
|
807
|
-
return { archivedCount: result.archivedCount, extractedCount: result.extractedEntries.length };
|
|
808
|
-
} catch {
|
|
809
|
-
// Consolidation failure is non-critical
|
|
810
|
-
return null;
|
|
811
|
-
}
|
|
752
|
+
return this.#runOrchestratorCompact(budget, compactCfg);
|
|
812
753
|
}
|
|
813
754
|
|
|
814
755
|
/**
|
|
815
|
-
*
|
|
816
|
-
*
|
|
817
|
-
*
|
|
818
|
-
*
|
|
819
|
-
*
|
|
756
|
+
* Run compact via the orchestrator (DESIGN §4.2).
|
|
757
|
+
*
|
|
758
|
+
* PR-B rip: the legacy entries-based extract hook is gone — Dream V2
|
|
759
|
+
* owns durable memory extraction now. The orchestrator runs Track 1
|
|
760
|
+
* (compaction + summary) and Track 2 (task summary refresh, when wired);
|
|
761
|
+
* Track 3 (extract) is intentionally omitted.
|
|
820
762
|
*
|
|
821
763
|
* @param {number} budget
|
|
822
764
|
* @param {object} compactCfg
|
|
@@ -824,7 +766,6 @@ export class Engine {
|
|
|
824
766
|
*/
|
|
825
767
|
async #runOrchestratorCompact(budget, _compactCfg) {
|
|
826
768
|
const conversationStore = this.#conversationStore;
|
|
827
|
-
const memoryStore = this.#memoryStore;
|
|
828
769
|
const adapter = this.#adapter;
|
|
829
770
|
const fastConfig = this.#fastConfig;
|
|
830
771
|
|
|
@@ -842,9 +783,9 @@ export class Engine {
|
|
|
842
783
|
});
|
|
843
784
|
if (!trig.trigger) return null;
|
|
844
785
|
|
|
845
|
-
// Use partitionMessages
|
|
846
|
-
//
|
|
847
|
-
//
|
|
786
|
+
// Use partitionMessages to decide what is "cooling": orchestrator's
|
|
787
|
+
// own keepHot is a count, but we want to honour the token-budget
|
|
788
|
+
// partitioning the rest of the system uses.
|
|
848
789
|
const { toArchive } = partitionMessages(messages, budget);
|
|
849
790
|
if (toArchive.length === 0) return null;
|
|
850
791
|
|
|
@@ -852,10 +793,6 @@ export class Engine {
|
|
|
852
793
|
|
|
853
794
|
const hooks = {
|
|
854
795
|
summarise: async () => {
|
|
855
|
-
// Reuse the legacy consolidate path's summary technique by
|
|
856
|
-
// invoking adapter directly with a fresh prompt. We keep the
|
|
857
|
-
// orchestrator's contract honoured: it takes the cooling slice
|
|
858
|
-
// and returns a string.
|
|
859
796
|
try {
|
|
860
797
|
const result = await adapter.call({
|
|
861
798
|
model: fastConfig.model,
|
|
@@ -871,11 +808,6 @@ export class Engine {
|
|
|
871
808
|
archive: async (_groupIdx, groupMsgs) => {
|
|
872
809
|
for (const m of groupMsgs) if (m.id) archiveIds.push(m.id);
|
|
873
810
|
const turnId = groupMsgs[0]?.id || `g_${Date.now()}`;
|
|
874
|
-
// Phase 8 PR-E: persist the cooling turn to
|
|
875
|
-
// <yeaftDir>/memory/archive/<turnId>.md so message_trace can
|
|
876
|
-
// replay it later. Scope is "user/" by default — group/task
|
|
877
|
-
// scoping is a follow-up that will arrive with multi-VP archive
|
|
878
|
-
// routing. Best-effort: archive failure must not abort compact.
|
|
879
811
|
if (this.#yeaftDir) {
|
|
880
812
|
try {
|
|
881
813
|
await archiveTurn({
|
|
@@ -888,26 +820,12 @@ export class Engine {
|
|
|
888
820
|
}
|
|
889
821
|
return { turnId };
|
|
890
822
|
},
|
|
891
|
-
extract: async (coolingMessages) => {
|
|
892
|
-
try {
|
|
893
|
-
const extracted = await extractMemories({
|
|
894
|
-
messages: coolingMessages, adapter, config: fastConfig,
|
|
895
|
-
});
|
|
896
|
-
for (const e of extracted) memoryStore.writeEntry(e);
|
|
897
|
-
if (extracted.length > 0) memoryStore.rebuildScopes();
|
|
898
|
-
return { written: extracted.length };
|
|
899
|
-
} catch {
|
|
900
|
-
return { written: 0 };
|
|
901
|
-
}
|
|
902
|
-
},
|
|
903
823
|
};
|
|
904
824
|
|
|
905
825
|
try {
|
|
906
826
|
const out = await runCompactOrchestrator({
|
|
907
827
|
messages, keepHot: 10, hooks,
|
|
908
828
|
});
|
|
909
|
-
// Apply side effects to the conversation store: move archived
|
|
910
|
-
// ids to cold, persist compact summary, update index.
|
|
911
829
|
if (archiveIds.length > 0) conversationStore.moveToColdBatch(archiveIds);
|
|
912
830
|
if (out.compactSummary) conversationStore.updateCompactSummary(out.compactSummary);
|
|
913
831
|
const lastKept = messages[messages.length - 1];
|
|
@@ -1012,30 +930,16 @@ export class Engine {
|
|
|
1012
930
|
*/
|
|
1013
931
|
async *#runQuery({ prompt, messages, signal, userEffort = null, scenario = 'chat', vpPersona, router, senderVpId, inboundEnvelope, taskId, taskMembers, groupId, vpPlan }) {
|
|
1014
932
|
|
|
1015
|
-
// ─── Pre-query: Memory
|
|
1016
|
-
//
|
|
1017
|
-
//
|
|
1018
|
-
//
|
|
1019
|
-
//
|
|
1020
|
-
//
|
|
1021
|
-
// memory_query on demand (memory_search still works as a deprecated alias).
|
|
933
|
+
// ─── Pre-query: FTS5 Memory Recall + Compact Summary ──
|
|
934
|
+
// Memory feed comes from two places:
|
|
935
|
+
// (a) FTS5 pre-flow recall (#recallMemory → groups/pre-flow.js →
|
|
936
|
+
// memory/preflow.js) — per-turn scoped recall
|
|
937
|
+
// (b) AMS snapshot (resident summaries + onDemand FTS hits) appended
|
|
938
|
+
// below
|
|
1022
939
|
let memoryInjection = '';
|
|
1023
940
|
let recallEntryCount = 0;
|
|
1024
|
-
if (this.#yeaftDir) {
|
|
1025
|
-
try {
|
|
1026
|
-
const entryCount = this.#memoryStore?.stats?.().entryCount ?? 0;
|
|
1027
|
-
memoryInjection = buildMemoryInjection({
|
|
1028
|
-
yeaftDir: this.#yeaftDir,
|
|
1029
|
-
cwd: process.cwd(),
|
|
1030
|
-
entryCount,
|
|
1031
|
-
language: this.#config.language || 'en',
|
|
1032
|
-
});
|
|
1033
|
-
} catch {
|
|
1034
|
-
// Injection failure is non-critical — fall back to empty.
|
|
1035
|
-
}
|
|
1036
|
-
}
|
|
1037
941
|
|
|
1038
|
-
//
|
|
942
|
+
// FTS5 recall: append per-turn scoped hits to memory injection
|
|
1039
943
|
const recallResult = await this.#recallMemory(prompt, {
|
|
1040
944
|
groupId,
|
|
1041
945
|
vpId: vpPersona && typeof vpPersona === 'object' && typeof vpPersona.vpId === 'string'
|
|
@@ -1326,7 +1230,7 @@ export class Engine {
|
|
|
1326
1230
|
}
|
|
1327
1231
|
|
|
1328
1232
|
// ─── LLMContextError → force compact → retry ──────
|
|
1329
|
-
if (err instanceof LLMContextError && this.#conversationStore
|
|
1233
|
+
if (err instanceof LLMContextError && this.#conversationStore) {
|
|
1330
1234
|
const consolidated = await this.#maybeConsolidate();
|
|
1331
1235
|
if (consolidated && consolidated.archivedCount > 0) {
|
|
1332
1236
|
yield { type: 'consolidate', archivedCount: consolidated.archivedCount, extractedCount: consolidated.extractedCount };
|
|
@@ -1451,7 +1355,6 @@ export class Engine {
|
|
|
1451
1355
|
const hookResult = await runStopHooks({
|
|
1452
1356
|
yeaftDir: this.#yeaftDir,
|
|
1453
1357
|
conversationStore: this.#conversationStore,
|
|
1454
|
-
memoryStore: this.#memoryStore,
|
|
1455
1358
|
adapter: this.#adapter,
|
|
1456
1359
|
config: this.#fastConfig,
|
|
1457
1360
|
primaryModel: this.#config.model,
|
|
@@ -1780,19 +1683,6 @@ export class Engine {
|
|
|
1780
1683
|
return this.#conversationStore;
|
|
1781
1684
|
}
|
|
1782
1685
|
|
|
1783
|
-
/**
|
|
1784
|
-
* Get the memory store (for external access, e.g., CLI commands).
|
|
1785
|
-
* @returns {import('./memory/store.js').MemoryStore|null}
|
|
1786
|
-
*/
|
|
1787
|
-
get memoryStore() {
|
|
1788
|
-
return this.#memoryStore;
|
|
1789
|
-
}
|
|
1790
|
-
|
|
1791
|
-
/** @returns {object|null} — R6 memory shard store (task-334f) */
|
|
1792
|
-
get memoryShardStore() {
|
|
1793
|
-
return this.#memoryShardStore;
|
|
1794
|
-
}
|
|
1795
|
-
|
|
1796
1686
|
/** @returns {import('./tools/registry.js').ToolRegistry|null} */
|
|
1797
1687
|
get toolRegistry() { return this.#toolRegistry; }
|
|
1798
1688
|
|