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.
Files changed (74) hide show
  1. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/PKG-INFO +241 -18
  2. vectorizer_sdk-3.2.0/vectorizer_sdk.egg-info/PKG-INFO → vectorizer_sdk-3.5.0/README.md +227 -54
  3. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/pyproject.toml +16 -17
  4. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/rpc/__init__.py +80 -1
  5. vectorizer_sdk-3.5.0/rpc/commands.py +2245 -0
  6. vectorizer_sdk-3.5.0/tests/test_admin_phase12.py +256 -0
  7. vectorizer_sdk-3.5.0/tests/test_auth_phase12.py +209 -0
  8. vectorizer_sdk-3.5.0/tests/test_cluster_auth_admin.py +532 -0
  9. vectorizer_sdk-3.5.0/tests/test_discovery_phase12.py +192 -0
  10. vectorizer_sdk-3.5.0/tests/test_filter.py +238 -0
  11. vectorizer_sdk-3.5.0/tests/test_hub.py +226 -0
  12. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/tests/test_mock_transport.py +7 -1
  13. vectorizer_sdk-3.5.0/tests/test_replication.py +120 -0
  14. vectorizer_sdk-3.5.0/tests/test_rpc_phase16.py +636 -0
  15. vectorizer_sdk-3.5.0/tests/test_runtime_metrics.py +151 -0
  16. vectorizer_sdk-3.5.0/tests/test_schema_evolution.py +496 -0
  17. vectorizer_sdk-3.5.0/tests/test_search_phase12.py +57 -0
  18. vectorizer_sdk-3.5.0/tests/test_tier_control.py +406 -0
  19. vectorizer_sdk-3.5.0/tests/test_tier_demotion.py +194 -0
  20. vectorizer_sdk-3.5.0/tests/test_vectors_phase12.py +251 -0
  21. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/utils/http_client.py +5 -1
  22. vectorizer_sdk-3.5.0/vectorizer/__init__.py +169 -0
  23. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/vectorizer/_base.py +7 -0
  24. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/vectorizer/admin.py +312 -6
  25. vectorizer_sdk-3.5.0/vectorizer/auth.py +414 -0
  26. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/vectorizer/client.py +12 -0
  27. vectorizer_sdk-3.5.0/vectorizer/collections.py +457 -0
  28. vectorizer_sdk-3.5.0/vectorizer/discovery.py +179 -0
  29. vectorizer_sdk-3.5.0/vectorizer/filter.py +258 -0
  30. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/vectorizer/graph.py +7 -7
  31. vectorizer_sdk-3.5.0/vectorizer/hub.py +244 -0
  32. vectorizer_sdk-3.5.0/vectorizer/replication.py +180 -0
  33. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/vectorizer/search.py +74 -2
  34. vectorizer_sdk-3.5.0/vectorizer/vectors.py +939 -0
  35. vectorizer_sdk-3.2.0/README.md → vectorizer_sdk-3.5.0/vectorizer_sdk.egg-info/PKG-INFO +277 -3
  36. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/vectorizer_sdk.egg-info/SOURCES.txt +18 -0
  37. vectorizer_sdk-3.5.0/vectorizer_sdk.egg-info/requires.txt +26 -0
  38. vectorizer_sdk-3.2.0/rpc/commands.py +0 -210
  39. vectorizer_sdk-3.2.0/vectorizer/__init__.py +0 -58
  40. vectorizer_sdk-3.2.0/vectorizer/auth.py +0 -75
  41. vectorizer_sdk-3.2.0/vectorizer/collections.py +0 -227
  42. vectorizer_sdk-3.2.0/vectorizer/vectors.py +0 -418
  43. vectorizer_sdk-3.2.0/vectorizer_sdk.egg-info/requires.txt +0 -26
  44. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/LICENSE +0 -0
  45. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/rpc/_codec.py +0 -0
  46. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/rpc/async_client.py +0 -0
  47. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/rpc/endpoint.py +0 -0
  48. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/rpc/pool.py +0 -0
  49. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/rpc/sync_client.py +0 -0
  50. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/rpc/types.py +0 -0
  51. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/setup.cfg +0 -0
  52. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/tests/test_client_integration.py +0 -0
  53. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/tests/test_discovery.py +0 -0
  54. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/tests/test_exceptions.py +0 -0
  55. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/tests/test_file_operations.py +0 -0
  56. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/tests/test_file_upload.py +0 -0
  57. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/tests/test_graph.py +0 -0
  58. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/tests/test_http_client.py +0 -0
  59. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/tests/test_intelligent_search.py +0 -0
  60. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/tests/test_models.py +0 -0
  61. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/tests/test_qdrant_advanced.py +0 -0
  62. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/tests/test_retry_after_parse.py +0 -0
  63. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/tests/test_routing.py +0 -0
  64. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/tests/test_sdk_comprehensive.py +0 -0
  65. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/tests/test_simple.py +0 -0
  66. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/tests/test_umicp.py +0 -0
  67. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/tests/test_validation.py +0 -0
  68. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/utils/__init__.py +0 -0
  69. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/utils/transport.py +0 -0
  70. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/utils/umicp_client.py +0 -0
  71. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/utils/validation.py +0 -0
  72. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/vectorizer_sdk.egg-info/dependency_links.txt +0 -0
  73. {vectorizer_sdk-3.2.0 → vectorizer_sdk-3.5.0}/vectorizer_sdk.egg-info/entry_points.txt +0 -0
  74. {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.2.0
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.8
24
+ Requires-Python: >=3.10
26
25
  Description-Content-Type: text/markdown
27
26
  License-File: LICENSE
28
- Requires-Dist: aiohttp>=3.10.0
29
- Requires-Dist: msgpack>=1.1.0
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.0.0; extra == "dev"
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.0; extra == "dev"
38
- Requires-Dist: flake8>=7.0.0; extra == "dev"
39
- Requires-Dist: mypy>=1.11.0; extra == "dev"
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.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"
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.0.0; extra == "test"
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.27.0; extra == "test"
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.2.0
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.2.0
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
  [![PyPI version](https://badge.fury.io/py/vectorizer-sdk.svg)](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.2.0
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.2.0
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 |