vectorizer-sdk 3.2.0__tar.gz → 3.5.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.
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/PKG-INFO +241 -18
- vectorizer_sdk-3.2.0/vectorizer_sdk.egg-info/PKG-INFO → vectorizer_sdk-3.5.0/README.md +227 -54
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/pyproject.toml +16 -17
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/rpc/__init__.py +80 -1
- vectorizer_sdk-3.5.0/rpc/commands.py +2245 -0
- vectorizer_sdk-3.5.0/tests/test_admin_phase12.py +256 -0
- vectorizer_sdk-3.5.0/tests/test_auth_phase12.py +209 -0
- vectorizer_sdk-3.5.0/tests/test_cluster_auth_admin.py +532 -0
- vectorizer_sdk-3.5.0/tests/test_discovery_phase12.py +192 -0
- vectorizer_sdk-3.5.0/tests/test_filter.py +238 -0
- vectorizer_sdk-3.5.0/tests/test_hub.py +226 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/tests/test_mock_transport.py +7 -1
- vectorizer_sdk-3.5.0/tests/test_replication.py +120 -0
- vectorizer_sdk-3.5.0/tests/test_rpc_phase16.py +636 -0
- vectorizer_sdk-3.5.0/tests/test_runtime_metrics.py +151 -0
- vectorizer_sdk-3.5.0/tests/test_schema_evolution.py +496 -0
- vectorizer_sdk-3.5.0/tests/test_search_phase12.py +57 -0
- vectorizer_sdk-3.5.0/tests/test_tier_control.py +406 -0
- vectorizer_sdk-3.5.0/tests/test_tier_demotion.py +194 -0
- vectorizer_sdk-3.5.0/tests/test_vectors_phase12.py +251 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/utils/http_client.py +5 -1
- vectorizer_sdk-3.5.0/vectorizer/__init__.py +169 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/vectorizer/_base.py +7 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/vectorizer/admin.py +312 -6
- vectorizer_sdk-3.5.0/vectorizer/auth.py +414 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/vectorizer/client.py +12 -0
- vectorizer_sdk-3.5.0/vectorizer/collections.py +457 -0
- vectorizer_sdk-3.5.0/vectorizer/discovery.py +179 -0
- vectorizer_sdk-3.5.0/vectorizer/filter.py +258 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/vectorizer/graph.py +7 -7
- vectorizer_sdk-3.5.0/vectorizer/hub.py +244 -0
- vectorizer_sdk-3.5.0/vectorizer/replication.py +180 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/vectorizer/search.py +74 -2
- vectorizer_sdk-3.5.0/vectorizer/vectors.py +939 -0
- vectorizer_sdk-3.2.0/README.md → vectorizer_sdk-3.5.0/vectorizer_sdk.egg-info/PKG-INFO +277 -3
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/vectorizer_sdk.egg-info/SOURCES.txt +18 -0
- vectorizer_sdk-3.5.0/vectorizer_sdk.egg-info/requires.txt +26 -0
- vectorizer_sdk-3.2.0/rpc/commands.py +0 -210
- vectorizer_sdk-3.2.0/vectorizer/__init__.py +0 -58
- vectorizer_sdk-3.2.0/vectorizer/auth.py +0 -75
- vectorizer_sdk-3.2.0/vectorizer/collections.py +0 -227
- vectorizer_sdk-3.2.0/vectorizer/vectors.py +0 -418
- vectorizer_sdk-3.2.0/vectorizer_sdk.egg-info/requires.txt +0 -26
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/LICENSE +0 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/rpc/_codec.py +0 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/rpc/async_client.py +0 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/rpc/endpoint.py +0 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/rpc/pool.py +0 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/rpc/sync_client.py +0 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/rpc/types.py +0 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/setup.cfg +0 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/tests/test_client_integration.py +0 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/tests/test_discovery.py +0 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/tests/test_exceptions.py +0 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/tests/test_file_operations.py +0 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/tests/test_file_upload.py +0 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/tests/test_graph.py +0 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/tests/test_http_client.py +0 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/tests/test_intelligent_search.py +0 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/tests/test_models.py +0 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/tests/test_qdrant_advanced.py +0 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/tests/test_retry_after_parse.py +0 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/tests/test_routing.py +0 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/tests/test_sdk_comprehensive.py +0 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/tests/test_simple.py +0 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/tests/test_umicp.py +0 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/tests/test_validation.py +0 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/utils/__init__.py +0 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/utils/transport.py +0 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/utils/umicp_client.py +0 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/utils/validation.py +0 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/vectorizer_sdk.egg-info/dependency_links.txt +0 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/vectorizer_sdk.egg-info/entry_points.txt +0 -0
- {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/vectorizer_sdk.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: vectorizer_sdk
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.5.0
|
|
4
4
|
Summary: Python SDK for Vectorizer - Semantic search, vector operations, and the VectorizerRPC binary transport (default in v3.x)
|
|
5
5
|
Author-email: HiveLLM Team <team@hivellm.org>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -13,40 +13,39 @@ Classifier: Development Status :: 5 - Production/Stable
|
|
|
13
13
|
Classifier: Intended Audience :: Developers
|
|
14
14
|
Classifier: Operating System :: OS Independent
|
|
15
15
|
Classifier: Programming Language :: Python :: 3
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
18
16
|
Classifier: Programming Language :: Python :: 3.10
|
|
19
17
|
Classifier: Programming Language :: Python :: 3.11
|
|
20
18
|
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
20
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
21
|
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
23
22
|
Classifier: Topic :: Text Processing :: Indexing
|
|
24
23
|
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
|
25
|
-
Requires-Python: >=3.
|
|
24
|
+
Requires-Python: >=3.10
|
|
26
25
|
Description-Content-Type: text/markdown
|
|
27
26
|
License-File: LICENSE
|
|
28
|
-
Requires-Dist: aiohttp>=3.10.
|
|
29
|
-
Requires-Dist: msgpack>=1.1.
|
|
27
|
+
Requires-Dist: aiohttp>=3.10.11
|
|
28
|
+
Requires-Dist: msgpack>=1.1.1
|
|
30
29
|
Provides-Extra: umicp
|
|
31
30
|
Requires-Dist: umicp-python>=0.1.3; extra == "umicp"
|
|
32
31
|
Provides-Extra: dev
|
|
33
|
-
Requires-Dist: pytest>=8.
|
|
32
|
+
Requires-Dist: pytest>=8.3.5; extra == "dev"
|
|
34
33
|
Requires-Dist: pytest-asyncio>=0.24.0; extra == "dev"
|
|
35
34
|
Requires-Dist: pytest-cov>=5.0.0; extra == "dev"
|
|
36
35
|
Requires-Dist: black>=25.0.0; extra == "dev"
|
|
37
|
-
Requires-Dist: isort>=5.13.
|
|
38
|
-
Requires-Dist: flake8>=7.
|
|
39
|
-
Requires-Dist: mypy>=1.
|
|
36
|
+
Requires-Dist: isort>=5.13.2; extra == "dev"
|
|
37
|
+
Requires-Dist: flake8>=7.1.2; extra == "dev"
|
|
38
|
+
Requires-Dist: mypy>=1.14.1; extra == "dev"
|
|
40
39
|
Requires-Dist: pre-commit>=4.0.0; extra == "dev"
|
|
41
40
|
Provides-Extra: docs
|
|
42
|
-
Requires-Dist: sphinx>=7.
|
|
43
|
-
Requires-Dist: sphinx-rtd-theme>=
|
|
44
|
-
Requires-Dist: myst-parser>=3.0.
|
|
41
|
+
Requires-Dist: sphinx>=7.1.2; extra == "docs"
|
|
42
|
+
Requires-Dist: sphinx-rtd-theme>=3.1.0; extra == "docs"
|
|
43
|
+
Requires-Dist: myst-parser>=3.0.1; extra == "docs"
|
|
45
44
|
Provides-Extra: test
|
|
46
|
-
Requires-Dist: pytest>=8.
|
|
45
|
+
Requires-Dist: pytest>=8.3.5; extra == "test"
|
|
47
46
|
Requires-Dist: pytest-asyncio>=0.24.0; extra == "test"
|
|
48
47
|
Requires-Dist: pytest-cov>=5.0.0; extra == "test"
|
|
49
|
-
Requires-Dist: httpx>=0.
|
|
48
|
+
Requires-Dist: httpx>=0.28.1; extra == "test"
|
|
50
49
|
Dynamic: license-file
|
|
51
50
|
|
|
52
51
|
# Vectorizer Python SDK
|
|
@@ -58,9 +57,18 @@ Dynamic: license-file
|
|
|
58
57
|
A comprehensive Python SDK for the Vectorizer semantic search service.
|
|
59
58
|
|
|
60
59
|
**Package**: `vectorizer_sdk` (PEP 625 compliant)
|
|
61
|
-
**Version**: 3.
|
|
60
|
+
**Version**: 3.5.0
|
|
62
61
|
**PyPI**: https://pypi.org/project/vectorizer-sdk/
|
|
63
62
|
|
|
63
|
+
## v3.5 — server alignment (no client API changes)
|
|
64
|
+
|
|
65
|
+
Version tracks the Vectorizer **3.5.0** server release: non-blocking
|
|
66
|
+
search during batch inserts, PQ/Binary quantization wiring, SIMD
|
|
67
|
+
quantize kernels, BM25-after-restart and WAL-durability fixes, and a
|
|
68
|
+
security/dependency refresh. All server-internal — the client API is
|
|
69
|
+
unchanged since **v3.3** (REST control-surface parity + dashboard
|
|
70
|
+
metrics). See `CHANGELOG.md` for the full method surface.
|
|
71
|
+
|
|
64
72
|
## v3.2 — backpressure-aware client (HTTP 429 + `Retry-After`)
|
|
65
73
|
|
|
66
74
|
The REST `VectorizerClient` honors server-side bulk-upsert
|
|
@@ -171,7 +179,7 @@ for a runnable end-to-end example.
|
|
|
171
179
|
pip install vectorizer-sdk
|
|
172
180
|
|
|
173
181
|
# Or specific version
|
|
174
|
-
pip install vectorizer-sdk==3.
|
|
182
|
+
pip install vectorizer-sdk==3.5.0
|
|
175
183
|
```
|
|
176
184
|
|
|
177
185
|
## Package Layout (v3.x)
|
|
@@ -714,7 +722,16 @@ await client.insert_texts("documents", [
|
|
|
714
722
|
await client.insert_texts("documents", [
|
|
715
723
|
{"id": "doc1", "text": "Sample document (updated)", "metadata": {"updated": True}}
|
|
716
724
|
])
|
|
717
|
-
await client.delete_vectors("documents", ["doc1"])
|
|
725
|
+
report = await client.delete_vectors("documents", ["doc1"])
|
|
726
|
+
print(f"deleted={report.deleted} failed={report.failed}")
|
|
727
|
+
|
|
728
|
+
# Tier demotion: move vectors between collections without re-embedding
|
|
729
|
+
# (issue #265). Insert into dst lands BEFORE delete from src so a
|
|
730
|
+
# mid-batch crash leaves a recoverable duplicate, never data loss.
|
|
731
|
+
mv = await client.move_to_collection("hot", "warm", ["vec-1", "vec-2"])
|
|
732
|
+
for row in mv.results:
|
|
733
|
+
if row.status != "ok":
|
|
734
|
+
print(f"move failed id={row.id!r} status={row.status} err={row.error!r}")
|
|
718
735
|
|
|
719
736
|
# Reads automatically go to replicas (load balanced)
|
|
720
737
|
results = await client.search_vectors("documents", query="sample", limit=10)
|
|
@@ -722,6 +739,212 @@ collections = await client.list_collections()
|
|
|
722
739
|
vector = await client.get_vector("documents", "doc1")
|
|
723
740
|
```
|
|
724
741
|
|
|
742
|
+
## Control surface (3.4)
|
|
743
|
+
|
|
744
|
+
### Admin / observability
|
|
745
|
+
|
|
746
|
+
```python
|
|
747
|
+
import asyncio
|
|
748
|
+
from vectorizer_sdk import VectorizerClient
|
|
749
|
+
|
|
750
|
+
async def main():
|
|
751
|
+
client = VectorizerClient(base_url="http://localhost:15002")
|
|
752
|
+
|
|
753
|
+
# Server health, uptime, collection/vector counts
|
|
754
|
+
stats = await client.get_stats()
|
|
755
|
+
print(f"Total vectors: {stats['total_vectors']}")
|
|
756
|
+
|
|
757
|
+
status = await client.get_status()
|
|
758
|
+
print(f"Server v{status['version']}, uptime: {status['uptime']}s")
|
|
759
|
+
|
|
760
|
+
# Recent logs
|
|
761
|
+
logs = await client.get_logs(lines=50, level="INFO")
|
|
762
|
+
for entry in logs:
|
|
763
|
+
print(f"{entry['timestamp']}: {entry['message']}")
|
|
764
|
+
|
|
765
|
+
# Per-collection indexing progress
|
|
766
|
+
progress = await client.get_indexing_progress()
|
|
767
|
+
for collection, pct in progress.items():
|
|
768
|
+
print(f"{collection}: {pct:.1f}% complete")
|
|
769
|
+
|
|
770
|
+
# Force flush one collection
|
|
771
|
+
await client.force_save_collection("my_docs")
|
|
772
|
+
|
|
773
|
+
# List and clean empty collections
|
|
774
|
+
empty = await client.list_empty_collections()
|
|
775
|
+
if empty:
|
|
776
|
+
report = await client.cleanup_empty_collections()
|
|
777
|
+
print(f"Cleaned up {report['deleted']} empty collections")
|
|
778
|
+
|
|
779
|
+
# List workspaces
|
|
780
|
+
workspaces = await client.list_workspaces()
|
|
781
|
+
print(f"Workspaces: {workspaces}")
|
|
782
|
+
|
|
783
|
+
asyncio.run(main())
|
|
784
|
+
```
|
|
785
|
+
|
|
786
|
+
### Auth
|
|
787
|
+
|
|
788
|
+
```python
|
|
789
|
+
import asyncio
|
|
790
|
+
from vectorizer_sdk import VectorizerClient
|
|
791
|
+
|
|
792
|
+
async def main():
|
|
793
|
+
client = VectorizerClient(base_url="http://localhost:15002")
|
|
794
|
+
|
|
795
|
+
# Current user info
|
|
796
|
+
me = await client.me()
|
|
797
|
+
print(f"Logged in as: {me['username']} (roles: {', '.join(me['roles'])})")
|
|
798
|
+
|
|
799
|
+
# Refresh token with extended TTL
|
|
800
|
+
token = await client.refresh_token()
|
|
801
|
+
print(f"Token refreshed, expires in: {token['expires_in']} seconds")
|
|
802
|
+
|
|
803
|
+
# Validate password before creating account
|
|
804
|
+
report = await client.validate_password("MySecure123!")
|
|
805
|
+
print(f"Valid: {report['valid']}, feedback: {', '.join(report['feedback'])}")
|
|
806
|
+
|
|
807
|
+
# Create API key for programmatic access
|
|
808
|
+
api_key = await client.create_api_key(
|
|
809
|
+
name="integration-key",
|
|
810
|
+
expires_in=86400 * 365 # 1 year
|
|
811
|
+
)
|
|
812
|
+
print(f"API Key: {api_key['api_key']}")
|
|
813
|
+
|
|
814
|
+
# List and revoke API keys
|
|
815
|
+
keys = await client.list_api_keys()
|
|
816
|
+
for key in keys:
|
|
817
|
+
print(f"Key: {key['id']} (expires: {key['expires_at']})")
|
|
818
|
+
await client.revoke_api_key(keys[0]['id'])
|
|
819
|
+
|
|
820
|
+
# Change password
|
|
821
|
+
await client.change_password("newPassword123!")
|
|
822
|
+
|
|
823
|
+
# Logout
|
|
824
|
+
await client.logout()
|
|
825
|
+
|
|
826
|
+
asyncio.run(main())
|
|
827
|
+
```
|
|
828
|
+
|
|
829
|
+
### Replication
|
|
830
|
+
|
|
831
|
+
```python
|
|
832
|
+
import asyncio
|
|
833
|
+
from vectorizer_sdk import VectorizerClient
|
|
834
|
+
|
|
835
|
+
async def main():
|
|
836
|
+
client = VectorizerClient(base_url="http://localhost:15002")
|
|
837
|
+
|
|
838
|
+
# Check replication role and status
|
|
839
|
+
status = await client.get_replication_status()
|
|
840
|
+
print(f"Role: {status['role']}, enabled: {status['enabled']}")
|
|
841
|
+
|
|
842
|
+
# Get replication statistics (lag, bytes synced)
|
|
843
|
+
stats = await client.get_replication_stats()
|
|
844
|
+
print(f"Bytes synced: {stats['bytes_synced']}")
|
|
845
|
+
|
|
846
|
+
# List all replicas connected to this master
|
|
847
|
+
replicas = await client.list_replicas()
|
|
848
|
+
for replica in replicas:
|
|
849
|
+
print(f"Replica: {replica['address']} (lag: {replica['lag_ms']}ms)")
|
|
850
|
+
|
|
851
|
+
asyncio.run(main())
|
|
852
|
+
```
|
|
853
|
+
|
|
854
|
+
### Discovery pipeline
|
|
855
|
+
|
|
856
|
+
The discovery pipeline chains six stages from broad search to final LLM-ready prompt:
|
|
857
|
+
|
|
858
|
+
```python
|
|
859
|
+
import asyncio
|
|
860
|
+
from vectorizer_sdk import VectorizerClient
|
|
861
|
+
|
|
862
|
+
async def main():
|
|
863
|
+
client = VectorizerClient(base_url="http://localhost:15002")
|
|
864
|
+
|
|
865
|
+
# Stage 1: Broad discovery — multi-query search across all collections
|
|
866
|
+
broad = await client.broad_discovery(
|
|
867
|
+
query="machine learning algorithms",
|
|
868
|
+
max_results=20
|
|
869
|
+
)
|
|
870
|
+
print(f"Found {len(broad['results'])} broad results")
|
|
871
|
+
|
|
872
|
+
# Stage 2: Semantic focus — narrow search to top collection
|
|
873
|
+
focused = await client.semantic_focus(
|
|
874
|
+
query="neural networks",
|
|
875
|
+
collection="research",
|
|
876
|
+
max_results=10
|
|
877
|
+
)
|
|
878
|
+
print(f"Focused results: {len(focused['results'])}")
|
|
879
|
+
|
|
880
|
+
# Stage 3: Promote README — elevate high-quality chunks
|
|
881
|
+
promoted = await client.promote_readme(
|
|
882
|
+
results=focused['results'],
|
|
883
|
+
readme_boost=2.0
|
|
884
|
+
)
|
|
885
|
+
|
|
886
|
+
# Stage 4: Compress evidence — distill to bullet points
|
|
887
|
+
bullets = await client.compress_evidence(
|
|
888
|
+
chunks=promoted['results'],
|
|
889
|
+
max_bullets=15
|
|
890
|
+
)
|
|
891
|
+
print(f"Evidence bullets: {bullets['bullets']}")
|
|
892
|
+
|
|
893
|
+
# Stage 5: Build answer plan — organize bullets into sections
|
|
894
|
+
plan = await client.build_answer_plan(
|
|
895
|
+
evidence=bullets['bullets'],
|
|
896
|
+
max_sections=5
|
|
897
|
+
)
|
|
898
|
+
print(f"Sections: {plan['sections']}")
|
|
899
|
+
|
|
900
|
+
# Stage 6: Render LLM prompt — final markdown string for LLM
|
|
901
|
+
llm_prompt = await client.render_llm_prompt(
|
|
902
|
+
plan=plan,
|
|
903
|
+
style="formal"
|
|
904
|
+
)
|
|
905
|
+
print(f"LLM prompt:\n{llm_prompt['markdown']}")
|
|
906
|
+
|
|
907
|
+
asyncio.run(main())
|
|
908
|
+
```
|
|
909
|
+
|
|
910
|
+
### Hub backups
|
|
911
|
+
|
|
912
|
+
```python
|
|
913
|
+
import asyncio
|
|
914
|
+
from vectorizer_sdk import VectorizerClient
|
|
915
|
+
|
|
916
|
+
async def main():
|
|
917
|
+
client = VectorizerClient(base_url="http://localhost:15002")
|
|
918
|
+
|
|
919
|
+
user_id = "user-123"
|
|
920
|
+
|
|
921
|
+
# List user's backups
|
|
922
|
+
backups = await client.list_user_backups(user_id)
|
|
923
|
+
for backup in backups:
|
|
924
|
+
print(f"Backup: {backup['id']} (size: {backup['size_bytes']} bytes)")
|
|
925
|
+
|
|
926
|
+
# Create a new backup
|
|
927
|
+
new_backup = await client.create_user_backup(
|
|
928
|
+
user_id=user_id,
|
|
929
|
+
name="full-backup-2024-01",
|
|
930
|
+
description="January full backup",
|
|
931
|
+
collections=None # backup all
|
|
932
|
+
)
|
|
933
|
+
print(f"Created backup: {new_backup['id']}")
|
|
934
|
+
|
|
935
|
+
# Restore a backup
|
|
936
|
+
await client.restore_user_backup(
|
|
937
|
+
user_id=user_id,
|
|
938
|
+
backup_id=new_backup['id']
|
|
939
|
+
)
|
|
940
|
+
print("Restore started")
|
|
941
|
+
|
|
942
|
+
# Delete old backup
|
|
943
|
+
await client.delete_user_backup(user_id, backups[0]['id'])
|
|
944
|
+
|
|
945
|
+
asyncio.run(main())
|
|
946
|
+
```
|
|
947
|
+
|
|
725
948
|
#### Read Preferences
|
|
726
949
|
|
|
727
950
|
| Preference | Description | Use Case |
|
|
@@ -1,54 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: vectorizer_sdk
|
|
3
|
-
Version: 3.2.0
|
|
4
|
-
Summary: Python SDK for Vectorizer - Semantic search, vector operations, and the VectorizerRPC binary transport (default in v3.x)
|
|
5
|
-
Author-email: HiveLLM Team <team@hivellm.org>
|
|
6
|
-
License: Apache-2.0
|
|
7
|
-
Project-URL: Homepage, https://github.com/hivellm/vectorizer
|
|
8
|
-
Project-URL: Documentation, https://github.com/hivellm/vectorizer/tree/main/docs
|
|
9
|
-
Project-URL: Repository, https://github.com/hivellm/vectorizer
|
|
10
|
-
Project-URL: Issues, https://github.com/hivellm/vectorizer/issues
|
|
11
|
-
Keywords: vectorizer,semantic-search,embeddings,machine-learning,ai,search,vectors,similarity,hivellm,umicp
|
|
12
|
-
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
-
Classifier: Intended Audience :: Developers
|
|
14
|
-
Classifier: Operating System :: OS Independent
|
|
15
|
-
Classifier: Programming Language :: Python :: 3
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
-
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
-
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
23
|
-
Classifier: Topic :: Text Processing :: Indexing
|
|
24
|
-
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
|
25
|
-
Requires-Python: >=3.8
|
|
26
|
-
Description-Content-Type: text/markdown
|
|
27
|
-
License-File: LICENSE
|
|
28
|
-
Requires-Dist: aiohttp>=3.10.0
|
|
29
|
-
Requires-Dist: msgpack>=1.1.0
|
|
30
|
-
Provides-Extra: umicp
|
|
31
|
-
Requires-Dist: umicp-python>=0.1.3; extra == "umicp"
|
|
32
|
-
Provides-Extra: dev
|
|
33
|
-
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
34
|
-
Requires-Dist: pytest-asyncio>=0.24.0; extra == "dev"
|
|
35
|
-
Requires-Dist: pytest-cov>=5.0.0; extra == "dev"
|
|
36
|
-
Requires-Dist: black>=25.0.0; extra == "dev"
|
|
37
|
-
Requires-Dist: isort>=5.13.0; extra == "dev"
|
|
38
|
-
Requires-Dist: flake8>=7.0.0; extra == "dev"
|
|
39
|
-
Requires-Dist: mypy>=1.11.0; extra == "dev"
|
|
40
|
-
Requires-Dist: pre-commit>=4.0.0; extra == "dev"
|
|
41
|
-
Provides-Extra: docs
|
|
42
|
-
Requires-Dist: sphinx>=7.0.0; extra == "docs"
|
|
43
|
-
Requires-Dist: sphinx-rtd-theme>=2.0.0; extra == "docs"
|
|
44
|
-
Requires-Dist: myst-parser>=3.0.0; extra == "docs"
|
|
45
|
-
Provides-Extra: test
|
|
46
|
-
Requires-Dist: pytest>=8.0.0; extra == "test"
|
|
47
|
-
Requires-Dist: pytest-asyncio>=0.24.0; extra == "test"
|
|
48
|
-
Requires-Dist: pytest-cov>=5.0.0; extra == "test"
|
|
49
|
-
Requires-Dist: httpx>=0.27.0; extra == "test"
|
|
50
|
-
Dynamic: license-file
|
|
51
|
-
|
|
52
1
|
# Vectorizer Python SDK
|
|
53
2
|
|
|
54
3
|
[](https://pypi.org/project/vectorizer-sdk/)
|
|
@@ -58,9 +7,18 @@ Dynamic: license-file
|
|
|
58
7
|
A comprehensive Python SDK for the Vectorizer semantic search service.
|
|
59
8
|
|
|
60
9
|
**Package**: `vectorizer_sdk` (PEP 625 compliant)
|
|
61
|
-
**Version**: 3.
|
|
10
|
+
**Version**: 3.5.0
|
|
62
11
|
**PyPI**: https://pypi.org/project/vectorizer-sdk/
|
|
63
12
|
|
|
13
|
+
## v3.5 — server alignment (no client API changes)
|
|
14
|
+
|
|
15
|
+
Version tracks the Vectorizer **3.5.0** server release: non-blocking
|
|
16
|
+
search during batch inserts, PQ/Binary quantization wiring, SIMD
|
|
17
|
+
quantize kernels, BM25-after-restart and WAL-durability fixes, and a
|
|
18
|
+
security/dependency refresh. All server-internal — the client API is
|
|
19
|
+
unchanged since **v3.3** (REST control-surface parity + dashboard
|
|
20
|
+
metrics). See `CHANGELOG.md` for the full method surface.
|
|
21
|
+
|
|
64
22
|
## v3.2 — backpressure-aware client (HTTP 429 + `Retry-After`)
|
|
65
23
|
|
|
66
24
|
The REST `VectorizerClient` honors server-side bulk-upsert
|
|
@@ -171,7 +129,7 @@ for a runnable end-to-end example.
|
|
|
171
129
|
pip install vectorizer-sdk
|
|
172
130
|
|
|
173
131
|
# Or specific version
|
|
174
|
-
pip install vectorizer-sdk==3.
|
|
132
|
+
pip install vectorizer-sdk==3.5.0
|
|
175
133
|
```
|
|
176
134
|
|
|
177
135
|
## Package Layout (v3.x)
|
|
@@ -714,7 +672,16 @@ await client.insert_texts("documents", [
|
|
|
714
672
|
await client.insert_texts("documents", [
|
|
715
673
|
{"id": "doc1", "text": "Sample document (updated)", "metadata": {"updated": True}}
|
|
716
674
|
])
|
|
717
|
-
await client.delete_vectors("documents", ["doc1"])
|
|
675
|
+
report = await client.delete_vectors("documents", ["doc1"])
|
|
676
|
+
print(f"deleted={report.deleted} failed={report.failed}")
|
|
677
|
+
|
|
678
|
+
# Tier demotion: move vectors between collections without re-embedding
|
|
679
|
+
# (issue #265). Insert into dst lands BEFORE delete from src so a
|
|
680
|
+
# mid-batch crash leaves a recoverable duplicate, never data loss.
|
|
681
|
+
mv = await client.move_to_collection("hot", "warm", ["vec-1", "vec-2"])
|
|
682
|
+
for row in mv.results:
|
|
683
|
+
if row.status != "ok":
|
|
684
|
+
print(f"move failed id={row.id!r} status={row.status} err={row.error!r}")
|
|
718
685
|
|
|
719
686
|
# Reads automatically go to replicas (load balanced)
|
|
720
687
|
results = await client.search_vectors("documents", query="sample", limit=10)
|
|
@@ -722,6 +689,212 @@ collections = await client.list_collections()
|
|
|
722
689
|
vector = await client.get_vector("documents", "doc1")
|
|
723
690
|
```
|
|
724
691
|
|
|
692
|
+
## Control surface (3.4)
|
|
693
|
+
|
|
694
|
+
### Admin / observability
|
|
695
|
+
|
|
696
|
+
```python
|
|
697
|
+
import asyncio
|
|
698
|
+
from vectorizer_sdk import VectorizerClient
|
|
699
|
+
|
|
700
|
+
async def main():
|
|
701
|
+
client = VectorizerClient(base_url="http://localhost:15002")
|
|
702
|
+
|
|
703
|
+
# Server health, uptime, collection/vector counts
|
|
704
|
+
stats = await client.get_stats()
|
|
705
|
+
print(f"Total vectors: {stats['total_vectors']}")
|
|
706
|
+
|
|
707
|
+
status = await client.get_status()
|
|
708
|
+
print(f"Server v{status['version']}, uptime: {status['uptime']}s")
|
|
709
|
+
|
|
710
|
+
# Recent logs
|
|
711
|
+
logs = await client.get_logs(lines=50, level="INFO")
|
|
712
|
+
for entry in logs:
|
|
713
|
+
print(f"{entry['timestamp']}: {entry['message']}")
|
|
714
|
+
|
|
715
|
+
# Per-collection indexing progress
|
|
716
|
+
progress = await client.get_indexing_progress()
|
|
717
|
+
for collection, pct in progress.items():
|
|
718
|
+
print(f"{collection}: {pct:.1f}% complete")
|
|
719
|
+
|
|
720
|
+
# Force flush one collection
|
|
721
|
+
await client.force_save_collection("my_docs")
|
|
722
|
+
|
|
723
|
+
# List and clean empty collections
|
|
724
|
+
empty = await client.list_empty_collections()
|
|
725
|
+
if empty:
|
|
726
|
+
report = await client.cleanup_empty_collections()
|
|
727
|
+
print(f"Cleaned up {report['deleted']} empty collections")
|
|
728
|
+
|
|
729
|
+
# List workspaces
|
|
730
|
+
workspaces = await client.list_workspaces()
|
|
731
|
+
print(f"Workspaces: {workspaces}")
|
|
732
|
+
|
|
733
|
+
asyncio.run(main())
|
|
734
|
+
```
|
|
735
|
+
|
|
736
|
+
### Auth
|
|
737
|
+
|
|
738
|
+
```python
|
|
739
|
+
import asyncio
|
|
740
|
+
from vectorizer_sdk import VectorizerClient
|
|
741
|
+
|
|
742
|
+
async def main():
|
|
743
|
+
client = VectorizerClient(base_url="http://localhost:15002")
|
|
744
|
+
|
|
745
|
+
# Current user info
|
|
746
|
+
me = await client.me()
|
|
747
|
+
print(f"Logged in as: {me['username']} (roles: {', '.join(me['roles'])})")
|
|
748
|
+
|
|
749
|
+
# Refresh token with extended TTL
|
|
750
|
+
token = await client.refresh_token()
|
|
751
|
+
print(f"Token refreshed, expires in: {token['expires_in']} seconds")
|
|
752
|
+
|
|
753
|
+
# Validate password before creating account
|
|
754
|
+
report = await client.validate_password("MySecure123!")
|
|
755
|
+
print(f"Valid: {report['valid']}, feedback: {', '.join(report['feedback'])}")
|
|
756
|
+
|
|
757
|
+
# Create API key for programmatic access
|
|
758
|
+
api_key = await client.create_api_key(
|
|
759
|
+
name="integration-key",
|
|
760
|
+
expires_in=86400 * 365 # 1 year
|
|
761
|
+
)
|
|
762
|
+
print(f"API Key: {api_key['api_key']}")
|
|
763
|
+
|
|
764
|
+
# List and revoke API keys
|
|
765
|
+
keys = await client.list_api_keys()
|
|
766
|
+
for key in keys:
|
|
767
|
+
print(f"Key: {key['id']} (expires: {key['expires_at']})")
|
|
768
|
+
await client.revoke_api_key(keys[0]['id'])
|
|
769
|
+
|
|
770
|
+
# Change password
|
|
771
|
+
await client.change_password("newPassword123!")
|
|
772
|
+
|
|
773
|
+
# Logout
|
|
774
|
+
await client.logout()
|
|
775
|
+
|
|
776
|
+
asyncio.run(main())
|
|
777
|
+
```
|
|
778
|
+
|
|
779
|
+
### Replication
|
|
780
|
+
|
|
781
|
+
```python
|
|
782
|
+
import asyncio
|
|
783
|
+
from vectorizer_sdk import VectorizerClient
|
|
784
|
+
|
|
785
|
+
async def main():
|
|
786
|
+
client = VectorizerClient(base_url="http://localhost:15002")
|
|
787
|
+
|
|
788
|
+
# Check replication role and status
|
|
789
|
+
status = await client.get_replication_status()
|
|
790
|
+
print(f"Role: {status['role']}, enabled: {status['enabled']}")
|
|
791
|
+
|
|
792
|
+
# Get replication statistics (lag, bytes synced)
|
|
793
|
+
stats = await client.get_replication_stats()
|
|
794
|
+
print(f"Bytes synced: {stats['bytes_synced']}")
|
|
795
|
+
|
|
796
|
+
# List all replicas connected to this master
|
|
797
|
+
replicas = await client.list_replicas()
|
|
798
|
+
for replica in replicas:
|
|
799
|
+
print(f"Replica: {replica['address']} (lag: {replica['lag_ms']}ms)")
|
|
800
|
+
|
|
801
|
+
asyncio.run(main())
|
|
802
|
+
```
|
|
803
|
+
|
|
804
|
+
### Discovery pipeline
|
|
805
|
+
|
|
806
|
+
The discovery pipeline chains six stages from broad search to final LLM-ready prompt:
|
|
807
|
+
|
|
808
|
+
```python
|
|
809
|
+
import asyncio
|
|
810
|
+
from vectorizer_sdk import VectorizerClient
|
|
811
|
+
|
|
812
|
+
async def main():
|
|
813
|
+
client = VectorizerClient(base_url="http://localhost:15002")
|
|
814
|
+
|
|
815
|
+
# Stage 1: Broad discovery — multi-query search across all collections
|
|
816
|
+
broad = await client.broad_discovery(
|
|
817
|
+
query="machine learning algorithms",
|
|
818
|
+
max_results=20
|
|
819
|
+
)
|
|
820
|
+
print(f"Found {len(broad['results'])} broad results")
|
|
821
|
+
|
|
822
|
+
# Stage 2: Semantic focus — narrow search to top collection
|
|
823
|
+
focused = await client.semantic_focus(
|
|
824
|
+
query="neural networks",
|
|
825
|
+
collection="research",
|
|
826
|
+
max_results=10
|
|
827
|
+
)
|
|
828
|
+
print(f"Focused results: {len(focused['results'])}")
|
|
829
|
+
|
|
830
|
+
# Stage 3: Promote README — elevate high-quality chunks
|
|
831
|
+
promoted = await client.promote_readme(
|
|
832
|
+
results=focused['results'],
|
|
833
|
+
readme_boost=2.0
|
|
834
|
+
)
|
|
835
|
+
|
|
836
|
+
# Stage 4: Compress evidence — distill to bullet points
|
|
837
|
+
bullets = await client.compress_evidence(
|
|
838
|
+
chunks=promoted['results'],
|
|
839
|
+
max_bullets=15
|
|
840
|
+
)
|
|
841
|
+
print(f"Evidence bullets: {bullets['bullets']}")
|
|
842
|
+
|
|
843
|
+
# Stage 5: Build answer plan — organize bullets into sections
|
|
844
|
+
plan = await client.build_answer_plan(
|
|
845
|
+
evidence=bullets['bullets'],
|
|
846
|
+
max_sections=5
|
|
847
|
+
)
|
|
848
|
+
print(f"Sections: {plan['sections']}")
|
|
849
|
+
|
|
850
|
+
# Stage 6: Render LLM prompt — final markdown string for LLM
|
|
851
|
+
llm_prompt = await client.render_llm_prompt(
|
|
852
|
+
plan=plan,
|
|
853
|
+
style="formal"
|
|
854
|
+
)
|
|
855
|
+
print(f"LLM prompt:\n{llm_prompt['markdown']}")
|
|
856
|
+
|
|
857
|
+
asyncio.run(main())
|
|
858
|
+
```
|
|
859
|
+
|
|
860
|
+
### Hub backups
|
|
861
|
+
|
|
862
|
+
```python
|
|
863
|
+
import asyncio
|
|
864
|
+
from vectorizer_sdk import VectorizerClient
|
|
865
|
+
|
|
866
|
+
async def main():
|
|
867
|
+
client = VectorizerClient(base_url="http://localhost:15002")
|
|
868
|
+
|
|
869
|
+
user_id = "user-123"
|
|
870
|
+
|
|
871
|
+
# List user's backups
|
|
872
|
+
backups = await client.list_user_backups(user_id)
|
|
873
|
+
for backup in backups:
|
|
874
|
+
print(f"Backup: {backup['id']} (size: {backup['size_bytes']} bytes)")
|
|
875
|
+
|
|
876
|
+
# Create a new backup
|
|
877
|
+
new_backup = await client.create_user_backup(
|
|
878
|
+
user_id=user_id,
|
|
879
|
+
name="full-backup-2024-01",
|
|
880
|
+
description="January full backup",
|
|
881
|
+
collections=None # backup all
|
|
882
|
+
)
|
|
883
|
+
print(f"Created backup: {new_backup['id']}")
|
|
884
|
+
|
|
885
|
+
# Restore a backup
|
|
886
|
+
await client.restore_user_backup(
|
|
887
|
+
user_id=user_id,
|
|
888
|
+
backup_id=new_backup['id']
|
|
889
|
+
)
|
|
890
|
+
print("Restore started")
|
|
891
|
+
|
|
892
|
+
# Delete old backup
|
|
893
|
+
await client.delete_user_backup(user_id, backups[0]['id'])
|
|
894
|
+
|
|
895
|
+
asyncio.run(main())
|
|
896
|
+
```
|
|
897
|
+
|
|
725
898
|
#### Read Preferences
|
|
726
899
|
|
|
727
900
|
| Preference | Description | Use Case |
|