bunnyquery 1.3.4 → 1.3.5
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 +40 -0
- package/dist/engine.cjs +40 -0
- package/dist/engine.cjs.map +1 -1
- package/dist/engine.d.mts +2 -0
- package/dist/engine.d.ts +2 -0
- package/dist/engine.mjs +40 -0
- package/dist/engine.mjs.map +1 -1
- package/package.json +1 -1
- package/src/engine/session.ts +54 -0
package/bunnyquery.js
CHANGED
|
@@ -1221,6 +1221,7 @@ ${options.inlineContentPlaceholder}
|
|
|
1221
1221
|
this.enqueueTypewrite(aiIdx, answer, lid);
|
|
1222
1222
|
}
|
|
1223
1223
|
}
|
|
1224
|
+
this._removeStrayPendingAssistants();
|
|
1224
1225
|
this.promoteNextQueuedToRunning();
|
|
1225
1226
|
this.updateHistoryCache();
|
|
1226
1227
|
this.host.notify();
|
|
@@ -1263,6 +1264,7 @@ ${options.inlineContentPlaceholder}
|
|
|
1263
1264
|
if (thPos2 !== -1) this.state.messages.splice(thPos2, 1);
|
|
1264
1265
|
}
|
|
1265
1266
|
if (serverId) this.cancelledServerIds.delete(serverId);
|
|
1267
|
+
this._removeStrayPendingAssistants();
|
|
1266
1268
|
this.promoteNextQueuedToRunning();
|
|
1267
1269
|
this.updateHistoryCache();
|
|
1268
1270
|
this.host.notify();
|
|
@@ -1276,6 +1278,7 @@ ${options.inlineContentPlaceholder}
|
|
|
1276
1278
|
return;
|
|
1277
1279
|
}
|
|
1278
1280
|
this.insertAtTarget({ role: "assistant", content: getErrorMessage(err), isError: true }, targetIdx);
|
|
1281
|
+
this._removeStrayPendingAssistants();
|
|
1279
1282
|
this.promoteNextQueuedToRunning();
|
|
1280
1283
|
this.updateHistoryCache();
|
|
1281
1284
|
this.host.notify();
|
|
@@ -1437,16 +1440,48 @@ ${options.inlineContentPlaceholder}
|
|
|
1437
1440
|
if (pendingIdx === -1) return Promise.resolve();
|
|
1438
1441
|
if (latest.isError || !latest.content) {
|
|
1439
1442
|
this.state.messages[pendingIdx] = { role: "assistant", content: latest.content || "", isError: !!latest.isError };
|
|
1443
|
+
this._removeStrayPendingAssistants();
|
|
1440
1444
|
this.host.notify();
|
|
1441
1445
|
this.promoteNextQueuedToRunning();
|
|
1442
1446
|
return Promise.resolve();
|
|
1443
1447
|
}
|
|
1444
1448
|
var lid = this._newLocalId();
|
|
1445
1449
|
this.state.messages[pendingIdx] = { role: "assistant", content: "", isPending: false, _localId: lid };
|
|
1450
|
+
this._removeStrayPendingAssistants();
|
|
1446
1451
|
this.host.notify();
|
|
1447
1452
|
this.promoteNextQueuedToRunning();
|
|
1448
1453
|
return this.enqueueTypewrite(pendingIdx, latest.content, lid);
|
|
1449
1454
|
}
|
|
1455
|
+
// Remove any leftover non-background pending ("Thinking…") assistant bubbles.
|
|
1456
|
+
// There is normally at most ONE such bubble at a time (promoteNext* refuses to
|
|
1457
|
+
// add a second), so any extra is a duplicate — it appears when a concurrent
|
|
1458
|
+
// history refetch re-maps the still-"running" turn into a pending placeholder
|
|
1459
|
+
// (with a real _serverItemId) while the local pending bubble (no _serverItemId)
|
|
1460
|
+
// is rescued and re-appended (see loadHistory rescue below). Each resolve path
|
|
1461
|
+
// only replaces the FIRST pending bubble, so without this a stray "Thinking…"
|
|
1462
|
+
// survives next to the reply/error. MUST run AFTER the resolved bubble has been
|
|
1463
|
+
// made non-pending and BEFORE promoteNext*() (so a freshly-promoted Thinking,
|
|
1464
|
+
// which is added only once no pending assistant remains, is preserved).
|
|
1465
|
+
_removeStrayPendingAssistants() {
|
|
1466
|
+
for (var k = this.state.messages.length - 1; k >= 0; k--) {
|
|
1467
|
+
var m = this.state.messages[k];
|
|
1468
|
+
if (m.isPending && m.role === "assistant" && !m.isBackgroundTask) this.state.messages.splice(k, 1);
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
// Drop the pending flags on the resolved turn's USER bubble (preserving its
|
|
1472
|
+
// content + background-task marker). Needed because a bg "Indexing:" turn's user
|
|
1473
|
+
// bubble carries isPendingInProcess; leaving it set keeps the bubble visually
|
|
1474
|
+
// stuck and keeps its bgTaskQueue entry alive forever.
|
|
1475
|
+
_clearPendingUserBubble(itemId) {
|
|
1476
|
+
var uIdx = this.state.messages.findIndex(function(m) {
|
|
1477
|
+
return m.role === "user" && m._serverItemId === itemId && (m.isPendingInProcess || m.isPendingQueued || m.isSendingToServer);
|
|
1478
|
+
});
|
|
1479
|
+
if (uIdx === -1) return;
|
|
1480
|
+
var u = this.state.messages[uIdx];
|
|
1481
|
+
var cleaned = { role: "user", content: u.content, _serverItemId: itemId };
|
|
1482
|
+
if (u.isBackgroundTask) cleaned.isBackgroundTask = true;
|
|
1483
|
+
this.state.messages[uIdx] = cleaned;
|
|
1484
|
+
}
|
|
1450
1485
|
// If an immediate-send request for the current cache key is still in flight
|
|
1451
1486
|
// (e.g. the view unmounted then remounted mid-request), show the sending
|
|
1452
1487
|
// state, await it, then render the reply from the cache. Skipped when the
|
|
@@ -1485,6 +1520,7 @@ ${options.inlineContentPlaceholder}
|
|
|
1485
1520
|
return m.isPending && m._serverItemId === itemId;
|
|
1486
1521
|
});
|
|
1487
1522
|
if (idx !== -1) {
|
|
1523
|
+
this._clearPendingUserBubble(itemId);
|
|
1488
1524
|
if (isErr) {
|
|
1489
1525
|
this.state.messages[idx] = { role: "assistant", content: answer, isError: true, _serverItemId: itemId };
|
|
1490
1526
|
this.host.notify();
|
|
@@ -1634,12 +1670,16 @@ ${options.inlineContentPlaceholder}
|
|
|
1634
1670
|
self.state.messages.forEach(function(m) {
|
|
1635
1671
|
if (m.isCancelled && m._serverItemId) locallyCancelled[m._serverItemId] = 1;
|
|
1636
1672
|
});
|
|
1673
|
+
var mappedHasPendingAssistant = mapped.some(function(m) {
|
|
1674
|
+
return m.isPending && m.role === "assistant" && !m.isBackgroundTask;
|
|
1675
|
+
});
|
|
1637
1676
|
var rescued = [];
|
|
1638
1677
|
for (var ri = 0; ri < self.state.messages.length; ri++) {
|
|
1639
1678
|
var mm = self.state.messages[ri];
|
|
1640
1679
|
if (mm.isBackgroundTask) continue;
|
|
1641
1680
|
if (mm._serverItemId && serverIds[mm._serverItemId]) continue;
|
|
1642
1681
|
if (!mm._serverItemId) {
|
|
1682
|
+
if (mappedHasPendingAssistant) continue;
|
|
1643
1683
|
if (mm.isSendingToServer || mm.isPendingQueued || mm.isPendingInProcess || mm.isPending) rescued.push(mm);
|
|
1644
1684
|
else if (self.state.sending && mm.role === "user") {
|
|
1645
1685
|
var next = self.state.messages[ri + 1];
|
package/dist/engine.cjs
CHANGED
|
@@ -1248,6 +1248,7 @@ var ChatSession = class {
|
|
|
1248
1248
|
this.enqueueTypewrite(aiIdx, answer, lid);
|
|
1249
1249
|
}
|
|
1250
1250
|
}
|
|
1251
|
+
this._removeStrayPendingAssistants();
|
|
1251
1252
|
this.promoteNextQueuedToRunning();
|
|
1252
1253
|
this.updateHistoryCache();
|
|
1253
1254
|
this.host.notify();
|
|
@@ -1290,6 +1291,7 @@ var ChatSession = class {
|
|
|
1290
1291
|
if (thPos2 !== -1) this.state.messages.splice(thPos2, 1);
|
|
1291
1292
|
}
|
|
1292
1293
|
if (serverId) this.cancelledServerIds.delete(serverId);
|
|
1294
|
+
this._removeStrayPendingAssistants();
|
|
1293
1295
|
this.promoteNextQueuedToRunning();
|
|
1294
1296
|
this.updateHistoryCache();
|
|
1295
1297
|
this.host.notify();
|
|
@@ -1303,6 +1305,7 @@ var ChatSession = class {
|
|
|
1303
1305
|
return;
|
|
1304
1306
|
}
|
|
1305
1307
|
this.insertAtTarget({ role: "assistant", content: getErrorMessage(err), isError: true }, targetIdx);
|
|
1308
|
+
this._removeStrayPendingAssistants();
|
|
1306
1309
|
this.promoteNextQueuedToRunning();
|
|
1307
1310
|
this.updateHistoryCache();
|
|
1308
1311
|
this.host.notify();
|
|
@@ -1464,16 +1467,48 @@ var ChatSession = class {
|
|
|
1464
1467
|
if (pendingIdx === -1) return Promise.resolve();
|
|
1465
1468
|
if (latest.isError || !latest.content) {
|
|
1466
1469
|
this.state.messages[pendingIdx] = { role: "assistant", content: latest.content || "", isError: !!latest.isError };
|
|
1470
|
+
this._removeStrayPendingAssistants();
|
|
1467
1471
|
this.host.notify();
|
|
1468
1472
|
this.promoteNextQueuedToRunning();
|
|
1469
1473
|
return Promise.resolve();
|
|
1470
1474
|
}
|
|
1471
1475
|
var lid = this._newLocalId();
|
|
1472
1476
|
this.state.messages[pendingIdx] = { role: "assistant", content: "", isPending: false, _localId: lid };
|
|
1477
|
+
this._removeStrayPendingAssistants();
|
|
1473
1478
|
this.host.notify();
|
|
1474
1479
|
this.promoteNextQueuedToRunning();
|
|
1475
1480
|
return this.enqueueTypewrite(pendingIdx, latest.content, lid);
|
|
1476
1481
|
}
|
|
1482
|
+
// Remove any leftover non-background pending ("Thinking…") assistant bubbles.
|
|
1483
|
+
// There is normally at most ONE such bubble at a time (promoteNext* refuses to
|
|
1484
|
+
// add a second), so any extra is a duplicate — it appears when a concurrent
|
|
1485
|
+
// history refetch re-maps the still-"running" turn into a pending placeholder
|
|
1486
|
+
// (with a real _serverItemId) while the local pending bubble (no _serverItemId)
|
|
1487
|
+
// is rescued and re-appended (see loadHistory rescue below). Each resolve path
|
|
1488
|
+
// only replaces the FIRST pending bubble, so without this a stray "Thinking…"
|
|
1489
|
+
// survives next to the reply/error. MUST run AFTER the resolved bubble has been
|
|
1490
|
+
// made non-pending and BEFORE promoteNext*() (so a freshly-promoted Thinking,
|
|
1491
|
+
// which is added only once no pending assistant remains, is preserved).
|
|
1492
|
+
_removeStrayPendingAssistants() {
|
|
1493
|
+
for (var k = this.state.messages.length - 1; k >= 0; k--) {
|
|
1494
|
+
var m = this.state.messages[k];
|
|
1495
|
+
if (m.isPending && m.role === "assistant" && !m.isBackgroundTask) this.state.messages.splice(k, 1);
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
// Drop the pending flags on the resolved turn's USER bubble (preserving its
|
|
1499
|
+
// content + background-task marker). Needed because a bg "Indexing:" turn's user
|
|
1500
|
+
// bubble carries isPendingInProcess; leaving it set keeps the bubble visually
|
|
1501
|
+
// stuck and keeps its bgTaskQueue entry alive forever.
|
|
1502
|
+
_clearPendingUserBubble(itemId) {
|
|
1503
|
+
var uIdx = this.state.messages.findIndex(function(m) {
|
|
1504
|
+
return m.role === "user" && m._serverItemId === itemId && (m.isPendingInProcess || m.isPendingQueued || m.isSendingToServer);
|
|
1505
|
+
});
|
|
1506
|
+
if (uIdx === -1) return;
|
|
1507
|
+
var u = this.state.messages[uIdx];
|
|
1508
|
+
var cleaned = { role: "user", content: u.content, _serverItemId: itemId };
|
|
1509
|
+
if (u.isBackgroundTask) cleaned.isBackgroundTask = true;
|
|
1510
|
+
this.state.messages[uIdx] = cleaned;
|
|
1511
|
+
}
|
|
1477
1512
|
// If an immediate-send request for the current cache key is still in flight
|
|
1478
1513
|
// (e.g. the view unmounted then remounted mid-request), show the sending
|
|
1479
1514
|
// state, await it, then render the reply from the cache. Skipped when the
|
|
@@ -1512,6 +1547,7 @@ var ChatSession = class {
|
|
|
1512
1547
|
return m.isPending && m._serverItemId === itemId;
|
|
1513
1548
|
});
|
|
1514
1549
|
if (idx !== -1) {
|
|
1550
|
+
this._clearPendingUserBubble(itemId);
|
|
1515
1551
|
if (isErr) {
|
|
1516
1552
|
this.state.messages[idx] = { role: "assistant", content: answer, isError: true, _serverItemId: itemId };
|
|
1517
1553
|
this.host.notify();
|
|
@@ -1661,12 +1697,16 @@ var ChatSession = class {
|
|
|
1661
1697
|
self.state.messages.forEach(function(m) {
|
|
1662
1698
|
if (m.isCancelled && m._serverItemId) locallyCancelled[m._serverItemId] = 1;
|
|
1663
1699
|
});
|
|
1700
|
+
var mappedHasPendingAssistant = mapped.some(function(m) {
|
|
1701
|
+
return m.isPending && m.role === "assistant" && !m.isBackgroundTask;
|
|
1702
|
+
});
|
|
1664
1703
|
var rescued = [];
|
|
1665
1704
|
for (var ri = 0; ri < self.state.messages.length; ri++) {
|
|
1666
1705
|
var mm = self.state.messages[ri];
|
|
1667
1706
|
if (mm.isBackgroundTask) continue;
|
|
1668
1707
|
if (mm._serverItemId && serverIds[mm._serverItemId]) continue;
|
|
1669
1708
|
if (!mm._serverItemId) {
|
|
1709
|
+
if (mappedHasPendingAssistant) continue;
|
|
1670
1710
|
if (mm.isSendingToServer || mm.isPendingQueued || mm.isPendingInProcess || mm.isPending) rescued.push(mm);
|
|
1671
1711
|
else if (self.state.sending && mm.role === "user") {
|
|
1672
1712
|
var next = self.state.messages[ri + 1];
|