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,219 @@
1
+ """
2
+ ACP session management.
3
+
4
+ Handles session creation, persistence, and resume functionality.
5
+ """
6
+
7
+ import json
8
+ import logging
9
+ import time
10
+ import uuid
11
+ from dataclasses import dataclass, field
12
+ from pathlib import Path
13
+ from typing import Any, Dict, List, Optional
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ @dataclass
19
+ class ACPSession:
20
+ """Represents an ACP conversation session."""
21
+
22
+ session_id: str
23
+ workspace: Path
24
+ created_at: float = field(default_factory=time.time)
25
+ last_activity: float = field(default_factory=time.time)
26
+
27
+ # Agent attribution
28
+ agent_id: Optional[str] = None
29
+ run_id: Optional[str] = None
30
+ trace_id: Optional[str] = None
31
+
32
+ # Session state
33
+ mode: str = "manual" # manual, auto, full_auto
34
+ model: Optional[str] = None
35
+
36
+ # Conversation history (for resume)
37
+ messages: List[Dict[str, Any]] = field(default_factory=list)
38
+ tool_calls: List[Dict[str, Any]] = field(default_factory=list)
39
+
40
+ # MCP servers
41
+ mcp_servers: List[Dict[str, Any]] = field(default_factory=list)
42
+
43
+ @classmethod
44
+ def create(cls, workspace: Path, agent_id: Optional[str] = None) -> "ACPSession":
45
+ """Create a new session."""
46
+ session_id = f"sess_{uuid.uuid4().hex[:16]}"
47
+ return cls(
48
+ session_id=session_id,
49
+ workspace=workspace,
50
+ agent_id=agent_id,
51
+ run_id=f"run_{uuid.uuid4().hex[:8]}",
52
+ trace_id=f"trace_{uuid.uuid4().hex[:8]}",
53
+ )
54
+
55
+ def update_activity(self) -> None:
56
+ """Update last activity timestamp."""
57
+ self.last_activity = time.time()
58
+
59
+ def add_message(self, role: str, content: Any) -> None:
60
+ """Add a message to the conversation history."""
61
+ self.messages.append({
62
+ "role": role,
63
+ "content": content,
64
+ "timestamp": time.time(),
65
+ })
66
+ self.update_activity()
67
+
68
+ def add_tool_call(self, tool_call_id: str, title: str, status: str, **kwargs) -> None:
69
+ """Add a tool call to the history."""
70
+ self.tool_calls.append({
71
+ "tool_call_id": tool_call_id,
72
+ "title": title,
73
+ "status": status,
74
+ "timestamp": time.time(),
75
+ **kwargs,
76
+ })
77
+ self.update_activity()
78
+
79
+ def to_dict(self) -> Dict[str, Any]:
80
+ """Serialize session to dictionary."""
81
+ return {
82
+ "session_id": self.session_id,
83
+ "workspace": str(self.workspace),
84
+ "created_at": self.created_at,
85
+ "last_activity": self.last_activity,
86
+ "agent_id": self.agent_id,
87
+ "run_id": self.run_id,
88
+ "trace_id": self.trace_id,
89
+ "mode": self.mode,
90
+ "model": self.model,
91
+ "messages": self.messages,
92
+ "tool_calls": self.tool_calls,
93
+ "mcp_servers": self.mcp_servers,
94
+ }
95
+
96
+ @classmethod
97
+ def from_dict(cls, data: Dict[str, Any]) -> "ACPSession":
98
+ """Deserialize session from dictionary."""
99
+ return cls(
100
+ session_id=data["session_id"],
101
+ workspace=Path(data["workspace"]),
102
+ created_at=data.get("created_at", time.time()),
103
+ last_activity=data.get("last_activity", time.time()),
104
+ agent_id=data.get("agent_id"),
105
+ run_id=data.get("run_id"),
106
+ trace_id=data.get("trace_id"),
107
+ mode=data.get("mode", "manual"),
108
+ model=data.get("model"),
109
+ messages=data.get("messages", []),
110
+ tool_calls=data.get("tool_calls", []),
111
+ mcp_servers=data.get("mcp_servers", []),
112
+ )
113
+
114
+
115
+ class SessionStore:
116
+ """Persistent storage for ACP sessions."""
117
+
118
+ def __init__(self, storage_dir: Optional[Path] = None):
119
+ """Initialize session store."""
120
+ if storage_dir is None:
121
+ storage_dir = Path.home() / ".praison" / "acp" / "sessions"
122
+ self.storage_dir = storage_dir
123
+ self.storage_dir.mkdir(parents=True, exist_ok=True)
124
+ self._last_session_file = self.storage_dir / ".last_session"
125
+
126
+ def _session_path(self, session_id: str) -> Path:
127
+ """Get path for session file."""
128
+ return self.storage_dir / f"{session_id}.json"
129
+
130
+ def save(self, session: ACPSession) -> None:
131
+ """Save session to disk."""
132
+ try:
133
+ path = self._session_path(session.session_id)
134
+ with open(path, "w") as f:
135
+ json.dump(session.to_dict(), f, indent=2)
136
+
137
+ # Update last session pointer
138
+ with open(self._last_session_file, "w") as f:
139
+ f.write(session.session_id)
140
+
141
+ logger.debug(f"Saved session {session.session_id}")
142
+ except Exception as e:
143
+ logger.error(f"Failed to save session: {e}")
144
+
145
+ def load(self, session_id: str) -> Optional[ACPSession]:
146
+ """Load session from disk."""
147
+ try:
148
+ path = self._session_path(session_id)
149
+ if not path.exists():
150
+ logger.warning(f"Session not found: {session_id}")
151
+ return None
152
+
153
+ with open(path) as f:
154
+ data = json.load(f)
155
+
156
+ return ACPSession.from_dict(data)
157
+ except Exception as e:
158
+ logger.error(f"Failed to load session: {e}")
159
+ return None
160
+
161
+ def load_last(self) -> Optional[ACPSession]:
162
+ """Load the most recent session."""
163
+ try:
164
+ if not self._last_session_file.exists():
165
+ return None
166
+
167
+ with open(self._last_session_file) as f:
168
+ session_id = f.read().strip()
169
+
170
+ if session_id:
171
+ return self.load(session_id)
172
+ return None
173
+ except Exception as e:
174
+ logger.error(f"Failed to load last session: {e}")
175
+ return None
176
+
177
+ def delete(self, session_id: str) -> bool:
178
+ """Delete a session."""
179
+ try:
180
+ path = self._session_path(session_id)
181
+ if path.exists():
182
+ path.unlink()
183
+ logger.debug(f"Deleted session {session_id}")
184
+ return True
185
+ return False
186
+ except Exception as e:
187
+ logger.error(f"Failed to delete session: {e}")
188
+ return False
189
+
190
+ def list_sessions(self, limit: int = 50) -> List[ACPSession]:
191
+ """List all sessions, sorted by last activity."""
192
+ sessions = []
193
+ try:
194
+ for path in self.storage_dir.glob("sess_*.json"):
195
+ try:
196
+ with open(path) as f:
197
+ data = json.load(f)
198
+ sessions.append(ACPSession.from_dict(data))
199
+ except Exception:
200
+ continue
201
+
202
+ # Sort by last activity, most recent first
203
+ sessions.sort(key=lambda s: s.last_activity, reverse=True)
204
+ return sessions[:limit]
205
+ except Exception as e:
206
+ logger.error(f"Failed to list sessions: {e}")
207
+ return []
208
+
209
+ def cleanup_old_sessions(self, max_age_days: int = 30) -> int:
210
+ """Remove sessions older than max_age_days."""
211
+ cutoff = time.time() - (max_age_days * 24 * 60 * 60)
212
+ removed = 0
213
+
214
+ for session in self.list_sessions(limit=1000):
215
+ if session.last_activity < cutoff:
216
+ if self.delete(session.session_id):
217
+ removed += 1
218
+
219
+ return removed
@@ -0,0 +1,50 @@
1
+ """
2
+ PraisonAI Adapters - Implementations for core protocols.
3
+
4
+ This module provides concrete implementations of:
5
+ - Reader adapters (AutoReader, LlamaIndexReaderAdapter, MarkItDownReaderAdapter)
6
+ - Vector store adapters (ChromaAdapter, PineconeAdapter, etc.)
7
+ - Retriever implementations
8
+ - Reranker implementations
9
+ """
10
+
11
+ # Lazy loading to avoid heavy imports at package load time
12
+ _LAZY_IMPORTS = {
13
+ # Readers
14
+ "AutoReader": ("praisonai.adapters.readers", "AutoReader"),
15
+ "MarkItDownReader": ("praisonai.adapters.readers", "MarkItDownReader"),
16
+ "TextReader": ("praisonai.adapters.readers", "TextReader"),
17
+ "DirectoryReader": ("praisonai.adapters.readers", "DirectoryReader"),
18
+ "register_default_readers": ("praisonai.adapters.readers", "register_default_readers"),
19
+
20
+ # Vector stores
21
+ "ChromaVectorStore": ("praisonai.adapters.vector_stores", "ChromaVectorStore"),
22
+ "register_default_vector_stores": ("praisonai.adapters.vector_stores", "register_default_vector_stores"),
23
+
24
+ # Retrievers
25
+ "BasicRetriever": ("praisonai.adapters.retrievers", "BasicRetriever"),
26
+ "FusionRetriever": ("praisonai.adapters.retrievers", "FusionRetriever"),
27
+ "register_default_retrievers": ("praisonai.adapters.retrievers", "register_default_retrievers"),
28
+
29
+ # Rerankers
30
+ "LLMReranker": ("praisonai.adapters.rerankers", "LLMReranker"),
31
+ "register_default_rerankers": ("praisonai.adapters.rerankers", "register_default_rerankers"),
32
+ }
33
+
34
+
35
+ def __getattr__(name: str):
36
+ """Lazy load adapters."""
37
+ if name in _LAZY_IMPORTS:
38
+ module_path, attr_name = _LAZY_IMPORTS[name]
39
+ import importlib
40
+ module = importlib.import_module(module_path)
41
+ return getattr(module, attr_name)
42
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
43
+
44
+
45
+ def __dir__():
46
+ """List available attributes."""
47
+ return list(_LAZY_IMPORTS.keys())
48
+
49
+
50
+ __all__ = list(_LAZY_IMPORTS.keys())
@@ -0,0 +1,395 @@
1
+ """
2
+ Reader Adapters for PraisonAI.
3
+
4
+ Provides concrete implementations of ReaderProtocol:
5
+ - TextReader: Plain text files
6
+ - MarkItDownReader: Uses markitdown for documents
7
+ - DirectoryReader: Reads all files in a directory
8
+ - AutoReader: Automatic file type detection and routing
9
+ """
10
+
11
+ import os
12
+ import glob as glob_module
13
+ import logging
14
+ import importlib.util
15
+ from typing import Any, Dict, List, Optional
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+ # Lazy import flags
20
+ _MARKITDOWN_AVAILABLE = None
21
+ _LLAMA_INDEX_AVAILABLE = None
22
+
23
+
24
+ def _check_markitdown():
25
+ """Check if markitdown is available."""
26
+ global _MARKITDOWN_AVAILABLE
27
+ if _MARKITDOWN_AVAILABLE is None:
28
+ _MARKITDOWN_AVAILABLE = importlib.util.find_spec("markitdown") is not None
29
+ return _MARKITDOWN_AVAILABLE
30
+
31
+
32
+ def _check_llama_index():
33
+ """Check if llama_index is available."""
34
+ global _LLAMA_INDEX_AVAILABLE
35
+ if _LLAMA_INDEX_AVAILABLE is None:
36
+ _LLAMA_INDEX_AVAILABLE = importlib.util.find_spec("llama_index") is not None
37
+ return _LLAMA_INDEX_AVAILABLE
38
+
39
+
40
+ class TextReader:
41
+ """Simple text file reader."""
42
+
43
+ name: str = "text"
44
+ supported_extensions: List[str] = ["txt", "text", "log"]
45
+
46
+ def load(
47
+ self,
48
+ source: str,
49
+ *,
50
+ metadata: Optional[Dict[str, Any]] = None
51
+ ) -> List[Dict[str, Any]]:
52
+ """Load a text file."""
53
+ from praisonaiagents.knowledge.readers import Document
54
+
55
+ try:
56
+ with open(source, 'r', encoding='utf-8') as f:
57
+ content = f.read()
58
+
59
+ doc_metadata = metadata or {}
60
+ doc_metadata.update({
61
+ "source": source,
62
+ "filename": os.path.basename(source),
63
+ "file_type": "text"
64
+ })
65
+
66
+ return [Document(content=content, metadata=doc_metadata)]
67
+ except Exception as e:
68
+ logger.error(f"Failed to read text file {source}: {e}")
69
+ return []
70
+
71
+ def can_handle(self, source: str) -> bool:
72
+ """Check if this reader can handle the source."""
73
+ ext = os.path.splitext(source)[1].lower().lstrip(".")
74
+ return ext in self.supported_extensions
75
+
76
+
77
+ class MarkItDownReader:
78
+ """Reader using markitdown for document conversion."""
79
+
80
+ name: str = "markitdown"
81
+ supported_extensions: List[str] = [
82
+ "pdf", "doc", "docx", "ppt", "pptx", "xls", "xlsx",
83
+ "html", "htm", "md", "markdown", "csv", "json", "xml",
84
+ "jpg", "jpeg", "png", "gif", "bmp", "tiff", "webp",
85
+ "mp3", "wav", "ogg", "m4a", "flac"
86
+ ]
87
+
88
+ def __init__(self):
89
+ self._converter = None
90
+
91
+ @property
92
+ def converter(self):
93
+ """Lazy load markitdown converter."""
94
+ if self._converter is None:
95
+ if not _check_markitdown():
96
+ raise ImportError(
97
+ "markitdown is required for document conversion. "
98
+ "Install with: pip install markitdown"
99
+ )
100
+ from markitdown import MarkItDown
101
+ self._converter = MarkItDown()
102
+ return self._converter
103
+
104
+ def load(
105
+ self,
106
+ source: str,
107
+ *,
108
+ metadata: Optional[Dict[str, Any]] = None
109
+ ) -> List[Dict[str, Any]]:
110
+ """Load a document using markitdown."""
111
+ from praisonaiagents.knowledge.readers import Document
112
+
113
+ try:
114
+ result = self.converter.convert(source)
115
+ content = result.text_content
116
+
117
+ if not content:
118
+ logger.warning(f"No content extracted from {source}")
119
+ return []
120
+
121
+ doc_metadata = metadata or {}
122
+ doc_metadata.update({
123
+ "source": source,
124
+ "filename": os.path.basename(source),
125
+ "file_type": os.path.splitext(source)[1].lower().lstrip(".")
126
+ })
127
+
128
+ return [Document(content=content, metadata=doc_metadata)]
129
+ except Exception as e:
130
+ logger.error(f"Failed to convert document {source}: {e}")
131
+ return []
132
+
133
+ def can_handle(self, source: str) -> bool:
134
+ """Check if this reader can handle the source."""
135
+ ext = os.path.splitext(source)[1].lower().lstrip(".")
136
+ return ext in self.supported_extensions and _check_markitdown()
137
+
138
+
139
+ class DirectoryReader:
140
+ """Reader for directories - recursively reads all files."""
141
+
142
+ name: str = "directory"
143
+ supported_extensions: List[str] = [] # Handles directories, not extensions
144
+
145
+ def __init__(self, recursive: bool = True, exclude_patterns: Optional[List[str]] = None):
146
+ self.recursive = recursive
147
+ self.exclude_patterns = exclude_patterns or [
148
+ "*.pyc", "__pycache__", ".git", ".svn", "node_modules",
149
+ "*.egg-info", ".env", ".venv", "venv"
150
+ ]
151
+
152
+ def load(
153
+ self,
154
+ source: str,
155
+ *,
156
+ metadata: Optional[Dict[str, Any]] = None
157
+ ) -> List[Dict[str, Any]]:
158
+ """Load all files from a directory."""
159
+ from praisonaiagents.knowledge.readers import get_reader_registry
160
+
161
+ if not os.path.isdir(source):
162
+ logger.error(f"Not a directory: {source}")
163
+ return []
164
+
165
+ documents = []
166
+ registry = get_reader_registry()
167
+
168
+ # Walk directory
169
+ if self.recursive:
170
+ for root, dirs, files in os.walk(source):
171
+ # Filter out excluded directories
172
+ dirs[:] = [d for d in dirs if not self._should_exclude(d)]
173
+
174
+ for file in files:
175
+ if self._should_exclude(file):
176
+ continue
177
+
178
+ file_path = os.path.join(root, file)
179
+ reader = registry.get_for_source(file_path)
180
+
181
+ if reader and reader.name != "directory":
182
+ file_metadata = (metadata or {}).copy()
183
+ file_metadata["parent_dir"] = source
184
+ loaded_docs = reader.load(file_path, metadata=file_metadata)
185
+ documents.extend(loaded_docs)
186
+ else:
187
+ for file in os.listdir(source):
188
+ if self._should_exclude(file):
189
+ continue
190
+
191
+ file_path = os.path.join(source, file)
192
+ if os.path.isfile(file_path):
193
+ reader = registry.get_for_source(file_path)
194
+ if reader and reader.name != "directory":
195
+ file_metadata = (metadata or {}).copy()
196
+ file_metadata["parent_dir"] = source
197
+ docs = reader.load(file_path, metadata=file_metadata)
198
+ documents.extend(docs)
199
+
200
+ return documents
201
+
202
+ def can_handle(self, source: str) -> bool:
203
+ """Check if this reader can handle the source."""
204
+ return os.path.isdir(source)
205
+
206
+ def _should_exclude(self, name: str) -> bool:
207
+ """Check if a file/directory should be excluded."""
208
+ import fnmatch
209
+ for pattern in self.exclude_patterns:
210
+ if fnmatch.fnmatch(name, pattern):
211
+ return True
212
+ return False
213
+
214
+
215
+ class GlobReader:
216
+ """Reader for glob patterns."""
217
+
218
+ name: str = "glob"
219
+ supported_extensions: List[str] = []
220
+
221
+ def load(
222
+ self,
223
+ source: str,
224
+ *,
225
+ metadata: Optional[Dict[str, Any]] = None
226
+ ) -> List[Dict[str, Any]]:
227
+ """Load files matching a glob pattern."""
228
+ from praisonaiagents.knowledge.readers import get_reader_registry
229
+
230
+ documents = []
231
+ registry = get_reader_registry()
232
+
233
+ for file_path in glob_module.glob(source, recursive=True):
234
+ if os.path.isfile(file_path):
235
+ reader = registry.get_for_source(file_path)
236
+ if reader and reader.name not in ("glob", "directory"):
237
+ file_metadata = (metadata or {}).copy()
238
+ file_metadata["glob_pattern"] = source
239
+ docs = reader.load(file_path, metadata=file_metadata)
240
+ documents.extend(docs)
241
+
242
+ return documents
243
+
244
+ def can_handle(self, source: str) -> bool:
245
+ """Check if this is a glob pattern."""
246
+ return "*" in source or "?" in source or "[" in source
247
+
248
+
249
+ class URLReader:
250
+ """Reader for URLs (HTML pages)."""
251
+
252
+ name: str = "url"
253
+ supported_extensions: List[str] = []
254
+
255
+ def load(
256
+ self,
257
+ source: str,
258
+ *,
259
+ metadata: Optional[Dict[str, Any]] = None
260
+ ) -> List[Dict[str, Any]]:
261
+ """Load content from a URL."""
262
+ from praisonaiagents.knowledge.readers import Document
263
+
264
+ try:
265
+ import httpx
266
+ except ImportError:
267
+ try:
268
+ import requests as httpx
269
+ except ImportError:
270
+ logger.error("httpx or requests required for URL reading")
271
+ return []
272
+
273
+ try:
274
+ response = httpx.get(source, timeout=30, follow_redirects=True)
275
+ response.raise_for_status()
276
+ content = response.text
277
+
278
+ # Try to extract text from HTML
279
+ try:
280
+ from bs4 import BeautifulSoup
281
+ soup = BeautifulSoup(content, 'html.parser')
282
+ # Remove script and style elements
283
+ for script in soup(["script", "style"]):
284
+ script.decompose()
285
+ content = soup.get_text(separator='\n', strip=True)
286
+ except ImportError:
287
+ # Fall back to raw content
288
+ pass
289
+
290
+ doc_metadata = metadata or {}
291
+ doc_metadata.update({
292
+ "source": source,
293
+ "url": source,
294
+ "file_type": "html"
295
+ })
296
+
297
+ return [Document(content=content, metadata=doc_metadata)]
298
+ except Exception as e:
299
+ logger.error(f"Failed to fetch URL {source}: {e}")
300
+ return []
301
+
302
+ def can_handle(self, source: str) -> bool:
303
+ """Check if this is a URL."""
304
+ return source.startswith(("http://", "https://"))
305
+
306
+
307
+ class AutoReader:
308
+ """
309
+ Automatic reader that detects source type and routes to appropriate reader.
310
+
311
+ Selection policy:
312
+ 1. If LlamaIndex reader is installed + supports the type → use it
313
+ 2. Else if MarkItDown supports → use it
314
+ 3. Else use simple built-in reader
315
+ """
316
+
317
+ name: str = "auto"
318
+ supported_extensions: List[str] = [] # Handles everything
319
+
320
+ def load(
321
+ self,
322
+ source: str,
323
+ *,
324
+ metadata: Optional[Dict[str, Any]] = None
325
+ ) -> List[Dict[str, Any]]:
326
+ """Load from any source type."""
327
+ from praisonaiagents.knowledge.readers import get_reader_registry, detect_source_kind
328
+
329
+ registry = get_reader_registry()
330
+ source_kind = detect_source_kind(source)
331
+
332
+ # Route based on source kind
333
+ if source_kind == "url":
334
+ reader = registry.get("url")
335
+ elif source_kind == "directory":
336
+ reader = registry.get("directory")
337
+ elif source_kind == "glob":
338
+ reader = registry.get("glob")
339
+ elif source_kind == "file":
340
+ # Find best reader for file type
341
+ reader = registry.get_for_source(source)
342
+ if reader and reader.name == "auto":
343
+ # Avoid infinite recursion - use markitdown or text
344
+ ext = os.path.splitext(source)[1].lower().lstrip(".")
345
+ if ext in MarkItDownReader.supported_extensions and _check_markitdown():
346
+ reader = registry.get("markitdown")
347
+ else:
348
+ reader = registry.get("text")
349
+ else:
350
+ # Unknown - try markitdown then text
351
+ if _check_markitdown():
352
+ reader = registry.get("markitdown")
353
+ else:
354
+ reader = registry.get("text")
355
+
356
+ if reader:
357
+ return reader.load(source, metadata=metadata)
358
+
359
+ logger.warning(f"No reader found for source: {source}")
360
+ return []
361
+
362
+ def can_handle(self, source: str) -> bool:
363
+ """AutoReader can handle anything."""
364
+ return True
365
+
366
+
367
+ def register_default_readers():
368
+ """Register all default readers with the registry."""
369
+ from praisonaiagents.knowledge.readers import get_reader_registry
370
+
371
+ registry = get_reader_registry()
372
+
373
+ # Register text reader
374
+ registry.register("text", TextReader, ["txt", "text", "log"])
375
+
376
+ # Register markitdown reader
377
+ registry.register("markitdown", MarkItDownReader, MarkItDownReader.supported_extensions)
378
+
379
+ # Register directory reader
380
+ registry.register("directory", DirectoryReader)
381
+
382
+ # Register glob reader
383
+ registry.register("glob", GlobReader)
384
+
385
+ # Register URL reader
386
+ registry.register("url", URLReader)
387
+
388
+ # Register auto reader
389
+ registry.register("auto", AutoReader)
390
+
391
+ logger.debug("Registered default readers")
392
+
393
+
394
+ # Auto-register on import
395
+ register_default_readers()