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,264 @@
1
+ """
2
+ Data models for the Doctor CLI module.
3
+
4
+ Defines the core data structures for check results, reports, and configuration.
5
+ """
6
+
7
+ from dataclasses import dataclass, field
8
+ from enum import Enum
9
+ from typing import Any, Dict, List, Optional
10
+ import time
11
+
12
+
13
+ class CheckStatus(Enum):
14
+ """Status of a doctor check."""
15
+ PASS = "pass"
16
+ WARN = "warn"
17
+ FAIL = "fail"
18
+ SKIP = "skip"
19
+ ERROR = "error"
20
+
21
+
22
+ class CheckCategory(Enum):
23
+ """Category of a doctor check."""
24
+ ENVIRONMENT = "environment"
25
+ CONFIG = "config"
26
+ TOOLS = "tools"
27
+ DATABASE = "database"
28
+ MCP = "mcp"
29
+ OBSERVABILITY = "observability"
30
+ SKILLS = "skills"
31
+ MEMORY = "memory"
32
+ PERMISSIONS = "permissions"
33
+ NETWORK = "network"
34
+ PERFORMANCE = "performance"
35
+ SELFTEST = "selftest"
36
+
37
+
38
+ class CheckSeverity(Enum):
39
+ """Severity level of a check."""
40
+ CRITICAL = "critical"
41
+ HIGH = "high"
42
+ MEDIUM = "medium"
43
+ LOW = "low"
44
+ INFO = "info"
45
+
46
+
47
+ @dataclass
48
+ class CheckResult:
49
+ """Result of a single doctor check."""
50
+ id: str
51
+ title: str
52
+ category: CheckCategory
53
+ status: CheckStatus
54
+ message: str
55
+ details: Optional[str] = None
56
+ remediation: Optional[str] = None
57
+ duration_ms: float = 0.0
58
+ severity: CheckSeverity = CheckSeverity.MEDIUM
59
+ metadata: Dict[str, Any] = field(default_factory=dict)
60
+
61
+ def to_dict(self) -> Dict[str, Any]:
62
+ """Convert to dictionary for JSON serialization."""
63
+ return {
64
+ "id": self.id,
65
+ "title": self.title,
66
+ "category": self.category.value,
67
+ "status": self.status.value,
68
+ "message": self.message,
69
+ "details": self.details,
70
+ "remediation": self.remediation,
71
+ "duration_ms": round(self.duration_ms, 2),
72
+ "severity": self.severity.value,
73
+ "metadata": self.metadata,
74
+ }
75
+
76
+ @property
77
+ def passed(self) -> bool:
78
+ """Check if this result is considered passing."""
79
+ return self.status in (CheckStatus.PASS, CheckStatus.SKIP)
80
+
81
+ @property
82
+ def is_warning(self) -> bool:
83
+ """Check if this result is a warning."""
84
+ return self.status == CheckStatus.WARN
85
+
86
+ @property
87
+ def is_failure(self) -> bool:
88
+ """Check if this result is a failure."""
89
+ return self.status in (CheckStatus.FAIL, CheckStatus.ERROR)
90
+
91
+
92
+ @dataclass
93
+ class CheckDefinition:
94
+ """Definition of a doctor check."""
95
+ id: str
96
+ title: str
97
+ description: str
98
+ category: CheckCategory
99
+ severity: CheckSeverity = CheckSeverity.MEDIUM
100
+ requires_deep: bool = False
101
+ dependencies: List[str] = field(default_factory=list)
102
+ tags: List[str] = field(default_factory=list)
103
+
104
+ def to_dict(self) -> Dict[str, Any]:
105
+ """Convert to dictionary."""
106
+ return {
107
+ "id": self.id,
108
+ "title": self.title,
109
+ "description": self.description,
110
+ "category": self.category.value,
111
+ "severity": self.severity.value,
112
+ "requires_deep": self.requires_deep,
113
+ "dependencies": self.dependencies,
114
+ "tags": self.tags,
115
+ }
116
+
117
+
118
+ @dataclass
119
+ class EnvironmentSummary:
120
+ """Summary of the runtime environment."""
121
+ python_version: str = ""
122
+ python_executable: str = ""
123
+ os_name: str = ""
124
+ os_version: str = ""
125
+ architecture: str = ""
126
+ praisonai_version: str = ""
127
+ praisonaiagents_version: str = ""
128
+ working_directory: str = ""
129
+ virtual_env: Optional[str] = None
130
+
131
+ def to_dict(self) -> Dict[str, Any]:
132
+ """Convert to dictionary."""
133
+ return {
134
+ "python_version": self.python_version,
135
+ "python_executable": self.python_executable,
136
+ "os_name": self.os_name,
137
+ "os_version": self.os_version,
138
+ "architecture": self.architecture,
139
+ "praisonai_version": self.praisonai_version,
140
+ "praisonaiagents_version": self.praisonaiagents_version,
141
+ "working_directory": self.working_directory,
142
+ "virtual_env": self.virtual_env,
143
+ }
144
+
145
+
146
+ @dataclass
147
+ class ReportSummary:
148
+ """Summary statistics for a doctor report."""
149
+ total: int = 0
150
+ passed: int = 0
151
+ warnings: int = 0
152
+ failed: int = 0
153
+ skipped: int = 0
154
+ errors: int = 0
155
+
156
+ def to_dict(self) -> Dict[str, Any]:
157
+ """Convert to dictionary."""
158
+ return {
159
+ "total": self.total,
160
+ "passed": self.passed,
161
+ "warnings": self.warnings,
162
+ "failed": self.failed,
163
+ "skipped": self.skipped,
164
+ "errors": self.errors,
165
+ }
166
+
167
+
168
+ @dataclass
169
+ class DoctorReport:
170
+ """Complete doctor report."""
171
+ version: str = "1.0.0"
172
+ timestamp: str = ""
173
+ duration_ms: float = 0.0
174
+ environment: EnvironmentSummary = field(default_factory=EnvironmentSummary)
175
+ results: List[CheckResult] = field(default_factory=list)
176
+ summary: ReportSummary = field(default_factory=ReportSummary)
177
+ exit_code: int = 0
178
+ mode: str = "fast"
179
+ filters: Dict[str, Any] = field(default_factory=dict)
180
+
181
+ def __post_init__(self):
182
+ if not self.timestamp:
183
+ from datetime import datetime, timezone
184
+ self.timestamp = datetime.now(timezone.utc).isoformat()
185
+
186
+ def calculate_summary(self) -> None:
187
+ """Calculate summary statistics from results."""
188
+ self.summary = ReportSummary(
189
+ total=len(self.results),
190
+ passed=sum(1 for r in self.results if r.status == CheckStatus.PASS),
191
+ warnings=sum(1 for r in self.results if r.status == CheckStatus.WARN),
192
+ failed=sum(1 for r in self.results if r.status == CheckStatus.FAIL),
193
+ skipped=sum(1 for r in self.results if r.status == CheckStatus.SKIP),
194
+ errors=sum(1 for r in self.results if r.status == CheckStatus.ERROR),
195
+ )
196
+
197
+ def calculate_exit_code(self, strict: bool = False) -> int:
198
+ """
199
+ Calculate exit code based on results.
200
+
201
+ Args:
202
+ strict: If True, treat warnings as failures
203
+
204
+ Returns:
205
+ 0: All passed (warnings allowed unless strict)
206
+ 1: Failures present
207
+ 2: Internal errors
208
+ """
209
+ if self.summary.errors > 0:
210
+ return 2
211
+ if self.summary.failed > 0:
212
+ return 1
213
+ if strict and self.summary.warnings > 0:
214
+ return 1
215
+ return 0
216
+
217
+ def to_dict(self) -> Dict[str, Any]:
218
+ """Convert to dictionary for JSON serialization."""
219
+ return {
220
+ "version": self.version,
221
+ "timestamp": self.timestamp,
222
+ "duration_ms": round(self.duration_ms, 2),
223
+ "environment": self.environment.to_dict(),
224
+ "results": [r.to_dict() for r in self.results],
225
+ "summary": self.summary.to_dict(),
226
+ "exit_code": self.exit_code,
227
+ "mode": self.mode,
228
+ "filters": self.filters,
229
+ }
230
+
231
+
232
+ @dataclass
233
+ class DoctorConfig:
234
+ """Configuration for doctor execution."""
235
+ deep: bool = False
236
+ timeout: float = 10.0
237
+ strict: bool = False
238
+ quiet: bool = False
239
+ no_color: bool = False
240
+ format: str = "text"
241
+ output_path: Optional[str] = None
242
+ only: List[str] = field(default_factory=list)
243
+ skip: List[str] = field(default_factory=list)
244
+
245
+ # Subcommand-specific options
246
+ show_keys: bool = False
247
+ require_keys: List[str] = field(default_factory=list)
248
+ config_file: Optional[str] = None
249
+ dsn: Optional[str] = None
250
+ provider: Optional[str] = None
251
+ read_only: bool = True
252
+ mock: bool = True
253
+ live: bool = False
254
+ model: Optional[str] = None
255
+ budget_ms: Optional[int] = None
256
+ top_n: int = 10
257
+ fail_fast: bool = False
258
+ list_tools: bool = False
259
+ all_checks: bool = False
260
+ missing_only: bool = False
261
+ name: Optional[str] = None
262
+ category: Optional[str] = None
263
+ path: Optional[str] = None
264
+ save_report: bool = False
@@ -0,0 +1,239 @@
1
+ """
2
+ Check registry for the Doctor CLI module.
3
+
4
+ Manages registration and discovery of doctor checks.
5
+ """
6
+
7
+ from typing import Callable, Dict, List, Optional, Set
8
+ from .models import CheckDefinition, CheckCategory, CheckSeverity, CheckResult
9
+
10
+
11
+ class CheckRegistry:
12
+ """
13
+ Registry for doctor checks.
14
+
15
+ Manages check definitions and their implementations.
16
+ """
17
+
18
+ _instance: Optional["CheckRegistry"] = None
19
+
20
+ def __new__(cls) -> "CheckRegistry":
21
+ """Singleton pattern for global registry."""
22
+ if cls._instance is None:
23
+ cls._instance = super().__new__(cls)
24
+ cls._instance._checks: Dict[str, CheckDefinition] = {}
25
+ cls._instance._implementations: Dict[str, Callable] = {}
26
+ cls._instance._initialized = False
27
+ return cls._instance
28
+
29
+ @classmethod
30
+ def get_instance(cls) -> "CheckRegistry":
31
+ """Get the singleton instance."""
32
+ return cls()
33
+
34
+ @classmethod
35
+ def reset(cls) -> None:
36
+ """Reset the registry (for testing)."""
37
+ cls._instance = None
38
+
39
+ def register(
40
+ self,
41
+ id: str,
42
+ title: str,
43
+ description: str,
44
+ category: CheckCategory,
45
+ implementation: Callable,
46
+ severity: CheckSeverity = CheckSeverity.MEDIUM,
47
+ requires_deep: bool = False,
48
+ dependencies: Optional[List[str]] = None,
49
+ tags: Optional[List[str]] = None,
50
+ ) -> None:
51
+ """
52
+ Register a doctor check.
53
+
54
+ Args:
55
+ id: Unique identifier (snake_case)
56
+ title: Human-readable title
57
+ description: Short description of what the check does
58
+ category: Check category
59
+ implementation: Callable that performs the check
60
+ severity: Severity level
61
+ requires_deep: Whether this check requires --deep mode
62
+ dependencies: List of check IDs this check depends on
63
+ tags: Optional tags for filtering
64
+ """
65
+ definition = CheckDefinition(
66
+ id=id,
67
+ title=title,
68
+ description=description,
69
+ category=category,
70
+ severity=severity,
71
+ requires_deep=requires_deep,
72
+ dependencies=dependencies or [],
73
+ tags=tags or [],
74
+ )
75
+ self._checks[id] = definition
76
+ self._implementations[id] = implementation
77
+
78
+ def get_check(self, id: str) -> Optional[CheckDefinition]:
79
+ """Get a check definition by ID."""
80
+ return self._checks.get(id)
81
+
82
+ def get_implementation(self, id: str) -> Optional[Callable]:
83
+ """Get a check implementation by ID."""
84
+ return self._implementations.get(id)
85
+
86
+ def get_all_checks(self) -> List[CheckDefinition]:
87
+ """Get all registered checks."""
88
+ return list(self._checks.values())
89
+
90
+ def get_check_ids(self) -> List[str]:
91
+ """Get all registered check IDs."""
92
+ return list(self._checks.keys())
93
+
94
+ def get_checks_by_category(self, category: CheckCategory) -> List[CheckDefinition]:
95
+ """Get all checks in a category."""
96
+ return [c for c in self._checks.values() if c.category == category]
97
+
98
+ def get_checks_by_tag(self, tag: str) -> List[CheckDefinition]:
99
+ """Get all checks with a specific tag."""
100
+ return [c for c in self._checks.values() if tag in c.tags]
101
+
102
+ def filter_checks(
103
+ self,
104
+ only: Optional[List[str]] = None,
105
+ skip: Optional[List[str]] = None,
106
+ categories: Optional[List[CheckCategory]] = None,
107
+ deep_mode: bool = False,
108
+ ) -> List[CheckDefinition]:
109
+ """
110
+ Filter checks based on criteria.
111
+
112
+ Args:
113
+ only: Only include these check IDs
114
+ skip: Skip these check IDs
115
+ categories: Only include checks in these categories
116
+ deep_mode: Include checks that require deep mode
117
+
118
+ Returns:
119
+ Filtered list of check definitions
120
+ """
121
+ checks = list(self._checks.values())
122
+
123
+ # Filter by only
124
+ if only:
125
+ only_set = set(only)
126
+ checks = [c for c in checks if c.id in only_set]
127
+
128
+ # Filter by skip
129
+ if skip:
130
+ skip_set = set(skip)
131
+ checks = [c for c in checks if c.id not in skip_set]
132
+
133
+ # Filter by categories
134
+ if categories:
135
+ checks = [c for c in checks if c.category in categories]
136
+
137
+ # Filter by deep mode
138
+ if not deep_mode:
139
+ checks = [c for c in checks if not c.requires_deep]
140
+
141
+ return checks
142
+
143
+ def resolve_dependencies(self, check_ids: List[str]) -> List[str]:
144
+ """
145
+ Resolve check dependencies and return ordered list.
146
+
147
+ Args:
148
+ check_ids: List of check IDs to resolve
149
+
150
+ Returns:
151
+ Ordered list of check IDs with dependencies first
152
+ """
153
+ resolved: List[str] = []
154
+ seen: Set[str] = set()
155
+
156
+ def resolve(id: str) -> None:
157
+ if id in seen:
158
+ return
159
+ seen.add(id)
160
+
161
+ check = self._checks.get(id)
162
+ if check:
163
+ for dep in check.dependencies:
164
+ resolve(dep)
165
+ resolved.append(id)
166
+
167
+ for id in check_ids:
168
+ resolve(id)
169
+
170
+ return resolved
171
+
172
+ def list_checks_text(self) -> str:
173
+ """Generate text listing of all checks."""
174
+ lines = ["Available Doctor Checks:", ""]
175
+
176
+ # Group by category
177
+ by_category: Dict[CheckCategory, List[CheckDefinition]] = {}
178
+ for check in self._checks.values():
179
+ if check.category not in by_category:
180
+ by_category[check.category] = []
181
+ by_category[check.category].append(check)
182
+
183
+ for category in CheckCategory:
184
+ if category in by_category:
185
+ lines.append(f" {category.value.upper()}:")
186
+ for check in sorted(by_category[category], key=lambda c: c.id):
187
+ deep_marker = " [deep]" if check.requires_deep else ""
188
+ lines.append(f" {check.id:<30} {check.description}{deep_marker}")
189
+ lines.append("")
190
+
191
+ return "\n".join(lines)
192
+
193
+
194
+ # Global registry instance
195
+ _registry = CheckRegistry()
196
+
197
+
198
+ def register_check(
199
+ id: str,
200
+ title: str,
201
+ description: str,
202
+ category: CheckCategory,
203
+ severity: CheckSeverity = CheckSeverity.MEDIUM,
204
+ requires_deep: bool = False,
205
+ dependencies: Optional[List[str]] = None,
206
+ tags: Optional[List[str]] = None,
207
+ ):
208
+ """
209
+ Decorator to register a doctor check.
210
+
211
+ Usage:
212
+ @register_check(
213
+ id="python_version",
214
+ title="Python Version",
215
+ description="Check Python version is 3.9+",
216
+ category=CheckCategory.ENVIRONMENT,
217
+ )
218
+ def check_python_version(config: DoctorConfig) -> CheckResult:
219
+ ...
220
+ """
221
+ def decorator(func: Callable) -> Callable:
222
+ _registry.register(
223
+ id=id,
224
+ title=title,
225
+ description=description,
226
+ category=category,
227
+ implementation=func,
228
+ severity=severity,
229
+ requires_deep=requires_deep,
230
+ dependencies=dependencies,
231
+ tags=tags,
232
+ )
233
+ return func
234
+ return decorator
235
+
236
+
237
+ def get_registry() -> CheckRegistry:
238
+ """Get the global check registry."""
239
+ return _registry