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,245 @@
1
+ """
2
+ Main Screen for PraisonAI TUI.
3
+
4
+ The primary chat interface screen.
5
+ """
6
+
7
+ from typing import Optional
8
+
9
+ try:
10
+ from textual.screen import Screen
11
+ from textual.containers import Horizontal, Vertical, Container
12
+ from textual.widgets import Static, Footer, Header
13
+ from textual.binding import Binding
14
+ from textual.message import Message
15
+ TEXTUAL_AVAILABLE = True
16
+ except ImportError:
17
+ TEXTUAL_AVAILABLE = False
18
+ Screen = object
19
+ Message = object
20
+
21
+
22
+ if TEXTUAL_AVAILABLE:
23
+ from ..widgets.chat import ChatWidget, ChatMessage
24
+ from ..widgets.composer import ComposerWidget
25
+ from ..widgets.status import StatusWidget, StatusInfo
26
+ from ..widgets.queue_panel import QueuePanelWidget
27
+ from ..widgets.tool_panel import ToolPanelWidget
28
+
29
+ class MainScreen(Screen):
30
+ """
31
+ Main chat screen.
32
+
33
+ Layout:
34
+ - Status bar (top)
35
+ - Chat history (main area)
36
+ - Tools panel (right sidebar)
37
+ - Queue panel (right sidebar)
38
+ - Composer (bottom)
39
+ - Footer with keybindings
40
+ """
41
+
42
+ BINDINGS = [
43
+ Binding("ctrl+q", "quit", "Quit", show=True),
44
+ Binding("ctrl+c", "cancel", "Cancel", show=True),
45
+ Binding("ctrl+l", "clear", "Clear", show=True),
46
+ Binding("f1", "help", "Help", show=True),
47
+ Binding("f2", "toggle_queue", "Queue", show=True),
48
+ Binding("f3", "settings", "Settings", show=True),
49
+ Binding("f5", "clear_chat", "Clear Chat", show=True),
50
+ Binding("tab", "focus_next", "Next", show=False),
51
+ Binding("escape", "cancel_input", "Cancel", show=False),
52
+ ]
53
+
54
+ DEFAULT_CSS = """
55
+ MainScreen {
56
+ layout: grid;
57
+ grid-size: 2;
58
+ grid-columns: 3fr 1fr;
59
+ grid-rows: 1 1fr auto 1;
60
+ }
61
+
62
+ MainScreen #status-bar {
63
+ column-span: 2;
64
+ }
65
+
66
+ MainScreen #main-area {
67
+ height: 100%;
68
+ }
69
+
70
+ MainScreen #sidebar {
71
+ height: 100%;
72
+ }
73
+
74
+ MainScreen #composer-area {
75
+ column-span: 2;
76
+ height: auto;
77
+ max-height: 10;
78
+ }
79
+
80
+ MainScreen Footer {
81
+ column-span: 2;
82
+ }
83
+
84
+ MainScreen .sidebar-panel {
85
+ height: 1fr;
86
+ }
87
+ """
88
+
89
+ class MessageSubmitted(Message):
90
+ """Event when a message is submitted."""
91
+ def __init__(self, content: str):
92
+ self.content = content
93
+ super().__init__()
94
+
95
+ class CommandExecuted(Message):
96
+ """Event when a command is executed."""
97
+ def __init__(self, command: str, args: str):
98
+ self.command = command
99
+ self.args = args
100
+ super().__init__()
101
+
102
+ class CancelRequested(Message):
103
+ """Event when cancel is requested."""
104
+ pass
105
+
106
+ def __init__(
107
+ self,
108
+ show_queue: bool = True,
109
+ show_tools: bool = True,
110
+ name: Optional[str] = None,
111
+ id: Optional[str] = None,
112
+ classes: Optional[str] = None,
113
+ ):
114
+ super().__init__(name=name, id=id, classes=classes)
115
+ self._show_queue = show_queue
116
+ self._show_tools = show_tools
117
+
118
+ def compose(self):
119
+ """Compose the screen."""
120
+ yield StatusWidget(id="status-bar")
121
+
122
+ yield ChatWidget(id="chat-widget")
123
+
124
+ with Vertical(id="sidebar"):
125
+ if self._show_tools:
126
+ yield ToolPanelWidget(id="tool-panel", classes="sidebar-panel")
127
+ if self._show_queue:
128
+ yield QueuePanelWidget(id="queue-panel", classes="sidebar-panel")
129
+
130
+ yield ComposerWidget(id="composer")
131
+
132
+ yield Footer()
133
+
134
+ def on_mount(self) -> None:
135
+ """Handle mount."""
136
+ # Focus composer
137
+ composer = self.query_one("#composer", ComposerWidget)
138
+ composer.focus_input()
139
+
140
+ def on_composer_widget_submitted(self, event: ComposerWidget.Submitted) -> None:
141
+ """Handle message submission."""
142
+ if event.is_command:
143
+ # Parse command
144
+ parts = event.content[1:].split(maxsplit=1)
145
+ command = parts[0] if parts else ""
146
+ args = parts[1] if len(parts) > 1 else ""
147
+ self.post_message(self.CommandExecuted(command, args))
148
+ else:
149
+ self.post_message(self.MessageSubmitted(event.content))
150
+
151
+ def action_quit(self) -> None:
152
+ """Quit the application."""
153
+ self.app.exit()
154
+
155
+ def action_cancel(self) -> None:
156
+ """Cancel current operation."""
157
+ self.post_message(self.CancelRequested())
158
+
159
+ def action_clear(self) -> None:
160
+ """Clear screen."""
161
+ pass
162
+
163
+ def action_help(self) -> None:
164
+ """Show help."""
165
+ self.app.push_screen("help")
166
+
167
+ def action_toggle_queue(self) -> None:
168
+ """Toggle queue panel visibility."""
169
+ try:
170
+ queue_panel = self.query_one("#queue-panel", QueuePanelWidget)
171
+ queue_panel.display = not queue_panel.display
172
+ except Exception:
173
+ pass
174
+
175
+ def action_settings(self) -> None:
176
+ """Show settings."""
177
+ self.app.push_screen("settings")
178
+
179
+ def action_clear_chat(self) -> None:
180
+ """Clear chat history."""
181
+ chat = self.query_one("#chat-widget", ChatWidget)
182
+ self.app.call_later(chat.clear)
183
+
184
+ def action_cancel_input(self) -> None:
185
+ """Cancel current input."""
186
+ composer = self.query_one("#composer", ComposerWidget)
187
+ composer.action_cancel()
188
+
189
+ # Public methods for updating UI
190
+
191
+ async def add_user_message(self, content: str) -> None:
192
+ """Add a user message to chat."""
193
+ chat = self.query_one("#chat-widget", ChatWidget)
194
+ await chat.add_message(ChatMessage(
195
+ role="user",
196
+ content=content,
197
+ ))
198
+
199
+ async def add_assistant_message(
200
+ self,
201
+ content: str,
202
+ run_id: Optional[str] = None,
203
+ agent_name: Optional[str] = None,
204
+ streaming: bool = False,
205
+ ) -> None:
206
+ """Add an assistant message to chat."""
207
+ chat = self.query_one("#chat-widget", ChatWidget)
208
+ await chat.add_message(ChatMessage(
209
+ role="assistant",
210
+ content=content,
211
+ run_id=run_id,
212
+ agent_name=agent_name,
213
+ is_streaming=streaming,
214
+ ))
215
+
216
+ async def update_streaming(self, run_id: str, content: str) -> None:
217
+ """Update streaming message."""
218
+ chat = self.query_one("#chat-widget", ChatWidget)
219
+ await chat.update_streaming(run_id, content)
220
+
221
+ async def complete_streaming(self, run_id: str, content: str) -> None:
222
+ """Complete streaming message."""
223
+ chat = self.query_one("#chat-widget", ChatWidget)
224
+ await chat.complete_streaming(run_id, content)
225
+
226
+ def update_status(self, info: StatusInfo) -> None:
227
+ """Update status bar."""
228
+ status = self.query_one("#status-bar", StatusWidget)
229
+ status.update_info(info)
230
+
231
+ def set_processing(self, processing: bool) -> None:
232
+ """Set processing state."""
233
+ composer = self.query_one("#composer", ComposerWidget)
234
+ composer.set_processing(processing)
235
+
236
+ status = self.query_one("#status-bar", StatusWidget)
237
+ status.is_processing = processing
238
+
239
+ else:
240
+ class MainScreen:
241
+ """Placeholder when Textual is not available."""
242
+ def __init__(self, *args, **kwargs):
243
+ raise ImportError(
244
+ "Textual is required for TUI. Install with: pip install praisonai[tui]"
245
+ )
@@ -0,0 +1,174 @@
1
+ """
2
+ Queue Screen for PraisonAI TUI.
3
+
4
+ Queue management interface.
5
+ """
6
+
7
+ from typing import Optional, List
8
+
9
+ try:
10
+ from textual.screen import Screen
11
+ from textual.containers import Vertical, Horizontal
12
+ from textual.widgets import Static, Footer, DataTable, Button
13
+ from textual.binding import Binding
14
+ from textual.message import Message
15
+ from rich.text import Text
16
+ TEXTUAL_AVAILABLE = True
17
+ except ImportError:
18
+ TEXTUAL_AVAILABLE = False
19
+ Screen = object
20
+ Message = object
21
+
22
+
23
+ if TEXTUAL_AVAILABLE:
24
+ class QueueScreen(Screen):
25
+ """
26
+ Queue management screen.
27
+
28
+ Displays full queue with management options.
29
+ """
30
+
31
+ BINDINGS = [
32
+ Binding("escape", "back", "Back", show=True),
33
+ Binding("c", "cancel", "Cancel", show=True),
34
+ Binding("r", "retry", "Retry", show=True),
35
+ Binding("x", "clear", "Clear Queue", show=True),
36
+ Binding("enter", "select", "Select", show=False),
37
+ ]
38
+
39
+ DEFAULT_CSS = """
40
+ QueueScreen {
41
+ background: $surface;
42
+ }
43
+
44
+ QueueScreen #queue-header {
45
+ height: 3;
46
+ background: $primary;
47
+ padding: 1;
48
+ }
49
+
50
+ QueueScreen DataTable {
51
+ height: 1fr;
52
+ }
53
+
54
+ QueueScreen #queue-actions {
55
+ height: 3;
56
+ padding: 1;
57
+ }
58
+ """
59
+
60
+ class RunCancelled(Message):
61
+ def __init__(self, run_id: str):
62
+ self.run_id = run_id
63
+ super().__init__()
64
+
65
+ class RunRetried(Message):
66
+ def __init__(self, run_id: str):
67
+ self.run_id = run_id
68
+ super().__init__()
69
+
70
+ class QueueCleared(Message):
71
+ pass
72
+
73
+ def __init__(
74
+ self,
75
+ name: Optional[str] = None,
76
+ id: Optional[str] = None,
77
+ classes: Optional[str] = None,
78
+ ):
79
+ super().__init__(name=name, id=id, classes=classes)
80
+ self._selected_run_id: Optional[str] = None
81
+
82
+ def compose(self):
83
+ """Compose the screen."""
84
+ yield Static("Queue Management", id="queue-header")
85
+ yield DataTable(id="queue-table")
86
+ with Horizontal(id="queue-actions"):
87
+ yield Button("Cancel [C]", id="btn-cancel", variant="error")
88
+ yield Button("Retry [R]", id="btn-retry", variant="warning")
89
+ yield Button("Clear [X]", id="btn-clear", variant="default")
90
+ yield Button("Back [Esc]", id="btn-back", variant="primary")
91
+ yield Footer()
92
+
93
+ def on_mount(self) -> None:
94
+ """Handle mount."""
95
+ table = self.query_one("#queue-table", DataTable)
96
+ table.add_columns(
97
+ "ID", "Agent", "Input", "State", "Priority",
98
+ "Wait Time", "Duration"
99
+ )
100
+ table.cursor_type = "row"
101
+
102
+ def update_runs(self, runs: List[dict]) -> None:
103
+ """Update the runs display."""
104
+ table = self.query_one("#queue-table", DataTable)
105
+ table.clear()
106
+
107
+ for run in runs:
108
+ state = run.get("state", "unknown")
109
+ state_style = {
110
+ "queued": "yellow",
111
+ "running": "green",
112
+ "succeeded": "cyan",
113
+ "failed": "red",
114
+ "cancelled": "dim",
115
+ }.get(state, "")
116
+
117
+ state_text = Text(state, style=state_style)
118
+
119
+ input_preview = run.get("input", "")[:40]
120
+ if len(run.get("input", "")) > 40:
121
+ input_preview += "..."
122
+
123
+ table.add_row(
124
+ run.get("run_id", "")[:8],
125
+ run.get("agent_name", ""),
126
+ input_preview,
127
+ state_text,
128
+ run.get("priority", "normal"),
129
+ run.get("wait_time", "-"),
130
+ run.get("duration", "-"),
131
+ key=run.get("run_id"),
132
+ )
133
+
134
+ def on_data_table_row_selected(self, event: DataTable.RowSelected) -> None:
135
+ """Handle row selection."""
136
+ if event.row_key:
137
+ self._selected_run_id = str(event.row_key.value)
138
+
139
+ def on_button_pressed(self, event: Button.Pressed) -> None:
140
+ """Handle button press."""
141
+ if event.button.id == "btn-cancel":
142
+ self.action_cancel()
143
+ elif event.button.id == "btn-retry":
144
+ self.action_retry()
145
+ elif event.button.id == "btn-clear":
146
+ self.action_clear()
147
+ elif event.button.id == "btn-back":
148
+ self.action_back()
149
+
150
+ def action_back(self) -> None:
151
+ """Go back to main screen."""
152
+ self.app.pop_screen()
153
+
154
+ def action_cancel(self) -> None:
155
+ """Cancel selected run."""
156
+ if self._selected_run_id:
157
+ self.post_message(self.RunCancelled(self._selected_run_id))
158
+
159
+ def action_retry(self) -> None:
160
+ """Retry selected run."""
161
+ if self._selected_run_id:
162
+ self.post_message(self.RunRetried(self._selected_run_id))
163
+
164
+ def action_clear(self) -> None:
165
+ """Clear the queue."""
166
+ self.post_message(self.QueueCleared())
167
+
168
+ else:
169
+ class QueueScreen:
170
+ """Placeholder when Textual is not available."""
171
+ def __init__(self, *args, **kwargs):
172
+ raise ImportError(
173
+ "Textual is required for TUI. Install with: pip install praisonai[tui]"
174
+ )
@@ -0,0 +1,124 @@
1
+ """
2
+ Session Screen for PraisonAI TUI.
3
+
4
+ Session browser and management.
5
+ """
6
+
7
+ from typing import Optional, List
8
+
9
+ try:
10
+ from textual.screen import Screen
11
+ from textual.containers import Vertical
12
+ from textual.widgets import Static, Footer, DataTable, Button
13
+ from textual.binding import Binding
14
+ from textual.message import Message
15
+ from rich.text import Text
16
+ TEXTUAL_AVAILABLE = True
17
+ except ImportError:
18
+ TEXTUAL_AVAILABLE = False
19
+ Screen = object
20
+ Message = object
21
+
22
+
23
+ if TEXTUAL_AVAILABLE:
24
+ class SessionScreen(Screen):
25
+ """
26
+ Session browser screen.
27
+
28
+ Displays recent sessions and allows resuming.
29
+ """
30
+
31
+ BINDINGS = [
32
+ Binding("escape", "back", "Back", show=True),
33
+ Binding("enter", "resume", "Resume", show=True),
34
+ Binding("d", "delete", "Delete", show=True),
35
+ ]
36
+
37
+ DEFAULT_CSS = """
38
+ SessionScreen {
39
+ background: $surface;
40
+ }
41
+
42
+ SessionScreen #session-header {
43
+ height: 3;
44
+ background: $primary;
45
+ padding: 1;
46
+ }
47
+
48
+ SessionScreen DataTable {
49
+ height: 1fr;
50
+ }
51
+ """
52
+
53
+ class SessionSelected(Message):
54
+ def __init__(self, session_id: str):
55
+ self.session_id = session_id
56
+ super().__init__()
57
+
58
+ class SessionDeleted(Message):
59
+ def __init__(self, session_id: str):
60
+ self.session_id = session_id
61
+ super().__init__()
62
+
63
+ def __init__(
64
+ self,
65
+ name: Optional[str] = None,
66
+ id: Optional[str] = None,
67
+ classes: Optional[str] = None,
68
+ ):
69
+ super().__init__(name=name, id=id, classes=classes)
70
+ self._selected_session_id: Optional[str] = None
71
+
72
+ def compose(self):
73
+ """Compose the screen."""
74
+ yield Static("Sessions", id="session-header")
75
+ yield DataTable(id="session-table")
76
+ yield Footer()
77
+
78
+ def on_mount(self) -> None:
79
+ """Handle mount."""
80
+ table = self.query_one("#session-table", DataTable)
81
+ table.add_columns("ID", "Created", "Updated", "Runs")
82
+ table.cursor_type = "row"
83
+
84
+ def update_sessions(self, sessions: List[dict]) -> None:
85
+ """Update the sessions display."""
86
+ table = self.query_one("#session-table", DataTable)
87
+ table.clear()
88
+
89
+ for session in sessions:
90
+ table.add_row(
91
+ session.get("session_id", "")[:8],
92
+ session.get("created_at", "-"),
93
+ session.get("updated_at", "-"),
94
+ str(session.get("run_count", 0)),
95
+ key=session.get("session_id"),
96
+ )
97
+
98
+ def on_data_table_row_selected(self, event: DataTable.RowSelected) -> None:
99
+ """Handle row selection."""
100
+ if event.row_key:
101
+ self._selected_session_id = str(event.row_key.value)
102
+
103
+ def action_back(self) -> None:
104
+ """Go back."""
105
+ self.app.pop_screen()
106
+
107
+ def action_resume(self) -> None:
108
+ """Resume selected session."""
109
+ if self._selected_session_id:
110
+ self.post_message(self.SessionSelected(self._selected_session_id))
111
+ self.app.pop_screen()
112
+
113
+ def action_delete(self) -> None:
114
+ """Delete selected session."""
115
+ if self._selected_session_id:
116
+ self.post_message(self.SessionDeleted(self._selected_session_id))
117
+
118
+ else:
119
+ class SessionScreen:
120
+ """Placeholder when Textual is not available."""
121
+ def __init__(self, *args, **kwargs):
122
+ raise ImportError(
123
+ "Textual is required for TUI. Install with: pip install praisonai[tui]"
124
+ )
@@ -0,0 +1,148 @@
1
+ """
2
+ Settings Screen for PraisonAI TUI.
3
+
4
+ Configuration interface.
5
+ """
6
+
7
+ from typing import Optional
8
+
9
+ try:
10
+ from textual.screen import Screen
11
+ from textual.containers import Vertical
12
+ from textual.widgets import Static, Footer, Input, Select, Switch, Button
13
+ from textual.binding import Binding
14
+ from textual.message import Message
15
+ TEXTUAL_AVAILABLE = True
16
+ except ImportError:
17
+ TEXTUAL_AVAILABLE = False
18
+ Screen = object
19
+ Message = object
20
+
21
+
22
+ if TEXTUAL_AVAILABLE:
23
+ class SettingsScreen(Screen):
24
+ """
25
+ Settings screen.
26
+
27
+ Allows configuration of:
28
+ - Model selection
29
+ - Queue settings
30
+ - Display preferences
31
+ """
32
+
33
+ BINDINGS = [
34
+ Binding("escape", "back", "Back", show=True),
35
+ Binding("s", "save", "Save", show=True),
36
+ ]
37
+
38
+ DEFAULT_CSS = """
39
+ SettingsScreen {
40
+ background: $surface;
41
+ }
42
+
43
+ SettingsScreen #settings-header {
44
+ height: 3;
45
+ background: $primary;
46
+ padding: 1;
47
+ }
48
+
49
+ SettingsScreen .setting-row {
50
+ height: 3;
51
+ padding: 0 1;
52
+ }
53
+
54
+ SettingsScreen .setting-label {
55
+ width: 20;
56
+ }
57
+
58
+ SettingsScreen Input {
59
+ width: 40;
60
+ }
61
+ """
62
+
63
+ class SettingsSaved(Message):
64
+ def __init__(self, settings: dict):
65
+ self.settings = settings
66
+ super().__init__()
67
+
68
+ def __init__(
69
+ self,
70
+ current_settings: Optional[dict] = None,
71
+ name: Optional[str] = None,
72
+ id: Optional[str] = None,
73
+ classes: Optional[str] = None,
74
+ ):
75
+ super().__init__(name=name, id=id, classes=classes)
76
+ self._settings = current_settings or {}
77
+
78
+ def compose(self):
79
+ """Compose the screen."""
80
+ yield Static("Settings", id="settings-header")
81
+
82
+ with Vertical(id="settings-form"):
83
+ # Model setting
84
+ yield Static("Model:", classes="setting-label")
85
+ yield Input(
86
+ value=self._settings.get("model", "gpt-4o-mini"),
87
+ id="setting-model",
88
+ placeholder="Model name"
89
+ )
90
+
91
+ # Max concurrent runs
92
+ yield Static("Max Concurrent:", classes="setting-label")
93
+ yield Input(
94
+ value=str(self._settings.get("max_concurrent", 4)),
95
+ id="setting-max-concurrent",
96
+ placeholder="4"
97
+ )
98
+
99
+ # Auto-save interval
100
+ yield Static("Autosave (sec):", classes="setting-label")
101
+ yield Input(
102
+ value=str(self._settings.get("autosave_interval", 30)),
103
+ id="setting-autosave",
104
+ placeholder="30"
105
+ )
106
+
107
+ # Buttons
108
+ yield Button("Save", id="btn-save", variant="primary")
109
+ yield Button("Cancel", id="btn-cancel", variant="default")
110
+
111
+ yield Footer()
112
+
113
+ def on_button_pressed(self, event: Button.Pressed) -> None:
114
+ """Handle button press."""
115
+ if event.button.id == "btn-save":
116
+ self.action_save()
117
+ elif event.button.id == "btn-cancel":
118
+ self.action_back()
119
+
120
+ def action_back(self) -> None:
121
+ """Go back."""
122
+ self.app.pop_screen()
123
+
124
+ def action_save(self) -> None:
125
+ """Save settings."""
126
+ try:
127
+ model_input = self.query_one("#setting-model", Input)
128
+ max_concurrent_input = self.query_one("#setting-max-concurrent", Input)
129
+ autosave_input = self.query_one("#setting-autosave", Input)
130
+
131
+ settings = {
132
+ "model": model_input.value,
133
+ "max_concurrent": int(max_concurrent_input.value or "4"),
134
+ "autosave_interval": int(autosave_input.value or "30"),
135
+ }
136
+
137
+ self.post_message(self.SettingsSaved(settings))
138
+ self.app.pop_screen()
139
+ except ValueError:
140
+ pass
141
+
142
+ else:
143
+ class SettingsScreen:
144
+ """Placeholder when Textual is not available."""
145
+ def __init__(self, *args, **kwargs):
146
+ raise ImportError(
147
+ "Textual is required for TUI. Install with: pip install praisonai[tui]"
148
+ )