@yeaft/webchat-agent 1.0.575 → 1.0.577

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/yeaft/session.js CHANGED
@@ -33,29 +33,13 @@ import { TaskManager } from './tasks/manager.js';
33
33
  // session still exposes a single default Engine; PR #797 adds group VP thread
34
34
  // engines in web-bridge runtime state, keyed below the session layer.
35
35
  //
36
- // GC.1 (final): the session opens a SegmentIndex (SQLite FTS5 over
37
- // memory.md) and passes it to the Engine. Engine.#recallMemory routes
38
- // pre-turn recall through sessions/pre-flow.js → memory/preflow.js (the
39
- // previous per-scope file reader recall-v2.js has been deleted).
40
- // The `config.memoryV2` opt-out flag was retired in task-710; wiring is
41
- // unconditional.
42
- //
43
- // When memoryIndex is wired we also open an AmsRegistry. It caches the
44
- // per-Session ActiveMemorySet object and keeps the version-1 ams.json shape for
45
- // disk compatibility. Engine rebuilds prompt-facing Resident entries from
46
- // query-selected canonical content on every turn; persisted segment ids are
47
- // never rehydrated into the prompt.
36
+ // Dream memory remains archived on disk, but normal Session startup must not
37
+ // open, migrate, reconcile, or inject it. Explicit memory tools own any direct
38
+ // access requested by a user.
48
39
  import { ensureDefaultSessionIfEmpty, migrateRegisteredWorkDirSessions } from './sessions/session-crud.js';
49
40
  import { seedDefaultVps } from './vp/seed-defaults.js';
50
41
  import { topUpDefaultVps } from './vp/seed-topup.js';
51
- import { archiveLegacyScopes } from './memory/seed-backfill.js';
52
- // Dream scheduler wiring is intentionally not imported while the runtime path is disabled.
53
- // import { createV2DreamScheduler, bootInitEmptyGroups, bootCatchUpStaleDream } from './dream/session-wiring.js';
54
42
  import { isWorkCenterEnabled } from './work-center/feature.js';
55
- import { openSegmentIndex } from './memory/index-db.js';
56
- import { syncAll as syncSegmentIndex } from './memory/segment-sync.js';
57
- import { backfillCanonicalContent } from './memory/content-backfill.js';
58
- import { openAmsRegistry } from './memory/ams-registry.js';
59
43
  import { join } from 'path';
60
44
  import { existsSync as existsSyncSafe, readFileSync as readFileSyncSafe, mkdirSync as mkdirSyncSafe } from 'fs';
61
45
 
@@ -139,7 +123,6 @@ export async function loadSession(options = {}) {
139
123
  extraTools = [],
140
124
  configOverrides = {},
141
125
  serverMode = false,
142
- dreamEnabled,
143
126
  managedCliReady = null,
144
127
  workCenterEnabled,
145
128
  } = options;
