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 +7 -0
- package/bunnyquery.js +108 -6
- package/dist/engine.cjs +65 -3
- package/dist/engine.cjs.map +1 -1
- package/dist/engine.d.mts +23 -1
- package/dist/engine.d.ts +23 -1
- package/dist/engine.mjs +64 -4
- package/dist/engine.mjs.map +1 -1
- package/package.json +1 -1
- package/src/engine/attachments.ts +0 -0
- package/src/engine/errors.ts +49 -0
- package/src/engine/index.ts +6 -1
- package/src/engine/session.ts +17 -4
- package/src/widget.css +7 -0
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 (
|
|
3566
|
-
|
|
3567
|
-
|
|
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;
|