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 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;