From c654398f7582f03f5c2ab30268ab71b3b7e5872d Mon Sep 17 00:00:00 2001
From: Thuc Pham <51660321+thucpn@users.noreply.github.com>
Date: Mon, 12 Aug 2024 17:41:05 +0700
Subject: [PATCH] feat: implement Weaviate Vector Store in TS (#1109)

---
 .changeset/four-avocados-divide.md            |   5 +
 examples/weaviate/README.md                   |  31 ++
 examples/weaviate/load.ts                     |  23 ++
 examples/weaviate/query.ts                    |  46 +++
 packages/llamaindex/package.json              |   1 +
 packages/llamaindex/src/storage/index.ts      |   1 +
 .../vectorStore/WeaviateVectorStore.ts        | 339 ++++++++++++++++++
 .../src/storage/vectorStore/utils.ts          |   5 +
 pnpm-lock.yaml                                |  97 ++++-
 9 files changed, 534 insertions(+), 14 deletions(-)
 create mode 100644 .changeset/four-avocados-divide.md
 create mode 100644 examples/weaviate/README.md
 create mode 100644 examples/weaviate/load.ts
 create mode 100644 examples/weaviate/query.ts
 create mode 100644 packages/llamaindex/src/storage/vectorStore/WeaviateVectorStore.ts

diff --git a/.changeset/four-avocados-divide.md b/.changeset/four-avocados-divide.md
new file mode 100644
index 000000000..129b1349b
--- /dev/null
+++ b/.changeset/four-avocados-divide.md
@@ -0,0 +1,5 @@
+---
+"llamaindex": patch
+---
+
+Implement Weaviate Vector Store in TS
diff --git a/examples/weaviate/README.md b/examples/weaviate/README.md
new file mode 100644
index 000000000..6d9d68678
--- /dev/null
+++ b/examples/weaviate/README.md
@@ -0,0 +1,31 @@
+# Weaviate Vector Store
+
+Here are two sample scripts which work with loading and querying data from a Weaviate Vector Store.
+
+## Prerequisites
+
+- An Weaviate Vector Database
+  - Hosted https://weaviate.io/
+  - Self Hosted https://weaviate.io/developers/weaviate/installation/docker-compose#starter-docker-compose-file
+- An OpenAI API Key
+
+## Setup
+
+1. Set your env variables:
+
+- `WEAVIATE_CLUSTER_URL`: Address of your Weaviate Vector Store (like localhost:8080)
+- `WEAVIATE_API_KEY`: Your Weaviate API key
+- `OPENAI_API_KEY`: Your OpenAI key
+
+2. `cd` Into the `examples` directory
+3. run `npm i`
+
+## Load the data
+
+This sample loads the same dataset of movie reviews as sample dataset
+
+run `npx tsx weaviate/load`
+
+## Use RAG to Query the data
+
+run `npx tsx weaviate/query`
diff --git a/examples/weaviate/load.ts b/examples/weaviate/load.ts
new file mode 100644
index 000000000..ac367c82d
--- /dev/null
+++ b/examples/weaviate/load.ts
@@ -0,0 +1,23 @@
+import {
+  PapaCSVReader,
+  storageContextFromDefaults,
+  VectorStoreIndex,
+  WeaviateVectorStore,
+} from "llamaindex";
+
+const indexName = "MovieReviews";
+
+async function main() {
+  try {
+    const reader = new PapaCSVReader(false);
+    const docs = await reader.loadData("./data/movie_reviews.csv");
+    const vectorStore = new WeaviateVectorStore({ indexName });
+    const storageContext = await storageContextFromDefaults({ vectorStore });
+    await VectorStoreIndex.fromDocuments(docs, { storageContext });
+    console.log("Successfully loaded data into Weaviate");
+  } catch (e) {
+    console.error(e);
+  }
+}
+
+void main();
diff --git a/examples/weaviate/query.ts b/examples/weaviate/query.ts
new file mode 100644
index 000000000..ad265dece
--- /dev/null
+++ b/examples/weaviate/query.ts
@@ -0,0 +1,46 @@
+import { VectorStoreIndex, WeaviateVectorStore } from "llamaindex";
+
+const indexName = "MovieReviews";
+
+async function main() {
+  try {
+    const query = "Get all movie titles.";
+    const vectorStore = new WeaviateVectorStore({ indexName });
+    const index = await VectorStoreIndex.fromVectorStore(vectorStore);
+    const retriever = index.asRetriever({ similarityTopK: 20 });
+
+    const queryEngine = index.asQueryEngine({ retriever });
+    const results = await queryEngine.query({ query });
+    console.log(`Query from ${results.sourceNodes?.length} nodes`);
+    console.log(results.response);
+
+    console.log("\n=====\nQuerying the index with filters");
+    const queryEngineWithFilters = index.asQueryEngine({
+      retriever,
+      preFilters: {
+        filters: [
+          {
+            key: "document_id",
+            value: "./data/movie_reviews.csv_37",
+            operator: "==",
+          },
+          {
+            key: "document_id",
+            value: "./data/movie_reviews.csv_21",
+            operator: "==",
+          },
+        ],
+        condition: "or",
+      },
+    });
+    const resultAfterFilter = await queryEngineWithFilters.query({
+      query: "Get all movie titles.",
+    });
+    console.log(`Query from ${resultAfterFilter.sourceNodes?.length} nodes`);
+    console.log(resultAfterFilter.response);
+  } catch (e) {
+    console.error(e);
+  }
+}
+
+void main();
diff --git a/packages/llamaindex/package.json b/packages/llamaindex/package.json
index 5bbddcbdf..05feec902 100644
--- a/packages/llamaindex/package.json
+++ b/packages/llamaindex/package.json
@@ -65,6 +65,7 @@
     "string-strip-html": "^13.4.8",
     "tiktoken": "^1.0.15",
     "unpdf": "^0.11.0",
+    "weaviate-client": "^3.1.4",
     "wikipedia": "^2.1.2",
     "wink-nlp": "^2.3.0",
     "zod": "^3.23.8"
diff --git a/packages/llamaindex/src/storage/index.ts b/packages/llamaindex/src/storage/index.ts
index 29d64a0b6..d839410e9 100644
--- a/packages/llamaindex/src/storage/index.ts
+++ b/packages/llamaindex/src/storage/index.ts
@@ -18,3 +18,4 @@ export { PineconeVectorStore } from "./vectorStore/PineconeVectorStore.js";
 export { QdrantVectorStore } from "./vectorStore/QdrantVectorStore.js";
 export { SimpleVectorStore } from "./vectorStore/SimpleVectorStore.js";
 export * from "./vectorStore/types.js";
+export { WeaviateVectorStore } from "./vectorStore/WeaviateVectorStore.js";
diff --git a/packages/llamaindex/src/storage/vectorStore/WeaviateVectorStore.ts b/packages/llamaindex/src/storage/vectorStore/WeaviateVectorStore.ts
new file mode 100644
index 000000000..7daef1683
--- /dev/null
+++ b/packages/llamaindex/src/storage/vectorStore/WeaviateVectorStore.ts
@@ -0,0 +1,339 @@
+/* eslint-disable turbo/no-undeclared-env-vars */
+import { BaseNode, MetadataMode, type Metadata } from "@llamaindex/core/schema";
+import weaviate, {
+  Filters,
+  type Collection,
+  type DeleteManyOptions,
+  type FilterValue,
+  type WeaviateClient,
+  type WeaviateNonGenericObject,
+} from "weaviate-client";
+
+import {
+  VectorStoreBase,
+  VectorStoreQueryMode,
+  type IEmbedModel,
+  type MetadataFilter,
+  type MetadataFilters,
+  type VectorStoreNoEmbedModel,
+  type VectorStoreQuery,
+  type VectorStoreQueryResult,
+} from "./types.js";
+import {
+  metadataDictToNode,
+  nodeToMetadata,
+  parseArrayValue,
+  parseNumberValue,
+} from "./utils.js";
+
+const NODE_SCHEMA = [
+  {
+    dataType: ["text"],
+    description: "Text property",
+    name: "text",
+  },
+  {
+    dataType: ["text"],
+    description: "The ref_doc_id of the Node",
+    name: "ref_doc_id",
+  },
+  {
+    dataType: ["text"],
+    description: "node_info (in JSON)",
+    name: "node_info",
+  },
+  {
+    dataType: ["text"],
+    description: "The relationships of the node (in JSON)",
+    name: "relationships",
+  },
+];
+
+const SIMILARITY_KEYS: {
+  [key: string]: "distance" | "score";
+} = {
+  [VectorStoreQueryMode.DEFAULT]: "distance",
+  [VectorStoreQueryMode.HYBRID]: "score",
+};
+
+const buildFilterItem = (
+  collection: Collection,
+  filter: MetadataFilter,
+): FilterValue => {
+  const { key, operator, value } = filter;
+
+  switch (operator) {
+    case "==": {
+      return collection.filter.byProperty(key).equal(value);
+    }
+    case "!=": {
+      return collection.filter.byProperty(key).notEqual(value);
+    }
+    case ">": {
+      return collection.filter
+        .byProperty(key)
+        .greaterThan(parseNumberValue(value));
+    }
+    case "<": {
+      return collection.filter
+        .byProperty(key)
+        .lessThan(parseNumberValue(value));
+    }
+    case ">=": {
+      return collection.filter
+        .byProperty(key)
+        .greaterOrEqual(parseNumberValue(value));
+    }
+    case "<=": {
+      return collection.filter
+        .byProperty(key)
+        .lessOrEqual(parseNumberValue(value));
+    }
+    case "any": {
+      return collection.filter
+        .byProperty(key)
+        .containsAny(parseArrayValue(value).map(String));
+    }
+    case "all": {
+      return collection.filter
+        .byProperty(key)
+        .containsAll(parseArrayValue(value).map(String));
+    }
+    default: {
+      throw new Error(`Operator ${operator} is not supported.`);
+    }
+  }
+};
+
+const toWeaviateFilter = (
+  collection: Collection,
+  standardFilters?: MetadataFilters,
+): FilterValue | undefined => {
+  if (!standardFilters?.filters.length) return undefined;
+  const filtersList = standardFilters.filters.map((filter) =>
+    buildFilterItem(collection, filter),
+  );
+  if (filtersList.length === 1) return filtersList[0];
+  const condition = standardFilters.condition ?? "and";
+  return Filters[condition](...filtersList);
+};
+
+export class WeaviateVectorStore
+  extends VectorStoreBase
+  implements VectorStoreNoEmbedModel
+{
+  public storesText: boolean = true;
+  private flatMetadata: boolean = true;
+
+  private weaviateClient?: WeaviateClient;
+  private clusterURL!: string;
+  private apiKey!: string;
+  private indexName: string;
+
+  private idKey: string;
+  private contentKey: string;
+  private embeddingKey: string;
+  private metadataKey: string;
+
+  constructor(
+    init?: Partial<IEmbedModel> & {
+      weaviateClient?: WeaviateClient;
+      cloudOptions?: {
+        clusterURL?: string;
+        apiKey?: string;
+      };
+      indexName?: string;
+      idKey?: string;
+      contentKey?: string;
+      metadataKey?: string;
+      embeddingKey?: string;
+    },
+  ) {
+    super(init?.embedModel);
+
+    if (init?.weaviateClient) {
+      // Use the provided client
+      this.weaviateClient = init.weaviateClient;
+    } else {
+      // Load client cloud options from config or env
+      const clusterURL =
+        init?.cloudOptions?.clusterURL ?? process.env.WEAVIATE_CLUSTER_URL;
+      const apiKey = init?.cloudOptions?.apiKey ?? process.env.WEAVIATE_API_KEY;
+      if (!clusterURL || !apiKey) {
+        throw new Error(
+          "Must specify WEAVIATE_CLUSTER_URL and WEAVIATE_API_KEY via env variable.",
+        );
+      }
+      this.clusterURL = clusterURL;
+      this.apiKey = apiKey;
+    }
+
+    this.checkIndexName(init?.indexName);
+    this.indexName = init?.indexName ?? "LlamaIndex";
+    this.idKey = init?.idKey ?? "id";
+    this.contentKey = init?.contentKey ?? "text";
+    this.embeddingKey = init?.embeddingKey ?? "vectors";
+    this.metadataKey = init?.metadataKey ?? "node_info";
+  }
+
+  public client() {
+    return this.getClient();
+  }
+
+  public async add(nodes: BaseNode<Metadata>[]): Promise<string[]> {
+    const collection = await this.ensureCollection({ createIfNotExists: true });
+
+    const result = await collection.data.insertMany(
+      nodes.map((node) => {
+        const metadata = nodeToMetadata(
+          node,
+          true,
+          this.contentKey,
+          this.flatMetadata,
+        );
+        const body = {
+          [this.idKey]: node.id_,
+          [this.embeddingKey]: node.getEmbedding(),
+          properties: {
+            ...metadata,
+            [this.contentKey]: node.getContent(MetadataMode.NONE),
+            [this.metadataKey]: JSON.stringify(metadata),
+            relationships: JSON.stringify({ ref_doc_id: metadata.ref_doc_id }),
+          },
+        };
+        return body;
+      }),
+    );
+
+    return Object.values(result.uuids);
+  }
+
+  public async delete(
+    refDocId: string,
+    deleteOptions?: DeleteManyOptions<boolean>,
+  ): Promise<void> {
+    const collection = await this.ensureCollection();
+    await collection.data.deleteMany(
+      collection.filter.byProperty("ref_doc_id").like(refDocId),
+      deleteOptions,
+    );
+  }
+
+  public async query(query: VectorStoreQuery): Promise<VectorStoreQueryResult> {
+    const collection = await this.ensureCollection();
+    const allProperties = await this.getAllProperties();
+
+    let filters: FilterValue | undefined = undefined;
+
+    if (query.docIds) {
+      filters = collection.filter
+        .byProperty("doc_id")
+        .containsAny(query.docIds);
+    }
+
+    if (query.filters) {
+      filters = toWeaviateFilter(collection, query.filters);
+    }
+
+    const queryResult = await collection.query.hybrid(query.queryStr!, {
+      vector: query.queryEmbedding,
+      alpha: this.getQueryAlpha(query),
+      limit: query.similarityTopK,
+      returnMetadata: Object.values(SIMILARITY_KEYS),
+      returnProperties: allProperties,
+      includeVector: true,
+      filters,
+    });
+
+    const entries = queryResult.objects;
+
+    const similarityKey = SIMILARITY_KEYS[query.mode];
+    const nodes: BaseNode<Metadata>[] = [];
+    const similarities: number[] = [];
+    const ids: string[] = [];
+
+    entries.forEach((entry, index) => {
+      if (index < query.similarityTopK && entry.metadata) {
+        const node = metadataDictToNode(entry.properties);
+        node.setContent(entry.properties[this.contentKey]);
+        nodes.push(node);
+        ids.push(entry.uuid);
+        similarities.push(this.getNodeSimilarity(entry, similarityKey));
+      }
+    });
+
+    return {
+      nodes,
+      similarities,
+      ids,
+    };
+  }
+
+  private async getClient(): Promise<WeaviateClient> {
+    if (this.weaviateClient) return this.weaviateClient;
+    const client = await weaviate.connectToWeaviateCloud(this.clusterURL, {
+      authCredentials: new weaviate.ApiKey(this.apiKey),
+    });
+    this.weaviateClient = client;
+    return client;
+  }
+
+  private async ensureCollection({ createIfNotExists = false } = {}) {
+    const client = await this.getClient();
+    const exists = await this.doesCollectionExist();
+    if (!exists) {
+      if (createIfNotExists) {
+        await this.createCollection();
+      } else {
+        throw new Error(`Collection ${this.indexName} does not exist.`);
+      }
+    }
+    return client.collections.get(this.indexName);
+  }
+
+  private async doesCollectionExist() {
+    const client = await this.getClient();
+    return client.collections.exists(this.indexName);
+  }
+
+  private async createCollection() {
+    const client = await this.getClient();
+    return await client.collections.createFromSchema({
+      class: this.indexName,
+      description: `Collection for ${this.indexName}`,
+      properties: NODE_SCHEMA,
+    });
+  }
+
+  private getQueryAlpha(query: VectorStoreQuery): number | undefined {
+    if (!query.queryEmbedding) return undefined;
+    if (query.mode === VectorStoreQueryMode.DEFAULT) return 1;
+    if (query.mode === VectorStoreQueryMode.HYBRID && query.queryStr)
+      return query.alpha;
+    return undefined;
+  }
+
+  private async getAllProperties(): Promise<string[]> {
+    const collection = await this.ensureCollection();
+    const properties = (await collection.config.get()).properties;
+    return properties.map((p) => p.name);
+  }
+
+  private checkIndexName(indexName?: string) {
+    if (indexName && indexName[0] !== indexName[0].toUpperCase()) {
+      throw new Error(
+        "Index name must start with a capital letter, e.g. 'LlamaIndex'",
+      );
+    }
+  }
+
+  private getNodeSimilarity(
+    entry: WeaviateNonGenericObject,
+    similarityKey: "distance" | "score" = "distance",
+  ): number {
+    const distance = entry.metadata?.[similarityKey];
+    if (distance === undefined) return 1;
+    // convert distance https://forum.weaviate.io/t/distance-vs-certainty-scores/258
+    return 1 - distance;
+  }
+}
diff --git a/packages/llamaindex/src/storage/vectorStore/utils.ts b/packages/llamaindex/src/storage/vectorStore/utils.ts
index 0e85d4bbd..d664c4f3d 100644
--- a/packages/llamaindex/src/storage/vectorStore/utils.ts
+++ b/packages/llamaindex/src/storage/vectorStore/utils.ts
@@ -99,3 +99,8 @@ export const parseArrayValue = (
   }
   return value;
 };
