bunnyquery 1.8.6 → 1.8.9
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 +95 -5
- package/bunnyquery.js +1470 -111
- package/dist/engine.cjs +1071 -80
- package/dist/engine.cjs.map +1 -1
- package/dist/engine.d.mts +608 -169
- package/dist/engine.d.ts +608 -169
- package/dist/engine.mjs +1048 -81
- package/dist/engine.mjs.map +1 -1
- package/package.json +1 -1
- package/src/engine/budget.ts +207 -68
- package/src/engine/config.ts +48 -0
- package/src/engine/errors.ts +38 -0
- package/src/engine/history.ts +546 -6
- package/src/engine/host.ts +7 -0
- package/src/engine/image_preview.ts +0 -0
- package/src/engine/index.ts +15 -1
- package/src/engine/indexing_groups.ts +248 -3
- package/src/engine/links.ts +143 -6
- package/src/engine/office.ts +24 -1
- package/src/engine/prompts/chat_system_prompt.ts +1 -1
- package/src/engine/requests.ts +164 -11
- package/src/engine/session.ts +544 -35
- package/src/widget.css +35 -1
- package/styles/chat.css +60 -4
package/dist/engine.cjs
CHANGED
|
@@ -217,7 +217,8 @@ function isWindowedReadFile(name, mime) {
|
|
|
217
217
|
if (isImageVisionFile(name, mime)) return false;
|
|
218
218
|
return isPagedReadFile(name, mime);
|
|
219
219
|
}
|
|
220
|
-
function composeUserMessage(text, attachmentUrls) {
|
|
220
|
+
function composeUserMessage(text, attachmentUrls, opts) {
|
|
221
|
+
const inlineExtracted = opts?.inlineExtractedContent !== false;
|
|
221
222
|
let composed = text;
|
|
222
223
|
let composedForLlm = composed;
|
|
223
224
|
if (attachmentUrls.length > 0) {
|
|
@@ -231,7 +232,7 @@ ${lines.join("\n")}`;
|
|
|
231
232
|
let extractContent;
|
|
232
233
|
let fileUrls;
|
|
233
234
|
if (attachmentUrls.length > 0) {
|
|
234
|
-
const extractFiles = attachmentUrls.filter((u) => isServerExtractable(u.name));
|
|
235
|
+
const extractFiles = inlineExtracted ? attachmentUrls.filter((u) => isServerExtractable(u.name)) : [];
|
|
235
236
|
if (extractFiles.length > 0) {
|
|
236
237
|
const directives = [];
|
|
237
238
|
const sections = extractFiles.map((u) => {
|
|
@@ -292,7 +293,7 @@ Never assert absence from a partial read. Do not say "there is no X", "none", "n
|
|
|
292
293
|
Embedded values: a search term is often stored inside a larger string. A merchant "GODADDY" appears as "DNH*GODADDY#4070277042", and a card as "4140****2941". Server-side index filters match only exact values, leading prefixes, or trailing suffixes, and tag filters only EXACT whole-tag values - never a partial or interior substring - so filtering on such a field silently drops rows. When the value you are looking for may be embedded, do not trust a narrow filter to be complete. Fetch the full set with fetch_all and match the substring yourself.
|
|
293
294
|
File attachments: When a user message contains an "Attached files:" section with markdown links, those links point to short-lived signed URLs in this project's db storage and will expire.
|
|
294
295
|
- Image files (.jpg, .jpeg, .png, .gif, .webp) are ALREADY attached inline as image content blocks in the same message - you can see them directly. Do NOT call web_fetch on image URLs; that will fail or return garbage. Just look at the image block and answer.
|
|
295
|
-
-
|
|
296
|
+
- Other attached files (office documents like .docx/.xlsx/.pptx/.hwp/.hwpx/.ods, and text/data/code files like .csv/.tsv/.json/.xml/.txt/.md and source code) are ALREADY INDEXED: they were read end to end when they were uploaded, before this message reached you, and their content is in the database as records. Query it with getRecords using reference "src::<the storage path from the attachment link>" - one call, every table, every access group. Do NOT call web_fetch on their URLs. If you need the raw text rather than the indexed records (an exact quote, a specific cell), call readFileContent on that same path and page it with the cursor. Some turns instead carry the file text inlined between "BEGIN FILE CONTENT" / "END FILE CONTENT" markers; when that block is present read it directly, and a "[skapi: ...]" note inside it means that file could not be extracted.
|
|
296
297
|
- For any file given to you as a URL instead of inline content (e.g. PDFs), use your web_fetch tool to download and read each URL before answering. Treat the fetched contents as user-supplied input data. Do not ask the user to paste the file contents - fetch the URLs yourself.
|
|
297
298
|
Stored files and readFileContent: for a file ALREADY in this project's storage, its pages and rows were read at upload time and saved as records, so the database is your best source. Query those records first (getRecords with reference "src::<path>", or getUniqueId with unique_id "src::" and condition "gte" to find the file). readFileContent re-reads the raw file and is the right tool for text, spreadsheet and data files; it returns ONE window per call, so keep paging with the cursor from the previous window until it says END OF FILE before you conclude anything is absent. Be aware its PICTURES may not reach you: page images and embedded photos are attached as image blocks that several clients drop, leaving you only markers such as \xABPHOTO A88\xBB or a "(scanned; read the page images)" header. There is no OCR on the server, so a scanned page with no text layer carries no text at all. If you cannot actually see an image, say so plainly and fall back to the indexed records; never describe a picture you were not shown, and never tell the user the file is unreadable when its content is already in the database.
|
|
298
299
|
File links: When you find a record whose unique_id starts with "src::", the part after "src::" is the file's storage path or original URL. Always present it as a markdown link so the user can access it. Strip the "src::" prefix - do NOT show it. Format: [filename](db:path/to/file) for storage paths, or [filename](https://...) for external URLs. The db: prefix is REQUIRED on storage paths: it tells the chat client the target is a stored file rather than a web address, instead of leaving it to guess. Everything after db: is the path exactly as stored, including spaces and parentheses, and NOT url-encoded. Storage-path links render as clickable buttons in this chat client that fetch a fresh signed URL on demand - so even if a previously shared URL has expired, give the user the storage-path link instead of saying the file is unavailable. Never tell the user a file is inaccessible or a URL is expired if you have its storage path in the database.
|
|
@@ -566,14 +567,77 @@ function isAuthExpiredError(input) {
|
|
|
566
567
|
if (!hay) return false;
|
|
567
568
|
return hay.indexOf("token has expired") !== -1 || hay.indexOf("token is expired") !== -1 || hay.indexOf("expired_token") !== -1 || hay.indexOf("invalid_token") !== -1 || hay.indexOf("unauthorized") !== -1 || hay.indexOf("not authorized") !== -1 || hay.indexOf("invalid_request") !== -1 && hay.indexOf("token") !== -1;
|
|
568
569
|
}
|
|
570
|
+
function isProviderApiKeyError(input) {
|
|
571
|
+
if (!input) return false;
|
|
572
|
+
var blobs = [];
|
|
573
|
+
var push = function(v) {
|
|
574
|
+
if (typeof v === "string" && v) blobs.push(v);
|
|
575
|
+
};
|
|
576
|
+
if (typeof input === "string") push(input);
|
|
577
|
+
else {
|
|
578
|
+
push(input.message);
|
|
579
|
+
push(input.code);
|
|
580
|
+
push(input.type);
|
|
581
|
+
if (input.error) {
|
|
582
|
+
push(input.error.message);
|
|
583
|
+
push(input.error.code);
|
|
584
|
+
push(input.error.type);
|
|
585
|
+
}
|
|
586
|
+
if (input.body) {
|
|
587
|
+
push(input.body.message);
|
|
588
|
+
push(input.body.type);
|
|
589
|
+
if (input.body.error) {
|
|
590
|
+
push(input.body.error.message);
|
|
591
|
+
push(input.body.error.code);
|
|
592
|
+
push(input.body.error.type);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
var hay = blobs.join(" | ").toLowerCase();
|
|
597
|
+
if (!hay) return false;
|
|
598
|
+
return hay.indexOf("authentication_error") !== -1 || hay.indexOf("invalid_api_key") !== -1 || hay.indexOf("invalid x-api-key") !== -1 || hay.indexOf("incorrect api key") !== -1 || hay.indexOf("invalid api key") !== -1 || hay.indexOf("no api key provided") !== -1;
|
|
599
|
+
}
|
|
569
600
|
|
|
570
601
|
// src/engine/links.ts
|
|
571
602
|
var EXPIRED_ATTACHMENT_URL_HOST = "_expired_.url";
|
|
572
603
|
var EXPIRED_ATTACHMENT_URL_ORIGIN = "https://" + EXPIRED_ATTACHMENT_URL_HOST;
|
|
573
604
|
var LINK_LABEL_MAX_DISPLAY_CHARS = 32;
|
|
574
605
|
var EXPIRED_LINK_REFRESH_EXPIRES_SECONDS = 20 * 60;
|
|
606
|
+
var PREVIEW_URL_EXPIRES_SECONDS = 60 * 60;
|
|
575
607
|
var PREVIEW_BROWSER_CACHE_SECONDS = 7 * 24 * 60 * 60;
|
|
576
608
|
var LINK_REFRESH_WINDOW_MS = (EXPIRED_LINK_REFRESH_EXPIRES_SECONDS - 5 * 60) * 1e3;
|
|
609
|
+
var MINT_CACHE_GENERATION = 2;
|
|
610
|
+
function mintCacheBustStamp(now) {
|
|
611
|
+
return Math.floor((now == null ? Date.now() : now) / LINK_REFRESH_WINDOW_MS);
|
|
612
|
+
}
|
|
613
|
+
function previewMintCacheToken(refresh) {
|
|
614
|
+
if (!refresh) return String(MINT_CACHE_GENERATION);
|
|
615
|
+
return MINT_CACHE_GENERATION + "." + mintCacheBustStamp();
|
|
616
|
+
}
|
|
617
|
+
var PRESIGN_SAFETY_MARGIN_MS = 60 * 1e3;
|
|
618
|
+
function presignExpiryEpochMs(url) {
|
|
619
|
+
if (!url) return null;
|
|
620
|
+
var q = url.indexOf("?");
|
|
621
|
+
if (q < 0) return null;
|
|
622
|
+
var params;
|
|
623
|
+
try {
|
|
624
|
+
params = new URLSearchParams(url.slice(q + 1));
|
|
625
|
+
} catch (e) {
|
|
626
|
+
return null;
|
|
627
|
+
}
|
|
628
|
+
var v2 = params.get("Expires");
|
|
629
|
+
if (v2 && /^\d+$/.test(v2)) return parseInt(v2, 10) * 1e3;
|
|
630
|
+
var signed = params.get("X-Amz-Date");
|
|
631
|
+
var lifetime = params.get("X-Amz-Expires");
|
|
632
|
+
if (signed && lifetime && /^\d+$/.test(lifetime)) {
|
|
633
|
+
var m = /^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})Z$/.exec(signed);
|
|
634
|
+
if (m) {
|
|
635
|
+
var at = Date.UTC(+m[1], +m[2] - 1, +m[3], +m[4], +m[5], +m[6]);
|
|
636
|
+
return at + parseInt(lifetime, 10) * 1e3;
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
return null;
|
|
640
|
+
}
|
|
577
641
|
function createInlineLinkRegex() {
|
|
578
642
|
return /src::(\S+)|\[([^\]\n]+)\]\((https?:\/\/(?:[^\s()]|\([^\s()]*\))+)\)|\[([^\]\n]+)\]\(((?:[^()\n]|\([^()\n]*\))+)\)|(https?:\/\/[^\s<>"']+)/g;
|
|
579
643
|
}
|
|
@@ -824,6 +888,13 @@ function linkUnavailableKeyForPath(remotePath) {
|
|
|
824
888
|
function linkUnavailableKeyForHref(href) {
|
|
825
889
|
return "href:" + (href || "");
|
|
826
890
|
}
|
|
891
|
+
function linkUnavailableKeysForPath(remotePath) {
|
|
892
|
+
if (!remotePath) return [];
|
|
893
|
+
return [
|
|
894
|
+
linkUnavailableKeyForPath(remotePath),
|
|
895
|
+
linkUnavailableKeyForHref(buildDisplayExpiredAttachmentHref(remotePath))
|
|
896
|
+
];
|
|
897
|
+
}
|
|
827
898
|
function isLinkUnavailable(link, map) {
|
|
828
899
|
if (!link || !map) return false;
|
|
829
900
|
if (link.remotePath && map[linkUnavailableKeyForPath(link.remotePath)]) return true;
|
|
@@ -840,33 +911,85 @@ function truncateLabelForDisplay(label) {
|
|
|
840
911
|
// src/engine/budget.ts
|
|
841
912
|
var CONTEXT_WINDOW_DEFAULT = { claude: 2e5, openai: 128e3 };
|
|
842
913
|
var CONTEXT_WINDOW_BY_MODEL = {
|
|
843
|
-
// exact ids
|
|
914
|
+
// claude, exact ids
|
|
915
|
+
"claude-fable-5": 1e6,
|
|
844
916
|
"claude-opus-5": 1e6,
|
|
845
917
|
"claude-opus-4-8": 1e6,
|
|
846
918
|
"claude-opus-4-7": 1e6,
|
|
919
|
+
"claude-opus-4-6": 1e6,
|
|
920
|
+
"claude-opus-4-5": 2e5,
|
|
847
921
|
"claude-sonnet-5": 1e6,
|
|
848
922
|
"claude-sonnet-4-6": 1e6,
|
|
923
|
+
"claude-sonnet-4-5": 1e6,
|
|
849
924
|
"claude-sonnet-4": 2e5,
|
|
850
925
|
"claude-haiku-4-5": 2e5,
|
|
851
|
-
"
|
|
852
|
-
|
|
926
|
+
"claude-3-5-sonnet": 2e5,
|
|
927
|
+
// openai, exact ids
|
|
928
|
+
"gpt-5.6-sol": 105e4,
|
|
929
|
+
"gpt-5.6-terra": 105e4,
|
|
930
|
+
"gpt-5.6-luna": 105e4,
|
|
931
|
+
"gpt-5.5": 1e6,
|
|
932
|
+
"gpt-5.4": 105e4,
|
|
933
|
+
"gpt-5.4-mini": 4e5,
|
|
934
|
+
"gpt-5.4-nano": 4e5,
|
|
935
|
+
"gpt-4.1": 104e4,
|
|
936
|
+
"gpt-4o": 128e3,
|
|
937
|
+
"o1": 2e5,
|
|
938
|
+
"o1-pro": 2e5,
|
|
853
939
|
// family keys
|
|
940
|
+
"claude-fable": 1e6,
|
|
854
941
|
"claude-opus": 1e6,
|
|
855
942
|
"claude-sonnet": 1e6,
|
|
856
943
|
"claude-haiku": 2e5,
|
|
944
|
+
"gpt-5.6": 105e4,
|
|
945
|
+
"gpt-5": 128e3
|
|
946
|
+
};
|
|
947
|
+
var MAX_OUTPUT_BY_MODEL = {
|
|
948
|
+
// claude
|
|
949
|
+
"claude-fable-5": 128e3,
|
|
950
|
+
"claude-opus-5": 128e3,
|
|
951
|
+
"claude-opus-4-8": 128e3,
|
|
952
|
+
"claude-sonnet-5": 128e3,
|
|
953
|
+
"claude-sonnet-4-6": 64e3,
|
|
954
|
+
"claude-haiku-4-5": 64e3,
|
|
955
|
+
"claude-3-5-sonnet": 8e3,
|
|
956
|
+
// openai
|
|
957
|
+
"gpt-5.6-sol": 128e3,
|
|
958
|
+
"gpt-5.6-terra": 128e3,
|
|
959
|
+
"gpt-5.6-luna": 128e3,
|
|
960
|
+
"gpt-5.5": 128e3,
|
|
961
|
+
"gpt-5.4": 128e3,
|
|
962
|
+
"gpt-5.4-mini": 128e3,
|
|
963
|
+
"gpt-5.4-nano": 128e3,
|
|
964
|
+
"gpt-4.1": 16e3,
|
|
965
|
+
"gpt-4o": 4e3,
|
|
966
|
+
"o1": 1e5,
|
|
967
|
+
"o1-pro": 1e5,
|
|
968
|
+
// family keys
|
|
969
|
+
"claude-fable": 128e3,
|
|
970
|
+
"claude-opus": 128e3,
|
|
971
|
+
"claude-sonnet": 64e3,
|
|
972
|
+
"claude-haiku": 64e3,
|
|
857
973
|
"gpt-5.6": 128e3,
|
|
858
974
|
"gpt-5": 128e3
|
|
859
975
|
};
|
|
976
|
+
var DEFAULT_CONTEXT_WINDOW = 88e4;
|
|
860
977
|
var apiReportedContextWindows = {};
|
|
978
|
+
var apiReportedMaxOutput = {};
|
|
861
979
|
function registerModelContextWindows(models) {
|
|
862
980
|
if (!Array.isArray(models)) return;
|
|
863
981
|
for (var i = 0; i < models.length; i++) {
|
|
864
982
|
var m = models[i];
|
|
865
983
|
var id = (m && m.id ? String(m.id) : "").trim().toLowerCase();
|
|
984
|
+
if (!id) continue;
|
|
866
985
|
var reported = m ? Number(m.max_input_tokens) : NaN;
|
|
867
|
-
if (
|
|
986
|
+
if (Number.isFinite(reported) && reported > 0) {
|
|
868
987
|
apiReportedContextWindows[id] = Math.floor(reported);
|
|
869
988
|
}
|
|
989
|
+
var out = m ? Number(m.max_tokens) : NaN;
|
|
990
|
+
if (Number.isFinite(out) && out > 0) {
|
|
991
|
+
apiReportedMaxOutput[id] = Math.floor(out);
|
|
992
|
+
}
|
|
870
993
|
}
|
|
871
994
|
}
|
|
872
995
|
var projectContextWindows = {};
|
|
@@ -881,13 +1004,16 @@ function getProjectContextWindow(projectId) {
|
|
|
881
1004
|
var key = (projectId || "").trim();
|
|
882
1005
|
return key && projectContextWindows[key] ? projectContextWindows[key] : null;
|
|
883
1006
|
}
|
|
884
|
-
var
|
|
1007
|
+
var MAX_OUTPUT_TOKENS = 25e3;
|
|
1008
|
+
var OUTPUT_TOKEN_RESERVE = MAX_OUTPUT_TOKENS;
|
|
885
1009
|
var TOOL_AND_RESPONSE_BUFFER = 4e3;
|
|
886
1010
|
var MIN_INPUT_TOKEN_BUDGET = 8e3;
|
|
887
|
-
var
|
|
1011
|
+
var MIN_PER_REQUEST_INPUT_CAP = 28e3;
|
|
1012
|
+
var CLAUDE_PER_REQUEST_INPUT_CAP = MIN_PER_REQUEST_INPUT_CAP;
|
|
888
1013
|
var MAX_HISTORY_MESSAGES = 20;
|
|
889
1014
|
var HISTORY_TOKEN_BUDGET = 8e3;
|
|
890
|
-
var
|
|
1015
|
+
var INPUT_CAP_RATIO = 0.16;
|
|
1016
|
+
var CLAUDE_INPUT_CAP_RATIO = INPUT_CAP_RATIO;
|
|
891
1017
|
var HISTORY_BUDGET_RATIO = 0.08;
|
|
892
1018
|
function estimateTextTokens(text) {
|
|
893
1019
|
return Math.ceil((text || "").length / 3);
|
|
@@ -895,38 +1021,61 @@ function estimateTextTokens(text) {
|
|
|
895
1021
|
function estimateMessageTokens(msg) {
|
|
896
1022
|
return estimateTextTokens(msg.content) + estimateTextTokens(msg.role) + 6;
|
|
897
1023
|
}
|
|
1024
|
+
function resolveByModelId(apiTable, staticTable, model) {
|
|
1025
|
+
var normalized = (model || "").trim().toLowerCase();
|
|
1026
|
+
if (!normalized) return 0;
|
|
1027
|
+
if (apiTable[normalized]) return apiTable[normalized];
|
|
1028
|
+
if (staticTable[normalized]) return staticTable[normalized];
|
|
1029
|
+
var parts = normalized.split("-");
|
|
1030
|
+
for (var end = parts.length - 1; end > 0; end--) {
|
|
1031
|
+
var family = parts.slice(0, end).join("-");
|
|
1032
|
+
if (staticTable[family]) return staticTable[family];
|
|
1033
|
+
}
|
|
1034
|
+
return 0;
|
|
1035
|
+
}
|
|
1036
|
+
function getModelContextWindow(platform, model) {
|
|
1037
|
+
return resolveByModelId(apiReportedContextWindows, CONTEXT_WINDOW_BY_MODEL, model) || CONTEXT_WINDOW_DEFAULT[platform];
|
|
1038
|
+
}
|
|
1039
|
+
function getMaxOutputTokens(platform, model) {
|
|
1040
|
+
var cap = resolveByModelId(apiReportedMaxOutput, MAX_OUTPUT_BY_MODEL, model);
|
|
1041
|
+
return cap ? Math.min(MAX_OUTPUT_TOKENS, cap) : MAX_OUTPUT_TOKENS;
|
|
1042
|
+
}
|
|
898
1043
|
function getContextWindow(platform, model, projectId) {
|
|
1044
|
+
var ceiling = getModelContextWindow(platform, model);
|
|
899
1045
|
var override = projectId ? getProjectContextWindow(projectId) : null;
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
return
|
|
1046
|
+
return Math.min(override || DEFAULT_CONTEXT_WINDOW, ceiling);
|
|
1047
|
+
}
|
|
1048
|
+
function contextBasedBudgetFor(platform, model, projectId) {
|
|
1049
|
+
var contextWindow = getContextWindow(platform, model, projectId);
|
|
1050
|
+
return Math.max(
|
|
1051
|
+
MIN_INPUT_TOKEN_BUDGET,
|
|
1052
|
+
contextWindow - getMaxOutputTokens(platform, model) - TOOL_AND_RESPONSE_BUFFER
|
|
1053
|
+
);
|
|
1054
|
+
}
|
|
1055
|
+
function getInputTokenBudget(platform, model, projectId) {
|
|
1056
|
+
var contextBasedBudget = contextBasedBudgetFor(platform, model, projectId);
|
|
1057
|
+
return Math.min(
|
|
1058
|
+
contextBasedBudget,
|
|
1059
|
+
Math.max(MIN_PER_REQUEST_INPUT_CAP, Math.round(contextBasedBudget * INPUT_CAP_RATIO))
|
|
1060
|
+
);
|
|
912
1061
|
}
|
|
913
1062
|
function stripFileBlocksFromHistory(content) {
|
|
914
1063
|
if (!content) return content;
|
|
915
1064
|
return content.replace(/```([^\n`]+?\.[^\s.`]+)\n[\s\S]*?```/g, "[file previously attached: $1]");
|
|
916
1065
|
}
|
|
917
1066
|
function buildBoundedChatMessages(options) {
|
|
918
|
-
var
|
|
919
|
-
var
|
|
920
|
-
MIN_INPUT_TOKEN_BUDGET,
|
|
921
|
-
contextWindow - OUTPUT_TOKEN_RESERVE - TOOL_AND_RESPONSE_BUFFER
|
|
922
|
-
);
|
|
923
|
-
var scaled = !!(options.projectId && getProjectContextWindow(options.projectId));
|
|
924
|
-
var claudeInputCap = scaled ? Math.max(CLAUDE_PER_REQUEST_INPUT_CAP, Math.round(contextBasedBudget * CLAUDE_INPUT_CAP_RATIO)) : CLAUDE_PER_REQUEST_INPUT_CAP;
|
|
925
|
-
var availableInputBudget = options.platform === "claude" ? Math.min(contextBasedBudget, claudeInputCap) : contextBasedBudget;
|
|
1067
|
+
var contextBasedBudget = contextBasedBudgetFor(options.platform, options.model, options.projectId);
|
|
1068
|
+
var availableInputBudget = getInputTokenBudget(options.platform, options.model, options.projectId);
|
|
926
1069
|
var systemCost = estimateTextTokens(options.systemPrompt) + 12;
|
|
927
|
-
var historyAllowance =
|
|
1070
|
+
var historyAllowance = Math.max(
|
|
1071
|
+
HISTORY_TOKEN_BUDGET,
|
|
1072
|
+
Math.round(contextBasedBudget * HISTORY_BUDGET_RATIO)
|
|
1073
|
+
);
|
|
928
1074
|
var budgetForHistory = Math.max(1e3, Math.min(historyAllowance, availableInputBudget - systemCost));
|
|
929
|
-
var maxHistoryMessages =
|
|
1075
|
+
var maxHistoryMessages = Math.max(
|
|
1076
|
+
MAX_HISTORY_MESSAGES,
|
|
1077
|
+
Math.round(MAX_HISTORY_MESSAGES * (budgetForHistory / HISTORY_TOKEN_BUDGET))
|
|
1078
|
+
);
|
|
930
1079
|
var windowed = options.history.slice(-maxHistoryMessages);
|
|
931
1080
|
var latestIndex = windowed.length - 1;
|
|
932
1081
|
var trimmed = windowed.map(function(m, i2) {
|
|
@@ -1168,8 +1317,11 @@ function clearImagePreviewCache(scope) {
|
|
|
1168
1317
|
}
|
|
1169
1318
|
function peekImagePreviewUrl(ctx, remotePath) {
|
|
1170
1319
|
var hit = previewUrlCache[cacheKey(ctx.scope, remotePath)];
|
|
1171
|
-
if (hit
|
|
1172
|
-
return null;
|
|
1320
|
+
if (!hit) return null;
|
|
1321
|
+
if (Date.now() - hit.at >= LINK_REFRESH_WINDOW_MS) return null;
|
|
1322
|
+
var dies = presignExpiryEpochMs(hit.url);
|
|
1323
|
+
if (dies !== null && Date.now() >= dies - PRESIGN_SAFETY_MARGIN_MS) return null;
|
|
1324
|
+
return hit.url;
|
|
1173
1325
|
}
|
|
1174
1326
|
function resolveImagePreviewUrl(ctx, remotePath, contentType, refresh) {
|
|
1175
1327
|
var key = cacheKey(ctx.scope, remotePath);
|
|
@@ -1219,6 +1371,7 @@ function hydrateOne(img, ctx) {
|
|
|
1219
1371
|
img.setAttribute("data-bq-img-state", "loading");
|
|
1220
1372
|
img.addEventListener("load", function() {
|
|
1221
1373
|
img.setAttribute("data-bq-img-state", "ready");
|
|
1374
|
+
img.removeAttribute("data-bq-img-retry");
|
|
1222
1375
|
if (ctx.onLoad) ctx.onLoad(path);
|
|
1223
1376
|
});
|
|
1224
1377
|
img.addEventListener("error", function() {
|
|
@@ -1319,7 +1472,6 @@ var WEB_FETCH_MAX_USES = 40;
|
|
|
1319
1472
|
var WEB_FETCH_MAX_CONTENT_TOKENS = 2e5;
|
|
1320
1473
|
var OPENAI_RESPONSES_API_URL = "https://api.openai.com/v1/responses";
|
|
1321
1474
|
var OPENAI_MODELS_API_URL = "https://api.openai.com/v1/models";
|
|
1322
|
-
var MAX_TOKENS = 25e3;
|
|
1323
1475
|
var DEFAULT_OPENAI_IMAGE_DETAIL = "auto";
|
|
1324
1476
|
var OPENAI_WEB_SEARCH_EXTERNAL_WEB_ACCESS = true;
|
|
1325
1477
|
var MCP_NAME = "BunnyQuery";
|
|
@@ -1559,7 +1711,7 @@ async function callClaudeWithPublicMcp(prompt, service, owner, messages, system,
|
|
|
1559
1711
|
owner,
|
|
1560
1712
|
userId,
|
|
1561
1713
|
model: model || DEFAULT_CLAUDE_MODEL,
|
|
1562
|
-
maxTokens:
|
|
1714
|
+
maxTokens: getMaxOutputTokens("claude", model || DEFAULT_CLAUDE_MODEL),
|
|
1563
1715
|
system,
|
|
1564
1716
|
extractContent,
|
|
1565
1717
|
fileUrls,
|
|
@@ -1604,7 +1756,7 @@ async function callOpenAIWithPublicMcp(prompt, service, owner, messages, system,
|
|
|
1604
1756
|
},
|
|
1605
1757
|
data: {
|
|
1606
1758
|
model: resolvedModel,
|
|
1607
|
-
max_output_tokens:
|
|
1759
|
+
max_output_tokens: getMaxOutputTokens("openai", resolvedModel),
|
|
1608
1760
|
...extractContent && extractContent.length ? { _skapi_extract: extractContent } : {},
|
|
1609
1761
|
...fileUrls && fileUrls.length ? { _skapi_file_urls: fileUrls } : {},
|
|
1610
1762
|
input: responseInput,
|
|
@@ -1634,6 +1786,29 @@ async function notifyAgentContinueIndexing(info) {
|
|
|
1634
1786
|
async function notifyAgentSaveAttachment(info) {
|
|
1635
1787
|
const { platform, service, owner, attachment, parsedContent } = info;
|
|
1636
1788
|
const continuing = !!info.continueIndexing;
|
|
1789
|
+
if (!continuing) {
|
|
1790
|
+
upsertIndexRunRecordSafe(service, attachment.storagePath, {
|
|
1791
|
+
status: "working",
|
|
1792
|
+
filename: attachment.name,
|
|
1793
|
+
started: Date.now(),
|
|
1794
|
+
queue: bgIndexingQueueName(info.userId, service),
|
|
1795
|
+
platform
|
|
1796
|
+
});
|
|
1797
|
+
}
|
|
1798
|
+
const tapDispatchFailure = (p) => {
|
|
1799
|
+
if (continuing) return p;
|
|
1800
|
+
return p.then(
|
|
1801
|
+
(ack) => ack,
|
|
1802
|
+
(err) => {
|
|
1803
|
+
upsertIndexRunRecordSafe(service, attachment.storagePath, {
|
|
1804
|
+
status: "error",
|
|
1805
|
+
finished: Date.now(),
|
|
1806
|
+
error: err && (err.message || String(err)) || "The indexing request could not be enqueued."
|
|
1807
|
+
});
|
|
1808
|
+
throw err;
|
|
1809
|
+
}
|
|
1810
|
+
);
|
|
1811
|
+
};
|
|
1637
1812
|
const visionFile = !parsedContent && isImageVisionFile(attachment.name, attachment.mime);
|
|
1638
1813
|
const renderFrom = Math.max(0, info.renderFrom || 0);
|
|
1639
1814
|
const renderPlaceholder = visionFile ? makeRenderPlaceholder(attachment.storagePath) : void 0;
|
|
@@ -1693,6 +1868,7 @@ async function notifyAgentSaveAttachment(info) {
|
|
|
1693
1868
|
save_media: !continuing
|
|
1694
1869
|
}))
|
|
1695
1870
|
} : {};
|
|
1871
|
+
const skapiFileUrls = attachment.url && attachment.storagePath ? { _skapi_file_urls: [{ path: attachment.storagePath, url: attachment.url }] } : {};
|
|
1696
1872
|
const userMessage = visionFile && renderPlaceholder ? buildIndexingRenderMessage(attachment, renderPlaceholder, renderFrom) : windowedRead && windowPlaceholder ? buildIndexingWindowMessage(attachment, windowPlaceholder, false) : continuing ? buildIndexingContinueMessage(attachment) : buildIndexingUserMessage(
|
|
1697
1873
|
attachment,
|
|
1698
1874
|
parsedContent ? { inlineContent: parsedContent } : placeholder ? { inlineContentPlaceholder: placeholder } : pagedRead ? { pagedRead: true } : void 0
|
|
@@ -1708,7 +1884,7 @@ async function notifyAgentSaveAttachment(info) {
|
|
|
1708
1884
|
if (platform === "openai") {
|
|
1709
1885
|
const resolvedModel2 = info.model || DEFAULT_OPENAI_MODEL;
|
|
1710
1886
|
const imageDetail = getOpenAIImageDetail(resolvedModel2);
|
|
1711
|
-
return clientSecretRequest({
|
|
1887
|
+
return tapDispatchFailure(clientSecretRequest({
|
|
1712
1888
|
clientSecretName: "openai",
|
|
1713
1889
|
queue: bgIndexingQueueName(info.userId, service),
|
|
1714
1890
|
service,
|
|
@@ -1722,12 +1898,13 @@ async function notifyAgentSaveAttachment(info) {
|
|
|
1722
1898
|
},
|
|
1723
1899
|
data: {
|
|
1724
1900
|
model: resolvedModel2,
|
|
1725
|
-
max_output_tokens:
|
|
1901
|
+
max_output_tokens: getMaxOutputTokens("openai", resolvedModel2),
|
|
1726
1902
|
// Nano-only transcription knobs. Indexing only; see variantIndexingOptions.
|
|
1727
1903
|
...variantIndexingOptions(resolvedModel2),
|
|
1728
1904
|
...skapiExtract,
|
|
1729
1905
|
...skapiRender,
|
|
1730
1906
|
...skapiWindow,
|
|
1907
|
+
...skapiFileUrls,
|
|
1731
1908
|
input: [
|
|
1732
1909
|
{ role: "system", content: systemPrompt },
|
|
1733
1910
|
{
|
|
@@ -1751,10 +1928,10 @@ async function notifyAgentSaveAttachment(info) {
|
|
|
1751
1928
|
]
|
|
1752
1929
|
]
|
|
1753
1930
|
}
|
|
1754
|
-
});
|
|
1931
|
+
}));
|
|
1755
1932
|
}
|
|
1756
1933
|
const resolvedModel = info.model || DEFAULT_CLAUDE_MODEL;
|
|
1757
|
-
return clientSecretRequest({
|
|
1934
|
+
return tapDispatchFailure(clientSecretRequest({
|
|
1758
1935
|
clientSecretName: "claude",
|
|
1759
1936
|
queue: bgIndexingQueueName(info.userId, service),
|
|
1760
1937
|
service,
|
|
@@ -1770,10 +1947,11 @@ async function notifyAgentSaveAttachment(info) {
|
|
|
1770
1947
|
},
|
|
1771
1948
|
data: {
|
|
1772
1949
|
model: resolvedModel,
|
|
1773
|
-
max_tokens:
|
|
1950
|
+
max_tokens: getMaxOutputTokens("claude", resolvedModel),
|
|
1774
1951
|
...skapiExtract,
|
|
1775
1952
|
...skapiRender,
|
|
1776
1953
|
...skapiWindow,
|
|
1954
|
+
...skapiFileUrls,
|
|
1777
1955
|
system: [
|
|
1778
1956
|
{
|
|
1779
1957
|
type: "text",
|
|
@@ -1809,7 +1987,7 @@ async function notifyAgentSaveAttachment(info) {
|
|
|
1809
1987
|
}
|
|
1810
1988
|
]
|
|
1811
1989
|
}
|
|
1812
|
-
});
|
|
1990
|
+
}));
|
|
1813
1991
|
}
|
|
1814
1992
|
function extractClaudeText(response) {
|
|
1815
1993
|
if (!Array.isArray(response?.content)) {
|
|
@@ -1870,6 +2048,21 @@ async function listOpenAIModels(service, owner) {
|
|
|
1870
2048
|
});
|
|
1871
2049
|
}
|
|
1872
2050
|
var BG_INDEXING_QUEUE_SUFFIX = "-bg";
|
|
2051
|
+
function indexDoneUniqueId(storagePath) {
|
|
2052
|
+
return "done::" + storagePath;
|
|
2053
|
+
}
|
|
2054
|
+
function runIndexUniqueId(storagePath) {
|
|
2055
|
+
return "run::" + storagePath;
|
|
2056
|
+
}
|
|
2057
|
+
function upsertIndexRunRecordSafe(service, storagePath, patch) {
|
|
2058
|
+
if (!service || !storagePath) return;
|
|
2059
|
+
try {
|
|
2060
|
+
const hook = chatEngineConfig().upsertIndexRunRecord;
|
|
2061
|
+
if (typeof hook !== "function") return;
|
|
2062
|
+
hook({ service, storagePath, patch });
|
|
2063
|
+
} catch (e) {
|
|
2064
|
+
}
|
|
2065
|
+
}
|
|
1873
2066
|
function bgIndexingQueueName(userId, service) {
|
|
1874
2067
|
return (userId || service || "") + BG_INDEXING_QUEUE_SUFFIX;
|
|
1875
2068
|
}
|
|
@@ -1893,13 +2086,20 @@ async function getChatHistory(params, fetchOptions) {
|
|
|
1893
2086
|
},
|
|
1894
2087
|
{ service: params.service, owner: params.owner },
|
|
1895
2088
|
params.queue ? { queue: params.queue } : {},
|
|
1896
|
-
params.status ? { status: params.status } : {}
|
|
2089
|
+
params.status ? { status: params.status } : {},
|
|
2090
|
+
params.queue_exact ? { queue_exact: true } : {},
|
|
2091
|
+
params.compact ? { compact: true } : {},
|
|
2092
|
+
params.queue_exclude ? { queue_exclude: params.queue_exclude } : {}
|
|
1897
2093
|
);
|
|
1898
2094
|
return chatEngineConfig().clientSecretRequestHistory(
|
|
1899
2095
|
p,
|
|
1900
2096
|
Object.assign({ ascending: false, limit: CHAT_HISTORY_PAGE_LIMIT }, fetchOptions)
|
|
1901
2097
|
);
|
|
1902
2098
|
}
|
|
2099
|
+
function buildHistoryItemFullId(platform, service, itemId) {
|
|
2100
|
+
const url = platform === "claude" ? ANTHROPIC_MESSAGES_API_URL : OPENAI_RESPONSES_API_URL;
|
|
2101
|
+
return `[POST]${url.toLowerCase()}#${service}:${itemId}`;
|
|
2102
|
+
}
|
|
1903
2103
|
|
|
1904
2104
|
// src/engine/history.ts
|
|
1905
2105
|
function filterListByClearHorizon(list, clearedAt) {
|
|
@@ -1949,6 +2149,278 @@ function parseIndexingRequestText(userText) {
|
|
|
1949
2149
|
continued: userText.indexOf("CONTINUE indexing") === 0
|
|
1950
2150
|
};
|
|
1951
2151
|
}
|
|
2152
|
+
var LIVE_INDEX_PROBE_LIMIT = 20;
|
|
2153
|
+
var BG_PROBE_TTL_MS = 4e3;
|
|
2154
|
+
var bgProbeCache = {};
|
|
2155
|
+
var bgProbeInflight = {};
|
|
2156
|
+
function probeBgQueue(params, opts) {
|
|
2157
|
+
const key = [params.service, params.owner, params.platform, params.queue, params.status, params.limit].join("|");
|
|
2158
|
+
const maxAge = opts && typeof opts.maxAgeMs === "number" ? opts.maxAgeMs : 0;
|
|
2159
|
+
const cached = bgProbeCache[key];
|
|
2160
|
+
if (maxAge > 0 && cached && Date.now() - cached.at < maxAge) {
|
|
2161
|
+
return Promise.resolve(cached);
|
|
2162
|
+
}
|
|
2163
|
+
const inflight = bgProbeInflight[key];
|
|
2164
|
+
if (inflight) return inflight;
|
|
2165
|
+
const p = Promise.resolve(getChatHistory(
|
|
2166
|
+
{ service: params.service, owner: params.owner, platform: params.platform, queue: params.queue, status: params.status },
|
|
2167
|
+
{ limit: params.limit, fetchMore: false }
|
|
2168
|
+
)).then(function(result) {
|
|
2169
|
+
const entry = { result, at: Date.now() };
|
|
2170
|
+
bgProbeCache[key] = entry;
|
|
2171
|
+
return entry;
|
|
2172
|
+
});
|
|
2173
|
+
bgProbeInflight[key] = p;
|
|
2174
|
+
p.then(function() {
|
|
2175
|
+
delete bgProbeInflight[key];
|
|
2176
|
+
}, function() {
|
|
2177
|
+
delete bgProbeInflight[key];
|
|
2178
|
+
});
|
|
2179
|
+
return p;
|
|
2180
|
+
}
|
|
2181
|
+
async function fetchLiveIndexingKeys(params) {
|
|
2182
|
+
const queue = bgIndexingQueueName(params.userId, params.service);
|
|
2183
|
+
const base = { service: params.service, owner: params.owner, platform: params.platform, queue };
|
|
2184
|
+
const [pending, running] = await Promise.all([
|
|
2185
|
+
probeBgQueue({ ...base, status: "pending", limit: LIVE_INDEX_PROBE_LIMIT }, { maxAgeMs: BG_PROBE_TTL_MS }),
|
|
2186
|
+
probeBgQueue({ ...base, status: "running", limit: LIVE_INDEX_PROBE_LIMIT }, { maxAgeMs: BG_PROBE_TTL_MS })
|
|
2187
|
+
]);
|
|
2188
|
+
const keys = /* @__PURE__ */ new Set();
|
|
2189
|
+
let truncated = false;
|
|
2190
|
+
for (const entry of [pending, running]) {
|
|
2191
|
+
const res = entry.result;
|
|
2192
|
+
const list = res && Array.isArray(res.list) ? res.list : [];
|
|
2193
|
+
if (list.length >= LIVE_INDEX_PROBE_LIMIT) truncated = true;
|
|
2194
|
+
for (const item of list) {
|
|
2195
|
+
const text = extractLastUserTextFromRequest(item && item.request_body);
|
|
2196
|
+
if (!text || !isIndexingRequestText(text)) continue;
|
|
2197
|
+
const ref = parseIndexingRequestText(text);
|
|
2198
|
+
if (!ref) continue;
|
|
2199
|
+
if (ref.path) keys.add(ref.path);
|
|
2200
|
+
if (ref.name) keys.add(ref.name);
|
|
2201
|
+
}
|
|
2202
|
+
}
|
|
2203
|
+
return { keys, checked: !truncated, at: Math.min(pending.at, running.at) };
|
|
2204
|
+
}
|
|
2205
|
+
var BG_COVERAGE_MAX_PAGES = 2;
|
|
2206
|
+
var splitHistoryStates = {};
|
|
2207
|
+
var splitHistoryLocks = {};
|
|
2208
|
+
function freshSplitState() {
|
|
2209
|
+
return { bgBuffer: [], bgEnd: false, bgStarted: false, surfaceEnd: false, pendingSurface: null, surfaceCarry: [], lastSurfaceKeys: [], newestBgId: "" };
|
|
2210
|
+
}
|
|
2211
|
+
function noteBgIds(state, list) {
|
|
2212
|
+
for (const it of list) {
|
|
2213
|
+
const id = it && typeof it.id === "string" ? it.id : "";
|
|
2214
|
+
if (id && id > state.newestBgId) state.newestBgId = id;
|
|
2215
|
+
}
|
|
2216
|
+
}
|
|
2217
|
+
function __resetSplitHistoryState(key) {
|
|
2218
|
+
if (key !== void 0) {
|
|
2219
|
+
delete splitHistoryStates[key];
|
|
2220
|
+
delete splitHistoryLocks[key];
|
|
2221
|
+
return;
|
|
2222
|
+
}
|
|
2223
|
+
for (const k in splitHistoryStates) delete splitHistoryStates[k];
|
|
2224
|
+
for (const k in splitHistoryLocks) delete splitHistoryLocks[k];
|
|
2225
|
+
}
|
|
2226
|
+
var createdOf = (it) => {
|
|
2227
|
+
const c = Number(it && it.created);
|
|
2228
|
+
return isFinite(c) && c > 0 ? c : NaN;
|
|
2229
|
+
};
|
|
2230
|
+
var oldestCreated = (lst) => {
|
|
2231
|
+
let m = Infinity;
|
|
2232
|
+
for (const it of lst) {
|
|
2233
|
+
const c = createdOf(it);
|
|
2234
|
+
if (!isNaN(c) && c < m) m = c;
|
|
2235
|
+
}
|
|
2236
|
+
return m;
|
|
2237
|
+
};
|
|
2238
|
+
var SURFACE_EMPTY_MAX_PAGES = 10;
|
|
2239
|
+
async function getSplitChatHistory(params, fetchOptions, _fetchImpl) {
|
|
2240
|
+
const key = [params.service, params.owner, params.platform, params.userId || ""].join("|");
|
|
2241
|
+
const prev = splitHistoryLocks[key] || Promise.resolve();
|
|
2242
|
+
let releaseLock;
|
|
2243
|
+
const lockTail = new Promise((r) => {
|
|
2244
|
+
releaseLock = r;
|
|
2245
|
+
});
|
|
2246
|
+
const run = () => _getSplitChatHistoryLocked(key, params, fetchOptions, releaseLock, _fetchImpl);
|
|
2247
|
+
const p = prev.then(run, run);
|
|
2248
|
+
p.then((res) => {
|
|
2249
|
+
if (!res || !res.bgPending) releaseLock();
|
|
2250
|
+
}, () => releaseLock());
|
|
2251
|
+
splitHistoryLocks[key] = p.then(() => lockTail, () => lockTail);
|
|
2252
|
+
return p;
|
|
2253
|
+
}
|
|
2254
|
+
async function _getSplitChatHistoryLocked(key, params, fetchOptions, releaseLock, _fetchImpl) {
|
|
2255
|
+
const fetch = _fetchImpl || getChatHistory;
|
|
2256
|
+
const bgQueue = bgIndexingQueueName(params.userId, params.service);
|
|
2257
|
+
const base = { service: params.service, owner: params.owner, platform: params.platform };
|
|
2258
|
+
const fetchMore = !!(fetchOptions && fetchOptions.fetchMore);
|
|
2259
|
+
const limit = fetchOptions && fetchOptions.limit;
|
|
2260
|
+
const firstLoad = !splitHistoryStates[key];
|
|
2261
|
+
let headRefresh = false;
|
|
2262
|
+
if (!splitHistoryStates[key]) {
|
|
2263
|
+
splitHistoryStates[key] = freshSplitState();
|
|
2264
|
+
} else if (!fetchMore) {
|
|
2265
|
+
const prev = splitHistoryStates[key];
|
|
2266
|
+
if (prev.surfaceEnd && prev.bgEnd) {
|
|
2267
|
+
headRefresh = true;
|
|
2268
|
+
prev.pendingSurface = null;
|
|
2269
|
+
prev.surfaceCarry = [];
|
|
2270
|
+
prev.bgBuffer = [];
|
|
2271
|
+
} else {
|
|
2272
|
+
splitHistoryStates[key] = freshSplitState();
|
|
2273
|
+
}
|
|
2274
|
+
}
|
|
2275
|
+
const state = splitHistoryStates[key];
|
|
2276
|
+
if (state.pendingSurface && state.pendingSurface.forFetchMore !== fetchMore) {
|
|
2277
|
+
state.pendingSurface = null;
|
|
2278
|
+
}
|
|
2279
|
+
if (!state.pendingSurface) {
|
|
2280
|
+
if (state.surfaceEnd && !headRefresh) {
|
|
2281
|
+
state.pendingSurface = { list: [], endOfList: true, startKeyHistory: state.lastSurfaceKeys, forFetchMore: fetchMore };
|
|
2282
|
+
} else {
|
|
2283
|
+
const sOpts = { fetchMore };
|
|
2284
|
+
if (limit) sOpts.limit = limit;
|
|
2285
|
+
let s = await fetch({ ...base, queue_exclude: bgQueue }, sOpts);
|
|
2286
|
+
let hops = 0;
|
|
2287
|
+
while (s && !s.endOfList && !(s.list || []).length && hops < SURFACE_EMPTY_MAX_PAGES) {
|
|
2288
|
+
hops++;
|
|
2289
|
+
const nOpts = { fetchMore: true };
|
|
2290
|
+
if (limit) nOpts.limit = limit;
|
|
2291
|
+
s = await fetch({ ...base, queue_exclude: bgQueue }, nOpts);
|
|
2292
|
+
}
|
|
2293
|
+
state.pendingSurface = {
|
|
2294
|
+
list: s && Array.isArray(s.list) ? s.list : [],
|
|
2295
|
+
endOfList: !!(s && s.endOfList),
|
|
2296
|
+
startKeyHistory: s && Array.isArray(s.startKeyHistory) ? s.startKeyHistory : [],
|
|
2297
|
+
forFetchMore: fetchMore
|
|
2298
|
+
};
|
|
2299
|
+
}
|
|
2300
|
+
}
|
|
2301
|
+
const surface = state.pendingSurface;
|
|
2302
|
+
if (fetchOptions && fetchOptions.deferBg && (!state.bgEnd || headRefresh)) {
|
|
2303
|
+
const surfaceList0 = state.surfaceCarry.length ? state.surfaceCarry.concat(surface.list) : surface.list.slice();
|
|
2304
|
+
state.surfaceCarry = [];
|
|
2305
|
+
const emitNow = surfaceList0.concat(state.bgBuffer);
|
|
2306
|
+
state.bgBuffer = [];
|
|
2307
|
+
if (!headRefresh) state.surfaceEnd = surface.endOfList;
|
|
2308
|
+
state.lastSurfaceKeys = surface.startKeyHistory;
|
|
2309
|
+
state.pendingSurface = null;
|
|
2310
|
+
const bgPending = (async () => {
|
|
2311
|
+
try {
|
|
2312
|
+
const batch = [];
|
|
2313
|
+
if (headRefresh) {
|
|
2314
|
+
const bOpts = { fetchMore: false };
|
|
2315
|
+
if (limit) bOpts.limit = limit;
|
|
2316
|
+
const b = await fetch({ ...base, queue: bgQueue, queue_exact: true, compact: true }, bOpts);
|
|
2317
|
+
const bList = b && Array.isArray(b.list) ? b.list : [];
|
|
2318
|
+
for (const it of bList) {
|
|
2319
|
+
if (it && typeof it === "object") it._fromBgChain = true;
|
|
2320
|
+
batch.push(it);
|
|
2321
|
+
}
|
|
2322
|
+
const prevNewest = state.newestBgId;
|
|
2323
|
+
noteBgIds(state, bList);
|
|
2324
|
+
if (prevNewest && !(b && b.endOfList) && !bList.some((it) => it && it.id === prevNewest)) {
|
|
2325
|
+
state.bgEnd = false;
|
|
2326
|
+
state.bgStarted = true;
|
|
2327
|
+
}
|
|
2328
|
+
} else {
|
|
2329
|
+
let hops = 0;
|
|
2330
|
+
while (!state.bgEnd && hops < BG_COVERAGE_MAX_PAGES) {
|
|
2331
|
+
hops++;
|
|
2332
|
+
const bOpts = { fetchMore: state.bgStarted };
|
|
2333
|
+
if (limit) bOpts.limit = limit;
|
|
2334
|
+
const b = await fetch({ ...base, queue: bgQueue, queue_exact: true, compact: true }, bOpts);
|
|
2335
|
+
state.bgStarted = true;
|
|
2336
|
+
const bList = b && Array.isArray(b.list) ? b.list : [];
|
|
2337
|
+
for (const it of bList) {
|
|
2338
|
+
if (it && typeof it === "object") it._fromBgChain = true;
|
|
2339
|
+
batch.push(it);
|
|
2340
|
+
}
|
|
2341
|
+
noteBgIds(state, bList);
|
|
2342
|
+
state.bgEnd = !!(b && b.endOfList);
|
|
2343
|
+
if (!bList.length && !state.bgEnd) break;
|
|
2344
|
+
if (state.bgEnd) break;
|
|
2345
|
+
}
|
|
2346
|
+
}
|
|
2347
|
+
return { list: batch, endOfList: state.surfaceEnd && state.bgEnd };
|
|
2348
|
+
} finally {
|
|
2349
|
+
releaseLock();
|
|
2350
|
+
}
|
|
2351
|
+
})();
|
|
2352
|
+
return {
|
|
2353
|
+
list: emitNow,
|
|
2354
|
+
// A head-refreshed ended chain KNOWS it is still ended — reporting
|
|
2355
|
+
// the hardcoded false here was what un-gated the fill loop on every
|
|
2356
|
+
// tab return. Mid-walk it computes to false exactly as before (this
|
|
2357
|
+
// branch is only entered with bgEnd false then); the bg batch still
|
|
2358
|
+
// carries the final word for that case.
|
|
2359
|
+
endOfList: state.surfaceEnd && state.bgEnd,
|
|
2360
|
+
startKeyHistory: surface.startKeyHistory,
|
|
2361
|
+
firstLoad,
|
|
2362
|
+
bgPending
|
|
2363
|
+
};
|
|
2364
|
+
}
|
|
2365
|
+
const surfaceList = state.surfaceCarry.length ? state.surfaceCarry.concat(surface.list) : surface.list.slice();
|
|
2366
|
+
const boundary = surface.endOfList ? -Infinity : oldestCreated(surfaceList);
|
|
2367
|
+
if (headRefresh) {
|
|
2368
|
+
const hOpts = { fetchMore: false };
|
|
2369
|
+
if (limit) hOpts.limit = limit;
|
|
2370
|
+
const hb = await fetch({ ...base, queue: bgQueue, queue_exact: true, compact: true }, hOpts);
|
|
2371
|
+
const hbList = hb && Array.isArray(hb.list) ? hb.list : [];
|
|
2372
|
+
for (const it of hbList) {
|
|
2373
|
+
if (it && typeof it === "object") it._fromBgChain = true;
|
|
2374
|
+
state.bgBuffer.push(it);
|
|
2375
|
+
}
|
|
2376
|
+
const prevNewestH = state.newestBgId;
|
|
2377
|
+
noteBgIds(state, hbList);
|
|
2378
|
+
if (prevNewestH && !(hb && hb.endOfList) && !hbList.some((it) => it && it.id === prevNewestH)) {
|
|
2379
|
+
state.bgEnd = false;
|
|
2380
|
+
state.bgStarted = true;
|
|
2381
|
+
}
|
|
2382
|
+
} else if (boundary !== Infinity || surface.endOfList) {
|
|
2383
|
+
let hops = 0;
|
|
2384
|
+
while (!state.bgEnd && hops < BG_COVERAGE_MAX_PAGES) {
|
|
2385
|
+
const bufOldest = state.bgBuffer.length ? oldestCreated(state.bgBuffer) : Infinity;
|
|
2386
|
+
if (state.bgBuffer.length && bufOldest <= boundary) break;
|
|
2387
|
+
hops++;
|
|
2388
|
+
const bOpts = { fetchMore: state.bgStarted };
|
|
2389
|
+
if (limit) bOpts.limit = limit;
|
|
2390
|
+
const b = await fetch({ ...base, queue: bgQueue, queue_exact: true, compact: true }, bOpts);
|
|
2391
|
+
state.bgStarted = true;
|
|
2392
|
+
const bList = b && Array.isArray(b.list) ? b.list : [];
|
|
2393
|
+
for (const it of bList) {
|
|
2394
|
+
if (it && typeof it === "object") it._fromBgChain = true;
|
|
2395
|
+
state.bgBuffer.push(it);
|
|
2396
|
+
}
|
|
2397
|
+
noteBgIds(state, bList);
|
|
2398
|
+
state.bgEnd = !!(b && b.endOfList);
|
|
2399
|
+
if (!bList.length && !state.bgEnd) break;
|
|
2400
|
+
if (state.bgEnd) break;
|
|
2401
|
+
}
|
|
2402
|
+
}
|
|
2403
|
+
const emitSurface = surfaceList;
|
|
2404
|
+
state.surfaceCarry = [];
|
|
2405
|
+
const emitBg = state.bgBuffer;
|
|
2406
|
+
state.bgBuffer = [];
|
|
2407
|
+
const seen = {};
|
|
2408
|
+
for (const it of emitSurface) {
|
|
2409
|
+
if (it && typeof it.id === "string") seen[it.id] = true;
|
|
2410
|
+
}
|
|
2411
|
+
const merged = emitSurface.concat(emitBg.filter((it) => !(it && typeof it.id === "string" && seen[it.id])));
|
|
2412
|
+
if (!headRefresh) state.surfaceEnd = surface.endOfList;
|
|
2413
|
+
state.lastSurfaceKeys = surface.startKeyHistory;
|
|
2414
|
+
state.pendingSurface = null;
|
|
2415
|
+
return {
|
|
2416
|
+
list: merged,
|
|
2417
|
+
endOfList: state.surfaceEnd && state.bgEnd && state.bgBuffer.length === 0 && state.surfaceCarry.length === 0,
|
|
2418
|
+
// Bookkeeping only (both the consumers and the SDK treat it opaquely);
|
|
2419
|
+
// the real cursors are the SDK's internal ones plus this module's state.
|
|
2420
|
+
startKeyHistory: surface.startKeyHistory,
|
|
2421
|
+
firstLoad
|
|
2422
|
+
};
|
|
2423
|
+
}
|
|
1952
2424
|
function mapHistoryListToMessages(list, platform, opts) {
|
|
1953
2425
|
var mapped = [], runningItemIds = [];
|
|
1954
2426
|
var extractAssistantText = platform === "openai" ? extractOpenAIText : extractClaudeText;
|
|
@@ -1961,10 +2433,11 @@ function mapHistoryListToMessages(list, platform, opts) {
|
|
|
1961
2433
|
var isPending = isInProcess || isQueued;
|
|
1962
2434
|
var isFailed = item && item.status === "failed";
|
|
1963
2435
|
var response = isFailed ? item.error != null ? item.error : item.response_body : item && item.response_body != null ? item.response_body : item && item.error;
|
|
1964
|
-
var
|
|
1965
|
-
var
|
|
1966
|
-
var
|
|
1967
|
-
var
|
|
2436
|
+
var isCompact = !!(item && item.compact);
|
|
2437
|
+
var userText = isCompact ? typeof item.request_text === "string" ? item.request_text : "" : extractLastUserTextFromRequest(requestBody);
|
|
2438
|
+
var assistantText = isPending ? "" : isCompact ? (typeof item.response_text === "string" ? item.response_text : "").trim() : (extractAssistantText(response) || "").trim() || "";
|
|
2439
|
+
var isErrorResponse = !isPending && (isFailed || !isCompact && isErrorResponseBody(response));
|
|
2440
|
+
var reportedComplete = !!(item && item._isBgTask) && !isErrorResponse && (isCompact ? item.response_complete_marker === true : !!assistantText && assistantText.indexOf(INDEXING_COMPLETE_MARKER) !== -1);
|
|
1968
2441
|
if (reportedComplete) assistantText = assistantText.split(INDEXING_COMPLETE_MARKER).join("").trim();
|
|
1969
2442
|
var serverItemId = item && typeof item.id === "string" && item.id ? item.id : void 0;
|
|
1970
2443
|
var createdTs = Number(item && item.created);
|
|
@@ -1993,9 +2466,11 @@ function mapHistoryListToMessages(list, platform, opts) {
|
|
|
1993
2466
|
displayContent = sanitizeAttachmentLinksForHistory(userText, opts.projectId);
|
|
1994
2467
|
}
|
|
1995
2468
|
var userMsg = { role: "user", content: displayContent };
|
|
2469
|
+
if (item._fromBgChain) userMsg._fromBgChain = true;
|
|
1996
2470
|
if (isInProcess) userMsg.isPendingInProcess = true;
|
|
1997
2471
|
if (isQueued) userMsg.isPendingQueued = true;
|
|
1998
2472
|
if (isCancelledItem) userMsg.isCancelled = true;
|
|
2473
|
+
if (isCompact) userMsg._compact = true;
|
|
1999
2474
|
if (item._isBgTask) userMsg.isBackgroundTask = true;
|
|
2000
2475
|
if (indexFile) userMsg._indexFile = indexFile;
|
|
2001
2476
|
if (item._isOnBgQueue) userMsg._useBgQueue = true;
|
|
@@ -2005,6 +2480,8 @@ function mapHistoryListToMessages(list, platform, opts) {
|
|
|
2005
2480
|
}
|
|
2006
2481
|
if (isCancelledItem) ; else if (isInProcess) {
|
|
2007
2482
|
var ph = { role: "assistant", content: "", isPending: true, isPendingInProcess: true };
|
|
2483
|
+
if (userTs !== void 0) ph._ts = userTs;
|
|
2484
|
+
if (item._fromBgChain) ph._fromBgChain = true;
|
|
2008
2485
|
if (item._isBgTask) ph.isBackgroundTask = true;
|
|
2009
2486
|
if (serverItemId !== void 0) {
|
|
2010
2487
|
ph._serverItemId = serverItemId;
|
|
@@ -2013,19 +2490,26 @@ function mapHistoryListToMessages(list, platform, opts) {
|
|
|
2013
2490
|
mapped.push(ph);
|
|
2014
2491
|
} else if (isQueued) ; else if (isErrorResponse) {
|
|
2015
2492
|
var em = { role: "assistant", content: getErrorMessage(response), isError: true };
|
|
2493
|
+
if (item._fromBgChain) em._fromBgChain = true;
|
|
2016
2494
|
if (item._isBgTask) em.isBackgroundTask = true;
|
|
2017
2495
|
if (serverItemId !== void 0) em._serverItemId = serverItemId;
|
|
2018
2496
|
if (replyTs !== void 0) em._ts = replyTs;
|
|
2019
2497
|
mapped.push(em);
|
|
2020
2498
|
} else if (assistantText || reportedComplete) {
|
|
2021
2499
|
var okm = { role: "assistant", content: sanitizeAttachmentLinksForHistory(assistantText, opts.projectId, true) || EMPTY_INDEXING_REPLY };
|
|
2500
|
+
if (item._fromBgChain) okm._fromBgChain = true;
|
|
2022
2501
|
if (item._isBgTask) okm.isBackgroundTask = true;
|
|
2502
|
+
if (isCompact) okm._compact = true;
|
|
2023
2503
|
if (serverItemId !== void 0) okm._serverItemId = serverItemId;
|
|
2024
2504
|
if (replyTs !== void 0) okm._ts = replyTs;
|
|
2025
2505
|
if (reportedComplete) okm._indexComplete = true;
|
|
2026
2506
|
mapped.push(okm);
|
|
2027
2507
|
}
|
|
2028
2508
|
});
|
|
2509
|
+
if (opts.projectId) {
|
|
2510
|
+
var ownerKey = opts.projectId + "#" + platform;
|
|
2511
|
+
for (var oi = 0; oi < mapped.length; oi++) mapped[oi]._ownerKey = ownerKey;
|
|
2512
|
+
}
|
|
2029
2513
|
return { messages: mapped, runningItemIds };
|
|
2030
2514
|
}
|
|
2031
2515
|
|
|
@@ -2143,6 +2627,7 @@ var INDEXING_DRAIN_BUSY_POLL_MS = 8e3;
|
|
|
2143
2627
|
var INDEXING_DRAIN_CONFIRM_POLL_MS = 3e3;
|
|
2144
2628
|
var INDEXING_DRAIN_IDLE_LOOKS = 2;
|
|
2145
2629
|
var INDEXING_DRAIN_MIN_MS = 8e3;
|
|
2630
|
+
var _bgHistoryBatchSeq = 0;
|
|
2146
2631
|
var INDEXING_DRAIN_TIMEOUT_MS = 15 * 60 * 1e3;
|
|
2147
2632
|
var INDEXING_DRAIN_LOOK_TIMEOUT_MS = 45e3;
|
|
2148
2633
|
var INDEXING_DRAIN_NUDGE_MIN_GAP_MS = 1500;
|
|
@@ -2164,6 +2649,14 @@ function isPollStopped(res) {
|
|
|
2164
2649
|
}
|
|
2165
2650
|
var ChatSession = class {
|
|
2166
2651
|
constructor(host) {
|
|
2652
|
+
// ─── compact-stub hydration ─────────────────────────────────────────────
|
|
2653
|
+
// Split-fetch bg pages arrive as label stubs (no bodies). When the user
|
|
2654
|
+
// expands a row, the real reply text is fetched per item (csr-poll point
|
|
2655
|
+
// lookup) and MEMOIZED per chat: every later remap (first-page refresh,
|
|
2656
|
+
// queue-detect tick, cache restore) re-applies the memo, so a hydrated
|
|
2657
|
+
// bubble can never silently revert to its 200-char head.
|
|
2658
|
+
this._hydratedBodies = {};
|
|
2659
|
+
this._hydratingItems = {};
|
|
2167
2660
|
this.typewriterQueue = Promise.resolve();
|
|
2168
2661
|
/**
|
|
2169
2662
|
* Pick up indexing passes the WORKER minted, which no client ever dispatched.
|
|
@@ -2204,6 +2697,9 @@ var ChatSession = class {
|
|
|
2204
2697
|
typingAbort: false,
|
|
2205
2698
|
loadingHistory: false,
|
|
2206
2699
|
loadingOlderHistory: false,
|
|
2700
|
+
// A deferred bg stub batch (first-paint split) is still in flight; the
|
|
2701
|
+
// views show a small 'loading indexing history' hint while true.
|
|
2702
|
+
bgHistoryLoading: false,
|
|
2207
2703
|
historyEndOfList: false,
|
|
2208
2704
|
historyStartKeyHistory: [],
|
|
2209
2705
|
historyRequestToken: 0,
|
|
@@ -2353,10 +2849,12 @@ var ChatSession = class {
|
|
|
2353
2849
|
}
|
|
2354
2850
|
var queue = bgIndexingQueueName(id.userId, id.projectId);
|
|
2355
2851
|
var ask = function(status) {
|
|
2356
|
-
return Promise.resolve(
|
|
2357
|
-
{ service: id.projectId, owner: id.owner, platform, queue, status },
|
|
2358
|
-
{
|
|
2359
|
-
)).
|
|
2852
|
+
return Promise.resolve(probeBgQueue(
|
|
2853
|
+
{ service: id.projectId, owner: id.owner, platform, queue, status, limit: WORKER_PASS_ADOPT_LIMIT },
|
|
2854
|
+
{ maxAgeMs: BG_PROBE_TTL_MS }
|
|
2855
|
+
)).then(function(entry) {
|
|
2856
|
+
return entry.result;
|
|
2857
|
+
}).catch(function() {
|
|
2360
2858
|
return null;
|
|
2361
2859
|
});
|
|
2362
2860
|
};
|
|
@@ -2448,7 +2946,7 @@ var ChatSession = class {
|
|
|
2448
2946
|
* instead of merely unconfirmed.
|
|
2449
2947
|
*/
|
|
2450
2948
|
refreshLiveIndexState() {
|
|
2451
|
-
this._adoptWorkerIndexingPasses(0);
|
|
2949
|
+
this._adoptWorkerIndexingPasses(0, true);
|
|
2452
2950
|
}
|
|
2453
2951
|
/** Forget what we know about which files are indexing — but ONLY when the
|
|
2454
2952
|
* snapshot was taken for a different chat than the one on screen now. For a
|
|
@@ -2625,6 +3123,66 @@ var ChatSession = class {
|
|
|
2625
3123
|
if (!id.projectId || id.platform === "none") return "";
|
|
2626
3124
|
return id.projectId + "#" + id.platform;
|
|
2627
3125
|
}
|
|
3126
|
+
/** Re-apply memoized hydrated texts onto freshly-mapped messages. Both
|
|
3127
|
+
* clients call this right after their mapper runs (loadHistory does it
|
|
3128
|
+
* internally); it mutates the given array's items in place. */
|
|
3129
|
+
applyHydratedBodies(messages) {
|
|
3130
|
+
var key = this.getHistoryCacheKey();
|
|
3131
|
+
var memo = key ? this._hydratedBodies[key] : null;
|
|
3132
|
+
if (!memo) return;
|
|
3133
|
+
var id = this.host.getIdentity();
|
|
3134
|
+
for (var i = 0; i < messages.length; i++) {
|
|
3135
|
+
var m = messages[i];
|
|
3136
|
+
if (!m || !m._compact || m.role !== "assistant" || !m._serverItemId) continue;
|
|
3137
|
+
var text = memo[m._serverItemId];
|
|
3138
|
+
if (typeof text !== "string") continue;
|
|
3139
|
+
m.content = sanitizeAttachmentLinksForHistory(text, id.projectId, true) || EMPTY_INDEXING_REPLY;
|
|
3140
|
+
delete m._compact;
|
|
3141
|
+
}
|
|
3142
|
+
}
|
|
3143
|
+
/** Fetch the real response bodies for compact history stubs (one csr-poll
|
|
3144
|
+
* point lookup per item id), memoize, and swap them into the live list.
|
|
3145
|
+
* Best-effort: a failed lookup leaves the stub (its head + fallback line
|
|
3146
|
+
* still render) and a later expand retries. */
|
|
3147
|
+
hydrateCompactItems(itemIds) {
|
|
3148
|
+
var self = this;
|
|
3149
|
+
var lookup = chatEngineConfig().csrHistoryItemLookup;
|
|
3150
|
+
if (!lookup || !itemIds || !itemIds.length) return Promise.resolve();
|
|
3151
|
+
var id = this.host.getIdentity();
|
|
3152
|
+
var platform = id.platform;
|
|
3153
|
+
if (!id.projectId || platform !== "claude" && platform !== "openai") return Promise.resolve();
|
|
3154
|
+
var chatKey = this.getHistoryCacheKey();
|
|
3155
|
+
if (!chatKey) return Promise.resolve();
|
|
3156
|
+
var jobs = itemIds.map(function(itemId) {
|
|
3157
|
+
if (!itemId) return Promise.resolve();
|
|
3158
|
+
var already = self._hydratedBodies[chatKey] && self._hydratedBodies[chatKey][itemId] !== void 0;
|
|
3159
|
+
var inflightKey = chatKey + "|" + itemId;
|
|
3160
|
+
if (already || self._hydratingItems[inflightKey]) return Promise.resolve();
|
|
3161
|
+
self._hydratingItems[inflightKey] = true;
|
|
3162
|
+
return Promise.resolve(lookup(buildHistoryItemFullId(platform, id.projectId, itemId), id.projectId, id.owner)).then(function(body) {
|
|
3163
|
+
var text = ((platform === "openai" ? extractOpenAIText(body) : extractClaudeText(body)) || "").trim();
|
|
3164
|
+
if (text.indexOf(INDEXING_COMPLETE_MARKER) !== -1) text = text.split(INDEXING_COMPLETE_MARKER).join("").trim();
|
|
3165
|
+
if (!self._hydratedBodies[chatKey]) self._hydratedBodies[chatKey] = {};
|
|
3166
|
+
self._hydratedBodies[chatKey][itemId] = text;
|
|
3167
|
+
if (self.getHistoryCacheKey() !== chatKey) return;
|
|
3168
|
+
for (var i = 0; i < self.state.messages.length; i++) {
|
|
3169
|
+
var m = self.state.messages[i];
|
|
3170
|
+
if (m && m._compact && m.role === "assistant" && m._serverItemId === itemId) {
|
|
3171
|
+
m.content = sanitizeAttachmentLinksForHistory(text, id.projectId, true) || EMPTY_INDEXING_REPLY;
|
|
3172
|
+
delete m._compact;
|
|
3173
|
+
}
|
|
3174
|
+
}
|
|
3175
|
+
}).catch(function() {
|
|
3176
|
+
}).then(function() {
|
|
3177
|
+
delete self._hydratingItems[inflightKey];
|
|
3178
|
+
});
|
|
3179
|
+
});
|
|
3180
|
+
return Promise.all(jobs).then(function() {
|
|
3181
|
+
if (self.getHistoryCacheKey() !== chatKey) return;
|
|
3182
|
+
self.host.notify();
|
|
3183
|
+
self.updateHistoryCache();
|
|
3184
|
+
});
|
|
3185
|
+
}
|
|
2628
3186
|
updateHistoryCache() {
|
|
2629
3187
|
var key = this.getHistoryCacheKey();
|
|
2630
3188
|
if (!key) return;
|
|
@@ -2947,11 +3505,11 @@ var ChatSession = class {
|
|
|
2947
3505
|
bail = setTimeout(function() {
|
|
2948
3506
|
settle(null);
|
|
2949
3507
|
}, INDEXING_DRAIN_LOOK_TIMEOUT_MS);
|
|
2950
|
-
Promise.resolve(
|
|
2951
|
-
{ service: svcId, owner, platform, queue, status },
|
|
2952
|
-
{
|
|
2953
|
-
)).then(function(
|
|
2954
|
-
settle(
|
|
3508
|
+
Promise.resolve(probeBgQueue(
|
|
3509
|
+
{ service: svcId, owner, platform, queue, status, limit: WORKER_PASS_ADOPT_LIMIT },
|
|
3510
|
+
{ maxAgeMs: 0 }
|
|
3511
|
+
)).then(function(entry) {
|
|
3512
|
+
settle(entry.result);
|
|
2955
3513
|
}, function() {
|
|
2956
3514
|
settle(null);
|
|
2957
3515
|
});
|
|
@@ -3578,6 +4136,32 @@ var ChatSession = class {
|
|
|
3578
4136
|
if (e && e.id && self._indexKeyOf(e) === scoped) stoppedIds[e.id] = true;
|
|
3579
4137
|
});
|
|
3580
4138
|
this.state.stoppedIndexIds = stoppedIds;
|
|
4139
|
+
var runPath = group.path || "";
|
|
4140
|
+
if (!runPath) {
|
|
4141
|
+
(group.members || []).some(function(m) {
|
|
4142
|
+
var p = m && m.msg && m.msg._indexFile && m.msg._indexFile.path;
|
|
4143
|
+
if (p) {
|
|
4144
|
+
runPath = p;
|
|
4145
|
+
return true;
|
|
4146
|
+
}
|
|
4147
|
+
return false;
|
|
4148
|
+
});
|
|
4149
|
+
}
|
|
4150
|
+
if (!runPath) {
|
|
4151
|
+
this.bgTaskQueue.some(function(e) {
|
|
4152
|
+
if (e && e.storagePath && self._indexKeyOf(e) === scoped) {
|
|
4153
|
+
runPath = e.storagePath;
|
|
4154
|
+
return true;
|
|
4155
|
+
}
|
|
4156
|
+
return false;
|
|
4157
|
+
});
|
|
4158
|
+
}
|
|
4159
|
+
if (runPath) {
|
|
4160
|
+
var ident = this.host.getIdentity();
|
|
4161
|
+
if (ident && ident.projectId) {
|
|
4162
|
+
upsertIndexRunRecordSafe(ident.projectId, runPath, { status: "cancelled", finished: Date.now() });
|
|
4163
|
+
}
|
|
4164
|
+
}
|
|
3581
4165
|
}
|
|
3582
4166
|
this._adoptWorkerIndexingPasses(0);
|
|
3583
4167
|
var ids = group.cancellableIds || [];
|
|
@@ -4091,7 +4675,7 @@ var ChatSession = class {
|
|
|
4091
4675
|
if (isImageVisionFile(filename, mime)) return true;
|
|
4092
4676
|
return windowedIndexingEnabled() && isWindowedReadFile(filename, mime);
|
|
4093
4677
|
}
|
|
4094
|
-
_adoptWorkerIndexingPasses(attempt) {
|
|
4678
|
+
_adoptWorkerIndexingPasses(attempt, passive) {
|
|
4095
4679
|
var self = this;
|
|
4096
4680
|
if (this._adoptingWorkerPasses) return;
|
|
4097
4681
|
var id = this.host.getIdentity();
|
|
@@ -4101,10 +4685,12 @@ var ChatSession = class {
|
|
|
4101
4685
|
var svcId = id.projectId, owner = id.owner;
|
|
4102
4686
|
var queue = bgIndexingQueueName(id.userId, id.projectId);
|
|
4103
4687
|
var ask = function(status) {
|
|
4104
|
-
return Promise.resolve(
|
|
4105
|
-
{ service: svcId, owner, platform, queue, status },
|
|
4106
|
-
{
|
|
4107
|
-
)).
|
|
4688
|
+
return Promise.resolve(probeBgQueue(
|
|
4689
|
+
{ service: svcId, owner, platform, queue, status, limit: WORKER_PASS_ADOPT_LIMIT },
|
|
4690
|
+
{ maxAgeMs: 0 }
|
|
4691
|
+
)).then(function(entry) {
|
|
4692
|
+
return entry.result;
|
|
4693
|
+
}).catch(function() {
|
|
4108
4694
|
return null;
|
|
4109
4695
|
});
|
|
4110
4696
|
};
|
|
@@ -4126,6 +4712,7 @@ var ChatSession = class {
|
|
|
4126
4712
|
self.drainBgTaskQueue();
|
|
4127
4713
|
if (self._isTrackingAny(adoptedIds)) return;
|
|
4128
4714
|
}
|
|
4715
|
+
if (passive && !self._hasLiveIndexEvidence(svcId)) return;
|
|
4129
4716
|
if (attempt + 1 >= WORKER_PASS_ADOPT_ATTEMPTS.length) {
|
|
4130
4717
|
self._nudgeIndexingDrain();
|
|
4131
4718
|
return;
|
|
@@ -4134,12 +4721,30 @@ var ChatSession = class {
|
|
|
4134
4721
|
var later = self.host.getIdentity();
|
|
4135
4722
|
if (later.projectId !== svcId || later.platform !== platform) return;
|
|
4136
4723
|
if (self.isPollingPaused() || !self.host.isViewMounted()) return;
|
|
4137
|
-
self._adoptWorkerIndexingPasses(attempt + 1);
|
|
4724
|
+
self._adoptWorkerIndexingPasses(attempt + 1, passive);
|
|
4138
4725
|
}, WORKER_PASS_ADOPT_ATTEMPTS[attempt + 1]);
|
|
4139
4726
|
}, function() {
|
|
4140
4727
|
self._adoptingWorkerPasses = false;
|
|
4141
4728
|
});
|
|
4142
4729
|
}
|
|
4730
|
+
/** Anything at all suggesting THIS project's indexing may be live: a queued
|
|
4731
|
+
* local entry, a recorded live key (the adopt look just wrote them), or an
|
|
4732
|
+
* attached poll. Gates the passive adopt ladder's climb. */
|
|
4733
|
+
_hasLiveIndexEvidence(svcId) {
|
|
4734
|
+
for (var i = 0; i < this.bgTaskQueue.length; i++) {
|
|
4735
|
+
var e = this.bgTaskQueue[i];
|
|
4736
|
+
if (e && e.projectId === svcId) return true;
|
|
4737
|
+
}
|
|
4738
|
+
var keys = this.state.liveIndexKeys || {};
|
|
4739
|
+
for (var k in keys) {
|
|
4740
|
+
if (keys[k]) return true;
|
|
4741
|
+
}
|
|
4742
|
+
var found = false;
|
|
4743
|
+
this.historyItemPolls.forEach(function(h) {
|
|
4744
|
+
if (h && h.kind === "bg") found = true;
|
|
4745
|
+
});
|
|
4746
|
+
return found;
|
|
4747
|
+
}
|
|
4143
4748
|
/** Any of these ids still queued or still polled, i.e. surviving work. */
|
|
4144
4749
|
_isTrackingAny(ids) {
|
|
4145
4750
|
for (var i = 0; i < ids.length; i++) {
|
|
@@ -4230,7 +4835,10 @@ var ChatSession = class {
|
|
|
4230
4835
|
for (var i = this.bgTaskQueue.length - 1; i >= 0; i--) {
|
|
4231
4836
|
var e = this.bgTaskQueue[i];
|
|
4232
4837
|
if (e.projectId !== svcId || e.platform !== plat) continue;
|
|
4233
|
-
if (presentIds[e.id] && !pendingIds[e.id])
|
|
4838
|
+
if (presentIds[e.id] && !pendingIds[e.id]) {
|
|
4839
|
+
this._flipRunFromSettledEntry(e);
|
|
4840
|
+
this.bgTaskQueue.splice(i, 1);
|
|
4841
|
+
}
|
|
4234
4842
|
}
|
|
4235
4843
|
var bgPollBudget = MAX_CONCURRENT_BG_POLLS - this._countBgPolls();
|
|
4236
4844
|
var injectedAny = false;
|
|
@@ -4304,6 +4912,8 @@ var ChatSession = class {
|
|
|
4304
4912
|
self.host.notify();
|
|
4305
4913
|
self.updateHistoryCache();
|
|
4306
4914
|
if (!self._isWorkerDrivenIndexing(capturedEntry.filename, capturedEntry.mime)) {
|
|
4915
|
+
if (isNotExists) self._flipRunRecord(capturedEntry, "cancelled");
|
|
4916
|
+
else self._flipRunRecord(capturedEntry, "error", self._runErrorText(err));
|
|
4307
4917
|
self._nudgeIndexingDrain();
|
|
4308
4918
|
}
|
|
4309
4919
|
}).then(function() {
|
|
@@ -4335,6 +4945,74 @@ var ChatSession = class {
|
|
|
4335
4945
|
// memory (a reload or a closed tab ended it), and it stopped whenever the model claimed
|
|
4336
4946
|
// completion, which on an 88-page file happened at page 15. Continuing to dispatch here
|
|
4337
4947
|
// as well would now double-index every window.
|
|
4948
|
+
/** Fire the consumer's done::-marker hook for a run whose completion this
|
|
4949
|
+
* client knows DETERMINISTICALLY (see the two call sites in
|
|
4950
|
+
* maybeResumeIndexing). Best-effort by contract; identity-checked so a
|
|
4951
|
+
* project switch mid-settle cannot stamp the wrong service. */
|
|
4952
|
+
_mintDoneMarker(entry) {
|
|
4953
|
+
try {
|
|
4954
|
+
var mint = chatEngineConfig().mintIndexDoneMarker;
|
|
4955
|
+
if (!mint || !entry || !entry.storagePath || !entry.projectId) return;
|
|
4956
|
+
var id = this.host.getIdentity();
|
|
4957
|
+
if (!id || id.projectId !== entry.projectId) return;
|
|
4958
|
+
mint({ service: entry.projectId, storagePath: entry.storagePath });
|
|
4959
|
+
} catch (_e) {
|
|
4960
|
+
}
|
|
4961
|
+
}
|
|
4962
|
+
/** Short, storable form of an error body for the run:: record. */
|
|
4963
|
+
_runErrorText(response) {
|
|
4964
|
+
var msg = "";
|
|
4965
|
+
try {
|
|
4966
|
+
msg = String(getErrorMessage(response) || "");
|
|
4967
|
+
} catch (_e) {
|
|
4968
|
+
}
|
|
4969
|
+
msg = msg.replace(/\s+/g, " ").trim();
|
|
4970
|
+
return msg ? msg.slice(0, 300) : "Indexing failed.";
|
|
4971
|
+
}
|
|
4972
|
+
/** Close the records of a run whose pass settled OFF-POLL — the answer came
|
|
4973
|
+
* back as history (hidden tab, dead poll, resume refetch), so none of the
|
|
4974
|
+
* poll-side settle handlers ran. Only for SINGLE-PASS files, where one
|
|
4975
|
+
* settled pass is deterministically the whole run (the same contract as
|
|
4976
|
+
* maybeResumeIndexing's single-pass branch); paged files stay with their
|
|
4977
|
+
* drivers. Outcome is read from the settled bubbles' own flags, which is
|
|
4978
|
+
* all the history mapping left us. Best-effort and idempotent throughout. */
|
|
4979
|
+
_flipRunFromSettledEntry(entry) {
|
|
4980
|
+
try {
|
|
4981
|
+
if (!entry || !entry.storagePath || !entry.id || !entry.projectId) return;
|
|
4982
|
+
if (isPagedReadFile(entry.filename, entry.mime)) return;
|
|
4983
|
+
if (this.cancelledIndexKeys.has(this._indexKeyOf(entry))) return;
|
|
4984
|
+
if (this.state.stoppedIndexIds[entry.id]) return;
|
|
4985
|
+
var userMsg = null, replyMsg = null;
|
|
4986
|
+
this.state.messages.forEach(function(m) {
|
|
4987
|
+
if (m._serverItemId !== entry.id) return;
|
|
4988
|
+
if (m.role === "user") {
|
|
4989
|
+
if (!userMsg) userMsg = m;
|
|
4990
|
+
} else if (!replyMsg) replyMsg = m;
|
|
4991
|
+
});
|
|
4992
|
+
if (userMsg && userMsg.isCancelled || replyMsg && replyMsg.isCancelled) {
|
|
4993
|
+
this._flipRunRecord(entry, "cancelled");
|
|
4994
|
+
} else if (replyMsg && replyMsg.isError) {
|
|
4995
|
+
var errText = typeof replyMsg.content === "string" ? replyMsg.content.replace(/\s+/g, " ").trim().slice(0, 300) : "";
|
|
4996
|
+
this._flipRunRecord(entry, "error", errText || "Indexing failed.");
|
|
4997
|
+
} else if (replyMsg) {
|
|
4998
|
+
this._mintDoneMarker(entry);
|
|
4999
|
+
this._flipRunRecord(entry, "done");
|
|
5000
|
+
}
|
|
5001
|
+
} catch (_e) {
|
|
5002
|
+
}
|
|
5003
|
+
}
|
|
5004
|
+
/** Close the durable run:: record for an ending THIS client observed.
|
|
5005
|
+
* service comes from the ENTRY, not the current identity: unlike the done::
|
|
5006
|
+
* mint above, a status flip must land even if the user switched projects
|
|
5007
|
+
* mid-settle — otherwise the record lies 'working' forever. Best-effort
|
|
5008
|
+
* through upsertIndexRunRecordSafe; the consumer's precedence guard keeps
|
|
5009
|
+
* repeats and races harmless. */
|
|
5010
|
+
_flipRunRecord(entry, status, error) {
|
|
5011
|
+
if (!entry || !entry.storagePath || !entry.projectId) return;
|
|
5012
|
+
var patch = { status, finished: Date.now() };
|
|
5013
|
+
if (error) patch.error = error;
|
|
5014
|
+
upsertIndexRunRecordSafe(entry.projectId, entry.storagePath, patch);
|
|
5015
|
+
}
|
|
4338
5016
|
maybeResumeIndexing(entry, response, platform) {
|
|
4339
5017
|
var self = this;
|
|
4340
5018
|
var endOfClientChain = function() {
|
|
@@ -4344,27 +5022,43 @@ var ChatSession = class {
|
|
|
4344
5022
|
if (!entry || !entry.storagePath) return;
|
|
4345
5023
|
if (this.cancelledIndexKeys.has(this._indexKeyOf(entry))) return;
|
|
4346
5024
|
if (!isPagedReadFile(entry.filename, entry.mime)) {
|
|
5025
|
+
if (!isErrorResponseBody(response) && !this._isCancelledPollResult(response)) {
|
|
5026
|
+
this._mintDoneMarker(entry);
|
|
5027
|
+
this._flipRunRecord(entry, "done");
|
|
5028
|
+
} else if (this._isCancelledPollResult(response)) {
|
|
5029
|
+
this._flipRunRecord(entry, "cancelled");
|
|
5030
|
+
} else {
|
|
5031
|
+
this._flipRunRecord(entry, "error", this._runErrorText(response));
|
|
5032
|
+
}
|
|
4347
5033
|
endOfClientChain();
|
|
4348
5034
|
return;
|
|
4349
5035
|
}
|
|
4350
5036
|
if (isImageVisionFile(entry.filename, entry.mime)) return;
|
|
4351
5037
|
if (windowedIndexingEnabled() && isWindowedReadFile(entry.filename, entry.mime)) return;
|
|
4352
5038
|
if (isErrorResponseBody(response)) {
|
|
5039
|
+
this._flipRunRecord(entry, "error", this._runErrorText(response));
|
|
4353
5040
|
endOfClientChain();
|
|
4354
5041
|
return;
|
|
4355
5042
|
}
|
|
4356
5043
|
var answer = (platform === "openai" ? extractOpenAIText(response) : extractClaudeText(response)) || "";
|
|
4357
5044
|
if (answer.indexOf(INDEXING_COMPLETE_MARKER) !== -1) {
|
|
5045
|
+
this._mintDoneMarker(entry);
|
|
5046
|
+
this._flipRunRecord(entry, "done");
|
|
4358
5047
|
endOfClientChain();
|
|
4359
5048
|
return;
|
|
4360
5049
|
}
|
|
4361
5050
|
var pass = (entry.resumePass || 0) + 1;
|
|
4362
5051
|
if (pass > MAX_INDEXING_RESUME_PASSES) {
|
|
5052
|
+
this._flipRunRecord(entry, "error", "Stopped after " + MAX_INDEXING_RESUME_PASSES + " passes without finishing.");
|
|
4363
5053
|
endOfClientChain();
|
|
4364
5054
|
return;
|
|
4365
5055
|
}
|
|
4366
5056
|
var id = this.host.getIdentity();
|
|
4367
|
-
if (!id || id.platform === "none" || id.projectId !== entry.projectId)
|
|
5057
|
+
if (!id || id.platform === "none" || id.projectId !== entry.projectId) {
|
|
5058
|
+
this._flipRunRecord(entry, "error", "Indexing stopped: the session or project changed before the file finished.");
|
|
5059
|
+
endOfClientChain();
|
|
5060
|
+
return;
|
|
5061
|
+
}
|
|
4368
5062
|
this.trackIndexDispatch(notifyAgentContinueIndexing({
|
|
4369
5063
|
platform: id.platform,
|
|
4370
5064
|
model: id.model,
|
|
@@ -4441,8 +5135,9 @@ var ChatSession = class {
|
|
|
4441
5135
|
var projectId = id.projectId, owner = id.owner;
|
|
4442
5136
|
var options = { fetchMore };
|
|
4443
5137
|
if (fetchMore && this.state.historyStartKeyHistory.length) options.startKeyHistory = this.state.historyStartKeyHistory.slice();
|
|
5138
|
+
if (!fetchMore) options.deferBg = true;
|
|
4444
5139
|
var fetchHistory = function() {
|
|
4445
|
-
return
|
|
5140
|
+
return getSplitChatHistory({ service: projectId, owner, platform, userId: id.userId }, options);
|
|
4446
5141
|
};
|
|
4447
5142
|
return Promise.resolve().then(fetchHistory).catch(function(err) {
|
|
4448
5143
|
if (isAuthExpiredError(err) && !isNonRetryableRequestError(err)) return self.host.refreshSession().then(fetchHistory);
|
|
@@ -4452,7 +5147,8 @@ var ChatSession = class {
|
|
|
4452
5147
|
var chatList = history && Array.isArray(history.list) ? history.list : [];
|
|
4453
5148
|
chatList.forEach(function(item) {
|
|
4454
5149
|
if (isBgIndexingQueue(item.queue_name)) {
|
|
4455
|
-
|
|
5150
|
+
var clsText = item.compact ? item.request_text : extractLastUserTextFromRequest(item.request_body);
|
|
5151
|
+
if (isIndexingRequestText(clsText)) item._isBgTask = true;
|
|
4456
5152
|
else item._isOnBgQueue = true;
|
|
4457
5153
|
}
|
|
4458
5154
|
});
|
|
@@ -4465,15 +5161,55 @@ var ChatSession = class {
|
|
|
4465
5161
|
projectId: id.projectId,
|
|
4466
5162
|
formatIndexingLabel: self.host.formatIndexingLabel
|
|
4467
5163
|
}).messages;
|
|
5164
|
+
self.applyHydratedBodies(mapped);
|
|
4468
5165
|
var keptOlderPages = false;
|
|
5166
|
+
var keptScreenAwaitingBg = false;
|
|
4469
5167
|
if (fetchMore) {
|
|
4470
|
-
|
|
5168
|
+
var incomingKeys = {};
|
|
5169
|
+
mapped.forEach(function(m) {
|
|
5170
|
+
if (m._serverItemId) incomingKeys[m._serverItemId + "|" + m.role] = m;
|
|
5171
|
+
});
|
|
5172
|
+
var existing = self.state.messages.filter(function(m) {
|
|
5173
|
+
if (!m._serverItemId) return true;
|
|
5174
|
+
var inc = incomingKeys[m._serverItemId + "|" + m.role];
|
|
5175
|
+
if (!inc) return true;
|
|
5176
|
+
if (m._cancelling) inc._cancelling = m._cancelling;
|
|
5177
|
+
if (m._cancelError) inc._cancelError = m._cancelError;
|
|
5178
|
+
return false;
|
|
5179
|
+
});
|
|
5180
|
+
var mergedList = [];
|
|
5181
|
+
var pi = 0, ei = 0;
|
|
5182
|
+
while (pi < mapped.length && ei < existing.length) {
|
|
5183
|
+
var pm = mapped[pi], em = existing[ei];
|
|
5184
|
+
var eid = em._serverItemId;
|
|
5185
|
+
if (typeof eid !== "string") break;
|
|
5186
|
+
var pid = pm._serverItemId;
|
|
5187
|
+
if (typeof pid !== "string" || pid <= eid) {
|
|
5188
|
+
mergedList.push(pm);
|
|
5189
|
+
pi++;
|
|
5190
|
+
} else {
|
|
5191
|
+
mergedList.push(em);
|
|
5192
|
+
ei++;
|
|
5193
|
+
}
|
|
5194
|
+
}
|
|
5195
|
+
while (pi < mapped.length) mergedList.push(mapped[pi++]);
|
|
5196
|
+
while (ei < existing.length) mergedList.push(existing[ei++]);
|
|
5197
|
+
self.state.messages = mergedList;
|
|
5198
|
+
} else if (!mapped.length && history && (history.endOfList === false || history.bgPending) && self.state.messages.some(function(m) {
|
|
5199
|
+
return m._ownerKey === void 0 || m._ownerKey === loadKey;
|
|
5200
|
+
})) {
|
|
5201
|
+
if (history.endOfList !== false) keptScreenAwaitingBg = true;
|
|
4471
5202
|
} else {
|
|
4472
5203
|
if (self.state.typing) self.state.typingAbort = true;
|
|
4473
5204
|
var serverIds = {};
|
|
4474
5205
|
mapped.forEach(function(m) {
|
|
4475
5206
|
if (m._serverItemId) serverIds[m._serverItemId] = 1;
|
|
4476
5207
|
});
|
|
5208
|
+
var surfaceOldestId = void 0;
|
|
5209
|
+
mapped.forEach(function(m) {
|
|
5210
|
+
if (typeof m._serverItemId !== "string" || m._fromBgChain) return;
|
|
5211
|
+
if (surfaceOldestId === void 0 || m._serverItemId < surfaceOldestId) surfaceOldestId = m._serverItemId;
|
|
5212
|
+
});
|
|
4477
5213
|
var locallyCancelled = {};
|
|
4478
5214
|
self.state.messages.forEach(function(m) {
|
|
4479
5215
|
if (m.isCancelled && m._serverItemId) locallyCancelled[m._serverItemId] = m;
|
|
@@ -4514,13 +5250,45 @@ var ChatSession = class {
|
|
|
4514
5250
|
var sharesPage1 = self.state.messages.some(function(m) {
|
|
4515
5251
|
return typeof m._serverItemId === "string" && !!serverIds[m._serverItemId];
|
|
4516
5252
|
});
|
|
4517
|
-
var
|
|
5253
|
+
var deferredBg = !!(history && history.bgPending);
|
|
5254
|
+
var retainBoundary = surfaceOldestId !== void 0 ? surfaceOldestId : oldestInPage1;
|
|
5255
|
+
var retainedOlder = !sharesPage1 || retainBoundary === void 0 ? [] : self.state.messages.filter(function(m) {
|
|
4518
5256
|
if (typeof m._serverItemId !== "string") return false;
|
|
4519
5257
|
if (m._ownerKey !== void 0 && m._ownerKey !== loadKey) return false;
|
|
4520
|
-
|
|
5258
|
+
if (deferredBg && m.isBackgroundTask) return true;
|
|
5259
|
+
if (m._fromBgChain) return true;
|
|
5260
|
+
return m._serverItemId < retainBoundary;
|
|
5261
|
+
});
|
|
5262
|
+
var prependOlder = [];
|
|
5263
|
+
var interleave = [];
|
|
5264
|
+
retainedOlder.forEach(function(m) {
|
|
5265
|
+
var sid = m._serverItemId;
|
|
5266
|
+
if (serverIds[sid]) return;
|
|
5267
|
+
if (retainBoundary !== void 0 && sid < retainBoundary) prependOlder.push(m);
|
|
5268
|
+
else interleave.push(m);
|
|
4521
5269
|
});
|
|
4522
|
-
|
|
4523
|
-
|
|
5270
|
+
var page1 = mapped;
|
|
5271
|
+
if (interleave.length) {
|
|
5272
|
+
var mergedP = [];
|
|
5273
|
+
var ii2 = 0, mi2 = 0;
|
|
5274
|
+
while (ii2 < interleave.length && mi2 < mapped.length) {
|
|
5275
|
+
var iv = interleave[ii2], mv = mapped[mi2];
|
|
5276
|
+
var mid2 = typeof mv._serverItemId === "string" ? mv._serverItemId : void 0;
|
|
5277
|
+
if (mid2 === void 0) break;
|
|
5278
|
+
if (iv._serverItemId <= mid2) {
|
|
5279
|
+
mergedP.push(iv);
|
|
5280
|
+
ii2++;
|
|
5281
|
+
} else {
|
|
5282
|
+
mergedP.push(mv);
|
|
5283
|
+
mi2++;
|
|
5284
|
+
}
|
|
5285
|
+
}
|
|
5286
|
+
while (ii2 < interleave.length) mergedP.push(interleave[ii2++]);
|
|
5287
|
+
while (mi2 < mapped.length) mergedP.push(mapped[mi2++]);
|
|
5288
|
+
page1 = mergedP;
|
|
5289
|
+
}
|
|
5290
|
+
keptOlderPages = prependOlder.length > 0 || interleave.length > 0;
|
|
5291
|
+
self.state.messages = prependOlder.length ? prependOlder.concat(page1) : page1;
|
|
4524
5292
|
rescued.forEach(function(m) {
|
|
4525
5293
|
self.state.messages.push(m);
|
|
4526
5294
|
});
|
|
@@ -4556,9 +5324,14 @@ var ChatSession = class {
|
|
|
4556
5324
|
self.state.historyEndOfList = !!(history && history.endOfList);
|
|
4557
5325
|
self.state.historyStartKeyHistory = history && Array.isArray(history.startKeyHistory) ? history.startKeyHistory : [];
|
|
4558
5326
|
var clearedAt = self.host.getClearedAt();
|
|
4559
|
-
if (clearedAt
|
|
4560
|
-
var
|
|
4561
|
-
|
|
5327
|
+
if (clearedAt) {
|
|
5328
|
+
var surfaceItems = chatList.filter(function(it) {
|
|
5329
|
+
return !(it && it._fromBgChain);
|
|
5330
|
+
});
|
|
5331
|
+
if (surfaceItems.length > 0) {
|
|
5332
|
+
var oldestUpdated = Number(surfaceItems[surfaceItems.length - 1] && surfaceItems[surfaceItems.length - 1].updated);
|
|
5333
|
+
if (isFinite(oldestUpdated) && oldestUpdated <= clearedAt) self.state.historyEndOfList = true;
|
|
5334
|
+
}
|
|
4562
5335
|
}
|
|
4563
5336
|
}
|
|
4564
5337
|
if (self.state.historyRequestToken === token) {
|
|
@@ -4567,6 +5340,85 @@ var ChatSession = class {
|
|
|
4567
5340
|
}
|
|
4568
5341
|
self.updateHistoryCache();
|
|
4569
5342
|
self.host.notify();
|
|
5343
|
+
var bgPending = !fetchMore && history && history.bgPending;
|
|
5344
|
+
if (bgPending) {
|
|
5345
|
+
var batchId = ++_bgHistoryBatchSeq;
|
|
5346
|
+
if (history.endOfList !== true && history.firstLoad === true) {
|
|
5347
|
+
self.state.bgHistoryLoading = true;
|
|
5348
|
+
self.host.notify();
|
|
5349
|
+
}
|
|
5350
|
+
var releaseBgFlag = function() {
|
|
5351
|
+
if (_bgHistoryBatchSeq === batchId) self.state.bgHistoryLoading = false;
|
|
5352
|
+
};
|
|
5353
|
+
bgPending.then(function(batch) {
|
|
5354
|
+
if (token !== self.state.gateRefreshToken) {
|
|
5355
|
+
releaseBgFlag();
|
|
5356
|
+
return;
|
|
5357
|
+
}
|
|
5358
|
+
var bList = batch && Array.isArray(batch.list) ? batch.list : [];
|
|
5359
|
+
bList.forEach(function(item) {
|
|
5360
|
+
if (isBgIndexingQueue(item.queue_name)) {
|
|
5361
|
+
var t = item.compact ? item.request_text : extractLastUserTextFromRequest(item.request_body);
|
|
5362
|
+
if (isIndexingRequestText(t)) item._isBgTask = true;
|
|
5363
|
+
else item._isOnBgQueue = true;
|
|
5364
|
+
}
|
|
5365
|
+
});
|
|
5366
|
+
var sorted = bList.sort(function(a, b) {
|
|
5367
|
+
var ai = typeof a.id === "string" ? a.id : "", bi = typeof b.id === "string" ? b.id : "";
|
|
5368
|
+
return ai > bi ? -1 : ai < bi ? 1 : 0;
|
|
5369
|
+
});
|
|
5370
|
+
var m2 = mapHistoryListToMessages(sorted, platform, {
|
|
5371
|
+
clearedAt: self.host.getClearedAt(),
|
|
5372
|
+
projectId: id.projectId,
|
|
5373
|
+
formatIndexingLabel: self.host.formatIndexingLabel
|
|
5374
|
+
}).messages;
|
|
5375
|
+
self.applyHydratedBodies(m2);
|
|
5376
|
+
if (keptScreenAwaitingBg && !m2.length && batch && batch.endOfList === true) {
|
|
5377
|
+
self.state.messages = self.state.messages.filter(function(m) {
|
|
5378
|
+
if (typeof m._serverItemId !== "string") return true;
|
|
5379
|
+
if (m._ownerKey !== void 0 && m._ownerKey !== loadKey) return true;
|
|
5380
|
+
return false;
|
|
5381
|
+
});
|
|
5382
|
+
self.state.historyEndOfList = true;
|
|
5383
|
+
releaseBgFlag();
|
|
5384
|
+
self.updateHistoryCache();
|
|
5385
|
+
self.host.notify();
|
|
5386
|
+
return;
|
|
5387
|
+
}
|
|
5388
|
+
var incoming = {};
|
|
5389
|
+
m2.forEach(function(m) {
|
|
5390
|
+
if (m._serverItemId) incoming[m._serverItemId + "|" + m.role] = true;
|
|
5391
|
+
});
|
|
5392
|
+
var baseList = self.state.messages.filter(function(m) {
|
|
5393
|
+
return !(m._serverItemId && incoming[m._serverItemId + "|" + m.role]);
|
|
5394
|
+
});
|
|
5395
|
+
var mergedList2 = [];
|
|
5396
|
+
var pi2 = 0, ei2 = 0;
|
|
5397
|
+
while (pi2 < m2.length && ei2 < baseList.length) {
|
|
5398
|
+
var pm2 = m2[pi2], em2 = baseList[ei2];
|
|
5399
|
+
var eid2 = em2._serverItemId;
|
|
5400
|
+
if (typeof eid2 !== "string") break;
|
|
5401
|
+
var pid2 = pm2._serverItemId;
|
|
5402
|
+
if (typeof pid2 !== "string" || pid2 <= eid2) {
|
|
5403
|
+
mergedList2.push(pm2);
|
|
5404
|
+
pi2++;
|
|
5405
|
+
} else {
|
|
5406
|
+
mergedList2.push(em2);
|
|
5407
|
+
ei2++;
|
|
5408
|
+
}
|
|
5409
|
+
}
|
|
5410
|
+
while (pi2 < m2.length) mergedList2.push(m2[pi2++]);
|
|
5411
|
+
while (ei2 < baseList.length) mergedList2.push(baseList[ei2++]);
|
|
5412
|
+
self.state.messages = mergedList2;
|
|
5413
|
+
if (batch && batch.endOfList === true) self.state.historyEndOfList = true;
|
|
5414
|
+
releaseBgFlag();
|
|
5415
|
+
self.updateHistoryCache();
|
|
5416
|
+
self.host.notify();
|
|
5417
|
+
}, function() {
|
|
5418
|
+
releaseBgFlag();
|
|
5419
|
+
self.host.notify();
|
|
5420
|
+
});
|
|
5421
|
+
}
|
|
4570
5422
|
if (!fetchMore) {
|
|
4571
5423
|
var bgAllow = {};
|
|
4572
5424
|
var bgHistBudget = MAX_CONCURRENT_BG_POLLS - self._countBgPolls();
|
|
@@ -4663,7 +5515,7 @@ var ChatSession = class {
|
|
|
4663
5515
|
var self = this;
|
|
4664
5516
|
var id = this.host.getIdentity();
|
|
4665
5517
|
att.status = "uploading";
|
|
4666
|
-
att.progress =
|
|
5518
|
+
att.progress = null;
|
|
4667
5519
|
att.errorMessage = "";
|
|
4668
5520
|
att.errorCode = "";
|
|
4669
5521
|
att.errorDetail = "";
|
|
@@ -4894,6 +5746,7 @@ var ChatSession = class {
|
|
|
4894
5746
|
};
|
|
4895
5747
|
|
|
4896
5748
|
// src/engine/indexing_groups.ts
|
|
5749
|
+
var RUN_RECORD_WORKING_STALE_MS = 6 * 60 * 60 * 1e3;
|
|
4897
5750
|
var INDEXING_LABEL_RE = /^(Re)?[Ii]ndexing(\s*\(continuing\))?\s*:?\s+(.+)$/;
|
|
4898
5751
|
var LEADING_MD_LINK_RE = /^\[([^\]]+)\]\(([^)]+)\)/;
|
|
4899
5752
|
function parseIndexingLabel(content) {
|
|
@@ -4948,10 +5801,12 @@ function buildChatDisplayList(messages, opts) {
|
|
|
4948
5801
|
var list = Array.isArray(messages) ? messages : [];
|
|
4949
5802
|
var liveIndexKeys = opts && opts.liveIndexKeys || {};
|
|
4950
5803
|
var liveIndexChecked = !!(opts && opts.liveIndexChecked);
|
|
5804
|
+
var doneKeys = opts && opts.doneKeys || {};
|
|
4951
5805
|
var stoppedIndexIds = opts && opts.stoppedIndexIds || {};
|
|
4952
5806
|
var windowedIndexing = opts && opts.windowedIndexing !== void 0 ? !!opts.windowedIndexing : windowedIndexingEnabled();
|
|
4953
5807
|
var hasMoreHistory = !!(opts && opts.hasMoreHistory);
|
|
4954
5808
|
var loadingOlderHistory = !!(opts && opts.loadingOlderHistory);
|
|
5809
|
+
var stubPlatform = opts && opts.stubPlatform;
|
|
4955
5810
|
var groups = {};
|
|
4956
5811
|
var order = [];
|
|
4957
5812
|
var runOfIndex = new Array(list.length);
|
|
@@ -5124,11 +5979,11 @@ function buildChatDisplayList(messages, opts) {
|
|
|
5124
5979
|
} else if (grp.driver === "client") {
|
|
5125
5980
|
grp.finished = sawComplete || grp.status === "error" || grp.passCount >= MAX_INDEXING_RESUME_PASSES;
|
|
5126
5981
|
} else {
|
|
5127
|
-
grp.finished = !newestRunOfKey[order[oi]] || liveIndexChecked && !liveIndexKeys[grp.key];
|
|
5982
|
+
grp.finished = !newestRunOfKey[order[oi]] || !!doneKeys[grp.key] && !liveIndexKeys[grp.key] || liveIndexChecked && !liveIndexKeys[grp.key];
|
|
5128
5983
|
}
|
|
5129
5984
|
if (grp.status !== "done") {
|
|
5130
5985
|
grp.resolving = false;
|
|
5131
|
-
} else if (grp.mayHaveOlder && loadingOlderHistory && !liveIndexKeys[grp.key] && newestRunOfKey[order[oi]]) {
|
|
5986
|
+
} else if (grp.mayHaveOlder && loadingOlderHistory && !liveIndexKeys[grp.key] && !doneKeys[grp.key] && newestRunOfKey[order[oi]]) {
|
|
5132
5987
|
grp.resolving = true;
|
|
5133
5988
|
grp.resolvingReason = "history";
|
|
5134
5989
|
} else if (!grp.finished && grp.driver === "worker" && !liveIndexChecked && !liveIndexKeys[grp.key]) {
|
|
@@ -5138,14 +5993,126 @@ function buildChatDisplayList(messages, opts) {
|
|
|
5138
5993
|
grp.resolving = false;
|
|
5139
5994
|
}
|
|
5140
5995
|
}
|
|
5996
|
+
var stubList = [];
|
|
5997
|
+
var runStubs = opts && opts.runStubs;
|
|
5998
|
+
if (runStubs) {
|
|
5999
|
+
var coveredPaths = {};
|
|
6000
|
+
var coveredPathlessNames = {};
|
|
6001
|
+
for (var ci = 0; ci < order.length; ci++) {
|
|
6002
|
+
var cg = groups[order[ci]];
|
|
6003
|
+
if (cg.path) {
|
|
6004
|
+
coveredPaths[cg.path] = true;
|
|
6005
|
+
if (cg.key) coveredPaths[cg.key] = true;
|
|
6006
|
+
} else if (cg.name) coveredPathlessNames[cg.name] = true;
|
|
6007
|
+
else if (cg.key) coveredPaths[cg.key] = true;
|
|
6008
|
+
}
|
|
6009
|
+
var now = opts && typeof opts.now === "number" ? opts.now : Date.now();
|
|
6010
|
+
var stubClearedAt = opts && typeof opts.stubClearedAt === "number" && opts.stubClearedAt > 0 ? opts.stubClearedAt : 0;
|
|
6011
|
+
for (var sp in runStubs) {
|
|
6012
|
+
var rec = runStubs[sp];
|
|
6013
|
+
if (!sp || !rec || !rec.status || coveredPaths[sp]) continue;
|
|
6014
|
+
var fname = rec.filename || sp.split("/").pop() || sp;
|
|
6015
|
+
if (coveredPathlessNames[fname]) continue;
|
|
6016
|
+
if (stubPlatform && rec.platform && rec.platform !== stubPlatform) continue;
|
|
6017
|
+
var live = !!liveIndexKeys[sp] || !!liveIndexKeys[fname];
|
|
6018
|
+
var recWhen = typeof rec.finished === "number" ? rec.finished : typeof rec.started === "number" ? rec.started : void 0;
|
|
6019
|
+
if (stubClearedAt && !live && recWhen !== void 0 && recWhen <= stubClearedAt) continue;
|
|
6020
|
+
var st = "active";
|
|
6021
|
+
var fin = false;
|
|
6022
|
+
var res = false;
|
|
6023
|
+
var reason;
|
|
6024
|
+
if (!live) {
|
|
6025
|
+
if (rec.status === "done" || doneKeys[sp] || doneKeys[fname]) {
|
|
6026
|
+
st = "done";
|
|
6027
|
+
fin = true;
|
|
6028
|
+
} else if (rec.status === "error") {
|
|
6029
|
+
st = "error";
|
|
6030
|
+
fin = true;
|
|
6031
|
+
} else if (rec.status === "cancelled") {
|
|
6032
|
+
st = "cancelled";
|
|
6033
|
+
fin = true;
|
|
6034
|
+
} else if (liveIndexChecked) {
|
|
6035
|
+
st = "done";
|
|
6036
|
+
fin = true;
|
|
6037
|
+
} else if (typeof rec.started === "number" && now - rec.started > RUN_RECORD_WORKING_STALE_MS) {
|
|
6038
|
+
st = "error";
|
|
6039
|
+
fin = true;
|
|
6040
|
+
} else {
|
|
6041
|
+
res = true;
|
|
6042
|
+
reason = "status";
|
|
6043
|
+
}
|
|
6044
|
+
}
|
|
6045
|
+
var sg = {
|
|
6046
|
+
key: sp,
|
|
6047
|
+
// ONE identity for the run whether it renders from the record or
|
|
6048
|
+
// from its loaded passes: the views key the DOM off runKey, so a
|
|
6049
|
+
// 'stub:'-prefixed key meant every handoff was an unmount plus a
|
|
6050
|
+
// remount somewhere else. Named after the record's start, which
|
|
6051
|
+
// the real group below reuses when it has one.
|
|
6052
|
+
runKey: "run:" + sp + "#" + (typeof rec.started === "number" ? rec.started : "n"),
|
|
6053
|
+
name: fname,
|
|
6054
|
+
path: sp,
|
|
6055
|
+
mime: void 0,
|
|
6056
|
+
size: void 0,
|
|
6057
|
+
isReindex: false,
|
|
6058
|
+
members: [],
|
|
6059
|
+
passCount: 0,
|
|
6060
|
+
status: st,
|
|
6061
|
+
cancellableIds: [],
|
|
6062
|
+
cancelling: false,
|
|
6063
|
+
stopped: st === "cancelled",
|
|
6064
|
+
mayHaveOlder: hasMoreHistory,
|
|
6065
|
+
anchorIndex: -1,
|
|
6066
|
+
anchorId: "",
|
|
6067
|
+
visibleMembers: [],
|
|
6068
|
+
driver: !isPagedReadFile(fname, void 0) ? "single" : isImageVisionFile(fname, void 0) ? "worker" : windowedIndexing ? "worker" : "client",
|
|
6069
|
+
finished: fin,
|
|
6070
|
+
resolving: res,
|
|
6071
|
+
resolvingReason: reason,
|
|
6072
|
+
stub: true,
|
|
6073
|
+
stubError: rec.error || (st === "error" && !rec.error ? "Indexing did not finish." : void 0)
|
|
6074
|
+
};
|
|
6075
|
+
stubList.push({ started: typeof rec.started === "number" ? rec.started : Infinity, group: sg });
|
|
6076
|
+
}
|
|
6077
|
+
}
|
|
6078
|
+
var suppressAnchor = {};
|
|
6079
|
+
if (runStubs) {
|
|
6080
|
+
for (var ti2 = 0; ti2 < order.length; ti2++) {
|
|
6081
|
+
var tg = groups[order[ti2]];
|
|
6082
|
+
if (!newestRunOfKey[order[ti2]]) continue;
|
|
6083
|
+
var trec = tg.path && runStubs[tg.path] || runStubs[tg.key];
|
|
6084
|
+
if (!trec || typeof trec.started !== "number") continue;
|
|
6085
|
+
if (stubPlatform && trec.platform && trec.platform !== stubPlatform) continue;
|
|
6086
|
+
suppressAnchor[order[ti2]] = true;
|
|
6087
|
+
tg.runKey = "run:" + (tg.path || tg.key) + "#" + trec.started;
|
|
6088
|
+
stubList.push({ started: trec.started, group: tg });
|
|
6089
|
+
}
|
|
6090
|
+
}
|
|
6091
|
+
stubList.sort(function(a, b) {
|
|
6092
|
+
return a.started - b.started;
|
|
6093
|
+
});
|
|
5141
6094
|
var out = [];
|
|
6095
|
+
var si = 0;
|
|
5142
6096
|
for (var j = 0; j < list.length; j++) {
|
|
6097
|
+
var mts = list[j] && typeof list[j]._ts === "number" ? list[j]._ts : void 0;
|
|
6098
|
+
if (mts !== void 0) {
|
|
6099
|
+
while (si < stubList.length && stubList[si].started <= mts) {
|
|
6100
|
+
out.push({ kind: "indexing", group: stubList[si].group, index: -1 - si });
|
|
6101
|
+
si++;
|
|
6102
|
+
}
|
|
6103
|
+
}
|
|
5143
6104
|
var r = runOfIndex[j];
|
|
5144
6105
|
if (r === void 0) {
|
|
5145
6106
|
out.push({ kind: "message", msg: list[j], index: j });
|
|
5146
6107
|
continue;
|
|
5147
6108
|
}
|
|
5148
|
-
if (groups[r].anchorIndex === j
|
|
6109
|
+
if (groups[r].anchorIndex === j && !suppressAnchor[r]) {
|
|
6110
|
+
out.push({ kind: "indexing", group: groups[r], index: j });
|
|
6111
|
+
}
|
|
6112
|
+
}
|
|
6113
|
+
while (si < stubList.length) {
|
|
6114
|
+
out.push({ kind: "indexing", group: stubList[si].group, index: -1 - si });
|
|
6115
|
+
si++;
|
|
5149
6116
|
}
|
|
5150
6117
|
return out;
|
|
5151
6118
|
}
|
|
@@ -5159,6 +6126,7 @@ exports.CONTEXT_WINDOW_BY_MODEL = CONTEXT_WINDOW_BY_MODEL;
|
|
|
5159
6126
|
exports.CONTEXT_WINDOW_DEFAULT = CONTEXT_WINDOW_DEFAULT;
|
|
5160
6127
|
exports.ChatSession = ChatSession;
|
|
5161
6128
|
exports.DEFAULT_CLAUDE_MODEL = DEFAULT_CLAUDE_MODEL;
|
|
6129
|
+
exports.DEFAULT_CONTEXT_WINDOW = DEFAULT_CONTEXT_WINDOW;
|
|
5162
6130
|
exports.DEFAULT_OPENAI_MODEL = DEFAULT_OPENAI_MODEL;
|
|
5163
6131
|
exports.EMPTY_INDEXING_REPLY = EMPTY_INDEXING_REPLY;
|
|
5164
6132
|
exports.EXPIRED_ATTACHMENT_URL_HOST = EXPIRED_ATTACHMENT_URL_HOST;
|
|
@@ -5175,22 +6143,31 @@ exports.INDEXING_COMPLETE_MARKER = INDEXING_COMPLETE_MARKER;
|
|
|
5175
6143
|
exports.INLINE_LINK_GLYPH = INLINE_LINK_GLYPH;
|
|
5176
6144
|
exports.INLINE_LINK_UNAVAILABLE_GLYPH = INLINE_LINK_UNAVAILABLE_GLYPH;
|
|
5177
6145
|
exports.INLINE_LINK_UNAVAILABLE_SUFFIX = INLINE_LINK_UNAVAILABLE_SUFFIX;
|
|
6146
|
+
exports.INPUT_CAP_RATIO = INPUT_CAP_RATIO;
|
|
5178
6147
|
exports.LINK_LABEL_MAX_DISPLAY_CHARS = LINK_LABEL_MAX_DISPLAY_CHARS;
|
|
5179
6148
|
exports.LINK_REFRESH_WINDOW_MS = LINK_REFRESH_WINDOW_MS;
|
|
5180
6149
|
exports.MAX_CONCURRENT_BG_POLLS = MAX_CONCURRENT_BG_POLLS;
|
|
5181
6150
|
exports.MAX_HISTORY_FILL_PAGES = MAX_HISTORY_FILL_PAGES;
|
|
5182
6151
|
exports.MAX_HISTORY_MESSAGES = MAX_HISTORY_MESSAGES;
|
|
6152
|
+
exports.MAX_OUTPUT_BY_MODEL = MAX_OUTPUT_BY_MODEL;
|
|
6153
|
+
exports.MAX_OUTPUT_TOKENS = MAX_OUTPUT_TOKENS;
|
|
5183
6154
|
exports.MAX_PARSED_CONTENT_CHARS = MAX_PARSED_CONTENT_CHARS;
|
|
5184
6155
|
exports.MCP_NAME = MCP_NAME;
|
|
6156
|
+
exports.MINT_CACHE_GENERATION = MINT_CACHE_GENERATION;
|
|
5185
6157
|
exports.MIN_INPUT_TOKEN_BUDGET = MIN_INPUT_TOKEN_BUDGET;
|
|
6158
|
+
exports.MIN_PER_REQUEST_INPUT_CAP = MIN_PER_REQUEST_INPUT_CAP;
|
|
5186
6159
|
exports.OUTPUT_TOKEN_RESERVE = OUTPUT_TOKEN_RESERVE;
|
|
5187
6160
|
exports.POLL_INTERVAL = POLL_INTERVAL;
|
|
6161
|
+
exports.PRESIGN_SAFETY_MARGIN_MS = PRESIGN_SAFETY_MARGIN_MS;
|
|
5188
6162
|
exports.PREVIEWABLE_IMAGE_CONTENT_TYPES = PREVIEWABLE_IMAGE_CONTENT_TYPES;
|
|
5189
6163
|
exports.PREVIEW_BROWSER_CACHE_SECONDS = PREVIEW_BROWSER_CACHE_SECONDS;
|
|
6164
|
+
exports.PREVIEW_URL_EXPIRES_SECONDS = PREVIEW_URL_EXPIRES_SECONDS;
|
|
5190
6165
|
exports.RENDER_FROM_TOKEN = RENDER_FROM_TOKEN;
|
|
5191
6166
|
exports.RTF_EXTS = RTF_EXTS;
|
|
6167
|
+
exports.RUN_RECORD_WORKING_STALE_MS = RUN_RECORD_WORKING_STALE_MS;
|
|
5192
6168
|
exports.TOOL_AND_RESPONSE_BUFFER = TOOL_AND_RESPONSE_BUFFER;
|
|
5193
6169
|
exports.XML_EXTS = XML_EXTS;
|
|
6170
|
+
exports.__resetSplitHistoryState = __resetSplitHistoryState;
|
|
5194
6171
|
exports.applyEncodingDeclaration = applyEncodingDeclaration;
|
|
5195
6172
|
exports.bgIndexingQueueName = bgIndexingQueueName;
|
|
5196
6173
|
exports.buildAiAgentValue = buildAiAgentValue;
|
|
@@ -5198,6 +6175,7 @@ exports.buildBoundedChatMessages = buildBoundedChatMessages;
|
|
|
5198
6175
|
exports.buildChatDisplayList = buildChatDisplayList;
|
|
5199
6176
|
exports.buildChatSystemPrompt = buildChatSystemPrompt;
|
|
5200
6177
|
exports.buildDisplayExpiredAttachmentHref = buildDisplayExpiredAttachmentHref;
|
|
6178
|
+
exports.buildHistoryItemFullId = buildHistoryItemFullId;
|
|
5201
6179
|
exports.buildIndexingContinueMessage = buildIndexingContinueMessage;
|
|
5202
6180
|
exports.buildIndexingRenderContinueTemplate = buildIndexingRenderContinueTemplate;
|
|
5203
6181
|
exports.buildIndexingRenderMessage = buildIndexingRenderMessage;
|
|
@@ -5229,6 +6207,7 @@ exports.extractClaudeText = extractClaudeText;
|
|
|
5229
6207
|
exports.extractLastUserTextFromRequest = extractLastUserTextFromRequest;
|
|
5230
6208
|
exports.extractOpenAIText = extractOpenAIText;
|
|
5231
6209
|
exports.extractRemotePathFromAttachmentHref = extractRemotePathFromAttachmentHref;
|
|
6210
|
+
exports.fetchLiveIndexingKeys = fetchLiveIndexingKeys;
|
|
5232
6211
|
exports.fillHistoryViewport = fillHistoryViewport;
|
|
5233
6212
|
exports.filterListByClearHorizon = filterListByClearHorizon;
|
|
5234
6213
|
exports.findAttachmentParser = findAttachmentParser;
|
|
@@ -5238,11 +6217,16 @@ exports.getChatHistory = getChatHistory;
|
|
|
5238
6217
|
exports.getContextWindow = getContextWindow;
|
|
5239
6218
|
exports.getErrorMessage = getErrorMessage;
|
|
5240
6219
|
exports.getExpiredAttachmentVisiblePath = getExpiredAttachmentVisiblePath;
|
|
6220
|
+
exports.getInputTokenBudget = getInputTokenBudget;
|
|
6221
|
+
exports.getMaxOutputTokens = getMaxOutputTokens;
|
|
6222
|
+
exports.getModelContextWindow = getModelContextWindow;
|
|
5241
6223
|
exports.getProjectContextWindow = getProjectContextWindow;
|
|
6224
|
+
exports.getSplitChatHistory = getSplitChatHistory;
|
|
5242
6225
|
exports.getVisionProfile = getVisionProfile;
|
|
5243
6226
|
exports.groupAttachmentFailures = groupAttachmentFailures;
|
|
5244
6227
|
exports.hasBom = hasBom;
|
|
5245
6228
|
exports.hydrateImagePreviews = hydrateImagePreviews;
|
|
6229
|
+
exports.indexDoneUniqueId = indexDoneUniqueId;
|
|
5246
6230
|
exports.isAuthExpiredError = isAuthExpiredError;
|
|
5247
6231
|
exports.isBgIndexingQueue = isBgIndexingQueue;
|
|
5248
6232
|
exports.isErrorResponseBody = isErrorResponseBody;
|
|
@@ -5252,16 +6236,19 @@ exports.isLinkUnavailable = isLinkUnavailable;
|
|
|
5252
6236
|
exports.isNonRetryableRequestError = isNonRetryableRequestError;
|
|
5253
6237
|
exports.isOfficeFile = isOfficeFile;
|
|
5254
6238
|
exports.isPreviewableImagePath = isPreviewableImagePath;
|
|
6239
|
+
exports.isProviderApiKeyError = isProviderApiKeyError;
|
|
5255
6240
|
exports.isServerExtractable = isServerExtractable;
|
|
5256
6241
|
exports.isServiceDbAttachmentHref = isServiceDbAttachmentHref;
|
|
5257
6242
|
exports.linkUnavailableKeyForHref = linkUnavailableKeyForHref;
|
|
5258
6243
|
exports.linkUnavailableKeyForPath = linkUnavailableKeyForPath;
|
|
6244
|
+
exports.linkUnavailableKeysForPath = linkUnavailableKeysForPath;
|
|
5259
6245
|
exports.listClaudeModels = listClaudeModels;
|
|
5260
6246
|
exports.listOpenAIModels = listOpenAIModels;
|
|
5261
6247
|
exports.looksLikeRtf = looksLikeRtf;
|
|
5262
6248
|
exports.makeExtractPlaceholder = makeExtractPlaceholder;
|
|
5263
6249
|
exports.mapHistoryListToMessages = mapHistoryListToMessages;
|
|
5264
6250
|
exports.markImagePreviewStale = markImagePreviewStale;
|
|
6251
|
+
exports.mintCacheBustStamp = mintCacheBustStamp;
|
|
5265
6252
|
exports.needsBomForExt = needsBomForExt;
|
|
5266
6253
|
exports.normalizeAttachmentPathCandidate = normalizeAttachmentPathCandidate;
|
|
5267
6254
|
exports.normalizeExt = normalizeExt;
|
|
@@ -5274,7 +6261,9 @@ exports.parseIndexingLabel = parseIndexingLabel;
|
|
|
5274
6261
|
exports.parseIndexingRequestText = parseIndexingRequestText;
|
|
5275
6262
|
exports.peekImagePreviewUrl = peekImagePreviewUrl;
|
|
5276
6263
|
exports.prepareDownloadText = prepareDownloadText;
|
|
6264
|
+
exports.presignExpiryEpochMs = presignExpiryEpochMs;
|
|
5277
6265
|
exports.previewImageContentType = previewImageContentType;
|
|
6266
|
+
exports.previewMintCacheToken = previewMintCacheToken;
|
|
5278
6267
|
exports.previewableExtOf = previewableExtOf;
|
|
5279
6268
|
exports.readExpiredAttachmentHref = readExpiredAttachmentHref;
|
|
5280
6269
|
exports.registerAttachmentParser = registerAttachmentParser;
|
|
@@ -5283,6 +6272,7 @@ exports.renderInlineLinkHtml = renderInlineLinkHtml;
|
|
|
5283
6272
|
exports.repairUrlEntities = repairUrlEntities;
|
|
5284
6273
|
exports.repairUrlWhitespace = repairUrlWhitespace;
|
|
5285
6274
|
exports.resolveImagePreviewUrl = resolveImagePreviewUrl;
|
|
6275
|
+
exports.runIndexUniqueId = runIndexUniqueId;
|
|
5286
6276
|
exports.safeDecodeURIComponent = safeDecodeURIComponent;
|
|
5287
6277
|
exports.sanitizeAttachmentLinksForHistory = sanitizeAttachmentLinksForHistory;
|
|
5288
6278
|
exports.setProjectContextWindow = setProjectContextWindow;
|
|
@@ -5290,6 +6280,7 @@ exports.stripFileBlocksFromHistory = stripFileBlocksFromHistory;
|
|
|
5290
6280
|
exports.transformContentWithImages = transformContentWithImages;
|
|
5291
6281
|
exports.transformContentWithOpenAIImages = transformContentWithOpenAIImages;
|
|
5292
6282
|
exports.truncateLabelForDisplay = truncateLabelForDisplay;
|
|
6283
|
+
exports.upsertIndexRunRecordSafe = upsertIndexRunRecordSafe;
|
|
5293
6284
|
exports.wallClockNow = wallClockNow;
|
|
5294
6285
|
//# sourceMappingURL=engine.cjs.map
|
|
5295
6286
|
//# sourceMappingURL=engine.cjs.map
|