bunnyquery 1.7.0 → 1.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bunnyquery.css +12 -0
- package/bunnyquery.js +337 -41
- package/dist/engine.cjs +351 -35
- package/dist/engine.cjs.map +1 -1
- package/dist/engine.d.mts +214 -12
- package/dist/engine.d.ts +214 -12
- package/dist/engine.mjs +340 -36
- package/dist/engine.mjs.map +1 -1
- package/package.json +1 -1
- package/src/engine/ai_agent.ts +80 -0
- package/src/engine/budget.ts +113 -7
- package/src/engine/history.ts +58 -18
- package/src/engine/host.ts +6 -0
- package/src/engine/index.ts +9 -0
- package/src/engine/indexing_groups.ts +50 -11
- package/src/engine/links.ts +35 -1
- package/src/engine/prompts/chat_system_prompt.ts +3 -0
- package/src/engine/requests.ts +11 -2
- package/src/engine/session.ts +220 -6
- package/src/engine/time.ts +34 -0
- package/styles/chat.css +12 -0
package/dist/engine.cjs
CHANGED
|
@@ -286,6 +286,9 @@ function buildChatSystemPrompt(params) {
|
|
|
286
286
|
You are a dedicated assistant for the project ID: "${formattedServiceId}".
|
|
287
287
|
Scope: Only answer questions about this project and its data. Do not answer questions about other projects or topics unrelated to this project. When the user refers to "my database", "my data", or "my files", treat those as references to this project's database and file storage.
|
|
288
288
|
Knowledge lookup: Before saying you don't know or that something isn't in the chat history, ALWAYS query this project's database through the available MCP tools to look for the answer. The user's data is the source of truth - the chat transcript is not. Only respond with "I don't know" or "I couldn't find that" after you have actually searched the project's data and come back empty.
|
|
289
|
+
Complete answers over stored data: The database holds one record per spreadsheet row, and each uploaded file becomes many records that usually share a table. So a question about the data almost always spans many records across several files. For any request that counts, sums, totals, lists every match, compares across records, finds which one, or asks whether something is present or ABSENT (for example "how many", "total spent", "which card", "is there any", "\uC5C6\uC5B4?", "\uD558\uB098\uB3C4 \uC5C6\uB098?"), you MUST read the COMPLETE matching set before answering. Query with fetch_all set to true, or page through getToolResponsePage until pagination.complete is true, across EVERY relevant table and EVERY relevant file. A single default query returns only the first page (about 50 records). That is a SAMPLE. Never treat it as the whole dataset.
|
|
290
|
+
Never assert absence from a partial read. Do not say "there is no X", "none", "not found", or "\uC544\uB2C8\uC694, \uC5C6\uC2B5\uB2C8\uB2E4" until a complete scan has come back empty. If you have not finished scanning every relevant table and file, keep querying instead of guessing. A confident "no" that later turns out wrong is worse than telling the user you are still checking.
|
|
291
|
+
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 and tag filters match only exact values or leading prefixes, not substrings, 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.
|
|
289
292
|
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.
|
|
290
293
|
- 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.
|
|
291
294
|
- Most 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) have ALREADY had their text extracted on the server and inlined in the same message between the "BEGIN FILE CONTENT" / "END FILE CONTENT" markers - read it directly there and do NOT call web_fetch for those files. A "[skapi: ...]" note in that block means the file could not be extracted.
|
|
@@ -620,6 +623,15 @@ function repairUrlWhitespace(href) {
|
|
|
620
623
|
if (/^https?:\/\/[^/\s]+\/download\/[A-Za-z0-9_-]+(\.[A-Za-z0-9_-]+)?$/i.test(stripped)) return stripped;
|
|
621
624
|
return href.trim().replace(/\s/g, "%20");
|
|
622
625
|
}
|
|
626
|
+
function repairUrlEntities(href) {
|
|
627
|
+
if (!href || href.indexOf("&") === -1) return href;
|
|
628
|
+
var out = href, prev = "";
|
|
629
|
+
while (out !== prev) {
|
|
630
|
+
prev = out;
|
|
631
|
+
out = out.replace(/&/gi, "&").replace(/�*38;/g, "&").replace(/�*26;/gi, "&");
|
|
632
|
+
}
|
|
633
|
+
return out;
|
|
634
|
+
}
|
|
623
635
|
function normalizeTrailingInlineToken(value) {
|
|
624
636
|
if (!value) return value;
|
|
625
637
|
var out = value.replace(/[.,;:!?]+$/, "");
|
|
@@ -667,8 +679,9 @@ function classifyInlineLink(full, groups, ctx) {
|
|
|
667
679
|
var tail = full.slice(("src::" + rawPath).length);
|
|
668
680
|
var srcIsUrl = isHttpUrlLike(rawPath);
|
|
669
681
|
if (srcIsUrl && !isDbHost(rawPath) && !readExpiredAttachmentHref(rawPath)) {
|
|
682
|
+
var srcUrl = repairUrlEntities(rawPath);
|
|
670
683
|
return {
|
|
671
|
-
part: { type: "link", label: truncateLabelForDisplay(
|
|
684
|
+
part: { type: "link", label: truncateLabelForDisplay(srcUrl), fullLabel: srcUrl, href: srcUrl, expired: false },
|
|
672
685
|
tail
|
|
673
686
|
};
|
|
674
687
|
}
|
|
@@ -702,6 +715,7 @@ function classifyInlineLink(full, groups, ctx) {
|
|
|
702
715
|
}
|
|
703
716
|
var originalHref = g3 || g6 || "";
|
|
704
717
|
if (!originalHref) return null;
|
|
718
|
+
originalHref = repairUrlEntities(originalHref);
|
|
705
719
|
var urlTail;
|
|
706
720
|
if (!g3 && g6) {
|
|
707
721
|
var trimmedUrl = normalizeTrailingInlineToken(originalHref);
|
|
@@ -743,25 +757,74 @@ function truncateLabelForDisplay(label) {
|
|
|
743
757
|
// src/engine/budget.ts
|
|
744
758
|
var CONTEXT_WINDOW_DEFAULT = { claude: 2e5, openai: 128e3 };
|
|
745
759
|
var CONTEXT_WINDOW_BY_MODEL = {
|
|
746
|
-
|
|
760
|
+
// exact ids
|
|
761
|
+
"claude-opus-5": 1e6,
|
|
762
|
+
"claude-opus-4-8": 1e6,
|
|
763
|
+
"claude-opus-4-7": 1e6,
|
|
764
|
+
"claude-sonnet-5": 1e6,
|
|
765
|
+
"claude-sonnet-4-6": 1e6,
|
|
747
766
|
"claude-sonnet-4": 2e5,
|
|
748
|
-
"
|
|
767
|
+
"claude-haiku-4-5": 2e5,
|
|
768
|
+
"gpt-5.4": 128e3,
|
|
769
|
+
"gpt-5.6-luna": 128e3,
|
|
770
|
+
// family keys
|
|
771
|
+
"claude-opus": 1e6,
|
|
772
|
+
"claude-sonnet": 1e6,
|
|
773
|
+
"claude-haiku": 2e5,
|
|
774
|
+
"gpt-5.6": 128e3,
|
|
775
|
+
"gpt-5": 128e3
|
|
749
776
|
};
|
|
777
|
+
var apiReportedContextWindows = {};
|
|
778
|
+
function registerModelContextWindows(models) {
|
|
779
|
+
if (!Array.isArray(models)) return;
|
|
780
|
+
for (var i = 0; i < models.length; i++) {
|
|
781
|
+
var m = models[i];
|
|
782
|
+
var id = (m && m.id ? String(m.id) : "").trim().toLowerCase();
|
|
783
|
+
var reported = m ? Number(m.max_input_tokens) : NaN;
|
|
784
|
+
if (id && Number.isFinite(reported) && reported > 0) {
|
|
785
|
+
apiReportedContextWindows[id] = Math.floor(reported);
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
var projectContextWindows = {};
|
|
790
|
+
function setProjectContextWindow(serviceId, tokens) {
|
|
791
|
+
var key = (serviceId || "").trim();
|
|
792
|
+
if (!key) return;
|
|
793
|
+
var n = Number(tokens);
|
|
794
|
+
if (Number.isFinite(n) && n > 0) projectContextWindows[key] = Math.floor(n);
|
|
795
|
+
else delete projectContextWindows[key];
|
|
796
|
+
}
|
|
797
|
+
function getProjectContextWindow(serviceId) {
|
|
798
|
+
var key = (serviceId || "").trim();
|
|
799
|
+
return key && projectContextWindows[key] ? projectContextWindows[key] : null;
|
|
800
|
+
}
|
|
750
801
|
var OUTPUT_TOKEN_RESERVE = 22e3;
|
|
751
802
|
var TOOL_AND_RESPONSE_BUFFER = 4e3;
|
|
752
803
|
var MIN_INPUT_TOKEN_BUDGET = 8e3;
|
|
753
804
|
var CLAUDE_PER_REQUEST_INPUT_CAP = 28e3;
|
|
754
805
|
var MAX_HISTORY_MESSAGES = 20;
|
|
755
806
|
var HISTORY_TOKEN_BUDGET = 8e3;
|
|
807
|
+
var CLAUDE_INPUT_CAP_RATIO = 0.16;
|
|
808
|
+
var HISTORY_BUDGET_RATIO = 0.08;
|
|
756
809
|
function estimateTextTokens(text) {
|
|
757
810
|
return Math.ceil((text || "").length / 3);
|
|
758
811
|
}
|
|
759
812
|
function estimateMessageTokens(msg) {
|
|
760
813
|
return estimateTextTokens(msg.content) + estimateTextTokens(msg.role) + 6;
|
|
761
814
|
}
|
|
762
|
-
function getContextWindow(platform, model) {
|
|
815
|
+
function getContextWindow(platform, model, serviceId) {
|
|
816
|
+
var override = serviceId ? getProjectContextWindow(serviceId) : null;
|
|
817
|
+
if (override) return override;
|
|
763
818
|
var normalized = (model || "").trim().toLowerCase();
|
|
764
|
-
if (normalized
|
|
819
|
+
if (normalized) {
|
|
820
|
+
if (apiReportedContextWindows[normalized]) return apiReportedContextWindows[normalized];
|
|
821
|
+
if (CONTEXT_WINDOW_BY_MODEL[normalized]) return CONTEXT_WINDOW_BY_MODEL[normalized];
|
|
822
|
+
var parts = normalized.split("-");
|
|
823
|
+
for (var end = parts.length - 1; end > 0; end--) {
|
|
824
|
+
var family = parts.slice(0, end).join("-");
|
|
825
|
+
if (CONTEXT_WINDOW_BY_MODEL[family]) return CONTEXT_WINDOW_BY_MODEL[family];
|
|
826
|
+
}
|
|
827
|
+
}
|
|
765
828
|
return CONTEXT_WINDOW_DEFAULT[platform];
|
|
766
829
|
}
|
|
767
830
|
function stripFileBlocksFromHistory(content) {
|
|
@@ -769,15 +832,19 @@ function stripFileBlocksFromHistory(content) {
|
|
|
769
832
|
return content.replace(/```([^\n`]+?\.[^\s.`]+)\n[\s\S]*?```/g, "[file previously attached: $1]");
|
|
770
833
|
}
|
|
771
834
|
function buildBoundedChatMessages(options) {
|
|
772
|
-
var contextWindow = getContextWindow(options.platform, options.model);
|
|
835
|
+
var contextWindow = getContextWindow(options.platform, options.model, options.serviceId);
|
|
773
836
|
var contextBasedBudget = Math.max(
|
|
774
837
|
MIN_INPUT_TOKEN_BUDGET,
|
|
775
838
|
contextWindow - OUTPUT_TOKEN_RESERVE - TOOL_AND_RESPONSE_BUFFER
|
|
776
839
|
);
|
|
777
|
-
var
|
|
840
|
+
var scaled = !!(options.serviceId && getProjectContextWindow(options.serviceId));
|
|
841
|
+
var claudeInputCap = scaled ? Math.max(CLAUDE_PER_REQUEST_INPUT_CAP, Math.round(contextBasedBudget * CLAUDE_INPUT_CAP_RATIO)) : CLAUDE_PER_REQUEST_INPUT_CAP;
|
|
842
|
+
var availableInputBudget = options.platform === "claude" ? Math.min(contextBasedBudget, claudeInputCap) : contextBasedBudget;
|
|
778
843
|
var systemCost = estimateTextTokens(options.systemPrompt) + 12;
|
|
779
|
-
var
|
|
780
|
-
var
|
|
844
|
+
var historyAllowance = scaled ? Math.max(HISTORY_TOKEN_BUDGET, Math.round(contextBasedBudget * HISTORY_BUDGET_RATIO)) : HISTORY_TOKEN_BUDGET;
|
|
845
|
+
var budgetForHistory = Math.max(1e3, Math.min(historyAllowance, availableInputBudget - systemCost));
|
|
846
|
+
var maxHistoryMessages = scaled ? Math.max(MAX_HISTORY_MESSAGES, Math.round(MAX_HISTORY_MESSAGES * (budgetForHistory / HISTORY_TOKEN_BUDGET))) : MAX_HISTORY_MESSAGES;
|
|
847
|
+
var windowed = options.history.slice(-maxHistoryMessages);
|
|
781
848
|
var latestIndex = windowed.length - 1;
|
|
782
849
|
var trimmed = windowed.map(function(m, i2) {
|
|
783
850
|
if (i2 === latestIndex) return m;
|
|
@@ -802,6 +869,60 @@ function buildBoundedChatMessages(options) {
|
|
|
802
869
|
};
|
|
803
870
|
}
|
|
804
871
|
|
|
872
|
+
// src/engine/time.ts
|
|
873
|
+
function wallClockNow() {
|
|
874
|
+
return Date.now();
|
|
875
|
+
}
|
|
876
|
+
function formatChatTimestamp(ms) {
|
|
877
|
+
if (typeof ms !== "number" || !isFinite(ms) || ms <= 0) return "";
|
|
878
|
+
try {
|
|
879
|
+
return new Date(ms).toLocaleString(void 0, {
|
|
880
|
+
year: "numeric",
|
|
881
|
+
month: "short",
|
|
882
|
+
day: "numeric",
|
|
883
|
+
hour: "numeric",
|
|
884
|
+
minute: "2-digit",
|
|
885
|
+
second: "2-digit"
|
|
886
|
+
});
|
|
887
|
+
} catch (e) {
|
|
888
|
+
return "";
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
// src/engine/ai_agent.ts
|
|
893
|
+
function normalizePlatform(raw) {
|
|
894
|
+
var p = (raw || "").trim().toLowerCase();
|
|
895
|
+
return p === "claude" || p === "openai" ? p : null;
|
|
896
|
+
}
|
|
897
|
+
function parseAiAgentValue(value) {
|
|
898
|
+
var raw = (value || "").trim();
|
|
899
|
+
if (!raw || raw.toLowerCase() === "none") {
|
|
900
|
+
return { platform: null, model: "", contextWindow: null, hasPlatform: false };
|
|
901
|
+
}
|
|
902
|
+
var firstHash = raw.indexOf("#");
|
|
903
|
+
if (firstHash === -1) {
|
|
904
|
+
var only = normalizePlatform(raw);
|
|
905
|
+
return { platform: only, model: "", contextWindow: null, hasPlatform: !!only };
|
|
906
|
+
}
|
|
907
|
+
var platform = normalizePlatform(raw.slice(0, firstHash));
|
|
908
|
+
var rest = raw.slice(firstHash + 1);
|
|
909
|
+
var secondHash = rest.indexOf("#");
|
|
910
|
+
var model = (secondHash === -1 ? rest : rest.slice(0, secondHash)).trim();
|
|
911
|
+
var windowRaw = secondHash === -1 ? "" : rest.slice(secondHash + 1).trim();
|
|
912
|
+
var parsedWindow = windowRaw ? Number(windowRaw) : NaN;
|
|
913
|
+
var contextWindow = Number.isFinite(parsedWindow) && parsedWindow > 0 ? Math.floor(parsedWindow) : null;
|
|
914
|
+
return { platform, model, contextWindow, hasPlatform: !!platform };
|
|
915
|
+
}
|
|
916
|
+
function buildAiAgentValue(platform, model, contextWindow) {
|
|
917
|
+
var p = (platform || "").trim().toLowerCase();
|
|
918
|
+
if (!p || p === "none") return "none";
|
|
919
|
+
var m = (model || "").trim();
|
|
920
|
+
if (!m) return p;
|
|
921
|
+
var n = Number(contextWindow);
|
|
922
|
+
if (!Number.isFinite(n) || n <= 0) return p + "#" + m;
|
|
923
|
+
return p + "#" + m + "#" + Math.floor(n);
|
|
924
|
+
}
|
|
925
|
+
|
|
805
926
|
// src/engine/requests.ts
|
|
806
927
|
var ANTHROPIC_MESSAGES_API_URL = "https://api.anthropic.com/v1/messages";
|
|
807
928
|
var ANTHROPIC_MODELS_API_URL = "https://api.anthropic.com/v1/models";
|
|
@@ -1310,7 +1431,8 @@ async function getChatHistory(params, fetchOptions) {
|
|
|
1310
1431
|
method: "POST"
|
|
1311
1432
|
},
|
|
1312
1433
|
{ service: params.service, owner: params.owner },
|
|
1313
|
-
params.queue ? { queue: params.queue } : {}
|
|
1434
|
+
params.queue ? { queue: params.queue } : {},
|
|
1435
|
+
params.status ? { status: params.status } : {}
|
|
1314
1436
|
);
|
|
1315
1437
|
return chatEngineConfig().clientSecretRequestHistory(
|
|
1316
1438
|
p,
|
|
@@ -1347,6 +1469,25 @@ function extractLastUserTextFromRequest(requestBody) {
|
|
|
1347
1469
|
}
|
|
1348
1470
|
return "";
|
|
1349
1471
|
}
|
|
1472
|
+
function isIndexingRequestText(userText) {
|
|
1473
|
+
if (typeof userText !== "string") return false;
|
|
1474
|
+
return userText.indexOf("A new file has just been uploaded") === 0 || userText.indexOf("CONTINUE indexing") === 0;
|
|
1475
|
+
}
|
|
1476
|
+
function parseIndexingRequestText(userText) {
|
|
1477
|
+
if (typeof userText !== "string" || !userText) return null;
|
|
1478
|
+
var nameMatch = userText.match(/^- name: (.+)$/m);
|
|
1479
|
+
if (!nameMatch) return null;
|
|
1480
|
+
var mimeMatch = userText.match(/^- mime type: (.+)$/m);
|
|
1481
|
+
var sizeMatch = userText.match(/^- size \(bytes\): (\d+)$/m);
|
|
1482
|
+
var pathMatch = userText.match(/^- storage path: (.+)$/m);
|
|
1483
|
+
return {
|
|
1484
|
+
name: nameMatch[1].trim(),
|
|
1485
|
+
path: pathMatch ? pathMatch[1].trim() : void 0,
|
|
1486
|
+
mime: mimeMatch ? mimeMatch[1].trim() : void 0,
|
|
1487
|
+
size: sizeMatch ? Number(sizeMatch[1]) : void 0,
|
|
1488
|
+
continued: userText.indexOf("CONTINUE indexing") === 0
|
|
1489
|
+
};
|
|
1490
|
+
}
|
|
1350
1491
|
function mapHistoryListToMessages(list, platform, opts) {
|
|
1351
1492
|
var mapped = [], runningItemIds = [];
|
|
1352
1493
|
var extractAssistantText = platform === "openai" ? extractOpenAIText : extractClaudeText;
|
|
@@ -1363,31 +1504,25 @@ function mapHistoryListToMessages(list, platform, opts) {
|
|
|
1363
1504
|
var assistantText = isPending ? "" : (extractAssistantText(response) || "").trim() || "";
|
|
1364
1505
|
var isErrorResponse = !isPending && (isFailed || isErrorResponseBody(response));
|
|
1365
1506
|
var serverItemId = item && typeof item.id === "string" && item.id ? item.id : void 0;
|
|
1507
|
+
var createdTs = Number(item && item.created);
|
|
1508
|
+
var updatedTs = Number(item && item.updated);
|
|
1509
|
+
var userTs = isFinite(createdTs) && createdTs > 0 ? createdTs : isFinite(updatedTs) && updatedTs > 0 ? updatedTs : void 0;
|
|
1510
|
+
var replyTs = isFinite(updatedTs) && updatedTs > 0 ? updatedTs : isFinite(createdTs) && createdTs > 0 ? createdTs : void 0;
|
|
1366
1511
|
if (userText) {
|
|
1367
1512
|
var displayContent;
|
|
1368
1513
|
var indexFile = void 0;
|
|
1369
1514
|
if (item._isBgTask) {
|
|
1370
|
-
var
|
|
1371
|
-
if (
|
|
1372
|
-
var mimeMatch = userText.match(/^- mime type: (.+)$/m);
|
|
1373
|
-
var sizeMatch = userText.match(/^- size \(bytes\): (\d+)$/m);
|
|
1374
|
-
var pathMatch = userText.match(/^- storage path: (.+)$/m);
|
|
1375
|
-
var isContinuePass = userText.indexOf("CONTINUE indexing") === 0;
|
|
1515
|
+
var ref = parseIndexingRequestText(userText);
|
|
1516
|
+
if (ref) {
|
|
1376
1517
|
displayContent = opts.formatIndexingLabel(
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1518
|
+
ref.name,
|
|
1519
|
+
ref.mime || "",
|
|
1520
|
+
typeof ref.size === "number" ? ref.size : null,
|
|
1521
|
+
ref.path,
|
|
1381
1522
|
false,
|
|
1382
|
-
|
|
1523
|
+
ref.continued
|
|
1383
1524
|
);
|
|
1384
|
-
indexFile =
|
|
1385
|
-
name: nameMatch[1].trim(),
|
|
1386
|
-
path: pathMatch ? pathMatch[1].trim() : void 0,
|
|
1387
|
-
mime: mimeMatch ? mimeMatch[1].trim() : void 0,
|
|
1388
|
-
size: sizeMatch ? Number(sizeMatch[1]) : void 0,
|
|
1389
|
-
continued: isContinuePass
|
|
1390
|
-
};
|
|
1525
|
+
indexFile = ref;
|
|
1391
1526
|
} else {
|
|
1392
1527
|
displayContent = userText;
|
|
1393
1528
|
}
|
|
@@ -1402,6 +1537,7 @@ function mapHistoryListToMessages(list, platform, opts) {
|
|
|
1402
1537
|
if (indexFile) userMsg._indexFile = indexFile;
|
|
1403
1538
|
if (item._isOnBgQueue) userMsg._useBgQueue = true;
|
|
1404
1539
|
if (serverItemId !== void 0) userMsg._serverItemId = serverItemId;
|
|
1540
|
+
if (userTs !== void 0) userMsg._ts = userTs;
|
|
1405
1541
|
mapped.push(userMsg);
|
|
1406
1542
|
}
|
|
1407
1543
|
if (isCancelledItem) ; else if (isInProcess) {
|
|
@@ -1416,11 +1552,13 @@ function mapHistoryListToMessages(list, platform, opts) {
|
|
|
1416
1552
|
var em = { role: "assistant", content: getErrorMessage(response), isError: true };
|
|
1417
1553
|
if (item._isBgTask) em.isBackgroundTask = true;
|
|
1418
1554
|
if (serverItemId !== void 0) em._serverItemId = serverItemId;
|
|
1555
|
+
if (replyTs !== void 0) em._ts = replyTs;
|
|
1419
1556
|
mapped.push(em);
|
|
1420
1557
|
} else if (assistantText) {
|
|
1421
1558
|
var okm = { role: "assistant", content: sanitizeAttachmentLinksForHistory(assistantText, opts.serviceId, true) };
|
|
1422
1559
|
if (item._isBgTask) okm.isBackgroundTask = true;
|
|
1423
1560
|
if (serverItemId !== void 0) okm._serverItemId = serverItemId;
|
|
1561
|
+
if (replyTs !== void 0) okm._ts = replyTs;
|
|
1424
1562
|
mapped.push(okm);
|
|
1425
1563
|
}
|
|
1426
1564
|
});
|
|
@@ -1513,6 +1651,8 @@ function createHistoryFiller(base) {
|
|
|
1513
1651
|
}
|
|
1514
1652
|
|
|
1515
1653
|
// src/engine/session.ts
|
|
1654
|
+
var WORKER_PASS_ADOPT_LIMIT = 20;
|
|
1655
|
+
var WORKER_PASS_ADOPT_ATTEMPTS = [0, 2e3, 6e3];
|
|
1516
1656
|
var _g = typeof globalThis !== "undefined" ? globalThis : {};
|
|
1517
1657
|
function nowMs() {
|
|
1518
1658
|
return _g.performance && typeof _g.performance.now === "function" ? _g.performance.now() : Date.now();
|
|
@@ -1532,6 +1672,35 @@ function isPollStopped(res) {
|
|
|
1532
1672
|
var ChatSession = class {
|
|
1533
1673
|
constructor(host) {
|
|
1534
1674
|
this.typewriterQueue = Promise.resolve();
|
|
1675
|
+
/**
|
|
1676
|
+
* Pick up indexing passes the WORKER minted, which no client ever dispatched.
|
|
1677
|
+
*
|
|
1678
|
+
* For a PDF (and for text/grid when windowed indexing is on) the worker writes
|
|
1679
|
+
* pass N+1's row itself, inside pass N's invocation, right after saving pass
|
|
1680
|
+
* N's result. That row reaches this client through nothing at all: it is not in
|
|
1681
|
+
* bgTaskQueue (the client never asked for it) and it is not in state.messages
|
|
1682
|
+
* (only a first-page history load maps it in, which happens on mount, project
|
|
1683
|
+
* switch or tab return). So between two worker passes every pass the client
|
|
1684
|
+
* knows about is settled, and the collapsed row renders "Indexed N passes"
|
|
1685
|
+
* with no spinner and no Stop, for a file that is still being read. A user who
|
|
1686
|
+
* believes that then asks questions against a half-indexed file — which is what
|
|
1687
|
+
* this exists to prevent.
|
|
1688
|
+
*
|
|
1689
|
+
* So when a background indexing pass settles, ask the bg queue what is still
|
|
1690
|
+
* unresolved on it and adopt anything unknown as an ordinary BgTaskEntry.
|
|
1691
|
+
* drainBgTaskQueue then treats it exactly like a pass this client dispatched:
|
|
1692
|
+
* same bubble, same `_indexFile` (so it joins the file's collapsed row), same
|
|
1693
|
+
* poll — and that poll settling runs this again, so the chain is followed to
|
|
1694
|
+
* its end. `status`-scoped so the reply carries the live items only, never a
|
|
1695
|
+
* page of finished ones with their bodies.
|
|
1696
|
+
*
|
|
1697
|
+
* Termination: the only trigger is a pass SETTLING, which happens once per
|
|
1698
|
+
* pass. An adopted item that is still running is not re-adopted (its id is
|
|
1699
|
+
* already polled), and when the queue holds nothing unknown the chain stops on
|
|
1700
|
+
* its own. Nothing here is periodic — a timer that re-reads history is the
|
|
1701
|
+
* shape that previously looped fetchHistoryPage after an already-DONE index.
|
|
1702
|
+
*/
|
|
1703
|
+
this._adoptingWorkerPasses = false;
|
|
1535
1704
|
this.host = host;
|
|
1536
1705
|
this.state = {
|
|
1537
1706
|
messages: [],
|
|
@@ -1833,7 +2002,7 @@ var ChatSession = class {
|
|
|
1833
2002
|
var offExisting = this.aiChatHistoryCache[key] || { messages: [], endOfList: false, startKeyHistory: [] };
|
|
1834
2003
|
this.aiChatHistoryCache[key] = {
|
|
1835
2004
|
messages: offExisting.messages.concat([
|
|
1836
|
-
{ role: "user", content: composed, _ownerKey: key },
|
|
2005
|
+
{ role: "user", content: composed, _ownerKey: key, _ts: wallClockNow() },
|
|
1837
2006
|
{ role: "assistant", content: "", isPending: true, isPendingInProcess: true, _ownerKey: key }
|
|
1838
2007
|
]),
|
|
1839
2008
|
endOfList: offExisting.endOfList,
|
|
@@ -1865,7 +2034,7 @@ var ChatSession = class {
|
|
|
1865
2034
|
serviceId: id.serviceId,
|
|
1866
2035
|
history: resolvedHistory.concat([{ role: "user", content: llmComposed }])
|
|
1867
2036
|
});
|
|
1868
|
-
var queuedBubble = { role: "user", content: composed, isPendingQueued: true, isSendingToServer: true };
|
|
2037
|
+
var queuedBubble = { role: "user", content: composed, isPendingQueued: true, isSendingToServer: true, _ts: wallClockNow() };
|
|
1869
2038
|
if (key) queuedBubble._ownerKey = key;
|
|
1870
2039
|
if (useBgQueue) queuedBubble._useBgQueue = true;
|
|
1871
2040
|
this.state.messages.push(queuedBubble);
|
|
@@ -1900,7 +2069,7 @@ var ChatSession = class {
|
|
|
1900
2069
|
});
|
|
1901
2070
|
return;
|
|
1902
2071
|
}
|
|
1903
|
-
this.state.messages.push({ role: "user", content: composed, ...key ? { _ownerKey: key } : {} });
|
|
2072
|
+
this.state.messages.push({ role: "user", content: composed, _ts: wallClockNow(), ...key ? { _ownerKey: key } : {} });
|
|
1904
2073
|
this.state.messages.push({ role: "assistant", content: "", isPending: true, isPendingInProcess: true, ...key ? { _ownerKey: key } : {} });
|
|
1905
2074
|
this.host.notify();
|
|
1906
2075
|
this.updateHistoryCache();
|
|
@@ -1957,6 +2126,7 @@ var ChatSession = class {
|
|
|
1957
2126
|
var existing = this.state.messages[nextIdx];
|
|
1958
2127
|
var promoted = { role: "user", content: existing.content, isPendingInProcess: true, isBackgroundTask: true };
|
|
1959
2128
|
if (existing._indexFile) promoted._indexFile = existing._indexFile;
|
|
2129
|
+
if (existing._ts !== void 0) promoted._ts = existing._ts;
|
|
1960
2130
|
if (existing._serverItemId !== void 0) promoted._serverItemId = existing._serverItemId;
|
|
1961
2131
|
if (existing._ownerKey !== void 0) promoted._ownerKey = existing._ownerKey;
|
|
1962
2132
|
this.state.messages[nextIdx] = promoted;
|
|
@@ -1978,6 +2148,7 @@ var ChatSession = class {
|
|
|
1978
2148
|
var promoted = { role: "user", content: existing.content, isPendingInProcess: true };
|
|
1979
2149
|
if (existing.isBackgroundTask) promoted.isBackgroundTask = true;
|
|
1980
2150
|
if (existing._indexFile) promoted._indexFile = existing._indexFile;
|
|
2151
|
+
if (existing._ts !== void 0) promoted._ts = existing._ts;
|
|
1981
2152
|
if (existing._serverItemId !== void 0) promoted._serverItemId = existing._serverItemId;
|
|
1982
2153
|
if (existing._ownerKey !== void 0) promoted._ownerKey = existing._ownerKey;
|
|
1983
2154
|
if (existing.isSendingToServer) promoted.isSendingToServer = true;
|
|
@@ -2027,6 +2198,7 @@ var ChatSession = class {
|
|
|
2027
2198
|
var repl = { role: "user", content: exist.content };
|
|
2028
2199
|
if (exist._serverItemId !== void 0) repl._serverItemId = exist._serverItemId;
|
|
2029
2200
|
if (exist._ownerKey !== void 0) repl._ownerKey = exist._ownerKey;
|
|
2201
|
+
if (exist._ts !== void 0) repl._ts = exist._ts;
|
|
2030
2202
|
this.state.messages[userIdx] = repl;
|
|
2031
2203
|
}
|
|
2032
2204
|
var thinkingIdx = userIdx >= 0 ? this.state.messages.findIndex(function(m, i) {
|
|
@@ -2035,6 +2207,7 @@ var ChatSession = class {
|
|
|
2035
2207
|
return thinkingIdx !== -1 ? thinkingIdx : userIdx >= 0 ? userIdx + 1 : -1;
|
|
2036
2208
|
}
|
|
2037
2209
|
insertAtTarget(msg, targetIdx) {
|
|
2210
|
+
if (msg && msg.role === "assistant" && msg._ts === void 0) msg._ts = wallClockNow();
|
|
2038
2211
|
if (targetIdx >= 0 && this.state.messages[targetIdx] && this.state.messages[targetIdx].isPending) this.state.messages[targetIdx] = msg;
|
|
2039
2212
|
else if (targetIdx >= 0) this.state.messages.splice(targetIdx, 0, msg);
|
|
2040
2213
|
else this.state.messages.push(msg);
|
|
@@ -2371,6 +2544,8 @@ var ChatSession = class {
|
|
|
2371
2544
|
}
|
|
2372
2545
|
enqueueTypewrite(idx, fullText, localId) {
|
|
2373
2546
|
var self = this;
|
|
2547
|
+
var target = this.state.messages[idx];
|
|
2548
|
+
if (target && target._ts === void 0) target._ts = wallClockNow();
|
|
2374
2549
|
this.typewriterQueue = this.typewriterQueue.then(function() {
|
|
2375
2550
|
return self.typewriteIntoIndex(idx, fullText, localId);
|
|
2376
2551
|
});
|
|
@@ -2440,6 +2615,7 @@ var ChatSession = class {
|
|
|
2440
2615
|
var u = this.state.messages[uIdx];
|
|
2441
2616
|
var cleaned = { role: "user", content: u.content, _serverItemId: itemId };
|
|
2442
2617
|
if (u.isBackgroundTask) cleaned.isBackgroundTask = true;
|
|
2618
|
+
if (u._ts !== void 0) cleaned._ts = u._ts;
|
|
2443
2619
|
if (u._indexFile) cleaned._indexFile = u._indexFile;
|
|
2444
2620
|
this.state.messages[uIdx] = cleaned;
|
|
2445
2621
|
}
|
|
@@ -2470,8 +2646,21 @@ var ChatSession = class {
|
|
|
2470
2646
|
}
|
|
2471
2647
|
// --- background-task resolution + drain -------------------------------
|
|
2472
2648
|
handleHistoryItemResolution(itemId, response, platform) {
|
|
2649
|
+
var indexRef = this._indexRefOfItem(itemId);
|
|
2473
2650
|
this.applyHistoryItemResolution(itemId, response, platform);
|
|
2474
2651
|
this.promoteNextBgQueuedToRunning();
|
|
2652
|
+
if (indexRef) this._followWorkerIndexingChain(indexRef.name, indexRef.mime);
|
|
2653
|
+
}
|
|
2654
|
+
/** The file an already-rendered background pass is about, off its request
|
|
2655
|
+
* bubble. Null for an ordinary turn, which is most of them. */
|
|
2656
|
+
_indexRefOfItem(itemId) {
|
|
2657
|
+
if (!itemId) return null;
|
|
2658
|
+
for (var i = 0; i < this.state.messages.length; i++) {
|
|
2659
|
+
var m = this.state.messages[i];
|
|
2660
|
+
if (m._serverItemId !== itemId || m.role !== "user" || !m.isBackgroundTask) continue;
|
|
2661
|
+
return m._indexFile || null;
|
|
2662
|
+
}
|
|
2663
|
+
return null;
|
|
2475
2664
|
}
|
|
2476
2665
|
applyHistoryItemResolution(itemId, response, platform) {
|
|
2477
2666
|
this.historyItemPolls.delete(itemId);
|
|
@@ -2512,6 +2701,7 @@ var ChatSession = class {
|
|
|
2512
2701
|
var ex = this.state.messages[userIdx];
|
|
2513
2702
|
var settledUser = { role: "user", content: ex.content, _serverItemId: itemId };
|
|
2514
2703
|
if (ex.isBackgroundTask) settledUser.isBackgroundTask = true;
|
|
2704
|
+
if (ex._ts !== void 0) settledUser._ts = ex._ts;
|
|
2515
2705
|
if (ex._indexFile) settledUser._indexFile = ex._indexFile;
|
|
2516
2706
|
if (ex._useBgQueue) settledUser._useBgQueue = true;
|
|
2517
2707
|
this.state.messages[userIdx] = settledUser;
|
|
@@ -2604,6 +2794,116 @@ var ChatSession = class {
|
|
|
2604
2794
|
self.cancelQueuedMessage(t.msg, idx === -1 ? t.idx : idx);
|
|
2605
2795
|
});
|
|
2606
2796
|
}
|
|
2797
|
+
/**
|
|
2798
|
+
* True when the WORKER, not this client, drives the rest of this file's chain.
|
|
2799
|
+
* The mirror image of the early returns in maybeResumeIndexing: whatever that
|
|
2800
|
+
* refuses to continue is exactly what nothing client-side is tracking.
|
|
2801
|
+
*/
|
|
2802
|
+
_isWorkerDrivenIndexing(filename, mime) {
|
|
2803
|
+
if (!isPagedReadFile(filename, mime)) return false;
|
|
2804
|
+
if (isImageVisionFile(filename, mime)) return true;
|
|
2805
|
+
return windowedIndexingEnabled() && isWindowedReadFile(filename, mime);
|
|
2806
|
+
}
|
|
2807
|
+
_adoptWorkerIndexingPasses(attempt) {
|
|
2808
|
+
var self = this;
|
|
2809
|
+
if (this._adoptingWorkerPasses) return;
|
|
2810
|
+
var id = this.host.getIdentity();
|
|
2811
|
+
var platform = id.platform;
|
|
2812
|
+
if (!id.serviceId || platform !== "claude" && platform !== "openai") return;
|
|
2813
|
+
if (this.isPollingPaused() || !this.host.isViewMounted()) return;
|
|
2814
|
+
var svcId = id.serviceId, owner = id.owner;
|
|
2815
|
+
var queue = (id.userId || id.serviceId) + BG_INDEXING_QUEUE_SUFFIX;
|
|
2816
|
+
var ask = function(status) {
|
|
2817
|
+
return Promise.resolve(getChatHistory(
|
|
2818
|
+
{ service: svcId, owner, platform, queue, status },
|
|
2819
|
+
{ limit: WORKER_PASS_ADOPT_LIMIT }
|
|
2820
|
+
)).catch(function() {
|
|
2821
|
+
return null;
|
|
2822
|
+
});
|
|
2823
|
+
};
|
|
2824
|
+
this._adoptingWorkerPasses = true;
|
|
2825
|
+
Promise.all([ask("running"), ask("pending")]).then(function(results) {
|
|
2826
|
+
self._adoptingWorkerPasses = false;
|
|
2827
|
+
var now = self.host.getIdentity();
|
|
2828
|
+
if (now.serviceId !== svcId || now.platform !== platform) return;
|
|
2829
|
+
if (!self.host.isViewMounted()) return;
|
|
2830
|
+
var adoptedIds = [];
|
|
2831
|
+
for (var ri = 0; ri < results.length; ri++) {
|
|
2832
|
+
var list = results[ri] && Array.isArray(results[ri].list) ? results[ri].list : [];
|
|
2833
|
+
for (var i = 0; i < list.length; i++) {
|
|
2834
|
+
if (self._adoptWorkerIndexingItem(list[i], svcId, platform)) adoptedIds.push(list[i].id);
|
|
2835
|
+
}
|
|
2836
|
+
}
|
|
2837
|
+
if (adoptedIds.length) {
|
|
2838
|
+
self.drainBgTaskQueue();
|
|
2839
|
+
if (self._isTrackingAny(adoptedIds)) return;
|
|
2840
|
+
}
|
|
2841
|
+
if (attempt + 1 >= WORKER_PASS_ADOPT_ATTEMPTS.length) return;
|
|
2842
|
+
setTimeout(function() {
|
|
2843
|
+
var later = self.host.getIdentity();
|
|
2844
|
+
if (later.serviceId !== svcId || later.platform !== platform) return;
|
|
2845
|
+
if (self.isPollingPaused() || !self.host.isViewMounted()) return;
|
|
2846
|
+
self._adoptWorkerIndexingPasses(attempt + 1);
|
|
2847
|
+
}, WORKER_PASS_ADOPT_ATTEMPTS[attempt + 1]);
|
|
2848
|
+
}, function() {
|
|
2849
|
+
self._adoptingWorkerPasses = false;
|
|
2850
|
+
});
|
|
2851
|
+
}
|
|
2852
|
+
/** Any of these ids still queued or still polled, i.e. surviving work. */
|
|
2853
|
+
_isTrackingAny(ids) {
|
|
2854
|
+
for (var i = 0; i < ids.length; i++) {
|
|
2855
|
+
if (this.historyItemPolls.has(ids[i])) return true;
|
|
2856
|
+
for (var q = 0; q < this.bgTaskQueue.length; q++) {
|
|
2857
|
+
if (this.bgTaskQueue[q].id === ids[i]) return true;
|
|
2858
|
+
}
|
|
2859
|
+
}
|
|
2860
|
+
return false;
|
|
2861
|
+
}
|
|
2862
|
+
/** One live bg-queue item -> a BgTaskEntry, if it is an indexing pass this
|
|
2863
|
+
* client is not already tracking. Returns whether it was adopted. */
|
|
2864
|
+
_adoptWorkerIndexingItem(item, svcId, platform) {
|
|
2865
|
+
if (!item || typeof item.id !== "string" || !item.id) return false;
|
|
2866
|
+
if (item.status !== "pending" && item.status !== "running") return false;
|
|
2867
|
+
if (typeof item.poll !== "function") return false;
|
|
2868
|
+
if (this.historyItemPolls.has(item.id)) return false;
|
|
2869
|
+
for (var q = 0; q < this.bgTaskQueue.length; q++) {
|
|
2870
|
+
if (this.bgTaskQueue[q].id === item.id) return false;
|
|
2871
|
+
}
|
|
2872
|
+
for (var m = 0; m < this.state.messages.length; m++) {
|
|
2873
|
+
var msg = this.state.messages[m];
|
|
2874
|
+
if (msg._serverItemId !== item.id) continue;
|
|
2875
|
+
if (!(msg.isPending || msg.isPendingInProcess || msg.isPendingQueued)) return false;
|
|
2876
|
+
}
|
|
2877
|
+
var body = item.request_body;
|
|
2878
|
+
if (!body || typeof body !== "object") return false;
|
|
2879
|
+
if (platform === "claude" ? !Array.isArray(body.messages) : !Array.isArray(body.input)) return false;
|
|
2880
|
+
var userText = extractLastUserTextFromRequest(body);
|
|
2881
|
+
if (!isIndexingRequestText(userText)) return false;
|
|
2882
|
+
var ref = parseIndexingRequestText(userText);
|
|
2883
|
+
if (!ref || !ref.name) return false;
|
|
2884
|
+
if (!this._isWorkerDrivenIndexing(ref.name, ref.mime)) return false;
|
|
2885
|
+
this.bgTaskQueue.push({
|
|
2886
|
+
serviceId: svcId,
|
|
2887
|
+
platform,
|
|
2888
|
+
id: item.id,
|
|
2889
|
+
filename: ref.name,
|
|
2890
|
+
storagePath: ref.path,
|
|
2891
|
+
mime: ref.mime,
|
|
2892
|
+
size: ref.size,
|
|
2893
|
+
status: item.status === "running" ? "running" : "pending",
|
|
2894
|
+
poll: item.poll,
|
|
2895
|
+
// Drives the "(continuing)" label and marks this as a continuation for
|
|
2896
|
+
// _applyIndexCancellations, which must not read a CONTINUE pass as the
|
|
2897
|
+
// fresh first pass that lifts a stop.
|
|
2898
|
+
resumePass: ref.continued ? 1 : 0
|
|
2899
|
+
});
|
|
2900
|
+
return true;
|
|
2901
|
+
}
|
|
2902
|
+
/** Follow the chain on from a background indexing pass that just settled. */
|
|
2903
|
+
_followWorkerIndexingChain(filename, mime) {
|
|
2904
|
+
if (!this._isWorkerDrivenIndexing(filename, mime)) return;
|
|
2905
|
+
this._adoptWorkerIndexingPasses(0);
|
|
2906
|
+
}
|
|
2607
2907
|
/** Best-effort server-side cancel of a bg-queue item that has no bubble (so
|
|
2608
2908
|
* cancelQueuedMessage, which drives one, has nothing to act on). */
|
|
2609
2909
|
_cancelServerItem(serverId) {
|
|
@@ -2814,8 +3114,7 @@ var ChatSession = class {
|
|
|
2814
3114
|
var chatList = history && Array.isArray(history.list) ? history.list : [];
|
|
2815
3115
|
chatList.forEach(function(item) {
|
|
2816
3116
|
if (isBgIndexingQueue(item.queue_name)) {
|
|
2817
|
-
|
|
2818
|
-
if (typeof userText === "string" && (userText.indexOf("A new file has just been uploaded") === 0 || userText.indexOf("CONTINUE indexing") === 0)) item._isBgTask = true;
|
|
3117
|
+
if (isIndexingRequestText(extractLastUserTextFromRequest(item.request_body))) item._isBgTask = true;
|
|
2819
3118
|
else item._isOnBgQueue = true;
|
|
2820
3119
|
}
|
|
2821
3120
|
});
|
|
@@ -3288,7 +3587,10 @@ function buildChatDisplayList(messages, opts) {
|
|
|
3288
3587
|
cancellableIds: [],
|
|
3289
3588
|
cancelling: false,
|
|
3290
3589
|
mayHaveOlder: false,
|
|
3291
|
-
|
|
3590
|
+
// The run's first loaded pass, and never re-stamped: see the file
|
|
3591
|
+
// docstring. `anchorId` is filled in once every member is known.
|
|
3592
|
+
anchorIndex: i,
|
|
3593
|
+
anchorId: ""
|
|
3292
3594
|
};
|
|
3293
3595
|
order.push(runId);
|
|
3294
3596
|
}
|
|
@@ -3302,7 +3604,6 @@ function buildChatDisplayList(messages, opts) {
|
|
|
3302
3604
|
g.passCount++;
|
|
3303
3605
|
}
|
|
3304
3606
|
g.members.push({ msg, index: i });
|
|
3305
|
-
g.anchorIndex = i;
|
|
3306
3607
|
runOfIndex[i] = runId;
|
|
3307
3608
|
if (msg._serverItemId) runByItemId[msg._serverItemId] = runId;
|
|
3308
3609
|
if (ref && ref.name) keyByName[ref.name] = g.key;
|
|
@@ -3364,6 +3665,9 @@ function buildChatDisplayList(messages, opts) {
|
|
|
3364
3665
|
}
|
|
3365
3666
|
}
|
|
3366
3667
|
grp.mayHaveOlder = !sawFirstPass && hasMoreHistory;
|
|
3668
|
+
var anchor = grp.members[0];
|
|
3669
|
+
grp.anchorIndex = anchor.index;
|
|
3670
|
+
grp.anchorId = anchor.msg._serverItemId || anchor.msg._localId || "";
|
|
3367
3671
|
}
|
|
3368
3672
|
var out = [];
|
|
3369
3673
|
for (var j = 0; j < list.length; j++) {
|
|
@@ -3378,6 +3682,7 @@ function buildChatDisplayList(messages, opts) {
|
|
|
3378
3682
|
}
|
|
3379
3683
|
|
|
3380
3684
|
exports.BG_INDEXING_QUEUE_SUFFIX = BG_INDEXING_QUEUE_SUFFIX;
|
|
3685
|
+
exports.CLAUDE_INPUT_CAP_RATIO = CLAUDE_INPUT_CAP_RATIO;
|
|
3381
3686
|
exports.CLAUDE_PER_REQUEST_INPUT_CAP = CLAUDE_PER_REQUEST_INPUT_CAP;
|
|
3382
3687
|
exports.CONTEXT_WINDOW_BY_MODEL = CONTEXT_WINDOW_BY_MODEL;
|
|
3383
3688
|
exports.CONTEXT_WINDOW_DEFAULT = CONTEXT_WINDOW_DEFAULT;
|
|
@@ -3387,6 +3692,7 @@ exports.DEFAULT_OPENAI_MODEL = DEFAULT_OPENAI_MODEL;
|
|
|
3387
3692
|
exports.EXPIRED_ATTACHMENT_URL_HOST = EXPIRED_ATTACHMENT_URL_HOST;
|
|
3388
3693
|
exports.EXPIRED_ATTACHMENT_URL_ORIGIN = EXPIRED_ATTACHMENT_URL_ORIGIN;
|
|
3389
3694
|
exports.EXPIRED_LINK_REFRESH_EXPIRES_SECONDS = EXPIRED_LINK_REFRESH_EXPIRES_SECONDS;
|
|
3695
|
+
exports.HISTORY_BUDGET_RATIO = HISTORY_BUDGET_RATIO;
|
|
3390
3696
|
exports.HISTORY_FILL_SLACK_PX = HISTORY_FILL_SLACK_PX;
|
|
3391
3697
|
exports.HISTORY_TOKEN_BUDGET = HISTORY_TOKEN_BUDGET;
|
|
3392
3698
|
exports.LINK_LABEL_MAX_DISPLAY_CHARS = LINK_LABEL_MAX_DISPLAY_CHARS;
|
|
@@ -3400,6 +3706,7 @@ exports.OUTPUT_TOKEN_RESERVE = OUTPUT_TOKEN_RESERVE;
|
|
|
3400
3706
|
exports.POLL_INTERVAL = POLL_INTERVAL;
|
|
3401
3707
|
exports.RENDER_FROM_TOKEN = RENDER_FROM_TOKEN;
|
|
3402
3708
|
exports.TOOL_AND_RESPONSE_BUFFER = TOOL_AND_RESPONSE_BUFFER;
|
|
3709
|
+
exports.buildAiAgentValue = buildAiAgentValue;
|
|
3403
3710
|
exports.buildBoundedChatMessages = buildBoundedChatMessages;
|
|
3404
3711
|
exports.buildChatDisplayList = buildChatDisplayList;
|
|
3405
3712
|
exports.buildChatSystemPrompt = buildChatSystemPrompt;
|
|
@@ -3430,16 +3737,19 @@ exports.extractRemotePathFromAttachmentHref = extractRemotePathFromAttachmentHre
|
|
|
3430
3737
|
exports.fillHistoryViewport = fillHistoryViewport;
|
|
3431
3738
|
exports.filterListByClearHorizon = filterListByClearHorizon;
|
|
3432
3739
|
exports.findAttachmentParser = findAttachmentParser;
|
|
3740
|
+
exports.formatChatTimestamp = formatChatTimestamp;
|
|
3433
3741
|
exports.getAttachmentParsers = getAttachmentParsers;
|
|
3434
3742
|
exports.getChatHistory = getChatHistory;
|
|
3435
3743
|
exports.getContextWindow = getContextWindow;
|
|
3436
3744
|
exports.getErrorMessage = getErrorMessage;
|
|
3437
3745
|
exports.getExpiredAttachmentVisiblePath = getExpiredAttachmentVisiblePath;
|
|
3746
|
+
exports.getProjectContextWindow = getProjectContextWindow;
|
|
3438
3747
|
exports.groupAttachmentFailures = groupAttachmentFailures;
|
|
3439
3748
|
exports.isAuthExpiredError = isAuthExpiredError;
|
|
3440
3749
|
exports.isBgIndexingQueue = isBgIndexingQueue;
|
|
3441
3750
|
exports.isErrorResponseBody = isErrorResponseBody;
|
|
3442
3751
|
exports.isHttpUrlLike = isHttpUrlLike;
|
|
3752
|
+
exports.isIndexingRequestText = isIndexingRequestText;
|
|
3443
3753
|
exports.isNonRetryableRequestError = isNonRetryableRequestError;
|
|
3444
3754
|
exports.isOfficeFile = isOfficeFile;
|
|
3445
3755
|
exports.isServerExtractable = isServerExtractable;
|
|
@@ -3452,16 +3762,22 @@ exports.normalizeAttachmentPathCandidate = normalizeAttachmentPathCandidate;
|
|
|
3452
3762
|
exports.normalizeTextContent = normalizeTextContent;
|
|
3453
3763
|
exports.normalizeTrailingInlineToken = normalizeTrailingInlineToken;
|
|
3454
3764
|
exports.notifyAgentSaveAttachment = notifyAgentSaveAttachment;
|
|
3765
|
+
exports.parseAiAgentValue = parseAiAgentValue;
|
|
3455
3766
|
exports.parseAttachmentContent = parseAttachmentContent;
|
|
3456
3767
|
exports.parseIndexingLabel = parseIndexingLabel;
|
|
3768
|
+
exports.parseIndexingRequestText = parseIndexingRequestText;
|
|
3457
3769
|
exports.readExpiredAttachmentHref = readExpiredAttachmentHref;
|
|
3458
3770
|
exports.registerAttachmentParser = registerAttachmentParser;
|
|
3771
|
+
exports.registerModelContextWindows = registerModelContextWindows;
|
|
3772
|
+
exports.repairUrlEntities = repairUrlEntities;
|
|
3459
3773
|
exports.repairUrlWhitespace = repairUrlWhitespace;
|
|
3460
3774
|
exports.safeDecodeURIComponent = safeDecodeURIComponent;
|
|
3461
3775
|
exports.sanitizeAttachmentLinksForHistory = sanitizeAttachmentLinksForHistory;
|
|
3776
|
+
exports.setProjectContextWindow = setProjectContextWindow;
|
|
3462
3777
|
exports.stripFileBlocksFromHistory = stripFileBlocksFromHistory;
|
|
3463
3778
|
exports.transformContentWithImages = transformContentWithImages;
|
|
3464
3779
|
exports.transformContentWithOpenAIImages = transformContentWithOpenAIImages;
|
|
3465
3780
|
exports.truncateLabelForDisplay = truncateLabelForDisplay;
|
|
3781
|
+
exports.wallClockNow = wallClockNow;
|
|
3466
3782
|
//# sourceMappingURL=engine.cjs.map
|
|
3467
3783
|
//# sourceMappingURL=engine.cjs.map
|