@anuma/sdk 6.4.2 → 6.5.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.
@@ -809,6 +809,63 @@ function cosineSimilarity(a, b) {
809
809
  return denom === 0 ? 0 : dot / denom;
810
810
  }
811
811
 
812
+ // src/lib/processors/encoding.ts
813
+ var B64_ENCODE_CHUNK = 32768 * 3;
814
+ function uint8ArrayToBase64(data) {
815
+ if (typeof Buffer !== "undefined") {
816
+ return Buffer.from(data).toString("base64");
817
+ }
818
+ let base64 = "";
819
+ for (let i = 0; i < data.length; i += B64_ENCODE_CHUNK) {
820
+ const slice = data.subarray(i, i + B64_ENCODE_CHUNK);
821
+ let binary = "";
822
+ for (let j = 0; j < slice.length; j++) {
823
+ binary += String.fromCharCode(slice[j]);
824
+ }
825
+ base64 += btoa(binary);
826
+ }
827
+ return base64;
828
+ }
829
+ function base64ToUint8Array(base64) {
830
+ if (typeof Buffer !== "undefined") {
831
+ const buf = Buffer.from(base64, "base64");
832
+ return new Uint8Array(buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength));
833
+ }
834
+ const binary = atob(base64);
835
+ const bytes = new Uint8Array(binary.length);
836
+ for (let i = 0; i < binary.length; i++) {
837
+ bytes[i] = binary.charCodeAt(i);
838
+ }
839
+ return bytes;
840
+ }
841
+
842
+ // src/lib/memoryEngine/vectorEncoding.ts
843
+ var BYTES_PER_FLOAT32 = 4;
844
+ var CANONICAL_BASE64 = /^[A-Za-z0-9+/]+={0,2}$/;
845
+ function encodeChunkVector(vector) {
846
+ const f32 = vector instanceof Float32Array ? vector : Float32Array.from(vector);
847
+ return uint8ArrayToBase64(new Uint8Array(f32.buffer, f32.byteOffset, f32.byteLength));
848
+ }
849
+ function decodeChunkVector(vector, onMalformed) {
850
+ if (!vector || vector.length === 0) return new Float32Array(0);
851
+ if (typeof vector !== "string") return Float32Array.from(vector);
852
+ if (vector.length % 4 !== 0 || !CANONICAL_BASE64.test(vector)) {
853
+ onMalformed?.();
854
+ return new Float32Array(0);
855
+ }
856
+ try {
857
+ const bytes = base64ToUint8Array(vector);
858
+ if (bytes.byteLength === 0 || bytes.byteLength % BYTES_PER_FLOAT32 !== 0) {
859
+ onMalformed?.();
860
+ return new Float32Array(0);
861
+ }
862
+ return new Float32Array(bytes.buffer, bytes.byteOffset, bytes.byteLength / BYTES_PER_FLOAT32);
863
+ } catch {
864
+ onMalformed?.();
865
+ return new Float32Array(0);
866
+ }
867
+ }
868
+
812
869
  // src/lib/db/encryption-utils.ts
813
870
  var ENCRYPTION_PREFIX = "enc:v3:";
