bunnyquery 1.3.0 → 1.3.4

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.css CHANGED
@@ -828,6 +828,13 @@
828
828
  .bq-modal-desc { margin: 0 0 1.25rem; font-size: 0.85rem; color: var(--bq-muted); line-height: 1.6; }
829
829
  .bq-modal-btns { display: flex; gap: 0.75rem; justify-content: flex-end; align-items: center; }
830
830
 
831
+ /* upload error report dialog (failed files grouped by error) */
832
+ .bq-upload-error-list { display: flex; flex-direction: column; gap: 0.85rem; margin: 0 0 1.25rem; max-height: 50vh; overflow-y: auto; }
833
+ .bq-upload-error-group { border-left: 3px solid var(--bq-danger); padding-left: 0.7rem; }
834
+ .bq-upload-error-heading { margin: 0 0 0.3rem; font-size: 0.82rem; font-weight: 600; color: var(--bq-danger); word-break: break-word; }
835
+ .bq-upload-error-files { margin: 0; padding-left: 1.1rem; font-size: 0.8rem; color: var(--bq-ink); }
836
+ .bq-upload-error-files li { margin: 0.1rem 0; word-break: break-word; }
837
+
831
838
  /* delete/clear (danger) modal accents */
832
839
  .bq-modal-delete-header {
833
840
  display: flex;
package/bunnyquery.js CHANGED
@@ -80,6 +80,28 @@ Extracted content of attached office files (read inline below; do NOT fetch thei
80
80
  return { composed, composedForLlm, extractContent };
81
81
  }
82
82
 
83
+ // src/engine/attachments.ts
84
+ function groupAttachmentFailures(attachments) {
85
+ const groups = {};
86
+ const order = [];
87
+ (attachments || []).forEach(function(att) {
88
+ if (!att || att.status !== "error" && att.status !== "indexError") return;
89
+ const code = String(att.errorCode || "");
90
+ const message = String(
91
+ att.errorDetail || att.errorMessage || (att.status === "indexError" ? "File indexing failed" : "File upload has failed")
92
+ );
93
+ const key = code + "\0" + message;
94
+ if (!groups[key]) {
95
+ groups[key] = { code, message, files: [] };
96
+ order.push(key);
97
+ }
98
+ groups[key].files.push(String(att.name || "(unnamed file)"));
99
+ });
100
+ return order.map(function(k) {
101
+ return groups[k];
102
+ });
103
+ }
104
+
83
105
  // src/engine/prompts/chat_system_prompt.ts
84
106
  function buildChatSystemPrompt(params) {
85
107
  const { formattedServiceId, serviceName, serviceDescription } = params;
@@ -174,6 +196,36 @@ ${options.inlineContentPlaceholder}
174
196
  }
175
197
  return false;
176
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
+ }
177
229
  function isAuthExpiredError(input) {
178
230
  if (!input) return false;
179
231
  var blobs = [];
@@ -928,10 +980,10 @@ ${options.inlineContentPlaceholder}
928
980
  });
929
981
  };
930
982
  var run = sendAndPoll().catch(function(err) {
931
- if (isAuthExpiredError(err)) return self.host.refreshSession().then(sendAndPoll);
983
+ if (isAuthExpiredError(err) && !isNonRetryableRequestError(err)) return self.host.refreshSession().then(sendAndPoll);
932
984
  throw err;
933
985
  }).then(function(response) {
934
- if (isErrorResponseBody(response) && isAuthExpiredError(response)) {
986
+ if (isErrorResponseBody(response) && isAuthExpiredError(response) && !isNonRetryableRequestError(response)) {
935
987
  return self.host.refreshSession().then(sendAndPoll);
936
988
  }
937
989
  return response;
@@ -1549,7 +1601,7 @@ ${options.inlineContentPlaceholder}
1549
1601
  return getChatHistory({ service: serviceId, owner, platform }, options);
1550
1602
  };
1551
1603
  return Promise.resolve().then(fetchHistory).catch(function(err) {
1552
- if (isAuthExpiredError(err)) return self.host.refreshSession().then(fetchHistory);
1604
+ if (isAuthExpiredError(err) && !isNonRetryableRequestError(err)) return self.host.refreshSession().then(fetchHistory);
1553
1605
  throw err;
1554
1606
  }).then(function(history) {
1555
1607
  if (token !== self.state.gateRefreshToken) return;
@@ -1696,6 +1748,8 @@ ${options.inlineContentPlaceholder}
1696
1748
  att.status = "uploading";
1697
1749
  att.progress = 0;
1698
1750
  att.errorMessage = "";
1751
+ att.errorCode = "";
1752
+ att.errorDetail = "";
1699
1753
  this.host.renderAttachmentChips();
1700
1754
  var members = att.kind === "folder" ? (att.files || []).map(function(f) {
1701
1755
  return { file: f.file, relPath: f.path, storagePath: self.host.storagePathFor(f.path) };
@@ -1777,6 +1831,10 @@ ${options.inlineContentPlaceholder}
1777
1831
  }, function(e) {
1778
1832
  console.error("[chat-engine] indexing request failed", e);
1779
1833
  anyIndexFailed = true;
1834
+ if (!att.errorCode && !att.errorDetail) {
1835
+ att.errorCode = e && (e.code || e.body && e.body.code) || "";
1836
+ att.errorDetail = e && (e.message || e.body && e.body.message) || (typeof e === "string" ? e : "");
1837
+ }
1780
1838
  });
1781
1839
  });
1782
1840
  });
