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,367 @@
1
+ """
2
+ Deploy doctor - connectivity and readiness checks.
3
+ """
4
+ import subprocess
5
+ import socket
6
+ import sys
7
+ from typing import Optional, List
8
+ from dataclasses import dataclass
9
+ from .schema import validate_agents_yaml
10
+
11
+
12
+ @dataclass
13
+ class DoctorCheckResult:
14
+ """Result of a single doctor check."""
15
+ name: str
16
+ passed: bool
17
+ message: str
18
+ fix_suggestion: Optional[str] = None
19
+
20
+
21
+ @dataclass
22
+ class DoctorReport:
23
+ """Aggregated report of all doctor checks."""
24
+ checks: List[DoctorCheckResult]
25
+
26
+ @property
27
+ def total_checks(self) -> int:
28
+ return len(self.checks)
29
+
30
+ @property
31
+ def passed_checks(self) -> int:
32
+ return sum(1 for c in self.checks if c.passed)
33
+
34
+ @property
35
+ def failed_checks(self) -> int:
36
+ return sum(1 for c in self.checks if not c.passed)
37
+
38
+ @property
39
+ def all_passed(self) -> bool:
40
+ return all(c.passed for c in self.checks)
41
+
42
+
43
+ def check_python_version() -> DoctorCheckResult:
44
+ """Check Python version is 3.9+."""
45
+ try:
46
+ version = sys.version_info
47
+ version_str = f"{version.major}.{version.minor}.{version.micro}"
48
+
49
+ if version.major >= 3 and version.minor >= 9:
50
+ return DoctorCheckResult(
51
+ name="Python Version",
52
+ passed=True,
53
+ message=f"Python {version_str} (>= 3.9 required)"
54
+ )
55
+ else:
56
+ return DoctorCheckResult(
57
+ name="Python Version",
58
+ passed=False,
59
+ message=f"Python {version_str} found, but 3.9+ required",
60
+ fix_suggestion="Upgrade Python to version 3.9 or higher"
61
+ )
62
+ except Exception as e:
63
+ return DoctorCheckResult(
64
+ name="Python Version",
65
+ passed=False,
66
+ message=f"Failed to check Python version: {e}",
67
+ fix_suggestion="Ensure Python is properly installed"
68
+ )
69
+
70
+
71
+ def check_docker_available() -> DoctorCheckResult:
72
+ """Check if Docker is installed and running."""
73
+ try:
74
+ result = subprocess.run(
75
+ ['docker', '--version'],
76
+ capture_output=True,
77
+ text=True,
78
+ timeout=5
79
+ )
80
+
81
+ if result.returncode == 0:
82
+ version = result.stdout.strip()
83
+ return DoctorCheckResult(
84
+ name="Docker",
85
+ passed=True,
86
+ message=f"Docker available: {version}"
87
+ )
88
+ else:
89
+ return DoctorCheckResult(
90
+ name="Docker",
91
+ passed=False,
92
+ message="Docker command failed",
93
+ fix_suggestion="Install Docker: https://docs.docker.com/get-docker/"
94
+ )
95
+ except FileNotFoundError:
96
+ return DoctorCheckResult(
97
+ name="Docker",
98
+ passed=False,
99
+ message="Docker not found",
100
+ fix_suggestion="Install Docker: https://docs.docker.com/get-docker/"
101
+ )
102
+ except Exception as e:
103
+ return DoctorCheckResult(
104
+ name="Docker",
105
+ passed=False,
106
+ message=f"Docker check failed: {e}",
107
+ fix_suggestion="Ensure Docker is installed and running"
108
+ )
109
+
110
+
111
+ def check_port_available(port: int) -> DoctorCheckResult:
112
+ """Check if a port is available."""
113
+ try:
114
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
115
+ result = s.connect_ex(('127.0.0.1', port))
116
+
117
+ if result != 0:
118
+ return DoctorCheckResult(
119
+ name=f"Port {port}",
120
+ passed=True,
121
+ message=f"Port {port} is available"
122
+ )
123
+ else:
124
+ return DoctorCheckResult(
125
+ name=f"Port {port}",
126
+ passed=False,
127
+ message=f"Port {port} is already in use",
128
+ fix_suggestion=f"Stop the service using port {port} or choose a different port"
129
+ )
130
+ except Exception as e:
131
+ return DoctorCheckResult(
132
+ name=f"Port {port}",
133
+ passed=False,
134
+ message=f"Failed to check port {port}: {e}",
135
+ fix_suggestion="Check network configuration"
136
+ )
137
+
138
+
139
+ def check_aws_cli() -> DoctorCheckResult:
140
+ """Check AWS CLI configuration."""
141
+ try:
142
+ result = subprocess.run(
143
+ ['aws', 'sts', 'get-caller-identity', '--output', 'json'],
144
+ capture_output=True,
145
+ text=True,
146
+ timeout=10
147
+ )
148
+
149
+ if result.returncode == 0:
150
+ import json
151
+ identity = json.loads(result.stdout)
152
+ account = identity.get('Account', 'unknown')
153
+ user_id = identity.get('UserId', 'unknown')
154
+
155
+ return DoctorCheckResult(
156
+ name="AWS CLI",
157
+ passed=True,
158
+ message=f"AWS CLI configured (Account: {account[:4]}...{account[-4:]})"
159
+ )
160
+ else:
161
+ return DoctorCheckResult(
162
+ name="AWS CLI",
163
+ passed=False,
164
+ message="AWS CLI not configured or credentials invalid",
165
+ fix_suggestion="Run: aws configure"
166
+ )
167
+ except FileNotFoundError:
168
+ return DoctorCheckResult(
169
+ name="AWS CLI",
170
+ passed=False,
171
+ message="AWS CLI not installed",
172
+ fix_suggestion="Install AWS CLI: https://aws.amazon.com/cli/"
173
+ )
174
+ except Exception as e:
175
+ return DoctorCheckResult(
176
+ name="AWS CLI",
177
+ passed=False,
178
+ message=f"AWS CLI check failed: {e}",
179
+ fix_suggestion="Run: aws configure"
180
+ )
181
+
182
+
183
+ def check_azure_cli() -> DoctorCheckResult:
184
+ """Check Azure CLI configuration."""
185
+ try:
186
+ result = subprocess.run(
187
+ ['az', 'account', 'show', '--output', 'json'],
188
+ capture_output=True,
189
+ text=True,
190
+ timeout=10
191
+ )
192
+
193
+ if result.returncode == 0:
194
+ import json
195
+ account = json.loads(result.stdout)
196
+ sub_id = account.get('id', 'unknown')
197
+ name = account.get('name', 'unknown')
198
+
199
+ return DoctorCheckResult(
200
+ name="Azure CLI",
201
+ passed=True,
202
+ message=f"Azure CLI logged in (Subscription: {sub_id[:8]}...)"
203
+ )
204
+ else:
205
+ return DoctorCheckResult(
206
+ name="Azure CLI",
207
+ passed=False,
208
+ message="Azure CLI not logged in",
209
+ fix_suggestion="Run: az login"
210
+ )
211
+ except FileNotFoundError:
212
+ return DoctorCheckResult(
213
+ name="Azure CLI",
214
+ passed=False,
215
+ message="Azure CLI not installed",
216
+ fix_suggestion="Install Azure CLI: https://docs.microsoft.com/en-us/cli/azure/install-azure-cli"
217
+ )
218
+ except Exception as e:
219
+ return DoctorCheckResult(
220
+ name="Azure CLI",
221
+ passed=False,
222
+ message=f"Azure CLI check failed: {e}",
223
+ fix_suggestion="Run: az login"
224
+ )
225
+
226
+
227
+ def check_gcp_cli() -> DoctorCheckResult:
228
+ """Check GCP CLI configuration."""
229
+ try:
230
+ result = subprocess.run(
231
+ ['gcloud', 'config', 'get-value', 'project'],
232
+ capture_output=True,
233
+ text=True,
234
+ timeout=10
235
+ )
236
+
237
+ if result.returncode == 0 and result.stdout.strip():
238
+ project_id = result.stdout.strip()
239
+
240
+ return DoctorCheckResult(
241
+ name="GCP CLI",
242
+ passed=True,
243
+ message=f"GCP CLI configured (Project: {project_id})"
244
+ )
245
+ else:
246
+ return DoctorCheckResult(
247
+ name="GCP CLI",
248
+ passed=False,
249
+ message="GCP CLI not configured or no project set",
250
+ fix_suggestion="Run: gcloud init"
251
+ )
252
+ except FileNotFoundError:
253
+ return DoctorCheckResult(
254
+ name="GCP CLI",
255
+ passed=False,
256
+ message="GCP CLI not installed",
257
+ fix_suggestion="Install gcloud CLI: https://cloud.google.com/sdk/docs/install"
258
+ )
259
+ except Exception as e:
260
+ return DoctorCheckResult(
261
+ name="GCP CLI",
262
+ passed=False,
263
+ message=f"GCP CLI check failed: {e}",
264
+ fix_suggestion="Run: gcloud init"
265
+ )
266
+
267
+
268
+ def check_agents_yaml(file_path: str) -> DoctorCheckResult:
269
+ """Check if agents.yaml exists and has valid deploy config."""
270
+ try:
271
+ config = validate_agents_yaml(file_path)
272
+
273
+ if config:
274
+ return DoctorCheckResult(
275
+ name="agents.yaml",
276
+ passed=True,
277
+ message=f"Valid deploy configuration found (type: {config.type.value})"
278
+ )
279
+ else:
280
+ return DoctorCheckResult(
281
+ name="agents.yaml",
282
+ passed=False,
283
+ message="No deploy section found in agents.yaml",
284
+ fix_suggestion="Add deploy configuration to agents.yaml or run: praisonai deploy init"
285
+ )
286
+ except FileNotFoundError:
287
+ return DoctorCheckResult(
288
+ name="agents.yaml",
289
+ passed=False,
290
+ message=f"File not found: {file_path}",
291
+ fix_suggestion="Create agents.yaml or run: praisonai deploy init"
292
+ )
293
+ except ValueError as e:
294
+ return DoctorCheckResult(
295
+ name="agents.yaml",
296
+ passed=False,
297
+ message=f"Invalid deploy configuration: {e}",
298
+ fix_suggestion="Fix deploy configuration in agents.yaml or run: praisonai deploy validate"
299
+ )
300
+ except Exception as e:
301
+ return DoctorCheckResult(
302
+ name="agents.yaml",
303
+ passed=False,
304
+ message=f"Failed to validate agents.yaml: {e}",
305
+ fix_suggestion="Check agents.yaml syntax"
306
+ )
307
+
308
+
309
+ def run_local_checks(port: int = 8005, agents_file: Optional[str] = None) -> DoctorReport:
310
+ """Run local environment checks."""
311
+ checks = [
312
+ check_python_version(),
313
+ check_port_available(port),
314
+ ]
315
+
316
+ if agents_file:
317
+ checks.append(check_agents_yaml(agents_file))
318
+
319
+ return DoctorReport(checks=checks)
320
+
321
+
322
+ def run_aws_checks() -> DoctorReport:
323
+ """Run AWS-specific checks."""
324
+ checks = [
325
+ check_aws_cli(),
326
+ ]
327
+ return DoctorReport(checks=checks)
328
+
329
+
330
+ def run_azure_checks() -> DoctorReport:
331
+ """Run Azure-specific checks."""
332
+ checks = [
333
+ check_azure_cli(),
334
+ ]
335
+ return DoctorReport(checks=checks)
336
+
337
+
338
+ def run_gcp_checks() -> DoctorReport:
339
+ """Run GCP-specific checks."""
340
+ checks = [
341
+ check_gcp_cli(),
342
+ ]
343
+ return DoctorReport(checks=checks)
344
+
345
+
346
+ def run_all_checks(agents_file: Optional[str] = None) -> DoctorReport:
347
+ """Run all available checks."""
348
+ checks = []
349
+
350
+ # Local checks
351
+ local_report = run_local_checks(agents_file=agents_file)
352
+ checks.extend(local_report.checks)
353
+
354
+ # Docker check
355
+ checks.append(check_docker_available())
356
+
357
+ # Cloud provider checks
358
+ aws_report = run_aws_checks()
359
+ checks.extend(aws_report.checks)
360
+
361
+ azure_report = run_azure_checks()
362
+ checks.extend(azure_report.checks)
363
+
364
+ gcp_report = run_gcp_checks()
365
+ checks.extend(gcp_report.checks)
366
+
367
+ return DoctorReport(checks=checks)
@@ -0,0 +1,327 @@
1
+ """
2
+ Main Deploy class for unified deployment interface.
3
+ """
4
+ from typing import Dict, Any
5
+ from .models import DeployConfig, DeployResult, DeployType, DeployStatus, DestroyResult, ServiceState
6
+ from .schema import validate_agents_yaml
7
+ from .api import start_api_server, generate_api_server_code
8
+ from .docker import (
9
+ build_docker_image, run_docker_container, push_docker_image, save_dockerfile,
10
+ get_docker_container_status, remove_docker_container
11
+ )
12
+ from .providers import get_provider
13
+
14
+
15
+ class Deploy:
16
+ """
17
+ Unified deployment interface for PraisonAI agents.
18
+
19
+ Supports:
20
+ - API server deployment (local/production)
21
+ - Docker containerization
22
+ - Cloud deployment (AWS, Azure, GCP)
23
+
24
+ Examples:
25
+ # From YAML
26
+ deploy = Deploy.from_yaml("agents.yaml")
27
+ result = deploy.deploy()
28
+
29
+ # Programmatic
30
+ from praisonai.deploy import Deploy, DeployConfig, DeployType
31
+
32
+ config = DeployConfig(type=DeployType.API)
33
+ deploy = Deploy(config, agents_file="agents.yaml")
34
+ result = deploy.deploy()
35
+ """
36
+
37
+ def __init__(self, config: DeployConfig, agents_file: str = "agents.yaml"):
38
+ """
39
+ Initialize Deploy with configuration.
40
+
41
+ Args:
42
+ config: Deployment configuration
43
+ agents_file: Path to agents.yaml file
44
+ """
45
+ self.config = config
46
+ self.agents_file = agents_file
47
+
48
+ @classmethod
49
+ def from_yaml(cls, agents_file: str = "agents.yaml") -> 'Deploy':
50
+ """
51
+ Create Deploy instance from agents.yaml file.
52
+
53
+ Args:
54
+ agents_file: Path to agents.yaml file
55
+
56
+ Returns:
57
+ Deploy instance
58
+
59
+ Raises:
60
+ ValueError: If no deploy configuration found in YAML
61
+ """
62
+ config = validate_agents_yaml(agents_file)
63
+
64
+ if config is None:
65
+ raise ValueError(f"No deploy configuration found in {agents_file}")
66
+
67
+ return cls(config, agents_file)
68
+
69
+ def deploy(self, background: bool = False) -> DeployResult:
70
+ """
71
+ Execute deployment based on configuration.
72
+
73
+ Args:
74
+ background: Run in background mode (for API deployments)
75
+
76
+ Returns:
77
+ DeployResult with deployment information
78
+ """
79
+ if self.config.type == DeployType.API:
80
+ return self._deploy_api(background)
81
+ elif self.config.type == DeployType.DOCKER:
82
+ return self._deploy_docker()
83
+ elif self.config.type == DeployType.CLOUD:
84
+ return self._deploy_cloud()
85
+ else:
86
+ return DeployResult(
87
+ success=False,
88
+ message=f"Unsupported deployment type: {self.config.type}",
89
+ error="Invalid deployment type"
90
+ )
91
+
92
+ def _deploy_api(self, background: bool = False) -> DeployResult:
93
+ """Deploy as API server."""
94
+ return start_api_server(
95
+ self.agents_file,
96
+ self.config.api,
97
+ background=background
98
+ )
99
+
100
+ def _deploy_docker(self) -> DeployResult:
101
+ """Deploy as Docker container."""
102
+ # Generate and save Dockerfile
103
+ save_dockerfile(self.agents_file, self.config.docker)
104
+
105
+ # Generate API server code
106
+ api_code = generate_api_server_code(self.agents_file, None)
107
+ with open("api_server.py", 'w') as f:
108
+ f.write(api_code)
109
+
110
+ # Build image
111
+ build_result = build_docker_image(self.config.docker)
112
+
113
+ if not build_result.success:
114
+ return build_result
115
+
116
+ # Push if configured
117
+ if self.config.docker.push and self.config.docker.registry:
118
+ push_result = push_docker_image(self.config.docker)
119
+ if not push_result.success:
120
+ return push_result
121
+
122
+ # Run container
123
+ return run_docker_container(self.config.docker)
124
+
125
+ def _deploy_cloud(self) -> DeployResult:
126
+ """Deploy to cloud provider."""
127
+ provider = get_provider(self.config.cloud)
128
+ return provider.deploy()
129
+
130
+ def plan(self) -> Dict[str, Any]:
131
+ """
132
+ Generate deployment plan without executing.
133
+
134
+ Returns:
135
+ Dictionary with planned deployment configuration
136
+ """
137
+ if self.config.type == DeployType.API:
138
+ return {
139
+ "type": "api",
140
+ "host": self.config.api.host,
141
+ "port": self.config.api.port,
142
+ "workers": self.config.api.workers,
143
+ "agents_file": self.agents_file
144
+ }
145
+ elif self.config.type == DeployType.DOCKER:
146
+ return {
147
+ "type": "docker",
148
+ "image": f"{self.config.docker.image_name}:{self.config.docker.tag}",
149
+ "registry": self.config.docker.registry,
150
+ "push": self.config.docker.push,
151
+ "ports": self.config.docker.expose
152
+ }
153
+ elif self.config.type == DeployType.CLOUD:
154
+ provider = get_provider(self.config.cloud)
155
+ return provider.plan()
156
+ else:
157
+ return {"error": "Invalid deployment type"}
158
+
159
+ def doctor(self):
160
+ """
161
+ Run health checks for deployment.
162
+
163
+ Returns:
164
+ DoctorReport with check results
165
+ """
166
+ from .doctor import run_local_checks, run_all_checks, DoctorReport
167
+
168
+ if self.config.type == DeployType.API:
169
+ return run_local_checks(
170
+ port=self.config.api.port,
171
+ agents_file=self.agents_file
172
+ )
173
+ elif self.config.type == DeployType.DOCKER:
174
+ from .doctor import check_docker_available, DoctorReport
175
+ checks = run_local_checks(agents_file=self.agents_file).checks
176
+ checks.append(check_docker_available())
177
+ return DoctorReport(checks=checks)
178
+ elif self.config.type == DeployType.CLOUD:
179
+ provider = get_provider(self.config.cloud)
180
+ return provider.doctor()
181
+ else:
182
+ return run_all_checks(self.agents_file)
183
+
184
+ def status(self) -> DeployStatus:
185
+ """
186
+ Get current deployment status.
187
+
188
+ Returns:
189
+ DeployStatus with current state and information
190
+ """
191
+ if self.config.type == DeployType.API:
192
+ return self._status_api()
193
+ elif self.config.type == DeployType.DOCKER:
194
+ return self._status_docker()
195
+ elif self.config.type == DeployType.CLOUD:
196
+ return self._status_cloud()
197
+ else:
198
+ return DeployStatus(
199
+ state=ServiceState.UNKNOWN,
200
+ message=f"Unsupported deployment type: {self.config.type}"
201
+ )
202
+
203
+ def _status_api(self) -> DeployStatus:
204
+ """Get status of local API server."""
205
+ import socket
206
+ port = self.config.api.port if self.config.api else 8005
207
+
208
+ try:
209
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
210
+ result = sock.connect_ex(('127.0.0.1', port))
211
+ sock.close()
212
+
213
+ if result == 0:
214
+ return DeployStatus(
215
+ state=ServiceState.RUNNING,
216
+ url=f"http://127.0.0.1:{port}",
217
+ message=f"API server running on port {port}",
218
+ service_name="praisonai-api",
219
+ provider="api",
220
+ healthy=True,
221
+ instances_running=1,
222
+ instances_desired=1
223
+ )
224
+ else:
225
+ return DeployStatus(
226
+ state=ServiceState.STOPPED,
227
+ message=f"No service running on port {port}",
228
+ service_name="praisonai-api",
229
+ provider="api",
230
+ healthy=False,
231
+ instances_running=0,
232
+ instances_desired=1
233
+ )
234
+ except Exception as e:
235
+ return DeployStatus(
236
+ state=ServiceState.UNKNOWN,
237
+ message=f"Failed to check status: {e}",
238
+ service_name="praisonai-api",
239
+ provider="api"
240
+ )
241
+
242
+ def _status_docker(self) -> DeployStatus:
243
+ """Get status of Docker container."""
244
+ return get_docker_container_status(self.config.docker)
245
+
246
+ def _status_cloud(self) -> DeployStatus:
247
+ """Get status of cloud deployment."""
248
+ provider = get_provider(self.config.cloud)
249
+ return provider.status()
250
+
251
+ def destroy(self, force: bool = False) -> DestroyResult:
252
+ """
253
+ Destroy/delete the deployment.
254
+
255
+ Args:
256
+ force: Force deletion without confirmation
257
+
258
+ Returns:
259
+ DestroyResult with deletion information
260
+ """
261
+ if self.config.type == DeployType.API:
262
+ return self._destroy_api()
263
+ elif self.config.type == DeployType.DOCKER:
264
+ return self._destroy_docker(force)
265
+ elif self.config.type == DeployType.CLOUD:
266
+ return self._destroy_cloud(force)
267
+ else:
268
+ return DestroyResult(
269
+ success=False,
270
+ message=f"Unsupported deployment type: {self.config.type}",
271
+ error="Invalid deployment type"
272
+ )
273
+
274
+ def _destroy_api(self) -> DestroyResult:
275
+ """Stop local API server."""
276
+ import subprocess
277
+ import signal
278
+ import os
279
+
280
+ port = self.config.api.port if self.config.api else 8005
281
+
282
+ try:
283
+ # Find process using the port
284
+ result = subprocess.run(
285
+ ['lsof', '-ti', f':{port}'],
286
+ capture_output=True,
287
+ text=True,
288
+ timeout=5
289
+ )
290
+
291
+ if result.returncode == 0 and result.stdout.strip():
292
+ pids = result.stdout.strip().split('\n')
293
+ deleted_resources = []
294
+
295
+ for pid in pids:
296
+ try:
297
+ os.kill(int(pid), signal.SIGTERM)
298
+ deleted_resources.append(f"process:{pid}")
299
+ except (ProcessLookupError, ValueError):
300
+ pass
301
+
302
+ return DestroyResult(
303
+ success=True,
304
+ message=f"Stopped API server on port {port}",
305
+ resources_deleted=deleted_resources
306
+ )
307
+ else:
308
+ return DestroyResult(
309
+ success=True,
310
+ message=f"No API server running on port {port}",
311
+ resources_deleted=[]
312
+ )
313
+ except Exception as e:
314
+ return DestroyResult(
315
+ success=False,
316
+ message="Failed to stop API server",
317
+ error=str(e)
318
+ )
319
+
320
+ def _destroy_docker(self, force: bool = False) -> DestroyResult:
321
+ """Remove Docker container."""
322
+ return remove_docker_container(self.config.docker, force)
323
+
324
+ def _destroy_cloud(self, force: bool = False) -> DestroyResult:
325
+ """Destroy cloud deployment."""
326
+ provider = get_provider(self.config.cloud)
327
+ return provider.destroy(force)