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
praisonai/deploy.py ADDED
@@ -0,0 +1,185 @@
1
+ import subprocess
2
+ import os
3
+ import platform
4
+ from dotenv import load_dotenv
5
+
6
+ class CloudDeployer:
7
+ """
8
+ A class for deploying a cloud-based application.
9
+
10
+ Attributes:
11
+ None
12
+
13
+ Methods:
14
+ __init__(self):
15
+ Loads environment variables from .env file or system and sets them.
16
+
17
+ """
18
+ def __init__(self):
19
+ """
20
+ Loads environment variables from .env file or system and sets them.
21
+
22
+ Parameters:
23
+ self: An instance of the CloudDeployer class.
24
+
25
+ Returns:
26
+ None
27
+
28
+ Raises:
29
+ None
30
+
31
+ """
32
+ # Load environment variables from .env file or system
33
+ load_dotenv()
34
+ self.set_environment_variables()
35
+
36
+ def create_dockerfile(self):
37
+ """
38
+ Creates a Dockerfile for the application.
39
+
40
+ Parameters:
41
+ self: An instance of the CloudDeployer class.
42
+
43
+ Returns:
44
+ None
45
+
46
+ Raises:
47
+ None
48
+
49
+ This method creates a Dockerfile in the current directory with the specified content.
50
+ The Dockerfile is used to build a Docker image for the application.
51
+ The content of the Dockerfile includes instructions to use the Python 3.11-slim base image,
52
+ set the working directory to /app, copy the current directory contents into the container,
53
+ install the required Python packages (flask, praisonai, gunicorn, and markdown),
54
+ expose port 8080, and run the application using Gunicorn.
55
+ """
56
+ with open("Dockerfile", "w") as file:
57
+ file.write("FROM python:3.11-slim\n")
58
+ file.write("WORKDIR /app\n")
59
+ file.write("COPY . .\n")
60
+ file.write("RUN pip install flask praisonai==3.0.0 gunicorn markdown\n")
61
+ file.write("EXPOSE 8080\n")
62
+ file.write('CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]\n')
63
+
64
+ def create_api_file(self):
65
+ """
66
+ Creates an API file for the application.
67
+
68
+ Parameters:
69
+ self (CloudDeployer): An instance of the CloudDeployer class.
70
+
71
+ Returns:
72
+ None
73
+
74
+ This method creates an API file named "api.py" in the current directory. The file contains a basic Flask application that uses the PraisonAI library to run a simple agent and returns the output as an HTML page. The application listens on the root path ("/") and uses the Markdown library to format the output.
75
+ """
76
+ with open("api.py", "w") as file:
77
+ file.write("from flask import Flask\n")
78
+ file.write("from praisonai import PraisonAI\n")
79
+ file.write("import markdown\n\n")
80
+ file.write("app = Flask(__name__)\n\n")
81
+ file.write("def basic():\n")
82
+ file.write(" praisonai = PraisonAI(agent_file=\"agents.yaml\")\n")
83
+ file.write(" return praisonai.run()\n\n")
84
+ file.write("@app.route('/')\n")
85
+ file.write("def home():\n")
86
+ file.write(" output = basic()\n")
87
+ file.write(" html_output = markdown.markdown(output)\n")
88
+ file.write(" return f'<html><body>{html_output}</body></html>'\n\n")
89
+ file.write("if __name__ == \"__main__\":\n")
90
+ file.write(" app.run(debug=True)\n")
91
+
92
+ def set_environment_variables(self):
93
+ """Sets environment variables with fallback to .env values or defaults."""
94
+ os.environ["OPENAI_MODEL_NAME"] = os.getenv("OPENAI_MODEL_NAME", "gpt-5-nano")
95
+ os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY", "Enter your API key")
96
+ os.environ["OPENAI_API_BASE"] = os.getenv("OPENAI_API_BASE", "https://api.openai.com/v1")
97
+
98
+ def run_commands(self):
99
+ """
100
+ Sets environment variables with fallback to .env values or defaults.
101
+
102
+ Parameters:
103
+ None
104
+
105
+ Returns:
106
+ None
107
+
108
+ Raises:
109
+ None
110
+
111
+ This method sets environment variables for the application. It uses the `os.environ` dictionary to set the following environment variables:
112
+
113
+ - `OPENAI_MODEL_NAME`: The name of the OpenAI model to use. If not specified in the .env file, it defaults to "gpt-5-nano".
114
+ - `OPENAI_API_KEY`: The API key for accessing the OpenAI API. If not specified in the .env file, it defaults to "Enter your API key".
115
+ - `OPENAI_API_BASE`: The base URL for the OpenAI API. If not specified in the .env file, it defaults to "https://api.openai.com/v1".
116
+ """
117
+ self.create_api_file()
118
+ self.create_dockerfile()
119
+ """Runs a sequence of shell commands for deployment, continues on error."""
120
+
121
+ # Get project ID upfront for Windows compatibility
122
+ try:
123
+ result = subprocess.run(['gcloud', 'config', 'get-value', 'project'],
124
+ capture_output=True, text=True, check=True)
125
+ project_id = result.stdout.strip()
126
+ except subprocess.CalledProcessError:
127
+ print("ERROR: Failed to get GCP project ID. Ensure gcloud is configured.")
128
+ return
129
+
130
+ # Get environment variables
131
+ openai_model = os.environ.get('OPENAI_MODEL_NAME', 'gpt-5-nano')
132
+ openai_key = os.environ.get('OPENAI_API_KEY', 'Enter your API key')
133
+ openai_base = os.environ.get('OPENAI_API_BASE', 'https://api.openai.com/v1')
134
+
135
+ # Build commands with actual values
136
+ commands = [
137
+ ['gcloud', 'auth', 'configure-docker', 'us-central1-docker.pkg.dev'],
138
+ ['gcloud', 'artifacts', 'repositories', 'create', 'praisonai-repository',
139
+ '--repository-format=docker', '--location=us-central1'],
140
+ ['docker', 'build', '--platform', 'linux/amd64', '-t',
141
+ f'gcr.io/{project_id}/praisonai-app:latest', '.'],
142
+ ['docker', 'tag', f'gcr.io/{project_id}/praisonai-app:latest',
143
+ f'us-central1-docker.pkg.dev/{project_id}/praisonai-repository/praisonai-app:latest'],
144
+ ['docker', 'push',
145
+ f'us-central1-docker.pkg.dev/{project_id}/praisonai-repository/praisonai-app:latest'],
146
+ ['gcloud', 'run', 'deploy', 'praisonai-service',
147
+ '--image', f'us-central1-docker.pkg.dev/{project_id}/praisonai-repository/praisonai-app:latest',
148
+ '--platform', 'managed', '--region', 'us-central1', '--allow-unauthenticated',
149
+ '--set-env-vars', f'OPENAI_MODEL_NAME={openai_model},OPENAI_API_KEY={openai_key},OPENAI_API_BASE={openai_base}']
150
+ ]
151
+
152
+ # Run commands with appropriate handling for each platform
153
+ for i, cmd in enumerate(commands):
154
+ try:
155
+ if i == 0: # First command (gcloud auth configure-docker)
156
+ if platform.system() != 'Windows':
157
+ # On Unix, pipe 'yes' to auto-confirm
158
+ proc = subprocess.Popen(cmd, stdin=subprocess.PIPE)
159
+ proc.communicate(input=b'Y\n')
160
+ if proc.returncode != 0:
161
+ raise subprocess.CalledProcessError(proc.returncode, cmd)
162
+ else:
163
+ # On Windows, try with --quiet flag to avoid prompts
164
+ cmd_with_quiet = cmd + ['--quiet']
165
+ try:
166
+ subprocess.run(cmd_with_quiet, check=True)
167
+ except subprocess.CalledProcessError:
168
+ # If --quiet fails, try without it
169
+ print("Note: You may need to manually confirm the authentication prompt")
170
+ subprocess.run(cmd, check=True)
171
+ else:
172
+ # Run other commands normally
173
+ subprocess.run(cmd, check=True)
174
+ except subprocess.CalledProcessError as e:
175
+ print(f"ERROR: Command failed with exit status {e.returncode}")
176
+ # Commands 2 (build) and 4 (push) and 5 (deploy) are critical
177
+ if i in [2, 4, 5]:
178
+ print("Critical command failed. Aborting deployment.")
179
+ return
180
+ print(f"Continuing with the next command...")
181
+
182
+ # Usage
183
+ if __name__ == "__main__":
184
+ deployer = CloudDeployer()
185
+ deployer.run_commands()
@@ -0,0 +1,53 @@
1
+ """
2
+ Unified Endpoints Module
3
+
4
+ Provides unified discovery, provider adapters, and server utilities
5
+ for all PraisonAI serve features.
6
+
7
+ Provider Types:
8
+ - recipe: Recipe runner endpoints
9
+ - agents-api: Single/multi-agent HTTP API
10
+ - mcp: MCP server (stdio, http, sse)
11
+ - tools-mcp: Tools exposed as MCP server
12
+ - a2a: Agent-to-agent protocol
13
+ - a2u: Agent-to-user event stream
14
+
15
+ Architecture:
16
+ - Discovery schema is versioned and consistent across all providers
17
+ - Provider adapters abstract protocol differences
18
+ - CLI client uses unified discovery for list/describe/invoke/health
19
+ """
20
+
21
+ # Lazy loading for all exports
22
+ _lazy_imports = {
23
+ "DiscoveryDocument": ".discovery",
24
+ "EndpointInfo": ".discovery",
25
+ "ProviderInfo": ".discovery",
26
+ "SCHEMA_VERSION": ".discovery",
27
+ "create_discovery_document": ".discovery",
28
+ "BaseProvider": ".providers.base",
29
+ "RecipeProvider": ".providers.recipe",
30
+ "AgentsAPIProvider": ".providers.agents_api",
31
+ "MCPProvider": ".providers.mcp",
32
+ "ToolsMCPProvider": ".providers.tools_mcp",
33
+ "A2AProvider": ".providers.a2a",
34
+ "A2UProvider": ".providers.a2u",
35
+ "ProviderRegistry": ".registry",
36
+ "get_provider": ".registry",
37
+ "register_provider": ".registry",
38
+ "list_provider_types": ".registry",
39
+ "get_provider_class": ".registry",
40
+ "create_unified_app": ".server",
41
+ "add_discovery_routes": ".server",
42
+ }
43
+
44
+ def __getattr__(name: str):
45
+ if name in _lazy_imports:
46
+ module_path = _lazy_imports[name]
47
+ import importlib
48
+ module = importlib.import_module(module_path, package=__name__)
49
+ return getattr(module, name)
50
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
51
+
52
+ def __dir__():
53
+ return list(_lazy_imports.keys())
@@ -0,0 +1,410 @@
1
+ """
2
+ A2U (Agent-to-User) Event Stream Server
3
+
4
+ Provides SSE-based event streaming for agent-to-user communication.
5
+ """
6
+
7
+ import asyncio
8
+ import json
9
+ import logging
10
+ import uuid
11
+ from dataclasses import dataclass, field
12
+ from datetime import datetime, timezone
13
+ from typing import Any, Dict, List, Optional, Set
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ @dataclass
19
+ class A2UEvent:
20
+ """An event in the A2U stream."""
21
+ event_type: str
22
+ data: Dict[str, Any]
23
+ timestamp: str = field(default_factory=lambda: datetime.now(timezone.utc).isoformat())
24
+ event_id: str = field(default_factory=lambda: uuid.uuid4().hex[:12])
25
+
26
+ def to_sse(self) -> str:
27
+ """Convert to SSE format."""
28
+ return f"event: {self.event_type}\ndata: {json.dumps(self.data)}\nid: {self.event_id}\n\n"
29
+
30
+ def to_dict(self) -> Dict[str, Any]:
31
+ """Convert to dictionary."""
32
+ return {
33
+ "event_type": self.event_type,
34
+ "data": self.data,
35
+ "timestamp": self.timestamp,
36
+ "event_id": self.event_id,
37
+ }
38
+
39
+
40
+ @dataclass
41
+ class A2USubscription:
42
+ """A subscription to an A2U event stream."""
43
+ subscription_id: str
44
+ stream_name: str
45
+ filters: List[str] = field(default_factory=list)
46
+ created_at: str = field(default_factory=lambda: datetime.now(timezone.utc).isoformat())
47
+
48
+ def matches_event(self, event: A2UEvent) -> bool:
49
+ """Check if event matches subscription filters."""
50
+ if not self.filters:
51
+ return True
52
+ return event.event_type in self.filters
53
+
54
+
55
+ class A2UEventBus:
56
+ """
57
+ Event bus for A2U event distribution.
58
+
59
+ Manages subscriptions and broadcasts events to subscribers.
60
+ """
61
+
62
+ def __init__(self):
63
+ """Initialize the event bus."""
64
+ self._subscriptions: Dict[str, A2USubscription] = {}
65
+ self._queues: Dict[str, asyncio.Queue] = {}
66
+ self._streams: Dict[str, Set[str]] = {} # stream_name -> subscription_ids
67
+
68
+ def subscribe(
69
+ self,
70
+ stream_name: str = "events",
71
+ filters: Optional[List[str]] = None,
72
+ ) -> A2USubscription:
73
+ """
74
+ Subscribe to an event stream.
75
+
76
+ Args:
77
+ stream_name: Name of the stream to subscribe to
78
+ filters: Optional list of event types to filter
79
+
80
+ Returns:
81
+ A2USubscription object
82
+ """
83
+ subscription_id = f"sub-{uuid.uuid4().hex[:12]}"
84
+ subscription = A2USubscription(
85
+ subscription_id=subscription_id,
86
+ stream_name=stream_name,
87
+ filters=filters or [],
88
+ )
89
+
90
+ self._subscriptions[subscription_id] = subscription
91
+ self._queues[subscription_id] = asyncio.Queue()
92
+
93
+ if stream_name not in self._streams:
94
+ self._streams[stream_name] = set()
95
+ self._streams[stream_name].add(subscription_id)
96
+
97
+ logger.debug(f"Created subscription {subscription_id} for stream {stream_name}")
98
+ return subscription
99
+
100
+ def unsubscribe(self, subscription_id: str) -> bool:
101
+ """
102
+ Unsubscribe from an event stream.
103
+
104
+ Args:
105
+ subscription_id: ID of the subscription to remove
106
+
107
+ Returns:
108
+ True if unsubscribed, False if not found
109
+ """
110
+ if subscription_id not in self._subscriptions:
111
+ return False
112
+
113
+ subscription = self._subscriptions[subscription_id]
114
+
115
+ # Remove from stream set
116
+ if subscription.stream_name in self._streams:
117
+ self._streams[subscription.stream_name].discard(subscription_id)
118
+
119
+ # Clean up
120
+ del self._subscriptions[subscription_id]
121
+ del self._queues[subscription_id]
122
+
123
+ logger.debug(f"Removed subscription {subscription_id}")
124
+ return True
125
+
126
+ async def publish(self, event: A2UEvent, stream_name: str = "events") -> int:
127
+ """
128
+ Publish an event to a stream.
129
+
130
+ Args:
131
+ event: Event to publish
132
+ stream_name: Name of the stream
133
+
134
+ Returns:
135
+ Number of subscribers that received the event
136
+ """
137
+ if stream_name not in self._streams:
138
+ return 0
139
+
140
+ count = 0
141
+ for sub_id in self._streams[stream_name]:
142
+ subscription = self._subscriptions.get(sub_id)
143
+ if subscription and subscription.matches_event(event):
144
+ await self._queues[sub_id].put(event)
145
+ count += 1
146
+
147
+ logger.debug(f"Published event {event.event_type} to {count} subscribers")
148
+ return count
149
+
150
+ def publish_sync(self, event: A2UEvent, stream_name: str = "events") -> int:
151
+ """
152
+ Synchronously publish an event (creates event loop if needed).
153
+
154
+ Args:
155
+ event: Event to publish
156
+ stream_name: Name of the stream
157
+
158
+ Returns:
159
+ Number of subscribers that received the event
160
+ """
161
+ try:
162
+ loop = asyncio.get_event_loop()
163
+ if loop.is_running():
164
+ # Schedule in running loop
165
+ asyncio.ensure_future(self.publish(event, stream_name))
166
+ return len(self._streams.get(stream_name, set()))
167
+ else:
168
+ return loop.run_until_complete(self.publish(event, stream_name))
169
+ except RuntimeError:
170
+ # No event loop, create one
171
+ return asyncio.run(self.publish(event, stream_name))
172
+
173
+ async def get_events(
174
+ self,
175
+ subscription_id: str,
176
+ timeout: float = 30.0,
177
+ ):
178
+ """
179
+ Async generator for subscription events.
180
+
181
+ Args:
182
+ subscription_id: ID of the subscription
183
+ timeout: Timeout for waiting for events
184
+
185
+ Yields:
186
+ A2UEvent objects
187
+ """
188
+ if subscription_id not in self._queues:
189
+ return
190
+
191
+ queue = self._queues[subscription_id]
192
+
193
+ while True:
194
+ try:
195
+ event = await asyncio.wait_for(queue.get(), timeout=timeout)
196
+ yield event
197
+ except asyncio.TimeoutError:
198
+ # Send keepalive
199
+ yield A2UEvent(event_type="keepalive", data={})
200
+
201
+
202
+ # Global event bus instance
203
+ _event_bus: Optional[A2UEventBus] = None
204
+
205
+
206
+ def get_event_bus() -> A2UEventBus:
207
+ """Get or create the global event bus."""
208
+ global _event_bus
209
+ if _event_bus is None:
210
+ _event_bus = A2UEventBus()
211
+ return _event_bus
212
+
213
+
214
+ def create_a2u_routes(app: Any, event_bus: Optional[A2UEventBus] = None) -> None:
215
+ """
216
+ Add A2U routes to a FastAPI/Starlette application.
217
+
218
+ Args:
219
+ app: FastAPI or Starlette application
220
+ event_bus: Optional event bus (uses global if not provided)
221
+ """
222
+ bus = event_bus or get_event_bus()
223
+
224
+ try:
225
+ from starlette.responses import JSONResponse, StreamingResponse
226
+ from starlette.routing import Route
227
+ except ImportError:
228
+ try:
229
+ from fastapi.responses import JSONResponse, StreamingResponse
230
+ except ImportError:
231
+ raise ImportError("Starlette or FastAPI required for A2U routes")
232
+
233
+ async def a2u_info(request):
234
+ """GET /a2u/info - Get A2U server info."""
235
+ return JSONResponse({
236
+ "name": "A2U Event Stream",
237
+ "version": "1.0.0",
238
+ "streams": list(bus._streams.keys()) or ["events"],
239
+ "event_types": [
240
+ "agent.started",
241
+ "agent.thinking",
242
+ "agent.tool_call",
243
+ "agent.response",
244
+ "agent.completed",
245
+ "agent.error",
246
+ ],
247
+ })
248
+
249
+ async def a2u_subscribe(request):
250
+ """POST /a2u/subscribe - Subscribe to an event stream."""
251
+ try:
252
+ body = await request.json()
253
+ except Exception:
254
+ body = {}
255
+
256
+ stream_name = body.get("stream", "events")
257
+ filters = body.get("filters", [])
258
+
259
+ subscription = bus.subscribe(stream_name, filters)
260
+
261
+ base_url = str(request.url).rsplit("/", 1)[0]
262
+
263
+ return JSONResponse({
264
+ "subscription_id": subscription.subscription_id,
265
+ "stream_name": subscription.stream_name,
266
+ "stream_url": f"{base_url}/events/{subscription.subscription_id}",
267
+ "created_at": subscription.created_at,
268
+ })
269
+
270
+ async def a2u_unsubscribe(request):
271
+ """POST /a2u/unsubscribe - Unsubscribe from an event stream."""
272
+ try:
273
+ body = await request.json()
274
+ except Exception:
275
+ return JSONResponse({"error": "Invalid JSON"}, status_code=400)
276
+
277
+ subscription_id = body.get("subscription_id")
278
+ if not subscription_id:
279
+ return JSONResponse({"error": "subscription_id required"}, status_code=400)
280
+
281
+ if bus.unsubscribe(subscription_id):
282
+ return JSONResponse({"status": "unsubscribed"})
283
+ else:
284
+ return JSONResponse({"error": "Subscription not found"}, status_code=404)
285
+
286
+ async def a2u_events_stream(request):
287
+ """GET /a2u/events/{stream_name} - Stream events via SSE."""
288
+ stream_name = request.path_params.get("stream_name", "events")
289
+
290
+ # Create subscription for this stream
291
+ subscription = bus.subscribe(stream_name)
292
+
293
+ async def event_generator():
294
+ try:
295
+ async for event in bus.get_events(subscription.subscription_id):
296
+ yield event.to_sse()
297
+ finally:
298
+ bus.unsubscribe(subscription.subscription_id)
299
+
300
+ return StreamingResponse(
301
+ event_generator(),
302
+ media_type="text/event-stream",
303
+ headers={
304
+ "Cache-Control": "no-cache",
305
+ "Connection": "keep-alive",
306
+ "X-Accel-Buffering": "no",
307
+ },
308
+ )
309
+
310
+ async def a2u_events_subscription(request):
311
+ """GET /a2u/events/sub/{subscription_id} - Stream events for subscription."""
312
+ subscription_id = request.path_params.get("subscription_id")
313
+
314
+ if subscription_id not in bus._subscriptions:
315
+ return JSONResponse({"error": "Subscription not found"}, status_code=404)
316
+
317
+ async def event_generator():
318
+ async for event in bus.get_events(subscription_id):
319
+ yield event.to_sse()
320
+
321
+ return StreamingResponse(
322
+ event_generator(),
323
+ media_type="text/event-stream",
324
+ headers={
325
+ "Cache-Control": "no-cache",
326
+ "Connection": "keep-alive",
327
+ "X-Accel-Buffering": "no",
328
+ },
329
+ )
330
+
331
+ async def a2u_health(request):
332
+ """GET /a2u/health - A2U health check."""
333
+ return JSONResponse({
334
+ "status": "healthy",
335
+ "active_subscriptions": len(bus._subscriptions),
336
+ "active_streams": len(bus._streams),
337
+ })
338
+
339
+ # Add routes based on app type
340
+ if hasattr(app, 'add_api_route'):
341
+ # FastAPI
342
+ app.add_api_route("/a2u/info", a2u_info, methods=["GET"])
343
+ app.add_api_route("/a2u/subscribe", a2u_subscribe, methods=["POST"])
344
+ app.add_api_route("/a2u/unsubscribe", a2u_unsubscribe, methods=["POST"])
345
+ app.add_api_route("/a2u/events/{stream_name}", a2u_events_stream, methods=["GET"])
346
+ app.add_api_route("/a2u/events/sub/{subscription_id}", a2u_events_subscription, methods=["GET"])
347
+ app.add_api_route("/a2u/health", a2u_health, methods=["GET"])
348
+ elif hasattr(app, 'routes'):
349
+ # Starlette
350
+ app.routes.extend([
351
+ Route("/a2u/info", a2u_info, methods=["GET"]),
352
+ Route("/a2u/subscribe", a2u_subscribe, methods=["POST"]),
353
+ Route("/a2u/unsubscribe", a2u_unsubscribe, methods=["POST"]),
354
+ Route("/a2u/events/{stream_name}", a2u_events_stream, methods=["GET"]),
355
+ Route("/a2u/events/sub/{subscription_id}", a2u_events_subscription, methods=["GET"]),
356
+ Route("/a2u/health", a2u_health, methods=["GET"]),
357
+ ])
358
+
359
+
360
+ # Helper functions for publishing events
361
+ def emit_agent_event(
362
+ event_type: str,
363
+ data: Dict[str, Any],
364
+ agent_id: Optional[str] = None,
365
+ stream_name: str = "events",
366
+ ) -> None:
367
+ """
368
+ Emit an agent event to the A2U stream.
369
+
370
+ Args:
371
+ event_type: Type of event (e.g., "agent.started", "agent.response")
372
+ data: Event data
373
+ agent_id: Optional agent ID to include
374
+ stream_name: Stream to publish to
375
+ """
376
+ if agent_id:
377
+ data["agent_id"] = agent_id
378
+
379
+ event = A2UEvent(event_type=event_type, data=data)
380
+ get_event_bus().publish_sync(event, stream_name)
381
+
382
+
383
+ def emit_agent_started(agent_id: str, agent_name: str, **kwargs) -> None:
384
+ """Emit agent.started event."""
385
+ emit_agent_event("agent.started", {"agent_name": agent_name, **kwargs}, agent_id)
386
+
387
+
388
+ def emit_agent_thinking(agent_id: str, message: str = "", **kwargs) -> None:
389
+ """Emit agent.thinking event."""
390
+ emit_agent_event("agent.thinking", {"message": message, **kwargs}, agent_id)
391
+
392
+
393
+ def emit_agent_tool_call(agent_id: str, tool_name: str, arguments: Dict = None, **kwargs) -> None:
394
+ """Emit agent.tool_call event."""
395
+ emit_agent_event("agent.tool_call", {"tool_name": tool_name, "arguments": arguments or {}, **kwargs}, agent_id)
396
+
397
+
398
+ def emit_agent_response(agent_id: str, response: str, **kwargs) -> None:
399
+ """Emit agent.response event."""
400
+ emit_agent_event("agent.response", {"response": response, **kwargs}, agent_id)
401
+
402
+
403
+ def emit_agent_completed(agent_id: str, result: Any = None, **kwargs) -> None:
404
+ """Emit agent.completed event."""
405
+ emit_agent_event("agent.completed", {"result": result, **kwargs}, agent_id)
406
+
407
+
408
+ def emit_agent_error(agent_id: str, error: str, **kwargs) -> None:
409
+ """Emit agent.error event."""
410
+ emit_agent_event("agent.error", {"error": error, **kwargs}, agent_id)