@langchain/core 0.0.10 → 0.0.11-rc.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.
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.BaseDocumentTransformer = void 0;
3
+ exports.MappingDocumentTransformer = exports.BaseDocumentTransformer = void 0;
4
4
  const base_js_1 = require("../runnables/base.cjs");
5
5
  /**
6
6
  * Abstract base class for document transformation systems.
@@ -34,3 +34,18 @@ class BaseDocumentTransformer extends base_js_1.Runnable {
34
34
  }
35
35
  }
36
36
  exports.BaseDocumentTransformer = BaseDocumentTransformer;
37
+ /**
38
+ * Class for document transformers that return exactly one transformed document
39
+ * for each input document.
40
+ */
41
+ class MappingDocumentTransformer extends BaseDocumentTransformer {
42
+ async transformDocuments(documents) {
43
+ const newDocuments = [];
44
+ for (const document of documents) {
45
+ const transformedDocument = await this._transformDocument(document);
46
+ newDocuments.push(transformedDocument);
47
+ }
48
+ return newDocuments;
49
+ }
50
+ }
51
+ exports.MappingDocumentTransformer = MappingDocumentTransformer;
@@ -28,3 +28,11 @@ export declare abstract class BaseDocumentTransformer<RunInput extends Document[
28
28
  */
29
29
  invoke(input: RunInput, _options: BaseCallbackConfig): Promise<RunOutput>;
30
30
  }
31
+ /**
32
+ * Class for document transformers that return exactly one transformed document
33
+ * for each input document.
34
+ */
35
+ export declare abstract class MappingDocumentTransformer extends BaseDocumentTransformer {
36
+ transformDocuments(documents: Document[]): Promise<Document[]>;
37
+ abstract _transformDocument(document: Document): Promise<Document>;
38
+ }
@@ -30,3 +30,17 @@ export class BaseDocumentTransformer extends Runnable {
30
30
  return this.transformDocuments(input);
31
31
  }
32
32
  }
33
+ /**
34
+ * Class for document transformers that return exactly one transformed document
35
+ * for each input document.
36
+ */
37
+ export class MappingDocumentTransformer extends BaseDocumentTransformer {
38
+ async transformDocuments(documents) {
39
+ const newDocuments = [];
40
+ for (const document of documents) {
41
+ const transformedDocument = await this._transformDocument(document);
42
+ newDocuments.push(transformedDocument);
43
+ }
44
+ return newDocuments;
45
+ }
46
+ }
@@ -24,7 +24,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
24
24
  return result;
25
25
  };
26
26
  Object.defineProperty(exports, "__esModule", { value: true });
27
- exports.vectorstores = exports.utils__types = exports.utils__tiktoken = exports.utils__testing = exports.utils__stream = exports.utils__json_schema = exports.utils__json_patch = exports.utils__hash = exports.utils__env = exports.utils__async_caller = exports.tracers__tracer_langchain = exports.tracers__tracer_langchain_v1 = exports.tracers__run_collector = exports.tracers__log_stream = exports.tracers__initialize = exports.tracers__console = exports.tracers__base = exports.tools = exports.stores = exports.retrievers = exports.runnables = exports.prompt_values = exports.prompts = exports.outputs = exports.output_parsers = exports.messages = exports.memory = exports.load__serializable = exports.language_models__llms = exports.language_models__chat_models = exports.language_models__base = exports.example_selectors = exports.embeddings = exports.documents = exports.chat_history = exports.callbacks__promises = exports.callbacks__manager = exports.callbacks__base = exports.caches = exports.agents = void 0;
27
+ exports.vectorstores = exports.utils__types = exports.utils__tiktoken = exports.utils__testing = exports.utils__stream = exports.utils__math = exports.utils__json_schema = exports.utils__json_patch = exports.utils__hash = exports.utils__env = exports.utils__async_caller = exports.tracers__tracer_langchain = exports.tracers__tracer_langchain_v1 = exports.tracers__run_collector = exports.tracers__log_stream = exports.tracers__initialize = exports.tracers__console = exports.tracers__base = exports.tools = exports.stores = exports.retrievers = exports.runnables = exports.prompt_values = exports.prompts = exports.outputs = exports.output_parsers = exports.messages = exports.memory = exports.load__serializable = exports.language_models__llms = exports.language_models__chat_models = exports.language_models__base = exports.example_selectors = exports.embeddings = exports.documents = exports.chat_history = exports.callbacks__promises = exports.callbacks__manager = exports.callbacks__base = exports.caches = exports.agents = void 0;
28
28
  exports.agents = __importStar(require("../agents.cjs"));
