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,410 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Async PostgreSQL implementation of ConversationStore.
|
|
3
|
+
|
|
4
|
+
Requires: asyncpg
|
|
5
|
+
Install: pip install asyncpg
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import asyncio
|
|
9
|
+
import json
|
|
10
|
+
import logging
|
|
11
|
+
import time
|
|
12
|
+
from typing import List, Optional
|
|
13
|
+
|
|
14
|
+
from .base import ConversationStore, ConversationSession, ConversationMessage
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class AsyncPostgresConversationStore(ConversationStore):
|
|
20
|
+
"""
|
|
21
|
+
Async PostgreSQL conversation store using asyncpg.
|
|
22
|
+
|
|
23
|
+
Provides high-performance async database operations.
|
|
24
|
+
|
|
25
|
+
Example:
|
|
26
|
+
store = AsyncPostgresConversationStore(
|
|
27
|
+
url="postgresql://user:pass@localhost:5432/praisonai"
|
|
28
|
+
)
|
|
29
|
+
await store.init()
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
def __init__(
|
|
33
|
+
self,
|
|
34
|
+
url: Optional[str] = None,
|
|
35
|
+
host: str = "localhost",
|
|
36
|
+
port: int = 5432,
|
|
37
|
+
database: str = "praisonai",
|
|
38
|
+
user: str = "postgres",
|
|
39
|
+
password: str = "",
|
|
40
|
+
table_prefix: str = "praisonai_",
|
|
41
|
+
pool_size: int = 10,
|
|
42
|
+
):
|
|
43
|
+
"""
|
|
44
|
+
Initialize async PostgreSQL store.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
url: PostgreSQL connection URL (takes precedence)
|
|
48
|
+
host: Database host
|
|
49
|
+
port: Database port
|
|
50
|
+
database: Database name
|
|
51
|
+
user: Database user
|
|
52
|
+
password: Database password
|
|
53
|
+
table_prefix: Prefix for table names
|
|
54
|
+
pool_size: Connection pool size
|
|
55
|
+
"""
|
|
56
|
+
self.url = url
|
|
57
|
+
self.host = host
|
|
58
|
+
self.port = port
|
|
59
|
+
self.database = database
|
|
60
|
+
self.user = user
|
|
61
|
+
self.password = password
|
|
62
|
+
self.table_prefix = table_prefix
|
|
63
|
+
self.pool_size = pool_size
|
|
64
|
+
self._pool = None
|
|
65
|
+
self._initialized = False
|
|
66
|
+
|
|
67
|
+
async def init(self):
|
|
68
|
+
"""Initialize connection pool and create tables."""
|
|
69
|
+
if self._initialized:
|
|
70
|
+
return
|
|
71
|
+
|
|
72
|
+
try:
|
|
73
|
+
import asyncpg
|
|
74
|
+
except ImportError:
|
|
75
|
+
raise ImportError(
|
|
76
|
+
"asyncpg is required for async PostgreSQL support. "
|
|
77
|
+
"Install with: pip install asyncpg"
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
if self.url:
|
|
81
|
+
self._pool = await asyncpg.create_pool(self.url, min_size=1, max_size=self.pool_size)
|
|
82
|
+
else:
|
|
83
|
+
self._pool = await asyncpg.create_pool(
|
|
84
|
+
host=self.host,
|
|
85
|
+
port=self.port,
|
|
86
|
+
database=self.database,
|
|
87
|
+
user=self.user,
|
|
88
|
+
password=self.password,
|
|
89
|
+
min_size=1,
|
|
90
|
+
max_size=self.pool_size
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
await self._create_tables()
|
|
94
|
+
self._initialized = True
|
|
95
|
+
|
|
96
|
+
async def _create_tables(self):
|
|
97
|
+
"""Create required tables if they don't exist."""
|
|
98
|
+
sessions_table = f"{self.table_prefix}sessions"
|
|
99
|
+
messages_table = f"{self.table_prefix}messages"
|
|
100
|
+
|
|
101
|
+
async with self._pool.acquire() as conn:
|
|
102
|
+
await conn.execute(f"""
|
|
103
|
+
CREATE TABLE IF NOT EXISTS {sessions_table} (
|
|
104
|
+
session_id VARCHAR(255) PRIMARY KEY,
|
|
105
|
+
user_id VARCHAR(255),
|
|
106
|
+
agent_id VARCHAR(255),
|
|
107
|
+
name VARCHAR(255),
|
|
108
|
+
metadata JSONB,
|
|
109
|
+
created_at DOUBLE PRECISION,
|
|
110
|
+
updated_at DOUBLE PRECISION
|
|
111
|
+
)
|
|
112
|
+
""")
|
|
113
|
+
|
|
114
|
+
await conn.execute(f"""
|
|
115
|
+
CREATE TABLE IF NOT EXISTS {messages_table} (
|
|
116
|
+
id VARCHAR(255) PRIMARY KEY,
|
|
117
|
+
session_id VARCHAR(255) REFERENCES {sessions_table}(session_id) ON DELETE CASCADE,
|
|
118
|
+
role VARCHAR(50),
|
|
119
|
+
content TEXT,
|
|
120
|
+
metadata JSONB,
|
|
121
|
+
created_at DOUBLE PRECISION
|
|
122
|
+
)
|
|
123
|
+
""")
|
|
124
|
+
|
|
125
|
+
await conn.execute(f"""
|
|
126
|
+
CREATE INDEX IF NOT EXISTS idx_{messages_table}_session
|
|
127
|
+
ON {messages_table}(session_id)
|
|
128
|
+
""")
|
|
129
|
+
|
|
130
|
+
async def async_create_session(self, session: ConversationSession) -> ConversationSession:
|
|
131
|
+
"""Create a new session asynchronously."""
|
|
132
|
+
if not self._initialized:
|
|
133
|
+
await self.init()
|
|
134
|
+
|
|
135
|
+
table = f"{self.table_prefix}sessions"
|
|
136
|
+
async with self._pool.acquire() as conn:
|
|
137
|
+
await conn.execute(f"""
|
|
138
|
+
INSERT INTO {table} (session_id, user_id, agent_id, name, metadata, created_at, updated_at)
|
|
139
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
|
140
|
+
""", session.session_id, session.user_id, session.agent_id, session.name,
|
|
141
|
+
json.dumps(session.metadata) if session.metadata else None,
|
|
142
|
+
session.created_at, session.updated_at)
|
|
143
|
+
|
|
144
|
+
return session
|
|
145
|
+
|
|
146
|
+
def create_session(self, session: ConversationSession) -> ConversationSession:
|
|
147
|
+
"""Sync wrapper for create_session."""
|
|
148
|
+
return asyncio.get_event_loop().run_until_complete(
|
|
149
|
+
self.async_create_session(session)
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
async def async_get_session(self, session_id: str) -> Optional[ConversationSession]:
|
|
153
|
+
"""Get a session by ID asynchronously."""
|
|
154
|
+
if not self._initialized:
|
|
155
|
+
await self.init()
|
|
156
|
+
|
|
157
|
+
table = f"{self.table_prefix}sessions"
|
|
158
|
+
async with self._pool.acquire() as conn:
|
|
159
|
+
row = await conn.fetchrow(f"""
|
|
160
|
+
SELECT * FROM {table} WHERE session_id = $1
|
|
161
|
+
""", session_id)
|
|
162
|
+
|
|
163
|
+
if row:
|
|
164
|
+
return ConversationSession(
|
|
165
|
+
session_id=row['session_id'],
|
|
166
|
+
user_id=row['user_id'],
|
|
167
|
+
agent_id=row['agent_id'],
|
|
168
|
+
name=row['name'],
|
|
169
|
+
metadata=json.loads(row['metadata']) if row['metadata'] else None,
|
|
170
|
+
created_at=row['created_at'],
|
|
171
|
+
updated_at=row['updated_at']
|
|
172
|
+
)
|
|
173
|
+
return None
|
|
174
|
+
|
|
175
|
+
def get_session(self, session_id: str) -> Optional[ConversationSession]:
|
|
176
|
+
"""Sync wrapper for get_session."""
|
|
177
|
+
return asyncio.get_event_loop().run_until_complete(
|
|
178
|
+
self.async_get_session(session_id)
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
async def async_update_session(self, session: ConversationSession) -> ConversationSession:
|
|
182
|
+
"""Update an existing session asynchronously."""
|
|
183
|
+
if not self._initialized:
|
|
184
|
+
await self.init()
|
|
185
|
+
|
|
186
|
+
session.updated_at = time.time()
|
|
187
|
+
table = f"{self.table_prefix}sessions"
|
|
188
|
+
|
|
189
|
+
async with self._pool.acquire() as conn:
|
|
190
|
+
await conn.execute(f"""
|
|
191
|
+
UPDATE {table}
|
|
192
|
+
SET name = $2, metadata = $3, updated_at = $4
|
|
193
|
+
WHERE session_id = $1
|
|
194
|
+
""", session.session_id, session.name,
|
|
195
|
+
json.dumps(session.metadata) if session.metadata else None,
|
|
196
|
+
session.updated_at)
|
|
197
|
+
|
|
198
|
+
return session
|
|
199
|
+
|
|
200
|
+
def update_session(self, session: ConversationSession) -> ConversationSession:
|
|
201
|
+
"""Sync wrapper for update_session."""
|
|
202
|
+
return asyncio.get_event_loop().run_until_complete(
|
|
203
|
+
self.async_update_session(session)
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
async def async_delete_session(self, session_id: str) -> bool:
|
|
207
|
+
"""Delete a session asynchronously."""
|
|
208
|
+
if not self._initialized:
|
|
209
|
+
await self.init()
|
|
210
|
+
|
|
211
|
+
table = f"{self.table_prefix}sessions"
|
|
212
|
+
async with self._pool.acquire() as conn:
|
|
213
|
+
result = await conn.execute(f"""
|
|
214
|
+
DELETE FROM {table} WHERE session_id = $1
|
|
215
|
+
""", session_id)
|
|
216
|
+
|
|
217
|
+
return "DELETE 1" in result
|
|
218
|
+
|
|
219
|
+
def delete_session(self, session_id: str) -> bool:
|
|
220
|
+
"""Sync wrapper for delete_session."""
|
|
221
|
+
return asyncio.get_event_loop().run_until_complete(
|
|
222
|
+
self.async_delete_session(session_id)
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
async def async_list_sessions(
|
|
226
|
+
self,
|
|
227
|
+
user_id: Optional[str] = None,
|
|
228
|
+
agent_id: Optional[str] = None,
|
|
229
|
+
limit: int = 100,
|
|
230
|
+
offset: int = 0
|
|
231
|
+
) -> List[ConversationSession]:
|
|
232
|
+
"""List sessions asynchronously."""
|
|
233
|
+
if not self._initialized:
|
|
234
|
+
await self.init()
|
|
235
|
+
|
|
236
|
+
table = f"{self.table_prefix}sessions"
|
|
237
|
+
conditions = []
|
|
238
|
+
params = []
|
|
239
|
+
param_idx = 1
|
|
240
|
+
|
|
241
|
+
if user_id:
|
|
242
|
+
conditions.append(f"user_id = ${param_idx}")
|
|
243
|
+
params.append(user_id)
|
|
244
|
+
param_idx += 1
|
|
245
|
+
|
|
246
|
+
if agent_id:
|
|
247
|
+
conditions.append(f"agent_id = ${param_idx}")
|
|
248
|
+
params.append(agent_id)
|
|
249
|
+
param_idx += 1
|
|
250
|
+
|
|
251
|
+
where_clause = f"WHERE {' AND '.join(conditions)}" if conditions else ""
|
|
252
|
+
params.extend([limit, offset])
|
|
253
|
+
|
|
254
|
+
async with self._pool.acquire() as conn:
|
|
255
|
+
rows = await conn.fetch(f"""
|
|
256
|
+
SELECT * FROM {table} {where_clause}
|
|
257
|
+
ORDER BY updated_at DESC
|
|
258
|
+
LIMIT ${param_idx} OFFSET ${param_idx + 1}
|
|
259
|
+
""", *params)
|
|
260
|
+
|
|
261
|
+
return [
|
|
262
|
+
ConversationSession(
|
|
263
|
+
session_id=row['session_id'],
|
|
264
|
+
user_id=row['user_id'],
|
|
265
|
+
agent_id=row['agent_id'],
|
|
266
|
+
name=row['name'],
|
|
267
|
+
metadata=json.loads(row['metadata']) if row['metadata'] else None,
|
|
268
|
+
created_at=row['created_at'],
|
|
269
|
+
updated_at=row['updated_at']
|
|
270
|
+
)
|
|
271
|
+
for row in rows
|
|
272
|
+
]
|
|
273
|
+
|
|
274
|
+
def list_sessions(
|
|
275
|
+
self,
|
|
276
|
+
user_id: Optional[str] = None,
|
|
277
|
+
agent_id: Optional[str] = None,
|
|
278
|
+
limit: int = 100,
|
|
279
|
+
offset: int = 0
|
|
280
|
+
) -> List[ConversationSession]:
|
|
281
|
+
"""Sync wrapper for list_sessions."""
|
|
282
|
+
return asyncio.get_event_loop().run_until_complete(
|
|
283
|
+
self.async_list_sessions(user_id, agent_id, limit, offset)
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
async def async_add_message(self, session_id: str, message: ConversationMessage) -> ConversationMessage:
|
|
287
|
+
"""Add a message asynchronously."""
|
|
288
|
+
if not self._initialized:
|
|
289
|
+
await self.init()
|
|
290
|
+
|
|
291
|
+
message.session_id = session_id
|
|
292
|
+
table = f"{self.table_prefix}messages"
|
|
293
|
+
|
|
294
|
+
async with self._pool.acquire() as conn:
|
|
295
|
+
await conn.execute(f"""
|
|
296
|
+
INSERT INTO {table} (id, session_id, role, content, metadata, created_at)
|
|
297
|
+
VALUES ($1, $2, $3, $4, $5, $6)
|
|
298
|
+
""", message.id, session_id, message.role, message.content,
|
|
299
|
+
json.dumps(message.metadata) if message.metadata else None,
|
|
300
|
+
message.created_at)
|
|
301
|
+
|
|
302
|
+
return message
|
|
303
|
+
|
|
304
|
+
def add_message(self, session_id: str, message: ConversationMessage) -> ConversationMessage:
|
|
305
|
+
"""Sync wrapper for add_message."""
|
|
306
|
+
return asyncio.get_event_loop().run_until_complete(
|
|
307
|
+
self.async_add_message(session_id, message)
|
|
308
|
+
)
|
|
309
|
+
|
|
310
|
+
async def async_get_messages(
|
|
311
|
+
self,
|
|
312
|
+
session_id: str,
|
|
313
|
+
limit: Optional[int] = None,
|
|
314
|
+
before: Optional[float] = None,
|
|
315
|
+
after: Optional[float] = None
|
|
316
|
+
) -> List[ConversationMessage]:
|
|
317
|
+
"""Get messages asynchronously."""
|
|
318
|
+
if not self._initialized:
|
|
319
|
+
await self.init()
|
|
320
|
+
|
|
321
|
+
table = f"{self.table_prefix}messages"
|
|
322
|
+
conditions = ["session_id = $1"]
|
|
323
|
+
params = [session_id]
|
|
324
|
+
param_idx = 2
|
|
325
|
+
|
|
326
|
+
if before:
|
|
327
|
+
conditions.append(f"created_at < ${param_idx}")
|
|
328
|
+
params.append(before)
|
|
329
|
+
param_idx += 1
|
|
330
|
+
|
|
331
|
+
if after:
|
|
332
|
+
conditions.append(f"created_at > ${param_idx}")
|
|
333
|
+
params.append(after)
|
|
334
|
+
param_idx += 1
|
|
335
|
+
|
|
336
|
+
where_clause = f"WHERE {' AND '.join(conditions)}"
|
|
337
|
+
limit_clause = f"LIMIT ${param_idx}" if limit else ""
|
|
338
|
+
if limit:
|
|
339
|
+
params.append(limit)
|
|
340
|
+
|
|
341
|
+
async with self._pool.acquire() as conn:
|
|
342
|
+
rows = await conn.fetch(f"""
|
|
343
|
+
SELECT * FROM {table} {where_clause}
|
|
344
|
+
ORDER BY created_at ASC {limit_clause}
|
|
345
|
+
""", *params)
|
|
346
|
+
|
|
347
|
+
return [
|
|
348
|
+
ConversationMessage(
|
|
349
|
+
id=row['id'],
|
|
350
|
+
session_id=row['session_id'],
|
|
351
|
+
role=row['role'],
|
|
352
|
+
content=row['content'],
|
|
353
|
+
metadata=json.loads(row['metadata']) if row['metadata'] else None,
|
|
354
|
+
created_at=row['created_at']
|
|
355
|
+
)
|
|
356
|
+
for row in rows
|
|
357
|
+
]
|
|
358
|
+
|
|
359
|
+
def get_messages(
|
|
360
|
+
self,
|
|
361
|
+
session_id: str,
|
|
362
|
+
limit: Optional[int] = None,
|
|
363
|
+
before: Optional[float] = None,
|
|
364
|
+
after: Optional[float] = None
|
|
365
|
+
) -> List[ConversationMessage]:
|
|
366
|
+
"""Sync wrapper for get_messages."""
|
|
367
|
+
return asyncio.get_event_loop().run_until_complete(
|
|
368
|
+
self.async_get_messages(session_id, limit, before, after)
|
|
369
|
+
)
|
|
370
|
+
|
|
371
|
+
async def async_delete_messages(self, session_id: str, message_ids: Optional[List[str]] = None) -> int:
|
|
372
|
+
"""Delete messages asynchronously."""
|
|
373
|
+
if not self._initialized:
|
|
374
|
+
await self.init()
|
|
375
|
+
|
|
376
|
+
table = f"{self.table_prefix}messages"
|
|
377
|
+
|
|
378
|
+
async with self._pool.acquire() as conn:
|
|
379
|
+
if message_ids is None:
|
|
380
|
+
result = await conn.execute(f"""
|
|
381
|
+
DELETE FROM {table} WHERE session_id = $1
|
|
382
|
+
""", session_id)
|
|
383
|
+
else:
|
|
384
|
+
result = await conn.execute(f"""
|
|
385
|
+
DELETE FROM {table} WHERE session_id = $1 AND id = ANY($2)
|
|
386
|
+
""", session_id, message_ids)
|
|
387
|
+
|
|
388
|
+
# Parse count from result like "DELETE 5"
|
|
389
|
+
try:
|
|
390
|
+
return int(result.split()[-1])
|
|
391
|
+
except (ValueError, IndexError):
|
|
392
|
+
return 0
|
|
393
|
+
|
|
394
|
+
def delete_messages(self, session_id: str, message_ids: Optional[List[str]] = None) -> int:
|
|
395
|
+
"""Sync wrapper for delete_messages."""
|
|
396
|
+
return asyncio.get_event_loop().run_until_complete(
|
|
397
|
+
self.async_delete_messages(session_id, message_ids)
|
|
398
|
+
)
|
|
399
|
+
|
|
400
|
+
async def async_close(self) -> None:
|
|
401
|
+
"""Close the connection pool."""
|
|
402
|
+
if self._pool:
|
|
403
|
+
await self._pool.close()
|
|
404
|
+
self._pool = None
|
|
405
|
+
self._initialized = False
|
|
406
|
+
|
|
407
|
+
def close(self) -> None:
|
|
408
|
+
"""Sync wrapper for close."""
|
|
409
|
+
if self._pool:
|
|
410
|
+
asyncio.get_event_loop().run_until_complete(self.async_close())
|