ag2 0.9.1a1__py3-none-any.whl → 0.9.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.

Potentially problematic release.


This version of ag2 might be problematic. Click here for more details.

Files changed (371) hide show
  1. {ag2-0.9.1a1.dist-info → ag2-0.9.2.dist-info}/METADATA +272 -75
  2. ag2-0.9.2.dist-info/RECORD +406 -0
  3. {ag2-0.9.1a1.dist-info → ag2-0.9.2.dist-info}/WHEEL +1 -2
  4. autogen/__init__.py +89 -0
  5. autogen/_website/__init__.py +3 -0
  6. autogen/_website/generate_api_references.py +427 -0
  7. autogen/_website/generate_mkdocs.py +1174 -0
  8. autogen/_website/notebook_processor.py +476 -0
  9. autogen/_website/process_notebooks.py +656 -0
  10. autogen/_website/utils.py +412 -0
  11. autogen/agentchat/__init__.py +44 -0
  12. autogen/agentchat/agent.py +182 -0
  13. autogen/agentchat/assistant_agent.py +85 -0
  14. autogen/agentchat/chat.py +309 -0
  15. autogen/agentchat/contrib/__init__.py +5 -0
  16. autogen/agentchat/contrib/agent_eval/README.md +7 -0
  17. autogen/agentchat/contrib/agent_eval/agent_eval.py +108 -0
  18. autogen/agentchat/contrib/agent_eval/criterion.py +43 -0
  19. autogen/agentchat/contrib/agent_eval/critic_agent.py +44 -0
  20. autogen/agentchat/contrib/agent_eval/quantifier_agent.py +39 -0
  21. autogen/agentchat/contrib/agent_eval/subcritic_agent.py +45 -0
  22. autogen/agentchat/contrib/agent_eval/task.py +42 -0
  23. autogen/agentchat/contrib/agent_optimizer.py +429 -0
  24. autogen/agentchat/contrib/capabilities/__init__.py +5 -0
  25. autogen/agentchat/contrib/capabilities/agent_capability.py +20 -0
  26. autogen/agentchat/contrib/capabilities/generate_images.py +301 -0
  27. autogen/agentchat/contrib/capabilities/teachability.py +393 -0
  28. autogen/agentchat/contrib/capabilities/text_compressors.py +66 -0
  29. autogen/agentchat/contrib/capabilities/tools_capability.py +22 -0
  30. autogen/agentchat/contrib/capabilities/transform_messages.py +93 -0
  31. autogen/agentchat/contrib/capabilities/transforms.py +566 -0
  32. autogen/agentchat/contrib/capabilities/transforms_util.py +122 -0
  33. autogen/agentchat/contrib/capabilities/vision_capability.py +214 -0
  34. autogen/agentchat/contrib/captainagent/__init__.py +9 -0
  35. autogen/agentchat/contrib/captainagent/agent_builder.py +790 -0
  36. autogen/agentchat/contrib/captainagent/captainagent.py +512 -0
  37. autogen/agentchat/contrib/captainagent/tool_retriever.py +335 -0
  38. autogen/agentchat/contrib/captainagent/tools/README.md +44 -0
  39. autogen/agentchat/contrib/captainagent/tools/__init__.py +5 -0
  40. autogen/agentchat/contrib/captainagent/tools/data_analysis/calculate_correlation.py +40 -0
  41. autogen/agentchat/contrib/captainagent/tools/data_analysis/calculate_skewness_and_kurtosis.py +28 -0
  42. autogen/agentchat/contrib/captainagent/tools/data_analysis/detect_outlier_iqr.py +28 -0
  43. autogen/agentchat/contrib/captainagent/tools/data_analysis/detect_outlier_zscore.py +28 -0
  44. autogen/agentchat/contrib/captainagent/tools/data_analysis/explore_csv.py +21 -0
  45. autogen/agentchat/contrib/captainagent/tools/data_analysis/shapiro_wilk_test.py +30 -0
  46. autogen/agentchat/contrib/captainagent/tools/information_retrieval/arxiv_download.py +27 -0
  47. autogen/agentchat/contrib/captainagent/tools/information_retrieval/arxiv_search.py +53 -0
  48. autogen/agentchat/contrib/captainagent/tools/information_retrieval/extract_pdf_image.py +53 -0
  49. autogen/agentchat/contrib/captainagent/tools/information_retrieval/extract_pdf_text.py +38 -0
  50. autogen/agentchat/contrib/captainagent/tools/information_retrieval/get_wikipedia_text.py +21 -0
  51. autogen/agentchat/contrib/captainagent/tools/information_retrieval/get_youtube_caption.py +34 -0
  52. autogen/agentchat/contrib/captainagent/tools/information_retrieval/image_qa.py +60 -0
  53. autogen/agentchat/contrib/captainagent/tools/information_retrieval/optical_character_recognition.py +61 -0
  54. autogen/agentchat/contrib/captainagent/tools/information_retrieval/perform_web_search.py +47 -0
  55. autogen/agentchat/contrib/captainagent/tools/information_retrieval/scrape_wikipedia_tables.py +33 -0
  56. autogen/agentchat/contrib/captainagent/tools/information_retrieval/transcribe_audio_file.py +21 -0
  57. autogen/agentchat/contrib/captainagent/tools/information_retrieval/youtube_download.py +35 -0
  58. autogen/agentchat/contrib/captainagent/tools/math/calculate_circle_area_from_diameter.py +21 -0
  59. autogen/agentchat/contrib/captainagent/tools/math/calculate_day_of_the_week.py +18 -0
  60. autogen/agentchat/contrib/captainagent/tools/math/calculate_fraction_sum.py +28 -0
  61. autogen/agentchat/contrib/captainagent/tools/math/calculate_matrix_power.py +31 -0
  62. autogen/agentchat/contrib/captainagent/tools/math/calculate_reflected_point.py +16 -0
  63. autogen/agentchat/contrib/captainagent/tools/math/complex_numbers_product.py +25 -0
  64. autogen/agentchat/contrib/captainagent/tools/math/compute_currency_conversion.py +23 -0
  65. autogen/agentchat/contrib/captainagent/tools/math/count_distinct_permutations.py +27 -0
  66. autogen/agentchat/contrib/captainagent/tools/math/evaluate_expression.py +28 -0
  67. autogen/agentchat/contrib/captainagent/tools/math/find_continuity_point.py +34 -0
  68. autogen/agentchat/contrib/captainagent/tools/math/fraction_to_mixed_numbers.py +39 -0
  69. autogen/agentchat/contrib/captainagent/tools/math/modular_inverse_sum.py +23 -0
  70. autogen/agentchat/contrib/captainagent/tools/math/simplify_mixed_numbers.py +36 -0
  71. autogen/agentchat/contrib/captainagent/tools/math/sum_of_digit_factorials.py +15 -0
  72. autogen/agentchat/contrib/captainagent/tools/math/sum_of_primes_below.py +15 -0
  73. autogen/agentchat/contrib/captainagent/tools/requirements.txt +10 -0
  74. autogen/agentchat/contrib/captainagent/tools/tool_description.tsv +34 -0
  75. autogen/agentchat/contrib/gpt_assistant_agent.py +526 -0
  76. autogen/agentchat/contrib/graph_rag/__init__.py +9 -0
  77. autogen/agentchat/contrib/graph_rag/document.py +29 -0
  78. autogen/agentchat/contrib/graph_rag/falkor_graph_query_engine.py +170 -0
  79. autogen/agentchat/contrib/graph_rag/falkor_graph_rag_capability.py +103 -0
  80. autogen/agentchat/contrib/graph_rag/graph_query_engine.py +53 -0
  81. autogen/agentchat/contrib/graph_rag/graph_rag_capability.py +63 -0
  82. autogen/agentchat/contrib/graph_rag/neo4j_graph_query_engine.py +268 -0
  83. autogen/agentchat/contrib/graph_rag/neo4j_graph_rag_capability.py +83 -0
  84. autogen/agentchat/contrib/graph_rag/neo4j_native_graph_query_engine.py +210 -0
  85. autogen/agentchat/contrib/graph_rag/neo4j_native_graph_rag_capability.py +93 -0
  86. autogen/agentchat/contrib/img_utils.py +397 -0
  87. autogen/agentchat/contrib/llamaindex_conversable_agent.py +117 -0
  88. autogen/agentchat/contrib/llava_agent.py +187 -0
  89. autogen/agentchat/contrib/math_user_proxy_agent.py +464 -0
  90. autogen/agentchat/contrib/multimodal_conversable_agent.py +125 -0
  91. autogen/agentchat/contrib/qdrant_retrieve_user_proxy_agent.py +324 -0
  92. autogen/agentchat/contrib/rag/__init__.py +10 -0
  93. autogen/agentchat/contrib/rag/chromadb_query_engine.py +272 -0
  94. autogen/agentchat/contrib/rag/llamaindex_query_engine.py +198 -0
  95. autogen/agentchat/contrib/rag/mongodb_query_engine.py +329 -0
  96. autogen/agentchat/contrib/rag/query_engine.py +74 -0
  97. autogen/agentchat/contrib/retrieve_assistant_agent.py +56 -0
  98. autogen/agentchat/contrib/retrieve_user_proxy_agent.py +703 -0
  99. autogen/agentchat/contrib/society_of_mind_agent.py +199 -0
  100. autogen/agentchat/contrib/swarm_agent.py +1425 -0
  101. autogen/agentchat/contrib/text_analyzer_agent.py +79 -0
  102. autogen/agentchat/contrib/vectordb/__init__.py +5 -0
  103. autogen/agentchat/contrib/vectordb/base.py +232 -0
  104. autogen/agentchat/contrib/vectordb/chromadb.py +315 -0
  105. autogen/agentchat/contrib/vectordb/couchbase.py +407 -0
  106. autogen/agentchat/contrib/vectordb/mongodb.py +550 -0
  107. autogen/agentchat/contrib/vectordb/pgvectordb.py +928 -0
  108. autogen/agentchat/contrib/vectordb/qdrant.py +320 -0
  109. autogen/agentchat/contrib/vectordb/utils.py +126 -0
  110. autogen/agentchat/contrib/web_surfer.py +303 -0
  111. autogen/agentchat/conversable_agent.py +4023 -0
  112. autogen/agentchat/group/__init__.py +64 -0
  113. autogen/agentchat/group/available_condition.py +91 -0
  114. autogen/agentchat/group/context_condition.py +77 -0
  115. autogen/agentchat/group/context_expression.py +238 -0
  116. autogen/agentchat/group/context_str.py +41 -0
  117. autogen/agentchat/group/context_variables.py +192 -0
  118. autogen/agentchat/group/group_tool_executor.py +202 -0
  119. autogen/agentchat/group/group_utils.py +591 -0
  120. autogen/agentchat/group/handoffs.py +244 -0
  121. autogen/agentchat/group/llm_condition.py +93 -0
  122. autogen/agentchat/group/multi_agent_chat.py +237 -0
  123. autogen/agentchat/group/on_condition.py +58 -0
  124. autogen/agentchat/group/on_context_condition.py +54 -0
  125. autogen/agentchat/group/patterns/__init__.py +18 -0
  126. autogen/agentchat/group/patterns/auto.py +159 -0
  127. autogen/agentchat/group/patterns/manual.py +176 -0
  128. autogen/agentchat/group/patterns/pattern.py +288 -0
  129. autogen/agentchat/group/patterns/random.py +106 -0
  130. autogen/agentchat/group/patterns/round_robin.py +117 -0
  131. autogen/agentchat/group/reply_result.py +26 -0
  132. autogen/agentchat/group/speaker_selection_result.py +41 -0
  133. autogen/agentchat/group/targets/__init__.py +4 -0
  134. autogen/agentchat/group/targets/group_chat_target.py +132 -0
  135. autogen/agentchat/group/targets/group_manager_target.py +151 -0
  136. autogen/agentchat/group/targets/transition_target.py +413 -0
  137. autogen/agentchat/group/targets/transition_utils.py +6 -0
  138. autogen/agentchat/groupchat.py +1694 -0
  139. autogen/agentchat/realtime/__init__.py +3 -0
  140. autogen/agentchat/realtime/experimental/__init__.py +20 -0
  141. autogen/agentchat/realtime/experimental/audio_adapters/__init__.py +8 -0
  142. autogen/agentchat/realtime/experimental/audio_adapters/twilio_audio_adapter.py +148 -0
  143. autogen/agentchat/realtime/experimental/audio_adapters/websocket_audio_adapter.py +139 -0
  144. autogen/agentchat/realtime/experimental/audio_observer.py +42 -0
  145. autogen/agentchat/realtime/experimental/clients/__init__.py +15 -0
  146. autogen/agentchat/realtime/experimental/clients/gemini/__init__.py +7 -0
  147. autogen/agentchat/realtime/experimental/clients/gemini/client.py +274 -0
  148. autogen/agentchat/realtime/experimental/clients/oai/__init__.py +8 -0
  149. autogen/agentchat/realtime/experimental/clients/oai/base_client.py +220 -0
  150. autogen/agentchat/realtime/experimental/clients/oai/rtc_client.py +243 -0
  151. autogen/agentchat/realtime/experimental/clients/oai/utils.py +48 -0
  152. autogen/agentchat/realtime/experimental/clients/realtime_client.py +190 -0
  153. autogen/agentchat/realtime/experimental/function_observer.py +85 -0
  154. autogen/agentchat/realtime/experimental/realtime_agent.py +158 -0
  155. autogen/agentchat/realtime/experimental/realtime_events.py +42 -0
  156. autogen/agentchat/realtime/experimental/realtime_observer.py +100 -0
  157. autogen/agentchat/realtime/experimental/realtime_swarm.py +475 -0
  158. autogen/agentchat/realtime/experimental/websockets.py +21 -0
  159. autogen/agentchat/realtime_agent/__init__.py +21 -0
  160. autogen/agentchat/user_proxy_agent.py +111 -0
  161. autogen/agentchat/utils.py +206 -0
  162. autogen/agents/__init__.py +3 -0
  163. autogen/agents/contrib/__init__.py +10 -0
  164. autogen/agents/contrib/time/__init__.py +8 -0
  165. autogen/agents/contrib/time/time_reply_agent.py +73 -0
  166. autogen/agents/contrib/time/time_tool_agent.py +51 -0
  167. autogen/agents/experimental/__init__.py +27 -0
  168. autogen/agents/experimental/deep_research/__init__.py +7 -0
  169. autogen/agents/experimental/deep_research/deep_research.py +52 -0
  170. autogen/agents/experimental/discord/__init__.py +7 -0
  171. autogen/agents/experimental/discord/discord.py +66 -0
  172. autogen/agents/experimental/document_agent/__init__.py +19 -0
  173. autogen/agents/experimental/document_agent/chroma_query_engine.py +316 -0
  174. autogen/agents/experimental/document_agent/docling_doc_ingest_agent.py +118 -0
  175. autogen/agents/experimental/document_agent/document_agent.py +461 -0
  176. autogen/agents/experimental/document_agent/document_conditions.py +50 -0
  177. autogen/agents/experimental/document_agent/document_utils.py +380 -0
  178. autogen/agents/experimental/document_agent/inmemory_query_engine.py +220 -0
  179. autogen/agents/experimental/document_agent/parser_utils.py +130 -0
  180. autogen/agents/experimental/document_agent/url_utils.py +426 -0
  181. autogen/agents/experimental/reasoning/__init__.py +7 -0
  182. autogen/agents/experimental/reasoning/reasoning_agent.py +1178 -0
  183. autogen/agents/experimental/slack/__init__.py +7 -0
  184. autogen/agents/experimental/slack/slack.py +73 -0
  185. autogen/agents/experimental/telegram/__init__.py +7 -0
  186. autogen/agents/experimental/telegram/telegram.py +77 -0
  187. autogen/agents/experimental/websurfer/__init__.py +7 -0
  188. autogen/agents/experimental/websurfer/websurfer.py +62 -0
  189. autogen/agents/experimental/wikipedia/__init__.py +7 -0
  190. autogen/agents/experimental/wikipedia/wikipedia.py +90 -0
  191. autogen/browser_utils.py +309 -0
  192. autogen/cache/__init__.py +10 -0
  193. autogen/cache/abstract_cache_base.py +75 -0
  194. autogen/cache/cache.py +203 -0
  195. autogen/cache/cache_factory.py +88 -0
  196. autogen/cache/cosmos_db_cache.py +144 -0
  197. autogen/cache/disk_cache.py +102 -0
  198. autogen/cache/in_memory_cache.py +58 -0
  199. autogen/cache/redis_cache.py +123 -0
  200. autogen/code_utils.py +596 -0
  201. autogen/coding/__init__.py +22 -0
  202. autogen/coding/base.py +119 -0
  203. autogen/coding/docker_commandline_code_executor.py +268 -0
  204. autogen/coding/factory.py +47 -0
  205. autogen/coding/func_with_reqs.py +202 -0
  206. autogen/coding/jupyter/__init__.py +23 -0
  207. autogen/coding/jupyter/base.py +36 -0
  208. autogen/coding/jupyter/docker_jupyter_server.py +167 -0
  209. autogen/coding/jupyter/embedded_ipython_code_executor.py +182 -0
  210. autogen/coding/jupyter/import_utils.py +82 -0
  211. autogen/coding/jupyter/jupyter_client.py +231 -0
  212. autogen/coding/jupyter/jupyter_code_executor.py +160 -0
  213. autogen/coding/jupyter/local_jupyter_server.py +172 -0
  214. autogen/coding/local_commandline_code_executor.py +405 -0
  215. autogen/coding/markdown_code_extractor.py +45 -0
  216. autogen/coding/utils.py +56 -0
  217. autogen/doc_utils.py +34 -0
  218. autogen/events/__init__.py +7 -0
  219. autogen/events/agent_events.py +1013 -0
  220. autogen/events/base_event.py +99 -0
  221. autogen/events/client_events.py +167 -0
  222. autogen/events/helpers.py +36 -0
  223. autogen/events/print_event.py +46 -0
  224. autogen/exception_utils.py +73 -0
  225. autogen/extensions/__init__.py +5 -0
  226. autogen/fast_depends/__init__.py +16 -0
  227. autogen/fast_depends/_compat.py +80 -0
  228. autogen/fast_depends/core/__init__.py +14 -0
  229. autogen/fast_depends/core/build.py +225 -0
  230. autogen/fast_depends/core/model.py +576 -0
  231. autogen/fast_depends/dependencies/__init__.py +15 -0
  232. autogen/fast_depends/dependencies/model.py +29 -0
  233. autogen/fast_depends/dependencies/provider.py +39 -0
  234. autogen/fast_depends/library/__init__.py +10 -0
  235. autogen/fast_depends/library/model.py +46 -0
  236. autogen/fast_depends/py.typed +6 -0
  237. autogen/fast_depends/schema.py +66 -0
  238. autogen/fast_depends/use.py +280 -0
  239. autogen/fast_depends/utils.py +187 -0
  240. autogen/formatting_utils.py +83 -0
  241. autogen/function_utils.py +13 -0
  242. autogen/graph_utils.py +178 -0
  243. autogen/import_utils.py +526 -0
  244. autogen/interop/__init__.py +22 -0
  245. autogen/interop/crewai/__init__.py +7 -0
  246. autogen/interop/crewai/crewai.py +88 -0
  247. autogen/interop/interoperability.py +71 -0
  248. autogen/interop/interoperable.py +46 -0
  249. autogen/interop/langchain/__init__.py +8 -0
  250. autogen/interop/langchain/langchain_chat_model_factory.py +155 -0
  251. autogen/interop/langchain/langchain_tool.py +82 -0
  252. autogen/interop/litellm/__init__.py +7 -0
  253. autogen/interop/litellm/litellm_config_factory.py +179 -0
  254. autogen/interop/pydantic_ai/__init__.py +7 -0
  255. autogen/interop/pydantic_ai/pydantic_ai.py +168 -0
  256. autogen/interop/registry.py +69 -0
  257. autogen/io/__init__.py +15 -0
  258. autogen/io/base.py +151 -0
  259. autogen/io/console.py +56 -0
  260. autogen/io/processors/__init__.py +12 -0
  261. autogen/io/processors/base.py +21 -0
  262. autogen/io/processors/console_event_processor.py +56 -0
  263. autogen/io/run_response.py +293 -0
  264. autogen/io/thread_io_stream.py +63 -0
  265. autogen/io/websockets.py +213 -0
  266. autogen/json_utils.py +43 -0
  267. autogen/llm_config.py +382 -0
  268. autogen/logger/__init__.py +11 -0
  269. autogen/logger/base_logger.py +128 -0
  270. autogen/logger/file_logger.py +261 -0
  271. autogen/logger/logger_factory.py +42 -0
  272. autogen/logger/logger_utils.py +57 -0
  273. autogen/logger/sqlite_logger.py +523 -0
  274. autogen/math_utils.py +339 -0
  275. autogen/mcp/__init__.py +7 -0
  276. autogen/mcp/__main__.py +78 -0
  277. autogen/mcp/mcp_client.py +208 -0
  278. autogen/mcp/mcp_proxy/__init__.py +19 -0
  279. autogen/mcp/mcp_proxy/fastapi_code_generator_helpers.py +63 -0
  280. autogen/mcp/mcp_proxy/mcp_proxy.py +581 -0
  281. autogen/mcp/mcp_proxy/operation_grouping.py +158 -0
  282. autogen/mcp/mcp_proxy/operation_renaming.py +114 -0
  283. autogen/mcp/mcp_proxy/patch_fastapi_code_generator.py +98 -0
  284. autogen/mcp/mcp_proxy/security.py +400 -0
  285. autogen/mcp/mcp_proxy/security_schema_visitor.py +37 -0
  286. autogen/messages/__init__.py +7 -0
  287. autogen/messages/agent_messages.py +948 -0
  288. autogen/messages/base_message.py +107 -0
  289. autogen/messages/client_messages.py +171 -0
  290. autogen/messages/print_message.py +49 -0
  291. autogen/oai/__init__.py +53 -0
  292. autogen/oai/anthropic.py +714 -0
  293. autogen/oai/bedrock.py +628 -0
  294. autogen/oai/cerebras.py +299 -0
  295. autogen/oai/client.py +1444 -0
  296. autogen/oai/client_utils.py +169 -0
  297. autogen/oai/cohere.py +479 -0
  298. autogen/oai/gemini.py +998 -0
  299. autogen/oai/gemini_types.py +155 -0
  300. autogen/oai/groq.py +305 -0
  301. autogen/oai/mistral.py +303 -0
  302. autogen/oai/oai_models/__init__.py +11 -0
  303. autogen/oai/oai_models/_models.py +16 -0
  304. autogen/oai/oai_models/chat_completion.py +87 -0
  305. autogen/oai/oai_models/chat_completion_audio.py +32 -0
  306. autogen/oai/oai_models/chat_completion_message.py +86 -0
  307. autogen/oai/oai_models/chat_completion_message_tool_call.py +37 -0
  308. autogen/oai/oai_models/chat_completion_token_logprob.py +63 -0
  309. autogen/oai/oai_models/completion_usage.py +60 -0
  310. autogen/oai/ollama.py +643 -0
  311. autogen/oai/openai_utils.py +881 -0
  312. autogen/oai/together.py +370 -0
  313. autogen/retrieve_utils.py +491 -0
  314. autogen/runtime_logging.py +160 -0
  315. autogen/token_count_utils.py +267 -0
  316. autogen/tools/__init__.py +20 -0
  317. autogen/tools/contrib/__init__.py +9 -0
  318. autogen/tools/contrib/time/__init__.py +7 -0
  319. autogen/tools/contrib/time/time.py +41 -0
  320. autogen/tools/dependency_injection.py +254 -0
  321. autogen/tools/experimental/__init__.py +48 -0
  322. autogen/tools/experimental/browser_use/__init__.py +7 -0
  323. autogen/tools/experimental/browser_use/browser_use.py +161 -0
  324. autogen/tools/experimental/crawl4ai/__init__.py +7 -0
  325. autogen/tools/experimental/crawl4ai/crawl4ai.py +153 -0
  326. autogen/tools/experimental/deep_research/__init__.py +7 -0
  327. autogen/tools/experimental/deep_research/deep_research.py +328 -0
  328. autogen/tools/experimental/duckduckgo/__init__.py +7 -0
  329. autogen/tools/experimental/duckduckgo/duckduckgo_search.py +109 -0
  330. autogen/tools/experimental/google/__init__.py +14 -0
  331. autogen/tools/experimental/google/authentication/__init__.py +11 -0
  332. autogen/tools/experimental/google/authentication/credentials_hosted_provider.py +43 -0
  333. autogen/tools/experimental/google/authentication/credentials_local_provider.py +91 -0
  334. autogen/tools/experimental/google/authentication/credentials_provider.py +35 -0
  335. autogen/tools/experimental/google/drive/__init__.py +9 -0
  336. autogen/tools/experimental/google/drive/drive_functions.py +124 -0
  337. autogen/tools/experimental/google/drive/toolkit.py +88 -0
  338. autogen/tools/experimental/google/model.py +17 -0
  339. autogen/tools/experimental/google/toolkit_protocol.py +19 -0
  340. autogen/tools/experimental/google_search/__init__.py +8 -0
  341. autogen/tools/experimental/google_search/google_search.py +93 -0
  342. autogen/tools/experimental/google_search/youtube_search.py +181 -0
  343. autogen/tools/experimental/messageplatform/__init__.py +17 -0
  344. autogen/tools/experimental/messageplatform/discord/__init__.py +7 -0
  345. autogen/tools/experimental/messageplatform/discord/discord.py +288 -0
  346. autogen/tools/experimental/messageplatform/slack/__init__.py +7 -0
  347. autogen/tools/experimental/messageplatform/slack/slack.py +391 -0
  348. autogen/tools/experimental/messageplatform/telegram/__init__.py +7 -0
  349. autogen/tools/experimental/messageplatform/telegram/telegram.py +275 -0
  350. autogen/tools/experimental/perplexity/__init__.py +7 -0
  351. autogen/tools/experimental/perplexity/perplexity_search.py +260 -0
  352. autogen/tools/experimental/reliable/__init__.py +10 -0
  353. autogen/tools/experimental/reliable/reliable.py +1316 -0
  354. autogen/tools/experimental/tavily/__init__.py +7 -0
  355. autogen/tools/experimental/tavily/tavily_search.py +183 -0
  356. autogen/tools/experimental/web_search_preview/__init__.py +7 -0
  357. autogen/tools/experimental/web_search_preview/web_search_preview.py +114 -0
  358. autogen/tools/experimental/wikipedia/__init__.py +7 -0
  359. autogen/tools/experimental/wikipedia/wikipedia.py +287 -0
  360. autogen/tools/function_utils.py +411 -0
  361. autogen/tools/tool.py +187 -0
  362. autogen/tools/toolkit.py +86 -0
  363. autogen/types.py +29 -0
  364. autogen/version.py +7 -0
  365. templates/client_template/main.jinja2 +69 -0
  366. templates/config_template/config.jinja2 +7 -0
  367. templates/main.jinja2 +61 -0
  368. ag2-0.9.1a1.dist-info/RECORD +0 -6
  369. ag2-0.9.1a1.dist-info/top_level.txt +0 -1
  370. {ag2-0.9.1a1.dist-info → ag2-0.9.2.dist-info/licenses}/LICENSE +0 -0
  371. {ag2-0.9.1a1.dist-info → ag2-0.9.2.dist-info/licenses}/NOTICE.md +0 -0
