genxai-framework 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.
Files changed (156) hide show
  1. cli/__init__.py +3 -0
  2. cli/commands/__init__.py +6 -0
  3. cli/commands/approval.py +85 -0
  4. cli/commands/audit.py +127 -0
  5. cli/commands/metrics.py +25 -0
  6. cli/commands/tool.py +389 -0
  7. cli/main.py +32 -0
  8. genxai/__init__.py +81 -0
  9. genxai/api/__init__.py +5 -0
  10. genxai/api/app.py +21 -0
  11. genxai/config/__init__.py +5 -0
  12. genxai/config/settings.py +37 -0
  13. genxai/connectors/__init__.py +19 -0
  14. genxai/connectors/base.py +122 -0
  15. genxai/connectors/kafka.py +92 -0
  16. genxai/connectors/postgres_cdc.py +95 -0
  17. genxai/connectors/registry.py +44 -0
  18. genxai/connectors/sqs.py +94 -0
  19. genxai/connectors/webhook.py +73 -0
  20. genxai/core/__init__.py +37 -0
  21. genxai/core/agent/__init__.py +32 -0
  22. genxai/core/agent/base.py +206 -0
  23. genxai/core/agent/config_io.py +59 -0
  24. genxai/core/agent/registry.py +98 -0
  25. genxai/core/agent/runtime.py +970 -0
  26. genxai/core/communication/__init__.py +6 -0
  27. genxai/core/communication/collaboration.py +44 -0
  28. genxai/core/communication/message_bus.py +192 -0
  29. genxai/core/communication/protocols.py +35 -0
  30. genxai/core/execution/__init__.py +22 -0
  31. genxai/core/execution/metadata.py +181 -0
  32. genxai/core/execution/queue.py +201 -0
  33. genxai/core/graph/__init__.py +30 -0
  34. genxai/core/graph/checkpoints.py +77 -0
  35. genxai/core/graph/edges.py +131 -0
  36. genxai/core/graph/engine.py +813 -0
  37. genxai/core/graph/executor.py +516 -0
  38. genxai/core/graph/nodes.py +161 -0
  39. genxai/core/graph/trigger_runner.py +40 -0
  40. genxai/core/memory/__init__.py +19 -0
  41. genxai/core/memory/base.py +72 -0
  42. genxai/core/memory/embedding.py +327 -0
  43. genxai/core/memory/episodic.py +448 -0
  44. genxai/core/memory/long_term.py +467 -0
  45. genxai/core/memory/manager.py +543 -0
  46. genxai/core/memory/persistence.py +297 -0
  47. genxai/core/memory/procedural.py +461 -0
  48. genxai/core/memory/semantic.py +526 -0
  49. genxai/core/memory/shared.py +62 -0
  50. genxai/core/memory/short_term.py +303 -0
  51. genxai/core/memory/vector_store.py +508 -0
  52. genxai/core/memory/working.py +211 -0
  53. genxai/core/state/__init__.py +6 -0
  54. genxai/core/state/manager.py +293 -0
  55. genxai/core/state/schema.py +115 -0
  56. genxai/llm/__init__.py +14 -0
  57. genxai/llm/base.py +150 -0
  58. genxai/llm/factory.py +329 -0
  59. genxai/llm/providers/__init__.py +1 -0
  60. genxai/llm/providers/anthropic.py +249 -0
  61. genxai/llm/providers/cohere.py +274 -0
  62. genxai/llm/providers/google.py +334 -0
  63. genxai/llm/providers/ollama.py +147 -0
  64. genxai/llm/providers/openai.py +257 -0
  65. genxai/llm/routing.py +83 -0
  66. genxai/observability/__init__.py +6 -0
  67. genxai/observability/logging.py +327 -0
  68. genxai/observability/metrics.py +494 -0
  69. genxai/observability/tracing.py +372 -0
  70. genxai/performance/__init__.py +39 -0
  71. genxai/performance/cache.py +256 -0
  72. genxai/performance/pooling.py +289 -0
  73. genxai/security/audit.py +304 -0
  74. genxai/security/auth.py +315 -0
  75. genxai/security/cost_control.py +528 -0
  76. genxai/security/default_policies.py +44 -0
  77. genxai/security/jwt.py +142 -0
  78. genxai/security/oauth.py +226 -0
  79. genxai/security/pii.py +366 -0
  80. genxai/security/policy_engine.py +82 -0
  81. genxai/security/rate_limit.py +341 -0
  82. genxai/security/rbac.py +247 -0
  83. genxai/security/validation.py +218 -0
  84. genxai/tools/__init__.py +21 -0
  85. genxai/tools/base.py +383 -0
  86. genxai/tools/builtin/__init__.py +131 -0
  87. genxai/tools/builtin/communication/__init__.py +15 -0
  88. genxai/tools/builtin/communication/email_sender.py +159 -0
  89. genxai/tools/builtin/communication/notification_manager.py +167 -0
  90. genxai/tools/builtin/communication/slack_notifier.py +118 -0
  91. genxai/tools/builtin/communication/sms_sender.py +118 -0
  92. genxai/tools/builtin/communication/webhook_caller.py +136 -0
  93. genxai/tools/builtin/computation/__init__.py +15 -0
  94. genxai/tools/builtin/computation/calculator.py +101 -0
  95. genxai/tools/builtin/computation/code_executor.py +183 -0
  96. genxai/tools/builtin/computation/data_validator.py +259 -0
  97. genxai/tools/builtin/computation/hash_generator.py +129 -0
  98. genxai/tools/builtin/computation/regex_matcher.py +201 -0
  99. genxai/tools/builtin/data/__init__.py +15 -0
  100. genxai/tools/builtin/data/csv_processor.py +213 -0
  101. genxai/tools/builtin/data/data_transformer.py +299 -0
  102. genxai/tools/builtin/data/json_processor.py +233 -0
  103. genxai/tools/builtin/data/text_analyzer.py +288 -0
  104. genxai/tools/builtin/data/xml_processor.py +175 -0
  105. genxai/tools/builtin/database/__init__.py +15 -0
  106. genxai/tools/builtin/database/database_inspector.py +157 -0
  107. genxai/tools/builtin/database/mongodb_query.py +196 -0
  108. genxai/tools/builtin/database/redis_cache.py +167 -0
  109. genxai/tools/builtin/database/sql_query.py +145 -0
  110. genxai/tools/builtin/database/vector_search.py +163 -0
  111. genxai/tools/builtin/file/__init__.py +17 -0
  112. genxai/tools/builtin/file/directory_scanner.py +214 -0
  113. genxai/tools/builtin/file/file_compressor.py +237 -0
  114. genxai/tools/builtin/file/file_reader.py +102 -0
  115. genxai/tools/builtin/file/file_writer.py +122 -0
  116. genxai/tools/builtin/file/image_processor.py +186 -0
  117. genxai/tools/builtin/file/pdf_parser.py +144 -0
  118. genxai/tools/builtin/test/__init__.py +15 -0
  119. genxai/tools/builtin/test/async_simulator.py +62 -0
  120. genxai/tools/builtin/test/data_transformer.py +99 -0
  121. genxai/tools/builtin/test/error_generator.py +82 -0
  122. genxai/tools/builtin/test/simple_math.py +94 -0
  123. genxai/tools/builtin/test/string_processor.py +72 -0
  124. genxai/tools/builtin/web/__init__.py +15 -0
  125. genxai/tools/builtin/web/api_caller.py +161 -0
  126. genxai/tools/builtin/web/html_parser.py +330 -0
  127. genxai/tools/builtin/web/http_client.py +187 -0
  128. genxai/tools/builtin/web/url_validator.py +162 -0
  129. genxai/tools/builtin/web/web_scraper.py +170 -0
  130. genxai/tools/custom/my_test_tool_2.py +9 -0
  131. genxai/tools/dynamic.py +105 -0
  132. genxai/tools/mcp_server.py +167 -0
  133. genxai/tools/persistence/__init__.py +6 -0
  134. genxai/tools/persistence/models.py +55 -0
  135. genxai/tools/persistence/service.py +322 -0
  136. genxai/tools/registry.py +227 -0
  137. genxai/tools/security/__init__.py +11 -0
  138. genxai/tools/security/limits.py +214 -0
  139. genxai/tools/security/policy.py +20 -0
  140. genxai/tools/security/sandbox.py +248 -0
  141. genxai/tools/templates.py +435 -0
  142. genxai/triggers/__init__.py +19 -0
  143. genxai/triggers/base.py +104 -0
  144. genxai/triggers/file_watcher.py +75 -0
  145. genxai/triggers/queue.py +68 -0
  146. genxai/triggers/registry.py +82 -0
  147. genxai/triggers/schedule.py +66 -0
  148. genxai/triggers/webhook.py +68 -0
  149. genxai/utils/__init__.py +1 -0
  150. genxai/utils/tokens.py +295 -0
  151. genxai_framework-0.1.0.dist-info/METADATA +495 -0
  152. genxai_framework-0.1.0.dist-info/RECORD +156 -0
  153. genxai_framework-0.1.0.dist-info/WHEEL +5 -0
  154. genxai_framework-0.1.0.dist-info/entry_points.txt +2 -0
  155. genxai_framework-0.1.0.dist-info/licenses/LICENSE +21 -0
  156. genxai_framework-0.1.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,508 @@
