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,150 @@
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
+ from typing import Annotated, Any, Optional
6
+
7
+ from pydantic import BaseModel
8
+
9
+ from ....doc_utils import export_module
10
+ from ....import_utils import optional_import_block, require_optional_import
11
+ from ....interop import LiteLLmConfigFactory
12
+ from ....llm_config import LLMConfig
13
+ from ... import Tool
14
+ from ...dependency_injection import Depends, on
15
+
16
+ with optional_import_block():
17
+ from crawl4ai import AsyncWebCrawler, BrowserConfig, CacheMode, CrawlerRunConfig
18
+ from crawl4ai.extraction_strategy import LLMExtractionStrategy
19
+
20
+ __all__ = ["Crawl4AITool"]
21
+
22
+
23
+ @require_optional_import(["crawl4ai"], "crawl4ai")
24
+ @export_module("autogen.tools.experimental")
25
+ class Crawl4AITool(Tool):
26
+ """Crawl a website and extract information using the crawl4ai library."""
27
+
28
+ def __init__(
29
+ self,
30
+ llm_config: LLMConfig | dict[str, Any] | None = None,
31
+ extraction_model: type[BaseModel] | None = None,
32
+ llm_strategy_kwargs: dict[str, Any] | None = None,
33
+ ) -> None:
34
+ """Initialize the Crawl4AITool.
35
+
36
+ Args:
37
+ llm_config: The config dictionary for the LLM model. If None, the tool will run without LLM.
38
+ extraction_model: The Pydantic model to use for extraction. If None, the tool will use the default schema.
39
+ llm_strategy_kwargs: The keyword arguments to pass to the LLM extraction strategy.
40
+ """
41
+ Crawl4AITool._validate_llm_strategy_kwargs(llm_strategy_kwargs, llm_config_provided=(llm_config is not None))
42
+
43
+ async def crawl4ai_helper( # type: ignore[no-any-unimported]
44
+ url: str,
45
+ browser_cfg: Optional["BrowserConfig"] = None,
46
+ crawl_config: Optional["CrawlerRunConfig"] = None,
47
+ ) -> Any:
48
+ async with AsyncWebCrawler(config=browser_cfg) as crawler:
49
+ result = await crawler.arun(
50
+ url=url,
51
+ config=crawl_config,
52
+ )
53
+
54
+ if crawl_config is None:
55
+ response = result.markdown
56
+ else:
57
+ response = result.extracted_content if result.success else result.error_message
58
+
59
+ return response
60
+
61
+ async def crawl4ai_without_llm(
62
+ url: Annotated[str, "The url to crawl and extract information from."],
63
+ ) -> Any:
64
+ return await crawl4ai_helper(url=url)
65
+
66
+ async def crawl4ai_with_llm(
67
+ url: Annotated[str, "The url to crawl and extract information from."],
68
+ instruction: Annotated[str, "The instruction to provide on how and what to extract."],
69
+ llm_config: Annotated[Any, Depends(on(llm_config))],
70
+ llm_strategy_kwargs: Annotated[dict[str, Any] | None, Depends(on(llm_strategy_kwargs))],
71
+ extraction_model: Annotated[type[BaseModel] | None, Depends(on(extraction_model))],
72
+ ) -> Any:
73
+ browser_cfg = BrowserConfig(headless=True)
74
+ crawl_config = Crawl4AITool._get_crawl_config(
75
+ llm_config=llm_config,
76
+ instruction=instruction,
77
+ extraction_model=extraction_model,
78
+ llm_strategy_kwargs=llm_strategy_kwargs,
79
+ )
80
+
81
+ return await crawl4ai_helper(url=url, browser_cfg=browser_cfg, crawl_config=crawl_config)
82
+
83
+ super().__init__(
84
+ name="crawl4ai",
85
+ description="Crawl a website and extract information.",
86
+ func_or_tool=crawl4ai_without_llm if llm_config is None else crawl4ai_with_llm,
87
+ )
88
+
89
+ @staticmethod
90
+ def _validate_llm_strategy_kwargs(llm_strategy_kwargs: dict[str, Any] | None, llm_config_provided: bool) -> None:
91
+ if not llm_strategy_kwargs:
92
+ return
93
+
94
+ if not llm_config_provided:
95
+ raise ValueError("llm_strategy_kwargs can only be provided if llm_config is also provided.")
96
+
97
+ check_parameters_error_msg = "".join(
98
+ f"'{key}' should not be provided in llm_strategy_kwargs. It is automatically set based on llm_config.\n"
99
+ for key in ["provider", "api_token"]
100
+ if key in llm_strategy_kwargs
101
+ )
102
+
103
+ check_parameters_error_msg += "".join(
104
+ "'schema' should not be provided in llm_strategy_kwargs. It is automatically set based on extraction_model type.\n"
105
+ if "schema" in llm_strategy_kwargs
106
+ else ""
107
+ )
108
+
109
+ check_parameters_error_msg += "".join(
110
+ "'instruction' should not be provided in llm_strategy_kwargs. It is provided at the time of calling the tool.\n"
111
+ if "instruction" in llm_strategy_kwargs
112
+ else ""
113
+ )
114
+
115
+ if check_parameters_error_msg:
116
+ raise ValueError(check_parameters_error_msg)
117
+
118
+ @staticmethod
119
+ def _get_crawl_config( # type: ignore[no-any-unimported]
120
+ llm_config: LLMConfig | dict[str, Any],
121
+ instruction: str,
122
+ llm_strategy_kwargs: dict[str, Any] | None = None,
123
+ extraction_model: type[BaseModel] | None = None,
124
+ ) -> "CrawlerRunConfig":
125
+ lite_llm_config = LiteLLmConfigFactory.create_lite_llm_config(llm_config)
126
+
127
+ if llm_strategy_kwargs is None:
128
+ llm_strategy_kwargs = {}
129
+
130
+ schema = (
131
+ extraction_model.model_json_schema()
132
+ if (extraction_model and issubclass(extraction_model, BaseModel))
133
+ else None
134
+ )
135
+
136
+ extraction_type = llm_strategy_kwargs.pop("extraction_type", "schema" if schema else "block")
137
+
138
+ # 1. Define the LLM extraction strategy
139
+ llm_strategy = LLMExtractionStrategy(
140
+ **lite_llm_config,
141
+ schema=schema,
142
+ extraction_type=extraction_type,
143
+ instruction=instruction,
144
+ **llm_strategy_kwargs,
145
+ )
146
+
147
+ # 2. Build the crawler config
148
+ crawl_config = CrawlerRunConfig(extraction_strategy=llm_strategy, cache_mode=CacheMode.BYPASS)
149
+
150
+ return crawl_config
@@ -0,0 +1,7 @@
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
+ from .deep_research import DeepResearchTool
6
+
7
+ __all__ = ["DeepResearchTool"]
@@ -0,0 +1,329 @@
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 typing import Annotated, Any
8
+
9
+ from pydantic import BaseModel, Field
10
+
11
+ from ....agentchat import ConversableAgent
12
+ from ....doc_utils import export_module
13
+ from ....llm_config import LLMConfig
14
+ from ... import Depends, Tool
15
+ from ...dependency_injection import on
16
+
17
+ __all__ = ["DeepResearchTool"]
18
+
19
+
20
+ class Subquestion(BaseModel):
21
+ question: Annotated[str, Field(description="The original question.")]
22
+
23
+ def format(self) -> str:
24
+ return f"Question: {self.question}\n"
25
+
26
+
27
+ class SubquestionAnswer(Subquestion):
28
+ answer: Annotated[str, Field(description="The answer to the question.")]
29
+
30
+ def format(self) -> str:
31
+ return f"Question: {self.question}\n{self.answer}\n"
32
+
33
+
34
+ class Task(BaseModel):
35
+ question: Annotated[str, Field(description="The original question.")]
36
+ subquestions: Annotated[list[Subquestion], Field(description="The subquestions that need to be answered.")]
37
+
38
+ def format(self) -> str:
39
+ return f"Task: {self.question}\n\n" + "\n".join(
40
+ "Subquestion " + str(i + 1) + ":\n" + subquestion.format()
41
+ for i, subquestion in enumerate(self.subquestions)
42
+ )
43
+
44
+
45
+ class CompletedTask(BaseModel):
46
+ question: Annotated[str, Field(description="The original question.")]
47
+ subquestions: Annotated[list[SubquestionAnswer], Field(description="The subquestions and their answers")]
48
+
49
+ def format(self) -> str:
50
+ return f"Task: {self.question}\n\n" + "\n".join(
51
+ "Subquestion " + str(i + 1) + ":\n" + subquestion.format()
52
+ for i, subquestion in enumerate(self.subquestions)
53
+ )
54
+
55
+
56
+ class InformationCrumb(BaseModel):
57
+ source_url: str
58
+ source_title: str
59
+ source_summary: str
60
+ relevant_info: str
61
+
62
+
63
+ class GatheredInformation(BaseModel):
64
+ information: list[InformationCrumb]
65
+
66
+ def format(self) -> str:
67
+ return "Here is the gathered information: \n" + "\n".join(
68
+ f"URL: {info.source_url}\nTitle: {info.source_title}\nSummary: {info.source_summary}\nRelevant Information: {info.relevant_info}\n\n"
69
+ for info in self.information
70
+ )
71
+
72
+
73
+ @export_module("autogen.tools.experimental")
74
+ class DeepResearchTool(Tool):
75
+ """A tool that delegates a web research task to the subteams of agents."""
76
+
77
+ ANSWER_CONFIRMED_PREFIX = "Answer confirmed:"
78
+
79
+ def __init__(
80
+ self,
81
+ llm_config: LLMConfig | dict[str, Any],
82
+ max_web_steps: int = 30,
83
+ ):
84
+ """Initialize the DeepResearchTool.
85
+
86
+ Args:
87
+ llm_config (LLMConfig, dict[str, Any]): The LLM configuration.
88
+ max_web_steps (int, optional): The maximum number of web steps. Defaults to 30.
89
+ """
90
+ self.llm_config = llm_config
91
+
92
+ self.summarizer_agent = ConversableAgent(
93
+ name="SummarizerAgent",
94
+ system_message=(
95
+ "You are an agent with a task of answering the question provided by the user."
96
+ "First you need to split the question into subquestions by calling the 'split_question_and_answer_subquestions' method."
97
+ "Then you need to sintesize the answers the original question by combining the answers to the subquestions."
98
+ ),
99
+ is_termination_msg=lambda x: x.get("content", "")
100
+ and x.get("content", "").startswith(self.ANSWER_CONFIRMED_PREFIX),
101
+ llm_config=llm_config,
102
+ human_input_mode="NEVER",
103
+ )
104
+
105
+ self.critic_agent = ConversableAgent(
106
+ name="CriticAgent",
107
+ system_message=(
108
+ "You are a critic agent responsible for evaluating the answer provided by the summarizer agent.\n"
109
+ "Your task is to assess the quality of the answer based on its coherence, relevance, and completeness.\n"
110
+ "Provide constructive feedback on how the answer can be improved.\n"
111
+ "If the answer is satisfactory, call the 'confirm_answer' method to end the task.\n"
112
+ ),
113
+ is_termination_msg=lambda x: x.get("content", "")
114
+ and x.get("content", "").startswith(self.ANSWER_CONFIRMED_PREFIX),
115
+ llm_config=llm_config,
116
+ human_input_mode="NEVER",
117
+ )
118
+
119
+ def delegate_research_task(
120
+ task: Annotated[str, "The task to perform a research on."],
121
+ llm_config: Annotated[LLMConfig | dict[str, Any], Depends(on(llm_config))],
122
+ max_web_steps: Annotated[int, Depends(on(max_web_steps))],
123
+ ) -> str:
124
+ """Delegate a research task to the agent.
125
+
126
+ Args:
127
+ task (str): The task to perform a research on.
128
+ llm_config (LLMConfig, dict[str, Any]): The LLM configuration.
129
+ max_web_steps (int): The maximum number of web steps.
130
+
131
+ Returns:
132
+ str: The answer to the research task.
133
+ """
134
+
135
+ @self.summarizer_agent.register_for_execution()
136
+ @self.critic_agent.register_for_llm(description="Call this method to confirm the final answer.")
137
+ def confirm_summary(answer: str, reasoning: str) -> str:
138
+ return f"{self.ANSWER_CONFIRMED_PREFIX}" + answer + "\nReasoning: " + reasoning
139
+
140
+ split_question_and_answer_subquestions = DeepResearchTool._get_split_question_and_answer_subquestions(
141
+ llm_config=llm_config,
142
+ max_web_steps=max_web_steps,
143
+ )
144
+
145
+ self.summarizer_agent.register_for_llm(description="Split the question into subquestions and get answers.")(
146
+ split_question_and_answer_subquestions
147
+ )
148
+ self.critic_agent.register_for_execution()(split_question_and_answer_subquestions)
149
+
150
+ result = self.critic_agent.initiate_chat(
151
+ self.summarizer_agent,
152
+ message="Please answer the following question: " + task,
153
+ # This outer chat should preserve the history of the conversation
154
+ clear_history=False,
155
+ )
156
+
157
+ return result.summary
158
+
159
+ super().__init__(
160
+ name=delegate_research_task.__name__,
161
+ description="Delegate a research task to the deep research agent.",
162
+ func_or_tool=delegate_research_task,
163
+ )
164
+
165
+ SUBQUESTIONS_ANSWER_PREFIX = "Subquestions answered:"
166
+
167
+ @staticmethod
168
+ def _get_split_question_and_answer_subquestions(
169
+ llm_config: LLMConfig | dict[str, Any], max_web_steps: int
170
+ ) -> Callable[..., Any]:
171
+ def split_question_and_answer_subquestions(
172
+ question: Annotated[str, "The question to split and answer."],
173
+ llm_config: Annotated[LLMConfig | dict[str, Any], Depends(on(llm_config))],
174
+ max_web_steps: Annotated[int, Depends(on(max_web_steps))],
175
+ ) -> str:
176
+ decomposition_agent = ConversableAgent(
177
+ name="DecompositionAgent",
178
+ system_message=(
179
+ "You are an expert at breaking down complex questions into smaller, focused subquestions.\n"
180
+ "Your task is to take any question provided and divide it into clear, actionable subquestions that can be individually answered.\n"
181
+ "Ensure the subquestions are logical, non-redundant, and cover all key aspects of the original question.\n"
182
+ "Avoid providing answers or interpretations—focus solely on decomposition.\n"
183
+ "Do not include banal, general knowledge questions\n"
184
+ "Do not include questions that go into unnecessary detail that is not relevant to the original question\n"
185
+ "Do not include question that require knowledge of the original or other subquestions to answer\n"
186
+ "Some rule of thumb is to have only one subquestion for easy questions, 3 for medium questions, and 5 for hard questions.\n"
187
+ ),
188
+ llm_config=llm_config,
189
+ is_termination_msg=lambda x: x.get("content", "")
190
+ and x.get("content", "").startswith(DeepResearchTool.SUBQUESTIONS_ANSWER_PREFIX),
191
+ human_input_mode="NEVER",
192
+ )
193
+
194
+ example_task = Task(
195
+ question="What is the capital of France?",
196
+ subquestions=[Subquestion(question="What is the capital of France?")],
197
+ )
198
+ decomposition_critic = ConversableAgent(
199
+ name="DecompositionCritic",
200
+ system_message=(
201
+ "You are a critic agent responsible for evaluating the subquestions provided by the initial analysis agent.\n"
202
+ "You need to confirm whether the subquestions are clear, actionable, and cover all key aspects of the original question.\n"
203
+ "Do not accept redundant or unnecessary subquestions, focus solely on the minimal viable subset of subqestions necessary to answer the original question. \n"
204
+ "Do not accept banal, general knowledge questions\n"
205
+ "Do not accept questions that go into unnecessary detail that is not relevant to the original question\n"
206
+ "Remove questions that can be answered with combining knowledge from other questions\n"
207
+ "After you are satisfied with the subquestions, call the 'generate_subquestions' method to answer each subquestion.\n"
208
+ "This is an example of an argument that can be passed to the 'generate_subquestions' method:\n"
209
+ f"{{'task': {example_task.model_dump()}}}\n"
210
+ "Some rule of thumb is to have only one subquestion for easy questions, 3 for medium questions, and 5 for hard questions.\n"
211
+ ),
212
+ llm_config=llm_config,
213
+ is_termination_msg=lambda x: x.get("content", "")
214
+ and x.get("content", "").startswith(DeepResearchTool.SUBQUESTIONS_ANSWER_PREFIX),
215
+ human_input_mode="NEVER",
216
+ )
217
+
218
+ generate_subquestions = DeepResearchTool._get_generate_subquestions(
219
+ llm_config=llm_config, max_web_steps=max_web_steps
220
+ )
221
+ decomposition_agent.register_for_execution()(generate_subquestions)
222
+ decomposition_critic.register_for_llm(description="Generate subquestions for a task.")(
223
+ generate_subquestions
224
+ )
225
+
226
+ result = decomposition_critic.initiate_chat(
227
+ decomposition_agent,
228
+ message="Analyse and gather subqestions for the following question: " + question,
229
+ )
230
+
231
+ return result.summary
232
+
233
+ return split_question_and_answer_subquestions
234
+
235
+ @staticmethod
236
+ def _get_generate_subquestions(
237
+ llm_config: LLMConfig | dict[str, Any],
238
+ max_web_steps: int,
239
+ ) -> Callable[..., str]:
240
+ """Get the generate_subquestions method.
241
+
242
+ Args:
243
+ llm_config (Union[LLMConfig, dict[str, Any]]): The LLM configuration.
244
+ max_web_steps (int): The maximum number of web steps.
245
+
246
+ Returns:
247
+ Callable[..., str]: The generate_subquestions method.
248
+ """
249
+
250
+ def generate_subquestions(
251
+ task: Task,
252
+ llm_config: Annotated[LLMConfig | dict[str, Any], Depends(on(llm_config))],
253
+ max_web_steps: Annotated[int, Depends(on(max_web_steps))],
254
+ ) -> str:
255
+ if not task.subquestions:
256
+ task.subquestions = [Subquestion(question=task.question)]
257
+
258
+ subquestions_answers: list[SubquestionAnswer] = []
259
+ for subquestion in task.subquestions:
260
+ answer = DeepResearchTool._answer_question(
261
+ subquestion.question, llm_config=llm_config, max_web_steps=max_web_steps
262
+ )
263
+ subquestions_answers.append(SubquestionAnswer(question=subquestion.question, answer=answer))
264
+
265
+ completed_task = CompletedTask(question=task.question, subquestions=subquestions_answers)
266
+
267
+ return f"{DeepResearchTool.SUBQUESTIONS_ANSWER_PREFIX} \n" + completed_task.format()
268
+
269
+ return generate_subquestions
270
+
271
+ @staticmethod
272
+ def _answer_question(
273
+ question: str,
274
+ llm_config: LLMConfig | dict[str, Any],
275
+ max_web_steps: int,
276
+ ) -> str:
277
+ from ....agents.experimental.websurfer import WebSurferAgent
278
+
279
+ websurfer_config = copy.deepcopy(llm_config)
280
+
281
+ websurfer_config["config_list"][0]["response_format"] = GatheredInformation
282
+
283
+ def is_termination_msg(x: dict[str, Any]) -> bool:
284
+ content = x.get("content", "")
285
+ return (content is not None) and content.startswith(DeepResearchTool.ANSWER_CONFIRMED_PREFIX)
286
+
287
+ websurfer_agent = WebSurferAgent(
288
+ llm_config=llm_config,
289
+ web_tool_llm_config=websurfer_config,
290
+ name="WebSurferAgent",
291
+ system_message=(
292
+ "You are a web surfer agent responsible for gathering information from the web to provide information for answering a question\n"
293
+ "You will be asked to find information related to the question and provide a summary of the information gathered.\n"
294
+ "The summary should include the URL, title, summary, and relevant information for each piece of information gathered.\n"
295
+ ),
296
+ is_termination_msg=is_termination_msg,
297
+ human_input_mode="NEVER",
298
+ web_tool_kwargs={
299
+ "agent_kwargs": {"max_steps": max_web_steps},
300
+ },
301
+ )
302
+
303
+ websurfer_critic = ConversableAgent(
304
+ name="WebSurferCritic",
305
+ system_message=(
306
+ "You are a critic agent responsible for evaluating the answer provided by the web surfer agent.\n"
307
+ "You need to confirm whether the information provided by the websurfer is correct and sufficient to answer the question.\n"
308
+ "You can ask the web surfer to provide more information or provide and confirm the answer.\n"
309
+ ),
310
+ llm_config=llm_config,
311
+ is_termination_msg=is_termination_msg,
312
+ human_input_mode="NEVER",
313
+ )
314
+
315
+ @websurfer_agent.register_for_execution()
316
+ @websurfer_critic.register_for_llm(
317
+ description="Call this method when you agree that the original question can be answered with the gathered information and provide the answer."
318
+ )
319
+ def confirm_answer(answer: str) -> str:
320
+ return f"{DeepResearchTool.ANSWER_CONFIRMED_PREFIX} " + answer
321
+
322
+ websurfer_critic.register_for_execution()(websurfer_agent.tool)
323
+
324
+ result = websurfer_critic.initiate_chat(
325
+ websurfer_agent,
326
+ message="Please find the answer to this question: " + question,
327
+ )
328
+
329
+ return result.summary
@@ -0,0 +1,7 @@
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
+ from .duckduckgo_search import DuckDuckGoSearchTool
6
+
7
+ __all__ = ["DuckDuckGoSearchTool"]
@@ -0,0 +1,103 @@
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 Annotated, Any
5
+
6
+ from ....doc_utils import export_module
7
+ from ....import_utils import optional_import_block, require_optional_import
8
+ from ... import Tool
9
+
10
+ with optional_import_block():
11
+ from duckduckgo_search import DDGS
12
+
13
+
14
+ @require_optional_import(
15
+ [
16
+ "duckduckgo_search",
17
+ ],
18
+ "duckduckgo_search",
19
+ )
20
+ def _execute_duckduckgo_query(
21
+ query: str,
22
+ num_results: int = 5,
23
+ ) -> list[dict[str, Any]]:
24
+ """Execute a search query using the DuckDuckGo Search API.
25
+
26
+ Args:
27
+ query (str): The search query string.
28
+ num_results (int, optional): The maximum number of results to return. Defaults to 5.
29
+
30
+ Returns:
31
+ list[dict[str, Any]]: A list of search results from the DuckDuckGo API.
32
+ """
33
+ with DDGS() as ddgs:
34
+ try:
35
+ # region='wt-wt' means worldwide
36
+ results = list(ddgs.text(query, region="wt-wt", max_results=num_results))
37
+ except Exception as e:
38
+ print(f"DuckDuckGo Search failed: {e}")
39
+ results = []
40
+ return results
41
+
42
+
43
+ def _duckduckgo_search(
44
+ query: str,
45
+ num_results: int = 5,
46
+ ) -> list[dict[str, Any]]:
47
+ """Perform a DuckDuckGo search and format the results.
48
+
49
+ This function takes search parameters, executes the query using `_execute_duckduckgo_query`,
50
+ and formats the results into a list of dictionaries containing title, link, and snippet.
51
+
52
+ Args:
53
+ query (str): The search query string.
54
+ num_results (int, optional): The maximum number of results to return. Defaults to 5.
55
+
56
+ Returns:
57
+ list[dict[str, Any]]: A list of dictionaries, where each dictionary represents a search result
58
+ with keys 'title', 'link', and 'snippet'. Returns an empty list if no results are found.
59
+ """
60
+ res = _execute_duckduckgo_query(
61
+ query=query,
62
+ num_results=num_results,
63
+ )
64
+
65
+ return [
66
+ {"title": item.get("title", ""), "link": item.get("href", ""), "snippet": item.get("body", "")} for item in res
67
+ ]
68
+
69
+
70
+ @export_module("autogen.tools.experimental")
71
+ class DuckDuckGoSearchTool(Tool):
72
+ """DuckDuckGoSearchTool is a tool that uses DuckDuckGo to perform a search.
73
+
74
+ This tool allows agents to leverage the DuckDuckGo search engine for information retrieval.
75
+ DuckDuckGo does not require an API key, making it easy to use.
76
+ """
77
+
78
+ def __init__(self) -> None:
79
+ """Initializes the DuckDuckGoSearchTool."""
80
+
81
+ def duckduckgo_search(
82
+ query: Annotated[str, "The search query."],
83
+ num_results: Annotated[int, "The number of results to return."] = 5,
84
+ ) -> list[dict[str, Any]]:
85
+ """Performs a search using the DuckDuckGo Search API and returns formatted results.
86
+
87
+ Args:
88
+ query: The search query string.
89
+ num_results: The maximum number of results to return. Defaults to 5.
90
+
91
+ Returns:
92
+ A list of dictionaries, each containing 'title', 'link', and 'snippet' of a search result.
93
+ """
94
+ return _duckduckgo_search(
95
+ query=query,
96
+ num_results=num_results,
97
+ )
98
+
99
+ super().__init__(
100
+ name="duckduckgo_search",
101
+ description="Use the DuckDuckGo Search API to perform a search.",
102
+ func_or_tool=duckduckgo_search,
103
+ )
@@ -0,0 +1,7 @@
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
+ from .firecrawl_tool import FirecrawlTool
6
+
7
+ __all__ = ["FirecrawlTool"]