@yeaft/webchat-agent 0.1.654 → 0.1.656
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 +4 -12
- package/package.json +1 -1
- package/unify/engine.js +8 -29
- package/unify/session.js +11 -80
- package/unify/web-bridge.js +15 -93
- package/unify/input-queue/store.js +0 -322
- package/unify/pipeline/dispatcher.js +0 -196
- package/unify/threads/engine-instance.js +0 -312
- package/unify/threads/engine-registry.js +0 -260
- package/unify/threads/store.js +0 -886
|
@@ -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,
|
|
39
|
+
import { handleUnifyChat, handleUnifyGroupChat, handleUnifyModeSwitch, handleUnifyModelSwitch, resetUnifySession, handleUnifyLoadHistory, handleUnifyAbortThread, handleUnifyAbortAll, handleUnifyVpSubscribe, handleUnifyVpCreate, handleUnifyVpUpdate, handleUnifyVpDelete, handleUnifyVpRead, handleUnifyFeatureMessage, handleUnifyUserMemoryWrite, handleUnifyUserMemoryRemove, handleUnifyMemoryScopeList, handleUnifyMemoryQuery, handleUnifyMemoryTrace, 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) {
|
|
@@ -381,18 +381,10 @@ export async function handleMessage(msg) {
|
|
|
381
381
|
await resetUnifySession();
|
|
382
382
|
break;
|
|
383
383
|
|
|
384
|
-
case 'unify_merge_thread':
|
|
385
|
-
handleUnifyMergeThread(msg);
|
|
386
|
-
break;
|
|
387
|
-
|
|
388
|
-
case 'unify_fork_thread':
|
|
389
|
-
handleUnifyForkThread(msg);
|
|
390
|
-
break;
|
|
391
|
-
|
|
392
384
|
case 'unify_abort_thread':
|
|
393
|
-
// task-325c: user-initiated abort of
|
|
394
|
-
//
|
|
395
|
-
//
|
|
385
|
+
// task-325c: user-initiated abort of an in-flight query. The
|
|
386
|
+
// legacy `threadId` field on the payload is accepted but ignored
|
|
387
|
+
// (H2.f.5: single-conversation model).
|
|
396
388
|
handleUnifyAbortThread(msg);
|
|
397
389
|
break;
|
|
398
390
|
|
package/package.json
CHANGED
package/unify/engine.js
CHANGED
|
@@ -32,7 +32,10 @@ import { buildMemoryInjection } from './memory/layout.js';
|
|
|
32
32
|
import { buildUserProfile } from './memory/user-memory-store.js';
|
|
33
33
|
import { readSummary as readScopeSummary } from './memory/store-v2.js';
|
|
34
34
|
import { runStopHooks } from './stop-hooks.js';
|
|
35
|
-
|
|
35
|
+
// H2.f.5: threads/ retired. Persisted messages still carry a `threadId`
|
|
36
|
+
// field for back-compat with old conversation files; new writes always use
|
|
37
|
+
// the constant 'main'.
|
|
38
|
+
const MAIN_THREAD_ID = 'main';
|
|
36
39
|
import { pickEffort, parseEffortPrefix } from './effort.js';
|
|
37
40
|
import { normalizeEffort } from './models.js';
|
|
38
41
|
import { attachRouterPlan, extractPriorPlan, stripMetaForWire } from './router/continuity.js';
|
|
@@ -581,17 +584,9 @@ export class Engine {
|
|
|
581
584
|
if (!this.#conversationStore) return;
|
|
582
585
|
if (this.#config._readOnly) return;
|
|
583
586
|
|
|
584
|
-
//
|
|
585
|
-
//
|
|
586
|
-
|
|
587
|
-
let threadStore = null;
|
|
588
|
-
try {
|
|
589
|
-
threadStore = getThreadStore();
|
|
590
|
-
threadId = threadStore.currentId || MAIN_THREAD_ID;
|
|
591
|
-
} catch {
|
|
592
|
-
// Defensive: any store failure falls back to 'main' so persistence
|
|
593
|
-
// never breaks because of thread bookkeeping.
|
|
594
|
-
}
|
|
587
|
+
// H2.f.5: threads retired. Persisted messages still carry threadId
|
|
588
|
+
// for back-compat with old conversation files; new writes always use 'main'.
|
|
589
|
+
const threadId = MAIN_THREAD_ID;
|
|
595
590
|
|
|
596
591
|
// Persist user message
|
|
597
592
|
this.#conversationStore.append({
|
|
@@ -614,18 +609,6 @@ export class Engine {
|
|
|
614
609
|
assistantMsg.toolCalls = toolCalls;
|
|
615
610
|
}
|
|
616
611
|
this.#conversationStore.append(assistantMsg);
|
|
617
|
-
|
|
618
|
-
// task-299 Phase 1 cached-field update: bump thread counters twice
|
|
619
|
-
// (once for user, once for assistant). Any exception is swallowed so
|
|
620
|
-
// bookkeeping never blocks the main persist path.
|
|
621
|
-
try {
|
|
622
|
-
if (threadStore) {
|
|
623
|
-
threadStore.noteMessage(threadId);
|
|
624
|
-
threadStore.noteMessage(threadId);
|
|
625
|
-
}
|
|
626
|
-
} catch {
|
|
627
|
-
// Non-critical; counters can be rebuilt via rebuildFromMessages().
|
|
628
|
-
}
|
|
629
612
|
}
|
|
630
613
|
|
|
631
614
|
/**
|
|
@@ -1709,11 +1692,7 @@ export class Engine {
|
|
|
1709
1692
|
* @returns {string}
|
|
1710
1693
|
*/
|
|
1711
1694
|
get currentThreadId() {
|
|
1712
|
-
|
|
1713
|
-
return getThreadStore().currentId || MAIN_THREAD_ID;
|
|
1714
|
-
} catch {
|
|
1715
|
-
return MAIN_THREAD_ID;
|
|
1716
|
-
}
|
|
1695
|
+
return MAIN_THREAD_ID;
|
|
1717
1696
|
}
|
|
1718
1697
|
|
|
1719
1698
|
/** @returns {string|null} */
|
package/unify/session.js
CHANGED
|
@@ -24,17 +24,10 @@ import { SkillManager, createSkillManager } from './skills.js';
|
|
|
24
24
|
import { MCPManager } from './mcp.js';
|
|
25
25
|
import { createFullRegistry } from './tools/index.js';
|
|
26
26
|
import { initFeatureStore } from './tools/feature-tools.js';
|
|
27
|
-
import { initThreadStore } from './threads/store.js';
|
|
28
27
|
import { Engine } from './engine.js';
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
// H2.f.1: intent-classifier (LLM router) is retired. Memory recall now
|
|
33
|
-
// runs through pre-flow (memory/preflow.js) + post-turn adjustMemory
|
|
34
|
-
// (memory/adjust.js); the dispatcher routes every input to the single
|
|
35
|
-
// MAIN_THREAD_ID engine instance.
|
|
36
|
-
import { initInputQueueStore } from './input-queue/store.js';
|
|
37
|
-
import { createDispatcher } from './pipeline/dispatcher.js';
|
|
28
|
+
// H2.f.5: threads/, pipeline/dispatcher and input-queue retired. The
|
|
29
|
+
// session now exposes a single Engine. Memory recall runs through
|
|
30
|
+
// pre-flow (memory/preflow.js) + post-turn adjustMemory (memory/adjust.js).
|
|
38
31
|
import { ensureDefaultGroupIfEmpty } from './groups/group-crud.js';
|
|
39
32
|
import { seedDefaultVps } from './vp/seed-defaults.js';
|
|
40
33
|
import { createDreamScheduler } from './memory/dream-scheduler.js';
|
|
@@ -223,16 +216,7 @@ export async function loadSession(options = {}) {
|
|
|
223
216
|
// ─── 5a. Initialize feature store ──────────────────────
|
|
224
217
|
initFeatureStore(yeaftDir, { readOnly: config._readOnly || false });
|
|
225
218
|
|
|
226
|
-
// ─── 5b.
|
|
227
|
-
// task-307a: now file-backed under ~/.yeaft/threads/. Passing the
|
|
228
|
-
// yeaftDir switches on disk persistence; read-only mode is honoured.
|
|
229
|
-
// task-318: forward the Unify autoArchiveIdleDays knob so the
|
|
230
|
-
// archive pass (owned by task-317) can read it off the store.
|
|
231
|
-
initThreadStore(yeaftDir, {
|
|
232
|
-
readOnly: config._readOnly || false,
|
|
233
|
-
force: true,
|
|
234
|
-
idleArchiveDays: config.unify?.autoArchiveIdleDays ?? 0,
|
|
235
|
-
});
|
|
219
|
+
// ─── 5b. (H2.f.5) thread store retired. Single conversation. ───
|
|
236
220
|
|
|
237
221
|
// ─── 5c. D1 first-boot seed (task-334m) ─────────────────
|
|
238
222
|
// When no groups exist on disk AND we're not in read-only mode,
|
|
@@ -341,46 +325,10 @@ export async function loadSession(options = {}) {
|
|
|
341
325
|
});
|
|
342
326
|
}
|
|
343
327
|
|
|
344
|
-
//
|
|
345
|
-
//
|
|
346
|
-
//
|
|
347
|
-
//
|
|
348
|
-
// callers use `session.engineRegistry.ensure(threadId)`.
|
|
349
|
-
const engineRegistry = createThreadEngineRegistry({
|
|
350
|
-
adapter,
|
|
351
|
-
trace,
|
|
352
|
-
config,
|
|
353
|
-
conversationStore,
|
|
354
|
-
memoryStore,
|
|
355
|
-
memoryShardStore,
|
|
356
|
-
toolRegistry,
|
|
357
|
-
skillManager,
|
|
358
|
-
mcpManager,
|
|
359
|
-
yeaftDir,
|
|
360
|
-
// task-318: concurrent-thread cap (UI-adjustable via Settings).
|
|
361
|
-
maxConcurrent: config.unify?.maxConcurrentThreads ?? null,
|
|
362
|
-
});
|
|
363
|
-
// Seed the main-thread instance so listActive() is non-empty from T=0.
|
|
364
|
-
engineRegistry.ensure(MAIN_THREAD_ID);
|
|
365
|
-
|
|
366
|
-
// H2.f.1: the LLM intent-classifier is retired. The dispatcher now
|
|
367
|
-
// unconditionally routes every input to the MAIN_THREAD_ID engine
|
|
368
|
-
// instance. Memory recall happens via memory/preflow.js (pre-turn)
|
|
369
|
-
// and memory/adjust.js (post-turn).
|
|
370
|
-
|
|
371
|
-
// task-310 Phase 2 integration: wire InputQueue + Dispatcher so the
|
|
372
|
-
// web-bridge can submit `unify_chat` inputs through the unified pipeline
|
|
373
|
-
// (queue → engineRegistry → EngineInstance). In read-only mode the
|
|
374
|
-
// queue is memory-only (no disk writes).
|
|
375
|
-
const inputQueue = initInputQueueStore({
|
|
376
|
-
yeaftDir: config._readOnly ? null : yeaftDir,
|
|
377
|
-
force: true,
|
|
378
|
-
});
|
|
379
|
-
const dispatcher = createDispatcher({
|
|
380
|
-
inputQueue,
|
|
381
|
-
engineRegistry,
|
|
382
|
-
trace,
|
|
383
|
-
});
|
|
328
|
+
// H2.f.5: thread engine registry, input queue, and dispatcher retired.
|
|
329
|
+
// The session exposes a single `engine`; web-bridge calls engine.query()
|
|
330
|
+
// directly. Memory recall happens via memory/preflow.js (pre-turn) and
|
|
331
|
+
// memory/adjust.js (post-turn).
|
|
384
332
|
|
|
385
333
|
// ─── 10. Build session ─────────────────────────────────
|
|
386
334
|
const status = {
|
|
@@ -397,11 +345,6 @@ export async function loadSession(options = {}) {
|
|
|
397
345
|
} catch {
|
|
398
346
|
// Best-effort cleanup
|
|
399
347
|
}
|
|
400
|
-
try {
|
|
401
|
-
engineRegistry.terminateAll();
|
|
402
|
-
} catch {
|
|
403
|
-
// Best-effort cleanup
|
|
404
|
-
}
|
|
405
348
|
try {
|
|
406
349
|
await mcpManager.disconnectAll();
|
|
407
350
|
} catch {
|
|
@@ -416,13 +359,6 @@ export async function loadSession(options = {}) {
|
|
|
416
359
|
|
|
417
360
|
return {
|
|
418
361
|
engine,
|
|
419
|
-
engineRegistry,
|
|
420
|
-
// H2.f.1: `router` removed (intent classifier retired). Kept the
|
|
421
|
-
// property as `null` for any caller doing back-compat existence
|
|
422
|
-
// checks; the dispatcher now always routes to MAIN_THREAD_ID.
|
|
423
|
-
router: null,
|
|
424
|
-
inputQueue,
|
|
425
|
-
dispatcher,
|
|
426
362
|
adapter,
|
|
427
363
|
config,
|
|
428
364
|
conversationStore,
|
|
@@ -434,17 +370,12 @@ export async function loadSession(options = {}) {
|
|
|
434
370
|
toolRegistry,
|
|
435
371
|
trace,
|
|
436
372
|
yeaftDir,
|
|
437
|
-
// task-318 rev-1 fix: expose the live ThreadStore handle so callers
|
|
438
|
-
// (web-bridge, message-router via ctx) can invoke setIdleArchiveDays()
|
|
439
|
-
// on the exact instance that's wired into the dispatcher. Without this
|
|
440
|
-
// export the setter was effectively dead code.
|
|
441
|
-
threadStore: getThreadStore(),
|
|
442
373
|
status,
|
|
443
374
|
shutdown,
|
|
444
375
|
// task-325c: user-initiated abort API. Delegates to web-bridge which
|
|
445
|
-
// owns the
|
|
446
|
-
//
|
|
447
|
-
//
|
|
376
|
+
// owns the single AbortController. Lazy-imported to avoid a hard cycle
|
|
377
|
+
// with web-bridge.js (which already imports this module to call
|
|
378
|
+
// loadSession).
|
|
448
379
|
async abort(opts = {}) {
|
|
449
380
|
const { abortUnifySession } = await import('./web-bridge.js');
|
|
450
381
|
return abortUnifySession(opts);
|
package/unify/web-bridge.js
CHANGED
|
@@ -426,47 +426,6 @@ export function installUnifyRuntimeBridge(s) {
|
|
|
426
426
|
};
|
|
427
427
|
}
|
|
428
428
|
|
|
429
|
-
/**
|
|
430
|
-
* Translate a pipeline event (from Dispatcher) into web-bridge outputs.
|
|
431
|
-
* Pipeline events are distinct from engine events — they carry queue /
|
|
432
|
-
* routing state for the UI. Engine events are unwrapped and forwarded.
|
|
433
|
-
*/
|
|
434
|
-
function forwardPipelineEvent(ev, pctx) {
|
|
435
|
-
if (!ev || typeof ev !== 'object') return false;
|
|
436
|
-
const gid = pctx && pctx.groupId;
|
|
437
|
-
switch (ev.type) {
|
|
438
|
-
case 'input_queue_updated':
|
|
439
|
-
sendUnifyEvent({
|
|
440
|
-
type: 'input_queue_updated',
|
|
441
|
-
total: ev.total,
|
|
442
|
-
pending: ev.pending,
|
|
443
|
-
routing: ev.routing,
|
|
444
|
-
dispatched: ev.dispatched,
|
|
445
|
-
head: ev.head,
|
|
446
|
-
}, gid);
|
|
447
|
-
return false;
|
|
448
|
-
case 'routing_decision':
|
|
449
|
-
// H2.f.2: still forwarded for wire compat, but frontend treats it as
|
|
450
|
-
// a no-op marker; targetThreadId is always 'main'.
|
|
451
|
-
sendUnifyEvent({
|
|
452
|
-
type: 'routing_decision',
|
|
453
|
-
entryId: ev.entryId,
|
|
454
|
-
action: ev.action,
|
|
455
|
-
source: ev.source,
|
|
456
|
-
reason: ev.reason,
|
|
457
|
-
}, gid);
|
|
458
|
-
return false;
|
|
459
|
-
case 'engine_event':
|
|
460
|
-
pctx.onEngineEvent(ev.event);
|
|
461
|
-
return false;
|
|
462
|
-
case 'error':
|
|
463
|
-
pctx.onError(ev.error);
|
|
464
|
-
return true;
|
|
465
|
-
default:
|
|
466
|
-
return false;
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
|
|
470
429
|
/**
|
|
471
430
|
* Handle a single engine event unwrapped from an `engine_event` envelope.
|
|
472
431
|
* H2.f.2: no longer stamps a threadId on outgoing claude_output frames.
|
|
@@ -957,34 +916,24 @@ export async function handleUnifyChat(msg) {
|
|
|
957
916
|
const toolCallsAccum = [];
|
|
958
917
|
const toolResultsAccum = [];
|
|
959
918
|
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
routing: 0,
|
|
969
|
-
dispatched: 0,
|
|
970
|
-
head: { id: entry.id, status: entry.status, text: entry.text.slice(0, 80) },
|
|
971
|
-
}, groupId);
|
|
972
|
-
|
|
973
|
-
const pipelineCtx = {
|
|
919
|
+
// H2.f.5: dispatcher + InputQueue retired. Call engine.query() directly,
|
|
920
|
+
// passing the flat conversation history as `messages` for context continuity.
|
|
921
|
+
const queryOpts = buildVpQueryOpts({ vpId, groupCoordinator, groupId });
|
|
922
|
+
const handlerCtx = {
|
|
923
|
+
assistantTextParts,
|
|
924
|
+
toolCallsAccum,
|
|
925
|
+
toolResultsAccum,
|
|
926
|
+
resetQueryTimer,
|
|
974
927
|
groupId,
|
|
975
|
-
onEngineEvent: (event) => handleEngineEvent(event, {
|
|
976
|
-
assistantTextParts,
|
|
977
|
-
toolCallsAccum,
|
|
978
|
-
toolResultsAccum,
|
|
979
|
-
resetQueryTimer,
|
|
980
|
-
groupId,
|
|
981
|
-
}),
|
|
982
|
-
onError: (err) => { throw err; },
|
|
983
928
|
};
|
|
984
|
-
|
|
985
|
-
|
|
929
|
+
for await (const event of session.engine.query({
|
|
930
|
+
prompt,
|
|
931
|
+
messages: [...conversationMessages],
|
|
932
|
+
signal: abortCtrl.signal,
|
|
933
|
+
...queryOpts,
|
|
934
|
+
})) {
|
|
986
935
|
resetQueryTimer();
|
|
987
|
-
|
|
936
|
+
handleEngineEvent(event, handlerCtx);
|
|
988
937
|
}
|
|
989
938
|
|
|
990
939
|
// Accumulate messages for context continuity.
|
|
@@ -1376,33 +1325,6 @@ export async function handleUnifyFeatureCrud(msg = {}) {
|
|
|
1376
1325
|
}
|
|
1377
1326
|
}
|
|
1378
1327
|
|
|
1379
|
-
/**
|
|
1380
|
-
* H2.f.2 stub: thread merge no longer exists. Kept for back-compat with
|
|
1381
|
-
* older message-router cases — emits a failed-ack.
|
|
1382
|
-
*/
|
|
1383
|
-
export function handleUnifyMergeThread(msg) {
|
|
1384
|
-
const { sourceId, targetId } = msg || {};
|
|
1385
|
-
sendUnifyEvent({
|
|
1386
|
-
type: 'thread_merge_failed',
|
|
1387
|
-
sourceId,
|
|
1388
|
-
targetId,
|
|
1389
|
-
error: 'thread merge is no longer supported (H2 single-conversation)',
|
|
1390
|
-
});
|
|
1391
|
-
}
|
|
1392
|
-
|
|
1393
|
-
/**
|
|
1394
|
-
* H2.f.2 stub: thread fork no longer exists.
|
|
1395
|
-
*/
|
|
1396
|
-
export function handleUnifyForkThread(msg) {
|
|
1397
|
-
const { sourceThreadId, atMessageId } = msg || {};
|
|
1398
|
-
sendUnifyEvent({
|
|
1399
|
-
type: 'thread_fork_failed',
|
|
1400
|
-
sourceThreadId,
|
|
1401
|
-
atMessageId,
|
|
1402
|
-
error: 'thread fork is no longer supported (H2 single-conversation)',
|
|
1403
|
-
});
|
|
1404
|
-
}
|
|
1405
|
-
|
|
1406
1328
|
/** Handle model switch from the web UI. */
|
|
1407
1329
|
export function handleUnifyModelSwitch(msg) {
|
|
1408
1330
|
if (!session || !msg.model) return;
|