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,358 @@
1
+ """
2
+ Azure provider for cloud deployment (Container Apps).
3
+ """
4
+ import subprocess
5
+ import json
6
+ from typing import Dict, Any
7
+ from .base import BaseProvider
8
+ from ..models import DeployResult, DeployStatus, DestroyResult, ServiceState
9
+ from ..doctor import DoctorReport, DoctorCheckResult, check_azure_cli
10
+
11
+
12
+ class AzureProvider(BaseProvider):
13
+ """Azure deployment provider using Container Apps."""
14
+
15
+ def doctor(self) -> DoctorReport:
16
+ """Run Azure-specific health checks."""
17
+ checks = [check_azure_cli()]
18
+
19
+ # Check if resource group exists
20
+ if self.config.resource_group:
21
+ try:
22
+ result = subprocess.run(
23
+ ['az', 'group', 'show',
24
+ '--name', self.config.resource_group,
25
+ '--output', 'json'],
26
+ capture_output=True,
27
+ text=True,
28
+ timeout=10
29
+ )
30
+
31
+ if result.returncode == 0:
32
+ checks.append(DoctorCheckResult(
33
+ name="Resource Group",
34
+ passed=True,
35
+ message=f"Resource group exists: {self.config.resource_group}"
36
+ ))
37
+ else:
38
+ checks.append(DoctorCheckResult(
39
+ name="Resource Group",
40
+ passed=False,
41
+ message=f"Resource group not found: {self.config.resource_group}",
42
+ fix_suggestion=f"Run: az group create --name {self.config.resource_group} --location {self.config.region}"
43
+ ))
44
+ except Exception as e:
45
+ checks.append(DoctorCheckResult(
46
+ name="Resource Group",
47
+ passed=False,
48
+ message=f"Failed to check resource group: {e}",
49
+ fix_suggestion="Check Azure CLI configuration"
50
+ ))
51
+
52
+ return DoctorReport(checks=checks)
53
+
54
+ def plan(self) -> Dict[str, Any]:
55
+ """Generate Azure deployment plan."""
56
+ plan = {
57
+ "provider": "azure",
58
+ "service_name": self.config.service_name,
59
+ "region": self.config.region,
60
+ "resource_group": self.config.resource_group,
61
+ "subscription_id": self.config.subscription_id,
62
+ "cpu": self.config.cpu,
63
+ "memory": self.config.memory,
64
+ "min_replicas": self.config.min_instances,
65
+ "max_replicas": self.config.max_instances,
66
+ "image": self.config.image or f"{self.config.service_name}:latest",
67
+ "steps": [
68
+ "1. Create resource group (if not exists)",
69
+ "2. Create Container Apps environment",
70
+ "3. Create or update Container App",
71
+ "4. Get app URL"
72
+ ]
73
+ }
74
+
75
+ return plan
76
+
77
+ def deploy(self) -> DeployResult:
78
+ """Deploy to Azure Container Apps."""
79
+ try:
80
+ if not self.config.resource_group:
81
+ return DeployResult(
82
+ success=False,
83
+ message="Resource group is required for Azure deployment",
84
+ error="Please specify resource_group in cloud config"
85
+ )
86
+
87
+ # Step 1: Create resource group if not exists
88
+ print(f"📦 Creating resource group: {self.config.resource_group}")
89
+ try:
90
+ subprocess.run(
91
+ ['az', 'group', 'create',
92
+ '--name', self.config.resource_group,
93
+ '--location', self.config.region],
94
+ capture_output=True,
95
+ timeout=30
96
+ )
97
+ except Exception:
98
+ pass # May already exist
99
+
100
+ # Step 2: Create Container Apps environment
101
+ env_name = f"{self.config.service_name}-env"
102
+ print(f"🌍 Creating Container Apps environment: {env_name}")
103
+
104
+ try:
105
+ subprocess.run(
106
+ ['az', 'containerapp', 'env', 'create',
107
+ '--name', env_name,
108
+ '--resource-group', self.config.resource_group,
109
+ '--location', self.config.region],
110
+ capture_output=True,
111
+ timeout=120
112
+ )
113
+ except Exception:
114
+ pass # May already exist
115
+
116
+ # Step 3: Create or update Container App
117
+ print(f"🚀 Deploying Container App: {self.config.service_name}")
118
+
119
+ cmd = [
120
+ 'az', 'containerapp', 'create',
121
+ '--name', self.config.service_name,
122
+ '--resource-group', self.config.resource_group,
123
+ '--environment', env_name,
124
+ '--image', self.config.image or f"{self.config.service_name}:latest",
125
+ '--target-port', '8005',
126
+ '--ingress', 'external',
127
+ '--cpu', str(self.config.cpu),
128
+ '--memory', f"{self.config.memory}Gi",
129
+ '--min-replicas', str(self.config.min_instances),
130
+ '--max-replicas', str(self.config.max_instances)
131
+ ]
132
+
133
+ # Add environment variables
134
+ if self.config.env_vars:
135
+ env_args = []
136
+ for k, v in self.config.env_vars.items():
137
+ env_args.extend(['--env-vars', f"{k}={v}"])
138
+ cmd.extend(env_args)
139
+
140
+ result = subprocess.run(
141
+ cmd,
142
+ capture_output=True,
143
+ text=True,
144
+ timeout=180
145
+ )
146
+
147
+ if result.returncode != 0:
148
+ # Try update instead
149
+ cmd[1] = 'update'
150
+ result = subprocess.run(
151
+ cmd,
152
+ capture_output=True,
153
+ text=True,
154
+ timeout=180
155
+ )
156
+
157
+ if result.returncode == 0:
158
+ # Get app URL
159
+ try:
160
+ show_result = subprocess.run(
161
+ ['az', 'containerapp', 'show',
162
+ '--name', self.config.service_name,
163
+ '--resource-group', self.config.resource_group,
164
+ '--output', 'json'],
165
+ capture_output=True,
166
+ text=True,
167
+ timeout=30
168
+ )
169
+
170
+ if show_result.returncode == 0:
171
+ app_data = json.loads(show_result.stdout)
172
+ url = app_data.get('properties', {}).get('configuration', {}).get('ingress', {}).get('fqdn')
173
+ if url:
174
+ url = f"https://{url}"
175
+ else:
176
+ url = None
177
+ except Exception:
178
+ url = None
179
+
180
+ return DeployResult(
181
+ success=True,
182
+ message=f"Container App deployed successfully",
183
+ url=url,
184
+ metadata={
185
+ "resource_group": self.config.resource_group,
186
+ "app_name": self.config.service_name,
187
+ "region": self.config.region
188
+ }
189
+ )
190
+ else:
191
+ return DeployResult(
192
+ success=False,
193
+ message="Failed to deploy Container App",
194
+ error=result.stderr
195
+ )
196
+
197
+ except Exception as e:
198
+ return DeployResult(
199
+ success=False,
200
+ message="Azure deployment failed",
201
+ error=str(e)
202
+ )
203
+
204
+ def status(self) -> DeployStatus:
205
+ """Get current Azure Container App status."""
206
+ try:
207
+ if not self.config.resource_group:
208
+ return DeployStatus(
209
+ state=ServiceState.UNKNOWN,
210
+ message="Resource group not configured",
211
+ service_name=self.config.service_name,
212
+ provider="azure",
213
+ region=self.config.region
214
+ )
215
+
216
+ result = subprocess.run(
217
+ ['az', 'containerapp', 'show',
218
+ '--name', self.config.service_name,
219
+ '--resource-group', self.config.resource_group,
220
+ '--output', 'json'],
221
+ capture_output=True,
222
+ text=True,
223
+ timeout=30
224
+ )
225
+
226
+ if result.returncode != 0:
227
+ return DeployStatus(
228
+ state=ServiceState.NOT_FOUND,
229
+ message=f"Container App not found: {result.stderr}",
230
+ service_name=self.config.service_name,
231
+ provider="azure",
232
+ region=self.config.region
233
+ )
234
+
235
+ data = json.loads(result.stdout)
236
+ properties = data.get('properties', {})
237
+ provisioning_state = properties.get('provisioningState', 'Unknown')
238
+ running_status = properties.get('runningStatus', {}).get('state', 'Unknown')
239
+
240
+ # Get URL
241
+ ingress = properties.get('configuration', {}).get('ingress', {})
242
+ fqdn = ingress.get('fqdn')
243
+ url = f"https://{fqdn}" if fqdn else None
244
+
245
+ # Get replica count
246
+ template = properties.get('template', {})
247
+ scale = template.get('scale', {})
248
+ min_replicas = scale.get('minReplicas', 0)
249
+ max_replicas = scale.get('maxReplicas', 0)
250
+
251
+ # Map status to ServiceState
252
+ if provisioning_state == 'Succeeded' and running_status == 'Running':
253
+ state = ServiceState.RUNNING
254
+ elif provisioning_state == 'Succeeded' and running_status == 'Stopped':
255
+ state = ServiceState.STOPPED
256
+ elif provisioning_state in ['Creating', 'Updating']:
257
+ state = ServiceState.PENDING
258
+ elif provisioning_state == 'Failed':
259
+ state = ServiceState.FAILED
260
+ else:
261
+ state = ServiceState.UNKNOWN
262
+
263
+ return DeployStatus(
264
+ state=state,
265
+ url=url,
266
+ message=f"Provisioning: {provisioning_state}, Running: {running_status}",
267
+ service_name=self.config.service_name,
268
+ provider="azure",
269
+ region=self.config.region,
270
+ healthy=state == ServiceState.RUNNING,
271
+ instances_running=min_replicas if state == ServiceState.RUNNING else 0,
272
+ instances_desired=min_replicas,
273
+ created_at=data.get('systemData', {}).get('createdAt'),
274
+ updated_at=data.get('systemData', {}).get('lastModifiedAt'),
275
+ metadata={
276
+ "resource_group": self.config.resource_group,
277
+ "provisioning_state": provisioning_state,
278
+ "running_status": running_status,
279
+ "min_replicas": min_replicas,
280
+ "max_replicas": max_replicas
281
+ }
282
+ )
283
+
284
+ except Exception as e:
285
+ return DeployStatus(
286
+ state=ServiceState.UNKNOWN,
287
+ message=f"Failed to get status: {e}",
288
+ service_name=self.config.service_name,
289
+ provider="azure",
290
+ region=self.config.region
291
+ )
292
+
293
+ def destroy(self, force: bool = False) -> DestroyResult:
294
+ """Destroy Azure Container App and related resources."""
295
+ try:
296
+ if not self.config.resource_group:
297
+ return DestroyResult(
298
+ success=False,
299
+ message="Resource group not configured",
300
+ error="Please specify resource_group in cloud config"
301
+ )
302
+
303
+ deleted_resources = []
304
+
305
+ # Step 1: Delete the Container App
306
+ print(f"🗑️ Deleting Container App: {self.config.service_name}")
307
+ result = subprocess.run(
308
+ ['az', 'containerapp', 'delete',
309
+ '--name', self.config.service_name,
310
+ '--resource-group', self.config.resource_group,
311
+ '--yes'],
312
+ capture_output=True,
313
+ text=True,
314
+ timeout=120
315
+ )
316
+
317
+ if result.returncode == 0:
318
+ deleted_resources.append(f"containerapp:{self.config.service_name}")
319
+ else:
320
+ return DestroyResult(
321
+ success=False,
322
+ message="Failed to delete Container App",
323
+ error=result.stderr,
324
+ resources_deleted=deleted_resources
325
+ )
326
+
327
+ # Step 2: Optionally delete environment if force
328
+ if force:
329
+ env_name = f"{self.config.service_name}-env"
330
+ print(f"🗑️ Deleting Container Apps environment: {env_name}")
331
+ env_result = subprocess.run(
332
+ ['az', 'containerapp', 'env', 'delete',
333
+ '--name', env_name,
334
+ '--resource-group', self.config.resource_group,
335
+ '--yes'],
336
+ capture_output=True,
337
+ text=True,
338
+ timeout=120
339
+ )
340
+ if env_result.returncode == 0:
341
+ deleted_resources.append(f"containerapp-env:{env_name}")
342
+
343
+ return DestroyResult(
344
+ success=True,
345
+ message="Successfully destroyed Azure Container App",
346
+ resources_deleted=deleted_resources,
347
+ metadata={
348
+ "resource_group": self.config.resource_group,
349
+ "region": self.config.region
350
+ }
351
+ )
352
+
353
+ except Exception as e:
354
+ return DestroyResult(
355
+ success=False,
356
+ message="Failed to destroy Azure resources",
357
+ error=str(e)
358
+ )
@@ -0,0 +1,101 @@
1
+ """
2
+ Base provider interface for cloud deployments.
3
+ """
4
+ from abc import ABC, abstractmethod
5
+ from typing import Dict, Any
6
+ from ..models import CloudConfig, DeployResult, DeployStatus, DestroyResult
7
+ from ..doctor import DoctorReport
8
+
9
+
10
+ class BaseProvider(ABC):
11
+ """Abstract base class for cloud providers."""
12
+
13
+ def __init__(self, config: CloudConfig):
14
+ """
15
+ Initialize provider with configuration.
16
+
17
+ Args:
18
+ config: Cloud configuration
19
+ """
20
+ self.config = config
21
+
22
+ @abstractmethod
23
+ def deploy(self) -> DeployResult:
24
+ """
25
+ Deploy to cloud provider.
26
+
27
+ Returns:
28
+ DeployResult with deployment information
29
+ """
30
+ pass
31
+
32
+ @abstractmethod
33
+ def doctor(self) -> DoctorReport:
34
+ """
35
+ Run provider-specific health checks.
36
+
37
+ Returns:
38
+ DoctorReport with check results
39
+ """
40
+ pass
41
+
42
+ @abstractmethod
43
+ def plan(self) -> Dict[str, Any]:
44
+ """
45
+ Generate deployment plan without executing.
46
+
47
+ Returns:
48
+ Dictionary with planned deployment configuration
49
+ """
50
+ pass
51
+
52
+ @abstractmethod
53
+ def status(self) -> DeployStatus:
54
+ """
55
+ Get current deployment status.
56
+
57
+ Returns:
58
+ DeployStatus with current state and info
59
+ """
60
+ pass
61
+
62
+ @abstractmethod
63
+ def destroy(self, force: bool = False) -> DestroyResult:
64
+ """
65
+ Destroy/delete the deployed service.
66
+
67
+ Args:
68
+ force: Force deletion without confirmation
69
+
70
+ Returns:
71
+ DestroyResult with deletion information
72
+ """
73
+ pass
74
+
75
+
76
+ def get_provider(config: CloudConfig) -> BaseProvider:
77
+ """
78
+ Get provider instance based on configuration.
79
+
80
+ Args:
81
+ config: Cloud configuration
82
+
83
+ Returns:
84
+ Provider instance
85
+
86
+ Raises:
87
+ ValueError: If provider is not supported
88
+ """
89
+ from ..models import CloudProvider
90
+
91
+ if config.provider == CloudProvider.AWS:
92
+ from .aws import AWSProvider
93
+ return AWSProvider(config)
94
+ elif config.provider == CloudProvider.AZURE:
95
+ from .azure import AzureProvider
96
+ return AzureProvider(config)
97
+ elif config.provider == CloudProvider.GCP:
98
+ from .gcp import GCPProvider
99
+ return GCPProvider(config)
100
+ else:
101
+ raise ValueError(f"Unsupported provider: {config.provider}")