@yeaft/webchat-agent 0.1.851 → 0.1.852
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/conversation/persist.js +64 -1
- package/unify/web-bridge.js +15 -10
package/package.json
CHANGED
|
@@ -22,7 +22,7 @@ import { existsSync, mkdirSync, writeFileSync, readFileSync, readdirSync, rename
|
|
|
22
22
|
import { join, basename } from 'path';
|
|
23
23
|
import { isPermissionError } from '../init.js';
|
|
24
24
|
import { pairSanitize } from '../pair-sanitize.js';
|
|
25
|
-
import { sliceLastNTurns } from '../turn-utils.js';
|
|
25
|
+
import { indexOfNthTurnFromEnd, sliceLastNTurns } from '../turn-utils.js';
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* Default cold-start "recent window" size, expressed in TURNS (not raw
|
|
@@ -870,6 +870,43 @@ export class ConversationStore {
|
|
|
870
870
|
return { messages: sliced, oldestSeq, hasMore };
|
|
871
871
|
}
|
|
872
872
|
|
|
873
|
+
/**
|
|
874
|
+
* Visible UI pagination read for one group. Unlike `loadOlderByGroup`, this
|
|
875
|
+
* projects out internal/reflection/system rows BEFORE applying the turn
|
|
876
|
+
* window, so a dense run of hidden metadata cannot force the first screen to
|
|
877
|
+
* scan and materialize the group's entire history in the web bridge.
|
|
878
|
+
*
|
|
879
|
+
* @param {string} groupId
|
|
880
|
+
* @param {number|null} beforeSeq — exclusive upper bound, or null for newest
|
|
881
|
+
* @param {number} [turnsLimit=DEFAULT_RECENT_TURNS]
|
|
882
|
+
* @returns {{ messages: object[], oldestSeq: number|null, hasMore: boolean }}
|
|
883
|
+
*/
|
|
884
|
+
loadVisibleByGroup(groupId, beforeSeq, turnsLimit = DEFAULT_RECENT_TURNS) {
|
|
885
|
+
if (!groupId || !(turnsLimit > 0)) return { messages: [], oldestSeq: null, hasMore: false };
|
|
886
|
+
|
|
887
|
+
const cutoff = Number.isFinite(beforeSeq) ? beforeSeq : Infinity;
|
|
888
|
+
const hot = this.#loadVisibleFromDirByGroup(this.#msgDir, groupId, cutoff);
|
|
889
|
+
const cold = this.#loadVisibleFromDirByGroup(this.#coldDir, groupId, cutoff);
|
|
890
|
+
const visible = [...cold, ...hot];
|
|
891
|
+
if (visible.length === 0) return { messages: [], oldestSeq: null, hasMore: false };
|
|
892
|
+
|
|
893
|
+
const startIdx = indexOfNthTurnFromEnd(visible, turnsLimit);
|
|
894
|
+
const start = startIdx === -1 ? 0 : startIdx;
|
|
895
|
+
const messages = pairSanitize(visible.slice(start));
|
|
896
|
+
const oldestSeq = messages.length ? parseSeqFromId(messages[0].id) : null;
|
|
897
|
+
const firstVisibleSeq = parseSeqFromId(visible[0].id);
|
|
898
|
+
const hasMore = messages.length > 0
|
|
899
|
+
&& Number.isFinite(oldestSeq)
|
|
900
|
+
&& Number.isFinite(firstVisibleSeq)
|
|
901
|
+
&& oldestSeq > firstVisibleSeq;
|
|
902
|
+
|
|
903
|
+
return {
|
|
904
|
+
messages,
|
|
905
|
+
oldestSeq: Number.isFinite(oldestSeq) ? oldestSeq : null,
|
|
906
|
+
hasMore,
|
|
907
|
+
};
|
|
908
|
+
}
|
|
909
|
+
|
|
873
910
|
/**
|
|
874
911
|
* Count hot messages.
|
|
875
912
|
*
|
|
@@ -1319,6 +1356,32 @@ export class ConversationStore {
|
|
|
1319
1356
|
return messages;
|
|
1320
1357
|
}
|
|
1321
1358
|
|
|
1359
|
+
#loadVisibleFromDirByGroup(dir, groupId, beforeSeq) {
|
|
1360
|
+
if (!existsSync(dir)) return [];
|
|
1361
|
+
|
|
1362
|
+
const files = readdirSync(dir)
|
|
1363
|
+
.filter(f => f.endsWith('.md'))
|
|
1364
|
+
.sort();
|
|
1365
|
+
|
|
1366
|
+
const out = [];
|
|
1367
|
+
for (const file of files) {
|
|
1368
|
+
const seq = parseSeqFromId(basename(file, '.md'));
|
|
1369
|
+
if (!Number.isFinite(seq) || seq >= beforeSeq) continue;
|
|
1370
|
+
|
|
1371
|
+
const raw = readFileSync(join(dir, file), 'utf8');
|
|
1372
|
+
if (!raw.includes(`groupId: ${groupId}`)) continue;
|
|
1373
|
+
if (!raw.includes('role: user') && !raw.includes('role: assistant')) continue;
|
|
1374
|
+
|
|
1375
|
+
const parsed = parseMessage(raw);
|
|
1376
|
+
if (!parsed || parsed.groupId !== groupId) continue;
|
|
1377
|
+
if (parsed._reflection || parsed.internal || parsed.systemOnly || parsed.systemOnlyMessage) continue;
|
|
1378
|
+
if (parsed.role !== 'user' && parsed.role !== 'assistant') continue;
|
|
1379
|
+
out.push(parsed);
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1382
|
+
return out;
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1322
1385
|
/**
|
|
1323
1386
|
* Determine the next sequence number by scanning existing files.
|
|
1324
1387
|
* @returns {number}
|
package/unify/web-bridge.js
CHANGED
|
@@ -602,10 +602,16 @@ function loadVisibleGroupHistoryPage(store, groupId, limit, beforeSeq = null) {
|
|
|
602
602
|
|
|
603
603
|
let rows = [];
|
|
604
604
|
try {
|
|
605
|
-
if (typeof store.
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
605
|
+
if (typeof store.loadVisibleByGroup === 'function') {
|
|
606
|
+
const page = store.loadVisibleByGroup(groupId, beforeSeq, limit);
|
|
607
|
+
return {
|
|
608
|
+
messages: (page.messages || []).map(projectPersistedToVisibleHistoryEntry).filter(Boolean),
|
|
609
|
+
oldestSeq: (typeof page.oldestSeq === 'number') ? page.oldestSeq : null,
|
|
610
|
+
hasMore: !!page.hasMore,
|
|
611
|
+
};
|
|
612
|
+
} else if (typeof store.loadOlderByGroup === 'function') {
|
|
613
|
+
// Compatibility fallback for older test doubles: use an unbounded raw
|
|
614
|
+
// prefix, then project/slice visible rows below.
|
|
609
615
|
rows = store.loadOlderByGroup(groupId, beforeSeq, Infinity).messages || [];
|
|
610
616
|
} else if (Number.isFinite(beforeSeq)) {
|
|
611
617
|
const all = typeof store.loadAllByGroup === 'function'
|
|
@@ -3582,11 +3588,10 @@ export async function handleUnifyLoadHistory(msg) {
|
|
|
3582
3588
|
}
|
|
3583
3589
|
|
|
3584
3590
|
// `msg.limit` is the replay-scrollback request from the frontend (UI
|
|
3585
|
-
// history pane, not engine context).
|
|
3586
|
-
//
|
|
3587
|
-
//
|
|
3588
|
-
|
|
3589
|
-
const limit = (typeof msg.limit === 'number') ? msg.limit : 50;
|
|
3591
|
+
// history pane, not engine context). Keep the bootstrap window small so
|
|
3592
|
+
// opening a group can paint the latest messages quickly; older rows are
|
|
3593
|
+
// paged via `unify_load_more_history` when the user scrolls upward.
|
|
3594
|
+
const limit = (typeof msg.limit === 'number') ? msg.limit : 10;
|
|
3590
3595
|
const visiblePage = groupId
|
|
3591
3596
|
? loadVisibleGroupHistoryPage(session.conversationStore, groupId, limit)
|
|
3592
3597
|
: { messages: limit > 0 ? pickRecent(session.conversationStore, limit) : [], oldestSeq: null, hasMore: false };
|
|
@@ -3691,7 +3696,7 @@ export async function handleUnifyLoadMoreHistory(msg) {
|
|
|
3691
3696
|
}
|
|
3692
3697
|
|
|
3693
3698
|
const beforeSeq = (typeof msg.beforeSeq === 'number') ? msg.beforeSeq : null;
|
|
3694
|
-
const turns = (typeof msg.turns === 'number' && msg.turns > 0) ? msg.turns :
|
|
3699
|
+
const turns = (typeof msg.turns === 'number' && msg.turns > 0) ? msg.turns : 10;
|
|
3695
3700
|
|
|
3696
3701
|
let result;
|
|
3697
3702
|
try {
|