bunnyquery 1.3.2 → 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 +73 -3
- package/dist/engine.cjs +74 -3
- package/dist/engine.cjs.map +1 -1
- package/dist/engine.d.mts +4 -1
- package/dist/engine.d.ts +4 -1
- package/dist/engine.mjs +74 -4
- package/dist/engine.mjs.map +1 -1
- package/package.json +1 -1
- package/src/engine/errors.ts +49 -0
- package/src/engine/index.ts +1 -1
- package/src/engine/session.ts +62 -4
package/bunnyquery.js
CHANGED
|
@@ -196,6 +196,36 @@ ${options.inlineContentPlaceholder}
|
|
|
196
196
|
}
|
|
197
197
|
return false;
|
|
198
198
|
}
|
|
199
|
+
function isNonRetryableRequestError(input) {
|
|
200
|
+
if (!input || typeof input !== "object") return false;
|
|
201
|
+
var status = typeof input.status_code === "number" ? input.status_code : typeof input.status === "number" ? input.status : void 0;
|
|
202
|
+
var param = void 0;
|
|
203
|
+
var blobs = [];
|
|
204
|
+
var sources = [input.error, input.body && input.body.error, input.body, input];
|
|
205
|
+
for (var i = 0; i < sources.length; i++) {
|
|
206
|
+
var e = sources[i];
|
|
207
|
+
if (!e) continue;
|
|
208
|
+
if (typeof e === "string") {
|
|
209
|
+
blobs.push(e);
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
if (typeof e !== "object") continue;
|
|
213
|
+
if (param === void 0 && e.param != null) param = e.param;
|
|
214
|
+
if (typeof e.code === "string") blobs.push(e.code);
|
|
215
|
+
if (typeof e.type === "string") blobs.push(e.type);
|
|
216
|
+
if (typeof e.message === "string") blobs.push(e.message);
|
|
217
|
+
}
|
|
218
|
+
var hay = blobs.join(" | ").toLowerCase();
|
|
219
|
+
if (hay.indexOf("unknown_parameter") !== -1 || hay.indexOf("unknown parameter") !== -1 || hay.indexOf("unsupported_parameter") !== -1 || hay.indexOf("unsupported parameter") !== -1) {
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
var isClientReqStatus = status === 400 || status === 422;
|
|
223
|
+
if (isClientReqStatus && param != null && param !== "") return true;
|
|
224
|
+
if (isClientReqStatus && hay.indexOf("invalid_request") !== -1 && (hay.indexOf("parameter") !== -1 || hay.indexOf("param") !== -1)) {
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
199
229
|
function isAuthExpiredError(input) {
|
|
200
230
|
if (!input) return false;
|
|
201
231
|
var blobs = [];
|
|
@@ -950,10 +980,10 @@ ${options.inlineContentPlaceholder}
|
|
|
950
980
|
});
|
|
951
981
|
};
|
|
952
982
|
var run = sendAndPoll().catch(function(err) {
|
|
953
|
-
if (isAuthExpiredError(err)) return self.host.refreshSession().then(sendAndPoll);
|
|
983
|
+
if (isAuthExpiredError(err) && !isNonRetryableRequestError(err)) return self.host.refreshSession().then(sendAndPoll);
|
|
954
984
|
throw err;
|
|
955
985
|
}).then(function(response) {
|
|
956
|
-
if (isErrorResponseBody(response) && isAuthExpiredError(response)) {
|
|
986
|
+
if (isErrorResponseBody(response) && isAuthExpiredError(response) && !isNonRetryableRequestError(response)) {
|
|
957
987
|
return self.host.refreshSession().then(sendAndPoll);
|
|
958
988
|
}
|
|
959
989
|
return response;
|
|
@@ -1191,6 +1221,7 @@ ${options.inlineContentPlaceholder}
|
|
|
1191
1221
|
this.enqueueTypewrite(aiIdx, answer, lid);
|
|
1192
1222
|
}
|
|
1193
1223
|
}
|
|
1224
|
+
this._removeStrayPendingAssistants();
|
|
1194
1225
|
this.promoteNextQueuedToRunning();
|
|
1195
1226
|
this.updateHistoryCache();
|
|
1196
1227
|
this.host.notify();
|
|
@@ -1233,6 +1264,7 @@ ${options.inlineContentPlaceholder}
|
|
|
1233
1264
|
if (thPos2 !== -1) this.state.messages.splice(thPos2, 1);
|
|
1234
1265
|
}
|
|
1235
1266
|
if (serverId) this.cancelledServerIds.delete(serverId);
|
|
1267
|
+
this._removeStrayPendingAssistants();
|
|
1236
1268
|
this.promoteNextQueuedToRunning();
|
|
1237
1269
|
this.updateHistoryCache();
|
|
1238
1270
|
this.host.notify();
|
|
@@ -1246,6 +1278,7 @@ ${options.inlineContentPlaceholder}
|
|
|
1246
1278
|
return;
|
|
1247
1279
|
}
|
|
1248
1280
|
this.insertAtTarget({ role: "assistant", content: getErrorMessage(err), isError: true }, targetIdx);
|
|
1281
|
+
this._removeStrayPendingAssistants();
|
|
1249
1282
|
this.promoteNextQueuedToRunning();
|
|
1250
1283
|
this.updateHistoryCache();
|
|
1251
1284
|
this.host.notify();
|
|
@@ -1407,16 +1440,48 @@ ${options.inlineContentPlaceholder}
|
|
|
1407
1440
|
if (pendingIdx === -1) return Promise.resolve();
|
|
1408
1441
|
if (latest.isError || !latest.content) {
|
|
1409
1442
|
this.state.messages[pendingIdx] = { role: "assistant", content: latest.content || "", isError: !!latest.isError };
|
|
1443
|
+
this._removeStrayPendingAssistants();
|
|
1410
1444
|
this.host.notify();
|
|
1411
1445
|
this.promoteNextQueuedToRunning();
|
|
1412
1446
|
return Promise.resolve();
|
|
1413
1447
|
}
|
|
1414
1448
|
var lid = this._newLocalId();
|
|
1415
1449
|
this.state.messages[pendingIdx] = { role: "assistant", content: "", isPending: false, _localId: lid };
|
|
1450
|
+
this._removeStrayPendingAssistants();
|
|
1416
1451
|
this.host.notify();
|
|
1417
1452
|
this.promoteNextQueuedToRunning();
|
|
1418
1453
|
return this.enqueueTypewrite(pendingIdx, latest.content, lid);
|
|
1419
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
|
+
}
|
|
1420
1485
|
// If an immediate-send request for the current cache key is still in flight
|
|
1421
1486
|
// (e.g. the view unmounted then remounted mid-request), show the sending
|
|
1422
1487
|
// state, await it, then render the reply from the cache. Skipped when the
|
|
@@ -1455,6 +1520,7 @@ ${options.inlineContentPlaceholder}
|
|
|
1455
1520
|
return m.isPending && m._serverItemId === itemId;
|
|
1456
1521
|
});
|
|
1457
1522
|
if (idx !== -1) {
|
|
1523
|
+
this._clearPendingUserBubble(itemId);
|
|
1458
1524
|
if (isErr) {
|
|
1459
1525
|
this.state.messages[idx] = { role: "assistant", content: answer, isError: true, _serverItemId: itemId };
|
|
1460
1526
|
this.host.notify();
|
|
@@ -1571,7 +1637,7 @@ ${options.inlineContentPlaceholder}
|
|
|
1571
1637
|
return getChatHistory({ service: serviceId, owner, platform }, options);
|
|
1572
1638
|
};
|
|
1573
1639
|
return Promise.resolve().then(fetchHistory).catch(function(err) {
|
|
1574
|
-
if (isAuthExpiredError(err)) return self.host.refreshSession().then(fetchHistory);
|
|
1640
|
+
if (isAuthExpiredError(err) && !isNonRetryableRequestError(err)) return self.host.refreshSession().then(fetchHistory);
|
|
1575
1641
|
throw err;
|
|
1576
1642
|
}).then(function(history) {
|
|
1577
1643
|
if (token !== self.state.gateRefreshToken) return;
|
|
@@ -1604,12 +1670,16 @@ ${options.inlineContentPlaceholder}
|
|
|
1604
1670
|
self.state.messages.forEach(function(m) {
|
|
1605
1671
|
if (m.isCancelled && m._serverItemId) locallyCancelled[m._serverItemId] = 1;
|
|
1606
1672
|
});
|
|
1673
|
+
var mappedHasPendingAssistant = mapped.some(function(m) {
|
|
1674
|
+
return m.isPending && m.role === "assistant" && !m.isBackgroundTask;
|
|
1675
|
+
});
|
|
1607
1676
|
var rescued = [];
|
|
1608
1677
|
for (var ri = 0; ri < self.state.messages.length; ri++) {
|
|
1609
1678
|
var mm = self.state.messages[ri];
|
|
1610
1679
|
if (mm.isBackgroundTask) continue;
|
|
1611
1680
|
if (mm._serverItemId && serverIds[mm._serverItemId]) continue;
|
|
1612
1681
|
if (!mm._serverItemId) {
|
|
1682
|
+
if (mappedHasPendingAssistant) continue;
|
|
1613
1683
|
if (mm.isSendingToServer || mm.isPendingQueued || mm.isPendingInProcess || mm.isPending) rescued.push(mm);
|
|
1614
1684
|
else if (self.state.sending && mm.role === "user") {
|
|
1615
1685
|
var next = self.state.messages[ri + 1];
|
package/dist/engine.cjs
CHANGED
|
@@ -195,6 +195,36 @@ function isErrorResponseBody(response) {
|
|
|
195
195
|
}
|
|
196
196
|
return false;
|
|
197
197
|
}
|
|
198
|
+
function isNonRetryableRequestError(input) {
|
|
199
|
+
if (!input || typeof input !== "object") return false;
|
|
200
|
+
var status = typeof input.status_code === "number" ? input.status_code : typeof input.status === "number" ? input.status : void 0;
|
|
201
|
+
var param = void 0;
|
|
202
|
+
var blobs = [];
|
|
203
|
+
var sources = [input.error, input.body && input.body.error, input.body, input];
|
|
204
|
+
for (var i = 0; i < sources.length; i++) {
|
|
205
|
+
var e = sources[i];
|
|
206
|
+
if (!e) continue;
|
|
207
|
+
if (typeof e === "string") {
|
|
208
|
+
blobs.push(e);
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
if (typeof e !== "object") continue;
|
|
212
|
+
if (param === void 0 && e.param != null) param = e.param;
|
|
213
|
+
if (typeof e.code === "string") blobs.push(e.code);
|
|
214
|
+
if (typeof e.type === "string") blobs.push(e.type);
|
|
215
|
+
if (typeof e.message === "string") blobs.push(e.message);
|
|
216
|
+
}
|
|
217
|
+
var hay = blobs.join(" | ").toLowerCase();
|
|
218
|
+
if (hay.indexOf("unknown_parameter") !== -1 || hay.indexOf("unknown parameter") !== -1 || hay.indexOf("unsupported_parameter") !== -1 || hay.indexOf("unsupported parameter") !== -1) {
|
|
219
|
+
return true;
|
|
220
|
+
}
|
|
221
|
+
var isClientReqStatus = status === 400 || status === 422;
|
|
222
|
+
if (isClientReqStatus && param != null && param !== "") return true;
|
|
223
|
+
if (isClientReqStatus && hay.indexOf("invalid_request") !== -1 && (hay.indexOf("parameter") !== -1 || hay.indexOf("param") !== -1)) {
|
|
224
|
+
return true;
|
|
225
|
+
}
|
|
226
|
+
return false;
|
|
227
|
+
}
|
|
198
228
|
function isAuthExpiredError(input) {
|
|
199
229
|
if (!input) return false;
|
|
200
230
|
var blobs = [];
|
|
@@ -977,10 +1007,10 @@ var ChatSession = class {
|
|
|
977
1007
|
});
|
|
978
1008
|
};
|
|
979
1009
|
var run = sendAndPoll().catch(function(err) {
|
|
980
|
-
if (isAuthExpiredError(err)) return self.host.refreshSession().then(sendAndPoll);
|
|
1010
|
+
if (isAuthExpiredError(err) && !isNonRetryableRequestError(err)) return self.host.refreshSession().then(sendAndPoll);
|
|
981
1011
|
throw err;
|
|
982
1012
|
}).then(function(response) {
|
|
983
|
-
if (isErrorResponseBody(response) && isAuthExpiredError(response)) {
|
|
1013
|
+
if (isErrorResponseBody(response) && isAuthExpiredError(response) && !isNonRetryableRequestError(response)) {
|
|
984
1014
|
return self.host.refreshSession().then(sendAndPoll);
|
|
985
1015
|
}
|
|
986
1016
|
return response;
|
|
@@ -1218,6 +1248,7 @@ var ChatSession = class {
|
|
|
1218
1248
|
this.enqueueTypewrite(aiIdx, answer, lid);
|
|
1219
1249
|
}
|
|
1220
1250
|
}
|
|
1251
|
+
this._removeStrayPendingAssistants();
|
|
1221
1252
|
this.promoteNextQueuedToRunning();
|
|
1222
1253
|
this.updateHistoryCache();
|
|
1223
1254
|
this.host.notify();
|
|
@@ -1260,6 +1291,7 @@ var ChatSession = class {
|
|
|
1260
1291
|
if (thPos2 !== -1) this.state.messages.splice(thPos2, 1);
|
|
1261
1292
|
}
|
|
1262
1293
|
if (serverId) this.cancelledServerIds.delete(serverId);
|
|
1294
|
+
this._removeStrayPendingAssistants();
|
|
1263
1295
|
this.promoteNextQueuedToRunning();
|
|
1264
1296
|
this.updateHistoryCache();
|
|
1265
1297
|
this.host.notify();
|
|
@@ -1273,6 +1305,7 @@ var ChatSession = class {
|
|
|
1273
1305
|
return;
|
|
1274
1306
|
}
|
|
1275
1307
|
this.insertAtTarget({ role: "assistant", content: getErrorMessage(err), isError: true }, targetIdx);
|
|
1308
|
+
this._removeStrayPendingAssistants();
|
|
1276
1309
|
this.promoteNextQueuedToRunning();
|
|
1277
1310
|
this.updateHistoryCache();
|
|
1278
1311
|
this.host.notify();
|
|
@@ -1434,16 +1467,48 @@ var ChatSession = class {
|
|
|
1434
1467
|
if (pendingIdx === -1) return Promise.resolve();
|
|
1435
1468
|
if (latest.isError || !latest.content) {
|
|
1436
1469
|
this.state.messages[pendingIdx] = { role: "assistant", content: latest.content || "", isError: !!latest.isError };
|
|
1470
|
+
this._removeStrayPendingAssistants();
|
|
1437
1471
|
this.host.notify();
|
|
1438
1472
|
this.promoteNextQueuedToRunning();
|
|
1439
1473
|
return Promise.resolve();
|
|
1440
1474
|
}
|
|
1441
1475
|
var lid = this._newLocalId();
|
|
1442
1476
|
this.state.messages[pendingIdx] = { role: "assistant", content: "", isPending: false, _localId: lid };
|
|
1477
|
+
this._removeStrayPendingAssistants();
|
|
1443
1478
|
this.host.notify();
|
|
1444
1479
|
this.promoteNextQueuedToRunning();
|
|
1445
1480
|
return this.enqueueTypewrite(pendingIdx, latest.content, lid);
|
|
1446
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
|
+
}
|
|
1447
1512
|
// If an immediate-send request for the current cache key is still in flight
|
|
1448
1513
|
// (e.g. the view unmounted then remounted mid-request), show the sending
|
|
1449
1514
|
// state, await it, then render the reply from the cache. Skipped when the
|
|
@@ -1482,6 +1547,7 @@ var ChatSession = class {
|
|
|
1482
1547
|
return m.isPending && m._serverItemId === itemId;
|
|
1483
1548
|
});
|
|
1484
1549
|
if (idx !== -1) {
|
|
1550
|
+
this._clearPendingUserBubble(itemId);
|
|
1485
1551
|
if (isErr) {
|
|
1486
1552
|
this.state.messages[idx] = { role: "assistant", content: answer, isError: true, _serverItemId: itemId };
|
|
1487
1553
|
this.host.notify();
|
|
@@ -1598,7 +1664,7 @@ var ChatSession = class {
|
|
|
1598
1664
|
return getChatHistory({ service: serviceId, owner, platform }, options);
|
|
1599
1665
|
};
|
|
1600
1666
|
return Promise.resolve().then(fetchHistory).catch(function(err) {
|
|
1601
|
-
if (isAuthExpiredError(err)) return self.host.refreshSession().then(fetchHistory);
|
|
1667
|
+
if (isAuthExpiredError(err) && !isNonRetryableRequestError(err)) return self.host.refreshSession().then(fetchHistory);
|
|
1602
1668
|
throw err;
|
|
1603
1669
|
}).then(function(history) {
|
|
1604
1670
|
if (token !== self.state.gateRefreshToken) return;
|
|
@@ -1631,12 +1697,16 @@ var ChatSession = class {
|
|
|
1631
1697
|
self.state.messages.forEach(function(m) {
|
|
1632
1698
|
if (m.isCancelled && m._serverItemId) locallyCancelled[m._serverItemId] = 1;
|
|
1633
1699
|
});
|
|
1700
|
+
var mappedHasPendingAssistant = mapped.some(function(m) {
|
|
1701
|
+
return m.isPending && m.role === "assistant" && !m.isBackgroundTask;
|
|
1702
|
+
});
|
|
1634
1703
|
var rescued = [];
|
|
1635
1704
|
for (var ri = 0; ri < self.state.messages.length; ri++) {
|
|
1636
1705
|
var mm = self.state.messages[ri];
|
|
1637
1706
|
if (mm.isBackgroundTask) continue;
|
|
1638
1707
|
if (mm._serverItemId && serverIds[mm._serverItemId]) continue;
|
|
1639
1708
|
if (!mm._serverItemId) {
|
|
1709
|
+
if (mappedHasPendingAssistant) continue;
|
|
1640
1710
|
if (mm.isSendingToServer || mm.isPendingQueued || mm.isPendingInProcess || mm.isPending) rescued.push(mm);
|
|
1641
1711
|
else if (self.state.sending && mm.role === "user") {
|
|
1642
1712
|
var next = self.state.messages[ri + 1];
|
|
@@ -1955,6 +2025,7 @@ exports.getExpiredAttachmentVisiblePath = getExpiredAttachmentVisiblePath;
|
|
|
1955
2025
|
exports.groupAttachmentFailures = groupAttachmentFailures;
|
|
1956
2026
|
exports.isAuthExpiredError = isAuthExpiredError;
|
|
1957
2027
|
exports.isErrorResponseBody = isErrorResponseBody;
|
|
2028
|
+
exports.isNonRetryableRequestError = isNonRetryableRequestError;
|
|
1958
2029
|
exports.isOfficeFile = isOfficeFile;
|
|
1959
2030
|
exports.listClaudeModels = listClaudeModels;
|
|
1960
2031
|
exports.listOpenAIModels = listOpenAIModels;
|