@yeaft/webchat-agent 0.1.659 → 0.1.661
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/package.json +1 -1
- package/unify/config.js +7 -15
- package/unify/engine.js +18 -80
- package/unify/groups/pre-flow.js +2 -3
- package/unify/memory/keywords.js +2 -3
- package/unify/session.js +31 -58
- package/unify/memory/dream-extract.js +0 -381
- package/unify/memory/dream-scheduler.js +0 -212
- package/unify/memory/recall-r6.js +0 -291
- package/unify/memory/recall-v2.js +0 -258
- package/unify/memory/recall.js +0 -247
- package/unify/memory/recompression.js +0 -122
package/package.json
CHANGED
package/unify/config.js
CHANGED
|
@@ -219,8 +219,6 @@ function loadLegacyConfig(dir, overrides) {
|
|
|
219
219
|
unify: normaliseUnifySection(null),
|
|
220
220
|
// DESIGN-v2 feature flag. Default true (PR-E flipped). Override wins.
|
|
221
221
|
memoryV2: overrides.memoryV2 !== undefined ? !!overrides.memoryV2 : true,
|
|
222
|
-
// GC.1: FTS pre-flow flag (legacy fallback config — defaults true).
|
|
223
|
-
memoryPreflow: overrides.memoryPreflow !== undefined ? !!overrides.memoryPreflow : true,
|
|
224
222
|
providers: null,
|
|
225
223
|
primaryModel: null,
|
|
226
224
|
fastModel: null,
|
|
@@ -317,22 +315,16 @@ export function loadConfig(overrides = {}) {
|
|
|
317
315
|
// don't pollute the flat config namespace used by chat/crew code.
|
|
318
316
|
unify: normaliseUnifySection(jsonConfig.unify),
|
|
319
317
|
|
|
320
|
-
// DESIGN-v2 feature flag. When true the
|
|
321
|
-
//
|
|
322
|
-
//
|
|
323
|
-
//
|
|
324
|
-
//
|
|
318
|
+
// DESIGN-v2 feature flag. When true the session opens the FTS5
|
|
319
|
+
// SegmentIndex (used by groups/pre-flow.js → memory/preflow.js
|
|
320
|
+
// for pre-turn recall) and wires the v2 dream pipeline
|
|
321
|
+
// (dream-v2/runner.js). When false both are skipped — no recall,
|
|
322
|
+
// no dream — turns still work but without memory injection. The
|
|
323
|
+
// legacy R6 recall + dream-scheduler paths have been deleted, so
|
|
324
|
+
// `false` is now a "memory off" kill switch rather than a fallback.
|
|
325
325
|
memoryV2: overrides.memoryV2 !== undefined ? !!overrides.memoryV2
|
|
326
326
|
: (jsonConfig.memoryV2 !== undefined ? !!jsonConfig.memoryV2 : true),
|
|
327
327
|
|
|
328
|
-
// GC.1 feature flag — route pre-turn memory recall through
|
|
329
|
-
// memory/preflow.js (SQLite FTS5) instead of memory/recall-v2.js
|
|
330
|
-
// (per-scope file reads). When OFF the engine falls back to v2.
|
|
331
|
-
// Default ON. Users can opt out via `"memoryPreflow": false` in
|
|
332
|
-
// ~/.yeaft/config.json. Only applies when memoryV2 is also ON.
|
|
333
|
-
memoryPreflow: overrides.memoryPreflow !== undefined ? !!overrides.memoryPreflow
|
|
334
|
-
: (jsonConfig.memoryPreflow !== undefined ? !!jsonConfig.memoryPreflow : true),
|
|
335
|
-
|
|
336
328
|
// Legacy fields (null when using config.json)
|
|
337
329
|
apiKey: overrides.apiKey || null,
|
|
338
330
|
openaiApiKey: null,
|
package/unify/engine.js
CHANGED
|
@@ -20,8 +20,6 @@
|
|
|
20
20
|
import { randomUUID } from 'crypto';
|
|
21
21
|
import { buildSystemPrompt, buildWorkerPrompt } from './prompts.js';
|
|
22
22
|
import { LLMContextError, LLMAbortError } from './llm/adapter.js';
|
|
23
|
-
import { recallR6, formatForInjection } from './memory/recall-r6.js';
|
|
24
|
-
import { recallV2 } from './memory/recall-v2.js';
|
|
25
23
|
import { runMemoryPreflow } from './groups/pre-flow.js';
|
|
26
24
|
import { shouldConsolidate, consolidate, partitionMessages } from './memory/consolidate.js';
|
|
27
25
|
import { extractMemories } from './memory/extract.js';
|
|
@@ -30,7 +28,6 @@ import { evaluateCompactTriggers } from './compact/triggers.js';
|
|
|
30
28
|
import { archiveTurn } from './archive/turn-archive.js';
|
|
31
29
|
import { archiveToolResults } from './archive/tool-results.js';
|
|
32
30
|
import { buildMemoryInjection } from './memory/layout.js';
|
|
33
|
-
import { buildUserProfile } from './memory/user-memory-store.js';
|
|
34
31
|
import { readSummary as readScopeSummary } from './memory/store-v2.js';
|
|
35
32
|
import { runStopHooks } from './stop-hooks.js';
|
|
36
33
|
// H2.f.5: threads/ retired. Persisted messages still carry a `threadId`
|
|
@@ -500,9 +497,11 @@ export class Engine {
|
|
|
500
497
|
/**
|
|
501
498
|
* Perform memory recall for a given prompt.
|
|
502
499
|
*
|
|
503
|
-
*
|
|
504
|
-
*
|
|
505
|
-
*
|
|
500
|
+
* Single path (GC.1 follow-up): SQLite FTS5 pre-flow via
|
|
501
|
+
* `groups/pre-flow.js` → `memory/preflow.js`. When the index isn't
|
|
502
|
+
* wired (e.g. read-only sessions or pre-FTS yeaft dirs) recall is
|
|
503
|
+
* skipped and an empty memory shape is returned — engine continues
|
|
504
|
+
* without injection.
|
|
506
505
|
*
|
|
507
506
|
* @param {string} prompt
|
|
508
507
|
* @param {{ groupId?: string, vpId?: string, featureId?: string }} [ctx]
|
|
@@ -510,82 +509,20 @@ export class Engine {
|
|
|
510
509
|
*/
|
|
511
510
|
async #recallMemory(prompt, ctx = {}) {
|
|
512
511
|
const memory = { profile: '', entries: [], formatted: '' };
|
|
513
|
-
|
|
514
|
-
// ─── GC.1: FTS5 pre-flow path ──────────────────────────────
|
|
515
|
-
// When the SegmentIndex is wired and the feature flag is on,
|
|
516
|
-
// route recall through groups/pre-flow.js → memory/preflow.js
|
|
517
|
-
// (SQLite FTS5). On any failure fall through to v2.
|
|
518
|
-
if (this.#memoryIndex && this.#config && this.#config.memoryPreflow) {
|
|
519
|
-
try {
|
|
520
|
-
const result = runMemoryPreflow(this.#memoryIndex, {
|
|
521
|
-
userMsg: prompt,
|
|
522
|
-
groupId: ctx.groupId,
|
|
523
|
-
vpId: ctx.vpId,
|
|
524
|
-
featureId: ctx.featureId,
|
|
525
|
-
});
|
|
526
|
-
memory.profile = result.profile || '';
|
|
527
|
-
memory.entries = result.entries || [];
|
|
528
|
-
memory.formatted = result.formatted || '';
|
|
529
|
-
return memory;
|
|
530
|
-
} catch {
|
|
531
|
-
// Fall through to v2 / R6 paths.
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
// ─── v2 path (DESIGN-v2) ───────────────────────────────────
|
|
536
|
-
if (this.#config && this.#config.memoryV2 && this.#yeaftDir) {
|
|
537
|
-
try {
|
|
538
|
-
const result = await recallV2({
|
|
539
|
-
prompt,
|
|
540
|
-
root: `${this.#yeaftDir}/memory`,
|
|
541
|
-
groupId: ctx.groupId,
|
|
542
|
-
vpId: ctx.vpId,
|
|
543
|
-
featureId: ctx.featureId,
|
|
544
|
-
});
|
|
545
|
-
memory.entries = result.sections || [];
|
|
546
|
-
memory.formatted = result.formatted || '';
|
|
547
|
-
// Profile concept: in v2 the user/memory.md IS the profile.
|
|
548
|
-
const userSec = (result.sections || []).find(s => s.kind === 'user');
|
|
549
|
-
memory.profile = userSec ? (userSec.summary || '') : '';
|
|
550
|
-
} catch {
|
|
551
|
-
// Fail soft — empty injection.
|
|
552
|
-
}
|
|
553
|
-
return memory;
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
// ─── R6 legacy path ────────────────────────────────────────
|
|
557
|
-
// Build user profile from user-memory shard store (R6 path),
|
|
558
|
-
// falling back to legacy readProfile if shard store unavailable.
|
|
512
|
+
if (!this.#memoryIndex) return memory;
|
|
559
513
|
try {
|
|
560
|
-
const
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
}
|
|
514
|
+
const result = runMemoryPreflow(this.#memoryIndex, {
|
|
515
|
+
userMsg: prompt,
|
|
516
|
+
groupId: ctx.groupId,
|
|
517
|
+
vpId: ctx.vpId,
|
|
518
|
+
featureId: ctx.featureId,
|
|
519
|
+
});
|
|
520
|
+
memory.profile = result.profile || '';
|
|
521
|
+
memory.entries = result.entries || [];
|
|
522
|
+
memory.formatted = result.formatted || '';
|
|
566
523
|
} catch {
|
|
567
|
-
//
|
|
568
|
-
if (this.#memoryStore) {
|
|
569
|
-
try { memory.profile = this.#memoryStore.readProfile(); } catch { /* */ }
|
|
570
|
-
}
|
|
524
|
+
// Fail soft — empty injection.
|
|
571
525
|
}
|
|
572
|
-
|
|
573
|
-
// R6 shard-based recall (preferred path)
|
|
574
|
-
if (this.#memoryShardStore) {
|
|
575
|
-
try {
|
|
576
|
-
const result = await recallR6({
|
|
577
|
-
prompt,
|
|
578
|
-
memoryShardStore: this.#memoryShardStore,
|
|
579
|
-
adapter: this.#adapter,
|
|
580
|
-
fastModel: this.#fastConfig?.model,
|
|
581
|
-
});
|
|
582
|
-
memory.entries = result.entries;
|
|
583
|
-
memory.formatted = formatForInjection(result.entries);
|
|
584
|
-
} catch {
|
|
585
|
-
// Recall failure is non-critical
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
|
|
589
526
|
return memory;
|
|
590
527
|
}
|
|
591
528
|
|
|
@@ -901,7 +838,8 @@ export class Engine {
|
|
|
901
838
|
// ─── Pre-query: Memory Injection (task-287) + Compact Summary ──
|
|
902
839
|
// Two-layer recall:
|
|
903
840
|
// 1. Static memory index injection (buildMemoryInjection — always)
|
|
904
|
-
// 2.
|
|
841
|
+
// 2. FTS5 pre-flow recall (#recallMemory → groups/pre-flow.js →
|
|
842
|
+
// memory/preflow.js — when memoryIndex is wired)
|
|
905
843
|
// No per-turn fuzzy recall via old recall.js — LLM calls memory_load /
|
|
906
844
|
// memory_query on demand (memory_search still works as a deprecated alias).
|
|
907
845
|
let memoryInjection = '';
|
package/unify/groups/pre-flow.js
CHANGED
|
@@ -158,9 +158,8 @@ export function selectRespondingVps(input) {
|
|
|
158
158
|
/**
|
|
159
159
|
* Build the heading for a single scope's formatted memory block.
|
|
160
160
|
*
|
|
161
|
-
*
|
|
162
|
-
* prompt
|
|
163
|
-
* (here) or from per-scope file reads (recall-v2).
|
|
161
|
+
* Heading style is the original recall-v2 format, kept so the system
|
|
162
|
+
* prompt the LLM sees stays stable across the FTS migration.
|
|
164
163
|
*
|
|
165
164
|
* @param {string} scope
|
|
166
165
|
* @returns {string}
|
package/unify/memory/keywords.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* keywords.js — pure-rule keyword extraction shared by memory recall paths.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* Pure CPU, no LLM, <1ms.
|
|
4
|
+
* Pure CPU, no LLM, <1ms. Used by `groups/pre-flow.js` to derive FTS
|
|
5
|
+
* query terms from the user message before hitting `memory/preflow.js`.
|
|
7
6
|
*/
|
|
8
7
|
|
|
9
8
|
/** Common stop words filtered out before frequency counting. */
|
package/unify/session.js
CHANGED
|
@@ -28,18 +28,17 @@ import { Engine } from './engine.js';
|
|
|
28
28
|
// H2.f.5: threads/, pipeline/dispatcher and input-queue retired. The
|
|
29
29
|
// session now exposes a single Engine.
|
|
30
30
|
//
|
|
31
|
-
// GC.1
|
|
32
|
-
//
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
//
|
|
31
|
+
// GC.1 (final): when config.memoryV2 is on, the session opens a
|
|
32
|
+
// SegmentIndex (SQLite FTS5 over memory.md) and passes it to the
|
|
33
|
+
// Engine. Engine.#recallMemory routes pre-turn recall through
|
|
34
|
+
// groups/pre-flow.js → memory/preflow.js (the previous per-scope
|
|
35
|
+
// file reader recall-v2.js has been deleted). Post-turn AMS
|
|
36
|
+
// correction (memory/adjust.js) is implemented but not yet wired —
|
|
37
|
+
// requires session-level AMS instance + scope resolution. Tracked
|
|
38
|
+
// as a follow-up.
|
|
38
39
|
import { ensureDefaultGroupIfEmpty } from './groups/group-crud.js';
|
|
39
40
|
import { seedDefaultVps } from './vp/seed-defaults.js';
|
|
40
|
-
import { createDreamScheduler } from './memory/dream-scheduler.js';
|
|
41
41
|
import { createV2DreamScheduler } from './dream-v2/session-wiring.js';
|
|
42
|
-
import { getUserMemoryStore } from './memory/user-memory-store.js';
|
|
43
42
|
import { openSegmentIndex } from './memory/index-db.js';
|
|
44
43
|
import { syncAll as syncSegmentIndex } from './memory/segment-sync.js';
|
|
45
44
|
import { migrateR6toV2 } from './memory/migrate-r6-to-v2.js';
|
|
@@ -223,15 +222,15 @@ export async function loadSession(options = {}) {
|
|
|
223
222
|
}
|
|
224
223
|
|
|
225
224
|
// ─── 5-fts. (GC.1) Open SegmentIndex for FTS pre-flow ────
|
|
226
|
-
// When config.memoryV2
|
|
227
|
-
//
|
|
228
|
-
//
|
|
229
|
-
//
|
|
230
|
-
//
|
|
231
|
-
//
|
|
232
|
-
//
|
|
225
|
+
// When config.memoryV2 is on, build a SQLite FTS5 index over
|
|
226
|
+
// ~/.yeaft/memory/<scope>/memory.md and pass it to the Engine.
|
|
227
|
+
// Engine.#recallMemory uses it via groups/pre-flow.js →
|
|
228
|
+
// memory/preflow.js. Disk is the source of truth; on boot we
|
|
229
|
+
// reconcile disk → index via syncAll. Failure to open the index
|
|
230
|
+
// is non-fatal: #recallMemory returns an empty result and the
|
|
231
|
+
// turn proceeds without pre-injected memory.
|
|
233
232
|
let memoryIndex = null;
|
|
234
|
-
if (config.memoryV2 &&
|
|
233
|
+
if (config.memoryV2 && !config._readOnly) {
|
|
235
234
|
try {
|
|
236
235
|
const indexPath = join(yeaftDir, 'memory', 'index.db');
|
|
237
236
|
memoryIndex = openSegmentIndex(indexPath);
|
|
@@ -322,47 +321,21 @@ export async function loadSession(options = {}) {
|
|
|
322
321
|
yeaftDir,
|
|
323
322
|
});
|
|
324
323
|
|
|
325
|
-
// ─── 9a. Create dream scheduler (
|
|
326
|
-
//
|
|
327
|
-
//
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
};
|
|
341
|
-
dreamScheduler = createV2DreamScheduler(partialSession);
|
|
342
|
-
} else {
|
|
343
|
-
dreamScheduler = createDreamScheduler({
|
|
344
|
-
memoryShardStore,
|
|
345
|
-
userMemoryStore: getUserMemoryStore(),
|
|
346
|
-
conversationStore,
|
|
347
|
-
adapter,
|
|
348
|
-
config,
|
|
349
|
-
onDreamStart: (vpId) => {
|
|
350
|
-
if (config.debug) console.log(`[Yeaft] Dream started for VP ${vpId}`);
|
|
351
|
-
},
|
|
352
|
-
onDreamEnd: (vpId, result) => {
|
|
353
|
-
if (config.debug) console.log(`[Yeaft] Dream ended for VP ${vpId}:`, JSON.stringify({
|
|
354
|
-
trigger: result.trigger,
|
|
355
|
-
entriesMerged: result.entriesMerged,
|
|
356
|
-
entriesPruned: result.entriesPruned,
|
|
357
|
-
bytesReclaimed: result.bytesReclaimed,
|
|
358
|
-
errors: result.errors?.length || 0,
|
|
359
|
-
}));
|
|
360
|
-
},
|
|
361
|
-
onError: (vpId, err) => {
|
|
362
|
-
console.warn(`[Yeaft] Dream error for VP ${vpId}:`, err?.message || err);
|
|
363
|
-
},
|
|
364
|
-
});
|
|
365
|
-
}
|
|
324
|
+
// ─── 9a. Create dream scheduler (DESIGN-v2) ────────────
|
|
325
|
+
// The legacy R6 dream-scheduler was retired alongside recall-r6;
|
|
326
|
+
// dream-v2 is the only active path. The `memoryV2: false` opt-out
|
|
327
|
+
// no longer leaves a usable system, so we always wire v2 here.
|
|
328
|
+
// partialSession lets the v2 scheduler dereference adapter/config/
|
|
329
|
+
// engine/trace lazily — safe because callers attach more fields
|
|
330
|
+
// after this line.
|
|
331
|
+
const partialSession = {
|
|
332
|
+
yeaftDir,
|
|
333
|
+
adapter,
|
|
334
|
+
config,
|
|
335
|
+
engine,
|
|
336
|
+
trace,
|
|
337
|
+
};
|
|
338
|
+
const dreamScheduler = createV2DreamScheduler(partialSession);
|
|
366
339
|
|
|
367
340
|
// H2.f.5: thread engine registry, input queue, and dispatcher retired.
|
|
368
341
|
// The session exposes a single `engine`; web-bridge calls engine.query()
|