(content: string)
| 1066 | >({ max: DEFAULT_EMBEDDING_CACHE_MAX_SIZE }); |
| 1067 | private firstEmbed: Promise<any> | undefined; |
| 1068 | protected async embedMessageContent(content: string) { |
| 1069 | // Key by the content hash (not the content itself) to keep keys small. Use the |
| 1070 | // 64-bit hash: h32 is only 32 bits, so distinct contents collide after ~tens of |
| 1071 | // thousands of entries, which would return another message's cached embeddings. |
| 1072 | const key = (await this.hasher).h64(content); |
| 1073 | const cached = this.embeddingCache.get(key); |
| 1074 | if (cached) { |
| 1075 | this.logger.debug('Embedding cache hit', { contentHash: key.toString(), chunks: cached.chunks.length }); |
| 1076 | return cached; |
| 1077 | } |
| 1078 | const chunks = this.chunkText(content); |
| 1079 | |
| 1080 | if (typeof this.embedder === `undefined`) { |
| 1081 | throw new Error(`Tried to embed message content but this Memory instance doesn't have an attached embedder.`); |
| 1082 | } |
| 1083 | // for fastembed multiple initial calls to embed will fail if the model hasn't been downloaded yet. |
| 1084 | const isFastEmbed = this.embedder.provider === `fastembed`; |
| 1085 | if (isFastEmbed && this.firstEmbed instanceof Promise) { |
| 1086 | // so wait for the first one |
| 1087 | await this.firstEmbed; |
| 1088 | } |
| 1089 | |
| 1090 | let embedFn: typeof embedMany | typeof embedManyV5 | typeof embedManyV6; |
| 1091 | const specVersion = this.embedder.specificationVersion; |
| 1092 | |
| 1093 | switch (specVersion) { |
| 1094 | case 'v3': |
| 1095 | embedFn = embedManyV6; |
| 1096 | break; |
| 1097 | case 'v2': |
| 1098 | embedFn = embedManyV5; |
| 1099 | break; |
| 1100 | default: |
| 1101 | embedFn = embedMany; |
| 1102 | break; |
| 1103 | } |
| 1104 | |
| 1105 | const promise = embedFn({ |
| 1106 | values: chunks, |
| 1107 | maxRetries: 3, |
| 1108 | // @ts-expect-error - embedder type mismatch |
| 1109 | model: this.embedder, |
| 1110 | ...(this.embedderOptions || {}), |
| 1111 | }); |
| 1112 | |
| 1113 | if (isFastEmbed && !this.firstEmbed) this.firstEmbed = promise; |
| 1114 | const { embeddings, usage } = await promise; |
| 1115 | |
| 1116 | const result = { |
| 1117 | embeddings, |
| 1118 | chunks, |
| 1119 | usage, |
| 1120 | dimension: embeddings[0]?.length, |
| 1121 | }; |
| 1122 | this.embeddingCache.set(key, result); |
| 1123 | return result; |
| 1124 | } |
| 1125 |
no test coverage detected