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,295 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ChromaDB implementation of KnowledgeStore.
|
|
3
|
+
|
|
4
|
+
Requires: chromadb
|
|
5
|
+
Install: pip install chromadb
|
|
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 ChromaKnowledgeStore(KnowledgeStore):
|
|
17
|
+
"""
|
|
18
|
+
ChromaDB-based knowledge store for vector search.
|
|
19
|
+
|
|
20
|
+
Zero-config embedded vector database.
|
|
21
|
+
|
|
22
|
+
Example:
|
|
23
|
+
store = ChromaKnowledgeStore(
|
|
24
|
+
path="./chroma_db"
|
|
25
|
+
)
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def __init__(
|
|
29
|
+
self,
|
|
30
|
+
path: Optional[str] = None,
|
|
31
|
+
host: Optional[str] = None,
|
|
32
|
+
port: int = 8000,
|
|
33
|
+
persistent: bool = True,
|
|
34
|
+
):
|
|
35
|
+
"""
|
|
36
|
+
Initialize ChromaDB knowledge store.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
path: Path for persistent storage (embedded mode)
|
|
40
|
+
host: Chroma server host (client mode)
|
|
41
|
+
port: Chroma server port
|
|
42
|
+
persistent: Use persistent storage
|
|
43
|
+
"""
|
|
44
|
+
try:
|
|
45
|
+
import chromadb
|
|
46
|
+
from chromadb.config import Settings
|
|
47
|
+
except ImportError:
|
|
48
|
+
raise ImportError(
|
|
49
|
+
"chromadb is required for ChromaDB support. "
|
|
50
|
+
"Install with: pip install chromadb"
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
self._chromadb = chromadb
|
|
54
|
+
|
|
55
|
+
if host:
|
|
56
|
+
# Client mode
|
|
57
|
+
self._client = chromadb.HttpClient(host=host, port=port)
|
|
58
|
+
elif path and persistent:
|
|
59
|
+
# Persistent embedded mode
|
|
60
|
+
self._client = chromadb.PersistentClient(
|
|
61
|
+
path=path,
|
|
62
|
+
settings=Settings(anonymized_telemetry=False)
|
|
63
|
+
)
|
|
64
|
+
else:
|
|
65
|
+
# In-memory mode
|
|
66
|
+
self._client = chromadb.Client(
|
|
67
|
+
settings=Settings(anonymized_telemetry=False)
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
self._collections: Dict[str, Any] = {}
|
|
71
|
+
logger.info(f"ChromaDB initialized (path={path}, host={host})")
|
|
72
|
+
|
|
73
|
+
def _get_collection(self, name: str):
|
|
74
|
+
"""Get or cache a collection."""
|
|
75
|
+
if name not in self._collections:
|
|
76
|
+
self._collections[name] = self._client.get_collection(name)
|
|
77
|
+
return self._collections[name]
|
|
78
|
+
|
|
79
|
+
def create_collection(
|
|
80
|
+
self,
|
|
81
|
+
name: str,
|
|
82
|
+
dimension: int,
|
|
83
|
+
distance: str = "cosine",
|
|
84
|
+
metadata: Optional[Dict[str, Any]] = None
|
|
85
|
+
) -> None:
|
|
86
|
+
"""Create a new collection."""
|
|
87
|
+
distance_map = {
|
|
88
|
+
"cosine": "cosine",
|
|
89
|
+
"euclidean": "l2",
|
|
90
|
+
"dot": "ip",
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
self._client.create_collection(
|
|
94
|
+
name=name,
|
|
95
|
+
metadata={"hnsw:space": distance_map.get(distance, "cosine"), **(metadata or {})}
|
|
96
|
+
)
|
|
97
|
+
logger.info(f"Created ChromaDB collection: {name}")
|
|
98
|
+
|
|
99
|
+
def delete_collection(self, name: str) -> bool:
|
|
100
|
+
"""Delete a collection."""
|
|
101
|
+
try:
|
|
102
|
+
self._client.delete_collection(name)
|
|
103
|
+
if name in self._collections:
|
|
104
|
+
del self._collections[name]
|
|
105
|
+
return True
|
|
106
|
+
except Exception as e:
|
|
107
|
+
logger.warning(f"Failed to delete collection {name}: {e}")
|
|
108
|
+
return False
|
|
109
|
+
|
|
110
|
+
def collection_exists(self, name: str) -> bool:
|
|
111
|
+
"""Check if a collection exists."""
|
|
112
|
+
try:
|
|
113
|
+
self._client.get_collection(name)
|
|
114
|
+
return True
|
|
115
|
+
except Exception:
|
|
116
|
+
return False
|
|
117
|
+
|
|
118
|
+
def list_collections(self) -> List[str]:
|
|
119
|
+
"""List all collections."""
|
|
120
|
+
return [c.name for c in self._client.list_collections()]
|
|
121
|
+
|
|
122
|
+
def insert(
|
|
123
|
+
self,
|
|
124
|
+
collection: str,
|
|
125
|
+
documents: List[KnowledgeDocument]
|
|
126
|
+
) -> List[str]:
|
|
127
|
+
"""Insert documents into a collection."""
|
|
128
|
+
col = self._get_collection(collection)
|
|
129
|
+
|
|
130
|
+
ids = []
|
|
131
|
+
embeddings = []
|
|
132
|
+
contents = []
|
|
133
|
+
metadatas = []
|
|
134
|
+
|
|
135
|
+
for doc in documents:
|
|
136
|
+
if doc.embedding is None:
|
|
137
|
+
raise ValueError(f"Document {doc.id} has no embedding")
|
|
138
|
+
ids.append(doc.id)
|
|
139
|
+
embeddings.append(doc.embedding)
|
|
140
|
+
contents.append(doc.content)
|
|
141
|
+
metadatas.append({
|
|
142
|
+
"content_hash": doc.content_hash or "",
|
|
143
|
+
"created_at": doc.created_at,
|
|
144
|
+
**(doc.metadata or {})
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
col.add(
|
|
148
|
+
ids=ids,
|
|
149
|
+
embeddings=embeddings,
|
|
150
|
+
documents=contents,
|
|
151
|
+
metadatas=metadatas,
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
return ids
|
|
155
|
+
|
|
156
|
+
def upsert(
|
|
157
|
+
self,
|
|
158
|
+
collection: str,
|
|
159
|
+
documents: List[KnowledgeDocument]
|
|
160
|
+
) -> List[str]:
|
|
161
|
+
"""Insert or update documents."""
|
|
162
|
+
col = self._get_collection(collection)
|
|
163
|
+
|
|
164
|
+
ids = []
|
|
165
|
+
embeddings = []
|
|
166
|
+
contents = []
|
|
167
|
+
metadatas = []
|
|
168
|
+
|
|
169
|
+
for doc in documents:
|
|
170
|
+
if doc.embedding is None:
|
|
171
|
+
raise ValueError(f"Document {doc.id} has no embedding")
|
|
172
|
+
ids.append(doc.id)
|
|
173
|
+
embeddings.append(doc.embedding)
|
|
174
|
+
contents.append(doc.content)
|
|
175
|
+
metadatas.append({
|
|
176
|
+
"content_hash": doc.content_hash or "",
|
|
177
|
+
"created_at": doc.created_at,
|
|
178
|
+
**(doc.metadata or {})
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
col.upsert(
|
|
182
|
+
ids=ids,
|
|
183
|
+
embeddings=embeddings,
|
|
184
|
+
documents=contents,
|
|
185
|
+
metadatas=metadatas,
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
return ids
|
|
189
|
+
|
|
190
|
+
def search(
|
|
191
|
+
self,
|
|
192
|
+
collection: str,
|
|
193
|
+
query_embedding: List[float],
|
|
194
|
+
limit: int = 5,
|
|
195
|
+
filters: Optional[Dict[str, Any]] = None,
|
|
196
|
+
score_threshold: Optional[float] = None
|
|
197
|
+
) -> List[KnowledgeDocument]:
|
|
198
|
+
"""Search for similar documents."""
|
|
199
|
+
col = self._get_collection(collection)
|
|
200
|
+
|
|
201
|
+
where = None
|
|
202
|
+
if filters:
|
|
203
|
+
where = {k: v for k, v in filters.items()}
|
|
204
|
+
|
|
205
|
+
results = col.query(
|
|
206
|
+
query_embeddings=[query_embedding],
|
|
207
|
+
n_results=limit,
|
|
208
|
+
where=where,
|
|
209
|
+
include=["documents", "metadatas", "distances"],
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
documents = []
|
|
213
|
+
if results["ids"] and results["ids"][0]:
|
|
214
|
+
for i, doc_id in enumerate(results["ids"][0]):
|
|
215
|
+
distance = results["distances"][0][i] if results.get("distances") else None
|
|
216
|
+
|
|
217
|
+
# Convert distance to similarity score (for cosine: 1 - distance)
|
|
218
|
+
if score_threshold is not None and distance is not None:
|
|
219
|
+
score = 1 - distance
|
|
220
|
+
if score < score_threshold:
|
|
221
|
+
continue
|
|
222
|
+
|
|
223
|
+
metadata = results["metadatas"][0][i] if results.get("metadatas") else {}
|
|
224
|
+
content_hash = metadata.pop("content_hash", None)
|
|
225
|
+
created_at = metadata.pop("created_at", 0)
|
|
226
|
+
|
|
227
|
+
doc = KnowledgeDocument(
|
|
228
|
+
id=doc_id,
|
|
229
|
+
content=results["documents"][0][i] if results.get("documents") else "",
|
|
230
|
+
embedding=None,
|
|
231
|
+
metadata=metadata,
|
|
232
|
+
content_hash=content_hash,
|
|
233
|
+
created_at=created_at,
|
|
234
|
+
)
|
|
235
|
+
documents.append(doc)
|
|
236
|
+
|
|
237
|
+
return documents
|
|
238
|
+
|
|
239
|
+
def get(
|
|
240
|
+
self,
|
|
241
|
+
collection: str,
|
|
242
|
+
ids: List[str]
|
|
243
|
+
) -> List[KnowledgeDocument]:
|
|
244
|
+
"""Get documents by IDs."""
|
|
245
|
+
col = self._get_collection(collection)
|
|
246
|
+
|
|
247
|
+
results = col.get(
|
|
248
|
+
ids=ids,
|
|
249
|
+
include=["documents", "metadatas", "embeddings"],
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
documents = []
|
|
253
|
+
if results["ids"]:
|
|
254
|
+
for i, doc_id in enumerate(results["ids"]):
|
|
255
|
+
metadata = results["metadatas"][i] if results.get("metadatas") else {}
|
|
256
|
+
content_hash = metadata.pop("content_hash", None)
|
|
257
|
+
created_at = metadata.pop("created_at", 0)
|
|
258
|
+
|
|
259
|
+
doc = KnowledgeDocument(
|
|
260
|
+
id=doc_id,
|
|
261
|
+
content=results["documents"][i] if results.get("documents") else "",
|
|
262
|
+
embedding=results["embeddings"][i] if results.get("embeddings") else None,
|
|
263
|
+
metadata=metadata,
|
|
264
|
+
content_hash=content_hash,
|
|
265
|
+
created_at=created_at,
|
|
266
|
+
)
|
|
267
|
+
documents.append(doc)
|
|
268
|
+
|
|
269
|
+
return documents
|
|
270
|
+
|
|
271
|
+
def delete(
|
|
272
|
+
self,
|
|
273
|
+
collection: str,
|
|
274
|
+
ids: Optional[List[str]] = None,
|
|
275
|
+
filters: Optional[Dict[str, Any]] = None
|
|
276
|
+
) -> int:
|
|
277
|
+
"""Delete documents."""
|
|
278
|
+
col = self._get_collection(collection)
|
|
279
|
+
|
|
280
|
+
if ids:
|
|
281
|
+
col.delete(ids=ids)
|
|
282
|
+
return len(ids)
|
|
283
|
+
elif filters:
|
|
284
|
+
col.delete(where=filters)
|
|
285
|
+
return -1 # Unknown count
|
|
286
|
+
return 0
|
|
287
|
+
|
|
288
|
+
def count(self, collection: str) -> int:
|
|
289
|
+
"""Count documents in a collection."""
|
|
290
|
+
col = self._get_collection(collection)
|
|
291
|
+
return col.count()
|
|
292
|
+
|
|
293
|
+
def close(self) -> None:
|
|
294
|
+
"""Close the store."""
|
|
295
|
+
self._collections.clear()
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ClickHouse Vector implementation of KnowledgeStore.
|
|
3
|
+
|
|
4
|
+
Requires: clickhouse-connect
|
|
5
|
+
Install: pip install clickhouse-connect
|
|
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 ClickHouseKnowledgeStore(KnowledgeStore):
|
|
17
|
+
"""
|
|
18
|
+
ClickHouse-based knowledge store using vector search.
|
|
19
|
+
|
|
20
|
+
Example:
|
|
21
|
+
store = ClickHouseKnowledgeStore(
|
|
22
|
+
host="localhost",
|
|
23
|
+
port=8123
|
|
24
|
+
)
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
host: str = "localhost",
|
|
30
|
+
port: int = 8123,
|
|
31
|
+
username: str = "default",
|
|
32
|
+
password: str = "",
|
|
33
|
+
database: str = "praisonai",
|
|
34
|
+
secure: bool = False,
|
|
35
|
+
):
|
|
36
|
+
try:
|
|
37
|
+
import clickhouse_connect
|
|
38
|
+
except ImportError:
|
|
39
|
+
raise ImportError(
|
|
40
|
+
"clickhouse-connect is required for ClickHouse support. "
|
|
41
|
+
"Install with: pip install clickhouse-connect"
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
self._client = clickhouse_connect.get_client(
|
|
45
|
+
host=host,
|
|
46
|
+
port=port,
|
|
47
|
+
username=username,
|
|
48
|
+
password=password,
|
|
49
|
+
database=database,
|
|
50
|
+
secure=secure,
|
|
51
|
+
)
|
|
52
|
+
self.database = database
|
|
53
|
+
|
|
54
|
+
# Create database if not exists
|
|
55
|
+
self._client.command(f"CREATE DATABASE IF NOT EXISTS {database}")
|
|
56
|
+
logger.info(f"Connected to ClickHouse database: {database}")
|
|
57
|
+
|
|
58
|
+
def _table_name(self, collection: str) -> str:
|
|
59
|
+
return f"{self.database}.praison_vec_{collection}"
|
|
60
|
+
|
|
61
|
+
def create_collection(
|
|
62
|
+
self,
|
|
63
|
+
name: str,
|
|
64
|
+
dimension: int,
|
|
65
|
+
distance: str = "cosine",
|
|
66
|
+
metadata: Optional[Dict[str, Any]] = None
|
|
67
|
+
) -> None:
|
|
68
|
+
"""Create a new table with vector column."""
|
|
69
|
+
table = self._table_name(name)
|
|
70
|
+
|
|
71
|
+
self._client.command(f"""
|
|
72
|
+
CREATE TABLE IF NOT EXISTS {table} (
|
|
73
|
+
id String,
|
|
74
|
+
content String,
|
|
75
|
+
content_hash String,
|
|
76
|
+
created_at Float64,
|
|
77
|
+
embedding Array(Float32)
|
|
78
|
+
) ENGINE = MergeTree()
|
|
79
|
+
ORDER BY id
|
|
80
|
+
""")
|
|
81
|
+
logger.info(f"Created ClickHouse table: {table}")
|
|
82
|
+
|
|
83
|
+
def delete_collection(self, name: str) -> bool:
|
|
84
|
+
"""Delete a table."""
|
|
85
|
+
table = self._table_name(name)
|
|
86
|
+
try:
|
|
87
|
+
self._client.command(f"DROP TABLE IF EXISTS {table}")
|
|
88
|
+
return True
|
|
89
|
+
except Exception as e:
|
|
90
|
+
logger.warning(f"Failed to delete table {table}: {e}")
|
|
91
|
+
return False
|
|
92
|
+
|
|
93
|
+
def collection_exists(self, name: str) -> bool:
|
|
94
|
+
"""Check if a table exists."""
|
|
95
|
+
table = self._table_name(name)
|
|
96
|
+
result = self._client.query(f"EXISTS TABLE {table}")
|
|
97
|
+
return result.result_rows[0][0] == 1
|
|
98
|
+
|
|
99
|
+
def list_collections(self) -> List[str]:
|
|
100
|
+
"""List all collections."""
|
|
101
|
+
result = self._client.query(f"""
|
|
102
|
+
SELECT name FROM system.tables
|
|
103
|
+
WHERE database = '{self.database}' AND name LIKE 'praison_vec_%'
|
|
104
|
+
""")
|
|
105
|
+
return [row[0].replace("praison_vec_", "") for row in result.result_rows]
|
|
106
|
+
|
|
107
|
+
def insert(
|
|
108
|
+
self,
|
|
109
|
+
collection: str,
|
|
110
|
+
documents: List[KnowledgeDocument]
|
|
111
|
+
) -> List[str]:
|
|
112
|
+
"""Insert documents."""
|
|
113
|
+
table = self._table_name(collection)
|
|
114
|
+
|
|
115
|
+
data = []
|
|
116
|
+
ids = []
|
|
117
|
+
for doc in documents:
|
|
118
|
+
if doc.embedding is None:
|
|
119
|
+
raise ValueError(f"Document {doc.id} has no embedding")
|
|
120
|
+
data.append([
|
|
121
|
+
doc.id,
|
|
122
|
+
doc.content,
|
|
123
|
+
doc.content_hash or "",
|
|
124
|
+
doc.created_at,
|
|
125
|
+
doc.embedding,
|
|
126
|
+
])
|
|
127
|
+
ids.append(doc.id)
|
|
128
|
+
|
|
129
|
+
self._client.insert(
|
|
130
|
+
table,
|
|
131
|
+
data,
|
|
132
|
+
column_names=["id", "content", "content_hash", "created_at", "embedding"]
|
|
133
|
+
)
|
|
134
|
+
return ids
|
|
135
|
+
|
|
136
|
+
def upsert(
|
|
137
|
+
self,
|
|
138
|
+
collection: str,
|
|
139
|
+
documents: List[KnowledgeDocument]
|
|
140
|
+
) -> List[str]:
|
|
141
|
+
"""Insert or update documents."""
|
|
142
|
+
# ClickHouse doesn't have native upsert for MergeTree
|
|
143
|
+
# Delete then insert
|
|
144
|
+
ids = [doc.id for doc in documents]
|
|
145
|
+
self.delete(collection, ids)
|
|
146
|
+
return self.insert(collection, documents)
|
|
147
|
+
|
|
148
|
+
def search(
|
|
149
|
+
self,
|
|
150
|
+
collection: str,
|
|
151
|
+
query_embedding: List[float],
|
|
152
|
+
limit: int = 5,
|
|
153
|
+
filters: Optional[Dict[str, Any]] = None,
|
|
154
|
+
score_threshold: Optional[float] = None
|
|
155
|
+
) -> List[KnowledgeDocument]:
|
|
156
|
+
"""Search for similar documents using cosine distance."""
|
|
157
|
+
table = self._table_name(collection)
|
|
158
|
+
|
|
159
|
+
# Convert embedding to string for query
|
|
160
|
+
embedding_str = "[" + ",".join(map(str, query_embedding)) + "]"
|
|
161
|
+
|
|
162
|
+
query = f"""
|
|
163
|
+
SELECT
|
|
164
|
+
id, content, content_hash, created_at,
|
|
165
|
+
1 - cosineDistance(embedding, {embedding_str}) as score
|
|
166
|
+
FROM {table}
|
|
167
|
+
"""
|
|
168
|
+
|
|
169
|
+
if score_threshold:
|
|
170
|
+
query += f" WHERE 1 - cosineDistance(embedding, {embedding_str}) >= {score_threshold}"
|
|
171
|
+
|
|
172
|
+
query += f" ORDER BY score DESC LIMIT {limit}"
|
|
173
|
+
|
|
174
|
+
result = self._client.query(query)
|
|
175
|
+
|
|
176
|
+
documents = []
|
|
177
|
+
for row in result.result_rows:
|
|
178
|
+
doc = KnowledgeDocument(
|
|
179
|
+
id=row[0],
|
|
180
|
+
content=row[1],
|
|
181
|
+
embedding=None,
|
|
182
|
+
metadata={},
|
|
183
|
+
content_hash=row[2],
|
|
184
|
+
created_at=row[3],
|
|
185
|
+
)
|
|
186
|
+
documents.append(doc)
|
|
187
|
+
|
|
188
|
+
return documents
|
|
189
|
+
|
|
190
|
+
def get(
|
|
191
|
+
self,
|
|
192
|
+
collection: str,
|
|
193
|
+
ids: List[str]
|
|
194
|
+
) -> List[KnowledgeDocument]:
|
|
195
|
+
"""Get documents by IDs."""
|
|
196
|
+
table = self._table_name(collection)
|
|
197
|
+
|
|
198
|
+
id_list = ", ".join([f"'{i}'" for i in ids])
|
|
199
|
+
result = self._client.query(f"""
|
|
200
|
+
SELECT id, content, content_hash, created_at, embedding
|
|
201
|
+
FROM {table} WHERE id IN ({id_list})
|
|
202
|
+
""")
|
|
203
|
+
|
|
204
|
+
documents = []
|
|
205
|
+
for row in result.result_rows:
|
|
206
|
+
doc = KnowledgeDocument(
|
|
207
|
+
id=row[0],
|
|
208
|
+
content=row[1],
|
|
209
|
+
embedding=list(row[4]) if row[4] else None,
|
|
210
|
+
metadata={},
|
|
211
|
+
content_hash=row[2],
|
|
212
|
+
created_at=row[3],
|
|
213
|
+
)
|
|
214
|
+
documents.append(doc)
|
|
215
|
+
|
|
216
|
+
return documents
|
|
217
|
+
|
|
218
|
+
def delete(
|
|
219
|
+
self,
|
|
220
|
+
collection: str,
|
|
221
|
+
ids: Optional[List[str]] = None,
|
|
222
|
+
filters: Optional[Dict[str, Any]] = None
|
|
223
|
+
) -> int:
|
|
224
|
+
"""Delete documents."""
|
|
225
|
+
table = self._table_name(collection)
|
|
226
|
+
|
|
227
|
+
if ids:
|
|
228
|
+
id_list = ", ".join([f"'{i}'" for i in ids])
|
|
229
|
+
self._client.command(f"ALTER TABLE {table} DELETE WHERE id IN ({id_list})")
|
|
230
|
+
return len(ids)
|
|
231
|
+
return 0
|
|
232
|
+
|
|
233
|
+
def count(self, collection: str) -> int:
|
|
234
|
+
"""Count documents."""
|
|
235
|
+
table = self._table_name(collection)
|
|
236
|
+
result = self._client.query(f"SELECT COUNT(*) FROM {table}")
|
|
237
|
+
return result.result_rows[0][0]
|
|
238
|
+
|
|
239
|
+
def close(self) -> None:
|
|
240
|
+
"""Close the store."""
|
|
241
|
+
if self._client:
|
|
242
|
+
self._client.close()
|