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,341 @@
1
+ """
2
+ SQLite implementation of ConversationStore.
3
+
4
+ Zero external dependencies - uses built-in sqlite3 module.
5
+ """
6
+
7
+ import json
8
+ import logging
9
+ import sqlite3
10
+ import threading
11
+ from typing import Any, List, Optional
12
+
13
+ from .base import ConversationStore, ConversationSession, ConversationMessage
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ class SQLiteConversationStore(ConversationStore):
19
+ """
20
+ SQLite-based conversation store.
21
+
22
+ Zero external dependencies - uses Python's built-in sqlite3.
23
+
24
+ Example:
25
+ store = SQLiteConversationStore(
26
+ path="./praisonai.db"
27
+ )
28
+ """
29
+
30
+ SCHEMA_VERSION = "1.0.0"
31
+
32
+ def __init__(
33
+ self,
34
+ path: str = "praisonai_conversations.db",
35
+ table_prefix: str = "praison_",
36
+ auto_create_tables: bool = True,
37
+ check_same_thread: bool = False,
38
+ ):
39
+ """
40
+ Initialize SQLite conversation store.
41
+
42
+ Args:
43
+ path: Path to SQLite database file
44
+ table_prefix: Prefix for table names
45
+ auto_create_tables: Create tables if they don't exist
46
+ check_same_thread: SQLite check_same_thread parameter
47
+ """
48
+ self.path = path
49
+ self.table_prefix = table_prefix
50
+ self.sessions_table = f"{table_prefix}sessions"
51
+ self.messages_table = f"{table_prefix}messages"
52
+ self._check_same_thread = check_same_thread
53
+ self._local = threading.local()
54
+
55
+ if auto_create_tables:
56
+ self._create_tables()
57
+
58
+ def _get_conn(self) -> sqlite3.Connection:
59
+ """Get thread-local connection."""
60
+ if not hasattr(self._local, "conn") or self._local.conn is None:
61
+ self._local.conn = sqlite3.connect(
62
+ self.path,
63
+ check_same_thread=self._check_same_thread
64
+ )
65
+ self._local.conn.row_factory = sqlite3.Row
66
+ return self._local.conn
67
+
68
+ def _create_tables(self) -> None:
69
+ """Create tables if they don't exist."""
70
+ conn = self._get_conn()
71
+ cur = conn.cursor()
72
+
73
+ # Sessions table
74
+ cur.execute(f"""
75
+ CREATE TABLE IF NOT EXISTS {self.sessions_table} (
76
+ session_id TEXT PRIMARY KEY,
77
+ user_id TEXT,
78
+ agent_id TEXT,
79
+ name TEXT,
80
+ state TEXT,
81
+ metadata TEXT,
82
+ created_at REAL,
83
+ updated_at REAL
84
+ )
85
+ """)
86
+
87
+ # Sessions indexes
88
+ cur.execute(f"""
89
+ CREATE INDEX IF NOT EXISTS idx_{self.table_prefix}sessions_user
90
+ ON {self.sessions_table}(user_id)
91
+ """)
92
+ cur.execute(f"""
93
+ CREATE INDEX IF NOT EXISTS idx_{self.table_prefix}sessions_agent
94
+ ON {self.sessions_table}(agent_id)
95
+ """)
96
+
97
+ # Messages table
98
+ cur.execute(f"""
99
+ CREATE TABLE IF NOT EXISTS {self.messages_table} (
100
+ id TEXT PRIMARY KEY,
101
+ session_id TEXT NOT NULL,
102
+ role TEXT NOT NULL,
103
+ content TEXT,
104
+ tool_calls TEXT,
105
+ tool_call_id TEXT,
106
+ metadata TEXT,
107
+ created_at REAL,
108
+ FOREIGN KEY (session_id) REFERENCES {self.sessions_table}(session_id) ON DELETE CASCADE
109
+ )
110
+ """)
111
+
112
+ # Messages indexes
113
+ cur.execute(f"""
114
+ CREATE INDEX IF NOT EXISTS idx_{self.table_prefix}messages_session
115
+ ON {self.messages_table}(session_id)
116
+ """)
117
+ cur.execute(f"""
118
+ CREATE INDEX IF NOT EXISTS idx_{self.table_prefix}messages_created
119
+ ON {self.messages_table}(session_id, created_at)
120
+ """)
121
+
122
+ # Enable foreign keys
123
+ cur.execute("PRAGMA foreign_keys = ON")
124
+
125
+ conn.commit()
126
+ logger.info(f"SQLite tables created: {self.sessions_table}, {self.messages_table}")
127
+
128
+ def create_session(self, session: ConversationSession) -> ConversationSession:
129
+ """Create a new session."""
130
+ conn = self._get_conn()
131
+ cur = conn.cursor()
132
+ cur.execute(f"""
133
+ INSERT INTO {self.sessions_table}
134
+ (session_id, user_id, agent_id, name, state, metadata, created_at, updated_at)
135
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
136
+ """, (
137
+ session.session_id,
138
+ session.user_id,
139
+ session.agent_id,
140
+ session.name,
141
+ json.dumps(session.state) if session.state else None,
142
+ json.dumps(session.metadata) if session.metadata else None,
143
+ session.created_at,
144
+ session.updated_at,
145
+ ))
146
+ conn.commit()
147
+ return session
148
+
149
+ def get_session(self, session_id: str) -> Optional[ConversationSession]:
150
+ """Get a session by ID."""
151
+ conn = self._get_conn()
152
+ cur = conn.cursor()
153
+ cur.execute(f"""
154
+ SELECT * FROM {self.sessions_table} WHERE session_id = ?
155
+ """, (session_id,))
156
+ row = cur.fetchone()
157
+ if not row:
158
+ return None
159
+ return ConversationSession(
160
+ session_id=row["session_id"],
161
+ user_id=row["user_id"],
162
+ agent_id=row["agent_id"],
163
+ name=row["name"],
164
+ state=json.loads(row["state"]) if row["state"] else None,
165
+ metadata=json.loads(row["metadata"]) if row["metadata"] else None,
166
+ created_at=row["created_at"],
167
+ updated_at=row["updated_at"],
168
+ )
169
+
170
+ def update_session(self, session: ConversationSession) -> ConversationSession:
171
+ """Update an existing session."""
172
+ conn = self._get_conn()
173
+ cur = conn.cursor()
174
+ cur.execute(f"""
175
+ UPDATE {self.sessions_table}
176
+ SET user_id = ?, agent_id = ?, name = ?,
177
+ state = ?, metadata = ?, updated_at = ?
178
+ WHERE session_id = ?
179
+ """, (
180
+ session.user_id,
181
+ session.agent_id,
182
+ session.name,
183
+ json.dumps(session.state) if session.state else None,
184
+ json.dumps(session.metadata) if session.metadata else None,
185
+ session.updated_at,
186
+ session.session_id,
187
+ ))
188
+ conn.commit()
189
+ return session
190
+
191
+ def delete_session(self, session_id: str) -> bool:
192
+ """Delete a session and all its messages."""
193
+ conn = self._get_conn()
194
+ cur = conn.cursor()
195
+ # Delete messages first (foreign key)
196
+ cur.execute(f"DELETE FROM {self.messages_table} WHERE session_id = ?", (session_id,))
197
+ cur.execute(f"DELETE FROM {self.sessions_table} WHERE session_id = ?", (session_id,))
198
+ deleted = cur.rowcount > 0
199
+ conn.commit()
200
+ return deleted
201
+
202
+ def list_sessions(
203
+ self,
204
+ user_id: Optional[str] = None,
205
+ agent_id: Optional[str] = None,
206
+ limit: int = 100,
207
+ offset: int = 0
208
+ ) -> List[ConversationSession]:
209
+ """List sessions, optionally filtered by user or agent."""
210
+ conn = self._get_conn()
211
+ cur = conn.cursor()
212
+
213
+ conditions = []
214
+ params: List[Any] = []
215
+
216
+ if user_id:
217
+ conditions.append("user_id = ?")
218
+ params.append(user_id)
219
+ if agent_id:
220
+ conditions.append("agent_id = ?")
221
+ params.append(agent_id)
222
+
223
+ where_clause = ""
224
+ if conditions:
225
+ where_clause = "WHERE " + " AND ".join(conditions)
226
+
227
+ params.extend([limit, offset])
228
+
229
+ cur.execute(f"""
230
+ SELECT * FROM {self.sessions_table}
231
+ {where_clause}
232
+ ORDER BY updated_at DESC
233
+ LIMIT ? OFFSET ?
234
+ """, params)
235
+
236
+ return [
237
+ ConversationSession(
238
+ session_id=row["session_id"],
239
+ user_id=row["user_id"],
240
+ agent_id=row["agent_id"],
241
+ name=row["name"],
242
+ state=json.loads(row["state"]) if row["state"] else None,
243
+ metadata=json.loads(row["metadata"]) if row["metadata"] else None,
244
+ created_at=row["created_at"],
245
+ updated_at=row["updated_at"],
246
+ )
247
+ for row in cur.fetchall()
248
+ ]
249
+
250
+ def add_message(self, session_id: str, message: ConversationMessage) -> ConversationMessage:
251
+ """Add a message to a session."""
252
+ message.session_id = session_id
253
+ conn = self._get_conn()
254
+ cur = conn.cursor()
255
+ cur.execute(f"""
256
+ INSERT INTO {self.messages_table}
257
+ (id, session_id, role, content, tool_calls, tool_call_id, metadata, created_at)
258
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
259
+ """, (
260
+ message.id,
261
+ session_id,
262
+ message.role,
263
+ message.content,
264
+ json.dumps(message.tool_calls) if message.tool_calls else None,
265
+ message.tool_call_id,
266
+ json.dumps(message.metadata) if message.metadata else None,
267
+ message.created_at,
268
+ ))
269
+ conn.commit()
270
+ return message
271
+
272
+ def get_messages(
273
+ self,
274
+ session_id: str,
275
+ limit: Optional[int] = None,
276
+ before: Optional[float] = None,
277
+ after: Optional[float] = None
278
+ ) -> List[ConversationMessage]:
279
+ """Get messages from a session."""
280
+ conn = self._get_conn()
281
+ cur = conn.cursor()
282
+
283
+ conditions = ["session_id = ?"]
284
+ params: List[Any] = [session_id]
285
+
286
+ if before:
287
+ conditions.append("created_at < ?")
288
+ params.append(before)
289
+ if after:
290
+ conditions.append("created_at > ?")
291
+ params.append(after)
292
+
293
+ where_clause = "WHERE " + " AND ".join(conditions)
294
+ limit_clause = f"LIMIT {limit}" if limit else ""
295
+
296
+ cur.execute(f"""
297
+ SELECT * FROM {self.messages_table}
298
+ {where_clause}
299
+ ORDER BY created_at ASC
300
+ {limit_clause}
301
+ """, params)
302
+
303
+ return [
304
+ ConversationMessage(
305
+ id=row["id"],
306
+ session_id=row["session_id"],
307
+ role=row["role"],
308
+ content=row["content"],
309
+ tool_calls=json.loads(row["tool_calls"]) if row["tool_calls"] else None,
310
+ tool_call_id=row["tool_call_id"],
311
+ metadata=json.loads(row["metadata"]) if row["metadata"] else None,
312
+ created_at=row["created_at"],
313
+ )
314
+ for row in cur.fetchall()
315
+ ]
316
+
317
+ def delete_messages(self, session_id: str, message_ids: Optional[List[str]] = None) -> int:
318
+ """Delete messages."""
319
+ conn = self._get_conn()
320
+ cur = conn.cursor()
321
+
322
+ if message_ids:
323
+ placeholders = ",".join(["?"] * len(message_ids))
324
+ cur.execute(f"""
325
+ DELETE FROM {self.messages_table}
326
+ WHERE session_id = ? AND id IN ({placeholders})
327
+ """, [session_id] + message_ids)
328
+ else:
329
+ cur.execute(f"""
330
+ DELETE FROM {self.messages_table} WHERE session_id = ?
331
+ """, (session_id,))
332
+
333
+ deleted = cur.rowcount
334
+ conn.commit()
335
+ return deleted
336
+
337
+ def close(self) -> None:
338
+ """Close the store."""
339
+ if hasattr(self._local, "conn") and self._local.conn:
340
+ self._local.conn.close()
341
+ self._local.conn = None
@@ -0,0 +1,203 @@
1
+ """
2
+ Supabase implementation of ConversationStore.
3
+
4
+ Requires: supabase
5
+ Install: pip install supabase
6
+ """
7
+
8
+ import json
9
+ import logging
10
+ import time
11
+ from typing import Any, Dict, List, Optional
12
+
13
+ from .base import ConversationStore, ConversationSession, ConversationMessage
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ class SupabaseConversationStore(ConversationStore):
19
+ """
20
+ Supabase-based conversation store.
21
+
22
+ Uses Supabase's PostgreSQL backend via REST API.
23
+
24
+ Example:
25
+ store = SupabaseConversationStore(
26
+ url="https://xxx.supabase.co",
27
+ key="your-anon-key"
28
+ )
29
+ """
30
+
31
+ SCHEMA_VERSION = "1.0.0"
32
+
33
+ def __init__(
34
+ self,
35
+ url: Optional[str] = None,
36
+ key: Optional[str] = None,
37
+ table_prefix: str = "praison_",
38
+ auto_create_tables: bool = False, # Tables should be created via Supabase dashboard
39
+ ):
40
+ """
41
+ Initialize Supabase conversation store.
42
+
43
+ Args:
44
+ url: Supabase project URL
45
+ key: Supabase anon/service key
46
+ table_prefix: Prefix for table names
47
+ auto_create_tables: Not supported - use Supabase dashboard
48
+ """
49
+ try:
50
+ from supabase import create_client, Client
51
+ except ImportError:
52
+ raise ImportError(
53
+ "supabase is required for Supabase support. "
54
+ "Install with: pip install supabase"
55
+ )
56
+
57
+ import os
58
+ url = url or os.getenv("SUPABASE_URL")
59
+ key = key or os.getenv("SUPABASE_KEY")
60
+
61
+ if not url or not key:
62
+ raise ValueError("Supabase URL and key are required")
63
+
64
+ self._client: Client = create_client(url, key)
65
+ self.table_prefix = table_prefix
66
+ self.sessions_table = f"{table_prefix}sessions"
67
+ self.messages_table = f"{table_prefix}messages"
68
+
69
+ if auto_create_tables:
70
+ logger.warning("auto_create_tables not supported for Supabase. Create tables via dashboard.")
71
+
72
+ def create_session(self, session: ConversationSession) -> ConversationSession:
73
+ data = {
74
+ "session_id": session.session_id,
75
+ "user_id": session.user_id,
76
+ "agent_id": session.agent_id,
77
+ "name": session.name,
78
+ "state": session.state,
79
+ "metadata": session.metadata,
80
+ "created_at": session.created_at,
81
+ "updated_at": session.updated_at,
82
+ }
83
+ self._client.table(self.sessions_table).insert(data).execute()
84
+ return session
85
+
86
+ def get_session(self, session_id: str) -> Optional[ConversationSession]:
87
+ result = self._client.table(self.sessions_table).select("*").eq("session_id", session_id).execute()
88
+ if not result.data:
89
+ return None
90
+ row = result.data[0]
91
+ return ConversationSession(
92
+ session_id=row["session_id"],
93
+ user_id=row.get("user_id"),
94
+ agent_id=row.get("agent_id"),
95
+ name=row.get("name"),
96
+ state=row.get("state"),
97
+ metadata=row.get("metadata"),
98
+ created_at=row.get("created_at"),
99
+ updated_at=row.get("updated_at"),
100
+ )
101
+
102
+ def update_session(self, session: ConversationSession) -> ConversationSession:
103
+ data = {
104
+ "user_id": session.user_id,
105
+ "agent_id": session.agent_id,
106
+ "name": session.name,
107
+ "state": session.state,
108
+ "metadata": session.metadata,
109
+ "updated_at": session.updated_at,
110
+ }
111
+ self._client.table(self.sessions_table).update(data).eq("session_id", session.session_id).execute()
112
+ return session
113
+
114
+ def delete_session(self, session_id: str) -> bool:
115
+ # Delete messages first
116
+ self._client.table(self.messages_table).delete().eq("session_id", session_id).execute()
117
+ result = self._client.table(self.sessions_table).delete().eq("session_id", session_id).execute()
118
+ return len(result.data) > 0 if result.data else False
119
+
120
+ def list_sessions(
121
+ self,
122
+ user_id: Optional[str] = None,
123
+ agent_id: Optional[str] = None,
124
+ limit: int = 100,
125
+ offset: int = 0
126
+ ) -> List[ConversationSession]:
127
+ query = self._client.table(self.sessions_table).select("*")
128
+ if user_id:
129
+ query = query.eq("user_id", user_id)
130
+ if agent_id:
131
+ query = query.eq("agent_id", agent_id)
132
+ query = query.order("updated_at", desc=True).range(offset, offset + limit - 1)
133
+ result = query.execute()
134
+
135
+ return [
136
+ ConversationSession(
137
+ session_id=row["session_id"],
138
+ user_id=row.get("user_id"),
139
+ agent_id=row.get("agent_id"),
140
+ name=row.get("name"),
141
+ state=row.get("state"),
142
+ metadata=row.get("metadata"),
143
+ created_at=row.get("created_at"),
144
+ updated_at=row.get("updated_at"),
145
+ )
146
+ for row in (result.data or [])
147
+ ]
148
+
149
+ def add_message(self, session_id: str, message: ConversationMessage) -> ConversationMessage:
150
+ message.session_id = session_id
151
+ data = {
152
+ "id": message.id,
153
+ "session_id": session_id,
154
+ "role": message.role,
155
+ "content": message.content,
156
+ "tool_calls": message.tool_calls,
157
+ "tool_call_id": message.tool_call_id,
158
+ "metadata": message.metadata,
159
+ "created_at": message.created_at,
160
+ }
161
+ self._client.table(self.messages_table).insert(data).execute()
162
+ return message
163
+
164
+ def get_messages(
165
+ self,
166
+ session_id: str,
167
+ limit: Optional[int] = None,
168
+ before: Optional[float] = None,
169
+ after: Optional[float] = None
170
+ ) -> List[ConversationMessage]:
171
+ query = self._client.table(self.messages_table).select("*").eq("session_id", session_id)
172
+ if before:
173
+ query = query.lt("created_at", before)
174
+ if after:
175
+ query = query.gt("created_at", after)
176
+ query = query.order("created_at", desc=False)
177
+ if limit:
178
+ query = query.limit(limit)
179
+ result = query.execute()
180
+
181
+ return [
182
+ ConversationMessage(
183
+ id=row["id"],
184
+ session_id=row["session_id"],
185
+ role=row["role"],
186
+ content=row.get("content", ""),
187
+ tool_calls=row.get("tool_calls"),
188
+ tool_call_id=row.get("tool_call_id"),
189
+ metadata=row.get("metadata"),
190
+ created_at=row.get("created_at"),
191
+ )
192
+ for row in (result.data or [])
193
+ ]
194
+
195
+ def delete_messages(self, session_id: str, message_ids: Optional[List[str]] = None) -> int:
196
+ if message_ids:
197
+ result = self._client.table(self.messages_table).delete().eq("session_id", session_id).in_("id", message_ids).execute()
198
+ else:
199
+ result = self._client.table(self.messages_table).delete().eq("session_id", session_id).execute()
200
+ return len(result.data) if result.data else 0
201
+
202
+ def close(self) -> None:
203
+ pass # Supabase client doesn't need explicit close