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,720 @@
1
+ """
2
+ Workflow Handler for CLI.
3
+
4
+ Provides YAML workflow management commands.
5
+ Usage: praisonai workflow run research.yaml
6
+ praisonai workflow validate research.yaml
7
+ praisonai workflow list
8
+ praisonai workflow create --template routing
9
+ """
10
+
11
+ import os
12
+ from pathlib import Path
13
+ from typing import Any, Dict, List, Optional
14
+ from .base import CommandHandler
15
+
16
+
17
+ class WorkflowHandler(CommandHandler):
18
+ """
19
+ Handler for workflow command.
20
+
21
+ Manages YAML workflow files - run, validate, list, and create from templates.
22
+
23
+ Example:
24
+ praisonai workflow run research.yaml --var topic="AI"
25
+ praisonai workflow validate research.yaml
26
+ praisonai workflow list
27
+ praisonai workflow create --template routing --output my_workflow.yaml
28
+ """
29
+
30
+ # Workflow templates
31
+ TEMPLATES = {
32
+ "simple": """# Simple Sequential Workflow
33
+ name: Simple Workflow
34
+ description: A simple sequential workflow
35
+
36
+ workflow:
37
+ verbose: true
38
+
39
+ agents:
40
+ researcher:
41
+ name: Researcher
42
+ role: Research Analyst
43
+ goal: Research topics
44
+ instructions: "Provide concise, factual information."
45
+
46
+ writer:
47
+ name: Writer
48
+ role: Content Writer
49
+ goal: Write content
50
+ instructions: "Write clear, engaging content."
51
+
52
+ steps:
53
+ - agent: researcher
54
+ action: "Research: {{input}}"
55
+
56
+ - agent: writer
57
+ action: "Write summary based on: {{previous_output}}"
58
+ """,
59
+ "routing": """# Routing Workflow
60
+ name: Routing Workflow
61
+ description: Classifier routes to specialized agents
62
+
63
+ workflow:
64
+ verbose: true
65
+
66
+ agents:
67
+ classifier:
68
+ name: Classifier
69
+ role: Request Classifier
70
+ goal: Classify requests
71
+ instructions: "Respond with ONLY 'technical', 'creative', or 'general'."
72
+
73
+ tech_agent:
74
+ name: TechExpert
75
+ role: Technical Expert
76
+ goal: Handle technical questions
77
+ instructions: "Provide technical answers."
78
+
79
+ creative_agent:
80
+ name: Creative
81
+ role: Creative Writer
82
+ goal: Handle creative requests
83
+ instructions: "Write creative content."
84
+
85
+ general_agent:
86
+ name: General
87
+ role: General Assistant
88
+ goal: Handle general requests
89
+ instructions: "Provide helpful responses."
90
+
91
+ steps:
92
+ - agent: classifier
93
+ action: "Classify: {{input}}"
94
+
95
+ - name: routing
96
+ route:
97
+ technical: [tech_agent]
98
+ creative: [creative_agent]
99
+ default: [general_agent]
100
+ """,
101
+ "parallel": """# Parallel Workflow
102
+ name: Parallel Research Workflow
103
+ description: Multiple agents work concurrently
104
+
105
+ workflow:
106
+ verbose: true
107
+
108
+ agents:
109
+ researcher1:
110
+ name: MarketResearcher
111
+ role: Market Analyst
112
+ goal: Research market trends
113
+ instructions: "Provide market insights."
114
+
115
+ researcher2:
116
+ name: CompetitorResearcher
117
+ role: Competitor Analyst
118
+ goal: Research competitors
119
+ instructions: "Provide competitor insights."
120
+
121
+ aggregator:
122
+ name: Aggregator
123
+ role: Synthesizer
124
+ goal: Combine findings
125
+ instructions: "Synthesize all research."
126
+
127
+ steps:
128
+ - name: parallel_research
129
+ parallel:
130
+ - agent: researcher1
131
+ action: "Research market for: {{input}}"
132
+ - agent: researcher2
133
+ action: "Research competitors for: {{input}}"
134
+
135
+ - agent: aggregator
136
+ action: "Combine all findings"
137
+ """,
138
+ "loop": """# Loop Workflow
139
+ name: Loop Processing Workflow
140
+ description: Process multiple items in a loop
141
+
142
+ workflow:
143
+ verbose: true
144
+
145
+ variables:
146
+ items:
147
+ - Item 1
148
+ - Item 2
149
+ - Item 3
150
+
151
+ agents:
152
+ processor:
153
+ name: Processor
154
+ role: Item Processor
155
+ goal: Process each item
156
+ instructions: "Process the given item thoroughly."
157
+
158
+ summarizer:
159
+ name: Summarizer
160
+ role: Summarizer
161
+ goal: Summarize results
162
+ instructions: "Summarize all processed items."
163
+
164
+ steps:
165
+ - agent: processor
166
+ action: "Process: {{item}}"
167
+ loop:
168
+ over: items
169
+
170
+ - agent: summarizer
171
+ action: "Summarize all processed items"
172
+ """,
173
+ "evaluator-optimizer": """# Evaluator-Optimizer Workflow
174
+ name: Evaluator Optimizer Workflow
175
+ description: Generate and improve until approved
176
+
177
+ workflow:
178
+ verbose: true
179
+
180
+ agents:
181
+ generator:
182
+ name: Generator
183
+ role: Content Generator
184
+ goal: Generate content
185
+ instructions: "Generate content. Improve based on feedback if provided."
186
+
187
+ evaluator:
188
+ name: Evaluator
189
+ role: Evaluator
190
+ goal: Evaluate content
191
+ instructions: "If good, respond 'APPROVED'. Otherwise provide feedback."
192
+
193
+ steps:
194
+ - agent: generator
195
+ action: "Generate content for: {{input}}"
196
+
197
+ - agent: evaluator
198
+ action: "Evaluate: {{previous_output}}"
199
+ repeat:
200
+ until: "approved"
201
+ max_iterations: 3
202
+ """,
203
+ "model-routing": """# Model Routing Workflow
204
+ name: Cost-Optimized Model Routing Workflow
205
+ description: Uses custom models with automatic routing based on task complexity
206
+
207
+ # Custom models configuration - define your own models with costs and capabilities
208
+ models:
209
+ cheap-fast:
210
+ provider: openai
211
+ complexity: [simple]
212
+ cost_per_1k: 0.0001
213
+ capabilities: [text]
214
+ context_window: 16000
215
+
216
+ balanced:
217
+ provider: openai
218
+ complexity: [moderate]
219
+ cost_per_1k: 0.001
220
+ capabilities: [text, function-calling]
221
+ context_window: 128000
222
+
223
+ premium:
224
+ provider: anthropic
225
+ complexity: [complex, very_complex]
226
+ cost_per_1k: 0.015
227
+ capabilities: [text, vision, function-calling]
228
+ context_window: 200000
229
+ strengths: [reasoning, analysis, code-generation]
230
+
231
+ workflow:
232
+ verbose: true
233
+ router: true # Enable model routing
234
+ routing_strategy: cost-optimized # Options: auto, cost-optimized, performance-optimized
235
+
236
+ agents:
237
+ classifier:
238
+ name: Classifier
239
+ role: Request Classifier
240
+ goal: Classify incoming requests by complexity
241
+ instructions: "Classify the request as 'simple', 'moderate', or 'complex'."
242
+ llm: cheap-fast # Always use cheap model for classification
243
+
244
+ researcher:
245
+ name: Researcher
246
+ role: Research Analyst
247
+ goal: Research topics thoroughly
248
+ instructions: "Research the topic and provide detailed findings."
249
+ llm_routing: auto # Auto-select based on task complexity
250
+ llm_models: [balanced, premium] # Models to choose from
251
+
252
+ writer:
253
+ name: Writer
254
+ role: Content Writer
255
+ goal: Write high-quality content
256
+ instructions: "Write clear, engaging content based on research."
257
+ llm: premium # Always use premium for quality writing
258
+
259
+ steps:
260
+ - agent: classifier
261
+ action: "Classify complexity of: {{input}}"
262
+
263
+ - name: routing
264
+ route:
265
+ simple: [researcher]
266
+ moderate: [researcher]
267
+ complex: [researcher, writer]
268
+ default: [researcher]
269
+ """
270
+ }
271
+
272
+ def __init__(self, verbose: bool = False):
273
+ super().__init__(verbose)
274
+ self._manager = None
275
+ self._parser = None
276
+
277
+ @property
278
+ def feature_name(self) -> str:
279
+ return "workflow"
280
+
281
+ def get_actions(self) -> List[str]:
282
+ return ["run", "validate", "list", "create", "auto", "help"]
283
+
284
+ def get_help_text(self) -> str:
285
+ return """
286
+ Workflow Commands:
287
+ praisonai workflow run <file.yaml> - Run a YAML workflow
288
+ praisonai workflow run <file.yaml> --var key=value - Run with variables
289
+ praisonai workflow validate <file.yaml> - Validate a YAML workflow
290
+ praisonai workflow list - List workflows in .praison/workflows/
291
+ praisonai workflow create --template <name> - Create from template
292
+ praisonai workflow auto "topic" --pattern <pattern> - Auto-generate workflow
293
+
294
+ Templates: simple, routing, parallel, loop, evaluator-optimizer, model-routing
295
+ Patterns: sequential, routing, parallel
296
+
297
+ Example:
298
+ praisonai workflow run research.yaml --var topic="AI trends"
299
+ praisonai workflow create --template routing --output my_workflow.yaml
300
+ praisonai workflow auto "Research AI trends" --pattern parallel
301
+ """
302
+
303
+ def _get_manager(self):
304
+ """Get WorkflowManager lazily."""
305
+ if self._manager is None:
306
+ try:
307
+ from praisonaiagents.workflows import WorkflowManager
308
+ self._manager = WorkflowManager()
309
+ except ImportError:
310
+ self.print_status(
311
+ "Workflows require praisonaiagents. Install with: pip install praisonaiagents",
312
+ "error"
313
+ )
314
+ return None
315
+ return self._manager
316
+
317
+ def _get_parser(self):
318
+ """Get YAMLWorkflowParser lazily."""
319
+ if self._parser is None:
320
+ try:
321
+ from praisonaiagents.workflows import YAMLWorkflowParser
322
+ self._parser = YAMLWorkflowParser()
323
+ except ImportError:
324
+ self.print_status(
325
+ "Workflows require praisonaiagents. Install with: pip install praisonaiagents",
326
+ "error"
327
+ )
328
+ return None
329
+ return self._parser
330
+
331
+ def _parse_variables(self, args: List[str]) -> Dict[str, Any]:
332
+ """Parse --var key=value arguments."""
333
+ variables = {}
334
+ i = 0
335
+ while i < len(args):
336
+ if args[i] == "--var" and i + 1 < len(args):
337
+ var_str = args[i + 1]
338
+ if "=" in var_str:
339
+ key, value = var_str.split("=", 1)
340
+ variables[key.strip()] = value.strip()
341
+ i += 2
342
+ else:
343
+ i += 1
344
+ return variables
345
+
346
+ def _get_file_from_args(self, args: List[str]) -> Optional[str]:
347
+ """Get the file path from arguments."""
348
+ for arg in args:
349
+ if arg.endswith(('.yaml', '.yml')) and not arg.startswith('--'):
350
+ return arg
351
+ return None
352
+
353
+ def action_run(self, args: List[str], **kwargs) -> Any:
354
+ """
355
+ Run a YAML workflow file.
356
+
357
+ Args:
358
+ args: [file.yaml, --var, key=value, ...]
359
+
360
+ Returns:
361
+ Workflow execution result
362
+ """
363
+ file_path = self._get_file_from_args(args)
364
+ if not file_path:
365
+ self.print_status("Usage: praisonai workflow run <file.yaml>", "error")
366
+ return None
367
+
368
+ if not os.path.exists(file_path):
369
+ self.print_status(f"File not found: {file_path}", "error")
370
+ return None
371
+
372
+ manager = self._get_manager()
373
+ if not manager:
374
+ return None
375
+
376
+ # Parse variables
377
+ variables = self._parse_variables(args)
378
+
379
+ # Get input if provided
380
+ input_data = kwargs.get('input', '')
381
+
382
+ # Check for --verbose flag
383
+ verbose = '--verbose' in args or '-v' in args
384
+
385
+ self.print_status(f"Running workflow: {file_path}", "info")
386
+ if variables:
387
+ self.print_status(f"Variables: {variables}", "info")
388
+
389
+ try:
390
+ result = manager.execute_yaml(
391
+ file_path,
392
+ input_data=input_data,
393
+ variables=variables,
394
+ verbose=verbose
395
+ )
396
+
397
+ self.print_status("Workflow completed!", "success")
398
+
399
+ # Print output
400
+ if result.get('output'):
401
+ from rich import print as rprint
402
+ rprint("\n[bold]Output:[/bold]")
403
+ rprint(result['output'])
404
+
405
+ return result
406
+
407
+ except Exception as e:
408
+ self.print_status(f"Workflow failed: {e}", "error")
409
+ return None
410
+
411
+ def action_validate(self, args: List[str], **kwargs) -> bool:
412
+ """
413
+ Validate a YAML workflow file.
414
+
415
+ Args:
416
+ args: [file.yaml]
417
+
418
+ Returns:
419
+ True if valid, False otherwise
420
+ """
421
+ file_path = self._get_file_from_args(args)
422
+ if not file_path:
423
+ self.print_status("Usage: praisonai workflow validate <file.yaml>", "error")
424
+ return False
425
+
426
+ if not os.path.exists(file_path):
427
+ self.print_status(f"File not found: {file_path}", "error")
428
+ return False
429
+
430
+ parser = self._get_parser()
431
+ if not parser:
432
+ return False
433
+
434
+ self.print_status(f"Validating: {file_path}", "info")
435
+
436
+ try:
437
+ # Load raw YAML to check for non-canonical names
438
+ import yaml
439
+ with open(file_path, 'r') as f:
440
+ raw_data = yaml.safe_load(f)
441
+
442
+ # Check for non-canonical names and suggest canonical ones
443
+ suggestions = self._get_canonical_suggestions(raw_data)
444
+
445
+ workflow = parser.parse_file(file_path)
446
+
447
+ # Print validation results
448
+ from rich import print as rprint
449
+ from rich.table import Table
450
+
451
+ table = Table(title="Workflow Validation")
452
+ table.add_column("Property", style="cyan")
453
+ table.add_column("Value", style="green")
454
+
455
+ table.add_row("Name", workflow.name)
456
+ table.add_row("Description", getattr(workflow, 'description', 'N/A'))
457
+ table.add_row("Steps", str(len(workflow.steps)))
458
+ table.add_row("Variables", str(len(workflow.variables)))
459
+ table.add_row("Planning", str(workflow.planning))
460
+ table.add_row("Reasoning", str(workflow.reasoning))
461
+
462
+ rprint(table)
463
+ self.print_status("✓ Workflow is valid!", "success")
464
+
465
+ # Show suggestions for canonical names
466
+ if suggestions:
467
+ rprint()
468
+ rprint("[yellow]💡 Suggestions for canonical field names:[/yellow]")
469
+ for suggestion in suggestions:
470
+ rprint(f" [dim]•[/dim] {suggestion}")
471
+ rprint()
472
+ rprint("[dim]Note: Both old and new names work, but canonical names are recommended.[/dim]")
473
+
474
+ return True
475
+
476
+ except Exception as e:
477
+ self.print_status(f"✗ Validation failed: {e}", "error")
478
+ return False
479
+
480
+ def _get_canonical_suggestions(self, data: Dict) -> List[str]:
481
+ """
482
+ Check for non-canonical field names and return suggestions.
483
+
484
+ Canonical names (A-I-G-S mnemonic):
485
+ - Agents (not roles)
486
+ - Instructions (not backstory)
487
+ - Goal (same)
488
+ - Steps (not tasks)
489
+
490
+ Also:
491
+ - name (not topic)
492
+ - action (not description)
493
+
494
+ Args:
495
+ data: Raw YAML data
496
+
497
+ Returns:
498
+ List of suggestion strings
499
+ """
500
+ suggestions = []
501
+
502
+ if not data:
503
+ return suggestions
504
+
505
+ # Check top-level keys
506
+ if 'roles' in data:
507
+ suggestions.append("Use 'agents' instead of 'roles'")
508
+
509
+ if 'topic' in data and 'name' not in data:
510
+ suggestions.append("Use 'name' instead of 'topic'")
511
+
512
+ # Check agent fields
513
+ agents_data = data.get('agents', data.get('roles', {}))
514
+ for agent_id, agent_config in agents_data.items():
515
+ if isinstance(agent_config, dict):
516
+ if 'backstory' in agent_config:
517
+ suggestions.append(f"Agent '{agent_id}': Use 'instructions' instead of 'backstory'")
518
+
519
+ # Check nested tasks
520
+ if 'tasks' in agent_config:
521
+ suggestions.append(f"Agent '{agent_id}': Use 'steps' at top level instead of nested 'tasks'")
522
+
523
+ # Check step fields
524
+ steps_data = data.get('steps', [])
525
+ for i, step in enumerate(steps_data):
526
+ if isinstance(step, dict):
527
+ if 'description' in step and 'action' not in step:
528
+ step_name = step.get('name', f'step {i+1}')
529
+ suggestions.append(f"Step '{step_name}': Use 'action' instead of 'description'")
530
+
531
+ # Check parallel steps
532
+ if 'parallel' in step:
533
+ for j, parallel_step in enumerate(step['parallel']):
534
+ if isinstance(parallel_step, dict):
535
+ if 'description' in parallel_step and 'action' not in parallel_step:
536
+ suggestions.append(f"Parallel step {j+1}: Use 'action' instead of 'description'")
537
+
538
+ return suggestions
539
+
540
+ def action_list(self, args: List[str], **kwargs) -> List[str]:
541
+ """
542
+ List available workflows in .praison/workflows/ directory.
543
+
544
+ Returns:
545
+ List of workflow file names
546
+ """
547
+ workflows_dir = Path(".praison/workflows")
548
+
549
+ if not workflows_dir.exists():
550
+ self.print_status("No .praison/workflows/ directory found", "warning")
551
+ self.print_status("Create one with: mkdir -p .praison/workflows", "info")
552
+ return []
553
+
554
+ # Find all YAML files
555
+ yaml_files = list(workflows_dir.glob("*.yaml")) + list(workflows_dir.glob("*.yml"))
556
+
557
+ if not yaml_files:
558
+ self.print_status("No workflow files found in .praison/workflows/", "warning")
559
+ return []
560
+
561
+ from rich import print as rprint
562
+ from rich.table import Table
563
+
564
+ table = Table(title="Available Workflows")
565
+ table.add_column("File", style="cyan")
566
+ table.add_column("Name", style="green")
567
+ table.add_column("Steps", style="yellow")
568
+
569
+ parser = self._get_parser()
570
+ workflow_names = []
571
+
572
+ for yaml_file in yaml_files:
573
+ try:
574
+ if parser:
575
+ workflow = parser.parse_file(yaml_file)
576
+ table.add_row(
577
+ yaml_file.name,
578
+ workflow.name,
579
+ str(len(workflow.steps))
580
+ )
581
+ else:
582
+ table.add_row(yaml_file.name, "N/A", "N/A")
583
+ workflow_names.append(yaml_file.name)
584
+ except Exception as e:
585
+ table.add_row(yaml_file.name, f"Error: {e}", "N/A")
586
+
587
+ rprint(table)
588
+ return workflow_names
589
+
590
+ def action_create(self, args: List[str], **kwargs) -> Optional[str]:
591
+ """
592
+ Create a workflow from a template.
593
+
594
+ Args:
595
+ args: [--template, <name>, --output, <file.yaml>]
596
+
597
+ Returns:
598
+ Path to created file
599
+ """
600
+ # Parse arguments
601
+ template_name = None
602
+ output_file = None
603
+
604
+ i = 0
605
+ while i < len(args):
606
+ if args[i] == "--template" and i + 1 < len(args):
607
+ template_name = args[i + 1]
608
+ i += 2
609
+ elif args[i] == "--output" and i + 1 < len(args):
610
+ output_file = args[i + 1]
611
+ i += 2
612
+ else:
613
+ i += 1
614
+
615
+ if not template_name:
616
+ self.print_status("Usage: praisonai workflow create --template <name>", "error")
617
+ self.print_status(f"Available templates: {', '.join(self.TEMPLATES.keys())}", "info")
618
+ return None
619
+
620
+ if template_name not in self.TEMPLATES:
621
+ self.print_status(f"Unknown template: {template_name}", "error")
622
+ self.print_status(f"Available templates: {', '.join(self.TEMPLATES.keys())}", "info")
623
+ return None
624
+
625
+ # Default output file
626
+ if not output_file:
627
+ output_file = f"{template_name}_workflow.yaml"
628
+
629
+ # Check if file exists
630
+ if os.path.exists(output_file):
631
+ self.print_status(f"File already exists: {output_file}", "error")
632
+ return None
633
+
634
+ # Write template
635
+ template_content = self.TEMPLATES[template_name]
636
+
637
+ with open(output_file, 'w') as f:
638
+ f.write(template_content)
639
+
640
+ self.print_status(f"✓ Created workflow: {output_file}", "success")
641
+ self.print_status(f"Run with: praisonai workflow run {output_file}", "info")
642
+
643
+ return output_file
644
+
645
+ def action_auto(self, args: List[str], **kwargs) -> Optional[str]:
646
+ """
647
+ Auto-generate a workflow from a topic description.
648
+
649
+ Args:
650
+ args: ["topic description", --pattern, <pattern>, --output, <file.yaml>]
651
+
652
+ Returns:
653
+ Path to created file
654
+ """
655
+ # Parse arguments
656
+ topic = None
657
+ pattern = "sequential"
658
+ output_file = None
659
+
660
+ i = 0
661
+ while i < len(args):
662
+ if args[i] == "--pattern" and i + 1 < len(args):
663
+ pattern = args[i + 1]
664
+ i += 2
665
+ elif args[i] == "--output" and i + 1 < len(args):
666
+ output_file = args[i + 1]
667
+ i += 2
668
+ elif not args[i].startswith("--") and topic is None:
669
+ topic = args[i]
670
+ i += 1
671
+ else:
672
+ i += 1
673
+
674
+ if not topic:
675
+ self.print_status('Usage: praisonai workflow auto "topic" --pattern <pattern>', "error")
676
+ self.print_status("Patterns: sequential, routing, parallel", "info")
677
+ return None
678
+
679
+ # Validate pattern
680
+ valid_patterns = ["sequential", "routing", "parallel", "loop", "orchestrator-workers", "evaluator-optimizer"]
681
+ if pattern not in valid_patterns:
682
+ self.print_status(f"Unknown pattern: {pattern}", "error")
683
+ self.print_status(f"Valid patterns: {', '.join(valid_patterns)}", "info")
684
+ return None
685
+
686
+ # Default output file
687
+ if not output_file:
688
+ # Create safe filename from topic
689
+ safe_name = "".join(c if c.isalnum() else "_" for c in topic[:30]).lower()
690
+ output_file = f"{safe_name}_workflow.yaml"
691
+
692
+ # Check if file exists
693
+ if os.path.exists(output_file):
694
+ self.print_status(f"File already exists: {output_file}", "error")
695
+ return None
696
+
697
+ self.print_status(f"Generating {pattern} workflow for: {topic}", "info")
698
+
699
+ try:
700
+ # Lazy import to avoid performance impact
701
+ from praisonai.auto import WorkflowAutoGenerator
702
+
703
+ generator = WorkflowAutoGenerator(
704
+ topic=topic,
705
+ workflow_file=output_file
706
+ )
707
+
708
+ result_path = generator.generate(pattern=pattern)
709
+
710
+ self.print_status(f"✓ Created workflow: {result_path}", "success")
711
+ self.print_status(f"Run with: praisonai workflow run {output_file}", "info")
712
+
713
+ return result_path
714
+
715
+ except ImportError:
716
+ self.print_status("Auto-generation requires instructor: pip install instructor", "error")
717
+ return None
718
+ except Exception as e:
719
+ self.print_status(f"Generation failed: {e}", "error")
720
+ return None