@anuma/sdk 6.3.0 → 6.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/expo/index.cjs +193 -4
- package/dist/expo/index.d.mts +73 -0
- package/dist/expo/index.d.ts +73 -0
- package/dist/expo/index.mjs +193 -4
- package/dist/react/index.cjs +144 -30
- package/dist/react/index.d.mts +65 -0
- package/dist/react/index.d.ts +65 -0
- package/dist/react/index.mjs +144 -30
- package/dist/server/index.cjs +3 -0
- package/dist/server/index.d.mts +25 -0
- package/dist/server/index.d.ts +25 -0
- package/dist/server/index.mjs +3 -0
- package/package.json +1 -1
package/dist/expo/index.mjs
CHANGED
|
@@ -4986,6 +4986,153 @@ async function cleanupConversationSummary(database, conversationId) {
|
|
|
4986
4986
|
}
|
|
4987
4987
|
}
|
|
4988
4988
|
|
|
4989
|
+
// src/lib/chat/toolResultMessage.ts
|
|
4990
|
+
var HEADER = "[Tool Execution Results]\n\n";
|
|
4991
|
+
var FOOTER = "\n\nBased on these results, continue with the task.";
|
|
4992
|
+
var ENTRY_SEPARATOR = "\n\n";
|
|
4993
|
+
var TOOL_RESULT_FOOTER_LINE = FOOTER.trim();
|
|
4994
|
+
var MAX_PERSISTED_TOOL_RESULT_CHARS = 1e5;
|
|
4995
|
+
function buildToolResultContent(results) {
|
|
4996
|
+
const entries = results.map((r) => `Tool "${r.name}" returned: ${JSON.stringify(r.result)}`);
|
|
4997
|
+
const framing = HEADER.length + FOOTER.length + ENTRY_SEPARATOR.length * Math.max(0, entries.length - 1);
|
|
4998
|
+
const summary = capEntries(entries, MAX_PERSISTED_TOOL_RESULT_CHARS - framing).join(
|
|
4999
|
+
ENTRY_SEPARATOR
|
|
5000
|
+
);
|
|
5001
|
+
return `${HEADER}${summary}${FOOTER}`;
|
|
5002
|
+
}
|
|
5003
|
+
function capToolResultEntries(entries, budget) {
|
|
5004
|
+
return capEntries(entries, budget);
|
|
5005
|
+
}
|
|
5006
|
+
function capEntries(entries, budget) {
|
|
5007
|
+
const smallestFirst = entries.map((_, index) => index).sort((a, b) => entries[a].length - entries[b].length);
|
|
5008
|
+
const capped = [...entries];
|
|
5009
|
+
let remaining = budget;
|
|
5010
|
+
let unassigned = entries.length;
|
|
5011
|
+
for (const index of smallestFirst) {
|
|
5012
|
+
capped[index] = truncateEntry(entries[index], Math.floor(remaining / unassigned));
|
|
5013
|
+
remaining -= capped[index].length;
|
|
5014
|
+
unassigned--;
|
|
5015
|
+
}
|
|
5016
|
+
return capped;
|
|
5017
|
+
}
|
|
5018
|
+
function truncateEntry(entry, allowance) {
|
|
5019
|
+
if (entry.length <= allowance) return entry;
|
|
5020
|
+
const keep = allowance - truncationMarker(entry.length).length;
|
|
5021
|
+
if (keep <= 0) return entry.slice(0, Math.max(0, allowance));
|
|
5022
|
+
return `${entry.slice(0, keep)}${truncationMarker(entry.length - keep)}`;
|
|
5023
|
+
}
|
|
5024
|
+
function truncationMarker(omitted) {
|
|
5025
|
+
return `
|
|
5026
|
+
|
|
5027
|
+
... (tool output truncated, ${omitted} characters omitted)`;
|
|
5028
|
+
}
|
|
5029
|
+
|
|
5030
|
+
// src/lib/chat/toolResults.ts
|
|
5031
|
+
var TOOL_RESULTS_PREFIX = "[Tool Execution Results]";
|
|
5032
|
+
var DISPLAY_CARD_PLACEHOLDER = "[displayed a card to the user with the tool result]";
|
|
5033
|
+
var TOOL_LINE = /^Tool "([^"]+)" returned: (.*)$/;
|
|
5034
|
+
var TOOL_RESULT_ORIGIN = "tool_result";
|
|
5035
|
+
function isToolResultsRow(row) {
|
|
5036
|
+
if (row.origin === TOOL_RESULT_ORIGIN) return true;
|
|
5037
|
+
if (typeof row.origin === "string") return false;
|
|
5038
|
+
if (row.role !== "user" || !row.content.startsWith(TOOL_RESULTS_PREFIX)) return false;
|
|
5039
|
+
return parseToolResultSegments(row.content).length > 0;
|
|
5040
|
+
}
|
|
5041
|
+
function parseToolResultSegments(content) {
|
|
5042
|
+
const segments = [];
|
|
5043
|
+
for (const raw of content.split("\n")) {
|
|
5044
|
+
const line = raw.trim();
|
|
5045
|
+
const match = TOOL_LINE.exec(line);
|
|
5046
|
+
if (match) {
|
|
5047
|
+
segments.push({ name: match[1], line });
|
|
5048
|
+
continue;
|
|
5049
|
+
}
|
|
5050
|
+
const current = segments[segments.length - 1];
|
|
5051
|
+
if (!current || line === "" || line === TOOL_RESULT_FOOTER_LINE) continue;
|
|
5052
|
+
if (line === TOOL_RESULTS_PREFIX) continue;
|
|
5053
|
+
current.line = `${current.line}
|
|
5054
|
+
${line}`;
|
|
5055
|
+
}
|
|
5056
|
+
return segments;
|
|
5057
|
+
}
|
|
5058
|
+
function prepareToolResultsForReplay(rows, options) {
|
|
5059
|
+
if (options.fold) {
|
|
5060
|
+
return foldToolResultsRows(rows, {
|
|
5061
|
+
exclude: options.exclude,
|
|
5062
|
+
placeholder: options.placeholder
|
|
5063
|
+
});
|
|
5064
|
+
}
|
|
5065
|
+
return rows.filter((row) => !isToolResultsRow(row));
|
|
5066
|
+
}
|
|
5067
|
+
function foldToolResultsRows(rows, options) {
|
|
5068
|
+
const exclude = new Set(options?.exclude ?? []);
|
|
5069
|
+
const out = [];
|
|
5070
|
+
const pending = [];
|
|
5071
|
+
const assistantIndexById = /* @__PURE__ */ new Map();
|
|
5072
|
+
for (const row of rows) {
|
|
5073
|
+
if (isToolResultsRow(row)) {
|
|
5074
|
+
pending.push({ row, insertionPoint: out.length });
|
|
5075
|
+
continue;
|
|
5076
|
+
}
|
|
5077
|
+
out.push(row);
|
|
5078
|
+
if (row.role === "assistant" && row.uniqueId) {
|
|
5079
|
+
assistantIndexById.set(row.uniqueId, out.length - 1);
|
|
5080
|
+
}
|
|
5081
|
+
}
|
|
5082
|
+
const byTarget = /* @__PURE__ */ new Map();
|
|
5083
|
+
for (const { row, insertionPoint } of pending) {
|
|
5084
|
+
const target = resolveFoldTarget(out, row, insertionPoint, assistantIndexById);
|
|
5085
|
+
if (target === void 0) continue;
|
|
5086
|
+
const group = byTarget.get(target);
|
|
5087
|
+
if (group) group.push(row);
|
|
5088
|
+
else byTarget.set(target, [row]);
|
|
5089
|
+
}
|
|
5090
|
+
for (const [target, groupedRows] of byTarget) {
|
|
5091
|
+
const assistant = out[target];
|
|
5092
|
+
const kept = groupedRows.flatMap((row) => parseToolResultSegments(row.content)).filter((segment) => !exclude.has(segment.name));
|
|
5093
|
+
if (kept.length > 0) {
|
|
5094
|
+
out[target] = { ...assistant, content: appendToolResults(assistant.content, kept) };
|
|
5095
|
+
} else if (!assistant.content.trim() && options?.placeholder) {
|
|
5096
|
+
out[target] = { ...assistant, content: options.placeholder };
|
|
5097
|
+
}
|
|
5098
|
+
}
|
|
5099
|
+
return out;
|
|
5100
|
+
}
|
|
5101
|
+
function resolveFoldTarget(out, row, insertionPoint, assistantIndexById) {
|
|
5102
|
+
const linked = row.parentMessageId ? assistantIndexById.get(row.parentMessageId) : void 0;
|
|
5103
|
+
if (linked !== void 0) return linked;
|
|
5104
|
+
let previous;
|
|
5105
|
+
for (let i = insertionPoint - 1; i >= 0; i--) {
|
|
5106
|
+
if (out[i].role === "assistant") {
|
|
5107
|
+
previous = i;
|
|
5108
|
+
break;
|
|
5109
|
+
}
|
|
5110
|
+
}
|
|
5111
|
+
let next;
|
|
5112
|
+
for (let i = insertionPoint; i < out.length; i++) {
|
|
5113
|
+
if (out[i].role === "assistant") {
|
|
5114
|
+
next = i;
|
|
5115
|
+
break;
|
|
5116
|
+
}
|
|
5117
|
+
}
|
|
5118
|
+
if (previous === void 0) return next;
|
|
5119
|
+
if (next === void 0) return previous;
|
|
5120
|
+
return next - insertionPoint < insertionPoint - previous ? next : previous;
|
|
5121
|
+
}
|
|
5122
|
+
var MAX_FOLDED_APPENDIX_CHARS = 2e4;
|
|
5123
|
+
function appendToolResults(assistantContent, kept) {
|
|
5124
|
+
const framing = TOOL_RESULTS_PREFIX.length + 1 + (kept.length - 1);
|
|
5125
|
+
const capped = capToolResultEntries(
|
|
5126
|
+
kept.map((segment) => segment.line),
|
|
5127
|
+
MAX_FOLDED_APPENDIX_CHARS - framing
|
|
5128
|
+
);
|
|
5129
|
+
const appendix = `${TOOL_RESULTS_PREFIX}
|
|
5130
|
+
${capped.join("\n")}`;
|
|
5131
|
+
return assistantContent.trim() ? `${assistantContent}
|
|
5132
|
+
|
|
5133
|
+
${appendix}` : appendix;
|
|
5134
|
+
}
|
|
5135
|
+
|
|
4989
5136
|
// src/lib/db/chat/lazyDecrypt.ts
|
|
4990
5137
|
var LRU_CAPACITY = 256;
|
|
4991
5138
|
var titleCache = /* @__PURE__ */ new Map();
|
|
@@ -7061,6 +7208,9 @@ async function extractFacts(messages, options) {
|
|
|
7061
7208
|
...options.apiKey !== void 0 && { apiKey: options.apiKey },
|
|
7062
7209
|
...options.getToken !== void 0 && { getToken: options.getToken },
|
|
7063
7210
|
...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
|
|
7211
|
+
...options.endpointOverride !== void 0 && {
|
|
7212
|
+
endpointOverride: options.endpointOverride
|
|
7213
|
+
},
|
|
7064
7214
|
model: options.model ?? DEFAULT_EXTRACTION_MODEL,
|
|
7065
7215
|
systemPrompt: SYSTEM_PROMPT2,
|
|
7066
7216
|
userMessage: `Today's date is ${today}. Resolve any relative dates ("yesterday", "next week") against it.
|
|
@@ -10530,11 +10680,17 @@ function useChatStorage(options) {
|
|
|
10530
10680
|
onPiiRedacted,
|
|
10531
10681
|
nerDetector,
|
|
10532
10682
|
onServerToolCall,
|
|
10533
|
-
onToolCallArgumentsDelta
|
|
10683
|
+
onToolCallArgumentsDelta,
|
|
10684
|
+
toolResultsHistoryExclude,
|
|
10685
|
+
foldToolResultsInHistory
|
|
10534
10686
|
} = options;
|
|
10535
10687
|
const [currentConversationId, setCurrentConversationId] = useState4(
|
|
10536
10688
|
initialConversationId || null
|
|
10537
10689
|
);
|
|
10690
|
+
const toolResultsHistoryExcludeRef = useRef4(toolResultsHistoryExclude);
|
|
10691
|
+
toolResultsHistoryExcludeRef.current = toolResultsHistoryExclude;
|
|
10692
|
+
const foldToolResultsInHistoryRef = useRef4(foldToolResultsInHistory);
|
|
10693
|
+
foldToolResultsInHistoryRef.current = foldToolResultsInHistory;
|
|
10538
10694
|
const nerDetectorRef = useRef4(nerDetector);
|
|
10539
10695
|
nerDetectorRef.current = nerDetector;
|
|
10540
10696
|
const resolvedPiiRedaction = useMemo(
|
|
@@ -11402,7 +11558,13 @@ function useChatStorage(options) {
|
|
|
11402
11558
|
}
|
|
11403
11559
|
if (includeHistory) {
|
|
11404
11560
|
const validMessages = storedMessages.filter((msg) => !msg.error);
|
|
11405
|
-
const
|
|
11561
|
+
const replayableMessages = prepareToolResultsForReplay(validMessages, {
|
|
11562
|
+
fold: foldToolResultsInHistoryRef.current === true,
|
|
11563
|
+
exclude: toolResultsHistoryExcludeRef.current,
|
|
11564
|
+
placeholder: DISPLAY_CARD_PLACEHOLDER
|
|
11565
|
+
});
|
|
11566
|
+
const limitedMessages = replayableMessages.slice(-maxHistoryMessages);
|
|
11567
|
+
const foldedHistory = limitedMessages;
|
|
11406
11568
|
if (summarizeHistory && !getTokenRef.current) {
|
|
11407
11569
|
getLogger().warn(
|
|
11408
11570
|
"[summarize] summarizeHistory is enabled but getToken is not provided \u2014 summarization will be skipped"
|
|
@@ -11412,7 +11574,7 @@ function useChatStorage(options) {
|
|
|
11412
11574
|
const { messagesToConvert, summarySystemMessage } = await maybeSummarizeHistory({
|
|
11413
11575
|
database,
|
|
11414
11576
|
conversationId: convId,
|
|
11415
|
-
messages:
|
|
11577
|
+
messages: foldedHistory,
|
|
11416
11578
|
summarizeHistory,
|
|
11417
11579
|
summaryTokenThreshold,
|
|
11418
11580
|
summaryMinWindowMessages,
|
|
@@ -11782,6 +11944,7 @@ function useChatStorage(options) {
|
|
|
11782
11944
|
uniqueId: effectiveAssistantUniqueId
|
|
11783
11945
|
};
|
|
11784
11946
|
let storedAssistantMessage;
|
|
11947
|
+
let assistantMsgQueueId;
|
|
11785
11948
|
try {
|
|
11786
11949
|
const assistantMsgResult = await writeOrQueue(
|
|
11787
11950
|
"createMessage",
|
|
@@ -11791,6 +11954,7 @@ function useChatStorage(options) {
|
|
|
11791
11954
|
userMsgQueueId ? [userMsgQueueId] : []
|
|
11792
11955
|
);
|
|
11793
11956
|
storedAssistantMessage = assistantMsgResult.result;
|
|
11957
|
+
assistantMsgQueueId = assistantMsgResult.queueId;
|
|
11794
11958
|
if (!assistantMsgResult.queued) {
|
|
11795
11959
|
void embedMessageAsync(storedAssistantMessage, maskForCall);
|
|
11796
11960
|
}
|
|
@@ -11801,6 +11965,29 @@ function useChatStorage(options) {
|
|
|
11801
11965
|
userMessage: storedUserMessage
|
|
11802
11966
|
};
|
|
11803
11967
|
}
|
|
11968
|
+
const autoToolResults = result.autoExecutedToolResults;
|
|
11969
|
+
let storedToolResultsMessage;
|
|
11970
|
+
if (autoToolResults && autoToolResults.length > 0) {
|
|
11971
|
+
const toolResultsOpts = {
|
|
11972
|
+
conversationId: convId,
|
|
11973
|
+
role: "user",
|
|
11974
|
+
content: buildToolResultContent(autoToolResults),
|
|
11975
|
+
model: "",
|
|
11976
|
+
parentMessageId: storedAssistantMessage.uniqueId,
|
|
11977
|
+
origin: TOOL_RESULT_ORIGIN
|
|
11978
|
+
};
|
|
11979
|
+
try {
|
|
11980
|
+
const toolResultsWrite = await writeOrQueue(
|
|
11981
|
+
"createMessage",
|
|
11982
|
+
toolResultsOpts,
|
|
11983
|
+
() => createMessageOp(storageCtx, toolResultsOpts),
|
|
11984
|
+
() => makeSyntheticStoredMessage(toolResultsOpts),
|
|
11985
|
+
assistantMsgQueueId ? [assistantMsgQueueId] : []
|
|
11986
|
+
);
|
|
11987
|
+
storedToolResultsMessage = toolResultsWrite.result;
|
|
11988
|
+
} catch {
|
|
11989
|
+
}
|
|
11990
|
+
}
|
|
11804
11991
|
const refreshGetToken = getTokenRef.current;
|
|
11805
11992
|
if (refreshGetToken) {
|
|
11806
11993
|
Promise.resolve().then(() => shouldRefreshTools(getToolsChecksum(responseData), serverToolsConfig?.cache)).then((refresh) => {
|
|
@@ -11820,7 +12007,9 @@ function useChatStorage(options) {
|
|
|
11820
12007
|
data: responseData,
|
|
11821
12008
|
error: null,
|
|
11822
12009
|
userMessage: storedUserMessage,
|
|
11823
|
-
assistantMessage: storedAssistantMessage
|
|
12010
|
+
assistantMessage: storedAssistantMessage,
|
|
12011
|
+
autoExecutedToolResults: autoToolResults,
|
|
12012
|
+
toolResultsMessage: storedToolResultsMessage
|
|
11824
12013
|
};
|
|
11825
12014
|
},
|
|
11826
12015
|
[
|
package/dist/react/index.cjs
CHANGED
|
@@ -14936,6 +14936,7 @@ async function cleanupConversationSummary(database, conversationId) {
|
|
|
14936
14936
|
var HEADER = "[Tool Execution Results]\n\n";
|
|
14937
14937
|
var FOOTER = "\n\nBased on these results, continue with the task.";
|
|
14938
14938
|
var ENTRY_SEPARATOR = "\n\n";
|
|
14939
|
+
var TOOL_RESULT_FOOTER_LINE = FOOTER.trim();
|
|
14939
14940
|
var MAX_PERSISTED_TOOL_RESULT_CHARS = 1e5;
|
|
14940
14941
|
function buildToolResultContent(results) {
|
|
14941
14942
|
const entries = results.map((r) => `Tool "${r.name}" returned: ${JSON.stringify(r.result)}`);
|
|
@@ -14945,6 +14946,9 @@ function buildToolResultContent(results) {
|
|
|
14945
14946
|
);
|
|
14946
14947
|
return `${HEADER}${summary}${FOOTER}`;
|
|
14947
14948
|
}
|
|
14949
|
+
function capToolResultEntries(entries, budget) {
|
|
14950
|
+
return capEntries(entries, budget);
|
|
14951
|
+
}
|
|
14948
14952
|
function capEntries(entries, budget) {
|
|
14949
14953
|
const smallestFirst = entries.map((_, index) => index).sort((a, b) => entries[a].length - entries[b].length);
|
|
14950
14954
|
const capped = [...entries];
|
|
@@ -14969,6 +14973,112 @@ function truncationMarker(omitted) {
|
|
|
14969
14973
|
... (tool output truncated, ${omitted} characters omitted)`;
|
|
14970
14974
|
}
|
|
14971
14975
|
|
|
14976
|
+
// src/lib/chat/toolResults.ts
|
|
14977
|
+
var TOOL_RESULTS_PREFIX = "[Tool Execution Results]";
|
|
14978
|
+
var DISPLAY_CARD_PLACEHOLDER = "[displayed a card to the user with the tool result]";
|
|
14979
|
+
var TOOL_LINE = /^Tool "([^"]+)" returned: (.*)$/;
|
|
14980
|
+
var TOOL_RESULT_ORIGIN = "tool_result";
|
|
14981
|
+
function isToolResultsRow(row) {
|
|
14982
|
+
if (row.origin === TOOL_RESULT_ORIGIN) return true;
|
|
14983
|
+
if (typeof row.origin === "string") return false;
|
|
14984
|
+
if (row.role !== "user" || !row.content.startsWith(TOOL_RESULTS_PREFIX)) return false;
|
|
14985
|
+
return parseToolResultSegments(row.content).length > 0;
|
|
14986
|
+
}
|
|
14987
|
+
function parseToolResultSegments(content) {
|
|
14988
|
+
const segments = [];
|
|
14989
|
+
for (const raw of content.split("\n")) {
|
|
14990
|
+
const line = raw.trim();
|
|
14991
|
+
const match = TOOL_LINE.exec(line);
|
|
14992
|
+
if (match) {
|
|
14993
|
+
segments.push({ name: match[1], line });
|
|
14994
|
+
continue;
|
|
14995
|
+
}
|
|
14996
|
+
const current = segments[segments.length - 1];
|
|
14997
|
+
if (!current || line === "" || line === TOOL_RESULT_FOOTER_LINE) continue;
|
|
14998
|
+
if (line === TOOL_RESULTS_PREFIX) continue;
|
|
14999
|
+
current.line = `${current.line}
|
|
15000
|
+
${line}`;
|
|
15001
|
+
}
|
|
15002
|
+
return segments;
|
|
15003
|
+
}
|
|
15004
|
+
function prepareToolResultsForReplay(rows, options) {
|
|
15005
|
+
if (options.fold) {
|
|
15006
|
+
return foldToolResultsRows(rows, {
|
|
15007
|
+
exclude: options.exclude,
|
|
15008
|
+
placeholder: options.placeholder
|
|
15009
|
+
});
|
|
15010
|
+
}
|
|
15011
|
+
return rows.filter((row) => !isToolResultsRow(row));
|
|
15012
|
+
}
|
|
15013
|
+
function foldToolResultsRows(rows, options) {
|
|
15014
|
+
const exclude = new Set(options?.exclude ?? []);
|
|
15015
|
+
const out = [];
|
|
15016
|
+
const pending = [];
|
|
15017
|
+
const assistantIndexById = /* @__PURE__ */ new Map();
|
|
15018
|
+
for (const row of rows) {
|
|
15019
|
+
if (isToolResultsRow(row)) {
|
|
15020
|
+
pending.push({ row, insertionPoint: out.length });
|
|
15021
|
+
continue;
|
|
15022
|
+
}
|
|
15023
|
+
out.push(row);
|
|
15024
|
+
if (row.role === "assistant" && row.uniqueId) {
|
|
15025
|
+
assistantIndexById.set(row.uniqueId, out.length - 1);
|
|
15026
|
+
}
|
|
15027
|
+
}
|
|
15028
|
+
const byTarget = /* @__PURE__ */ new Map();
|
|
15029
|
+
for (const { row, insertionPoint } of pending) {
|
|
15030
|
+
const target = resolveFoldTarget(out, row, insertionPoint, assistantIndexById);
|
|
15031
|
+
if (target === void 0) continue;
|
|
15032
|
+
const group = byTarget.get(target);
|
|
15033
|
+
if (group) group.push(row);
|
|
15034
|
+
else byTarget.set(target, [row]);
|
|
15035
|
+
}
|
|
15036
|
+
for (const [target, groupedRows] of byTarget) {
|
|
15037
|
+
const assistant = out[target];
|
|
15038
|
+
const kept = groupedRows.flatMap((row) => parseToolResultSegments(row.content)).filter((segment) => !exclude.has(segment.name));
|
|
15039
|
+
if (kept.length > 0) {
|
|
15040
|
+
out[target] = { ...assistant, content: appendToolResults(assistant.content, kept) };
|
|
15041
|
+
} else if (!assistant.content.trim() && options?.placeholder) {
|
|
15042
|
+
out[target] = { ...assistant, content: options.placeholder };
|
|
15043
|
+
}
|
|
15044
|
+
}
|
|
15045
|
+
return out;
|
|
15046
|
+
}
|
|
15047
|
+
function resolveFoldTarget(out, row, insertionPoint, assistantIndexById) {
|
|
15048
|
+
const linked = row.parentMessageId ? assistantIndexById.get(row.parentMessageId) : void 0;
|
|
15049
|
+
if (linked !== void 0) return linked;
|
|
15050
|
+
let previous;
|
|
15051
|
+
for (let i = insertionPoint - 1; i >= 0; i--) {
|
|
15052
|
+
if (out[i].role === "assistant") {
|
|
15053
|
+
previous = i;
|
|
15054
|
+
break;
|
|
15055
|
+
}
|
|
15056
|
+
}
|
|
15057
|
+
let next;
|
|
15058
|
+
for (let i = insertionPoint; i < out.length; i++) {
|
|
15059
|
+
if (out[i].role === "assistant") {
|
|
15060
|
+
next = i;
|
|
15061
|
+
break;
|
|
15062
|
+
}
|
|
15063
|
+
}
|
|
15064
|
+
if (previous === void 0) return next;
|
|
15065
|
+
if (next === void 0) return previous;
|
|
15066
|
+
return next - insertionPoint < insertionPoint - previous ? next : previous;
|
|
15067
|
+
}
|
|
15068
|
+
var MAX_FOLDED_APPENDIX_CHARS = 2e4;
|
|
15069
|
+
function appendToolResults(assistantContent, kept) {
|
|
15070
|
+
const framing = TOOL_RESULTS_PREFIX.length + 1 + (kept.length - 1);
|
|
15071
|
+
const capped = capToolResultEntries(
|
|
15072
|
+
kept.map((segment) => segment.line),
|
|
15073
|
+
MAX_FOLDED_APPENDIX_CHARS - framing
|
|
15074
|
+
);
|
|
15075
|
+
const appendix = `${TOOL_RESULTS_PREFIX}
|
|
15076
|
+
${capped.join("\n")}`;
|
|
15077
|
+
return assistantContent.trim() ? `${assistantContent}
|
|
15078
|
+
|
|
15079
|
+
${appendix}` : appendix;
|
|
15080
|
+
}
|
|
15081
|
+
|
|
14972
15082
|
// src/lib/db/chat/lazyDecrypt.ts
|
|
14973
15083
|
init_useEncryption();
|
|
14974
15084
|
init_encryption_utils();
|
|
@@ -17543,6 +17653,9 @@ async function extractFacts(messages, options) {
|
|
|
17543
17653
|
...options.apiKey !== void 0 && { apiKey: options.apiKey },
|
|
17544
17654
|
...options.getToken !== void 0 && { getToken: options.getToken },
|
|
17545
17655
|
...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
|
|
17656
|
+
...options.endpointOverride !== void 0 && {
|
|
17657
|
+
endpointOverride: options.endpointOverride
|
|
17658
|
+
},
|
|
17546
17659
|
model: options.model ?? DEFAULT_EXTRACTION_MODEL,
|
|
17547
17660
|
systemPrompt: SYSTEM_PROMPT4,
|
|
17548
17661
|
userMessage: `Today's date is ${today}. Resolve any relative dates ("yesterday", "next week") against it.
|
|
@@ -22321,11 +22434,17 @@ function useChatStorage(options) {
|
|
|
22321
22434
|
preProcessors,
|
|
22322
22435
|
piiRedaction,
|
|
22323
22436
|
onPiiRedacted,
|
|
22324
|
-
nerDetector
|
|
22437
|
+
nerDetector,
|
|
22438
|
+
toolResultsHistoryExclude,
|
|
22439
|
+
foldToolResultsInHistory
|
|
22325
22440
|
} = options;
|
|
22326
22441
|
const [currentConversationId, setCurrentConversationId] = (0, import_react5.useState)(
|
|
22327
22442
|
initialConversationId || null
|
|
22328
22443
|
);
|
|
22444
|
+
const toolResultsHistoryExcludeRef = (0, import_react5.useRef)(toolResultsHistoryExclude);
|
|
22445
|
+
toolResultsHistoryExcludeRef.current = toolResultsHistoryExclude;
|
|
22446
|
+
const foldToolResultsInHistoryRef = (0, import_react5.useRef)(foldToolResultsInHistory);
|
|
22447
|
+
foldToolResultsInHistoryRef.current = foldToolResultsInHistory;
|
|
22329
22448
|
const nerDetectorRef = (0, import_react5.useRef)(nerDetector);
|
|
22330
22449
|
nerDetectorRef.current = nerDetector;
|
|
22331
22450
|
const resolvedPiiRedaction = (0, import_react5.useMemo)(
|
|
@@ -23333,7 +23452,12 @@ function useChatStorage(options) {
|
|
|
23333
23452
|
}
|
|
23334
23453
|
if (includeHistory) {
|
|
23335
23454
|
const validMessages = storedMessages.filter((msg) => !msg.error);
|
|
23336
|
-
const
|
|
23455
|
+
const replayableMessages = prepareToolResultsForReplay(validMessages, {
|
|
23456
|
+
fold: foldToolResultsInHistoryRef.current === true,
|
|
23457
|
+
exclude: toolResultsHistoryExcludeRef.current,
|
|
23458
|
+
placeholder: DISPLAY_CARD_PLACEHOLDER
|
|
23459
|
+
});
|
|
23460
|
+
const limitedMessages = replayableMessages.slice(-maxHistoryMessages);
|
|
23337
23461
|
if (!fileContextForRequest) {
|
|
23338
23462
|
for (let i = limitedMessages.length - 1; i >= 0; i--) {
|
|
23339
23463
|
const msg = limitedMessages[i];
|
|
@@ -23343,6 +23467,7 @@ function useChatStorage(options) {
|
|
|
23343
23467
|
}
|
|
23344
23468
|
}
|
|
23345
23469
|
}
|
|
23470
|
+
const foldedHistory = limitedMessages;
|
|
23346
23471
|
let encryptionKey;
|
|
23347
23472
|
if (walletAddress && hasEncryptionKey(walletAddress) && isOPFSSupported()) {
|
|
23348
23473
|
try {
|
|
@@ -23359,7 +23484,7 @@ function useChatStorage(options) {
|
|
|
23359
23484
|
const { messagesToConvert, summarySystemMessage } = await maybeSummarizeHistory({
|
|
23360
23485
|
database,
|
|
23361
23486
|
conversationId: convId,
|
|
23362
|
-
messages:
|
|
23487
|
+
messages: foldedHistory,
|
|
23363
23488
|
summarizeHistory,
|
|
23364
23489
|
summaryTokenThreshold,
|
|
23365
23490
|
summaryMinWindowMessages,
|
|
@@ -23817,37 +23942,25 @@ function useChatStorage(options) {
|
|
|
23817
23942
|
}
|
|
23818
23943
|
}
|
|
23819
23944
|
const autoToolResults = result.autoExecutedToolResults;
|
|
23945
|
+
let storedToolResultsMessage;
|
|
23820
23946
|
if (autoToolResults && autoToolResults.length > 0) {
|
|
23821
|
-
const
|
|
23947
|
+
const toolResultsOpts = {
|
|
23948
|
+
conversationId: convId,
|
|
23949
|
+
role: "user",
|
|
23950
|
+
content: buildToolResultContent(autoToolResults),
|
|
23951
|
+
model: "",
|
|
23952
|
+
parentMessageId: storedAssistantMessage.uniqueId,
|
|
23953
|
+
origin: TOOL_RESULT_ORIGIN
|
|
23954
|
+
};
|
|
23822
23955
|
try {
|
|
23823
|
-
await writeOrQueue(
|
|
23956
|
+
const toolResultsWrite = await writeOrQueue(
|
|
23824
23957
|
"createMessage",
|
|
23825
|
-
|
|
23826
|
-
|
|
23827
|
-
|
|
23828
|
-
content: toolResultContent,
|
|
23829
|
-
model: "",
|
|
23830
|
-
parentMessageId: storedAssistantMessage.uniqueId,
|
|
23831
|
-
origin: "tool_result"
|
|
23832
|
-
},
|
|
23833
|
-
() => createMessageOp(storageCtx, {
|
|
23834
|
-
conversationId: convId,
|
|
23835
|
-
role: "user",
|
|
23836
|
-
content: toolResultContent,
|
|
23837
|
-
model: "",
|
|
23838
|
-
parentMessageId: storedAssistantMessage.uniqueId,
|
|
23839
|
-
origin: "tool_result"
|
|
23840
|
-
}),
|
|
23841
|
-
() => makeSyntheticStoredMessage({
|
|
23842
|
-
conversationId: convId,
|
|
23843
|
-
role: "user",
|
|
23844
|
-
content: toolResultContent,
|
|
23845
|
-
model: "",
|
|
23846
|
-
parentMessageId: storedAssistantMessage.uniqueId,
|
|
23847
|
-
origin: "tool_result"
|
|
23848
|
-
}),
|
|
23958
|
+
toolResultsOpts,
|
|
23959
|
+
() => createMessageOp(storageCtx, toolResultsOpts),
|
|
23960
|
+
() => makeSyntheticStoredMessage(toolResultsOpts),
|
|
23849
23961
|
assistantMsgQueueId ? [assistantMsgQueueId] : []
|
|
23850
23962
|
);
|
|
23963
|
+
storedToolResultsMessage = toolResultsWrite.result;
|
|
23851
23964
|
} catch {
|
|
23852
23965
|
}
|
|
23853
23966
|
}
|
|
@@ -23870,7 +23983,8 @@ function useChatStorage(options) {
|
|
|
23870
23983
|
error: null,
|
|
23871
23984
|
userMessage: storedUserMessage,
|
|
23872
23985
|
assistantMessage: storedAssistantMessage,
|
|
23873
|
-
autoExecutedToolResults:
|
|
23986
|
+
autoExecutedToolResults: autoToolResults,
|
|
23987
|
+
toolResultsMessage: storedToolResultsMessage
|
|
23874
23988
|
};
|
|
23875
23989
|
},
|
|
23876
23990
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- intentionally omitting stable refs and config values that don't change identity
|
package/dist/react/index.d.mts
CHANGED
|
@@ -5220,6 +5220,40 @@ interface BaseUseChatStorageOptions {
|
|
|
5220
5220
|
* Defaults to the hardcoded MCP_R2_DOMAIN from clientConfig.
|
|
5221
5221
|
*/
|
|
5222
5222
|
mcpR2Domain?: string;
|
|
5223
|
+
/**
|
|
5224
|
+
* Tool names whose persisted results must never be replayed to the model.
|
|
5225
|
+
*
|
|
5226
|
+
* A turn's auto-executed tool results are stored as a synthetic
|
|
5227
|
+
* `[Tool Execution Results]` row and, on a replayed send, folded back onto the
|
|
5228
|
+
* assistant turn they belong to — that is what lets a follow-up question about a
|
|
5229
|
+
* tool's output work after a reload. Name a tool here when its payload exists for
|
|
5230
|
+
* the RENDERER rather than the model: a display card can carry data the model was
|
|
5231
|
+
* deliberately never given (People Nearby's card holds third parties' snapped
|
|
5232
|
+
* coordinates, which the search result strips), and replaying it would hand that
|
|
5233
|
+
* data straight back.
|
|
5234
|
+
*
|
|
5235
|
+
* Hook-level rather than per-send on purpose: an exclusion that has to be
|
|
5236
|
+
* remembered at every call site is one bad send away from leaking.
|
|
5237
|
+
*/
|
|
5238
|
+
toolResultsHistoryExclude?: string[];
|
|
5239
|
+
/**
|
|
5240
|
+
* Fold persisted `[Tool Execution Results]` rows onto the assistant turn that produced them
|
|
5241
|
+
* when replaying stored history, instead of dropping them.
|
|
5242
|
+
*
|
|
5243
|
+
* **Defaults to `false`, and that default is deliberate.** Folding is the better behaviour —
|
|
5244
|
+
* it is what lets a follow-up about a tool's output work after a reload — but it moves the
|
|
5245
|
+
* payload from a `role: "user"` row onto an `assistant` row. Any consumer that scrubs these
|
|
5246
|
+
* rows by checking `role === "user"` plus the content prefix (which is how both apps did it
|
|
5247
|
+
* before this option existed) stops catching them the moment folding turns on, and starts
|
|
5248
|
+
* replaying whatever the row held. Opting in is therefore a statement that the caller has
|
|
5249
|
+
* checked its own filters and set {@link toolResultsHistoryExclude} for any payload that must
|
|
5250
|
+
* not reach the model.
|
|
5251
|
+
*
|
|
5252
|
+
* With it off, rows are dropped from the replayed history rather than sent verbatim. Verbatim
|
|
5253
|
+
* would put two consecutive `user` turns on the wire, and the model answers the previous turn
|
|
5254
|
+
* instead of the new prompt.
|
|
5255
|
+
*/
|
|
5256
|
+
foldToolResultsInHistory?: boolean;
|
|
5223
5257
|
/**
|
|
5224
5258
|
* Pre-processors run after the last user message is received but before
|
|
5225
5259
|
* the first LLM request. Each receives the prompt text and a shared
|
|
@@ -7094,6 +7128,31 @@ interface QuarantinedMemoryInfo {
|
|
|
7094
7128
|
interface ExtractFactsOptions extends PortalLlmAuth {
|
|
7095
7129
|
baseUrl?: string;
|
|
7096
7130
|
model?: string;
|
|
7131
|
+
/**
|
|
7132
|
+
* Optional per-call request path override, forwarded to
|
|
7133
|
+
* {@link callPortalJsonCompletion}. When set, the extraction call POSTs to
|
|
7134
|
+
* `baseUrl + endpointOverride` instead of the default
|
|
7135
|
+
* `/api/v1/chat/completions` — path only, body unchanged. Lets callers route
|
|
7136
|
+
* this internal-utility pass to a dedicated endpoint. Invalid values throw at
|
|
7137
|
+
* call time (see {@link validateEndpointOverride}).
|
|
7138
|
+
*
|
|
7139
|
+
* Why this exists (anuma-ai/ai-memoryless-client#5536): auto-extraction is the
|
|
7140
|
+
* highest-volume first-party background call in the product — one per
|
|
7141
|
+
* extracting turn, on every platform — and it carries no flow fingerprint, so
|
|
7142
|
+
* the portal's freeloader detector classifies it as scripted abuse. In reject
|
|
7143
|
+
* mode that 403s every basic-tier extraction, which surfaces here as
|
|
7144
|
+
* `onExhaustedEmpty` → `empty-after-retry` and leaves free-tier vaults empty.
|
|
7145
|
+
* {@link TopicExtractOptions.endpointOverride} already exists for the same
|
|
7146
|
+
* reason on the topic pass; this is the fact pass catching up.
|
|
7147
|
+
*
|
|
7148
|
+
* IMPORTANT — the utility endpoint clamps to a PRICE CEILING and never
|
|
7149
|
+
* rejects, so pointing this at `/api/v1/utility/chat/completions` while the
|
|
7150
|
+
* portal's ceiling prices below {@link DEFAULT_EXTRACTION_MODEL} silently
|
|
7151
|
+
* rewrites the model instead of 403-ing. That trades a visible failure for an
|
|
7152
|
+
* invisible quality regression: raise `PORTAL_UTILITY_CEILING_MODEL` to at
|
|
7153
|
+
* least the extraction model's rate BEFORE setting this in a client.
|
|
7154
|
+
*/
|
|
7155
|
+
endpointOverride?: string;
|
|
7097
7156
|
/** Override the global fetch implementation (useful for tests). */
|
|
7098
7157
|
fetchFn?: typeof fetch;
|
|
7099
7158
|
/**
|
|
@@ -10329,6 +10388,12 @@ type SendMessageWithStorageResult = {
|
|
|
10329
10388
|
name: string;
|
|
10330
10389
|
result: unknown;
|
|
10331
10390
|
}[];
|
|
10391
|
+
/**
|
|
10392
|
+
* The synthetic `[Tool Execution Results]` row those results were persisted as, so a caller can
|
|
10393
|
+
* key its transient overlay on the id the SDK actually wrote instead of deriving one (#5519).
|
|
10394
|
+
* Absent when no tool ran, or when that (non-fatal) write failed.
|
|
10395
|
+
*/
|
|
10396
|
+
toolResultsMessage?: StoredMessage;
|
|
10332
10397
|
} | {
|
|
10333
10398
|
data: ApiResponse;
|
|
10334
10399
|
error: null;
|
package/dist/react/index.d.ts
CHANGED
|
@@ -5220,6 +5220,40 @@ interface BaseUseChatStorageOptions {
|
|
|
5220
5220
|
* Defaults to the hardcoded MCP_R2_DOMAIN from clientConfig.
|
|
5221
5221
|
*/
|
|
5222
5222
|
mcpR2Domain?: string;
|
|
5223
|
+
/**
|
|
5224
|
+
* Tool names whose persisted results must never be replayed to the model.
|
|
5225
|
+
*
|
|
5226
|
+
* A turn's auto-executed tool results are stored as a synthetic
|
|
5227
|
+
* `[Tool Execution Results]` row and, on a replayed send, folded back onto the
|
|
5228
|
+
* assistant turn they belong to — that is what lets a follow-up question about a
|
|
5229
|
+
* tool's output work after a reload. Name a tool here when its payload exists for
|
|
5230
|
+
* the RENDERER rather than the model: a display card can carry data the model was
|
|
5231
|
+
* deliberately never given (People Nearby's card holds third parties' snapped
|
|
5232
|
+
* coordinates, which the search result strips), and replaying it would hand that
|
|
5233
|
+
* data straight back.
|
|
5234
|
+
*
|
|
5235
|
+
* Hook-level rather than per-send on purpose: an exclusion that has to be
|
|
5236
|
+
* remembered at every call site is one bad send away from leaking.
|
|
5237
|
+
*/
|
|
5238
|
+
toolResultsHistoryExclude?: string[];
|
|
5239
|
+
/**
|
|
5240
|
+
* Fold persisted `[Tool Execution Results]` rows onto the assistant turn that produced them
|
|
5241
|
+
* when replaying stored history, instead of dropping them.
|
|
5242
|
+
*
|
|
5243
|
+
* **Defaults to `false`, and that default is deliberate.** Folding is the better behaviour —
|
|
5244
|
+
* it is what lets a follow-up about a tool's output work after a reload — but it moves the
|
|
5245
|
+
* payload from a `role: "user"` row onto an `assistant` row. Any consumer that scrubs these
|
|
5246
|
+
* rows by checking `role === "user"` plus the content prefix (which is how both apps did it
|
|
5247
|
+
* before this option existed) stops catching them the moment folding turns on, and starts
|
|
5248
|
+
* replaying whatever the row held. Opting in is therefore a statement that the caller has
|
|
5249
|
+
* checked its own filters and set {@link toolResultsHistoryExclude} for any payload that must
|
|
5250
|
+
* not reach the model.
|
|
5251
|
+
*
|
|
5252
|
+
* With it off, rows are dropped from the replayed history rather than sent verbatim. Verbatim
|
|
5253
|
+
* would put two consecutive `user` turns on the wire, and the model answers the previous turn
|
|
5254
|
+
* instead of the new prompt.
|
|
5255
|
+
*/
|
|
5256
|
+
foldToolResultsInHistory?: boolean;
|
|
5223
5257
|
/**
|
|
5224
5258
|
* Pre-processors run after the last user message is received but before
|
|
5225
5259
|
* the first LLM request. Each receives the prompt text and a shared
|
|
@@ -7094,6 +7128,31 @@ interface QuarantinedMemoryInfo {
|
|
|
7094
7128
|
interface ExtractFactsOptions extends PortalLlmAuth {
|
|
7095
7129
|
baseUrl?: string;
|
|
7096
7130
|
model?: string;
|
|
7131
|
+
/**
|
|
7132
|
+
* Optional per-call request path override, forwarded to
|
|
7133
|
+
* {@link callPortalJsonCompletion}. When set, the extraction call POSTs to
|
|
7134
|
+
* `baseUrl + endpointOverride` instead of the default
|
|
7135
|
+
* `/api/v1/chat/completions` — path only, body unchanged. Lets callers route
|
|
7136
|
+
* this internal-utility pass to a dedicated endpoint. Invalid values throw at
|
|
7137
|
+
* call time (see {@link validateEndpointOverride}).
|
|
7138
|
+
*
|
|
7139
|
+
* Why this exists (anuma-ai/ai-memoryless-client#5536): auto-extraction is the
|
|
7140
|
+
* highest-volume first-party background call in the product — one per
|
|
7141
|
+
* extracting turn, on every platform — and it carries no flow fingerprint, so
|
|
7142
|
+
* the portal's freeloader detector classifies it as scripted abuse. In reject
|
|
7143
|
+
* mode that 403s every basic-tier extraction, which surfaces here as
|
|
7144
|
+
* `onExhaustedEmpty` → `empty-after-retry` and leaves free-tier vaults empty.
|
|
7145
|
+
* {@link TopicExtractOptions.endpointOverride} already exists for the same
|
|
7146
|
+
* reason on the topic pass; this is the fact pass catching up.
|
|
7147
|
+
*
|
|
7148
|
+
* IMPORTANT — the utility endpoint clamps to a PRICE CEILING and never
|
|
7149
|
+
* rejects, so pointing this at `/api/v1/utility/chat/completions` while the
|
|
7150
|
+
* portal's ceiling prices below {@link DEFAULT_EXTRACTION_MODEL} silently
|
|
7151
|
+
* rewrites the model instead of 403-ing. That trades a visible failure for an
|
|
7152
|
+
* invisible quality regression: raise `PORTAL_UTILITY_CEILING_MODEL` to at
|
|
7153
|
+
* least the extraction model's rate BEFORE setting this in a client.
|
|
7154
|
+
*/
|
|
7155
|
+
endpointOverride?: string;
|
|
7097
7156
|
/** Override the global fetch implementation (useful for tests). */
|
|
7098
7157
|
fetchFn?: typeof fetch;
|
|
7099
7158
|
/**
|
|
@@ -10329,6 +10388,12 @@ type SendMessageWithStorageResult = {
|
|
|
10329
10388
|
name: string;
|
|
10330
10389
|
result: unknown;
|
|
10331
10390
|
}[];
|
|
10391
|
+
/**
|
|
10392
|
+
* The synthetic `[Tool Execution Results]` row those results were persisted as, so a caller can
|
|
10393
|
+
* key its transient overlay on the id the SDK actually wrote instead of deriving one (#5519).
|
|
10394
|
+
* Absent when no tool ran, or when that (non-fatal) write failed.
|
|
10395
|
+
*/
|
|
10396
|
+
toolResultsMessage?: StoredMessage;
|
|
10332
10397
|
} | {
|
|
10333
10398
|
data: ApiResponse;
|
|
10334
10399
|
error: null;
|