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,903 @@
1
+ # praisonai/agents_generator.py
2
+
3
+ import sys
4
+ from .version import __version__
5
+ import yaml, os
6
+ from rich import print
7
+ from dotenv import load_dotenv
8
+ from .auto import AutoGenerator
9
+ from .inbuilt_tools import *
10
+ from .inc import PraisonAIModel
11
+ import inspect
12
+ from pathlib import Path
13
+ import importlib
14
+ import importlib.util
15
+ import os
16
+ import logging
17
+ import re
18
+ import keyword
19
+
20
+ # Framework-specific imports with availability checks
21
+ CREWAI_AVAILABLE = False
22
+ AUTOGEN_AVAILABLE = False
23
+ AUTOGEN_V4_AVAILABLE = False
24
+ PRAISONAI_TOOLS_AVAILABLE = False
25
+ AGENTOPS_AVAILABLE = False
26
+ PRAISONAI_AVAILABLE = False
27
+
28
+ try:
29
+ from praisonaiagents import Agent as PraisonAgent, Task as PraisonTask, PraisonAIAgents
30
+ PRAISONAI_AVAILABLE = True
31
+ except ImportError:
32
+ pass
33
+
34
+ try:
35
+ from crewai import Agent, Task, Crew
36
+ from crewai.telemetry import Telemetry
37
+ CREWAI_AVAILABLE = True
38
+ except ImportError:
39
+ pass
40
+
41
+ try:
42
+ import autogen
43
+ AUTOGEN_AVAILABLE = True
44
+ except ImportError:
45
+ pass
46
+
47
+ try:
48
+ from autogen_agentchat.agents import AssistantAgent as AutoGenV4AssistantAgent
49
+ from autogen_ext.models.openai import OpenAIChatCompletionClient
50
+ from autogen_agentchat.teams import RoundRobinGroupChat
51
+ from autogen_agentchat.conditions import TextMentionTermination, MaxMessageTermination
52
+ from autogen_agentchat.messages import TextMessage
53
+ from autogen_core import CancellationToken
54
+ AUTOGEN_V4_AVAILABLE = True
55
+ except ImportError:
56
+ pass
57
+
58
+ try:
59
+ import agentops
60
+ AGENTOPS_AVAILABLE = True
61
+ AGENTOPS_API_KEY = os.getenv("AGENTOPS_API_KEY")
62
+ if not AGENTOPS_API_KEY:
63
+ AGENTOPS_AVAILABLE = False
64
+ except ImportError:
65
+ pass
66
+
67
+ # Only try to import praisonai_tools if either CrewAI or AutoGen is available
68
+ if CREWAI_AVAILABLE or AUTOGEN_AVAILABLE or PRAISONAI_AVAILABLE:
69
+ try:
70
+ from praisonai_tools import (
71
+ CodeDocsSearchTool, CSVSearchTool, DirectorySearchTool, DOCXSearchTool, DirectoryReadTool,
72
+ FileReadTool, TXTSearchTool, JSONSearchTool, MDXSearchTool, PDFSearchTool, RagTool,
73
+ ScrapeElementFromWebsiteTool, ScrapeWebsiteTool, WebsiteSearchTool, XMLSearchTool,
74
+ YoutubeChannelSearchTool, YoutubeVideoSearchTool, BaseTool
75
+ )
76
+ PRAISONAI_TOOLS_AVAILABLE = True
77
+ except ImportError:
78
+ # If import fails, define BaseTool as a simple base class
79
+ class BaseTool:
80
+ pass
81
+
82
+ os.environ["OTEL_SDK_DISABLED"] = "true"
83
+
84
+ def noop(*args, **kwargs):
85
+ pass
86
+
87
+ def sanitize_agent_name_for_autogen_v4(name):
88
+ """
89
+ Sanitize agent name to be a valid Python identifier for AutoGen v0.4.
90
+
91
+ Args:
92
+ name (str): The original agent name
93
+
94
+ Returns:
95
+ str: A valid Python identifier
96
+ """
97
+ # Convert to string and replace invalid characters with underscores
98
+ sanitized = re.sub(r'[^a-zA-Z0-9_]', '_', str(name))
99
+
100
+ # Collapse only very excessive underscores (5 or more) to reduce extreme cases
101
+ sanitized = re.sub(r'_{5,}', '_', sanitized)
102
+
103
+ # Remove trailing underscores only if not part of a dunder pattern and only if singular
104
+ if sanitized.endswith('_') and not sanitized.endswith('__') and sanitized != '_':
105
+ sanitized = sanitized.rstrip('_')
106
+
107
+ # Ensure it starts with a letter or underscore (not a digit)
108
+ if sanitized and sanitized[0].isdigit():
109
+ sanitized = 'agent_' + sanitized
110
+
111
+ # Handle empty string or only invalid characters (including single underscore from all invalid chars)
112
+ if not sanitized or sanitized == '_':
113
+ sanitized = 'agent'
114
+
115
+ # Check if it's a Python keyword and append underscore if so
116
+ if keyword.iskeyword(sanitized):
117
+ sanitized += '_'
118
+
119
+ return sanitized
120
+
121
+ def disable_crewai_telemetry():
122
+ if CREWAI_AVAILABLE:
123
+ for attr in dir(Telemetry):
124
+ if callable(getattr(Telemetry, attr)) and not attr.startswith("__"):
125
+ setattr(Telemetry, attr, noop)
126
+
127
+ # Only disable telemetry if CrewAI is available
128
+ if CREWAI_AVAILABLE:
129
+ disable_crewai_telemetry()
130
+
131
+ class AgentsGenerator:
132
+ def __init__(self, agent_file, framework, config_list, log_level=None, agent_callback=None, task_callback=None, agent_yaml=None, tools=None):
133
+ """
134
+ Initialize the AgentsGenerator object.
135
+
136
+ Parameters:
137
+ agent_file (str): The path to the agent file.
138
+ framework (str): The framework to be used for the agents.
139
+ config_list (list): A list of configurations for the agents.
140
+ log_level (int, optional): The logging level to use. Defaults to logging.INFO.
141
+ agent_callback (callable, optional): A callback function to be executed after each agent step.
142
+ task_callback (callable, optional): A callback function to be executed after each tool run.
143
+ agent_yaml (str, optional): The content of the YAML file. Defaults to None.
144
+ tools (dict, optional): A dictionary containing the tools to be used for the agents. Defaults to None.
145
+
146
+ Attributes:
147
+ agent_file (str): The path to the agent file.
148
+ framework (str): The framework to be used for the agents.
149
+ config_list (list): A list of configurations for the agents.
150
+ log_level (int): The logging level to use.
151
+ agent_callback (callable, optional): A callback function to be executed after each agent step.
152
+ task_callback (callable, optional): A callback function to be executed after each tool run.
153
+ tools (dict): A dictionary containing the tools to be used for the agents.
154
+ """
155
+ self.agent_file = agent_file
156
+ self.framework = framework
157
+ self.config_list = config_list
158
+ self.log_level = log_level
159
+ self.agent_callback = agent_callback
160
+ self.task_callback = task_callback
161
+ self.agent_yaml = agent_yaml
162
+ self.tools = tools or [] # Store tool class names as a list
163
+ self.log_level = log_level or logging.getLogger().getEffectiveLevel()
164
+ if self.log_level == logging.NOTSET:
165
+ self.log_level = os.environ.get('LOGLEVEL', 'INFO').upper()
166
+
167
+ logging.basicConfig(level=self.log_level, format='%(asctime)s - %(levelname)s - %(message)s')
168
+ self.logger = logging.getLogger(__name__)
169
+ self.logger.setLevel(self.log_level)
170
+
171
+ # Validate framework availability
172
+ if framework == "crewai" and not CREWAI_AVAILABLE:
173
+ raise ImportError("CrewAI is not installed. Please install it with 'pip install praisonai[crewai]'")
174
+ elif framework == "autogen" and not (AUTOGEN_AVAILABLE or AUTOGEN_V4_AVAILABLE):
175
+ raise ImportError("AutoGen is not installed. Please install it with 'pip install praisonai[autogen]' for v0.2 or 'pip install praisonai[autogen-v4]' for v0.4")
176
+ elif framework == "praisonai" and not PRAISONAI_AVAILABLE:
177
+ raise ImportError("PraisonAI is not installed. Please install it with 'pip install praisonaiagents'")
178
+
179
+ def is_function_or_decorated(self, obj):
180
+ """
181
+ Checks if the given object is a function or has a __call__ method.
182
+
183
+ Parameters:
184
+ obj (object): The object to be checked.
185
+
186
+ Returns:
187
+ bool: True if the object is a function or has a __call__ method, False otherwise.
188
+ """
189
+ return inspect.isfunction(obj) or hasattr(obj, '__call__')
190
+
191
+ def load_tools_from_module(self, module_path):
192
+ """
193
+ Loads tools from a specified module path.
194
+
195
+ Parameters:
196
+ module_path (str): The path to the module containing the tools.
197
+
198
+ Returns:
199
+ dict: A dictionary containing the names of the tools as keys and the corresponding functions or objects as values.
200
+
201
+ Raises:
202
+ FileNotFoundError: If the specified module path does not exist.
203
+ """
204
+ spec = importlib.util.spec_from_file_location("tools_module", module_path)
205
+ module = importlib.util.module_from_spec(spec)
206
+ spec.loader.exec_module(module)
207
+ return {name: obj for name, obj in inspect.getmembers(module, self.is_function_or_decorated)}
208
+
209
+ def load_tools_from_module_class(self, module_path):
210
+ """
211
+ Loads tools from a specified module path containing classes that inherit from BaseTool
212
+ or are part of langchain_community.tools package.
213
+ """
214
+ spec = importlib.util.spec_from_file_location("tools_module", module_path)
215
+ module = importlib.util.module_from_spec(spec)
216
+ try:
217
+ spec.loader.exec_module(module)
218
+ return {name: obj() for name, obj in inspect.getmembers(module,
219
+ lambda x: inspect.isclass(x) and (
220
+ x.__module__.startswith('langchain_community.tools') or
221
+ (PRAISONAI_TOOLS_AVAILABLE and issubclass(x, BaseTool))
222
+ ) and x is not BaseTool)}
223
+ except ImportError as e:
224
+ self.logger.warning(f"Error loading tools from {module_path}: {e}")
225
+ return {}
226
+
227
+ def load_tools_from_package(self, package_path):
228
+ """
229
+ Loads tools from a specified package path containing modules with functions or classes.
230
+
231
+ Parameters:
232
+ package_path (str): The path to the package containing the tools.
233
+
234
+ Returns:
235
+ dict: A dictionary containing the names of the tools as keys and the corresponding initialized instances of the classes as values.
236
+
237
+ Raises:
238
+ FileNotFoundError: If the specified package path does not exist.
239
+
240
+ This function iterates through all the .py files in the specified package path, excluding those that start with "__". For each file, it imports the corresponding module and checks if it contains any functions or classes that can be loaded as tools. The function then returns a dictionary containing the names of the tools as keys and the corresponding initialized instances of the classes as values.
241
+ """
242
+ tools_dict = {}
243
+ for module_file in os.listdir(package_path):
244
+ if module_file.endswith('.py') and not module_file.startswith('__'):
245
+ module_name = f"{package_path.name}.{module_file[:-3]}" # Remove .py for import
246
+ module = importlib.import_module(module_name)
247
+ for name, obj in inspect.getmembers(module, self.is_function_or_decorated):
248
+ tools_dict[name] = obj
249
+ return tools_dict
250
+
251
+ def load_tools_from_tools_py(self):
252
+ """
253
+ Imports and returns all contents from tools.py file.
254
+ Also adds the tools to the global namespace.
255
+
256
+ Returns:
257
+ list: A list of callable functions with proper formatting
258
+ """
259
+ tools_list = []
260
+ try:
261
+ # Try to import tools.py from current directory
262
+ spec = importlib.util.spec_from_file_location("tools", "tools.py")
263
+ self.logger.debug(f"Spec: {spec}")
264
+ if spec is None:
265
+ self.logger.debug("tools.py not found in current directory")
266
+ return tools_list
267
+
268
+ module = importlib.util.module_from_spec(spec)
269
+ spec.loader.exec_module(module)
270
+
271
+ # Get all module attributes except private ones and classes
272
+ for name, obj in inspect.getmembers(module):
273
+ if (not name.startswith('_') and
274
+ callable(obj) and
275
+ not inspect.isclass(obj)):
276
+ # Add the function to global namespace
277
+ globals()[name] = obj
278
+ # Add to tools list
279
+ tools_list.append(obj)
280
+ self.logger.debug(f"Loaded and globalized tool function: {name}")
281
+
282
+ self.logger.debug(f"Loaded {len(tools_list)} tool functions from tools.py")
283
+ self.logger.debug(f"Tools list: {tools_list}")
284
+
285
+ except FileNotFoundError:
286
+ self.logger.debug("tools.py not found in current directory")
287
+ except Exception as e:
288
+ self.logger.warning(f"Error loading tools from tools.py: {e}")
289
+
290
+ return tools_list
291
+
292
+ def generate_crew_and_kickoff(self):
293
+ """
294
+ Generates a crew of agents and initiates tasks based on the provided configuration.
295
+
296
+ Parameters:
297
+ agent_file (str): The path to the agent file.
298
+ framework (str): The framework to be used for the agents.
299
+ config_list (list): A list of configurations for the agents.
300
+
301
+ Returns:
302
+ str: The output of the tasks performed by the crew of agents.
303
+
304
+ Raises:
305
+ FileNotFoundError: If the specified agent file does not exist.
306
+
307
+ This function first loads the agent configuration from the specified file. It then initializes the tools required for the agents based on the specified framework. If the specified framework is "autogen", it loads the LLM configuration dynamically and creates an AssistantAgent for each role in the configuration. It then adds tools to the agents if specified in the configuration. Finally, it prepares tasks for the agents based on the configuration and initiates the tasks using the crew of agents. If the specified framework is not "autogen", it creates a crew of agents and initiates tasks based on the configuration.
308
+ """
309
+ if self.agent_yaml:
310
+ config = yaml.safe_load(self.agent_yaml)
311
+ else:
312
+ if self.agent_file == '/app/api:app' or self.agent_file == 'api:app':
313
+ self.agent_file = 'agents.yaml'
314
+ try:
315
+ with open(self.agent_file, 'r') as f:
316
+ config = yaml.safe_load(f)
317
+ except FileNotFoundError:
318
+ print(f"File not found: {self.agent_file}")
319
+ return
320
+
321
+ # Check if this is a workflow-mode YAML (process: workflow or has steps section)
322
+ process_type = config.get('process', 'sequential')
323
+ has_steps = 'steps' in config
324
+ has_workflow_config = 'workflow' in config
325
+
326
+ if process_type == 'workflow' or (has_steps and has_workflow_config):
327
+ # Route to YAMLWorkflowParser for advanced workflow patterns
328
+ return self._run_yaml_workflow(config)
329
+
330
+ # Get workflow input: 'input' is canonical, 'topic' is alias for backward compatibility
331
+ topic = config.get('input', config.get('topic', ''))
332
+ tools_dict = {}
333
+
334
+ # Only try to use praisonai_tools if it's available and needed
335
+ if PRAISONAI_TOOLS_AVAILABLE and (CREWAI_AVAILABLE or AUTOGEN_AVAILABLE or PRAISONAI_AVAILABLE):
336
+ tools_dict = {
337
+ 'CodeDocsSearchTool': CodeDocsSearchTool(),
338
+ 'CSVSearchTool': CSVSearchTool(),
339
+ 'DirectorySearchTool': DirectorySearchTool(),
340
+ 'DOCXSearchTool': DOCXSearchTool(),
341
+ 'DirectoryReadTool': DirectoryReadTool(),
342
+ 'FileReadTool': FileReadTool(),
343
+ 'TXTSearchTool': TXTSearchTool(),
344
+ 'JSONSearchTool': JSONSearchTool(),
345
+ 'MDXSearchTool': MDXSearchTool(),
346
+ 'PDFSearchTool': PDFSearchTool(),
347
+ 'RagTool': RagTool(),
348
+ 'ScrapeElementFromWebsiteTool': ScrapeElementFromWebsiteTool(),
349
+ 'ScrapeWebsiteTool': ScrapeWebsiteTool(),
350
+ 'WebsiteSearchTool': WebsiteSearchTool(),
351
+ 'XMLSearchTool': XMLSearchTool(),
352
+ 'YoutubeChannelSearchTool': YoutubeChannelSearchTool(),
353
+ 'YoutubeVideoSearchTool': YoutubeVideoSearchTool(),
354
+ }
355
+
356
+ # Add tools from class names
357
+ for tool_class in self.tools:
358
+ if isinstance(tool_class, type) and issubclass(tool_class, BaseTool):
359
+ tool_name = tool_class.__name__
360
+ tools_dict[tool_name] = tool_class()
361
+ self.logger.debug(f"Added tool: {tool_name}")
362
+
363
+ root_directory = os.getcwd()
364
+ tools_py_path = os.path.join(root_directory, 'tools.py')
365
+ tools_dir_path = Path(root_directory) / 'tools'
366
+
367
+ if os.path.isfile(tools_py_path):
368
+ tools_dict.update(self.load_tools_from_module_class(tools_py_path))
369
+ self.logger.debug("tools.py exists in the root directory. Loading tools.py and skipping tools folder.")
370
+ elif tools_dir_path.is_dir():
371
+ tools_dict.update(self.load_tools_from_module_class(tools_dir_path))
372
+ self.logger.debug("tools folder exists in the root directory")
373
+
374
+ framework = self.framework or config.get('framework')
375
+
376
+ if framework == "autogen":
377
+ if not (AUTOGEN_AVAILABLE or AUTOGEN_V4_AVAILABLE):
378
+ raise ImportError("AutoGen is not installed. Please install it with 'pip install praisonai[autogen]' for v0.2 or 'pip install praisonai[autogen-v4]' for v0.4")
379
+
380
+ # Choose autogen version based on availability and environment preference
381
+ # AUTOGEN_VERSION can be set to "v0.2" or "v0.4" to force a specific version
382
+ autogen_version = os.environ.get("AUTOGEN_VERSION", "auto").lower()
383
+
384
+ use_v4 = False
385
+ if autogen_version == "v0.4" and AUTOGEN_V4_AVAILABLE:
386
+ use_v4 = True
387
+ elif autogen_version == "v0.2" and AUTOGEN_AVAILABLE:
388
+ use_v4 = False
389
+ elif autogen_version == "auto":
390
+ # Default preference: use v0.4 if available, fallback to v0.2
391
+ use_v4 = AUTOGEN_V4_AVAILABLE
392
+ else:
393
+ # Fallback to whatever is available
394
+ use_v4 = AUTOGEN_V4_AVAILABLE and not AUTOGEN_AVAILABLE
395
+
396
+ if AGENTOPS_AVAILABLE:
397
+ version_tag = "autogen-v4" if use_v4 else "autogen-v2"
398
+ agentops.init(os.environ.get("AGENTOPS_API_KEY"), default_tags=[version_tag])
399
+
400
+ if use_v4:
401
+ self.logger.info("Using AutoGen v0.4")
402
+ return self._run_autogen_v4(config, topic, tools_dict)
403
+ else:
404
+ self.logger.info("Using AutoGen v0.2")
405
+ return self._run_autogen(config, topic, tools_dict)
406
+ elif framework == "praisonai":
407
+ if not PRAISONAI_AVAILABLE:
408
+ raise ImportError("PraisonAI is not installed. Please install it with 'pip install praisonaiagents'")
409
+ if AGENTOPS_AVAILABLE:
410
+ agentops.init(os.environ.get("AGENTOPS_API_KEY"), default_tags=["praisonai"])
411
+ return self._run_praisonai(config, topic, tools_dict)
412
+ else: # framework=crewai
413
+ if not CREWAI_AVAILABLE:
414
+ raise ImportError("CrewAI is not installed. Please install it with 'pip install praisonai[crewai]'")
415
+ if AGENTOPS_AVAILABLE:
416
+ agentops.init(os.environ.get("AGENTOPS_API_KEY"), default_tags=["crewai"])
417
+ return self._run_crewai(config, topic, tools_dict)
418
+
419
+ def _run_yaml_workflow(self, config):
420
+ """
421
+ Run a YAML workflow using the YAMLWorkflowParser.
422
+
423
+ This method handles agents.yaml files that have:
424
+ - process: workflow
425
+ - steps section with workflow patterns (route, parallel, loop, repeat)
426
+
427
+ Args:
428
+ config (dict): The parsed YAML configuration
429
+
430
+ Returns:
431
+ str: Result of the workflow execution
432
+ """
433
+ if not PRAISONAI_AVAILABLE:
434
+ raise ImportError("PraisonAI is not installed. Please install it with 'pip install praisonaiagents'")
435
+
436
+ try:
437
+ from praisonaiagents.workflows import YAMLWorkflowParser
438
+ except ImportError:
439
+ raise ImportError("YAMLWorkflowParser not available. Please update praisonaiagents.")
440
+
441
+ # Ensure name is present (YAMLWorkflowParser handles roles->agents conversion)
442
+ if 'name' not in config:
443
+ config['name'] = config.get('topic', 'Workflow')
444
+
445
+ # Pass model from config_list to workflow as default_llm
446
+ if self.config_list and self.config_list[0].get('model'):
447
+ model_from_cli = self.config_list[0]['model']
448
+ # Set default_llm in workflow config if not already set
449
+ if 'workflow' not in config:
450
+ config['workflow'] = {}
451
+ if 'default_llm' not in config['workflow']:
452
+ config['workflow']['default_llm'] = model_from_cli
453
+
454
+ # Convert config back to YAML string for parser
455
+ # Note: YAMLWorkflowParser handles 'roles' to 'agents' conversion internally
456
+ import yaml as yaml_module
457
+ yaml_content = yaml_module.dump(config, default_flow_style=False)
458
+
459
+ # Parse and execute
460
+ parser = YAMLWorkflowParser()
461
+ workflow = parser.parse_string(yaml_content)
462
+
463
+ # Get input: 'input' is canonical, 'topic' is alias for backward compatibility
464
+ input_data = config.get('input', config.get('topic', ''))
465
+
466
+ # Execute workflow
467
+ self.logger.debug(f"Running workflow: {workflow.name}")
468
+ result = workflow.start(input_data)
469
+
470
+ if result.get("status") == "completed":
471
+ return result.get("output", "Workflow completed successfully")
472
+ else:
473
+ return f"Workflow failed: {result.get('error', 'Unknown error')}"
474
+
475
+ def _run_autogen(self, config, topic, tools_dict):
476
+ """
477
+ Run agents using the AutoGen framework.
478
+
479
+ Args:
480
+ config (dict): Configuration dictionary
481
+ topic (str): The topic to process
482
+ tools_dict (dict): Dictionary of available tools
483
+
484
+ Returns:
485
+ str: Result of the agent interactions
486
+ """
487
+ llm_config = {"config_list": self.config_list}
488
+
489
+ # Set up user proxy agent
490
+ user_proxy = autogen.UserProxyAgent(
491
+ name="User",
492
+ human_input_mode="NEVER",
493
+ is_termination_msg=lambda x: (x.get("content") or "").rstrip().rstrip(".").lower().endswith("terminate") or "TERMINATE" in (x.get("content") or ""),
494
+ code_execution_config={
495
+ "work_dir": "coding",
496
+ "use_docker": False,
497
+ }
498
+ )
499
+
500
+ agents = {}
501
+ tasks = []
502
+
503
+ # Create agents and tasks from config
504
+ for role, details in config['roles'].items():
505
+ agent_name = details['role'].format(topic=topic).replace("{topic}", topic)
506
+ agent_goal = details['goal'].format(topic=topic)
507
+
508
+ # Create AutoGen assistant agent
509
+ agents[role] = autogen.AssistantAgent(
510
+ name=agent_name,
511
+ llm_config=llm_config,
512
+ system_message=details['backstory'].format(topic=topic) +
513
+ ". Must Reply \"TERMINATE\" in the end when everything is done.",
514
+ )
515
+
516
+ # Add tools to agent if specified
517
+ for tool in details.get('tools', []):
518
+ if tool in tools_dict:
519
+ try:
520
+ tool_class = globals()[f'autogen_{type(tools_dict[tool]).__name__}']
521
+ self.logger.debug(f"Found {tool_class.__name__} for {tool}")
522
+ tool_class(agents[role], user_proxy)
523
+ except KeyError:
524
+ self.logger.warning(f"Warning: autogen_{type(tools_dict[tool]).__name__} function not found. Skipping this tool.")
525
+ continue
526
+
527
+ # Prepare tasks
528
+ for task_name, task_details in details.get('tasks', {}).items():
529
+ description_filled = task_details['description'].format(topic=topic)
530
+ expected_output_filled = task_details['expected_output'].format(topic=topic)
531
+
532
+ chat_task = {
533
+ "recipient": agents[role],
534
+ "message": description_filled,
535
+ "summary_method": "last_msg",
536
+ }
537
+ tasks.append(chat_task)
538
+
539
+ # Execute tasks
540
+ response = user_proxy.initiate_chats(tasks)
541
+ result = "### Output ###\n" + response[-1].summary if hasattr(response[-1], 'summary') else ""
542
+
543
+ if AGENTOPS_AVAILABLE:
544
+ agentops.end_session("Success")
545
+
546
+ return result
547
+
548
+ def _run_autogen_v4(self, config, topic, tools_dict):
549
+ """
550
+ Run agents using the AutoGen v0.4 framework with async, event-driven architecture.
551
+
552
+ Args:
553
+ config (dict): Configuration dictionary
554
+ topic (str): The topic to process
555
+ tools_dict (dict): Dictionary of available tools
556
+
557
+ Returns:
558
+ str: Result of the agent interactions
559
+ """
560
+ import asyncio
561
+
562
+ async def run_autogen_v4_async():
563
+ # Create model client for v0.4
564
+ model_config = self.config_list[0] if self.config_list else {}
565
+ model_client = OpenAIChatCompletionClient(
566
+ model=model_config.get('model', 'gpt-5-nano'),
567
+ api_key=model_config.get('api_key', os.environ.get("OPENAI_API_KEY")),
568
+ base_url=model_config.get('base_url', "https://api.openai.com/v1")
569
+ )
570
+
571
+ agents = []
572
+ combined_tasks = []
573
+
574
+ # Create agents from config
575
+ for role, details in config['roles'].items():
576
+ # For AutoGen v0.4, ensure agent name is a valid Python identifier
577
+ agent_name = details['role'].format(topic=topic).replace("{topic}", topic)
578
+ agent_name = sanitize_agent_name_for_autogen_v4(agent_name)
579
+ backstory = details['backstory'].format(topic=topic)
580
+
581
+ # Convert tools for v0.4 - simplified tool passing
582
+ agent_tools = []
583
+ for tool_name in details.get('tools', []):
584
+ if tool_name in tools_dict:
585
+ tool_instance = tools_dict[tool_name]
586
+ # For v0.4, we can pass the tool's run method directly if it's callable
587
+ if hasattr(tool_instance, 'run') and callable(tool_instance.run):
588
+ agent_tools.append(tool_instance.run)
589
+
590
+ # Create v0.4 AssistantAgent
591
+ assistant = AutoGenV4AssistantAgent(
592
+ name=agent_name,
593
+ system_message=backstory + ". Must reply with 'TERMINATE' when the task is complete.",
594
+ model_client=model_client,
595
+ tools=agent_tools,
596
+ reflect_on_tool_use=True
597
+ )
598
+
599
+ agents.append(assistant)
600
+
601
+ # Collect all task descriptions for sequential execution
602
+ for task_name, task_details in details.get('tasks', {}).items():
603
+ description_filled = task_details['description'].format(topic=topic)
604
+ combined_tasks.append(description_filled)
605
+
606
+ if not agents:
607
+ return "No agents created from configuration"
608
+
609
+ # Create termination conditions
610
+ text_termination = TextMentionTermination("TERMINATE")
611
+ max_messages_termination = MaxMessageTermination(max_messages=20)
612
+ termination_condition = text_termination | max_messages_termination
613
+
614
+ # Create RoundRobinGroupChat for parallel/sequential execution
615
+ group_chat = RoundRobinGroupChat(
616
+ agents,
617
+ termination_condition=termination_condition,
618
+ max_turns=len(agents) * 3 # Allow multiple rounds
619
+ )
620
+
621
+ # Combine all tasks into a single task description
622
+ task_description = f"Topic: {topic}\n\nTasks to complete:\n" + "\n".join(
623
+ f"{i+1}. {task}" for i, task in enumerate(combined_tasks)
624
+ )
625
+
626
+ # Run the group chat
627
+ try:
628
+ result = await group_chat.run(task=task_description)
629
+
630
+ # Extract the final message content
631
+ if result.messages:
632
+ final_message = result.messages[-1]
633
+ if hasattr(final_message, 'content'):
634
+ return f"### AutoGen v0.4 Output ###\n{final_message.content}"
635
+ else:
636
+ return f"### AutoGen v0.4 Output ###\n{str(final_message)}"
637
+ else:
638
+ return "### AutoGen v0.4 Output ###\nNo messages generated"
639
+
640
+ except Exception as e:
641
+ self.logger.error(f"Error in AutoGen v0.4 execution: {str(e)}")
642
+ return f"### AutoGen v0.4 Error ###\n{str(e)}"
643
+
644
+ finally:
645
+ # Close the model client
646
+ await model_client.close()
647
+
648
+ # Run the async function
649
+ try:
650
+ return asyncio.run(run_autogen_v4_async())
651
+ except Exception as e:
652
+ self.logger.error(f"Error running AutoGen v0.4: {str(e)}")
653
+ return f"### AutoGen v0.4 Error ###\n{str(e)}"
654
+
655
+ def _run_crewai(self, config, topic, tools_dict):
656
+ """
657
+ Run agents using the CrewAI framework.
658
+
659
+ Args:
660
+ config (dict): Configuration dictionary
661
+ topic (str): The topic to process
662
+ tools_dict (dict): Dictionary of available tools
663
+
664
+ Returns:
665
+ str: Result of the agent interactions
666
+ """
667
+ agents = {}
668
+ tasks = []
669
+ tasks_dict = {}
670
+
671
+ # Create agents from config
672
+ for role, details in config['roles'].items():
673
+ role_filled = details['role'].format(topic=topic)
674
+ goal_filled = details['goal'].format(topic=topic)
675
+ backstory_filled = details['backstory'].format(topic=topic)
676
+
677
+ # Get agent tools
678
+ agent_tools = [tools_dict[tool] for tool in details.get('tools', [])
679
+ if tool in tools_dict]
680
+
681
+ # Configure LLM
682
+ llm_model = details.get('llm')
683
+ if llm_model:
684
+ llm = PraisonAIModel(
685
+ model=llm_model.get("model") or os.environ.get("MODEL_NAME") or "openai/gpt-5-nano",
686
+ base_url=self.config_list[0].get('base_url') if self.config_list else None,
687
+ api_key=self.config_list[0].get('api_key') if self.config_list else None
688
+ ).get_model()
689
+ else:
690
+ llm = PraisonAIModel(
691
+ base_url=self.config_list[0].get('base_url') if self.config_list else None,
692
+ api_key=self.config_list[0].get('api_key') if self.config_list else None
693
+ ).get_model()
694
+
695
+ # Configure function calling LLM
696
+ function_calling_llm_model = details.get('function_calling_llm')
697
+ if function_calling_llm_model:
698
+ function_calling_llm = PraisonAIModel(
699
+ model=function_calling_llm_model.get("model") or os.environ.get("MODEL_NAME") or "openai/gpt-5-nano",
700
+ base_url=self.config_list[0].get('base_url') if self.config_list else None,
701
+ api_key=self.config_list[0].get('api_key') if self.config_list else None
702
+ ).get_model()
703
+ else:
704
+ function_calling_llm = PraisonAIModel(
705
+ base_url=self.config_list[0].get('base_url') if self.config_list else None,
706
+ api_key=self.config_list[0].get('api_key') if self.config_list else None
707
+ ).get_model()
708
+
709
+ # Create CrewAI agent
710
+ agent = Agent(
711
+ role=role_filled,
712
+ goal=goal_filled,
713
+ backstory=backstory_filled,
714
+ tools=agent_tools,
715
+ allow_delegation=details.get('allow_delegation', False),
716
+ llm=llm,
717
+ function_calling_llm=function_calling_llm,
718
+ max_iter=details.get('max_iter') or 15,
719
+ max_rpm=details.get('max_rpm') or None,
720
+ max_execution_time=details.get('max_execution_time') or None,
721
+ verbose=details.get('verbose', True),
722
+ cache=details.get('cache', True),
723
+ system_template=details.get('system_template') or None,
724
+ prompt_template=details.get('prompt_template') or None,
725
+ response_template=details.get('response_template') or None,
726
+ )
727
+
728
+ # Set agent callback if provided
729
+ if self.agent_callback:
730
+ agent.step_callback = self.agent_callback
731
+
732
+ agents[role] = agent
733
+
734
+ # Create tasks for the agent
735
+ for task_name, task_details in details.get('tasks', {}).items():
736
+ description_filled = task_details['description'].format(topic=topic)
737
+ expected_output_filled = task_details['expected_output'].format(topic=topic)
738
+
739
+ task = Task(
740
+ description=description_filled,
741
+ expected_output=expected_output_filled,
742
+ agent=agent,
743
+ tools=task_details.get('tools', []),
744
+ async_execution=task_details.get('async_execution', False),
745
+ context=[],
746
+ config=task_details.get('config', {}),
747
+ output_json=task_details.get('output_json'),
748
+ output_pydantic=task_details.get('output_pydantic'),
749
+ output_file=task_details.get('output_file', ""),
750
+ callback=task_details.get('callback'),
751
+ human_input=task_details.get('human_input', False),
752
+ create_directory=task_details.get('create_directory', False)
753
+ )
754
+
755
+ # Set task callback if provided
756
+ if self.task_callback:
757
+ task.callback = self.task_callback
758
+
759
+ tasks.append(task)
760
+ tasks_dict[task_name] = task
761
+
762
+ # Set up task contexts
763
+ for role, details in config['roles'].items():
764
+ for task_name, task_details in details.get('tasks', {}).items():
765
+ task = tasks_dict[task_name]
766
+ context_tasks = [tasks_dict[ctx] for ctx in task_details.get('context', [])
767
+ if ctx in tasks_dict]
768
+ task.context = context_tasks
769
+
770
+ # Create and run the crew
771
+ crew = Crew(
772
+ agents=list(agents.values()),
773
+ tasks=tasks,
774
+ verbose=True
775
+ )
776
+
777
+ self.logger.debug("Final Crew Configuration:")
778
+ self.logger.debug(f"Agents: {crew.agents}")
779
+ self.logger.debug(f"Tasks: {crew.tasks}")
780
+
781
+ response = crew.kickoff()
782
+ result = f"### Task Output ###\n{response}"
783
+
784
+ if AGENTOPS_AVAILABLE:
785
+ agentops.end_session("Success")
786
+
787
+ return result
788
+
789
+ def _run_praisonai(self, config, topic, tools_dict):
790
+ """
791
+ Run agents using the PraisonAI framework.
792
+ """
793
+ agents = {}
794
+ tasks = []
795
+ tasks_dict = {}
796
+
797
+ # Load tools once at the beginning
798
+ tools_list = self.load_tools_from_tools_py()
799
+ self.logger.debug(f"Loaded tools: {tools_list}")
800
+
801
+ # Create agents from config
802
+ for role, details in config['roles'].items():
803
+ role_filled = details['role'].format(topic=topic)
804
+ goal_filled = details['goal'].format(topic=topic)
805
+ backstory_filled = details['backstory'].format(topic=topic)
806
+
807
+ # Pass all loaded tools to the agent
808
+ agent = PraisonAgent(
809
+ name=role_filled,
810
+ role=role_filled,
811
+ goal=goal_filled,
812
+ backstory=backstory_filled,
813
+ tools=tools_list, # Pass the entire tools list to the agent
814
+ allow_delegation=details.get('allow_delegation', False),
815
+ llm=details.get('llm', {}).get("model") or os.environ.get("MODEL_NAME") or "openai/gpt-5-nano",
816
+ function_calling_llm=details.get('function_calling_llm', {}).get("model") or os.environ.get("MODEL_NAME") or "openai/gpt-5-nano",
817
+ max_iter=details.get('max_iter', 15),
818
+ max_rpm=details.get('max_rpm'),
819
+ max_execution_time=details.get('max_execution_time'),
820
+ verbose=details.get('verbose', True),
821
+ cache=details.get('cache', True),
822
+ system_template=details.get('system_template'),
823
+ prompt_template=details.get('prompt_template'),
824
+ response_template=details.get('response_template'),
825
+ reflect_llm=details.get('reflect_llm', {}).get("model") or os.environ.get("MODEL_NAME") or "openai/gpt-5-nano",
826
+ min_reflect=details.get('min_reflect', 1),
827
+ max_reflect=details.get('max_reflect', 3),
828
+ )
829
+
830
+ if self.agent_callback:
831
+ agent.step_callback = self.agent_callback
832
+
833
+ agents[role] = agent
834
+ self.logger.debug(f"Created agent {role_filled} with tools: {agent.tools}")
835
+
836
+ # Create tasks for the agent
837
+ for task_name, task_details in details.get('tasks', {}).items():
838
+ description_filled = task_details['description'].format(topic=topic)
839
+ expected_output_filled = task_details['expected_output'].format(topic=topic)
840
+
841
+ task = PraisonTask(
842
+ description=description_filled,
843
+ expected_output=expected_output_filled,
844
+ agent=agent,
845
+ tools=tools_list, # Pass the same tools list to the task
846
+ async_execution=task_details.get('async_execution', False),
847
+ context=[],
848
+ config=task_details.get('config', {}),
849
+ output_json=task_details.get('output_json'),
850
+ output_pydantic=task_details.get('output_pydantic'),
851
+ output_file=task_details.get('output_file', ""),
852
+ callback=task_details.get('callback'),
853
+ create_directory=task_details.get('create_directory', False)
854
+ )
855
+
856
+ self.logger.debug(f"Created task {task_name} with tools: {task.tools}")
857
+
858
+ if self.task_callback:
859
+ task.callback = self.task_callback
860
+
861
+ tasks.append(task)
862
+ tasks_dict[task_name] = task
863
+
864
+ # Set up task contexts
865
+ for role, details in config['roles'].items():
866
+ for task_name, task_details in details.get('tasks', {}).items():
867
+ task = tasks_dict[task_name]
868
+ context_tasks = [tasks_dict[ctx] for ctx in task_details.get('context', [])
869
+ if ctx in tasks_dict]
870
+ task.context = context_tasks
871
+
872
+ # Create and run the PraisonAI agents
873
+ memory = config.get('memory', False)
874
+ self.logger.debug(f"Memory: {memory}")
875
+ if config.get('process') == 'hierarchical':
876
+ agents = PraisonAIAgents(
877
+ agents=list(agents.values()),
878
+ tasks=tasks,
879
+ verbose=True,
880
+ process="hierarchical",
881
+ manager_llm=config.get('manager_llm') or os.environ.get("MODEL_NAME") or "openai/gpt-5-nano",
882
+ memory=memory
883
+ )
884
+ else:
885
+ agents = PraisonAIAgents(
886
+ agents=list(agents.values()),
887
+ tasks=tasks,
888
+ verbose=True,
889
+ memory=memory
890
+ )
891
+
892
+ self.logger.debug("Final Configuration:")
893
+ self.logger.debug(f"Agents: {agents.agents}")
894
+ self.logger.debug(f"Tasks: {agents.tasks}")
895
+
896
+ response = agents.start()
897
+ self.logger.debug(f"Result: {response}")
898
+ result = ""
899
+
900
+ if AGENTOPS_AVAILABLE:
901
+ agentops.end_session("Success")
902
+
903
+ return result