mantisdk 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of mantisdk might be problematic. Click here for more details.

Files changed (190) hide show
  1. mantisdk/__init__.py +22 -0
  2. mantisdk/adapter/__init__.py +15 -0
  3. mantisdk/adapter/base.py +94 -0
  4. mantisdk/adapter/messages.py +270 -0
  5. mantisdk/adapter/triplet.py +1028 -0
  6. mantisdk/algorithm/__init__.py +39 -0
  7. mantisdk/algorithm/apo/__init__.py +5 -0
  8. mantisdk/algorithm/apo/apo.py +889 -0
  9. mantisdk/algorithm/apo/prompts/apply_edit_variant01.poml +22 -0
  10. mantisdk/algorithm/apo/prompts/apply_edit_variant02.poml +18 -0
  11. mantisdk/algorithm/apo/prompts/text_gradient_variant01.poml +18 -0
  12. mantisdk/algorithm/apo/prompts/text_gradient_variant02.poml +16 -0
  13. mantisdk/algorithm/apo/prompts/text_gradient_variant03.poml +107 -0
  14. mantisdk/algorithm/base.py +162 -0
  15. mantisdk/algorithm/decorator.py +264 -0
  16. mantisdk/algorithm/fast.py +250 -0
  17. mantisdk/algorithm/gepa/__init__.py +59 -0
  18. mantisdk/algorithm/gepa/adapter.py +459 -0
  19. mantisdk/algorithm/gepa/gepa.py +364 -0
  20. mantisdk/algorithm/gepa/lib/__init__.py +18 -0
  21. mantisdk/algorithm/gepa/lib/adapters/README.md +12 -0
  22. mantisdk/algorithm/gepa/lib/adapters/__init__.py +0 -0
  23. mantisdk/algorithm/gepa/lib/adapters/anymaths_adapter/README.md +341 -0
  24. mantisdk/algorithm/gepa/lib/adapters/anymaths_adapter/__init__.py +1 -0
  25. mantisdk/algorithm/gepa/lib/adapters/anymaths_adapter/anymaths_adapter.py +174 -0
  26. mantisdk/algorithm/gepa/lib/adapters/anymaths_adapter/requirements.txt +1 -0
  27. mantisdk/algorithm/gepa/lib/adapters/default_adapter/README.md +0 -0
  28. mantisdk/algorithm/gepa/lib/adapters/default_adapter/__init__.py +0 -0
  29. mantisdk/algorithm/gepa/lib/adapters/default_adapter/default_adapter.py +209 -0
  30. mantisdk/algorithm/gepa/lib/adapters/dspy_adapter/README.md +7 -0
  31. mantisdk/algorithm/gepa/lib/adapters/dspy_adapter/__init__.py +0 -0
  32. mantisdk/algorithm/gepa/lib/adapters/dspy_adapter/dspy_adapter.py +307 -0
  33. mantisdk/algorithm/gepa/lib/adapters/dspy_full_program_adapter/README.md +99 -0
  34. mantisdk/algorithm/gepa/lib/adapters/dspy_full_program_adapter/dspy_program_proposal_signature.py +137 -0
  35. mantisdk/algorithm/gepa/lib/adapters/dspy_full_program_adapter/full_program_adapter.py +266 -0
  36. mantisdk/algorithm/gepa/lib/adapters/generic_rag_adapter/GEPA_RAG.md +621 -0
  37. mantisdk/algorithm/gepa/lib/adapters/generic_rag_adapter/__init__.py +56 -0
  38. mantisdk/algorithm/gepa/lib/adapters/generic_rag_adapter/evaluation_metrics.py +226 -0
  39. mantisdk/algorithm/gepa/lib/adapters/generic_rag_adapter/generic_rag_adapter.py +496 -0
  40. mantisdk/algorithm/gepa/lib/adapters/generic_rag_adapter/rag_pipeline.py +238 -0
  41. mantisdk/algorithm/gepa/lib/adapters/generic_rag_adapter/vector_store_interface.py +212 -0
  42. mantisdk/algorithm/gepa/lib/adapters/generic_rag_adapter/vector_stores/__init__.py +2 -0
  43. mantisdk/algorithm/gepa/lib/adapters/generic_rag_adapter/vector_stores/chroma_store.py +196 -0
  44. mantisdk/algorithm/gepa/lib/adapters/generic_rag_adapter/vector_stores/lancedb_store.py +422 -0
  45. mantisdk/algorithm/gepa/lib/adapters/generic_rag_adapter/vector_stores/milvus_store.py +409 -0
  46. mantisdk/algorithm/gepa/lib/adapters/generic_rag_adapter/vector_stores/qdrant_store.py +368 -0
  47. mantisdk/algorithm/gepa/lib/adapters/generic_rag_adapter/vector_stores/weaviate_store.py +418 -0
  48. mantisdk/algorithm/gepa/lib/adapters/mcp_adapter/README.md +552 -0
  49. mantisdk/algorithm/gepa/lib/adapters/mcp_adapter/__init__.py +37 -0
  50. mantisdk/algorithm/gepa/lib/adapters/mcp_adapter/mcp_adapter.py +705 -0
  51. mantisdk/algorithm/gepa/lib/adapters/mcp_adapter/mcp_client.py +364 -0
  52. mantisdk/algorithm/gepa/lib/adapters/terminal_bench_adapter/README.md +9 -0
  53. mantisdk/algorithm/gepa/lib/adapters/terminal_bench_adapter/__init__.py +0 -0
  54. mantisdk/algorithm/gepa/lib/adapters/terminal_bench_adapter/terminal_bench_adapter.py +217 -0
  55. mantisdk/algorithm/gepa/lib/api.py +375 -0
  56. mantisdk/algorithm/gepa/lib/core/__init__.py +0 -0
  57. mantisdk/algorithm/gepa/lib/core/adapter.py +180 -0
  58. mantisdk/algorithm/gepa/lib/core/data_loader.py +74 -0
  59. mantisdk/algorithm/gepa/lib/core/engine.py +356 -0
  60. mantisdk/algorithm/gepa/lib/core/result.py +233 -0
  61. mantisdk/algorithm/gepa/lib/core/state.py +636 -0
  62. mantisdk/algorithm/gepa/lib/examples/__init__.py +0 -0
  63. mantisdk/algorithm/gepa/lib/examples/aime.py +24 -0
  64. mantisdk/algorithm/gepa/lib/examples/anymaths-bench/eval_default.py +111 -0
  65. mantisdk/algorithm/gepa/lib/examples/anymaths-bench/prompt-templates/instruction_prompt.txt +9 -0
  66. mantisdk/algorithm/gepa/lib/examples/anymaths-bench/prompt-templates/optimal_prompt.txt +24 -0
  67. mantisdk/algorithm/gepa/lib/examples/anymaths-bench/train_anymaths.py +177 -0
  68. mantisdk/algorithm/gepa/lib/examples/dspy_full_program_evolution/arc_agi.ipynb +25705 -0
  69. mantisdk/algorithm/gepa/lib/examples/dspy_full_program_evolution/example.ipynb +348 -0
  70. mantisdk/algorithm/gepa/lib/examples/mcp_adapter/__init__.py +4 -0
  71. mantisdk/algorithm/gepa/lib/examples/mcp_adapter/mcp_optimization_example.py +455 -0
  72. mantisdk/algorithm/gepa/lib/examples/rag_adapter/RAG_GUIDE.md +613 -0
  73. mantisdk/algorithm/gepa/lib/examples/rag_adapter/__init__.py +9 -0
  74. mantisdk/algorithm/gepa/lib/examples/rag_adapter/rag_optimization.py +824 -0
  75. mantisdk/algorithm/gepa/lib/examples/rag_adapter/requirements-rag.txt +29 -0
  76. mantisdk/algorithm/gepa/lib/examples/terminal-bench/prompt-templates/instruction_prompt.txt +16 -0
  77. mantisdk/algorithm/gepa/lib/examples/terminal-bench/prompt-templates/terminus.txt +9 -0
  78. mantisdk/algorithm/gepa/lib/examples/terminal-bench/train_terminus.py +161 -0
  79. mantisdk/algorithm/gepa/lib/gepa_utils.py +117 -0
  80. mantisdk/algorithm/gepa/lib/logging/__init__.py +0 -0
  81. mantisdk/algorithm/gepa/lib/logging/experiment_tracker.py +187 -0
  82. mantisdk/algorithm/gepa/lib/logging/logger.py +75 -0
  83. mantisdk/algorithm/gepa/lib/logging/utils.py +103 -0
  84. mantisdk/algorithm/gepa/lib/proposer/__init__.py +0 -0
  85. mantisdk/algorithm/gepa/lib/proposer/base.py +31 -0
  86. mantisdk/algorithm/gepa/lib/proposer/merge.py +357 -0
  87. mantisdk/algorithm/gepa/lib/proposer/reflective_mutation/__init__.py +0 -0
  88. mantisdk/algorithm/gepa/lib/proposer/reflective_mutation/base.py +49 -0
  89. mantisdk/algorithm/gepa/lib/proposer/reflective_mutation/reflective_mutation.py +176 -0
  90. mantisdk/algorithm/gepa/lib/py.typed +0 -0
  91. mantisdk/algorithm/gepa/lib/strategies/__init__.py +0 -0
  92. mantisdk/algorithm/gepa/lib/strategies/batch_sampler.py +77 -0
  93. mantisdk/algorithm/gepa/lib/strategies/candidate_selector.py +50 -0
  94. mantisdk/algorithm/gepa/lib/strategies/component_selector.py +36 -0
  95. mantisdk/algorithm/gepa/lib/strategies/eval_policy.py +64 -0
  96. mantisdk/algorithm/gepa/lib/strategies/instruction_proposal.py +127 -0
  97. mantisdk/algorithm/gepa/lib/utils/__init__.py +10 -0
  98. mantisdk/algorithm/gepa/lib/utils/stop_condition.py +196 -0
  99. mantisdk/algorithm/gepa/tracing.py +105 -0
  100. mantisdk/algorithm/utils.py +177 -0
  101. mantisdk/algorithm/verl/__init__.py +5 -0
  102. mantisdk/algorithm/verl/interface.py +202 -0
  103. mantisdk/cli/__init__.py +56 -0
  104. mantisdk/cli/prometheus.py +115 -0
  105. mantisdk/cli/store.py +131 -0
  106. mantisdk/cli/vllm.py +29 -0
  107. mantisdk/client.py +408 -0
  108. mantisdk/config.py +348 -0
  109. mantisdk/emitter/__init__.py +43 -0
  110. mantisdk/emitter/annotation.py +370 -0
  111. mantisdk/emitter/exception.py +54 -0
  112. mantisdk/emitter/message.py +61 -0
  113. mantisdk/emitter/object.py +117 -0
  114. mantisdk/emitter/reward.py +320 -0
  115. mantisdk/env_var.py +156 -0
  116. mantisdk/execution/__init__.py +15 -0
  117. mantisdk/execution/base.py +64 -0
  118. mantisdk/execution/client_server.py +443 -0
  119. mantisdk/execution/events.py +69 -0
  120. mantisdk/execution/inter_process.py +16 -0
  121. mantisdk/execution/shared_memory.py +282 -0
  122. mantisdk/instrumentation/__init__.py +119 -0
  123. mantisdk/instrumentation/agentops.py +314 -0
  124. mantisdk/instrumentation/agentops_langchain.py +45 -0
  125. mantisdk/instrumentation/litellm.py +83 -0
  126. mantisdk/instrumentation/vllm.py +81 -0
  127. mantisdk/instrumentation/weave.py +500 -0
  128. mantisdk/litagent/__init__.py +11 -0
  129. mantisdk/litagent/decorator.py +536 -0
  130. mantisdk/litagent/litagent.py +252 -0
  131. mantisdk/llm_proxy.py +1890 -0
  132. mantisdk/logging.py +370 -0
  133. mantisdk/reward.py +7 -0
  134. mantisdk/runner/__init__.py +11 -0
  135. mantisdk/runner/agent.py +845 -0
  136. mantisdk/runner/base.py +182 -0
  137. mantisdk/runner/legacy.py +309 -0
  138. mantisdk/semconv.py +170 -0
  139. mantisdk/server.py +401 -0
  140. mantisdk/store/__init__.py +23 -0
  141. mantisdk/store/base.py +897 -0
  142. mantisdk/store/client_server.py +2092 -0
  143. mantisdk/store/collection/__init__.py +30 -0
  144. mantisdk/store/collection/base.py +587 -0
  145. mantisdk/store/collection/memory.py +970 -0
  146. mantisdk/store/collection/mongo.py +1412 -0
  147. mantisdk/store/collection_based.py +1823 -0
  148. mantisdk/store/insight.py +648 -0
  149. mantisdk/store/listener.py +58 -0
  150. mantisdk/store/memory.py +396 -0
  151. mantisdk/store/mongo.py +165 -0
  152. mantisdk/store/sqlite.py +3 -0
  153. mantisdk/store/threading.py +357 -0
  154. mantisdk/store/utils.py +142 -0
  155. mantisdk/tracer/__init__.py +16 -0
  156. mantisdk/tracer/agentops.py +242 -0
  157. mantisdk/tracer/base.py +287 -0
  158. mantisdk/tracer/dummy.py +106 -0
  159. mantisdk/tracer/otel.py +555 -0
  160. mantisdk/tracer/weave.py +677 -0
  161. mantisdk/trainer/__init__.py +6 -0
  162. mantisdk/trainer/init_utils.py +263 -0
  163. mantisdk/trainer/legacy.py +367 -0
  164. mantisdk/trainer/registry.py +12 -0
  165. mantisdk/trainer/trainer.py +618 -0
  166. mantisdk/types/__init__.py +6 -0
  167. mantisdk/types/core.py +553 -0
  168. mantisdk/types/resources.py +204 -0
  169. mantisdk/types/tracer.py +515 -0
  170. mantisdk/types/tracing.py +218 -0
  171. mantisdk/utils/__init__.py +1 -0
  172. mantisdk/utils/id.py +18 -0
  173. mantisdk/utils/metrics.py +1025 -0
  174. mantisdk/utils/otel.py +578 -0
  175. mantisdk/utils/otlp.py +536 -0
  176. mantisdk/utils/server_launcher.py +1045 -0
  177. mantisdk/utils/system_snapshot.py +81 -0
  178. mantisdk/verl/__init__.py +8 -0
  179. mantisdk/verl/__main__.py +6 -0
  180. mantisdk/verl/async_server.py +46 -0
  181. mantisdk/verl/config.yaml +27 -0
  182. mantisdk/verl/daemon.py +1154 -0
  183. mantisdk/verl/dataset.py +44 -0
  184. mantisdk/verl/entrypoint.py +248 -0
  185. mantisdk/verl/trainer.py +549 -0
  186. mantisdk-0.1.0.dist-info/METADATA +119 -0
  187. mantisdk-0.1.0.dist-info/RECORD +190 -0
  188. mantisdk-0.1.0.dist-info/WHEEL +4 -0
  189. mantisdk-0.1.0.dist-info/entry_points.txt +2 -0
  190. mantisdk-0.1.0.dist-info/licenses/LICENSE +19 -0
