PraisonAI 3.0.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.
- praisonai/__init__.py +54 -0
- praisonai/__main__.py +15 -0
- praisonai/acp/__init__.py +54 -0
- praisonai/acp/config.py +159 -0
- praisonai/acp/server.py +587 -0
- praisonai/acp/session.py +219 -0
- praisonai/adapters/__init__.py +50 -0
- praisonai/adapters/readers.py +395 -0
- praisonai/adapters/rerankers.py +315 -0
- praisonai/adapters/retrievers.py +394 -0
- praisonai/adapters/vector_stores.py +409 -0
- praisonai/agent_scheduler.py +337 -0
- praisonai/agents_generator.py +903 -0
- praisonai/api/call.py +292 -0
- praisonai/auto.py +1197 -0
- praisonai/capabilities/__init__.py +275 -0
- praisonai/capabilities/a2a.py +140 -0
- praisonai/capabilities/assistants.py +283 -0
- praisonai/capabilities/audio.py +320 -0
- praisonai/capabilities/batches.py +469 -0
- praisonai/capabilities/completions.py +336 -0
- praisonai/capabilities/container_files.py +155 -0
- praisonai/capabilities/containers.py +93 -0
- praisonai/capabilities/embeddings.py +158 -0
- praisonai/capabilities/files.py +467 -0
- praisonai/capabilities/fine_tuning.py +293 -0
- praisonai/capabilities/guardrails.py +182 -0
- praisonai/capabilities/images.py +330 -0
- praisonai/capabilities/mcp.py +190 -0
- praisonai/capabilities/messages.py +270 -0
- praisonai/capabilities/moderations.py +154 -0
- praisonai/capabilities/ocr.py +217 -0
- praisonai/capabilities/passthrough.py +204 -0
- praisonai/capabilities/rag.py +207 -0
- praisonai/capabilities/realtime.py +160 -0
- praisonai/capabilities/rerank.py +165 -0
- praisonai/capabilities/responses.py +266 -0
- praisonai/capabilities/search.py +109 -0
- praisonai/capabilities/skills.py +133 -0
- praisonai/capabilities/vector_store_files.py +334 -0
- praisonai/capabilities/vector_stores.py +304 -0
- praisonai/capabilities/videos.py +141 -0
- praisonai/chainlit_ui.py +304 -0
- praisonai/chat/__init__.py +106 -0
- praisonai/chat/app.py +125 -0
- praisonai/cli/__init__.py +26 -0
- praisonai/cli/app.py +213 -0
- praisonai/cli/commands/__init__.py +75 -0
- praisonai/cli/commands/acp.py +70 -0
- praisonai/cli/commands/completion.py +333 -0
- praisonai/cli/commands/config.py +166 -0
- praisonai/cli/commands/debug.py +142 -0
- praisonai/cli/commands/diag.py +55 -0
- praisonai/cli/commands/doctor.py +166 -0
- praisonai/cli/commands/environment.py +179 -0
- praisonai/cli/commands/lsp.py +112 -0
- praisonai/cli/commands/mcp.py +210 -0
- praisonai/cli/commands/profile.py +457 -0
- praisonai/cli/commands/run.py +228 -0
- praisonai/cli/commands/schedule.py +150 -0
- praisonai/cli/commands/serve.py +97 -0
- praisonai/cli/commands/session.py +212 -0
- praisonai/cli/commands/traces.py +145 -0
- praisonai/cli/commands/version.py +101 -0
- praisonai/cli/configuration/__init__.py +18 -0
- praisonai/cli/configuration/loader.py +353 -0
- praisonai/cli/configuration/paths.py +114 -0
- praisonai/cli/configuration/schema.py +164 -0
- praisonai/cli/features/__init__.py +268 -0
- praisonai/cli/features/acp.py +236 -0
- praisonai/cli/features/action_orchestrator.py +546 -0
- praisonai/cli/features/agent_scheduler.py +773 -0
- praisonai/cli/features/agent_tools.py +474 -0
- praisonai/cli/features/agents.py +375 -0
- praisonai/cli/features/at_mentions.py +471 -0
- praisonai/cli/features/auto_memory.py +182 -0
- praisonai/cli/features/autonomy_mode.py +490 -0
- praisonai/cli/features/background.py +356 -0
- praisonai/cli/features/base.py +168 -0
- praisonai/cli/features/capabilities.py +1326 -0
- praisonai/cli/features/checkpoints.py +338 -0
- praisonai/cli/features/code_intelligence.py +652 -0
- praisonai/cli/features/compaction.py +294 -0
- praisonai/cli/features/compare.py +534 -0
- praisonai/cli/features/cost_tracker.py +514 -0
- praisonai/cli/features/debug.py +810 -0
- praisonai/cli/features/deploy.py +517 -0
- praisonai/cli/features/diag.py +289 -0
- praisonai/cli/features/doctor/__init__.py +63 -0
- praisonai/cli/features/doctor/checks/__init__.py +24 -0
- praisonai/cli/features/doctor/checks/acp_checks.py +240 -0
- praisonai/cli/features/doctor/checks/config_checks.py +366 -0
- praisonai/cli/features/doctor/checks/db_checks.py +366 -0
- praisonai/cli/features/doctor/checks/env_checks.py +543 -0
- praisonai/cli/features/doctor/checks/lsp_checks.py +199 -0
- praisonai/cli/features/doctor/checks/mcp_checks.py +349 -0
- praisonai/cli/features/doctor/checks/memory_checks.py +268 -0
- praisonai/cli/features/doctor/checks/network_checks.py +251 -0
- praisonai/cli/features/doctor/checks/obs_checks.py +328 -0
- praisonai/cli/features/doctor/checks/performance_checks.py +235 -0
- praisonai/cli/features/doctor/checks/permissions_checks.py +259 -0
- praisonai/cli/features/doctor/checks/selftest_checks.py +322 -0
- praisonai/cli/features/doctor/checks/serve_checks.py +426 -0
- praisonai/cli/features/doctor/checks/skills_checks.py +231 -0
- praisonai/cli/features/doctor/checks/tools_checks.py +371 -0
- praisonai/cli/features/doctor/engine.py +266 -0
- praisonai/cli/features/doctor/formatters.py +310 -0
- praisonai/cli/features/doctor/handler.py +397 -0
- praisonai/cli/features/doctor/models.py +264 -0
- praisonai/cli/features/doctor/registry.py +239 -0
- praisonai/cli/features/endpoints.py +1019 -0
- praisonai/cli/features/eval.py +560 -0
- praisonai/cli/features/external_agents.py +231 -0
- praisonai/cli/features/fast_context.py +410 -0
- praisonai/cli/features/flow_display.py +566 -0
- praisonai/cli/features/git_integration.py +651 -0
- praisonai/cli/features/guardrail.py +171 -0
- praisonai/cli/features/handoff.py +185 -0
- praisonai/cli/features/hooks.py +583 -0
- praisonai/cli/features/image.py +384 -0
- praisonai/cli/features/interactive_runtime.py +585 -0
- praisonai/cli/features/interactive_tools.py +380 -0
- praisonai/cli/features/interactive_tui.py +603 -0
- praisonai/cli/features/jobs.py +632 -0
- praisonai/cli/features/knowledge.py +531 -0
- praisonai/cli/features/lite.py +244 -0
- praisonai/cli/features/lsp_cli.py +225 -0
- praisonai/cli/features/mcp.py +169 -0
- praisonai/cli/features/message_queue.py +587 -0
- praisonai/cli/features/metrics.py +211 -0
- praisonai/cli/features/n8n.py +673 -0
- praisonai/cli/features/observability.py +293 -0
- praisonai/cli/features/ollama.py +361 -0
- praisonai/cli/features/output_style.py +273 -0
- praisonai/cli/features/package.py +631 -0
- praisonai/cli/features/performance.py +308 -0
- praisonai/cli/features/persistence.py +636 -0
- praisonai/cli/features/profile.py +226 -0
- praisonai/cli/features/profiler/__init__.py +81 -0
- praisonai/cli/features/profiler/core.py +558 -0
- praisonai/cli/features/profiler/optimizations.py +652 -0
- praisonai/cli/features/profiler/suite.py +386 -0
- praisonai/cli/features/profiling.py +350 -0
- praisonai/cli/features/queue/__init__.py +73 -0
- praisonai/cli/features/queue/manager.py +395 -0
- praisonai/cli/features/queue/models.py +286 -0
- praisonai/cli/features/queue/persistence.py +564 -0
- praisonai/cli/features/queue/scheduler.py +484 -0
- praisonai/cli/features/queue/worker.py +372 -0
- praisonai/cli/features/recipe.py +1723 -0
- praisonai/cli/features/recipes.py +449 -0
- praisonai/cli/features/registry.py +229 -0
- praisonai/cli/features/repo_map.py +860 -0
- praisonai/cli/features/router.py +466 -0
- praisonai/cli/features/sandbox_executor.py +515 -0
- praisonai/cli/features/serve.py +829 -0
- praisonai/cli/features/session.py +222 -0
- praisonai/cli/features/skills.py +856 -0
- praisonai/cli/features/slash_commands.py +650 -0
- praisonai/cli/features/telemetry.py +179 -0
- praisonai/cli/features/templates.py +1384 -0
- praisonai/cli/features/thinking.py +305 -0
- praisonai/cli/features/todo.py +334 -0
- praisonai/cli/features/tools.py +680 -0
- praisonai/cli/features/tui/__init__.py +83 -0
- praisonai/cli/features/tui/app.py +580 -0
- praisonai/cli/features/tui/cli.py +566 -0
- praisonai/cli/features/tui/debug.py +511 -0
- praisonai/cli/features/tui/events.py +99 -0
- praisonai/cli/features/tui/mock_provider.py +328 -0
- praisonai/cli/features/tui/orchestrator.py +652 -0
- praisonai/cli/features/tui/screens/__init__.py +50 -0
- praisonai/cli/features/tui/screens/main.py +245 -0
- praisonai/cli/features/tui/screens/queue.py +174 -0
- praisonai/cli/features/tui/screens/session.py +124 -0
- praisonai/cli/features/tui/screens/settings.py +148 -0
- praisonai/cli/features/tui/widgets/__init__.py +56 -0
- praisonai/cli/features/tui/widgets/chat.py +261 -0
- praisonai/cli/features/tui/widgets/composer.py +224 -0
- praisonai/cli/features/tui/widgets/queue_panel.py +200 -0
- praisonai/cli/features/tui/widgets/status.py +167 -0
- praisonai/cli/features/tui/widgets/tool_panel.py +248 -0
- praisonai/cli/features/workflow.py +720 -0
- praisonai/cli/legacy.py +236 -0
- praisonai/cli/main.py +5559 -0
- praisonai/cli/schedule_cli.py +54 -0
- praisonai/cli/state/__init__.py +31 -0
- praisonai/cli/state/identifiers.py +161 -0
- praisonai/cli/state/sessions.py +313 -0
- praisonai/code/__init__.py +93 -0
- praisonai/code/agent_tools.py +344 -0
- praisonai/code/diff/__init__.py +21 -0
- praisonai/code/diff/diff_strategy.py +432 -0
- praisonai/code/tools/__init__.py +27 -0
- praisonai/code/tools/apply_diff.py +221 -0
- praisonai/code/tools/execute_command.py +275 -0
- praisonai/code/tools/list_files.py +274 -0
- praisonai/code/tools/read_file.py +206 -0
- praisonai/code/tools/search_replace.py +248 -0
- praisonai/code/tools/write_file.py +217 -0
- praisonai/code/utils/__init__.py +46 -0
- praisonai/code/utils/file_utils.py +307 -0
- praisonai/code/utils/ignore_utils.py +308 -0
- praisonai/code/utils/text_utils.py +276 -0
- praisonai/db/__init__.py +64 -0
- praisonai/db/adapter.py +531 -0
- praisonai/deploy/__init__.py +62 -0
- praisonai/deploy/api.py +231 -0
- praisonai/deploy/docker.py +454 -0
- praisonai/deploy/doctor.py +367 -0
- praisonai/deploy/main.py +327 -0
- praisonai/deploy/models.py +179 -0
- praisonai/deploy/providers/__init__.py +33 -0
- praisonai/deploy/providers/aws.py +331 -0
- praisonai/deploy/providers/azure.py +358 -0
- praisonai/deploy/providers/base.py +101 -0
- praisonai/deploy/providers/gcp.py +314 -0
- praisonai/deploy/schema.py +208 -0
- praisonai/deploy.py +185 -0
- praisonai/endpoints/__init__.py +53 -0
- praisonai/endpoints/a2u_server.py +410 -0
- praisonai/endpoints/discovery.py +165 -0
- praisonai/endpoints/providers/__init__.py +28 -0
- praisonai/endpoints/providers/a2a.py +253 -0
- praisonai/endpoints/providers/a2u.py +208 -0
- praisonai/endpoints/providers/agents_api.py +171 -0
- praisonai/endpoints/providers/base.py +231 -0
- praisonai/endpoints/providers/mcp.py +263 -0
- praisonai/endpoints/providers/recipe.py +206 -0
- praisonai/endpoints/providers/tools_mcp.py +150 -0
- praisonai/endpoints/registry.py +131 -0
- praisonai/endpoints/server.py +161 -0
- praisonai/inbuilt_tools/__init__.py +24 -0
- praisonai/inbuilt_tools/autogen_tools.py +117 -0
- praisonai/inc/__init__.py +2 -0
- praisonai/inc/config.py +96 -0
- praisonai/inc/models.py +155 -0
- praisonai/integrations/__init__.py +56 -0
- praisonai/integrations/base.py +303 -0
- praisonai/integrations/claude_code.py +270 -0
- praisonai/integrations/codex_cli.py +255 -0
- praisonai/integrations/cursor_cli.py +195 -0
- praisonai/integrations/gemini_cli.py +222 -0
- praisonai/jobs/__init__.py +67 -0
- praisonai/jobs/executor.py +425 -0
- praisonai/jobs/models.py +230 -0
- praisonai/jobs/router.py +314 -0
- praisonai/jobs/server.py +186 -0
- praisonai/jobs/store.py +203 -0
- praisonai/llm/__init__.py +66 -0
- praisonai/llm/registry.py +382 -0
- praisonai/mcp_server/__init__.py +152 -0
- praisonai/mcp_server/adapters/__init__.py +74 -0
- praisonai/mcp_server/adapters/agents.py +128 -0
- praisonai/mcp_server/adapters/capabilities.py +168 -0
- praisonai/mcp_server/adapters/cli_tools.py +568 -0
- praisonai/mcp_server/adapters/extended_capabilities.py +462 -0
- praisonai/mcp_server/adapters/knowledge.py +93 -0
- praisonai/mcp_server/adapters/memory.py +104 -0
- praisonai/mcp_server/adapters/prompts.py +306 -0
- praisonai/mcp_server/adapters/resources.py +124 -0
- praisonai/mcp_server/adapters/tools_bridge.py +280 -0
- praisonai/mcp_server/auth/__init__.py +48 -0
- praisonai/mcp_server/auth/api_key.py +291 -0
- praisonai/mcp_server/auth/oauth.py +460 -0
- praisonai/mcp_server/auth/oidc.py +289 -0
- praisonai/mcp_server/auth/scopes.py +260 -0
- praisonai/mcp_server/cli.py +852 -0
- praisonai/mcp_server/elicitation.py +445 -0
- praisonai/mcp_server/icons.py +302 -0
- praisonai/mcp_server/recipe_adapter.py +573 -0
- praisonai/mcp_server/recipe_cli.py +824 -0
- praisonai/mcp_server/registry.py +703 -0
- praisonai/mcp_server/sampling.py +422 -0
- praisonai/mcp_server/server.py +490 -0
- praisonai/mcp_server/tasks.py +443 -0
- praisonai/mcp_server/transports/__init__.py +18 -0
- praisonai/mcp_server/transports/http_stream.py +376 -0
- praisonai/mcp_server/transports/stdio.py +132 -0
- praisonai/persistence/__init__.py +84 -0
- praisonai/persistence/config.py +238 -0
- praisonai/persistence/conversation/__init__.py +25 -0
- praisonai/persistence/conversation/async_mysql.py +427 -0
- praisonai/persistence/conversation/async_postgres.py +410 -0
- praisonai/persistence/conversation/async_sqlite.py +371 -0
- praisonai/persistence/conversation/base.py +151 -0
- praisonai/persistence/conversation/json_store.py +250 -0
- praisonai/persistence/conversation/mysql.py +387 -0
- praisonai/persistence/conversation/postgres.py +401 -0
- praisonai/persistence/conversation/singlestore.py +240 -0
- praisonai/persistence/conversation/sqlite.py +341 -0
- praisonai/persistence/conversation/supabase.py +203 -0
- praisonai/persistence/conversation/surrealdb.py +287 -0
- praisonai/persistence/factory.py +301 -0
- praisonai/persistence/hooks/__init__.py +18 -0
- praisonai/persistence/hooks/agent_hooks.py +297 -0
- praisonai/persistence/knowledge/__init__.py +26 -0
- praisonai/persistence/knowledge/base.py +144 -0
- praisonai/persistence/knowledge/cassandra.py +232 -0
- praisonai/persistence/knowledge/chroma.py +295 -0
- praisonai/persistence/knowledge/clickhouse.py +242 -0
- praisonai/persistence/knowledge/cosmosdb_vector.py +438 -0
- praisonai/persistence/knowledge/couchbase.py +286 -0
- praisonai/persistence/knowledge/lancedb.py +216 -0
- praisonai/persistence/knowledge/langchain_adapter.py +291 -0
- praisonai/persistence/knowledge/lightrag_adapter.py +212 -0
- praisonai/persistence/knowledge/llamaindex_adapter.py +256 -0
- praisonai/persistence/knowledge/milvus.py +277 -0
- praisonai/persistence/knowledge/mongodb_vector.py +306 -0
- praisonai/persistence/knowledge/pgvector.py +335 -0
- praisonai/persistence/knowledge/pinecone.py +253 -0
- praisonai/persistence/knowledge/qdrant.py +301 -0
- praisonai/persistence/knowledge/redis_vector.py +291 -0
- praisonai/persistence/knowledge/singlestore_vector.py +299 -0
- praisonai/persistence/knowledge/surrealdb_vector.py +309 -0
- praisonai/persistence/knowledge/upstash_vector.py +266 -0
- praisonai/persistence/knowledge/weaviate.py +223 -0
- praisonai/persistence/migrations/__init__.py +10 -0
- praisonai/persistence/migrations/manager.py +251 -0
- praisonai/persistence/orchestrator.py +406 -0
- praisonai/persistence/state/__init__.py +21 -0
- praisonai/persistence/state/async_mongodb.py +200 -0
- praisonai/persistence/state/base.py +107 -0
- praisonai/persistence/state/dynamodb.py +226 -0
- praisonai/persistence/state/firestore.py +175 -0
- praisonai/persistence/state/gcs.py +155 -0
- praisonai/persistence/state/memory.py +245 -0
- praisonai/persistence/state/mongodb.py +158 -0
- praisonai/persistence/state/redis.py +190 -0
- praisonai/persistence/state/upstash.py +144 -0
- praisonai/persistence/tests/__init__.py +3 -0
- praisonai/persistence/tests/test_all_backends.py +633 -0
- praisonai/profiler.py +1214 -0
- praisonai/recipe/__init__.py +134 -0
- praisonai/recipe/bridge.py +278 -0
- praisonai/recipe/core.py +893 -0
- praisonai/recipe/exceptions.py +54 -0
- praisonai/recipe/history.py +402 -0
- praisonai/recipe/models.py +266 -0
- praisonai/recipe/operations.py +440 -0
- praisonai/recipe/policy.py +422 -0
- praisonai/recipe/registry.py +849 -0
- praisonai/recipe/runtime.py +214 -0
- praisonai/recipe/security.py +711 -0
- praisonai/recipe/serve.py +859 -0
- praisonai/recipe/server.py +613 -0
- praisonai/scheduler/__init__.py +45 -0
- praisonai/scheduler/agent_scheduler.py +552 -0
- praisonai/scheduler/base.py +124 -0
- praisonai/scheduler/daemon_manager.py +225 -0
- praisonai/scheduler/state_manager.py +155 -0
- praisonai/scheduler/yaml_loader.py +193 -0
- praisonai/scheduler.py +194 -0
- praisonai/setup/__init__.py +1 -0
- praisonai/setup/build.py +21 -0
- praisonai/setup/post_install.py +23 -0
- praisonai/setup/setup_conda_env.py +25 -0
- praisonai/setup.py +16 -0
- praisonai/templates/__init__.py +116 -0
- praisonai/templates/cache.py +364 -0
- praisonai/templates/dependency_checker.py +358 -0
- praisonai/templates/discovery.py +391 -0
- praisonai/templates/loader.py +564 -0
- praisonai/templates/registry.py +511 -0
- praisonai/templates/resolver.py +206 -0
- praisonai/templates/security.py +327 -0
- praisonai/templates/tool_override.py +498 -0
- praisonai/templates/tools_doctor.py +256 -0
- praisonai/test.py +105 -0
- praisonai/train.py +562 -0
- praisonai/train_vision.py +306 -0
- praisonai/ui/agents.py +824 -0
- praisonai/ui/callbacks.py +57 -0
- praisonai/ui/chainlit_compat.py +246 -0
- praisonai/ui/chat.py +532 -0
- praisonai/ui/code.py +717 -0
- praisonai/ui/colab.py +474 -0
- praisonai/ui/colab_chainlit.py +81 -0
- praisonai/ui/components/aicoder.py +284 -0
- praisonai/ui/context.py +283 -0
- praisonai/ui/database_config.py +56 -0
- praisonai/ui/db.py +294 -0
- praisonai/ui/realtime.py +488 -0
- praisonai/ui/realtimeclient/__init__.py +756 -0
- praisonai/ui/realtimeclient/tools.py +242 -0
- praisonai/ui/sql_alchemy.py +710 -0
- praisonai/upload_vision.py +140 -0
- praisonai/version.py +1 -0
- praisonai-3.0.0.dist-info/METADATA +3493 -0
- praisonai-3.0.0.dist-info/RECORD +393 -0
- praisonai-3.0.0.dist-info/WHEEL +5 -0
- praisonai-3.0.0.dist-info/entry_points.txt +4 -0
- praisonai-3.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
"""
|
|
2
|
+
SurrealDB Vector implementation of KnowledgeStore.
|
|
3
|
+
|
|
4
|
+
Requires: surrealdb
|
|
5
|
+
Install: pip install surrealdb
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
from typing import Any, Dict, List, Optional
|
|
10
|
+
|
|
11
|
+
from .base import KnowledgeStore, KnowledgeDocument
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class SurrealDBVectorKnowledgeStore(KnowledgeStore):
|
|
17
|
+
"""
|
|
18
|
+
SurrealDB vector store for knowledge/RAG.
|
|
19
|
+
|
|
20
|
+
Uses SurrealDB's vector capabilities.
|
|
21
|
+
|
|
22
|
+
Example:
|
|
23
|
+
store = SurrealDBVectorKnowledgeStore(
|
|
24
|
+
url="ws://localhost:8000/rpc",
|
|
25
|
+
namespace="praisonai",
|
|
26
|
+
database="vectors"
|
|
27
|
+
)
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
def __init__(
|
|
31
|
+
self,
|
|
32
|
+
url: str = "ws://localhost:8000/rpc",
|
|
33
|
+
namespace: str = "praisonai",
|
|
34
|
+
database: str = "vectors",
|
|
35
|
+
username: str = "root",
|
|
36
|
+
password: str = "root",
|
|
37
|
+
embedding_dim: int = 1536,
|
|
38
|
+
):
|
|
39
|
+
"""
|
|
40
|
+
Initialize SurrealDB Vector store.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
url: SurrealDB WebSocket URL
|
|
44
|
+
namespace: SurrealDB namespace
|
|
45
|
+
database: SurrealDB database
|
|
46
|
+
username: Authentication username
|
|
47
|
+
password: Authentication password
|
|
48
|
+
embedding_dim: Embedding dimension
|
|
49
|
+
"""
|
|
50
|
+
self.url = url
|
|
51
|
+
self.namespace = namespace
|
|
52
|
+
self.database = database
|
|
53
|
+
self.username = username
|
|
54
|
+
self.password = password
|
|
55
|
+
self.embedding_dim = embedding_dim
|
|
56
|
+
|
|
57
|
+
self._client = None
|
|
58
|
+
self._initialized = False
|
|
59
|
+
|
|
60
|
+
def _init_client(self):
|
|
61
|
+
"""Initialize SurrealDB client lazily."""
|
|
62
|
+
if self._initialized:
|
|
63
|
+
return
|
|
64
|
+
|
|
65
|
+
try:
|
|
66
|
+
from surrealdb import Surreal
|
|
67
|
+
except ImportError:
|
|
68
|
+
raise ImportError(
|
|
69
|
+
"surrealdb is required for SurrealDB Vector support. "
|
|
70
|
+
"Install with: pip install surrealdb"
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
import asyncio
|
|
74
|
+
|
|
75
|
+
async def connect():
|
|
76
|
+
client = Surreal(self.url)
|
|
77
|
+
await client.connect()
|
|
78
|
+
await client.signin({"user": self.username, "pass": self.password})
|
|
79
|
+
await client.use(self.namespace, self.database)
|
|
80
|
+
return client
|
|
81
|
+
|
|
82
|
+
loop = asyncio.get_event_loop()
|
|
83
|
+
self._client = loop.run_until_complete(connect())
|
|
84
|
+
self._initialized = True
|
|
85
|
+
|
|
86
|
+
def _run_async(self, coro):
|
|
87
|
+
"""Run async coroutine synchronously."""
|
|
88
|
+
import asyncio
|
|
89
|
+
return asyncio.get_event_loop().run_until_complete(coro)
|
|
90
|
+
|
|
91
|
+
def create_collection(
|
|
92
|
+
self,
|
|
93
|
+
name: str,
|
|
94
|
+
dimension: int = 1536,
|
|
95
|
+
distance: str = "cosine",
|
|
96
|
+
metadata: Optional[Dict[str, Any]] = None
|
|
97
|
+
) -> None:
|
|
98
|
+
"""Create a collection (SurrealDB creates tables on insert)."""
|
|
99
|
+
self._init_client()
|
|
100
|
+
# SurrealDB creates tables automatically
|
|
101
|
+
logger.info(f"Collection '{name}' will be created on first insert")
|
|
102
|
+
|
|
103
|
+
def delete_collection(self, name: str) -> bool:
|
|
104
|
+
"""Delete a collection."""
|
|
105
|
+
self._init_client()
|
|
106
|
+
try:
|
|
107
|
+
self._run_async(self._client.query(f"REMOVE TABLE {name}"))
|
|
108
|
+
return True
|
|
109
|
+
except Exception as e:
|
|
110
|
+
logger.error(f"Failed to delete collection {name}: {e}")
|
|
111
|
+
return False
|
|
112
|
+
|
|
113
|
+
def collection_exists(self, name: str) -> bool:
|
|
114
|
+
"""Check if collection exists."""
|
|
115
|
+
self._init_client()
|
|
116
|
+
try:
|
|
117
|
+
result = self._run_async(self._client.query(f"INFO FOR TABLE {name}"))
|
|
118
|
+
return bool(result)
|
|
119
|
+
except Exception:
|
|
120
|
+
return False
|
|
121
|
+
|
|
122
|
+
def list_collections(self) -> List[str]:
|
|
123
|
+
"""List all collections."""
|
|
124
|
+
self._init_client()
|
|
125
|
+
try:
|
|
126
|
+
result = self._run_async(self._client.query("INFO FOR DB"))
|
|
127
|
+
if result and len(result) > 0:
|
|
128
|
+
tables = result[0].get("result", {}).get("tables", {})
|
|
129
|
+
return list(tables.keys())
|
|
130
|
+
return []
|
|
131
|
+
except Exception as e:
|
|
132
|
+
logger.error(f"Failed to list collections: {e}")
|
|
133
|
+
return []
|
|
134
|
+
|
|
135
|
+
def insert(
|
|
136
|
+
self,
|
|
137
|
+
collection: str,
|
|
138
|
+
documents: List[KnowledgeDocument]
|
|
139
|
+
) -> List[str]:
|
|
140
|
+
"""Insert documents."""
|
|
141
|
+
self._init_client()
|
|
142
|
+
|
|
143
|
+
ids = []
|
|
144
|
+
for doc in documents:
|
|
145
|
+
record = {
|
|
146
|
+
"content": doc.content,
|
|
147
|
+
"embedding": doc.embedding,
|
|
148
|
+
"metadata": doc.metadata or {},
|
|
149
|
+
"content_hash": doc.content_hash,
|
|
150
|
+
"created_at": doc.created_at,
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
try:
|
|
154
|
+
result = self._run_async(
|
|
155
|
+
self._client.create(f"{collection}:{doc.id}", record)
|
|
156
|
+
)
|
|
157
|
+
ids.append(doc.id)
|
|
158
|
+
except Exception as e:
|
|
159
|
+
logger.warning(f"Failed to insert document {doc.id}: {e}")
|
|
160
|
+
|
|
161
|
+
return ids
|
|
162
|
+
|
|
163
|
+
def upsert(
|
|
164
|
+
self,
|
|
165
|
+
collection: str,
|
|
166
|
+
documents: List[KnowledgeDocument]
|
|
167
|
+
) -> List[str]:
|
|
168
|
+
"""Upsert documents."""
|
|
169
|
+
self._init_client()
|
|
170
|
+
|
|
171
|
+
ids = []
|
|
172
|
+
for doc in documents:
|
|
173
|
+
record = {
|
|
174
|
+
"content": doc.content,
|
|
175
|
+
"embedding": doc.embedding,
|
|
176
|
+
"metadata": doc.metadata or {},
|
|
177
|
+
"content_hash": doc.content_hash,
|
|
178
|
+
"created_at": doc.created_at,
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
try:
|
|
182
|
+
self._run_async(
|
|
183
|
+
self._client.update(f"{collection}:{doc.id}", record)
|
|
184
|
+
)
|
|
185
|
+
ids.append(doc.id)
|
|
186
|
+
except Exception as e:
|
|
187
|
+
logger.warning(f"Failed to upsert document {doc.id}: {e}")
|
|
188
|
+
|
|
189
|
+
return ids
|
|
190
|
+
|
|
191
|
+
def search(
|
|
192
|
+
self,
|
|
193
|
+
collection: str,
|
|
194
|
+
query_embedding: List[float],
|
|
195
|
+
limit: int = 5,
|
|
196
|
+
filters: Optional[Dict[str, Any]] = None,
|
|
197
|
+
score_threshold: Optional[float] = None
|
|
198
|
+
) -> List[KnowledgeDocument]:
|
|
199
|
+
"""Search for similar documents using vector search."""
|
|
200
|
+
self._init_client()
|
|
201
|
+
|
|
202
|
+
# SurrealDB vector search query
|
|
203
|
+
embedding_str = str(query_embedding)
|
|
204
|
+
query = f"""
|
|
205
|
+
SELECT *, vector::similarity::cosine(embedding, {embedding_str}) AS score
|
|
206
|
+
FROM {collection}
|
|
207
|
+
ORDER BY score DESC
|
|
208
|
+
LIMIT {limit}
|
|
209
|
+
"""
|
|
210
|
+
|
|
211
|
+
try:
|
|
212
|
+
result = self._run_async(self._client.query(query))
|
|
213
|
+
|
|
214
|
+
documents = []
|
|
215
|
+
if result and len(result) > 0:
|
|
216
|
+
for row in result[0].get("result", []):
|
|
217
|
+
score = row.get("score", 0)
|
|
218
|
+
if score_threshold and score < score_threshold:
|
|
219
|
+
continue
|
|
220
|
+
|
|
221
|
+
doc_id = str(row.get("id", "")).split(":")[-1]
|
|
222
|
+
documents.append(KnowledgeDocument(
|
|
223
|
+
id=doc_id,
|
|
224
|
+
content=row.get("content", ""),
|
|
225
|
+
embedding=row.get("embedding"),
|
|
226
|
+
metadata={**(row.get("metadata") or {}), "score": score},
|
|
227
|
+
content_hash=row.get("content_hash"),
|
|
228
|
+
created_at=row.get("created_at", 0)
|
|
229
|
+
))
|
|
230
|
+
|
|
231
|
+
return documents
|
|
232
|
+
except Exception as e:
|
|
233
|
+
logger.error(f"Vector search failed: {e}")
|
|
234
|
+
return []
|
|
235
|
+
|
|
236
|
+
def get(
|
|
237
|
+
self,
|
|
238
|
+
collection: str,
|
|
239
|
+
ids: List[str]
|
|
240
|
+
) -> List[KnowledgeDocument]:
|
|
241
|
+
"""Get documents by IDs."""
|
|
242
|
+
self._init_client()
|
|
243
|
+
|
|
244
|
+
documents = []
|
|
245
|
+
for doc_id in ids:
|
|
246
|
+
try:
|
|
247
|
+
result = self._run_async(self._client.select(f"{collection}:{doc_id}"))
|
|
248
|
+
if result:
|
|
249
|
+
row = result if isinstance(result, dict) else result[0]
|
|
250
|
+
documents.append(KnowledgeDocument(
|
|
251
|
+
id=doc_id,
|
|
252
|
+
content=row.get("content", ""),
|
|
253
|
+
embedding=row.get("embedding"),
|
|
254
|
+
metadata=row.get("metadata"),
|
|
255
|
+
content_hash=row.get("content_hash"),
|
|
256
|
+
created_at=row.get("created_at", 0)
|
|
257
|
+
))
|
|
258
|
+
except Exception as e:
|
|
259
|
+
logger.warning(f"Failed to get document {doc_id}: {e}")
|
|
260
|
+
|
|
261
|
+
return documents
|
|
262
|
+
|
|
263
|
+
def delete(
|
|
264
|
+
self,
|
|
265
|
+
collection: str,
|
|
266
|
+
ids: Optional[List[str]] = None,
|
|
267
|
+
filters: Optional[Dict[str, Any]] = None
|
|
268
|
+
) -> int:
|
|
269
|
+
"""Delete documents."""
|
|
270
|
+
self._init_client()
|
|
271
|
+
|
|
272
|
+
count = 0
|
|
273
|
+
if ids:
|
|
274
|
+
for doc_id in ids:
|
|
275
|
+
try:
|
|
276
|
+
self._run_async(self._client.delete(f"{collection}:{doc_id}"))
|
|
277
|
+
count += 1
|
|
278
|
+
except Exception as e:
|
|
279
|
+
logger.warning(f"Failed to delete {doc_id}: {e}")
|
|
280
|
+
else:
|
|
281
|
+
try:
|
|
282
|
+
self._run_async(self._client.query(f"DELETE FROM {collection}"))
|
|
283
|
+
count = -1 # Unknown count
|
|
284
|
+
except Exception as e:
|
|
285
|
+
logger.error(f"Failed to delete all: {e}")
|
|
286
|
+
|
|
287
|
+
return count
|
|
288
|
+
|
|
289
|
+
def count(self, collection: str) -> int:
|
|
290
|
+
"""Count documents."""
|
|
291
|
+
self._init_client()
|
|
292
|
+
|
|
293
|
+
try:
|
|
294
|
+
result = self._run_async(
|
|
295
|
+
self._client.query(f"SELECT count() FROM {collection} GROUP ALL")
|
|
296
|
+
)
|
|
297
|
+
if result and len(result) > 0:
|
|
298
|
+
return result[0].get("result", [{}])[0].get("count", 0)
|
|
299
|
+
return 0
|
|
300
|
+
except Exception as e:
|
|
301
|
+
logger.error(f"Count failed: {e}")
|
|
302
|
+
return 0
|
|
303
|
+
|
|
304
|
+
def close(self) -> None:
|
|
305
|
+
"""Close the connection."""
|
|
306
|
+
if self._client:
|
|
307
|
+
self._run_async(self._client.close())
|
|
308
|
+
self._client = None
|
|
309
|
+
self._initialized = False
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Upstash Vector implementation of KnowledgeStore.
|
|
3
|
+
|
|
4
|
+
Requires: upstash-vector
|
|
5
|
+
Install: pip install upstash-vector
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
import os
|
|
10
|
+
from typing import Any, Dict, List, Optional
|
|
11
|
+
|
|
12
|
+
from .base import KnowledgeStore, KnowledgeDocument
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class UpstashVectorKnowledgeStore(KnowledgeStore):
|
|
18
|
+
"""
|
|
19
|
+
Upstash Vector store for knowledge/RAG.
|
|
20
|
+
|
|
21
|
+
Uses Upstash's serverless vector database.
|
|
22
|
+
|
|
23
|
+
Example:
|
|
24
|
+
store = UpstashVectorKnowledgeStore(
|
|
25
|
+
url="https://xxx.upstash.io",
|
|
26
|
+
token="your-token"
|
|
27
|
+
)
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
def __init__(
|
|
31
|
+
self,
|
|
32
|
+
url: Optional[str] = None,
|
|
33
|
+
token: Optional[str] = None,
|
|
34
|
+
embedding_dim: int = 1536,
|
|
35
|
+
):
|
|
36
|
+
"""
|
|
37
|
+
Initialize Upstash Vector store.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
url: Upstash Vector REST URL (or UPSTASH_VECTOR_REST_URL env)
|
|
41
|
+
token: Upstash Vector REST token (or UPSTASH_VECTOR_REST_TOKEN env)
|
|
42
|
+
embedding_dim: Embedding dimension
|
|
43
|
+
"""
|
|
44
|
+
self.url = url or os.getenv("UPSTASH_VECTOR_REST_URL")
|
|
45
|
+
self.token = token or os.getenv("UPSTASH_VECTOR_REST_TOKEN")
|
|
46
|
+
self.embedding_dim = embedding_dim
|
|
47
|
+
|
|
48
|
+
self._index = None
|
|
49
|
+
self._initialized = False
|
|
50
|
+
|
|
51
|
+
def _init_client(self):
|
|
52
|
+
"""Initialize Upstash client lazily."""
|
|
53
|
+
if self._initialized:
|
|
54
|
+
return
|
|
55
|
+
|
|
56
|
+
if not self.url or not self.token:
|
|
57
|
+
raise ValueError(
|
|
58
|
+
"Upstash Vector requires url and token. "
|
|
59
|
+
"Set UPSTASH_VECTOR_REST_URL and UPSTASH_VECTOR_REST_TOKEN env vars."
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
try:
|
|
63
|
+
from upstash_vector import Index
|
|
64
|
+
except ImportError:
|
|
65
|
+
raise ImportError(
|
|
66
|
+
"upstash-vector is required for Upstash Vector support. "
|
|
67
|
+
"Install with: pip install upstash-vector"
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
self._index = Index(url=self.url, token=self.token)
|
|
71
|
+
self._initialized = True
|
|
72
|
+
|
|
73
|
+
def create_collection(
|
|
74
|
+
self,
|
|
75
|
+
name: str,
|
|
76
|
+
dimension: int = 1536,
|
|
77
|
+
distance: str = "cosine",
|
|
78
|
+
metadata: Optional[Dict[str, Any]] = None
|
|
79
|
+
) -> None:
|
|
80
|
+
"""Create collection (Upstash uses namespaces)."""
|
|
81
|
+
self._init_client()
|
|
82
|
+
# Upstash Vector uses a single index with namespaces
|
|
83
|
+
logger.info(f"Using namespace '{name}' in Upstash Vector index")
|
|
84
|
+
|
|
85
|
+
def delete_collection(self, name: str) -> bool:
|
|
86
|
+
"""Delete all vectors in namespace."""
|
|
87
|
+
self._init_client()
|
|
88
|
+
try:
|
|
89
|
+
self._index.delete_namespace(name)
|
|
90
|
+
return True
|
|
91
|
+
except Exception as e:
|
|
92
|
+
logger.error(f"Failed to delete namespace {name}: {e}")
|
|
93
|
+
return False
|
|
94
|
+
|
|
95
|
+
def collection_exists(self, name: str) -> bool:
|
|
96
|
+
"""Check if namespace has vectors."""
|
|
97
|
+
self._init_client()
|
|
98
|
+
try:
|
|
99
|
+
info = self._index.info()
|
|
100
|
+
namespaces = info.namespaces if hasattr(info, 'namespaces') else {}
|
|
101
|
+
return name in namespaces
|
|
102
|
+
except Exception:
|
|
103
|
+
return False
|
|
104
|
+
|
|
105
|
+
def list_collections(self) -> List[str]:
|
|
106
|
+
"""List all namespaces."""
|
|
107
|
+
self._init_client()
|
|
108
|
+
try:
|
|
109
|
+
info = self._index.info()
|
|
110
|
+
namespaces = info.namespaces if hasattr(info, 'namespaces') else {}
|
|
111
|
+
return list(namespaces.keys())
|
|
112
|
+
except Exception as e:
|
|
113
|
+
logger.error(f"Failed to list namespaces: {e}")
|
|
114
|
+
return []
|
|
115
|
+
|
|
116
|
+
def insert(
|
|
117
|
+
self,
|
|
118
|
+
collection: str,
|
|
119
|
+
documents: List[KnowledgeDocument]
|
|
120
|
+
) -> List[str]:
|
|
121
|
+
"""Insert documents."""
|
|
122
|
+
self._init_client()
|
|
123
|
+
|
|
124
|
+
vectors = []
|
|
125
|
+
for doc in documents:
|
|
126
|
+
if not doc.embedding:
|
|
127
|
+
logger.warning(f"Document {doc.id} has no embedding, skipping")
|
|
128
|
+
continue
|
|
129
|
+
|
|
130
|
+
vectors.append({
|
|
131
|
+
"id": doc.id,
|
|
132
|
+
"vector": doc.embedding,
|
|
133
|
+
"metadata": {
|
|
134
|
+
"content": doc.content,
|
|
135
|
+
**(doc.metadata or {}),
|
|
136
|
+
"content_hash": doc.content_hash,
|
|
137
|
+
"created_at": doc.created_at,
|
|
138
|
+
}
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
if vectors:
|
|
142
|
+
self._index.upsert(vectors, namespace=collection)
|
|
143
|
+
|
|
144
|
+
return [v["id"] for v in vectors]
|
|
145
|
+
|
|
146
|
+
def upsert(
|
|
147
|
+
self,
|
|
148
|
+
collection: str,
|
|
149
|
+
documents: List[KnowledgeDocument]
|
|
150
|
+
) -> List[str]:
|
|
151
|
+
"""Upsert documents (same as insert for Upstash)."""
|
|
152
|
+
return self.insert(collection, documents)
|
|
153
|
+
|
|
154
|
+
def search(
|
|
155
|
+
self,
|
|
156
|
+
collection: str,
|
|
157
|
+
query_embedding: List[float],
|
|
158
|
+
limit: int = 5,
|
|
159
|
+
filters: Optional[Dict[str, Any]] = None,
|
|
160
|
+
score_threshold: Optional[float] = None
|
|
161
|
+
) -> List[KnowledgeDocument]:
|
|
162
|
+
"""Search for similar documents."""
|
|
163
|
+
self._init_client()
|
|
164
|
+
|
|
165
|
+
try:
|
|
166
|
+
results = self._index.query(
|
|
167
|
+
vector=query_embedding,
|
|
168
|
+
top_k=limit,
|
|
169
|
+
include_metadata=True,
|
|
170
|
+
namespace=collection,
|
|
171
|
+
filter=filters
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
documents = []
|
|
175
|
+
for result in results:
|
|
176
|
+
score = result.score if hasattr(result, 'score') else 0
|
|
177
|
+
if score_threshold and score < score_threshold:
|
|
178
|
+
continue
|
|
179
|
+
|
|
180
|
+
metadata = result.metadata if hasattr(result, 'metadata') else {}
|
|
181
|
+
content = metadata.pop("content", "") if metadata else ""
|
|
182
|
+
|
|
183
|
+
documents.append(KnowledgeDocument(
|
|
184
|
+
id=result.id,
|
|
185
|
+
content=content,
|
|
186
|
+
metadata={**metadata, "score": score},
|
|
187
|
+
content_hash=metadata.get("content_hash") if metadata else None,
|
|
188
|
+
created_at=metadata.get("created_at", 0) if metadata else 0
|
|
189
|
+
))
|
|
190
|
+
|
|
191
|
+
return documents
|
|
192
|
+
except Exception as e:
|
|
193
|
+
logger.error(f"Search failed: {e}")
|
|
194
|
+
return []
|
|
195
|
+
|
|
196
|
+
def get(
|
|
197
|
+
self,
|
|
198
|
+
collection: str,
|
|
199
|
+
ids: List[str]
|
|
200
|
+
) -> List[KnowledgeDocument]:
|
|
201
|
+
"""Get documents by IDs."""
|
|
202
|
+
self._init_client()
|
|
203
|
+
|
|
204
|
+
documents = []
|
|
205
|
+
try:
|
|
206
|
+
results = self._index.fetch(ids, include_metadata=True, namespace=collection)
|
|
207
|
+
|
|
208
|
+
for result in results:
|
|
209
|
+
if result:
|
|
210
|
+
metadata = result.metadata if hasattr(result, 'metadata') else {}
|
|
211
|
+
content = metadata.pop("content", "") if metadata else ""
|
|
212
|
+
|
|
213
|
+
documents.append(KnowledgeDocument(
|
|
214
|
+
id=result.id,
|
|
215
|
+
content=content,
|
|
216
|
+
embedding=result.vector if hasattr(result, 'vector') else None,
|
|
217
|
+
metadata=metadata,
|
|
218
|
+
content_hash=metadata.get("content_hash") if metadata else None,
|
|
219
|
+
created_at=metadata.get("created_at", 0) if metadata else 0
|
|
220
|
+
))
|
|
221
|
+
except Exception as e:
|
|
222
|
+
logger.error(f"Fetch failed: {e}")
|
|
223
|
+
|
|
224
|
+
return documents
|
|
225
|
+
|
|
226
|
+
def delete(
|
|
227
|
+
self,
|
|
228
|
+
collection: str,
|
|
229
|
+
ids: Optional[List[str]] = None,
|
|
230
|
+
filters: Optional[Dict[str, Any]] = None
|
|
231
|
+
) -> int:
|
|
232
|
+
"""Delete documents."""
|
|
233
|
+
self._init_client()
|
|
234
|
+
|
|
235
|
+
try:
|
|
236
|
+
if ids:
|
|
237
|
+
self._index.delete(ids, namespace=collection)
|
|
238
|
+
return len(ids)
|
|
239
|
+
elif filters:
|
|
240
|
+
# Upstash doesn't support filter-based delete directly
|
|
241
|
+
logger.warning("Filter-based delete not supported, use IDs")
|
|
242
|
+
return 0
|
|
243
|
+
else:
|
|
244
|
+
self._index.delete_namespace(collection)
|
|
245
|
+
return -1 # Unknown count
|
|
246
|
+
except Exception as e:
|
|
247
|
+
logger.error(f"Delete failed: {e}")
|
|
248
|
+
return 0
|
|
249
|
+
|
|
250
|
+
def count(self, collection: str) -> int:
|
|
251
|
+
"""Count documents in namespace."""
|
|
252
|
+
self._init_client()
|
|
253
|
+
|
|
254
|
+
try:
|
|
255
|
+
info = self._index.info()
|
|
256
|
+
namespaces = info.namespaces if hasattr(info, 'namespaces') else {}
|
|
257
|
+
ns_info = namespaces.get(collection, {})
|
|
258
|
+
return ns_info.get("vector_count", 0) if isinstance(ns_info, dict) else 0
|
|
259
|
+
except Exception as e:
|
|
260
|
+
logger.error(f"Count failed: {e}")
|
|
261
|
+
return 0
|
|
262
|
+
|
|
263
|
+
def close(self) -> None:
|
|
264
|
+
"""Close the client."""
|
|
265
|
+
self._index = None
|
|
266
|
+
self._initialized = False
|