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,67 @@
1
+ """
2
+ Async Jobs API for PraisonAI.
3
+
4
+ Provides HTTP API endpoints for long-running agent tasks:
5
+ - Submit jobs (POST /api/v1/runs)
6
+ - Check status (GET /api/v1/runs/{job_id})
7
+ - Get results (GET /api/v1/runs/{job_id}/result)
8
+ - Cancel jobs (POST /api/v1/runs/{job_id}/cancel)
9
+ - Stream progress (GET /api/v1/runs/{job_id}/stream)
10
+
11
+ Zero Performance Impact:
12
+ - All imports are lazy loaded via __getattr__
13
+ - Server only starts when explicitly requested
14
+ - No overhead when not in use
15
+
16
+ Usage:
17
+ # Start the jobs server
18
+ praisonai serve --port 8005
19
+
20
+ # Or programmatically
21
+ from praisonai.jobs import start_server
22
+ start_server(port=8005)
23
+ """
24
+
25
+ __all__ = [
26
+ # Models
27
+ "Job",
28
+ "JobStatus",
29
+ "JobSubmitRequest",
30
+ "JobStatusResponse",
31
+ "JobResultResponse",
32
+ # Store
33
+ "JobStore",
34
+ "InMemoryJobStore",
35
+ # Executor
36
+ "JobExecutor",
37
+ # Router
38
+ "create_router",
39
+ # Server
40
+ "start_server",
41
+ "create_app",
42
+ ]
43
+
44
+
45
+ def __getattr__(name: str):
46
+ """Lazy load module components to avoid import overhead."""
47
+ if name in ("Job", "JobStatus", "JobSubmitRequest", "JobStatusResponse", "JobResultResponse"):
48
+ from .models import Job, JobStatus, JobSubmitRequest, JobStatusResponse, JobResultResponse
49
+ return locals()[name]
50
+
51
+ if name in ("JobStore", "InMemoryJobStore"):
52
+ from .store import JobStore, InMemoryJobStore
53
+ return locals()[name]
54
+
55
+ if name == "JobExecutor":
56
+ from .executor import JobExecutor
57
+ return JobExecutor
58
+
59
+ if name == "create_router":
60
+ from .router import create_router
61
+ return create_router
62
+
63
+ if name in ("start_server", "create_app"):
64
+ from .server import start_server, create_app
65
+ return locals()[name]
66
+
67
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
@@ -0,0 +1,425 @@
1
+ """
2
+ Job Executor for PraisonAI Async Jobs API.
3
+
4
+ Handles background execution of agent jobs.
5
+ """
6
+
7
+ import asyncio
8
+ import logging
9
+ import os
10
+ from typing import Optional, Callable, Any, Dict
11
+
12
+ from .models import Job, JobStatus
13
+ from .store import JobStore
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ class JobExecutor:
19
+ """
20
+ Executes jobs in the background using asyncio.
21
+
22
+ Features:
23
+ - Concurrent job execution with configurable limits
24
+ - Timeout handling
25
+ - Cancellation support
26
+ - Progress callbacks
27
+ - Webhook notifications
28
+ """
29
+
30
+ def __init__(
31
+ self,
32
+ store: JobStore,
33
+ max_concurrent: int = 10,
34
+ default_timeout: int = 3600,
35
+ cleanup_interval: int = 300
36
+ ):
37
+ self.store = store
38
+ self.max_concurrent = max_concurrent
39
+ self.default_timeout = default_timeout
40
+ self.cleanup_interval = cleanup_interval
41
+
42
+ self._semaphore: Optional[asyncio.Semaphore] = None
43
+ self._running_tasks: Dict[str, asyncio.Task] = {}
44
+ self._cleanup_task: Optional[asyncio.Task] = None
45
+ self._shutdown = False
46
+ self._progress_callbacks: Dict[str, Callable] = {}
47
+
48
+ def _get_semaphore(self) -> asyncio.Semaphore:
49
+ """Lazily create semaphore to avoid event loop issues."""
50
+ if self._semaphore is None:
51
+ self._semaphore = asyncio.Semaphore(self.max_concurrent)
52
+ return self._semaphore
53
+
54
+ async def start(self):
55
+ """Start the executor and cleanup loop."""
56
+ self._shutdown = False
57
+ self._cleanup_task = asyncio.create_task(self._cleanup_loop())
58
+ logger.info(f"JobExecutor started (max_concurrent={self.max_concurrent})")
59
+
60
+ async def stop(self):
61
+ """Stop the executor and cancel all running jobs."""
62
+ self._shutdown = True
63
+
64
+ # Cancel cleanup task
65
+ if self._cleanup_task:
66
+ self._cleanup_task.cancel()
67
+ try:
68
+ await self._cleanup_task
69
+ except asyncio.CancelledError:
70
+ pass
71
+
72
+ # Cancel all running jobs
73
+ for job_id, task in list(self._running_tasks.items()):
74
+ task.cancel()
75
+ try:
76
+ await task
77
+ except asyncio.CancelledError:
78
+ pass
79
+
80
+ self._running_tasks.clear()
81
+ logger.info("JobExecutor stopped")
82
+
83
+ async def _cleanup_loop(self):
84
+ """Periodically clean up old completed jobs."""
85
+ while not self._shutdown:
86
+ try:
87
+ await asyncio.sleep(self.cleanup_interval)
88
+ await self.store.cleanup_old_jobs(max_age_seconds=86400) # 24 hours
89
+ except asyncio.CancelledError:
90
+ break
91
+ except Exception as e:
92
+ logger.error(f"Cleanup error: {e}")
93
+
94
+ async def submit(self, job: Job) -> Job:
95
+ """
96
+ Submit a job for execution.
97
+
98
+ Args:
99
+ job: Job to execute
100
+
101
+ Returns:
102
+ The submitted job
103
+ """
104
+ # Save job to store
105
+ await self.store.save(job)
106
+
107
+ # Start execution task
108
+ task = asyncio.create_task(self._execute_job(job))
109
+ self._running_tasks[job.id] = task
110
+
111
+ # Clean up task reference when done
112
+ task.add_done_callback(lambda t: self._running_tasks.pop(job.id, None))
113
+
114
+ logger.info(f"Job submitted: {job.id}")
115
+ return job
116
+
117
+ async def cancel(self, job_id: str) -> bool:
118
+ """
119
+ Cancel a running job.
120
+
121
+ Args:
122
+ job_id: ID of job to cancel
123
+
124
+ Returns:
125
+ True if cancelled, False if not found or already complete
126
+ """
127
+ job = await self.store.get(job_id)
128
+ if not job:
129
+ return False
130
+
131
+ if job.is_terminal:
132
+ return False
133
+
134
+ # Mark as cancelled
135
+ job.cancel()
136
+ await self.store.save(job)
137
+
138
+ # Cancel the task if running
139
+ task = self._running_tasks.get(job_id)
140
+ if task and not task.done():
141
+ task.cancel()
142
+
143
+ logger.info(f"Job cancelled: {job_id}")
144
+ return True
145
+
146
+ def register_progress_callback(self, job_id: str, callback: Callable):
147
+ """Register a callback for job progress updates."""
148
+ self._progress_callbacks[job_id] = callback
149
+
150
+ def unregister_progress_callback(self, job_id: str):
151
+ """Unregister a progress callback."""
152
+ self._progress_callbacks.pop(job_id, None)
153
+
154
+ async def _execute_job(self, job: Job):
155
+ """Execute a job."""
156
+ async with self._get_semaphore():
157
+ try:
158
+ # Mark as running
159
+ job.start()
160
+ await self.store.save(job)
161
+ await self._notify_progress(job)
162
+
163
+ logger.info(f"Job started: {job.id}")
164
+
165
+ # Execute with timeout
166
+ timeout = job.timeout or self.default_timeout
167
+ result = await asyncio.wait_for(
168
+ self._run_agent(job),
169
+ timeout=timeout
170
+ )
171
+
172
+ # Mark as succeeded
173
+ job.succeed(result)
174
+ await self.store.save(job)
175
+ await self._notify_progress(job)
176
+
177
+ logger.info(f"Job succeeded: {job.id}")
178
+
179
+ # Send webhook if configured
180
+ if job.webhook_url:
181
+ await self._send_webhook(job)
182
+
183
+ except asyncio.TimeoutError:
184
+ job.fail(f"Job timed out after {job.timeout}s")
185
+ await self.store.save(job)
186
+ await self._notify_progress(job)
187
+ logger.warning(f"Job timed out: {job.id}")
188
+
189
+ except asyncio.CancelledError:
190
+ if job.status != JobStatus.CANCELLED:
191
+ job.cancel()
192
+ await self.store.save(job)
193
+ await self._notify_progress(job)
194
+ logger.info(f"Job cancelled: {job.id}")
195
+ raise
196
+
197
+ except Exception as e:
198
+ job.fail(str(e))
199
+ await self.store.save(job)
200
+ await self._notify_progress(job)
201
+ logger.error(f"Job failed: {job.id} - {e}")
202
+
203
+ # Send webhook for failures too
204
+ if job.webhook_url:
205
+ await self._send_webhook(job)
206
+
207
+ async def _run_agent(self, job: Job) -> Any:
208
+ """
209
+ Run the agent for a job.
210
+
211
+ This is the core execution logic that runs the PraisonAI agent.
212
+ Supports both direct agent execution and recipe-based execution.
213
+ """
214
+ # Check if this is a recipe job
215
+ if job.recipe_name:
216
+ return await self._run_recipe(job)
217
+
218
+ # Imports are done lazily in _run_praisonai_agents and _run_legacy_praisonai
219
+
220
+ # Determine agent configuration
221
+ agent_file = job.agent_file or "agents.yaml"
222
+ framework = job.framework or "praisonai"
223
+
224
+ # Check if we should use inline YAML
225
+ if job.agent_yaml:
226
+ # Write to temp file
227
+ import tempfile
228
+ with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
229
+ f.write(job.agent_yaml)
230
+ agent_file = f.name
231
+
232
+ # Update progress
233
+ job.update_progress(percentage=10.0, step="Initializing agent")
234
+ await self.store.save(job)
235
+ await self._notify_progress(job)
236
+
237
+ try:
238
+ # Try praisonaiagents first (preferred)
239
+ if framework == "praisonai":
240
+ result = await self._run_praisonai_agents(job, agent_file)
241
+ else:
242
+ # Use legacy PraisonAI for crewai/autogen
243
+ result = await self._run_legacy_praisonai(job, agent_file, framework)
244
+
245
+ return result
246
+
247
+ finally:
248
+ # Clean up temp file if created
249
+ if job.agent_yaml and agent_file != "agents.yaml":
250
+ try:
251
+ os.unlink(agent_file)
252
+ except Exception:
253
+ pass
254
+
255
+ async def _run_recipe(self, job: Job) -> Any:
256
+ """Run a recipe-based job."""
257
+ try:
258
+ from praisonai.recipe.bridge import resolve, execute_resolved_recipe
259
+ except ImportError:
260
+ raise RuntimeError("Recipe execution requires praisonai.recipe module")
261
+
262
+ # Update progress
263
+ job.update_progress(percentage=10.0, step=f"Resolving recipe: {job.recipe_name}")
264
+ await self.store.save(job)
265
+ await self._notify_progress(job)
266
+
267
+ # Resolve the recipe
268
+ resolved = resolve(
269
+ job.recipe_name,
270
+ input_data=job.prompt,
271
+ config=job.recipe_config or {},
272
+ session_id=job.session_id,
273
+ options={'timeout_sec': job.timeout},
274
+ )
275
+
276
+ # Update job with recipe info
277
+ job.agent_id = f"recipe:{resolved.name}"
278
+ job.run_id = resolved.run_id
279
+
280
+ # Update progress
281
+ job.update_progress(percentage=20.0, step=f"Executing recipe: {resolved.name}")
282
+ await self.store.save(job)
283
+ await self._notify_progress(job)
284
+
285
+ # Execute the recipe
286
+ loop = asyncio.get_event_loop()
287
+ result = await loop.run_in_executor(
288
+ None,
289
+ lambda: execute_resolved_recipe(resolved)
290
+ )
291
+
292
+ # Update progress
293
+ job.update_progress(percentage=90.0, step="Finalizing")
294
+ await self.store.save(job)
295
+ await self._notify_progress(job)
296
+
297
+ return result
298
+
299
+ async def _run_praisonai_agents(self, job: Job, agent_file: str) -> Any:
300
+ """Run using praisonaiagents framework."""
301
+ try:
302
+ from praisonaiagents import Agent
303
+ except ImportError:
304
+ raise RuntimeError("praisonaiagents not installed")
305
+
306
+ # Update progress
307
+ job.update_progress(percentage=20.0, step="Creating agent")
308
+ await self.store.save(job)
309
+ await self._notify_progress(job)
310
+
311
+ # Create agent
312
+ agent = Agent(
313
+ instructions="You are a helpful AI assistant.",
314
+ verbose=False
315
+ )
316
+
317
+ # Update job with agent info
318
+ job.agent_id = getattr(agent, 'name', 'agent')
319
+ job.run_id = getattr(agent, 'run_id', None)
320
+
321
+ # Update progress
322
+ job.update_progress(percentage=30.0, step="Running agent")
323
+ await self.store.save(job)
324
+ await self._notify_progress(job)
325
+
326
+ # Run the agent
327
+ loop = asyncio.get_event_loop()
328
+ result = await loop.run_in_executor(
329
+ None,
330
+ lambda: agent.start(job.prompt)
331
+ )
332
+
333
+ # Update progress
334
+ job.update_progress(percentage=90.0, step="Finalizing")
335
+ await self.store.save(job)
336
+ await self._notify_progress(job)
337
+
338
+ return result
339
+
340
+ async def _run_legacy_praisonai(self, job: Job, agent_file: str, framework: str) -> Any:
341
+ """Run using legacy PraisonAI (crewai/autogen)."""
342
+ try:
343
+ from praisonai import PraisonAI
344
+ except ImportError:
345
+ raise RuntimeError("praisonai not installed")
346
+
347
+ # Update progress
348
+ job.update_progress(percentage=20.0, step="Creating PraisonAI instance")
349
+ await self.store.save(job)
350
+ await self._notify_progress(job)
351
+
352
+ # Create PraisonAI instance
353
+ praisonai = PraisonAI(
354
+ agent_file=agent_file,
355
+ framework=framework
356
+ )
357
+
358
+ # Update progress
359
+ job.update_progress(percentage=30.0, step="Running agents")
360
+ await self.store.save(job)
361
+ await self._notify_progress(job)
362
+
363
+ # Run in executor (blocking call)
364
+ loop = asyncio.get_event_loop()
365
+ result = await loop.run_in_executor(None, praisonai.run)
366
+
367
+ # Update progress
368
+ job.update_progress(percentage=90.0, step="Finalizing")
369
+ await self.store.save(job)
370
+ await self._notify_progress(job)
371
+
372
+ return result
373
+
374
+ async def _notify_progress(self, job: Job):
375
+ """Notify progress callback if registered."""
376
+ callback = self._progress_callbacks.get(job.id)
377
+ if callback:
378
+ try:
379
+ if asyncio.iscoroutinefunction(callback):
380
+ await callback(job)
381
+ else:
382
+ callback(job)
383
+ except Exception as e:
384
+ logger.warning(f"Progress callback error for {job.id}: {e}")
385
+
386
+ async def _send_webhook(self, job: Job):
387
+ """Send webhook notification for job completion."""
388
+ if not job.webhook_url:
389
+ return
390
+
391
+ try:
392
+ import httpx
393
+
394
+ payload = {
395
+ "job_id": job.id,
396
+ "status": job.status.value,
397
+ "result": job.result if job.status == JobStatus.SUCCEEDED else None,
398
+ "error": job.error if job.status == JobStatus.FAILED else None,
399
+ "completed_at": job.completed_at.isoformat() if job.completed_at else None,
400
+ "duration_seconds": job.duration_seconds
401
+ }
402
+
403
+ async with httpx.AsyncClient(timeout=30.0) as client:
404
+ response = await client.post(
405
+ job.webhook_url,
406
+ json=payload,
407
+ headers={"Content-Type": "application/json"}
408
+ )
409
+
410
+ if response.status_code >= 400:
411
+ logger.warning(f"Webhook failed for {job.id}: {response.status_code}")
412
+ else:
413
+ logger.info(f"Webhook sent for {job.id}")
414
+
415
+ except Exception as e:
416
+ logger.error(f"Webhook error for {job.id}: {e}")
417
+
418
+ def get_stats(self) -> Dict[str, Any]:
419
+ """Get executor statistics."""
420
+ return {
421
+ "running_jobs": len(self._running_tasks),
422
+ "max_concurrent": self.max_concurrent,
423
+ "default_timeout": self.default_timeout,
424
+ "shutdown": self._shutdown
425
+ }