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/bunnyquery.js +144 -77
- package/dist/engine.cjs +143 -75
- package/dist/engine.cjs.map +1 -1
- package/dist/engine.mjs +143 -75
- package/dist/engine.mjs.map +1 -1
- package/package.json +1 -1
- package/src/engine/session.ts +185 -70
package/bunnyquery.js
CHANGED
|
@@ -1036,10 +1036,18 @@ ${options.inlineContentPlaceholder}
|
|
|
1036
1036
|
}
|
|
1037
1037
|
|
|
1038
1038
|
// src/engine/session.ts
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
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) {
|
|
@@ -1090,11 +1098,17 @@ ${options.inlineContentPlaceholder}
|
|
|
1090
1098
|
}
|
|
1091
1099
|
dispatchAgentRequest(params) {
|
|
1092
1100
|
var self = this;
|
|
1101
|
+
var dispatchItemId;
|
|
1093
1102
|
var sendAndPoll = function() {
|
|
1094
1103
|
return Promise.resolve(
|
|
1095
1104
|
self._callProviderFor(params.aiPlatform, params.text, params.boundedMessages, params.systemPrompt, params.aiModel, params.userId, params.extractContent)
|
|
1096
1105
|
).then(function(initial) {
|
|
1097
1106
|
if (initial && initial.poll && (initial.status === "pending" || initial.status === "running")) {
|
|
1107
|
+
if (initial.id) {
|
|
1108
|
+
if (dispatchItemId && dispatchItemId !== initial.id) self.historyItemPolls.delete(dispatchItemId);
|
|
1109
|
+
dispatchItemId = initial.id;
|
|
1110
|
+
self.historyItemPolls.set(initial.id, true);
|
|
1111
|
+
}
|
|
1098
1112
|
return initial.poll({ latency: POLL_INTERVAL });
|
|
1099
1113
|
}
|
|
1100
1114
|
return initial;
|
|
@@ -1117,37 +1131,29 @@ ${options.inlineContentPlaceholder}
|
|
|
1117
1131
|
return { content: getErrorMessage(err), isError: true };
|
|
1118
1132
|
}).then(function(result) {
|
|
1119
1133
|
delete self.pendingAgentRequests[params.key];
|
|
1134
|
+
if (dispatchItemId) self.historyItemPolls.delete(dispatchItemId);
|
|
1120
1135
|
var existing = self.aiChatHistoryCache[params.key] || { messages: [], endOfList: false, startKeyHistory: [] };
|
|
1121
1136
|
var reply = { role: "assistant", content: result.content, isError: result.isError };
|
|
1122
|
-
var
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
} else {
|
|
1130
|
-
var msgs = existing.messages.slice();
|
|
1131
|
-
var idx = -1;
|
|
1132
|
-
for (var i = msgs.length - 1; i >= 0; i--) {
|
|
1133
|
-
var m = msgs[i];
|
|
1134
|
-
if (m && m.isPending && m.role === "assistant" && !m.isBackgroundTask) {
|
|
1135
|
-
idx = i;
|
|
1136
|
-
break;
|
|
1137
|
-
}
|
|
1138
|
-
}
|
|
1139
|
-
if (idx !== -1) {
|
|
1140
|
-
reply._serverItemId = msgs[idx]._serverItemId;
|
|
1141
|
-
msgs[idx] = reply;
|
|
1142
|
-
} else {
|
|
1143
|
-
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;
|
|
1144
1144
|
}
|
|
1145
|
-
self.aiChatHistoryCache[params.key] = {
|
|
1146
|
-
messages: msgs,
|
|
1147
|
-
endOfList: existing.endOfList,
|
|
1148
|
-
startKeyHistory: existing.startKeyHistory
|
|
1149
|
-
};
|
|
1150
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
|
+
};
|
|
1151
1157
|
return result;
|
|
1152
1158
|
});
|
|
1153
1159
|
this.pendingAgentRequests[params.key] = run;
|
|
@@ -1200,6 +1206,7 @@ ${options.inlineContentPlaceholder}
|
|
|
1200
1206
|
self.host.notify();
|
|
1201
1207
|
}
|
|
1202
1208
|
if (result && result.poll && (result.status === "pending" || result.status === "running")) {
|
|
1209
|
+
if (serverId) self.historyItemPolls.set(serverId, true);
|
|
1203
1210
|
return result.poll({ latency: POLL_INTERVAL }).then(function(res) {
|
|
1204
1211
|
return self.onQueuedSendResponse(capturedComposed, res, capturedPlatform, serverId);
|
|
1205
1212
|
}).catch(function(err) {
|
|
@@ -1289,7 +1296,9 @@ ${options.inlineContentPlaceholder}
|
|
|
1289
1296
|
if (existing._serverItemId !== void 0) promoted._serverItemId = existing._serverItemId;
|
|
1290
1297
|
if (existing.isSendingToServer) promoted.isSendingToServer = true;
|
|
1291
1298
|
this.state.messages[nextIdx] = promoted;
|
|
1292
|
-
|
|
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);
|
|
1293
1302
|
this.host.notify();
|
|
1294
1303
|
}
|
|
1295
1304
|
resolveQueuedUserBubble(serverId) {
|
|
@@ -1339,6 +1348,7 @@ ${options.inlineContentPlaceholder}
|
|
|
1339
1348
|
else this.state.messages.push(msg);
|
|
1340
1349
|
}
|
|
1341
1350
|
onQueuedSendResponse(_composed, response, platform, serverId) {
|
|
1351
|
+
if (serverId) this.historyItemPolls.delete(serverId);
|
|
1342
1352
|
var targetIdx = this.resolveQueuedUserBubble(serverId);
|
|
1343
1353
|
if (targetIdx === void 0) {
|
|
1344
1354
|
this.host.notify();
|
|
@@ -1373,6 +1383,7 @@ ${options.inlineContentPlaceholder}
|
|
|
1373
1383
|
this.host.scrollToBottom(true);
|
|
1374
1384
|
}
|
|
1375
1385
|
onQueuedSendError(_composed, err, serverId) {
|
|
1386
|
+
if (serverId) this.historyItemPolls.delete(serverId);
|
|
1376
1387
|
var isNotExists = err && (err.code === "NOT_EXISTS" || err.body && err.body.code === "NOT_EXISTS");
|
|
1377
1388
|
if (isNotExists) {
|
|
1378
1389
|
var userIdx = serverId ? this.state.messages.findIndex(function(m) {
|
|
@@ -1497,61 +1508,118 @@ ${options.inlineContentPlaceholder}
|
|
|
1497
1508
|
});
|
|
1498
1509
|
}
|
|
1499
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.
|
|
1500
1526
|
typewriteIntoIndex(idx, fullText, localId) {
|
|
1501
1527
|
var self = this;
|
|
1502
1528
|
if (!fullText) return Promise.resolve();
|
|
1503
|
-
var
|
|
1504
|
-
var
|
|
1505
|
-
var
|
|
1529
|
+
var CHARS_PER_SEC = 300;
|
|
1530
|
+
var MIN_STEP = 1;
|
|
1531
|
+
var MAX_FRAME_MS = 1e3;
|
|
1532
|
+
var regions = [], m;
|
|
1506
1533
|
var fenceRegex = /```[\w.-]+\.[a-zA-Z0-9]+\n[\s\S]*?```/g;
|
|
1507
|
-
while ((m = fenceRegex.exec(fullText)) !== null)
|
|
1508
|
-
var linkRegions = [], lm;
|
|
1534
|
+
while ((m = fenceRegex.exec(fullText)) !== null) regions.push({ start: m.index, end: m.index + m[0].length });
|
|
1509
1535
|
var linkRegex = createInlineLinkRegex();
|
|
1510
|
-
while ((
|
|
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
|
+
});
|
|
1511
1540
|
this.state.typing = true;
|
|
1512
1541
|
this.state.typingAbort = false;
|
|
1513
1542
|
var i = 0;
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
var
|
|
1517
|
-
var
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
if (region) step = Math.max(charsPerTick, Math.ceil((region.end - i) / fenceTicks));
|
|
1524
|
-
else if (linkRegion) step = Math.max(charsPerTick, linkRegion.end - i);
|
|
1525
|
-
else {
|
|
1526
|
-
var nextLink = linkRegions.find(function(r) {
|
|
1527
|
-
return i < r.start && i + step > r.start;
|
|
1528
|
-
});
|
|
1529
|
-
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);
|
|
1530
1552
|
}
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
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) {
|
|
1546
1602
|
return mm._localId === localId;
|
|
1547
1603
|
}) : idx;
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
self.host.refreshMessageBubble(fi !== -1 ? fi : idx);
|
|
1604
|
+
if (currentIdx === -1) {
|
|
1605
|
+
finish();
|
|
1606
|
+
return;
|
|
1552
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;
|
|
1553
1621
|
}
|
|
1554
|
-
|
|
1622
|
+
nextFrame(frame);
|
|
1555
1623
|
});
|
|
1556
1624
|
}
|
|
1557
1625
|
enqueueTypewrite(idx, fullText, localId) {
|
|
@@ -1865,7 +1933,7 @@ ${options.inlineContentPlaceholder}
|
|
|
1865
1933
|
if (item.status !== "running" && item.status !== "pending") return;
|
|
1866
1934
|
if (!item.poll || !item.id) return;
|
|
1867
1935
|
if (self.historyItemPolls.has(item.id)) return;
|
|
1868
|
-
if (
|
|
1936
|
+
if (self.pendingAgentRequests[self.getHistoryCacheKey()] && !item._isBgTask && !item._isOnBgQueue) return;
|
|
1869
1937
|
self.historyItemPolls.set(item.id, true);
|
|
1870
1938
|
var capturedId = item.id;
|
|
1871
1939
|
var pp = item.poll({
|
|
@@ -2108,7 +2176,7 @@ ${options.inlineContentPlaceholder}
|
|
|
2108
2176
|
(function() {
|
|
2109
2177
|
var MCP_PROD = "https://mcp.broadwayinc.computer";
|
|
2110
2178
|
var MCP_DEV = "https://mcp-dev.broadwayinc.computer";
|
|
2111
|
-
var BQ_VERSION = "1.4.
|
|
2179
|
+
var BQ_VERSION = "1.4.6" ;
|
|
2112
2180
|
var ATTACHMENT_URL_EXPIRES_SECONDS = 600;
|
|
2113
2181
|
var GOOGLE_AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth";
|
|
2114
2182
|
var GOOGLE_TOKEN_URL = "https://oauth2.googleapis.com/token";
|
|
@@ -4841,7 +4909,6 @@ ${options.inlineContentPlaceholder}
|
|
|
4841
4909
|
CS.settingsBtnEl = null;
|
|
4842
4910
|
CS.composerEl = null;
|
|
4843
4911
|
CS.gateRefreshToken += 1;
|
|
4844
|
-
historyItemPolls.clear();
|
|
4845
4912
|
if (CS.pollTimer) {
|
|
4846
4913
|
clearInterval(CS.pollTimer);
|
|
4847
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
|
-
|
|
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) {
|
|
@@ -1124,11 +1132,17 @@ var ChatSession = class {
|
|
|
1124
1132
|
}
|
|
1125
1133
|
dispatchAgentRequest(params) {
|
|
1126
1134
|
var self = this;
|
|
1135
|
+
var dispatchItemId;
|
|
1127
1136
|
var sendAndPoll = function() {
|
|
1128
1137
|
return Promise.resolve(
|
|
1129
1138
|
self._callProviderFor(params.aiPlatform, params.text, params.boundedMessages, params.systemPrompt, params.aiModel, params.userId, params.extractContent)
|
|
1130
1139
|
).then(function(initial) {
|
|
1131
1140
|
if (initial && initial.poll && (initial.status === "pending" || initial.status === "running")) {
|
|
1141
|
+
if (initial.id) {
|
|
1142
|
+
if (dispatchItemId && dispatchItemId !== initial.id) self.historyItemPolls.delete(dispatchItemId);
|
|
1143
|
+
dispatchItemId = initial.id;
|
|
1144
|
+
self.historyItemPolls.set(initial.id, true);
|
|
1145
|
+
}
|
|
1132
1146
|
return initial.poll({ latency: POLL_INTERVAL });
|
|
1133
1147
|
}
|
|
1134
1148
|
return initial;
|
|
@@ -1151,37 +1165,29 @@ var ChatSession = class {
|
|
|
1151
1165
|
return { content: getErrorMessage(err), isError: true };
|
|
1152
1166
|
}).then(function(result) {
|
|
1153
1167
|
delete self.pendingAgentRequests[params.key];
|
|
1168
|
+
if (dispatchItemId) self.historyItemPolls.delete(dispatchItemId);
|
|
1154
1169
|
var existing = self.aiChatHistoryCache[params.key] || { messages: [], endOfList: false, startKeyHistory: [] };
|
|
1155
1170
|
var reply = { role: "assistant", content: result.content, isError: result.isError };
|
|
1156
|
-
var
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
} else {
|
|
1164
|
-
var msgs = existing.messages.slice();
|
|
1165
|
-
var idx = -1;
|
|
1166
|
-
for (var i = msgs.length - 1; i >= 0; i--) {
|
|
1167
|
-
var m = msgs[i];
|
|
1168
|
-
if (m && m.isPending && m.role === "assistant" && !m.isBackgroundTask) {
|
|
1169
|
-
idx = i;
|
|
1170
|
-
break;
|
|
1171
|
-
}
|
|
1172
|
-
}
|
|
1173
|
-
if (idx !== -1) {
|
|
1174
|
-
reply._serverItemId = msgs[idx]._serverItemId;
|
|
1175
|
-
msgs[idx] = reply;
|
|
1176
|
-
} else {
|
|
1177
|
-
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;
|
|
1178
1178
|
}
|
|
1179
|
-
self.aiChatHistoryCache[params.key] = {
|
|
1180
|
-
messages: msgs,
|
|
1181
|
-
endOfList: existing.endOfList,
|
|
1182
|
-
startKeyHistory: existing.startKeyHistory
|
|
1183
|
-
};
|
|
1184
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
|
+
};
|
|
1185
1191
|
return result;
|
|
1186
1192
|
});
|
|
1187
1193
|
this.pendingAgentRequests[params.key] = run;
|
|
@@ -1234,6 +1240,7 @@ var ChatSession = class {
|
|
|
1234
1240
|
self.host.notify();
|
|
1235
1241
|
}
|
|
1236
1242
|
if (result && result.poll && (result.status === "pending" || result.status === "running")) {
|
|
1243
|
+
if (serverId) self.historyItemPolls.set(serverId, true);
|
|
1237
1244
|
return result.poll({ latency: POLL_INTERVAL }).then(function(res) {
|
|
1238
1245
|
return self.onQueuedSendResponse(capturedComposed, res, capturedPlatform, serverId);
|
|
1239
1246
|
}).catch(function(err) {
|
|
@@ -1323,7 +1330,9 @@ var ChatSession = class {
|
|
|
1323
1330
|
if (existing._serverItemId !== void 0) promoted._serverItemId = existing._serverItemId;
|
|
1324
1331
|
if (existing.isSendingToServer) promoted.isSendingToServer = true;
|
|
1325
1332
|
this.state.messages[nextIdx] = promoted;
|
|
1326
|
-
|
|
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);
|
|
1327
1336
|
this.host.notify();
|
|
1328
1337
|
}
|
|
1329
1338
|
resolveQueuedUserBubble(serverId) {
|
|
@@ -1373,6 +1382,7 @@ var ChatSession = class {
|
|
|
1373
1382
|
else this.state.messages.push(msg);
|
|
1374
1383
|
}
|
|
1375
1384
|
onQueuedSendResponse(_composed, response, platform, serverId) {
|
|
1385
|
+
if (serverId) this.historyItemPolls.delete(serverId);
|
|
1376
1386
|
var targetIdx = this.resolveQueuedUserBubble(serverId);
|
|
1377
1387
|
if (targetIdx === void 0) {
|
|
1378
1388
|
this.host.notify();
|
|
@@ -1407,6 +1417,7 @@ var ChatSession = class {
|
|
|
1407
1417
|
this.host.scrollToBottom(true);
|
|
1408
1418
|
}
|
|
1409
1419
|
onQueuedSendError(_composed, err, serverId) {
|
|
1420
|
+
if (serverId) this.historyItemPolls.delete(serverId);
|
|
1410
1421
|
var isNotExists = err && (err.code === "NOT_EXISTS" || err.body && err.body.code === "NOT_EXISTS");
|
|
1411
1422
|
if (isNotExists) {
|
|
1412
1423
|
var userIdx = serverId ? this.state.messages.findIndex(function(m) {
|
|
@@ -1531,61 +1542,118 @@ var ChatSession = class {
|
|
|
1531
1542
|
});
|
|
1532
1543
|
}
|
|
1533
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.
|
|
1534
1560
|
typewriteIntoIndex(idx, fullText, localId) {
|
|
1535
1561
|
var self = this;
|
|
1536
1562
|
if (!fullText) return Promise.resolve();
|
|
1537
|
-
var
|
|
1538
|
-
var
|
|
1539
|
-
var
|
|
1563
|
+
var CHARS_PER_SEC = 300;
|
|
1564
|
+
var MIN_STEP = 1;
|
|
1565
|
+
var MAX_FRAME_MS = 1e3;
|
|
1566
|
+
var regions = [], m;
|
|
1540
1567
|
var fenceRegex = /```[\w.-]+\.[a-zA-Z0-9]+\n[\s\S]*?```/g;
|
|
1541
|
-
while ((m = fenceRegex.exec(fullText)) !== null)
|
|
1542
|
-
var linkRegions = [], lm;
|
|
1568
|
+
while ((m = fenceRegex.exec(fullText)) !== null) regions.push({ start: m.index, end: m.index + m[0].length });
|
|
1543
1569
|
var linkRegex = createInlineLinkRegex();
|
|
1544
|
-
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
|
+
});
|
|
1545
1574
|
this.state.typing = true;
|
|
1546
1575
|
this.state.typingAbort = false;
|
|
1547
1576
|
var i = 0;
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
var
|
|
1551
|
-
var
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
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();
|
|
1564
1608
|
}
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
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) {
|
|
1580
1636
|
return mm._localId === localId;
|
|
1581
1637
|
}) : idx;
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
self.host.refreshMessageBubble(fi !== -1 ? fi : idx);
|
|
1638
|
+
if (currentIdx === -1) {
|
|
1639
|
+
finish();
|
|
1640
|
+
return;
|
|
1586
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;
|
|
1587
1655
|
}
|
|
1588
|
-
|
|
1656
|
+
nextFrame(frame);
|
|
1589
1657
|
});
|
|
1590
1658
|
}
|
|
1591
1659
|
enqueueTypewrite(idx, fullText, localId) {
|
|
@@ -1899,7 +1967,7 @@ var ChatSession = class {
|
|
|
1899
1967
|
if (item.status !== "running" && item.status !== "pending") return;
|
|
1900
1968
|
if (!item.poll || !item.id) return;
|
|
1901
1969
|
if (self.historyItemPolls.has(item.id)) return;
|
|
1902
|
-
if (
|
|
1970
|
+
if (self.pendingAgentRequests[self.getHistoryCacheKey()] && !item._isBgTask && !item._isOnBgQueue) return;
|
|
1903
1971
|
self.historyItemPolls.set(item.id, true);
|
|
1904
1972
|
var capturedId = item.id;
|
|
1905
1973
|
var pp = item.poll({
|