+
+export const parseNumberValue = (value?: MetadataFilterValue): number => {
+  if (typeof value !== "number") throw new Error("Value must be a number");
+  return value;
+};
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 96574d0ef..d89192a65 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -163,7 +163,7 @@ importers:
         version: link:../packages/llamaindex
       mongodb:
         specifier: ^6.7.0
-        version: 6.8.0(@aws-sdk/credential-providers@3.613.0(@aws-sdk/client-sso-oidc@3.613.0(@aws-sdk/client-sts@3.613.0)))
+        version: 6.8.0(@aws-sdk/credential-providers@3.613.0)
       pathe:
         specifier: ^1.1.2
         version: 1.1.2
@@ -568,7 +568,7 @@ importers:
         version: 2.0.0
       mongodb:
         specifier: ^6.7.0
-        version: 6.8.0(@aws-sdk/credential-providers@3.613.0(@aws-sdk/client-sso-oidc@3.613.0(@aws-sdk/client-sts@3.613.0)))
+        version: 6.8.0(@aws-sdk/credential-providers@3.613.0)
       notion-md-crawler:
         specifier: ^1.0.0
         version: 1.0.0(encoding@0.1.13)
@@ -602,6 +602,9 @@ importers:
       unpdf:
         specifier: ^0.11.0
         version: 0.11.0(encoding@0.1.13)