@@ -0,0 +1,391 @@
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, Optional, Tuple, Union
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
+ """
30
+ Initialize the SlackSendTool.
31
+
32
+ Args:
33
+ bot_token: Bot User OAuth Token starting with "xoxb-".
34
+ channel_id: Channel ID where messages will be sent.
35
+ """
36
+
37
+ # Function that sends the message, uses dependency injection for bot token / channel / guild
38
+ async def slack_send_message(
39
+ message: Annotated[str, "Message to send to the channel."],
40
+ bot_token: Annotated[str, Depends(on(bot_token))],
41
+ channel_id: Annotated[str, Depends(on(channel_id))],
42
+ ) -> Any:
43
+ """
44
+ Sends a message to a Slack channel.
45
+
46
+ Args:
47
+ message: The message to send to the channel.
48
+ bot_token: The bot token to use for Slack. (uses dependency injection)
49
+ channel_id: The ID of the channel. (uses dependency injection)
50
+ """
51
+ try:
52
+ web_client = WebClient(token=bot_token)
53
+
54
+ # Send the message
55
+ if len(message) > MAX_MESSAGE_LENGTH:
56
+ chunks = [
57
+ message[i : i + (MAX_MESSAGE_LENGTH - 1)]
58
+ for i in range(0, len(message), (MAX_MESSAGE_LENGTH - 1))
59
+ ]
60
+ for i, chunk in enumerate(chunks):
61
+ response = web_client.chat_postMessage(channel=channel_id, text=chunk)
62
+
63
+ if not response["ok"]:
64
+ return f"Message send failed on chunk {i + 1}, Slack response error: {response['error']}"
65
+
66
+ # Store ID for the first chunk
67
+ if i == 0:
68
+ sent_message_id = response["ts"]
69
+
70
+ return f"Message sent successfully ({len(chunks)} chunks, first ID: {sent_message_id}):\n{message}"
71
+ else:
72
+ response = web_client.chat_postMessage(channel=channel_id, text=message)
73
+
74
+ if not response["ok"]:
75
+ return f"Message send failed, Slack response error: {response['error']}"
76
+
77
+ return f"Message sent successfully (ID: {response['ts']}):\n{message}"
78
+ except SlackApiError as e:
79
+ return f"Message send failed, Slack API exception: {e.response['error']} (See https://api.slack.com/automation/cli/errors#{e.response['error']})"
80
+ except Exception as e:
81
+ return f"Message send failed, exception: {e}"
82
+
83
+ super().__init__(
84
+ name="slack_send",
85
+ description="Sends a message to a Slack channel.",
86
+ func_or_tool=slack_send_message,
87
+ )
88
+
89
+
90
+ @require_optional_import(["slack_sdk"], "commsagent-slack")
91
+ @export_module("autogen.tools.experimental")
92
+ class SlackRetrieveTool(Tool):
93
+ """Retrieves messages from a Slack channel."""
94
+
95
+ def __init__(self, *, bot_token: str, channel_id: str) -> None:
96
+ """
97
+ Initialize the SlackRetrieveTool.
98
+
99
+ Args:
100
+ bot_token: Bot User OAuth Token starting with "xoxb-".
101
+ channel_id: Channel ID where messages will be sent.
102
+ """
103
+
104
+ async def slack_retrieve_messages(
105
+ bot_token: Annotated[str, Depends(on(bot_token))],
106
+ channel_id: Annotated[str, Depends(on(channel_id))],
107
+ messages_since: Annotated[
108
+ Union[str, None],
109
+ "Date to retrieve messages from (ISO format) OR Slack message ID. If None, retrieves latest messages.",
110
+ ] = None,
111
+ maximum_messages: Annotated[
112
+ Union[int, None], "Maximum number of messages to retrieve. If None, retrieves all messages since date."
113
+ ] = None,
114
+ ) -> Any:
115
+ """
116
+ Retrieves messages from a Discord channel.
117
+
118
+ Args:
119
+ bot_token: The bot token to use for Discord. (uses dependency injection)
120
+ channel_id: The ID of the channel. (uses dependency injection)
121
+ messages_since: ISO format date string OR Slack message ID, to retrieve messages from. If None, retrieves latest messages.
122
+ maximum_messages: Maximum number of messages to retrieve. If None, retrieves all messages since date.
123
+ """
124
+ try:
125
+ web_client = WebClient(token=bot_token)
126
+
127
+ # Convert ISO datetime to Unix timestamp if needed
128
+ oldest = None
129
+ if messages_since:
130
+ if "." in messages_since: # Likely a Slack message ID
131
+ oldest = messages_since
132
+ else: # Assume ISO format
133
+ try:
134
+ dt = datetime.fromisoformat(messages_since.replace("Z", "+00:00"))
135
+ oldest = str(dt.timestamp())
136
+ except ValueError as e:
137
+ 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}"
138
+
139
+ messages = []
140
+ cursor = None
141
+
142
+ while True:
143
+ try:
144
+ # Prepare API call parameters
145
+ params = {
146
+ "channel": channel_id,
147
+ "limit": min(1000, maximum_messages) if maximum_messages else 1000,
148
+ }
149
+ if oldest:
150
+ params["oldest"] = oldest
151
+ if cursor:
152
+ params["cursor"] = cursor
153
+
154
+ # Make API call
155
+ response = web_client.conversations_history(**params) # type: ignore[arg-type]
156
+
157
+ if not response["ok"]:
158
+ return f"Message retrieval failed, Slack response error: {response['error']}"
159
+
160
+ # Add messages to our list
161
+ messages.extend(response["messages"])
162
+
163
+ # Check if we've hit our maximum
164
+ if maximum_messages and len(messages) >= maximum_messages:
165
+ messages = messages[:maximum_messages]
166
+ break
167
+
168
+ # Check if there are more messages
169
+ if not response["has_more"]:
170
+ break
171
+
172
+ cursor = response["response_metadata"]["next_cursor"]
173
+
174
+ except SlackApiError as e:
175
+ return f"Message retrieval failed on pagination, Slack API error: {e.response['error']}"
176
+
177
+ return {
178
+ "message_count": len(messages),
179
+ "messages": messages,
180
+ "start_time": oldest or "latest",
181
+ }
182
+
183
+ except SlackApiError as e:
184
+ return f"Message retrieval failed, Slack API exception: {e.response['error']} (See https://api.slack.com/automation/cli/errors#{e.response['error']})"
185
+ except Exception as e:
186
+ return f"Message retrieval failed, exception: {e}"
187
+
188
+ super().__init__(
189
+ name="slack_retrieve",
190
+ description="Retrieves messages from a Slack channel based datetime/message ID and/or number of latest messages.",
191
+ func_or_tool=slack_retrieve_messages,
192
+ )
193
+
194
+
195
+ @require_optional_import(["slack_sdk"], "commsagent-slack")
196
+ @export_module("autogen.tools.experimental")
197
+ class SlackRetrieveRepliesTool(Tool):
198
+ """Retrieves replies to a specific Slack message from both threads and the channel."""
199
+
200
+ def __init__(self, *, bot_token: str, channel_id: str) -> None:
201
+ """
202
+ Initialize the SlackRetrieveRepliesTool.
203
+
204
+ Args:
205
+ bot_token: Bot User OAuth Token starting with "xoxb-".
206
+ channel_id: Channel ID where the parent message exists.
207
+ """
208
+
209
+ async def slack_retrieve_replies(
210
+ message_ts: Annotated[str, "Timestamp (ts) of the parent message to retrieve replies for."],
211
+ bot_token: Annotated[str, Depends(on(bot_token))],
212
+ channel_id: Annotated[str, Depends(on(channel_id))],
213
+ min_replies: Annotated[
214
+ Optional[int],
215
+ "Minimum number of replies to wait for before returning (thread + channel). If None, returns immediately.",
216
+ ] = None,
217
+ timeout_seconds: Annotated[
218
+ int, "Maximum time in seconds to wait for the requested number of replies."
219
+ ] = 60,
220
+ poll_interval: Annotated[int, "Time in seconds between polling attempts when waiting for replies."] = 5,
221
+ include_channel_messages: Annotated[
222
+ bool, "Whether to include messages in the channel after the original message."
223
+ ] = True,
224
+ ) -> Any:
225
+ """
226
+ Retrieves replies to a specific Slack message, from both threads and the main channel.
227
+
228
+ Args:
229
+ message_ts: The timestamp (ts) identifier of the parent message.
230
+ bot_token: The bot token to use for Slack. (uses dependency injection)
231
+ channel_id: The ID of the channel. (uses dependency injection)
232
+ min_replies: Minimum number of combined replies to wait for before returning. If None, returns immediately.
233
+ timeout_seconds: Maximum time in seconds to wait for the requested number of replies.
234
+ poll_interval: Time in seconds between polling attempts when waiting for replies.
235
+ include_channel_messages: Whether to include messages posted in the channel after the original message.
236
+ """
237
+ try:
238
+ web_client = WebClient(token=bot_token)
239
+
240
+ # Function to get current thread replies
241
+ async def get_thread_replies() -> tuple[Optional[list[dict[str, Any]]], Optional[str]]:
242
+ try:
243
+ response = web_client.conversations_replies(
244
+ channel=channel_id,
245
+ ts=message_ts,
246
+ )
247
+
248
+ if not response["ok"]:
249
+ return None, f"Thread reply retrieval failed, Slack response error: {response['error']}"
250
+
251
+ # The first message is the parent message itself, so exclude it when counting replies
252
+ replies = response["messages"][1:] if len(response["messages"]) > 0 else []
253
+ return replies, None
254
+
255
+ except SlackApiError as e:
256
+ return None, f"Thread reply retrieval failed, Slack API exception: {e.response['error']}"
257
+ except Exception as e:
258
+ return None, f"Thread reply retrieval failed, exception: {e}"
259
+
260
+ # Function to get messages in the channel after the original message
261
+ async def get_channel_messages() -> Tuple[Optional[list[dict[str, Any]]], Optional[str]]:
262
+ try:
263
+ response = web_client.conversations_history(
264
+ channel=channel_id,
265
+ oldest=message_ts, # Start from the original message timestamp
266
+ inclusive=False, # Don't include the original message
267
+ )
268
+
269
+ if not response["ok"]:
270
+ return None, f"Channel message retrieval failed, Slack response error: {response['error']}"
271
+
272
+ # Return all messages in the channel after the original message
273
+ # We need to filter out any that are part of the thread we're already getting
274
+ messages = []
275
+ for msg in response["messages"]:
276
+ # Skip if the message is part of the thread we're already retrieving
277
+ if "thread_ts" in msg and msg["thread_ts"] == message_ts:
278
+ continue
279
+ messages.append(msg)
280
+
281
+ return messages, None
282
+
283
+ except SlackApiError as e:
284
+ return None, f"Channel message retrieval failed, Slack API exception: {e.response['error']}"
285
+ except Exception as e:
286
+ return None, f"Channel message retrieval failed, exception: {e}"
287
+
288
+ # Function to get all replies (both thread and channel)
289
+ async def get_all_replies() -> Tuple[
290
+ Optional[list[dict[str, Any]]], Optional[list[dict[str, Any]]], Optional[str]
291
+ ]:
292
+ thread_replies, thread_error = await get_thread_replies()
293
+ if thread_error:
294
+ return None, None, thread_error
295
+
296
+ channel_messages: list[dict[str, Any]] = []
297
+ channel_error = None
298
+
299
+ if include_channel_messages:
300
+ channel_results, channel_error = await get_channel_messages()
301
+ if channel_error:
302
+ return thread_replies, None, channel_error
303
+ channel_messages = channel_results if channel_results is not None else []
304
+
305
+ return thread_replies, channel_messages, None
306
+
307
+ # If no waiting is required, just get replies and return
308
+ if min_replies is None:
309
+ thread_replies, channel_messages, error = await get_all_replies()
310
+ if error:
311
+ return error
312
+
313
+ thread_replies_list: list[dict[str, Any]] = [] if thread_replies is None else thread_replies
314
+ channel_messages_list: list[dict[str, Any]] = [] if channel_messages is None else channel_messages
315
+
316
+ # Combine replies for counting but keep them separate in the result
317
+ total_reply_count = len(thread_replies_list) + len(channel_messages_list)
318
+
319
+ return {
320
+ "parent_message_ts": message_ts,
321
+ "total_reply_count": total_reply_count,
322
+ "thread_replies": thread_replies_list,
323
+ "thread_reply_count": len(thread_replies_list),
324
+ "channel_messages": channel_messages_list if include_channel_messages else None,
325
+ "channel_message_count": len(channel_messages_list) if include_channel_messages else None,
326
+ }
327
+
328
+ # Wait for the required number of replies with timeout
329
+ start_time = datetime.now()
330
+ end_time = start_time + timedelta(seconds=timeout_seconds)
331
+
332
+ while datetime.now() < end_time:
333
+ thread_replies, channel_messages, error = await get_all_replies()
334
+ if error:
335
+ return error
336
+
337
+ thread_replies_current: list[dict[str, Any]] = [] if thread_replies is None else thread_replies
338
+ channel_messages_current: list[dict[str, Any]] = (
339
+ [] if channel_messages is None else channel_messages
340
+ )
341
+
342
+ # Combine replies for counting
343
+ total_reply_count = len(thread_replies_current) + len(channel_messages_current)
344
+
345
+ # If we have enough total replies, return them
346
+ if total_reply_count >= min_replies:
347
+ return {
348
+ "parent_message_ts": message_ts,
349
+ "total_reply_count": total_reply_count,
350
+ "thread_replies": thread_replies_current,
351
+ "thread_reply_count": len(thread_replies_current),
352
+ "channel_messages": channel_messages_current if include_channel_messages else None,
353
+ "channel_message_count": len(channel_messages_current)
354
+ if include_channel_messages
355
+ else None,
356
+ "waited_seconds": (datetime.now() - start_time).total_seconds(),
357
+ }
358
+
359
+ # Wait before checking again
360
+ await asyncio.sleep(poll_interval)
361
+
362
+ # If we reach here, we timed out waiting for replies
363
+ thread_replies, channel_messages, error = await get_all_replies()
364
+ if error:
365
+ return error
366
+
367
+ # Combine replies for counting
368
+ total_reply_count = len(thread_replies or []) + len(channel_messages or [])
369
+
370
+ return {
371
+ "parent_message_ts": message_ts,
372
+ "total_reply_count": total_reply_count,
373
+ "thread_replies": thread_replies or [],
374
+ "thread_reply_count": len(thread_replies or []),
375
+ "channel_messages": channel_messages or [] if include_channel_messages else None,
376
+ "channel_message_count": len(channel_messages or []) if include_channel_messages else None,
377
+ "timed_out": True,
378
+ "waited_seconds": timeout_seconds,
379
+ "requested_replies": min_replies,
380
+ }
381
+
382
+ except SlackApiError as e:
383
+ return f"Reply retrieval failed, Slack API exception: {e.response['error']} (See https://api.slack.com/automation/cli/errors#{e.response['error']})"
384
+ except Exception as e:
385
+ return f"Reply retrieval failed, exception: {e}"
386
+
387
+ super().__init__(
388
+ name="slack_retrieve_replies",
389
+ description="Retrieves replies to a specific Slack message, checking both thread replies and messages in the channel after the original message.",
390
+ func_or_tool=slack_retrieve_replies,
391
+ )
@@ -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,275 @@
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
+ """
96
+ Initialize the TelegramSendTool.
97
+
98
+ Args:
99
+ api_id: Telegram API ID from https://my.telegram.org/apps.
100
+ api_hash: Telegram API hash from https://my.telegram.org/apps.
101
+ chat_id: The ID of the destination (Channel, Group, or User ID).
102
+ """
103
+ BaseTelegramTool.__init__(self, api_id, api_hash, "telegram_send_session")
104
+
105
+ async def telegram_send_message(
106
+ message: Annotated[str, "Message to send to the chat."],
107
+ chat_id: Annotated[str, Depends(on(chat_id))],
108
+ ) -> Any:
109
+ """
110
+ Sends a message to a Telegram chat.
111
+
112
+ Args:
113
+ message: The message to send.
114
+ chat_id: The ID of the destination. (uses dependency injection)
115
+ """
116
+ try:
117
+ client = self._get_client()
118
+ async with client:
119
+ # Initialize and cache the entity
120
+ entity = await self._initialize_entity(client, chat_id)
121
+
122
+ if len(message) > MAX_MESSAGE_LENGTH:
123
+ chunks = [
124
+ message[i : i + (MAX_MESSAGE_LENGTH - 1)]
125
+ for i in range(0, len(message), (MAX_MESSAGE_LENGTH - 1))
126
+ ]
127
+ first_message: Union[Message, None] = None # type: ignore[no-any-unimported]
128
+
129
+ for i, chunk in enumerate(chunks):
130
+ sent = await client.send_message(
131
+ entity=entity,
132
+ message=chunk,
133
+ parse_mode="html",
134
+ reply_to=first_message.id if first_message else None,
135
+ )
136
+
137
+ # Store the first message to chain replies
138
+ if i == 0:
139
+ first_message = sent
140
+ sent_message_id = str(sent.id)
141
+
142
+ return (
143
+ f"Message sent successfully ({len(chunks)} chunks, first ID: {sent_message_id}):\n{message}"
144
+ )
145
+ else:
146
+ sent = await client.send_message(entity=entity, message=message, parse_mode="html")
147
+ return f"Message sent successfully (ID: {sent.id}):\n{message}"
148
+
149
+ except Exception as e:
150
+ return f"Message send failed, exception: {str(e)}"
151
+
152
+ Tool.__init__(
153
+ self,
154
+ name="telegram_send",
155
+ description="Sends a message to a personal channel, bot channel, group, or channel.",
156
+ func_or_tool=telegram_send_message,
157
+ )
158
+
159
+
160
+ @require_optional_import(["telethon"], "commsagent-telegram")
161
+ @export_module("autogen.tools.experimental")
162
+ class TelegramRetrieveTool(BaseTelegramTool, Tool):
163
+ """Retrieves messages from a Telegram channel."""
164
+
165
+ def __init__(self, *, api_id: str, api_hash: str, chat_id: str) -> None:
166
+ """
167
+ Initialize the TelegramRetrieveTool.
168
+
169
+ Args:
170
+ api_id: Telegram API ID from https://my.telegram.org/apps.
171
+ api_hash: Telegram API hash from https://my.telegram.org/apps.
172
+ chat_id: The ID of the chat to retrieve messages from (Channel, Group, Bot Chat ID).
173
+ """
174
+ BaseTelegramTool.__init__(self, api_id, api_hash, "telegram_retrieve_session")
175
+ self._chat_id = chat_id
176
+
177
+ async def telegram_retrieve_messages(
178
+ chat_id: Annotated[str, Depends(on(chat_id))],
179
+ messages_since: Annotated[
180
+ Union[str, None],
181
+ "Date to retrieve messages from (ISO format) OR message ID. If None, retrieves latest messages.",
182
+ ] = None,
183
+ maximum_messages: Annotated[
184
+ Union[int, None], "Maximum number of messages to retrieve. If None, retrieves all messages since date."
185
+ ] = None,
186
+ search: Annotated[Union[str, None], "Optional string to search for in messages."] = None,
187
+ ) -> Any:
188
+ """
189
+ Retrieves messages from a Telegram chat.
190
+
191
+ Args:
192
+ chat_id: The ID of the chat. (uses dependency injection)
193
+ messages_since: ISO format date string OR message ID to retrieve messages from.
194
+ maximum_messages: Maximum number of messages to retrieve.
195
+ search: Optional string to search for in messages.
196
+ """
197
+ try:
198
+ client = self._get_client()
199
+ async with client:
200
+ # Initialize and cache the entity
201
+ entity = await self._initialize_entity(client, chat_id)
202
+
203
+ # Setup retrieval parameters
204
+ params = {
205
+ "entity": entity,
206
+ "limit": maximum_messages if maximum_messages else None,
207
+ "search": search if search else None,
208
+ "filter": InputMessagesFilterEmpty(),
209
+ "wait_time": None, # No wait time between requests
210
+ }
211
+
212
+ # Handle messages_since parameter
213
+ if messages_since:
214
+ try:
215
+ # Try to parse as message ID first
216
+ msg_id = int(messages_since)
217
+ params["min_id"] = msg_id
218
+ except ValueError:
219
+ # Not a message ID, try as ISO date
220
+ try:
221
+ date = datetime.fromisoformat(messages_since.replace("Z", "+00:00"))
222
+ params["offset_date"] = date
223
+ params["reverse"] = (
224
+ True # Need this because the date gets messages before a certain date by default
225
+ )
226
+ except ValueError:
227
+ return {
228
+ "error": "Invalid messages_since format. Please provide either a message ID or ISO format date (e.g., '2025-01-25T00:00:00Z')"
229
+ }
230
+
231
+ # Retrieve messages
232
+ messages = []
233
+ count = 0
234
+ # For bot users, we need to get both sent and received messages
235
+ if isinstance(self._get_peer_from_id(chat_id), PeerUser):
236
+ print(f"Retrieving messages for bot chat {chat_id}")
237
+
238
+ async for message in client.iter_messages(**params):
239
+ count += 1
240
+ messages.append({
241
+ "id": str(message.id),
242
+ "date": message.date.isoformat(),
243
+ "from_id": str(message.from_id) if message.from_id else None,
244
+ "text": message.text,
245
+ "reply_to_msg_id": str(message.reply_to_msg_id) if message.reply_to_msg_id else None,
246
+ "forward_from": str(message.forward.from_id) if message.forward else None,
247
+ "edit_date": message.edit_date.isoformat() if message.edit_date else None,
248
+ "media": bool(message.media),
249
+ "entities": [
250
+ {"type": e.__class__.__name__, "offset": e.offset, "length": e.length}
251
+ for e in message.entities
252
+ ]
253
+ if message.entities
254
+ else None,
255
+ })
256
+
257
+ # Check if we've hit the maximum
258
+ if maximum_messages and len(messages) >= maximum_messages:
259
+ break
260
+
261
+ return {
262
+ "message_count": len(messages),
263
+ "messages": messages,
264
+ "start_time": messages_since or "latest",
265
+ }
266
+
267
+ except Exception as e:
268
+ return f"Message retrieval failed, exception: {str(e)}"
269
+
270
+ Tool.__init__(
271
+ self,
272
+ name="telegram_retrieve",
273
+ description="Retrieves messages from a Telegram chat based on datetime/message ID and/or number of latest messages.",
274
+ func_or_tool=telegram_retrieve_messages,
275
+ )
@@ -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"]