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,401 @@
1
+ """
2
+ PostgreSQL implementation of ConversationStore.
3
+
4
+ Requires: psycopg2-binary or psycopg2
5
+ Install: pip install psycopg2-binary
6
+ """
7
+
8
+ import json
9
+ import logging
10
+ from typing import Any, Dict, List, Optional
11
+
12
+ from .base import ConversationStore, ConversationSession, ConversationMessage
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ class PostgresConversationStore(ConversationStore):
18
+ """
19
+ PostgreSQL-based conversation store.
20
+
21
+ Connection URL format: postgresql://user:password@host:port/database
22
+
23
+ Example:
24
+ store = PostgresConversationStore(
25
+ url="postgresql://postgres:password@localhost:5432/praisonai"
26
+ )
27
+ """
28
+
29
+ SCHEMA_VERSION = "1.0.0"
30
+
31
+ def __init__(
32
+ self,
33
+ url: Optional[str] = None,
34
+ host: str = "localhost",
35
+ port: int = 5432,
36
+ database: str = "praisonai",
37
+ user: str = "postgres",
38
+ password: str = "",
39
+ schema: str = "public",
40
+ table_prefix: str = "praison_",
41
+ auto_create_tables: bool = True,
42
+ pool_size: int = 5,
43
+ ):
44
+ """
45
+ Initialize PostgreSQL conversation store.
46
+
47
+ Args:
48
+ url: Full connection URL (overrides individual params)
49
+ host: Database host
50
+ port: Database port
51
+ database: Database name
52
+ user: Database user
53
+ password: Database password
54
+ schema: PostgreSQL schema
55
+ table_prefix: Prefix for table names
56
+ auto_create_tables: Create tables if they don't exist
57
+ pool_size: Connection pool size
58
+ """
59
+ try:
60
+ import psycopg2
61
+ from psycopg2 import pool as pg_pool
62
+ from psycopg2.extras import RealDictCursor
63
+ except ImportError:
64
+ raise ImportError(
65
+ "psycopg2 is required for PostgreSQL support. "
66
+ "Install with: pip install psycopg2-binary"
67
+ )
68
+
69
+ self._psycopg2 = psycopg2
70
+ self._RealDictCursor = RealDictCursor
71
+
72
+ self.schema = schema
73
+ self.table_prefix = table_prefix
74
+ self.sessions_table = f"{schema}.{table_prefix}sessions"
75
+ self.messages_table = f"{schema}.{table_prefix}messages"
76
+
77
+ # Build connection params
78
+ if url:
79
+ self._pool = pg_pool.ThreadedConnectionPool(1, pool_size, url)
80
+ else:
81
+ self._pool = pg_pool.ThreadedConnectionPool(
82
+ 1, pool_size,
83
+ host=host,
84
+ port=port,
85
+ database=database,
86
+ user=user,
87
+ password=password,
88
+ )
89
+
90
+ if auto_create_tables:
91
+ self._create_tables()
92
+
93
+ def _get_conn(self):
94
+ """Get a connection from the pool."""
95
+ return self._pool.getconn()
96
+
97
+ def _put_conn(self, conn):
98
+ """Return a connection to the pool."""
99
+ self._pool.putconn(conn)
100
+
101
+ def _create_tables(self) -> None:
102
+ """Create tables if they don't exist."""
103
+ conn = self._get_conn()
104
+ try:
105
+ with conn.cursor() as cur:
106
+ # Create schema if not exists
107
+ cur.execute(f"CREATE SCHEMA IF NOT EXISTS {self.schema}")
108
+
109
+ # Sessions table
110
+ cur.execute(f"""
111
+ CREATE TABLE IF NOT EXISTS {self.sessions_table} (
112
+ session_id VARCHAR(255) PRIMARY KEY,
113
+ user_id VARCHAR(255),
114
+ agent_id VARCHAR(255),
115
+ name VARCHAR(255),
116
+ state JSONB,
117
+ metadata JSONB,
118
+ created_at DOUBLE PRECISION,
119
+ updated_at DOUBLE PRECISION
120
+ )
121
+ """)
122
+
123
+ # Sessions indexes
124
+ cur.execute(f"""
125
+ CREATE INDEX IF NOT EXISTS idx_{self.table_prefix}sessions_user
126
+ ON {self.sessions_table}(user_id)
127
+ """)
128
+ cur.execute(f"""
129
+ CREATE INDEX IF NOT EXISTS idx_{self.table_prefix}sessions_agent
130
+ ON {self.sessions_table}(agent_id)
131
+ """)
132
+ cur.execute(f"""
133
+ CREATE INDEX IF NOT EXISTS idx_{self.table_prefix}sessions_updated
134
+ ON {self.sessions_table}(updated_at DESC)
135
+ """)
136
+
137
+ # Messages table
138
+ cur.execute(f"""
139
+ CREATE TABLE IF NOT EXISTS {self.messages_table} (
140
+ id VARCHAR(255) PRIMARY KEY,
141
+ session_id VARCHAR(255) NOT NULL
142
+ REFERENCES {self.sessions_table}(session_id) ON DELETE CASCADE,
143
+ role VARCHAR(50) NOT NULL,
144
+ content TEXT,
145
+ tool_calls JSONB,
146
+ tool_call_id VARCHAR(255),
147
+ metadata JSONB,
148
+ created_at DOUBLE PRECISION DEFAULT EXTRACT(EPOCH FROM NOW())
149
+ )
150
+ """)
151
+
152
+ # Messages indexes
153
+ cur.execute(f"""
154
+ CREATE INDEX IF NOT EXISTS idx_{self.table_prefix}messages_session
155
+ ON {self.messages_table}(session_id)
156
+ """)
157
+ cur.execute(f"""
158
+ CREATE INDEX IF NOT EXISTS idx_{self.table_prefix}messages_created
159
+ ON {self.messages_table}(session_id, created_at)
160
+ """)
161
+
162
+ conn.commit()
163
+ logger.info(f"PostgreSQL tables created: {self.sessions_table}, {self.messages_table}")
164
+ finally:
165
+ self._put_conn(conn)
166
+
167
+ def create_session(self, session: ConversationSession) -> ConversationSession:
168
+ """Create a new session."""
169
+ conn = self._get_conn()
170
+ try:
171
+ with conn.cursor() as cur:
172
+ cur.execute(f"""
173
+ INSERT INTO {self.sessions_table}
174
+ (session_id, user_id, agent_id, name, state, metadata, created_at, updated_at)
175
+ VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
176
+ RETURNING session_id
177
+ """, (
178
+ session.session_id,
179
+ session.user_id,
180
+ session.agent_id,
181
+ session.name,
182
+ json.dumps(session.state) if session.state else None,
183
+ json.dumps(session.metadata) if session.metadata else None,
184
+ session.created_at,
185
+ session.updated_at,
186
+ ))
187
+ conn.commit()
188
+ return session
189
+ finally:
190
+ self._put_conn(conn)
191
+
192
+ def get_session(self, session_id: str) -> Optional[ConversationSession]:
193
+ """Get a session by ID."""
194
+ conn = self._get_conn()
195
+ try:
196
+ with conn.cursor(cursor_factory=self._RealDictCursor) as cur:
197
+ cur.execute(f"""
198
+ SELECT * FROM {self.sessions_table} WHERE session_id = %s
199
+ """, (session_id,))
200
+ row = cur.fetchone()
201
+ if not row:
202
+ return None
203
+ return ConversationSession(
204
+ session_id=row["session_id"],
205
+ user_id=row["user_id"],
206
+ agent_id=row["agent_id"],
207
+ name=row["name"],
208
+ state=row["state"],
209
+ metadata=row["metadata"],
210
+ created_at=row["created_at"],
211
+ updated_at=row["updated_at"],
212
+ )
213
+ finally:
214
+ self._put_conn(conn)
215
+
216
+ def update_session(self, session: ConversationSession) -> ConversationSession:
217
+ """Update an existing session."""
218
+ conn = self._get_conn()
219
+ try:
220
+ with conn.cursor() as cur:
221
+ cur.execute(f"""
222
+ UPDATE {self.sessions_table}
223
+ SET user_id = %s, agent_id = %s, name = %s,
224
+ state = %s, metadata = %s, updated_at = %s
225
+ WHERE session_id = %s
226
+ """, (
227
+ session.user_id,
228
+ session.agent_id,
229
+ session.name,
230
+ json.dumps(session.state) if session.state else None,
231
+ json.dumps(session.metadata) if session.metadata else None,
232
+ session.updated_at,
233
+ session.session_id,
234
+ ))
235
+ conn.commit()
236
+ return session
237
+ finally:
238
+ self._put_conn(conn)
239
+
240
+ def delete_session(self, session_id: str) -> bool:
241
+ """Delete a session and all its messages."""
242
+ conn = self._get_conn()
243
+ try:
244
+ with conn.cursor() as cur:
245
+ cur.execute(f"""
246
+ DELETE FROM {self.sessions_table} WHERE session_id = %s
247
+ """, (session_id,))
248
+ deleted = cur.rowcount > 0
249
+ conn.commit()
250
+ return deleted
251
+ finally:
252
+ self._put_conn(conn)
253
+
254
+ def list_sessions(
255
+ self,
256
+ user_id: Optional[str] = None,
257
+ agent_id: Optional[str] = None,
258
+ limit: int = 100,
259
+ offset: int = 0
260
+ ) -> List[ConversationSession]:
261
+ """List sessions, optionally filtered by user or agent."""
262
+ conn = self._get_conn()
263
+ try:
264
+ with conn.cursor(cursor_factory=self._RealDictCursor) as cur:
265
+ conditions = []
266
+ params = []
267
+
268
+ if user_id:
269
+ conditions.append("user_id = %s")
270
+ params.append(user_id)
271
+ if agent_id:
272
+ conditions.append("agent_id = %s")
273
+ params.append(agent_id)
274
+
275
+ where_clause = ""
276
+ if conditions:
277
+ where_clause = "WHERE " + " AND ".join(conditions)
278
+
279
+ params.extend([limit, offset])
280
+
281
+ cur.execute(f"""
282
+ SELECT * FROM {self.sessions_table}
283
+ {where_clause}
284
+ ORDER BY updated_at DESC
285
+ LIMIT %s OFFSET %s
286
+ """, params)
287
+
288
+ return [
289
+ ConversationSession(
290
+ session_id=row["session_id"],
291
+ user_id=row["user_id"],
292
+ agent_id=row["agent_id"],
293
+ name=row["name"],
294
+ state=row["state"],
295
+ metadata=row["metadata"],
296
+ created_at=row["created_at"],
297
+ updated_at=row["updated_at"],
298
+ )
299
+ for row in cur.fetchall()
300
+ ]
301
+ finally:
302
+ self._put_conn(conn)
303
+
304
+ def add_message(self, session_id: str, message: ConversationMessage) -> ConversationMessage:
305
+ """Add a message to a session."""
306
+ message.session_id = session_id
307
+ conn = self._get_conn()
308
+ try:
309
+ with conn.cursor() as cur:
310
+ cur.execute(f"""
311
+ INSERT INTO {self.messages_table}
312
+ (id, session_id, role, content, tool_calls, tool_call_id, metadata, created_at)
313
+ VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
314
+ """, (
315
+ message.id,
316
+ session_id,
317
+ message.role,
318
+ message.content,
319
+ json.dumps(message.tool_calls) if message.tool_calls else None,
320
+ message.tool_call_id,
321
+ json.dumps(message.metadata) if message.metadata else None,
322
+ message.created_at,
323
+ ))
324
+ conn.commit()
325
+ return message
326
+ finally:
327
+ self._put_conn(conn)
328
+
329
+ def 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 from a session."""
337
+ conn = self._get_conn()
338
+ try:
339
+ with conn.cursor(cursor_factory=self._RealDictCursor) as cur:
340
+ conditions = ["session_id = %s"]
341
+ params: List[Any] = [session_id]
342
+
343
+ if before:
344
+ conditions.append("created_at < %s")
345
+ params.append(before)
346
+ if after:
347
+ conditions.append("created_at > %s")
348
+ params.append(after)
349
+
350
+ where_clause = "WHERE " + " AND ".join(conditions)
351
+ limit_clause = f"LIMIT {limit}" if limit else ""
352
+
353
+ cur.execute(f"""
354
+ SELECT * FROM {self.messages_table}
355
+ {where_clause}
356
+ ORDER BY created_at ASC
357
+ {limit_clause}
358
+ """, params)
359
+
360
+ return [
361
+ ConversationMessage(
362
+ id=row["id"],
363
+ session_id=row["session_id"],
364
+ role=row["role"],
365
+ content=row["content"],
366
+ tool_calls=row["tool_calls"],
367
+ tool_call_id=row["tool_call_id"],
368
+ metadata=row["metadata"],
369
+ created_at=row["created_at"],
370
+ )
371
+ for row in cur.fetchall()
372
+ ]
373
+ finally:
374
+ self._put_conn(conn)
375
+
376
+ def delete_messages(self, session_id: str, message_ids: Optional[List[str]] = None) -> int:
377
+ """Delete messages. If message_ids is None, delete all messages in session."""
378
+ conn = self._get_conn()
379
+ try:
380
+ with conn.cursor() as cur:
381
+ if message_ids:
382
+ placeholders = ",".join(["%s"] * len(message_ids))
383
+ cur.execute(f"""
384
+ DELETE FROM {self.messages_table}
385
+ WHERE session_id = %s AND id IN ({placeholders})
386
+ """, [session_id] + message_ids)
387
+ else:
388
+ cur.execute(f"""
389
+ DELETE FROM {self.messages_table} WHERE session_id = %s
390
+ """, (session_id,))
391
+ deleted = cur.rowcount
392
+ conn.commit()
393
+ return deleted
394
+ finally:
395
+ self._put_conn(conn)
396
+
397
+ def close(self) -> None:
398
+ """Close the store and release resources."""
399
+ if self._pool:
400
+ self._pool.closeall()
401
+ self._pool = None
@@ -0,0 +1,240 @@
1
+ """
2
+ SingleStore implementation of ConversationStore.
3
+
4
+ Requires: singlestoredb
5
+ Install: pip install singlestoredb
6
+ """
7
+
8
+ import json
9
+ import logging
10
+ from typing import Any, List, Optional
11
+
12
+ from .base import ConversationStore, ConversationSession, ConversationMessage
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ class SingleStoreConversationStore(ConversationStore):
18
+ """
19
+ SingleStore-based conversation store.
20
+
21
+ SingleStore is MySQL-compatible with additional vector capabilities.
22
+
23
+ Example:
24
+ store = SingleStoreConversationStore(
25
+ url="singlestoredb://user:password@host:3306/database"
26
+ )
27
+ """
28
+
29
+ SCHEMA_VERSION = "1.0.0"
30
+
31
+ def __init__(
32
+ self,
33
+ url: Optional[str] = None,
34
+ host: str = "localhost",
35
+ port: int = 3306,
36
+ database: str = "praisonai",
37
+ user: str = "root",
38
+ password: str = "",
39
+ table_prefix: str = "praison_",
40
+ auto_create_tables: bool = True,
41
+ ):
42
+ try:
43
+ import singlestoredb as s2
44
+ except ImportError:
45
+ raise ImportError(
46
+ "singlestoredb is required for SingleStore support. "
47
+ "Install with: pip install singlestoredb"
48
+ )
49
+
50
+ self._s2 = s2
51
+ self.table_prefix = table_prefix
52
+ self.sessions_table = f"{table_prefix}sessions"
53
+ self.messages_table = f"{table_prefix}messages"
54
+
55
+ if url:
56
+ self._conn = s2.connect(url)
57
+ else:
58
+ self._conn = s2.connect(
59
+ host=host,
60
+ port=port,
61
+ database=database,
62
+ user=user,
63
+ password=password,
64
+ )
65
+
66
+ if auto_create_tables:
67
+ self._create_tables()
68
+
69
+ def _create_tables(self) -> None:
70
+ """Create tables if they don't exist."""
71
+ cur = self._conn.cursor()
72
+
73
+ cur.execute(f"""
74
+ CREATE TABLE IF NOT EXISTS {self.sessions_table} (
75
+ session_id VARCHAR(255) PRIMARY KEY,
76
+ user_id VARCHAR(255),
77
+ agent_id VARCHAR(255),
78
+ name VARCHAR(255),
79
+ state JSON,
80
+ metadata JSON,
81
+ created_at DOUBLE,
82
+ updated_at DOUBLE,
83
+ KEY idx_user (user_id),
84
+ KEY idx_agent (agent_id)
85
+ )
86
+ """)
87
+
88
+ cur.execute(f"""
89
+ CREATE TABLE IF NOT EXISTS {self.messages_table} (
90
+ id VARCHAR(255) PRIMARY KEY,
91
+ session_id VARCHAR(255) NOT NULL,
92
+ role VARCHAR(50) NOT NULL,
93
+ content TEXT,
94
+ tool_calls JSON,
95
+ tool_call_id VARCHAR(255),
96
+ metadata JSON,
97
+ created_at DOUBLE,
98
+ KEY idx_session (session_id),
99
+ KEY idx_created (session_id, created_at)
100
+ )
101
+ """)
102
+
103
+ self._conn.commit()
104
+ logger.info(f"SingleStore tables created")
105
+
106
+ def create_session(self, session: ConversationSession) -> ConversationSession:
107
+ cur = self._conn.cursor()
108
+ cur.execute(f"""
109
+ INSERT INTO {self.sessions_table}
110
+ (session_id, user_id, agent_id, name, state, metadata, created_at, updated_at)
111
+ VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
112
+ """, (
113
+ session.session_id, session.user_id, session.agent_id, session.name,
114
+ json.dumps(session.state) if session.state else None,
115
+ json.dumps(session.metadata) if session.metadata else None,
116
+ session.created_at, session.updated_at,
117
+ ))
118
+ self._conn.commit()
119
+ return session
120
+
121
+ def get_session(self, session_id: str) -> Optional[ConversationSession]:
122
+ cur = self._conn.cursor()
123
+ cur.execute(f"SELECT * FROM {self.sessions_table} WHERE session_id = %s", (session_id,))
124
+ row = cur.fetchone()
125
+ if not row:
126
+ return None
127
+ cols = [d[0] for d in cur.description]
128
+ data = dict(zip(cols, row))
129
+ return ConversationSession(
130
+ session_id=data["session_id"], user_id=data["user_id"],
131
+ agent_id=data["agent_id"], name=data["name"],
132
+ state=json.loads(data["state"]) if data["state"] else None,
133
+ metadata=json.loads(data["metadata"]) if data["metadata"] else None,
134
+ created_at=data["created_at"], updated_at=data["updated_at"],
135
+ )
136
+
137
+ def update_session(self, session: ConversationSession) -> ConversationSession:
138
+ cur = self._conn.cursor()
139
+ cur.execute(f"""
140
+ UPDATE {self.sessions_table}
141
+ SET user_id=%s, agent_id=%s, name=%s, state=%s, metadata=%s, updated_at=%s
142
+ WHERE session_id=%s
143
+ """, (
144
+ session.user_id, session.agent_id, session.name,
145
+ json.dumps(session.state) if session.state else None,
146
+ json.dumps(session.metadata) if session.metadata else None,
147
+ session.updated_at, session.session_id,
148
+ ))
149
+ self._conn.commit()
150
+ return session
151
+
152
+ def delete_session(self, session_id: str) -> bool:
153
+ cur = self._conn.cursor()
154
+ cur.execute(f"DELETE FROM {self.messages_table} WHERE session_id = %s", (session_id,))
155
+ cur.execute(f"DELETE FROM {self.sessions_table} WHERE session_id = %s", (session_id,))
156
+ self._conn.commit()
157
+ return cur.rowcount > 0
158
+
159
+ def list_sessions(self, user_id: Optional[str] = None, agent_id: Optional[str] = None,
160
+ limit: int = 100, offset: int = 0) -> List[ConversationSession]:
161
+ cur = self._conn.cursor()
162
+ conditions, params = [], []
163
+ if user_id:
164
+ conditions.append("user_id = %s")
165
+ params.append(user_id)
166
+ if agent_id:
167
+ conditions.append("agent_id = %s")
168
+ params.append(agent_id)
169
+ where = "WHERE " + " AND ".join(conditions) if conditions else ""
170
+ params.extend([limit, offset])
171
+ cur.execute(f"SELECT * FROM {self.sessions_table} {where} ORDER BY updated_at DESC LIMIT %s OFFSET %s", params)
172
+ cols = [d[0] for d in cur.description]
173
+ return [ConversationSession(
174
+ session_id=dict(zip(cols, r))["session_id"],
175
+ user_id=dict(zip(cols, r))["user_id"],
176
+ agent_id=dict(zip(cols, r))["agent_id"],
177
+ name=dict(zip(cols, r))["name"],
178
+ state=json.loads(dict(zip(cols, r))["state"]) if dict(zip(cols, r))["state"] else None,
179
+ metadata=json.loads(dict(zip(cols, r))["metadata"]) if dict(zip(cols, r))["metadata"] else None,
180
+ created_at=dict(zip(cols, r))["created_at"],
181
+ updated_at=dict(zip(cols, r))["updated_at"],
182
+ ) for r in cur.fetchall()]
183
+
184
+ def add_message(self, session_id: str, message: ConversationMessage) -> ConversationMessage:
185
+ message.session_id = session_id
186
+ cur = self._conn.cursor()
187
+ cur.execute(f"""
188
+ INSERT INTO {self.messages_table}
189
+ (id, session_id, role, content, tool_calls, tool_call_id, metadata, created_at)
190
+ VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
191
+ """, (
192
+ message.id, session_id, message.role, message.content,
193
+ json.dumps(message.tool_calls) if message.tool_calls else None,
194
+ message.tool_call_id,
195
+ json.dumps(message.metadata) if message.metadata else None,
196
+ message.created_at,
197
+ ))
198
+ self._conn.commit()
199
+ return message
200
+
201
+ def get_messages(self, session_id: str, limit: Optional[int] = None,
202
+ before: Optional[float] = None, after: Optional[float] = None) -> List[ConversationMessage]:
203
+ cur = self._conn.cursor()
204
+ conditions, params = ["session_id = %s"], [session_id]
205
+ if before:
206
+ conditions.append("created_at < %s")
207
+ params.append(before)
208
+ if after:
209
+ conditions.append("created_at > %s")
210
+ params.append(after)
211
+ where = "WHERE " + " AND ".join(conditions)
212
+ limit_clause = f"LIMIT {limit}" if limit else ""
213
+ cur.execute(f"SELECT * FROM {self.messages_table} {where} ORDER BY created_at ASC {limit_clause}", params)
214
+ cols = [d[0] for d in cur.description]
215
+ return [ConversationMessage(
216
+ id=dict(zip(cols, r))["id"],
217
+ session_id=dict(zip(cols, r))["session_id"],
218
+ role=dict(zip(cols, r))["role"],
219
+ content=dict(zip(cols, r))["content"],
220
+ tool_calls=json.loads(dict(zip(cols, r))["tool_calls"]) if dict(zip(cols, r))["tool_calls"] else None,
221
+ tool_call_id=dict(zip(cols, r))["tool_call_id"],
222
+ metadata=json.loads(dict(zip(cols, r))["metadata"]) if dict(zip(cols, r))["metadata"] else None,
223
+ created_at=dict(zip(cols, r))["created_at"],
224
+ ) for r in cur.fetchall()]
225
+
226
+ def delete_messages(self, session_id: str, message_ids: Optional[List[str]] = None) -> int:
227
+ cur = self._conn.cursor()
228
+ if message_ids:
229
+ placeholders = ",".join(["%s"] * len(message_ids))
230
+ cur.execute(f"DELETE FROM {self.messages_table} WHERE session_id = %s AND id IN ({placeholders})",
231
+ [session_id] + message_ids)
232
+ else:
233
+ cur.execute(f"DELETE FROM {self.messages_table} WHERE session_id = %s", (session_id,))
234
+ self._conn.commit()
235
+ return cur.rowcount
236
+
237
+ def close(self) -> None:
238
+ if self._conn:
239
+ self._conn.close()
240
+ self._conn = None