+      weaviate-client:
+        specifier: ^3.1.4
+        version: 3.1.4(encoding@0.1.13)
       wikipedia:
         specifier: ^2.1.2
         version: 2.1.2
@@ -2666,6 +2669,11 @@ packages:
     resolution: {integrity: sha512-krWjurjEUHSFhCX4lGHMOhbnpBfYZGU31mpHpPBQwcfWm0T+/+wxC4UCAJfkxxc3/HvGJVG8r4AqrffaeDHDlA==}
     engines: {node: '>=18.0.0'}
 
+  '@graphql-typed-document-node/core@3.2.0':
+    resolution: {integrity: sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==}
+    peerDependencies:
+      graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
+
   '@grpc/grpc-js@1.10.11':
     resolution: {integrity: sha512-3RaoxOqkHHN2c05bwtBNVJmOf/UwMam0rZYtdl7dsRpsvDwcNpv6LkGgzltQ7xVf822LzBoKEPRvf4D7+xeIDw==}
     engines: {node: '>=12.10.0'}
@@ -4375,6 +4383,9 @@ packages:
   abbrev@1.1.1:
     resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==}
 
+  abort-controller-x@0.4.3:
+    resolution: {integrity: sha512-VtUwTNU8fpMwvWGn4xE93ywbogTYsuT+AUxAXOeelbXuQVIwNmC5YLeho9sH4vZ4ITW8414TTAOG1nW6uIVHCA==}
+
   abort-controller@3.0.0:
     resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
     engines: {node: '>=6.5'}
