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.
Files changed (393) hide show
  1. praisonai/__init__.py +54 -0
  2. praisonai/__main__.py +15 -0
  3. praisonai/acp/__init__.py +54 -0
  4. praisonai/acp/config.py +159 -0
  5. praisonai/acp/server.py +587 -0
  6. praisonai/acp/session.py +219 -0
  7. praisonai/adapters/__init__.py +50 -0
  8. praisonai/adapters/readers.py +395 -0
  9. praisonai/adapters/rerankers.py +315 -0
  10. praisonai/adapters/retrievers.py +394 -0
  11. praisonai/adapters/vector_stores.py +409 -0
  12. praisonai/agent_scheduler.py +337 -0
  13. praisonai/agents_generator.py +903 -0
  14. praisonai/api/call.py +292 -0
  15. praisonai/auto.py +1197 -0
  16. praisonai/capabilities/__init__.py +275 -0
  17. praisonai/capabilities/a2a.py +140 -0
  18. praisonai/capabilities/assistants.py +283 -0
  19. praisonai/capabilities/audio.py +320 -0
  20. praisonai/capabilities/batches.py +469 -0
  21. praisonai/capabilities/completions.py +336 -0
  22. praisonai/capabilities/container_files.py +155 -0
  23. praisonai/capabilities/containers.py +93 -0
  24. praisonai/capabilities/embeddings.py +158 -0
  25. praisonai/capabilities/files.py +467 -0
  26. praisonai/capabilities/fine_tuning.py +293 -0
  27. praisonai/capabilities/guardrails.py +182 -0
  28. praisonai/capabilities/images.py +330 -0
  29. praisonai/capabilities/mcp.py +190 -0
  30. praisonai/capabilities/messages.py +270 -0
  31. praisonai/capabilities/moderations.py +154 -0
  32. praisonai/capabilities/ocr.py +217 -0
  33. praisonai/capabilities/passthrough.py +204 -0
  34. praisonai/capabilities/rag.py +207 -0
  35. praisonai/capabilities/realtime.py +160 -0
  36. praisonai/capabilities/rerank.py +165 -0
  37. praisonai/capabilities/responses.py +266 -0
  38. praisonai/capabilities/search.py +109 -0
  39. praisonai/capabilities/skills.py +133 -0
  40. praisonai/capabilities/vector_store_files.py +334 -0
  41. praisonai/capabilities/vector_stores.py +304 -0
  42. praisonai/capabilities/videos.py +141 -0
  43. praisonai/chainlit_ui.py +304 -0
  44. praisonai/chat/__init__.py +106 -0
  45. praisonai/chat/app.py +125 -0
  46. praisonai/cli/__init__.py +26 -0
  47. praisonai/cli/app.py +213 -0
  48. praisonai/cli/commands/__init__.py +75 -0
  49. praisonai/cli/commands/acp.py +70 -0
  50. praisonai/cli/commands/completion.py +333 -0
  51. praisonai/cli/commands/config.py +166 -0
  52. praisonai/cli/commands/debug.py +142 -0
  53. praisonai/cli/commands/diag.py +55 -0
  54. praisonai/cli/commands/doctor.py +166 -0
  55. praisonai/cli/commands/environment.py +179 -0
  56. praisonai/cli/commands/lsp.py +112 -0
  57. praisonai/cli/commands/mcp.py +210 -0
  58. praisonai/cli/commands/profile.py +457 -0
  59. praisonai/cli/commands/run.py +228 -0
  60. praisonai/cli/commands/schedule.py +150 -0
  61. praisonai/cli/commands/serve.py +97 -0
  62. praisonai/cli/commands/session.py +212 -0
  63. praisonai/cli/commands/traces.py +145 -0
  64. praisonai/cli/commands/version.py +101 -0
  65. praisonai/cli/configuration/__init__.py +18 -0
  66. praisonai/cli/configuration/loader.py +353 -0
  67. praisonai/cli/configuration/paths.py +114 -0
  68. praisonai/cli/configuration/schema.py +164 -0
  69. praisonai/cli/features/__init__.py +268 -0
  70. praisonai/cli/features/acp.py +236 -0
  71. praisonai/cli/features/action_orchestrator.py +546 -0
  72. praisonai/cli/features/agent_scheduler.py +773 -0
  73. praisonai/cli/features/agent_tools.py +474 -0
  74. praisonai/cli/features/agents.py +375 -0
  75. praisonai/cli/features/at_mentions.py +471 -0
  76. praisonai/cli/features/auto_memory.py +182 -0
  77. praisonai/cli/features/autonomy_mode.py +490 -0
  78. praisonai/cli/features/background.py +356 -0
  79. praisonai/cli/features/base.py +168 -0
  80. praisonai/cli/features/capabilities.py +1326 -0
  81. praisonai/cli/features/checkpoints.py +338 -0
  82. praisonai/cli/features/code_intelligence.py +652 -0
  83. praisonai/cli/features/compaction.py +294 -0
  84. praisonai/cli/features/compare.py +534 -0
  85. praisonai/cli/features/cost_tracker.py +514 -0
  86. praisonai/cli/features/debug.py +810 -0
  87. praisonai/cli/features/deploy.py +517 -0
  88. praisonai/cli/features/diag.py +289 -0
  89. praisonai/cli/features/doctor/__init__.py +63 -0
  90. praisonai/cli/features/doctor/checks/__init__.py +24 -0
  91. praisonai/cli/features/doctor/checks/acp_checks.py +240 -0
  92. praisonai/cli/features/doctor/checks/config_checks.py +366 -0
  93. praisonai/cli/features/doctor/checks/db_checks.py +366 -0
  94. praisonai/cli/features/doctor/checks/env_checks.py +543 -0
  95. praisonai/cli/features/doctor/checks/lsp_checks.py +199 -0
  96. praisonai/cli/features/doctor/checks/mcp_checks.py +349 -0
  97. praisonai/cli/features/doctor/checks/memory_checks.py +268 -0
  98. praisonai/cli/features/doctor/checks/network_checks.py +251 -0
  99. praisonai/cli/features/doctor/checks/obs_checks.py +328 -0
  100. praisonai/cli/features/doctor/checks/performance_checks.py +235 -0
  101. praisonai/cli/features/doctor/checks/permissions_checks.py +259 -0
  102. praisonai/cli/features/doctor/checks/selftest_checks.py +322 -0
  103. praisonai/cli/features/doctor/checks/serve_checks.py +426 -0
  104. praisonai/cli/features/doctor/checks/skills_checks.py +231 -0
  105. praisonai/cli/features/doctor/checks/tools_checks.py +371 -0
  106. praisonai/cli/features/doctor/engine.py +266 -0
  107. praisonai/cli/features/doctor/formatters.py +310 -0
  108. praisonai/cli/features/doctor/handler.py +397 -0
  109. praisonai/cli/features/doctor/models.py +264 -0
  110. praisonai/cli/features/doctor/registry.py +239 -0
  111. praisonai/cli/features/endpoints.py +1019 -0
  112. praisonai/cli/features/eval.py +560 -0
  113. praisonai/cli/features/external_agents.py +231 -0
  114. praisonai/cli/features/fast_context.py +410 -0
  115. praisonai/cli/features/flow_display.py +566 -0
  116. praisonai/cli/features/git_integration.py +651 -0
  117. praisonai/cli/features/guardrail.py +171 -0
  118. praisonai/cli/features/handoff.py +185 -0
  119. praisonai/cli/features/hooks.py +583 -0
  120. praisonai/cli/features/image.py +384 -0
  121. praisonai/cli/features/interactive_runtime.py +585 -0
  122. praisonai/cli/features/interactive_tools.py +380 -0
  123. praisonai/cli/features/interactive_tui.py +603 -0
  124. praisonai/cli/features/jobs.py +632 -0
  125. praisonai/cli/features/knowledge.py +531 -0
  126. praisonai/cli/features/lite.py +244 -0
  127. praisonai/cli/features/lsp_cli.py +225 -0
  128. praisonai/cli/features/mcp.py +169 -0
  129. praisonai/cli/features/message_queue.py +587 -0
  130. praisonai/cli/features/metrics.py +211 -0
  131. praisonai/cli/features/n8n.py +673 -0
  132. praisonai/cli/features/observability.py +293 -0
  133. praisonai/cli/features/ollama.py +361 -0
  134. praisonai/cli/features/output_style.py +273 -0
  135. praisonai/cli/features/package.py +631 -0
  136. praisonai/cli/features/performance.py +308 -0
  137. praisonai/cli/features/persistence.py +636 -0
  138. praisonai/cli/features/profile.py +226 -0
  139. praisonai/cli/features/profiler/__init__.py +81 -0
  140. praisonai/cli/features/profiler/core.py +558 -0
  141. praisonai/cli/features/profiler/optimizations.py +652 -0
  142. praisonai/cli/features/profiler/suite.py +386 -0
  143. praisonai/cli/features/profiling.py +350 -0
  144. praisonai/cli/features/queue/__init__.py +73 -0
  145. praisonai/cli/features/queue/manager.py +395 -0
  146. praisonai/cli/features/queue/models.py +286 -0
  147. praisonai/cli/features/queue/persistence.py +564 -0
  148. praisonai/cli/features/queue/scheduler.py +484 -0
  149. praisonai/cli/features/queue/worker.py +372 -0
  150. praisonai/cli/features/recipe.py +1723 -0
  151. praisonai/cli/features/recipes.py +449 -0
  152. praisonai/cli/features/registry.py +229 -0
  153. praisonai/cli/features/repo_map.py +860 -0
  154. praisonai/cli/features/router.py +466 -0
  155. praisonai/cli/features/sandbox_executor.py +515 -0
  156. praisonai/cli/features/serve.py +829 -0
  157. praisonai/cli/features/session.py +222 -0
  158. praisonai/cli/features/skills.py +856 -0
  159. praisonai/cli/features/slash_commands.py +650 -0
  160. praisonai/cli/features/telemetry.py +179 -0
  161. praisonai/cli/features/templates.py +1384 -0
  162. praisonai/cli/features/thinking.py +305 -0
  163. praisonai/cli/features/todo.py +334 -0
  164. praisonai/cli/features/tools.py +680 -0
  165. praisonai/cli/features/tui/__init__.py +83 -0
  166. praisonai/cli/features/tui/app.py +580 -0
  167. praisonai/cli/features/tui/cli.py +566 -0
  168. praisonai/cli/features/tui/debug.py +511 -0
  169. praisonai/cli/features/tui/events.py +99 -0
  170. praisonai/cli/features/tui/mock_provider.py +328 -0
  171. praisonai/cli/features/tui/orchestrator.py +652 -0
  172. praisonai/cli/features/tui/screens/__init__.py +50 -0
  173. praisonai/cli/features/tui/screens/main.py +245 -0
  174. praisonai/cli/features/tui/screens/queue.py +174 -0
  175. praisonai/cli/features/tui/screens/session.py +124 -0
  176. praisonai/cli/features/tui/screens/settings.py +148 -0
  177. praisonai/cli/features/tui/widgets/__init__.py +56 -0
  178. praisonai/cli/features/tui/widgets/chat.py +261 -0
  179. praisonai/cli/features/tui/widgets/composer.py +224 -0
  180. praisonai/cli/features/tui/widgets/queue_panel.py +200 -0
  181. praisonai/cli/features/tui/widgets/status.py +167 -0
  182. praisonai/cli/features/tui/widgets/tool_panel.py +248 -0
  183. praisonai/cli/features/workflow.py +720 -0
  184. praisonai/cli/legacy.py +236 -0
  185. praisonai/cli/main.py +5559 -0
  186. praisonai/cli/schedule_cli.py +54 -0
  187. praisonai/cli/state/__init__.py +31 -0
  188. praisonai/cli/state/identifiers.py +161 -0
  189. praisonai/cli/state/sessions.py +313 -0
  190. praisonai/code/__init__.py +93 -0
  191. praisonai/code/agent_tools.py +344 -0
  192. praisonai/code/diff/__init__.py +21 -0
  193. praisonai/code/diff/diff_strategy.py +432 -0
  194. praisonai/code/tools/__init__.py +27 -0
  195. praisonai/code/tools/apply_diff.py +221 -0
  196. praisonai/code/tools/execute_command.py +275 -0
  197. praisonai/code/tools/list_files.py +274 -0
  198. praisonai/code/tools/read_file.py +206 -0
  199. praisonai/code/tools/search_replace.py +248 -0
  200. praisonai/code/tools/write_file.py +217 -0
  201. praisonai/code/utils/__init__.py +46 -0
  202. praisonai/code/utils/file_utils.py +307 -0
  203. praisonai/code/utils/ignore_utils.py +308 -0
  204. praisonai/code/utils/text_utils.py +276 -0
  205. praisonai/db/__init__.py +64 -0
  206. praisonai/db/adapter.py +531 -0
  207. praisonai/deploy/__init__.py +62 -0
  208. praisonai/deploy/api.py +231 -0
  209. praisonai/deploy/docker.py +454 -0
  210. praisonai/deploy/doctor.py +367 -0
  211. praisonai/deploy/main.py +327 -0
  212. praisonai/deploy/models.py +179 -0
  213. praisonai/deploy/providers/__init__.py +33 -0
  214. praisonai/deploy/providers/aws.py +331 -0
  215. praisonai/deploy/providers/azure.py +358 -0
  216. praisonai/deploy/providers/base.py +101 -0
  217. praisonai/deploy/providers/gcp.py +314 -0
  218. praisonai/deploy/schema.py +208 -0
  219. praisonai/deploy.py +185 -0
  220. praisonai/endpoints/__init__.py +53 -0
  221. praisonai/endpoints/a2u_server.py +410 -0
  222. praisonai/endpoints/discovery.py +165 -0
  223. praisonai/endpoints/providers/__init__.py +28 -0
  224. praisonai/endpoints/providers/a2a.py +253 -0
  225. praisonai/endpoints/providers/a2u.py +208 -0
  226. praisonai/endpoints/providers/agents_api.py +171 -0
  227. praisonai/endpoints/providers/base.py +231 -0
  228. praisonai/endpoints/providers/mcp.py +263 -0
  229. praisonai/endpoints/providers/recipe.py +206 -0
  230. praisonai/endpoints/providers/tools_mcp.py +150 -0
  231. praisonai/endpoints/registry.py +131 -0
  232. praisonai/endpoints/server.py +161 -0
  233. praisonai/inbuilt_tools/__init__.py +24 -0
  234. praisonai/inbuilt_tools/autogen_tools.py +117 -0
  235. praisonai/inc/__init__.py +2 -0
  236. praisonai/inc/config.py +96 -0
  237. praisonai/inc/models.py +155 -0
  238. praisonai/integrations/__init__.py +56 -0
  239. praisonai/integrations/base.py +303 -0
  240. praisonai/integrations/claude_code.py +270 -0
  241. praisonai/integrations/codex_cli.py +255 -0
  242. praisonai/integrations/cursor_cli.py +195 -0
  243. praisonai/integrations/gemini_cli.py +222 -0
  244. praisonai/jobs/__init__.py +67 -0
  245. praisonai/jobs/executor.py +425 -0
  246. praisonai/jobs/models.py +230 -0
  247. praisonai/jobs/router.py +314 -0
  248. praisonai/jobs/server.py +186 -0
  249. praisonai/jobs/store.py +203 -0
  250. praisonai/llm/__init__.py +66 -0
  251. praisonai/llm/registry.py +382 -0
  252. praisonai/mcp_server/__init__.py +152 -0
  253. praisonai/mcp_server/adapters/__init__.py +74 -0
  254. praisonai/mcp_server/adapters/agents.py +128 -0
  255. praisonai/mcp_server/adapters/capabilities.py +168 -0
  256. praisonai/mcp_server/adapters/cli_tools.py +568 -0
  257. praisonai/mcp_server/adapters/extended_capabilities.py +462 -0
  258. praisonai/mcp_server/adapters/knowledge.py +93 -0
  259. praisonai/mcp_server/adapters/memory.py +104 -0
  260. praisonai/mcp_server/adapters/prompts.py +306 -0
  261. praisonai/mcp_server/adapters/resources.py +124 -0
  262. praisonai/mcp_server/adapters/tools_bridge.py +280 -0
  263. praisonai/mcp_server/auth/__init__.py +48 -0
  264. praisonai/mcp_server/auth/api_key.py +291 -0
  265. praisonai/mcp_server/auth/oauth.py +460 -0
  266. praisonai/mcp_server/auth/oidc.py +289 -0
  267. praisonai/mcp_server/auth/scopes.py +260 -0
  268. praisonai/mcp_server/cli.py +852 -0
  269. praisonai/mcp_server/elicitation.py +445 -0
  270. praisonai/mcp_server/icons.py +302 -0
  271. praisonai/mcp_server/recipe_adapter.py +573 -0
  272. praisonai/mcp_server/recipe_cli.py +824 -0
  273. praisonai/mcp_server/registry.py +703 -0
  274. praisonai/mcp_server/sampling.py +422 -0
  275. praisonai/mcp_server/server.py +490 -0
  276. praisonai/mcp_server/tasks.py +443 -0
  277. praisonai/mcp_server/transports/__init__.py +18 -0
  278. praisonai/mcp_server/transports/http_stream.py +376 -0
  279. praisonai/mcp_server/transports/stdio.py +132 -0
  280. praisonai/persistence/__init__.py +84 -0
  281. praisonai/persistence/config.py +238 -0
  282. praisonai/persistence/conversation/__init__.py +25 -0
  283. praisonai/persistence/conversation/async_mysql.py +427 -0
  284. praisonai/persistence/conversation/async_postgres.py +410 -0
  285. praisonai/persistence/conversation/async_sqlite.py +371 -0
  286. praisonai/persistence/conversation/base.py +151 -0
  287. praisonai/persistence/conversation/json_store.py +250 -0
  288. praisonai/persistence/conversation/mysql.py +387 -0
  289. praisonai/persistence/conversation/postgres.py +401 -0
  290. praisonai/persistence/conversation/singlestore.py +240 -0
  291. praisonai/persistence/conversation/sqlite.py +341 -0
  292. praisonai/persistence/conversation/supabase.py +203 -0
  293. praisonai/persistence/conversation/surrealdb.py +287 -0
  294. praisonai/persistence/factory.py +301 -0
  295. praisonai/persistence/hooks/__init__.py +18 -0
  296. praisonai/persistence/hooks/agent_hooks.py +297 -0
  297. praisonai/persistence/knowledge/__init__.py +26 -0
  298. praisonai/persistence/knowledge/base.py +144 -0
  299. praisonai/persistence/knowledge/cassandra.py +232 -0
  300. praisonai/persistence/knowledge/chroma.py +295 -0
  301. praisonai/persistence/knowledge/clickhouse.py +242 -0
  302. praisonai/persistence/knowledge/cosmosdb_vector.py +438 -0
  303. praisonai/persistence/knowledge/couchbase.py +286 -0
  304. praisonai/persistence/knowledge/lancedb.py +216 -0
  305. praisonai/persistence/knowledge/langchain_adapter.py +291 -0
  306. praisonai/persistence/knowledge/lightrag_adapter.py +212 -0
  307. praisonai/persistence/knowledge/llamaindex_adapter.py +256 -0
  308. praisonai/persistence/knowledge/milvus.py +277 -0
  309. praisonai/persistence/knowledge/mongodb_vector.py +306 -0
  310. praisonai/persistence/knowledge/pgvector.py +335 -0
  311. praisonai/persistence/knowledge/pinecone.py +253 -0
  312. praisonai/persistence/knowledge/qdrant.py +301 -0
  313. praisonai/persistence/knowledge/redis_vector.py +291 -0
  314. praisonai/persistence/knowledge/singlestore_vector.py +299 -0
  315. praisonai/persistence/knowledge/surrealdb_vector.py +309 -0
  316. praisonai/persistence/knowledge/upstash_vector.py +266 -0
  317. praisonai/persistence/knowledge/weaviate.py +223 -0
  318. praisonai/persistence/migrations/__init__.py +10 -0
  319. praisonai/persistence/migrations/manager.py +251 -0
  320. praisonai/persistence/orchestrator.py +406 -0
  321. praisonai/persistence/state/__init__.py +21 -0
  322. praisonai/persistence/state/async_mongodb.py +200 -0
  323. praisonai/persistence/state/base.py +107 -0
  324. praisonai/persistence/state/dynamodb.py +226 -0
  325. praisonai/persistence/state/firestore.py +175 -0
  326. praisonai/persistence/state/gcs.py +155 -0
  327. praisonai/persistence/state/memory.py +245 -0
  328. praisonai/persistence/state/mongodb.py +158 -0
  329. praisonai/persistence/state/redis.py +190 -0
  330. praisonai/persistence/state/upstash.py +144 -0
  331. praisonai/persistence/tests/__init__.py +3 -0
  332. praisonai/persistence/tests/test_all_backends.py +633 -0
  333. praisonai/profiler.py +1214 -0
  334. praisonai/recipe/__init__.py +134 -0
  335. praisonai/recipe/bridge.py +278 -0
  336. praisonai/recipe/core.py +893 -0
  337. praisonai/recipe/exceptions.py +54 -0
  338. praisonai/recipe/history.py +402 -0
  339. praisonai/recipe/models.py +266 -0
  340. praisonai/recipe/operations.py +440 -0
  341. praisonai/recipe/policy.py +422 -0
  342. praisonai/recipe/registry.py +849 -0
  343. praisonai/recipe/runtime.py +214 -0
  344. praisonai/recipe/security.py +711 -0
  345. praisonai/recipe/serve.py +859 -0
  346. praisonai/recipe/server.py +613 -0
  347. praisonai/scheduler/__init__.py +45 -0
  348. praisonai/scheduler/agent_scheduler.py +552 -0
  349. praisonai/scheduler/base.py +124 -0
  350. praisonai/scheduler/daemon_manager.py +225 -0
  351. praisonai/scheduler/state_manager.py +155 -0
  352. praisonai/scheduler/yaml_loader.py +193 -0
  353. praisonai/scheduler.py +194 -0
  354. praisonai/setup/__init__.py +1 -0
  355. praisonai/setup/build.py +21 -0
  356. praisonai/setup/post_install.py +23 -0
  357. praisonai/setup/setup_conda_env.py +25 -0
  358. praisonai/setup.py +16 -0
  359. praisonai/templates/__init__.py +116 -0
  360. praisonai/templates/cache.py +364 -0
  361. praisonai/templates/dependency_checker.py +358 -0
  362. praisonai/templates/discovery.py +391 -0
  363. praisonai/templates/loader.py +564 -0
  364. praisonai/templates/registry.py +511 -0
  365. praisonai/templates/resolver.py +206 -0
  366. praisonai/templates/security.py +327 -0
  367. praisonai/templates/tool_override.py +498 -0
  368. praisonai/templates/tools_doctor.py +256 -0
  369. praisonai/test.py +105 -0
  370. praisonai/train.py +562 -0
  371. praisonai/train_vision.py +306 -0
  372. praisonai/ui/agents.py +824 -0
  373. praisonai/ui/callbacks.py +57 -0
  374. praisonai/ui/chainlit_compat.py +246 -0
  375. praisonai/ui/chat.py +532 -0
  376. praisonai/ui/code.py +717 -0
  377. praisonai/ui/colab.py +474 -0
  378. praisonai/ui/colab_chainlit.py +81 -0
  379. praisonai/ui/components/aicoder.py +284 -0
  380. praisonai/ui/context.py +283 -0
  381. praisonai/ui/database_config.py +56 -0
  382. praisonai/ui/db.py +294 -0
  383. praisonai/ui/realtime.py +488 -0
  384. praisonai/ui/realtimeclient/__init__.py +756 -0
  385. praisonai/ui/realtimeclient/tools.py +242 -0
  386. praisonai/ui/sql_alchemy.py +710 -0
  387. praisonai/upload_vision.py +140 -0
  388. praisonai/version.py +1 -0
  389. praisonai-3.0.0.dist-info/METADATA +3493 -0
  390. praisonai-3.0.0.dist-info/RECORD +393 -0
  391. praisonai-3.0.0.dist-info/WHEEL +5 -0
  392. praisonai-3.0.0.dist-info/entry_points.txt +4 -0
  393. praisonai-3.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,238 @@
