@anuma/sdk 6.3.1 → 6.4.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/dist/expo/{chunk-PBCULYOW.mjs → chunk-WYARTNEN.mjs} +49 -1
- package/dist/expo/index.cjs +239 -4
- package/dist/expo/index.d.mts +48 -0
- package/dist/expo/index.d.ts +48 -0
- package/dist/expo/index.mjs +191 -5
- package/dist/expo/{recall-UVM2366D.mjs → recall-7FOWWX5T.mjs} +1 -1
- package/dist/react/{chunk-TI3UVQPF.mjs → chunk-IO4ZCPK2.mjs} +49 -1
- package/dist/react/index.cjs +190 -30
- package/dist/react/index.d.mts +40 -0
- package/dist/react/index.d.ts +40 -0
- package/dist/react/index.mjs +142 -31
- package/dist/react/{recall-PCM7H5TA.mjs → recall-2J2755WC.mjs} +1 -1
- package/dist/server/{chunk-S5WEN7TE.mjs → chunk-EKYGWD5N.mjs} +49 -1
- package/dist/server/index.cjs +49 -0
- package/dist/server/index.mjs +1 -1
- package/dist/server/{recall-BQSCJBGI.mjs → recall-IVV6EILK.mjs} +1 -1
- package/package.json +1 -1
|
@@ -4641,6 +4641,12 @@ async function embedMessage(ctx, messageId, options) {
|
|
|
4641
4641
|
if (message.origin === NON_EMBEDDABLE_ORIGIN) {
|
|
4642
4642
|
return message;
|
|
4643
4643
|
}
|
|
4644
|
+
if (isEncrypted(message.content)) {
|
|
4645
|
+
getLogger().warn(
|
|
4646
|
+
`memoryEngine: message ${messageId} is still encrypted (key unavailable?) \u2014 not embedded`
|
|
4647
|
+
);
|
|
4648
|
+
return message;
|
|
4649
|
+
}
|
|
4644
4650
|
const embedding = await generateEmbedding(message.content, options);
|
|
4645
4651
|
const embeddingModel = options.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
4646
4652
|
return updateMessageEmbeddingOp(ctx, messageId, embedding, embeddingModel);
|
|
@@ -4648,11 +4654,17 @@ async function embedMessage(ctx, messageId, options) {
|
|
|
4648
4654
|
async function embedAllMessages(ctx, options, filter) {
|
|
4649
4655
|
const embeddingModel = options.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
4650
4656
|
let embeddedCount = 0;
|
|
4657
|
+
let stillEncrypted = 0;
|
|
4658
|
+
let considered = 0;
|
|
4659
|
+
let sealedRowsSeen = 0;
|
|
4660
|
+
let rowsSeen = 0;
|
|
4651
4661
|
const conversations = await getConversationsOp(ctx);
|
|
4652
4662
|
const targetConversations = filter?.conversationId ? conversations.filter((c) => c.conversationId === filter.conversationId) : conversations;
|
|
4653
4663
|
for (const conv of targetConversations) {
|
|
4654
4664
|
const messages = await getMessagesOp(ctx, conv.conversationId);
|
|
4655
4665
|
for (const message of messages) {
|
|
4666
|
+
rowsSeen++;
|
|
4667
|
+
if (isEncrypted(message.content)) sealedRowsSeen++;
|
|
4656
4668
|
if (message.vector && message.vector.length > 0) {
|
|
4657
4669
|
continue;
|
|
4658
4670
|
}
|
|
@@ -4665,6 +4677,11 @@ async function embedAllMessages(ctx, options, filter) {
|
|
|
4665
4677
|
if (message.origin === NON_EMBEDDABLE_ORIGIN) {
|
|
4666
4678
|
continue;
|
|
4667
4679
|
}
|
|
4680
|
+
considered++;
|
|
4681
|
+
if (isEncrypted(message.content)) {
|
|
4682
|
+
stillEncrypted++;
|
|
4683
|
+
continue;
|
|
4684
|
+
}
|
|
4668
4685
|
const minLength = filter?.minContentLength ?? DEFAULT_MIN_CONTENT_LENGTH;
|
|
4669
4686
|
if (message.content.length < minLength) {
|
|
4670
4687
|
continue;
|
|
@@ -4679,6 +4696,13 @@ async function embedAllMessages(ctx, options, filter) {
|
|
|
4679
4696
|
}
|
|
4680
4697
|
}
|
|
4681
4698
|
}
|
|
4699
|
+
if (stillEncrypted > 0 || sealedRowsSeen > 0) {
|
|
4700
|
+
getLogger().error(
|
|
4701
|
+
"memoryEngine: messages still encrypted (key unavailable?) \u2014 excluded from embedding",
|
|
4702
|
+
void 0,
|
|
4703
|
+
{ stillEncrypted, considered, sealedRowsSeen, rowsSeen }
|
|
4704
|
+
);
|
|
4705
|
+
}
|
|
4682
4706
|
return embeddedCount;
|
|
4683
4707
|
}
|
|
4684
4708
|
async function chunkAndEmbedMessage(ctx, messageId, options) {
|
|
@@ -4693,6 +4717,12 @@ async function chunkAndEmbedMessage(ctx, messageId, options) {
|
|
|
4693
4717
|
if (message.origin === NON_EMBEDDABLE_ORIGIN) {
|
|
4694
4718
|
return message;
|
|
4695
4719
|
}
|
|
4720
|
+
if (isEncrypted(message.content)) {
|
|
4721
|
+
getLogger().warn(
|
|
4722
|
+
`memoryEngine: message ${messageId} is still encrypted (key unavailable?) \u2014 not embedded`
|
|
4723
|
+
);
|
|
4724
|
+
return message;
|
|
4725
|
+
}
|
|
4696
4726
|
const embeddingModel = options.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
4697
4727
|
if (!shouldChunkMessage(message.content, chunkSize)) {
|
|
4698
4728
|
const embedding = await generateEmbedding(message.content, options);
|
|
@@ -4717,9 +4747,15 @@ async function chunkAndEmbedAllMessages(ctx, options, filter) {
|
|
|
4717
4747
|
const targetConversations = filter?.conversationId ? conversations.filter((c) => c.conversationId === filter.conversationId) : conversations;
|
|
4718
4748
|
const shortMessages = [];
|
|
4719
4749
|
const longMessages = [];
|
|
4750
|
+
let stillEncrypted = 0;
|
|
4751
|
+
let considered = 0;
|
|
4752
|
+
let sealedRowsSeen = 0;
|
|
4753
|
+
let rowsSeen = 0;
|
|
4720
4754
|
for (const conv of targetConversations) {
|
|
4721
4755
|
const messages = await getMessagesOp(ctx, conv.conversationId);
|
|
4722
4756
|
for (const message of messages) {
|
|
4757
|
+
rowsSeen++;
|
|
4758
|
+
if (isEncrypted(message.content)) sealedRowsSeen++;
|
|
4723
4759
|
const isStale = message.embeddingModel !== void 0 && message.embeddingModel !== null && message.embeddingModel !== embeddingModel;
|
|
4724
4760
|
if (message.chunks && message.chunks.length > 0 && !isStale) continue;
|
|
4725
4761
|
const hasVector = message.vector && message.vector.length > 0;
|
|
@@ -4727,6 +4763,11 @@ async function chunkAndEmbedAllMessages(ctx, options, filter) {
|
|
|
4727
4763
|
if (filter?.roles && !filter.roles.includes(message.role)) continue;
|
|
4728
4764
|
if (message.role === "system") continue;
|
|
4729
4765
|
if (message.origin === NON_EMBEDDABLE_ORIGIN) continue;
|
|
4766
|
+
considered++;
|
|
4767
|
+
if (isEncrypted(message.content)) {
|
|
4768
|
+
stillEncrypted++;
|
|
4769
|
+
continue;
|
|
4770
|
+
}
|
|
4730
4771
|
if (message.content.length < minLength) continue;
|
|
4731
4772
|
if (shouldChunkMessage(message.content, chunkSize)) {
|
|
4732
4773
|
longMessages.push({
|
|
@@ -4738,6 +4779,13 @@ async function chunkAndEmbedAllMessages(ctx, options, filter) {
|
|
|
4738
4779
|
}
|
|
4739
4780
|
}
|
|
4740
4781
|
}
|
|
4782
|
+
if (stillEncrypted > 0 || sealedRowsSeen > 0) {
|
|
4783
|
+
getLogger().error(
|
|
4784
|
+
"memoryEngine: messages still encrypted (key unavailable?) \u2014 excluded from embedding",
|
|
4785
|
+
void 0,
|
|
4786
|
+
{ stillEncrypted, considered, sealedRowsSeen, rowsSeen }
|
|
4787
|
+
);
|
|
4788
|
+
}
|
|
4741
4789
|
let embeddedCount = 0;
|
|
4742
4790
|
if (shortMessages.length > 0) {
|
|
4743
4791
|
try {
|
|
@@ -6518,7 +6566,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
|
|
|
6518
6566
|
subQueries = decomp.subQueries;
|
|
6519
6567
|
}
|
|
6520
6568
|
}
|
|
6521
|
-
const { recall: recall2 } = await import("./recall-
|
|
6569
|
+
const { recall: recall2 } = await import("./recall-7FOWWX5T.mjs");
|
|
6522
6570
|
let recallDegraded = [];
|
|
6523
6571
|
const result = await recall2(
|
|
6524
6572
|
query,
|
package/dist/expo/index.cjs
CHANGED
|
@@ -3437,6 +3437,12 @@ async function embedMessage(ctx, messageId, options) {
|
|
|
3437
3437
|
if (message.origin === NON_EMBEDDABLE_ORIGIN) {
|
|
3438
3438
|
return message;
|
|
3439
3439
|
}
|
|
3440
|
+
if (isEncrypted(message.content)) {
|
|
3441
|
+
getLogger().warn(
|
|
3442
|
+
`memoryEngine: message ${messageId} is still encrypted (key unavailable?) \u2014 not embedded`
|
|
3443
|
+
);
|
|
3444
|
+
return message;
|
|
3445
|
+
}
|
|
3440
3446
|
const embedding = await generateEmbedding(message.content, options);
|
|
3441
3447
|
const embeddingModel = options.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
3442
3448
|
return updateMessageEmbeddingOp(ctx, messageId, embedding, embeddingModel);
|
|
@@ -3444,11 +3450,17 @@ async function embedMessage(ctx, messageId, options) {
|
|
|
3444
3450
|
async function embedAllMessages(ctx, options, filter) {
|
|
3445
3451
|
const embeddingModel = options.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
3446
3452
|
let embeddedCount = 0;
|
|
3453
|
+
let stillEncrypted = 0;
|
|
3454
|
+
let considered = 0;
|
|
3455
|
+
let sealedRowsSeen = 0;
|
|
3456
|
+
let rowsSeen = 0;
|
|
3447
3457
|
const conversations = await getConversationsOp(ctx);
|
|
3448
3458
|
const targetConversations = filter?.conversationId ? conversations.filter((c) => c.conversationId === filter.conversationId) : conversations;
|
|
3449
3459
|
for (const conv of targetConversations) {
|
|
3450
3460
|
const messages = await getMessagesOp(ctx, conv.conversationId);
|
|
3451
3461
|
for (const message of messages) {
|
|
3462
|
+
rowsSeen++;
|
|
3463
|
+
if (isEncrypted(message.content)) sealedRowsSeen++;
|
|
3452
3464
|
if (message.vector && message.vector.length > 0) {
|
|
3453
3465
|
continue;
|
|
3454
3466
|
}
|
|
@@ -3461,6 +3473,11 @@ async function embedAllMessages(ctx, options, filter) {
|
|
|
3461
3473
|
if (message.origin === NON_EMBEDDABLE_ORIGIN) {
|
|
3462
3474
|
continue;
|
|
3463
3475
|
}
|
|
3476
|
+
considered++;
|
|
3477
|
+
if (isEncrypted(message.content)) {
|
|
3478
|
+
stillEncrypted++;
|
|
3479
|
+
continue;
|
|
3480
|
+
}
|
|
3464
3481
|
const minLength = filter?.minContentLength ?? DEFAULT_MIN_CONTENT_LENGTH;
|
|
3465
3482
|
if (message.content.length < minLength) {
|
|
3466
3483
|
continue;
|
|
@@ -3475,6 +3492,13 @@ async function embedAllMessages(ctx, options, filter) {
|
|
|
3475
3492
|
}
|
|
3476
3493
|
}
|
|
3477
3494
|
}
|
|
3495
|
+
if (stillEncrypted > 0 || sealedRowsSeen > 0) {
|
|
3496
|
+
getLogger().error(
|
|
3497
|
+
"memoryEngine: messages still encrypted (key unavailable?) \u2014 excluded from embedding",
|
|
3498
|
+
void 0,
|
|
3499
|
+
{ stillEncrypted, considered, sealedRowsSeen, rowsSeen }
|
|
3500
|
+
);
|
|
3501
|
+
}
|
|
3478
3502
|
return embeddedCount;
|
|
3479
3503
|
}
|
|
3480
3504
|
async function chunkAndEmbedMessage(ctx, messageId, options) {
|
|
@@ -3489,6 +3513,12 @@ async function chunkAndEmbedMessage(ctx, messageId, options) {
|
|
|
3489
3513
|
if (message.origin === NON_EMBEDDABLE_ORIGIN) {
|
|
3490
3514
|
return message;
|
|
3491
3515
|
}
|
|
3516
|
+
if (isEncrypted(message.content)) {
|
|
3517
|
+
getLogger().warn(
|
|
3518
|
+
`memoryEngine: message ${messageId} is still encrypted (key unavailable?) \u2014 not embedded`
|
|
3519
|
+
);
|
|
3520
|
+
return message;
|
|
3521
|
+
}
|
|
3492
3522
|
const embeddingModel = options.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
3493
3523
|
if (!shouldChunkMessage(message.content, chunkSize)) {
|
|
3494
3524
|
const embedding = await generateEmbedding(message.content, options);
|
|
@@ -3513,9 +3543,15 @@ async function chunkAndEmbedAllMessages(ctx, options, filter) {
|
|
|
3513
3543
|
const targetConversations = filter?.conversationId ? conversations.filter((c) => c.conversationId === filter.conversationId) : conversations;
|
|
3514
3544
|
const shortMessages = [];
|
|
3515
3545
|
const longMessages = [];
|
|
3546
|
+
let stillEncrypted = 0;
|
|
3547
|
+
let considered = 0;
|
|
3548
|
+
let sealedRowsSeen = 0;
|
|
3549
|
+
let rowsSeen = 0;
|
|
3516
3550
|
for (const conv of targetConversations) {
|
|
3517
3551
|
const messages = await getMessagesOp(ctx, conv.conversationId);
|
|
3518
3552
|
for (const message of messages) {
|
|
3553
|
+
rowsSeen++;
|
|
3554
|
+
if (isEncrypted(message.content)) sealedRowsSeen++;
|
|
3519
3555
|
const isStale = message.embeddingModel !== void 0 && message.embeddingModel !== null && message.embeddingModel !== embeddingModel;
|
|
3520
3556
|
if (message.chunks && message.chunks.length > 0 && !isStale) continue;
|
|
3521
3557
|
const hasVector = message.vector && message.vector.length > 0;
|
|
@@ -3523,6 +3559,11 @@ async function chunkAndEmbedAllMessages(ctx, options, filter) {
|
|
|
3523
3559
|
if (filter?.roles && !filter.roles.includes(message.role)) continue;
|
|
3524
3560
|
if (message.role === "system") continue;
|
|
3525
3561
|
if (message.origin === NON_EMBEDDABLE_ORIGIN) continue;
|
|
3562
|
+
considered++;
|
|
3563
|
+
if (isEncrypted(message.content)) {
|
|
3564
|
+
stillEncrypted++;
|
|
3565
|
+
continue;
|
|
3566
|
+
}
|
|
3526
3567
|
if (message.content.length < minLength) continue;
|
|
3527
3568
|
if (shouldChunkMessage(message.content, chunkSize)) {
|
|
3528
3569
|
longMessages.push({
|
|
@@ -3534,6 +3575,13 @@ async function chunkAndEmbedAllMessages(ctx, options, filter) {
|
|
|
3534
3575
|
}
|
|
3535
3576
|
}
|
|
3536
3577
|
}
|
|
3578
|
+
if (stillEncrypted > 0 || sealedRowsSeen > 0) {
|
|
3579
|
+
getLogger().error(
|
|
3580
|
+
"memoryEngine: messages still encrypted (key unavailable?) \u2014 excluded from embedding",
|
|
3581
|
+
void 0,
|
|
3582
|
+
{ stillEncrypted, considered, sealedRowsSeen, rowsSeen }
|
|
3583
|
+
);
|
|
3584
|
+
}
|
|
3537
3585
|
let embeddedCount = 0;
|
|
3538
3586
|
if (shortMessages.length > 0) {
|
|
3539
3587
|
try {
|
|
@@ -3584,6 +3632,7 @@ var init_embeddings = __esm({
|
|
|
3584
3632
|
"src/lib/memoryEngine/embeddings.ts"() {
|
|
3585
3633
|
"use strict";
|
|
3586
3634
|
init_operations();
|
|
3635
|
+
init_encryption_utils();
|
|
3587
3636
|
init_logger();
|
|
3588
3637
|
init_chunking();
|
|
3589
3638
|
init_constants();
|
|
@@ -14092,6 +14141,153 @@ async function cleanupConversationSummary(database, conversationId) {
|
|
|
14092
14141
|
}
|
|
14093
14142
|
}
|
|
14094
14143
|
|
|
14144
|
+
// src/lib/chat/toolResultMessage.ts
|
|
14145
|
+
var HEADER = "[Tool Execution Results]\n\n";
|
|
14146
|
+
var FOOTER = "\n\nBased on these results, continue with the task.";
|
|
14147
|
+
var ENTRY_SEPARATOR = "\n\n";
|
|
14148
|
+
var TOOL_RESULT_FOOTER_LINE = FOOTER.trim();
|
|
14149
|
+
var MAX_PERSISTED_TOOL_RESULT_CHARS = 1e5;
|
|
14150
|
+
function buildToolResultContent(results) {
|
|
14151
|
+
const entries = results.map((r) => `Tool "${r.name}" returned: ${JSON.stringify(r.result)}`);
|
|
14152
|
+
const framing = HEADER.length + FOOTER.length + ENTRY_SEPARATOR.length * Math.max(0, entries.length - 1);
|
|
14153
|
+
const summary = capEntries(entries, MAX_PERSISTED_TOOL_RESULT_CHARS - framing).join(
|
|
14154
|
+
ENTRY_SEPARATOR
|
|
14155
|
+
);
|
|
14156
|
+
return `${HEADER}${summary}${FOOTER}`;
|
|
14157
|
+
}
|
|
14158
|
+
function capToolResultEntries(entries, budget) {
|
|
14159
|
+
return capEntries(entries, budget);
|
|
14160
|
+
}
|
|
14161
|
+
function capEntries(entries, budget) {
|
|
14162
|
+
const smallestFirst = entries.map((_, index) => index).sort((a, b) => entries[a].length - entries[b].length);
|
|
14163
|
+
const capped = [...entries];
|
|
14164
|
+
let remaining = budget;
|
|
14165
|
+
let unassigned = entries.length;
|
|
14166
|
+
for (const index of smallestFirst) {
|
|
14167
|
+
capped[index] = truncateEntry(entries[index], Math.floor(remaining / unassigned));
|
|
14168
|
+
remaining -= capped[index].length;
|
|
14169
|
+
unassigned--;
|
|
14170
|
+
}
|
|
14171
|
+
return capped;
|
|
14172
|
+
}
|
|
14173
|
+
function truncateEntry(entry, allowance) {
|
|
14174
|
+
if (entry.length <= allowance) return entry;
|
|
14175
|
+
const keep = allowance - truncationMarker(entry.length).length;
|
|
14176
|
+
if (keep <= 0) return entry.slice(0, Math.max(0, allowance));
|
|
14177
|
+
return `${entry.slice(0, keep)}${truncationMarker(entry.length - keep)}`;
|
|
14178
|
+
}
|
|
14179
|
+
function truncationMarker(omitted) {
|
|
14180
|
+
return `
|
|
14181
|
+
|
|
14182
|
+
... (tool output truncated, ${omitted} characters omitted)`;
|
|
14183
|
+
}
|
|
14184
|
+
|
|
14185
|
+
// src/lib/chat/toolResults.ts
|
|
14186
|
+
var TOOL_RESULTS_PREFIX = "[Tool Execution Results]";
|
|
14187
|
+
var DISPLAY_CARD_PLACEHOLDER = "[displayed a card to the user with the tool result]";
|
|
14188
|
+
var TOOL_LINE = /^Tool "([^"]+)" returned: (.*)$/;
|
|
14189
|
+
var TOOL_RESULT_ORIGIN = "tool_result";
|
|
14190
|
+
function isToolResultsRow(row) {
|
|
14191
|
+
if (row.origin === TOOL_RESULT_ORIGIN) return true;
|
|
14192
|
+
if (typeof row.origin === "string") return false;
|
|
14193
|
+
if (row.role !== "user" || !row.content.startsWith(TOOL_RESULTS_PREFIX)) return false;
|
|
14194
|
+
return parseToolResultSegments(row.content).length > 0;
|
|
14195
|
+
}
|
|
14196
|
+
function parseToolResultSegments(content) {
|
|
14197
|
+
const segments = [];
|
|
14198
|
+
for (const raw of content.split("\n")) {
|
|
14199
|
+
const line = raw.trim();
|
|
14200
|
+
const match = TOOL_LINE.exec(line);
|
|
14201
|
+
if (match) {
|
|
14202
|
+
segments.push({ name: match[1], line });
|
|
14203
|
+
continue;
|
|
14204
|
+
}
|
|
14205
|
+
const current = segments[segments.length - 1];
|
|
14206
|
+
if (!current || line === "" || line === TOOL_RESULT_FOOTER_LINE) continue;
|
|
14207
|
+
if (line === TOOL_RESULTS_PREFIX) continue;
|
|
14208
|
+
current.line = `${current.line}
|
|
14209
|
+
${line}`;
|
|
14210
|
+
}
|
|
14211
|
+
return segments;
|
|
14212
|
+
}
|
|
14213
|
+
function prepareToolResultsForReplay(rows, options) {
|
|
14214
|
+
if (options.fold) {
|
|
14215
|
+
return foldToolResultsRows(rows, {
|
|
14216
|
+
exclude: options.exclude,
|
|
14217
|
+
placeholder: options.placeholder
|
|
14218
|
+
});
|
|
14219
|
+
}
|
|
14220
|
+
return rows.filter((row) => !isToolResultsRow(row));
|
|
14221
|
+
}
|
|
14222
|
+
function foldToolResultsRows(rows, options) {
|
|
14223
|
+
const exclude = new Set(options?.exclude ?? []);
|
|
14224
|
+
const out = [];
|
|
14225
|
+
const pending = [];
|
|
14226
|
+
const assistantIndexById = /* @__PURE__ */ new Map();
|
|
14227
|
+
for (const row of rows) {
|
|
14228
|
+
if (isToolResultsRow(row)) {
|
|
14229
|
+
pending.push({ row, insertionPoint: out.length });
|
|
14230
|
+
continue;
|
|
14231
|
+
}
|
|
14232
|
+
out.push(row);
|
|
14233
|
+
if (row.role === "assistant" && row.uniqueId) {
|
|
14234
|
+
assistantIndexById.set(row.uniqueId, out.length - 1);
|
|
14235
|
+
}
|
|
14236
|
+
}
|
|
14237
|
+
const byTarget = /* @__PURE__ */ new Map();
|
|
14238
|
+
for (const { row, insertionPoint } of pending) {
|
|
14239
|
+
const target = resolveFoldTarget(out, row, insertionPoint, assistantIndexById);
|
|
14240
|
+
if (target === void 0) continue;
|
|
14241
|
+
const group = byTarget.get(target);
|
|
14242
|
+
if (group) group.push(row);
|
|
14243
|
+
else byTarget.set(target, [row]);
|
|
14244
|
+
}
|
|
14245
|
+
for (const [target, groupedRows] of byTarget) {
|
|
14246
|
+
const assistant = out[target];
|
|
14247
|
+
const kept = groupedRows.flatMap((row) => parseToolResultSegments(row.content)).filter((segment) => !exclude.has(segment.name));
|
|
14248
|
+
if (kept.length > 0) {
|
|
14249
|
+
out[target] = { ...assistant, content: appendToolResults(assistant.content, kept) };
|
|
14250
|
+
} else if (!assistant.content.trim() && options?.placeholder) {
|
|
14251
|
+
out[target] = { ...assistant, content: options.placeholder };
|
|
14252
|
+
}
|
|
14253
|
+
}
|
|
14254
|
+
return out;
|
|
14255
|
+
}
|
|
14256
|
+
function resolveFoldTarget(out, row, insertionPoint, assistantIndexById) {
|
|
14257
|
+
const linked = row.parentMessageId ? assistantIndexById.get(row.parentMessageId) : void 0;
|
|
14258
|
+
if (linked !== void 0) return linked;
|
|
14259
|
+
let previous;
|
|
14260
|
+
for (let i = insertionPoint - 1; i >= 0; i--) {
|
|
14261
|
+
if (out[i].role === "assistant") {
|
|
14262
|
+
previous = i;
|
|
14263
|
+
break;
|
|
14264
|
+
}
|
|
14265
|
+
}
|
|
14266
|
+
let next;
|
|
14267
|
+
for (let i = insertionPoint; i < out.length; i++) {
|
|
14268
|
+
if (out[i].role === "assistant") {
|
|
14269
|
+
next = i;
|
|
14270
|
+
break;
|
|
14271
|
+
}
|
|
14272
|
+
}
|
|
14273
|
+
if (previous === void 0) return next;
|
|
14274
|
+
if (next === void 0) return previous;
|
|
14275
|
+
return next - insertionPoint < insertionPoint - previous ? next : previous;
|
|
14276
|
+
}
|
|
14277
|
+
var MAX_FOLDED_APPENDIX_CHARS = 2e4;
|
|
14278
|
+
function appendToolResults(assistantContent, kept) {
|
|
14279
|
+
const framing = TOOL_RESULTS_PREFIX.length + 1 + (kept.length - 1);
|
|
14280
|
+
const capped = capToolResultEntries(
|
|
14281
|
+
kept.map((segment) => segment.line),
|
|
14282
|
+
MAX_FOLDED_APPENDIX_CHARS - framing
|
|
14283
|
+
);
|
|
14284
|
+
const appendix = `${TOOL_RESULTS_PREFIX}
|
|
14285
|
+
${capped.join("\n")}`;
|
|
14286
|
+
return assistantContent.trim() ? `${assistantContent}
|
|
14287
|
+
|
|
14288
|
+
${appendix}` : appendix;
|
|
14289
|
+
}
|
|
14290
|
+
|
|
14095
14291
|
// src/lib/db/chat/lazyDecrypt.ts
|
|
14096
14292
|
init_useEncryption();
|
|
14097
14293
|
init_encryption_utils();
|
|
@@ -19749,11 +19945,17 @@ function useChatStorage(options) {
|
|
|
19749
19945
|
onPiiRedacted,
|
|
19750
19946
|
nerDetector,
|
|
19751
19947
|
onServerToolCall,
|
|
19752
|
-
onToolCallArgumentsDelta
|
|
19948
|
+
onToolCallArgumentsDelta,
|
|
19949
|
+
toolResultsHistoryExclude,
|
|
19950
|
+
foldToolResultsInHistory
|
|
19753
19951
|
} = options;
|
|
19754
19952
|
const [currentConversationId, setCurrentConversationId] = (0, import_react4.useState)(
|
|
19755
19953
|
initialConversationId || null
|
|
19756
19954
|
);
|
|
19955
|
+
const toolResultsHistoryExcludeRef = (0, import_react4.useRef)(toolResultsHistoryExclude);
|
|
19956
|
+
toolResultsHistoryExcludeRef.current = toolResultsHistoryExclude;
|
|
19957
|
+
const foldToolResultsInHistoryRef = (0, import_react4.useRef)(foldToolResultsInHistory);
|
|
19958
|
+
foldToolResultsInHistoryRef.current = foldToolResultsInHistory;
|
|
19757
19959
|
const nerDetectorRef = (0, import_react4.useRef)(nerDetector);
|
|
19758
19960
|
nerDetectorRef.current = nerDetector;
|
|
19759
19961
|
const resolvedPiiRedaction = (0, import_react4.useMemo)(
|
|
@@ -20621,7 +20823,13 @@ function useChatStorage(options) {
|
|
|
20621
20823
|
}
|
|
20622
20824
|
if (includeHistory) {
|
|
20623
20825
|
const validMessages = storedMessages.filter((msg) => !msg.error);
|
|
20624
|
-
const
|
|
20826
|
+
const replayableMessages = prepareToolResultsForReplay(validMessages, {
|
|
20827
|
+
fold: foldToolResultsInHistoryRef.current === true,
|
|
20828
|
+
exclude: toolResultsHistoryExcludeRef.current,
|
|
20829
|
+
placeholder: DISPLAY_CARD_PLACEHOLDER
|
|
20830
|
+
});
|
|
20831
|
+
const limitedMessages = replayableMessages.slice(-maxHistoryMessages);
|
|
20832
|
+
const foldedHistory = limitedMessages;
|
|
20625
20833
|
if (summarizeHistory && !getTokenRef.current) {
|
|
20626
20834
|
getLogger().warn(
|
|
20627
20835
|
"[summarize] summarizeHistory is enabled but getToken is not provided \u2014 summarization will be skipped"
|
|
@@ -20631,7 +20839,7 @@ function useChatStorage(options) {
|
|
|
20631
20839
|
const { messagesToConvert, summarySystemMessage } = await maybeSummarizeHistory({
|
|
20632
20840
|
database,
|
|
20633
20841
|
conversationId: convId,
|
|
20634
|
-
messages:
|
|
20842
|
+
messages: foldedHistory,
|
|
20635
20843
|
summarizeHistory,
|
|
20636
20844
|
summaryTokenThreshold,
|
|
20637
20845
|
summaryMinWindowMessages,
|
|
@@ -21001,6 +21209,7 @@ function useChatStorage(options) {
|
|
|
21001
21209
|
uniqueId: effectiveAssistantUniqueId
|
|
21002
21210
|
};
|
|
21003
21211
|
let storedAssistantMessage;
|
|
21212
|
+
let assistantMsgQueueId;
|
|
21004
21213
|
try {
|
|
21005
21214
|
const assistantMsgResult = await writeOrQueue(
|
|
21006
21215
|
"createMessage",
|
|
@@ -21010,6 +21219,7 @@ function useChatStorage(options) {
|
|
|
21010
21219
|
userMsgQueueId ? [userMsgQueueId] : []
|
|
21011
21220
|
);
|
|
21012
21221
|
storedAssistantMessage = assistantMsgResult.result;
|
|
21222
|
+
assistantMsgQueueId = assistantMsgResult.queueId;
|
|
21013
21223
|
if (!assistantMsgResult.queued) {
|
|
21014
21224
|
void embedMessageAsync(storedAssistantMessage, maskForCall);
|
|
21015
21225
|
}
|
|
@@ -21020,6 +21230,29 @@ function useChatStorage(options) {
|
|
|
21020
21230
|
userMessage: storedUserMessage
|
|
21021
21231
|
};
|
|
21022
21232
|
}
|
|
21233
|
+
const autoToolResults = result.autoExecutedToolResults;
|
|
21234
|
+
let storedToolResultsMessage;
|
|
21235
|
+
if (autoToolResults && autoToolResults.length > 0) {
|
|
21236
|
+
const toolResultsOpts = {
|
|
21237
|
+
conversationId: convId,
|
|
21238
|
+
role: "user",
|
|
21239
|
+
content: buildToolResultContent(autoToolResults),
|
|
21240
|
+
model: "",
|
|
21241
|
+
parentMessageId: storedAssistantMessage.uniqueId,
|
|
21242
|
+
origin: TOOL_RESULT_ORIGIN
|
|
21243
|
+
};
|
|
21244
|
+
try {
|
|
21245
|
+
const toolResultsWrite = await writeOrQueue(
|
|
21246
|
+
"createMessage",
|
|
21247
|
+
toolResultsOpts,
|
|
21248
|
+
() => createMessageOp(storageCtx, toolResultsOpts),
|
|
21249
|
+
() => makeSyntheticStoredMessage(toolResultsOpts),
|
|
21250
|
+
assistantMsgQueueId ? [assistantMsgQueueId] : []
|
|
21251
|
+
);
|
|
21252
|
+
storedToolResultsMessage = toolResultsWrite.result;
|
|
21253
|
+
} catch {
|
|
21254
|
+
}
|
|
21255
|
+
}
|
|
21023
21256
|
const refreshGetToken = getTokenRef.current;
|
|
21024
21257
|
if (refreshGetToken) {
|
|
21025
21258
|
Promise.resolve().then(() => shouldRefreshTools(getToolsChecksum(responseData), serverToolsConfig?.cache)).then((refresh) => {
|
|
@@ -21039,7 +21272,9 @@ function useChatStorage(options) {
|
|
|
21039
21272
|
data: responseData,
|
|
21040
21273
|
error: null,
|
|
21041
21274
|
userMessage: storedUserMessage,
|
|
21042
|
-
assistantMessage: storedAssistantMessage
|
|
21275
|
+
assistantMessage: storedAssistantMessage,
|
|
21276
|
+
autoExecutedToolResults: autoToolResults,
|
|
21277
|
+
toolResultsMessage: storedToolResultsMessage
|
|
21043
21278
|
};
|
|
21044
21279
|
},
|
|
21045
21280
|
[
|
package/dist/expo/index.d.mts
CHANGED
|
@@ -3777,6 +3777,40 @@ interface BaseUseChatStorageOptions {
|
|
|
3777
3777
|
* Defaults to the hardcoded MCP_R2_DOMAIN from clientConfig.
|
|
3778
3778
|
*/
|
|
3779
3779
|
mcpR2Domain?: string;
|
|
3780
|
+
/**
|
|
3781
|
+
* Tool names whose persisted results must never be replayed to the model.
|
|
3782
|
+
*
|
|
3783
|
+
* A turn's auto-executed tool results are stored as a synthetic
|
|
3784
|
+
* `[Tool Execution Results]` row and, on a replayed send, folded back onto the
|
|
3785
|
+
* assistant turn they belong to — that is what lets a follow-up question about a
|
|
3786
|
+
* tool's output work after a reload. Name a tool here when its payload exists for
|
|
3787
|
+
* the RENDERER rather than the model: a display card can carry data the model was
|
|
3788
|
+
* deliberately never given (People Nearby's card holds third parties' snapped
|
|
3789
|
+
* coordinates, which the search result strips), and replaying it would hand that
|
|
3790
|
+
* data straight back.
|
|
3791
|
+
*
|
|
3792
|
+
* Hook-level rather than per-send on purpose: an exclusion that has to be
|
|
3793
|
+
* remembered at every call site is one bad send away from leaking.
|
|
3794
|
+
*/
|
|
3795
|
+
toolResultsHistoryExclude?: string[];
|
|
3796
|
+
/**
|
|
3797
|
+
* Fold persisted `[Tool Execution Results]` rows onto the assistant turn that produced them
|
|
3798
|
+
* when replaying stored history, instead of dropping them.
|
|
3799
|
+
*
|
|
3800
|
+
* **Defaults to `false`, and that default is deliberate.** Folding is the better behaviour —
|
|
3801
|
+
* it is what lets a follow-up about a tool's output work after a reload — but it moves the
|
|
3802
|
+
* payload from a `role: "user"` row onto an `assistant` row. Any consumer that scrubs these
|
|
3803
|
+
* rows by checking `role === "user"` plus the content prefix (which is how both apps did it
|
|
3804
|
+
* before this option existed) stops catching them the moment folding turns on, and starts
|
|
3805
|
+
* replaying whatever the row held. Opting in is therefore a statement that the caller has
|
|
3806
|
+
* checked its own filters and set {@link toolResultsHistoryExclude} for any payload that must
|
|
3807
|
+
* not reach the model.
|
|
3808
|
+
*
|
|
3809
|
+
* With it off, rows are dropped from the replayed history rather than sent verbatim. Verbatim
|
|
3810
|
+
* would put two consecutive `user` turns on the wire, and the model answers the previous turn
|
|
3811
|
+
* instead of the new prompt.
|
|
3812
|
+
*/
|
|
3813
|
+
foldToolResultsInHistory?: boolean;
|
|
3780
3814
|
/**
|
|
3781
3815
|
* Pre-processors run after the last user message is received but before
|
|
3782
3816
|
* the first LLM request. Each receives the prompt text and a shared
|
|
@@ -4126,6 +4160,20 @@ interface BaseSendMessageSuccessResult {
|
|
|
4126
4160
|
error: null;
|
|
4127
4161
|
userMessage: StoredMessage;
|
|
4128
4162
|
assistantMessage: StoredMessage;
|
|
4163
|
+
/** Results from tools the SDK auto-executed this turn (e.g. display tools). */
|
|
4164
|
+
autoExecutedToolResults?: {
|
|
4165
|
+
name: string;
|
|
4166
|
+
result: unknown;
|
|
4167
|
+
}[];
|
|
4168
|
+
/**
|
|
4169
|
+
* The synthetic `[Tool Execution Results]` row those results were persisted as.
|
|
4170
|
+
*
|
|
4171
|
+
* Returned so a caller can key its transient overlay on the id the SDK actually wrote instead of
|
|
4172
|
+
* deriving one and hoping the two agree — that guesswork is what mobile's per-card persist
|
|
4173
|
+
* workarounds existed to do (#5519). Absent when the turn executed no tools, or when the row write
|
|
4174
|
+
* failed (non-fatal: the assistant reply is already stored).
|
|
4175
|
+
*/
|
|
4176
|
+
toolResultsMessage?: StoredMessage;
|
|
4129
4177
|
}
|
|
4130
4178
|
interface BaseSendMessageSkippedResult {
|
|
4131
4179
|
data: ApiResponse;
|
package/dist/expo/index.d.ts
CHANGED
|
@@ -3777,6 +3777,40 @@ interface BaseUseChatStorageOptions {
|
|
|
3777
3777
|
* Defaults to the hardcoded MCP_R2_DOMAIN from clientConfig.
|
|
3778
3778
|
*/
|
|
3779
3779
|
mcpR2Domain?: string;
|
|
3780
|
+
/**
|
|
3781
|
+
* Tool names whose persisted results must never be replayed to the model.
|
|
3782
|
+
*
|
|
3783
|
+
* A turn's auto-executed tool results are stored as a synthetic
|
|
3784
|
+
* `[Tool Execution Results]` row and, on a replayed send, folded back onto the
|
|
3785
|
+
* assistant turn they belong to — that is what lets a follow-up question about a
|
|
3786
|
+
* tool's output work after a reload. Name a tool here when its payload exists for
|
|
3787
|
+
* the RENDERER rather than the model: a display card can carry data the model was
|
|
3788
|
+
* deliberately never given (People Nearby's card holds third parties' snapped
|
|
3789
|
+
* coordinates, which the search result strips), and replaying it would hand that
|
|
3790
|
+
* data straight back.
|
|
3791
|
+
*
|
|
3792
|
+
* Hook-level rather than per-send on purpose: an exclusion that has to be
|
|
3793
|
+
* remembered at every call site is one bad send away from leaking.
|
|
3794
|
+
*/
|
|
3795
|
+
toolResultsHistoryExclude?: string[];
|
|
3796
|
+
/**
|
|
3797
|
+
* Fold persisted `[Tool Execution Results]` rows onto the assistant turn that produced them
|
|
3798
|
+
* when replaying stored history, instead of dropping them.
|
|
3799
|
+
*
|
|
3800
|
+
* **Defaults to `false`, and that default is deliberate.** Folding is the better behaviour —
|
|
3801
|
+
* it is what lets a follow-up about a tool's output work after a reload — but it moves the
|
|
3802
|
+
* payload from a `role: "user"` row onto an `assistant` row. Any consumer that scrubs these
|
|
3803
|
+
* rows by checking `role === "user"` plus the content prefix (which is how both apps did it
|
|
3804
|
+
* before this option existed) stops catching them the moment folding turns on, and starts
|
|
3805
|
+
* replaying whatever the row held. Opting in is therefore a statement that the caller has
|
|
3806
|
+
* checked its own filters and set {@link toolResultsHistoryExclude} for any payload that must
|
|
3807
|
+
* not reach the model.
|
|
3808
|
+
*
|
|
3809
|
+
* With it off, rows are dropped from the replayed history rather than sent verbatim. Verbatim
|
|
3810
|
+
* would put two consecutive `user` turns on the wire, and the model answers the previous turn
|
|
3811
|
+
* instead of the new prompt.
|
|
3812
|
+
*/
|
|
3813
|
+
foldToolResultsInHistory?: boolean;
|
|
3780
3814
|
/**
|
|
3781
3815
|
* Pre-processors run after the last user message is received but before
|
|
3782
3816
|
* the first LLM request. Each receives the prompt text and a shared
|
|
@@ -4126,6 +4160,20 @@ interface BaseSendMessageSuccessResult {
|
|
|
4126
4160
|
error: null;
|
|
4127
4161
|
userMessage: StoredMessage;
|
|
4128
4162
|
assistantMessage: StoredMessage;
|
|
4163
|
+
/** Results from tools the SDK auto-executed this turn (e.g. display tools). */
|
|
4164
|
+
autoExecutedToolResults?: {
|
|
4165
|
+
name: string;
|
|
4166
|
+
result: unknown;
|
|
4167
|
+
}[];
|
|
4168
|
+
/**
|
|
4169
|
+
* The synthetic `[Tool Execution Results]` row those results were persisted as.
|
|
4170
|
+
*
|
|
4171
|
+
* Returned so a caller can key its transient overlay on the id the SDK actually wrote instead of
|
|
4172
|
+
* deriving one and hoping the two agree — that guesswork is what mobile's per-card persist
|
|
4173
|
+
* workarounds existed to do (#5519). Absent when the turn executed no tools, or when the row write
|
|
4174
|
+
* failed (non-fatal: the assistant reply is already stored).
|
|
4175
|
+
*/
|
|
4176
|
+
toolResultsMessage?: StoredMessage;
|
|
4129
4177
|
}
|
|
4130
4178
|
interface BaseSendMessageSkippedResult {
|
|
4131
4179
|
data: ApiResponse;
|