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,511 @@
1
+ """
2
+ Debug and Simulation CLI Commands for PraisonAI TUI.
3
+
4
+ Provides headless TUI simulation, tracing, and debugging capabilities.
5
+ """
6
+
7
+ import asyncio
8
+ import json
9
+ import sys
10
+ import time
11
+ from pathlib import Path
12
+ from typing import Any, Dict, List, Optional
13
+
14
+ try:
15
+ import typer
16
+ from rich.console import Console
17
+ from rich.table import Table
18
+ from rich.panel import Panel
19
+ from rich.live import Live
20
+ from rich.text import Text
21
+ TYPER_AVAILABLE = True
22
+ except ImportError:
23
+ TYPER_AVAILABLE = False
24
+ typer = None
25
+
26
+ console = Console() if TYPER_AVAILABLE else None
27
+
28
+
29
+ def create_debug_app():
30
+ """Create the debug CLI app with simulation commands."""
31
+ if not TYPER_AVAILABLE:
32
+ return None
33
+
34
+ app = typer.Typer(
35
+ name="tui",
36
+ help="TUI and simulation commands",
37
+ no_args_is_help=True,
38
+ )
39
+
40
+ @app.command("launch")
41
+ def tui_launch(
42
+ workspace: Optional[str] = typer.Option(None, "--workspace", "-w"),
43
+ session: Optional[str] = typer.Option(None, "--session", "-s"),
44
+ model: Optional[str] = typer.Option(None, "--model", "-m"),
45
+ debug: bool = typer.Option(False, "--debug", "-d", help="Enable debug overlays"),
46
+ log_jsonl: Optional[str] = typer.Option(None, "--log-jsonl", help="Write events to JSONL file"),
47
+ profile: bool = typer.Option(False, "--profile", help="Enable performance profiling"),
48
+ ):
49
+ """Launch the interactive TUI."""
50
+ try:
51
+ from .app import run_tui
52
+ except ImportError:
53
+ console.print("[red]Textual is required for TUI. Install with:[/red]\n pip install praisonai[tui]")
54
+ raise typer.Exit(1)
55
+
56
+ # Set debug environment
57
+ if debug:
58
+ import os
59
+ os.environ["PRAISONAI_TUI_DEBUG"] = "1"
60
+
61
+ if log_jsonl:
62
+ import os
63
+ os.environ["PRAISONAI_TUI_JSONL"] = log_jsonl
64
+
65
+ run_tui(workspace=workspace, session_id=session, model=model)
66
+
67
+ @app.command("simulate")
68
+ def tui_simulate(
69
+ script: str = typer.Argument(..., help="Path to simulation script (YAML/JSON)"),
70
+ mock: bool = typer.Option(True, "--mock/--real-llm", help="Use mock provider"),
71
+ pretty: bool = typer.Option(True, "--pretty/--jsonl", help="Output format"),
72
+ assert_mode: bool = typer.Option(False, "--assert", help="Validate expected outcomes"),
73
+ timeout: float = typer.Option(60.0, "--timeout", help="Max execution time"),
74
+ ):
75
+ """Run a headless TUI simulation script."""
76
+ import os
77
+
78
+ # Safety gate for real LLM
79
+ if not mock:
80
+ if not os.environ.get("PRAISONAI_REAL_LLM"):
81
+ console.print("[red]Real LLM mode requires PRAISONAI_REAL_LLM=1 environment variable[/red]")
82
+ raise typer.Exit(1)
83
+
84
+ # Load script
85
+ script_path = Path(script)
86
+ if not script_path.exists():
87
+ console.print(f"[red]Script not found: {script}[/red]")
88
+ raise typer.Exit(1)
89
+
90
+ with open(script_path) as f:
91
+ if script_path.suffix in (".yaml", ".yml"):
92
+ import yaml
93
+ script_data = yaml.safe_load(f)
94
+ else:
95
+ script_data = json.load(f)
96
+
97
+ # Run simulation
98
+ from .orchestrator import TuiOrchestrator, SimulationRunner, OutputMode
99
+ from ..queue import QueueConfig
100
+
101
+ output_mode = OutputMode.PRETTY if pretty else OutputMode.JSONL
102
+
103
+ config = QueueConfig(enable_persistence=not mock)
104
+ orchestrator = TuiOrchestrator(
105
+ queue_config=config,
106
+ output_mode=output_mode,
107
+ debug=True,
108
+ )
109
+
110
+ runner = SimulationRunner(orchestrator, assert_mode=assert_mode)
111
+
112
+ async def run():
113
+ return await asyncio.wait_for(
114
+ runner.run_script(script_data),
115
+ timeout=timeout
116
+ )
117
+
118
+ try:
119
+ success = asyncio.run(run())
120
+ except asyncio.TimeoutError:
121
+ console.print(f"[red]Simulation timed out after {timeout}s[/red]")
122
+ raise typer.Exit(1)
123
+
124
+ # Print summary
125
+ summary = runner.get_summary()
126
+ if assert_mode:
127
+ console.print(Panel(
128
+ f"Passed: {summary['assertions_passed']}\n"
129
+ f"Failed: {summary['assertions_failed']}\n"
130
+ f"Errors: {len(summary['errors'])}",
131
+ title="Simulation Results"
132
+ ))
133
+
134
+ if summary['errors']:
135
+ for error in summary['errors']:
136
+ console.print(f"[red] ✗ {error}[/red]")
137
+
138
+ if not success:
139
+ raise typer.Exit(1)
140
+
141
+ @app.command("snapshot")
142
+ def tui_snapshot(
143
+ session: Optional[str] = typer.Option(None, "--session", "-s"),
144
+ run_id: Optional[str] = typer.Option(None, "--run", "-r"),
145
+ json_output: bool = typer.Option(False, "--json", "-j"),
146
+ ):
147
+ """Print a TUI-like snapshot of current state."""
148
+ from ..queue import QueuePersistence, RunState
149
+
150
+ persistence = QueuePersistence()
151
+ persistence.initialize()
152
+
153
+ # Build snapshot
154
+ snapshot = {
155
+ "timestamp": time.time(),
156
+ "session_id": session,
157
+ }
158
+
159
+ # Get runs
160
+ runs = persistence.list_runs(session_id=session, limit=100)
161
+
162
+ queued = [r for r in runs if r.state == RunState.QUEUED]
163
+ running = [r for r in runs if r.state == RunState.RUNNING]
164
+ recent = [r for r in runs if r.state.is_terminal()][-5:]
165
+
166
+ snapshot["queued_count"] = len(queued)
167
+ snapshot["running_count"] = len(running)
168
+ snapshot["recent_runs"] = [
169
+ {
170
+ "run_id": r.run_id[:8],
171
+ "agent": r.agent_name,
172
+ "state": r.state.value,
173
+ "input": r.input_content[:50],
174
+ }
175
+ for r in recent
176
+ ]
177
+
178
+ # Get specific run if requested
179
+ if run_id:
180
+ run = persistence.load_run(run_id)
181
+ if run:
182
+ snapshot["run"] = run.to_dict()
183
+
184
+ # Get session info
185
+ if session:
186
+ session_data = persistence.load_session(session)
187
+ if session_data:
188
+ snapshot["session"] = session_data
189
+
190
+ persistence.close()
191
+
192
+ if json_output:
193
+ console.print(json.dumps(snapshot, indent=2, default=str))
194
+ else:
195
+ # Pretty print
196
+ console.print("─" * 60)
197
+ console.print(f"◉ PraisonAI Snapshot │ {time.strftime('%Y-%m-%d %H:%M:%S')}")
198
+ console.print("─" * 60)
199
+
200
+ console.print(f"\n[bold]Queue Status[/bold]")
201
+ console.print(f" Queued: {snapshot['queued_count']} │ Running: {snapshot['running_count']}")
202
+
203
+ if snapshot["recent_runs"]:
204
+ console.print(f"\n[bold]Recent Runs[/bold]")
205
+ for r in snapshot["recent_runs"]:
206
+ state_color = {
207
+ "succeeded": "green",
208
+ "failed": "red",
209
+ "cancelled": "dim",
210
+ }.get(r["state"], "yellow")
211
+ console.print(f" [{state_color}]{r['run_id']}[/{state_color}] {r['agent']}: {r['input'][:30]}...")
212
+
213
+ if "run" in snapshot:
214
+ console.print(f"\n[bold]Run Details[/bold]")
215
+ run = snapshot["run"]
216
+ console.print(f" ID: {run.get('run_id', 'N/A')}")
217
+ console.print(f" State: {run.get('state', 'N/A')}")
218
+ console.print(f" Agent: {run.get('agent_name', 'N/A')}")
219
+
220
+ console.print("─" * 60)
221
+
222
+ @app.command("trace")
223
+ def tui_trace(
224
+ id: str = typer.Argument(..., help="Session or run ID to trace"),
225
+ follow: bool = typer.Option(False, "--follow", "-f", help="Follow new events"),
226
+ limit: int = typer.Option(50, "--limit", "-n", help="Max events to show"),
227
+ ):
228
+ """Replay events from persistence like a timeline."""
229
+ from ..queue import QueuePersistence
230
+
231
+ persistence = QueuePersistence()
232
+ persistence.initialize()
233
+
234
+ # Try to find as session or run
235
+ session = persistence.load_session(id)
236
+ run = persistence.load_run(id)
237
+
238
+ if not session and not run:
239
+ # Try partial match
240
+ runs = persistence.list_runs(limit=100)
241
+ matches = [r for r in runs if r.run_id.startswith(id) or r.session_id.startswith(id)]
242
+ if matches:
243
+ run = matches[0]
244
+
245
+ if not session and not run:
246
+ console.print(f"[red]No session or run found for: {id}[/red]")
247
+ persistence.close()
248
+ raise typer.Exit(1)
249
+
250
+ # Get runs for timeline
251
+ if session:
252
+ runs = persistence.list_runs(session_id=id, limit=limit)
253
+ else:
254
+ runs = [run] if run else []
255
+
256
+ # Build timeline
257
+ events = []
258
+ for r in runs:
259
+ events.append({
260
+ "timestamp": r.created_at,
261
+ "type": "run_created",
262
+ "run_id": r.run_id[:8],
263
+ "agent": r.agent_name,
264
+ "input": r.input_content[:50],
265
+ })
266
+ if r.started_at:
267
+ events.append({
268
+ "timestamp": r.started_at,
269
+ "type": "run_started",
270
+ "run_id": r.run_id[:8],
271
+ })
272
+ if r.ended_at:
273
+ events.append({
274
+ "timestamp": r.ended_at,
275
+ "type": f"run_{r.state.value}",
276
+ "run_id": r.run_id[:8],
277
+ })
278
+
279
+ # Sort by timestamp
280
+ events.sort(key=lambda e: e["timestamp"])
281
+
282
+ persistence.close()
283
+
284
+ # Print timeline
285
+ console.print(f"\n[bold]Event Timeline for {id[:8]}[/bold]\n")
286
+
287
+ for event in events[-limit:]:
288
+ ts = time.strftime("%H:%M:%S", time.localtime(event["timestamp"]))
289
+ event_type = event["type"]
290
+
291
+ type_colors = {
292
+ "run_created": "cyan",
293
+ "run_started": "yellow",
294
+ "run_succeeded": "green",
295
+ "run_failed": "red",
296
+ "run_cancelled": "dim",
297
+ }
298
+ color = type_colors.get(event_type, "white")
299
+
300
+ line = f"[dim]{ts}[/dim] [{color}]{event_type:15}[/{color}]"
301
+ if "run_id" in event:
302
+ line += f" run={event['run_id']}"
303
+ if "agent" in event:
304
+ line += f" agent={event['agent']}"
305
+ if "input" in event:
306
+ line += f" \"{event['input']}...\""
307
+
308
+ console.print(line)
309
+
310
+ if follow:
311
+ console.print("\n[dim]Following... (Ctrl+C to stop)[/dim]")
312
+ # In a real implementation, this would poll for new events
313
+
314
+ return app
315
+
316
+
317
+ def create_queue_watch_command():
318
+ """Create the queue watch command."""
319
+ if not TYPER_AVAILABLE:
320
+ return None
321
+
322
+ def queue_watch(
323
+ state: Optional[str] = typer.Option(None, "--state", "-s"),
324
+ agent: Optional[str] = typer.Option(None, "--agent", "-a"),
325
+ run_id: Optional[str] = typer.Option(None, "--run", "-r"),
326
+ jsonl: bool = typer.Option(False, "--jsonl", "-j"),
327
+ interval: float = typer.Option(1.0, "--interval", "-i"),
328
+ ):
329
+ """Watch queue events in real time."""
330
+ from ..queue import QueuePersistence, RunState
331
+
332
+ persistence = QueuePersistence()
333
+ persistence.initialize()
334
+
335
+ last_seen = {}
336
+
337
+ try:
338
+ while True:
339
+ runs = persistence.list_runs(limit=100)
340
+
341
+ # Filter
342
+ if state:
343
+ try:
344
+ state_filter = RunState(state.lower())
345
+ runs = [r for r in runs if r.state == state_filter]
346
+ except ValueError:
347
+ pass
348
+
349
+ if agent:
350
+ runs = [r for r in runs if agent.lower() in r.agent_name.lower()]
351
+
352
+ if run_id:
353
+ runs = [r for r in runs if r.run_id.startswith(run_id)]
354
+
355
+ # Check for changes
356
+ for run in runs:
357
+ key = run.run_id
358
+ current_state = run.state.value
359
+
360
+ if key not in last_seen or last_seen[key] != current_state:
361
+ last_seen[key] = current_state
362
+
363
+ if jsonl:
364
+ event = {
365
+ "timestamp": time.time(),
366
+ "run_id": run.run_id,
367
+ "agent": run.agent_name,
368
+ "state": current_state,
369
+ }
370
+ print(json.dumps(event))
371
+ else:
372
+ ts = time.strftime("%H:%M:%S")
373
+ state_colors = {
374
+ "queued": "yellow",
375
+ "running": "cyan",
376
+ "succeeded": "green",
377
+ "failed": "red",
378
+ "cancelled": "dim",
379
+ }
380
+ color = state_colors.get(current_state, "white")
381
+ console.print(
382
+ f"[dim]{ts}[/dim] [{color}]{current_state:10}[/{color}] "
383
+ f"{run.run_id[:8]} {run.agent_name}"
384
+ )
385
+
386
+ time.sleep(interval)
387
+
388
+ except KeyboardInterrupt:
389
+ console.print("\n[dim]Stopped watching[/dim]")
390
+ finally:
391
+ persistence.close()
392
+
393
+ return queue_watch
394
+
395
+
396
+ def create_doctor_command():
397
+ """Create the doctor command for TUI diagnostics."""
398
+ if not TYPER_AVAILABLE:
399
+ return None
400
+
401
+ def doctor_tui():
402
+ """Validate TUI dependencies, DB schema, and wiring."""
403
+ checks = []
404
+
405
+ # Check Textual
406
+ try:
407
+ import textual
408
+ checks.append(("Textual", "✓", f"v{textual.__version__}", "green"))
409
+ except ImportError:
410
+ checks.append(("Textual", "✗", "Not installed", "red"))
411
+
412
+ # Check Rich
413
+ try:
414
+ import rich
415
+ checks.append(("Rich", "✓", f"v{rich.__version__}", "green"))
416
+ except ImportError:
417
+ checks.append(("Rich", "✗", "Not installed", "red"))
418
+
419
+ # Check Typer
420
+ try:
421
+ import typer
422
+ checks.append(("Typer", "✓", f"v{typer.__version__}", "green"))
423
+ except ImportError:
424
+ checks.append(("Typer", "✗", "Not installed", "red"))
425
+
426
+ # Check queue modules
427
+ try:
428
+ from ..queue import QueueManager, QueueScheduler, QueuePersistence
429
+ checks.append(("Queue System", "✓", "All modules loaded", "green"))
430
+ except ImportError as e:
431
+ checks.append(("Queue System", "✗", str(e), "red"))
432
+
433
+ # Check TUI modules
434
+ try:
435
+ from .orchestrator import TuiOrchestrator
436
+ checks.append(("TUI Orchestrator", "✓", "Loaded", "green"))
437
+ except ImportError as e:
438
+ checks.append(("TUI Orchestrator", "✗", str(e), "red"))
439
+
440
+ # Check events
441
+ try:
442
+ from .events import TUIEvent, TUIEventType
443
+ event_count = len(TUIEventType)
444
+ checks.append(("TUI Events", "✓", f"{event_count} event types", "green"))
445
+ except ImportError as e:
446
+ checks.append(("TUI Events", "✗", str(e), "red"))
447
+
448
+ # Check DB
449
+ try:
450
+ from ..queue import QueuePersistence
451
+ p = QueuePersistence()
452
+ p.initialize()
453
+ stats = p.get_stats()
454
+ p.close()
455
+ checks.append(("Database", "✓", f"{stats.total_runs} runs in DB", "green"))
456
+ except Exception as e:
457
+ checks.append(("Database", "✗", str(e), "red"))
458
+
459
+ # Check slash commands
460
+ try:
461
+ from ..slash_commands import SlashCommandRegistry
462
+ registry = SlashCommandRegistry()
463
+ cmd_count = len(registry.commands)
464
+ checks.append(("Slash Commands", "✓", f"{cmd_count} commands", "green"))
465
+ except Exception as e:
466
+ checks.append(("Slash Commands", "⚠", str(e), "yellow"))
467
+
468
+ # Print results
469
+ console.print("\n[bold]PraisonAI TUI Diagnostics[/bold]\n")
470
+
471
+ table = Table(show_header=True)
472
+ table.add_column("Component")
473
+ table.add_column("Status")
474
+ table.add_column("Details")
475
+
476
+ all_ok = True
477
+ for name, status, details, color in checks:
478
+ table.add_row(name, f"[{color}]{status}[/{color}]", details)
479
+ if status == "✗":
480
+ all_ok = False
481
+
482
+ console.print(table)
483
+
484
+ if all_ok:
485
+ console.print("\n[green]All checks passed![/green]")
486
+ else:
487
+ console.print("\n[red]Some checks failed. Run 'pip install praisonai[tui]' to install missing dependencies.[/red]")
488
+ raise typer.Exit(1)
489
+
490
+ return doctor_tui
491
+
492
+
493
+ def register_debug_commands(app):
494
+ """Register debug commands with the main CLI app."""
495
+ if not TYPER_AVAILABLE:
496
+ return
497
+
498
+ debug_app = create_debug_app()
499
+ watch_cmd = create_queue_watch_command()
500
+ doctor_cmd = create_doctor_command()
501
+
502
+ if debug_app:
503
+ app.add_typer(debug_app, name="tui")
504
+
505
+ if watch_cmd:
506
+ # Add to queue subcommand
507
+ pass # Will be added via queue app
508
+
509
+ if doctor_cmd:
510
+ # Add doctor --tui option
511
+ pass # Will be added via main app
@@ -0,0 +1,99 @@
1
+ """
2
+ Custom events for PraisonAI TUI.
3
+
4
+ Defines event types for communication between TUI components.
5
+ """
6
+
7
+ from dataclasses import dataclass, field
8
+ from enum import Enum
9
+ from typing import Any, Dict, Optional
10
+ import time
11
+
12
+
13
+ class TUIEventType(str, Enum):
14
+ """Types of TUI events."""
15
+ # User input events
16
+ MESSAGE_SUBMITTED = "message_submitted"
17
+ COMMAND_EXECUTED = "command_executed"
18
+
19
+ # Queue events
20
+ RUN_QUEUED = "run_queued"
21
+ RUN_STARTED = "run_started"
22
+ RUN_COMPLETED = "run_completed"
23
+ RUN_FAILED = "run_failed"
24
+ RUN_CANCELLED = "run_cancelled"
25
+
26
+ # Output events
27
+ OUTPUT_CHUNK = "output_chunk"
28
+ OUTPUT_COMPLETE = "output_complete"
29
+
30
+ # Tool events
31
+ TOOL_CALL_STARTED = "tool_call_started"
32
+ TOOL_CALL_COMPLETED = "tool_call_completed"
33
+ TOOL_APPROVAL_REQUIRED = "tool_approval_required"
34
+
35
+ # Session events
36
+ SESSION_STARTED = "session_started"
37
+ SESSION_SAVED = "session_saved"
38
+ SESSION_LOADED = "session_loaded"
39
+
40
+ # UI events
41
+ SCREEN_CHANGED = "screen_changed"
42
+ FOCUS_CHANGED = "focus_changed"
43
+ ERROR_OCCURRED = "error_occurred"
44
+ STATUS_UPDATED = "status_updated"
45
+
46
+
47
+ @dataclass
48
+ class TUIEvent:
49
+ """A TUI event."""
50
+ event_type: TUIEventType
51
+ timestamp: float = field(default_factory=time.time)
52
+ data: Dict[str, Any] = field(default_factory=dict)
53
+
54
+ # Optional identifiers
55
+ run_id: Optional[str] = None
56
+ session_id: Optional[str] = None
57
+ agent_name: Optional[str] = None
58
+
59
+ @classmethod
60
+ def message_submitted(cls, content: str, **kwargs) -> "TUIEvent":
61
+ """Create a message submitted event."""
62
+ return cls(
63
+ event_type=TUIEventType.MESSAGE_SUBMITTED,
64
+ data={"content": content, **kwargs}
65
+ )
66
+
67
+ @classmethod
68
+ def output_chunk(cls, run_id: str, content: str, **kwargs) -> "TUIEvent":
69
+ """Create an output chunk event."""
70
+ return cls(
71
+ event_type=TUIEventType.OUTPUT_CHUNK,
72
+ run_id=run_id,
73
+ data={"content": content, **kwargs}
74
+ )
75
+
76
+ @classmethod
77
+ def run_completed(cls, run_id: str, output: str, **kwargs) -> "TUIEvent":
78
+ """Create a run completed event."""
79
+ return cls(
80
+ event_type=TUIEventType.RUN_COMPLETED,
81
+ run_id=run_id,
82
+ data={"output": output, **kwargs}
83
+ )
84
+
85
+ @classmethod
86
+ def error(cls, message: str, **kwargs) -> "TUIEvent":
87
+ """Create an error event."""
88
+ return cls(
89
+ event_type=TUIEventType.ERROR_OCCURRED,
90
+ data={"message": message, **kwargs}
91
+ )
92
+
93
+ @classmethod
94
+ def status_update(cls, status: str, **kwargs) -> "TUIEvent":
95
+ """Create a status update event."""
96
+ return cls(
97
+ event_type=TUIEventType.STATUS_UPDATED,
98
+ data={"status": status, **kwargs}
99
+ )