bunnyquery 1.4.5 → 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/bunnyquery.js CHANGED
@@ -1036,10 +1036,18 @@ ${options.inlineContentPlaceholder}
1036
1036
  }
1037
1037
 
1038
1038
  // src/engine/session.ts
1039
- function sleep(ms) {
1040
- return new Promise(function(r) {
1041
- setTimeout(r, ms);
1042
- });
1039
+ var _g = typeof globalThis !== "undefined" ? globalThis : {};
1040
+ function nowMs() {
1041
+ return _g.performance && typeof _g.performance.now === "function" ? _g.performance.now() : Date.now();
1042
+ }
1043
+ function nextFrame(cb) {
1044
+ if (typeof _g.requestAnimationFrame === "function") {
1045
+ _g.requestAnimationFrame(cb);
1046
+ return;
1047
+ }
1048
+ setTimeout(function() {
1049
+ cb(nowMs());
1050
+ }, 16);
1043
1051
  }
1044
1052
  var ChatSession = class {
1045
1053
  constructor(host) {
@@ -1126,35 +1134,26 @@ ${options.inlineContentPlaceholder}
1126
1134
  if (dispatchItemId) self.historyItemPolls.delete(dispatchItemId);
1127
1135
  var existing = self.aiChatHistoryCache[params.key] || { messages: [], endOfList: false, startKeyHistory: [] };
1128
1136
  var reply = { role: "assistant", content: result.content, isError: result.isError };
1129
- var onThisVisibleChat = self.host.isViewMounted() && self.getHistoryCacheKey() === params.key;
1130
- if (onThisVisibleChat) {
1131
- self.aiChatHistoryCache[params.key] = {
1132
- messages: existing.messages.concat([reply]),
1133
- endOfList: existing.endOfList,
1134
- startKeyHistory: existing.startKeyHistory
1135
- };
1136
- } else {
1137
- var msgs = existing.messages.slice();
1138
- var idx = -1;
1139
- for (var i = msgs.length - 1; i >= 0; i--) {
1140
- var m = msgs[i];
1141
- if (m && m.isPending && m.role === "assistant" && !m.isBackgroundTask) {
1142
- idx = i;
1143
- break;
1144
- }
1145
- }
1146
- if (idx !== -1) {
1147
- reply._serverItemId = msgs[idx]._serverItemId;
1148
- msgs[idx] = reply;
1149
- } else {
1150
- msgs.push(reply);
1137
+ var msgs = existing.messages.slice();
1138
+ var idx = -1;
1139
+ for (var i = msgs.length - 1; i >= 0; i--) {
1140
+ var m = msgs[i];
1141
+ if (m && m.isPending && m.role === "assistant" && !m.isBackgroundTask) {
1142
+ idx = i;
1143
+ break;
1151
1144
  }
1152
- self.aiChatHistoryCache[params.key] = {
1153
- messages: msgs,
1154
- endOfList: existing.endOfList,
1155
- startKeyHistory: existing.startKeyHistory
1156
- };
1157
1145
  }
1146
+ if (idx !== -1) {
1147
+ reply._serverItemId = msgs[idx]._serverItemId;
1148
+ msgs[idx] = reply;
1149
+ } else {
1150
+ msgs.push(reply);
1151
+ }
1152
+ self.aiChatHistoryCache[params.key] = {
1153
+ messages: msgs,
1154
+ endOfList: existing.endOfList,
1155
+ startKeyHistory: existing.startKeyHistory
1156
+ };
1158
1157
  return result;
1159
1158
  });
1160
1159
  this.pendingAgentRequests[params.key] = run;
@@ -1297,7 +1296,9 @@ ${options.inlineContentPlaceholder}
1297
1296
  if (existing._serverItemId !== void 0) promoted._serverItemId = existing._serverItemId;
1298
1297
  if (existing.isSendingToServer) promoted.isSendingToServer = true;
1299
1298
  this.state.messages[nextIdx] = promoted;
1300
- this.state.messages.splice(nextIdx + 1, 0, { role: "assistant", content: "", isPending: true });
1299
+ var placeholder = { role: "assistant", content: "", isPending: true };
1300
+ if (existing._serverItemId !== void 0) placeholder._serverItemId = existing._serverItemId;
1301
+ this.state.messages.splice(nextIdx + 1, 0, placeholder);
1301
1302
  this.host.notify();
1302
1303
  }
1303
1304
  resolveQueuedUserBubble(serverId) {
@@ -1507,61 +1508,118 @@ ${options.inlineContentPlaceholder}
1507
1508
  });
1508
1509
  }
