bunnyquery 1.4.5 → 1.5.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/bunnyquery.css +81 -0
- package/bunnyquery.js +171 -80
- package/dist/engine.cjs +133 -75
- package/dist/engine.cjs.map +1 -1
- package/dist/engine.mjs +133 -75
- package/dist/engine.mjs.map +1 -1
- package/package.json +1 -1
- package/src/engine/session.ts +167 -70
- package/src/widget.css +81 -0
package/dist/engine.cjs
CHANGED
|
@@ -1070,10 +1070,18 @@ function mapHistoryListToMessages(list, platform, opts) {
|
|
|
1070
1070
|
}
|
|
1071
1071
|
|
|
1072
1072
|
// src/engine/session.ts
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1073
|
+
var _g = typeof globalThis !== "undefined" ? globalThis : {};
|
|
1074
|
+
function nowMs() {
|
|
1075
|
+
return _g.performance && typeof _g.performance.now === "function" ? _g.performance.now() : Date.now();
|
|
1076
|
+
}
|
|
1077
|
+
function nextFrame(cb) {
|
|
1078
|
+
if (typeof _g.requestAnimationFrame === "function") {
|
|
1079
|
+
_g.requestAnimationFrame(cb);
|
|
1080
|
+
return;
|
|
1081
|
+
}
|
|
1082
|
+
setTimeout(function() {
|
|
1083
|
+
cb(nowMs());
|
|
1084
|
+
}, 16);
|
|
1077
1085
|
}
|
|
1078
1086
|
var ChatSession = class {
|
|
1079
1087
|
constructor(host) {
|
|
@@ -1160,35 +1168,26 @@ var ChatSession = class {
|
|
|
1160
1168
|
if (dispatchItemId) self.historyItemPolls.delete(dispatchItemId);
|
|
1161
1169
|
var existing = self.aiChatHistoryCache[params.key] || { messages: [], endOfList: false, startKeyHistory: [] };
|
|
1162
1170
|
var reply = { role: "assistant", content: result.content, isError: result.isError };
|
|
1163
|
-
var
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
} else {
|
|
1171
|
-
var msgs = existing.messages.slice();
|
|
1172
|
-
var idx = -1;
|
|
1173
|
-
for (var i = msgs.length - 1; i >= 0; i--) {
|
|
1174
|
-
var m = msgs[i];
|
|
1175
|
-
if (m && m.isPending && m.role === "assistant" && !m.isBackgroundTask) {
|
|
1176
|
-
idx = i;
|
|
1177
|
-
break;
|
|
1178
|
-
}
|
|
1179
|
-
}
|
|
1180
|
-
if (idx !== -1) {
|
|
1181
|
-
reply._serverItemId = msgs[idx]._serverItemId;
|
|
1182
|
-
msgs[idx] = reply;
|
|
1183
|
-
} else {
|
|
1184
|
-
msgs.push(reply);
|
|
1171
|
+
var msgs = existing.messages.slice();
|
|
1172
|
+
var idx = -1;
|
|
1173
|
+
for (var i = msgs.length - 1; i >= 0; i--) {
|
|
1174
|
+
var m = msgs[i];
|
|
1175
|
+
if (m && m.isPending && m.role === "assistant" && !m.isBackgroundTask) {
|
|
1176
|
+
idx = i;
|
|
1177
|
+
break;
|
|
1185
1178
|
}
|
|
1186
|
-
self.aiChatHistoryCache[params.key] = {
|
|
1187
|
-
messages: msgs,
|
|
1188
|
-
endOfList: existing.endOfList,
|
|
1189
|
-
startKeyHistory: existing.startKeyHistory
|
|
1190
|
-
};
|
|
1191
1179
|
}
|
|
1180
|
+
if (idx !== -1) {
|
|
1181
|
+
reply._serverItemId = msgs[idx]._serverItemId;
|
|
1182
|
+
msgs[idx] = reply;
|
|
1183
|
+
} else {
|
|
1184
|
+
msgs.push(reply);
|
|
1185
|
+
}
|
|
1186
|
+
self.aiChatHistoryCache[params.key] = {
|
|
1187
|
+
messages: msgs,
|
|
1188
|
+
endOfList: existing.endOfList,
|
|
1189
|
+
startKeyHistory: existing.startKeyHistory
|
|
1190
|
+
};
|
|
1192
1191
|
return result;
|
|
1193
1192
|
});
|
|
1194
1193
|
this.pendingAgentRequests[params.key] = run;
|
|
@@ -1331,7 +1330,9 @@ var ChatSession = class {
|
|
|
1331
1330
|
if (existing._serverItemId !== void 0) promoted._serverItemId = existing._serverItemId;
|
|
1332
1331
|
if (existing.isSendingToServer) promoted.isSendingToServer = true;
|
|
1333
1332
|
this.state.messages[nextIdx] = promoted;
|
|
1334
|
-
|
|
1333
|
+
var placeholder = { role: "assistant", content: "", isPending: true };
|
|
1334
|
+
if (existing._serverItemId !== void 0) placeholder._serverItemId = existing._serverItemId;
|
|
1335
|
+
this.state.messages.splice(nextIdx + 1, 0, placeholder);
|
|
1335
1336
|
this.host.notify();
|
|
1336
1337
|
}
|
|
1337
1338
|
resolveQueuedUserBubble(serverId) {
|
|
@@ -1541,61 +1542,118 @@ var ChatSession = class {
|
|
|
1541
1542
|
});
|
|
1542
1543
|
}
|
|
1543
1544
|
// --- typewriter -------------------------------------------------------
|
|
1545
|
+
// Reveal `fullText` into a message bubble at a constant wall-clock RATE
|
|
1546
|
+
// (chars/second) driven by requestAnimationFrame, rather than a fixed number
|
|
1547
|
+
// of characters per fixed-delay tick. This is what keeps typing smooth and
|
|
1548
|
+
// cheap on slow machines:
|
|
1549
|
+
//
|
|
1550
|
+
// * Each frame reveals `elapsed_ms * CHARS_PER_SEC` characters, so the
|
|
1551
|
+
// visual speed is the same regardless of how long a frame actually took.
|
|
1552
|
+
// * As the bubble's markdown grows, each re-render gets more expensive, so
|
|
1553
|
+
// frames get longer — which makes each frame reveal MORE characters and
|
|
1554
|
+
// therefore do FEWER, larger renders. That converts the old O(n^2)
|
|
1555
|
+
// "re-render the whole growing string once per 3 characters" (which got
|
|
1556
|
+
// slower and slower and pegged the CPU) into roughly O(n): the number of
|
|
1557
|
+
// renders self-throttles to what the machine can actually paint.
|
|
1558
|
+
// * rAF paces us to the browser's paint cycle and pauses in background
|
|
1559
|
+
// tabs, so we never queue work faster than it can be drawn.
|
|
1544
1560
|
typewriteIntoIndex(idx, fullText, localId) {
|
|
1545
1561
|
var self = this;
|
|
1546
1562
|
if (!fullText) return Promise.resolve();
|
|
1547
|
-
var
|
|
1548
|
-
var
|
|
1549
|
-
var
|
|
1563
|
+
var CHARS_PER_SEC = 300;
|
|
1564
|
+
var MIN_STEP = 1;
|
|
1565
|
+
var MAX_FRAME_MS = 1e3;
|
|
1566
|
+
var regions = [], m;
|
|
1550
1567
|
var fenceRegex = /```[\w.-]+\.[a-zA-Z0-9]+\n[\s\S]*?```/g;
|
|
1551
|
-
while ((m = fenceRegex.exec(fullText)) !== null)
|
|
1552
|
-
var linkRegions = [], lm;
|
|
1568
|
+
while ((m = fenceRegex.exec(fullText)) !== null) regions.push({ start: m.index, end: m.index + m[0].length });
|
|
1553
1569
|
var linkRegex = createInlineLinkRegex();
|
|
1554
|
-
while ((
|
|
1570
|
+
while ((m = linkRegex.exec(fullText)) !== null) regions.push({ start: m.index, end: m.index + m[0].length });
|
|
1571
|
+
regions.sort(function(a, b) {
|
|
1572
|
+
return a.start - b.start;
|
|
1573
|
+
});
|
|
1555
1574
|
this.state.typing = true;
|
|
1556
1575
|
this.state.typingAbort = false;
|
|
1557
1576
|
var i = 0;
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
var
|
|
1561
|
-
var
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1577
|
+
var last = nowMs();
|
|
1578
|
+
return new Promise(function(resolve) {
|
|
1579
|
+
var done = false;
|
|
1580
|
+
var doc = _g.document;
|
|
1581
|
+
function isHidden() {
|
|
1582
|
+
return !!(doc && doc.hidden);
|
|
1583
|
+
}
|
|
1584
|
+
function cleanup() {
|
|
1585
|
+
if (doc && doc.removeEventListener) doc.removeEventListener("visibilitychange", onVisibility);
|
|
1586
|
+
}
|
|
1587
|
+
function finish() {
|
|
1588
|
+
if (done) return;
|
|
1589
|
+
done = true;
|
|
1590
|
+
cleanup();
|
|
1591
|
+
if (!self.state.typingAbort) {
|
|
1592
|
+
var fi = localId ? self.state.messages.findIndex(function(mm) {
|
|
1593
|
+
return mm._localId === localId;
|
|
1594
|
+
}) : idx;
|
|
1595
|
+
if (fi !== -1) {
|
|
1596
|
+
var t = self.state.messages[fi];
|
|
1597
|
+
if (t) {
|
|
1598
|
+
t.content = fullText;
|
|
1599
|
+
self.host.refreshMessageBubble(fi);
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
self.state.typing = false;
|
|
1604
|
+
resolve();
|
|
1605
|
+
}
|
|
1606
|
+
function onVisibility() {
|
|
1607
|
+
if (isHidden()) finish();
|
|
1574
1608
|
}
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
var
|
|
1609
|
+
if (doc && doc.addEventListener) doc.addEventListener("visibilitychange", onVisibility);
|
|
1610
|
+
function frame(t) {
|
|
1611
|
+
if (done) return;
|
|
1612
|
+
if (self.state.typingAbort || i >= fullText.length || isHidden()) {
|
|
1613
|
+
finish();
|
|
1614
|
+
return;
|
|
1615
|
+
}
|
|
1616
|
+
var dt = t - last;
|
|
1617
|
+
last = t;
|
|
1618
|
+
if (!(dt > 0)) dt = 16;
|
|
1619
|
+
if (dt > MAX_FRAME_MS) dt = MAX_FRAME_MS;
|
|
1620
|
+
var step = Math.round(dt * CHARS_PER_SEC / 1e3);
|
|
1621
|
+
if (step < MIN_STEP) step = MIN_STEP;
|
|
1622
|
+
var next = Math.min(fullText.length, i + step);
|
|
1623
|
+
for (var changed = true; changed; ) {
|
|
1624
|
+
changed = false;
|
|
1625
|
+
for (var k = 0; k < regions.length; k++) {
|
|
1626
|
+
var r = regions[k];
|
|
1627
|
+
if (next > r.start && i < r.end && r.end > next) {
|
|
1628
|
+
next = r.end;
|
|
1629
|
+
changed = true;
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1632
|
+
}
|
|
1633
|
+
if (next > fullText.length) next = fullText.length;
|
|
1634
|
+
i = next;
|
|
1635
|
+
var currentIdx = localId ? self.state.messages.findIndex(function(mm) {
|
|
1590
1636
|
return mm._localId === localId;
|
|
1591
1637
|
}) : idx;
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
self.host.refreshMessageBubble(fi !== -1 ? fi : idx);
|
|
1638
|
+
if (currentIdx === -1) {
|
|
1639
|
+
finish();
|
|
1640
|
+
return;
|
|
1596
1641
|
}
|
|
1642
|
+
var target = self.state.messages[currentIdx];
|
|
1643
|
+
if (!target) {
|
|
1644
|
+
finish();
|
|
1645
|
+
return;
|
|
1646
|
+
}
|
|
1647
|
+
target.content = fullText.slice(0, i);
|
|
1648
|
+
self.host.refreshMessageBubble(currentIdx);
|
|
1649
|
+
self.host.scrollToBottomIfSticky();
|
|
1650
|
+
nextFrame(frame);
|
|
1651
|
+
}
|
|
1652
|
+
if (isHidden()) {
|
|
1653
|
+
finish();
|
|
1654
|
+
return;
|
|
1597
1655
|
}
|
|
1598
|
-
|
|
1656
|
+
nextFrame(frame);
|
|
1599
1657
|
});
|
|
1600
1658
|
}
|
|
1601
1659
|
enqueueTypewrite(idx, fullText, localId) {
|
|
@@ -1909,7 +1967,7 @@ var ChatSession = class {
|
|
|
1909
1967
|
if (item.status !== "running" && item.status !== "pending") return;
|
|
1910
1968
|
if (!item.poll || !item.id) return;
|
|
1911
1969
|
if (self.historyItemPolls.has(item.id)) return;
|
|
1912
|
-
if (
|
|
1970
|
+
if (self.pendingAgentRequests[self.getHistoryCacheKey()] && !item._isBgTask && !item._isOnBgQueue) return;
|
|
1913
1971
|
self.historyItemPolls.set(item.id, true);
|
|
1914
1972
|
var capturedId = item.id;
|
|
1915
1973
|
var pp = item.poll({
|