814
871
  function isEncrypted(value) {
@@ -1879,6 +1936,7 @@ async function searchChunksOp(ctx, queryVector, options) {
1879
1936
  const messages = await ctx.messagesCollection.query(...queryConditions).fetch();
1880
1937
  const candidates = [];
1881
1938
  let staleSkipped = 0;
1939
+ let unreadableVectors = 0;
1882
1940
  for (const message of messages) {
1883
1941
  const msgConvId = String(message._getRaw("conversation_id"));
1884
1942
  if (!activeConversationIds.has(msgConvId)) continue;
@@ -1916,7 +1974,9 @@ async function searchChunksOp(ctx, queryVector, options) {
1916
1974
  const chunks = await readJsonField(message, "chunks", ctx.walletAddress);
1917
1975
  if (chunks && chunks.length > 0) {
1918
1976
  const vectors = chunks.map(
1919
- (chunk) => chunk.vector && chunk.vector.length > 0 ? Float32Array.from(chunk.vector) : new Float32Array(0)
1977
+ (chunk) => decodeChunkVector(chunk.vector, () => {
1978
+ unreadableVectors++;
1979
+ })
1920
1980
  );
1921
1981
  chunkCache?.set(message.id, { version, chunks: vectors });
1922
1982
  for (let ci = 0; ci < chunks.length; ci++) {
@@ -1947,6 +2007,11 @@ async function searchChunksOp(ctx, queryVector, options) {
1947
2007
  `searchChunksOp: skipped ${staleSkipped} messages whose embedding model differs from the current model (${embeddingModel}) \u2014 re-embed via chunkAndEmbedAllMessages`
1948
2008
  );
1949
2009
  }
2010
+ if (unreadableVectors > 0) {
2011
+ getLogger().warn(
2012
+ `searchChunksOp: could not read ${unreadableVectors} chunk vectors and left them out of ranking \u2014 the stored value is corrupt, so those chunks stay unsearchable until the message is re-embedded via chunkAndEmbedAllMessages`
2013
+ );
2014
+ }
1950
2015
  const topK = candidates.sort((a, b) => b.similarity - a.similarity).slice(0, limit);
1951
2016
  const uniqueMessages = /* @__PURE__ */ new Map();
1952
2017
  for (const c of topK) uniqueMessages.set(c.message.id, c.message);
@@ -3493,6 +3558,153 @@ async function updateVaultMemoryEmbeddingOp(ctx, id, embedding, embeddingModel)
3493
3558
  // src/lib/memoryEngine/constants.ts
3494
3559
  var DEFAULT_API_EMBEDDING_MODEL = "qwen/qwen3-embedding-8b";
3495
3560
 
3561
+ // src/lib/chat/toolResultMessage.ts
3562
+ var HEADER = "[Tool Execution Results]\n\n";
3563
+ var FOOTER = "\n\nBased on these results, continue with the task.";
3564
+ var ENTRY_SEPARATOR = "\n\n";
3565
+ var TOOL_RESULT_FOOTER_LINE = FOOTER.trim();
3566
+ var MAX_PERSISTED_TOOL_RESULT_CHARS = 1e5;
3567
+ function buildToolResultContent(results) {
3568
+ const entries = results.map((r) => `Tool "${r.name}" returned: ${JSON.stringify(r.result)}`);
3569
+ const framing = HEADER.length + FOOTER.length + ENTRY_SEPARATOR.length * Math.max(0, entries.length - 1);
3570
+ const summary = capEntries(entries, MAX_PERSISTED_TOOL_RESULT_CHARS - framing).join(
3571
+ ENTRY_SEPARATOR
3572
+ );
3573
+ return `${HEADER}${summary}${FOOTER}`;
3574
+ }
3575
+ function capToolResultEntries(entries, budget) {
3576
+ return capEntries(entries, budget);
3577
+ }
3578
+ function capEntries(entries, budget) {
3579
+ const smallestFirst = entries.map((_, index) => index).sort((a, b) => entries[a].length - entries[b].length);
3580
+ const capped = [...entries];
3581
+ let remaining = budget;
3582
+ let unassigned = entries.length;
3583
+ for (const index of smallestFirst) {
3584
+ capped[index] = truncateEntry(entries[index], Math.floor(remaining / unassigned));
3585
+ remaining -= capped[index].length;
3586
+ unassigned--;
3587
+ }
3588
+ return capped;
3589
+ }
3590
+ function truncateEntry(entry, allowance) {
3591
+ if (entry.length <= allowance) return entry;
3592
+ const keep = allowance - truncationMarker(entry.length).length;
3593
+ if (keep <= 0) return entry.slice(0, Math.max(0, allowance));
3594
+ return `${entry.slice(0, keep)}${truncationMarker(entry.length - keep)}`;
3595
+ }
3596
+ function truncationMarker(omitted) {
3597
+ return `
3598
+
3599
+ ... (tool output truncated, ${omitted} characters omitted)`;
3600
+ }
3601
+
3602
+ // src/lib/chat/toolResults.ts
3603
+ var TOOL_RESULTS_PREFIX = "[Tool Execution Results]";
3604
+ var DISPLAY_CARD_PLACEHOLDER = "[displayed a card to the user with the tool result]";
3605
+ var TOOL_LINE = /^Tool "([^"]+)" returned: (.*)$/;
3606
+ var TOOL_RESULT_ORIGIN = "tool_result";
3607
+ function isToolResultsRow(row) {
3608
+ if (row.origin === TOOL_RESULT_ORIGIN) return true;
3609
+ if (typeof row.origin === "string") return false;
3610
+ if (row.role !== "user" || !row.content.startsWith(TOOL_RESULTS_PREFIX)) return false;
3611
+ return parseToolResultSegments(row.content).length > 0;
3612
+ }
3613
+ function parseToolResultSegments(content) {
3614
+ const segments = [];
3615
+ for (const raw of content.split("\n")) {
3616
+ const line = raw.trim();
3617
+ const match = TOOL_LINE.exec(line);
3618
+ if (match) {
3619
+ segments.push({ name: match[1], line });
3620
+ continue;
3621
+ }
3622
+ const current = segments[segments.length - 1];
3623
+ if (!current || line === "" || line === TOOL_RESULT_FOOTER_LINE) continue;
3624
+ if (line === TOOL_RESULTS_PREFIX) continue;
3625
+ current.line = `${current.line}
3626
+ ${line}`;
3627
+ }
3628
+ return segments;
3629
+ }
3630
+ function prepareToolResultsForReplay(rows, options) {
3631
+ if (options.fold) {
3632
+ return foldToolResultsRows(rows, {
3633
+ exclude: options.exclude,
3634
+ placeholder: options.placeholder
3635
+ });
3636
+ }
3637
+ return rows.filter((row) => !isToolResultsRow(row));
3638
+ }
3639
+ function foldToolResultsRows(rows, options) {
3640
+ const exclude = new Set(options?.exclude ?? []);
3641
+ const out = [];
3642
+ const pending = [];
3643
+ const assistantIndexById = /* @__PURE__ */ new Map();
3644
+ for (const row of rows) {
3645
+ if (isToolResultsRow(row)) {
3646
+ pending.push({ row, insertionPoint: out.length });
3647
+ continue;
3648
+ }
3649
+ out.push(row);
3650
+ if (row.role === "assistant" && row.uniqueId) {
3651
+ assistantIndexById.set(row.uniqueId, out.length - 1);
3652
+ }
3653
+ }
3654
+ const byTarget = /* @__PURE__ */ new Map();
3655
+ for (const { row, insertionPoint } of pending) {
3656
+ const target = resolveFoldTarget(out, row, insertionPoint, assistantIndexById);
3657
+ if (target === void 0) continue;
3658
+ const group = byTarget.get(target);
3659
+ if (group) group.push(row);
3660
+ else byTarget.set(target, [row]);
3661
+ }
3662
+ for (const [target, groupedRows] of byTarget) {
3663
+ const assistant = out[target];
3664
+ const kept = groupedRows.flatMap((row) => parseToolResultSegments(row.content)).filter((segment) => !exclude.has(segment.name));
3665
+ if (kept.length > 0) {
3666
+ out[target] = { ...assistant, content: appendToolResults(assistant.content, kept) };
3667
+ } else if (!assistant.content.trim() && options?.placeholder) {
3668
+ out[target] = { ...assistant, content: options.placeholder };
3669
+ }
3670
+ }
3671
+ return out;
3672
+ }
3673
+ function resolveFoldTarget(out, row, insertionPoint, assistantIndexById) {
3674
+ const linked = row.parentMessageId ? assistantIndexById.get(row.parentMessageId) : void 0;
3675
+ if (linked !== void 0) return linked;
3676
+ let previous;
3677
+ for (let i = insertionPoint - 1; i >= 0; i--) {
3678
+ if (out[i].role === "assistant") {
3679
+ previous = i;
3680
+ break;
3681
+ }
3682
+ }
3683
+ let next;
3684
+ for (let i = insertionPoint; i < out.length; i++) {
3685
+ if (out[i].role === "assistant") {
3686
+ next = i;
3687
+ break;
3688
+ }
3689
+ }
3690
+ if (previous === void 0) return next;
3691
+ if (next === void 0) return previous;
3692
+ return next - insertionPoint < insertionPoint - previous ? next : previous;
3693
+ }
3694
+ var MAX_FOLDED_APPENDIX_CHARS = 2e4;
3695
+ function appendToolResults(assistantContent, kept) {
3696
+ const framing = TOOL_RESULTS_PREFIX.length + 1 + (kept.length - 1);
3697
+ const capped = capToolResultEntries(
3698
+ kept.map((segment) => segment.line),
3699
+ MAX_FOLDED_APPENDIX_CHARS - framing
3700
+ );
3701
+ const appendix = `${TOOL_RESULTS_PREFIX}
3702
+ ${capped.join("\n")}`;
3703
+ return assistantContent.trim() ? `${assistantContent}
3704
+
3705
+ ${appendix}` : appendix;
3706
+ }
3707
+
3496
3708
  // src/lib/memoryEngine/chunking.ts
3497
3709
  var DEFAULT_CHUNK_SIZE = 400;
3498
3710
  var DEFAULT_CHUNK_OVERLAP = 50;
@@ -4629,7 +4841,13 @@ async function generateEmbeddings(texts, options) {
4629
4841
 
4630
4842
  // src/lib/memoryEngine/embeddings.ts
4631
4843
  var DEFAULT_MIN_CONTENT_LENGTH = 10;
4632
- var NON_EMBEDDABLE_ORIGIN = "tool_result";
4844
+ var CHUNKS_DISCARDED_ORIGIN = "chunks_discarded";
4845
+ var NON_EMBEDDABLE_ORIGINS = /* @__PURE__ */ new Set([TOOL_RESULT_ORIGIN, CHUNKS_DISCARDED_ORIGIN]);
4846
+ function isNonEmbeddableOrigin(origin, reembedDiscarded = false) {
4847
+ if (typeof origin !== "string") return false;
4848
+ if (reembedDiscarded && origin === CHUNKS_DISCARDED_ORIGIN) return false;
4849
+ return NON_EMBEDDABLE_ORIGINS.has(origin);
4850
+ }
4633
4851
  async function embedMessage(ctx, messageId, options) {
4634
4852
  const message = await getMessageOp(ctx, messageId);
4635
4853
  if (!message) {
@@ -4638,7 +4856,7 @@ async function embedMessage(ctx, messageId, options) {
4638
4856
  if (message.vector && message.vector.length > 0) {
4639
4857
  return message;
4640
4858
  }
4641
- if (message.origin === NON_EMBEDDABLE_ORIGIN) {
4859
+ if (isNonEmbeddableOrigin(message.origin)) {
4642
4860
  return message;
4643
4861
  }
4644
4862
  if (isEncrypted(message.content)) {
@@ -4674,7 +4892,7 @@ async function embedAllMessages(ctx, options, filter) {
4674
4892
  if (message.role === "system") {
4675
4893
  continue;
4676
4894
  }
4677
- if (message.origin === NON_EMBEDDABLE_ORIGIN) {
4895
+ if (isNonEmbeddableOrigin(message.origin, filter?.reembedDiscarded)) {
4678
4896
  continue;
4679
4897
  }
4680
4898
  considered++;
@@ -4714,7 +4932,7 @@ async function chunkAndEmbedMessage(ctx, messageId, options) {
4714
4932
  if (message.chunks && message.chunks.length > 0) {
4715
4933
  return message;
4716
4934
  }
4717
- if (message.origin === NON_EMBEDDABLE_ORIGIN) {
4935
+ if (isNonEmbeddableOrigin(message.origin)) {
4718
4936
  return message;
4719
4937
  }
4720
4938
  if (isEncrypted(message.content)) {
@@ -4762,7 +4980,7 @@ async function chunkAndEmbedAllMessages(ctx, options, filter) {
4762
4980
  if (hasVector && !filter?.rechunkExisting && !isStale) continue;
4763
4981
  if (filter?.roles && !filter.roles.includes(message.role)) continue;
4764
4982
  if (message.role === "system") continue;
4765
- if (message.origin === NON_EMBEDDABLE_ORIGIN) continue;
4983
+ if (isNonEmbeddableOrigin(message.origin, filter?.reembedDiscarded)) continue;
4766
4984
  considered++;
4767
4985
  if (isEncrypted(message.content)) {
4768
4986
  stillEncrypted++;
@@ -6566,7 +6784,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
6566
6784
  subQueries = decomp.subQueries;
6567
6785
  }
6568
6786
  }
6569
- const { recall: recall2 } = await import("./recall-7FOWWX5T.mjs");
6787
+ const { recall: recall2 } = await import("./recall-ISSI7RMD.mjs");
6570
6788
  let recallDegraded = [];
6571
6789
  const result = await recall2(
6572
6790
  query,
@@ -7511,6 +7729,10 @@ function toChunkMemory(r) {
7511
7729
  }
7512
7730
 
7513
7731
  export {
7732
+ buildToolResultContent,
7733
+ DISPLAY_CARD_PLACEHOLDER,
7734
+ TOOL_RESULT_ORIGIN,
7735
+ prepareToolResultsForReplay,
7514
7736
  EncryptionKeyMissingError,
7515
7737
  onClearAllEncryptionState,
7516
7738
  onKeyAvailable,
@@ -7523,6 +7745,8 @@ export {
7523
7745
  refreshEncryptionKeyIfMatches,
7524
7746
  useEncryption,
7525
7747
  cosineSimilarity,
7748
+ encodeChunkVector,
7749
+ decodeChunkVector,
7526
7750
  isEncrypted,
7527
7751
  encryptField,
7528
7752
  decryptField,
@@ -7575,6 +7799,7 @@ export {
7575
7799
  generateEmbedding,
7576
7800
  generateEmbeddings,
7577
7801
  DEFAULT_MIN_CONTENT_LENGTH,
7802
+ CHUNKS_DISCARDED_ORIGIN,
7578
7803
  embedMessage,
7579
7804
  embedAllMessages,
7580
7805
  chunkAndEmbedMessage,