@@ -159,7 +142,7 @@ export async function loadSession(options = {}) {
159
142
  const sessionWorkDir = typeof workDir === 'string' && workDir.trim() ? workDir.trim() : '';
160
143
  const configDir = overrides.dir || process.env.YEAFT_DIR || DEFAULT_YEAFT_DIR;
161
144
  const yeaftDir = configDir;
162
- const configInitResult = initYeaftDir(configDir);
145
+ const configInitResult = initYeaftDir(configDir, { migrateMemory: false });
163
146
  const storeInitResult = configInitResult;
164
147
  overrides.dir = configDir;
165
148
 
@@ -174,11 +157,10 @@ export async function loadSession(options = {}) {
174
157
  // ─── 2. Load config ───────────────────────────────────
175
158
  const config = loadConfig(overrides);
176
159
  const effectiveWorkCenterEnabled = workCenterEnabled ?? isWorkCenterEnabled(process.env, config);
177
- // fix/dream-cadence-and-ui-trigger: tag config so the dream scheduler
178
- // can decide whether to keep its interval timer alive (server) or
179
- // unref it (CLI / tests). Non-persisted — set per-session by caller.
180
160
  if (serverMode) config.serverMode = true;
181
- if (typeof dreamEnabled === 'boolean') config.dream.enabled = dreamEnabled;
161
+ // Dream is disabled at the runtime boundary. Ignore legacy caller/config
162
+ // toggles so an old client cannot re-enable scheduling or loading.
163
+ config.dream = { ...(config.dream || {}), enabled: false };
182
164
 
183
165
  // Propagate the (clamped) cold-start replay window to the conversation
184
166
  // store. The default is 10 turns; a user wanting more recall after a
@@ -260,60 +242,11 @@ export async function loadSession(options = {}) {
260
242
  // ─── 5. Create stores ──────────────────────────────────
261
243
  const conversationStore = new ConversationStore(yeaftDir);
262
244
 
263
- // ─── 5-fts. (GC.1) Open SegmentIndex for FTS pre-flow ────
264
- // Build a SQLite FTS5 index over per-scope evidence memory.md and
265
- // canonical content.md, then pass it to Engine for scope selection.
266
- // Engine.#recallMemory uses it via sessions/pre-flow.js →
267
- // memory/preflow.js. Disk is the source of
268
- // truth; on boot we reconcile disk → index via syncAll. Failure
269
- // to open the index is non-fatal: #recallMemory returns an empty
270
- // result and the turn proceeds without pre-injected memory.
271
- let memoryIndex = null;
272
- if (!config._readOnly) {
273
- try {
274
- const indexPath = join(yeaftDir, 'memory', 'index.db');
275
- memoryIndex = openSegmentIndex(indexPath);
276
- const memoryRoot = join(yeaftDir, 'memory');
277
- // One-shot migration to the group-isolated memory layout: move any
278
- // remaining top-level vp/ feature/ topic/ dirs into .legacy/ before
279
- // we open the FTS index and re-sync from disk.
280
- try {
281
- archiveLegacyScopes(memoryRoot);
282
- } catch (archiveErr) {
283
- if (config.debug) {
284
- console.warn(`[Yeaft] legacy scope archive warning: ${archiveErr?.message || archiveErr}`);
285
- }
286
- }
287
- try {
288
- backfillCanonicalContent(memoryRoot);
289
- syncSegmentIndex(memoryRoot, memoryIndex);
290
- } catch (syncErr) {
291
- // Sync is best-effort; an empty / partial index just produces
292
- // empty recall results, never an error.
293
- if (config.debug) {
294
- console.warn(`[Yeaft] FTS index sync warning: ${syncErr?.message || syncErr}`);
295
- }
296
- }
297
- } catch (err) {
298
- console.warn(`[Yeaft] Failed to open FTS segment index (preflow disabled): ${err?.message || err}`);
299
- memoryIndex = null;
300
- }
301
- }
302
-
303
- // ─── 5-ams. Session-keyed AMS registry ─────────────────
304
- // The registry caches one ActiveMemorySet per sessionId and
305
- // retains version-1 metadata for disk compatibility. Prompt state is
306
- // rebuilt from selected canonical content each turn; old segment ids are
307
- // not rehydrated. Without memoryIndex the registry remains disabled.
308
- let amsRegistry = null;
309
- if (memoryIndex && !config._readOnly) {
310
- try {
311
- amsRegistry = openAmsRegistry({ yeaftDir, memoryIndex, config });
312
- } catch (err) {
313
- console.warn(`[Yeaft] Failed to open AMS registry (adjust disabled): ${err?.message || err}`);
314
- amsRegistry = null;
315
- }
316
- }
245
+ // Dream runtime loading is disabled. Keep these compatibility properties
246
+ // null for callers that still pass them through to Engine/sub-agent setup,
247
+ // without touching the archived memory tree or its SQLite index on boot.
248
+ const memoryIndex = null;
249
+ const amsRegistry = null;
317
250
 
318
251
  // ─── 5a. (removed 2026-05-13) Feature store init — Feature system retired.
319
252
 
@@ -475,19 +408,8 @@ export async function loadSession(options = {}) {
475
408
  });
476
409
 
477
410
 
478
- // ─── 9a. Dream runtime temporarily disabled ────────────
479
- // Message history now supplies turn context. Keep the Dream implementation
480
- // and persisted data intact, but do not create a scheduler or run boot-time
481
- // initialization/catch-up while the replacement is evaluated.
482
- //
483
- // const partialSession = { yeaftDir, adapter, config, engine, trace };
484
- // const dreamScheduler = createV2DreamScheduler(partialSession);
485
- // if (memoryIndex && !config._readOnly) {
486
- // bootInitEmptyGroups({ yeaftDir, memoryIndex, dreamScheduler, config }).catch(() => {});
487
- // }
488
- // if (!config._readOnly) {
489
- // bootCatchUpStaleDream({ yeaftDir, dreamScheduler, config }).catch(() => {});
490
- // }
411
+ // Dream implementation and persisted data remain available for explicit
412
+ // tooling, but Session runtime has no scheduler or boot-time Dream hooks.
491
413
  const dreamScheduler = null;
492
414
 
493
415
  // H2.f.5 retired the old session-level thread engine registry, input queue,
@@ -507,13 +429,8 @@ export async function loadSession(options = {}) {
507
429
  tools: toolRegistry.size,
508
430
  };
509
431
 
510
- /** Graceful shutdown: disconnect MCP, close trace DB, stop dream scheduler. */
432
+ /** Graceful shutdown: disconnect MCP and close runtime-owned resources. */
511
433
  async function shutdown() {
512
- try {
513
- dreamScheduler.shutdown();
514
- } catch {
515
- // Best-effort cleanup
516
- }
517
434
  try {
518
435
  await mcpManager.disconnectAll();
519
436
  } catch {
@@ -529,16 +446,6 @@ export async function loadSession(options = {}) {
529
446
  } catch {
530
447
  // Performance telemetry is best-effort and must not block shutdown.
531
448
  }
532
- try {
533
- if (memoryIndex) memoryIndex.close();
534
- } catch {
535
- // Best-effort cleanup
536
- }
537
- try {
538
- if (amsRegistry) amsRegistry.persistAll();
539
- } catch {
540
- // Best-effort cleanup
541
- }
542
449
  try {
543
450
  if (toolStats && typeof toolStats.flush === 'function') {
544
451
  await toolStats.flush();
@@ -14,20 +14,10 @@
14
14
 
15
15
  import { existsSync, mkdirSync } from 'fs';
16
16
  import { join } from 'path';
17
- import { homedir } from 'os';
18
17
  import { openSession, createSession, loadSessionMeta } from './session-store.js';
19
- import { seedSummaryIfMissingSync } from '../memory/store.js';
20
18
 
21
19
  export const DEFAULT_SESSION_ID = 'session_default';
22
20
 
23
- /**
24
- * Default memory root used when callers don't pass `options.memoryRoot`.
25
- * See `sessions/session-crud.js` and `vp/vp-crud.js` for the same default;
26
- * production code threads `<yeaftDir>/memory` through to keep test/prod
27
- * isolation honest.
28
- */
29
- const DEFAULT_MEMORY_ROOT = join(homedir(), '.yeaft', 'memory');
30
-
31
21
  /**
32
22
  * Build the default-session seed summary body. Pulled into a helper so
33
23
  * tests can pin the exact format. Mirrors `buildSessionSeedSummary` in
@@ -54,7 +44,6 @@ export function buildDefaultSessionSeedSummary(spec) {
54
44
  * @returns {{ group: import('./session-store.js').GroupHandle, created: boolean }}
55
45
  */
56
46
  export function seedDefaultSession(yeaftDir, spec = {}) {
57
- const memoryRoot = spec.memoryRoot || DEFAULT_MEMORY_ROOT;
58
47
  const sessionsRoot = join(yeaftDir, 'sessions');
59
48
  if (!existsSync(sessionsRoot)) mkdirSync(sessionsRoot, { recursive: true });
60
49
 
@@ -76,20 +65,5 @@ export function seedDefaultSession(yeaftDir, spec = {}) {
76
65
  defaultVpId,
77
66
  });
78
67
 
79
- // Seed Layer-A resident summary so the very first session — even on a
80
- // brand-new install where only `session_default` exists — renders a non-
81
- // empty memory section in the system prompt. No-op once Dream-v2 (or
82
- // createSessionFromSpec) has already written one. Best-effort: a memory-
83
- // root permission failure must NOT break the bootstrap flow.
84
- try {
85
- seedSummaryIfMissingSync(
86
- { kind: 'session', id: DEFAULT_SESSION_ID },
87
- buildDefaultSessionSeedSummary({ name, roster, defaultVpId }),
88
- { root: memoryRoot },
89
- );
90
- } catch (err) {
91
- console.warn(`[seed-default] failed to seed summary.md for ${DEFAULT_SESSION_ID}:`, err?.message || err);
92
- }
93
-
94
68
  return { group, created: true };
95
69
  }
@@ -56,7 +56,7 @@ import { addVp as rosterAdd, removeVp as rosterRemove, setDefaultVp } from './ro
56
56
  import { seedDefaultSession, DEFAULT_SESSION_ID } from './seed-default.js';
57
57
  import { nextSessionId, validateVpId, isReservedVpId } from './ids.js';
58
58
  import { scanVpLibrary, DEFAULT_VP_LIB_DIR } from '../vp/vp-store.js';
59
- import { seedSummaryIfMissingSync, removeScopeDirSync } from '../memory/store.js';
59
+ import { removeScopeDirSync } from '../memory/store.js';
60
60
  import {
61
61
  markConversationDirty,
62
62
  removeConversationIndexScope,
@@ -218,7 +218,8 @@ function ensureSessionManifestReady(yeaftDir) {
218
218
  registry: readWorkDirRegistry(yeaftDir),
219
219
  yeaftDirForWorkDir,
220
220
  sessionsRootForYeaftDir: sessionsRoot,
221
- copySessionExtras: (projectYeaftDir, sessionId) => copySessionExtras(projectYeaftDir, yeaftDir, sessionId),
221
+ // Archived Dream scopes stay at their original data root. Session bootstrap
222
+ // migrates Session metadata/transcripts only and must not read or copy memory.
222
223
  unregisterSessionWorkDir: (sessionId) => unregisterSessionWorkDir(yeaftDir, sessionId),
223
224
  });
224
225
  for (const row of listManifestSessions(yeaftDir)) {
@@ -237,16 +238,6 @@ function ensureSessionManifestReady(yeaftDir) {
237
238
  return result;
238
239
  }
239
240
 
240
- function copySessionExtras(sourceYeaftDir, destYeaftDir, sessionId) {
241
- for (const family of ['session', 'sessions', 'group']) {
242
- const src = join(sourceYeaftDir, 'memory', family, sessionId);
243
- const dst = join(destYeaftDir, 'memory', family, sessionId);
244
- if (!existsSync(src) || existsSync(dst)) continue;
245
- mkdirSync(join(dst, '..'), { recursive: true });
246
- cpSync(src, dst, { recursive: true, errorOnExist: false });
247
- }
248
- }
249
-
250
241
  function repairSessionStoreAndManifest(yeaftDir, options = {}) {
251
242
  const repaired = repairSessionStore(yeaftDir, options);
252
243
  ensureSessionManifestReady(yeaftDir);
@@ -392,7 +383,9 @@ export function restoreSessionToRegistry(defaultYeaftDir, sessionId, workDir) {
392
383
  } finally {
393
384
  handle.close();
394
385
  }
395
- copySessionExtras(projectYeaftDir, defaultYeaftDir, sessionId);
386
+ // Restore only the explicitly selected Session and its transcript. Archived
387
+ // Dream scopes are owned by their existing data root and are not Session
388
+ // storage extras.
396
389
  invalidateSessionConversationIndex(
397
390
  [defaultYeaftDir],
398
391
  sessionId,
@@ -477,7 +470,6 @@ function scanSortedVpIds(libDir) {
477
470
  */
478
471
  export function ensureDefaultSessionIfEmpty(yeaftDir, options = {}) {
479
472
  const libDir = options.libDir || DEFAULT_VP_LIB_DIR;
480
- const memoryRoot = options.memoryRoot || DEFAULT_MEMORY_ROOT;
481
473
  repairSessionStoreAndManifest(yeaftDir, {
482
474
  defaultRoster: scanSortedVpIds(libDir),
483
475
  });
@@ -496,7 +488,6 @@ export function ensureDefaultSessionIfEmpty(yeaftDir, options = {}) {
496
488
  name: options.name || 'Default',
497
489
  roster: vps,
498
490
  defaultVpId,
499
- memoryRoot,
500
491
  });
501
492
  const meta = group.getMeta();
502
493
  if (meta) addOrUpdateManifestSession(yeaftDir, meta, join(sessionsRoot(yeaftDir), meta.id));
@@ -524,7 +515,6 @@ export function createSessionFromSpec(yeaftDir, spec, options = {}) {
524
515
  const workspaceKey = canonicalWorkspaceKey(normalizedWorkDir);
525
516
  ensureSessionManifestReady(yeaftDir);
526
517
  const groupYeaftDir = yeaftDir;
527
- const memoryRoot = options.memoryRoot || (groupYeaftDir ? join(groupYeaftDir, 'memory') : DEFAULT_MEMORY_ROOT);
528
518
  const libDir = options.libDir || DEFAULT_VP_LIB_DIR;
529
519
  const name = String(input.name || '').trim();
530
520
  if (!name) throw new SessionCrudError('invalid_name', null, 'group name required');
@@ -583,19 +573,6 @@ export function createSessionFromSpec(yeaftDir, spec, options = {}) {
583
573
  console.warn(`[session-crud] failed to seed config.json for ${id}:`, err?.message || err);
584
574
  }
585
575
 
586
- // Seed Layer-A resident summary so the first session has memory content
587
- // even before Dream-v2 has run. No-op if a summary.md already exists.
588
- // Best-effort: a memory-root permission failure must NOT break group create.
589
- try {
590
- seedSummaryIfMissingSync(
591
- { kind: 'session', id },
592
- buildSessionSeedSummary({ name, roster, defaultVpId }),
593
- { root: memoryRoot },
594
- );
595
- } catch (err) {
596
- console.warn(`[session-crud] failed to seed summary.md for ${id}:`, err?.message || err);
597
- }
598
-
599
576
  return meta;
600
577
  }
601
578
 
@@ -133,11 +133,10 @@ export function startSubAgent(agent, deps = {}) {
133
133
  let subEngine = null;
134
134
  let outputLog = null;
135
135
  try {
136
- // Build sub-engine wired to the parent's adapter/stores/config but with
137
- // a restricted toolset. We DO NOT pass a conversationStore: sub-agent
138
- // turns must not pollute the user-facing conversation history. The
139
- // memory stores are shared so memory recall still works for the
140
- // sub-agent (matches parent VP persona memory).
136
+ // Build sub-engine wired to the parent's adapter/config but with a
137
+ // restricted toolset. We DO NOT pass a conversationStore: sub-agent
138
+ // turns must not pollute the user-facing conversation history. Dream
139
+ // runtime recall remains disabled for sub-agents as it is for Sessions.
141
140
  agent.budget = resolveSubAgentBudget(agent.budget);
142
141
  agent.execution = agent.execution || createExecutionStats();
143
142
  const childRegistry = buildChildToolRegistry(deps.parentToolRegistry, { agent });
@@ -149,9 +148,9 @@ export function startSubAgent(agent, deps = {}) {
149
148
  _gitReadAlwaysVisible: (agent.personaData || getPersona(agent.persona))?.id === 'reviewer',
150
149
  },
151
150
  conversationStore: null,
152
- memoryIndex: deps.memoryIndex || null,
153
- memoryStore: deps.memoryStore || null,
154
- memoryShardStore: deps.memoryShardStore || null,
151
+ memoryIndex: null,
152
+ memoryStore: null,
153
+ memoryShardStore: null,
155
154
  toolRegistry: childRegistry,
156
155
  skillManager: deps.skillManager || null,
157
156
  mcpManager: deps.mcpManager || null,
@@ -491,6 +490,8 @@ async function driveSubAgent(agent, subEngine, vpPersona, deps) {
491
490
  // Liveness — update first so even listener throws don't lose
492
491
  // the bump.
493
492
  bumpLivenessFromEvent(agent.liveness, evt);
493
+ // Hidden provider progress is liveness only, never a log/task/UI event.
494
+ if (evt?.type === 'provider_activity') continue;
494
495
 
495
496
  // Mirror every raw event to the durable log. We still keep
496
497
  // `sub_agent_event` text_delta suppressed so the inline transcript