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.
- mantisdk/__init__.py +22 -0
- mantisdk/adapter/__init__.py +15 -0
- mantisdk/adapter/base.py +94 -0
- mantisdk/adapter/messages.py +270 -0
- mantisdk/adapter/triplet.py +1028 -0
- mantisdk/algorithm/__init__.py +39 -0
- mantisdk/algorithm/apo/__init__.py +5 -0
- mantisdk/algorithm/apo/apo.py +889 -0
- mantisdk/algorithm/apo/prompts/apply_edit_variant01.poml +22 -0
- mantisdk/algorithm/apo/prompts/apply_edit_variant02.poml +18 -0
- mantisdk/algorithm/apo/prompts/text_gradient_variant01.poml +18 -0
- mantisdk/algorithm/apo/prompts/text_gradient_variant02.poml +16 -0
- mantisdk/algorithm/apo/prompts/text_gradient_variant03.poml +107 -0
- mantisdk/algorithm/base.py +162 -0
- mantisdk/algorithm/decorator.py +264 -0
- mantisdk/algorithm/fast.py +250 -0
- mantisdk/algorithm/gepa/__init__.py +59 -0
- mantisdk/algorithm/gepa/adapter.py +459 -0
- mantisdk/algorithm/gepa/gepa.py +364 -0
- mantisdk/algorithm/gepa/lib/__init__.py +18 -0
- mantisdk/algorithm/gepa/lib/adapters/README.md +12 -0
- mantisdk/algorithm/gepa/lib/adapters/__init__.py +0 -0
- mantisdk/algorithm/gepa/lib/adapters/anymaths_adapter/README.md +341 -0
- mantisdk/algorithm/gepa/lib/adapters/anymaths_adapter/__init__.py +1 -0
- mantisdk/algorithm/gepa/lib/adapters/anymaths_adapter/anymaths_adapter.py +174 -0
- mantisdk/algorithm/gepa/lib/adapters/anymaths_adapter/requirements.txt +1 -0
- mantisdk/algorithm/gepa/lib/adapters/default_adapter/README.md +0 -0
- mantisdk/algorithm/gepa/lib/adapters/default_adapter/__init__.py +0 -0
- mantisdk/algorithm/gepa/lib/adapters/default_adapter/default_adapter.py +209 -0
- mantisdk/algorithm/gepa/lib/adapters/dspy_adapter/README.md +7 -0
- mantisdk/algorithm/gepa/lib/adapters/dspy_adapter/__init__.py +0 -0
- mantisdk/algorithm/gepa/lib/adapters/dspy_adapter/dspy_adapter.py +307 -0
- mantisdk/algorithm/gepa/lib/adapters/dspy_full_program_adapter/README.md +99 -0
- mantisdk/algorithm/gepa/lib/adapters/dspy_full_program_adapter/dspy_program_proposal_signature.py +137 -0
- mantisdk/algorithm/gepa/lib/adapters/dspy_full_program_adapter/full_program_adapter.py +266 -0
- mantisdk/algorithm/gepa/lib/adapters/generic_rag_adapter/GEPA_RAG.md +621 -0
- mantisdk/algorithm/gepa/lib/adapters/generic_rag_adapter/__init__.py +56 -0
- mantisdk/algorithm/gepa/lib/adapters/generic_rag_adapter/evaluation_metrics.py +226 -0
- mantisdk/algorithm/gepa/lib/adapters/generic_rag_adapter/generic_rag_adapter.py +496 -0
- mantisdk/algorithm/gepa/lib/adapters/generic_rag_adapter/rag_pipeline.py +238 -0
- mantisdk/algorithm/gepa/lib/adapters/generic_rag_adapter/vector_store_interface.py +212 -0
- mantisdk/algorithm/gepa/lib/adapters/generic_rag_adapter/vector_stores/__init__.py +2 -0
- mantisdk/algorithm/gepa/lib/adapters/generic_rag_adapter/vector_stores/chroma_store.py +196 -0
- mantisdk/algorithm/gepa/lib/adapters/generic_rag_adapter/vector_stores/lancedb_store.py +422 -0
- mantisdk/algorithm/gepa/lib/adapters/generic_rag_adapter/vector_stores/milvus_store.py +409 -0
- mantisdk/algorithm/gepa/lib/adapters/generic_rag_adapter/vector_stores/qdrant_store.py +368 -0
- mantisdk/algorithm/gepa/lib/adapters/generic_rag_adapter/vector_stores/weaviate_store.py +418 -0
- mantisdk/algorithm/gepa/lib/adapters/mcp_adapter/README.md +552 -0
- mantisdk/algorithm/gepa/lib/adapters/mcp_adapter/__init__.py +37 -0
- mantisdk/algorithm/gepa/lib/adapters/mcp_adapter/mcp_adapter.py +705 -0
- mantisdk/algorithm/gepa/lib/adapters/mcp_adapter/mcp_client.py +364 -0
- mantisdk/algorithm/gepa/lib/adapters/terminal_bench_adapter/README.md +9 -0
- mantisdk/algorithm/gepa/lib/adapters/terminal_bench_adapter/__init__.py +0 -0
- mantisdk/algorithm/gepa/lib/adapters/terminal_bench_adapter/terminal_bench_adapter.py +217 -0
- mantisdk/algorithm/gepa/lib/api.py +375 -0
- mantisdk/algorithm/gepa/lib/core/__init__.py +0 -0
- mantisdk/algorithm/gepa/lib/core/adapter.py +180 -0
- mantisdk/algorithm/gepa/lib/core/data_loader.py +74 -0
- mantisdk/algorithm/gepa/lib/core/engine.py +356 -0
- mantisdk/algorithm/gepa/lib/core/result.py +233 -0
- mantisdk/algorithm/gepa/lib/core/state.py +636 -0
- mantisdk/algorithm/gepa/lib/examples/__init__.py +0 -0
- mantisdk/algorithm/gepa/lib/examples/aime.py +24 -0
- mantisdk/algorithm/gepa/lib/examples/anymaths-bench/eval_default.py +111 -0
- mantisdk/algorithm/gepa/lib/examples/anymaths-bench/prompt-templates/instruction_prompt.txt +9 -0
- mantisdk/algorithm/gepa/lib/examples/anymaths-bench/prompt-templates/optimal_prompt.txt +24 -0
- mantisdk/algorithm/gepa/lib/examples/anymaths-bench/train_anymaths.py +177 -0
- mantisdk/algorithm/gepa/lib/examples/dspy_full_program_evolution/arc_agi.ipynb +25705 -0
- mantisdk/algorithm/gepa/lib/examples/dspy_full_program_evolution/example.ipynb +348 -0
- mantisdk/algorithm/gepa/lib/examples/mcp_adapter/__init__.py +4 -0
- mantisdk/algorithm/gepa/lib/examples/mcp_adapter/mcp_optimization_example.py +455 -0
- mantisdk/algorithm/gepa/lib/examples/rag_adapter/RAG_GUIDE.md +613 -0
- mantisdk/algorithm/gepa/lib/examples/rag_adapter/__init__.py +9 -0
- mantisdk/algorithm/gepa/lib/examples/rag_adapter/rag_optimization.py +824 -0
- mantisdk/algorithm/gepa/lib/examples/rag_adapter/requirements-rag.txt +29 -0
- mantisdk/algorithm/gepa/lib/examples/terminal-bench/prompt-templates/instruction_prompt.txt +16 -0
- mantisdk/algorithm/gepa/lib/examples/terminal-bench/prompt-templates/terminus.txt +9 -0
- mantisdk/algorithm/gepa/lib/examples/terminal-bench/train_terminus.py +161 -0
- mantisdk/algorithm/gepa/lib/gepa_utils.py +117 -0
- mantisdk/algorithm/gepa/lib/logging/__init__.py +0 -0
- mantisdk/algorithm/gepa/lib/logging/experiment_tracker.py +187 -0
- mantisdk/algorithm/gepa/lib/logging/logger.py +75 -0
- mantisdk/algorithm/gepa/lib/logging/utils.py +103 -0
- mantisdk/algorithm/gepa/lib/proposer/__init__.py +0 -0
- mantisdk/algorithm/gepa/lib/proposer/base.py +31 -0
- mantisdk/algorithm/gepa/lib/proposer/merge.py +357 -0
- mantisdk/algorithm/gepa/lib/proposer/reflective_mutation/__init__.py +0 -0
- mantisdk/algorithm/gepa/lib/proposer/reflective_mutation/base.py +49 -0
- mantisdk/algorithm/gepa/lib/proposer/reflective_mutation/reflective_mutation.py +176 -0
- mantisdk/algorithm/gepa/lib/py.typed +0 -0
- mantisdk/algorithm/gepa/lib/strategies/__init__.py +0 -0
- mantisdk/algorithm/gepa/lib/strategies/batch_sampler.py +77 -0
- mantisdk/algorithm/gepa/lib/strategies/candidate_selector.py +50 -0
- mantisdk/algorithm/gepa/lib/strategies/component_selector.py +36 -0
- mantisdk/algorithm/gepa/lib/strategies/eval_policy.py +64 -0
- mantisdk/algorithm/gepa/lib/strategies/instruction_proposal.py +127 -0
- mantisdk/algorithm/gepa/lib/utils/__init__.py +10 -0
- mantisdk/algorithm/gepa/lib/utils/stop_condition.py +196 -0
- mantisdk/algorithm/gepa/tracing.py +105 -0
- mantisdk/algorithm/utils.py +177 -0
- mantisdk/algorithm/verl/__init__.py +5 -0
- mantisdk/algorithm/verl/interface.py +202 -0
- mantisdk/cli/__init__.py +56 -0
- mantisdk/cli/prometheus.py +115 -0
- mantisdk/cli/store.py +131 -0
- mantisdk/cli/vllm.py +29 -0
- mantisdk/client.py +408 -0
- mantisdk/config.py +348 -0
- mantisdk/emitter/__init__.py +43 -0
- mantisdk/emitter/annotation.py +370 -0
- mantisdk/emitter/exception.py +54 -0
- mantisdk/emitter/message.py +61 -0
- mantisdk/emitter/object.py +117 -0
- mantisdk/emitter/reward.py +320 -0
- mantisdk/env_var.py +156 -0
- mantisdk/execution/__init__.py +15 -0
- mantisdk/execution/base.py +64 -0
- mantisdk/execution/client_server.py +443 -0
- mantisdk/execution/events.py +69 -0
- mantisdk/execution/inter_process.py +16 -0
- mantisdk/execution/shared_memory.py +282 -0
- mantisdk/instrumentation/__init__.py +119 -0
- mantisdk/instrumentation/agentops.py +314 -0
- mantisdk/instrumentation/agentops_langchain.py +45 -0
- mantisdk/instrumentation/litellm.py +83 -0
- mantisdk/instrumentation/vllm.py +81 -0
- mantisdk/instrumentation/weave.py +500 -0
- mantisdk/litagent/__init__.py +11 -0
- mantisdk/litagent/decorator.py +536 -0
- mantisdk/litagent/litagent.py +252 -0
- mantisdk/llm_proxy.py +1890 -0
- mantisdk/logging.py +370 -0
- mantisdk/reward.py +7 -0
- mantisdk/runner/__init__.py +11 -0
- mantisdk/runner/agent.py +845 -0
- mantisdk/runner/base.py +182 -0
- mantisdk/runner/legacy.py +309 -0
- mantisdk/semconv.py +170 -0
- mantisdk/server.py +401 -0
- mantisdk/store/__init__.py +23 -0
- mantisdk/store/base.py +897 -0
- mantisdk/store/client_server.py +2092 -0
- mantisdk/store/collection/__init__.py +30 -0
- mantisdk/store/collection/base.py +587 -0
- mantisdk/store/collection/memory.py +970 -0
- mantisdk/store/collection/mongo.py +1412 -0
- mantisdk/store/collection_based.py +1823 -0
- mantisdk/store/insight.py +648 -0
- mantisdk/store/listener.py +58 -0
- mantisdk/store/memory.py +396 -0
- mantisdk/store/mongo.py +165 -0
- mantisdk/store/sqlite.py +3 -0
- mantisdk/store/threading.py +357 -0
- mantisdk/store/utils.py +142 -0
- mantisdk/tracer/__init__.py +16 -0
- mantisdk/tracer/agentops.py +242 -0
- mantisdk/tracer/base.py +287 -0
- mantisdk/tracer/dummy.py +106 -0
- mantisdk/tracer/otel.py +555 -0
- mantisdk/tracer/weave.py +677 -0
- mantisdk/trainer/__init__.py +6 -0
- mantisdk/trainer/init_utils.py +263 -0
- mantisdk/trainer/legacy.py +367 -0
- mantisdk/trainer/registry.py +12 -0
- mantisdk/trainer/trainer.py +618 -0
- mantisdk/types/__init__.py +6 -0
- mantisdk/types/core.py +553 -0
- mantisdk/types/resources.py +204 -0
- mantisdk/types/tracer.py +515 -0
- mantisdk/types/tracing.py +218 -0
- mantisdk/utils/__init__.py +1 -0
- mantisdk/utils/id.py +18 -0
- mantisdk/utils/metrics.py +1025 -0
- mantisdk/utils/otel.py +578 -0
- mantisdk/utils/otlp.py +536 -0
- mantisdk/utils/server_launcher.py +1045 -0
- mantisdk/utils/system_snapshot.py +81 -0
- mantisdk/verl/__init__.py +8 -0
- mantisdk/verl/__main__.py +6 -0
- mantisdk/verl/async_server.py +46 -0
- mantisdk/verl/config.yaml +27 -0
- mantisdk/verl/daemon.py +1154 -0
- mantisdk/verl/dataset.py +44 -0
- mantisdk/verl/entrypoint.py +248 -0
- mantisdk/verl/trainer.py +549 -0
- mantisdk-0.1.0.dist-info/METADATA +119 -0
- mantisdk-0.1.0.dist-info/RECORD +190 -0
- mantisdk-0.1.0.dist-info/WHEEL +4 -0
- mantisdk-0.1.0.dist-info/entry_points.txt +2 -0
- 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)
|