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,449 @@
1
+ """
2
+ Recipes CLI - Commands for managing and running Agent-Recipes.
3
+
4
+ Provides commands for:
5
+ - praison recipes list - List available recipes
6
+ - praison recipes info <name> - Show recipe details
7
+ - praison recipes run <name> <input> - Run a recipe
8
+ - praison recipes doctor <name> - Check recipe dependencies
9
+ - praison recipes explain <name> - Show recipe execution plan
10
+ - praison recipes init <name> - Initialize recipe in current directory
11
+ """
12
+
13
+ import os
14
+ import sys
15
+ import json
16
+ import yaml
17
+ import argparse
18
+ import logging
19
+ from pathlib import Path
20
+ from typing import Optional, List, Dict, Any
21
+
22
+ logger = logging.getLogger(__name__)
23
+
24
+ # Recipe discovery paths in order of precedence
25
+ RECIPE_PATHS = [
26
+ Path.home() / ".praison" / "templates",
27
+ Path.home() / ".config" / "praison" / "templates",
28
+ Path.cwd() / ".praison" / "templates",
29
+ Path("/Users/praison/Agent-Recipes/agent_recipes/templates"),
30
+ ]
31
+
32
+
33
+ def find_recipe_paths() -> List[Path]:
34
+ """Find all valid recipe directories."""
35
+ paths = []
36
+ for p in RECIPE_PATHS:
37
+ if p.exists() and p.is_dir():
38
+ paths.append(p)
39
+ return paths
40
+
41
+
42
+ def list_recipes() -> List[Dict[str, Any]]:
43
+ """List all available recipes."""
44
+ recipes = []
45
+ seen = set()
46
+
47
+ for base_path in find_recipe_paths():
48
+ for recipe_dir in base_path.iterdir():
49
+ if not recipe_dir.is_dir():
50
+ continue
51
+
52
+ template_file = recipe_dir / "TEMPLATE.yaml"
53
+ if not template_file.exists():
54
+ continue
55
+
56
+ name = recipe_dir.name
57
+ if name in seen:
58
+ continue
59
+ seen.add(name)
60
+
61
+ try:
62
+ with open(template_file) as f:
63
+ template = yaml.safe_load(f)
64
+ recipes.append({
65
+ "name": name,
66
+ "description": template.get("description", ""),
67
+ "version": template.get("version", "1.0.0"),
68
+ "tags": template.get("tags", []),
69
+ "path": str(recipe_dir),
70
+ })
71
+ except Exception as e:
72
+ logger.warning(f"Failed to load recipe {name}: {e}")
73
+
74
+ return sorted(recipes, key=lambda x: x["name"])
75
+
76
+
77
+ def get_recipe(name: str) -> Optional[Dict[str, Any]]:
78
+ """Get recipe by name."""
79
+ for base_path in find_recipe_paths():
80
+ recipe_dir = base_path / name
81
+ template_file = recipe_dir / "TEMPLATE.yaml"
82
+
83
+ if template_file.exists():
84
+ with open(template_file) as f:
85
+ template = yaml.safe_load(f)
86
+ template["path"] = str(recipe_dir)
87
+ return template
88
+
89
+ return None
90
+
91
+
92
+ def check_dependencies(recipe: Dict[str, Any]) -> Dict[str, bool]:
93
+ """Check if recipe dependencies are satisfied."""
94
+ results = {}
95
+ requires = recipe.get("requires", {})
96
+
97
+ # Check environment variables
98
+ for env_var in requires.get("env", []):
99
+ results[f"env:{env_var}"] = bool(os.environ.get(env_var))
100
+
101
+ # Check Python packages
102
+ for package in requires.get("packages", []):
103
+ try:
104
+ __import__(package.replace("-", "_").split("[")[0])
105
+ results[f"package:{package}"] = True
106
+ except ImportError:
107
+ results[f"package:{package}"] = False
108
+
109
+ # Check external tools
110
+ import shutil
111
+ for tool in requires.get("external", []):
112
+ results[f"external:{tool}"] = shutil.which(tool) is not None
113
+
114
+ # Check recipe tools
115
+ for tool in requires.get("tools", []):
116
+ try:
117
+ from praisonai_tools.recipe_tools import __all__ as available_tools
118
+ # Check if tool class exists
119
+ tool_class = tool.replace("_tool", "").title() + "Tool"
120
+ results[f"tool:{tool}"] = tool_class in available_tools or tool in str(available_tools)
121
+ except ImportError:
122
+ results[f"tool:{tool}"] = False
123
+
124
+ return results
125
+
126
+
127
+ def cmd_list(args: argparse.Namespace) -> int:
128
+ """List available recipes."""
129
+ recipes = list_recipes()
130
+
131
+ if args.json:
132
+ print(json.dumps(recipes, indent=2))
133
+ return 0
134
+
135
+ if not recipes:
136
+ print("No recipes found.")
137
+ return 0
138
+
139
+ # Group by first tag if available
140
+ if args.group:
141
+ groups = {}
142
+ for r in recipes:
143
+ tag = r["tags"][0] if r["tags"] else "other"
144
+ if tag not in groups:
145
+ groups[tag] = []
146
+ groups[tag].append(r)
147
+
148
+ for group, group_recipes in sorted(groups.items()):
149
+ print(f"\n{group.upper()}:")
150
+ for r in group_recipes:
151
+ print(f" {r['name']:<35} {r['description'][:50]}")
152
+ else:
153
+ print(f"{'Recipe':<35} {'Description':<50} {'Version'}")
154
+ print("-" * 95)
155
+ for r in recipes:
156
+ desc = r["description"][:47] + "..." if len(r["description"]) > 50 else r["description"]
157
+ print(f"{r['name']:<35} {desc:<50} {r['version']}")
158
+
159
+ print(f"\nTotal: {len(recipes)} recipes")
160
+ return 0
161
+
162
+
163
+ def cmd_info(args: argparse.Namespace) -> int:
164
+ """Show recipe details."""
165
+ recipe = get_recipe(args.name)
166
+
167
+ if not recipe:
168
+ print(f"Recipe not found: {args.name}")
169
+ return 1
170
+
171
+ if args.json:
172
+ print(json.dumps(recipe, indent=2, default=str))
173
+ return 0
174
+
175
+ print(f"Name: {recipe.get('name', args.name)}")
176
+ print(f"Version: {recipe.get('version', '1.0.0')}")
177
+ print(f"Description: {recipe.get('description', '')}")
178
+ print(f"Author: {recipe.get('author', 'unknown')}")
179
+ print(f"License: {recipe.get('license', 'unknown')}")
180
+ print(f"Path: {recipe.get('path', '')}")
181
+
182
+ if recipe.get("tags"):
183
+ print(f"Tags: {', '.join(recipe['tags'])}")
184
+
185
+ requires = recipe.get("requires", {})
186
+ if requires:
187
+ print("\nRequirements:")
188
+ if requires.get("env"):
189
+ print(f" Environment: {', '.join(requires['env'])}")
190
+ if requires.get("packages"):
191
+ print(f" Packages: {', '.join(requires['packages'])}")
192
+ if requires.get("external"):
193
+ print(f" External: {', '.join(requires['external'])}")
194
+ if requires.get("tools"):
195
+ print(f" Tools: {', '.join(requires['tools'])}")
196
+
197
+ cli = recipe.get("cli", {})
198
+ if cli:
199
+ print("\nCLI:")
200
+ print(f" Command: {cli.get('command', '')}")
201
+ if cli.get("examples"):
202
+ print(" Examples:")
203
+ for ex in cli["examples"]:
204
+ print(f" {ex}")
205
+
206
+ safety = recipe.get("safety", {})
207
+ if safety:
208
+ print("\nSafety:")
209
+ print(f" Dry-run default: {safety.get('dry_run_default', False)}")
210
+ if safety.get("requires_consent"):
211
+ print(f" Requires consent: {safety.get('consent_message', 'Yes')}")
212
+ if safety.get("legal_disclaimer"):
213
+ print(f" Legal disclaimer: {safety.get('legal_disclaimer')}")
214
+
215
+ return 0
216
+
217
+
218
+ def cmd_doctor(args: argparse.Namespace) -> int:
219
+ """Check recipe dependencies."""
220
+ recipe = get_recipe(args.name)
221
+
222
+ if not recipe:
223
+ print(f"Recipe not found: {args.name}")
224
+ return 1
225
+
226
+ print(f"Checking dependencies for: {args.name}")
227
+ print("-" * 50)
228
+
229
+ deps = check_dependencies(recipe)
230
+ all_ok = True
231
+
232
+ for dep, status in sorted(deps.items()):
233
+ icon = "✓" if status else "✗"
234
+ color = "\033[92m" if status else "\033[91m"
235
+ reset = "\033[0m"
236
+ print(f" {color}{icon}{reset} {dep}")
237
+ if not status:
238
+ all_ok = False
239
+
240
+ print("-" * 50)
241
+ if all_ok:
242
+ print("All dependencies satisfied!")
243
+ return 0
244
+ else:
245
+ print("\nMissing dependencies. Install with:")
246
+ requires = recipe.get("requires", {})
247
+
248
+ if requires.get("packages"):
249
+ missing_pkgs = [p for p in requires["packages"] if not deps.get(f"package:{p}", True)]
250
+ if missing_pkgs:
251
+ print(f" pip install {' '.join(missing_pkgs)}")
252
+
253
+ if requires.get("external"):
254
+ missing_ext = [e for e in requires["external"] if not deps.get(f"external:{e}", True)]
255
+ if missing_ext:
256
+ print(f" # Install external tools: {', '.join(missing_ext)}")
257
+
258
+ if requires.get("env"):
259
+ missing_env = [e for e in requires["env"] if not deps.get(f"env:{e}", True)]
260
+ if missing_env:
261
+ print(f" # Set environment variables: {', '.join(missing_env)}")
262
+
263
+ return 1
264
+
265
+
266
+ def cmd_run(args: argparse.Namespace) -> int:
267
+ """Run a recipe."""
268
+ recipe = get_recipe(args.name)
269
+
270
+ if not recipe:
271
+ print(f"Recipe not found: {args.name}")
272
+ return 1
273
+
274
+ # Check safety requirements
275
+ safety = recipe.get("safety", {})
276
+
277
+ if safety.get("requires_consent") and not args.consent:
278
+ print(f"This recipe requires consent: {safety.get('consent_message', '')}")
279
+ print("Use --consent flag to acknowledge.")
280
+ return 1
281
+
282
+ if safety.get("legal_disclaimer"):
283
+ print(f"LEGAL DISCLAIMER: {safety['legal_disclaimer']}")
284
+
285
+ # Check dependencies
286
+ if not args.skip_checks:
287
+ deps = check_dependencies(recipe)
288
+ missing = [k for k, v in deps.items() if not v]
289
+ if missing:
290
+ print(f"Missing dependencies: {', '.join(missing)}")
291
+ print("Run 'praison recipes doctor {args.name}' for details.")
292
+ if not args.force:
293
+ return 1
294
+
295
+ # Dry run mode
296
+ if args.dry_run or (safety.get("dry_run_default") and not args.write):
297
+ print(f"DRY RUN: Would execute recipe '{args.name}'")
298
+ print(f" Input: {args.input}")
299
+ print(f" Output: {args.output or 'default'}")
300
+ print("\nUse --write to execute.")
301
+ return 0
302
+
303
+ # Execute recipe
304
+ print(f"Running recipe: {args.name}")
305
+ print(f"Input: {args.input}")
306
+
307
+ # TODO: Implement actual recipe execution via praisonaiagents
308
+ # For now, show what would be executed
309
+ print("\nRecipe execution would involve:")
310
+ for tool in recipe.get("requires", {}).get("tools", []):
311
+ print(f" - Using {tool}")
312
+
313
+ print("\nRecipe execution completed (placeholder).")
314
+ return 0
315
+
316
+
317
+ def cmd_explain(args: argparse.Namespace) -> int:
318
+ """Explain recipe execution plan."""
319
+ recipe = get_recipe(args.name)
320
+
321
+ if not recipe:
322
+ print(f"Recipe not found: {args.name}")
323
+ return 1
324
+
325
+ print(f"Execution Plan for: {args.name}")
326
+ print("=" * 50)
327
+
328
+ print("\n1. Dependency Check:")
329
+ for tool in recipe.get("requires", {}).get("tools", []):
330
+ print(f" - Load {tool}")
331
+
332
+ print("\n2. Input Processing:")
333
+ inputs = recipe.get("inputs", {})
334
+ for name, spec in inputs.items():
335
+ print(f" - {name}: {spec.get('type', 'unknown')}")
336
+
337
+ print("\n3. Execution:")
338
+ print(f" - Run recipe workflow")
339
+
340
+ print("\n4. Output:")
341
+ outputs = recipe.get("outputs", {})
342
+ for name, spec in outputs.items():
343
+ print(f" - {name}: {spec.get('type', 'unknown')}")
344
+
345
+ return 0
346
+
347
+
348
+ def cmd_init(args: argparse.Namespace) -> int:
349
+ """Initialize recipe in current directory."""
350
+ recipe = get_recipe(args.name)
351
+
352
+ if not recipe:
353
+ print(f"Recipe not found: {args.name}")
354
+ return 1
355
+
356
+ target_dir = Path(args.output) if args.output else Path.cwd() / args.name
357
+
358
+ if target_dir.exists() and not args.force:
359
+ print(f"Directory already exists: {target_dir}")
360
+ print("Use --force to overwrite.")
361
+ return 1
362
+
363
+ import shutil
364
+ source_dir = Path(recipe["path"])
365
+
366
+ if args.dry_run:
367
+ print(f"DRY RUN: Would copy {source_dir} to {target_dir}")
368
+ return 0
369
+
370
+ target_dir.mkdir(parents=True, exist_ok=True)
371
+
372
+ # Copy recipe files
373
+ for item in source_dir.iterdir():
374
+ if item.is_file():
375
+ shutil.copy2(item, target_dir / item.name)
376
+
377
+ print(f"Initialized recipe '{args.name}' in {target_dir}")
378
+ return 0
379
+
380
+
381
+ def setup_parser(subparsers: argparse._SubParsersAction) -> None:
382
+ """Setup recipes subcommand parser."""
383
+ recipes_parser = subparsers.add_parser(
384
+ "recipes",
385
+ help="Manage and run Agent-Recipes",
386
+ description="Commands for managing and running Agent-Recipes templates.",
387
+ )
388
+
389
+ recipes_subparsers = recipes_parser.add_subparsers(dest="recipes_command")
390
+
391
+ # List command
392
+ list_parser = recipes_subparsers.add_parser("list", help="List available recipes")
393
+ list_parser.add_argument("--json", action="store_true", help="Output as JSON")
394
+ list_parser.add_argument("--group", action="store_true", help="Group by category")
395
+ list_parser.set_defaults(func=cmd_list)
396
+
397
+ # Info command
398
+ info_parser = recipes_subparsers.add_parser("info", help="Show recipe details")
399
+ info_parser.add_argument("name", help="Recipe name")
400
+ info_parser.add_argument("--json", action="store_true", help="Output as JSON")
401
+ info_parser.set_defaults(func=cmd_info)
402
+
403
+ # Doctor command
404
+ doctor_parser = recipes_subparsers.add_parser("doctor", help="Check recipe dependencies")
405
+ doctor_parser.add_argument("name", help="Recipe name")
406
+ doctor_parser.set_defaults(func=cmd_doctor)
407
+
408
+ # Run command
409
+ run_parser = recipes_subparsers.add_parser("run", help="Run a recipe")
410
+ run_parser.add_argument("name", help="Recipe name")
411
+ run_parser.add_argument("input", nargs="?", help="Input file or value")
412
+ run_parser.add_argument("--output", "-o", help="Output directory")
413
+ run_parser.add_argument("--dry-run", action="store_true", help="Show what would be done")
414
+ run_parser.add_argument("--write", action="store_true", help="Actually execute (for dry-run-default recipes)")
415
+ run_parser.add_argument("--force", action="store_true", help="Force execution despite missing deps")
416
+ run_parser.add_argument("--consent", action="store_true", help="Acknowledge consent requirements")
417
+ run_parser.add_argument("--skip-checks", action="store_true", help="Skip dependency checks")
418
+ run_parser.add_argument("--json", action="store_true", help="Output as JSON")
419
+ run_parser.set_defaults(func=cmd_run)
420
+
421
+ # Explain command
422
+ explain_parser = recipes_subparsers.add_parser("explain", help="Explain recipe execution plan")
423
+ explain_parser.add_argument("name", help="Recipe name")
424
+ explain_parser.set_defaults(func=cmd_explain)
425
+
426
+ # Init command
427
+ init_parser = recipes_subparsers.add_parser("init", help="Initialize recipe in directory")
428
+ init_parser.add_argument("name", help="Recipe name")
429
+ init_parser.add_argument("--output", "-o", help="Target directory")
430
+ init_parser.add_argument("--force", action="store_true", help="Overwrite existing")
431
+ init_parser.add_argument("--dry-run", action="store_true", help="Show what would be done")
432
+ init_parser.set_defaults(func=cmd_init)
433
+
434
+
435
+ def handle_recipes_command(args: argparse.Namespace) -> int:
436
+ """Handle recipes subcommand."""
437
+ if not hasattr(args, "func"):
438
+ # No subcommand specified, show help
439
+ print("Usage: praison recipes <command> [options]")
440
+ print("\nCommands:")
441
+ print(" list List available recipes")
442
+ print(" info Show recipe details")
443
+ print(" doctor Check recipe dependencies")
444
+ print(" run Run a recipe")
445
+ print(" explain Explain recipe execution plan")
446
+ print(" init Initialize recipe in directory")
447
+ return 0
448
+
449
+ return args.func(args)
@@ -0,0 +1,229 @@
1
+ """
2
+ Registry CLI Feature Handler
3
+
4
+ Provides CLI commands for recipe registry management:
5
+ - serve: Start local HTTP registry server
6
+ - status: Check registry status
7
+
8
+ All commands use the canonical `praisonai registry` prefix.
9
+ """
10
+
11
+ import os
12
+ import sys
13
+ from pathlib import Path
14
+ from typing import Any, Dict, List
15
+
16
+
17
+ class RegistryHandler:
18
+ """
19
+ CLI handler for registry operations.
20
+
21
+ Commands:
22
+ - serve: Start local HTTP registry server
23
+ - status: Check registry server status
24
+ """
25
+
26
+ # Stable exit codes
27
+ EXIT_SUCCESS = 0
28
+ EXIT_GENERAL_ERROR = 1
29
+ EXIT_VALIDATION_ERROR = 2
30
+ EXIT_NETWORK_ERROR = 10
31
+ EXIT_AUTH_ERROR = 9
32
+
33
+ def __init__(self):
34
+ """Initialize the handler."""
35
+ pass
36
+
37
+ def handle(self, args: List[str]) -> int:
38
+ """
39
+ Handle registry subcommand.
40
+
41
+ Args:
42
+ args: Command arguments
43
+
44
+ Returns:
45
+ Exit code
46
+ """
47
+ if not args:
48
+ self._print_help()
49
+ return self.EXIT_SUCCESS
50
+
51
+ command = args[0]
52
+ remaining = args[1:]
53
+
54
+ commands = {
55
+ "serve": self.cmd_serve,
56
+ "status": self.cmd_status,
57
+ "help": lambda _: self._print_help() or self.EXIT_SUCCESS,
58
+ "--help": lambda _: self._print_help() or self.EXIT_SUCCESS,
59
+ "-h": lambda _: self._print_help() or self.EXIT_SUCCESS,
60
+ }
61
+
62
+ handler = commands.get(command)
63
+ if handler:
64
+ return handler(remaining)
65
+
66
+ self._print_error(f"Unknown command: {command}")
67
+ self._print_help()
68
+ return self.EXIT_VALIDATION_ERROR
69
+
70
+ def _print_help(self):
71
+ """Print help message."""
72
+ print("""
73
+ PraisonAI Registry Commands
74
+
75
+ Usage: praisonai registry <command> [options]
76
+
77
+ Commands:
78
+ serve Start local HTTP registry server
79
+ status Check registry server status
80
+
81
+ Examples:
82
+ praisonai registry serve
83
+ praisonai registry serve --port 7777 --token mysecret
84
+ praisonai registry serve --read-only
85
+ praisonai registry status --registry http://localhost:7777
86
+
87
+ Options for 'serve':
88
+ --host HOST Host to bind to (default: 127.0.0.1)
89
+ --port PORT Port to bind to (default: 7777)
90
+ --dir PATH Registry directory (default: ~/.praison/registry)
91
+ --token TOKEN Require token for write operations
92
+ --read-only Disable all write operations
93
+ --json Output in JSON format
94
+
95
+ Options for 'status':
96
+ --registry URL Registry URL to check (default: http://localhost:7777)
97
+ --json Output in JSON format
98
+ """)
99
+
100
+ def _print_error(self, message: str):
101
+ """Print error message."""
102
+ print(f"Error: {message}", file=sys.stderr)
103
+
104
+ def _print_success(self, message: str):
105
+ """Print success message."""
106
+ print(f"✓ {message}")
107
+
108
+ def _print_json(self, data: Any):
109
+ """Print JSON output."""
110
+ import json
111
+ print(json.dumps(data, indent=2))
112
+
113
+ def _parse_args(self, args: List[str], spec: Dict[str, Any]) -> Dict[str, Any]:
114
+ """Parse command arguments based on spec."""
115
+ result = {k: v.get("default") for k, v in spec.items()}
116
+
117
+ i = 0
118
+ while i < len(args):
119
+ arg = args[i]
120
+
121
+ if arg.startswith("--"):
122
+ key = arg[2:].replace("-", "_")
123
+ if key in spec:
124
+ if spec[key].get("flag"):
125
+ result[key] = True
126
+ elif i + 1 < len(args):
127
+ result[key] = args[i + 1]
128
+ i += 1
129
+ elif arg.startswith("-") and len(arg) == 2:
130
+ # Short flag
131
+ for key, val in spec.items():
132
+ if val.get("short") == arg:
133
+ if val.get("flag"):
134
+ result[key] = True
135
+ elif i + 1 < len(args):
136
+ result[key] = args[i + 1]
137
+ i += 1
138
+ break
139
+ i += 1
140
+
141
+ return result
142
+
143
+ def cmd_serve(self, args: List[str]) -> int:
144
+ """Start local HTTP registry server."""
145
+ spec = {
146
+ "host": {"default": "127.0.0.1"},
147
+ "port": {"default": "7777"},
148
+ "dir": {"default": None},
149
+ "token": {"default": None},
150
+ "read_only": {"flag": True, "default": False},
151
+ "json": {"flag": True, "default": False},
152
+ }
153
+ parsed = self._parse_args(args, spec)
154
+
155
+ try:
156
+ from praisonai.recipe.server import run_server
157
+ from praisonai.recipe.registry import DEFAULT_REGISTRY_PATH
158
+
159
+ host = parsed["host"]
160
+ port = int(parsed["port"])
161
+ registry_path = Path(parsed["dir"]) if parsed["dir"] else DEFAULT_REGISTRY_PATH
162
+ token = parsed["token"] or os.environ.get("PRAISONAI_REGISTRY_TOKEN")
163
+ read_only = parsed["read_only"]
164
+
165
+ if parsed["json"]:
166
+ self._print_json({
167
+ "ok": True,
168
+ "message": "Starting registry server",
169
+ "host": host,
170
+ "port": port,
171
+ "registry_path": str(registry_path),
172
+ "read_only": read_only,
173
+ "auth_required": bool(token),
174
+ })
175
+
176
+ run_server(
177
+ host=host,
178
+ port=port,
179
+ registry_path=registry_path,
180
+ token=token,
181
+ read_only=read_only,
182
+ )
183
+
184
+ return self.EXIT_SUCCESS
185
+
186
+ except KeyboardInterrupt:
187
+ print("\nServer stopped.")
188
+ return self.EXIT_SUCCESS
189
+ except Exception as e:
190
+ self._print_error(str(e))
191
+ return self.EXIT_GENERAL_ERROR
192
+
193
+ def cmd_status(self, args: List[str]) -> int:
194
+ """Check registry server status."""
195
+ spec = {
196
+ "registry": {"default": "http://localhost:7777"},
197
+ "json": {"flag": True, "default": False},
198
+ }
199
+ parsed = self._parse_args(args, spec)
200
+
201
+ try:
202
+ from praisonai.recipe.registry import HttpRegistry
203
+
204
+ registry = HttpRegistry(parsed["registry"])
205
+ health = registry.health()
206
+
207
+ if parsed["json"]:
208
+ self._print_json(health)
209
+ else:
210
+ status = "healthy" if health.get("ok") else "unhealthy"
211
+ print(f"Registry: {parsed['registry']}")
212
+ print(f"Status: {status}")
213
+ if health.get("read_only"):
214
+ print("Mode: read-only")
215
+ if health.get("auth_required"):
216
+ print("Auth: required for writes")
217
+
218
+ return self.EXIT_SUCCESS
219
+
220
+ except Exception as e:
221
+ if parsed["json"]:
222
+ self._print_json({
223
+ "ok": False,
224
+ "error": str(e),
225
+ "registry": parsed["registry"],
226
+ })
227
+ else:
228
+ self._print_error(f"Cannot connect to registry: {e}")
229
+ return self.EXIT_NETWORK_ERROR