@yeaft/webchat-agent 0.1.797 → 0.1.798
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/web-bridge.js +66 -28
package/package.json
CHANGED
package/unify/web-bridge.js
CHANGED
|
@@ -52,6 +52,7 @@ import {
|
|
|
52
52
|
} from './history-compact.js';
|
|
53
53
|
import { persistUnifyAttachments, attachmentsForPersistence } from './attachments.js';
|
|
54
54
|
import { parseSeqFromId } from './conversation/persist.js';
|
|
55
|
+
import { sliceLastNTurns } from './turn-utils.js';
|
|
55
56
|
import { createVpStatusBroker } from './vp-status-broker.js';
|
|
56
57
|
import { classifyThread as defaultClassifyThread, fallbackTitle } from './vp/thread-classifier.js';
|
|
57
58
|
|
|
@@ -523,6 +524,54 @@ function projectPersistedToHistoryEntry(m) {
|
|
|
523
524
|
return entry;
|
|
524
525
|
}
|
|
525
526
|
|
|
527
|
+
function projectPersistedToVisibleHistoryEntry(m) {
|
|
528
|
+
const entry = projectPersistedToHistoryEntry(m);
|
|
529
|
+
return entry && (entry.role === 'user' || entry.role === 'assistant') ? entry : null;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
function loadVisibleGroupHistoryPage(store, groupId, limit, beforeSeq = null) {
|
|
533
|
+
if (!store || !groupId || !(limit > 0)) return { messages: [], oldestSeq: null, hasMore: false };
|
|
534
|
+
|
|
535
|
+
let rows = [];
|
|
536
|
+
try {
|
|
537
|
+
if (typeof store.loadOlderByGroup === 'function') {
|
|
538
|
+
// Use an unbounded raw prefix, then project/slice visible rows below.
|
|
539
|
+
// This preserves loadOlderByGroup's hot+cold scan without letting raw
|
|
540
|
+
// reflection/internal rows consume the UI-visible page window.
|
|
541
|
+
rows = store.loadOlderByGroup(groupId, beforeSeq, Infinity).messages || [];
|
|
542
|
+
} else if (Number.isFinite(beforeSeq)) {
|
|
543
|
+
const all = typeof store.loadAllByGroup === 'function'
|
|
544
|
+
? store.loadAllByGroup(groupId)
|
|
545
|
+
: store.loadRecentByGroup(groupId, Infinity);
|
|
546
|
+
rows = all.filter(m => parseSeqFromId(m?.id) < beforeSeq);
|
|
547
|
+
} else if (typeof store.loadAllByGroup === 'function') {
|
|
548
|
+
rows = store.loadAllByGroup(groupId);
|
|
549
|
+
} else {
|
|
550
|
+
rows = store.loadRecentByGroup(groupId, Infinity);
|
|
551
|
+
}
|
|
552
|
+
} catch (err) {
|
|
553
|
+
console.error('[Unify] visible history page load failed:', err?.message || err);
|
|
554
|
+
return { messages: [], oldestSeq: null, hasMore: false };
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
const visible = rows
|
|
558
|
+
.map(projectPersistedToVisibleHistoryEntry)
|
|
559
|
+
.filter(Boolean);
|
|
560
|
+
const messages = sliceLastNTurns(visible, limit);
|
|
561
|
+
const oldestSeq = messages.length ? parseSeqFromId(messages[0].id) : null;
|
|
562
|
+
const firstVisibleSeq = visible.length ? parseSeqFromId(visible[0].id) : null;
|
|
563
|
+
const hasMore = messages.length > 0
|
|
564
|
+
&& Number.isFinite(oldestSeq)
|
|
565
|
+
&& Number.isFinite(firstVisibleSeq)
|
|
566
|
+
&& oldestSeq > firstVisibleSeq;
|
|
567
|
+
|
|
568
|
+
return {
|
|
569
|
+
messages,
|
|
570
|
+
oldestSeq: Number.isFinite(oldestSeq) ? oldestSeq : null,
|
|
571
|
+
hasMore,
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
|
|
526
575
|
/**
|
|
527
576
|
* Hydrate a freshly-created GroupContext's history from the on-disk
|
|
528
577
|
* conversation store. Returns an empty array if the session isn't
|
|
@@ -3283,12 +3332,17 @@ export async function handleUnifyLoadHistory(msg) {
|
|
|
3283
3332
|
// ~20–25 turns; in the turn-count world 50 turns of UI scrollback is
|
|
3284
3333
|
// still cheap and matches what the frontend already passes through.
|
|
3285
3334
|
const limit = (typeof msg.limit === 'number') ? msg.limit : 50;
|
|
3286
|
-
const
|
|
3335
|
+
const visiblePage = groupId
|
|
3336
|
+
? loadVisibleGroupHistoryPage(session.conversationStore, groupId, limit)
|
|
3337
|
+
: { messages: limit > 0 ? pickRecent(session.conversationStore, limit) : [], oldestSeq: null, hasMore: false };
|
|
3287
3338
|
const compactSummary = session.conversationStore.readCompactSummary();
|
|
3339
|
+
const replayEntries = groupId
|
|
3340
|
+
? visiblePage.messages
|
|
3341
|
+
: visiblePage.messages
|
|
3342
|
+
.map(projectPersistedToVisibleHistoryEntry)
|
|
3343
|
+
.filter(Boolean);
|
|
3288
3344
|
|
|
3289
|
-
for (const
|
|
3290
|
-
const entry = projectPersistedToHistoryEntry(m);
|
|
3291
|
-
if (!entry) continue;
|
|
3345
|
+
for (const entry of replayEntries) {
|
|
3292
3346
|
if (entry.role === 'user') {
|
|
3293
3347
|
sendUnifyOutput({ type: 'user', message: { content: entry.content, id: entry.id || null } }, { groupId: entry.groupId || null });
|
|
3294
3348
|
} else if (entry.role === 'assistant') {
|
|
@@ -3310,33 +3364,19 @@ export async function handleUnifyLoadHistory(msg) {
|
|
|
3310
3364
|
|
|
3311
3365
|
// Compute the pagination cursor for the bootstrap load so the frontend
|
|
3312
3366
|
// knows whether a "Load older messages" hint should be shown and where
|
|
3313
|
-
// to start the next page.
|
|
3314
|
-
//
|
|
3315
|
-
//
|
|
3367
|
+
// to start the next page. For group history, this is computed from the
|
|
3368
|
+
// visible projected page, not raw persisted rows, so reflection/internal
|
|
3369
|
+
// tail rows cannot consume the bootstrap window or create false hasMore.
|
|
3316
3370
|
let hasMore = false;
|
|
3317
3371
|
let oldestSeq = null;
|
|
3318
|
-
if (groupId
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
// Defend against malformed ids: a NaN cursor would round-trip back as
|
|
3322
|
-
// a poison `beforeSeq` and degrade subsequent paginations to "give me
|
|
3323
|
-
// the newest page again". Surface as null instead.
|
|
3324
|
-
oldestSeq = Number.isFinite(seq) ? seq : null;
|
|
3325
|
-
if (oldestSeq != null) {
|
|
3326
|
-
// Consult the store for whether anything older exists in the same
|
|
3327
|
-
// group. Cheap: a single extra `loadOlderByGroup` with turns=1.
|
|
3328
|
-
try {
|
|
3329
|
-
const probe = session.conversationStore.loadOlderByGroup(groupId, oldestSeq, 1);
|
|
3330
|
-
hasMore = probe.messages.length > 0;
|
|
3331
|
-
} catch (err) {
|
|
3332
|
-
console.error('[Unify] history-load probe failed:', err.message);
|
|
3333
|
-
}
|
|
3334
|
-
}
|
|
3372
|
+
if (groupId) {
|
|
3373
|
+
hasMore = visiblePage.hasMore;
|
|
3374
|
+
oldestSeq = visiblePage.oldestSeq;
|
|
3335
3375
|
}
|
|
3336
3376
|
|
|
3337
3377
|
sendUnifyEvent({
|
|
3338
3378
|
type: 'history_loaded',
|
|
3339
|
-
count:
|
|
3379
|
+
count: replayEntries.length,
|
|
3340
3380
|
hasCompactSummary: !!compactSummary,
|
|
3341
3381
|
totalHot: session.conversationStore.countHot(),
|
|
3342
3382
|
totalCold: session.conversationStore.countCold(),
|
|
@@ -3378,7 +3418,7 @@ export async function handleUnifyLoadMoreHistory(msg) {
|
|
|
3378
3418
|
|
|
3379
3419
|
let result;
|
|
3380
3420
|
try {
|
|
3381
|
-
result = session.conversationStore
|
|
3421
|
+
result = loadVisibleGroupHistoryPage(session.conversationStore, groupId, turns, beforeSeq);
|
|
3382
3422
|
} catch (err) {
|
|
3383
3423
|
console.error('[Unify] loadOlderByGroup failed:', err.message);
|
|
3384
3424
|
result = { messages: [], oldestSeq: null, hasMore: false };
|
|
@@ -3389,8 +3429,6 @@ export async function handleUnifyLoadMoreHistory(msg) {
|
|
|
3389
3429
|
// server-side, and stable ids + speaker attribution ride with each row
|
|
3390
3430
|
// so older-history prepend renders exactly like refresh replay.
|
|
3391
3431
|
const projected = (result.messages || [])
|
|
3392
|
-
.map(projectPersistedToHistoryEntry)
|
|
3393
|
-
.filter(m => m && (m.role === 'user' || m.role === 'assistant'))
|
|
3394
3432
|
.map(m => ({
|
|
3395
3433
|
...(m.id ? { id: m.id } : {}),
|
|
3396
3434
|
role: m.role,
|