ag2 0.10.2__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 (423) hide show
  1. ag2-0.10.2.dist-info/METADATA +819 -0
  2. ag2-0.10.2.dist-info/RECORD +423 -0
  3. ag2-0.10.2.dist-info/WHEEL +4 -0
  4. ag2-0.10.2.dist-info/licenses/LICENSE +201 -0
  5. ag2-0.10.2.dist-info/licenses/NOTICE.md +19 -0
  6. autogen/__init__.py +88 -0
  7. autogen/_website/__init__.py +3 -0
  8. autogen/_website/generate_api_references.py +426 -0
  9. autogen/_website/generate_mkdocs.py +1216 -0
  10. autogen/_website/notebook_processor.py +475 -0
  11. autogen/_website/process_notebooks.py +656 -0
  12. autogen/_website/utils.py +413 -0
  13. autogen/a2a/__init__.py +36 -0
  14. autogen/a2a/agent_executor.py +86 -0
  15. autogen/a2a/client.py +357 -0
  16. autogen/a2a/errors.py +18 -0
  17. autogen/a2a/httpx_client_factory.py +79 -0
  18. autogen/a2a/server.py +221 -0
  19. autogen/a2a/utils.py +207 -0
  20. autogen/agentchat/__init__.py +47 -0
  21. autogen/agentchat/agent.py +180 -0
  22. autogen/agentchat/assistant_agent.py +86 -0
  23. autogen/agentchat/chat.py +325 -0
  24. autogen/agentchat/contrib/__init__.py +5 -0
  25. autogen/agentchat/contrib/agent_eval/README.md +7 -0
  26. autogen/agentchat/contrib/agent_eval/agent_eval.py +108 -0
  27. autogen/agentchat/contrib/agent_eval/criterion.py +43 -0
  28. autogen/agentchat/contrib/agent_eval/critic_agent.py +44 -0
  29. autogen/agentchat/contrib/agent_eval/quantifier_agent.py +39 -0
  30. autogen/agentchat/contrib/agent_eval/subcritic_agent.py +45 -0
  31. autogen/agentchat/contrib/agent_eval/task.py +42 -0
  32. autogen/agentchat/contrib/agent_optimizer.py +432 -0
  33. autogen/agentchat/contrib/capabilities/__init__.py +5 -0
  34. autogen/agentchat/contrib/capabilities/agent_capability.py +20 -0
  35. autogen/agentchat/contrib/capabilities/generate_images.py +301 -0
  36. autogen/agentchat/contrib/capabilities/teachability.py +393 -0
  37. autogen/agentchat/contrib/capabilities/text_compressors.py +66 -0
  38. autogen/agentchat/contrib/capabilities/tools_capability.py +22 -0
  39. autogen/agentchat/contrib/capabilities/transform_messages.py +93 -0
  40. autogen/agentchat/contrib/capabilities/transforms.py +578 -0
  41. autogen/agentchat/contrib/capabilities/transforms_util.py +122 -0
  42. autogen/agentchat/contrib/capabilities/vision_capability.py +215 -0
  43. autogen/agentchat/contrib/captainagent/__init__.py +9 -0
  44. autogen/agentchat/contrib/captainagent/agent_builder.py +790 -0
  45. autogen/agentchat/contrib/captainagent/captainagent.py +514 -0
  46. autogen/agentchat/contrib/captainagent/tool_retriever.py +334 -0
  47. autogen/agentchat/contrib/captainagent/tools/README.md +44 -0
  48. autogen/agentchat/contrib/captainagent/tools/__init__.py +5 -0
  49. autogen/agentchat/contrib/captainagent/tools/data_analysis/calculate_correlation.py +40 -0
  50. autogen/agentchat/contrib/captainagent/tools/data_analysis/calculate_skewness_and_kurtosis.py +28 -0
  51. autogen/agentchat/contrib/captainagent/tools/data_analysis/detect_outlier_iqr.py +28 -0
  52. autogen/agentchat/contrib/captainagent/tools/data_analysis/detect_outlier_zscore.py +28 -0
  53. autogen/agentchat/contrib/captainagent/tools/data_analysis/explore_csv.py +21 -0
  54. autogen/agentchat/contrib/captainagent/tools/data_analysis/shapiro_wilk_test.py +30 -0
  55. autogen/agentchat/contrib/captainagent/tools/information_retrieval/arxiv_download.py +27 -0
  56. autogen/agentchat/contrib/captainagent/tools/information_retrieval/arxiv_search.py +53 -0
  57. autogen/agentchat/contrib/captainagent/tools/information_retrieval/extract_pdf_image.py +53 -0
  58. autogen/agentchat/contrib/captainagent/tools/information_retrieval/extract_pdf_text.py +38 -0
  59. autogen/agentchat/contrib/captainagent/tools/information_retrieval/get_wikipedia_text.py +21 -0
  60. autogen/agentchat/contrib/captainagent/tools/information_retrieval/get_youtube_caption.py +34 -0
  61. autogen/agentchat/contrib/captainagent/tools/information_retrieval/image_qa.py +60 -0
  62. autogen/agentchat/contrib/captainagent/tools/information_retrieval/optical_character_recognition.py +61 -0
  63. autogen/agentchat/contrib/captainagent/tools/information_retrieval/perform_web_search.py +47 -0
  64. autogen/agentchat/contrib/captainagent/tools/information_retrieval/scrape_wikipedia_tables.py +33 -0
  65. autogen/agentchat/contrib/captainagent/tools/information_retrieval/transcribe_audio_file.py +21 -0
  66. autogen/agentchat/contrib/captainagent/tools/information_retrieval/youtube_download.py +35 -0
  67. autogen/agentchat/contrib/captainagent/tools/math/calculate_circle_area_from_diameter.py +21 -0
  68. autogen/agentchat/contrib/captainagent/tools/math/calculate_day_of_the_week.py +18 -0
  69. autogen/agentchat/contrib/captainagent/tools/math/calculate_fraction_sum.py +28 -0
  70. autogen/agentchat/contrib/captainagent/tools/math/calculate_matrix_power.py +31 -0
  71. autogen/agentchat/contrib/captainagent/tools/math/calculate_reflected_point.py +16 -0
  72. autogen/agentchat/contrib/captainagent/tools/math/complex_numbers_product.py +25 -0
  73. autogen/agentchat/contrib/captainagent/tools/math/compute_currency_conversion.py +23 -0
  74. autogen/agentchat/contrib/captainagent/tools/math/count_distinct_permutations.py +27 -0
  75. autogen/agentchat/contrib/captainagent/tools/math/evaluate_expression.py +28 -0
  76. autogen/agentchat/contrib/captainagent/tools/math/find_continuity_point.py +34 -0
  77. autogen/agentchat/contrib/captainagent/tools/math/fraction_to_mixed_numbers.py +39 -0
  78. autogen/agentchat/contrib/captainagent/tools/math/modular_inverse_sum.py +23 -0
  79. autogen/agentchat/contrib/captainagent/tools/math/simplify_mixed_numbers.py +36 -0
  80. autogen/agentchat/contrib/captainagent/tools/math/sum_of_digit_factorials.py +15 -0
  81. autogen/agentchat/contrib/captainagent/tools/math/sum_of_primes_below.py +15 -0
  82. autogen/agentchat/contrib/captainagent/tools/requirements.txt +10 -0
  83. autogen/agentchat/contrib/captainagent/tools/tool_description.tsv +34 -0
  84. autogen/agentchat/contrib/gpt_assistant_agent.py +526 -0
  85. autogen/agentchat/contrib/graph_rag/__init__.py +9 -0
  86. autogen/agentchat/contrib/graph_rag/document.py +29 -0
  87. autogen/agentchat/contrib/graph_rag/falkor_graph_query_engine.py +167 -0
  88. autogen/agentchat/contrib/graph_rag/falkor_graph_rag_capability.py +103 -0
  89. autogen/agentchat/contrib/graph_rag/graph_query_engine.py +53 -0
  90. autogen/agentchat/contrib/graph_rag/graph_rag_capability.py +63 -0
  91. autogen/agentchat/contrib/graph_rag/neo4j_graph_query_engine.py +263 -0
  92. autogen/agentchat/contrib/graph_rag/neo4j_graph_rag_capability.py +83 -0
  93. autogen/agentchat/contrib/graph_rag/neo4j_native_graph_query_engine.py +210 -0
  94. autogen/agentchat/contrib/graph_rag/neo4j_native_graph_rag_capability.py +93 -0
  95. autogen/agentchat/contrib/img_utils.py +397 -0
  96. autogen/agentchat/contrib/llamaindex_conversable_agent.py +117 -0
  97. autogen/agentchat/contrib/llava_agent.py +189 -0
  98. autogen/agentchat/contrib/math_user_proxy_agent.py +464 -0
  99. autogen/agentchat/contrib/multimodal_conversable_agent.py +125 -0
  100. autogen/agentchat/contrib/qdrant_retrieve_user_proxy_agent.py +325 -0
  101. autogen/agentchat/contrib/rag/__init__.py +10 -0
  102. autogen/agentchat/contrib/rag/chromadb_query_engine.py +268 -0
  103. autogen/agentchat/contrib/rag/llamaindex_query_engine.py +195 -0
  104. autogen/agentchat/contrib/rag/mongodb_query_engine.py +319 -0
  105. autogen/agentchat/contrib/rag/query_engine.py +76 -0
  106. autogen/agentchat/contrib/retrieve_assistant_agent.py +59 -0
  107. autogen/agentchat/contrib/retrieve_user_proxy_agent.py +704 -0
  108. autogen/agentchat/contrib/society_of_mind_agent.py +200 -0
  109. autogen/agentchat/contrib/swarm_agent.py +1404 -0
  110. autogen/agentchat/contrib/text_analyzer_agent.py +79 -0
  111. autogen/agentchat/contrib/vectordb/__init__.py +5 -0
  112. autogen/agentchat/contrib/vectordb/base.py +224 -0
  113. autogen/agentchat/contrib/vectordb/chromadb.py +316 -0
  114. autogen/agentchat/contrib/vectordb/couchbase.py +405 -0
  115. autogen/agentchat/contrib/vectordb/mongodb.py +551 -0
  116. autogen/agentchat/contrib/vectordb/pgvectordb.py +927 -0
  117. autogen/agentchat/contrib/vectordb/qdrant.py +320 -0
  118. autogen/agentchat/contrib/vectordb/utils.py +126 -0
  119. autogen/agentchat/contrib/web_surfer.py +304 -0
  120. autogen/agentchat/conversable_agent.py +4307 -0
  121. autogen/agentchat/group/__init__.py +67 -0
  122. autogen/agentchat/group/available_condition.py +91 -0
  123. autogen/agentchat/group/context_condition.py +77 -0
  124. autogen/agentchat/group/context_expression.py +238 -0
  125. autogen/agentchat/group/context_str.py +39 -0
  126. autogen/agentchat/group/context_variables.py +182 -0
  127. autogen/agentchat/group/events/transition_events.py +111 -0
  128. autogen/agentchat/group/group_tool_executor.py +324 -0
  129. autogen/agentchat/group/group_utils.py +659 -0
  130. autogen/agentchat/group/guardrails.py +179 -0
  131. autogen/agentchat/group/handoffs.py +303 -0
  132. autogen/agentchat/group/llm_condition.py +93 -0
  133. autogen/agentchat/group/multi_agent_chat.py +291 -0
  134. autogen/agentchat/group/on_condition.py +55 -0
  135. autogen/agentchat/group/on_context_condition.py +51 -0
  136. autogen/agentchat/group/patterns/__init__.py +18 -0
  137. autogen/agentchat/group/patterns/auto.py +160 -0
  138. autogen/agentchat/group/patterns/manual.py +177 -0
  139. autogen/agentchat/group/patterns/pattern.py +295 -0
  140. autogen/agentchat/group/patterns/random.py +106 -0
  141. autogen/agentchat/group/patterns/round_robin.py +117 -0
  142. autogen/agentchat/group/reply_result.py +24 -0
  143. autogen/agentchat/group/safeguards/__init__.py +21 -0
  144. autogen/agentchat/group/safeguards/api.py +241 -0
  145. autogen/agentchat/group/safeguards/enforcer.py +1158 -0
  146. autogen/agentchat/group/safeguards/events.py +140 -0
  147. autogen/agentchat/group/safeguards/validator.py +435 -0
  148. autogen/agentchat/group/speaker_selection_result.py +41 -0
  149. autogen/agentchat/group/targets/__init__.py +4 -0
  150. autogen/agentchat/group/targets/function_target.py +245 -0
  151. autogen/agentchat/group/targets/group_chat_target.py +133 -0
  152. autogen/agentchat/group/targets/group_manager_target.py +151 -0
  153. autogen/agentchat/group/targets/transition_target.py +424 -0
  154. autogen/agentchat/group/targets/transition_utils.py +6 -0
  155. autogen/agentchat/groupchat.py +1832 -0
  156. autogen/agentchat/realtime/__init__.py +3 -0
  157. autogen/agentchat/realtime/experimental/__init__.py +20 -0
  158. autogen/agentchat/realtime/experimental/audio_adapters/__init__.py +8 -0
  159. autogen/agentchat/realtime/experimental/audio_adapters/twilio_audio_adapter.py +148 -0
  160. autogen/agentchat/realtime/experimental/audio_adapters/websocket_audio_adapter.py +139 -0
  161. autogen/agentchat/realtime/experimental/audio_observer.py +42 -0
  162. autogen/agentchat/realtime/experimental/clients/__init__.py +15 -0
  163. autogen/agentchat/realtime/experimental/clients/gemini/__init__.py +7 -0
  164. autogen/agentchat/realtime/experimental/clients/gemini/client.py +274 -0
  165. autogen/agentchat/realtime/experimental/clients/oai/__init__.py +8 -0
  166. autogen/agentchat/realtime/experimental/clients/oai/base_client.py +220 -0
  167. autogen/agentchat/realtime/experimental/clients/oai/rtc_client.py +243 -0
  168. autogen/agentchat/realtime/experimental/clients/oai/utils.py +48 -0
  169. autogen/agentchat/realtime/experimental/clients/realtime_client.py +191 -0
  170. autogen/agentchat/realtime/experimental/function_observer.py +84 -0
  171. autogen/agentchat/realtime/experimental/realtime_agent.py +158 -0
  172. autogen/agentchat/realtime/experimental/realtime_events.py +42 -0
  173. autogen/agentchat/realtime/experimental/realtime_observer.py +100 -0
  174. autogen/agentchat/realtime/experimental/realtime_swarm.py +533 -0
  175. autogen/agentchat/realtime/experimental/websockets.py +21 -0
  176. autogen/agentchat/realtime_agent/__init__.py +21 -0
  177. autogen/agentchat/user_proxy_agent.py +114 -0
  178. autogen/agentchat/utils.py +206 -0
  179. autogen/agents/__init__.py +3 -0
  180. autogen/agents/contrib/__init__.py +10 -0
  181. autogen/agents/contrib/time/__init__.py +8 -0
  182. autogen/agents/contrib/time/time_reply_agent.py +74 -0
  183. autogen/agents/contrib/time/time_tool_agent.py +52 -0
  184. autogen/agents/experimental/__init__.py +27 -0
  185. autogen/agents/experimental/deep_research/__init__.py +7 -0
  186. autogen/agents/experimental/deep_research/deep_research.py +52 -0
  187. autogen/agents/experimental/discord/__init__.py +7 -0
  188. autogen/agents/experimental/discord/discord.py +66 -0
  189. autogen/agents/experimental/document_agent/__init__.py +19 -0
  190. autogen/agents/experimental/document_agent/chroma_query_engine.py +301 -0
  191. autogen/agents/experimental/document_agent/docling_doc_ingest_agent.py +113 -0
  192. autogen/agents/experimental/document_agent/document_agent.py +643 -0
  193. autogen/agents/experimental/document_agent/document_conditions.py +50 -0
  194. autogen/agents/experimental/document_agent/document_utils.py +376 -0
  195. autogen/agents/experimental/document_agent/inmemory_query_engine.py +214 -0
  196. autogen/agents/experimental/document_agent/parser_utils.py +134 -0
  197. autogen/agents/experimental/document_agent/url_utils.py +417 -0
  198. autogen/agents/experimental/reasoning/__init__.py +7 -0
  199. autogen/agents/experimental/reasoning/reasoning_agent.py +1178 -0
  200. autogen/agents/experimental/slack/__init__.py +7 -0
  201. autogen/agents/experimental/slack/slack.py +73 -0
  202. autogen/agents/experimental/telegram/__init__.py +7 -0
  203. autogen/agents/experimental/telegram/telegram.py +76 -0
  204. autogen/agents/experimental/websurfer/__init__.py +7 -0
  205. autogen/agents/experimental/websurfer/websurfer.py +70 -0
  206. autogen/agents/experimental/wikipedia/__init__.py +7 -0
  207. autogen/agents/experimental/wikipedia/wikipedia.py +88 -0
  208. autogen/browser_utils.py +309 -0
  209. autogen/cache/__init__.py +10 -0
  210. autogen/cache/abstract_cache_base.py +71 -0
  211. autogen/cache/cache.py +203 -0
  212. autogen/cache/cache_factory.py +88 -0
  213. autogen/cache/cosmos_db_cache.py +144 -0
  214. autogen/cache/disk_cache.py +97 -0
  215. autogen/cache/in_memory_cache.py +54 -0
  216. autogen/cache/redis_cache.py +119 -0
  217. autogen/code_utils.py +598 -0
  218. autogen/coding/__init__.py +30 -0
  219. autogen/coding/base.py +120 -0
  220. autogen/coding/docker_commandline_code_executor.py +283 -0
  221. autogen/coding/factory.py +56 -0
  222. autogen/coding/func_with_reqs.py +203 -0
  223. autogen/coding/jupyter/__init__.py +23 -0
  224. autogen/coding/jupyter/base.py +36 -0
  225. autogen/coding/jupyter/docker_jupyter_server.py +160 -0
  226. autogen/coding/jupyter/embedded_ipython_code_executor.py +182 -0
  227. autogen/coding/jupyter/import_utils.py +82 -0
  228. autogen/coding/jupyter/jupyter_client.py +224 -0
  229. autogen/coding/jupyter/jupyter_code_executor.py +154 -0
  230. autogen/coding/jupyter/local_jupyter_server.py +164 -0
  231. autogen/coding/local_commandline_code_executor.py +341 -0
  232. autogen/coding/markdown_code_extractor.py +44 -0
  233. autogen/coding/utils.py +55 -0
  234. autogen/coding/yepcode_code_executor.py +197 -0
  235. autogen/doc_utils.py +35 -0
  236. autogen/environments/__init__.py +10 -0
  237. autogen/environments/docker_python_environment.py +365 -0
  238. autogen/environments/python_environment.py +125 -0
  239. autogen/environments/system_python_environment.py +85 -0
  240. autogen/environments/venv_python_environment.py +220 -0
  241. autogen/environments/working_directory.py +74 -0
  242. autogen/events/__init__.py +7 -0
  243. autogen/events/agent_events.py +1016 -0
  244. autogen/events/base_event.py +100 -0
  245. autogen/events/client_events.py +168 -0
  246. autogen/events/helpers.py +44 -0
  247. autogen/events/print_event.py +45 -0
  248. autogen/exception_utils.py +73 -0
  249. autogen/extensions/__init__.py +5 -0
  250. autogen/fast_depends/__init__.py +16 -0
  251. autogen/fast_depends/_compat.py +75 -0
  252. autogen/fast_depends/core/__init__.py +14 -0
  253. autogen/fast_depends/core/build.py +206 -0
  254. autogen/fast_depends/core/model.py +527 -0
  255. autogen/fast_depends/dependencies/__init__.py +15 -0
  256. autogen/fast_depends/dependencies/model.py +30 -0
  257. autogen/fast_depends/dependencies/provider.py +40 -0
  258. autogen/fast_depends/library/__init__.py +10 -0
  259. autogen/fast_depends/library/model.py +46 -0
  260. autogen/fast_depends/py.typed +6 -0
  261. autogen/fast_depends/schema.py +66 -0
  262. autogen/fast_depends/use.py +272 -0
  263. autogen/fast_depends/utils.py +177 -0
  264. autogen/formatting_utils.py +83 -0
  265. autogen/function_utils.py +13 -0
  266. autogen/graph_utils.py +173 -0
  267. autogen/import_utils.py +539 -0
  268. autogen/interop/__init__.py +22 -0
  269. autogen/interop/crewai/__init__.py +7 -0
  270. autogen/interop/crewai/crewai.py +88 -0
  271. autogen/interop/interoperability.py +71 -0
  272. autogen/interop/interoperable.py +46 -0
  273. autogen/interop/langchain/__init__.py +8 -0
  274. autogen/interop/langchain/langchain_chat_model_factory.py +156 -0
  275. autogen/interop/langchain/langchain_tool.py +78 -0
  276. autogen/interop/litellm/__init__.py +7 -0
  277. autogen/interop/litellm/litellm_config_factory.py +178 -0
  278. autogen/interop/pydantic_ai/__init__.py +7 -0
  279. autogen/interop/pydantic_ai/pydantic_ai.py +172 -0
  280. autogen/interop/registry.py +70 -0
  281. autogen/io/__init__.py +15 -0
  282. autogen/io/base.py +151 -0
  283. autogen/io/console.py +56 -0
  284. autogen/io/processors/__init__.py +12 -0
  285. autogen/io/processors/base.py +21 -0
  286. autogen/io/processors/console_event_processor.py +61 -0
  287. autogen/io/run_response.py +294 -0
  288. autogen/io/thread_io_stream.py +63 -0
  289. autogen/io/websockets.py +214 -0
  290. autogen/json_utils.py +42 -0
  291. autogen/llm_clients/MIGRATION_TO_V2.md +782 -0
  292. autogen/llm_clients/__init__.py +77 -0
  293. autogen/llm_clients/client_v2.py +122 -0
  294. autogen/llm_clients/models/__init__.py +55 -0
  295. autogen/llm_clients/models/content_blocks.py +389 -0
  296. autogen/llm_clients/models/unified_message.py +145 -0
  297. autogen/llm_clients/models/unified_response.py +83 -0
  298. autogen/llm_clients/openai_completions_client.py +444 -0
  299. autogen/llm_config/__init__.py +11 -0
  300. autogen/llm_config/client.py +59 -0
  301. autogen/llm_config/config.py +461 -0
  302. autogen/llm_config/entry.py +169 -0
  303. autogen/llm_config/types.py +37 -0
  304. autogen/llm_config/utils.py +223 -0
  305. autogen/logger/__init__.py +11 -0
  306. autogen/logger/base_logger.py +129 -0
  307. autogen/logger/file_logger.py +262 -0
  308. autogen/logger/logger_factory.py +42 -0
  309. autogen/logger/logger_utils.py +57 -0
  310. autogen/logger/sqlite_logger.py +524 -0
  311. autogen/math_utils.py +338 -0
  312. autogen/mcp/__init__.py +7 -0
  313. autogen/mcp/__main__.py +78 -0
  314. autogen/mcp/helpers.py +45 -0
  315. autogen/mcp/mcp_client.py +349 -0
  316. autogen/mcp/mcp_proxy/__init__.py +19 -0
  317. autogen/mcp/mcp_proxy/fastapi_code_generator_helpers.py +62 -0
  318. autogen/mcp/mcp_proxy/mcp_proxy.py +577 -0
  319. autogen/mcp/mcp_proxy/operation_grouping.py +166 -0
  320. autogen/mcp/mcp_proxy/operation_renaming.py +110 -0
  321. autogen/mcp/mcp_proxy/patch_fastapi_code_generator.py +98 -0
  322. autogen/mcp/mcp_proxy/security.py +399 -0
  323. autogen/mcp/mcp_proxy/security_schema_visitor.py +37 -0
  324. autogen/messages/__init__.py +7 -0
  325. autogen/messages/agent_messages.py +946 -0
  326. autogen/messages/base_message.py +108 -0
  327. autogen/messages/client_messages.py +172 -0
  328. autogen/messages/print_message.py +48 -0
  329. autogen/oai/__init__.py +61 -0
  330. autogen/oai/anthropic.py +1516 -0
  331. autogen/oai/bedrock.py +800 -0
  332. autogen/oai/cerebras.py +302 -0
  333. autogen/oai/client.py +1658 -0
  334. autogen/oai/client_utils.py +196 -0
  335. autogen/oai/cohere.py +494 -0
  336. autogen/oai/gemini.py +1045 -0
  337. autogen/oai/gemini_types.py +156 -0
  338. autogen/oai/groq.py +319 -0
  339. autogen/oai/mistral.py +311 -0
  340. autogen/oai/oai_models/__init__.py +23 -0
  341. autogen/oai/oai_models/_models.py +16 -0
  342. autogen/oai/oai_models/chat_completion.py +86 -0
  343. autogen/oai/oai_models/chat_completion_audio.py +32 -0
  344. autogen/oai/oai_models/chat_completion_message.py +97 -0
  345. autogen/oai/oai_models/chat_completion_message_tool_call.py +60 -0
  346. autogen/oai/oai_models/chat_completion_token_logprob.py +62 -0
  347. autogen/oai/oai_models/completion_usage.py +59 -0
  348. autogen/oai/ollama.py +657 -0
  349. autogen/oai/openai_responses.py +451 -0
  350. autogen/oai/openai_utils.py +897 -0
  351. autogen/oai/together.py +387 -0
  352. autogen/remote/__init__.py +18 -0
  353. autogen/remote/agent.py +199 -0
  354. autogen/remote/agent_service.py +197 -0
  355. autogen/remote/errors.py +17 -0
  356. autogen/remote/httpx_client_factory.py +131 -0
  357. autogen/remote/protocol.py +37 -0
  358. autogen/remote/retry.py +102 -0
  359. autogen/remote/runtime.py +96 -0
  360. autogen/retrieve_utils.py +490 -0
  361. autogen/runtime_logging.py +161 -0
  362. autogen/testing/__init__.py +12 -0
  363. autogen/testing/messages.py +45 -0
  364. autogen/testing/test_agent.py +111 -0
  365. autogen/token_count_utils.py +280 -0
  366. autogen/tools/__init__.py +20 -0
  367. autogen/tools/contrib/__init__.py +9 -0
  368. autogen/tools/contrib/time/__init__.py +7 -0
  369. autogen/tools/contrib/time/time.py +40 -0
  370. autogen/tools/dependency_injection.py +249 -0
  371. autogen/tools/experimental/__init__.py +54 -0
  372. autogen/tools/experimental/browser_use/__init__.py +7 -0
  373. autogen/tools/experimental/browser_use/browser_use.py +154 -0
  374. autogen/tools/experimental/code_execution/__init__.py +7 -0
  375. autogen/tools/experimental/code_execution/python_code_execution.py +86 -0
  376. autogen/tools/experimental/crawl4ai/__init__.py +7 -0
  377. autogen/tools/experimental/crawl4ai/crawl4ai.py +150 -0
  378. autogen/tools/experimental/deep_research/__init__.py +7 -0
  379. autogen/tools/experimental/deep_research/deep_research.py +329 -0
  380. autogen/tools/experimental/duckduckgo/__init__.py +7 -0
  381. autogen/tools/experimental/duckduckgo/duckduckgo_search.py +103 -0
  382. autogen/tools/experimental/firecrawl/__init__.py +7 -0
  383. autogen/tools/experimental/firecrawl/firecrawl_tool.py +836 -0
  384. autogen/tools/experimental/google/__init__.py +14 -0
  385. autogen/tools/experimental/google/authentication/__init__.py +11 -0
  386. autogen/tools/experimental/google/authentication/credentials_hosted_provider.py +43 -0
  387. autogen/tools/experimental/google/authentication/credentials_local_provider.py +91 -0
  388. autogen/tools/experimental/google/authentication/credentials_provider.py +35 -0
  389. autogen/tools/experimental/google/drive/__init__.py +9 -0
  390. autogen/tools/experimental/google/drive/drive_functions.py +124 -0
  391. autogen/tools/experimental/google/drive/toolkit.py +88 -0
  392. autogen/tools/experimental/google/model.py +17 -0
  393. autogen/tools/experimental/google/toolkit_protocol.py +19 -0
  394. autogen/tools/experimental/google_search/__init__.py +8 -0
  395. autogen/tools/experimental/google_search/google_search.py +93 -0
  396. autogen/tools/experimental/google_search/youtube_search.py +181 -0
  397. autogen/tools/experimental/messageplatform/__init__.py +17 -0
  398. autogen/tools/experimental/messageplatform/discord/__init__.py +7 -0
  399. autogen/tools/experimental/messageplatform/discord/discord.py +284 -0
  400. autogen/tools/experimental/messageplatform/slack/__init__.py +7 -0
  401. autogen/tools/experimental/messageplatform/slack/slack.py +385 -0
  402. autogen/tools/experimental/messageplatform/telegram/__init__.py +7 -0
  403. autogen/tools/experimental/messageplatform/telegram/telegram.py +271 -0
  404. autogen/tools/experimental/perplexity/__init__.py +7 -0
  405. autogen/tools/experimental/perplexity/perplexity_search.py +249 -0
  406. autogen/tools/experimental/reliable/__init__.py +10 -0
  407. autogen/tools/experimental/reliable/reliable.py +1311 -0
  408. autogen/tools/experimental/searxng/__init__.py +7 -0
  409. autogen/tools/experimental/searxng/searxng_search.py +142 -0
  410. autogen/tools/experimental/tavily/__init__.py +7 -0
  411. autogen/tools/experimental/tavily/tavily_search.py +176 -0
  412. autogen/tools/experimental/web_search_preview/__init__.py +7 -0
  413. autogen/tools/experimental/web_search_preview/web_search_preview.py +120 -0
  414. autogen/tools/experimental/wikipedia/__init__.py +7 -0
  415. autogen/tools/experimental/wikipedia/wikipedia.py +284 -0
  416. autogen/tools/function_utils.py +412 -0
  417. autogen/tools/tool.py +188 -0
  418. autogen/tools/toolkit.py +86 -0
  419. autogen/types.py +29 -0
  420. autogen/version.py +7 -0
  421. templates/client_template/main.jinja2 +72 -0
  422. templates/config_template/config.jinja2 +7 -0
  423. templates/main.jinja2 +61 -0
