langchain-envector 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,10 @@
1
+ """Envector LangChain integration package.
2
+
3
+ Provides a LangChain-compatible VectorStore that wraps the high-level `es2` SDK.
4
+ All code and comments are in English as per project rules.
5
+ """
6
+
7
+ from .vectorstore import Envector
8
+
9
+ __all__ = ["Envector"]
10
+
@@ -0,0 +1,82 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Optional
4
+
5
+ from .config import EnvectorConfig
6
+
7
+
8
+ class EnvectorClient:
9
+ """Thin convenience client around the high-level `es2` SDK.
10
+
11
+ - Establishes a connection
12
+ - Initializes key and index configuration
13
+ - Optionally creates the index if missing
14
+ - Provides access to the ES2 `Index` instance
15
+ """
16
+
17
+ def __init__(self, config: EnvectorConfig):
18
+ self.config = config
19
+ self._es2 = None
20
+ self._index = None
21
+
22
+ def init(self):
23
+ import es2
24
+
25
+ c = self.config.connection
26
+ k = self.config.key
27
+ i = self.config.index
28
+
29
+ es2_client = es2.ES2()
30
+
31
+ # Connection
32
+ if c.address:
33
+ es2_client.init_connect(address=c.address, access_token=c.access_token)
34
+ else:
35
+ if not (c.host and c.port):
36
+ raise ValueError("Either address or host+port must be provided.")
37
+ es2_client.init_connect(host=c.host, port=c.port, access_token=c.access_token)
38
+
39
+ # Key path baseline for Index
40
+ from es2.index import Index as _Index
41
+
42
+ _Index.init_key_path(k.key_path)
43
+
44
+ # Index config + key setup
45
+ es2_client.init_index_config(
46
+ index_name=i.index_name,
47
+ dim=i.dim,
48
+ key_path=k.key_path,
49
+ key_id=k.key_id,
50
+ seal_mode=k.seal_mode,
51
+ seal_kek_path=k.seal_kek_path,
52
+ preset=k.preset,
53
+ eval_mode=k.eval_mode,
54
+ query_encryption=i.query_encryption,
55
+ index_encryption="cipher", # server vectors are always encrypted
56
+ index_type=i.index_type,
57
+ auto_key_setup=True,
58
+ )
59
+
60
+ # Create index if missing
61
+ if self.config.create_if_missing:
62
+ idx_list = es2_client.get_index_list()
63
+ if i.index_name not in idx_list:
64
+ es2_client.create_index(index_name=i.index_name, dim=i.dim)
65
+
66
+ # Bind index instance
67
+ self._index = es2.Index(i.index_name)
68
+ self._es2 = es2_client
69
+ return self
70
+
71
+ @property
72
+ def index(self):
73
+ if self._index is None:
74
+ raise RuntimeError("Client not initialized. Call init().")
75
+ return self._index
76
+
77
+ @property
78
+ def es2(self):
79
+ if self._es2 is None:
80
+ raise RuntimeError("Client not initialized. Call init().")
81
+ return self._es2
82
+
@@ -0,0 +1,42 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from typing import List, Optional
5
+
6
+
7
+ @dataclass
8
+ class ConnectionConfig:
9
+ address: Optional[str] = None
10
+ host: Optional[str] = None
11
+ port: Optional[int] = None
12
+ access_token: Optional[str] = None
13
+
14
+
15
+ @dataclass
16
+ class KeyConfig:
17
+ key_path: str
18
+ key_id: str
19
+ preset: Optional[str] = None
20
+ eval_mode: Optional[str] = None
21
+ seal_mode: Optional[str] = None
22
+ seal_kek_path: Optional[str] = None
23
+
24
+
25
+ @dataclass
26
+ class IndexSettings:
27
+ index_name: str
28
+ dim: int
29
+ query_encryption: str = "plain" # plain | cipher
30
+ index_encryption: str = "cipher" # fixed to cipher
31
+ index_type: str = "flat"
32
+ output_fields: List[str] = field(default_factory=lambda: ["metadata"])
33
+ fetch_k: Optional[int] = None # over-fetch to support client-side filters
34
+
35
+
36
+ @dataclass
37
+ class EnvectorConfig:
38
+ connection: ConnectionConfig
39
+ key: KeyConfig
40
+ index: IndexSettings
41
+ create_if_missing: bool = True
42
+
File without changes
@@ -0,0 +1,20 @@
1
+ """Optional custom retriever wrapper.
2
+
3
+ Prefer using VectorStore.as_retriever, which returns LangChain's VectorStoreRetriever
4
+ when available. This module exists as an extension point if custom behavior is needed.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import Any, Dict, List, Optional
10
+
11
+ from .vectorstore import Envector, Document
12
+
13
+
14
+ class EnvectorRetriever:
15
+ def __init__(self, store: Envector, *, search_kwargs: Optional[Dict[str, Any]] = None) -> None:
16
+ self.store = store
17
+ self.search_kwargs = search_kwargs or {}
18
+
19
+ def get_relevant_documents(self, query: str) -> List[Document]:
20
+ return self.store.similarity_search(query, **self.search_kwargs)
@@ -0,0 +1,142 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Any, Callable, Dict, List, Optional, Protocol, Tuple, Union, overload
5
+
6
+
7
+ class Embeddings(Protocol):
8
+ """Minimal Embeddings protocol to avoid hard-coding a dependency on LangChain.
9
+
10
+ LangChain-compatible embeddings typically implement these two methods.
11
+ """
12
+
13
+ def embed_documents(self, texts: List[str]) -> List[List[float]]: # pragma: no cover - interface only
14
+ ...
15
+
16
+ def embed_query(self, text: str) -> List[float]: # pragma: no cover - interface only
17
+ ...
18
+
19
+
20
+ @dataclass
21
+ class SearchResult:
22
+ id: str
23
+ score: float
24
+ metadata: Dict[str, Any]
25
+
26
+
27
+ def pack_metadata(text: str, metadata: Optional[Dict[str, Any]] = None) -> str:
28
+ """Pack text and metadata into a single JSON string field accepted by ES2.
29
+
30
+ ES2 metadata API stores lists of strings; we store a single JSON blob per item.
31
+ Item-level IDs are not persisted/addressable.
32
+ """
33
+ import json
34
+
35
+ payload = {
36
+ "text": text,
37
+ "metadata": metadata or {},
38
+ }
39
+ return json.dumps(payload, ensure_ascii=False)
40
+
41
+
42
+ def unpack_metadata(raw: Any) -> Dict[str, Any]:
43
+ """Return metadata as a dict regardless of the raw payload type.
44
+
45
+ Recent ES2 versions may return decrypted metadata as a Python dict instead
46
+ of the JSON string we originally stored. We normalise the payload here so
47
+ downstream code always works with a dictionary.
48
+ """
49
+
50
+ import json
51
+
52
+ # Already a dict → nothing to do.
53
+ if isinstance(raw, dict):
54
+ return raw
55
+
56
+ print("slafjklshglkhslafhlksadjlghsal;hf")
57
+
58
+ # Some responses wrap the payload in a single-element list.
59
+ if isinstance(raw, (list, tuple)):
60
+ if len(raw) == 1:
61
+ return unpack_metadata(raw[0])
62
+ return {"_raw": list(raw)}
63
+
64
+ if raw is None:
65
+ return {"_raw": None}
66
+
67
+ # Decode bytes before attempting JSON parsing.
68
+ if isinstance(raw, (bytes, bytearray)):
69
+ try:
70
+ raw = raw.decode("utf-8")
71
+ except Exception:
72
+ return {"_raw": raw}
73
+
74
+ if isinstance(raw, str):
75
+ try:
76
+ data = json.loads(raw)
77
+ if isinstance(data, dict):
78
+ return data
79
+ except Exception:
80
+ # Some ES2 responses return Python-literal strings (single quotes).
81
+ try:
82
+ import ast
83
+
84
+ data = ast.literal_eval(raw)
85
+ if isinstance(data, dict):
86
+ return data
87
+ except Exception:
88
+ pass
89
+ return {"_raw": raw}
90
+
91
+ # Fallback: expose the raw object for debugging purposes.
92
+ return {"_raw": raw}
93
+
94
+
95
+ # --- Embeddings adaptation helpers -----------------------------------------------------
96
+
97
+ class _CallableEmbeddings:
98
+ def __init__(self, docs_fn: Callable[[List[str]], List[List[float]]], query_fn: Callable[[str], List[float]]):
99
+ self._docs_fn = docs_fn
100
+ self._query_fn = query_fn
101
+
102
+ def embed_documents(self, texts: List[str]) -> List[List[float]]:
103
+ return self._docs_fn(texts)
104
+
105
+ def embed_query(self, text: str) -> List[float]:
106
+ return self._query_fn(text)
107
+
108
+
109
+ def as_embeddings(emb: Any) -> Embeddings:
110
+ """Adapt various embedding providers into the Embeddings protocol.
111
+
112
+ Supported inputs:
113
+ - Object with `embed_documents` and `embed_query` (LangChain-style) — returned as-is.
114
+ - Object with `encode` supporting list[str] -> list[vec] and str -> vec — wrapped.
115
+ - Tuple(callable_docs, callable_query) — wrapped.
116
+ """
117
+ # Case 1: Already satisfies the protocol
118
+ if hasattr(emb, "embed_documents") and hasattr(emb, "embed_query"):
119
+ return emb # type: ignore[return-value]
120
+
121
+ # Case 2: Sentence-Transformers style `.encode()`
122
+ if hasattr(emb, "encode"):
123
+ encode = getattr(emb, "encode")
124
+
125
+ def docs_fn(texts: List[str]) -> List[List[float]]:
126
+ return list(encode(texts))
127
+
128
+ def query_fn(text: str) -> List[float]:
129
+ out = encode([text])
130
+ return list(out[0]) if isinstance(out, (list, tuple)) else list(out)
131
+
132
+ return _CallableEmbeddings(docs_fn, query_fn)
133
+
134
+ # Case 3: Tuple of callables
135
+ if isinstance(emb, tuple) and len(emb) == 2 and callable(emb[0]) and callable(emb[1]):
136
+ docs_fn, query_fn = emb # type: ignore[assignment]
137
+ return _CallableEmbeddings(docs_fn, query_fn)
138
+
139
+ raise TypeError(
140
+ "Unsupported embeddings provider. Provide an object with 'embed_documents'/'embed_query', "
141
+ "an object with 'encode', or a tuple of two callables (docs_fn, query_fn)."
142
+ )
@@ -0,0 +1,232 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from typing import Any, Dict, Iterable, List, Optional, Sequence
5
+ from uuid import uuid4
6
+
7
+ from .config import EnvectorConfig
8
+ from .client import EnvectorClient
9
+ from .types import Embeddings, as_embeddings, pack_metadata, unpack_metadata
10
+
11
+
12
+ def _try_import_langchain():
13
+ """Return (VectorStoreBase, DocumentClass) with safe fallbacks.
14
+
15
+ Ensures we always return a valid base class even if LangChain is missing.
16
+ """
17
+ VectorStoreBase: Any = object
18
+
19
+ try:
20
+ from langchain_core.documents import Document # type: ignore
21
+ except Exception: # pragma: no cover - optional dependency
22
+ # Minimal shim if LangChain is not installed
23
+ class Document: # type: ignore
24
+ def __init__(self, page_content: str, metadata: Optional[Dict[str, Any]] = None):
25
+ self.page_content = page_content
26
+ self.metadata = metadata or {}
27
+
28
+ try:
29
+ from langchain_core.vectorstores import VectorStore as _VectorStore # type: ignore
30
+ VectorStoreBase = _VectorStore
31
+ except Exception: # pragma: no cover - optional dependency
32
+ pass
33
+
34
+ return VectorStoreBase, Document
35
+
36
+
37
+ VectorStore, Document = _try_import_langchain()
38
+
39
+
40
+ class Envector(VectorStore): # type: ignore[misc]
41
+ """LangChain-compatible VectorStore adaptor for Envector (ES2).
42
+
43
+ This class wraps the high-level `es2` SDK. It does not use low-level
44
+ gRPC stubs or `es2.api.Indexer` directly.
45
+ """
46
+
47
+ def __init__(
48
+ self,
49
+ *,
50
+ config: EnvectorConfig,
51
+ embeddings: Optional[Embeddings] = None,
52
+ client: Optional[EnvectorClient] = None,
53
+ ) -> None:
54
+ self.config = config
55
+ self._embeddings = as_embeddings(embeddings) if embeddings is not None else None
56
+ self.client = client or EnvectorClient(config)
57
+ self.client.init()
58
+
59
+ # -------------------------------
60
+ # VectorStore API
61
+ # -------------------------------
62
+ def add_texts(
63
+ self,
64
+ texts: List[str],
65
+ metadatas: Optional[List[Dict[str, Any]]] = None,
66
+ ids: Optional[List[str]] = None,
67
+ *,
68
+ vectors: Optional[List[List[float]]] = None,
69
+ **kwargs: Any,
70
+ ) -> List[str]:
71
+ """Add texts to the encrypted index.
72
+
73
+ If embeddings are provided, the texts are embedded automatically.
74
+ Otherwise, provide pre-computed `vectors`.
75
+ """
76
+ if not texts:
77
+ return []
78
+
79
+ if metadatas is None:
80
+ metadatas = [{} for _ in texts]
81
+ if len(metadatas) != len(texts):
82
+ raise ValueError("texts and metadatas must have equal length")
83
+
84
+ if vectors is None:
85
+ if self._embeddings is None:
86
+ raise ValueError("embeddings is None and vectors not provided")
87
+ vectors = self._embeddings.embed_documents(texts)
88
+
89
+ # Prepare metadata JSON strings per item
90
+ packed = [pack_metadata(t, m) for t, m in zip(texts, metadatas)]
91
+
92
+ # Insert using high-level ES2 Index
93
+ self.client.index.insert(data=vectors, metadata=packed)
94
+
95
+ # Return ephemeral placeholders to satisfy VectorStore interface,
96
+ # but they are NOT persisted/addressable.
97
+ return [f"ephemeral-{uuid4()}" for _ in texts]
98
+
99
+ def similarity_search(
100
+ self,
101
+ query: str,
102
+ k: int = 4,
103
+ *,
104
+ filter: Optional[Dict[str, Any]] = None,
105
+ score_threshold: Optional[float] = None,
106
+ fetch_k: Optional[int] = None,
107
+ **kwargs: Any,
108
+ ) -> List[Document]:
109
+ """Search similar items for a text query.
110
+
111
+ - Embeds query if embeddings are provided; else expect `embedding` kwarg.
112
+ - Applies optional client-side filter and score threshold.
113
+ """
114
+ embedding: Optional[List[float]] = kwargs.get("embedding")
115
+ if embedding is None:
116
+ if self._embeddings is None:
117
+ raise ValueError("embeddings is None and no `embedding` provided")
118
+ embedding = self._embeddings.embed_query(query)
119
+
120
+ top_k = fetch_k or self.config.index.fetch_k or k
121
+
122
+ results = self.client.index.search(query=embedding, top_k=top_k, output_fields=self.config.index.output_fields)
123
+ # ES2 Index.search returns a list for each query; we passed single query
124
+ result = results[0] if isinstance(results, list) and results and isinstance(results[0], list) else results
125
+
126
+ docs = []
127
+ # Iterate from top-1 to top-k
128
+ for item in result:
129
+ # item = {"id": ..., "score": float, "metadata": [str] or {...}}
130
+ score = float(item.get("score", 0.0))
131
+ md_obj_raw = item.get("metadata")
132
+
133
+ # Metadata encryption/decryption is handled by the SDK.
134
+ # Envector currently supports a single associated data field (string).
135
+ # Convention: if the string is JSON like {"text": str, "metadata": {...}},
136
+ # we unpack it; otherwise, we treat the raw string as the document text.
137
+ md_obj = unpack_metadata(md_obj_raw)
138
+
139
+ text = md_obj.get("text", "") if "_raw" not in md_obj else md_obj["_raw"]
140
+ metadata = md_obj.get("metadata", {}) if "_raw" not in md_obj else {}
141
+
142
+ # client-side filter
143
+ if filter:
144
+ # simple dict-equality filter on top-level user metadata
145
+ matched = all(metadata.get(k) == v for k, v in filter.items())
146
+ if not matched:
147
+ continue
148
+ if score_threshold is not None and score < score_threshold:
149
+ continue
150
+
151
+ doc = Document(page_content=text, metadata={**metadata, "_score": score, "_id": item.get("id")})
152
+ docs.append(doc)
153
+
154
+ # Trim to k after filtering
155
+ return docs[:k]
156
+
157
+ # Vector-based variant required by some VectorStore interfaces
158
+ def similarity_search_by_vector(
159
+ self,
160
+ embedding: List[float],
161
+ k: int = 4,
162
+ *,
163
+ filter: Optional[Dict[str, Any]] = None,
164
+ score_threshold: Optional[float] = None,
165
+ fetch_k: Optional[int] = None,
166
+ **kwargs: Any,
167
+ ) -> List[Document]:
168
+ return self.similarity_search(
169
+ query="", # unused
170
+ k=k,
171
+ filter=filter,
172
+ score_threshold=score_threshold,
173
+ fetch_k=fetch_k,
174
+ embedding=embedding,
175
+ **kwargs,
176
+ )
177
+
178
+ # -------------------------------
179
+ # Class constructors (LangChain compatibility)
180
+ # -------------------------------
181
+ @classmethod
182
+ def from_texts(
183
+ cls,
184
+ texts: List[str],
185
+ metadatas: Optional[List[Dict[str, Any]]] = None,
186
+ *,
187
+ embeddings: Optional[Embeddings] = None,
188
+ ids: Optional[List[str]] = None,
189
+ **kwargs: Any,
190
+ ) -> "Envector": # type: ignore[override]
191
+ """Create a store from texts. Requires `config` in kwargs.
192
+
193
+ Example:
194
+ Envector.from_texts(texts, metadatas=..., embeddings=..., config=cfg)
195
+ """
196
+ config: Optional[EnvectorConfig] = kwargs.get("config") # type: ignore
197
+ client: Optional[EnvectorClient] = kwargs.get("client") # type: ignore
198
+ if config is None:
199
+ raise ValueError("`config` (EnvectorConfig) is required for from_texts().")
200
+ store = cls(config=config, embeddings=embeddings, client=client)
201
+ store.add_texts(texts=texts, metadatas=metadatas, ids=ids)
202
+ return store
203
+
204
+ @classmethod
205
+ def from_documents(
206
+ cls,
207
+ documents: List[Document],
208
+ *,
209
+ embeddings: Optional[Embeddings] = None,
210
+ **kwargs: Any,
211
+ ) -> "Envector": # type: ignore[override]
212
+ texts = [d.page_content for d in documents]
213
+ metadatas = [getattr(d, "metadata", {}) for d in documents]
214
+ return cls.from_texts(texts=texts, metadatas=metadatas, embeddings=embeddings, **kwargs)
215
+
216
+ # Optional: if LangChain is installed, this will be used; otherwise, users may call similarity_search directly.
217
+ def as_retriever(self, **kwargs: Any): # pragma: no cover - wrapper
218
+ try:
219
+ from langchain_core.vectorstores import VectorStoreRetriever # type: ignore
220
+
221
+ return VectorStoreRetriever(vectorstore=self, **kwargs)
222
+ except Exception:
223
+ # Minimal shim if VectorStoreRetriever is unavailable
224
+ class _Retriever:
225
+ def __init__(self, vs: Envector, search_kwargs: Optional[Dict[str, Any]] = None):
226
+ self.vs = vs
227
+ self.search_kwargs = search_kwargs or {}
228
+
229
+ def get_relevant_documents(self, query: str) -> List[Document]:
230
+ return self.vs.similarity_search(query, **self.search_kwargs)
231
+
232
+ return _Retriever(self, kwargs.get("search_kwargs"))
@@ -0,0 +1,73 @@
1
+ Metadata-Version: 2.4
2
+ Name: langchain-envector
3
+ Version: 0.1.0
4
+ Summary: LangChain VectorStore integration for Envector (ES2) encrypted vector search
5
+ Author: Envector Contributors
6
+ License: MIT
7
+ Project-URL: Homepage, https://example.com/
8
+ Project-URL: Repository, https://example.com/repo
9
+ Keywords: langchain,vectorstore,homomorphic-encryption,ckks,encrypted-search,envector,es2
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.9
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Intended Audience :: Developers
18
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
19
+ Requires-Python: <3.14,>=3.9
20
+ Description-Content-Type: text/markdown
21
+ Requires-Dist: es2==1.1.0rc1
22
+ Requires-Dist: langchain>=0.2.0
23
+
24
+ # LangChain Envector Integration
25
+
26
+ Encrypted vector search for LangChain using Envector (ES2), powered by homomorphic encryption (CKKS). This repo ships a LangChain-compatible VectorStore and retriever utilities built on the high-level `es2` Python SDK.
27
+
28
+ ## Features
29
+ - LangChain `VectorStore` interface with `similarity_search`, `from_texts`, etc.
30
+ - Optional `VectorStoreRetriever` helper for quick RAG integrations.
31
+ - Client-side encryption handled transparently by the SDK, including score thresholds and filtering.
32
+
33
+ ## Installation
34
+ - Python 3.9–3.13 (recommend 3.11)
35
+ - Create and activate a virtualenv:
36
+ - `python3.11 -m venv .venv && source .venv/bin/activate`
37
+ - Install runtime dependencies:
38
+ - `pip install -U pip setuptools wheel`
39
+ - `pip install es2==1.1.0rc1 langchain sentence-transformers`
40
+
41
+ ## Usage Overview
42
+ 1. Configure Envector using `EnvectorConfig`, pointing to your ES2 endpoint and keys.
43
+ 2. Initialize embeddings (or provide pre-computed vectors).
44
+ 3. Instantiate `Envector(config=cfg, embeddings=emb)` and call `add_texts` or `as_retriever`.
45
+ 4. Run `similarity_search` or plug the retriever into your LangChain pipeline.
46
+
47
+ > See `notebooks/` for end-to-end walkthroughs and the `libs/envector` package for implementation details.
48
+
49
+ ## Configuration
50
+ Key dataclasses live in `libs/envector/config.py`:
51
+ - `ConnectionConfig`: address or host/port for ES2.
52
+ - `KeyConfig`: key path, key ID, optional preset/eval mode.
53
+ - `IndexSettings`: index name, dimension (16–4096), query encryption mode, optional output fields and fetch parameters.
54
+ - `EnvectorConfig`: wraps the above and enables auto-creation via `create_if_missing`.
55
+
56
+ ## Data Model
57
+ - Each vector stores a single `metadata` string in ES2.
58
+ - To align with LangChain’s `Document`, inserts wrap data as JSON: `{"text": ..., "metadata": ...}`.
59
+ - Retrieval unwraps JSON, returning `Document(page_content=text, metadata={...})`.
60
+ - Client-side filtering requires the JSON envelope to include an object under `metadata`.
61
+
62
+ ## Limitations
63
+ - Item-level delete/update is unsupported (drop the index to reset).
64
+ - Manual item IDs are not accepted; returned IDs from `add_texts` are ephemeral.
65
+ - Filtering happens client-side; ensure metadata is JSON for structured filters.
66
+
67
+ ## Troubleshooting
68
+ - Connection issues: verify ES2 address and registered keys.
69
+ - Embeddings mismatch: ensure embedding dimension equals `index.dim` when supplying vectors.
70
+ - Unexpected raw strings: confirm inserts used the JSON envelope.
71
+
72
+ ## Contributing
73
+ See [`CONTRIBUTE.md`](CONTRIBUTE.md) for development, testing, and PR guidelines.
@@ -0,0 +1,11 @@
1
+ langchain_envector/__init__.py,sha256=9th8ylpoi-hopUC5cXtJtfH_ycol6_N5X82_NwPcltA,248
2
+ langchain_envector/client.py,sha256=8Y8CYBDnQ6-KMTat7q4qf94AXWi-SI_YeaqshgtajnI,2397
3
+ langchain_envector/config.py,sha256=d67OgSqYEQXKJIGI0PFxgAkiauTJ3G5UN29bWJZ7tCc,1000
4
+ langchain_envector/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ langchain_envector/retriever.py,sha256=Hx2OcyzTHSAGBRmBvnoddHtuXrqS0VTWGe2Q4JgxpVw,688
6
+ langchain_envector/types.py,sha256=HaedNy-MquIw4Zmyy1wgGWPVge3LjbxpwCRxAEpiJHk,4607
7
+ langchain_envector/vectorstore.py,sha256=hnxRBafefzmqBk10b_UdlD8DQ59JC3LQSpD5i3-d8ig,8813
8
+ langchain_envector-0.1.0.dist-info/METADATA,sha256=YNng8JP4Oxync2cITzF9CtEUHw-XlMvSh_HOTM-XPAc,3544
9
+ langchain_envector-0.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
10
+ langchain_envector-0.1.0.dist-info/top_level.txt,sha256=z87JZVH090LT8D8iNhPrBrTr94spsou5YscMWzTelYo,19
11
+ langchain_envector-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ langchain_envector