@@ -6568,6 +6579,15 @@ packages:
   graphemer@1.4.0:
     resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
 
+  graphql-request@6.1.0:
+    resolution: {integrity: sha512-p+XPfS4q7aIpKVcgmnZKhMNqhltk20hfXtkaIkTfjjmiKMJ5xrt5c743cL03y/K7y1rg3WrIC49xGiEQ4mxdNw==}
+    peerDependencies:
+      graphql: 14 - 16
+
+  graphql@16.9.0:
+    resolution: {integrity: sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==}
+    engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0}
+
   gray-matter@4.0.3:
     resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==}
     engines: {node: '>=6.0'}
@@ -8126,6 +8146,15 @@ packages:
       sass:
         optional: true
 
+  nice-grpc-client-middleware-deadline@2.0.12:
+    resolution: {integrity: sha512-drKxQJzTbh+Qkd6v+BcRhTmY2mw9zR8Qigu/jk0vIkDi90K6NOOJGgvBdbTxKXtv6QY1g07T1LvwaqW3Mlwdvw==}
+
+  nice-grpc-common@2.0.2:
+    resolution: {integrity: sha512-7RNWbls5kAL1QVUOXvBsv1uO0wPQK3lHv+cY1gwkTzirnG1Nop4cBJZubpgziNbaVc/bl9QJcyvsf/NQxa3rjQ==}
+
+  nice-grpc@2.1.9:
+    resolution: {integrity: sha512-shJlg1t4Wn3qTVE31gxofbTrgCX/p4tS1xRnk4bNskCYKvXNEUpJQZpjModsVk1aau69YZDViyC18K9nC7QHYA==}
+
   nice-napi@1.0.2:
     resolution: {integrity: sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==}
     os: ['!win32']
