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,141 @@
1
+ """
2
+ Videos Capabilities Module
3
+
4
+ Provides video generation functionality via LiteLLM.
5
+ """
6
+
7
+ from dataclasses import dataclass, field
8
+ from typing import Optional, List, Any, Dict
9
+
10
+
11
+ @dataclass
12
+ class VideoResult:
13
+ """Result from video generation."""
14
+ url: Optional[str] = None
15
+ id: Optional[str] = None
16
+ status: Optional[str] = None
17
+ model: Optional[str] = None
18
+ metadata: Dict[str, Any] = field(default_factory=dict)
19
+
20
+
21
+ def video_generate(
22
+ prompt: str,
23
+ model: str = "runway/gen3a_turbo",
24
+ duration: int = 5,
25
+ aspect_ratio: str = "16:9",
26
+ timeout: float = 600.0,
27
+ api_key: Optional[str] = None,
28
+ api_base: Optional[str] = None,
29
+ metadata: Optional[Dict[str, Any]] = None,
30
+ **kwargs
31
+ ) -> VideoResult:
32
+ """
33
+ Generate a video from a text prompt.
34
+
35
+ Args:
36
+ prompt: Text description of the video to generate
37
+ model: Model name (e.g., "runway/gen3a_turbo")
38
+ duration: Video duration in seconds
39
+ aspect_ratio: Aspect ratio (e.g., "16:9", "9:16", "1:1")
40
+ timeout: Request timeout in seconds
41
+ api_key: Optional API key override
42
+ api_base: Optional API base URL override
43
+ metadata: Optional metadata for tracing
44
+
45
+ Returns:
46
+ VideoResult with video URL or ID
47
+
48
+ Example:
49
+ >>> result = video_generate("A sunset over the ocean")
50
+ >>> print(result.url)
51
+ """
52
+ import litellm
53
+
54
+ call_kwargs = {
55
+ 'model': model,
56
+ 'prompt': prompt,
57
+ 'duration': duration,
58
+ 'aspect_ratio': aspect_ratio,
59
+ 'timeout': timeout,
60
+ }
61
+
62
+ if api_key:
63
+ call_kwargs['api_key'] = api_key
64
+ if api_base:
65
+ call_kwargs['api_base'] = api_base
66
+
67
+ call_kwargs.update(kwargs)
68
+
69
+ if metadata:
70
+ call_kwargs['metadata'] = metadata
71
+
72
+ # Try to use video generation if available
73
+ try:
74
+ response = litellm.video_generation(**call_kwargs)
75
+
76
+ return VideoResult(
77
+ url=getattr(response, 'url', None),
78
+ id=getattr(response, 'id', None),
79
+ status=getattr(response, 'status', 'completed'),
80
+ model=model,
81
+ metadata=metadata or {},
82
+ )
83
+ except AttributeError:
84
+ # Fallback if video_generation not available
85
+ raise NotImplementedError(
86
+ "Video generation is not yet fully supported. "
87
+ "Please check LiteLLM documentation for available video models."
88
+ )
89
+
90
+
91
+ async def avideo_generate(
92
+ prompt: str,
93
+ model: str = "runway/gen3a_turbo",
94
+ duration: int = 5,
95
+ aspect_ratio: str = "16:9",
96
+ timeout: float = 600.0,
97
+ api_key: Optional[str] = None,
98
+ api_base: Optional[str] = None,
99
+ metadata: Optional[Dict[str, Any]] = None,
100
+ **kwargs
101
+ ) -> VideoResult:
102
+ """
103
+ Async: Generate a video from a text prompt.
104
+
105
+ See video_generate() for full documentation.
106
+ """
107
+ import litellm
108
+
109
+ call_kwargs = {
110
+ 'model': model,
111
+ 'prompt': prompt,
112
+ 'duration': duration,
113
+ 'aspect_ratio': aspect_ratio,
114
+ 'timeout': timeout,
115
+ }
116
+
117
+ if api_key:
118
+ call_kwargs['api_key'] = api_key
119
+ if api_base:
120
+ call_kwargs['api_base'] = api_base
121
+
122
+ call_kwargs.update(kwargs)
123
+
124
+ if metadata:
125
+ call_kwargs['metadata'] = metadata
126
+
127
+ try:
128
+ response = await litellm.avideo_generation(**call_kwargs)
129
+
130
+ return VideoResult(
131
+ url=getattr(response, 'url', None),
132
+ id=getattr(response, 'id', None),
133
+ status=getattr(response, 'status', 'completed'),
134
+ model=model,
135
+ metadata=metadata or {},
136
+ )
137
+ except AttributeError:
138
+ raise NotImplementedError(
139
+ "Video generation is not yet fully supported. "
140
+ "Please check LiteLLM documentation for available video models."
141
+ )
@@ -0,0 +1,304 @@
1
+ # praisonai/chainlit_ui.py
2
+ from praisonai.agents_generator import AgentsGenerator
3
+ from praisonai.auto import AutoGenerator
4
+ import chainlit as cl
5
+ import os
6
+ from chainlit.types import ThreadDict
7
+ from chainlit.input_widget import Select, TextInput
8
+ from typing import Optional
9
+ from dotenv import load_dotenv
10
+ load_dotenv()
11
+ from contextlib import redirect_stdout
12
+ from io import StringIO
13
+ import logging
14
+ logging.basicConfig(level=os.environ.get('LOGLEVEL', 'INFO').upper(), format='%(asctime)s - %(levelname)s - %(message)s')
15
+
16
+ framework = "crewai"
17
+ config_list = [
18
+ {
19
+ 'model': os.environ.get("OPENAI_MODEL_NAME", "gpt-5-nano"),
20
+ 'base_url': os.environ.get("OPENAI_API_BASE", "https://api.openai.com/v1"),
21
+ 'api_key': os.environ.get("OPENAI_API_KEY", "")
22
+ }
23
+ ]
24
+ agent_file = "test.yaml"
25
+
26
+ actions=[
27
+ cl.Action(name="run", payload={"value": "run"}, label="run"),
28
+ cl.Action(name="modify", payload={"value": "modify"}, label="Modify"),
29
+ ]
30
+
31
+ @cl.action_callback("run")
32
+ async def on_run(action):
33
+ await main(cl.Message(content=""))
34
+
35
+ @cl.action_callback("modify")
36
+ async def on_modify(action):
37
+ await cl.Message(content="Modify the agents and tools from below settings").send()
38
+
39
+
40
+ @cl.set_chat_profiles
41
+ async def set_profiles(current_user: cl.User):
42
+ return [
43
+ cl.ChatProfile(
44
+ name="Auto",
45
+ markdown_description="Automatically generate agents and tasks based on your input.",
46
+ starters=[
47
+ cl.Starter(
48
+ label="Create a movie script",
49
+ message="Create a movie script about a futuristic society where AI and humans coexist, focusing on the conflict and resolution between them. Start with an intriguing opening scene.",
50
+ icon="/public/movie.svg",
51
+ ),
52
+ cl.Starter(
53
+ label="Design a fantasy world",
54
+ message="Design a detailed fantasy world with unique geography, cultures, and magical systems. Start by describing the main continent and its inhabitants.",
55
+ icon="/public/fantasy.svg",
56
+ ),
57
+ cl.Starter(
58
+ label="Write a futuristic political thriller",
59
+ message="Write a futuristic political thriller involving a conspiracy within a global government. Start with a high-stakes meeting that sets the plot in motion.",
60
+ icon="/public/thriller.svg",
61
+ ),
62
+ cl.Starter(
63
+ label="Develop a new board game",
64
+ message="Develop a new, innovative board game. Describe the game's objective, rules, and unique mechanics. Create a scenario to illustrate gameplay.",
65
+ icon="/public/game.svg",
66
+ ),
67
+ ]
68
+ ),
69
+ cl.ChatProfile(
70
+ name="Manual",
71
+ markdown_description="Manually define your agents and tasks using a YAML file.",
72
+ ),
73
+ ]
74
+
75
+
76
+ @cl.on_chat_start
77
+ async def start_chat():
78
+ cl.user_session.set(
79
+ "message_history",
80
+ [{"role": "system", "content": "You are a helpful assistant."}],
81
+ )
82
+
83
+ # Create tools.py if it doesn't exist
84
+ if not os.path.exists("tools.py"):
85
+ with open("tools.py", "w") as f:
86
+ f.write("# Add your custom tools here\n")
87
+
88
+ settings = await cl.ChatSettings(
89
+ [
90
+ TextInput(id="Model", label="OpenAI - Model", initial=config_list[0]['model']),
91
+ TextInput(id="BaseUrl", label="OpenAI - Base URL", initial=config_list[0]['base_url']),
92
+ TextInput(id="ApiKey", label="OpenAI - API Key", initial=config_list[0]['api_key']),
93
+ Select(
94
+ id="Framework",
95
+ label="Framework",
96
+ values=["crewai", "autogen"],
97
+ initial_index=0,
98
+ ),
99
+ ]
100
+ ).send()
101
+ cl.user_session.set("settings", settings)
102
+ chat_profile = cl.user_session.get("chat_profile")
103
+ if chat_profile=="Manual":
104
+
105
+ agent_file = "agents.yaml"
106
+ full_agent_file_path = os.path.abspath(agent_file) # Get full path
107
+ if os.path.exists(full_agent_file_path):
108
+ with open(full_agent_file_path, 'r') as f:
109
+ yaml_content = f.read()
110
+ msg = cl.Message(content=yaml_content, language="yaml")
111
+ await msg.send()
112
+
113
+
114
+ full_tools_file_path = os.path.abspath("tools.py") # Get full path
115
+ if os.path.exists(full_tools_file_path):
116
+ with open(full_tools_file_path, 'r') as f:
117
+ tools_content = f.read()
118
+ msg = cl.Message(content=tools_content, language="python")
119
+ await msg.send()
120
+
121
+ settings = await cl.ChatSettings(
122
+ [
123
+ TextInput(id="Model", label="OpenAI - Model", initial=config_list[0]['model']),
124
+ TextInput(id="BaseUrl", label="OpenAI - Base URL", initial=config_list[0]['base_url']),
125
+ TextInput(id="ApiKey", label="OpenAI - API Key", initial=config_list[0]['api_key']),
126
+ Select(
127
+ id="Framework",
128
+ label="Framework",
129
+ values=["crewai", "autogen"],
130
+ initial_index=0,
131
+ ),
132
+ TextInput(id="agents", label="agents.yaml", initial=yaml_content, multiline=True),
133
+ TextInput(id="tools", label="tools.py", initial=tools_content, multiline=True),
134
+ ]
135
+ ).send()
136
+ cl.user_session.set("settings", settings)
137
+
138
+ res = await cl.AskActionMessage(
139
+ content="Pick an action!",
140
+ actions=actions,
141
+ ).send()
142
+ if res and res.get("value") == "modify":
143
+ await cl.Message(content="Modify the agents and tools from below settings", actions=actions).send()
144
+ elif res and res.get("value") == "run":
145
+ await main(cl.Message(content="", actions=actions))
146
+
147
+ await on_settings_update(settings)
148
+
149
+ @cl.on_settings_update
150
+ async def on_settings_update(settings):
151
+ """Handle updates to the ChatSettings form."""
152
+ global config_list, framework
153
+ config_list[0]['model'] = settings["Model"]
154
+ config_list[0]['base_url'] = settings["BaseUrl"]
155
+ config_list[0]['api_key'] = settings["ApiKey"]
156
+ os.environ["OPENAI_API_KEY"] = config_list[0]['api_key']
157
+ os.environ["OPENAI_MODEL_NAME"] = config_list[0]['model']
158
+ os.environ["OPENAI_API_BASE"] = config_list[0]['base_url']
159
+ framework = settings["Framework"]
160
+
161
+ if "agents" in settings:
162
+ with open("agents.yaml", "w") as f:
163
+ f.write(settings["agents"])
164
+ if "tools" in settings:
165
+ with open("tools.py", "w") as f:
166
+ f.write(settings["tools"])
167
+
168
+ print("Settings updated")
169
+
170
+ @cl.on_chat_resume
171
+ async def on_chat_resume(thread: ThreadDict):
172
+ message_history = cl.user_session.get("message_history", [])
173
+ root_messages = [m for m in thread["steps"] if m["parentId"] is None]
174
+ for message in root_messages:
175
+ if message["type"] == "user_message":
176
+ message_history.append({"role": "user", "content": message["output"]})
177
+ elif message["type"] == "ai_message":
178
+ message_history.append({"role": "assistant", "content": message["content"]})
179
+ cl.user_session.set("message_history", message_history)
180
+
181
+ # @cl.step(type="tool")
182
+ # async def tool(data: Optional[str] = None, language: Optional[str] = None):
183
+ # return cl.Message(content=data, language=language)
184
+
185
+ @cl.step(type="tool", show_input=False)
186
+ async def run_agents(agent_file: str, framework: str):
187
+ """Runs the agents and returns the result."""
188
+ agents_generator = AgentsGenerator(agent_file, framework, config_list)
189
+ current_step = cl.context.current_step
190
+ print("Current Step:", current_step)
191
+
192
+ stdout_buffer = StringIO()
193
+ with redirect_stdout(stdout_buffer):
194
+ result = agents_generator.generate_crew_and_kickoff()
195
+
196
+ complete_output = stdout_buffer.getvalue()
197
+
198
+ async with cl.Step(name="gpt4", type="llm", show_input=True) as step:
199
+ step.input = ""
200
+
201
+ for line in stdout_buffer.getvalue().splitlines():
202
+ print(line)
203
+ await step.stream_token(line)
204
+
205
+ tool_res = await output(complete_output)
206
+
207
+ yield result
208
+
209
+ @cl.step(type="tool", show_input=False, language="yaml")
210
+ async def output(output):
211
+ return output
212
+
213
+ @cl.step(type="tool", show_input=False, language="yaml")
214
+ def agent(output):
215
+ return(f"""
216
+ Agent Step Completed!
217
+ Output: {output}
218
+ """)
219
+
220
+ @cl.step(type="tool", show_input=False, language="yaml")
221
+ def task(output):
222
+ return(f"""
223
+ Task Completed!
224
+ Task: {output.description}
225
+ Output: {output.raw_output}
226
+ {output}
227
+ """)
228
+
229
+ @cl.on_message
230
+ async def main(message: cl.Message):
231
+ """Run PraisonAI with the provided message as the topic."""
232
+ message_history = cl.user_session.get("message_history")
233
+ if message_history is None:
234
+ message_history = []
235
+ cl.user_session.set("message_history", message_history)
236
+ message_history.append({"role": "user", "content": message.content})
237
+ topic = message.content
238
+ chat_profile = cl.user_session.get("chat_profile")
239
+
240
+ if chat_profile == "Auto":
241
+ agent_file = "agents.yaml"
242
+ generator = AutoGenerator(topic=topic, agent_file=agent_file, framework=framework, config_list=config_list)
243
+ await cl.sleep(2)
244
+ agent_file = generator.generate()
245
+ agents_generator = AgentsGenerator(
246
+ agent_file,
247
+ framework,
248
+ config_list,
249
+ # agent_callback=agent,
250
+ # task_callback=task
251
+ )
252
+ # Capture stdout
253
+ stdout_buffer = StringIO()
254
+ with redirect_stdout(stdout_buffer):
255
+ result = agents_generator.generate_crew_and_kickoff()
256
+
257
+ complete_output = stdout_buffer.getvalue()
258
+ tool_res = await output(complete_output)
259
+ msg = cl.Message(content=result)
260
+ await msg.send()
261
+ message_history.append({"role": "assistant", "content": message.content})
262
+ else: # chat_profile == "Manual"
263
+ agent_file = "agents.yaml"
264
+ full_agent_file_path = os.path.abspath(agent_file) # Get full path
265
+ full_tools_file_path = os.path.abspath("tools.py")
266
+ if os.path.exists(full_agent_file_path):
267
+ with open(full_agent_file_path, 'r') as f:
268
+ yaml_content = f.read()
269
+ # tool_res = await tool()
270
+ msg_agents = cl.Message(content=yaml_content, language="yaml")
271
+ await msg_agents.send()
272
+ if os.path.exists(full_tools_file_path):
273
+ with open(full_tools_file_path, 'r') as f:
274
+ tools_content = f.read()
275
+ msg_tools = cl.Message(content=tools_content, language="python")
276
+ await msg_tools.send()
277
+ else:
278
+ # If the file doesn't exist, follow the same process as "Auto"
279
+ generator = AutoGenerator(topic=topic, agent_file=agent_file, framework=framework, config_list=config_list)
280
+ agent_file = generator.generate()
281
+
282
+ agents_generator = AgentsGenerator(agent_file, framework, config_list)
283
+ result = agents_generator.generate_crew_and_kickoff()
284
+ msg = cl.Message(content=result, actions=actions)
285
+ await msg.send()
286
+ message_history.append({"role": "assistant", "content": message.content})
287
+
288
+ # Load environment variables from .env file
289
+ load_dotenv()
290
+
291
+ # Get username and password from environment variables
292
+ username = os.getenv("CHAINLIT_USERNAME", "admin") # Default to "admin" if not found
293
+ password = os.getenv("CHAINLIT_PASSWORD", "admin") # Default to "admin" if not found
294
+
295
+ @cl.password_auth_callback
296
+ def auth_callback(username: str, password: str):
297
+ # Fetch the user matching username from your database
298
+ # and compare the hashed password with the value stored in the database
299
+ if (username, password) == (username, password):
300
+ return cl.User(
301
+ identifier=username, metadata={"role": "ADMIN", "provider": "credentials"}
302
+ )
303
+ else:
304
+ return None
@@ -0,0 +1,106 @@
1
+ """
2
+ PraisonAI Chat Module
3
+
4
+ This module provides the chat UI integration for PraisonAI agents.
5
+ It uses the PraisonAI Chat (based on Chainlit) for the frontend.
6
+ """
7
+
8
+ from typing import Optional, Any
9
+
10
+ __all__ = ["start_chat_server", "ChatConfig"]
11
+
12
+
13
+ class ChatConfig:
14
+ """Configuration for the PraisonAI Chat server."""
15
+
16
+ def __init__(
17
+ self,
18
+ host: str = "0.0.0.0",
19
+ port: int = 8000,
20
+ debug: bool = False,
21
+ auth_enabled: bool = False,
22
+ session_id: Optional[str] = None,
23
+ ):
24
+ self.host = host
25
+ self.port = port
26
+ self.debug = debug
27
+ self.auth_enabled = auth_enabled
28
+ self.session_id = session_id
29
+
30
+
31
+ def start_chat_server(
32
+ agent: Optional[Any] = None,
33
+ agents: Optional[list] = None,
34
+ config: Optional[ChatConfig] = None,
35
+ port: int = 8000,
36
+ host: str = "0.0.0.0",
37
+ debug: bool = False,
38
+ ) -> None:
39
+ """
40
+ Start the PraisonAI Chat server.
41
+
42
+ Args:
43
+ agent: A single PraisonAI agent to use in the chat.
44
+ agents: A list of PraisonAI agents for multi-agent chat.
45
+ config: ChatConfig object with server settings.
46
+ port: Port to run the server on (default: 8000).
47
+ host: Host to bind to (default: 0.0.0.0).
48
+ debug: Enable debug mode (default: False).
49
+
50
+ Example:
51
+ >>> from praisonaiagents import Agent
52
+ >>> from praisonai.chat import start_chat_server
53
+ >>>
54
+ >>> agent = Agent(name="Assistant", instructions="You are helpful.")
55
+ >>> start_chat_server(agent=agent, port=8000)
56
+ """
57
+ # Lazy import to avoid loading chainlit unless needed
58
+ try:
59
+ from chainlit.cli import run_chainlit
60
+ except ImportError:
61
+ raise ImportError(
62
+ "PraisonAI Chat requires the 'praisonai-chat' package. "
63
+ "Install it with: pip install praisonai-chat"
64
+ )
65
+
66
+ if config is None:
67
+ config = ChatConfig(host=host, port=port, debug=debug)
68
+
69
+ # Store agents in a way accessible to the chainlit app
70
+ import os
71
+ os.environ["PRAISONAI_CHAT_MODE"] = "true"
72
+
73
+ if agent is not None:
74
+ # Single agent mode
75
+ _register_agent(agent)
76
+ elif agents is not None:
77
+ # Multi-agent mode
78
+ for a in agents:
79
+ _register_agent(a)
80
+
81
+ # Start the chainlit server
82
+ from pathlib import Path
83
+
84
+ # Use the built-in app file
85
+ app_file = Path(__file__).parent / "app.py"
86
+
87
+ # Set environment variables for chainlit
88
+ os.environ["CHAINLIT_HOST"] = config.host
89
+ os.environ["CHAINLIT_PORT"] = str(config.port)
90
+
91
+ run_chainlit(str(app_file))
92
+
93
+
94
+ # Global registry for agents
95
+ _REGISTERED_AGENTS: dict = {}
96
+
97
+
98
+ def _register_agent(agent: Any) -> None:
99
+ """Register an agent for use in the chat UI."""
100
+ agent_name = getattr(agent, "name", None) or getattr(agent, "role", "Agent")
101
+ _REGISTERED_AGENTS[agent_name] = agent
102
+
103
+
104
+ def get_registered_agents() -> dict:
105
+ """Get all registered agents."""
106
+ return _REGISTERED_AGENTS
praisonai/chat/app.py ADDED
@@ -0,0 +1,125 @@
1
+ """
2
+ PraisonAI Chat - Default Chainlit Application
3
+
4
+ This is the default chat application that runs when using `praisonai chat`.
5
+ It integrates with PraisonAI agents for multi-agent conversations.
6
+ """
7
+
8
+ import os
9
+ import chainlit as cl
10
+
11
+ # Check if we're in PraisonAI Chat mode with registered agents
12
+ PRAISONAI_CHAT_MODE = os.environ.get("PRAISONAI_CHAT_MODE", "false").lower() == "true"
13
+
14
+
15
+ def get_agents():
16
+ """Get registered agents from the chat module."""
17
+ try:
18
+ from praisonai.chat import get_registered_agents
19
+ return get_registered_agents()
20
+ except ImportError:
21
+ return {}
22
+
23
+
24
+ @cl.on_chat_start
25
+ async def on_chat_start():
26
+ """Initialize the chat session."""
27
+ agents = get_agents()
28
+
29
+ if agents:
30
+ agent_names = list(agents.keys())
31
+ cl.user_session.set("agents", agents)
32
+ cl.user_session.set("current_agent", agent_names[0] if agent_names else None)
33
+
34
+ await cl.Message(
35
+ content=f"Welcome to PraisonAI Chat! Available agents: {', '.join(agent_names)}"
36
+ ).send()
37
+ else:
38
+ await cl.Message(
39
+ content="Welcome to PraisonAI Chat! No agents configured. "
40
+ "Use the API to register agents or configure via YAML."
41
+ ).send()
42
+
43
+ cl.user_session.set("message_history", [])
44
+
45
+
46
+ @cl.on_message
47
+ async def on_message(message: cl.Message):
48
+ """Handle incoming messages."""
49
+ agents = cl.user_session.get("agents", {})
50
+ current_agent_name = cl.user_session.get("current_agent")
51
+ message_history = cl.user_session.get("message_history", [])
52
+
53
+ # Add user message to history
54
+ message_history.append({"role": "user", "content": message.content})
55
+
56
+ if not agents or not current_agent_name:
57
+ # No agents configured - use a simple echo response
58
+ response = f"Echo: {message.content}\n\n(No agents configured. Register agents to enable AI responses.)"
59
+ await cl.Message(content=response).send()
60
+ return
61
+
62
+ agent = agents.get(current_agent_name)
63
+ if agent is None:
64
+ await cl.Message(content=f"Agent '{current_agent_name}' not found.").send()
65
+ return
66
+
67
+ # Create a step for the agent response
68
+ async with cl.Step(name=current_agent_name, type="llm") as step:
69
+ step.input = message.content
70
+
71
+ try:
72
+ # Try to call the agent
73
+ if hasattr(agent, "chat"):
74
+ # PraisonAI Agent with chat method
75
+ response = await _call_agent_async(agent, message.content)
76
+ elif hasattr(agent, "run"):
77
+ # Agent with run method
78
+ response = await _call_agent_async(agent, message.content, method="run")
79
+ elif callable(agent):
80
+ # Callable agent
81
+ response = agent(message.content)
82
+ else:
83
+ response = f"Agent '{current_agent_name}' does not have a callable interface."
84
+
85
+ step.output = str(response)
86
+
87
+ except Exception as e:
88
+ response = f"Error calling agent: {str(e)}"
89
+ step.output = response
90
+
91
+ # Add assistant response to history
92
+ message_history.append({"role": "assistant", "content": str(response)})
93
+ cl.user_session.set("message_history", message_history)
94
+
95
+ # Send the response
96
+ await cl.Message(content=str(response)).send()
97
+
98
+
99
+ async def _call_agent_async(agent, message: str, method: str = "chat"):
100
+ """Call an agent method, handling both sync and async."""
101
+ import asyncio
102
+
103
+ func = getattr(agent, method)
104
+
105
+ if asyncio.iscoroutinefunction(func):
106
+ return await func(message)
107
+ else:
108
+ # Run sync function in thread pool
109
+ loop = asyncio.get_event_loop()
110
+ return await loop.run_in_executor(None, func, message)
111
+
112
+
113
+ @cl.on_chat_resume
114
+ async def on_chat_resume(thread):
115
+ """Resume a chat session."""
116
+ message_history = []
117
+
118
+ root_messages = [m for m in thread.get("steps", []) if m.get("parentId") is None]
119
+ for msg in root_messages:
120
+ if msg.get("type") == "user_message":
121
+ message_history.append({"role": "user", "content": msg.get("output", "")})
122
+ elif msg.get("type") == "assistant_message":
123
+ message_history.append({"role": "assistant", "content": msg.get("output", "")})
124
+
125
+ cl.user_session.set("message_history", message_history)