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,231 @@
1
+ """
2
+ API server deployment functionality.
3
+ """
4
+ import subprocess
5
+ import os
6
+ import signal
7
+ import time
8
+ from typing import Optional
9
+ from .models import APIConfig, DeployResult
10
+
11
+
12
+ def generate_api_server_code(agents_file: str, config: Optional[APIConfig] = None) -> str:
13
+ """
14
+ Generate API server code for serving agents.
15
+
16
+ Args:
17
+ agents_file: Path to agents.yaml file
18
+ config: API configuration
19
+
20
+ Returns:
21
+ Python code for API server
22
+ """
23
+ if config is None:
24
+ config = APIConfig()
25
+
26
+ code = f'''"""
27
+ Auto-generated API server for PraisonAI agents.
28
+ """
29
+ from flask import Flask, request, jsonify
30
+ from flask_cors import CORS
31
+ from praisonai import PraisonAI
32
+ import os
33
+
34
+ app = Flask(__name__)
35
+
36
+ # CORS configuration
37
+ {"CORS(app)" if config.cors_enabled else "# CORS disabled"}
38
+
39
+ # Authentication
40
+ AUTH_ENABLED = {config.auth_enabled}
41
+ AUTH_TOKEN = {repr(config.auth_token)}
42
+
43
+ def check_auth():
44
+ """Check authentication if enabled."""
45
+ if not AUTH_ENABLED:
46
+ return True
47
+
48
+ token = request.headers.get('Authorization', '').replace('Bearer ', '')
49
+ return token == AUTH_TOKEN
50
+
51
+ @app.route('/health', methods=['GET'])
52
+ def health():
53
+ """Health check endpoint."""
54
+ return jsonify({{"status": "ok", "service": "praisonai-api"}})
55
+
56
+ @app.route('/chat', methods=['POST'])
57
+ def chat():
58
+ """Chat endpoint for agent interaction."""
59
+ if not check_auth():
60
+ return jsonify({{"error": "Unauthorized"}}), 401
61
+
62
+ data = request.get_json()
63
+ if not data or 'message' not in data:
64
+ return jsonify({{"error": "Message required"}}), 400
65
+
66
+ try:
67
+ praisonai = PraisonAI(agent_file="{agents_file}")
68
+ result = praisonai.run()
69
+
70
+ return jsonify({{
71
+ "response": result,
72
+ "status": "success"
73
+ }})
74
+ except Exception as e:
75
+ return jsonify({{
76
+ "error": str(e),
77
+ "status": "error"
78
+ }}), 500
79
+
80
+ @app.route('/agents', methods=['GET'])
81
+ def list_agents():
82
+ """List available agents."""
83
+ if not check_auth():
84
+ return jsonify({{"error": "Unauthorized"}}), 401
85
+
86
+ return jsonify({{
87
+ "agents": ["default"],
88
+ "agent_file": "{agents_file}"
89
+ }})
90
+
91
+ if __name__ == '__main__':
92
+ app.run(
93
+ host='{config.host}',
94
+ port={config.port},
95
+ debug={config.reload}
96
+ )
97
+ '''
98
+
99
+ return code
100
+
101
+
102
+ def start_api_server(
103
+ agents_file: str,
104
+ config: Optional[APIConfig] = None,
105
+ background: bool = False
106
+ ) -> DeployResult:
107
+ """
108
+ Start API server for agents.
109
+
110
+ Args:
111
+ agents_file: Path to agents.yaml file
112
+ config: API configuration
113
+ background: Run in background mode
114
+
115
+ Returns:
116
+ DeployResult with server information
117
+ """
118
+ if config is None:
119
+ config = APIConfig()
120
+
121
+ try:
122
+ # Generate server code
123
+ server_code = generate_api_server_code(agents_file, config)
124
+
125
+ # Write to temporary file
126
+ server_file = "api_server.py"
127
+ with open(server_file, 'w') as f:
128
+ f.write(server_code)
129
+
130
+ # Install flask and flask-cors if needed
131
+ try:
132
+ subprocess.run(
133
+ ['pip', 'install', '-q', 'flask', 'flask-cors'],
134
+ check=False,
135
+ capture_output=True
136
+ )
137
+ except Exception:
138
+ pass
139
+
140
+ # Start server
141
+ if background:
142
+ process = subprocess.Popen(
143
+ ['python', server_file],
144
+ stdout=subprocess.PIPE,
145
+ stderr=subprocess.PIPE,
146
+ start_new_session=True
147
+ )
148
+
149
+ # Wait a bit to check if it started successfully
150
+ time.sleep(2)
151
+
152
+ if process.poll() is None:
153
+ url = f"http://{config.host}:{config.port}"
154
+ return DeployResult(
155
+ success=True,
156
+ message=f"API server started in background (PID: {process.pid})",
157
+ url=url,
158
+ metadata={"pid": process.pid, "server_file": server_file}
159
+ )
160
+ else:
161
+ stderr = process.stderr.read().decode() if process.stderr else "Unknown error"
162
+ return DeployResult(
163
+ success=False,
164
+ message="Failed to start API server",
165
+ error=stderr
166
+ )
167
+ else:
168
+ # Run in foreground
169
+ url = f"http://{config.host}:{config.port}"
170
+ print(f"\n🚀 Starting API server at {url}")
171
+ print(f"📁 Serving agents from: {agents_file}")
172
+ print(f"🔗 Health check: {url}/health")
173
+ print(f"💬 Chat endpoint: {url}/chat")
174
+ print("\nPress Ctrl+C to stop the server\n")
175
+
176
+ process = subprocess.Popen(['python', server_file])
177
+
178
+ return DeployResult(
179
+ success=True,
180
+ message=f"API server running at {url}",
181
+ url=url,
182
+ metadata={"pid": process.pid, "server_file": server_file}
183
+ )
184
+
185
+ except Exception as e:
186
+ return DeployResult(
187
+ success=False,
188
+ message="Failed to start API server",
189
+ error=str(e)
190
+ )
191
+
192
+
193
+ def check_api_health(url: str, timeout: int = 5) -> bool:
194
+ """
195
+ Check if API server is healthy.
196
+
197
+ Args:
198
+ url: Base URL of API server
199
+ timeout: Request timeout in seconds
200
+
201
+ Returns:
202
+ True if healthy, False otherwise
203
+ """
204
+ try:
205
+ import urllib.request
206
+ health_url = f"{url}/health"
207
+
208
+ req = urllib.request.Request(health_url)
209
+ with urllib.request.urlopen(req, timeout=timeout) as response:
210
+ return response.status == 200
211
+ except Exception:
212
+ return False
213
+
214
+
215
+ def stop_api_server(pid: int) -> bool:
216
+ """
217
+ Stop API server by PID.
218
+
219
+ Args:
220
+ pid: Process ID of server
221
+
222
+ Returns:
223
+ True if stopped successfully, False otherwise
224
+ """
225
+ try:
226
+ os.kill(pid, signal.SIGTERM)
227
+ return True
228
+ except ProcessLookupError:
229
+ return False
230
+ except Exception:
231
+ return False
@@ -0,0 +1,454 @@
1
+ """
2
+ Docker deployment functionality.
3
+ """
4
+ import subprocess
5
+ import json
6
+ from typing import Optional, Dict
7
+ from pathlib import Path
8
+ from .models import DockerConfig, DeployResult, DeployStatus, DestroyResult, ServiceState
9
+
10
+
11
+ def generate_dockerfile(agents_file: str, config: Optional[DockerConfig] = None) -> str:
12
+ """
13
+ Generate Dockerfile for agents.
14
+
15
+ Args:
16
+ agents_file: Path to agents.yaml file
17
+ config: Docker configuration
18
+
19
+ Returns:
20
+ Dockerfile content as string
21
+ """
22
+ if config is None:
23
+ config = DockerConfig()
24
+
25
+ # Build expose statements
26
+ expose_lines = "\n".join([f"EXPOSE {port}" for port in config.expose])
27
+
28
+ dockerfile = f"""FROM {config.base_image}
29
+
30
+ WORKDIR /app
31
+
32
+ # Copy application files
33
+ COPY {agents_file} /app/{agents_file}
34
+ COPY . /app/
35
+
36
+ # Install dependencies
37
+ RUN pip install --no-cache-dir praisonai flask flask-cors gunicorn
38
+
39
+ # Expose ports
40
+ {expose_lines}
41
+
42
+ # Health check
43
+ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \\
44
+ CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:{config.expose[0]}/health')" || exit 1
45
+
46
+ # Run the application
47
+ CMD ["gunicorn", "-b", "0.0.0.0:{config.expose[0]}", "-w", "1", "api_server:app"]
48
+ """
49
+
50
+ return dockerfile
51
+
52
+
53
+ def check_docker_installed() -> bool:
54
+ """
55
+ Check if Docker is installed and available.
56
+
57
+ Returns:
58
+ True if Docker is available, False otherwise
59
+ """
60
+ try:
61
+ result = subprocess.run(
62
+ ['docker', '--version'],
63
+ capture_output=True,
64
+ timeout=5
65
+ )
66
+ return result.returncode == 0
67
+ except (FileNotFoundError, subprocess.TimeoutExpired):
68
+ return False
69
+
70
+
71
+ def build_docker_image(config: DockerConfig, build_context: str = ".") -> DeployResult:
72
+ """
73
+ Build Docker image.
74
+
75
+ Args:
76
+ config: Docker configuration
77
+ build_context: Build context directory
78
+
79
+ Returns:
80
+ DeployResult with build information
81
+ """
82
+ try:
83
+ if not check_docker_installed():
84
+ return DeployResult(
85
+ success=False,
86
+ message="Docker not installed",
87
+ error="Docker is required for Docker deployment"
88
+ )
89
+
90
+ # Build image tag
91
+ image_tag = f"{config.image_name}:{config.tag}"
92
+ if config.registry:
93
+ image_tag = f"{config.registry}/{image_tag}"
94
+
95
+ # Build command
96
+ cmd = ['docker', 'build', '-t', image_tag]
97
+
98
+ # Add build args if provided
99
+ if config.build_args:
100
+ for key, value in config.build_args.items():
101
+ cmd.extend(['--build-arg', f"{key}={value}"])
102
+
103
+ cmd.append(build_context)
104
+
105
+ print(f"🐳 Building Docker image: {image_tag}")
106
+
107
+ # Run build
108
+ result = subprocess.run(
109
+ cmd,
110
+ capture_output=True,
111
+ text=True
112
+ )
113
+
114
+ if result.returncode == 0:
115
+ return DeployResult(
116
+ success=True,
117
+ message=f"Docker image built successfully: {image_tag}",
118
+ metadata={"image": image_tag, "tag": config.tag}
119
+ )
120
+ else:
121
+ return DeployResult(
122
+ success=False,
123
+ message="Docker build failed",
124
+ error=result.stderr
125
+ )
126
+
127
+ except Exception as e:
128
+ return DeployResult(
129
+ success=False,
130
+ message="Docker build failed",
131
+ error=str(e)
132
+ )
133
+
134
+
135
+ def run_docker_container(
136
+ config: DockerConfig,
137
+ env_vars: Optional[Dict[str, str]] = None,
138
+ detached: bool = True
139
+ ) -> DeployResult:
140
+ """
141
+ Run Docker container.
142
+
143
+ Args:
144
+ config: Docker configuration
145
+ env_vars: Environment variables to pass to container
146
+ detached: Run in detached mode
147
+
148
+ Returns:
149
+ DeployResult with container information
150
+ """
151
+ try:
152
+ # Build image tag
153
+ image_tag = f"{config.image_name}:{config.tag}"
154
+ if config.registry:
155
+ image_tag = f"{config.registry}/{image_tag}"
156
+
157
+ # Build run command
158
+ cmd = ['docker', 'run']
159
+
160
+ if detached:
161
+ cmd.append('-d')
162
+
163
+ # Add port mappings
164
+ for port in config.expose:
165
+ cmd.extend(['-p', f"{port}:{port}"])
166
+
167
+ # Add environment variables
168
+ if env_vars:
169
+ for key, value in env_vars.items():
170
+ cmd.extend(['-e', f"{key}={value}"])
171
+
172
+ # Add container name
173
+ container_name = f"{config.image_name}-{config.tag}".replace(':', '-')
174
+ cmd.extend(['--name', container_name])
175
+
176
+ cmd.append(image_tag)
177
+
178
+ print(f"🚀 Starting Docker container: {container_name}")
179
+
180
+ # Run container
181
+ result = subprocess.run(
182
+ cmd,
183
+ capture_output=True,
184
+ text=True
185
+ )
186
+
187
+ if result.returncode == 0:
188
+ container_id = result.stdout.strip()
189
+ url = f"http://localhost:{config.expose[0]}"
190
+
191
+ return DeployResult(
192
+ success=True,
193
+ message=f"Container started successfully: {container_name}",
194
+ url=url,
195
+ metadata={
196
+ "container_id": container_id,
197
+ "container_name": container_name,
198
+ "image": image_tag
199
+ }
200
+ )
201
+ else:
202
+ return DeployResult(
203
+ success=False,
204
+ message="Failed to start container",
205
+ error=result.stderr
206
+ )
207
+
208
+ except Exception as e:
209
+ return DeployResult(
210
+ success=False,
211
+ message="Failed to start container",
212
+ error=str(e)
213
+ )
214
+
215
+
216
+ def push_docker_image(config: DockerConfig) -> DeployResult:
217
+ """
218
+ Push Docker image to registry.
219
+
220
+ Args:
221
+ config: Docker configuration
222
+
223
+ Returns:
224
+ DeployResult with push information
225
+ """
226
+ try:
227
+ if not config.registry:
228
+ return DeployResult(
229
+ success=False,
230
+ message="No registry specified",
231
+ error="Registry URL required for push operation"
232
+ )
233
+
234
+ # Build image tag
235
+ image_tag = f"{config.registry}/{config.image_name}:{config.tag}"
236
+
237
+ print(f"📤 Pushing Docker image to registry: {image_tag}")
238
+
239
+ # Push image
240
+ result = subprocess.run(
241
+ ['docker', 'push', image_tag],
242
+ capture_output=True,
243
+ text=True
244
+ )
245
+
246
+ if result.returncode == 0:
247
+ return DeployResult(
248
+ success=True,
249
+ message=f"Image pushed successfully: {image_tag}",
250
+ metadata={"image": image_tag}
251
+ )
252
+ else:
253
+ return DeployResult(
254
+ success=False,
255
+ message="Docker push failed",
256
+ error=result.stderr
257
+ )
258
+
259
+ except Exception as e:
260
+ return DeployResult(
261
+ success=False,
262
+ message="Docker push failed",
263
+ error=str(e)
264
+ )
265
+
266
+
267
+ def stop_docker_container(container_id: str) -> bool:
268
+ """
269
+ Stop Docker container.
270
+
271
+ Args:
272
+ container_id: Container ID or name
273
+
274
+ Returns:
275
+ True if stopped successfully, False otherwise
276
+ """
277
+ try:
278
+ result = subprocess.run(
279
+ ['docker', 'stop', container_id],
280
+ capture_output=True,
281
+ timeout=30
282
+ )
283
+ return result.returncode == 0
284
+ except Exception:
285
+ return False
286
+
287
+
288
+ def save_dockerfile(agents_file: str, config: Optional[DockerConfig] = None, output_path: str = "Dockerfile"):
289
+ """
290
+ Save generated Dockerfile to file.
291
+
292
+ Args:
293
+ agents_file: Path to agents.yaml file
294
+ config: Docker configuration
295
+ output_path: Path to save Dockerfile
296
+ """
297
+ dockerfile_content = generate_dockerfile(agents_file, config)
298
+
299
+ path = Path(output_path)
300
+ with open(path, 'w') as f:
301
+ f.write(dockerfile_content)
302
+
303
+
304
+ def get_docker_container_status(config: DockerConfig) -> DeployStatus:
305
+ """
306
+ Get status of a Docker container.
307
+
308
+ Args:
309
+ config: Docker configuration
310
+
311
+ Returns:
312
+ DeployStatus with container information
313
+ """
314
+ try:
315
+ container_name = f"{config.image_name}-{config.tag}".replace(':', '-')
316
+
317
+ result = subprocess.run(
318
+ ['docker', 'inspect', container_name, '--format', '{{json .}}'],
319
+ capture_output=True,
320
+ text=True,
321
+ timeout=10
322
+ )
323
+
324
+ if result.returncode != 0:
325
+ return DeployStatus(
326
+ state=ServiceState.NOT_FOUND,
327
+ message=f"Container not found: {container_name}",
328
+ service_name=container_name,
329
+ provider="docker"
330
+ )
331
+
332
+ data = json.loads(result.stdout)
333
+ state_data = data.get('State', {})
334
+ running = state_data.get('Running', False)
335
+ status_str = state_data.get('Status', 'unknown')
336
+
337
+ # Map Docker status to ServiceState
338
+ if running:
339
+ state = ServiceState.RUNNING
340
+ elif status_str == 'exited':
341
+ state = ServiceState.STOPPED
342
+ elif status_str == 'created':
343
+ state = ServiceState.PENDING
344
+ elif status_str == 'dead':
345
+ state = ServiceState.FAILED
346
+ else:
347
+ state = ServiceState.UNKNOWN
348
+
349
+ # Get port mapping
350
+ ports = data.get('NetworkSettings', {}).get('Ports', {})
351
+ url = None
352
+ if ports and config.expose:
353
+ port_key = f"{config.expose[0]}/tcp"
354
+ if port_key in ports and ports[port_key]:
355
+ host_port = ports[port_key][0].get('HostPort')
356
+ if host_port:
357
+ url = f"http://localhost:{host_port}"
358
+
359
+ return DeployStatus(
360
+ state=state,
361
+ url=url,
362
+ message=f"Status: {status_str}",
363
+ service_name=container_name,
364
+ provider="docker",
365
+ healthy=running,
366
+ instances_running=1 if running else 0,
367
+ instances_desired=1,
368
+ created_at=data.get('Created'),
369
+ metadata={
370
+ "container_id": data.get('Id', '')[:12],
371
+ "image": data.get('Config', {}).get('Image'),
372
+ "status": status_str,
373
+ "started_at": state_data.get('StartedAt'),
374
+ "finished_at": state_data.get('FinishedAt')
375
+ }
376
+ )
377
+
378
+ except Exception as e:
379
+ return DeployStatus(
380
+ state=ServiceState.UNKNOWN,
381
+ message=f"Failed to get status: {e}",
382
+ service_name=config.image_name,
383
+ provider="docker"
384
+ )
385
+
386
+
387
+ def remove_docker_container(config: DockerConfig, force: bool = False) -> DestroyResult:
388
+ """
389
+ Remove Docker container and optionally the image.
390
+
391
+ Args:
392
+ config: Docker configuration
393
+ force: Force removal and also remove image
394
+
395
+ Returns:
396
+ DestroyResult with removal information
397
+ """
398
+ try:
399
+ container_name = f"{config.image_name}-{config.tag}".replace(':', '-')
400
+ deleted_resources = []
401
+
402
+ # Stop container first
403
+ print(f"🛑 Stopping container: {container_name}")
404
+ subprocess.run(
405
+ ['docker', 'stop', container_name],
406
+ capture_output=True,
407
+ timeout=30
408
+ )
409
+
410
+ # Remove container
411
+ print(f"🗑️ Removing container: {container_name}")
412
+ result = subprocess.run(
413
+ ['docker', 'rm', container_name] + (['-f'] if force else []),
414
+ capture_output=True,
415
+ text=True,
416
+ timeout=30
417
+ )
418
+
419
+ if result.returncode == 0:
420
+ deleted_resources.append(f"container:{container_name}")
421
+ else:
422
+ return DestroyResult(
423
+ success=False,
424
+ message="Failed to remove container",
425
+ error=result.stderr,
426
+ resources_deleted=deleted_resources
427
+ )
428
+
429
+ # Optionally remove image
430
+ if force:
431
+ image_tag = f"{config.image_name}:{config.tag}"
432
+ print(f"🗑️ Removing image: {image_tag}")
433
+ img_result = subprocess.run(
434
+ ['docker', 'rmi', image_tag, '-f'],
435
+ capture_output=True,
436
+ text=True,
437
+ timeout=30
438
+ )
439
+ if img_result.returncode == 0:
440
+ deleted_resources.append(f"image:{image_tag}")
441
+
442
+ return DestroyResult(
443
+ success=True,
444
+ message="Successfully removed Docker container",
445
+ resources_deleted=deleted_resources,
446
+ metadata={"container_name": container_name}
447
+ )
448
+
449
+ except Exception as e:
450
+ return DestroyResult(
451
+ success=False,
452
+ message="Failed to remove Docker resources",
453
+ error=str(e)
454
+ )