@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.
@@ -1,22 +1,19 @@
1
1
  /**
2
- * consolidate.js — Consolidate = compact + extract (one LLM call)
2
+ * consolidate.js — Hot-window budget partitioning utilities.
3
3
  *
4
- * Triggered when hot_tokens > MESSAGE_TOKEN_BUDGET.
5
- * One LLM call does two things simultaneously:
6
- * 1. Generate compact summary append to compact.md ("short-term memory")
7
- * 2. Extract memory entries → write to entries/ ("long-term memory")
4
+ * Reduced surface (PR-B rip): the legacy LLM-driven consolidate() pipeline
5
+ * (compact summary + entries-store extraction) has been retired. The only
6
+ * survivors are the pure functions used by the compact orchestrator:
8
7
  *
9
- * After consolidation:
10
- * - Processed messages moved from messages/ to cold/
11
- * - index.md + scopes.md updated
8
+ * - shouldConsolidate(store, budget) — decide when to compact
9
+ * - partitionMessages(messages, budget) split hot messages into
10
+ * toArchive / toKeep based on token budget
12
11
  *
13
- * Reference: yeaft-unify-core-systems.md §3.1, §4.2
14
- * yeaft-unify-design.md §6.1
12
+ * Memory extraction is now owned by Dream V2 (per-group diff -> triage ->
13
+ * merge by target scope -> apply via segment-store + summary-store).
14
+ * Conversation summarisation lives in compact/orchestrator.js's hooks.
15
15
  */
16
16
 
17
- import { extractMemories } from './extract.js';
18
- import { pickEffort } from '../effort.js';
19
-
20
17
  // ─── Constants ──────────────────────────────────────────────────
21
18
 
22
19
  /** Default MESSAGE_TOKEN_BUDGET (context * 4%, default ~8192). */
@@ -28,8 +25,6 @@ export const COMPACT_KEEP_RATIO = 0.4;
28
25
  /** Minimum messages to keep hot (newest). */
29
26
  const MIN_KEEP_MESSAGES = 3;
30
27
 
