vectorizer-sdk 3.0.3__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 (75) hide show
  1. {vectorizer_sdk-3.0.3/vectorizer_sdk.egg-info → vectorizer_sdk-3.5.0}/PKG-INFO +292 -20
  2. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/README.md +278 -5
  3. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/pyproject.toml +16 -17
  4. {vectorizer_sdk-3.0.3 → 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.0.3 → 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_retry_after_parse.py +51 -0
  15. vectorizer_sdk-3.5.0/tests/test_rpc_phase16.py +636 -0
  16. vectorizer_sdk-3.5.0/tests/test_runtime_metrics.py +151 -0
  17. vectorizer_sdk-3.5.0/tests/test_schema_evolution.py +496 -0
  18. vectorizer_sdk-3.5.0/tests/test_search_phase12.py +57 -0
  19. vectorizer_sdk-3.5.0/tests/test_tier_control.py +406 -0
  20. vectorizer_sdk-3.5.0/tests/test_tier_demotion.py +194 -0
  21. vectorizer_sdk-3.5.0/tests/test_vectors_phase12.py +251 -0
  22. vectorizer_sdk-3.5.0/utils/http_client.py +216 -0
  23. vectorizer_sdk-3.5.0/vectorizer/__init__.py +169 -0
  24. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/vectorizer/_base.py +7 -0
  25. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/vectorizer/admin.py +312 -6
  26. vectorizer_sdk-3.5.0/vectorizer/auth.py +414 -0
  27. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/vectorizer/client.py +12 -0
  28. vectorizer_sdk-3.5.0/vectorizer/collections.py +457 -0
  29. vectorizer_sdk-3.5.0/vectorizer/discovery.py +179 -0
  30. vectorizer_sdk-3.5.0/vectorizer/filter.py +258 -0
  31. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/vectorizer/graph.py +7 -7
  32. vectorizer_sdk-3.5.0/vectorizer/hub.py +244 -0
  33. vectorizer_sdk-3.5.0/vectorizer/replication.py +180 -0
  34. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/vectorizer/search.py +74 -2
  35. vectorizer_sdk-3.5.0/vectorizer/vectors.py +939 -0
  36. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0/vectorizer_sdk.egg-info}/PKG-INFO +292 -20
  37. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/vectorizer_sdk.egg-info/SOURCES.txt +19 -0
  38. vectorizer_sdk-3.5.0/vectorizer_sdk.egg-info/requires.txt +26 -0
  39. vectorizer_sdk-3.0.3/rpc/commands.py +0 -210
  40. vectorizer_sdk-3.0.3/utils/http_client.py +0 -153
  41. vectorizer_sdk-3.0.3/vectorizer/__init__.py +0 -58
  42. vectorizer_sdk-3.0.3/vectorizer/auth.py +0 -75
  43. vectorizer_sdk-3.0.3/vectorizer/collections.py +0 -227
  44. vectorizer_sdk-3.0.3/vectorizer/vectors.py +0 -418
  45. vectorizer_sdk-3.0.3/vectorizer_sdk.egg-info/requires.txt +0 -26
  46. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/LICENSE +0 -0
  47. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/rpc/_codec.py +0 -0
  48. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/rpc/async_client.py +0 -0
  49. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/rpc/endpoint.py +0 -0
  50. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/rpc/pool.py +0 -0
  51. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/rpc/sync_client.py +0 -0
  52. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/rpc/types.py +0 -0
  53. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/setup.cfg +0 -0
  54. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/tests/test_client_integration.py +0 -0
  55. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/tests/test_discovery.py +0 -0
  56. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/tests/test_exceptions.py +0 -0
  57. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/tests/test_file_operations.py +0 -0
  58. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/tests/test_file_upload.py +0 -0
  59. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/tests/test_graph.py +0 -0
  60. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/tests/test_http_client.py +0 -0
  61. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/tests/test_intelligent_search.py +0 -0
  62. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/tests/test_models.py +0 -0
  63. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/tests/test_qdrant_advanced.py +0 -0
  64. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/tests/test_routing.py +0 -0
  65. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/tests/test_sdk_comprehensive.py +0 -0
  66. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/tests/test_simple.py +0 -0
  67. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/tests/test_umicp.py +0 -0
  68. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/tests/test_validation.py +0 -0
  69. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/utils/__init__.py +0 -0
  70. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/utils/transport.py +0 -0
  71. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/utils/umicp_client.py +0 -0
  72. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/utils/validation.py +0 -0
  73. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/vectorizer_sdk.egg-info/dependency_links.txt +0 -0
  74. {vectorizer_sdk-3.0.3 → vectorizer_sdk-3.5.0}/vectorizer_sdk.egg-info/entry_points.txt +0 -0
  75. {vectorizer_sdk-3.0.3 → 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.0.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.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,47 @@ 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.0.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
+
72
+ ## v3.2 — backpressure-aware client (HTTP 429 + `Retry-After`)
73
+
74
+ The REST `VectorizerClient` honors server-side bulk-upsert
75
+ backpressure shipped in Vectorizer 3.2.0
76
+ ([#263](https://github.com/hivellm/vectorizer/issues/263)). On HTTP
77
+ `429 Too Many Requests` the client parses `Retry-After` (seconds
78
+ form, 1 s default, 30 s cap), sleeps, and retries up to 3 times
79
+ before raising a typed `RateLimitError`. Pre-3.2.0 clients bounced
80
+ 429s into a generic 5xx and lost the retry budget. Identical
81
+ semantics ship in every first-party SDK (Rust, Python, TypeScript,
82
+ Go, C#) — see `tests/test_retry_after_parse.py`.
83
+
84
+ ## v3.1 — `/insert_vectors` + stable client-id upserts
85
+
86
+ - `insert_vectors(collection, vectors, public_key=None)` — bulk-
87
+ insert pre-computed embeddings with caller-supplied vector ids.
88
+ Skips the embedding pipeline entirely.
89
+ - `insert` / `insert_texts`: the request `id` is now used verbatim
90
+ as the stored `Vector.id` (non-chunked) or as `<id>#<chunk_index>`
91
+ (chunked). Re-running the same payload upserts in place instead
92
+ of duplicating.
93
+ - Chunked vectors expose a flat payload layout (`{content,
94
+ file_path, chunk_index, parent_id, ...user_metadata}`). Legacy
95
+ nested payloads from ≤ 3.0.x stay readable during the deprecation
96
+ window.
97
+
98
+ Client-id contract: non-empty, length ≤ 256, no leading/trailing
99
+ whitespace, must not contain `#`.
100
+
64
101
  ## v3.0 — VectorizerRPC is the default transport
65
102
 
66
103
  Starting with v3.0, the recommended transport is **VectorizerRPC**: a
@@ -79,6 +116,8 @@ import vectorizer_sdk
79
116
 
80
117
  async def main():
81
118
  client = await vectorizer_sdk.connect_async("vectorizer://127.0.0.1:15503")
119
+ # `hello` and `search_basic` are RPC-only (not available on the legacy
120
+ # REST `VectorizerClient`).
82
121
  await client.hello(vectorizer_sdk.HelloPayload(client_name="my-app"))
83
122
  print(await client.list_collections())
84
123
  hits = await client.search_basic("docs", "vector database", limit=5)
@@ -140,7 +179,7 @@ for a runnable end-to-end example.
140
179
  pip install vectorizer-sdk
141
180
 
142
181
  # Or specific version
143
- pip install vectorizer-sdk==3.0.0
182
+ pip install vectorizer-sdk==3.5.0
144
183
  ```
145
184
 
146
185
  ## Package Layout (v3.x)
@@ -477,6 +516,11 @@ related = await client.get_related_files(
477
516
 
478
517
  ### Summarization Operations
479
518
 
519
+ > WARNING: The `/summarize/*` REST endpoints are documented but not yet wired
520
+ > server-side (see `DOC_GAP_ANALYSIS`). The SDK methods below
521
+ > (`summarize_text`, `summarize_context`) will fail until server wiring is
522
+ > complete.
523
+
480
524
  #### Summarize Text
481
525
  Summarize text using various methods:
482
526
 
@@ -509,6 +553,11 @@ summary = await client.summarize_context(
509
553
 
510
554
  ### Workspace Management
511
555
 
556
+ > WARNING: `add_workspace`, `list_workspaces`, and `remove_workspace` are
557
+ > exposed via the REST transport through dynamic `__getattr__` delegation,
558
+ > but they are not first-class SDK methods yet. They work at runtime but
559
+ > won't autocomplete in IDEs. A future release will add explicit methods.
560
+
512
561
  #### Add Workspace
513
562
  Add a new workspace:
514
563
 
@@ -537,6 +586,11 @@ await client.remove_workspace(
537
586
 
538
587
  ### Backup Operations
539
588
 
589
+ > WARNING: `create_backup`, `list_backups`, and `restore_backup` are
590
+ > exposed via the REST transport through dynamic `__getattr__` delegation,
591
+ > but they are not first-class SDK methods yet. They work at runtime but
592
+ > won't autocomplete in IDEs. A future release will add explicit methods.
593
+
540
594
  #### Create Backup
541
595
  Create a backup of collections:
542
596
 
@@ -664,8 +718,20 @@ await client.create_collection("documents", dimension=768)
664
718
  await client.insert_texts("documents", [
665
719
  {"id": "doc1", "text": "Sample document", "metadata": {"source": "api"}}
666
720
  ])
667
- await client.update_vector("documents", "doc1", metadata={"updated": True})
668
- await client.delete_vector("documents", "doc1")
721
+ # Update-via-reinsert: re-call `insert_texts` with the same id to replace the record.
722
+ await client.insert_texts("documents", [
723
+ {"id": "doc1", "text": "Sample document (updated)", "metadata": {"updated": True}}
724
+ ])
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}")
669
735
 
670
736
  # Reads automatically go to replicas (load balanced)
671
737
  results = await client.search_vectors("documents", query="sample", limit=10)
@@ -673,6 +739,212 @@ collections = await client.list_collections()
673
739
  vector = await client.get_vector("documents", "doc1")
674
740
  ```
675
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
+
676
948
  #### Read Preferences
677
949
 
678
950
  | Preference | Description | Use Case |
@@ -702,7 +974,7 @@ The SDK automatically classifies operations:
702
974
 
703
975
  | Operation Type | Routed To | Methods |
704
976
  |---------------|-----------|---------|
705
- | **Writes** | Always Master | `insert_texts`, `insert_vectors`, `update_vector`, `delete_vector`, `create_collection`, `delete_collection` |
977
+ | **Writes** | Always Master | `insert_texts`, `insert_vectors`, `delete_vectors`, `create_collection`, `delete_collection` |
706
978
  | **Reads** | Based on `read_preference` | `search_vectors`, `get_vector`, `list_collections`, `intelligent_search`, `semantic_search`, `hybrid_search` |
707
979
 
708
980
  #### Standalone Mode (Single Node)