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,210 @@
1
+ """
2
+ MCP command group for PraisonAI CLI.
3
+
4
+ Provides MCP (Model Context Protocol) server management.
5
+ """
6
+
7
+ from typing import Optional
8
+
9
+ import typer
10
+
11
+ from ..output.console import get_output_controller
12
+ from ..configuration.loader import get_config_loader
13
+
14
+ app = typer.Typer(help="MCP server management")
15
+
16
+
17
+ @app.command("list")
18
+ def mcp_list(
19
+ json_output: bool = typer.Option(False, "--json", help="Output JSON"),
20
+ ):
21
+ """List configured MCP servers."""
22
+ output = get_output_controller()
23
+ loader = get_config_loader()
24
+
25
+ config = loader.load()
26
+ servers = config.mcp.servers
27
+
28
+ if output.is_json_mode or json_output:
29
+ output.print_json({
30
+ "servers": {
31
+ name: {
32
+ "command": s.command,
33
+ "args": s.args,
34
+ "enabled": s.enabled,
35
+ }
36
+ for name, s in servers.items()
37
+ }
38
+ })
39
+ return
40
+
41
+ if not servers:
42
+ output.print_info("No MCP servers configured")
43
+ output.print("\nAdd a server with: praisonai mcp add <name> <command>")
44
+ return
45
+
46
+ headers = ["Name", "Command", "Enabled"]
47
+ rows = []
48
+ for name, server in servers.items():
49
+ cmd = f"{server.command} {' '.join(server.args)}"
50
+ if len(cmd) > 50:
51
+ cmd = cmd[:47] + "..."
52
+ rows.append([name, cmd, "āœ“" if server.enabled else "āœ—"])
53
+
54
+ output.print_table(headers, rows, title="MCP Servers")
55
+
56
+
57
+ @app.command("add")
58
+ def mcp_add(
59
+ name: str = typer.Argument(..., help="Server name"),
60
+ command: str = typer.Argument(..., help="Command to run"),
61
+ args: Optional[str] = typer.Option(None, "--args", "-a", help="Command arguments (space-separated)"),
62
+ env: Optional[str] = typer.Option(None, "--env", "-e", help="Environment variables (KEY=VALUE,...)"),
63
+ ):
64
+ """Add an MCP server."""
65
+ output = get_output_controller()
66
+ loader = get_config_loader()
67
+
68
+ # Parse args
69
+ arg_list = args.split() if args else []
70
+
71
+ # Parse env
72
+ env_dict = {}
73
+ if env:
74
+ for pair in env.split(","):
75
+ if "=" in pair:
76
+ key, value = pair.split("=", 1)
77
+ env_dict[key.strip()] = value.strip()
78
+
79
+ # Build server config
80
+ server_config = {
81
+ "command": command,
82
+ "args": arg_list,
83
+ "env": env_dict,
84
+ "enabled": True,
85
+ }
86
+
87
+ # Save to config
88
+ loader.set(f"mcp.servers.{name}", server_config)
89
+
90
+ if output.is_json_mode:
91
+ output.print_json({"added": name, "config": server_config})
92
+ else:
93
+ output.print_success(f"Added MCP server: {name}")
94
+
95
+
96
+ @app.command("remove")
97
+ def mcp_remove(
98
+ name: str = typer.Argument(..., help="Server name to remove"),
99
+ confirm: bool = typer.Option(False, "--yes", "-y", help="Skip confirmation"),
100
+ ):
101
+ """Remove an MCP server."""
102
+ output = get_output_controller()
103
+ loader = get_config_loader()
104
+
105
+ config = loader.load()
106
+ if name not in config.mcp.servers:
107
+ output.print_error(f"Server not found: {name}")
108
+ raise typer.Exit(1)
109
+
110
+ if not confirm:
111
+ confirmed = typer.confirm(f"Remove MCP server '{name}'?")
112
+ if not confirmed:
113
+ output.print_info("Cancelled")
114
+ raise typer.Exit(0)
115
+
116
+ # Remove from config by setting to None (will be cleaned up)
117
+ # For now, we need to reload and modify the raw config
118
+ from ..configuration.paths import get_user_config_path
119
+ from ..configuration.loader import _load_toml, _save_toml
120
+
121
+ config_path = get_user_config_path()
122
+ if config_path.exists():
123
+ raw_config = _load_toml(config_path)
124
+ if "mcp" in raw_config and "servers" in raw_config["mcp"]:
125
+ if name in raw_config["mcp"]["servers"]:
126
+ del raw_config["mcp"]["servers"][name]
127
+ _save_toml(config_path, raw_config)
128
+
129
+ if output.is_json_mode:
130
+ output.print_json({"removed": name})
131
+ else:
132
+ output.print_success(f"Removed MCP server: {name}")
133
+
134
+
135
+ @app.command("test")
136
+ def mcp_test(
137
+ name: str = typer.Argument(..., help="Server name to test"),
138
+ timeout: float = typer.Option(10.0, "--timeout", "-t", help="Timeout in seconds"),
139
+ ):
140
+ """Test an MCP server connection."""
141
+ output = get_output_controller()
142
+ loader = get_config_loader()
143
+
144
+ config = loader.load()
145
+ if name not in config.mcp.servers:
146
+ output.print_error(f"Server not found: {name}")
147
+ raise typer.Exit(1)
148
+
149
+ server = config.mcp.servers[name]
150
+
151
+ output.print_info(f"Testing MCP server: {name}")
152
+ output.print(f" Command: {server.command} {' '.join(server.args)}")
153
+
154
+ # Try to start the server and check if it responds
155
+ import subprocess
156
+ import time
157
+
158
+ try:
159
+ cmd = [server.command] + server.args
160
+ env = dict(**server.env) if server.env else None
161
+
162
+ # Start process
163
+ proc = subprocess.Popen(
164
+ cmd,
165
+ stdin=subprocess.PIPE,
166
+ stdout=subprocess.PIPE,
167
+ stderr=subprocess.PIPE,
168
+ env=env,
169
+ )
170
+
171
+ # Wait briefly and check if it's running
172
+ time.sleep(0.5)
173
+
174
+ if proc.poll() is None:
175
+ # Process is running
176
+ proc.terminate()
177
+ proc.wait(timeout=2)
178
+
179
+ if output.is_json_mode:
180
+ output.print_json({"name": name, "status": "ok", "message": "Server started successfully"})
181
+ else:
182
+ output.print_success(f"Server '{name}' started successfully")
183
+ else:
184
+ # Process exited
185
+ stderr = proc.stderr.read().decode() if proc.stderr else ""
186
+ if output.is_json_mode:
187
+ output.print_json({"name": name, "status": "error", "message": stderr or "Server exited immediately"})
188
+ else:
189
+ output.print_error(f"Server exited immediately: {stderr}")
190
+ raise typer.Exit(1)
191
+
192
+ except FileNotFoundError:
193
+ if output.is_json_mode:
194
+ output.print_json({"name": name, "status": "error", "message": f"Command not found: {server.command}"})
195
+ else:
196
+ output.print_error(f"Command not found: {server.command}")
197
+ raise typer.Exit(1)
198
+ except Exception as e:
199
+ if output.is_json_mode:
200
+ output.print_json({"name": name, "status": "error", "message": str(e)})
201
+ else:
202
+ output.print_error(f"Test failed: {e}")
203
+ raise typer.Exit(1)
204
+
205
+
206
+ @app.callback(invoke_without_command=True)
207
+ def mcp_callback(ctx: typer.Context):
208
+ """Show MCP help or list servers."""
209
+ if ctx.invoked_subcommand is None:
210
+ mcp_list(json_output=False)
@@ -0,0 +1,457 @@
1
+ """
2
+ Profile command group for PraisonAI CLI.
3
+
4
+ Provides detailed cProfile-based profiling for query execution.
5
+ """
6
+
7
+ import sys
8
+ from typing import Optional
9
+
10
+ import typer
11
+
12
+ app = typer.Typer(help="Performance profiling and diagnostics")
13
+
14
+
15
+ @app.command("query")
16
+ def profile_query(
17
+ prompt: str = typer.Argument(..., help="Prompt to profile"),
18
+ model: Optional[str] = typer.Option(None, "--model", "-m", help="Model to use"),
19
+ stream: bool = typer.Option(False, "--stream/--no-stream", help="Use streaming mode"),
20
+ deep: bool = typer.Option(False, "--deep", help="Enable deep call tracing (higher overhead)"),
21
+ limit: int = typer.Option(30, "--limit", "-n", help="Top N functions to show"),
22
+ sort: str = typer.Option("cumulative", "--sort", "-s", help="Sort by: cumulative or tottime"),
23
+ show_files: bool = typer.Option(False, "--show-files", help="Group timing by file/module"),
24
+ show_callers: bool = typer.Option(False, "--show-callers", help="Show caller functions"),
25
+ show_callees: bool = typer.Option(False, "--show-callees", help="Show callee functions"),
26
+ importtime: bool = typer.Option(False, "--importtime", help="Show module import times"),
27
+ first_token: bool = typer.Option(False, "--first-token", help="Track time to first token (streaming)"),
28
+ save: Optional[str] = typer.Option(None, "--save", help="Save artifacts to path (creates .prof, .txt)"),
29
+ output_format: str = typer.Option("text", "--format", "-f", help="Output format: text or json"),
30
+ ):
31
+ """
32
+ Profile a query execution with detailed timing breakdown.
33
+
34
+ Shows per-function and per-file timing, call graphs, and latency metrics.
35
+
36
+ Examples:
37
+ praisonai profile query "What is 2+2?"
38
+ praisonai profile query "Hello" --show-files --limit 20
39
+ praisonai profile query "Test" --stream --first-token
40
+ praisonai profile query "Test" --deep --show-callers --show-callees
41
+ praisonai profile query "Test" --save ./profile_results
42
+ """
43
+ # Lazy import to avoid startup overhead
44
+ try:
45
+ from ..features.profiler import (
46
+ ProfilerConfig,
47
+ QueryProfiler,
48
+ format_profile_report,
49
+ )
50
+ except ImportError as e:
51
+ typer.echo(f"Error: Profiler module not available: {e}", err=True)
52
+ raise typer.Exit(1)
53
+
54
+ # Warn about deep tracing overhead
55
+ if deep:
56
+ typer.echo("āš ļø Deep call tracing enabled - this adds significant overhead", err=True)
57
+
58
+ # Create config
59
+ config = ProfilerConfig(
60
+ deep=deep,
61
+ limit=limit,
62
+ sort_by=sort,
63
+ show_files=show_files,
64
+ show_callers=show_callers,
65
+ show_callees=show_callees,
66
+ importtime=importtime,
67
+ first_token=first_token,
68
+ save_path=save,
69
+ output_format=output_format,
70
+ stream=stream,
71
+ )
72
+
73
+ # Run profiler
74
+ typer.echo("šŸ”¬ Starting profiled execution...", err=True)
75
+
76
+ try:
77
+ profiler = QueryProfiler(config)
78
+ result = profiler.profile_query(prompt, model=model, stream=stream)
79
+ except ImportError as e:
80
+ typer.echo(f"Error: {e}", err=True)
81
+ typer.echo("Install praisonaiagents: pip install praisonaiagents", err=True)
82
+ raise typer.Exit(1)
83
+ except Exception as e:
84
+ typer.echo(f"Error during profiling: {e}", err=True)
85
+ raise typer.Exit(1)
86
+
87
+ # Output results
88
+ if output_format == "json":
89
+ import json
90
+ typer.echo(json.dumps(result.to_dict(), indent=2, default=str))
91
+ else:
92
+ report = format_profile_report(result, config)
93
+ typer.echo(report)
94
+
95
+ # Save artifacts if requested
96
+ if save:
97
+ try:
98
+ prof_path, txt_path = profiler.save_artifacts(result, save)
99
+ typer.echo("\nāœ… Artifacts saved:", err=True)
100
+ typer.echo(f" {prof_path}", err=True)
101
+ typer.echo(f" {txt_path}", err=True)
102
+ except Exception as e:
103
+ typer.echo(f"Warning: Failed to save artifacts: {e}", err=True)
104
+
105
+
106
+ @app.command("imports")
107
+ def profile_imports():
108
+ """
109
+ Profile module import times.
110
+
111
+ Shows which modules take longest to import, useful for optimizing startup time.
112
+ """
113
+ import subprocess
114
+ import re
115
+
116
+ typer.echo("šŸ”¬ Profiling import times...", err=True)
117
+
118
+ try:
119
+ result = subprocess.run(
120
+ [sys.executable, "-X", "importtime", "-c", "import praisonaiagents"],
121
+ capture_output=True,
122
+ text=True,
123
+ timeout=60,
124
+ )
125
+
126
+ # Parse import times
127
+ import_times = []
128
+ for line in result.stderr.split('\n'):
129
+ if 'import time:' in line:
130
+ match = re.search(r'import time:\s+(\d+)\s+\|\s+(\d+)\s+\|\s+(.+)', line)
131
+ if match:
132
+ self_time = int(match.group(1))
133
+ cumulative = int(match.group(2))
134
+ module = match.group(3).strip()
135
+ import_times.append((module, self_time, cumulative))
136
+
137
+ # Sort by cumulative time
138
+ import_times.sort(key=lambda x: x[2], reverse=True)
139
+
140
+ # Display
141
+ typer.echo("\n" + "=" * 70)
142
+ typer.echo("Import Time Analysis")
143
+ typer.echo("=" * 70)
144
+ typer.echo(f"{'Module':<45} {'Self (μs)':>10} {'Cumul (μs)':>12}")
145
+ typer.echo("-" * 70)
146
+
147
+ for module, self_time, cumulative in import_times[:30]:
148
+ module_name = module
149
+ if len(module_name) > 43:
150
+ module_name = "..." + module_name[-40:]
151
+ typer.echo(f"{module_name:<45} {self_time:>10} {cumulative:>12}")
152
+
153
+ typer.echo("-" * 70)
154
+
155
+ if import_times:
156
+ total_time = max(t[2] for t in import_times)
157
+ typer.echo(f"Total import time: {total_time / 1000:.2f} ms")
158
+
159
+ except subprocess.TimeoutExpired:
160
+ typer.echo("Error: Import profiling timed out", err=True)
161
+ raise typer.Exit(1)
162
+ except Exception as e:
163
+ typer.echo(f"Error: {e}", err=True)
164
+ raise typer.Exit(1)
165
+
166
+
167
+ @app.command("startup")
168
+ def profile_startup():
169
+ """
170
+ Profile CLI startup time.
171
+
172
+ Measures time from CLI invocation to ready state.
173
+ """
174
+ import time
175
+ import subprocess
176
+
177
+ typer.echo("šŸ”¬ Profiling startup time...", err=True)
178
+
179
+ # Measure cold start (new process)
180
+ start = time.perf_counter()
181
+ subprocess.run(
182
+ [sys.executable, "-c", "import praisonai; import praisonai.cli"],
183
+ capture_output=True,
184
+ text=True,
185
+ )
186
+ cold_start = (time.perf_counter() - start) * 1000
187
+
188
+ # Measure warm start (imports cached)
189
+ start = time.perf_counter()
190
+ subprocess.run(
191
+ [sys.executable, "-c", "import praisonai; import praisonai.cli"],
192
+ capture_output=True,
193
+ text=True,
194
+ )
195
+ warm_start = (time.perf_counter() - start) * 1000
196
+
197
+ typer.echo("\n" + "=" * 50)
198
+ typer.echo("Startup Time Analysis")
199
+ typer.echo("=" * 50)
200
+ typer.echo(f"Cold Start: {cold_start:>10.2f} ms")
201
+ typer.echo(f"Warm Start: {warm_start:>10.2f} ms")
202
+ typer.echo("=" * 50)
203
+
204
+ if cold_start > 1000:
205
+ typer.echo("\nāš ļø Cold start > 1s - consider lazy imports", err=True)
206
+
207
+
208
+ @app.command("suite")
209
+ def profile_suite(
210
+ output_dir: Optional[str] = typer.Option("/tmp/praisonai_profile_suite", "--output", "-o", help="Output directory for results"),
211
+ iterations: int = typer.Option(3, "--iterations", "-n", help="Iterations per scenario"),
212
+ quick: bool = typer.Option(False, "--quick", help="Quick mode (fewer iterations)"),
213
+ ):
214
+ """
215
+ Run a comprehensive profiling suite.
216
+
217
+ Runs multiple scenarios (streaming/non-streaming, simple/complex prompts)
218
+ and produces aggregated statistics and reports.
219
+
220
+ Examples:
221
+ praisonai profile suite
222
+ praisonai profile suite --output ./my_profile_results
223
+ praisonai profile suite --quick
224
+ """
225
+ try:
226
+ from ..features.profiler import run_profile_suite, ScenarioConfig
227
+ except ImportError as e:
228
+ typer.echo(f"Error: Profiler module not available: {e}", err=True)
229
+ raise typer.Exit(1)
230
+
231
+ # Define scenarios
232
+ iters = 1 if quick else iterations
233
+ scenarios = [
234
+ ScenarioConfig(name="simple_non_stream", prompt="hi", stream=False, iterations=iters, warmup=0 if quick else 1),
235
+ ScenarioConfig(name="simple_stream", prompt="hi", stream=True, iterations=iters, warmup=0 if quick else 1),
236
+ ]
237
+
238
+ if not quick:
239
+ scenarios.extend([
240
+ ScenarioConfig(name="medium_non_stream", prompt="Explain Python in 2 sentences", stream=False, iterations=max(1, iters-1)),
241
+ ScenarioConfig(name="medium_stream", prompt="Explain Python in 2 sentences", stream=True, iterations=max(1, iters-1)),
242
+ ])
243
+
244
+ typer.echo("šŸ”¬ Running Profile Suite...", err=True)
245
+ typer.echo(f" Output: {output_dir}", err=True)
246
+ typer.echo(f" Scenarios: {len(scenarios)}", err=True)
247
+ typer.echo(f" Iterations: {iterations}", err=True)
248
+
249
+ try:
250
+ result = run_profile_suite(
251
+ output_dir=output_dir,
252
+ scenarios=scenarios,
253
+ verbose=True,
254
+ )
255
+
256
+ # Print summary
257
+ typer.echo("\n" + "=" * 60)
258
+ typer.echo("Profile Suite Summary")
259
+ typer.echo("=" * 60)
260
+ typer.echo(f"Startup Cold: {result.startup_cold_ms:.2f}ms")
261
+ typer.echo(f"Startup Warm: {result.startup_warm_ms:.2f}ms")
262
+
263
+ if result.import_analysis:
264
+ typer.echo(f"\nTop Import: {result.import_analysis[0]['module']}")
265
+ typer.echo(f" Time: {result.import_analysis[0]['cumulative_ms']:.2f}ms")
266
+
267
+ typer.echo("\nScenario Results:")
268
+ for scenario in result.scenarios:
269
+ stats = scenario.get_stats(scenario.total_times)
270
+ typer.echo(f" {scenario.name}: {stats['mean']:.2f}ms (±{stats['stdev']:.2f}ms)")
271
+
272
+ typer.echo(f"\nāœ… Full results saved to: {output_dir}")
273
+
274
+ except Exception as e:
275
+ typer.echo(f"Error running suite: {e}", err=True)
276
+ raise typer.Exit(1)
277
+
278
+
279
+ @app.command("snapshot")
280
+ def profile_snapshot(
281
+ name: str = typer.Argument("current", help="Name for the snapshot"),
282
+ baseline: bool = typer.Option(False, "--baseline", "-b", help="Save as baseline for comparison"),
283
+ compare: bool = typer.Option(False, "--compare", "-c", help="Compare against baseline"),
284
+ output_format: str = typer.Option("text", "--format", "-f", help="Output format: text or json"),
285
+ ):
286
+ """
287
+ Create or compare performance snapshots.
288
+
289
+ Snapshots record timing data for baseline comparison.
290
+ Use --baseline to save a reference point, then --compare to check for regressions.
291
+
292
+ Examples:
293
+ praisonai profile snapshot --baseline
294
+ praisonai profile snapshot current --compare
295
+ praisonai profile snapshot v2.0 --format json
296
+ """
297
+ try:
298
+ from ..features.profiler import (
299
+ run_profile_suite,
300
+ ScenarioConfig,
301
+ PerfSnapshotManager,
302
+ create_snapshot_from_suite,
303
+ format_comparison_report,
304
+ )
305
+ except ImportError as e:
306
+ typer.echo(f"Error: Profiler module not available: {e}", err=True)
307
+ raise typer.Exit(1)
308
+
309
+ manager = PerfSnapshotManager()
310
+
311
+ if compare:
312
+ # Load baseline and compare
313
+ baseline_snap = manager.load_baseline()
314
+ if not baseline_snap:
315
+ typer.echo("āŒ No baseline found. Create one with: praisonai profile snapshot --baseline", err=True)
316
+ raise typer.Exit(1)
317
+
318
+ typer.echo("šŸ”¬ Running current profile for comparison...", err=True)
319
+
320
+ # Run quick suite
321
+ scenarios = [
322
+ ScenarioConfig(name="simple", prompt="hi", stream=False, iterations=2, warmup=1),
323
+ ]
324
+ result = run_profile_suite(
325
+ output_dir="/tmp/praisonai_snapshot_compare",
326
+ scenarios=scenarios,
327
+ verbose=False,
328
+ )
329
+
330
+ current_snap = create_snapshot_from_suite(result, name)
331
+ comparison = manager.compare(current_snap)
332
+
333
+ if output_format == "json":
334
+ import json
335
+ typer.echo(json.dumps(comparison.to_dict(), indent=2))
336
+ else:
337
+ typer.echo(format_comparison_report(comparison))
338
+
339
+ if comparison.is_regression():
340
+ raise typer.Exit(1) # Exit with error on regression
341
+ else:
342
+ # Create new snapshot
343
+ typer.echo(f"šŸ”¬ Creating performance snapshot '{name}'...", err=True)
344
+
345
+ scenarios = [
346
+ ScenarioConfig(name="simple", prompt="hi", stream=False, iterations=3, warmup=1),
347
+ ScenarioConfig(name="stream", prompt="hi", stream=True, iterations=2, warmup=1),
348
+ ]
349
+ result = run_profile_suite(
350
+ output_dir="/tmp/praisonai_snapshot",
351
+ scenarios=scenarios,
352
+ verbose=True,
353
+ )
354
+
355
+ snapshot = create_snapshot_from_suite(result, name)
356
+
357
+ if baseline:
358
+ path = manager.save_baseline(snapshot)
359
+ typer.echo(f"\nāœ… Baseline saved to: {path}")
360
+ else:
361
+ path = manager.save(snapshot)
362
+ typer.echo(f"\nāœ… Snapshot saved to: {path}")
363
+
364
+ if output_format == "json":
365
+ import json
366
+ typer.echo(json.dumps(snapshot.to_dict(), indent=2))
367
+ else:
368
+ typer.echo("\nSnapshot Summary:")
369
+ typer.echo(f" Startup Cold: {snapshot.startup_cold_ms:.2f}ms")
370
+ typer.echo(f" Import Time: {snapshot.import_time_ms:.2f}ms")
371
+ typer.echo(f" Query Time: {snapshot.query_time_ms:.2f}ms")
372
+
373
+
374
+ @app.command("optimize")
375
+ def profile_optimize(
376
+ prewarm: bool = typer.Option(False, "--prewarm", help="Enable provider pre-warming"),
377
+ lite: bool = typer.Option(False, "--lite", help="Enable lite mode (skip type validation)"),
378
+ show_config: bool = typer.Option(False, "--show", help="Show current optimization config"),
379
+ ):
380
+ """
381
+ Configure performance optimizations.
382
+
383
+ All optimizations are opt-in and safe by default.
384
+
385
+ Examples:
386
+ praisonai profile optimize --show
387
+ praisonai profile optimize --prewarm
388
+ praisonai profile optimize --lite
389
+ """
390
+ try:
391
+ from ..features.profiler import (
392
+ PrewarmManager,
393
+ get_lite_mode_config,
394
+ get_provider_cache,
395
+ )
396
+ except ImportError as e:
397
+ typer.echo(f"Error: Profiler module not available: {e}", err=True)
398
+ raise typer.Exit(1)
399
+
400
+ if show_config:
401
+ typer.echo("=" * 50)
402
+ typer.echo("Performance Optimization Status")
403
+ typer.echo("=" * 50)
404
+
405
+ lite_config = get_lite_mode_config()
406
+ typer.echo(f"\nLite Mode: {'Enabled' if lite_config.enabled else 'Disabled'}")
407
+ if lite_config.enabled:
408
+ typer.echo(f" Skip Type Validation: {lite_config.skip_type_validation}")
409
+ typer.echo(f" Skip Model Validation: {lite_config.skip_model_validation}")
410
+ typer.echo(f" Minimal Imports: {lite_config.minimal_imports}")
411
+
412
+ typer.echo(f"\nPre-warming: {'Enabled' if PrewarmManager.is_enabled() else 'Disabled'}")
413
+
414
+ cache = get_provider_cache()
415
+ stats = cache.get_stats()
416
+ typer.echo("\nProvider Cache:")
417
+ typer.echo(f" Hits: {stats['hits']}")
418
+ typer.echo(f" Misses: {stats['misses']}")
419
+ typer.echo(f" Size: {stats['size']}")
420
+
421
+ typer.echo("\n" + "=" * 50)
422
+ typer.echo("\nTo enable optimizations, set environment variables:")
423
+ typer.echo(" PRAISONAI_LITE_MODE=1")
424
+ typer.echo(" PRAISONAI_SKIP_TYPE_VALIDATION=1")
425
+ typer.echo(" PRAISONAI_MINIMAL_IMPORTS=1")
426
+ return
427
+
428
+ if prewarm:
429
+ typer.echo("šŸ”„ Enabling provider pre-warming...")
430
+ PrewarmManager.enable()
431
+
432
+ import os
433
+ if os.environ.get('OPENAI_API_KEY'):
434
+ typer.echo(" Pre-warming OpenAI...")
435
+ PrewarmManager.prewarm_provider('openai')
436
+ if os.environ.get('ANTHROPIC_API_KEY'):
437
+ typer.echo(" Pre-warming Anthropic...")
438
+ PrewarmManager.prewarm_provider('anthropic')
439
+
440
+ typer.echo("āœ… Pre-warming initiated (runs in background)")
441
+
442
+ if lite:
443
+ typer.echo("⚔ Lite mode configuration:")
444
+ typer.echo(" Set these environment variables to enable:")
445
+ typer.echo(" export PRAISONAI_LITE_MODE=1")
446
+ typer.echo(" export PRAISONAI_SKIP_TYPE_VALIDATION=1")
447
+ typer.echo(" export PRAISONAI_MINIMAL_IMPORTS=1")
448
+
449
+ if not prewarm and not lite and not show_config:
450
+ typer.echo("Use --show to see current config, or --prewarm/--lite to enable optimizations")
451
+
452
+
453
+ @app.callback(invoke_without_command=True)
454
+ def profile_callback(ctx: typer.Context):
455
+ """Show profile help if no subcommand."""
456
+ if ctx.invoked_subcommand is None:
457
+ typer.echo(ctx.get_help())