1509
1510
  // --- typewriter -------------------------------------------------------
1511
+ // Reveal `fullText` into a message bubble at a constant wall-clock RATE
1512
+ // (chars/second) driven by requestAnimationFrame, rather than a fixed number
1513
+ // of characters per fixed-delay tick. This is what keeps typing smooth and
1514
+ // cheap on slow machines:
1515
+ //
1516
+ // * Each frame reveals `elapsed_ms * CHARS_PER_SEC` characters, so the
1517
+ // visual speed is the same regardless of how long a frame actually took.
1518
+ // * As the bubble's markdown grows, each re-render gets more expensive, so
1519
+ // frames get longer — which makes each frame reveal MORE characters and
1520
+ // therefore do FEWER, larger renders. That converts the old O(n^2)
1521
+ // "re-render the whole growing string once per 3 characters" (which got
1522
+ // slower and slower and pegged the CPU) into roughly O(n): the number of
1523
+ // renders self-throttles to what the machine can actually paint.
1524
+ // * rAF paces us to the browser's paint cycle and pauses in background
1525
+ // tabs, so we never queue work faster than it can be drawn.
1510
1526
  typewriteIntoIndex(idx, fullText, localId) {
1511
1527
  var self = this;
1512
1528
  if (!fullText) return Promise.resolve();
1513
- var TICK_MS = 16, charsPerTick = 3, FENCE_REVEAL_MS = 200;
1514
- var fenceTicks = Math.max(1, Math.floor(FENCE_REVEAL_MS / TICK_MS));
1515
- var fenceRegions = [], m;
1529
+ var CHARS_PER_SEC = 300;
1530
+ var MIN_STEP = 1;
1531
+ var MAX_FRAME_MS = 1e3;
1532
+ var regions = [], m;
1516
1533
  var fenceRegex = /```[\w.-]+\.[a-zA-Z0-9]+\n[\s\S]*?```/g;
1517
- while ((m = fenceRegex.exec(fullText)) !== null) fenceRegions.push({ start: m.index, end: m.index + m[0].length });
1518
- var linkRegions = [], lm;
1534
+ while ((m = fenceRegex.exec(fullText)) !== null) regions.push({ start: m.index, end: m.index + m[0].length });
1519
1535
  var linkRegex = createInlineLinkRegex();
1520
- while ((lm = linkRegex.exec(fullText)) !== null) linkRegions.push({ start: lm.index, end: lm.index + lm[0].length });
1536
+ while ((m = linkRegex.exec(fullText)) !== null) regions.push({ start: m.index, end: m.index + m[0].length });
1537
+ regions.sort(function(a, b) {
1538
+ return a.start - b.start;
1539
+ });
1521
1540
  this.state.typing = true;
1522
1541
  this.state.typingAbort = false;
1523
1542
  var i = 0;
1524
- return (function loop() {
1525
- if (self.state.typingAbort || i >= fullText.length) return Promise.resolve();
1526
- var step = charsPerTick;
1527
- var region = fenceRegions.find(function(r) {
1528
- return i >= r.start && i < r.end;
1529
- });
1530
- var linkRegion = linkRegions.find(function(r) {
1531
- return i >= r.start && i < r.end;
1532
- });
1533
- if (region) step = Math.max(charsPerTick, Math.ceil((region.end - i) / fenceTicks));
1534
- else if (linkRegion) step = Math.max(charsPerTick, linkRegion.end - i);
1535
- else {
1536
- var nextLink = linkRegions.find(function(r) {
1537
- return i < r.start && i + step > r.start;
1538
- });
1539
- if (nextLink) step = nextLink.end - i;
1543
+ var last = nowMs();
1544
+ return new Promise(function(resolve) {
1545
+ var done = false;
1546
+ var doc = _g.document;
1547
+ function isHidden() {
1548
+ return !!(doc && doc.hidden);
1549
+ }
1550
+ function cleanup() {
1551
+ if (doc && doc.removeEventListener) doc.removeEventListener("visibilitychange", onVisibility);
1540
1552
  }
1541
- i = Math.min(fullText.length, i + step);
1542
- var currentIdx = localId ? self.state.messages.findIndex(function(mm) {
1543
- return mm._localId === localId;
1544
- }) : idx;
1545
- if (currentIdx === -1) return Promise.resolve();
1546
- var target = self.state.messages[currentIdx];
1547
- if (!target) return Promise.resolve();
1548
- target.content = fullText.slice(0, i);
1549
- self.host.refreshMessageBubble(currentIdx);
1550
- return Promise.resolve(self.host.scrollToBottomIfSticky()).then(function() {
1551
- return sleep(TICK_MS);
1552
- }).then(loop);
1553
- })().then(function() {
1554
- if (!self.state.typingAbort) {
1555
- var fi = localId ? self.state.messages.findIndex(function(mm) {
1553
+ function finish() {
1554
+ if (done) return;
1555
+ done = true;
1556
+ cleanup();
1557
+ if (!self.state.typingAbort) {
1558
+ var fi = localId ? self.state.messages.findIndex(function(mm) {
1559
+ return mm._localId === localId;
1560
+ }) : idx;
1561
+ if (fi !== -1) {
1562
+ var t = self.state.messages[fi];
1563
+ if (t) {
1564
+ t.content = fullText;
1565
+ self.host.refreshMessageBubble(fi);
1566
+ }
1567
+ }
1568
+ }
1569
+ self.state.typing = false;
1570
+ resolve();
1571
+ }
1572
+ function onVisibility() {
1573
+ if (isHidden()) finish();
1574
+ }
1575
+ if (doc && doc.addEventListener) doc.addEventListener("visibilitychange", onVisibility);
1576
+ function frame(t) {
1577
+ if (done) return;
1578
+ if (self.state.typingAbort || i >= fullText.length || isHidden()) {
1579
+ finish();
1580
+ return;
1581
+ }
1582
+ var dt = t - last;
1583
+ last = t;
1584
+ if (!(dt > 0)) dt = 16;
1585
+ if (dt > MAX_FRAME_MS) dt = MAX_FRAME_MS;
1586
+ var step = Math.round(dt * CHARS_PER_SEC / 1e3);
1587
+ if (step < MIN_STEP) step = MIN_STEP;
1588
+ var next = Math.min(fullText.length, i + step);
1589
+ for (var changed = true; changed; ) {
1590
+ changed = false;
1591
+ for (var k = 0; k < regions.length; k++) {
1592
+ var r = regions[k];
1593
+ if (next > r.start && i < r.end && r.end > next) {
1594
+ next = r.end;
1595
+ changed = true;
1596
+ }
1597
+ }
1598
+ }
1599
+ if (next > fullText.length) next = fullText.length;
1600
+ i = next;
1601
+ var currentIdx = localId ? self.state.messages.findIndex(function(mm) {
1556
1602
  return mm._localId === localId;
1557
1603
  }) : idx;
1558
- var t = fi !== -1 ? self.state.messages[fi] : self.state.messages[idx];
1559
- if (t) {
1560
- t.content = fullText;
1561
- self.host.refreshMessageBubble(fi !== -1 ? fi : idx);
1604
+ if (currentIdx === -1) {
1605
+ finish();
1606
+ return;
1562
1607
  }
1608
+ var target = self.state.messages[currentIdx];
1609
+ if (!target) {
1610
+ finish();
1611
+ return;
1612
+ }
1613
+ target.content = fullText.slice(0, i);
1614
+ self.host.refreshMessageBubble(currentIdx);
1615
+ self.host.scrollToBottomIfSticky();
1616
+ nextFrame(frame);
1617
+ }
1618
+ if (isHidden()) {
1619
+ finish();
1620
+ return;
1563
1621
  }
1564
- self.state.typing = false;
1622
+ nextFrame(frame);
1565
1623
  });
1566
1624
  }
1567
1625
  enqueueTypewrite(idx, fullText, localId) {
@@ -1875,7 +1933,7 @@ ${options.inlineContentPlaceholder}
1875
1933
  if (item.status !== "running" && item.status !== "pending") return;
1876
1934
  if (!item.poll || !item.id) return;
1877
1935
  if (self.historyItemPolls.has(item.id)) return;
1878
- if ((item.status === "running" || item.status === "pending") && self.pendingAgentRequests[self.getHistoryCacheKey()]) return;
1936
+ if (self.pendingAgentRequests[self.getHistoryCacheKey()] && !item._isBgTask && !item._isOnBgQueue) return;
1879
1937
  self.historyItemPolls.set(item.id, true);
1880
1938
  var capturedId = item.id;
1881
1939
  var pp = item.poll({
@@ -2118,7 +2176,7 @@ ${options.inlineContentPlaceholder}
2118
2176
  (function() {
2119
2177
  var MCP_PROD = "https://mcp.broadwayinc.computer";
2120
2178
  var MCP_DEV = "https://mcp-dev.broadwayinc.computer";
2121
- var BQ_VERSION = "1.4.5" ;
2179
+ var BQ_VERSION = "1.4.6" ;
2122
2180
  var ATTACHMENT_URL_EXPIRES_SECONDS = 600;
2123
2181
  var GOOGLE_AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth";
2124
2182
  var GOOGLE_TOKEN_URL = "https://oauth2.googleapis.com/token";
@@ -4851,7 +4909,6 @@ ${options.inlineContentPlaceholder}
4851
4909
  CS.settingsBtnEl = null;
4852
4910
  CS.composerEl = null;
4853
4911
  CS.gateRefreshToken += 1;
4854
- historyItemPolls.clear();
4855
4912
  if (CS.pollTimer) {
4856
4913
  clearInterval(CS.pollTimer);
4857
4914
  CS.pollTimer = null;
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
- function sleep(ms) {
1074
- return new Promise(function(r) {
1075
- setTimeout(r, ms);
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 onThisVisibleChat = self.host.isViewMounted() && self.getHistoryCacheKey() === params.key;
1164
- if (onThisVisibleChat) {
1165
- self.aiChatHistoryCache[params.key] = {
1166
- messages: existing.messages.concat([reply]),
1167
- endOfList: existing.endOfList,
1168
- startKeyHistory: existing.startKeyHistory
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
- this.state.messages.splice(nextIdx + 1, 0, { role: "assistant", content: "", isPending: true });
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 TICK_MS = 16, charsPerTick = 3, FENCE_REVEAL_MS = 200;
1548
- var fenceTicks = Math.max(1, Math.floor(FENCE_REVEAL_MS / TICK_MS));
1549
- var fenceRegions = [], m;
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) fenceRegions.push({ start: m.index, end: m.index + m[0].length });
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 ((lm = linkRegex.exec(fullText)) !== null) linkRegions.push({ start: lm.index, end: lm.index + lm[0].length });
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
- return (function loop() {
1559
- if (self.state.typingAbort || i >= fullText.length) return Promise.resolve();
1560
- var step = charsPerTick;
1561
- var region = fenceRegions.find(function(r) {
1562
- return i >= r.start && i < r.end;
1563
- });
1564
- var linkRegion = linkRegions.find(function(r) {
1565
- return i >= r.start && i < r.end;
1566
- });
1567
- if (region) step = Math.max(charsPerTick, Math.ceil((region.end - i) / fenceTicks));
1568
- else if (linkRegion) step = Math.max(charsPerTick, linkRegion.end - i);
1569
- else {
1570
- var nextLink = linkRegions.find(function(r) {
1571
- return i < r.start && i + step > r.start;
1572
- });
1573
- if (nextLink) step = nextLink.end - i;
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
- i = Math.min(fullText.length, i + step);
1576
- var currentIdx = localId ? self.state.messages.findIndex(function(mm) {
1577
- return mm._localId === localId;
1578
- }) : idx;
1579
- if (currentIdx === -1) return Promise.resolve();
1580
- var target = self.state.messages[currentIdx];
1581
- if (!target) return Promise.resolve();
1582
- target.content = fullText.slice(0, i);
1583
- self.host.refreshMessageBubble(currentIdx);
1584
- return Promise.resolve(self.host.scrollToBottomIfSticky()).then(function() {
1585
- return sleep(TICK_MS);
1586
- }).then(loop);
1587
- })().then(function() {
1588
- if (!self.state.typingAbort) {
1589
- var fi = localId ? self.state.messages.findIndex(function(mm) {
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
- var t = fi !== -1 ? self.state.messages[fi] : self.state.messages[idx];
1593
- if (t) {
1594
- t.content = fullText;
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
- self.state.typing = false;
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 ((item.status === "running" || item.status === "pending") && self.pendingAgentRequests[self.getHistoryCacheKey()]) return;
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({