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,385 @@
1
+ # Copyright (c) 2023 - 2025, AG2ai, Inc., AG2ai open-source projects maintainers and core contributors
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ import asyncio
6
+ from datetime import datetime, timedelta
7
+ from typing import Annotated, Any
8
+
9
+ from .....doc_utils import export_module
10
+ from .....import_utils import optional_import_block, require_optional_import
11
+ from .... import Tool
12
+ from ....dependency_injection import Depends, on
13
+
14
+ __all__ = ["SlackSendTool"]
15
+
16
+ with optional_import_block():
17
+ from slack_sdk import WebClient
18
+ from slack_sdk.errors import SlackApiError
19
+
20
+ MAX_MESSAGE_LENGTH = 40000
21
+
22
+
23
+ @require_optional_import(["slack_sdk"], "commsagent-slack")
24
+ @export_module("autogen.tools.experimental")
25
+ class SlackSendTool(Tool):
26
+ """Sends a message to a Slack channel."""
27
+
28
+ def __init__(self, *, bot_token: str, channel_id: str) -> None:
29
+ """Initialize the SlackSendTool.
30
+
31
+ Args:
32
+ bot_token: Bot User OAuth Token starting with "xoxb-".
33
+ channel_id: Channel ID where messages will be sent.
34
+ """
35
+
36
+ # Function that sends the message, uses dependency injection for bot token / channel / guild
37
+ async def slack_send_message(
38
+ message: Annotated[str, "Message to send to the channel."],
39
+ bot_token: Annotated[str, Depends(on(bot_token))],
40
+ channel_id: Annotated[str, Depends(on(channel_id))],
41
+ ) -> Any:
42
+ """Sends a message to a Slack channel.
43
+
44
+ Args:
45
+ message: The message to send to the channel.
46
+ bot_token: The bot token to use for Slack. (uses dependency injection)
47
+ channel_id: The ID of the channel. (uses dependency injection)
48
+ """
49
+ try:
50
+ web_client = WebClient(token=bot_token)
51
+
52
+ # Send the message
53
+ if len(message) > MAX_MESSAGE_LENGTH:
54
+ chunks = [
55
+ message[i : i + (MAX_MESSAGE_LENGTH - 1)]
56
+ for i in range(0, len(message), (MAX_MESSAGE_LENGTH - 1))
57
+ ]
58
+ for i, chunk in enumerate(chunks):
59
+ response = web_client.chat_postMessage(channel=channel_id, text=chunk)
60
+
61
+ if not response["ok"]:
62
+ return f"Message send failed on chunk {i + 1}, Slack response error: {response['error']}"
63
+
64
+ # Store ID for the first chunk
65
+ if i == 0:
66
+ sent_message_id = response["ts"]
67
+
68
+ return f"Message sent successfully ({len(chunks)} chunks, first ID: {sent_message_id}):\n{message}"
69
+ else:
70
+ response = web_client.chat_postMessage(channel=channel_id, text=message)
71
+
72
+ if not response["ok"]:
73
+ return f"Message send failed, Slack response error: {response['error']}"
74
+
75
+ return f"Message sent successfully (ID: {response['ts']}):\n{message}"
76
+ except SlackApiError as e:
77
+ return f"Message send failed, Slack API exception: {e.response['error']} (See https://api.slack.com/automation/cli/errors#{e.response['error']})"
78
+ except Exception as e:
79
+ return f"Message send failed, exception: {e}"
80
+
81
+ super().__init__(
82
+ name="slack_send",
83
+ description="Sends a message to a Slack channel.",
84
+ func_or_tool=slack_send_message,
85
+ )
86
+
87
+
88
+ @require_optional_import(["slack_sdk"], "commsagent-slack")
89
+ @export_module("autogen.tools.experimental")
90
+ class SlackRetrieveTool(Tool):
91
+ """Retrieves messages from a Slack channel."""
92
+
93
+ def __init__(self, *, bot_token: str, channel_id: str) -> None:
94
+ """Initialize the SlackRetrieveTool.
95
+
96
+ Args:
97
+ bot_token: Bot User OAuth Token starting with "xoxb-".
98
+ channel_id: Channel ID where messages will be sent.
99
+ """
100
+
101
+ async def slack_retrieve_messages(
102
+ bot_token: Annotated[str, Depends(on(bot_token))],
103
+ channel_id: Annotated[str, Depends(on(channel_id))],
104
+ messages_since: Annotated[
105
+ str | None,
106
+ "Date to retrieve messages from (ISO format) OR Slack message ID. If None, retrieves latest messages.",
107
+ ] = None,
108
+ maximum_messages: Annotated[
109
+ int | None, "Maximum number of messages to retrieve. If None, retrieves all messages since date."
110
+ ] = None,
111
+ ) -> Any:
112
+ """Retrieves messages from a Discord channel.
113
+
114
+ Args:
115
+ bot_token: The bot token to use for Discord. (uses dependency injection)
116
+ channel_id: The ID of the channel. (uses dependency injection)
117
+ messages_since: ISO format date string OR Slack message ID, to retrieve messages from. If None, retrieves latest messages.
118
+ maximum_messages: Maximum number of messages to retrieve. If None, retrieves all messages since date.
119
+ """
120
+ try:
121
+ web_client = WebClient(token=bot_token)
122
+
123
+ # Convert ISO datetime to Unix timestamp if needed
124
+ oldest = None
125
+ if messages_since:
126
+ if "." in messages_since: # Likely a Slack message ID
127
+ oldest = messages_since
128
+ else: # Assume ISO format
129
+ try:
130
+ dt = datetime.fromisoformat(messages_since.replace("Z", "+00:00"))
131
+ oldest = str(dt.timestamp())
132
+ except ValueError as e:
133
+ return f"Invalid date format. Please provide either a Slack message ID or ISO format date (e.g., '2025-01-25T00:00:00Z'). Error: {e}"
134
+
135
+ messages = []
136
+ cursor = None
137
+
138
+ while True:
139
+ try:
140
+ # Prepare API call parameters
141
+ params = {
142
+ "channel": channel_id,
143
+ "limit": min(1000, maximum_messages) if maximum_messages else 1000,
144
+ }
145
+ if oldest:
146
+ params["oldest"] = oldest
147
+ if cursor:
148
+ params["cursor"] = cursor
149
+
150
+ # Make API call
151
+ response = web_client.conversations_history(**params) # type: ignore[arg-type]
152
+
153
+ if not response["ok"]:
154
+ return f"Message retrieval failed, Slack response error: {response['error']}"
155
+
156
+ # Add messages to our list
157
+ messages.extend(response["messages"])
158
+
159
+ # Check if we've hit our maximum
160
+ if maximum_messages and len(messages) >= maximum_messages:
161
+ messages = messages[:maximum_messages]
162
+ break
163
+
164
+ # Check if there are more messages
165
+ if not response["has_more"]:
166
+ break
167
+
168
+ cursor = response["response_metadata"]["next_cursor"]
169
+
170
+ except SlackApiError as e:
171
+ return f"Message retrieval failed on pagination, Slack API error: {e.response['error']}"
172
+
173
+ return {
174
+ "message_count": len(messages),
175
+ "messages": messages,
176
+ "start_time": oldest or "latest",
177
+ }
178
+
179
+ except SlackApiError as e:
180
+ return f"Message retrieval failed, Slack API exception: {e.response['error']} (See https://api.slack.com/automation/cli/errors#{e.response['error']})"
181
+ except Exception as e:
182
+ return f"Message retrieval failed, exception: {e}"
183
+
184
+ super().__init__(
185
+ name="slack_retrieve",
186
+ description="Retrieves messages from a Slack channel based datetime/message ID and/or number of latest messages.",
187
+ func_or_tool=slack_retrieve_messages,
188
+ )
189
+
190
+
191
+ @require_optional_import(["slack_sdk"], "commsagent-slack")
192
+ @export_module("autogen.tools.experimental")
193
+ class SlackRetrieveRepliesTool(Tool):
194
+ """Retrieves replies to a specific Slack message from both threads and the channel."""
195
+
196
+ def __init__(self, *, bot_token: str, channel_id: str) -> None:
197
+ """Initialize the SlackRetrieveRepliesTool.
198
+
199
+ Args:
200
+ bot_token: Bot User OAuth Token starting with "xoxb-".
201
+ channel_id: Channel ID where the parent message exists.
202
+ """
203
+
204
+ async def slack_retrieve_replies(
205
+ message_ts: Annotated[str, "Timestamp (ts) of the parent message to retrieve replies for."],
206
+ bot_token: Annotated[str, Depends(on(bot_token))],
207
+ channel_id: Annotated[str, Depends(on(channel_id))],
208
+ min_replies: Annotated[
209
+ int | None,
210
+ "Minimum number of replies to wait for before returning (thread + channel). If None, returns immediately.",
211
+ ] = None,
212
+ timeout_seconds: Annotated[
213
+ int, "Maximum time in seconds to wait for the requested number of replies."
214
+ ] = 60,
215
+ poll_interval: Annotated[int, "Time in seconds between polling attempts when waiting for replies."] = 5,
216
+ include_channel_messages: Annotated[
217
+ bool, "Whether to include messages in the channel after the original message."
218
+ ] = True,
219
+ ) -> Any:
220
+ """Retrieves replies to a specific Slack message, from both threads and the main channel.
221
+
222
+ Args:
223
+ message_ts: The timestamp (ts) identifier of the parent message.
224
+ bot_token: The bot token to use for Slack. (uses dependency injection)
225
+ channel_id: The ID of the channel. (uses dependency injection)
226
+ min_replies: Minimum number of combined replies to wait for before returning. If None, returns immediately.
227
+ timeout_seconds: Maximum time in seconds to wait for the requested number of replies.
228
+ poll_interval: Time in seconds between polling attempts when waiting for replies.
229
+ include_channel_messages: Whether to include messages posted in the channel after the original message.
230
+ """
231
+ try:
232
+ web_client = WebClient(token=bot_token)
233
+
234
+ # Function to get current thread replies
235
+ async def get_thread_replies() -> tuple[list[dict[str, Any]] | None, str | None]:
236
+ try:
237
+ response = web_client.conversations_replies(
238
+ channel=channel_id,
239
+ ts=message_ts,
240
+ )
241
+
242
+ if not response["ok"]:
243
+ return None, f"Thread reply retrieval failed, Slack response error: {response['error']}"
244
+
245
+ # The first message is the parent message itself, so exclude it when counting replies
246
+ replies = response["messages"][1:] if len(response["messages"]) > 0 else []
247
+ return replies, None
248
+
249
+ except SlackApiError as e:
250
+ return None, f"Thread reply retrieval failed, Slack API exception: {e.response['error']}"
251
+ except Exception as e:
252
+ return None, f"Thread reply retrieval failed, exception: {e}"
253
+
254
+ # Function to get messages in the channel after the original message
255
+ async def get_channel_messages() -> tuple[list[dict[str, Any]] | None, str | None]:
256
+ try:
257
+ response = web_client.conversations_history(
258
+ channel=channel_id,
259
+ oldest=message_ts, # Start from the original message timestamp
260
+ inclusive=False, # Don't include the original message
261
+ )
262
+
263
+ if not response["ok"]:
264
+ return None, f"Channel message retrieval failed, Slack response error: {response['error']}"
265
+
266
+ # Return all messages in the channel after the original message
267
+ # We need to filter out any that are part of the thread we're already getting
268
+ messages = []
269
+ for msg in response["messages"]:
270
+ # Skip if the message is part of the thread we're already retrieving
271
+ if "thread_ts" in msg and msg["thread_ts"] == message_ts:
272
+ continue
273
+ messages.append(msg)
274
+
275
+ return messages, None
276
+
277
+ except SlackApiError as e:
278
+ return None, f"Channel message retrieval failed, Slack API exception: {e.response['error']}"
279
+ except Exception as e:
280
+ return None, f"Channel message retrieval failed, exception: {e}"
281
+
282
+ # Function to get all replies (both thread and channel)
283
+ async def get_all_replies() -> tuple[
284
+ list[dict[str, Any]] | None, list[dict[str, Any]] | None, str | None
285
+ ]:
286
+ thread_replies, thread_error = await get_thread_replies()
287
+ if thread_error:
288
+ return None, None, thread_error
289
+
290
+ channel_messages: list[dict[str, Any]] = []
291
+ channel_error = None
292
+
293
+ if include_channel_messages:
294
+ channel_results, channel_error = await get_channel_messages()
295
+ if channel_error:
296
+ return thread_replies, None, channel_error
297
+ channel_messages = channel_results if channel_results is not None else []
298
+
299
+ return thread_replies, channel_messages, None
300
+
301
+ # If no waiting is required, just get replies and return
302
+ if min_replies is None:
303
+ thread_replies, channel_messages, error = await get_all_replies()
304
+ if error:
305
+ return error
306
+
307
+ thread_replies_list: list[dict[str, Any]] = [] if thread_replies is None else thread_replies
308
+ channel_messages_list: list[dict[str, Any]] = [] if channel_messages is None else channel_messages
309
+
310
+ # Combine replies for counting but keep them separate in the result
311
+ total_reply_count = len(thread_replies_list) + len(channel_messages_list)
312
+
313
+ return {
314
+ "parent_message_ts": message_ts,
315
+ "total_reply_count": total_reply_count,
316
+ "thread_replies": thread_replies_list,
317
+ "thread_reply_count": len(thread_replies_list),
318
+ "channel_messages": channel_messages_list if include_channel_messages else None,
319
+ "channel_message_count": len(channel_messages_list) if include_channel_messages else None,
320
+ }
321
+
322
+ # Wait for the required number of replies with timeout
323
+ start_time = datetime.now()
324
+ end_time = start_time + timedelta(seconds=timeout_seconds)
325
+
326
+ while datetime.now() < end_time:
327
+ thread_replies, channel_messages, error = await get_all_replies()
328
+ if error:
329
+ return error
330
+
331
+ thread_replies_current: list[dict[str, Any]] = [] if thread_replies is None else thread_replies
332
+ channel_messages_current: list[dict[str, Any]] = (
333
+ [] if channel_messages is None else channel_messages
334
+ )
335
+
336
+ # Combine replies for counting
337
+ total_reply_count = len(thread_replies_current) + len(channel_messages_current)
338
+
339
+ # If we have enough total replies, return them
340
+ if total_reply_count >= min_replies:
341
+ return {
342
+ "parent_message_ts": message_ts,
343
+ "total_reply_count": total_reply_count,
344
+ "thread_replies": thread_replies_current,
345
+ "thread_reply_count": len(thread_replies_current),
346
+ "channel_messages": channel_messages_current if include_channel_messages else None,
347
+ "channel_message_count": len(channel_messages_current)
348
+ if include_channel_messages
349
+ else None,
350
+ "waited_seconds": (datetime.now() - start_time).total_seconds(),
351
+ }
352
+
353
+ # Wait before checking again
354
+ await asyncio.sleep(poll_interval)
355
+
356
+ # If we reach here, we timed out waiting for replies
357
+ thread_replies, channel_messages, error = await get_all_replies()
358
+ if error:
359
+ return error
360
+
361
+ # Combine replies for counting
362
+ total_reply_count = len(thread_replies or []) + len(channel_messages or [])
363
+
364
+ return {
365
+ "parent_message_ts": message_ts,
366
+ "total_reply_count": total_reply_count,
367
+ "thread_replies": thread_replies or [],
368
+ "thread_reply_count": len(thread_replies or []),
369
+ "channel_messages": channel_messages or [] if include_channel_messages else None,
370
+ "channel_message_count": len(channel_messages or []) if include_channel_messages else None,
371
+ "timed_out": True,
372
+ "waited_seconds": timeout_seconds,
373
+ "requested_replies": min_replies,
374
+ }
375
+
376
+ except SlackApiError as e:
377
+ return f"Reply retrieval failed, Slack API exception: {e.response['error']} (See https://api.slack.com/automation/cli/errors#{e.response['error']})"
378
+ except Exception as e:
379
+ return f"Reply retrieval failed, exception: {e}"
380
+
381
+ super().__init__(
382
+ name="slack_retrieve_replies",
383
+ description="Retrieves replies to a specific Slack message, checking both thread replies and messages in the channel after the original message.",
384
+ func_or_tool=slack_retrieve_replies,
385
+ )
@@ -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 .telegram import TelegramRetrieveTool, TelegramSendTool
6
+
7
+ __all__ = ["TelegramRetrieveTool", "TelegramSendTool"]
@@ -0,0 +1,271 @@
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 datetime import datetime
6
+ from typing import Annotated, Any, Union
7
+
8
+ from .....doc_utils import export_module
9
+ from .....import_utils import optional_import_block, require_optional_import
10
+ from .... import Tool
11
+ from ....dependency_injection import Depends, on
12
+
13
+ __all__ = ["TelegramRetrieveTool", "TelegramSendTool"]
14
+
15
+ with optional_import_block():
16
+ from telethon import TelegramClient
17
+ from telethon.tl.types import InputMessagesFilterEmpty, Message, PeerChannel, PeerChat, PeerUser
18
+
19
+ MAX_MESSAGE_LENGTH = 4096
20
+
21
+
22
+ @require_optional_import(["telethon", "telethon.tl.types"], "commsagent-telegram")
23
+ @export_module("autogen.tools.experimental")
24
+ class BaseTelegramTool:
25
+ """Base class for Telegram tools containing shared functionality."""
26
+
27
+ def __init__(self, api_id: str, api_hash: str, session_name: str) -> None:
28
+ self._api_id = api_id
29
+ self._api_hash = api_hash
30
+ self._session_name = session_name
31
+
32
+ def _get_client(self) -> "TelegramClient": # type: ignore[no-any-unimported]
33
+ """Get a fresh TelegramClient instance."""
34
+ return TelegramClient(self._session_name, self._api_id, self._api_hash)
35
+
36
+ @staticmethod
37
+ def _get_peer_from_id(chat_id: str) -> Union["PeerChat", "PeerChannel", "PeerUser"]: # type: ignore[no-any-unimported]
38
+ """Convert a chat ID string to appropriate Peer type."""
39
+ try:
40
+ # Convert string to integer
41
+ id_int = int(chat_id)
42
+
43
+ # Channel/Supergroup: -100 prefix
44
+ if str(chat_id).startswith("-100"):
45
+ channel_id = int(str(chat_id)[4:]) # Remove -100 prefix
46
+ return PeerChannel(channel_id)
47
+
48
+ # Group: negative number without -100 prefix
49
+ elif id_int < 0:
50
+ group_id = -id_int # Remove the negative sign
51
+ return PeerChat(group_id)
52
+
53
+ # User/Bot: positive number
54
+ else:
55
+ return PeerUser(id_int)
56
+
57
+ except ValueError as e:
58
+ raise ValueError(f"Invalid chat_id format: {chat_id}. Error: {str(e)}")
59
+
60
+ async def _initialize_entity(self, client: "TelegramClient", chat_id: str) -> Any: # type: ignore[no-any-unimported]
61
+ """Initialize and cache the entity by trying different methods."""
62
+ peer = self._get_peer_from_id(chat_id)
63
+
64
+ try:
65
+ # Try direct entity resolution first
66
+ entity = await client.get_entity(peer)
67
+ return entity
68
+ except ValueError:
69
+ try:
70
+ # Get all dialogs (conversations)
71
+ async for dialog in client.iter_dialogs():
72
+ # For users/bots, we need to find the dialog with the user
73
+ if (
74
+ isinstance(peer, PeerUser)
75
+ and dialog.entity.id == peer.user_id
76
+ or dialog.entity.id == getattr(peer, "channel_id", getattr(peer, "chat_id", None))
77
+ ):
78
+ return dialog.entity
79
+
80
+ # If we get here, we didn't find the entity in dialogs
81
+ raise ValueError(f"Could not find entity {chat_id} in dialogs")
82
+ except Exception as e:
83
+ raise ValueError(
84
+ f"Could not initialize entity for {chat_id}. "
85
+ f"Make sure you have access to this chat. Error: {str(e)}"
86
+ )
87
+
88
+
89
+ @require_optional_import(["telethon"], "commsagent-telegram")
90
+ @export_module("autogen.tools.experimental")
91
+ class TelegramSendTool(BaseTelegramTool, Tool):
92
+ """Sends a message to a Telegram channel, group, or user."""
93
+
94
+ def __init__(self, *, api_id: str, api_hash: str, chat_id: str) -> None:
95
+ """Initialize the TelegramSendTool.
96
+
97
+ Args:
98
+ api_id: Telegram API ID from https://my.telegram.org/apps.
99
+ api_hash: Telegram API hash from https://my.telegram.org/apps.
100
+ chat_id: The ID of the destination (Channel, Group, or User ID).
101
+ """
102
+ BaseTelegramTool.__init__(self, api_id, api_hash, "telegram_send_session")
103
+
104
+ async def telegram_send_message(
105
+ message: Annotated[str, "Message to send to the chat."],
106
+ chat_id: Annotated[str, Depends(on(chat_id))],
107
+ ) -> Any:
108
+ """Sends a message to a Telegram chat.
109
+
110
+ Args:
111
+ message: The message to send.
112
+ chat_id: The ID of the destination. (uses dependency injection)
113
+ """
114
+ try:
115
+ client = self._get_client()
116
+ async with client:
117
+ # Initialize and cache the entity
118
+ entity = await self._initialize_entity(client, chat_id)
119
+
120
+ if len(message) > MAX_MESSAGE_LENGTH:
121
+ chunks = [
122
+ message[i : i + (MAX_MESSAGE_LENGTH - 1)]
123
+ for i in range(0, len(message), (MAX_MESSAGE_LENGTH - 1))
124
+ ]
125
+ first_message: Message | None = None # type: ignore[no-any-unimported]
126
+
127
+ for i, chunk in enumerate(chunks):
128
+ sent = await client.send_message(
129
+ entity=entity,
130
+ message=chunk,
131
+ parse_mode="html",
132
+ reply_to=first_message.id if first_message else None,
133
+ )
134
+
135
+ # Store the first message to chain replies
136
+ if i == 0:
137
+ first_message = sent
138
+ sent_message_id = str(sent.id)
139
+
140
+ return (
141
+ f"Message sent successfully ({len(chunks)} chunks, first ID: {sent_message_id}):\n{message}"
142
+ )
143
+ else:
144
+ sent = await client.send_message(entity=entity, message=message, parse_mode="html")
145
+ return f"Message sent successfully (ID: {sent.id}):\n{message}"
146
+
147
+ except Exception as e:
148
+ return f"Message send failed, exception: {str(e)}"
149
+
150
+ Tool.__init__(
151
+ self,
152
+ name="telegram_send",
153
+ description="Sends a message to a personal channel, bot channel, group, or channel.",
154
+ func_or_tool=telegram_send_message,
155
+ )
156
+
157
+
158
+ @require_optional_import(["telethon"], "commsagent-telegram")
159
+ @export_module("autogen.tools.experimental")
160
+ class TelegramRetrieveTool(BaseTelegramTool, Tool):
161
+ """Retrieves messages from a Telegram channel."""
162
+
163
+ def __init__(self, *, api_id: str, api_hash: str, chat_id: str) -> None:
164
+ """Initialize the TelegramRetrieveTool.
165
+
166
+ Args:
167
+ api_id: Telegram API ID from https://my.telegram.org/apps.
168
+ api_hash: Telegram API hash from https://my.telegram.org/apps.
169
+ chat_id: The ID of the chat to retrieve messages from (Channel, Group, Bot Chat ID).
170
+ """
171
+ BaseTelegramTool.__init__(self, api_id, api_hash, "telegram_retrieve_session")
172
+ self._chat_id = chat_id
173
+
174
+ async def telegram_retrieve_messages(
175
+ chat_id: Annotated[str, Depends(on(chat_id))],
176
+ messages_since: Annotated[
177
+ str | None,
178
+ "Date to retrieve messages from (ISO format) OR message ID. If None, retrieves latest messages.",
179
+ ] = None,
180
+ maximum_messages: Annotated[
181
+ int | None, "Maximum number of messages to retrieve. If None, retrieves all messages since date."
182
+ ] = None,
183
+ search: Annotated[str | None, "Optional string to search for in messages."] = None,
184
+ ) -> Any:
185
+ """Retrieves messages from a Telegram chat.
186
+
187
+ Args:
188
+ chat_id: The ID of the chat. (uses dependency injection)
189
+ messages_since: ISO format date string OR message ID to retrieve messages from.
190
+ maximum_messages: Maximum number of messages to retrieve.
191
+ search: Optional string to search for in messages.
192
+ """
193
+ try:
194
+ client = self._get_client()
195
+ async with client:
196
+ # Initialize and cache the entity
197
+ entity = await self._initialize_entity(client, chat_id)
198
+
199
+ # Setup retrieval parameters
200
+ params = {
201
+ "entity": entity,
202
+ "limit": maximum_messages if maximum_messages else None,
203
+ "search": search if search else None,
204
+ "filter": InputMessagesFilterEmpty(),
205
+ "wait_time": None, # No wait time between requests
206
+ }
207
+
208
+ # Handle messages_since parameter
209
+ if messages_since:
210
+ try:
211
+ # Try to parse as message ID first
212
+ msg_id = int(messages_since)
213
+ params["min_id"] = msg_id
214
+ except ValueError:
215
+ # Not a message ID, try as ISO date
216
+ try:
217
+ date = datetime.fromisoformat(messages_since.replace("Z", "+00:00"))
218
+ params["offset_date"] = date
219
+ params["reverse"] = (
220
+ True # Need this because the date gets messages before a certain date by default
221
+ )
222
+ except ValueError:
223
+ return {
224
+ "error": "Invalid messages_since format. Please provide either a message ID or ISO format date (e.g., '2025-01-25T00:00:00Z')"
225
+ }
226
+
227
+ # Retrieve messages
228
+ messages = []
229
+ count = 0
230
+ # For bot users, we need to get both sent and received messages
231
+ if isinstance(self._get_peer_from_id(chat_id), PeerUser):
232
+ print(f"Retrieving messages for bot chat {chat_id}")
233
+
234
+ async for message in client.iter_messages(**params):
235
+ count += 1
236
+ messages.append({
237
+ "id": str(message.id),
238
+ "date": message.date.isoformat(),
239
+ "from_id": str(message.from_id) if message.from_id else None,
240
+ "text": message.text,
241
+ "reply_to_msg_id": str(message.reply_to_msg_id) if message.reply_to_msg_id else None,
242
+ "forward_from": str(message.forward.from_id) if message.forward else None,
243
+ "edit_date": message.edit_date.isoformat() if message.edit_date else None,
244
+ "media": bool(message.media),
245
+ "entities": [
246
+ {"type": e.__class__.__name__, "offset": e.offset, "length": e.length}
247
+ for e in message.entities
248
+ ]
249
+ if message.entities
250
+ else None,
251
+ })
252
+
253
+ # Check if we've hit the maximum
254
+ if maximum_messages and len(messages) >= maximum_messages:
255
+ break
256
+
257
+ return {
258
+ "message_count": len(messages),
259
+ "messages": messages,
260
+ "start_time": messages_since or "latest",
261
+ }
262
+
263
+ except Exception as e:
264
+ return f"Message retrieval failed, exception: {str(e)}"
265
+
266
+ Tool.__init__(
267
+ self,
268
+ name="telegram_retrieve",
269
+ description="Retrieves messages from a Telegram chat based on datetime/message ID and/or number of latest messages.",
270
+ func_or_tool=telegram_retrieve_messages,
271
+ )
@@ -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 .perplexity_search import PerplexitySearchTool
6
+
7
+ __all__ = ["PerplexitySearchTool"]