@yeaft/webchat-agent 0.1.874 → 0.1.876
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 +20 -13
- package/package.json +1 -1
- package/yeaft/attachments.js +2 -2
- package/yeaft/cli.js +13 -13
- package/yeaft/compact/compactor.js +20 -20
- package/yeaft/conversation/persist.js +95 -95
- package/yeaft/debug-trace.js +12 -12
- package/yeaft/dream-v2/apply.js +15 -15
- package/yeaft/dream-v2/merge.js +12 -12
- package/yeaft/dream-v2/prompts/{extract-group.md → extract-session.md} +12 -12
- package/yeaft/dream-v2/prompts/index.js +3 -3
- package/yeaft/dream-v2/prompts/triage-pass1.md +1 -1
- package/yeaft/dream-v2/runner.js +37 -37
- package/yeaft/dream-v2/segment.js +3 -3
- package/yeaft/dream-v2/session-wiring.js +22 -22
- package/yeaft/dream-v2/state.js +7 -7
- package/yeaft/dream-v2/triage.js +22 -22
- package/yeaft/engine.js +65 -65
- package/yeaft/memory/ams-registry.js +22 -22
- package/yeaft/memory/seed-backfill.js +9 -9
- package/yeaft/memory/store-v2.js +27 -27
- package/yeaft/prompts.js +9 -9
- package/yeaft/routing/loop-guard.js +14 -14
- package/yeaft/routing/router.js +5 -5
- package/yeaft/session.js +5 -5
- package/yeaft/sessions/coordinator.js +96 -20
- package/yeaft/{groups → sessions}/ids.js +3 -3
- package/yeaft/{groups → sessions}/index.js +28 -28
- package/yeaft/sessions/pre-flow.js +178 -42
- package/yeaft/{groups → sessions}/seed-default.js +19 -19
- package/yeaft/{groups/group-config.js → sessions/session-config.js} +29 -29
- package/yeaft/{groups/group-crud.js → sessions/session-crud.js} +113 -113
- package/yeaft/sessions/session-store.js +85 -154
- package/yeaft/stop-hooks.js +4 -4
- package/yeaft/tools/todo-write.js +1 -1
- package/yeaft/tools/types.js +2 -2
- package/yeaft/vp/registry.js +1 -1
- package/yeaft/vp/vp-crud.js +1 -1
- package/yeaft/vp-status-broker.js +28 -28
- package/yeaft/web-bridge.js +411 -398
- package/yeaft/groups/coordinator.js +0 -221
- package/yeaft/groups/group-store.js +0 -212
- package/yeaft/groups/pre-flow.js +0 -329
- /package/yeaft/{groups → sessions}/feature-flag.js +0 -0
- /package/yeaft/{groups → sessions}/project-doc.js +0 -0
- /package/yeaft/{groups → sessions}/roster.js +0 -0
|
@@ -37,9 +37,16 @@ import { handleRestartAgent, handleUpgradeAgent } from './upgrade.js';
|
|
|
37
37
|
import { loadMcpServers, updateMcpConfig } from '../mcp.js';
|
|
38
38
|
import { getLlmConfig, updateLlmConfig, getYeaftSettings, updateYeaftSettings, getSearchSettings, updateSearchSettings, fetchTavilyUsage } from '../yeaft/config-api.js';
|
|
39
39
|
import { fetchModelsDev } from '../yeaft/llm/models-dev.js';
|
|
40
|
-
import {
|
|
40
|
+
import { handleYeaftSessionSend, handleYeaftModeSwitch, handleYeaftModelSwitch, resetYeaftSession, handleYeaftLoadHistory, handleYeaftLoadMoreHistory, handleYeaftAbortThread, handleYeaftAbortAll, handleYeaftAbortTurn, handleYeaftVpSubscribe, handleYeaftVpCreate, handleYeaftVpUpdate, handleYeaftVpDelete, handleYeaftVpRead, handleYeaftListSessions, handleYeaftCreateSession, handleYeaftRenameSession, handleYeaftUpdateSession, handleYeaftUpdateSessionConfig, handleYeaftArchiveSession, handleYeaftDeleteSession, handleYeaftSessionAddMember, handleYeaftSessionRemoveMember, handleYeaftSessionSetDefaultVp, handleYeaftDreamTrigger, handleYeaftFetchToolStats, handleYeaftFetchDebugHistory, broadcastLanguageChange } from '../yeaft/web-bridge.js';
|
|
41
41
|
|
|
42
42
|
export async function handleMessage(msg) {
|
|
43
|
+
// Wire-compat: old web bundles send `groupId` on Yeaft messages;
|
|
44
|
+
// the agent runtime has switched to `sessionId`. Coerce here so
|
|
45
|
+
// handlers don't each have to do it. Keep both fields populated.
|
|
46
|
+
if (msg && typeof msg === 'object') {
|
|
47
|
+
if (msg.sessionId == null && typeof msg.groupId === 'string') msg.sessionId = msg.groupId;
|
|
48
|
+
if (msg.groupId == null && typeof msg.sessionId === 'string') msg.groupId = msg.sessionId;
|
|
49
|
+
}
|
|
43
50
|
switch (msg.type) {
|
|
44
51
|
case 'registered':
|
|
45
52
|
if (msg.sessionKey) {
|
|
@@ -429,7 +436,7 @@ export async function handleMessage(msg) {
|
|
|
429
436
|
// Yeaft — single conversation backed by the default group.
|
|
430
437
|
case 'yeaft_group_chat':
|
|
431
438
|
case 'unify_group_chat':
|
|
432
|
-
await
|
|
439
|
+
await handleYeaftSessionSend(msg);
|
|
433
440
|
break;
|
|
434
441
|
|
|
435
442
|
case 'yeaft_load_history':
|
|
@@ -513,56 +520,56 @@ export async function handleMessage(msg) {
|
|
|
513
520
|
case 'yeaft_list_groups':
|
|
514
521
|
case 'unify_list_groups':
|
|
515
522
|
case 'yeaft_list_sessions':
|
|
516
|
-
|
|
523
|
+
handleYeaftListSessions(msg);
|
|
517
524
|
break;
|
|
518
525
|
case 'yeaft_create_group':
|
|
519
526
|
case 'unify_create_group':
|
|
520
527
|
case 'yeaft_create_session':
|
|
521
|
-
|
|
528
|
+
handleYeaftCreateSession(msg);
|
|
522
529
|
break;
|
|
523
530
|
case 'yeaft_rename_group':
|
|
524
531
|
case 'unify_rename_group':
|
|
525
532
|
case 'yeaft_rename_session':
|
|
526
|
-
|
|
533
|
+
handleYeaftRenameSession(msg);
|
|
527
534
|
break;
|
|
528
535
|
case 'yeaft_update_group':
|
|
529
536
|
case 'unify_update_group':
|
|
530
537
|
case 'yeaft_update_session':
|
|
531
|
-
|
|
538
|
+
handleYeaftUpdateSession(msg);
|
|
532
539
|
break;
|
|
533
540
|
case 'yeaft_update_group_config':
|
|
534
541
|
case 'unify_update_group_config':
|
|
535
542
|
case 'yeaft_update_session_config':
|
|
536
|
-
|
|
543
|
+
handleYeaftUpdateSessionConfig(msg);
|
|
537
544
|
break;
|
|
538
545
|
case 'yeaft_archive_group':
|
|
539
546
|
case 'unify_archive_group':
|
|
540
547
|
case 'yeaft_archive_session':
|
|
541
|
-
|
|
548
|
+
handleYeaftArchiveSession(msg);
|
|
542
549
|
break;
|
|
543
550
|
case 'yeaft_delete_group':
|
|
544
551
|
case 'unify_delete_group':
|
|
545
552
|
case 'yeaft_delete_session':
|
|
546
|
-
|
|
553
|
+
handleYeaftDeleteSession(msg);
|
|
547
554
|
break;
|
|
548
555
|
case 'yeaft_add_member':
|
|
549
556
|
case 'unify_add_member':
|
|
550
557
|
case 'yeaft_session_add_member':
|
|
551
|
-
|
|
558
|
+
handleYeaftSessionAddMember(msg);
|
|
552
559
|
break;
|
|
553
560
|
case 'yeaft_remove_member':
|
|
554
561
|
case 'unify_remove_member':
|
|
555
562
|
case 'yeaft_session_remove_member':
|
|
556
|
-
|
|
563
|
+
handleYeaftSessionRemoveMember(msg);
|
|
557
564
|
break;
|
|
558
565
|
case 'yeaft_set_default_vp':
|
|
559
566
|
case 'unify_set_default_vp':
|
|
560
567
|
case 'yeaft_session_set_default_vp':
|
|
561
|
-
|
|
568
|
+
handleYeaftSessionSetDefaultVp(msg);
|
|
562
569
|
break;
|
|
563
570
|
// Phase 2: session_send is just group_chat (N≥1 fan-out already works).
|
|
564
571
|
case 'yeaft_session_send':
|
|
565
|
-
|
|
572
|
+
handleYeaftSessionSend(msg);
|
|
566
573
|
break;
|
|
567
574
|
|
|
568
575
|
// wave-6b: manual dream trigger from VP detail page
|
package/package.json
CHANGED
package/yeaft/attachments.js
CHANGED
|
@@ -90,7 +90,7 @@ function sanitizeBaseName(base) {
|
|
|
90
90
|
* Resolved files from server (pendingFiles → base64).
|
|
91
91
|
* @param {Object} [opts]
|
|
92
92
|
* @param {string} [opts.subdir] Sub-folder under TEMP_UPLOAD_DIR
|
|
93
|
-
* (e.g.
|
|
93
|
+
* (e.g. sessionId). Lets multiple groups co-exist without clobbering.
|
|
94
94
|
* @param {string} [opts.cwd] Override base dir; defaults to process.cwd()
|
|
95
95
|
* which is what yeaft tools (file-read, bash, ...) resolve relative
|
|
96
96
|
* paths against.
|
|
@@ -104,7 +104,7 @@ function sanitizeBaseName(base) {
|
|
|
104
104
|
export function persistYeaftAttachments(files, opts = {}) {
|
|
105
105
|
const cwd = opts.cwd || process.cwd();
|
|
106
106
|
// Subdir is OURS — it must remain ASCII-safe because we generate it
|
|
107
|
-
// from
|
|
107
|
+
// from sessionId. Keep the existing strict policy here; this is NOT
|
|
108
108
|
// user-visible.
|
|
109
109
|
const subdir = opts.subdir ? String(opts.subdir).replace(/[^a-zA-Z0-9._-]/g, '_') : '';
|
|
110
110
|
const uploadDir = subdir
|
package/yeaft/cli.js
CHANGED
|
@@ -32,7 +32,7 @@ import { listModels, resolveModel, parseModelRef } from './models.js';
|
|
|
32
32
|
import { buildSystemPrompt } from './prompts.js';
|
|
33
33
|
import { searchMessages } from './conversation/search.js';
|
|
34
34
|
import { ConversationStore } from './conversation/persist.js';
|
|
35
|
-
import {
|
|
35
|
+
import { snapshotSessions } from './sessions/session-crud.js';
|
|
36
36
|
|
|
37
37
|
// ─── Argument parsing ──────────────────────────────────────────
|
|
38
38
|
|
|
@@ -50,7 +50,7 @@ function parseArgs(argv) {
|
|
|
50
50
|
skipSkills: false,
|
|
51
51
|
compactOrphans: false,
|
|
52
52
|
compactOrphansDry: false,
|
|
53
|
-
|
|
53
|
+
deleteSession: null,
|
|
54
54
|
prompt: null,
|
|
55
55
|
};
|
|
56
56
|
|
|
@@ -100,7 +100,7 @@ function parseArgs(argv) {
|
|
|
100
100
|
args.compactOrphansDry = true;
|
|
101
101
|
break;
|
|
102
102
|
case '--delete-group':
|
|
103
|
-
args.
|
|
103
|
+
args.deleteSession = rest[++i] || null;
|
|
104
104
|
break;
|
|
105
105
|
default:
|
|
106
106
|
if (!arg.startsWith('-') && !args.prompt) {
|
|
@@ -216,7 +216,7 @@ function handleDryRun(args, config) {
|
|
|
216
216
|
|
|
217
217
|
/**
|
|
218
218
|
* One-shot orphan-message sweep. Reads the live group list off disk and
|
|
219
|
-
* deletes every persisted message whose `
|
|
219
|
+
* deletes every persisted message whose `sessionId` frontmatter is missing
|
|
220
220
|
* or points to a group that no longer exists.
|
|
221
221
|
*
|
|
222
222
|
* Exposed via `--compact-orphans` (delete) and `--compact-orphans-dry`
|
|
@@ -227,7 +227,7 @@ function handleCompactOrphans(config, { dryRun = false } = {}) {
|
|
|
227
227
|
const yeaftDir = config.dir;
|
|
228
228
|
let groups;
|
|
229
229
|
try {
|
|
230
|
-
groups =
|
|
230
|
+
groups = snapshotSessions(yeaftDir);
|
|
231
231
|
} catch (err) {
|
|
232
232
|
console.error(`Cannot read groups directory: ${err.message}`);
|
|
233
233
|
console.error('Refusing to compact orphans without an authoritative live-group list.');
|
|
@@ -258,30 +258,30 @@ function handleCompactOrphans(config, { dryRun = false } = {}) {
|
|
|
258
258
|
* as the web-bridge `yeaft_delete_group` op, but reachable from the CLI
|
|
259
259
|
* for scripted maintenance.
|
|
260
260
|
*/
|
|
261
|
-
function handleDeleteGroup(config,
|
|
261
|
+
function handleDeleteGroup(config, sessionId) {
|
|
262
262
|
const yeaftDir = config.dir;
|
|
263
263
|
// Lazy import to avoid loading the whole groups module on every CLI call.
|
|
264
264
|
// (Static `import` at top is fine too — kept dynamic to mirror the web-bridge
|
|
265
265
|
// pattern and keep the maintenance path self-contained.)
|
|
266
266
|
// eslint-disable-next-line global-require
|
|
267
|
-
return import('./
|
|
267
|
+
return import('./sessions/session-crud.js').then(({ deleteSession }) => {
|
|
268
268
|
let result;
|
|
269
269
|
try {
|
|
270
|
-
result =
|
|
270
|
+
result = deleteSession(yeaftDir, sessionId);
|
|
271
271
|
} catch (err) {
|
|
272
|
-
console.error(`Failed to delete group ${
|
|
272
|
+
console.error(`Failed to delete group ${sessionId}: ${err.message}`);
|
|
273
273
|
process.exitCode = 1;
|
|
274
274
|
return;
|
|
275
275
|
}
|
|
276
276
|
let messagesRemoved = 0;
|
|
277
277
|
try {
|
|
278
278
|
const store = new ConversationStore(yeaftDir);
|
|
279
|
-
messagesRemoved = store.deleteByGroup(
|
|
279
|
+
messagesRemoved = store.deleteByGroup(sessionId);
|
|
280
280
|
} catch (err) {
|
|
281
281
|
console.warn(`Group dir removed, but cascade failed: ${err.message}`);
|
|
282
282
|
}
|
|
283
283
|
console.log('=== DELETE GROUP ===');
|
|
284
|
-
console.log(` Group: ${result.
|
|
284
|
+
console.log(` Group: ${result.sessionId}`);
|
|
285
285
|
console.log(` Legacy archives swept: ${result.legacyCleanedUp}`);
|
|
286
286
|
console.log(` Messages cascaded: ${messagesRemoved}`);
|
|
287
287
|
});
|
|
@@ -784,8 +784,8 @@ async function main() {
|
|
|
784
784
|
handleCompactOrphans(config, { dryRun: args.compactOrphansDry });
|
|
785
785
|
return;
|
|
786
786
|
}
|
|
787
|
-
if (args.
|
|
788
|
-
await handleDeleteGroup(config, args.
|
|
787
|
+
if (args.deleteSession) {
|
|
788
|
+
await handleDeleteGroup(config, args.deleteSession);
|
|
789
789
|
return;
|
|
790
790
|
}
|
|
791
791
|
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* separately via `setOnCompacted`.
|
|
20
20
|
*
|
|
21
21
|
* Engine instances are per-VP-per-group (`vpEngines` keyed by
|
|
22
|
-
* `${
|
|
22
|
+
* `${sessionId}::${vpId}`), so this orchestration cannot live on `Engine`
|
|
23
23
|
* itself: a per-group single-flight slot pinned to a per-VP Engine is a
|
|
24
24
|
* category error. Compactor is constructed once per session, beside the
|
|
25
25
|
* `dreamScheduler`.
|
|
@@ -67,7 +67,7 @@ export class Compactor {
|
|
|
67
67
|
* `compactHistory` so the compactor's summary prompt + the
|
|
68
68
|
* "session continued" wrapper render in the user's preferred
|
|
69
69
|
* locale instead of always English.
|
|
70
|
-
* @param {(
|
|
70
|
+
* @param {(sessionId: string, result: CompactedResult) => void} [opts.onCompacted]
|
|
71
71
|
* Optional sink. Bridge wires this to send the
|
|
72
72
|
* `yeaft_history_compacted` WS event. Default: no-op. Can be
|
|
73
73
|
* replaced post-construction via `setOnCompacted`.
|
|
@@ -100,11 +100,11 @@ export class Compactor {
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
/** Get-or-create the per-group state record. */
|
|
103
|
-
_state(
|
|
104
|
-
let s = this._states.get(
|
|
103
|
+
_state(sessionId) {
|
|
104
|
+
let s = this._states.get(sessionId);
|
|
105
105
|
if (!s) {
|
|
106
106
|
s = { inFlight: null, pending: false };
|
|
107
|
-
this._states.set(
|
|
107
|
+
this._states.set(sessionId, s);
|
|
108
108
|
}
|
|
109
109
|
return s;
|
|
110
110
|
}
|
|
@@ -114,11 +114,11 @@ export class Compactor {
|
|
|
114
114
|
* so a brand-new turn never reads a half-mutated history mid-compact.
|
|
115
115
|
* Other groups' compacts never block this gate (per-group keying).
|
|
116
116
|
*
|
|
117
|
-
* @param {string}
|
|
117
|
+
* @param {string} sessionId
|
|
118
118
|
*/
|
|
119
|
-
async awaitInFlight(
|
|
120
|
-
if (!
|
|
121
|
-
const s = this._states.get(
|
|
119
|
+
async awaitInFlight(sessionId) {
|
|
120
|
+
if (!sessionId) return;
|
|
121
|
+
const s = this._states.get(sessionId);
|
|
122
122
|
if (s && s.inFlight) {
|
|
123
123
|
try { await s.inFlight; } catch { /* _runOnce already logs */ }
|
|
124
124
|
}
|
|
@@ -127,7 +127,7 @@ export class Compactor {
|
|
|
127
127
|
/**
|
|
128
128
|
* Post-turn fire-and-forget. Bridge calls after the per-VP fanout
|
|
129
129
|
* completes for a turn. The `historyHandle` MUST be a per-call value:
|
|
130
|
-
* its `get` / `set` close over the bridge's
|
|
130
|
+
* its `get` / `set` close over the bridge's sessionId-scoped helpers
|
|
131
131
|
* (`getOrCreateGroupHistory` / `setGroupHistory`), not over a frozen
|
|
132
132
|
* snapshot, so a chained follow-up sees fresh state.
|
|
133
133
|
*
|
|
@@ -136,12 +136,12 @@ export class Compactor {
|
|
|
136
136
|
* the in-flight finishes, exactly one follow-up runs (no matter how
|
|
137
137
|
* many turns piled up during the await).
|
|
138
138
|
*
|
|
139
|
-
* @param {string}
|
|
139
|
+
* @param {string} sessionId
|
|
140
140
|
* @param {CompactorHistoryHandle} historyHandle
|
|
141
141
|
*/
|
|
142
|
-
scheduleAfterTurn(
|
|
143
|
-
if (!
|
|
144
|
-
const s = this._state(
|
|
142
|
+
scheduleAfterTurn(sessionId, historyHandle) {
|
|
143
|
+
if (!sessionId || !historyHandle) return;
|
|
144
|
+
const s = this._state(sessionId);
|
|
145
145
|
if (s.inFlight) {
|
|
146
146
|
// Anti-starvation: compact is already running. Mark a follow-up
|
|
147
147
|
// so when it finishes, it re-evaluates and runs again if still
|
|
@@ -149,14 +149,14 @@ export class Compactor {
|
|
|
149
149
|
s.pending = true;
|
|
150
150
|
return;
|
|
151
151
|
}
|
|
152
|
-
s.inFlight = this._runOnce(
|
|
152
|
+
s.inFlight = this._runOnce(sessionId, historyHandle).finally(() => {
|
|
153
153
|
s.inFlight = null;
|
|
154
154
|
// If turns piled up while we were running and compaction is still
|
|
155
155
|
// needed, chain a follow-up. Use a microtask so the .finally
|
|
156
156
|
// chain settles cleanly before the next promise is created.
|
|
157
157
|
if (s.pending) {
|
|
158
158
|
s.pending = false;
|
|
159
|
-
queueMicrotask(() => this.scheduleAfterTurn(
|
|
159
|
+
queueMicrotask(() => this.scheduleAfterTurn(sessionId, historyHandle));
|
|
160
160
|
}
|
|
161
161
|
});
|
|
162
162
|
}
|
|
@@ -167,10 +167,10 @@ export class Compactor {
|
|
|
167
167
|
* `historyHandle.set`, then notifies `onCompacted`. All errors are
|
|
168
168
|
* swallowed (logged) so `inFlight` always clears.
|
|
169
169
|
*
|
|
170
|
-
* @param {string}
|
|
170
|
+
* @param {string} sessionId
|
|
171
171
|
* @param {CompactorHistoryHandle} historyHandle
|
|
172
172
|
*/
|
|
173
|
-
async _runOnce(
|
|
173
|
+
async _runOnce(sessionId, historyHandle) {
|
|
174
174
|
try {
|
|
175
175
|
// Capture reference AND length. If a different code path swaps the
|
|
176
176
|
// array (`consolidate` event, session reset, manual clear) the
|
|
@@ -233,7 +233,7 @@ export class Compactor {
|
|
|
233
233
|
);
|
|
234
234
|
|
|
235
235
|
try {
|
|
236
|
-
this._onCompacted(
|
|
236
|
+
this._onCompacted(sessionId, {
|
|
237
237
|
reason: result.reason,
|
|
238
238
|
beforeTurns: result.beforeTurns,
|
|
239
239
|
afterTurns: result.afterTurns,
|
|
@@ -243,7 +243,7 @@ export class Compactor {
|
|
|
243
243
|
});
|
|
244
244
|
} catch { /* sink failure must not abort the orchestrator */ }
|
|
245
245
|
} catch (err) {
|
|
246
|
-
console.warn(`[Yeaft] history compact: unexpected failure (
|
|
246
|
+
console.warn(`[Yeaft] history compact: unexpected failure (sessionId=${sessionId})`, err?.message || err);
|
|
247
247
|
}
|
|
248
248
|
}
|
|
249
249
|
|