@@ -10313,6 +10342,9 @@ packages:
     peerDependencies:
       typescript: '>=4.2.0'
 
+  ts-error@1.0.6:
+    resolution: {integrity: sha512-tLJxacIQUM82IR7JO1UUkKlYuUTmoY9HBJAmNWFzheSlDS5SPMcNIepejHJa4BpPQLAcbRhRf3GDJzyj6rbKvA==}
+
   ts-graphviz@1.8.2:
     resolution: {integrity: sha512-5YhbFoHmjxa7pgQLkB07MtGnGJ/yhvjmc9uhsnDBEICME6gkPf83SBwLDQqGDoCa3XzUMWLk1AU2Wn1u1naDtA==}
     engines: {node: '>=14.16'}
@@ -10788,6 +10820,10 @@ packages:
   wcwidth@1.0.1:
     resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
 
+  weaviate-client@3.1.4:
+    resolution: {integrity: sha512-Bw9KV0wtFd4TdifhPAkmc2Lv7bKIX0L2oqObUNG8K8Mv0zoVixGcqlAS3xJdfQ2jSqz0vH3mfetsOBdlvogxfg==}
+    engines: {node: '>=18.0.0'}
+
   web-namespaces@2.0.1:
     resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==}
 
@@ -13987,6 +14023,10 @@ snapshots:
 
   '@google/generative-ai@0.12.0': {}
 