@@ -1831,6 +1889,8 @@ ${options.inlineContentPlaceholder}
1831
1889
  if (removed || aborted) return;
1832
1890
  att.status = "error";
1833
1891
  att.errorMessage = "File upload has failed";
1892
+ att.errorCode = err && (err.code || err.body && err.body.code) || "";
1893
+ att.errorDetail = err && (err.message || err.body && err.body.message) || (typeof err === "string" ? err : "");
1834
1894
  self.host.renderAttachmentChips();
1835
1895
  });
1836
1896
  });
@@ -3561,10 +3621,13 @@ ${options.inlineContentPlaceholder}
3561
3621
  var bgBefore = bgTaskQueue.length;
3562
3622
  session.uploadPendingAttachments().then(function(attachmentUrls) {
3563
3623
  var hasNewIndexing = bgTaskQueue.length > bgBefore;
3624
+ var failureGroups = groupAttachmentFailures(CS.attachments);
3564
3625
  clearSuccessfulAttachments();
3565
- if (!text) return;
3566
- var c = composeUserMessage(text, attachmentUrls);
3567
- session.dispatchComposedMessage(c.composed, hasNewIndexing, c.composedForLlm, c.extractContent);
3626
+ if (text) {
3627
+ var c = composeUserMessage(text, attachmentUrls);
3628
+ session.dispatchComposedMessage(c.composed, hasNewIndexing, c.composedForLlm, c.extractContent);
3629
+ }
3630
+ if (failureGroups.length) showUploadErrorReport(failureGroups);
3568
3631
  }).catch(function(err) {
3569
3632
  console.error("[bunnyquery] attachment upload failed", err);
3570
3633
  CS.uploadingAttachments = false;
@@ -4730,6 +4793,45 @@ ${options.inlineContentPlaceholder}
4730
4793
  }, { dismissible: false });
4731
4794
  });
4732
4795
  }
4796
+ function showUploadErrorReport(groups) {
4797
+ if (!groups || !groups.length) return;
4798
+ var totalFiles = groups.reduce(function(n, g) {
4799
+ return n + g.files.length;
4800
+ }, 0);
4801
+ openModal(function(close) {
4802
+ var sections = groups.map(function(g) {
4803
+ var heading = g.code ? g.code + " \u2014 " + g.message : g.message;
4804
+ return h(
4805
+ "div",
4806
+ { class: "bq-upload-error-group" },
4807
+ h("p", { class: "bq-upload-error-heading", text: heading }),
4808
+ h(
4809
+ "ul",
4810
+ { class: "bq-upload-error-files" },
4811
+ g.files.map(function(name) {
4812
+ return h("li", { text: name });
4813
+ })
4814
+ )
4815
+ );
4816
+ });
4817
+ return h(
4818
+ "div",
4819
+ { class: "bq-modal" },
4820
+ h(
4821
+ "div",
4822
+ { class: "bq-modal-delete-header" },
4823
+ h("span", { text: totalFiles === 1 ? "1 file could not be added" : totalFiles + " files could not be added" })
4824
+ ),
4825
+ h("p", { class: "bq-modal-desc", text: "These files were not added to your message. They stay in the attachment row so you can remove or retry them." }),
4826
+ h("div", { class: "bq-upload-error-list" }, sections),
4827
+ h(
4828
+ "div",
4829
+ { class: "bq-modal-btns" },
4830
+ h("button", { class: "btn btn--outline", type: "button", onclick: close }, "Close")
4831
+ )
4832
+ );
4833
+ });
4834
+ }
4733
4835
  function agentBadgeText() {
4734
4836
  if (S.aiPlatform === "none") return "No agent configured";
4735
4837
  return S.serviceName ? "BunnyQuery \xB7 " + S.serviceName : "BunnyQuery";
package/dist/engine.cjs CHANGED
@@ -79,6 +79,28 @@ Extracted content of attached office files (read inline below; do NOT fetch thei
79
79
  return { composed, composedForLlm, extractContent };
80
80
  }
81
81
 
82
+ // src/engine/attachments.ts
83
+ function groupAttachmentFailures(attachments) {
84
+ const groups = {};
85
+ const order = [];
86
+ (attachments || []).forEach(function(att) {
87
+ if (!att || att.status !== "error" && att.status !== "indexError") return;
88
+ const code = String(att.errorCode || "");
89
+ const message = String(
90
+ att.errorDetail || att.errorMessage || (att.status === "indexError" ? "File indexing failed" : "File upload has failed")
91
+ );
92
+ const key = code + "\0" + message;
93
+ if (!groups[key]) {
94
+ groups[key] = { code, message, files: [] };
95
+ order.push(key);
96
+ }
97
+ groups[key].files.push(String(att.name || "(unnamed file)"));
98
+ });
99
+ return order.map(function(k) {
100
+ return groups[k];
101
+ });
102
+ }
103
+
82
104
  // src/engine/prompts/chat_system_prompt.ts
83
105
  function buildChatSystemPrompt(params) {
84
106
  const { formattedServiceId, serviceName, serviceDescription } = params;
@@ -173,6 +195,36 @@ function isErrorResponseBody(response) {
173
195
  }
174
196
  return false;
175
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
+ }
176
228
  function isAuthExpiredError(input) {
177
229
  if (!input) return false;
178
230
  var blobs = [];
@@ -955,10 +1007,10 @@ var ChatSession = class {
955
1007
  });
956
1008
  };