29
29
  exports.caches = __importStar(require("../caches.cjs"));
30
30
  exports.callbacks__base = __importStar(require("../callbacks/base.cjs"));
@@ -60,6 +60,7 @@ exports.utils__env = __importStar(require("../utils/env.cjs"));
60
60
  exports.utils__hash = __importStar(require("../utils/hash.cjs"));
61
61
  exports.utils__json_patch = __importStar(require("../utils/json_patch.cjs"));
62
62
  exports.utils__json_schema = __importStar(require("../utils/json_schema.cjs"));
63
+ exports.utils__math = __importStar(require("../utils/math.cjs"));
63
64
  exports.utils__stream = __importStar(require("../utils/stream.cjs"));
64
65
  exports.utils__testing = __importStar(require("../utils/testing/index.cjs"));
65
66
  exports.utils__tiktoken = __importStar(require("../utils/tiktoken.cjs"));
@@ -33,6 +33,7 @@ export * as utils__env from "../utils/env.js";
33
33
  export * as utils__hash from "../utils/hash.js";
34
34
  export * as utils__json_patch from "../utils/json_patch.js";
35
35
  export * as utils__json_schema from "../utils/json_schema.js";
36
+ export * as utils__math from "../utils/math.js";
36
37
  export * as utils__stream from "../utils/stream.js";
37
38
  export * as utils__testing from "../utils/testing/index.js";
38
39
  export * as utils__tiktoken from "../utils/tiktoken.js";
@@ -34,6 +34,7 @@ export * as utils__env from "../utils/env.js";
34
34
  export * as utils__hash from "../utils/hash.js";
35
35
  export * as utils__json_patch from "../utils/json_patch.js";
36
36
  export * as utils__json_schema from "../utils/json_schema.js";
37
+ export * as utils__math from "../utils/math.js";
37
38
  export * as utils__stream from "../utils/stream.js";
38
39
  export * as utils__testing from "../utils/testing/index.js";
39
40
  export * as utils__tiktoken from "../utils/tiktoken.js";