+  '@graphql-typed-document-node/core@3.2.0(graphql@16.9.0)':
+    dependencies:
+      graphql: 16.9.0
+
   '@grpc/grpc-js@1.10.11':
     dependencies:
       '@grpc/proto-loader': 0.7.13
@@ -15865,6 +15905,8 @@ snapshots:
   abbrev@1.1.1:
     optional: true
 
+  abort-controller-x@0.4.3: {}
+
   abort-controller@3.0.0:
     dependencies:
       event-target-shim: 5.0.1
@@ -17700,16 +17742,6 @@ snapshots:
       - eslint-import-resolver-webpack
       - supports-color
 
-  eslint-module-utils@2.8.1(@typescript-eslint/parser@7.16.0(eslint@8.57.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0):
-    dependencies:
-      debug: 3.2.7
-    optionalDependencies:
-      '@typescript-eslint/parser': 7.16.0(eslint@8.57.0)(typescript@5.5.3)
-      eslint: 8.57.0
-      eslint-import-resolver-node: 0.3.9
-    transitivePeerDependencies:
-      - supports-color
-
   eslint-module-utils@2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0):
     dependencies:
       debug: 3.2.7
@@ -17731,7 +17763,7 @@ snapshots:
       doctrine: 2.1.0
       eslint: 8.57.0
       eslint-import-resolver-node: 0.3.9