1
+ """Vector store implementations for long-term memory."""
2
+
3
+ from typing import Any, Dict, List, Optional, Tuple
4
+ from abc import ABC, abstractmethod
5
+ import logging
6
+ from datetime import datetime
7
+
8
+ from genxai.core.memory.base import Memory, MemoryType
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ class VectorStore(ABC):
14
+ """Abstract base class for vector stores."""
15
+
16
+ @abstractmethod
17
+ async def store(
18
+ self,
19
+ memory: Memory,
20
+ embedding: List[float],
21
+ ) -> None:
22
+ """Store a memory with its embedding.
23
+
24
+ Args:
25
+ memory: Memory to store
26
+ embedding: Vector embedding of the memory
27
+ """
28
+ pass
29
+
30
+ @abstractmethod
31
+ async def search(
32
+ self,
33
+ query_embedding: List[float],
34
+ limit: int = 10,
35
+ filters: Optional[Dict[str, Any]] = None,
36
+ ) -> List[Tuple[Memory, float]]:
37
+ """Search for similar memories.
38
+
39
+ Args:
40
+ query_embedding: Query vector
41
+ limit: Maximum number of results
42
+ filters: Optional metadata filters
43
+
44
+ Returns:
45
+ List of (memory, similarity_score) tuples
46
+ """
47
+ pass
48
+
49
+ @abstractmethod
50
+ async def delete(self, memory_id: str) -> bool:
51
+ """Delete a memory by ID.
52
+
53
+ Args:
54
+ memory_id: ID of memory to delete
55
+
56
+ Returns:
57
+ True if deleted, False if not found
58
+ """
59
+ pass
60
+
61
+ @abstractmethod
62
+ async def clear(self) -> None:
63
+ """Clear all memories."""
64
+ pass
65
+
66
+ @abstractmethod
67
+ async def get_stats(self) -> Dict[str, Any]:
68
+ """Get vector store statistics."""
69
+ pass
70
+
71
+
72
+ class ChromaVectorStore(VectorStore):
73
+ """ChromaDB vector store implementation."""
74
+
75
+ def __init__(
76
+ self,
77
+ collection_name: str = "genxai_memories",
78
+ persist_directory: Optional[str] = None,
79
+ ) -> None:
80
+ """Initialize ChromaDB vector store.
81
+
82
+ Args:
83
+ collection_name: Name of the collection
84
+ persist_directory: Directory to persist data (None for in-memory)
85
+ """
86
+ self.collection_name = collection_name
87
+ self.persist_directory = persist_directory
88
+ self._client = None
89
+ self._collection = None
90
+ self._initialized = False
91
+
92
+ async def _ensure_initialized(self) -> None:
93
+ """Ensure ChromaDB client is initialized."""
94
+ if self._initialized:
95
+ return
96
+
97
+ try:
98
+ import chromadb
99
+ from chromadb.config import Settings
100
+
101
+ if self.persist_directory:
102
+ self._client = chromadb.Client(
103
+ Settings(
104
+ persist_directory=self.persist_directory,
105
+ anonymized_telemetry=False,
106
+ )
107
+ )
108
+ else:
109
+ self._client = chromadb.Client()
110
+
111
+ # Get or create collection
112
+ self._collection = self._client.get_or_create_collection(
113
+ name=self.collection_name,
114
+ metadata={"description": "GenXAI agent memories"},
115
+ )
116
+
117
+ self._initialized = True
118
+ logger.info(f"Initialized ChromaDB collection: {self.collection_name}")
119
+
120
+ except ImportError:
121
+ logger.error(
122
+ "ChromaDB not installed. Install with: pip install chromadb"
123
+ )
124
+ raise RuntimeError("ChromaDB not available")
125
+ except Exception as e:
126
+ logger.error(f"Failed to initialize ChromaDB: {e}")
127
+ raise
128
+
129
+ async def store(
130
+ self,
131
+ memory: Memory,
132
+ embedding: List[float],
133
+ ) -> None:
134
+ """Store a memory with its embedding."""
135
+ await self._ensure_initialized()
136
+
137
+ try:
138
+ # Prepare metadata
139
+ metadata = {
140
+ "type": memory.type.value,
141
+ "importance": memory.importance,
142
+ "timestamp": memory.timestamp.isoformat(),
143
+ "access_count": memory.access_count,
144
+ "tags": ",".join(memory.tags) if memory.tags else "",
145
+ **memory.metadata,
146
+ }
147
+
148
+ # Store in ChromaDB
149
+ self._collection.add(
150
+ ids=[memory.id],
151
+ embeddings=[embedding],
152
+ documents=[str(memory.content)],
153
+ metadatas=[metadata],
154
+ )
155
+
156
+ logger.debug(f"Stored memory {memory.id} in ChromaDB")
157
+
158
+ except Exception as e:
159
+ logger.error(f"Failed to store memory in ChromaDB: {e}")
160
+ raise
161
+
162
+ async def search(
163
+ self,
164
+ query_embedding: List[float],
165
+ limit: int = 10,
166
+ filters: Optional[Dict[str, Any]] = None,
167
+ ) -> List[Tuple[Memory, float]]:
168
+ """Search for similar memories."""
169
+ await self._ensure_initialized()
170
+
171
+ try:
172
+ # Build where clause for filters
173
+ where = None
174
+ if filters:
175
+ where = {}
176
+ for key, value in filters.items():
177
+ if key in ["type", "importance", "tags"]:
178
+ where[key] = value
179
+
180
+ # Query ChromaDB
181
+ results = self._collection.query(
182
+ query_embeddings=[query_embedding],
183
+ n_results=limit,
184
+ where=where,
185
+ )
186
+
187
+ # Convert results to Memory objects
188
+ memories = []
189
+ if results["ids"] and results["ids"][0]:
190
+ for i, memory_id in enumerate(results["ids"][0]):
191
+ metadata = results["metadatas"][0][i]
192
+ content = results["documents"][0][i]
193
+ distance = results["distances"][0][i] if "distances" in results else 0.0
194
+
195
+ # Reconstruct Memory object
196
+ memory = Memory(
197
+ id=memory_id,
198
+ type=MemoryType(metadata["type"]),
199
+ content=content,
200
+ metadata={k: v for k, v in metadata.items() if k not in ["type", "importance", "timestamp", "access_count", "tags"]},
201
+ timestamp=datetime.fromisoformat(metadata["timestamp"]),
202
+ importance=metadata["importance"],
203
+ access_count=metadata["access_count"],
204
+ last_accessed=datetime.now(),
205
+ tags=metadata["tags"].split(",") if metadata.get("tags") else [],
206
+ )
207
+
208
+ # Convert distance to similarity score (0-1)
209
+ similarity = 1.0 / (1.0 + distance)
210
+ memories.append((memory, similarity))
211
+
212
+ logger.debug(f"Found {len(memories)} similar memories in ChromaDB")
213
+ return memories
214
+
215
+ except Exception as e:
216
+ logger.error(f"Failed to search ChromaDB: {e}")
217
+ return []
218
+
219
+ async def delete(self, memory_id: str) -> bool:
220
+ """Delete a memory by ID."""
221
+ await self._ensure_initialized()
222
+
223
+ try:
224
+ self._collection.delete(ids=[memory_id])
225
+ logger.debug(f"Deleted memory {memory_id} from ChromaDB")
226
+ return True
227
+ except Exception as e:
228
+ logger.error(f"Failed to delete memory from ChromaDB: {e}")
229
+ return False
230
+
231
+ async def clear(self) -> None:
232
+ """Clear all memories."""
233
+ await self._ensure_initialized()
234
+
235
+ try:
236
+ # Delete and recreate collection
237
+ self._client.delete_collection(name=self.collection_name)
238
+ self._collection = self._client.create_collection(
239
+ name=self.collection_name,
240
+ metadata={"description": "GenXAI agent memories"},
241
+ )
242
+ logger.info(f"Cleared ChromaDB collection: {self.collection_name}")
243
+ except Exception as e:
244
+ logger.error(f"Failed to clear ChromaDB: {e}")
245
+ raise
246
+
247
+ async def get_stats(self) -> Dict[str, Any]:
248
+ """Get vector store statistics."""
249
+ await self._ensure_initialized()
250
+
251
+ try:
252
+ count = self._collection.count()
253
+ return {
254
+ "backend": "chromadb",
255
+ "collection": self.collection_name,
256
+ "count": count,
257
+ "persist_directory": self.persist_directory,
258
+ }
259
+ except Exception as e:
260
+ logger.error(f"Failed to get ChromaDB stats: {e}")
261
+ return {"backend": "chromadb", "error": str(e)}
262
+
263
+
264
+ class PineconeVectorStore(VectorStore):
265
+ """Pinecone vector store implementation."""
266
+
267
+ def __init__(
268
+ self,
269
+ index_name: str = "genxai-memories",
270
+ api_key: Optional[str] = None,
271
+ environment: Optional[str] = None,
272
+ dimension: int = 1536,
273
+ ) -> None:
274
+ """Initialize Pinecone vector store.
275
+
276
+ Args:
277
+ index_name: Name of the Pinecone index
278
+ api_key: Pinecone API key (or set PINECONE_API_KEY env var)
279
+ environment: Pinecone environment (or set PINECONE_ENVIRONMENT env var)
280
+ dimension: Vector dimension
281
+ """
282
+ self.index_name = index_name
283
+ self.api_key = api_key
284
+ self.environment = environment
285
+ self.dimension = dimension
286
+ self._index = None
287
+ self._initialized = False
288
+
289
+ async def _ensure_initialized(self) -> None:
290
+ """Ensure Pinecone client is initialized."""
291
+ if self._initialized:
292
+ return
293
+
294
+ try:
295
+ import pinecone
296
+ import os
297
+
298
+ # Get API key and environment
299
+ api_key = self.api_key or os.getenv("PINECONE_API_KEY")
300
+ environment = self.environment or os.getenv("PINECONE_ENVIRONMENT")
301
+
302
+ if not api_key or not environment:
303
+ raise ValueError(
304
+ "Pinecone API key and environment required. "
305
+ "Set PINECONE_API_KEY and PINECONE_ENVIRONMENT env vars."
306
+ )
307
+
308
+ # Initialize Pinecone
309
+ pinecone.init(api_key=api_key, environment=environment)
310
+
311
+ # Create index if it doesn't exist
312
+ if self.index_name not in pinecone.list_indexes():
313
+ pinecone.create_index(
314
+ name=self.index_name,
315
+ dimension=self.dimension,
316
+ metric="cosine",
317
+ )
318
+ logger.info(f"Created Pinecone index: {self.index_name}")
319
+
320
+ # Connect to index
321
+ self._index = pinecone.Index(self.index_name)
322
+ self._initialized = True
323
+ logger.info(f"Initialized Pinecone index: {self.index_name}")
324
+
325
+ except ImportError:
326
+ logger.error(
327
+ "Pinecone not installed. Install with: pip install pinecone-client"
328
+ )
329
+ raise RuntimeError("Pinecone not available")
330
+ except Exception as e:
331
+ logger.error(f"Failed to initialize Pinecone: {e}")
332
+ raise
333
+
334
+ async def store(
335
+ self,
336
+ memory: Memory,
337
+ embedding: List[float],
338
+ ) -> None:
339
+ """Store a memory with its embedding."""
340
+ await self._ensure_initialized()
341
+
342
+ try:
343
+ # Prepare metadata
344
+ metadata = {
345
+ "type": memory.type.value,
346
+ "content": str(memory.content),
347
+ "importance": memory.importance,
348
+ "timestamp": memory.timestamp.isoformat(),
349
+ "access_count": memory.access_count,
350
+ "tags": ",".join(memory.tags) if memory.tags else "",
351
+ **memory.metadata,
352
+ }
353
+
354
+ # Store in Pinecone
355
+ self._index.upsert(
356
+ vectors=[(memory.id, embedding, metadata)]
357
+ )
358
+
359
+ logger.debug(f"Stored memory {memory.id} in Pinecone")
360
+
361
+ except Exception as e:
362
+ logger.error(f"Failed to store memory in Pinecone: {e}")
363
+ raise
364
+
365
+ async def search(
366
+ self,
367
+ query_embedding: List[float],
368
+ limit: int = 10,
369
+ filters: Optional[Dict[str, Any]] = None,
370
+ ) -> List[Tuple[Memory, float]]:
371
+ """Search for similar memories."""
372
+ await self._ensure_initialized()
373
+
374
+ try:
375
+ # Build filter
376
+ filter_dict = None
377
+ if filters:
378
+ filter_dict = {}
379
+ for key, value in filters.items():
380
+ if key in ["type", "importance", "tags"]:
381
+ filter_dict[key] = value
382
+
383
+ # Query Pinecone
384
+ results = self._index.query(
385
+ vector=query_embedding,
386
+ top_k=limit,
387
+ filter=filter_dict,
388
+ include_metadata=True,
389
+ )
390
+
391
+ # Convert results to Memory objects
392
+ memories = []
393
+ for match in results.matches:
394
+ metadata = match.metadata
395
+
396
+ # Reconstruct Memory object
397
+ memory = Memory(
398
+ id=match.id,
399
+ type=MemoryType(metadata["type"]),
400
+ content=metadata["content"],
401
+ metadata={k: v for k, v in metadata.items() if k not in ["type", "content", "importance", "timestamp", "access_count", "tags"]},
402
+ timestamp=datetime.fromisoformat(metadata["timestamp"]),
403
+ importance=metadata["importance"],
404
+ access_count=metadata["access_count"],
405
+ last_accessed=datetime.now(),
406
+ tags=metadata["tags"].split(",") if metadata.get("tags") else [],
407
+ )
408
+
409
+ memories.append((memory, match.score))
410
+
411
+ logger.debug(f"Found {len(memories)} similar memories in Pinecone")
412
+ return memories
413
+
414
+ except Exception as e:
415
+ logger.error(f"Failed to search Pinecone: {e}")
416
+ return []
417
+
418
+ async def delete(self, memory_id: str) -> bool:
419
+ """Delete a memory by ID."""
420
+ await self._ensure_initialized()
421
+
422
+ try:
423
+ self._index.delete(ids=[memory_id])
424
+ logger.debug(f"Deleted memory {memory_id} from Pinecone")
425
+ return True
426
+ except Exception as e:
427
+ logger.error(f"Failed to delete memory from Pinecone: {e}")
428
+ return False
429
+
430
+ async def clear(self) -> None:
431
+ """Clear all memories."""
432
+ await self._ensure_initialized()
433
+
434
+ try:
435
+ self._index.delete(delete_all=True)
436
+ logger.info(f"Cleared Pinecone index: {self.index_name}")
437
+ except Exception as e:
438
+ logger.error(f"Failed to clear Pinecone: {e}")
439
+ raise
440
+
441
+ async def get_stats(self) -> Dict[str, Any]:
442
+ """Get vector store statistics."""
443
+ await self._ensure_initialized()
444
+
445
+ try:
446
+ stats = self._index.describe_index_stats()
447
+ return {
448
+ "backend": "pinecone",
449
+ "index": self.index_name,
450
+ "dimension": self.dimension,
451
+ "total_vector_count": stats.total_vector_count,
452
+ "namespaces": stats.namespaces,
453
+ }
454
+ except Exception as e:
455
+ logger.error(f"Failed to get Pinecone stats: {e}")
456
+ return {"backend": "pinecone", "error": str(e)}
457
+
458
+
459
+ class VectorStoreFactory:
460
+ """Factory for creating vector stores."""
461
+
462
+ _stores = {
463
+ "chromadb": ChromaVectorStore,
464
+ "pinecone": PineconeVectorStore,
465
+ }
466
+
467
+ @classmethod
468
+ def create(
469
+ cls,
470
+ backend: str,
471
+ **kwargs
472
+ ) -> VectorStore:
473
+ """Create a vector store instance.
474
+
475
+ Args:
476
+ backend: Vector store backend ("chromadb", "pinecone")
477
+ **kwargs: Backend-specific arguments
478
+
479
+ Returns:
480
+ VectorStore instance
481
+
482
+ Raises:
483
+ ValueError: If backend is not supported
484
+ """
485
+ if backend not in cls._stores:
486
+ raise ValueError(
487
+ f"Unsupported vector store backend: {backend}. "
488
+ f"Supported: {list(cls._stores.keys())}"
489
+ )
490
+
491
+ store_class = cls._stores[backend]
492
+ return store_class(**kwargs)
493
+
494
+ @classmethod
495
+ def register(cls, name: str, store_class: type) -> None:
496
+ """Register a custom vector store.
497
+
498
+ Args:
499
+ name: Name of the vector store
500
+ store_class: Vector store class
501
+ """
502
+ cls._stores[name] = store_class
503
+ logger.info(f"Registered vector store: {name}")
504
+
505
+ @classmethod
506
+ def list_backends(cls) -> List[str]:
507
+ """List available vector store backends."""
508
+ return list(cls._stores.keys())