@chenacc/agentbridge 0.2.6 → 0.2.7
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/public/transcript.js +34 -5
package/package.json
CHANGED
package/public/transcript.js
CHANGED
|
@@ -28,14 +28,35 @@ export function indexDeltas(events, index = new Map()) {
|
|
|
28
28
|
return index;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Keep the buffer in sequence order, whatever order events arrive in.
|
|
33
|
+
*
|
|
34
|
+
* Appending blindly was wrong in a way that only shows up on a real phone: when the
|
|
35
|
+
* event stream reconnects it replays from the last id it saw, so a batch of *older*
|
|
36
|
+
* events lands after the newest ones already on screen, and the transcript's clock
|
|
37
|
+
* visibly jumps backwards (11:37 above 10:07). Appending is still the common case —
|
|
38
|
+
* the scan almost always stops on the first comparison.
|
|
39
|
+
*/
|
|
40
|
+
function insertInOrder(events, event) {
|
|
41
|
+
const seq = Number.isFinite(event.seq) ? event.seq : Infinity;
|
|
42
|
+
let index = events.length;
|
|
43
|
+
while (index > 0) {
|
|
44
|
+
const previous = Number.isFinite(events[index - 1].seq) ? events[index - 1].seq : -Infinity;
|
|
45
|
+
if (previous <= seq) break;
|
|
46
|
+
index -= 1;
|
|
47
|
+
}
|
|
48
|
+
if (index === events.length) events.push(event);
|
|
49
|
+
else events.splice(index, 0, event);
|
|
50
|
+
return event;
|
|
51
|
+
}
|
|
52
|
+
|
|
31
53
|
// Token deltas are folded into a single cumulative entry per turn, matching the
|
|
32
54
|
// bridge. Without this a long turn's tokens fill the whole buffer and push the
|
|
33
55
|
// actual conversation out of it, which is why replies used to arrive missing or
|
|
34
56
|
// half-rendered.
|
|
35
57
|
export function absorbEvent(events, deltaIndex, event) {
|
|
36
58
|
if (event.kind !== "message.delta") {
|
|
37
|
-
events
|
|
38
|
-
return event;
|
|
59
|
+
return insertInOrder(events, event);
|
|
39
60
|
}
|
|
40
61
|
const text = String(event.payload?.text ?? "");
|
|
41
62
|
const existing = deltaIndex.get(deltaKeyOf(event));
|
|
@@ -51,8 +72,7 @@ export function absorbEvent(events, deltaIndex, event) {
|
|
|
51
72
|
}
|
|
52
73
|
const entry = { ...event, payload: { ...event.payload, offset: 0 } };
|
|
53
74
|
deltaIndex.set(deltaKeyOf(event), entry);
|
|
54
|
-
events
|
|
55
|
-
return entry;
|
|
75
|
+
return insertInOrder(events, entry);
|
|
56
76
|
}
|
|
57
77
|
|
|
58
78
|
// Trimming normally drops the oldest entries, which is exactly what a freshly
|
|
@@ -347,7 +367,16 @@ function collapsedEntry(event, label, summary, text, className, options) {
|
|
|
347
367
|
}
|
|
348
368
|
|
|
349
369
|
/** Turn a session's events into the list of transcript entries to display. */
|
|
350
|
-
export function buildEntries(
|
|
370
|
+
export function buildEntries(incomingEvents, options = {}) {
|
|
371
|
+
// The buffer should already be in sequence order; sorting here means a page that
|
|
372
|
+
// was assembled before that was true (or by an older client) still renders in
|
|
373
|
+
// chronological order instead of jumping backwards mid-conversation.
|
|
374
|
+
const relevant = [...incomingEvents].sort((left, right) => {
|
|
375
|
+
const a = Number.isFinite(left.seq) ? left.seq : Infinity;
|
|
376
|
+
const b = Number.isFinite(right.seq) ? right.seq : Infinity;
|
|
377
|
+
if (a !== b) return a - b;
|
|
378
|
+
return (Date.parse(left.time) || 0) - (Date.parse(right.time) || 0);
|
|
379
|
+
});
|
|
351
380
|
const statusLabel = options.statusLabel ?? ((kind) => DEFAULT_STATUS_LABELS[kind] ?? kind);
|
|
352
381
|
const settings = { cache: entryCache, formatMessageTime: options.formatMessageTime, math: options.math };
|
|
353
382
|
const { textByTurn, completedTurns } = foldDeltas(relevant);
|