@@ -93,12 +93,17 @@ async function reviver(value) {
93
93
  const namespace = namespaceReverse.reverse();
94
94
  const finalImportMap = { ...defaultImportMap, ...importMap };
95
95
  let module = null;
96
+ const optionalImportNamespaceAliases = [namespace.join("/")];
97
+ if (namespace[0] === "langchain_community") {
98
+ optionalImportNamespaceAliases.push(["langchain", ...namespace.slice(1)].join("/"));
99
+ }
100
+ const matchingNamespaceAlias = optionalImportNamespaceAliases.find((alias) => alias in optionalImportsMap);
96
101
  if (import_constants_js_1.optionalImportEntrypoints
97
102
  .concat(optionalImportEntrypoints)
98
103
  .includes(namespace.join("/")) ||
99
- namespace.join("/") in optionalImportsMap) {
100
- if (namespace.join("/") in optionalImportsMap) {
101
- module = await optionalImportsMap[namespace.join("/")];
104
+ matchingNamespaceAlias) {
105
+ if (matchingNamespaceAlias !== undefined) {
106
+ module = await optionalImportsMap[matchingNamespaceAlias];
102
107
  }
103
108
  else {
104
109
  throw new Error(`Missing key "${namespace.join("/")}" for ${pathStr} in load(optionalImportsMap={})`);
@@ -108,6 +113,7 @@ async function reviver(value) {
108
113
  // Currently, we only support langchain imports.
109
114
  if (namespace[0] === "langchain" ||
110
115
  namespace[0] === "langchain_core" ||
116
+ namespace[0] === "langchain_community" ||
111
117
  namespace[0] === "langchain_anthropic" ||
112
118
  namespace[0] === "langchain_openai") {
113
119
  namespace.shift();
@@ -67,12 +67,17 @@ async function reviver(value) {
67
67
  const namespace = namespaceReverse.reverse();
68
68
  const finalImportMap = { ...defaultImportMap, ...importMap };
69
69
  let module = null;
70
+ const optionalImportNamespaceAliases = [namespace.join("/")];
71
+ if (namespace[0] === "langchain_community") {
72
+ optionalImportNamespaceAliases.push(["langchain", ...namespace.slice(1)].join("/"));
73
+ }
74
+ const matchingNamespaceAlias = optionalImportNamespaceAliases.find((alias) => alias in optionalImportsMap);
70
75
  if (defaultOptionalImportEntrypoints
71
76
  .concat(optionalImportEntrypoints)
72
77
  .includes(namespace.join("/")) ||
73
- namespace.join("/") in optionalImportsMap) {
74
- if (namespace.join("/") in optionalImportsMap) {
75
- module = await optionalImportsMap[namespace.join("/")];
78
+ matchingNamespaceAlias) {
79
+ if (matchingNamespaceAlias !== undefined) {
80
+ module = await optionalImportsMap[matchingNamespaceAlias];
76
81
  }
77
82
  else {
78
83
  throw new Error(`Missing key "${namespace.join("/")}" for ${pathStr} in load(optionalImportsMap={})`);
@@ -82,6 +87,7 @@ async function reviver(value) {
82
87
  // Currently, we only support langchain imports.
83
88
  if (namespace[0] === "langchain" ||
84
89
  namespace[0] === "langchain_core" ||
90
+ namespace[0] === "langchain_community" ||
85
91
  namespace[0] === "langchain_anthropic" ||
86
92
  namespace[0] === "langchain_openai") {
87
93
  namespace.shift();
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.mapStoredMessageToChatMessage = exports.getBufferString = exports.ChatMessageChunk = exports.coerceMessageLikeToMessage = exports.isBaseMessageChunk = exports.isBaseMessage = exports.ChatMessage = exports.ToolMessageChunk = exports.ToolMessage = exports.FunctionMessageChunk = exports.FunctionMessage = exports.SystemMessageChunk = exports.SystemMessage = exports.AIMessageChunk = exports.AIMessage = exports.HumanMessageChunk = exports.HumanMessage = exports.BaseMessageChunk = exports.BaseMessage = void 0;
3
+ exports.mapChatMessagesToStoredMessages = exports.mapStoredMessagesToChatMessages = exports.mapStoredMessageToChatMessage = exports.getBufferString = exports.ChatMessageChunk = exports.coerceMessageLikeToMessage = exports.isBaseMessageChunk = exports.isBaseMessage = exports.ChatMessage = exports.ToolMessageChunk = exports.ToolMessage = exports.FunctionMessageChunk = exports.FunctionMessage = exports.SystemMessageChunk = exports.SystemMessage = exports.AIMessageChunk = exports.AIMessage = exports.HumanMessageChunk = exports.HumanMessage = exports.BaseMessageChunk = exports.BaseMessage = void 0;
4
4
  const serializable_js_1 = require("../load/serializable.cjs");
5
5
  function mergeContent(firstContent, secondContent) {
6
6
  // If first content is a string
@@ -556,3 +556,25 @@ function mapStoredMessageToChatMessage(message) {
556
556
  }
557
557
  }
558
558
  exports.mapStoredMessageToChatMessage = mapStoredMessageToChatMessage;
559
+ /**
560
+ * Transforms an array of `StoredMessage` instances into an array of
561
+ * `BaseMessage` instances. It uses the `mapV1MessageToStoredMessage`
562
+ * function to ensure all messages are in the `StoredMessage` format, then
563
+ * creates new instances of the appropriate `BaseMessage` subclass based
564
+ * on the type of each message. This function is used to prepare stored
565
+ * messages for use in a chat context.
566
+ */
567
+ function mapStoredMessagesToChatMessages(messages) {
568
+ return messages.map(mapStoredMessageToChatMessage);
569
+ }
570
+ exports.mapStoredMessagesToChatMessages = mapStoredMessagesToChatMessages;
571
+ /**
572
+ * Transforms an array of `BaseMessage` instances into an array of
573
+ * `StoredMessage` instances. It does this by calling the `toDict` method
574
+ * on each `BaseMessage`, which returns a `StoredMessage`. This function
575
+ * is used to prepare chat messages for storage.
576
+ */
577
+ function mapChatMessagesToStoredMessages(messages) {
578
+ return messages.map((message) => message.toDict());
579
+ }
580
+ exports.mapChatMessagesToStoredMessages = mapChatMessagesToStoredMessages;
@@ -234,3 +234,19 @@ export declare class ChatMessageChunk extends BaseMessageChunk {
234
234
  */
235
235
  export declare function getBufferString(messages: BaseMessage[], humanPrefix?: string, aiPrefix?: string): string;
236
236
  export declare function mapStoredMessageToChatMessage(message: StoredMessage): ChatMessage | HumanMessage | AIMessage | SystemMessage | FunctionMessage | ToolMessage;
237
+ /**
238
+ * Transforms an array of `StoredMessage` instances into an array of
239
+ * `BaseMessage` instances. It uses the `mapV1MessageToStoredMessage`
240
+ * function to ensure all messages are in the `StoredMessage` format, then
241
+ * creates new instances of the appropriate `BaseMessage` subclass based
242
+ * on the type of each message. This function is used to prepare stored
243
+ * messages for use in a chat context.
244
+ */
245
+ export declare function mapStoredMessagesToChatMessages(messages: StoredMessage[]): BaseMessage[];
246
+ /**
247
+ * Transforms an array of `BaseMessage` instances into an array of
248
+ * `StoredMessage` instances. It does this by calling the `toDict` method
249
+ * on each `BaseMessage`, which returns a `StoredMessage`. This function
250
+ * is used to prepare chat messages for storage.
251
+ */
252
+ export declare function mapChatMessagesToStoredMessages(messages: BaseMessage[]): StoredMessage[];
@@ -534,3 +534,23 @@ export function mapStoredMessageToChatMessage(message) {
534
534
  throw new Error(`Got unexpected type: ${storedMessage.type}`);
535
535
  }
536
536
  }
537
+ /**
538
+ * Transforms an array of `StoredMessage` instances into an array of
539
+ * `BaseMessage` instances. It uses the `mapV1MessageToStoredMessage`
540
+ * function to ensure all messages are in the `StoredMessage` format, then
541
+ * creates new instances of the appropriate `BaseMessage` subclass based
542
+ * on the type of each message. This function is used to prepare stored
543
+ * messages for use in a chat context.
544
+ */
545
+ export function mapStoredMessagesToChatMessages(messages) {
546
+ return messages.map(mapStoredMessageToChatMessage);
547
+ }
548
+ /**
549
+ * Transforms an array of `BaseMessage` instances into an array of
550
+ * `StoredMessage` instances. It does this by calling the `toDict` method
551
+ * on each `BaseMessage`, which returns a `StoredMessage`. This function
552
+ * is used to prepare chat messages for storage.
553
+ */
554
+ export function mapChatMessagesToStoredMessages(messages) {
555
+ return messages.map((message) => message.toDict());
556
+ }
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.maximalMarginalRelevance = exports.euclideanDistance = exports.innerProduct = exports.cosineSimilarity = exports.normalize = exports.matrixFunc = void 0;
4
+ const ml_distance_1 = require("ml-distance");
5
+ /**
6
+ * Apply a row-wise function between two matrices with the same number of columns.
7
+ *
8
+ * @param {number[][]} X - The first matrix.
9
+ * @param {number[][]} Y - The second matrix.
10
+ * @param {VectorFunction} func - The function to apply.
11
+ *
12
+ * @throws {Error} If the number of columns in X and Y are not the same.
13
+ *
14
+ * @returns {number[][] | [[]]} A matrix where each row represents the result of applying the function between the corresponding rows of X and Y.
15
+ */
16
+ function matrixFunc(X, Y, func) {
17
+ if (X.length === 0 ||
18
+ X[0].length === 0 ||
19
+ Y.length === 0 ||
20
+ Y[0].length === 0) {
21
+ return [[]];
22
+ }
23
+ if (X[0].length !== Y[0].length) {
24
+ throw new Error(`Number of columns in X and Y must be the same. X has shape ${[
25
+ X.length,
26
+ X[0].length,
27
+ ]} and Y has shape ${[Y.length, Y[0].length]}.`);
28
+ }
29
+ return X.map((xVector) => Y.map((yVector) => func(xVector, yVector)).map((similarity) => Number.isNaN(similarity) ? 0 : similarity));
30
+ }
31
+ exports.matrixFunc = matrixFunc;
32
+ function normalize(M, similarity = false) {
33
+ const max = matrixMaxVal(M);
34
+ return M.map((row) => row.map((val) => (similarity ? 1 - val / max : val / max)));
35
+ }
36
+ exports.normalize = normalize;
37
+ /**
38
+ * This function calculates the row-wise cosine similarity between two matrices with the same number of columns.
39
+ *
40
+ * @param {number[][]} X - The first matrix.
41
+ * @param {number[][]} Y - The second matrix.
42
+ *
43
+ * @throws {Error} If the number of columns in X and Y are not the same.
44
+ *
45
+ * @returns {number[][] | [[]]} A matrix where each row represents the cosine similarity values between the corresponding rows of X and Y.
46
+ */
47
+ function cosineSimilarity(X, Y) {
48
+ return matrixFunc(X, Y, ml_distance_1.similarity.cosine);
49
+ }
50
+ exports.cosineSimilarity = cosineSimilarity;
51
+ function innerProduct(X, Y) {
52
+ return matrixFunc(X, Y, ml_distance_1.distance.innerProduct);
53
+ }
54
+ exports.innerProduct = innerProduct;
55
+ function euclideanDistance(X, Y) {
56
+ return matrixFunc(X, Y, ml_distance_1.distance.euclidean);
57
+ }
58
+ exports.euclideanDistance = euclideanDistance;
59
+ /**
60
+ * This function implements the Maximal Marginal Relevance algorithm
61
+ * to select a set of embeddings that maximizes the diversity and relevance to a query embedding.
62
+ *
63
+ * @param {number[]|number[][]} queryEmbedding - The query embedding.
64
+ * @param {number[][]} embeddingList - The list of embeddings to select from.
65
+ * @param {number} [lambda=0.5] - The trade-off parameter between relevance and diversity.
66
+ * @param {number} [k=4] - The maximum number of embeddings to select.
67
+ *
68
+ * @returns {number[]} The indexes of the selected embeddings in the embeddingList.
69
+ */
70
+ function maximalMarginalRelevance(queryEmbedding, embeddingList, lambda = 0.5, k = 4) {
71
+ if (Math.min(k, embeddingList.length) <= 0) {
72
+ return [];
73
+ }
74
+ const queryEmbeddingExpanded = (Array.isArray(queryEmbedding[0]) ? queryEmbedding : [queryEmbedding]);
75
+ const similarityToQuery = cosineSimilarity(queryEmbeddingExpanded, embeddingList)[0];
76
+ const mostSimilarEmbeddingIndex = argMax(similarityToQuery).maxIndex;
77
+ const selectedEmbeddings = [embeddingList[mostSimilarEmbeddingIndex]];
78
+ const selectedEmbeddingsIndexes = [mostSimilarEmbeddingIndex];
79
+ while (selectedEmbeddingsIndexes.length < Math.min(k, embeddingList.length)) {
80
+ let bestScore = -Infinity;
81
+ let bestIndex = -1;
82
+ const similarityToSelected = cosineSimilarity(embeddingList, selectedEmbeddings);
83
+ similarityToQuery.forEach((queryScore, queryScoreIndex) => {
84
+ if (selectedEmbeddingsIndexes.includes(queryScoreIndex)) {
85
+ return;
86
+ }
87
+ const maxSimilarityToSelected = Math.max(...similarityToSelected[queryScoreIndex]);
88
+ const score = lambda * queryScore - (1 - lambda) * maxSimilarityToSelected;
89
+ if (score > bestScore) {
90
+ bestScore = score;
91
+ bestIndex = queryScoreIndex;
92
+ }
93
+ });
94
+ selectedEmbeddings.push(embeddingList[bestIndex]);
95
+ selectedEmbeddingsIndexes.push(bestIndex);
96
+ }
97
+ return selectedEmbeddingsIndexes;
98
+ }
99
+ exports.maximalMarginalRelevance = maximalMarginalRelevance;
100
+ /**
101
+ * Finds the index of the maximum value in the given array.
102
+ * @param {number[]} array - The input array.
103
+ *
104
+ * @returns {number} The index of the maximum value in the array. If the array is empty, returns -1.
105
+ */
106
+ function argMax(array) {
107
+ if (array.length === 0) {
108
+ return {
109
+ maxIndex: -1,
110
+ maxValue: NaN,
111
+ };
112
+ }
113
+ let maxValue = array[0];
114
+ let maxIndex = 0;
115
+ for (let i = 1; i < array.length; i += 1) {
116
+ if (array[i] > maxValue) {
117
+ maxIndex = i;
118
+ maxValue = array[i];
119
+ }
120
+ }
121
+ return { maxIndex, maxValue };
122
+ }
123
+ function matrixMaxVal(arrays) {
124
+ return arrays.reduce((acc, array) => Math.max(acc, argMax(array).maxValue), 0);
125
+ }
@@ -0,0 +1,40 @@
1
+ type VectorFunction = (xVector: number[], yVector: number[]) => number;
2
+ /**
3
+ * Apply a row-wise function between two matrices with the same number of columns.
4
+ *
5
+ * @param {number[][]} X - The first matrix.
6
+ * @param {number[][]} Y - The second matrix.
7
+ * @param {VectorFunction} func - The function to apply.
8
+ *
9
+ * @throws {Error} If the number of columns in X and Y are not the same.
10
+ *
11
+ * @returns {number[][] | [[]]} A matrix where each row represents the result of applying the function between the corresponding rows of X and Y.
12
+ */
13
+ export declare function matrixFunc(X: number[][], Y: number[][], func: VectorFunction): number[][];
14
+ export declare function normalize(M: number[][], similarity?: boolean): number[][];
15
+ /**
16
+ * This function calculates the row-wise cosine similarity between two matrices with the same number of columns.
17
+ *
18
+ * @param {number[][]} X - The first matrix.
19
+ * @param {number[][]} Y - The second matrix.
20
+ *
21
+ * @throws {Error} If the number of columns in X and Y are not the same.
22
+ *
23
+ * @returns {number[][] | [[]]} A matrix where each row represents the cosine similarity values between the corresponding rows of X and Y.
24
+ */
25
+ export declare function cosineSimilarity(X: number[][], Y: number[][]): number[][];
26
+ export declare function innerProduct(X: number[][], Y: number[][]): number[][];
27
+ export declare function euclideanDistance(X: number[][], Y: number[][]): number[][];
28
+ /**
29
+ * This function implements the Maximal Marginal Relevance algorithm
30
+ * to select a set of embeddings that maximizes the diversity and relevance to a query embedding.
31
+ *
32
+ * @param {number[]|number[][]} queryEmbedding - The query embedding.
33
+ * @param {number[][]} embeddingList - The list of embeddings to select from.
34
+ * @param {number} [lambda=0.5] - The trade-off parameter between relevance and diversity.
35
+ * @param {number} [k=4] - The maximum number of embeddings to select.
36
+ *
37
+ * @returns {number[]} The indexes of the selected embeddings in the embeddingList.
38
+ */
39
+ export declare function maximalMarginalRelevance(queryEmbedding: number[] | number[][], embeddingList: number[][], lambda?: number, k?: number): number[];
40
+ export {};
@@ -0,0 +1,116 @@
1
+ import { similarity as ml_distance_similarity, distance as ml_distance, } from "ml-distance";
2
+ /**
3
+ * Apply a row-wise function between two matrices with the same number of columns.
4
+ *
5
+ * @param {number[][]} X - The first matrix.
6
+ * @param {number[][]} Y - The second matrix.
7
+ * @param {VectorFunction} func - The function to apply.
8
+ *
9
+ * @throws {Error} If the number of columns in X and Y are not the same.
10
+ *
11
+ * @returns {number[][] | [[]]} A matrix where each row represents the result of applying the function between the corresponding rows of X and Y.
12
+ */
13
+ export function matrixFunc(X, Y, func) {
14
+ if (X.length === 0 ||
15
+ X[0].length === 0 ||
16
+ Y.length === 0 ||
17
+ Y[0].length === 0) {
18
+ return [[]];
19
+ }
20
+ if (X[0].length !== Y[0].length) {
21
+ throw new Error(`Number of columns in X and Y must be the same. X has shape ${[
22
+ X.length,
23
+ X[0].length,
24
+ ]} and Y has shape ${[Y.length, Y[0].length]}.`);
25
+ }
26
+ return X.map((xVector) => Y.map((yVector) => func(xVector, yVector)).map((similarity) => Number.isNaN(similarity) ? 0 : similarity));
27
+ }
28
+ export function normalize(M, similarity = false) {
29
+ const max = matrixMaxVal(M);
30
+ return M.map((row) => row.map((val) => (similarity ? 1 - val / max : val / max)));
31
+ }
32
+ /**
33
+ * This function calculates the row-wise cosine similarity between two matrices with the same number of columns.
34
+ *
35
+ * @param {number[][]} X - The first matrix.
36
+ * @param {number[][]} Y - The second matrix.
37
+ *
38
+ * @throws {Error} If the number of columns in X and Y are not the same.
39
+ *
40
+ * @returns {number[][] | [[]]} A matrix where each row represents the cosine similarity values between the corresponding rows of X and Y.
41
+ */
42
+ export function cosineSimilarity(X, Y) {
43
+ return matrixFunc(X, Y, ml_distance_similarity.cosine);
44
+ }
45
+ export function innerProduct(X, Y) {
46
+ return matrixFunc(X, Y, ml_distance.innerProduct);
47
+ }
48
+ export function euclideanDistance(X, Y) {
49
+ return matrixFunc(X, Y, ml_distance.euclidean);
50
+ }
51
+ /**
52
+ * This function implements the Maximal Marginal Relevance algorithm
53
+ * to select a set of embeddings that maximizes the diversity and relevance to a query embedding.
54
+ *
55
+ * @param {number[]|number[][]} queryEmbedding - The query embedding.
56
+ * @param {number[][]} embeddingList - The list of embeddings to select from.
57
+ * @param {number} [lambda=0.5] - The trade-off parameter between relevance and diversity.
58
+ * @param {number} [k=4] - The maximum number of embeddings to select.
59
+ *
60
+ * @returns {number[]} The indexes of the selected embeddings in the embeddingList.
61
+ */
62
+ export function maximalMarginalRelevance(queryEmbedding, embeddingList, lambda = 0.5, k = 4) {
63
+ if (Math.min(k, embeddingList.length) <= 0) {
64
+ return [];
65
+ }
66
+ const queryEmbeddingExpanded = (Array.isArray(queryEmbedding[0]) ? queryEmbedding : [queryEmbedding]);
67
+ const similarityToQuery = cosineSimilarity(queryEmbeddingExpanded, embeddingList)[0];
68
+ const mostSimilarEmbeddingIndex = argMax(similarityToQuery).maxIndex;
69
+ const selectedEmbeddings = [embeddingList[mostSimilarEmbeddingIndex]];
70
+ const selectedEmbeddingsIndexes = [mostSimilarEmbeddingIndex];
71
+ while (selectedEmbeddingsIndexes.length < Math.min(k, embeddingList.length)) {
72
+ let bestScore = -Infinity;
73
+ let bestIndex = -1;
74
+ const similarityToSelected = cosineSimilarity(embeddingList, selectedEmbeddings);
75
+ similarityToQuery.forEach((queryScore, queryScoreIndex) => {
76
+ if (selectedEmbeddingsIndexes.includes(queryScoreIndex)) {
77
+ return;
78
+ }
79
+ const maxSimilarityToSelected = Math.max(...similarityToSelected[queryScoreIndex]);
80
+ const score = lambda * queryScore - (1 - lambda) * maxSimilarityToSelected;
81
+ if (score > bestScore) {
82
+ bestScore = score;
83
+ bestIndex = queryScoreIndex;
84
+ }
85
+ });
86
+ selectedEmbeddings.push(embeddingList[bestIndex]);
87
+ selectedEmbeddingsIndexes.push(bestIndex);
88
+ }
89
+ return selectedEmbeddingsIndexes;
90
+ }
91
+ /**
92
+ * Finds the index of the maximum value in the given array.
93
+ * @param {number[]} array - The input array.
94
+ *
95
+ * @returns {number} The index of the maximum value in the array. If the array is empty, returns -1.
96
+ */
97
+ function argMax(array) {
98
+ if (array.length === 0) {
99
+ return {
100
+ maxIndex: -1,
101
+ maxValue: NaN,
102
+ };
103
+ }
104
+ let maxValue = array[0];
105
+ let maxIndex = 0;
106
+ for (let i = 1; i < array.length; i += 1) {
107
+ if (array[i] > maxValue) {
108
+ maxIndex = i;
109
+ maxValue = array[i];
110
+ }
111
+ }
112
+ return { maxIndex, maxValue };
113
+ }
114
+ function matrixMaxVal(arrays) {
115
+ return arrays.reduce((acc, array) => Math.max(acc, argMax(array).maxValue), 0);
116
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/core",
3
- "version": "0.0.10",
3
+ "version": "0.0.11-rc.1",
4
4
  "description": "Core LangChain.js abstractions and schemas",
5
5
  "type": "module",
6
6
  "engines": {
@@ -40,6 +40,7 @@
40
40
  "decamelize": "1.2.0",
41
41
  "js-tiktoken": "^1.0.8",
42
42
  "langsmith": "~0.0.48",
43
+ "ml-distance": "^4.0.0",
43
44
  "p-queue": "^6.6.2",
44
45
  "p-retry": "4",
45
46
  "uuid": "^9.0.0",
@@ -59,6 +60,7 @@
59
60
  "eslint-plugin-prettier": "^4.2.1",
60
61
  "jest": "^29.5.0",
61
62
  "jest-environment-node": "^29.6.4",
63
+ "ml-matrix": "^6.10.4",
62
64
  "prettier": "^2.8.3",
63
65
  "release-it": "^15.10.1",
64
66
  "rimraf": "^5.0.1",
@@ -263,6 +265,11 @@
263
265
  "import": "./utils/json_schema.js",
264
266
  "require": "./utils/json_schema.cjs"
265
267
  },
268
+ "./utils/math": {
269
+ "types": "./utils/math.d.ts",
270
+ "import": "./utils/math.js",
271
+ "require": "./utils/math.cjs"
272
+ },
266
273
  "./utils/stream": {
267
274
  "types": "./utils/stream.d.ts",
268
275
  "import": "./utils/stream.js",
@@ -400,6 +407,9 @@
400
407
  "utils/json_schema.cjs",
401
408
  "utils/json_schema.js",
402
409
  "utils/json_schema.d.ts",
410
+ "utils/math.cjs",
411
+ "utils/math.js",
412
+ "utils/math.d.ts",
403
413
  "utils/stream.cjs",
404
414
  "utils/stream.js",
405
415
  "utils/stream.d.ts",
package/utils/math.cjs ADDED
@@ -0,0 +1 @@
1
+ module.exports = require('../dist/utils/math.cjs');
@@ -0,0 +1 @@
1
+ export * from '../dist/utils/math.js'
package/utils/math.js ADDED
@@ -0,0 +1 @@
1
+ export * from '../dist/utils/math.js'