31
- // ─── Consolidate ────────────────────────────────────────────────
32
-
33
28
  /**
34
29
  * Check if consolidation should be triggered.
35
30
  *
@@ -81,113 +76,3 @@ export function partitionMessages(messages, budget = DEFAULT_MESSAGE_TOKEN_BUDGE
81
76
  toKeep: messages.slice(keepStart),
82
77
  };
83
78
  }
84
-
85
- /**
86
- * Generate a compact summary of messages.
87
- *
88
- * @param {object[]} messages — messages to summarize
89
- * @param {object} adapter — LLM adapter with .call()
90
- * @param {object} config — { model }
91
- * @returns {Promise<string>} — compact summary text
92
- */
93
- async function generateSummary(messages, adapter, config) {
94
- const conversation = messages.map(m => {
95
- const prefix = m.role === 'user' ? 'User' : m.role === 'assistant' ? 'Assistant' : m.role;
96
- return `[${prefix}]: ${(m.content || '').slice(0, 500)}`;
97
- }).join('\n\n');
98
-
99
- const system = 'You are a conversation summarizer. Summarize the conversation concisely in 2-3 paragraphs, preserving key decisions, facts, and context. Write in the same language as the conversation.';
100
-
101
- try {
102
- const result = await adapter.call({
103
- model: config.model,
104
- system,
105
- messages: [{ role: 'user', content: `Summarize this conversation:\n\n${conversation}` }],
106
- maxTokens: 1024,
107
- // task-327c: consolidate is a high-complexity side-query; flag as
108
- // 'max' effort so supported models use extended thinking / reasoning.
109
- // Router/adapter silently drops the param for models that don't
110
- // support thinking, or when UNIFY_THINKING_V1 is off.
111
- effort: pickEffort({ scenario: 'consolidate' }),
112
- });
113
- return result.text.trim();
114
- } catch {
115
- // Fallback: simple concatenation of first/last messages
116
- const first = messages[0]?.content?.slice(0, 200) || '';
117
- const last = messages[messages.length - 1]?.content?.slice(0, 200) || '';
118
- return `[Auto-summary failed] Started with: ${first}... Ended with: ${last}`;
119
- }
120
- }
121
-
122
- /**
123
- * Run the full Consolidate pipeline.
124
- *
125
- * 1. Partition messages (what to archive vs keep)
126
- * 2. Generate compact summary (LLM call)
127
- * 3. Extract memory entries (LLM call)
128
- * 4. Move archived messages to cold/
129
- * 5. Update compact.md, index.md, scopes.md
130
- *
131
- * @param {{
132
- * conversationStore: import('../conversation/persist.js').ConversationStore,
133
- * memoryStore: import('./store.js').MemoryStore,
134
- * adapter: object,
135
- * config: object,
136
- * budget?: number
137
- * }} params
138
- * @returns {Promise<{ compactSummary: string, extractedEntries: string[], archivedCount: number }>}
139
- */
140
- export async function consolidate({ conversationStore, memoryStore, adapter, config, budget = DEFAULT_MESSAGE_TOKEN_BUDGET }) {
141
- // Load all hot messages
142
- const messages = conversationStore.loadAll();
143
-
144
- if (messages.length <= MIN_KEEP_MESSAGES) {
145
- return { compactSummary: '', extractedEntries: [], archivedCount: 0 };
146
- }
147
-
148
- // Step 1: Partition
149
- const { toArchive, toKeep } = partitionMessages(messages, budget);
150
-
151
- if (toArchive.length === 0) {
152
- return { compactSummary: '', extractedEntries: [], archivedCount: 0 };
153
- }
154
-
155
- // Step 2: Generate compact summary
156
- const compactSummary = await generateSummary(toArchive, adapter, config);
157
-
158
- // Step 3: Extract memory entries
159
- const extracted = await extractMemories({ messages: toArchive, adapter, config });
160
-
161
- // Step 4: Move archived messages to cold
162
- const archiveIds = toArchive.map(m => m.id).filter(Boolean);
163
- conversationStore.moveToColdBatch(archiveIds);
164
-
165
- // Step 5a: Update compact.md
166
- if (compactSummary) {
167
- conversationStore.updateCompactSummary(compactSummary);
168
- }
169
-
170
- // Step 5b: Write extracted memory entries
171
- const entryNames = [];
172
- for (const entry of extracted) {
173
- const slug = memoryStore.writeEntry(entry);
174
- entryNames.push(slug);
175
- }
176
-
177
- // Step 5c: Update index.md
178
- const lastMsg = toKeep[toKeep.length - 1];
179
- conversationStore.updateIndex({
180
- lastMessageId: lastMsg?.id || null,
181
- });
182
-
183
- // Step 5d: Rebuild scopes.md
184
- if (entryNames.length > 0) {
185
- memoryStore.rebuildScopes();
186
- }
187
-
188
- return {
189
- compactSummary,
190
- extractedEntries: entryNames,
191
- archivedCount: archiveIds.length,
192
- };
193
- }
package/unify/prompts.js CHANGED
@@ -368,27 +368,11 @@ export function buildSystemPrompt({
368
368
  }
369
369
 
370
370
  // ─── 6. Memory Section ─────────────────────────────────
371
+ // FTS5 pre-flow recall + AMS snapshot are concatenated upstream by the
372
+ // engine into a single `memoryInjection` block. The legacy entries-based
373
+ // memory.profile / memory.entries shape was retired in the H2-AMS rip.
371
374
  if (memoryInjection && memoryInjection.trim()) {
372
- // New path (task-287): prebuilt injection from memory/layout.buildMemoryInjection()
373
- // Contains index.md + user-preferences.md + optional project header excerpt.
374
375
  parts.push(memoryInjection.trim());
375
- } else if (memory && (memory.profile || (memory.entries && memory.entries.length > 0))) {
376
- // Legacy path — kept for callers (tests, CLI) that have not migrated yet.
377
- const memoryParts = [lang.memoryHeader];
378
-
379
- if (memory.profile) {
380
- memoryParts.push(`${lang.profileHeader}\n${memory.profile}`);
381
- }
382
-
383
- if (memory.entries && memory.entries.length > 0) {
384
- const entryLines = memory.entries.map(e => {
385
- const tags = (e.tags && e.tags.length > 0) ? ` [${e.tags.join(', ')}]` : '';
386
- return `- **${e.name}** (${e.kind}): ${e.content}${tags}`;
387
- });
388
- memoryParts.push(`${lang.recalledHeader}\n${entryLines.join('\n')}`);
389
- }
390
-
391
- parts.push(memoryParts.join('\n\n'));
392
376
  }
393
377
 
394
378
  // ─── 7. Compact Summary Section ────────────────────────
package/unify/session.js CHANGED
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Wires all subsystems together:
7
7
  * initYeaftDir → loadConfig → createTrace → createLLMAdapter →
8
- * ConversationStore → MemoryStore → SkillManager → MCPManager →
8
+ * ConversationStore → SkillManager → MCPManager →
9
9
  * ToolRegistry → Engine → Session
10
10
  *
11
11
  * The ~/.yeaft/ directory is the agent's persistent workspace.
@@ -18,8 +18,6 @@ import { loadConfig, loadMCPConfig } from './config.js';
18
18
  import { createTrace } from './debug-trace.js';
19
19
  import { createLLMAdapter } from './llm/adapter.js';
20
20
  import { ConversationStore } from './conversation/persist.js';
21
- import { MemoryStore } from './memory/store.js';
22
- import { openMemoryShardStore } from './memory/shard-store.js';
23
21
  import { SkillManager, createSkillManager } from './skills.js';
24
22
  import { MCPManager } from './mcp.js';
25
23
  import { createFullRegistry } from './tools/index.js';
@@ -68,7 +66,6 @@ import { existsSync as existsSyncSafe, readFileSync as readFileSyncSafe } from '
68
66
  * @property {import('./llm/adapter.js').LLMAdapter} adapter — The LLM adapter
69
67
  * @property {object} config — Resolved configuration
70
68
  * @property {ConversationStore} conversationStore — Conversation persistence
71
- * @property {MemoryStore} memoryStore — Memory persistence
72
69
  * @property {SkillManager} skillManager — Skill manager
73
70
  * @property {MCPManager} mcpManager — MCP manager
74
71
  * @property {import('./tools/registry.js').ToolRegistry} toolRegistry — Tool registry
@@ -169,19 +166,6 @@ export async function loadSession(options = {}) {
169
166
 
170
167
  // ─── 5. Create stores ──────────────────────────────────
171
168
  const conversationStore = new ConversationStore(yeaftDir);
172
- const memoryStore = new MemoryStore(yeaftDir);
173
-
174
- // ─── 5-shard. Open R6 memory shard store (task-334f) ──────
175
- // VP-level memory shard store rooted at ~/.yeaft/memory/vp/default.
176
- // The 'default' VP matches the single-user Unify mode; R6 multi-VP
177
- // callers open per-VP stores via openMemoryShardStore() directly.
178
- const memoryShardDir = join(yeaftDir, 'memory', 'vp', 'default');
179
- let memoryShardStore = null;
180
- try {
181
- memoryShardStore = openMemoryShardStore(memoryShardDir, 'vp');
182
- } catch (err) {
183
- console.warn(`[Yeaft] Failed to open R6 memory shard store: ${err?.message || err}`);
184
- }
185
169
 
186
170
  // ─── 5-fts. (GC.1) Open SegmentIndex for FTS pre-flow ────
187
171
  // When config.memoryV2 is on, build a SQLite FTS5 index over
@@ -290,8 +274,6 @@ export async function loadSession(options = {}) {
290
274
  trace,
291
275
  config,
292
276
  conversationStore,
293
- memoryStore,
294
- memoryShardStore,
295
277
  memoryIndex,
296
278
  amsRegistry,
297
279
  toolRegistry,
@@ -363,8 +345,6 @@ export async function loadSession(options = {}) {
363
345
  adapter,
364
346
  config,
365
347
  conversationStore,
366
- memoryStore,
367
- memoryShardStore,
368
348
  dreamScheduler,
369
349
  skillManager,
370
350
  mcpManager,
@@ -3,17 +3,17 @@
3
3
  *
4
4
  * Runs after each query loop completes:
5
5
  * 1. Persist messages to conversation/messages/
6
- * 2. Consolidate check (compact + extract) — only when budget exceeded
6
+ *
7
+ * Consolidation (compact orchestrator) is driven by the engine itself
8
+ * via `#maybeConsolidate`; the legacy LLM-driven `consolidate()` plus
9
+ * entries-store extraction was retired in the H2-AMS rip.
7
10
  *
8
11
  * Dream V2 owns all background memory maintenance (scope summaries +
9
- * memory writes via dream-v2/session-wiring.js → createV2DreamScheduler);
10
- * the legacy `memory/dream.js` gate that used to fire here was retired
11
- * alongside recall-r6.
12
+ * memory writes via dream-v2/session-wiring.js → createV2DreamScheduler).
12
13
  *
13
14
  * Reference: yeaft-unify-core-systems.md §4.4
14
15
  */
15
16
 
16
- import { shouldConsolidate, consolidate } from './memory/consolidate.js';
17
17
  import { isPermissionError } from './init.js';
18
18
 
19
19
  /** Track whether we've already warned about permission issues in stop hooks. */
@@ -26,7 +26,6 @@ let _permissionWarned = false;
26
26
  * yeaftDir: string,
27
27
  * mode: string,
28
28
  * conversationStore: import('./conversation/persist.js').ConversationStore,
29
- * memoryStore: import('./memory/store.js').MemoryStore,
30
29
  * adapter: object,
31
30
  * config: object,
32
31
  * primaryModel?: string,
@@ -42,7 +41,6 @@ export async function runStopHooks(context) {
42
41
  yeaftDir,
43
42
  mode,
44
43
  conversationStore,
45
- memoryStore,
46
44
  adapter,
47
45
  config,
48
46
  primaryModel,
@@ -60,7 +58,6 @@ export async function runStopHooks(context) {
60
58
 
61
59
  const result = {
62
60
  messagesPersisted: 0,
63
- consolidated: false,
64
61
  errors: [],
65
62
  };
66
63
 
@@ -133,41 +130,9 @@ export async function runStopHooks(context) {
133
130
  }
134
131
  }
135
132
 
136
- // 2. Consolidate check (non-blocking, but awaited for correctness)
137
- try {
138
- if (conversationStore && memoryStore && adapter) {
139
- if (shouldConsolidate(conversationStore, config.messageTokenBudget)) {
140
- const consolidated = await consolidate({
141
- conversationStore,
142
- memoryStore,
143
- adapter,
144
- config,
145
- budget: config.messageTokenBudget,
146
- });
147
- result.consolidated = true;
148
- trace?.logEvent({
149
- eventType: 'consolidate',
150
- eventData: {
151
- archivedCount: consolidated.archivedCount,
152
- extractedEntries: consolidated.extractedEntries.length,
153
- },
154
- });
155
- }
156
- }
157
- } catch (err) {
158
- if (isPermissionError(err)) {
159
- if (!_permissionWarned) {
160
- result.errors.push('Cannot write to ~/.yeaft/ — consolidation skipped');
161
- _permissionWarned = true;
162
- }
163
- } else {
164
- result.errors.push(`Consolidate failed: ${err.message}`);
165
- }
166
- }
167
-
168
- // 3. Dream V2 owns background scope-memory maintenance via the session
169
- // dream scheduler (createV2DreamScheduler). No legacy dream gate is
170
- // invoked here; the scheduler decides when to run on its own cadence.
133
+ // 2. Consolidation is owned by the engine (#maybeConsolidate → compact
134
+ // orchestrator). Dream V2 owns background scope-memory maintenance
135
+ // via the session dream scheduler (createV2DreamScheduler).
171
136
 
172
137
  return result;
173
138
  }
@@ -175,6 +140,5 @@ export async function runStopHooks(context) {
175
140
  /**
176
141
  * @typedef {Object} StopHookResult
177
142
  * @property {number} messagesPersisted — how many messages were persisted
178
- * @property {boolean} consolidated — whether consolidation ran
179
143
  * @property {string[]} errors — any non-fatal errors
180
144
  */
@@ -18,11 +18,6 @@ import exitWorktree from './exit-worktree.js';
18
18
 
19
19
  // --- P0 Core tools ---
20
20
  import askUser from './ask-user.js';
21
- import memoryRead from './memory-read.js';
22
- import memoryWrite from './memory-write.js';
23
- import memorySearch, { memorySearchAlias } from './memory-search.js';
24
- import memoryQuery from './memory-query.js';
25
- import memoryTrace from './memory-trace.js';
26
21
  import openSourceMessage from './open-source-message.js';
27
22
  import webSearch from './web-search.js';
28
23
  import webFetch from './web-fetch.js';
@@ -89,12 +84,6 @@ export const allTools = [
89
84
 
90
85
  // P0 Core
91
86
  askUser,
92
- memoryRead,
93
- memoryWrite,
94
- memorySearch,
95
- memorySearchAlias,
96
- memoryQuery,
97
- memoryTrace,
98
87
  openSourceMessage,
99
88
  webSearch,
100
89
  webFetch,
@@ -26,10 +26,6 @@ import { createVp, updateVp, deleteVp, readVp, VpCrudError } from './vp/vp-crud.
26
26
  import { scanVpLibrary } from './vp/vp-store.js';
27
27
  import { createRouter } from './routing/router.js';
28
28
  import { handleUnifyFeatureMessage as _handleUnifyFeatureMessage } from './feature-message.js';
29
- import {
30
- handleUnifyUserMemoryWrite as _handleUnifyUserMemoryWrite,
31
- handleUnifyUserMemoryRemove as _handleUnifyUserMemoryRemove,
32
- } from './user-memory.js';
33
29
  import {
34
30
  GroupCrudError,
35
31
  createGroupFromSpec,
@@ -209,36 +205,6 @@ export function handleUnifyFeatureMessage(msg) {
209
205
  _handleUnifyFeatureMessage(msg, sendUnifyEvent);
210
206
  }
211
207
 
212
- export function handleUnifyUserMemoryWrite(msg) {
213
- _handleUnifyUserMemoryWrite(msg, sendUnifyEvent);
214
- }
215
-
216
- export function handleUnifyUserMemoryRemove(msg) {
217
- _handleUnifyUserMemoryRemove(msg, sendUnifyEvent);
218
- }
219
-
220
- export function handleUnifyMemoryScopeList(msg) {
221
- const requestId = msg && typeof msg.requestId === 'string' ? msg.requestId : undefined;
222
- try {
223
- const store = session && session.memoryStore;
224
- const entries = store && typeof store.listEntries === 'function'
225
- ? store.listEntries()
226
- : [];
227
- sendUnifyEvent({
228
- type: 'memory_scope_snapshot',
229
- entries,
230
- ...(requestId ? { requestId } : {}),
231
- });
232
- } catch (err) {
233
- sendUnifyEvent({
234
- type: 'memory_scope_snapshot',
235
- entries: [],
236
- error: String(err && err.message || err),
237
- ...(requestId ? { requestId } : {}),
238
- });
239
- }
240
- }
241
-
242
208
  export function handleUnifyVpRead(msg) {
243
209
  const requestId = msg && msg.requestId;
244
210
  const vpId = msg && msg.vpId;
@@ -1130,70 +1096,6 @@ export function handleUnifyModeSwitch(_msg) {
1130
1096
  console.warn('[Unify] unify_mode_switch is deprecated and ignored — Unify now runs in a single unified mode.');
1131
1097
  }
1132
1098
 
1133
- /** Read-only memory query for the UI memory browser. */
1134
- export function handleUnifyMemoryQuery(msg = {}) {
1135
- const requestId = typeof msg.requestId === 'string' ? msg.requestId : undefined;
1136
- const vpId = typeof msg.vpId === 'string' ? msg.vpId : null;
1137
- const featureId = typeof msg.featureId === 'string' ? msg.featureId : null;
1138
- const limit = Number.isFinite(msg.limit) ? Math.max(1, Math.min(200, msg.limit)) : 50;
1139
-
1140
- const reply = (extra = {}) => sendUnifyEvent({
1141
- type: 'unify_memory_query_result',
1142
- scope: { vpId, featureId },
1143
- ...extra,
1144
- ...(requestId ? { requestId } : {}),
1145
- });
1146
-
1147
- if (!session || !session.memoryShardStore) {
1148
- reply({ entries: [], error: 'no_memory_store' });
1149
- return;
1150
- }
1151
-
1152
- try {
1153
- const filter = {};
1154
- if (vpId) filter.vp = vpId;
1155
- if (featureId) filter.feature = featureId;
1156
- const res = session.memoryShardStore.query(filter);
1157
- const list = Array.isArray(res?.results) ? res.results : [];
1158
- list.sort((a, b) => {
1159
- const ax = (a && (a.updatedAt || a.createdAt)) || 0;
1160
- const bx = (b && (b.updatedAt || b.createdAt)) || 0;
1161
- const at = typeof ax === 'string' ? Date.parse(ax) : ax;
1162
- const bt = typeof bx === 'string' ? Date.parse(bx) : bx;
1163
- return (bt || 0) - (at || 0);
1164
- });
1165
- reply({ entries: list.slice(0, limit) });
1166
- } catch (err) {
1167
- reply({ entries: [], error: String(err?.message || err) });
1168
- }
1169
- }
1170
-
1171
- /** Open the source message behind a memory entry. */
1172
- export function handleUnifyMemoryTrace(msg = {}) {
1173
- const requestId = typeof msg.requestId === 'string' ? msg.requestId : undefined;
1174
- const entryId = typeof msg.entryId === 'string' ? msg.entryId : null;
1175
-
1176
- const reply = (extra = {}) => sendUnifyEvent({
1177
- type: 'unify_memory_trace_result',
1178
- entryId,
1179
- ...extra,
1180
- ...(requestId ? { requestId } : {}),
1181
- });
1182
-
1183
- if (!entryId) { reply({ entry: null, sourceRef: null, error: 'missing_entry_id' }); return; }
1184
- if (!session || !session.memoryShardStore) {
1185
- reply({ entry: null, sourceRef: null, error: 'no_memory_store' });
1186
- return;
1187
- }
1188
- try {
1189
- const entry = session.memoryShardStore.get(entryId);
1190
- if (!entry) { reply({ entry: null, sourceRef: null, error: 'not_found' }); return; }
1191
- reply({ entry, sourceRef: entry.sourceRef || null });
1192
- } catch (err) {
1193
- reply({ entry: null, sourceRef: null, error: String(err?.message || err) });
1194
- }
1195
- }
1196
-
1197
1099
  /** Fetch a feature's summary history (revision chain). */
1198
1100
  export async function handleUnifyFetchSummaryHistory(msg = {}) {
1199
1101
  const requestId = typeof msg.requestId === 'string' ? msg.requestId : undefined;