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,371 @@
1
+ """
2
+ Tools checks for the Doctor CLI module.
3
+
4
+ Validates tool availability, dependencies, and API keys.
5
+ """
6
+
7
+ import os
8
+
9
+ from ..models import (
10
+ CheckCategory,
11
+ CheckResult,
12
+ CheckStatus,
13
+ CheckSeverity,
14
+ DoctorConfig,
15
+ )
16
+ from ..registry import register_check
17
+
18
+
19
+ # Tool categories and their requirements
20
+ TOOL_CATEGORIES = {
21
+ "web_search": {
22
+ "tools": ["internet_search", "duckduckgo", "tavily_search", "exa_search", "searxng_search"],
23
+ "description": "Web search tools",
24
+ },
25
+ "file_ops": {
26
+ "tools": ["read_file", "write_file", "list_files", "file_tools"],
27
+ "description": "File operation tools",
28
+ },
29
+ "data": {
30
+ "tools": ["csv_tools", "json_tools", "excel_tools", "xml_tools", "yaml_tools", "pandas_tools"],
31
+ "description": "Data processing tools",
32
+ },
33
+ "database": {
34
+ "tools": ["duckdb_tools", "mongodb_tools"],
35
+ "description": "Database tools",
36
+ },
37
+ "code": {
38
+ "tools": ["python_tools", "shell_tools", "execute_code"],
39
+ "description": "Code execution tools",
40
+ },
41
+ "web_crawl": {
42
+ "tools": ["crawl4ai", "spider_tools", "newspaper_tools"],
43
+ "description": "Web crawling tools",
44
+ },
45
+ "knowledge": {
46
+ "tools": ["wiki_search", "arxiv_tools", "wikipedia_tools"],
47
+ "description": "Knowledge/research tools",
48
+ },
49
+ "finance": {
50
+ "tools": ["yfinance", "get_stock_price", "get_stock_info"],
51
+ "description": "Financial data tools",
52
+ },
53
+ }
54
+
55
+ # Tools that require API keys
56
+ TOOLS_REQUIRING_API_KEYS = {
57
+ "tavily_search": "TAVILY_API_KEY",
58
+ "tavily": "TAVILY_API_KEY",
59
+ "exa_search": "EXA_API_KEY",
60
+ "exa": "EXA_API_KEY",
61
+ "ydc_search": "YDC_API_KEY",
62
+ "ydc": "YDC_API_KEY",
63
+ }
64
+
65
+ # Tools that require optional dependencies
66
+ TOOLS_REQUIRING_DEPS = {
67
+ "crawl4ai": "crawl4ai",
68
+ "tavily_search": "tavily",
69
+ "tavily": "tavily",
70
+ "pandas_tools": "pandas",
71
+ "excel_tools": "openpyxl",
72
+ "yfinance": "yfinance",
73
+ "duckdb_tools": "duckdb",
74
+ "mongodb_tools": "pymongo",
75
+ "newspaper_tools": "newspaper3k",
76
+ "arxiv_tools": "arxiv",
77
+ }
78
+
79
+
80
+ @register_check(
81
+ id="tools_registry",
82
+ title="Tools Registry",
83
+ description="Check tool registry is accessible",
84
+ category=CheckCategory.TOOLS,
85
+ severity=CheckSeverity.MEDIUM,
86
+ )
87
+ def check_tools_registry(config: DoctorConfig) -> CheckResult:
88
+ """Check tool registry is accessible."""
89
+ try:
90
+ from praisonaiagents.tools import TOOL_MAPPINGS
91
+ tool_count = len(TOOL_MAPPINGS)
92
+
93
+ return CheckResult(
94
+ id="tools_registry",
95
+ title="Tools Registry",
96
+ category=CheckCategory.TOOLS,
97
+ status=CheckStatus.PASS,
98
+ message=f"Tool registry accessible with {tool_count} tools",
99
+ metadata={"tool_count": tool_count},
100
+ )
101
+ except ImportError as e:
102
+ return CheckResult(
103
+ id="tools_registry",
104
+ title="Tools Registry",
105
+ category=CheckCategory.TOOLS,
106
+ status=CheckStatus.FAIL,
107
+ message="Cannot access tool registry",
108
+ details=str(e),
109
+ remediation="Ensure praisonaiagents is properly installed",
110
+ severity=CheckSeverity.HIGH,
111
+ )
112
+
113
+
114
+ @register_check(
115
+ id="tools_web_search",
116
+ title="Web Search Tools",
117
+ description="Check web search tool availability",
118
+ category=CheckCategory.TOOLS,
119
+ severity=CheckSeverity.MEDIUM,
120
+ )
121
+ def check_tools_web_search(config: DoctorConfig) -> CheckResult:
122
+ """Check web search tool availability."""
123
+ available = []
124
+ missing = []
125
+
126
+ # Check DuckDuckGo (no API key required)
127
+ try:
128
+ from praisonaiagents.tools import internet_search
129
+ available.append("internet_search (DuckDuckGo)")
130
+ except ImportError:
131
+ missing.append("internet_search")
132
+
133
+ # Check Tavily
134
+ if os.environ.get("TAVILY_API_KEY"):
135
+ try:
136
+ from praisonaiagents.tools import tavily_search
137
+ available.append("tavily_search")
138
+ except ImportError:
139
+ missing.append("tavily_search (missing tavily package)")
140
+ else:
141
+ missing.append("tavily_search (TAVILY_API_KEY not set)")
142
+
143
+ # Check Exa
144
+ if os.environ.get("EXA_API_KEY"):
145
+ try:
146
+ from praisonaiagents.tools import exa_search
147
+ available.append("exa_search")
148
+ except ImportError:
149
+ missing.append("exa_search (missing exa package)")
150
+ else:
151
+ missing.append("exa_search (EXA_API_KEY not set)")
152
+
153
+ if available:
154
+ return CheckResult(
155
+ id="tools_web_search",
156
+ title="Web Search Tools",
157
+ category=CheckCategory.TOOLS,
158
+ status=CheckStatus.PASS,
159
+ message=f"{len(available)} web search tool(s) available",
160
+ details=", ".join(available),
161
+ metadata={"available": available, "missing": missing},
162
+ )
163
+ else:
164
+ return CheckResult(
165
+ id="tools_web_search",
166
+ title="Web Search Tools",
167
+ category=CheckCategory.TOOLS,
168
+ status=CheckStatus.WARN,
169
+ message="No web search tools available",
170
+ details=", ".join(missing),
171
+ remediation="Install duckduckgo-search or set TAVILY_API_KEY",
172
+ )
173
+
174
+
175
+ @register_check(
176
+ id="tools_file_ops",
177
+ title="File Operation Tools",
178
+ description="Check file operation tool availability",
179
+ category=CheckCategory.TOOLS,
180
+ severity=CheckSeverity.LOW,
181
+ )
182
+ def check_tools_file_ops(config: DoctorConfig) -> CheckResult:
183
+ """Check file operation tool availability."""
184
+ try:
185
+ from praisonaiagents.tools import read_file, write_file, list_files
186
+ return CheckResult(
187
+ id="tools_file_ops",
188
+ title="File Operation Tools",
189
+ category=CheckCategory.TOOLS,
190
+ status=CheckStatus.PASS,
191
+ message="File operation tools available (read_file, write_file, list_files)",
192
+ )
193
+ except ImportError as e:
194
+ return CheckResult(
195
+ id="tools_file_ops",
196
+ title="File Operation Tools",
197
+ category=CheckCategory.TOOLS,
198
+ status=CheckStatus.WARN,
199
+ message="Some file operation tools not available",
200
+ details=str(e),
201
+ )
202
+
203
+
204
+ @register_check(
205
+ id="tools_code_execution",
206
+ title="Code Execution Tools",
207
+ description="Check code execution tool availability",
208
+ category=CheckCategory.TOOLS,
209
+ severity=CheckSeverity.LOW,
210
+ )
211
+ def check_tools_code_execution(config: DoctorConfig) -> CheckResult:
212
+ """Check code execution tool availability."""
213
+ available = []
214
+
215
+ try:
216
+ from praisonaiagents.tools import execute_code
217
+ available.append("execute_code")
218
+ except ImportError:
219
+ pass
220
+
221
+ try:
222
+ from praisonaiagents.tools import execute_command
223
+ available.append("execute_command")
224
+ except ImportError:
225
+ pass
226
+
227
+ if available:
228
+ return CheckResult(
229
+ id="tools_code_execution",
230
+ title="Code Execution Tools",
231
+ category=CheckCategory.TOOLS,
232
+ status=CheckStatus.PASS,
233
+ message=f"Code execution tools available: {', '.join(available)}",
234
+ metadata={"available": available},
235
+ )
236
+ else:
237
+ return CheckResult(
238
+ id="tools_code_execution",
239
+ title="Code Execution Tools",
240
+ category=CheckCategory.TOOLS,
241
+ status=CheckStatus.SKIP,
242
+ message="Code execution tools not loaded (optional)",
243
+ )
244
+
245
+
246
+ @register_check(
247
+ id="tools_api_keys",
248
+ title="Tool API Keys",
249
+ description="Check API keys for tools that require them",
250
+ category=CheckCategory.TOOLS,
251
+ severity=CheckSeverity.INFO,
252
+ )
253
+ def check_tools_api_keys(config: DoctorConfig) -> CheckResult:
254
+ """Check API keys for tools that require them."""
255
+ configured = []
256
+ missing = []
257
+
258
+ api_keys = {
259
+ "TAVILY_API_KEY": "Tavily search",
260
+ "EXA_API_KEY": "Exa search",
261
+ "YDC_API_KEY": "You.com search",
262
+ "SPIDER_API_KEY": "Spider web crawling",
263
+ }
264
+
265
+ for key, description in api_keys.items():
266
+ if os.environ.get(key):
267
+ configured.append(description)
268
+ else:
269
+ missing.append(f"{description} ({key})")
270
+
271
+ if configured:
272
+ return CheckResult(
273
+ id="tools_api_keys",
274
+ title="Tool API Keys",
275
+ category=CheckCategory.TOOLS,
276
+ status=CheckStatus.PASS,
277
+ message=f"{len(configured)} tool API key(s) configured",
278
+ details=f"Configured: {', '.join(configured)}",
279
+ metadata={"configured": configured, "missing": missing},
280
+ )
281
+ else:
282
+ return CheckResult(
283
+ id="tools_api_keys",
284
+ title="Tool API Keys",
285
+ category=CheckCategory.TOOLS,
286
+ status=CheckStatus.SKIP,
287
+ message="No optional tool API keys configured",
288
+ details="Tools like Tavily, Exa require API keys for enhanced functionality",
289
+ )
290
+
291
+
292
+ @register_check(
293
+ id="tools_optional_deps",
294
+ title="Tool Optional Dependencies",
295
+ description="Check optional dependencies for tools",
296
+ category=CheckCategory.TOOLS,
297
+ severity=CheckSeverity.INFO,
298
+ requires_deep=True,
299
+ )
300
+ def check_tools_optional_deps(config: DoctorConfig) -> CheckResult:
301
+ """Check optional dependencies for tools."""
302
+ available = []
303
+ missing = []
304
+
305
+ deps_to_check = [
306
+ ("crawl4ai", "Crawl4AI web crawling"),
307
+ ("tavily", "Tavily search"),
308
+ ("pandas", "Pandas data tools"),
309
+ ("openpyxl", "Excel tools"),
310
+ ("yfinance", "Yahoo Finance tools"),
311
+ ("duckdb", "DuckDB tools"),
312
+ ("pymongo", "MongoDB tools"),
313
+ ("arxiv", "arXiv tools"),
314
+ ]
315
+
316
+ for package, description in deps_to_check:
317
+ try:
318
+ __import__(package)
319
+ available.append(description)
320
+ except ImportError:
321
+ missing.append(f"{description} ({package})")
322
+
323
+ total = len(deps_to_check)
324
+
325
+ return CheckResult(
326
+ id="tools_optional_deps",
327
+ title="Tool Optional Dependencies",
328
+ category=CheckCategory.TOOLS,
329
+ status=CheckStatus.PASS,
330
+ message=f"{len(available)}/{total} optional tool dependencies installed",
331
+ details=f"Missing: {', '.join(missing[:3])}{'...' if len(missing) > 3 else ''}" if missing else "All installed",
332
+ metadata={"available": available, "missing": missing},
333
+ )
334
+
335
+
336
+ @register_check(
337
+ id="tools_summary",
338
+ title="Tools Summary",
339
+ description="Summary of tool availability by category",
340
+ category=CheckCategory.TOOLS,
341
+ severity=CheckSeverity.INFO,
342
+ )
343
+ def check_tools_summary(config: DoctorConfig) -> CheckResult:
344
+ """Summary of tool availability by category."""
345
+ try:
346
+ from praisonaiagents.tools import TOOL_MAPPINGS
347
+
348
+ category_counts = {}
349
+ for cat_name, cat_info in TOOL_CATEGORIES.items():
350
+ available = sum(1 for t in cat_info["tools"] if t in TOOL_MAPPINGS)
351
+ total = len(cat_info["tools"])
352
+ category_counts[cat_name] = f"{available}/{total}"
353
+
354
+ summary = ", ".join(f"{k}: {v}" for k, v in category_counts.items())
355
+
356
+ return CheckResult(
357
+ id="tools_summary",
358
+ title="Tools Summary",
359
+ category=CheckCategory.TOOLS,
360
+ status=CheckStatus.PASS,
361
+ message=f"Tool categories: {summary}",
362
+ metadata={"categories": category_counts},
363
+ )
364
+ except ImportError:
365
+ return CheckResult(
366
+ id="tools_summary",
367
+ title="Tools Summary",
368
+ category=CheckCategory.TOOLS,
369
+ status=CheckStatus.SKIP,
370
+ message="Cannot generate tools summary",
371
+ )
@@ -0,0 +1,266 @@
1
+ """
2
+ Doctor engine for executing health checks.
3
+
4
+ Provides the core execution logic for running doctor checks.
5
+ """
6
+
7
+ import os
8
+ import platform
9
+ import sys
10
+ import traceback
11
+ from concurrent.futures import ThreadPoolExecutor, TimeoutError as FuturesTimeoutError
12
+ from datetime import datetime, timezone
13
+ from typing import Callable, List, Optional
14
+ import time
15
+
16
+ from .models import (
17
+ CheckCategory,
18
+ CheckResult,
19
+ CheckStatus,
20
+ CheckSeverity,
21
+ DoctorConfig,
22
+ DoctorReport,
23
+ EnvironmentSummary,
24
+ )
25
+ from .registry import CheckRegistry, get_registry
26
+
27
+
28
+ class DoctorEngine:
29
+ """
30
+ Engine for executing doctor checks.
31
+
32
+ Handles check execution, timeout management, and report generation.
33
+ """
34
+
35
+ def __init__(self, config: Optional[DoctorConfig] = None):
36
+ """
37
+ Initialize the doctor engine.
38
+
39
+ Args:
40
+ config: Doctor configuration
41
+ """
42
+ self.config = config or DoctorConfig()
43
+ self.registry = get_registry()
44
+ self._results: List[CheckResult] = []
45
+
46
+ def get_environment_summary(self) -> EnvironmentSummary:
47
+ """Gather environment information."""
48
+ # Get package versions lazily
49
+ praisonai_version = "unknown"
50
+ praisonaiagents_version = "unknown"
51
+
52
+ try:
53
+ from praisonai.version import __version__ as pai_version
54
+ praisonai_version = pai_version
55
+ except ImportError:
56
+ pass
57
+
58
+ try:
59
+ import praisonaiagents
60
+ praisonaiagents_version = getattr(praisonaiagents, "__version__", "unknown")
61
+ except ImportError:
62
+ pass
63
+
64
+ return EnvironmentSummary(
65
+ python_version=f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}",
66
+ python_executable=sys.executable,
67
+ os_name=platform.system(),
68
+ os_version=platform.release(),
69
+ architecture=platform.machine(),
70
+ praisonai_version=praisonai_version,
71
+ praisonaiagents_version=praisonaiagents_version,
72
+ working_directory=os.getcwd(),
73
+ virtual_env=os.environ.get("VIRTUAL_ENV"),
74
+ )
75
+
76
+ def run_check(
77
+ self,
78
+ check_id: str,
79
+ implementation: Callable,
80
+ timeout: Optional[float] = None,
81
+ ) -> CheckResult:
82
+ """
83
+ Run a single check with timeout handling.
84
+
85
+ Args:
86
+ check_id: Check identifier
87
+ implementation: Check function
88
+ timeout: Timeout in seconds
89
+
90
+ Returns:
91
+ Check result
92
+ """
93
+ timeout = timeout or self.config.timeout
94
+ definition = self.registry.get_check(check_id)
95
+
96
+ start_time = time.time()
97
+
98
+ try:
99
+ # Run with timeout using ThreadPoolExecutor
100
+ with ThreadPoolExecutor(max_workers=1) as executor:
101
+ future = executor.submit(implementation, self.config)
102
+ try:
103
+ result = future.result(timeout=timeout)
104
+ result.duration_ms = (time.time() - start_time) * 1000
105
+ return result
106
+ except FuturesTimeoutError:
107
+ return CheckResult(
108
+ id=check_id,
109
+ title=definition.title if definition else check_id,
110
+ category=definition.category if definition else CheckCategory.ENVIRONMENT,
111
+ status=CheckStatus.ERROR,
112
+ message=f"Check timed out after {timeout}s",
113
+ remediation="Increase timeout with --timeout or check for hanging operations",
114
+ duration_ms=(time.time() - start_time) * 1000,
115
+ severity=CheckSeverity.HIGH,
116
+ )
117
+ except Exception as e:
118
+ # Capture exception details but redact potential secrets
119
+ tb = traceback.format_exc()
120
+ return CheckResult(
121
+ id=check_id,
122
+ title=definition.title if definition else check_id,
123
+ category=definition.category if definition else CheckCategory.ENVIRONMENT,
124
+ status=CheckStatus.ERROR,
125
+ message=f"Check failed with error: {type(e).__name__}: {str(e)[:100]}",
126
+ details=tb[:500] if not self.config.quiet else None,
127
+ remediation="Check the error details and fix the underlying issue",
128
+ duration_ms=(time.time() - start_time) * 1000,
129
+ severity=CheckSeverity.HIGH,
130
+ )
131
+
132
+ def run_checks(
133
+ self,
134
+ check_ids: Optional[List[str]] = None,
135
+ categories: Optional[List[CheckCategory]] = None,
136
+ ) -> List[CheckResult]:
137
+ """
138
+ Run multiple checks.
139
+
140
+ Args:
141
+ check_ids: Specific check IDs to run (None = all)
142
+ categories: Filter by categories
143
+
144
+ Returns:
145
+ List of check results
146
+ """
147
+ # Get filtered checks
148
+ checks = self.registry.filter_checks(
149
+ only=check_ids or self.config.only or None,
150
+ skip=self.config.skip or None,
151
+ categories=categories,
152
+ deep_mode=self.config.deep,
153
+ )
154
+
155
+ # Resolve dependencies and get ordered list
156
+ ordered_ids = self.registry.resolve_dependencies([c.id for c in checks])
157
+
158
+ results = []
159
+ failed_deps = set()
160
+
161
+ for check_id in ordered_ids:
162
+ definition = self.registry.get_check(check_id)
163
+ implementation = self.registry.get_implementation(check_id)
164
+
165
+ if not definition or not implementation:
166
+ continue
167
+
168
+ # Check if dependencies failed
169
+ if any(dep in failed_deps for dep in definition.dependencies):
170
+ results.append(CheckResult(
171
+ id=check_id,
172
+ title=definition.title,
173
+ category=definition.category,
174
+ status=CheckStatus.SKIP,
175
+ message="Skipped due to failed dependency",
176
+ severity=definition.severity,
177
+ ))
178
+ continue
179
+
180
+ # Run the check
181
+ result = self.run_check(check_id, implementation)
182
+ results.append(result)
183
+
184
+ # Track failures for dependency resolution
185
+ if result.status in (CheckStatus.FAIL, CheckStatus.ERROR):
186
+ failed_deps.add(check_id)
187
+
188
+ # Fail fast if configured
189
+ if self.config.fail_fast:
190
+ break
191
+
192
+ self._results = results
193
+ return results
194
+
195
+ def generate_report(self, results: Optional[List[CheckResult]] = None) -> DoctorReport:
196
+ """
197
+ Generate a complete doctor report.
198
+
199
+ Args:
200
+ results: Check results (uses stored results if None)
201
+
202
+ Returns:
203
+ Complete doctor report
204
+ """
205
+ results = results or self._results
206
+
207
+ report = DoctorReport(
208
+ version="1.0.0",
209
+ timestamp=datetime.now(timezone.utc).isoformat(),
210
+ environment=self.get_environment_summary(),
211
+ results=results,
212
+ mode="deep" if self.config.deep else "fast",
213
+ filters={
214
+ "only": self.config.only,
215
+ "skip": self.config.skip,
216
+ },
217
+ )
218
+
219
+ report.calculate_summary()
220
+ report.exit_code = report.calculate_exit_code(strict=self.config.strict)
221
+
222
+ return report
223
+
224
+ def run(
225
+ self,
226
+ check_ids: Optional[List[str]] = None,
227
+ categories: Optional[List[CheckCategory]] = None,
228
+ ) -> DoctorReport:
229
+ """
230
+ Run checks and generate report.
231
+
232
+ Args:
233
+ check_ids: Specific check IDs to run
234
+ categories: Filter by categories
235
+
236
+ Returns:
237
+ Complete doctor report
238
+ """
239
+ start_time = time.time()
240
+
241
+ results = self.run_checks(check_ids, categories)
242
+ report = self.generate_report(results)
243
+
244
+ report.duration_ms = (time.time() - start_time) * 1000
245
+
246
+ return report
247
+
248
+
249
+ def run_doctor(
250
+ config: Optional[DoctorConfig] = None,
251
+ check_ids: Optional[List[str]] = None,
252
+ categories: Optional[List[CheckCategory]] = None,
253
+ ) -> DoctorReport:
254
+ """
255
+ Convenience function to run doctor checks.
256
+
257
+ Args:
258
+ config: Doctor configuration
259
+ check_ids: Specific check IDs to run
260
+ categories: Filter by categories
261
+
262
+ Returns:
263
+ Complete doctor report
264
+ """
265
+ engine = DoctorEngine(config)
266
+ return engine.run(check_ids, categories)