@@ -0,0 +1,418 @@
1
+ # Copyright (c) 2025 Lakshya A Agrawal and the GEPA contributors
2
+ # https://github.com/gepa-ai/gepa
3
+
4
+ from typing import Any
5
+
6
+ from mantisdk.algorithm.gepa.lib.adapters.generic_rag_adapter.vector_store_interface import VectorStoreInterface
7
+
8
+
9
+ class WeaviateVectorStore(VectorStoreInterface):
10
+ """
11
+ Weaviate implementation of the VectorStoreInterface.
12
+
13
+ Weaviate is a cloud-native, modular, real-time vector database
14
+ with powerful search capabilities including hybrid search.
15
+ Supports both Weaviate Cloud Services and self-hosted deployments.
16
+ """
17
+
18
+ def __init__(self, client, collection_name: str, embedding_function=None):
19
+ """
20
+ Initialize WeaviateVectorStore.
21
+
22
+ Args:
23
+ client: Weaviate client instance (WeaviateClient from weaviate-client)
24
+ collection_name: Name of the collection/class to use
25
+ embedding_function: Optional function to compute embeddings for queries
26
+ """
27
+ import importlib.util
28
+
29
+ if importlib.util.find_spec("weaviate") is None:
30
+ raise ImportError(
31
+ "Weaviate client is required for WeaviateVectorStore. Install with: pip install litellm weaviate-client"
32
+ )
33
+
34
+ import weaviate.classes as wvc
35
+
36
+ self.client = client
37
+ self.collection_name = collection_name
38
+ self.wvc = wvc
39
+ self.embedding_function = embedding_function
40
+
41
+ # Get the collection
42
+ try:
43
+ self.collection = self.client.collections.get(collection_name)
44
+ except Exception as e:
45
+ raise ValueError(
46
+ f"Collection '{collection_name}' not found. Please create the collection first. Error: {e!s}"
47
+ ) from e
48
+
49
+ def similarity_search(
50
+ self,
51
+ query: str,
52
+ k: int = 5,
53
+ filters: dict[str, Any] | None = None,
54
+ ) -> list[dict[str, Any]]:
55
+ """Search for documents similar to the query text using embeddings."""
56
+ if self.embedding_function is None:
57
+ raise ValueError("No embedding function provided for similarity search")
58
+
59
+ # Compute embeddings for the query
60
+ try:
61
+ query_vector = self.embedding_function(query)
62
+ if hasattr(query_vector, "tolist"):
63
+ query_vector = query_vector.tolist()
64
+ except Exception as e:
65
+ raise RuntimeError(f"Failed to compute embeddings for query: {e!s}") from e
66
+
67
+ # Use vector search with computed embeddings
68
+ return self.vector_search(query_vector, k, filters)
69
+
70
+ def vector_search(
71
+ self,
72
+ query_vector: list[float],
73
+ k: int = 5,
74
+ filters: dict[str, Any] | None = None,
75
+ ) -> list[dict[str, Any]]:
76
+ """Search using a pre-computed query vector."""
77
+ weaviate_filters = self._convert_filters(filters) if filters else None
78
+
79
+ try:
80
+ # Execute query
81
+ if weaviate_filters:
82
+ response = self.collection.query.near_vector(near_vector=query_vector, limit=k).where(weaviate_filters)
83
+ else:
84
+ response = self.collection.query.near_vector(near_vector=query_vector, limit=k)
85
+
86
+ # Handle GenerativeReturn object - access .objects attribute
87
+ if hasattr(response, "objects"):
88
+ results = response.objects
89
+ else:
90
+ results = response
91
+
92
+ return self._format_results(results)
93
+
94
+ except Exception as e:
95
+ raise RuntimeError(f"Weaviate vector search failed: {e!s}") from e
96
+
97
+ def hybrid_search(
98
+ self,
99
+ query: str,
100
+ k: int = 5,
101
+ alpha: float = 0.5,
102
+ filters: dict[str, Any] | None = None,
103
+ ) -> list[dict[str, Any]]:
104
+ """
105
+ Hybrid semantic + keyword search using Weaviate's native hybrid search.
106
+
107
+ Args:
108
+ query: Text query to search for
109
+ k: Number of documents to return
110
+ alpha: Weight for semantic vs keyword search (0.0 = pure keyword, 1.0 = pure semantic)
111
+ filters: Optional metadata filters
112
+ """
113
+ weaviate_filters = self._convert_filters(filters) if filters else None
114
+
115
+ try:
116
+ results = self.collection.query.hybrid(
117
+ query=query,
118
+ alpha=alpha,
119
+ limit=k,
120
+ where=weaviate_filters,
121
+ return_metadata=self.wvc.query.MetadataQuery(score=True, explain_score=True),
122
+ return_properties=["content", "*"],
123
+ )
124
+
125
+ return self._format_results(results)
126
+
127
+ except Exception as e:
128
+ raise RuntimeError(f"Weaviate hybrid search failed: {e!s}") from e
129
+
130
+ def get_collection_info(self) -> dict[str, Any]:
131
+ """Get metadata about the Weaviate collection."""
132
+ try:
133
+ # Get collection configuration
134
+ config = self.collection.config.get()
135
+
136
+ # Count objects in collection
137
+ count_result = self.collection.aggregate.over_all(total_count=True)
138
+ total_count = count_result.total_count
139
+
140
+ # Try to determine vector dimensions
141
+ dimension = 0
142
+ if hasattr(config, "vector_config") and config.vector_config:
143
+ # For collections with vector config
144
+ if hasattr(config.vector_config, "vector_index_config"):
145
+ vector_index = config.vector_index_config
146
+ if hasattr(vector_index, "distance"):
147
+ # This indicates vectors are configured
148
+ # Try to get dimension from a sample object
149
+ try:
150
+ sample = self.collection.query.fetch_objects(limit=1, include_vector=True)
151
+ if sample.objects and hasattr(sample.objects[0], "vector") and sample.objects[0].vector:
152
+ # Handle both named vectors and default vector
153
+ vector_data = sample.objects[0].vector
154
+ if isinstance(vector_data, dict):
155
+ # Named vectors case
156
+ for _vector_name, vector_values in vector_data.items():
157
+ if vector_values:
158
+ dimension = len(vector_values)
159
+ break
160
+ elif isinstance(vector_data, list):
161
+ # Default vector case
162
+ dimension = len(vector_data)
163
+ except Exception:
164
+ # If we can't determine dimension from sample, that's ok
165
+ pass
166
+
167
+ # Determine if hybrid search is supported
168
+ supports_hybrid = True # Weaviate generally supports hybrid search
169
+ try:
170
+ # Test if hybrid search works by doing a minimal query
171
+ self.collection.query.hybrid(query="test", limit=1)
172
+ supports_hybrid = True
173
+ except Exception:
174
+ supports_hybrid = False
175
+
176
+ return {
177
+ "name": self.collection_name,
178
+ "document_count": total_count,
179
+ "dimension": dimension,
180
+ "vector_store_type": "weaviate",
181
+ "supports_hybrid_search": supports_hybrid,
182
+ "vectorizer": getattr(config, "vectorizer_config", None),
183
+ "properties": [prop.name for prop in getattr(config, "properties", [])],
184
+ }
185
+
186
+ except Exception as e:
187
+ # Fallback info if detailed info fails
188
+ return {
189
+ "name": self.collection_name,
190
+ "document_count": 0,
191
+ "dimension": 0,
192
+ "vector_store_type": "weaviate",
193
+ "error": str(e),
194
+ }
195
+
196
+ def supports_hybrid_search(self) -> bool:
197
+ """Weaviate supports hybrid search."""
198
+ try:
199
+ # Test if hybrid search works
200
+ self.collection.query.hybrid(query="test", limit=1)
201
+ return True
202
+ except Exception:
203
+ return False
204
+
205
+ def supports_metadata_filtering(self) -> bool:
206
+ """Weaviate supports metadata filtering with where clauses."""
207
+ return True
208
+
209
+ def _convert_filters(self, filters: dict[str, Any]) -> Any:
210
+ """
211
+ Convert generic filters to Weaviate where clause format.
212
+
213
+ Generic format: {"key": "value", "key2": {"$gt": 5}}
214
+ Weaviate format uses Filter class
215
+ """
216
+ if not filters:
217
+ return None
218
+
219
+ try:
220
+ from weaviate.collections.classes.filters import Filter
221
+ except ImportError:
222
+ # Fallback if Filter class not available
223
+ return None
224
+
225
+ filter_conditions = []
226
+
227
+ for key, value in filters.items():
228
+ if isinstance(value, dict):
229
+ # Handle operator-based filters
230
+ for op, op_value in value.items():
231
+ if op == "$eq" or op == "equal":
232
+ filter_conditions.append(Filter.by_property(key).equal(op_value))
233
+ elif op == "$ne" or op == "not_equal":
234
+ filter_conditions.append(Filter.by_property(key).not_equal(op_value))
235
+ elif op == "$gt" or op == "greater_than":
236
+ filter_conditions.append(Filter.by_property(key).greater_than(op_value))
237
+ elif op == "$gte" or op == "greater_equal":
238
+ filter_conditions.append(Filter.by_property(key).greater_or_equal(op_value))
239
+ elif op == "$lt" or op == "less_than":
240
+ filter_conditions.append(Filter.by_property(key).less_than(op_value))
241
+ elif op == "$lte" or op == "less_equal":
242
+ filter_conditions.append(Filter.by_property(key).less_or_equal(op_value))
243
+ elif op == "$in" or op == "contains_any":
244
+ if isinstance(op_value, list):
245
+ filter_conditions.append(Filter.by_property(key).contains_any(op_value))
246
+ elif op == "$like" or op == "like":
247
+ filter_conditions.append(Filter.by_property(key).like(op_value))
248
+ else:
249
+ # Simple equality filter
250
+ filter_conditions.append(Filter.by_property(key).equal(value))
251
+
252
+ # Combine all conditions with AND
253
+ if len(filter_conditions) == 1:
254
+ return filter_conditions[0]
255
+ elif len(filter_conditions) > 1:
256
+ combined_filter = filter_conditions[0]
257
+ for condition in filter_conditions[1:]:
258
+ combined_filter = combined_filter & condition
259
+ return combined_filter
260
+
261
+ return None
262
+
263
+ def _format_results(self, results) -> list[dict[str, Any]]:
264
+ """Convert Weaviate results to standardized format."""
265
+ documents = []
266
+
267
+ # Handle both GenerativeReturn objects and direct lists
268
+ if hasattr(results, "objects"):
269
+ objects_list = results.objects
270
+ else:
271
+ objects_list = results
272
+
273
+ if not objects_list:
274
+ return documents
275
+
276
+ for obj in objects_list:
277
+ # Get the content - try different property names
278
+ content = ""
279
+ properties = obj.properties
280
+
281
+ # Common content field names
282
+ content_fields = ["content", "text", "document", "body", "description"]
283
+ for field in content_fields:
284
+ if field in properties:
285
+ content = properties[field]
286
+ break
287
+
288
+ # If no content field found, use all text properties
289
+ if not content:
290
+ text_properties = []
291
+ for key, value in properties.items():
292
+ if isinstance(value, str) and value.strip():
293
+ text_properties.append(f"{key}: {value}")
294
+ content = " | ".join(text_properties)
295
+
296
+ # Extract metadata (all properties except content)
297
+ metadata = {}
298
+ for key, value in properties.items():
299
+ if key not in ["content", "text", "document", "body"] or not content:
300
+ metadata[key] = value
301
+
302
+ # Add UUID as doc_id in metadata
303
+ metadata["doc_id"] = str(obj.uuid)
304
+
305
+ # Calculate similarity score from distance or use provided score
306
+ score = 0.0
307
+ if hasattr(obj.metadata, "score") and obj.metadata.score is not None:
308
+ score = float(obj.metadata.score)
309
+ elif hasattr(obj.metadata, "distance") and obj.metadata.distance is not None:
310
+ # Convert distance to similarity (assuming cosine distance)
311
+ # Weaviate cosine distance is between 0 and 2, similarity = 1 - (distance/2)
312
+ distance = float(obj.metadata.distance)
313
+ score = max(0.0, 1.0 - (distance / 2.0))
314
+
315
+ documents.append({"content": content, "metadata": metadata, "score": score})
316
+
317
+ return documents
318
+
319
+ @classmethod
320
+ def create_local(
321
+ cls,
322
+ host: str = "localhost",
323
+ port: int = 8080,
324
+ grpc_port: int = 50051,
325
+ collection_name: str = "Documents",
326
+ headers: dict[str, str] | None = None,
327
+ ) -> "WeaviateVectorStore":
328
+ """
329
+ Create a WeaviateVectorStore connected to local Weaviate instance.
330
+
331
+ Args:
332
+ host: Weaviate host
333
+ port: HTTP port
334
+ grpc_port: gRPC port
335
+ collection_name: Name of the collection
336
+ headers: Optional headers for authentication
337
+
338
+ Returns:
339
+ WeaviateVectorStore instance
340
+ """
341
+ try:
342
+ import weaviate
343
+ except ImportError as e:
344
+ raise ImportError("Weaviate client is required. Install with: pip install litellm weaviate-client") from e
345
+
346
+ client = weaviate.connect_to_local(host=host, port=port, grpc_port=grpc_port, headers=headers)
347
+
348
+ return cls(client, collection_name)
349
+
350
+ @classmethod
351
+ def create_cloud(
352
+ cls,
353
+ cluster_url: str,
354
+ auth_credentials,
355
+ collection_name: str = "Documents",
356
+ headers: dict[str, str] | None = None,
357
+ ) -> "WeaviateVectorStore":
358
+ """
359
+ Create a WeaviateVectorStore connected to Weaviate Cloud Services.
360
+
361
+ Args:
362
+ cluster_url: Weaviate cluster URL
363
+ auth_credentials: Authentication credentials (API key or other auth)
364
+ collection_name: Name of the collection
365
+ headers: Optional headers
366
+
367
+ Returns:
368
+ WeaviateVectorStore instance
369
+ """
370
+ try:
371
+ import weaviate
372
+ except ImportError as e:
373
+ raise ImportError("Weaviate client is required. Install with: pip install litellm weaviate-client") from e
374
+
375
+ client = weaviate.connect_to_weaviate_cloud(
376
+ cluster_url=cluster_url, auth_credentials=auth_credentials, headers=headers
377
+ )
378
+
379
+ return cls(client, collection_name)
380
+
381
+ @classmethod
382
+ def create_custom(
383
+ cls,
384
+ url: str,
385
+ auth_credentials=None,
386
+ collection_name: str = "Documents",
387
+ headers: dict[str, str] | None = None,
388
+ grpc_port: int | None = None,
389
+ ) -> "WeaviateVectorStore":
390
+ """
391
+ Create a WeaviateVectorStore with custom connection parameters.
392
+
393
+ Args:
394
+ url: Weaviate instance URL
395
+ auth_credentials: Authentication credentials
396
+ collection_name: Name of the collection
397
+ headers: Optional headers
398
+ grpc_port: Optional gRPC port
399
+
400
+ Returns:
401
+ WeaviateVectorStore instance
402
+ """
403
+ try:
404
+ import weaviate
405
+ except ImportError as e:
406
+ raise ImportError("Weaviate client is required. Install with: pip install litellm weaviate-client") from e
407
+
408
+ client = weaviate.connect_to_custom(
409
+ http_host=url,
410
+ http_port=443 if "https" in url else 80,
411
+ http_secure="https" in url,
412
+ grpc_port=grpc_port,
413
+ grpc_secure="https" in url,
414
+ auth_credentials=auth_credentials,
415
+ headers=headers,
416
+ )
417
+
418
+ return cls(client, collection_name)