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,659 @@
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 copy
6
+ from collections.abc import Callable
7
+ from functools import partial
8
+ from types import MethodType
9
+ from typing import TYPE_CHECKING, Any, Optional
10
+
11
+ from autogen.agentchat.group.events.transition_events import (
12
+ AfterWorksTransitionEvent,
13
+ OnContextConditionTransitionEvent,
14
+ )
15
+ from autogen.io.base import IOStream
16
+
17
+ from ..agent import Agent
18
+ from ..groupchat import GroupChat, GroupChatManager
19
+ from .context_variables import ContextVariables
20
+ from .group_tool_executor import GroupToolExecutor
21
+ from .targets.group_manager_target import GroupManagerTarget
22
+ from .targets.transition_target import (
23
+ AgentNameTarget,
24
+ AgentTarget,
25
+ TransitionTarget,
26
+ )
27
+
28
+ if TYPE_CHECKING:
29
+ from ..conversable_agent import ConversableAgent
30
+
31
+ # Utility functions for group chat preparation and management
32
+ # These are extracted from multi_agent_chat.py to avoid circular imports
33
+
34
+
35
+ def update_conditional_functions(agent: "ConversableAgent", messages: list[dict[str, Any]]) -> None:
36
+ """Updates the agent's functions based on the OnCondition's available condition.
37
+
38
+ All functions are removed and then added back if they are available
39
+ """
40
+ for on_condition in agent.handoffs.llm_conditions:
41
+ is_available = on_condition.available.is_available(agent, messages) if on_condition.available else True
42
+
43
+ # Remove it from their tools
44
+ for tool in agent.tools:
45
+ if tool.name == on_condition.llm_function_name:
46
+ agent.remove_tool_for_llm(tool)
47
+ break
48
+
49
+ # then add the function if it is available, so that the function signature is updated
50
+ if is_available:
51
+ agent._add_single_function(
52
+ _create_on_condition_handoff_function(on_condition.target),
53
+ on_condition.llm_function_name,
54
+ on_condition.condition.get_prompt(agent, messages),
55
+ )
56
+
57
+
58
+ def establish_group_agent(agent: "ConversableAgent") -> None:
59
+ """Establish the group agent with the group-related attributes and hooks. Not for the tool executor.
60
+
61
+ Args:
62
+ agent ("ConversableAgent"): The agent to establish as a group agent.
63
+ """
64
+
65
+ def _group_agent_str(self: "ConversableAgent") -> str:
66
+ """Customise the __str__ method to show the agent name for transition messages."""
67
+ return f"Group agent --> {self.name}"
68
+
69
+ # Register the hook to update agent state (except tool executor)
70
+ agent.register_hook("update_agent_state", update_conditional_functions)
71
+
72
+ # Register a reply function to run Python function-based OnContextConditions before any other reply function
73
+ agent.register_reply(trigger=([Agent, None]), reply_func=_run_oncontextconditions, position=0)
74
+
75
+ agent._get_display_name = MethodType(_group_agent_str, agent) # type: ignore[method-assign]
76
+
77
+ # Mark this agent as established as a group agent
78
+ agent._group_is_established = True # type: ignore[attr-defined]
79
+
80
+
81
+ def link_agents_to_group_manager(agents: list[Agent], group_chat_manager: Agent) -> None:
82
+ """Link all agents to the GroupChatManager so they can access the underlying GroupChat and other agents.
83
+
84
+ This is primarily used so that agents can get to the tool executor to help set the next agent.
85
+
86
+ Does not link the Tool Executor agent.
87
+ """
88
+ for agent in agents:
89
+ agent._group_manager = group_chat_manager # type: ignore[attr-defined]
90
+
91
+
92
+ def _evaluate_after_works_conditions(
93
+ agent: "ConversableAgent",
94
+ groupchat: GroupChat,
95
+ user_agent: Optional["ConversableAgent"],
96
+ ) -> Agent | str | None:
97
+ """Evaluate after_works context conditions for an agent.
98
+
99
+ Args:
100
+ agent: The agent to evaluate after_works conditions for
101
+ groupchat: The current group chat
102
+ user_agent: Optional user proxy agent
103
+
104
+ Returns:
105
+ The resolved speaker selection result if a condition matches, None otherwise
106
+ """
107
+ if not hasattr(agent, "handoffs") or not agent.handoffs.after_works: # type: ignore[attr-defined]
108
+ return None
109
+
110
+ for after_work_condition in agent.handoffs.after_works: # type: ignore[attr-defined]
111
+ # Check if condition is available
112
+ is_available = (
113
+ after_work_condition.available.is_available(agent, groupchat.messages)
114
+ if after_work_condition.available
115
+ else True
116
+ )
117
+
118
+ # Evaluate the condition (None condition means always true)
119
+ if is_available and (
120
+ after_work_condition.condition is None or after_work_condition.condition.evaluate(agent.context_variables)
121
+ ):
122
+ # Condition matched, resolve and return
123
+ after_works_speaker = after_work_condition.target.resolve(
124
+ groupchat,
125
+ agent,
126
+ user_agent,
127
+ ).get_speaker_selection_result(groupchat)
128
+
129
+ iostream = IOStream.get_default()
130
+ iostream.send(AfterWorksTransitionEvent(source_agent=agent, transition_target=after_work_condition.target))
131
+
132
+ return after_works_speaker
133
+
134
+ return None
135
+
136
+
137
+ def _run_oncontextconditions(
138
+ agent: "ConversableAgent",
139
+ messages: list[dict[str, Any]] | None = None,
140
+ sender: Agent | None = None,
141
+ config: Any | None = None,
142
+ ) -> tuple[bool, str | dict[str, Any] | None]:
143
+ """Run OnContextConditions for an agent before any other reply function."""
144
+ for on_condition in agent.handoffs.context_conditions: # type: ignore[attr-defined]
145
+ is_available = (
146
+ on_condition.available.is_available(agent, messages if messages else []) if on_condition.available else True
147
+ )
148
+
149
+ if is_available and (
150
+ on_condition.condition is None or on_condition.condition.evaluate(agent.context_variables)
151
+ ):
152
+ on_condition.target.activate_target(agent._group_manager.groupchat) # type: ignore[attr-defined]
153
+
154
+ transfer_name = on_condition.target.display_name()
155
+
156
+ iostream = IOStream.get_default()
157
+ iostream.send(OnContextConditionTransitionEvent(source_agent=agent, transition_target=on_condition.target))
158
+
159
+ return True, "[Handing off to " + transfer_name + "]"
160
+
161
+ return False, None
162
+
163
+
164
+ def _create_on_condition_handoff_function(target: TransitionTarget) -> Callable[[], TransitionTarget]:
165
+ """Creates a function that will be used by the tool call reply function when the condition is met.
166
+
167
+ Args:
168
+ target (TransitionTarget): The target to transfer to.
169
+
170
+ Returns:
171
+ Callable: The transfer function.
172
+ """
173
+
174
+ def transfer_to_target() -> TransitionTarget:
175
+ return target
176
+
177
+ return transfer_to_target
178
+
179
+
180
+ def create_on_condition_handoff_functions(agent: "ConversableAgent") -> None:
181
+ """Creates the functions for the OnConditions so that the current tool handling works.
182
+
183
+ Args:
184
+ agent ("ConversableAgent"): The agent to create the functions for.
185
+ """
186
+ # Populate the function names for the handoffs
187
+ agent.handoffs.set_llm_function_names()
188
+
189
+ # Create a function for each OnCondition
190
+ for on_condition in agent.handoffs.llm_conditions:
191
+ # Create a function that will be called when the condition is met
192
+ agent._add_single_function(
193
+ _create_on_condition_handoff_function(on_condition.target),
194
+ on_condition.llm_function_name,
195
+ on_condition.condition.get_prompt(agent, []),
196
+ )
197
+
198
+
199
+ def ensure_handoff_agents_in_group(agents: list["ConversableAgent"]) -> None:
200
+ """Ensure the agents in handoffs are in the group chat."""
201
+ agent_names = [agent.name for agent in agents]
202
+ for agent in agents:
203
+ for llm_conditions in agent.handoffs.llm_conditions:
204
+ if (
205
+ isinstance(llm_conditions.target, (AgentTarget, AgentNameTarget))
206
+ and llm_conditions.target.agent_name not in agent_names
207
+ ):
208
+ raise ValueError("Agent in OnCondition Hand-offs must be in the agents list")
209
+ for context_conditions in agent.handoffs.context_conditions:
210
+ if (
211
+ isinstance(context_conditions.target, (AgentTarget, AgentNameTarget))
212
+ and context_conditions.target.agent_name not in agent_names
213
+ ):
214
+ raise ValueError("Agent in OnContextCondition Hand-offs must be in the agents list")
215
+ # Check after_works targets
216
+ for after_work_condition in agent.handoffs.after_works:
217
+ if (
218
+ isinstance(after_work_condition.target, (AgentTarget, AgentNameTarget))
219
+ and after_work_condition.target.agent_name not in agent_names
220
+ ):
221
+ raise ValueError("Agent in after work target Hand-offs must be in the agents list")
222
+
223
+
224
+ def ensure_guardrail_agents_in_group(agents: list["ConversableAgent"]) -> None:
225
+ """Ensure the agents in handoffs are in the group chat."""
226
+ agent_names = [agent.name for agent in agents]
227
+ for agent in agents:
228
+ for guardrail in agent.input_guardrails + agent.output_guardrails:
229
+ if (
230
+ isinstance(guardrail.target, (AgentTarget, AgentNameTarget))
231
+ and guardrail.target.agent_name not in agent_names
232
+ ):
233
+ raise ValueError("Agent in guardrail's target must be in the agents list")
234
+
235
+
236
+ def prepare_exclude_transit_messages(agents: list["ConversableAgent"]) -> None:
237
+ """Preparation for excluding transit messages by getting all tool names and registering a hook on agents to remove those messages."""
238
+ # get all transit functions names
239
+ to_be_removed: list[str] = []
240
+ for agent in agents:
241
+ for on_condition in agent.handoffs.llm_conditions:
242
+ if on_condition.llm_function_name:
243
+ to_be_removed.append(on_condition.llm_function_name)
244
+ else:
245
+ raise ValueError("OnCondition must have a function name")
246
+
247
+ remove_function = make_remove_function(to_be_removed)
248
+
249
+ # register hook to remove transit messages for group agents
250
+ for agent in agents:
251
+ agent.register_hook("process_all_messages_before_reply", remove_function)
252
+
253
+
254
+ def prepare_group_agents(
255
+ agents: list["ConversableAgent"],
256
+ context_variables: ContextVariables,
257
+ exclude_transit_message: bool = True,
258
+ ) -> tuple[GroupToolExecutor, list["ConversableAgent"]]:
259
+ """Validates agents, create the tool executor, wrap necessary targets in agents.
260
+
261
+ Args:
262
+ agents (list["ConversableAgent"]): List of all agents in the conversation.
263
+ context_variables (ContextVariables): Context variables to assign to all agents.
264
+ exclude_transit_message (bool): Whether to exclude transit messages from the agents.
265
+
266
+ Returns:
267
+ "ConversableAgent": The tool executor agent.
268
+ list["ConversableAgent"]: List of wrapped agents.
269
+ """
270
+ # Initialise all agents as group agents
271
+ for agent in agents:
272
+ if not hasattr(agent, "_group_is_established"):
273
+ establish_group_agent(agent)
274
+
275
+ # Ensure all agents in hand-off after-works are in the passed in agents list
276
+ ensure_handoff_agents_in_group(agents)
277
+
278
+ # Ensure all agents in guardrails are in the passed in agents list
279
+ ensure_guardrail_agents_in_group(agents)
280
+
281
+ # Create Tool Executor for the group
282
+ tool_execution = GroupToolExecutor()
283
+
284
+ # Wrap handoff targets in agents that need to be wrapped
285
+ wrapped_chat_agents: list[ConversableAgent] = []
286
+ for agent in agents:
287
+ wrap_agent_handoff_targets(agent, wrapped_chat_agents)
288
+
289
+ # Create the functions for the OnConditions so that the current tool handling works
290
+ for agent in agents:
291
+ create_on_condition_handoff_functions(agent)
292
+
293
+ # Register all the agents' functions with the tool executor and
294
+ # use dependency injection for the context variables parameter
295
+ # Update tool execution agent with all the functions from all the agents
296
+ tool_execution.register_agents_functions(agents + wrapped_chat_agents, context_variables)
297
+
298
+ if exclude_transit_message:
299
+ prepare_exclude_transit_messages(agents)
300
+
301
+ return tool_execution, wrapped_chat_agents
302
+
303
+
304
+ def wrap_agent_handoff_targets(agent: "ConversableAgent", wrapped_agent_list: list["ConversableAgent"]) -> None:
305
+ """Wrap handoff targets in agents that need to be wrapped to be part of the group chat.
306
+
307
+ Example is NestedChatTarget.
308
+
309
+ Args:
310
+ agent ("ConversableAgent"): The agent to wrap the handoff targets for.
311
+ wrapped_agent_list (list["ConversableAgent"]): List of wrapped chat agents that will be appended to.
312
+ """
313
+ # Wrap OnCondition targets
314
+ for i, handoff_oncondition_requiring_wrapping in enumerate(agent.handoffs.get_llm_conditions_requiring_wrapping()):
315
+ # Create wrapper agent
316
+ wrapper_agent = handoff_oncondition_requiring_wrapping.target.create_wrapper_agent(parent_agent=agent, index=i)
317
+ wrapped_agent_list.append(wrapper_agent)
318
+
319
+ # Change this handoff target to point to the newly created agent
320
+ handoff_oncondition_requiring_wrapping.target = AgentTarget(wrapper_agent)
321
+
322
+ for i, handoff_oncontextcondition_requiring_wrapping in enumerate(
323
+ agent.handoffs.get_context_conditions_requiring_wrapping()
324
+ ):
325
+ # Create wrapper agent
326
+ wrapper_agent = handoff_oncontextcondition_requiring_wrapping.target.create_wrapper_agent(
327
+ parent_agent=agent, index=i
328
+ )
329
+ wrapped_agent_list.append(wrapper_agent)
330
+
331
+ # Change this handoff target to point to the newly created agent
332
+ handoff_oncontextcondition_requiring_wrapping.target = AgentTarget(wrapper_agent)
333
+
334
+
335
+ def process_initial_messages(
336
+ messages: list[dict[str, Any]] | str,
337
+ user_agent: Optional["ConversableAgent"],
338
+ agents: list["ConversableAgent"],
339
+ wrapped_agents: list["ConversableAgent"],
340
+ ) -> tuple[list[dict[str, Any]], Optional["ConversableAgent"], list[str], list[Agent]]:
341
+ """Process initial messages, validating agent names against messages, and determining the last agent to speak.
342
+
343
+ Args:
344
+ messages: Initial messages to process.
345
+ user_agent: Optional user proxy agent passed in to a_/initiate_group_chat.
346
+ agents: Agents in the group.
347
+ wrapped_agents: List of wrapped agents.
348
+
349
+ Returns:
350
+ list[dict[str, Any]]: Processed message(s).
351
+ Agent: Last agent to speak.
352
+ list[str]: List of agent names.
353
+ list[Agent]: List of temporary user proxy agents to add to GroupChat.
354
+ """
355
+ from ..conversable_agent import ConversableAgent # NEED SOLUTION
356
+
357
+ if isinstance(messages, str):
358
+ messages = [{"role": "user", "content": messages}]
359
+
360
+ group_agent_names = [agent.name for agent in agents + wrapped_agents]
361
+
362
+ # If there's only one message and there's no identified group agent
363
+ # Start with a user proxy agent, creating one if they haven't passed one in
364
+ last_agent: ConversableAgent | None
365
+ temp_user_proxy: ConversableAgent | None = None
366
+ temp_user_list: list[Agent] = []
367
+ if len(messages) == 1 and "name" not in messages[0] and not user_agent:
368
+ temp_user_proxy = ConversableAgent(name="_User", code_execution_config=False, human_input_mode="ALWAYS")
369
+ last_agent = temp_user_proxy
370
+ temp_user_list.append(temp_user_proxy)
371
+ else:
372
+ last_message = messages[0]
373
+ if "name" in last_message:
374
+ if last_message["name"] in group_agent_names:
375
+ last_agent = next(agent for agent in agents + wrapped_agents if agent.name == last_message["name"]) # type: ignore[assignment]
376
+ elif user_agent and last_message["name"] == user_agent.name:
377
+ last_agent = user_agent
378
+ else:
379
+ raise ValueError(f"Invalid group agent name in last message: {last_message['name']}")
380
+ else:
381
+ last_agent = user_agent if user_agent else temp_user_proxy
382
+
383
+ return messages, last_agent, group_agent_names, temp_user_list
384
+
385
+
386
+ def setup_context_variables(
387
+ tool_execution: "ConversableAgent",
388
+ agents: list["ConversableAgent"],
389
+ manager: GroupChatManager,
390
+ user_agent: Optional["ConversableAgent"],
391
+ context_variables: ContextVariables,
392
+ ) -> None:
393
+ """Assign a common context_variables reference to all agents in the group, including the tool executor, group chat manager, and user proxy agent.
394
+
395
+ Args:
396
+ tool_execution: The tool execution agent.
397
+ agents: List of all agents in the conversation.
398
+ manager: GroupChatManager instance.
399
+ user_agent: Optional user proxy agent.
400
+ context_variables: Context variables to assign to all agents.
401
+ """
402
+ for agent in agents + [tool_execution] + [manager] + ([user_agent] if user_agent else []):
403
+ agent.context_variables = context_variables
404
+
405
+
406
+ def cleanup_temp_user_messages(chat_result: Any) -> None:
407
+ """Remove temporary user proxy agent name from messages before returning.
408
+
409
+ Args:
410
+ chat_result: ChatResult instance.
411
+ """
412
+ for message in chat_result.chat_history:
413
+ if "name" in message and message["name"] == "_User":
414
+ del message["name"]
415
+
416
+
417
+ def get_last_agent_speaker(
418
+ groupchat: GroupChat, group_agent_names: list[str], tool_executor: GroupToolExecutor
419
+ ) -> Agent:
420
+ """Get the last group agent from the group chat messages. Not including the tool executor."""
421
+ last_group_speaker = None
422
+ for message in reversed(groupchat.messages):
423
+ if "name" in message and message["name"] in group_agent_names and message["name"] != tool_executor.name:
424
+ agent = groupchat.agent_by_name(name=message["name"])
425
+ if agent:
426
+ last_group_speaker = agent
427
+ break
428
+ if last_group_speaker is None:
429
+ raise ValueError("No group agent found in the message history")
430
+
431
+ return last_group_speaker
432
+
433
+
434
+ def determine_next_agent(
435
+ last_speaker: "ConversableAgent",
436
+ groupchat: GroupChat,
437
+ initial_agent: "ConversableAgent",
438
+ use_initial_agent: bool,
439
+ tool_executor: GroupToolExecutor,
440
+ group_agent_names: list[str],
441
+ user_agent: Optional["ConversableAgent"],
442
+ group_after_work: TransitionTarget,
443
+ ) -> Agent | str | None:
444
+ """Determine the next agent in the conversation.
445
+
446
+ Args:
447
+ last_speaker ("ConversableAgent"): The last agent to speak.
448
+ groupchat (GroupChat): GroupChat instance.
449
+ initial_agent ("ConversableAgent"): The initial agent in the conversation.
450
+ use_initial_agent (bool): Whether to use the initial agent straight away.
451
+ tool_executor ("ConversableAgent"): The tool execution agent.
452
+ group_agent_names (list[str]): List of agent names.
453
+ user_agent (UserProxyAgent): Optional user proxy agent.
454
+ group_after_work (TransitionTarget): Group-level Transition option when an agent doesn't select the next agent.
455
+
456
+ Returns:
457
+ Optional[Union[Agent, str]]: The next agent or speaker selection method.
458
+ """
459
+ # Logic for determining the next target (anything based on Transition Target: an agent, wrapped agent, TerminateTarget, StayTarget, RevertToUserTarget, GroupManagerTarget, etc.
460
+ # 1. If it's the first response -> initial agent
461
+ # 2. If the last message is a tool call -> tool execution agent
462
+ # 3. If the Tool Executor has determined a next target (e.g. ReplyResult specified target) -> transition to tool reply target
463
+ # 4. If the user last spoke -> return to the previous agent
464
+ # NOW "AFTER WORK":
465
+ # 5. Get the After Work condition (if the agent doesn't have one, get the group-level one)
466
+ # 6. Resolve and return the After Work condition -> agent / wrapped agent / TerminateTarget / StayTarget / RevertToUserTarget / GroupManagerTarget / etc.
467
+
468
+ # 1. If it's the first response, return the initial agent
469
+ if use_initial_agent:
470
+ return initial_agent
471
+
472
+ # 2. If the last message is a tool call, return the tool execution agent
473
+ if "tool_calls" in groupchat.messages[-1]:
474
+ return tool_executor
475
+
476
+ # 3. If the Tool Executor has determined a next target, return that
477
+ if tool_executor.has_next_target():
478
+ next_agent = tool_executor.get_next_target()
479
+ tool_executor.clear_next_target()
480
+
481
+ if next_agent.can_resolve_for_speaker_selection():
482
+ return next_agent.resolve(groupchat, last_speaker, user_agent).get_speaker_selection_result(groupchat)
483
+ else:
484
+ raise ValueError(
485
+ "Tool Executor next target must be a valid TransitionTarget that can resolve for speaker selection."
486
+ )
487
+
488
+ # get the last group agent
489
+ last_agent_speaker = get_last_agent_speaker(groupchat, group_agent_names, tool_executor)
490
+
491
+ # If we are returning from a tool execution, return to the last agent that spoke
492
+ if groupchat.messages[-1]["role"] == "tool":
493
+ return last_agent_speaker
494
+
495
+ # If the user last spoke, return to the agent prior to them (if they don't have an after work, otherwise it's treated like any other agent)
496
+ if user_agent and last_speaker == user_agent:
497
+ if not user_agent.handoffs.after_works:
498
+ return last_agent_speaker
499
+ else:
500
+ last_agent_speaker = user_agent
501
+
502
+ # AFTER WORK:
503
+
504
+ # First, try to evaluate after_works context conditions
505
+ after_works_result = _evaluate_after_works_conditions(
506
+ last_agent_speaker, # type: ignore[arg-type]
507
+ groupchat,
508
+ user_agent,
509
+ )
510
+ if after_works_result is not None:
511
+ return after_works_result
512
+
513
+ # If no after_works conditions matched, use the group-level after_work
514
+ # Resolve the next agent, termination, or speaker selection method
515
+ resolved_speaker_selection_result = group_after_work.resolve(
516
+ groupchat,
517
+ last_agent_speaker, # type: ignore[arg-type]
518
+ user_agent,
519
+ ).get_speaker_selection_result(groupchat)
520
+
521
+ return resolved_speaker_selection_result
522
+
523
+
524
+ def create_group_transition(
525
+ initial_agent: "ConversableAgent",
526
+ tool_execution: GroupToolExecutor,
527
+ group_agent_names: list[str],
528
+ user_agent: Optional["ConversableAgent"],
529
+ group_after_work: TransitionTarget,
530
+ ) -> Callable[["ConversableAgent", GroupChat], Agent | str | None]:
531
+ """Creates a transition function for group chat with enclosed state for the use_initial_agent.
532
+
533
+ Args:
534
+ initial_agent ("ConversableAgent"): The first agent to speak
535
+ tool_execution (GroupToolExecutor): The tool execution agent
536
+ group_agent_names (list[str]): List of all agent names
537
+ user_agent (UserProxyAgent): Optional user proxy agent
538
+ group_after_work (TransitionTarget): Group-level after work
539
+
540
+ Returns:
541
+ Callable[["ConversableAgent", GroupChat], Optional[Union[Agent, str]]]: The transition function
542
+ """
543
+ # Create enclosed state, this will be set once per creation so will only be True on the first execution
544
+ # of group_transition
545
+ state = {"use_initial_agent": True}
546
+
547
+ def group_transition(last_speaker: "ConversableAgent", groupchat: GroupChat) -> Agent | str | None:
548
+ result = determine_next_agent(
549
+ last_speaker=last_speaker,
550
+ groupchat=groupchat,
551
+ initial_agent=initial_agent,
552
+ use_initial_agent=state["use_initial_agent"],
553
+ tool_executor=tool_execution,
554
+ group_agent_names=group_agent_names,
555
+ user_agent=user_agent,
556
+ group_after_work=group_after_work,
557
+ )
558
+ state["use_initial_agent"] = False
559
+ return result
560
+
561
+ return group_transition
562
+
563
+
564
+ def create_group_manager(
565
+ groupchat: GroupChat,
566
+ group_manager_args: dict[str, Any] | None,
567
+ agents: list["ConversableAgent"],
568
+ group_after_work: TransitionTarget,
569
+ ) -> GroupChatManager:
570
+ """Create a GroupChatManager for the group chat utilising any arguments passed in and ensure an LLM Config exists if needed
571
+
572
+ Args:
573
+ groupchat (GroupChat): The groupchat.
574
+ group_manager_args (dict[str, Any]): Group manager arguments to create the GroupChatManager.
575
+ agents (list["ConversableAgent"]): List of agents in the group to check handoffs and after work.
576
+ group_after_work (TransitionTarget): Group-level after work to check.
577
+
578
+ Returns:
579
+ GroupChatManager: GroupChatManager instance.
580
+ """
581
+ manager_args = (group_manager_args or {}).copy()
582
+ if "groupchat" in manager_args:
583
+ raise ValueError("'groupchat' cannot be specified in group_manager_args as it is set by initiate_group_chat")
584
+ manager = GroupChatManager(groupchat, **manager_args)
585
+
586
+ # Ensure that our manager has an LLM Config if we have any GroupManagerTarget targets used
587
+ if manager.llm_config is False:
588
+ has_group_manager_target = False
589
+
590
+ if isinstance(group_after_work, GroupManagerTarget):
591
+ # Check group after work
592
+ has_group_manager_target = True
593
+ else:
594
+ # Check agent hand-offs and after work
595
+ for agent in agents:
596
+ if (
597
+ len(agent.handoffs.get_context_conditions_by_target_type(GroupManagerTarget)) > 0
598
+ or len(agent.handoffs.get_llm_conditions_by_target_type(GroupManagerTarget)) > 0
599
+ or any(isinstance(aw.target, GroupManagerTarget) for aw in agent.handoffs.after_works)
600
+ ):
601
+ has_group_manager_target = True
602
+ break
603
+
604
+ if has_group_manager_target:
605
+ raise ValueError(
606
+ "The group manager doesn't have an LLM Config and it is required for any targets or after works using a GroupManagerTarget. Use the 'llm_config' in the group_manager_args parameter to specify the LLM Config for the group manager."
607
+ )
608
+
609
+ return manager
610
+
611
+
612
+ def make_remove_function(tool_msgs_to_remove: list[str]) -> Callable[[list[dict[str, Any]]], list[dict[str, Any]]]:
613
+ """Create a function to remove messages with tool calls from the messages list.
614
+
615
+ The returned function can be registered as a hook to "process_all_messages_before_reply"" to remove messages with tool calls.
616
+ """
617
+
618
+ def remove_messages(messages: list[dict[str, Any]], tool_msgs_to_remove: list[str]) -> list[dict[str, Any]]:
619
+ copied = copy.deepcopy(messages)
620
+ new_messages = []
621
+ removed_tool_ids = []
622
+ for message in copied:
623
+ # remove tool calls
624
+ if message.get("tool_calls") is not None:
625
+ filtered_tool_calls = []
626
+ for tool_call in message["tool_calls"]:
627
+ if tool_call.get("function") is not None and tool_call["function"]["name"] in tool_msgs_to_remove:
628
+ # remove
629
+ removed_tool_ids.append(tool_call["id"])
630
+ else:
631
+ filtered_tool_calls.append(tool_call)
632
+ if len(filtered_tool_calls) > 0:
633
+ message["tool_calls"] = filtered_tool_calls
634
+ else:
635
+ del message["tool_calls"]
636
+ if (
637
+ message.get("content") is None
638
+ or message.get("content") == ""
639
+ or message.get("content") == "None"
640
+ ):
641
+ continue # if no tool call and no content, skip this message
642
+ # else: keep the message with tool_calls removed
643
+ # remove corresponding tool responses
644
+ elif message.get("tool_responses") is not None:
645
+ filtered_tool_responses = []
646
+ for tool_response in message["tool_responses"]:
647
+ if tool_response["tool_call_id"] not in removed_tool_ids:
648
+ filtered_tool_responses.append(tool_response)
649
+
650
+ if len(filtered_tool_responses) > 0:
651
+ message["tool_responses"] = filtered_tool_responses
652
+ else:
653
+ continue
654
+
655
+ new_messages.append(message)
656
+
657
+ return new_messages
658
+
659
+ return partial(remove_messages, tool_msgs_to_remove=tool_msgs_to_remove)