@astralform/js 9.5.0 → 9.7.0
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/dist/index.cjs +55 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +37 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.js +55 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2825,6 +2825,48 @@ var ChatSession = class {
|
|
|
2825
2825
|
if (!fresh.length) return;
|
|
2826
2826
|
this.setMessages([...fresh, ...this.messages]);
|
|
2827
2827
|
}
|
|
2828
|
+
/**
|
|
2829
|
+
* Re-fetch the NEWEST page of the conversation list and merge it in.
|
|
2830
|
+
*
|
|
2831
|
+
* The list the sidebar renders is seeded once at `connect()` and then only
|
|
2832
|
+
* changed by this client's own actions (create, delete, rename) — so a row's
|
|
2833
|
+
* `activeJobId` is as fresh as that seed, and a job started in ANOTHER tab or
|
|
2834
|
+
* on another device never appears, while one that ended elsewhere stays lit
|
|
2835
|
+
* forever. A caller that refreshes on a trigger (the tab becoming visible, or
|
|
2836
|
+
* a bounded interval while any job is live) keeps the rows honest without a
|
|
2837
|
+
* socket per conversation.
|
|
2838
|
+
*
|
|
2839
|
+
* Merge rules, and why each is what it is:
|
|
2840
|
+
*
|
|
2841
|
+
* - the server's ORDER wins for the rows it returns: an updated conversation
|
|
2842
|
+
* moves to its new place, which is the whole point of the call;
|
|
2843
|
+
* - rows paged in EARLIER (`loadMoreConversations`) are kept — this reads page
|
|
2844
|
+
* 1 only, and dropping the tail would make a refresh silently truncate a
|
|
2845
|
+
* list the reader has already scrolled;
|
|
2846
|
+
* - a row the caller MINTED locally and the server does not know yet is kept
|
|
2847
|
+
* too (it has no server row to be refreshed by);
|
|
2848
|
+
* - `conversationsGeneration` is bumped, for the same reason `connect()`
|
|
2849
|
+
* bumps it: a page request already in flight was cut against the old head
|
|
2850
|
+
* and its offset no longer means what it did.
|
|
2851
|
+
*/
|
|
2852
|
+
async refreshConversations() {
|
|
2853
|
+
const page = await this.client.getConversations(CONVERSATION_PAGE_SIZE, 0);
|
|
2854
|
+
const pageIds = new Set(page.map((c) => c.id));
|
|
2855
|
+
const known = new Set(this.conversations.map((c) => c.id));
|
|
2856
|
+
this.conversationsGeneration++;
|
|
2857
|
+
this.conversations = [
|
|
2858
|
+
...page,
|
|
2859
|
+
// Everything the page did not mention: older pages, and rows that exist
|
|
2860
|
+
// only on this client (a minted conversation the server has not been told
|
|
2861
|
+
// about yet).
|
|
2862
|
+
...this.conversations.filter((c) => !pageIds.has(c.id))
|
|
2863
|
+
];
|
|
2864
|
+
for (const c of page) {
|
|
2865
|
+
this.serverConversationIds.add(c.id);
|
|
2866
|
+
known.delete(c.id);
|
|
2867
|
+
}
|
|
2868
|
+
return page;
|
|
2869
|
+
}
|
|
2828
2870
|
async loadMoreConversations() {
|
|
2829
2871
|
if (this.isLoadingConversations || !this.hasMoreConversations) return [];
|
|
2830
2872
|
this.isLoadingConversations = true;
|
|
@@ -3420,6 +3462,7 @@ var StreamManager = class _StreamManager {
|
|
|
3420
3462
|
const haveByJobId = new Map(
|
|
3421
3463
|
(have ?? []).map((h) => [h.jobId, h.lastSeq])
|
|
3422
3464
|
);
|
|
3465
|
+
const heldFromMarks = (have ?? []).map((h) => h.messageId).filter((id) => typeof id === "string" && id.length > 0);
|
|
3423
3466
|
const superseded = () => gen !== this.generation;
|
|
3424
3467
|
if (superseded()) return;
|
|
3425
3468
|
const turn = this.turnCounter;
|
|
@@ -3447,7 +3490,8 @@ var StreamManager = class _StreamManager {
|
|
|
3447
3490
|
activeJobId,
|
|
3448
3491
|
turn,
|
|
3449
3492
|
jobsRequest,
|
|
3450
|
-
haveByJobId
|
|
3493
|
+
haveByJobId,
|
|
3494
|
+
heldFromMarks
|
|
3451
3495
|
))
|
|
3452
3496
|
return;
|
|
3453
3497
|
if (activeJobId) {
|
|
@@ -3644,7 +3688,7 @@ var StreamManager = class _StreamManager {
|
|
|
3644
3688
|
session.isLoadingEarlierTurns = false;
|
|
3645
3689
|
}
|
|
3646
3690
|
}
|
|
3647
|
-
async replayHistory(conversationId, gen, activeJobId, turn, jobsRequest, haveByJobId) {
|
|
3691
|
+
async replayHistory(conversationId, gen, activeJobId, turn, jobsRequest, haveByJobId, heldFromMarks) {
|
|
3648
3692
|
const stopReplay = () => gen !== this.generation || this.viewTakenOverByLiveTurn() || this.turnStarted(turn);
|
|
3649
3693
|
let complete = false;
|
|
3650
3694
|
try {
|
|
@@ -3691,7 +3735,10 @@ var StreamManager = class _StreamManager {
|
|
|
3691
3735
|
// primary cache scenario, a SETTLED conversation whose turns are all
|
|
3692
3736
|
// held — and the empty-walk rescue would otherwise re-emit every one of
|
|
3693
3737
|
// them as a steer bubble.
|
|
3694
|
-
heldMessageIds:
|
|
3738
|
+
heldMessageIds: [
|
|
3739
|
+
...jobs.filter((j) => haveByJobId.has(j.job_id)).map((j) => j.message_id),
|
|
3740
|
+
...heldFromMarks
|
|
3741
|
+
],
|
|
3695
3742
|
userMessages: userMessages.map((m) => ({
|
|
3696
3743
|
id: m.id,
|
|
3697
3744
|
content: m.content
|
|
@@ -3725,8 +3772,11 @@ var StreamManager = class _StreamManager {
|
|
|
3725
3772
|
step.messageId
|
|
3726
3773
|
);
|
|
3727
3774
|
}
|
|
3728
|
-
|
|
3729
|
-
|
|
3775
|
+
const drewNothing = plan.length === 0;
|
|
3776
|
+
const holdsTurns = haveByJobId.size > 0;
|
|
3777
|
+
const noDrawableTurns = drewNothing && holdsTurns;
|
|
3778
|
+
this.session.hasMoreTurns = noDrawableTurns ? false : page.hasMore;
|
|
3779
|
+
this.session.oldestTurnCursor = noDrawableTurns ? null : page.nextBefore;
|
|
3730
3780
|
this.oldestDrawnMessageId = plan[0]?.messageId ?? null;
|
|
3731
3781
|
complete = true;
|
|
3732
3782
|
if (stopReplay()) return false;
|