957
1009
  var run = sendAndPoll().catch(function(err) {
958
- if (isAuthExpiredError(err)) return self.host.refreshSession().then(sendAndPoll);
1010
+ if (isAuthExpiredError(err) && !isNonRetryableRequestError(err)) return self.host.refreshSession().then(sendAndPoll);
959
1011
  throw err;
960
1012
  }).then(function(response) {
961
- if (isErrorResponseBody(response) && isAuthExpiredError(response)) {
1013
+ if (isErrorResponseBody(response) && isAuthExpiredError(response) && !isNonRetryableRequestError(response)) {
962
1014
  return self.host.refreshSession().then(sendAndPoll);
963
1015
  }
964
1016
  return response;
@@ -1576,7 +1628,7 @@ var ChatSession = class {
1576
1628
  return getChatHistory({ service: serviceId, owner, platform }, options);
1577
1629
  };
1578
1630
  return Promise.resolve().then(fetchHistory).catch(function(err) {
1579
- if (isAuthExpiredError(err)) return self.host.refreshSession().then(fetchHistory);
1631
+ if (isAuthExpiredError(err) && !isNonRetryableRequestError(err)) return self.host.refreshSession().then(fetchHistory);
1580
1632
  throw err;
1581
1633
  }).then(function(history) {
1582
1634
  if (token !== self.state.gateRefreshToken) return;
@@ -1723,6 +1775,8 @@ var ChatSession = class {
1723
1775
  att.status = "uploading";
1724
1776
  att.progress = 0;
1725
1777
  att.errorMessage = "";
1778
+ att.errorCode = "";
1779
+ att.errorDetail = "";
1726
1780
  this.host.renderAttachmentChips();
1727
1781
  var members = att.kind === "folder" ? (att.files || []).map(function(f) {
1728
1782
  return { file: f.file, relPath: f.path, storagePath: self.host.storagePathFor(f.path) };
@@ -1804,6 +1858,10 @@ var ChatSession = class {
1804
1858
  }, function(e) {
1805
1859
  console.error("[chat-engine] indexing request failed", e);
1806
1860
  anyIndexFailed = true;
1861
+ if (!att.errorCode && !att.errorDetail) {
1862
+ att.errorCode = e && (e.code || e.body && e.body.code) || "";
1863
+ att.errorDetail = e && (e.message || e.body && e.body.message) || (typeof e === "string" ? e : "");
1864
+ }
1807
1865
  });
1808
1866
  });
1809
1867
  });
@@ -1858,6 +1916,8 @@ var ChatSession = class {
1858
1916
  if (removed || aborted) return;
1859
1917
  att.status = "error";
1860
1918
  att.errorMessage = "File upload has failed";
1919
+ att.errorCode = err && (err.code || err.body && err.body.code) || "";
1920
+ att.errorDetail = err && (err.message || err.body && err.body.message) || (typeof err === "string" ? err : "");
1861
1921
  self.host.renderAttachmentChips();
1862
1922
  });
1863
1923
  });
@@ -1922,8 +1982,10 @@ exports.getChatHistory = getChatHistory;
1922
1982
  exports.getContextWindow = getContextWindow;
1923
1983
  exports.getErrorMessage = getErrorMessage;
1924
1984
  exports.getExpiredAttachmentVisiblePath = getExpiredAttachmentVisiblePath;
1985
+ exports.groupAttachmentFailures = groupAttachmentFailures;
1925
1986
  exports.isAuthExpiredError = isAuthExpiredError;
1926
1987
  exports.isErrorResponseBody = isErrorResponseBody;
1988
+ exports.isNonRetryableRequestError = isNonRetryableRequestError;
1927
1989
  exports.isOfficeFile = isOfficeFile;
1928
1990
  exports.listClaudeModels = listClaudeModels;
1929
1991
  exports.listOpenAIModels = listOpenAIModels;