bunnyquery 1.11.0 → 1.12.1

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/dist/engine.cjs CHANGED
@@ -627,6 +627,11 @@ function getErrorMessage(input) {
627
627
  }
628
628
  return "Something went wrong.";
629
629
  }
630
+ function isRetriedFailure(input) {
631
+ var envErr = csrEnvelopeError(input);
632
+ if (envErr !== void 0) input = envErr;
633
+ return !!input && typeof input === "object" && input.retried === true;
634
+ }
630
635
  function isErrorResponseBody(response) {
631
636
  var envErr = csrEnvelopeError(response);
632
637
  if (envErr !== void 0) response = envErr;
@@ -1070,6 +1075,9 @@ function truncateLabelForDisplay(label) {
1070
1075
  var CONTEXT_WINDOW_DEFAULT = { claude: 2e5, openai: 128e3 };
1071
1076
  var CONTEXT_WINDOW_BY_MODEL = {
1072
1077
  // claude, exact ids
1078
+ "claude-fable-5-1": 1e6,
1079
+ "claude-opus-5-5": 1e6,
1080
+ "claude-sonnet-5-5": 1e6,
1073
1081
  "claude-fable-5": 1e6,
1074
1082
  "claude-opus-5": 1e6,
1075
1083
  "claude-opus-4-8": 1e6,
@@ -1083,6 +1091,9 @@ var CONTEXT_WINDOW_BY_MODEL = {
1083
1091
  "claude-haiku-4-5": 2e5,
1084
1092
  "claude-3-5-sonnet": 2e5,
1085
1093
  // openai, exact ids
1094
+ "gpt-6-astra": 105e4,
1095
+ "gpt-6-sol": 105e4,
1096
+ "gpt-6-luna": 105e4,
1086
1097
  "gpt-5.6-sol": 105e4,
1087
1098
  "gpt-5.6-terra": 105e4,
1088
1099
  "gpt-5.6-luna": 105e4,
@@ -1099,11 +1110,15 @@ var CONTEXT_WINDOW_BY_MODEL = {
1099
1110
  "claude-opus": 1e6,
1100
1111
  "claude-sonnet": 1e6,
1101
1112
  "claude-haiku": 2e5,
1113
+ "gpt-6": 105e4,
1102
1114
  "gpt-5.6": 105e4,
1103
1115
  "gpt-5": 128e3
1104
1116
  };
1105
1117
  var MAX_OUTPUT_BY_MODEL = {
1106
1118
  // claude
1119
+ "claude-fable-5-1": 128e3,
1120
+ "claude-opus-5-5": 128e3,
1121
+ "claude-sonnet-5-5": 128e3,
1107
1122
  "claude-fable-5": 128e3,
1108
1123
  "claude-opus-5": 128e3,
1109
1124
  "claude-opus-4-8": 128e3,
@@ -1112,6 +1127,9 @@ var MAX_OUTPUT_BY_MODEL = {
1112
1127
  "claude-haiku-4-5": 64e3,
1113
1128
  "claude-3-5-sonnet": 8e3,
1114
1129
  // openai
1130
+ "gpt-6-astra": 128e3,
1131
+ "gpt-6-sol": 128e3,
1132
+ "gpt-6-luna": 128e3,
1115
1133
  "gpt-5.6-sol": 128e3,
1116
1134
  "gpt-5.6-terra": 128e3,
1117
1135
  "gpt-5.6-luna": 128e3,
@@ -1128,6 +1146,7 @@ var MAX_OUTPUT_BY_MODEL = {
1128
1146
  "claude-opus": 128e3,
1129
1147
  "claude-sonnet": 64e3,
1130
1148
  "claude-haiku": 64e3,
1149
+ "gpt-6": 128e3,
1131
1150
  "gpt-5.6": 128e3,
1132
1151
  "gpt-5": 128e3
1133
1152
  };
@@ -3284,6 +3303,7 @@ function mapHistoryListToMessages(list, platform, opts) {
3284
3303
  mapped.push(ph);
3285
3304
  } else if (isQueued) ; else if (isErrorResponse) {
3286
3305
  var em = { role: "assistant", content: getErrorMessage(response), isError: true };
3306
+ if (isRetriedFailure(response)) em.isRetried = true;
3287
3307
  if (item._fromBgChain) em._fromBgChain = true;
3288
3308
  if (item._isBgTask) em.isBackgroundTask = true;
3289
3309
  if (serverItemId !== void 0) em._serverItemId = serverItemId;
@@ -4312,7 +4332,9 @@ var ChatSession = class {
4312
4332
  timers = [];
4313
4333
  };
4314
4334
  var stopBase = base && typeof base.stop === "function" ? base.stop.bind(base) : null;
4335
+ var resolveRaced = null;
4315
4336
  var raced = new Promise(function(resolve, reject) {
4337
+ resolveRaced = resolve;
4316
4338
  base.then(function(res) {
4317
4339
  if (settled) return;
4318
4340
  settled = true;
@@ -4353,9 +4375,16 @@ var ChatSession = class {
4353
4375
  });
4354
4376
  });
4355
4377
  raced.stop = function() {
4378
+ if (settled) return;
4356
4379
  settled = true;
4357
4380
  clearProbes();
4358
- if (stopBase) stopBase();
4381
+ if (stopBase) {
4382
+ try {
4383
+ stopBase();
4384
+ } catch (e) {
4385
+ }
4386
+ }
4387
+ if (resolveRaced) resolveRaced({ id: itemId, status: "stopped" });
4359
4388
  };
4360
4389
  return raced;
4361
4390
  }
@@ -5368,6 +5397,7 @@ var ChatSession = class {
5368
5397
  }
5369
5398
  return response;
5370
5399
  }).then(function(response) {
5400
+ if (isPollStopped(response) || self._isCancelledPollResult(response)) return { content: "", isError: false, cancelled: true };
5371
5401
  if (isErrorResponseBody(response)) return { content: getErrorMessage(response), isError: true };
5372
5402
  var answer = params.aiPlatform === "openai" ? extractOpenAIText(response) : extractClaudeText(response);
5373
5403
  answer = (answer || "").trim();
@@ -5377,6 +5407,10 @@ var ChatSession = class {
5377
5407
  }).then(function(result) {
5378
5408
  delete self.pendingAgentRequests[params.key];
5379
5409
  if (dispatchItemId) self.historyItemPolls.delete(dispatchItemId);
5410
+ if (result.cancelled) {
5411
+ if (dispatchItemId) self._settleCancelledTurn(dispatchItemId, params.key);
5412
+ return result;
5413
+ }
5380
5414
  var reply = { role: "assistant", content: result.content, isError: result.isError };
5381
5415
  if (dispatchItemId) reply._serverItemId = dispatchItemId;
5382
5416
  self._applyReplyToCache(params.key, reply, dispatchItemId);
@@ -5855,8 +5889,9 @@ var ChatSession = class {
5855
5889
  }
5856
5890
  });
5857
5891
  Promise.resolve(run).catch(function() {
5858
- }).then(function() {
5892
+ }).then(function(result) {
5859
5893
  self.state.sending = false;
5894
+ if (result && result.cancelled) return;
5860
5895
  if (!(self.host.isViewMounted() && self.getHistoryCacheKey() === key)) return;
5861
5896
  return Promise.resolve(self.typewriteLatestReply(key)).then(function() {
5862
5897
  self.host.scrollToBottomIfSticky(true);
@@ -6035,6 +6070,10 @@ var ChatSession = class {
6035
6070
  }
6036
6071
  onQueuedSendResponse(_composed, response, platform, serverId, ownerKey) {
6037
6072
  if (serverId) this.historyItemPolls.delete(serverId);
6073
+ if (this._isCancelledPollResult(response)) {
6074
+ if (serverId) this._settleCancelledTurn(serverId, ownerKey);
6075
+ return;
6076
+ }
6038
6077
  if (ownerKey && this.getHistoryCacheKey() !== ownerKey) {
6039
6078
  var offReply = isErrorResponseBody(response) ? { role: "assistant", content: getErrorMessage(response), isError: true } : { role: "assistant", content: ((platform === "openai" ? extractOpenAIText(response) : extractClaudeText(response)) || "").trim() || "No text response received from AI provider." };
6040
6079
  this._applyReplyToCache(ownerKey, offReply, serverId);
@@ -6234,6 +6273,191 @@ var ChatSession = class {
6234
6273
  }
6235
6274
  });
6236
6275
  }
6276
+ /**
6277
+ * Stop waiting for the reply to the chat turn that is running now, and move on.
6278
+ *
6279
+ * `msg` is the turn's pending ASSISTANT bubble (the dot-trail "Thinking"
6280
+ * placeholder), which is where both views draw the control. A turn's two bubbles
6281
+ * carry the same _serverItemId, so it is also how the request is found.
6282
+ * cancelQueuedMessage is the sibling for a turn still waiting in the queue and
6283
+ * takes the USER bubble; the two differ in what they are handed and in what has
6284
+ * to be unwound afterwards, not in what the server is asked.
6285
+ *
6286
+ * What ends the wait:
6287
+ * 1. csr-cancel marks the running row cancelled. The worker stops relaying and
6288
+ * never stores an answer for it, so the reply cannot turn up later on this
6289
+ * device or another, and history replays the turn as cancelled;
6290
+ * 2. the poll on it is stopped, which settles whichever chain was awaiting it
6291
+ * with a stopped result: dispatchAgentRequest's for an immediate send, the
6292
+ * queued chain for a promoted turn, the history poll after a reload. Each
6293
+ * reads a stopped or cancelled result as "no reply" and releases what it
6294
+ * holds (state.sending, pendingAgentRequests, historyItemPolls), which is
6295
+ * what lets the next send go out immediately instead of queueing;
6296
+ * 3. the bubbles settle at once, without waiting for that chain: the user
6297
+ * bubble takes its cancelled form, the placeholder goes, and the next queued
6298
+ * turn, if there is one, is promoted so its own "Thinking" appears.
6299
+ *
6300
+ * What it does NOT do: the provider call already in flight on the worker runs
6301
+ * to its end (a streamed one stops within about a second). A message sent
6302
+ * behind it on the same queue starts once the worker acks the cancelled row.
6303
+ *
6304
+ * Refused without a server id (the ack has not come back yet; the views disable
6305
+ * the control until it has) and while a cancel is already out. Indexing passes
6306
+ * are not this method's business: their Stop is cancelIndexingGroup, which ends
6307
+ * the file's whole chain.
6308
+ */
6309
+ cancelPendingReply(msg, idx) {
6310
+ var self = this;
6311
+ var id = this.host.getIdentity();
6312
+ var serverId = msg._serverItemId;
6313
+ if (!serverId || msg._cancelling) return;
6314
+ if (msg.role !== "assistant" || !msg.isPending || msg.isBackgroundTask) return;
6315
+ var platform = id.platform;
6316
+ if (platform !== "claude" && platform !== "openai") return;
6317
+ var url = platform === "claude" ? ANTHROPIC_MESSAGES_API_URL : OPENAI_RESPONSES_API_URL;
6318
+ var queueBase = id.userId || id.projectId;
6319
+ var queue = msg._useBgQueue ? bgIndexingQueueName(queueBase) : queueBase;
6320
+ var findPlaceholder = function() {
6321
+ return self.state.messages.findIndex(function(m) {
6322
+ return m._serverItemId === serverId && m.role === "assistant" && !!m.isPending;
6323
+ });
6324
+ };
6325
+ var at = this.state.messages[idx] && this.state.messages[idx]._serverItemId === serverId && this.state.messages[idx].role === "assistant" ? idx : findPlaceholder();
6326
+ if (at !== -1) {
6327
+ this.state.messages[at] = Object.assign({}, this.state.messages[at], { _cancelling: true, _cancelError: void 0 });
6328
+ }
6329
+ this.host.notify();
6330
+ var unmark = function(errMsg) {
6331
+ var ci = findPlaceholder();
6332
+ if (ci === -1) return;
6333
+ self.state.messages[ci] = Object.assign({}, self.state.messages[ci], { _cancelling: false, _cancelError: errMsg });
6334
+ self.host.notify();
6335
+ };
6336
+ Promise.resolve(this.host.cancelRequest({
6337
+ url,
6338
+ method: "POST",
6339
+ id: serverId,
6340
+ queue,
6341
+ service: id.projectId,
6342
+ owner: id.owner
6343
+ })).then(function(result) {
6344
+ if (result && result.removed) {
6345
+ self._stopPoll(serverId);
6346
+ self._settleCancelledTurn(serverId);
6347
+ return;
6348
+ }
6349
+ unmark(void 0);
6350
+ }).catch(function(err) {
6351
+ unmark(err && typeof err.message === "string" && err.message ? err.message : "Could not stop this request.");
6352
+ });
6353
+ }
6354
+ /** The cancelled form of a request bubble, with everything that keeps it in
6355
+ * place carried over: the file markers that hold an indexing pass in its
6356
+ * collapsed row, the chat it belongs to, its send time and its render key. */
6357
+ _cancelledCopyOf(m, itemId) {
6358
+ var cancelled = { role: "user", content: m.content, isCancelled: true };
6359
+ if (itemId !== void 0) cancelled._serverItemId = itemId;
6360
+ else if (m._serverItemId !== void 0) cancelled._serverItemId = m._serverItemId;
6361
+ if (m.isBackgroundTask) cancelled.isBackgroundTask = true;
6362
+ if (m._indexFile) cancelled._indexFile = m._indexFile;
6363
+ if (m._useBgQueue) cancelled._useBgQueue = true;
6364
+ if (m._ownerKey !== void 0) cancelled._ownerKey = m._ownerKey;
6365
+ if (m._ts !== void 0) cancelled._ts = m._ts;
6366
+ if (m._localId !== void 0) cancelled._localId = m._localId;
6367
+ return cancelled;
6368
+ }
6369
+ /**
6370
+ * Settle a turn as cancelled wherever it lives, and let the queue move on.
6371
+ *
6372
+ * On the chat on screen: every pending placeholder carrying the id goes (a
6373
+ * history refetch can have re-mapped the running turn into a second one), the
6374
+ * request bubble takes its cancelled form, and the next queued turn is promoted
6375
+ * so the conversation does not sit on an "(In queue)" bubble with nothing
6376
+ * running. For a chat that is NOT on screen (the user moved on while the turn
6377
+ * ran, and it was cancelled from elsewhere) the same edit is made in that chat's
6378
+ * history cache, which is what the next visit renders.
6379
+ *
6380
+ * Idempotent on purpose: a cancel this client made settles the bubbles at once,
6381
+ * and the chain that was awaiting the poll settles again a moment later when the
6382
+ * stop resolves it. The second pass finds nothing to do. Deliberately NOT
6383
+ * _removeStrayPendingAssistants: by then the placeholder on screen is the freshly
6384
+ * promoted turn's, whose user bubble is pending, and the sweep would take it.
6385
+ */
6386
+ _settleCancelledTurn(itemId, ownerKey) {
6387
+ if (!itemId) return;
6388
+ if (ownerKey && this.getHistoryCacheKey() !== ownerKey) {
6389
+ this._applyCancelToCache(ownerKey, itemId);
6390
+ return;
6391
+ }
6392
+ var changed = false, wasBg = false;
6393
+ for (var i = this.state.messages.length - 1; i >= 0; i--) {
6394
+ var m = this.state.messages[i];
6395
+ if (!m || m._serverItemId !== itemId) continue;
6396
+ if (m.role === "assistant" && m.isPending) {
6397
+ this.state.messages.splice(i, 1);
6398
+ changed = true;
6399
+ continue;
6400
+ }
6401
+ if (m.role === "user" && !m.isCancelled) {
6402
+ if (m.isBackgroundTask) wasBg = true;
6403
+ this.state.messages[i] = this._cancelledCopyOf(m, itemId);
6404
+ changed = true;
6405
+ }
6406
+ }
6407
+ this.cancelledServerIds.delete(itemId);
6408
+ if (!changed) return;
6409
+ if (wasBg) this.promoteNextBgQueuedToRunning();
6410
+ else this.promoteNextQueuedToRunning();
6411
+ this.updateHistoryCache();
6412
+ this.host.notify();
6413
+ }
6414
+ /**
6415
+ * _settleCancelledTurn for a chat that is not on screen: the same edit, made in
6416
+ * its history cache. Matched by id where the cached bubbles carry one; an
6417
+ * off-chat send caches its pair before the ack (see dispatchComposedMessage), so
6418
+ * the fallback is positional, exactly as _applyReplyToCache's is: the trailing
6419
+ * pending placeholder, and the last request bubble still marked in flight.
6420
+ */
6421
+ _applyCancelToCache(key, itemId) {
6422
+ var existing = key ? this.aiChatHistoryCache[key] : void 0;
6423
+ if (!existing) return;
6424
+ var msgs = existing.messages.slice();
6425
+ var changed = false;
6426
+ var pIdx = -1, uIdx = -1;
6427
+ for (var i = msgs.length - 1; i >= 0; i--) {
6428
+ var m = msgs[i];
6429
+ if (!m || m._serverItemId !== itemId) continue;
6430
+ if (m.role === "assistant" && m.isPending) {
6431
+ msgs.splice(i, 1);
6432
+ changed = true;
6433
+ pIdx = i;
6434
+ } else if (m.role === "user" && !m.isCancelled && uIdx === -1) uIdx = i;
6435
+ }
6436
+ if (pIdx === -1) {
6437
+ for (var p = msgs.length - 1; p >= 0; p--) {
6438
+ var pm = msgs[p];
6439
+ if (!pm || !pm.isPending || pm.role !== "assistant" || pm.isBackgroundTask || pm._serverItemId !== void 0) continue;
6440
+ msgs.splice(p, 1);
6441
+ changed = true;
6442
+ break;
6443
+ }
6444
+ }
6445
+ if (uIdx === -1) {
6446
+ for (var u = msgs.length - 1; u >= 0; u--) {
6447
+ var um = msgs[u];
6448
+ if (!um || um.role !== "user" || um.isBackgroundTask || um._serverItemId !== void 0 || um._stageId) continue;
6449
+ if (!(um.isPendingQueued || um.isPendingInProcess || um.isSendingToServer)) continue;
6450
+ uIdx = u;
6451
+ break;
6452
+ }
6453
+ }
6454
+ if (uIdx !== -1) {
6455
+ msgs[uIdx] = this._cancelledCopyOf(msgs[uIdx], itemId);
6456
+ changed = true;
6457
+ }
6458
+ if (!changed) return;
6459
+ this.aiChatHistoryCache[key] = { messages: msgs, endOfList: existing.endOfList, startKeyHistory: existing.startKeyHistory };
6460
+ }
6237
6461
  /**
6238
6462
  * Stop indexing a file, from its collapsed row — every pass at once, not just
6239
6463
  * the bubble the user happens to see.
@@ -6300,6 +6524,7 @@ var ChatSession = class {
6300
6524
  }
6301
6525
  }
6302
6526
  this._adoptWorkerIndexingPasses(0);
6527
+ this._sweepCancelledIndexing();
6303
6528
  var ids = group.cancellableIds || [];
6304
6529
  if (!ids.length) {
6305
6530
  this.host.notify();
@@ -6582,9 +6807,10 @@ var ChatSession = class {
6582
6807
  this.state.sending = true;
6583
6808
  this.host.scrollToBottomIfSticky(true);
6584
6809
  return Promise.resolve(pending).catch(function() {
6585
- }).then(function() {
6810
+ }).then(function(result) {
6586
6811
  if (token !== self.state.gateRefreshToken) return;
6587
6812
  self.state.sending = false;
6813
+ if (result && result.cancelled) return;
6588
6814
  return Promise.resolve(self.typewriteLatestReply(key)).then(function() {
6589
6815
  self.host.scrollToBottomIfSticky(true);
6590
6816
  });
@@ -8213,8 +8439,19 @@ function buildChatDisplayList(messages, opts) {
8213
8439
  } else if (stopped) {
8214
8440
  grp.status = "cancelled";
8215
8441
  } else {
8216
- var last = grp.members[grp.members.length - 1].msg;
8217
- grp.status = last.isError ? "error" : "done";
8442
+ var retriedIds = {};
8443
+ for (var ri = 0; ri < grp.members.length; ri++) {
8444
+ var rm = grp.members[ri].msg;
8445
+ if (rm.isRetried && rm._serverItemId) retriedIds[rm._serverItemId] = true;
8446
+ }
8447
+ var li = grp.members.length - 1;
8448
+ while (li >= 0 && (grp.members[li].msg.isRetried || grp.members[li].msg._serverItemId && retriedIds[grp.members[li].msg._serverItemId])) li--;
8449
+ if (li < 0) {
8450
+ grp.status = "active";
8451
+ } else {
8452
+ var last = grp.members[li].msg;
8453
+ grp.status = last.isError ? "error" : "done";
8454
+ }
8218
8455
  }
8219
8456
  var sawFirstPass = false;
8220
8457
  for (var pi = 0; pi < grp.members.length; pi++) {
@@ -8679,6 +8916,7 @@ exports.isOfficeFile = isOfficeFile;
8679
8916
  exports.isPagedReadFile = isPagedReadFile;
8680
8917
  exports.isPreviewableImagePath = isPreviewableImagePath;
8681
8918
  exports.isProviderApiKeyError = isProviderApiKeyError;
8919
+ exports.isRetriedFailure = isRetriedFailure;
8682
8920
  exports.isServerExtractable = isServerExtractable;
8683
8921
  exports.isServiceDbAttachmentHref = isServiceDbAttachmentHref;
8684
8922
  exports.isWindowedReadFile = isWindowedReadFile;