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,200 @@
1
+ """
2
+ Queue Panel Widget for PraisonAI TUI.
3
+
4
+ Displays queue status and allows queue management.
5
+ """
6
+
7
+ from typing import List, Optional
8
+ from dataclasses import dataclass
9
+
10
+ try:
11
+ from textual.widget import Widget
12
+ from textual.widgets import Static, DataTable, Button
13
+ from textual.containers import Vertical
14
+ from textual.reactive import reactive
15
+ from textual.message import Message
16
+ from rich.text import Text
17
+ from rich.panel import Panel
18
+ TEXTUAL_AVAILABLE = True
19
+ except ImportError:
20
+ TEXTUAL_AVAILABLE = False
21
+ Widget = object
22
+ Message = object
23
+
24
+
25
+ @dataclass
26
+ class QueueItem:
27
+ """A queue item for display."""
28
+ run_id: str
29
+ agent_name: str
30
+ input_preview: str
31
+ state: str
32
+ priority: str
33
+ wait_time: str
34
+
35
+
36
+ if TEXTUAL_AVAILABLE:
37
+ class QueuePanelWidget(Vertical):
38
+ """
39
+ Queue panel widget.
40
+
41
+ Displays:
42
+ - Queue summary (queued/running counts)
43
+ - List of queued runs
44
+ - Cancel/retry buttons
45
+ """
46
+
47
+ DEFAULT_CSS = """
48
+ QueuePanelWidget {
49
+ height: 100%;
50
+ border: solid $secondary;
51
+ background: $surface;
52
+ padding: 0 1;
53
+ }
54
+
55
+ QueuePanelWidget .queue-header {
56
+ height: 1;
57
+ background: $secondary;
58
+ padding: 0 1;
59
+ }
60
+
61
+ QueuePanelWidget DataTable {
62
+ height: 1fr;
63
+ }
64
+
65
+ QueuePanelWidget .queue-item-queued {
66
+ color: $warning;
67
+ }
68
+
69
+ QueuePanelWidget .queue-item-running {
70
+ color: $success;
71
+ }
72
+
73
+ QueuePanelWidget .queue-item-failed {
74
+ color: $error;
75
+ }
76
+ """
77
+
78
+ class RunSelected(Message):
79
+ """Event when a run is selected."""
80
+ def __init__(self, run_id: str):
81
+ self.run_id = run_id
82
+ super().__init__()
83
+
84
+ class CancelRequested(Message):
85
+ """Event when cancel is requested."""
86
+ def __init__(self, run_id: str):
87
+ self.run_id = run_id
88
+ super().__init__()
89
+
90
+ class RetryRequested(Message):
91
+ """Event when retry is requested."""
92
+ def __init__(self, run_id: str):
93
+ self.run_id = run_id
94
+ super().__init__()
95
+
96
+ queued_count: reactive[int] = reactive(0)
97
+ running_count: reactive[int] = reactive(0)
98
+
99
+ def __init__(
100
+ self,
101
+ name: Optional[str] = None,
102
+ id: Optional[str] = None,
103
+ classes: Optional[str] = None,
104
+ ):
105
+ super().__init__(name=name, id=id, classes=classes)
106
+ self._items: List[QueueItem] = []
107
+ self._selected_run_id: Optional[str] = None
108
+
109
+ def compose(self):
110
+ """Compose the widget."""
111
+ yield Static("Queue", id="queue-title", classes="queue-header")
112
+ yield DataTable(id="queue-table")
113
+
114
+ def on_mount(self) -> None:
115
+ """Handle mount."""
116
+ table = self.query_one("#queue-table", DataTable)
117
+ table.add_columns("ID", "Agent", "Input", "State", "Priority")
118
+ table.cursor_type = "row"
119
+ self._update_header()
120
+
121
+ def watch_queued_count(self, value: int) -> None:
122
+ self._update_header()
123
+
124
+ def watch_running_count(self, value: int) -> None:
125
+ self._update_header()
126
+
127
+ def _update_header(self) -> None:
128
+ """Update the header text."""
129
+ try:
130
+ header = self.query_one("#queue-title", Static)
131
+ text = Text()
132
+ text.append("Queue ", style="bold")
133
+ text.append(f"⏳ {self.queued_count} queued", style="yellow")
134
+ text.append(" │ ", style="dim")
135
+ text.append(f"▶ {self.running_count} running", style="green")
136
+ header.update(text)
137
+ except Exception:
138
+ pass
139
+
140
+ def update_items(self, items: List[QueueItem]) -> None:
141
+ """Update the queue items."""
142
+ self._items = items
143
+
144
+ table = self.query_one("#queue-table", DataTable)
145
+ table.clear()
146
+
147
+ for item in items:
148
+ # Style based on state
149
+ state_style = {
150
+ "queued": "yellow",
151
+ "running": "green",
152
+ "failed": "red",
153
+ "cancelled": "dim",
154
+ "succeeded": "cyan",
155
+ }.get(item.state.lower(), "")
156
+
157
+ state_text = Text(item.state, style=state_style)
158
+
159
+ # Truncate input preview
160
+ input_preview = item.input_preview[:30]
161
+ if len(item.input_preview) > 30:
162
+ input_preview += "..."
163
+
164
+ table.add_row(
165
+ item.run_id[:8],
166
+ item.agent_name,
167
+ input_preview,
168
+ state_text,
169
+ item.priority,
170
+ key=item.run_id,
171
+ )
172
+
173
+ def on_data_table_row_selected(self, event: DataTable.RowSelected) -> None:
174
+ """Handle row selection."""
175
+ if event.row_key:
176
+ self._selected_run_id = str(event.row_key.value)
177
+ self.post_message(self.RunSelected(self._selected_run_id))
178
+
179
+ def cancel_selected(self) -> None:
180
+ """Cancel the selected run."""
181
+ if self._selected_run_id:
182
+ self.post_message(self.CancelRequested(self._selected_run_id))
183
+
184
+ def retry_selected(self) -> None:
185
+ """Retry the selected run."""
186
+ if self._selected_run_id:
187
+ self.post_message(self.RetryRequested(self._selected_run_id))
188
+
189
+ @property
190
+ def selected_run_id(self) -> Optional[str]:
191
+ """Get the selected run ID."""
192
+ return self._selected_run_id
193
+
194
+ else:
195
+ class QueuePanelWidget:
196
+ """Placeholder when Textual is not available."""
197
+ def __init__(self, *args, **kwargs):
198
+ raise ImportError(
199
+ "Textual is required for TUI. Install with: pip install praisonai[tui]"
200
+ )
@@ -0,0 +1,167 @@
1
+ """
2
+ Status Widget for PraisonAI TUI.
3
+
4
+ Displays status bar with session info, model, tokens, and cost.
5
+ """
6
+
7
+ from typing import Optional
8
+ from dataclasses import dataclass
9
+
10
+ try:
11
+ from textual.widget import Widget
12
+ from textual.widgets import Static
13
+ from textual.containers import Horizontal
14
+ from textual.reactive import reactive
15
+ from rich.text import Text
16
+ from rich.table import Table
17
+ TEXTUAL_AVAILABLE = True
18
+ except ImportError:
19
+ TEXTUAL_AVAILABLE = False
20
+ Widget = object
21
+
22
+
23
+ @dataclass
24
+ class StatusInfo:
25
+ """Status information."""
26
+ session_id: str = ""
27
+ model: str = "gpt-4o-mini"
28
+ total_tokens: int = 0
29
+ total_cost: float = 0.0
30
+ queued_count: int = 0
31
+ running_count: int = 0
32
+ is_processing: bool = False
33
+ status_message: str = ""
34
+
35
+
36
+ if TEXTUAL_AVAILABLE:
37
+ class StatusWidget(Static):
38
+ """
39
+ Status bar widget.
40
+
41
+ Displays:
42
+ - Session ID
43
+ - Current model
44
+ - Token usage
45
+ - Cost
46
+ - Queue status
47
+ - Processing indicator
48
+ """
49
+
50
+ DEFAULT_CSS = """
51
+ StatusWidget {
52
+ height: 1;
53
+ background: $primary;
54
+ color: $text;
55
+ padding: 0 1;
56
+ }
57
+ """
58
+
59
+ session_id: reactive[str] = reactive("")
60
+ model: reactive[str] = reactive("gpt-4o-mini")
61
+ total_tokens: reactive[int] = reactive(0)
62
+ total_cost: reactive[float] = reactive(0.0)
63
+ queued_count: reactive[int] = reactive(0)
64
+ running_count: reactive[int] = reactive(0)
65
+ is_processing: reactive[bool] = reactive(False)
66
+ status_message: reactive[str] = reactive("")
67
+
68
+ def __init__(
69
+ self,
70
+ name: Optional[str] = None,
71
+ id: Optional[str] = None,
72
+ classes: Optional[str] = None,
73
+ ):
74
+ super().__init__("", name=name, id=id, classes=classes)
75
+
76
+ def on_mount(self) -> None:
77
+ """Handle mount."""
78
+ self._update_display()
79
+
80
+ def watch_session_id(self, value: str) -> None:
81
+ self._update_display()
82
+
83
+ def watch_model(self, value: str) -> None:
84
+ self._update_display()
85
+
86
+ def watch_total_tokens(self, value: int) -> None:
87
+ self._update_display()
88
+
89
+ def watch_total_cost(self, value: float) -> None:
90
+ self._update_display()
91
+
92
+ def watch_queued_count(self, value: int) -> None:
93
+ self._update_display()
94
+
95
+ def watch_running_count(self, value: int) -> None:
96
+ self._update_display()
97
+
98
+ def watch_is_processing(self, value: bool) -> None:
99
+ self._update_display()
100
+
101
+ def watch_status_message(self, value: str) -> None:
102
+ self._update_display()
103
+
104
+ def _update_display(self) -> None:
105
+ """Update the status display."""
106
+ parts = []
107
+
108
+ # App name
109
+ parts.append(("◉ PraisonAI", "bold cyan"))
110
+
111
+ # Session
112
+ if self.session_id:
113
+ parts.append((f"Session: {self.session_id[:8]}", ""))
114
+
115
+ # Model
116
+ parts.append((f"Model: {self.model}", ""))
117
+
118
+ # Tokens
119
+ if self.total_tokens > 0:
120
+ parts.append((f"Tokens: {self.total_tokens:,}", ""))
121
+
122
+ # Cost
123
+ if self.total_cost > 0:
124
+ parts.append((f"${self.total_cost:.4f}", "green"))
125
+
126
+ # Queue status
127
+ if self.queued_count > 0 or self.running_count > 0:
128
+ queue_text = f"⏳ {self.queued_count} queued"
129
+ if self.running_count > 0:
130
+ queue_text += f" │ ▶ {self.running_count} running"
131
+ parts.append((queue_text, "yellow"))
132
+
133
+ # Processing indicator
134
+ if self.is_processing:
135
+ parts.append(("⟳ Processing...", "bold magenta"))
136
+
137
+ # Status message
138
+ if self.status_message:
139
+ parts.append((self.status_message, "italic"))
140
+
141
+ # Build text
142
+ text = Text()
143
+ for i, (content, style) in enumerate(parts):
144
+ if i > 0:
145
+ text.append(" │ ", style="dim")
146
+ text.append(content, style=style)
147
+
148
+ self.update(text)
149
+
150
+ def update_info(self, info: StatusInfo) -> None:
151
+ """Update all status info at once."""
152
+ self.session_id = info.session_id
153
+ self.model = info.model
154
+ self.total_tokens = info.total_tokens
155
+ self.total_cost = info.total_cost
156
+ self.queued_count = info.queued_count
157
+ self.running_count = info.running_count
158
+ self.is_processing = info.is_processing
159
+ self.status_message = info.status_message
160
+
161
+ else:
162
+ class StatusWidget:
163
+ """Placeholder when Textual is not available."""
164
+ def __init__(self, *args, **kwargs):
165
+ raise ImportError(
166
+ "Textual is required for TUI. Install with: pip install praisonai[tui]"
167
+ )
@@ -0,0 +1,248 @@
1
+ """
2
+ Tool Panel Widget for PraisonAI TUI.
3
+
4
+ Displays tool execution status and approval dialogs.
5
+ """
6
+
7
+ from typing import List, Optional
8
+ from dataclasses import dataclass, field
9
+ import time
10
+
11
+ try:
12
+ from textual.widget import Widget
13
+ from textual.widgets import Static, ListView, ListItem
14
+ from textual.containers import Vertical
15
+ from textual.reactive import reactive
16
+ from textual.message import Message
17
+ from rich.text import Text
18
+ from rich.panel import Panel
19
+ TEXTUAL_AVAILABLE = True
20
+ except ImportError:
21
+ TEXTUAL_AVAILABLE = False
22
+ Widget = object
23
+ Message = object
24
+
25
+
26
+ @dataclass
27
+ class ToolCall:
28
+ """A tool call for display."""
29
+ call_id: str
30
+ tool_name: str
31
+ args_preview: str
32
+ status: str # "pending", "running", "completed", "failed", "approved", "rejected"
33
+ result_preview: Optional[str] = None
34
+ started_at: float = field(default_factory=time.time)
35
+ ended_at: Optional[float] = None
36
+ requires_approval: bool = False
37
+
38
+
39
+ if TEXTUAL_AVAILABLE:
40
+ class ToolPanelWidget(Vertical):
41
+ """
42
+ Tool panel widget.
43
+
44
+ Displays:
45
+ - Recent tool calls
46
+ - Tool execution status
47
+ - Approval requests
48
+ """
49
+
50
+ DEFAULT_CSS = """
51
+ ToolPanelWidget {
52
+ height: 100%;
53
+ border: solid $accent;
54
+ background: $surface;
55
+ padding: 0 1;
56
+ }
57
+
58
+ ToolPanelWidget .tool-header {
59
+ height: 1;
60
+ background: $accent;
61
+ padding: 0 1;
62
+ }
63
+
64
+ ToolPanelWidget .tool-pending {
65
+ color: $warning;
66
+ }
67
+
68
+ ToolPanelWidget .tool-running {
69
+ color: $primary;
70
+ }
71
+
72
+ ToolPanelWidget .tool-completed {
73
+ color: $success;
74
+ }
75
+
76
+ ToolPanelWidget .tool-failed {
77
+ color: $error;
78
+ }
79
+
80
+ ToolPanelWidget .tool-approval {
81
+ background: $warning-darken-2;
82
+ border: solid $warning;
83
+ padding: 1;
84
+ }
85
+ """
86
+
87
+ class ApprovalResponse(Message):
88
+ """Event when user responds to approval request."""
89
+ def __init__(self, call_id: str, approved: bool):
90
+ self.call_id = call_id
91
+ self.approved = approved
92
+ super().__init__()
93
+
94
+ def __init__(
95
+ self,
96
+ max_items: int = 50,
97
+ name: Optional[str] = None,
98
+ id: Optional[str] = None,
99
+ classes: Optional[str] = None,
100
+ ):
101
+ super().__init__(name=name, id=id, classes=classes)
102
+ self._calls: List[ToolCall] = []
103
+ self._max_items = max_items
104
+ self._pending_approval: Optional[ToolCall] = None
105
+
106
+ def compose(self):
107
+ """Compose the widget."""
108
+ yield Static("Tools", id="tool-title", classes="tool-header")
109
+ yield Vertical(id="tool-list")
110
+
111
+ def on_mount(self) -> None:
112
+ """Handle mount."""
113
+ self._update_display()
114
+
115
+ def add_call(self, call: ToolCall) -> None:
116
+ """Add a tool call."""
117
+ self._calls.append(call)
118
+
119
+ # Trim old calls
120
+ if len(self._calls) > self._max_items:
121
+ self._calls = self._calls[-self._max_items:]
122
+
123
+ # Check for approval
124
+ if call.requires_approval and call.status == "pending":
125
+ self._pending_approval = call
126
+
127
+ self._update_display()
128
+
129
+ def update_call(self, call_id: str, status: str, result: Optional[str] = None) -> None:
130
+ """Update a tool call status."""
131
+ for call in self._calls:
132
+ if call.call_id == call_id:
133
+ call.status = status
134
+ if result:
135
+ call.result_preview = result[:100]
136
+ if status in ("completed", "failed"):
137
+ call.ended_at = time.time()
138
+ break
139
+
140
+ # Clear pending approval if this was it
141
+ if self._pending_approval and self._pending_approval.call_id == call_id:
142
+ self._pending_approval = None
143
+
144
+ self._update_display()
145
+
146
+ def _update_display(self) -> None:
147
+ """Update the display."""
148
+ try:
149
+ container = self.query_one("#tool-list", Vertical)
150
+ except Exception:
151
+ return
152
+
153
+ # Clear existing
154
+ container.remove_children()
155
+
156
+ # Show pending approval first
157
+ if self._pending_approval:
158
+ approval_text = Text()
159
+ approval_text.append("⚠ Approval Required\n", style="bold yellow")
160
+ approval_text.append(f"Tool: {self._pending_approval.tool_name}\n")
161
+ approval_text.append(f"Args: {self._pending_approval.args_preview}\n")
162
+ approval_text.append("[Y] Approve [N] Reject", style="dim")
163
+
164
+ container.mount(Static(
165
+ Panel(approval_text, border_style="yellow"),
166
+ classes="tool-approval"
167
+ ))
168
+
169
+ # Show recent calls
170
+ for call in reversed(self._calls[-10:]):
171
+ if call == self._pending_approval:
172
+ continue
173
+
174
+ # Status icon
175
+ status_icons = {
176
+ "pending": "⏳",
177
+ "running": "⟳",
178
+ "completed": "✓",
179
+ "failed": "✗",
180
+ "approved": "✓",
181
+ "rejected": "✗",
182
+ }
183
+ icon = status_icons.get(call.status, "?")
184
+
185
+ # Status style
186
+ status_styles = {
187
+ "pending": "yellow",
188
+ "running": "cyan",
189
+ "completed": "green",
190
+ "failed": "red",
191
+ "approved": "green",
192
+ "rejected": "red",
193
+ }
194
+ style = status_styles.get(call.status, "")
195
+
196
+ text = Text()
197
+ text.append(f"{icon} ", style=style)
198
+ text.append(call.tool_name, style="bold")
199
+
200
+ if call.result_preview:
201
+ text.append(f" → {call.result_preview[:30]}...", style="dim")
202
+
203
+ container.mount(Static(text, classes=f"tool-{call.status}"))
204
+
205
+ def handle_approval_key(self, key: str) -> bool:
206
+ """
207
+ Handle approval key press.
208
+
209
+ Returns True if handled.
210
+ """
211
+ if not self._pending_approval:
212
+ return False
213
+
214
+ if key.lower() == "y":
215
+ self.post_message(self.ApprovalResponse(
216
+ self._pending_approval.call_id,
217
+ approved=True
218
+ ))
219
+ self.update_call(self._pending_approval.call_id, "approved")
220
+ return True
221
+ elif key.lower() == "n":
222
+ self.post_message(self.ApprovalResponse(
223
+ self._pending_approval.call_id,
224
+ approved=False
225
+ ))
226
+ self.update_call(self._pending_approval.call_id, "rejected")
227
+ return True
228
+
229
+ return False
230
+
231
+ @property
232
+ def has_pending_approval(self) -> bool:
233
+ """Check if there's a pending approval."""
234
+ return self._pending_approval is not None
235
+
236
+ def clear(self) -> None:
237
+ """Clear all tool calls."""
238
+ self._calls.clear()
239
+ self._pending_approval = None
240
+ self._update_display()
241
+
242
+ else:
243
+ class ToolPanelWidget:
244
+ """Placeholder when Textual is not available."""
245
+ def __init__(self, *args, **kwargs):
246
+ raise ImportError(
247
+ "Textual is required for TUI. Install with: pip install praisonai[tui]"
248
+ )