bunnyquery 1.4.4 → 1.4.6

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/engine.mjs CHANGED
@@ -1068,10 +1068,18 @@ function mapHistoryListToMessages(list, platform, opts) {
1068
1068
  }
1069
1069
 
1070
1070
  // src/engine/session.ts
1071
- function sleep(ms) {
1072
- return new Promise(function(r) {
1073
- setTimeout(r, ms);
1074
- });
1071
+ var _g = typeof globalThis !== "undefined" ? globalThis : {};
1072
+ function nowMs() {
1073
+ return _g.performance && typeof _g.performance.now === "function" ? _g.performance.now() : Date.now();
1074
+ }
1075
+ function nextFrame(cb) {
1076
+ if (typeof _g.requestAnimationFrame === "function") {
1077
+ _g.requestAnimationFrame(cb);
1078
+ return;
1079
+ }
1080
+ setTimeout(function() {
1081
+ cb(nowMs());
1082
+ }, 16);
1075
1083
  }
1076
1084
  var ChatSession = class {
1077
1085
  constructor(host) {
@@ -1122,11 +1130,17 @@ var ChatSession = class {
1122
1130
  }
1123
1131
  dispatchAgentRequest(params) {
1124
1132
  var self = this;
1133
+ var dispatchItemId;
1125
1134
  var sendAndPoll = function() {
1126
1135
  return Promise.resolve(
1127
1136
  self._callProviderFor(params.aiPlatform, params.text, params.boundedMessages, params.systemPrompt, params.aiModel, params.userId, params.extractContent)
1128
1137
  ).then(function(initial) {
1129
1138
  if (initial && initial.poll && (initial.status === "pending" || initial.status === "running")) {
1139
+ if (initial.id) {
1140
+ if (dispatchItemId && dispatchItemId !== initial.id) self.historyItemPolls.delete(dispatchItemId);
1141
+ dispatchItemId = initial.id;
1142
+ self.historyItemPolls.set(initial.id, true);
1143
+ }
1130
1144
  return initial.poll({ latency: POLL_INTERVAL });
1131
1145
  }
1132
1146
  return initial;
@@ -1149,37 +1163,29 @@ var ChatSession = class {
1149
1163
  return { content: getErrorMessage(err), isError: true };
1150
1164
  }).then(function(result) {
1151
1165
  delete self.pendingAgentRequests[params.key];
1166
+ if (dispatchItemId) self.historyItemPolls.delete(dispatchItemId);
1152
1167
  var existing = self.aiChatHistoryCache[params.key] || { messages: [], endOfList: false, startKeyHistory: [] };
1153
1168
  var reply = { role: "assistant", content: result.content, isError: result.isError };
1154
- var onThisVisibleChat = self.host.isViewMounted() && self.getHistoryCacheKey() === params.key;
1155
- if (onThisVisibleChat) {
1156
- self.aiChatHistoryCache[params.key] = {
1157
- messages: existing.messages.concat([reply]),
1158
- endOfList: existing.endOfList,
1159
- startKeyHistory: existing.startKeyHistory
1160
- };
1161
- } else {
1162
- var msgs = existing.messages.slice();
1163
- var idx = -1;
1164
- for (var i = msgs.length - 1; i >= 0; i--) {
1165
- var m = msgs[i];
1166
- if (m && m.isPending && m.role === "assistant" && !m.isBackgroundTask) {
1167
- idx = i;
1168
- break;
1169
- }
1170
- }
1171
- if (idx !== -1) {
1172
- reply._serverItemId = msgs[idx]._serverItemId;
1173
- msgs[idx] = reply;
1174
- } else {
1175
- msgs.push(reply);
1169
+ var msgs = existing.messages.slice();
1170
+ var idx = -1;
1171
+ for (var i = msgs.length - 1; i >= 0; i--) {
1172
+ var m = msgs[i];
1173
+ if (m && m.isPending && m.role === "assistant" && !m.isBackgroundTask) {
1174
+ idx = i;
1175
+ break;
1176
1176
  }
1177
- self.aiChatHistoryCache[params.key] = {
1178
- messages: msgs,
1179
- endOfList: existing.endOfList,
1180
- startKeyHistory: existing.startKeyHistory
1181
- };
1182
1177
  }
1178
+ if (idx !== -1) {
1179
+ reply._serverItemId = msgs[idx]._serverItemId;
1180
+ msgs[idx] = reply;
1181
+ } else {
1182
+ msgs.push(reply);
1183
+ }
1184
+ self.aiChatHistoryCache[params.key] = {
1185
+ messages: msgs,
1186
+ endOfList: existing.endOfList,
1187
+ startKeyHistory: existing.startKeyHistory
1188
+ };
1183
1189
  return result;
1184
1190
  });
1185
1191
  this.pendingAgentRequests[params.key] = run;
@@ -1232,6 +1238,7 @@ var ChatSession = class {
1232
1238
  self.host.notify();
1233
1239
  }
1234
1240
  if (result && result.poll && (result.status === "pending" || result.status === "running")) {
1241
+ if (serverId) self.historyItemPolls.set(serverId, true);
1235
1242
  return result.poll({ latency: POLL_INTERVAL }).then(function(res) {
1236
1243
  return self.onQueuedSendResponse(capturedComposed, res, capturedPlatform, serverId);
1237
1244
  }).catch(function(err) {
@@ -1321,7 +1328,9 @@ var ChatSession = class {
1321
1328
  if (existing._serverItemId !== void 0) promoted._serverItemId = existing._serverItemId;
1322
1329
  if (existing.isSendingToServer) promoted.isSendingToServer = true;
1323
1330
  this.state.messages[nextIdx] = promoted;
1324
- this.state.messages.splice(nextIdx + 1, 0, { role: "assistant", content: "", isPending: true });
1331
+ var placeholder = { role: "assistant", content: "", isPending: true };
1332
+ if (existing._serverItemId !== void 0) placeholder._serverItemId = existing._serverItemId;
1333
+ this.state.messages.splice(nextIdx + 1, 0, placeholder);
1325
1334
  this.host.notify();
1326
1335
  }
1327
1336
  resolveQueuedUserBubble(serverId) {
@@ -1371,6 +1380,7 @@ var ChatSession = class {
1371
1380
  else this.state.messages.push(msg);
1372
1381
  }
1373
1382
  onQueuedSendResponse(_composed, response, platform, serverId) {
1383
+ if (serverId) this.historyItemPolls.delete(serverId);
1374
1384
  var targetIdx = this.resolveQueuedUserBubble(serverId);
1375
1385
  if (targetIdx === void 0) {
1376
1386
  this.host.notify();
@@ -1405,6 +1415,7 @@ var ChatSession = class {
1405
1415
  this.host.scrollToBottom(true);
1406
1416
  }
1407
1417
  onQueuedSendError(_composed, err, serverId) {
1418
+ if (serverId) this.historyItemPolls.delete(serverId);
1408
1419
  var isNotExists = err && (err.code === "NOT_EXISTS" || err.body && err.body.code === "NOT_EXISTS");
1409
1420
  if (isNotExists) {
1410
1421
  var userIdx = serverId ? this.state.messages.findIndex(function(m) {
@@ -1529,61 +1540,118 @@ var ChatSession = class {
1529
1540
  });
1530
1541
  }
1531
1542
  // --- typewriter -------------------------------------------------------
1543
+ // Reveal `fullText` into a message bubble at a constant wall-clock RATE
1544
+ // (chars/second) driven by requestAnimationFrame, rather than a fixed number
1545
+ // of characters per fixed-delay tick. This is what keeps typing smooth and
1546
+ // cheap on slow machines:
1547
+ //
1548
+ // * Each frame reveals `elapsed_ms * CHARS_PER_SEC` characters, so the
1549
+ // visual speed is the same regardless of how long a frame actually took.
1550
+ // * As the bubble's markdown grows, each re-render gets more expensive, so
1551
+ // frames get longer — which makes each frame reveal MORE characters and
1552
+ // therefore do FEWER, larger renders. That converts the old O(n^2)
1553
+ // "re-render the whole growing string once per 3 characters" (which got
1554
+ // slower and slower and pegged the CPU) into roughly O(n): the number of
1555
+ // renders self-throttles to what the machine can actually paint.
1556
+ // * rAF paces us to the browser's paint cycle and pauses in background
1557
+ // tabs, so we never queue work faster than it can be drawn.
1532
1558
  typewriteIntoIndex(idx, fullText, localId) {
1533
1559
  var self = this;
1534
1560
  if (!fullText) return Promise.resolve();
1535
- var TICK_MS = 16, charsPerTick = 3, FENCE_REVEAL_MS = 200;
1536
- var fenceTicks = Math.max(1, Math.floor(FENCE_REVEAL_MS / TICK_MS));
1537
- var fenceRegions = [], m;
1561
+ var CHARS_PER_SEC = 300;
1562
+ var MIN_STEP = 1;
1563
+ var MAX_FRAME_MS = 1e3;
1564
+ var regions = [], m;
1538
1565
  var fenceRegex = /```[\w.-]+\.[a-zA-Z0-9]+\n[\s\S]*?```/g;
1539
- while ((m = fenceRegex.exec(fullText)) !== null) fenceRegions.push({ start: m.index, end: m.index + m[0].length });
1540
- var linkRegions = [], lm;
1566
+ while ((m = fenceRegex.exec(fullText)) !== null) regions.push({ start: m.index, end: m.index + m[0].length });
1541
1567
  var linkRegex = createInlineLinkRegex();
1542
- while ((lm = linkRegex.exec(fullText)) !== null) linkRegions.push({ start: lm.index, end: lm.index + lm[0].length });
1568
+ while ((m = linkRegex.exec(fullText)) !== null) regions.push({ start: m.index, end: m.index + m[0].length });
1569
+ regions.sort(function(a, b) {
1570
+ return a.start - b.start;
1571
+ });
1543
1572
  this.state.typing = true;
1544
1573
  this.state.typingAbort = false;
1545
1574
  var i = 0;
1546
- return (function loop() {
1547
- if (self.state.typingAbort || i >= fullText.length) return Promise.resolve();
1548
- var step = charsPerTick;
1549
- var region = fenceRegions.find(function(r) {
1550
- return i >= r.start && i < r.end;
1551
- });
1552
- var linkRegion = linkRegions.find(function(r) {
1553
- return i >= r.start && i < r.end;
1554
- });
1555
- if (region) step = Math.max(charsPerTick, Math.ceil((region.end - i) / fenceTicks));
1556
- else if (linkRegion) step = Math.max(charsPerTick, linkRegion.end - i);
1557
- else {
1558
- var nextLink = linkRegions.find(function(r) {
1559
- return i < r.start && i + step > r.start;
1560
- });
1561
- if (nextLink) step = nextLink.end - i;
1575
+ var last = nowMs();
1576
+ return new Promise(function(resolve) {
1577
+ var done = false;
1578
+ var doc = _g.document;
1579
+ function isHidden() {
1580
+ return !!(doc && doc.hidden);
1581
+ }
1582
+ function cleanup() {
1583
+ if (doc && doc.removeEventListener) doc.removeEventListener("visibilitychange", onVisibility);
1584
+ }
1585
+ function finish() {
1586
+ if (done) return;
1587
+ done = true;
1588
+ cleanup();
1589
+ if (!self.state.typingAbort) {
1590
+ var fi = localId ? self.state.messages.findIndex(function(mm) {
1591
+ return mm._localId === localId;
1592
+ }) : idx;
1593
+ if (fi !== -1) {
1594
+ var t = self.state.messages[fi];
1595
+ if (t) {
1596
+ t.content = fullText;
1597
+ self.host.refreshMessageBubble(fi);
1598
+ }
1599
+ }
1600
+ }
1601
+ self.state.typing = false;
1602
+ resolve();
1603
+ }
1604
+ function onVisibility() {
1605
+ if (isHidden()) finish();
1562
1606
  }
1563
- i = Math.min(fullText.length, i + step);
1564
- var currentIdx = localId ? self.state.messages.findIndex(function(mm) {
1565
- return mm._localId === localId;
1566
- }) : idx;
1567
- if (currentIdx === -1) return Promise.resolve();
1568
- var target = self.state.messages[currentIdx];
1569
- if (!target) return Promise.resolve();
1570
- target.content = fullText.slice(0, i);
1571
- self.host.refreshMessageBubble(currentIdx);
1572
- return Promise.resolve(self.host.scrollToBottomIfSticky()).then(function() {
1573
- return sleep(TICK_MS);
1574
- }).then(loop);
1575
- })().then(function() {
1576
- if (!self.state.typingAbort) {
1577
- var fi = localId ? self.state.messages.findIndex(function(mm) {
1607
+ if (doc && doc.addEventListener) doc.addEventListener("visibilitychange", onVisibility);
1608
+ function frame(t) {
1609
+ if (done) return;
1610
+ if (self.state.typingAbort || i >= fullText.length || isHidden()) {
1611
+ finish();
1612
+ return;
1613
+ }
1614
+ var dt = t - last;
1615
+ last = t;
1616
+ if (!(dt > 0)) dt = 16;
1617
+ if (dt > MAX_FRAME_MS) dt = MAX_FRAME_MS;
1618
+ var step = Math.round(dt * CHARS_PER_SEC / 1e3);
1619
+ if (step < MIN_STEP) step = MIN_STEP;
1620
+ var next = Math.min(fullText.length, i + step);
1621
+ for (var changed = true; changed; ) {
1622
+ changed = false;
1623
+ for (var k = 0; k < regions.length; k++) {
1624
+ var r = regions[k];
1625
+ if (next > r.start && i < r.end && r.end > next) {
1626
+ next = r.end;
1627
+ changed = true;
1628
+ }
1629
+ }
1630
+ }
1631
+ if (next > fullText.length) next = fullText.length;
1632
+ i = next;
1633
+ var currentIdx = localId ? self.state.messages.findIndex(function(mm) {
1578
1634
  return mm._localId === localId;
1579
1635
  }) : idx;
1580
- var t = fi !== -1 ? self.state.messages[fi] : self.state.messages[idx];
1581
- if (t) {
1582
- t.content = fullText;
1583
- self.host.refreshMessageBubble(fi !== -1 ? fi : idx);
1636
+ if (currentIdx === -1) {
1637
+ finish();
1638
+ return;
1584
1639
  }
1640
+ var target = self.state.messages[currentIdx];
1641
+ if (!target) {
1642
+ finish();
1643
+ return;
1644
+ }
1645
+ target.content = fullText.slice(0, i);
1646
+ self.host.refreshMessageBubble(currentIdx);
1647
+ self.host.scrollToBottomIfSticky();
1648
+ nextFrame(frame);
1649
+ }
1650
+ if (isHidden()) {
1651
+ finish();
1652
+ return;
1585
1653
  }
1586
- self.state.typing = false;
1654
+ nextFrame(frame);
1587
1655
  });
1588
1656
  }
1589
1657
  enqueueTypewrite(idx, fullText, localId) {
@@ -1897,7 +1965,7 @@ var ChatSession = class {
1897
1965
  if (item.status !== "running" && item.status !== "pending") return;
1898
1966
  if (!item.poll || !item.id) return;
1899
1967
  if (self.historyItemPolls.has(item.id)) return;
1900
- if ((item.status === "running" || item.status === "pending") && self.pendingAgentRequests[self.getHistoryCacheKey()]) return;
1968
+ if (self.pendingAgentRequests[self.getHistoryCacheKey()] && !item._isBgTask && !item._isOnBgQueue) return;
1901
1969
  self.historyItemPolls.set(item.id, true);
1902
1970
  var capturedId = item.id;
1903
1971
  var pp = item.poll({