1
+ """
2
+ Configuration handling for PraisonAI persistence layer.
3
+
4
+ Supports configuration via:
5
+ - Environment variables
6
+ - Config file (YAML/JSON)
7
+ - CLI arguments
8
+ - Direct Python API
9
+ """
10
+
11
+ import os
12
+ import logging
13
+ from dataclasses import dataclass, field
14
+ from typing import Any, Dict, Optional
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+
19
+ # Environment variable mappings
20
+ ENV_VARS = {
21
+ # Conversation stores
22
+ "conversation_store": "PRAISONAI_CONVERSATION_STORE",
23
+ "conversation_url": "PRAISONAI_CONVERSATION_URL",
24
+ # Knowledge stores
25
+ "knowledge_store": "PRAISONAI_KNOWLEDGE_STORE",
26
+ "knowledge_url": "PRAISONAI_KNOWLEDGE_URL",
27
+ # State stores
28
+ "state_store": "PRAISONAI_STATE_STORE",
29
+ "state_url": "PRAISONAI_STATE_URL",
30
+ # Common
31
+ "session_id": "PRAISONAI_SESSION_ID",
32
+ "user_id": "PRAISONAI_USER_ID",
33
+ # PostgreSQL
34
+ "postgres_url": "POSTGRES_URL",
35
+ "postgres_host": "POSTGRES_HOST",
36
+ "postgres_port": "POSTGRES_PORT",
37
+ "postgres_database": "POSTGRES_DATABASE",
38
+ "postgres_user": "POSTGRES_USER",
39
+ "postgres_password": "POSTGRES_PASSWORD",
40
+ # Qdrant
41
+ "qdrant_url": "QDRANT_URL",
42
+ "qdrant_host": "QDRANT_HOST",
43
+ "qdrant_port": "QDRANT_PORT",
44
+ "qdrant_api_key": "QDRANT_API_KEY",
45
+ # Redis
46
+ "redis_url": "REDIS_URL",
47
+ "redis_host": "REDIS_HOST",
48
+ "redis_port": "REDIS_PORT",
49
+ "redis_password": "REDIS_PASSWORD",
50
+ # Pinecone
51
+ "pinecone_api_key": "PINECONE_API_KEY",
52
+ "pinecone_environment": "PINECONE_ENVIRONMENT",
53
+ "pinecone_index": "PINECONE_INDEX",
54
+ # ChromaDB
55
+ "chroma_path": "CHROMA_DB_PATH",
56
+ "chroma_host": "CHROMA_HOST",
57
+ "chroma_port": "CHROMA_PORT",
58
+ # Weaviate
59
+ "weaviate_url": "WEAVIATE_URL",
60
+ "weaviate_api_key": "WEAVIATE_API_KEY",
61
+ # Milvus
62
+ "milvus_host": "MILVUS_HOST",
63
+ "milvus_port": "MILVUS_PORT",
64
+ "milvus_token": "MILVUS_TOKEN",
65
+ # MongoDB
66
+ "mongodb_url": "MONGODB_URL",
67
+ "mongodb_database": "MONGODB_DATABASE",
68
+ # DynamoDB
69
+ "aws_region": "AWS_REGION",
70
+ "dynamodb_table": "DYNAMODB_TABLE",
71
+ # Firestore
72
+ "google_credentials": "GOOGLE_APPLICATION_CREDENTIALS",
73
+ "firestore_project": "FIRESTORE_PROJECT",
74
+ # Upstash
75
+ "upstash_redis_url": "UPSTASH_REDIS_URL",
76
+ "upstash_redis_token": "UPSTASH_REDIS_TOKEN",
77
+ "upstash_vector_url": "UPSTASH_VECTOR_URL",
78
+ "upstash_vector_token": "UPSTASH_VECTOR_TOKEN",
79
+ # Supabase
80
+ "supabase_url": "SUPABASE_URL",
81
+ "supabase_key": "SUPABASE_KEY",
82
+ # SurrealDB
83
+ "surrealdb_url": "SURREALDB_URL",
84
+ "surrealdb_namespace": "SURREALDB_NS",
85
+ "surrealdb_database": "SURREALDB_DB",
86
+ # MySQL
87
+ "mysql_url": "MYSQL_URL",
88
+ "mysql_host": "MYSQL_HOST",
89
+ "mysql_port": "MYSQL_PORT",
90
+ "mysql_database": "MYSQL_DATABASE",
91
+ "mysql_user": "MYSQL_USER",
92
+ "mysql_password": "MYSQL_PASSWORD",
93
+ # SingleStore
94
+ "singlestore_url": "SINGLESTORE_URL",
95
+ # ClickHouse
96
+ "clickhouse_host": "CLICKHOUSE_HOST",
97
+ "clickhouse_port": "CLICKHOUSE_PORT",
98
+ "clickhouse_user": "CLICKHOUSE_USER",
99
+ "clickhouse_password": "CLICKHOUSE_PASSWORD",
100
+ # Cassandra
101
+ "cassandra_hosts": "CASSANDRA_HOSTS",
102
+ "cassandra_keyspace": "CASSANDRA_KEYSPACE",
103
+ # LanceDB
104
+ "lancedb_path": "LANCEDB_PATH",
105
+ "lancedb_uri": "LANCEDB_URI",
106
+ }
107
+
108
+ # Supported backends
109
+ CONVERSATION_BACKENDS = ["postgres", "mysql", "sqlite", "singlestore", "supabase", "surrealdb"]
110
+ KNOWLEDGE_BACKENDS = ["qdrant", "pinecone", "chroma", "weaviate", "lancedb", "milvus", "pgvector", "redis", "cassandra", "clickhouse"]
111
+ STATE_BACKENDS = ["redis", "dynamodb", "firestore", "mongodb", "upstash", "memory"]
112
+
113
+
114
+ @dataclass
115
+ class PersistenceConfig:
116
+ """
117
+ Configuration for PraisonAI persistence layer.
118
+
119
+ Example:
120
+ config = PersistenceConfig(
121
+ conversation_store="postgres",
122
+ conversation_url="postgresql://localhost:5432/praisonai",
123
+ knowledge_store="qdrant",
124
+ knowledge_url="http://localhost:6333",
125
+ state_store="redis",
126
+ state_url="redis://localhost:6379",
127
+ )
128
+ """
129
+ # Store backends
130
+ conversation_store: Optional[str] = None
131
+ conversation_url: Optional[str] = None
132
+ conversation_options: Dict[str, Any] = field(default_factory=dict)
133
+
134
+ knowledge_store: Optional[str] = None
135
+ knowledge_url: Optional[str] = None
136
+ knowledge_options: Dict[str, Any] = field(default_factory=dict)
137
+
138
+ state_store: Optional[str] = None
139
+ state_url: Optional[str] = None
140
+ state_options: Dict[str, Any] = field(default_factory=dict)
141
+
142
+ # Session/user context
143
+ session_id: Optional[str] = None
144
+ user_id: Optional[str] = None
145
+
146
+ # General options
147
+ auto_create_tables: bool = True
148
+ lazy_init: bool = True
149
+
150
+ @classmethod
151
+ def from_env(cls) -> "PersistenceConfig":
152
+ """Create config from environment variables."""
153
+ return cls(
154
+ conversation_store=os.getenv(ENV_VARS["conversation_store"]),
155
+ conversation_url=os.getenv(ENV_VARS["conversation_url"]) or os.getenv(ENV_VARS["postgres_url"]),
156
+ knowledge_store=os.getenv(ENV_VARS["knowledge_store"]),
157
+ knowledge_url=os.getenv(ENV_VARS["knowledge_url"]) or os.getenv(ENV_VARS["qdrant_url"]),
158
+ state_store=os.getenv(ENV_VARS["state_store"]),
159
+ state_url=os.getenv(ENV_VARS["state_url"]) or os.getenv(ENV_VARS["redis_url"]),
160
+ session_id=os.getenv(ENV_VARS["session_id"]),
161
+ user_id=os.getenv(ENV_VARS["user_id"]),
162
+ )
163
+
164
+ @classmethod
165
+ def from_dict(cls, data: Dict[str, Any]) -> "PersistenceConfig":
166
+ """Create config from dictionary."""
167
+ return cls(**{k: v for k, v in data.items() if hasattr(cls, k)})
168
+
169
+ @classmethod
170
+ def from_yaml(cls, path: str) -> "PersistenceConfig":
171
+ """Load config from YAML file."""
172
+ try:
173
+ import yaml
174
+ except ImportError:
175
+ raise ImportError("PyYAML required for YAML config. Install with: pip install pyyaml")
176
+
177
+ with open(path) as f:
178
+ data = yaml.safe_load(f)
179
+
180
+ # Handle nested persistence config
181
+ if "persistence" in data:
182
+ data = data["persistence"]
183
+
184
+ return cls.from_dict(data)
185
+
186
+ def to_dict(self) -> Dict[str, Any]:
187
+ """Convert config to dictionary."""
188
+ return {
189
+ "conversation_store": self.conversation_store,
190
+ "conversation_url": self.conversation_url,
191
+ "conversation_options": self.conversation_options,
192
+ "knowledge_store": self.knowledge_store,
193
+ "knowledge_url": self.knowledge_url,
194
+ "knowledge_options": self.knowledge_options,
195
+ "state_store": self.state_store,
196
+ "state_url": self.state_url,
197
+ "state_options": self.state_options,
198
+ "session_id": self.session_id,
199
+ "user_id": self.user_id,
200
+ "auto_create_tables": self.auto_create_tables,
201
+ "lazy_init": self.lazy_init,
202
+ }
203
+
204
+ def validate(self) -> bool:
205
+ """Validate configuration."""
206
+ valid = True
207
+
208
+ if self.conversation_store and self.conversation_store not in CONVERSATION_BACKENDS:
209
+ logger.error(f"Invalid conversation_store: {self.conversation_store}. "
210
+ f"Supported: {CONVERSATION_BACKENDS}")
211
+ valid = False
212
+
213
+ if self.knowledge_store and self.knowledge_store not in KNOWLEDGE_BACKENDS:
214
+ logger.error(f"Invalid knowledge_store: {self.knowledge_store}. "
215
+ f"Supported: {KNOWLEDGE_BACKENDS}")
216
+ valid = False
217
+
218
+ if self.state_store and self.state_store not in STATE_BACKENDS:
219
+ logger.error(f"Invalid state_store: {self.state_store}. "
220
+ f"Supported: {STATE_BACKENDS}")
221
+ valid = False
222
+
223
+ return valid
224
+
225
+
226
+ def get_env_var(key: str, default: Optional[str] = None) -> Optional[str]:
227
+ """Get environment variable by config key name."""
228
+ env_name = ENV_VARS.get(key, key.upper())
229
+ return os.getenv(env_name, default)
230
+
231
+
232
+ def list_available_backends() -> Dict[str, list]:
233
+ """List all available backends by store type."""
234
+ return {
235
+ "conversation": CONVERSATION_BACKENDS,
236
+ "knowledge": KNOWLEDGE_BACKENDS,
237
+ "state": STATE_BACKENDS,
238
+ }
@@ -0,0 +1,25 @@
1
+ """
2
+ ConversationStore implementations for session and message persistence.
3
+
4
+ Supported backends:
5
+ - PostgreSQL (postgres)
6
+ - MySQL (mysql)
7
+ - SQLite (sqlite)
8
+ - SingleStore (singlestore)
9
+ - Supabase (supabase)
10
+ - SurrealDB (surrealdb)
11
+ """
12
+
13
+ from typing import TYPE_CHECKING
14
+
15
+ __all__ = [
16
+ "ConversationStore",
17
+ "ConversationSession",
18
+ "ConversationMessage",
19
+ ]
20
+
21
+ def __getattr__(name: str):
22
+ if name in ("ConversationStore", "ConversationSession", "ConversationMessage"):
23
+ from .base import ConversationStore, ConversationSession, ConversationMessage
24
+ return locals()[name]
25
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
@@ -0,0 +1,427 @@
1
+ """
2
+ Async MySQL implementation of ConversationStore.
3
+
4
+ Requires: aiomysql
5
+ Install: pip install aiomysql
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 AsyncMySQLConversationStore(ConversationStore):
20
+ """
21
+ Async MySQL conversation store using aiomysql.
22
+
23
+ Provides high-performance async database operations.
24
+
25
+ Example:
26
+ store = AsyncMySQLConversationStore(
27
+ host="localhost",
28
+ user="root",
29
+ password="password",
30
+ database="praisonai"
31
+ )
32
+ await store.init()
33
+ """
34
+
35
+ def __init__(
36
+ self,
37
+ url: Optional[str] = None,
38
+ host: str = "localhost",
39
+ port: int = 3306,
40
+ database: str = "praisonai",
41
+ user: str = "root",
42
+ password: str = "",
43
+ table_prefix: str = "praisonai_",
44
+ pool_size: int = 10,
45
+ ):
46
+ """
47
+ Initialize async MySQL store.
48
+
49
+ Args:
50
+ url: MySQL connection URL (takes precedence)
51
+ host: Database host
52
+ port: Database port
53
+ database: Database name
54
+ user: Database user
55
+ password: Database password
56
+ table_prefix: Prefix for table names
57
+ pool_size: Connection pool size
58
+ """
59
+ self.url = url
60
+ self.host = host
61
+ self.port = port
62
+ self.database = database
63
+ self.user = user
64
+ self.password = password
65
+ self.table_prefix = table_prefix
66
+ self.pool_size = pool_size
67
+ self._pool = None
68
+ self._initialized = False
69
+
70
+ if url:
71
+ self._parse_url(url)
72
+
73
+ def _parse_url(self, url: str):
74
+ """Parse MySQL URL into components."""
75
+ from urllib.parse import urlparse
76
+ parsed = urlparse(url)
77
+ self.host = parsed.hostname or "localhost"
78
+ self.port = parsed.port or 3306
79
+ self.database = parsed.path.lstrip('/') or "praisonai"
80
+ self.user = parsed.username or "root"
81
+ self.password = parsed.password or ""
82
+
83
+ async def init(self):
84
+ """Initialize connection pool and create tables."""
85
+ if self._initialized:
86
+ return
87
+
88
+ try:
89
+ import aiomysql
90
+ except ImportError:
91
+ raise ImportError(
92
+ "aiomysql is required for async MySQL support. "
93
+ "Install with: pip install aiomysql"
94
+ )
95
+
96
+ self._pool = await aiomysql.create_pool(
97
+ host=self.host,
98
+ port=self.port,
99
+ user=self.user,
100
+ password=self.password,
101
+ db=self.database,
102
+ minsize=1,
103
+ maxsize=self.pool_size,
104
+ autocommit=True
105
+ )
106
+
107
+ await self._create_tables()
108
+ self._initialized = True
109
+
110
+ async def _create_tables(self):
111
+ """Create required tables if they don't exist."""
112
+ sessions_table = f"{self.table_prefix}sessions"
113
+ messages_table = f"{self.table_prefix}messages"
114
+
115
+ async with self._pool.acquire() as conn:
116
+ async with conn.cursor() as cur:
117
+ await cur.execute(f"""
118
+ CREATE TABLE IF NOT EXISTS {sessions_table} (
119
+ session_id VARCHAR(255) PRIMARY KEY,
120
+ user_id VARCHAR(255),
121
+ agent_id VARCHAR(255),
122
+ name VARCHAR(255),
123
+ metadata JSON,
124
+ created_at DOUBLE,
125
+ updated_at DOUBLE,
126
+ INDEX idx_user_id (user_id),
127
+ INDEX idx_agent_id (agent_id)
128
+ )
129
+ """)
130
+
131
+ await cur.execute(f"""
132
+ CREATE TABLE IF NOT EXISTS {messages_table} (
133
+ id VARCHAR(255) PRIMARY KEY,
134
+ session_id VARCHAR(255),
135
+ role VARCHAR(50),
136
+ content TEXT,
137
+ metadata JSON,
138
+ created_at DOUBLE,
139
+ INDEX idx_session_id (session_id),
140
+ FOREIGN KEY (session_id) REFERENCES {sessions_table}(session_id) ON DELETE CASCADE
141
+ )
142
+ """)
143
+
144
+ async def async_create_session(self, session: ConversationSession) -> ConversationSession:
145
+ """Create a new session asynchronously."""
146
+ if not self._initialized:
147
+ await self.init()
148
+
149
+ table = f"{self.table_prefix}sessions"
150
+ async with self._pool.acquire() as conn:
151
+ async with conn.cursor() as cur:
152
+ await cur.execute(f"""
153
+ INSERT INTO {table} (session_id, user_id, agent_id, name, metadata, created_at, updated_at)
154
+ VALUES (%s, %s, %s, %s, %s, %s, %s)
155
+ """, (session.session_id, session.user_id, session.agent_id, session.name,
156
+ json.dumps(session.metadata) if session.metadata else None,
157
+ session.created_at, session.updated_at))
158
+
159
+ return session
160
+
161
+ def create_session(self, session: ConversationSession) -> ConversationSession:
162
+ """Sync wrapper for create_session."""
163
+ return asyncio.get_event_loop().run_until_complete(
164
+ self.async_create_session(session)
165
+ )
166
+
167
+ async def async_get_session(self, session_id: str) -> Optional[ConversationSession]:
168
+ """Get a session by ID asynchronously."""
169
+ if not self._initialized:
170
+ await self.init()
171
+
172
+ table = f"{self.table_prefix}sessions"
173
+ async with self._pool.acquire() as conn:
174
+ async with conn.cursor() as cur:
175
+ await cur.execute(f"""
176
+ SELECT session_id, user_id, agent_id, name, metadata, created_at, updated_at
177
+ FROM {table} WHERE session_id = %s
178
+ """, (session_id,))
179
+ row = await cur.fetchone()
180
+
181
+ if row:
182
+ return ConversationSession(
183
+ session_id=row[0],
184
+ user_id=row[1],
185
+ agent_id=row[2],
186
+ name=row[3],
187
+ metadata=json.loads(row[4]) if row[4] else None,
188
+ created_at=row[5],
189
+ updated_at=row[6]
190
+ )
191
+ return None
192
+
193
+ def get_session(self, session_id: str) -> Optional[ConversationSession]:
194
+ """Sync wrapper for get_session."""
195
+ return asyncio.get_event_loop().run_until_complete(
196
+ self.async_get_session(session_id)
197
+ )
198
+
199
+ async def async_update_session(self, session: ConversationSession) -> ConversationSession:
200
+ """Update an existing session asynchronously."""
201
+ if not self._initialized:
202
+ await self.init()
203
+
204
+ session.updated_at = time.time()
205
+ table = f"{self.table_prefix}sessions"
206
+
207
+ async with self._pool.acquire() as conn:
208
+ async with conn.cursor() as cur:
209
+ await cur.execute(f"""
210
+ UPDATE {table}
211
+ SET name = %s, metadata = %s, updated_at = %s
212
+ WHERE session_id = %s
213
+ """, (session.name, json.dumps(session.metadata) if session.metadata else None,
214
+ session.updated_at, session.session_id))
215
+
216
+ return session
217
+
218
+ def update_session(self, session: ConversationSession) -> ConversationSession:
219
+ """Sync wrapper for update_session."""
220
+ return asyncio.get_event_loop().run_until_complete(
221
+ self.async_update_session(session)
222
+ )
223
+
224
+ async def async_delete_session(self, session_id: str) -> bool:
225
+ """Delete a session asynchronously."""
226
+ if not self._initialized:
227
+ await self.init()
228
+
229
+ table = f"{self.table_prefix}sessions"
230
+ async with self._pool.acquire() as conn:
231
+ async with conn.cursor() as cur:
232
+ await cur.execute(f"""
233
+ DELETE FROM {table} WHERE session_id = %s
234
+ """, (session_id,))
235
+ return cur.rowcount > 0
236
+
237
+ def delete_session(self, session_id: str) -> bool:
238
+ """Sync wrapper for delete_session."""
239
+ return asyncio.get_event_loop().run_until_complete(
240
+ self.async_delete_session(session_id)
241
+ )
242
+
243
+ async def async_list_sessions(
244
+ self,
245
+ user_id: Optional[str] = None,
246
+ agent_id: Optional[str] = None,
247
+ limit: int = 100,
248
+ offset: int = 0
249
+ ) -> List[ConversationSession]:
250
+ """List sessions asynchronously."""
251
+ if not self._initialized:
252
+ await self.init()
253
+
254
+ table = f"{self.table_prefix}sessions"
255
+ conditions = []
256
+ params = []
257
+
258
+ if user_id:
259
+ conditions.append("user_id = %s")
260
+ params.append(user_id)
261
+
262
+ if agent_id:
263
+ conditions.append("agent_id = %s")
264
+ params.append(agent_id)
265
+
266
+ where_clause = f"WHERE {' AND '.join(conditions)}" if conditions else ""
267
+ params.extend([limit, offset])
268
+
269
+ async with self._pool.acquire() as conn:
270
+ async with conn.cursor() as cur:
271
+ await cur.execute(f"""
272
+ SELECT session_id, user_id, agent_id, name, metadata, created_at, updated_at
273
+ FROM {table} {where_clause}
274
+ ORDER BY updated_at DESC
275
+ LIMIT %s OFFSET %s
276
+ """, params)
277
+ rows = await cur.fetchall()
278
+
279
+ return [
280
+ ConversationSession(
281
+ session_id=row[0],
282
+ user_id=row[1],
283
+ agent_id=row[2],
284
+ name=row[3],
285
+ metadata=json.loads(row[4]) if row[4] else None,
286
+ created_at=row[5],
287
+ updated_at=row[6]
288
+ )
289
+ for row in rows
290
+ ]
291
+
292
+ def list_sessions(
293
+ self,
294
+ user_id: Optional[str] = None,
295
+ agent_id: Optional[str] = None,
296
+ limit: int = 100,
297
+ offset: int = 0
298
+ ) -> List[ConversationSession]:
299
+ """Sync wrapper for list_sessions."""
300
+ return asyncio.get_event_loop().run_until_complete(
301
+ self.async_list_sessions(user_id, agent_id, limit, offset)
302
+ )
303
+
304
+ async def async_add_message(self, session_id: str, message: ConversationMessage) -> ConversationMessage:
305
+ """Add a message asynchronously."""
306
+ if not self._initialized:
307
+ await self.init()
308
+
309
+ message.session_id = session_id
310
+ table = f"{self.table_prefix}messages"
311
+
312
+ async with self._pool.acquire() as conn:
313
+ async with conn.cursor() as cur:
314
+ await cur.execute(f"""
315
+ INSERT INTO {table} (id, session_id, role, content, metadata, created_at)
316
+ VALUES (%s, %s, %s, %s, %s, %s)
317
+ """, (message.id, session_id, message.role, message.content,
318
+ json.dumps(message.metadata) if message.metadata else None,
319
+ message.created_at))
320
+
321
+ return message
322
+
323
+ def add_message(self, session_id: str, message: ConversationMessage) -> ConversationMessage:
324
+ """Sync wrapper for add_message."""
325
+ return asyncio.get_event_loop().run_until_complete(
326
+ self.async_add_message(session_id, message)
327
+ )
328
+
329
+ async def async_get_messages(
330
+ self,
331
+ session_id: str,
332
+ limit: Optional[int] = None,
333
+ before: Optional[float] = None,
334
+ after: Optional[float] = None
335
+ ) -> List[ConversationMessage]:
336
+ """Get messages asynchronously."""
337
+ if not self._initialized:
338
+ await self.init()
339
+
340
+ table = f"{self.table_prefix}messages"
341
+ conditions = ["session_id = %s"]
342
+ params = [session_id]
343
+
344
+ if before:
345
+ conditions.append("created_at < %s")
346
+ params.append(before)
347
+
348
+ if after:
349
+ conditions.append("created_at > %s")
350
+ params.append(after)
351
+
352
+ where_clause = f"WHERE {' AND '.join(conditions)}"
353
+ limit_clause = "LIMIT %s" if limit else ""
354
+ if limit:
355
+ params.append(limit)
356
+
357
+ async with self._pool.acquire() as conn:
358
+ async with conn.cursor() as cur:
359
+ await cur.execute(f"""
360
+ SELECT id, session_id, role, content, metadata, created_at
361
+ FROM {table} {where_clause}
362
+ ORDER BY created_at ASC {limit_clause}
363
+ """, params)
364
+ rows = await cur.fetchall()
365
+
366
+ return [
367
+ ConversationMessage(
368
+ id=row[0],
369
+ session_id=row[1],
370
+ role=row[2],
371
+ content=row[3],
372
+ metadata=json.loads(row[4]) if row[4] else None,
373
+ created_at=row[5]
374
+ )
375
+ for row in rows
376
+ ]
377
+
378
+ def get_messages(
379
+ self,
380
+ session_id: str,
381
+ limit: Optional[int] = None,
382
+ before: Optional[float] = None,
383
+ after: Optional[float] = None
384
+ ) -> List[ConversationMessage]:
385
+ """Sync wrapper for get_messages."""
386
+ return asyncio.get_event_loop().run_until_complete(
387
+ self.async_get_messages(session_id, limit, before, after)
388
+ )
389
+
390
+ async def async_delete_messages(self, session_id: str, message_ids: Optional[List[str]] = None) -> int:
391
+ """Delete messages asynchronously."""
392
+ if not self._initialized:
393
+ await self.init()
394
+
395
+ table = f"{self.table_prefix}messages"
396
+
397
+ async with self._pool.acquire() as conn:
398
+ async with conn.cursor() as cur:
399
+ if message_ids is None:
400
+ await cur.execute(f"""
401
+ DELETE FROM {table} WHERE session_id = %s
402
+ """, (session_id,))
403
+ else:
404
+ placeholders = ','.join(['%s'] * len(message_ids))
405
+ await cur.execute(f"""
406
+ DELETE FROM {table} WHERE session_id = %s AND id IN ({placeholders})
407
+ """, [session_id] + message_ids)
408
+ return cur.rowcount
409
+
410
+ def delete_messages(self, session_id: str, message_ids: Optional[List[str]] = None) -> int:
411
+ """Sync wrapper for delete_messages."""
412
+ return asyncio.get_event_loop().run_until_complete(
413
+ self.async_delete_messages(session_id, message_ids)
414
+ )
415
+
416
+ async def async_close(self) -> None:
417
+ """Close the connection pool."""
418
+ if self._pool:
419
+ self._pool.close()
420
+ await self._pool.wait_closed()
421
+ self._pool = None
422
+ self._initialized = False
423
+
424
+ def close(self) -> None:
425
+ """Sync wrapper for close."""
426
+ if self._pool:
427
+ asyncio.get_event_loop().run_until_complete(self.async_close())