langchain-cyborgdb 0.1.0__tar.gz
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.
- langchain_cyborgdb-0.1.0/LICENSE +7 -0
- langchain_cyborgdb-0.1.0/PKG-INFO +96 -0
- langchain_cyborgdb-0.1.0/README.md +67 -0
- langchain_cyborgdb-0.1.0/langchain_cyborgdb/__init__.py +16 -0
- langchain_cyborgdb-0.1.0/langchain_cyborgdb.egg-info/PKG-INFO +96 -0
- langchain_cyborgdb-0.1.0/langchain_cyborgdb.egg-info/SOURCES.txt +11 -0
- langchain_cyborgdb-0.1.0/langchain_cyborgdb.egg-info/dependency_links.txt +1 -0
- langchain_cyborgdb-0.1.0/langchain_cyborgdb.egg-info/requires.txt +4 -0
- langchain_cyborgdb-0.1.0/langchain_cyborgdb.egg-info/top_level.txt +1 -0
- langchain_cyborgdb-0.1.0/pyproject.toml +38 -0
- langchain_cyborgdb-0.1.0/setup.cfg +4 -0
- langchain_cyborgdb-0.1.0/tests/test_functional.py +189 -0
- langchain_cyborgdb-0.1.0/tests/test_imports.py +26 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright 2025, Cyborg Inc.
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: langchain-cyborgdb
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: LangChain integration for CyborgDB: The Confidential Vector Database
|
|
5
|
+
Author: Cyborg Inc.
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://www.cyborg.co
|
|
8
|
+
Project-URL: Documentation, https://docs.cyborg.co/versions/latest/integrations/langchain/introduction
|
|
9
|
+
Project-URL: Repository, https://github.com/cyborginc/langchain-cyborgdb
|
|
10
|
+
Keywords: langchain,vectorstore,cyborgdb,encrypted,vector database
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Intended Audience :: Information Technology
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Database
|
|
20
|
+
Classifier: Topic :: Security :: Cryptography
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: cyborgdb-core[langchain]>=0.18.0
|
|
26
|
+
Provides-Extra: test
|
|
27
|
+
Requires-Dist: pytest; extra == "test"
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
|
|
30
|
+
# langchain-cyborgdb
|
|
31
|
+
|
|
32
|
+
LangChain integration for [CyborgDB](https://www.cyborg.co), the Confidential Vector Database. Provides `CyborgVectorStore`, a [LangChain](https://www.langchain.com/) `VectorStore` backed by CyborgDB's encrypted vector indexes.
|
|
33
|
+
|
|
34
|
+
This package is a thin wrapper around the integration that ships in [`cyborgdb-core`](https://pypi.org/project/cyborgdb-core/) — it re-exports `CyborgVectorStore`, `CyborgEmbeddings`, and `StorageConfig` under the standalone package name that LangChain's integration directory expects.
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pip install langchain-cyborgdb
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Quick Start
|
|
43
|
+
|
|
44
|
+
The example below uses OpenAI embeddings (`pip install langchain-openai`), but any LangChain `Embeddings` implementation works. You'll need a CyborgDB API key from [cyborg.co](https://www.cyborg.co).
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
from langchain_cyborgdb import CyborgVectorStore, StorageConfig
|
|
48
|
+
from langchain_openai import OpenAIEmbeddings
|
|
49
|
+
|
|
50
|
+
store = CyborgVectorStore.from_texts(
|
|
51
|
+
texts=["hello world", "goodbye world"],
|
|
52
|
+
embedding=OpenAIEmbeddings(),
|
|
53
|
+
index_key=CyborgVectorStore.generate_key(),
|
|
54
|
+
api_key="your-api-key",
|
|
55
|
+
storage_config=StorageConfig.disk("/tmp/cyborgdb-langchain"),
|
|
56
|
+
metric="cosine"
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
docs = store.similarity_search("hello")
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Key Features
|
|
63
|
+
|
|
64
|
+
- Full VectorStore API compatibility (`add_texts`, `similarity_search`, etc.)
|
|
65
|
+
- Async operations support
|
|
66
|
+
- Configurable distance metrics (`cosine`, `euclidean`, `squared_euclidean`)
|
|
67
|
+
- Document ID tracking and management
|
|
68
|
+
- Max marginal relevance search
|
|
69
|
+
- Factory methods (`from_texts`, `from_documents`) for quick setup
|
|
70
|
+
|
|
71
|
+
## Key Classes
|
|
72
|
+
|
|
73
|
+
### `CyborgVectorStore`
|
|
74
|
+
|
|
75
|
+
Implements the LangChain-compatible vector store interface. Supports:
|
|
76
|
+
|
|
77
|
+
- `.add_texts()` / `.add_documents()`
|
|
78
|
+
- `.similarity_search()` / `.similarity_search_with_score()`
|
|
79
|
+
- `.max_marginal_relevance_search()`
|
|
80
|
+
- `.get()` / `.list_ids()` / `.delete()`
|
|
81
|
+
- `.as_retriever()` for use in LangChain chains
|
|
82
|
+
- Async variants (`.aadd_texts()`, `.asimilarity_search()`, etc.)
|
|
83
|
+
|
|
84
|
+
### `StorageConfig`
|
|
85
|
+
|
|
86
|
+
Configuration object for defining where index data is stored, built with `StorageConfig.disk(path)` or `StorageConfig.s3(bucket, ...)`.
|
|
87
|
+
|
|
88
|
+
## Documentation
|
|
89
|
+
|
|
90
|
+
Full documentation, including metadata filtering and hybrid (BM25) search, lives at [docs.cyborg.co](https://docs.cyborg.co/versions/latest/integrations/langchain/introduction).
|
|
91
|
+
|
|
92
|
+
Using the CyborgDB client/server deployment instead of the embedded engine? The same integration is available via `pip install cyborgdb[langchain]` — see the [Deployment Models Guide](https://docs.cyborg.co/versions/latest/intro/deployment-models).
|
|
93
|
+
|
|
94
|
+
## License
|
|
95
|
+
|
|
96
|
+
This wrapper is MIT licensed. It depends on `cyborgdb-core`, which is distributed under its own [proprietary license](https://www.cyborg.co).
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# langchain-cyborgdb
|
|
2
|
+
|
|
3
|
+
LangChain integration for [CyborgDB](https://www.cyborg.co), the Confidential Vector Database. Provides `CyborgVectorStore`, a [LangChain](https://www.langchain.com/) `VectorStore` backed by CyborgDB's encrypted vector indexes.
|
|
4
|
+
|
|
5
|
+
This package is a thin wrapper around the integration that ships in [`cyborgdb-core`](https://pypi.org/project/cyborgdb-core/) — it re-exports `CyborgVectorStore`, `CyborgEmbeddings`, and `StorageConfig` under the standalone package name that LangChain's integration directory expects.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install langchain-cyborgdb
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
The example below uses OpenAI embeddings (`pip install langchain-openai`), but any LangChain `Embeddings` implementation works. You'll need a CyborgDB API key from [cyborg.co](https://www.cyborg.co).
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
from langchain_cyborgdb import CyborgVectorStore, StorageConfig
|
|
19
|
+
from langchain_openai import OpenAIEmbeddings
|
|
20
|
+
|
|
21
|
+
store = CyborgVectorStore.from_texts(
|
|
22
|
+
texts=["hello world", "goodbye world"],
|
|
23
|
+
embedding=OpenAIEmbeddings(),
|
|
24
|
+
index_key=CyborgVectorStore.generate_key(),
|
|
25
|
+
api_key="your-api-key",
|
|
26
|
+
storage_config=StorageConfig.disk("/tmp/cyborgdb-langchain"),
|
|
27
|
+
metric="cosine"
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
docs = store.similarity_search("hello")
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Key Features
|
|
34
|
+
|
|
35
|
+
- Full VectorStore API compatibility (`add_texts`, `similarity_search`, etc.)
|
|
36
|
+
- Async operations support
|
|
37
|
+
- Configurable distance metrics (`cosine`, `euclidean`, `squared_euclidean`)
|
|
38
|
+
- Document ID tracking and management
|
|
39
|
+
- Max marginal relevance search
|
|
40
|
+
- Factory methods (`from_texts`, `from_documents`) for quick setup
|
|
41
|
+
|
|
42
|
+
## Key Classes
|
|
43
|
+
|
|
44
|
+
### `CyborgVectorStore`
|
|
45
|
+
|
|
46
|
+
Implements the LangChain-compatible vector store interface. Supports:
|
|
47
|
+
|
|
48
|
+
- `.add_texts()` / `.add_documents()`
|
|
49
|
+
- `.similarity_search()` / `.similarity_search_with_score()`
|
|
50
|
+
- `.max_marginal_relevance_search()`
|
|
51
|
+
- `.get()` / `.list_ids()` / `.delete()`
|
|
52
|
+
- `.as_retriever()` for use in LangChain chains
|
|
53
|
+
- Async variants (`.aadd_texts()`, `.asimilarity_search()`, etc.)
|
|
54
|
+
|
|
55
|
+
### `StorageConfig`
|
|
56
|
+
|
|
57
|
+
Configuration object for defining where index data is stored, built with `StorageConfig.disk(path)` or `StorageConfig.s3(bucket, ...)`.
|
|
58
|
+
|
|
59
|
+
## Documentation
|
|
60
|
+
|
|
61
|
+
Full documentation, including metadata filtering and hybrid (BM25) search, lives at [docs.cyborg.co](https://docs.cyborg.co/versions/latest/integrations/langchain/introduction).
|
|
62
|
+
|
|
63
|
+
Using the CyborgDB client/server deployment instead of the embedded engine? The same integration is available via `pip install cyborgdb[langchain]` — see the [Deployment Models Guide](https://docs.cyborg.co/versions/latest/intro/deployment-models).
|
|
64
|
+
|
|
65
|
+
## License
|
|
66
|
+
|
|
67
|
+
This wrapper is MIT licensed. It depends on `cyborgdb-core`, which is distributed under its own [proprietary license](https://www.cyborg.co).
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""LangChain integration for CyborgDB.
|
|
2
|
+
|
|
3
|
+
This package is a thin wrapper around ``cyborgdb_core.integrations.langchain``,
|
|
4
|
+
published under the standalone name LangChain's integration directory expects.
|
|
5
|
+
All functionality lives in ``cyborgdb-core[langchain]``.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from cyborgdb_core.integrations.langchain import (
|
|
9
|
+
CyborgEmbeddings,
|
|
10
|
+
CyborgVectorStore,
|
|
11
|
+
StorageConfig,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
__version__ = "0.1.0"
|
|
15
|
+
|
|
16
|
+
__all__ = ["CyborgVectorStore", "CyborgEmbeddings", "StorageConfig"]
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: langchain-cyborgdb
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: LangChain integration for CyborgDB: The Confidential Vector Database
|
|
5
|
+
Author: Cyborg Inc.
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://www.cyborg.co
|
|
8
|
+
Project-URL: Documentation, https://docs.cyborg.co/versions/latest/integrations/langchain/introduction
|
|
9
|
+
Project-URL: Repository, https://github.com/cyborginc/langchain-cyborgdb
|
|
10
|
+
Keywords: langchain,vectorstore,cyborgdb,encrypted,vector database
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Intended Audience :: Information Technology
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Database
|
|
20
|
+
Classifier: Topic :: Security :: Cryptography
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: cyborgdb-core[langchain]>=0.18.0
|
|
26
|
+
Provides-Extra: test
|
|
27
|
+
Requires-Dist: pytest; extra == "test"
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
|
|
30
|
+
# langchain-cyborgdb
|
|
31
|
+
|
|
32
|
+
LangChain integration for [CyborgDB](https://www.cyborg.co), the Confidential Vector Database. Provides `CyborgVectorStore`, a [LangChain](https://www.langchain.com/) `VectorStore` backed by CyborgDB's encrypted vector indexes.
|
|
33
|
+
|
|
34
|
+
This package is a thin wrapper around the integration that ships in [`cyborgdb-core`](https://pypi.org/project/cyborgdb-core/) — it re-exports `CyborgVectorStore`, `CyborgEmbeddings`, and `StorageConfig` under the standalone package name that LangChain's integration directory expects.
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pip install langchain-cyborgdb
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Quick Start
|
|
43
|
+
|
|
44
|
+
The example below uses OpenAI embeddings (`pip install langchain-openai`), but any LangChain `Embeddings` implementation works. You'll need a CyborgDB API key from [cyborg.co](https://www.cyborg.co).
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
from langchain_cyborgdb import CyborgVectorStore, StorageConfig
|
|
48
|
+
from langchain_openai import OpenAIEmbeddings
|
|
49
|
+
|
|
50
|
+
store = CyborgVectorStore.from_texts(
|
|
51
|
+
texts=["hello world", "goodbye world"],
|
|
52
|
+
embedding=OpenAIEmbeddings(),
|
|
53
|
+
index_key=CyborgVectorStore.generate_key(),
|
|
54
|
+
api_key="your-api-key",
|
|
55
|
+
storage_config=StorageConfig.disk("/tmp/cyborgdb-langchain"),
|
|
56
|
+
metric="cosine"
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
docs = store.similarity_search("hello")
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Key Features
|
|
63
|
+
|
|
64
|
+
- Full VectorStore API compatibility (`add_texts`, `similarity_search`, etc.)
|
|
65
|
+
- Async operations support
|
|
66
|
+
- Configurable distance metrics (`cosine`, `euclidean`, `squared_euclidean`)
|
|
67
|
+
- Document ID tracking and management
|
|
68
|
+
- Max marginal relevance search
|
|
69
|
+
- Factory methods (`from_texts`, `from_documents`) for quick setup
|
|
70
|
+
|
|
71
|
+
## Key Classes
|
|
72
|
+
|
|
73
|
+
### `CyborgVectorStore`
|
|
74
|
+
|
|
75
|
+
Implements the LangChain-compatible vector store interface. Supports:
|
|
76
|
+
|
|
77
|
+
- `.add_texts()` / `.add_documents()`
|
|
78
|
+
- `.similarity_search()` / `.similarity_search_with_score()`
|
|
79
|
+
- `.max_marginal_relevance_search()`
|
|
80
|
+
- `.get()` / `.list_ids()` / `.delete()`
|
|
81
|
+
- `.as_retriever()` for use in LangChain chains
|
|
82
|
+
- Async variants (`.aadd_texts()`, `.asimilarity_search()`, etc.)
|
|
83
|
+
|
|
84
|
+
### `StorageConfig`
|
|
85
|
+
|
|
86
|
+
Configuration object for defining where index data is stored, built with `StorageConfig.disk(path)` or `StorageConfig.s3(bucket, ...)`.
|
|
87
|
+
|
|
88
|
+
## Documentation
|
|
89
|
+
|
|
90
|
+
Full documentation, including metadata filtering and hybrid (BM25) search, lives at [docs.cyborg.co](https://docs.cyborg.co/versions/latest/integrations/langchain/introduction).
|
|
91
|
+
|
|
92
|
+
Using the CyborgDB client/server deployment instead of the embedded engine? The same integration is available via `pip install cyborgdb[langchain]` — see the [Deployment Models Guide](https://docs.cyborg.co/versions/latest/intro/deployment-models).
|
|
93
|
+
|
|
94
|
+
## License
|
|
95
|
+
|
|
96
|
+
This wrapper is MIT licensed. It depends on `cyborgdb-core`, which is distributed under its own [proprietary license](https://www.cyborg.co).
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
langchain_cyborgdb/__init__.py
|
|
5
|
+
langchain_cyborgdb.egg-info/PKG-INFO
|
|
6
|
+
langchain_cyborgdb.egg-info/SOURCES.txt
|
|
7
|
+
langchain_cyborgdb.egg-info/dependency_links.txt
|
|
8
|
+
langchain_cyborgdb.egg-info/requires.txt
|
|
9
|
+
langchain_cyborgdb.egg-info/top_level.txt
|
|
10
|
+
tests/test_functional.py
|
|
11
|
+
tests/test_imports.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
langchain_cyborgdb
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "langchain-cyborgdb"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "LangChain integration for CyborgDB: The Confidential Vector Database"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">= 3.10"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
authors = [{ name = "Cyborg Inc." }]
|
|
13
|
+
keywords = ["langchain", "vectorstore", "cyborgdb", "encrypted", "vector database"]
|
|
14
|
+
dependencies = ["cyborgdb-core[langchain] >= 0.18.0"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"Intended Audience :: Information Technology",
|
|
18
|
+
"Operating System :: OS Independent",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Programming Language :: Python :: 3.10",
|
|
21
|
+
"Programming Language :: Python :: 3.11",
|
|
22
|
+
"Programming Language :: Python :: 3.12",
|
|
23
|
+
"Programming Language :: Python :: 3.13",
|
|
24
|
+
"Topic :: Database",
|
|
25
|
+
"Topic :: Security :: Cryptography",
|
|
26
|
+
"Topic :: Software Development :: Libraries",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
[project.urls]
|
|
30
|
+
"Homepage" = "https://www.cyborg.co"
|
|
31
|
+
"Documentation" = "https://docs.cyborg.co/versions/latest/integrations/langchain/introduction"
|
|
32
|
+
"Repository" = "https://github.com/cyborginc/langchain-cyborgdb"
|
|
33
|
+
|
|
34
|
+
[project.optional-dependencies]
|
|
35
|
+
test = ["pytest"]
|
|
36
|
+
|
|
37
|
+
[tool.setuptools.packages.find]
|
|
38
|
+
include = ["langchain_cyborgdb*"]
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"""Functional tests: the re-exported integration works end-to-end.
|
|
2
|
+
|
|
3
|
+
Adapted from cyborgdb-core's py_langchain_test.py, but importing everything
|
|
4
|
+
through ``langchain_cyborgdb`` — proving the wrapper exposes a working
|
|
5
|
+
integration, not just importable names.
|
|
6
|
+
|
|
7
|
+
Uses DeterministicFakeEmbedding (identical text -> identical vector), so
|
|
8
|
+
exact-text queries must return that text as the top hit and no embedding
|
|
9
|
+
model download or OpenAI key is needed. Semantic-quality tests (synonym /
|
|
10
|
+
paraphrase search) stay in cyborgdb-core where the real models live.
|
|
11
|
+
|
|
12
|
+
cyborgdb-core validates the CyborgDB API key against Cyborg's backend, so
|
|
13
|
+
the whole module is skipped unless CYBORGDB_API_KEY is set.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import os
|
|
17
|
+
import uuid
|
|
18
|
+
|
|
19
|
+
import pytest
|
|
20
|
+
from langchain_core.documents import Document
|
|
21
|
+
from langchain_core.embeddings import DeterministicFakeEmbedding
|
|
22
|
+
|
|
23
|
+
from langchain_cyborgdb import CyborgVectorStore, StorageConfig
|
|
24
|
+
|
|
25
|
+
pytestmark = pytest.mark.skipif(
|
|
26
|
+
not os.environ.get("CYBORGDB_API_KEY"),
|
|
27
|
+
reason="CYBORGDB_API_KEY not set; functional tests need a real key",
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
EMBEDDING = DeterministicFakeEmbedding(size=128)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@pytest.fixture
|
|
34
|
+
def make_store(tmp_path):
|
|
35
|
+
"""Build stores with unique index names; delete their indexes afterward."""
|
|
36
|
+
stores = []
|
|
37
|
+
|
|
38
|
+
def _make(texts=None, metadatas=None, ids=None, documents=None, **overrides):
|
|
39
|
+
kwargs = dict(
|
|
40
|
+
embedding=EMBEDDING,
|
|
41
|
+
index_name=f"lc_wrapper_{uuid.uuid4().hex[:12]}",
|
|
42
|
+
index_key=CyborgVectorStore.generate_key(),
|
|
43
|
+
api_key=os.environ["CYBORGDB_API_KEY"],
|
|
44
|
+
storage_config=StorageConfig.disk(str(tmp_path)),
|
|
45
|
+
metric="cosine",
|
|
46
|
+
)
|
|
47
|
+
kwargs.update(overrides)
|
|
48
|
+
if documents is not None:
|
|
49
|
+
store = CyborgVectorStore.from_documents(documents=documents, **kwargs)
|
|
50
|
+
elif texts is not None:
|
|
51
|
+
store = CyborgVectorStore.from_texts(
|
|
52
|
+
texts=texts, metadatas=metadatas, ids=ids, **kwargs
|
|
53
|
+
)
|
|
54
|
+
else:
|
|
55
|
+
store = CyborgVectorStore(**kwargs)
|
|
56
|
+
stores.append(store)
|
|
57
|
+
return store
|
|
58
|
+
|
|
59
|
+
yield _make
|
|
60
|
+
|
|
61
|
+
for store in stores:
|
|
62
|
+
try:
|
|
63
|
+
store.delete(delete_index=True)
|
|
64
|
+
except Exception:
|
|
65
|
+
pass
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def test_quickstart_flow(make_store):
|
|
69
|
+
"""The docs quickstart shape: from_texts -> similarity_search."""
|
|
70
|
+
store = make_store(texts=["hello world", "goodbye world"])
|
|
71
|
+
|
|
72
|
+
docs = store.similarity_search("hello world", k=2)
|
|
73
|
+
|
|
74
|
+
assert len(docs) == 2
|
|
75
|
+
assert docs[0].page_content == "hello world"
|
|
76
|
+
assert {doc.page_content for doc in docs} == {"hello world", "goodbye world"}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def test_search_methods_return_contents_and_metadata(make_store):
|
|
80
|
+
texts = ["cat on a mat", "dog in a fog", "bird on a wire", "fish in a dish"]
|
|
81
|
+
metadatas = [{"animal": text.split()[0], "idx": i} for i, text in enumerate(texts)]
|
|
82
|
+
expected = dict(zip(texts, metadatas))
|
|
83
|
+
store = make_store(texts=texts, metadatas=metadatas)
|
|
84
|
+
|
|
85
|
+
query = "cat on a mat"
|
|
86
|
+
searches = {
|
|
87
|
+
"similarity_search": store.similarity_search(query, k=4),
|
|
88
|
+
"similarity_search_with_score": [
|
|
89
|
+
doc for doc, _ in store.similarity_search_with_score(query, k=4)
|
|
90
|
+
],
|
|
91
|
+
"similarity_search_by_vector": store.similarity_search_by_vector(
|
|
92
|
+
EMBEDDING.embed_query(query), k=4
|
|
93
|
+
),
|
|
94
|
+
}
|
|
95
|
+
for name, docs in searches.items():
|
|
96
|
+
assert len(docs) == len(texts), name
|
|
97
|
+
for doc in docs:
|
|
98
|
+
assert doc.page_content in expected, name
|
|
99
|
+
assert doc.metadata == expected[doc.page_content], name
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def test_metadata_filtering(make_store):
|
|
103
|
+
texts = [f"Doc {i}" for i in range(10)]
|
|
104
|
+
metadatas = [
|
|
105
|
+
{"owner": {"name": "Jane" if i % 2 == 0 else "John"}} for i in range(10)
|
|
106
|
+
]
|
|
107
|
+
store = make_store(texts=texts, metadatas=metadatas)
|
|
108
|
+
|
|
109
|
+
results = store.similarity_search(
|
|
110
|
+
"Doc 0", k=10, filter={"owner.name": {"$eq": "Jane"}}
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
assert results
|
|
114
|
+
assert all(doc.metadata["owner"]["name"] == "Jane" for doc in results)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def test_delete_documents(make_store):
|
|
118
|
+
texts = [f"Delete Me {i}" for i in range(5)]
|
|
119
|
+
store = make_store()
|
|
120
|
+
ids = store.add_texts(texts, metadatas=[{"n": i} for i in range(5)])
|
|
121
|
+
assert len(ids) == 5
|
|
122
|
+
|
|
123
|
+
store.delete(ids=[ids[1], ids[3]])
|
|
124
|
+
|
|
125
|
+
remaining = store.similarity_search("Delete Me 0", k=5)
|
|
126
|
+
remaining_ns = {doc.metadata["n"] for doc in remaining}
|
|
127
|
+
assert remaining_ns == {0, 2, 4}
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def test_mmr_search(make_store):
|
|
131
|
+
texts = [f"topic {i} foxes and dogs" for i in range(10)]
|
|
132
|
+
store = make_store(
|
|
133
|
+
texts=texts, metadatas=[{"category": f"group_{i % 3}"} for i in range(10)]
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
results = store.max_marginal_relevance_search(
|
|
137
|
+
"topic 1 foxes and dogs", k=3, fetch_k=6, lambda_mult=0.5
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
assert len(results) == 3
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def test_from_documents(make_store):
|
|
144
|
+
documents = [
|
|
145
|
+
Document(page_content=f"LangChain doc {i}", metadata={"category": "test"})
|
|
146
|
+
for i in range(10)
|
|
147
|
+
]
|
|
148
|
+
store = make_store(documents=documents)
|
|
149
|
+
|
|
150
|
+
results = store.similarity_search("LangChain doc 5", k=2)
|
|
151
|
+
|
|
152
|
+
assert results
|
|
153
|
+
assert results[0].page_content == "LangChain doc 5"
|
|
154
|
+
assert results[0].metadata == {"category": "test"}
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def test_list_ids_get_and_upsert(make_store):
|
|
158
|
+
texts = ["alpha text", "beta text", "gamma text"]
|
|
159
|
+
ids = ["doc_001", "doc_002", "doc_003"]
|
|
160
|
+
store = make_store()
|
|
161
|
+
store.add_texts(texts, [{"pos": i} for i in range(3)], ids=ids)
|
|
162
|
+
|
|
163
|
+
assert sorted(store.list_ids()) == ids
|
|
164
|
+
|
|
165
|
+
doc = store.get_document("doc_002")
|
|
166
|
+
assert doc is not None
|
|
167
|
+
assert doc.page_content == "beta text"
|
|
168
|
+
assert doc.metadata == {"pos": 1}
|
|
169
|
+
|
|
170
|
+
docs = store.get_documents(["doc_001", "doc_003", "doc_999"])
|
|
171
|
+
assert len(docs) == 3
|
|
172
|
+
assert docs[0] is not None and docs[1] is not None
|
|
173
|
+
assert docs[2] is None
|
|
174
|
+
|
|
175
|
+
# Re-adding an existing ID upserts rather than duplicating.
|
|
176
|
+
store.add_texts(["alpha text updated"], ids=["doc_001"])
|
|
177
|
+
assert len(store.list_ids()) == 3
|
|
178
|
+
assert store.get_document("doc_001").page_content == "alpha text updated"
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def test_as_retriever(make_store):
|
|
182
|
+
texts = ["red apple", "green pear", "blue sky"]
|
|
183
|
+
store = make_store(texts=texts)
|
|
184
|
+
|
|
185
|
+
retriever = store.as_retriever(search_kwargs={"k": 2})
|
|
186
|
+
docs = retriever.invoke("red apple")
|
|
187
|
+
|
|
188
|
+
assert len(docs) == 2
|
|
189
|
+
assert docs[0].page_content == "red apple"
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""Smoke tests: the package installs and the public API is importable.
|
|
2
|
+
|
|
3
|
+
These mirror the acceptance criteria on cyborginc/cyborgdb-core#2719 —
|
|
4
|
+
`from langchain_cyborgdb import CyborgVectorStore, StorageConfig` must work
|
|
5
|
+
in a clean environment against cyborgdb-core 0.18.x.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from langchain_core.vectorstores import VectorStore
|
|
9
|
+
|
|
10
|
+
import langchain_cyborgdb
|
|
11
|
+
from langchain_cyborgdb import CyborgEmbeddings, CyborgVectorStore, StorageConfig
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_cyborg_vector_store_is_a_langchain_vectorstore():
|
|
15
|
+
assert issubclass(CyborgVectorStore, VectorStore)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def test_storage_config_factories_exist():
|
|
19
|
+
assert callable(StorageConfig.disk)
|
|
20
|
+
assert callable(StorageConfig.s3)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def test_public_api_matches_all():
|
|
24
|
+
for name in langchain_cyborgdb.__all__:
|
|
25
|
+
assert getattr(langchain_cyborgdb, name) is not None
|
|
26
|
+
assert CyborgEmbeddings is not None
|