sf-vector-sdk 0.2.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.
- sf_vector_sdk-0.2.0.dist-info/METADATA +476 -0
- sf_vector_sdk-0.2.0.dist-info/RECORD +27 -0
- sf_vector_sdk-0.2.0.dist-info/WHEEL +4 -0
- vector_sdk/__init__.py +262 -0
- vector_sdk/client.py +538 -0
- vector_sdk/content_types.py +233 -0
- vector_sdk/generated/embedding_pipeline/content_types/v1/content_types_pb2.py +57 -0
- vector_sdk/generated/embedding_pipeline/content_types/v1/content_types_pb2.pyi +141 -0
- vector_sdk/generated/embedding_pipeline/db/vectors/v1/vectors_pb2.py +58 -0
- vector_sdk/generated/embedding_pipeline/db/vectors/v1/vectors_pb2.pyi +145 -0
- vector_sdk/generated/embedding_pipeline/query/v1/query_pb2.py +58 -0
- vector_sdk/generated/embedding_pipeline/query/v1/query_pb2.pyi +109 -0
- vector_sdk/generated/embedding_pipeline/tools/v1/tools_pb2.py +39 -0
- vector_sdk/generated/embedding_pipeline/tools/v1/tools_pb2.pyi +31 -0
- vector_sdk/hash/__init__.py +31 -0
- vector_sdk/hash/hasher.py +259 -0
- vector_sdk/hash/types.py +67 -0
- vector_sdk/namespaces/__init__.py +13 -0
- vector_sdk/namespaces/base.py +45 -0
- vector_sdk/namespaces/db.py +230 -0
- vector_sdk/namespaces/embeddings.py +268 -0
- vector_sdk/namespaces/search.py +258 -0
- vector_sdk/structured/__init__.py +60 -0
- vector_sdk/structured/router.py +190 -0
- vector_sdk/structured/structured_embeddings.py +431 -0
- vector_sdk/structured/tool_config.py +254 -0
- vector_sdk/types.py +864 -0
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Search namespace for vector similarity search operations.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import uuid
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
from typing import Optional
|
|
9
|
+
|
|
10
|
+
from vector_sdk.namespaces.base import BaseNamespace
|
|
11
|
+
from vector_sdk.types import (
|
|
12
|
+
EmbeddingConfigOverride,
|
|
13
|
+
QueryConfig,
|
|
14
|
+
QueryRequest,
|
|
15
|
+
QueryResult,
|
|
16
|
+
get_query_stream_for_priority,
|
|
17
|
+
validate_model,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class SearchNamespace(BaseNamespace):
|
|
22
|
+
"""
|
|
23
|
+
Namespace for vector search operations.
|
|
24
|
+
|
|
25
|
+
Example:
|
|
26
|
+
```python
|
|
27
|
+
client = VectorClient("redis://localhost:6379")
|
|
28
|
+
|
|
29
|
+
# Search for similar vectors
|
|
30
|
+
result = client.search.query_and_wait(
|
|
31
|
+
query_text="What is machine learning?",
|
|
32
|
+
database="turbopuffer",
|
|
33
|
+
namespace="topic_vectors",
|
|
34
|
+
top_k=10,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
for match in result.matches:
|
|
38
|
+
print(f"{match.id}: {match.score}")
|
|
39
|
+
```
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
def query(
|
|
43
|
+
self,
|
|
44
|
+
query_text: str,
|
|
45
|
+
database: str,
|
|
46
|
+
top_k: int = 10,
|
|
47
|
+
min_score: Optional[float] = None,
|
|
48
|
+
filters: Optional[dict[str, str]] = None,
|
|
49
|
+
namespace: Optional[str] = None,
|
|
50
|
+
collection: Optional[str] = None,
|
|
51
|
+
database_name: Optional[str] = None,
|
|
52
|
+
include_vectors: bool = False,
|
|
53
|
+
include_metadata: bool = True,
|
|
54
|
+
embedding_model: Optional[str] = None,
|
|
55
|
+
embedding_dimensions: Optional[int] = None,
|
|
56
|
+
priority: str = "normal",
|
|
57
|
+
metadata: Optional[dict[str, str]] = None,
|
|
58
|
+
request_id: Optional[str] = None,
|
|
59
|
+
) -> str:
|
|
60
|
+
"""
|
|
61
|
+
Submit a vector search query.
|
|
62
|
+
|
|
63
|
+
This method embeds the query text and searches for similar vectors in
|
|
64
|
+
the specified database. Returns a request ID - use `wait_for()` to get
|
|
65
|
+
the results, or use `query_and_wait()` for a combined operation.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
query_text: The text to search for (will be embedded)
|
|
69
|
+
database: Which vector database to search ("mongodb", "turbopuffer", "pinecone")
|
|
70
|
+
top_k: Number of results to return (default: 10)
|
|
71
|
+
min_score: Minimum similarity score threshold (0.0 to 1.0)
|
|
72
|
+
filters: Metadata filters for filtering results
|
|
73
|
+
namespace: Namespace for Pinecone/TurboPuffer
|
|
74
|
+
collection: Collection name for MongoDB
|
|
75
|
+
database_name: Database name for MongoDB
|
|
76
|
+
include_vectors: Whether to include vector values in response
|
|
77
|
+
include_metadata: Whether to include metadata in response
|
|
78
|
+
embedding_model: Optional embedding model override
|
|
79
|
+
embedding_dimensions: Optional embedding dimensions override
|
|
80
|
+
priority: Queue priority (default: "normal")
|
|
81
|
+
metadata: Optional key-value pairs for tracking
|
|
82
|
+
request_id: Optional custom request ID
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
The request ID for tracking the query
|
|
86
|
+
|
|
87
|
+
Raises:
|
|
88
|
+
ValueError: If query_text is empty
|
|
89
|
+
ModelValidationError: If embedding model is not supported
|
|
90
|
+
"""
|
|
91
|
+
if not query_text or query_text.strip() == "":
|
|
92
|
+
raise ValueError("query_text cannot be empty")
|
|
93
|
+
|
|
94
|
+
# Validate embedding model if specified
|
|
95
|
+
if embedding_model:
|
|
96
|
+
validate_model(embedding_model, embedding_dimensions)
|
|
97
|
+
|
|
98
|
+
if request_id is None:
|
|
99
|
+
request_id = str(uuid.uuid4())
|
|
100
|
+
|
|
101
|
+
query_config = QueryConfig(
|
|
102
|
+
top_k=top_k,
|
|
103
|
+
min_score=min_score,
|
|
104
|
+
filters=filters,
|
|
105
|
+
namespace=namespace,
|
|
106
|
+
collection=collection,
|
|
107
|
+
database=database_name,
|
|
108
|
+
include_vectors=include_vectors,
|
|
109
|
+
include_metadata=include_metadata,
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
embedding_config = None
|
|
113
|
+
if embedding_model or embedding_dimensions:
|
|
114
|
+
embedding_config = EmbeddingConfigOverride(
|
|
115
|
+
model=embedding_model,
|
|
116
|
+
dimensions=embedding_dimensions,
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
request = QueryRequest(
|
|
120
|
+
request_id=request_id,
|
|
121
|
+
query_text=query_text,
|
|
122
|
+
database=database,
|
|
123
|
+
priority=priority,
|
|
124
|
+
query_config=query_config,
|
|
125
|
+
embedding_config=embedding_config,
|
|
126
|
+
metadata=metadata or {},
|
|
127
|
+
created_at=datetime.utcnow(),
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
stream = get_query_stream_for_priority(priority)
|
|
131
|
+
payload = json.dumps(request.to_dict())
|
|
132
|
+
self._redis.xadd(stream, {"data": payload})
|
|
133
|
+
|
|
134
|
+
return request_id
|
|
135
|
+
|
|
136
|
+
def wait_for(
|
|
137
|
+
self,
|
|
138
|
+
request_id: str,
|
|
139
|
+
timeout: int = 30,
|
|
140
|
+
) -> QueryResult:
|
|
141
|
+
"""
|
|
142
|
+
Wait for a search query to complete.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
request_id: The request ID to wait for
|
|
146
|
+
timeout: Maximum time to wait in seconds (default: 30)
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
The query result
|
|
150
|
+
|
|
151
|
+
Raises:
|
|
152
|
+
TimeoutError: If no result is received within the timeout
|
|
153
|
+
"""
|
|
154
|
+
channel = f"query:result:{request_id}"
|
|
155
|
+
pubsub = self._redis.pubsub()
|
|
156
|
+
pubsub.subscribe(channel)
|
|
157
|
+
|
|
158
|
+
try:
|
|
159
|
+
start_time = datetime.utcnow()
|
|
160
|
+
while True:
|
|
161
|
+
message = pubsub.get_message(timeout=1.0)
|
|
162
|
+
if message and message["type"] == "message":
|
|
163
|
+
data = json.loads(message["data"])
|
|
164
|
+
return QueryResult.from_dict(data)
|
|
165
|
+
|
|
166
|
+
elapsed = (datetime.utcnow() - start_time).total_seconds()
|
|
167
|
+
if elapsed >= timeout:
|
|
168
|
+
raise TimeoutError(
|
|
169
|
+
f"No query result received for {request_id} within {timeout}s"
|
|
170
|
+
)
|
|
171
|
+
finally:
|
|
172
|
+
pubsub.unsubscribe(channel)
|
|
173
|
+
pubsub.close()
|
|
174
|
+
|
|
175
|
+
def query_and_wait(
|
|
176
|
+
self,
|
|
177
|
+
query_text: str,
|
|
178
|
+
database: str,
|
|
179
|
+
top_k: int = 10,
|
|
180
|
+
min_score: Optional[float] = None,
|
|
181
|
+
filters: Optional[dict[str, str]] = None,
|
|
182
|
+
namespace: Optional[str] = None,
|
|
183
|
+
collection: Optional[str] = None,
|
|
184
|
+
database_name: Optional[str] = None,
|
|
185
|
+
include_vectors: bool = False,
|
|
186
|
+
include_metadata: bool = True,
|
|
187
|
+
embedding_model: Optional[str] = None,
|
|
188
|
+
embedding_dimensions: Optional[int] = None,
|
|
189
|
+
priority: str = "normal",
|
|
190
|
+
metadata: Optional[dict[str, str]] = None,
|
|
191
|
+
timeout: int = 30,
|
|
192
|
+
) -> QueryResult:
|
|
193
|
+
"""
|
|
194
|
+
Submit a search query and wait for the result.
|
|
195
|
+
|
|
196
|
+
This method subscribes to the result channel BEFORE submitting the request,
|
|
197
|
+
ensuring no race condition where the result is published before we're listening.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
query_text: The text to search for
|
|
201
|
+
database: Which vector database to search
|
|
202
|
+
top_k: Number of results to return
|
|
203
|
+
min_score: Minimum similarity score threshold
|
|
204
|
+
filters: Metadata filters
|
|
205
|
+
namespace: Namespace for Pinecone/TurboPuffer
|
|
206
|
+
collection: Collection name for MongoDB
|
|
207
|
+
database_name: Database name for MongoDB
|
|
208
|
+
include_vectors: Include vectors in response
|
|
209
|
+
include_metadata: Include metadata in response
|
|
210
|
+
embedding_model: Optional embedding model override
|
|
211
|
+
embedding_dimensions: Optional embedding dimensions override
|
|
212
|
+
priority: Queue priority
|
|
213
|
+
metadata: Optional metadata for tracking
|
|
214
|
+
timeout: Maximum time to wait in seconds
|
|
215
|
+
|
|
216
|
+
Returns:
|
|
217
|
+
The query result
|
|
218
|
+
"""
|
|
219
|
+
request_id = str(uuid.uuid4())
|
|
220
|
+
channel = f"query:result:{request_id}"
|
|
221
|
+
|
|
222
|
+
pubsub = self._redis.pubsub()
|
|
223
|
+
pubsub.subscribe(channel)
|
|
224
|
+
|
|
225
|
+
try:
|
|
226
|
+
self.query(
|
|
227
|
+
query_text=query_text,
|
|
228
|
+
database=database,
|
|
229
|
+
top_k=top_k,
|
|
230
|
+
min_score=min_score,
|
|
231
|
+
filters=filters,
|
|
232
|
+
namespace=namespace,
|
|
233
|
+
collection=collection,
|
|
234
|
+
database_name=database_name,
|
|
235
|
+
include_vectors=include_vectors,
|
|
236
|
+
include_metadata=include_metadata,
|
|
237
|
+
embedding_model=embedding_model,
|
|
238
|
+
embedding_dimensions=embedding_dimensions,
|
|
239
|
+
priority=priority,
|
|
240
|
+
metadata=metadata,
|
|
241
|
+
request_id=request_id,
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
start_time = datetime.utcnow()
|
|
245
|
+
while True:
|
|
246
|
+
message = pubsub.get_message(timeout=1.0)
|
|
247
|
+
if message and message["type"] == "message":
|
|
248
|
+
data = json.loads(message["data"])
|
|
249
|
+
return QueryResult.from_dict(data)
|
|
250
|
+
|
|
251
|
+
elapsed = (datetime.utcnow() - start_time).total_seconds()
|
|
252
|
+
if elapsed >= timeout:
|
|
253
|
+
raise TimeoutError(
|
|
254
|
+
f"No query result received for {request_id} within {timeout}s"
|
|
255
|
+
)
|
|
256
|
+
finally:
|
|
257
|
+
pubsub.unsubscribe(channel)
|
|
258
|
+
pubsub.close()
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Structured Embeddings Module.
|
|
3
|
+
|
|
4
|
+
Provides type-safe methods for embedding known tool types (FlashCard, TestQuestion, etc.)
|
|
5
|
+
with automatic text extraction, content hash computation, and database routing.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from .router import (
|
|
9
|
+
DatabaseRoutingError,
|
|
10
|
+
DatabaseRoutingMode,
|
|
11
|
+
build_storage_config,
|
|
12
|
+
get_content_type,
|
|
13
|
+
get_database_routing_mode,
|
|
14
|
+
validate_database_routing,
|
|
15
|
+
)
|
|
16
|
+
from .structured_embeddings import (
|
|
17
|
+
StructuredEmbeddingsNamespace,
|
|
18
|
+
TestQuestionInput,
|
|
19
|
+
ToolMetadata,
|
|
20
|
+
)
|
|
21
|
+
from .tool_config import (
|
|
22
|
+
TOOL_CONFIGS,
|
|
23
|
+
PineconeToolConfig,
|
|
24
|
+
QuestionType,
|
|
25
|
+
ToolConfig,
|
|
26
|
+
ToolDatabaseConfig,
|
|
27
|
+
TurboPufferToolConfig,
|
|
28
|
+
get_flashcard_namespace_suffix,
|
|
29
|
+
get_pinecone_namespace,
|
|
30
|
+
get_question_namespace_suffix,
|
|
31
|
+
get_tool_config,
|
|
32
|
+
get_turbopuffer_namespace,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
__all__ = [
|
|
36
|
+
# Namespace class
|
|
37
|
+
"StructuredEmbeddingsNamespace",
|
|
38
|
+
# Types
|
|
39
|
+
"ToolMetadata",
|
|
40
|
+
"TestQuestionInput",
|
|
41
|
+
# Tool configuration
|
|
42
|
+
"ToolConfig",
|
|
43
|
+
"ToolDatabaseConfig",
|
|
44
|
+
"TurboPufferToolConfig",
|
|
45
|
+
"PineconeToolConfig",
|
|
46
|
+
"QuestionType",
|
|
47
|
+
"TOOL_CONFIGS",
|
|
48
|
+
"get_tool_config",
|
|
49
|
+
"get_flashcard_namespace_suffix",
|
|
50
|
+
"get_question_namespace_suffix",
|
|
51
|
+
"get_turbopuffer_namespace",
|
|
52
|
+
"get_pinecone_namespace",
|
|
53
|
+
# Database router
|
|
54
|
+
"DatabaseRoutingMode",
|
|
55
|
+
"DatabaseRoutingError",
|
|
56
|
+
"get_database_routing_mode",
|
|
57
|
+
"validate_database_routing",
|
|
58
|
+
"build_storage_config",
|
|
59
|
+
"get_content_type",
|
|
60
|
+
]
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Database Router for Structured Embeddings.
|
|
3
|
+
|
|
4
|
+
Routes embedding writes to the appropriate databases based on:
|
|
5
|
+
- STRUCTURED_EMBEDDING_DATABASE_ROUTER environment variable
|
|
6
|
+
- Per-tool enabled/disabled configuration
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import os
|
|
10
|
+
from typing import Any, Literal, Optional
|
|
11
|
+
|
|
12
|
+
from ..hash import ToolCollection
|
|
13
|
+
from ..types import (
|
|
14
|
+
PineconeStorageConfig,
|
|
15
|
+
StorageConfig,
|
|
16
|
+
TurboPufferStorage,
|
|
17
|
+
)
|
|
18
|
+
from .tool_config import (
|
|
19
|
+
get_pinecone_namespace,
|
|
20
|
+
get_tool_config,
|
|
21
|
+
get_turbopuffer_namespace,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
# ============================================================================
|
|
25
|
+
# Types
|
|
26
|
+
# ============================================================================
|
|
27
|
+
|
|
28
|
+
DatabaseRoutingMode = Literal["dual", "turbopuffer", "pinecone"]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class DatabaseRoutingError(Exception):
|
|
32
|
+
"""Error thrown when database routing fails."""
|
|
33
|
+
|
|
34
|
+
pass
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# ============================================================================
|
|
38
|
+
# Environment Variable
|
|
39
|
+
# ============================================================================
|
|
40
|
+
|
|
41
|
+
ENV_VAR_NAME = "STRUCTURED_EMBEDDING_DATABASE_ROUTER"
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def get_database_routing_mode() -> DatabaseRoutingMode:
|
|
45
|
+
"""
|
|
46
|
+
Get the database routing mode from environment variable.
|
|
47
|
+
Defaults to 'turbopuffer' if not set.
|
|
48
|
+
"""
|
|
49
|
+
env_value = os.environ.get(ENV_VAR_NAME)
|
|
50
|
+
|
|
51
|
+
if not env_value:
|
|
52
|
+
return "turbopuffer"
|
|
53
|
+
|
|
54
|
+
mode = env_value.lower()
|
|
55
|
+
|
|
56
|
+
if mode not in ("dual", "turbopuffer", "pinecone"):
|
|
57
|
+
raise DatabaseRoutingError(
|
|
58
|
+
f"Invalid {ENV_VAR_NAME} value: '{env_value}'. "
|
|
59
|
+
"Must be 'dual', 'turbopuffer', or 'pinecone'."
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
return mode # type: ignore
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
# ============================================================================
|
|
66
|
+
# Validation
|
|
67
|
+
# ============================================================================
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def validate_database_routing(
|
|
71
|
+
tool_collection: ToolCollection,
|
|
72
|
+
mode: DatabaseRoutingMode,
|
|
73
|
+
) -> None:
|
|
74
|
+
"""
|
|
75
|
+
Validate that the required databases are enabled for the routing mode.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
tool_collection: The tool collection type
|
|
79
|
+
mode: The database routing mode
|
|
80
|
+
|
|
81
|
+
Raises:
|
|
82
|
+
DatabaseRoutingError: If validation fails
|
|
83
|
+
"""
|
|
84
|
+
config = get_tool_config(tool_collection)
|
|
85
|
+
|
|
86
|
+
if mode == "turbopuffer":
|
|
87
|
+
if not config.turbopuffer.enabled:
|
|
88
|
+
raise DatabaseRoutingError(
|
|
89
|
+
f"Database routing mode 'turbopuffer' requested but "
|
|
90
|
+
f"turbopuffer.enabled is false for {tool_collection}"
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
elif mode == "pinecone":
|
|
94
|
+
if not config.pinecone.enabled:
|
|
95
|
+
raise DatabaseRoutingError(
|
|
96
|
+
f"Database routing mode 'pinecone' requested but "
|
|
97
|
+
f"pinecone.enabled is false for {tool_collection}"
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
elif mode == "dual":
|
|
101
|
+
# In dual mode, at least one database must be enabled
|
|
102
|
+
if not config.turbopuffer.enabled and not config.pinecone.enabled:
|
|
103
|
+
raise DatabaseRoutingError(
|
|
104
|
+
f"No databases enabled for {tool_collection}. "
|
|
105
|
+
"At least one of turbopuffer or pinecone must be enabled."
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
# ============================================================================
|
|
110
|
+
# Storage Config Builder
|
|
111
|
+
# ============================================================================
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def build_storage_config(
|
|
115
|
+
tool_collection: ToolCollection,
|
|
116
|
+
sub_type: Optional[str],
|
|
117
|
+
content_hash: str,
|
|
118
|
+
document_fields: dict[str, Any],
|
|
119
|
+
) -> StorageConfig:
|
|
120
|
+
"""
|
|
121
|
+
Build the storage configuration for a structured embedding request.
|
|
122
|
+
|
|
123
|
+
This function:
|
|
124
|
+
1. Gets the routing mode from environment
|
|
125
|
+
2. Validates that required databases are enabled
|
|
126
|
+
3. Builds the storage config with appropriate namespaces
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
tool_collection: Tool collection type
|
|
130
|
+
sub_type: Sub-type (FlashCardType or QuestionType)
|
|
131
|
+
content_hash: Content hash (used as vector ID)
|
|
132
|
+
document_fields: Additional document fields to store
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
StorageConfig for the embedding request
|
|
136
|
+
|
|
137
|
+
Raises:
|
|
138
|
+
DatabaseRoutingError: If validation fails
|
|
139
|
+
"""
|
|
140
|
+
mode = get_database_routing_mode()
|
|
141
|
+
validate_database_routing(tool_collection, mode)
|
|
142
|
+
|
|
143
|
+
config = get_tool_config(tool_collection)
|
|
144
|
+
|
|
145
|
+
# Build TurboPuffer config if enabled and requested
|
|
146
|
+
turbopuffer = None
|
|
147
|
+
include_turbopuffer = config.turbopuffer.enabled and mode in (
|
|
148
|
+
"turbopuffer",
|
|
149
|
+
"dual",
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
if include_turbopuffer:
|
|
153
|
+
namespace = get_turbopuffer_namespace(tool_collection, sub_type)
|
|
154
|
+
turbopuffer = TurboPufferStorage(
|
|
155
|
+
namespace=namespace,
|
|
156
|
+
id_field=config.turbopuffer.id_field,
|
|
157
|
+
metadata=list(config.turbopuffer.metadata_fields),
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
# Build Pinecone config if enabled and requested
|
|
161
|
+
pinecone = None
|
|
162
|
+
include_pinecone = config.pinecone.enabled and mode in ("pinecone", "dual")
|
|
163
|
+
|
|
164
|
+
if include_pinecone:
|
|
165
|
+
namespace = get_pinecone_namespace(tool_collection, sub_type)
|
|
166
|
+
pinecone = PineconeStorageConfig(
|
|
167
|
+
index_name=config.pinecone.index_name,
|
|
168
|
+
namespace=namespace,
|
|
169
|
+
id_field=config.pinecone.id_field,
|
|
170
|
+
metadata=list(config.pinecone.metadata_fields),
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
return StorageConfig(
|
|
174
|
+
turbopuffer=turbopuffer,
|
|
175
|
+
pinecone=pinecone,
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def get_content_type(tool_collection: ToolCollection) -> str:
|
|
180
|
+
"""
|
|
181
|
+
Get the content type string for the embedding request.
|
|
182
|
+
Maps tool collections to the contentType used in embedding requests.
|
|
183
|
+
"""
|
|
184
|
+
mapping: dict[ToolCollection, str] = {
|
|
185
|
+
"FlashCard": "flashcard",
|
|
186
|
+
"TestQuestion": "testquestion",
|
|
187
|
+
"SpacedTestQuestion": "spacedtestquestion",
|
|
188
|
+
"AudioRecapV2Section": "audiorecap",
|
|
189
|
+
}
|
|
190
|
+
return mapping.get(tool_collection, "tool")
|