-      eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.16.0(eslint@8.57.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0)
+      eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0)
       hasown: 2.0.2
       is-core-module: 2.14.0
       is-glob: 4.0.3
@@ -18625,6 +18657,16 @@ snapshots:
 
   graphemer@1.4.0: {}
 
+  graphql-request@6.1.0(encoding@0.1.13)(graphql@16.9.0):
+    dependencies:
+      '@graphql-typed-document-node/core': 3.2.0(graphql@16.9.0)
+      cross-fetch: 3.1.8(encoding@0.1.13)
+      graphql: 16.9.0
+    transitivePeerDependencies:
+      - encoding
+
+  graphql@16.9.0: {}
+
   gray-matter@4.0.3:
     dependencies:
       js-yaml: 3.14.1
@@ -20421,7 +20463,7 @@ snapshots:
     optionalDependencies:
       '@aws-sdk/credential-providers': 3.613.0(@aws-sdk/client-sso-oidc@3.613.0(@aws-sdk/client-sts@3.613.0))
 
-  mongodb@6.8.0(@aws-sdk/credential-providers@3.613.0(@aws-sdk/client-sso-oidc@3.613.0(@aws-sdk/client-sts@3.613.0))):
+  mongodb@6.8.0(@aws-sdk/credential-providers@3.613.0):
     dependencies:
       '@mongodb-js/saslprep': 1.1.7
       bson: 6.8.0
@@ -20599,6 +20641,20 @@ snapshots:
       - '@babel/core'
       - babel-plugin-macros
 
+  nice-grpc-client-middleware-deadline@2.0.12:
+    dependencies:
+      nice-grpc-common: 2.0.2
+
+  nice-grpc-common@2.0.2:
+    dependencies:
+      ts-error: 1.0.6
+
+  nice-grpc@2.1.9:
+    dependencies:
+      '@grpc/grpc-js': 1.10.11
+      abort-controller-x: 0.4.3
+      nice-grpc-common: 2.0.2
+
   nice-napi@1.0.2:
     dependencies:
       node-addon-api: 3.2.1
@@ -23091,6 +23147,8 @@ snapshots:
     dependencies:
       typescript: 5.5.3
 
+  ts-error@1.0.6: {}
+
   ts-graphviz@1.8.2: {}
 
   ts-interface-checker@0.1.13: {}
@@ -23603,6 +23661,17 @@ snapshots:
     dependencies:
       defaults: 1.0.4
 
+  weaviate-client@3.1.4(encoding@0.1.13):
+    dependencies:
+      graphql: 16.9.0
+      graphql-request: 6.1.0(encoding@0.1.13)(graphql@16.9.0)
+      long: 5.2.3
+      nice-grpc: 2.1.9
+      nice-grpc-client-middleware-deadline: 2.0.12
+      uuid: 9.0.1
+    transitivePeerDependencies:
+      - encoding
+
   web-namespaces@2.0.1: {}
 
   web-streams-polyfill@3.3.3: {}
-- 
GitLab