@@ -0,0 +1,197 @@
1
+ # Copyright (c) 2023 - 2025, AG2ai, Inc., AG2ai open-source projects maintainers and core contributors
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ import warnings
6
+ from typing import Any, Literal, cast
7
+
8
+ from autogen.agentchat import ConversableAgent
9
+ from autogen.agentchat.conversable_agent import normilize_message_to_oai
10
+ from autogen.agentchat.group.context_variables import ContextVariables
11
+ from autogen.agentchat.group.group_tool_executor import GroupToolExecutor
12
+ from autogen.agentchat.group.reply_result import ReplyResult
13
+ from autogen.agentchat.group.targets.transition_target import AskUserTarget, TransitionTarget
14
+ from autogen.events.agent_events import TerminationAndHumanReplyNoInputEvent, TerminationEvent, UsingAutoReplyEvent
15
+ from autogen.events.base_event import BaseEvent
16
+ from autogen.io.base import AsyncIOStreamProtocol
17
+
18
+ from .protocol import RemoteService, RequestMessage, ResponseMessage, get_tool_names
19
+
20
+
21
+ class AgentService(RemoteService):
22
+ def __init__(self, agent: ConversableAgent) -> None:
23
+ self.name = agent.name
24
+ self.agent = agent
25
+
26
+ async def __call__(self, state: RequestMessage) -> ResponseMessage | None:
27
+ out_message: dict[str, Any] | None
28
+ if guardrail_result := self.agent.run_input_guardrails(state.messages):
29
+ # input guardrail activated by initial messages
30
+ _, out_message = normilize_message_to_oai(guardrail_result.reply, self.agent.name, role="assistant")
31
+ return ResponseMessage(messages=[out_message], context=state.context)
32
+
33
+ context_variables = ContextVariables(state.context)
34
+ tool_executor = self._make_tool_executor(context_variables)
35
+
36
+ local_history: list[dict[str, Any]] = []
37
+ while True:
38
+ messages = state.messages + local_history
39
+
40
+ stream = HITLStream()
41
+ await self.agent.a_check_termination_and_human_reply(messages, iostream=stream)
42
+ if stream.is_input_required:
43
+ return ResponseMessage(
44
+ messages=local_history,
45
+ context=context_variables.data or None,
46
+ input_required=stream.input_prompt,
47
+ )
48
+
49
+ reply = await self.agent.a_generate_reply(
50
+ messages,
51
+ exclude=(
52
+ ConversableAgent.check_termination_and_human_reply,
53
+ ConversableAgent.a_check_termination_and_human_reply,
54
+ ConversableAgent.generate_oai_reply,
55
+ ConversableAgent.a_generate_oai_reply,
56
+ ),
57
+ )
58
+
59
+ if not reply:
60
+ _, reply = await self.agent.a_generate_oai_reply(
61
+ messages,
62
+ tools=state.client_tools,
63
+ )
64
+
65
+ should_continue, out_message = self._add_message_to_local_history(reply, role="assistant")
66
+ if out_message:
67
+ local_history.append(out_message)
68
+ if not should_continue:
69
+ break
70
+ out_message = cast(dict[str, Any], out_message)
71
+
72
+ called_tools = get_tool_names(out_message.get("tool_calls", []))
73
+ if state.client_tool_names.intersection(called_tools):
74
+ break # return client tool execution command back to client
75
+
76
+ tool_result, updated_context_variables, return_to_user = self._try_execute_local_tool(
77
+ tool_executor, out_message
78
+ )
79
+
80
+ if updated_context_variables:
81
+ context_variables.update(updated_context_variables.to_dict())
82
+
83
+ should_continue, out_message = self._add_message_to_local_history(tool_result, role="tool")
84
+ if out_message:
85
+ local_history.append(out_message)
86
+
87
+ if return_to_user:
88
+ return ResponseMessage(
89
+ messages=local_history,
90
+ context=context_variables.data or None,
91
+ input_required="Please, provide additional information:\n",
92
+ )
93
+
94
+ if not should_continue:
95
+ break
96
+
97
+ if not local_history:
98
+ return None
99
+
100
+ return ResponseMessage(
101
+ messages=local_history,
102
+ context=context_variables.data or None,
103
+ )
104
+
105
+ def _add_message_to_local_history(
106
+ self, message: str | dict[str, Any] | None, role: str
107
+ ) -> tuple[Literal[True], dict[str, Any]] | tuple[Literal[False], dict[str, Any] | None]:
108
+ if message is None:
109
+ return False, None # output message is empty, interrupt the loop
110
+
111
+ if guardrail_result := self.agent.run_output_guardrails(message):
112
+ _, out_message = normilize_message_to_oai(guardrail_result.reply, self.agent.name, role=role)
113
+ return False, out_message # output guardrail activated, interrupt the loop
114
+
115
+ valid, out_message = normilize_message_to_oai(message, self.agent.name, role=role)
116
+ if not valid:
117
+ return False, None # tool result is not valid OAI message, interrupt the loop
118
+
119
+ return True, out_message
120
+
121
+ def _make_tool_executor(self, context_variables: ContextVariables) -> GroupToolExecutor:
122
+ tool_executor = GroupToolExecutor()
123
+ for tool in self.agent.tools:
124
+ # TODO: inject ChatContext to tool
125
+ new_tool = tool_executor.make_tool_copy_with_context_variables(tool, context_variables) or tool
126
+ tool_executor.register_for_execution(serialize=False, silent_override=True)(new_tool)
127
+ return tool_executor
128
+
129
+ def _try_execute_local_tool(
130
+ self,
131
+ tool_executor: GroupToolExecutor,
132
+ tool_message: dict[str, Any],
133
+ ) -> tuple[dict[str, Any] | None, ContextVariables | None, bool]:
134
+ tool_result: dict[str, Any] | None = None
135
+ updated_context_variables: ContextVariables | None = None
136
+
137
+ if "tool_calls" in tool_message:
138
+ _, tool_result = tool_executor.generate_tool_calls_reply([tool_message])
139
+ if tool_result is None:
140
+ return tool_result, updated_context_variables, False
141
+
142
+ if "tool_responses" in tool_result:
143
+ # TODO: catch handoffs
144
+ for tool_response in tool_result["tool_responses"]:
145
+ content = tool_response["content"]
146
+
147
+ if isinstance(content, AskUserTarget):
148
+ return tool_result, updated_context_variables, True
149
+
150
+ if isinstance(content, TransitionTarget):
151
+ warnings.warn(
152
+ f"Tool {self.agent.name} returned a target, which is not supported in remote mode"
153
+ )
154
+
155
+ elif isinstance(content, ReplyResult):
156
+ if content.context_variables:
157
+ updated_context_variables = content.context_variables
158
+ tool_response["content"] = content.message
159
+
160
+ if isinstance(content.target, AskUserTarget):
161
+ return tool_result, updated_context_variables, True
162
+
163
+ if content.target:
164
+ warnings.warn(
165
+ f"Tool {self.agent.name} returned a target, which is not supported in remote mode"
166
+ )
167
+
168
+ return tool_result, updated_context_variables, False
169
+
170
+
171
+ class HITLStream(AsyncIOStreamProtocol):
172
+ def __init__(self) -> None:
173
+ self.input_prompt = ""
174
+
175
+ @property
176
+ def is_input_required(self) -> bool:
177
+ return bool(self.input_prompt)
178
+
179
+ async def input(self, prompt: str = "", *, password: bool = False) -> str:
180
+ self.input_prompt = prompt
181
+ return ""
182
+
183
+ def print(self, *objects: Any, sep: str = " ", end: str = "\n", flush: bool = False) -> None:
184
+ raise NotImplementedError("HITLStream does not support printing")
185
+
186
+ def send(self, message: BaseEvent) -> None:
187
+ if isinstance(
188
+ message,
189
+ (
190
+ UsingAutoReplyEvent,
191
+ TerminationAndHumanReplyNoInputEvent,
192
+ TerminationEvent,
193
+ ),
194
+ ):
195
+ return
196
+
197
+ raise NotImplementedError("HITLStream does not support sending messages")
@@ -0,0 +1,17 @@
1
+ # Copyright (c) 2023 - 2025, AG2ai, Inc., AG2ai open-source projects maintainers and core contributors
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+
6
+ class RemoteAgentError(Exception):
7
+ """Base class for remote agent errors"""
8
+
9
+ pass
10
+
11
+
12
+ class RemoteAgentNotFoundError(RemoteAgentError):
13
+ """Raised when a remote agent is not found"""
14
+
15
+ def __init__(self, agent_name: str) -> None:
16
+ self.agent_name = agent_name
17
+ super().__init__(f"Remote agent `{agent_name}` not found")
@@ -0,0 +1,131 @@
1
+ # Copyright (c) 2023 - 2025, AG2ai, Inc., AG2ai open-source projects maintainers and core contributors
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ import ssl
6
+ import typing
7
+ from typing import Protocol
8
+
9
+ from httpx._client import AsyncClient, Client, EventHook
10
+ from httpx._config import DEFAULT_LIMITS, DEFAULT_MAX_REDIRECTS, DEFAULT_TIMEOUT_CONFIG, Limits
11
+ from httpx._transports.base import AsyncBaseTransport
12
+ from httpx._types import AuthTypes, CertTypes, CookieTypes, HeaderTypes, ProxyTypes, QueryParamTypes, TimeoutTypes
13
+ from httpx._urls import URL
14
+
15
+ from autogen.doc_utils import export_module
16
+
17
+
18
+ class ClientFactory(Protocol):
19
+ def __call__(self) -> AsyncClient: ...
20
+
21
+ def make_sync(self) -> Client: ...
22
+
23
+
24
+ @export_module("autogen.a2a")
25
+ class HttpxClientFactory(ClientFactory):
26
+ """
27
+ An asynchronous HTTP client factory, with connection pooling, HTTP/2, redirects,
28
+ cookie persistence, etc.
29
+
30
+ It can be shared between tasks.
31
+
32
+ Usage:
33
+
34
+ ```python
35
+ >>> factory = HttpxClientFactory()
36
+ >>> async with factory() as client:
37
+ >>> response = await client.get('https://example.org')
38
+ ```
39
+
40
+ **Parameters:**
41
+
42
+ * **auth** - *(optional)* An authentication class to use when sending
43
+ requests.
44
+ * **params** - *(optional)* Query parameters to include in request URLs, as
45
+ a string, dictionary, or sequence of two-tuples.
46
+ * **headers** - *(optional)* Dictionary of HTTP headers to include when
47
+ sending requests.
48
+ * **cookies** - *(optional)* Dictionary of Cookie items to include when
49
+ sending requests.
50
+ * **verify** - *(optional)* Either `True` to use an SSL context with the
51
+ default CA bundle, `False` to disable verification, or an instance of
52
+ `ssl.SSLContext` to use a custom context.
53
+ * **http2** - *(optional)* A boolean indicating if HTTP/2 support should be
54
+ enabled. Defaults to `False`.
55
+ * **proxy** - *(optional)* A proxy URL where all the traffic should be routed.
56
+ * **timeout** - *(optional)* The timeout configuration to use when sending
57
+ requests.
58
+ * **limits** - *(optional)* The limits configuration to use.
59
+ * **max_redirects** - *(optional)* The maximum number of redirect responses
60
+ that should be followed.
61
+ * **base_url** - *(optional)* A URL to use as the base when building
62
+ request URLs.
63
+ * **transport** - *(optional)* A transport class to use for sending requests
64
+ over the network.
65
+ * **trust_env** - *(optional)* Enables or disables usage of environment
66
+ variables for configuration.
67
+ * **default_encoding** - *(optional)* The default encoding to use for decoding
68
+ response text, if no charset information is included in a response Content-Type
69
+ header. Set to a callable for automatic character set detection. Default: "utf-8".
70
+ """
71
+
72
+ def __init__(
73
+ self,
74
+ *,
75
+ auth: AuthTypes | None = None,
76
+ params: QueryParamTypes | None = None,
77
+ headers: HeaderTypes | None = None,
78
+ cookies: CookieTypes | None = None,
79
+ verify: ssl.SSLContext | str | bool = True,
80
+ cert: CertTypes | None = None,
81
+ http1: bool = True,
82
+ http2: bool = False,
83
+ proxy: ProxyTypes | None = None,
84
+ mounts: None | (typing.Mapping[str, AsyncBaseTransport | None]) = None,
85
+ timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG,
86
+ follow_redirects: bool = False,
87
+ limits: Limits = DEFAULT_LIMITS,
88
+ max_redirects: int = DEFAULT_MAX_REDIRECTS,
89
+ event_hooks: None | (typing.Mapping[str, list[EventHook]]) = None,
90
+ base_url: URL | str = "",
91
+ transport: AsyncBaseTransport | None = None,
92
+ trust_env: bool = True,
93
+ default_encoding: str | typing.Callable[[bytes], str] = "utf-8",
94
+ **kwargs: typing.Any,
95
+ ) -> None:
96
+ self.options = {
97
+ "auth": auth,
98
+ "params": params,
99
+ "headers": headers,
100
+ "cookies": cookies,
101
+ "verify": verify,
102
+ "cert": cert,
103
+ "http1": http1,
104
+ "http2": http2,
105
+ "proxy": proxy,
106
+ "mounts": mounts,
107
+ "timeout": timeout,
108
+ "follow_redirects": follow_redirects,
109
+ "limits": limits,
110
+ "max_redirects": max_redirects,
111
+ "event_hooks": event_hooks,
112
+ "base_url": base_url,
113
+ "transport": transport,
114
+ "trust_env": trust_env,
115
+ "default_encoding": default_encoding,
116
+ **kwargs,
117
+ }
118
+
119
+ def __call__(self) -> AsyncClient:
120
+ return AsyncClient(**self.options)
121
+
122
+ def make_sync(self) -> Client:
123
+ return Client(**self.options)
124
+
125
+
126
+ class EmptyClientFactory(ClientFactory):
127
+ def __call__(self) -> AsyncClient:
128
+ return AsyncClient(timeout=30.0)
129
+
130
+ def make_sync(self) -> Client:
131
+ return Client(timeout=30.0)
@@ -0,0 +1,37 @@
1
+ # Copyright (c) 2023 - 2025, AG2ai, Inc., AG2ai open-source projects maintainers and core contributors
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+ from typing import Any, Protocol
5
+
6
+ from pydantic import BaseModel, Field
7
+
8
+
9
+ class AgentBusMessage(BaseModel):
10
+ messages: list[dict[str, Any]] = Field(default_factory=list)
11
+ context: dict[str, Any] | None = None
12
+
13
+
14
+ class RequestMessage(AgentBusMessage):
15
+ client_tools: list[dict[str, Any]] = Field(default_factory=list)
16
+
17
+ @property
18
+ def client_tool_names(self) -> set[str]:
19
+ return get_tool_names(self.client_tools)
20
+
21
+
22
+ class ResponseMessage(AgentBusMessage):
23
+ input_required: str | None = None
24
+
25
+
26
+ class RemoteService(Protocol):
27
+ """Interface to make AgentBus compatible with non AG2 systems."""
28
+
29
+ name: str
30
+
31
+ async def __call__(self, state: RequestMessage) -> ResponseMessage | None:
32
+ """Executable that consumes Conversation State and returns a new state."""
33
+ ...
34
+
35
+
36
+ def get_tool_names(tools: list[dict[str, Any]]) -> set[str]:
37
+ return set(filter(bool, (tool.get("function", {}).get("name", "") for tool in tools)))
@@ -0,0 +1,102 @@
1
+ # Copyright (c) 2023 - 2025, AG2ai, Inc., AG2ai open-source projects maintainers and core contributors
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+ import time
5
+ from types import TracebackType
6
+ from typing import Protocol
7
+
8
+ import anyio
9
+
10
+
11
+ class RetryPolicyManager(Protocol):
12
+ def __enter__(self) -> None:
13
+ pass
14
+
15
+ async def __aenter__(self) -> None:
16
+ pass
17
+
18
+ def __exit__(
19
+ self, exc_type: type[BaseException] | None, exc_value: BaseException | None, traceback: TracebackType | None
20
+ ) -> None | bool:
21
+ pass
22
+
23
+ async def __aexit__(
24
+ self, exc_type: type[BaseException] | None, exc_value: BaseException | None, traceback: TracebackType | None
25
+ ) -> None | bool:
26
+ pass
27
+
28
+
29
+ class RetryPolicy(Protocol):
30
+ def __call__(self) -> RetryPolicyManager: ...
31
+
32
+
33
+ class SleepRetryPolicy(RetryPolicy):
34
+ def __init__(self, retry_interval: float = 10.0, retry_count: int = 3) -> None:
35
+ self.retry_interval = retry_interval
36
+ self.retry_count = retry_count
37
+
38
+ def __call__(self) -> RetryPolicyManager:
39
+ return _SleepRetryPolicy(self.retry_interval, self.retry_count)
40
+
41
+
42
+ class _SleepRetryPolicy(RetryPolicyManager):
43
+ def __init__(self, retry_interval: float = 10.0, retry_count: int = 3) -> None:
44
+ self.retry_interval = retry_interval
45
+ self.retry_count = retry_count
46
+ self.errors_count = 0
47
+
48
+ def __enter__(self) -> None:
49
+ pass
50
+
51
+ async def __aenter__(self) -> None:
52
+ pass
53
+
54
+ def __exit__(
55
+ self,
56
+ exc_type: type[BaseException] | None,
57
+ exc_value: BaseException | None,
58
+ traceback: TracebackType | None,
59
+ ) -> None | bool:
60
+ if exc_type is not None:
61
+ self.errors_count += 1
62
+ should_suppress = self.errors_count < self.retry_count
63
+ time.sleep(self.retry_interval)
64
+ return should_suppress
65
+ return None
66
+
67
+ async def __aexit__(
68
+ self,
69
+ exc_type: type[BaseException] | None,
70
+ exc_value: BaseException | None,
71
+ traceback: TracebackType | None,
72
+ ) -> None | bool:
73
+ if exc_type is not None:
74
+ self.errors_count += 1
75
+ should_suppress = self.errors_count < self.retry_count
76
+ await anyio.sleep(self.retry_interval)
77
+ return should_suppress
78
+ return None
79
+
80
+
81
+ class NoRetryPolicy(RetryPolicyManager):
82
+ def __enter__(self) -> None:
83
+ pass
84
+
85
+ async def __aenter__(self) -> None:
86
+ pass
87
+
88
+ async def __aexit__(
89
+ self,
90
+ exc_type: type[BaseException] | None,
91
+ exc_value: BaseException | None,
92
+ traceback: TracebackType | None,
93
+ ) -> None | bool:
94
+ pass
95
+
96
+ def __exit__(
97
+ self,
98
+ exc_type: type[BaseException] | None,
99
+ exc_value: BaseException | None,
100
+ traceback: TracebackType | None,
101
+ ) -> None | bool:
102
+ pass
@@ -0,0 +1,96 @@
1
+ # Copyright (c) 2023 - 2025, AG2ai, Inc., AG2ai open-source projects maintainers and core contributors
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ import asyncio
6
+ from collections.abc import Awaitable, Callable, Iterable, MutableMapping
7
+ from itertools import chain
8
+ from typing import Any
9
+ from uuid import UUID, uuid4
10
+
11
+ from fastapi import FastAPI, HTTPException, Response, status
12
+
13
+ from autogen.agentchat import ConversableAgent
14
+
15
+ from .agent_service import AgentService
16
+ from .protocol import RemoteService, RequestMessage, ResponseMessage
17
+
18
+
19
+ class HTTPAgentBus:
20
+ def __init__(
21
+ self,
22
+ agents: Iterable[ConversableAgent] = (),
23
+ *,
24
+ long_polling_interval: float = 10.0,
25
+ additional_services: Iterable[RemoteService] = (),
26
+ ) -> None:
27
+ """Create HTTPAgentBus runtime.
28
+
29
+ Makes the passed agents capable of processing remote calls.
30
+
31
+ Args:
32
+ agents: Agents to register as remote services.
33
+ long_polling_interval: Timeout to respond on task status calls for long-living executions.
34
+ Should be less than clients' HTTP request timeout.
35
+ additional_services: Additional services to register.
36
+ """
37
+ self.app = FastAPI()
38
+
39
+ for service in chain(map(AgentService, agents), additional_services):
40
+ register_agent_endpoints(
41
+ app=self.app,
42
+ service=service,
43
+ long_polling_interval=long_polling_interval,
44
+ )
45
+
46
+ async def __call__(
47
+ self,
48
+ scope: MutableMapping[str, Any],
49
+ receive: Callable[[], Awaitable[MutableMapping[str, Any]]],
50
+ send: Callable[[MutableMapping[str, Any]], Awaitable[None]],
51
+ ) -> None:
52
+ """ASGI interface."""
53
+ await self.app(scope, receive, send)
54
+
55
+
56
+ def register_agent_endpoints(
57
+ app: FastAPI,
58
+ service: RemoteService,
59
+ long_polling_interval: float,
60
+ ) -> None:
61
+ tasks: dict[UUID, asyncio.Task[ResponseMessage | None]] = {}
62
+
63
+ @app.get(f"/{service.name}" + "/{task_id}", response_model=ResponseMessage | None)
64
+ async def remote_call_result(task_id: UUID) -> Response | ResponseMessage | None:
65
+ if task_id not in tasks:
66
+ raise HTTPException(
67
+ detail=f"`{task_id}` task not found",
68
+ status_code=status.HTTP_404_NOT_FOUND,
69
+ )
70
+
71
+ task = tasks[task_id]
72
+
73
+ await asyncio.wait(
74
+ (task, asyncio.create_task(asyncio.sleep(long_polling_interval))),
75
+ return_when=asyncio.FIRST_COMPLETED,
76
+ )
77
+
78
+ if not task.done():
79
+ return Response(status_code=status.HTTP_425_TOO_EARLY)
80
+
81
+ try:
82
+ reply = task.result() # Task inner errors raising here
83
+ finally:
84
+ # TODO: how to clear hanged tasks?
85
+ tasks.pop(task_id, None)
86
+
87
+ if reply is None:
88
+ return Response(status_code=status.HTTP_204_NO_CONTENT)
89
+
90
+ return reply
91
+
92
+ @app.post(f"/{service.name}", status_code=status.HTTP_202_ACCEPTED)
93
+ async def remote_call_starter(state: RequestMessage) -> UUID:
94
+ task, task_id = asyncio.create_task(service(state)), uuid4()
95
+ tasks[task_id] = task
96
+ return task_id