@yeaft/webchat-agent 0.1.665 → 0.1.666
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/engine.js +22 -130
- package/unify/features/summary.js +15 -98
- package/unify/index.js +0 -2
- package/unify/memory/consolidate.js +10 -125
- package/unify/prompts.js +3 -19
- package/unify/session.js +1 -21
- 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/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;
|
|
@@ -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,28 +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
|
-
//
|
|
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
|
|
939
|
+
// The legacy entries-aggregate `buildMemoryInjection` (index.md / by-project /
|
|
940
|
+
// by-topic / timeline) was retired in the H2-AMS rip.
|
|
1022
941
|
let memoryInjection = '';
|
|
1023
942
|
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
943
|
|
|
1038
944
|
// R6 recall: append shard-based recall results to memory injection
|
|
1039
945
|
const recallResult = await this.#recallMemory(prompt, {
|
|
@@ -1326,7 +1232,7 @@ export class Engine {
|
|
|
1326
1232
|
}
|
|
1327
1233
|
|
|
1328
1234
|
// ─── LLMContextError → force compact → retry ──────
|
|
1329
|
-
if (err instanceof LLMContextError && this.#conversationStore
|
|
1235
|
+
if (err instanceof LLMContextError && this.#conversationStore) {
|
|
1330
1236
|
const consolidated = await this.#maybeConsolidate();
|
|
1331
1237
|
if (consolidated && consolidated.archivedCount > 0) {
|
|
1332
1238
|
yield { type: 'consolidate', archivedCount: consolidated.archivedCount, extractedCount: consolidated.extractedCount };
|
|
@@ -1451,7 +1357,6 @@ export class Engine {
|
|
|
1451
1357
|
const hookResult = await runStopHooks({
|
|
1452
1358
|
yeaftDir: this.#yeaftDir,
|
|
1453
1359
|
conversationStore: this.#conversationStore,
|
|
1454
|
-
memoryStore: this.#memoryStore,
|
|
1455
1360
|
adapter: this.#adapter,
|
|
1456
1361
|
config: this.#fastConfig,
|
|
1457
1362
|
primaryModel: this.#config.model,
|
|
@@ -1780,19 +1685,6 @@ export class Engine {
|
|
|
1780
1685
|
return this.#conversationStore;
|
|
1781
1686
|
}
|
|
1782
1687
|
|
|
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
1688
|
/** @returns {import('./tools/registry.js').ToolRegistry|null} */
|
|
1797
1689
|
get toolRegistry() { return this.#toolRegistry; }
|
|
1798
1690
|
|
|
@@ -1,30 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* summary.js —
|
|
2
|
+
* summary.js — Feature multi-VP collaboration summary protocol.
|
|
3
3
|
*
|
|
4
4
|
* Owns:
|
|
5
5
|
* - postSummary() — write a `type=summary` message to the group jsonl
|
|
6
|
-
* and run the extractor (B + C)
|
|
7
|
-
* - extractFeatureMemory() — turn a summary body into 2-5 feature-memory entries
|
|
8
|
-
* via 334f feature-memory shard lib (C)
|
|
9
6
|
* - buildSummaryReminder() — compute the §Δ31.4 3-AND soft reminder shape
|
|
10
|
-
*
|
|
11
|
-
* - buildFeatureCtxMemories() — assemble feature-memory top-5 (pinned + recent +
|
|
12
|
-
* tag relevance) for feature_ctx (E)
|
|
7
|
+
* - buildFeatureCtxMemories() — feature-memory top-5 (post-rip stub: returns [])
|
|
13
8
|
*
|
|
14
9
|
* Hard boundaries:
|
|
15
|
-
* - does NOT touch
|
|
16
|
-
* - does NOT
|
|
17
|
-
*
|
|
18
|
-
* the existing renderFeatureCtx contract)
|
|
19
|
-
* - does NOT self-loop-write VP-memory (extractor writes feature-memory only;
|
|
20
|
-
* VP-level synthesis is deferred to 334g dream)
|
|
21
|
-
* - softCap overflow does NOT create new shards (334f already routes into
|
|
22
|
-
* dream queue via projectDeriveHint; we just surface `needsRecompression`)
|
|
10
|
+
* - does NOT touch jsonl rotation internals (calls group.appendMessage)
|
|
11
|
+
* - does NOT write feature-memory shards — the H2-AMS rip retired the shard
|
|
12
|
+
* store; feature memory now flows through Dream V2's scope merge instead.
|
|
23
13
|
*/
|
|
24
14
|
|
|
25
15
|
import { join } from 'path';
|
|
26
|
-
import { openMemoryShardStore } from '../memory/shard-store.js';
|
|
27
|
-
import { AUTHORED_BY } from '../memory/schema.js';
|
|
28
16
|
|
|
29
17
|
// ─── §Δ31.4 soft-reminder thresholds ─────────────────────────────
|
|
30
18
|
/** Must be initiator AND members>1 AND (age≥20min OR turns≥10). */
|
|
@@ -119,36 +107,11 @@ export function postSummary(opts) {
|
|
|
119
107
|
},
|
|
120
108
|
});
|
|
121
109
|
|
|
122
|
-
// 2)
|
|
110
|
+
// 2) Feature-memory extraction is now owned by Dream V2 (per-group diff →
|
|
111
|
+
// triage → merge by target scope → atomic segments). The legacy in-line
|
|
112
|
+
// shard-store extractor was retired in the H2-AMS rip; we leave
|
|
113
|
+
// `memoryIds` empty so callers don't depend on inline-extracted IDs.
|
|
123
114
|
const memoryIds = [];
|
|
124
|
-
try {
|
|
125
|
-
const store = openMemoryShardStore(memoryDir, 'feature');
|
|
126
|
-
const raw = extractor(body) || [];
|
|
127
|
-
const bounded = clampExtracted(raw);
|
|
128
|
-
for (const [i, item] of bounded.entries()) {
|
|
129
|
-
const kind = EXTRACT_KINDS.includes(item.kind) ? item.kind : 'progress';
|
|
130
|
-
const shard = KIND_TO_SHARD[kind] || 'progress';
|
|
131
|
-
const id = `mem-${stored.id}-${i + 1}`;
|
|
132
|
-
store.put({
|
|
133
|
-
id,
|
|
134
|
-
shard,
|
|
135
|
-
kind,
|
|
136
|
-
featureId,
|
|
137
|
-
body: typeof item.body === 'string' ? item.body.trim() : '',
|
|
138
|
-
tags: Array.isArray(item.tags) ? item.tags.slice(0, 5) : [],
|
|
139
|
-
authoredBy: AUTHORED_BY.SUMMARY,
|
|
140
|
-
sourceRef: { featureId, msgIds: [stored.id] },
|
|
141
|
-
createdAt: new Date(now()).toISOString(),
|
|
142
|
-
});
|
|
143
|
-
memoryIds.push(id);
|
|
144
|
-
}
|
|
145
|
-
} catch (err) {
|
|
146
|
-
// Extractor failures must not fail the summary post; the message is
|
|
147
|
-
// already persisted (audit property). We return the empty memoryIds so
|
|
148
|
-
// callers can surface a warning if they want.
|
|
149
|
-
// eslint-disable-next-line no-console
|
|
150
|
-
console.warn('[task-334n] summary-extractor failed:', err?.message || err);
|
|
151
|
-
}
|
|
152
115
|
|
|
153
116
|
return {
|
|
154
117
|
message: stored,
|
|
@@ -241,62 +204,16 @@ export function buildSummaryReminder(input) {
|
|
|
241
204
|
|
|
242
205
|
/**
|
|
243
206
|
* Assemble feature-memory top-5 for 334e's `featureCtx.memories` field.
|
|
244
|
-
*
|
|
245
|
-
*
|
|
207
|
+
* Post-rip stub: the underlying shard store was retired in the H2-AMS rip;
|
|
208
|
+
* Dream V2 owns feature-scope memory now. Returning `[]` keeps the prompt
|
|
209
|
+
* shape valid until a follow-up wires the new scope-summary read path.
|
|
246
210
|
*
|
|
247
|
-
* @param {string} memoryDir
|
|
211
|
+
* @param {string} memoryDir unused (kept for callsite compatibility)
|
|
248
212
|
* @param {{ tags?: string[], top?: number }} [opts]
|
|
249
213
|
* @returns {Array<{body:string, shard:string, authoredBy?:string}>}
|
|
250
214
|
*/
|
|
251
|
-
export function buildFeatureCtxMemories(
|
|
252
|
-
|
|
253
|
-
const tagHints = Array.isArray(opts.tags) ? opts.tags : [];
|
|
254
|
-
const nowMs = typeof opts.now === 'number' ? opts.now : Date.now();
|
|
255
|
-
let results = [];
|
|
256
|
-
try {
|
|
257
|
-
const store = openMemoryShardStore(memoryDir, 'feature');
|
|
258
|
-
const q = store.query({});
|
|
259
|
-
const hits = (q.results || [])
|
|
260
|
-
.filter((r) => !r.supersededBy)
|
|
261
|
-
.map((r) => {
|
|
262
|
-
const full = store.get(r.id);
|
|
263
|
-
return {
|
|
264
|
-
id: r.id,
|
|
265
|
-
shard: r.shard || 'general',
|
|
266
|
-
body: full?.body || '',
|
|
267
|
-
tags: Array.isArray(r.tags) ? r.tags : [],
|
|
268
|
-
pinned: !!r.pinned,
|
|
269
|
-
createdAt: full?.createdAt || null,
|
|
270
|
-
authoredBy: full?.authoredBy || null,
|
|
271
|
-
};
|
|
272
|
-
})
|
|
273
|
-
.filter((r) => r.body && r.body.trim());
|
|
274
|
-
|
|
275
|
-
const score = (r) => {
|
|
276
|
-
let s = 0;
|
|
277
|
-
if (r.pinned) s += 1000;
|
|
278
|
-
if (r.createdAt) {
|
|
279
|
-
const ageMs = nowMs - new Date(r.createdAt).getTime();
|
|
280
|
-
const halfLifeMs = 24 * 60 * 60 * 1000;
|
|
281
|
-
s += Math.max(0, 100 * Math.pow(0.5, Math.max(0, ageMs) / halfLifeMs));
|
|
282
|
-
}
|
|
283
|
-
for (const t of tagHints) if (r.tags.includes(t)) s += 5;
|
|
284
|
-
return s;
|
|
285
|
-
};
|
|
286
|
-
hits.sort((a, b) => {
|
|
287
|
-
const ds = score(b) - score(a);
|
|
288
|
-
if (ds !== 0) return ds;
|
|
289
|
-
return String(b.createdAt || '').localeCompare(String(a.createdAt || ''));
|
|
290
|
-
});
|
|
291
|
-
results = hits.slice(0, top).map((r) => ({
|
|
292
|
-
body: r.body,
|
|
293
|
-
shard: r.shard,
|
|
294
|
-
...(r.authoredBy ? { authoredBy: r.authoredBy } : {}),
|
|
295
|
-
}));
|
|
296
|
-
} catch {
|
|
297
|
-
results = [];
|
|
298
|
-
}
|
|
299
|
-
return results;
|
|
215
|
+
export function buildFeatureCtxMemories(_memoryDir, _opts = {}) {
|
|
216
|
+
return [];
|
|
300
217
|
}
|
|
301
218
|
|
|
302
219
|
// ─── (F) related-feature ACL fail-closed gate ─────────────────────
|
package/unify/index.js
CHANGED
|
@@ -22,10 +22,8 @@ export { buildSystemPrompt, SUPPORTED_LANGUAGES } from './prompts.js';
|
|
|
22
22
|
export { Engine } from './engine.js';
|
|
23
23
|
export { ConversationStore, parseMessage, estimateTokens } from './conversation/persist.js';
|
|
24
24
|
export { searchMessages } from './conversation/search.js';
|
|
25
|
-
export { MemoryStore, parseEntry, serializeEntry, MEMORY_KINDS } from './memory/store.js';
|
|
26
25
|
|
|
27
26
|
// Phase 5: Advanced features
|
|
28
|
-
export { KINDS, KIND_PRIORITY, KIND_DESCRIPTIONS, IMPORTANCE_LEVELS, validateEntry, parseScopePath, getAncestorScopes, areScopesRelated } from './memory/types.js';
|
|
29
27
|
export { runStopHooks } from './stop-hooks.js';
|
|
30
28
|
export { MCPManager, createMCPManager } from './mcp.js';
|
|
31
29
|
export { SkillManager, createSkillManager, parseSkill, serializeSkill } from './skills.js';
|