ag2 0.9.6__py3-none-any.whl → 0.9.8.post1__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 (236) hide show
  1. {ag2-0.9.6.dist-info → ag2-0.9.8.post1.dist-info}/METADATA +102 -75
  2. ag2-0.9.8.post1.dist-info/RECORD +387 -0
  3. autogen/__init__.py +1 -2
  4. autogen/_website/generate_api_references.py +4 -5
  5. autogen/_website/generate_mkdocs.py +9 -15
  6. autogen/_website/notebook_processor.py +13 -14
  7. autogen/_website/process_notebooks.py +10 -10
  8. autogen/_website/utils.py +5 -4
  9. autogen/agentchat/agent.py +13 -13
  10. autogen/agentchat/assistant_agent.py +7 -6
  11. autogen/agentchat/contrib/agent_eval/agent_eval.py +3 -3
  12. autogen/agentchat/contrib/agent_eval/critic_agent.py +3 -3
  13. autogen/agentchat/contrib/agent_eval/quantifier_agent.py +3 -3
  14. autogen/agentchat/contrib/agent_eval/subcritic_agent.py +3 -3
  15. autogen/agentchat/contrib/agent_optimizer.py +3 -3
  16. autogen/agentchat/contrib/capabilities/generate_images.py +11 -11
  17. autogen/agentchat/contrib/capabilities/teachability.py +15 -15
  18. autogen/agentchat/contrib/capabilities/transforms.py +17 -18
  19. autogen/agentchat/contrib/capabilities/transforms_util.py +5 -5
  20. autogen/agentchat/contrib/capabilities/vision_capability.py +4 -3
  21. autogen/agentchat/contrib/captainagent/agent_builder.py +30 -30
  22. autogen/agentchat/contrib/captainagent/captainagent.py +22 -21
  23. autogen/agentchat/contrib/captainagent/tool_retriever.py +2 -3
  24. autogen/agentchat/contrib/gpt_assistant_agent.py +9 -9
  25. autogen/agentchat/contrib/graph_rag/document.py +3 -3
  26. autogen/agentchat/contrib/graph_rag/falkor_graph_query_engine.py +3 -3
  27. autogen/agentchat/contrib/graph_rag/falkor_graph_rag_capability.py +6 -6
  28. autogen/agentchat/contrib/graph_rag/graph_query_engine.py +3 -3
  29. autogen/agentchat/contrib/graph_rag/neo4j_graph_query_engine.py +5 -11
  30. autogen/agentchat/contrib/graph_rag/neo4j_graph_rag_capability.py +6 -6
  31. autogen/agentchat/contrib/graph_rag/neo4j_native_graph_query_engine.py +7 -7
  32. autogen/agentchat/contrib/graph_rag/neo4j_native_graph_rag_capability.py +6 -6
  33. autogen/agentchat/contrib/img_utils.py +1 -1
  34. autogen/agentchat/contrib/llamaindex_conversable_agent.py +11 -11
  35. autogen/agentchat/contrib/llava_agent.py +18 -4
  36. autogen/agentchat/contrib/math_user_proxy_agent.py +11 -11
  37. autogen/agentchat/contrib/multimodal_conversable_agent.py +8 -8
  38. autogen/agentchat/contrib/qdrant_retrieve_user_proxy_agent.py +6 -5
  39. autogen/agentchat/contrib/rag/chromadb_query_engine.py +22 -26
  40. autogen/agentchat/contrib/rag/llamaindex_query_engine.py +14 -17
  41. autogen/agentchat/contrib/rag/mongodb_query_engine.py +27 -37
  42. autogen/agentchat/contrib/rag/query_engine.py +7 -5
  43. autogen/agentchat/contrib/retrieve_assistant_agent.py +5 -5
  44. autogen/agentchat/contrib/retrieve_user_proxy_agent.py +8 -7
  45. autogen/agentchat/contrib/society_of_mind_agent.py +15 -14
  46. autogen/agentchat/contrib/swarm_agent.py +76 -98
  47. autogen/agentchat/contrib/text_analyzer_agent.py +7 -7
  48. autogen/agentchat/contrib/vectordb/base.py +10 -18
  49. autogen/agentchat/contrib/vectordb/chromadb.py +2 -1
  50. autogen/agentchat/contrib/vectordb/couchbase.py +18 -20
  51. autogen/agentchat/contrib/vectordb/mongodb.py +6 -5
  52. autogen/agentchat/contrib/vectordb/pgvectordb.py +40 -41
  53. autogen/agentchat/contrib/vectordb/qdrant.py +5 -5
  54. autogen/agentchat/contrib/web_surfer.py +20 -19
  55. autogen/agentchat/conversable_agent.py +311 -295
  56. autogen/agentchat/group/context_str.py +1 -3
  57. autogen/agentchat/group/context_variables.py +15 -25
  58. autogen/agentchat/group/group_tool_executor.py +10 -10
  59. autogen/agentchat/group/group_utils.py +15 -15
  60. autogen/agentchat/group/guardrails.py +7 -7
  61. autogen/agentchat/group/handoffs.py +19 -36
  62. autogen/agentchat/group/multi_agent_chat.py +7 -7
  63. autogen/agentchat/group/on_condition.py +4 -7
  64. autogen/agentchat/group/on_context_condition.py +4 -7
  65. autogen/agentchat/group/patterns/auto.py +8 -7
  66. autogen/agentchat/group/patterns/manual.py +7 -6
  67. autogen/agentchat/group/patterns/pattern.py +13 -12
  68. autogen/agentchat/group/patterns/random.py +3 -3
  69. autogen/agentchat/group/patterns/round_robin.py +3 -3
  70. autogen/agentchat/group/reply_result.py +2 -4
  71. autogen/agentchat/group/speaker_selection_result.py +5 -5
  72. autogen/agentchat/group/targets/group_chat_target.py +7 -6
  73. autogen/agentchat/group/targets/group_manager_target.py +4 -4
  74. autogen/agentchat/group/targets/transition_target.py +2 -1
  75. autogen/agentchat/groupchat.py +58 -61
  76. autogen/agentchat/realtime/experimental/audio_adapters/twilio_audio_adapter.py +4 -4
  77. autogen/agentchat/realtime/experimental/audio_adapters/websocket_audio_adapter.py +4 -4
  78. autogen/agentchat/realtime/experimental/clients/gemini/client.py +7 -7
  79. autogen/agentchat/realtime/experimental/clients/oai/base_client.py +8 -8
  80. autogen/agentchat/realtime/experimental/clients/oai/rtc_client.py +6 -6
  81. autogen/agentchat/realtime/experimental/clients/realtime_client.py +10 -9
  82. autogen/agentchat/realtime/experimental/realtime_agent.py +10 -9
  83. autogen/agentchat/realtime/experimental/realtime_observer.py +3 -3
  84. autogen/agentchat/realtime/experimental/realtime_swarm.py +44 -44
  85. autogen/agentchat/user_proxy_agent.py +10 -9
  86. autogen/agentchat/utils.py +3 -3
  87. autogen/agents/contrib/time/time_reply_agent.py +6 -5
  88. autogen/agents/contrib/time/time_tool_agent.py +2 -1
  89. autogen/agents/experimental/deep_research/deep_research.py +3 -3
  90. autogen/agents/experimental/discord/discord.py +2 -2
  91. autogen/agents/experimental/document_agent/chroma_query_engine.py +29 -44
  92. autogen/agents/experimental/document_agent/docling_doc_ingest_agent.py +9 -14
  93. autogen/agents/experimental/document_agent/document_agent.py +15 -16
  94. autogen/agents/experimental/document_agent/document_conditions.py +3 -3
  95. autogen/agents/experimental/document_agent/document_utils.py +5 -9
  96. autogen/agents/experimental/document_agent/inmemory_query_engine.py +14 -20
  97. autogen/agents/experimental/document_agent/parser_utils.py +4 -4
  98. autogen/agents/experimental/document_agent/url_utils.py +14 -23
  99. autogen/agents/experimental/reasoning/reasoning_agent.py +33 -33
  100. autogen/agents/experimental/slack/slack.py +2 -2
  101. autogen/agents/experimental/telegram/telegram.py +2 -3
  102. autogen/agents/experimental/websurfer/websurfer.py +4 -4
  103. autogen/agents/experimental/wikipedia/wikipedia.py +5 -7
  104. autogen/browser_utils.py +8 -8
  105. autogen/cache/abstract_cache_base.py +5 -5
  106. autogen/cache/cache.py +12 -12
  107. autogen/cache/cache_factory.py +4 -4
  108. autogen/cache/cosmos_db_cache.py +9 -9
  109. autogen/cache/disk_cache.py +6 -6
  110. autogen/cache/in_memory_cache.py +4 -4
  111. autogen/cache/redis_cache.py +4 -4
  112. autogen/code_utils.py +18 -18
  113. autogen/coding/base.py +6 -6
  114. autogen/coding/docker_commandline_code_executor.py +9 -9
  115. autogen/coding/func_with_reqs.py +7 -6
  116. autogen/coding/jupyter/base.py +3 -3
  117. autogen/coding/jupyter/docker_jupyter_server.py +3 -4
  118. autogen/coding/jupyter/import_utils.py +3 -3
  119. autogen/coding/jupyter/jupyter_client.py +5 -5
  120. autogen/coding/jupyter/jupyter_code_executor.py +3 -4
  121. autogen/coding/jupyter/local_jupyter_server.py +2 -6
  122. autogen/coding/local_commandline_code_executor.py +8 -7
  123. autogen/coding/markdown_code_extractor.py +1 -2
  124. autogen/coding/utils.py +1 -2
  125. autogen/doc_utils.py +3 -2
  126. autogen/environments/docker_python_environment.py +19 -29
  127. autogen/environments/python_environment.py +8 -17
  128. autogen/environments/system_python_environment.py +3 -4
  129. autogen/environments/venv_python_environment.py +8 -12
  130. autogen/environments/working_directory.py +1 -2
  131. autogen/events/agent_events.py +106 -109
  132. autogen/events/base_event.py +6 -5
  133. autogen/events/client_events.py +15 -14
  134. autogen/events/helpers.py +1 -1
  135. autogen/events/print_event.py +4 -5
  136. autogen/fast_depends/_compat.py +10 -15
  137. autogen/fast_depends/core/build.py +17 -36
  138. autogen/fast_depends/core/model.py +64 -113
  139. autogen/fast_depends/dependencies/model.py +2 -1
  140. autogen/fast_depends/dependencies/provider.py +3 -2
  141. autogen/fast_depends/library/model.py +4 -4
  142. autogen/fast_depends/schema.py +7 -7
  143. autogen/fast_depends/use.py +17 -25
  144. autogen/fast_depends/utils.py +10 -30
  145. autogen/formatting_utils.py +6 -6
  146. autogen/graph_utils.py +1 -4
  147. autogen/import_utils.py +13 -13
  148. autogen/interop/crewai/crewai.py +2 -2
  149. autogen/interop/interoperable.py +2 -2
  150. autogen/interop/langchain/langchain_chat_model_factory.py +3 -2
  151. autogen/interop/langchain/langchain_tool.py +2 -6
  152. autogen/interop/litellm/litellm_config_factory.py +6 -7
  153. autogen/interop/pydantic_ai/pydantic_ai.py +4 -7
  154. autogen/interop/registry.py +2 -1
  155. autogen/io/base.py +5 -5
  156. autogen/io/run_response.py +33 -32
  157. autogen/io/websockets.py +6 -5
  158. autogen/json_utils.py +1 -2
  159. autogen/llm_config/__init__.py +11 -0
  160. autogen/llm_config/client.py +58 -0
  161. autogen/llm_config/config.py +384 -0
  162. autogen/llm_config/entry.py +154 -0
  163. autogen/logger/base_logger.py +4 -3
  164. autogen/logger/file_logger.py +2 -1
  165. autogen/logger/logger_factory.py +2 -2
  166. autogen/logger/logger_utils.py +2 -2
  167. autogen/logger/sqlite_logger.py +3 -2
  168. autogen/math_utils.py +4 -5
  169. autogen/mcp/__main__.py +6 -6
  170. autogen/mcp/helpers.py +4 -4
  171. autogen/mcp/mcp_client.py +170 -29
  172. autogen/mcp/mcp_proxy/fastapi_code_generator_helpers.py +3 -4
  173. autogen/mcp/mcp_proxy/mcp_proxy.py +23 -26
  174. autogen/mcp/mcp_proxy/operation_grouping.py +4 -5
  175. autogen/mcp/mcp_proxy/operation_renaming.py +6 -10
  176. autogen/mcp/mcp_proxy/security.py +2 -3
  177. autogen/messages/agent_messages.py +96 -98
  178. autogen/messages/base_message.py +6 -5
  179. autogen/messages/client_messages.py +15 -14
  180. autogen/messages/print_message.py +4 -5
  181. autogen/oai/__init__.py +1 -2
  182. autogen/oai/anthropic.py +42 -41
  183. autogen/oai/bedrock.py +68 -57
  184. autogen/oai/cerebras.py +26 -25
  185. autogen/oai/client.py +118 -138
  186. autogen/oai/client_utils.py +3 -3
  187. autogen/oai/cohere.py +34 -11
  188. autogen/oai/gemini.py +40 -17
  189. autogen/oai/gemini_types.py +11 -12
  190. autogen/oai/groq.py +22 -10
  191. autogen/oai/mistral.py +17 -11
  192. autogen/oai/oai_models/__init__.py +14 -2
  193. autogen/oai/oai_models/_models.py +2 -2
  194. autogen/oai/oai_models/chat_completion.py +13 -14
  195. autogen/oai/oai_models/chat_completion_message.py +11 -9
  196. autogen/oai/oai_models/chat_completion_message_tool_call.py +26 -3
  197. autogen/oai/oai_models/chat_completion_token_logprob.py +3 -4
  198. autogen/oai/oai_models/completion_usage.py +8 -9
  199. autogen/oai/ollama.py +22 -10
  200. autogen/oai/openai_responses.py +40 -17
  201. autogen/oai/openai_utils.py +159 -85
  202. autogen/oai/together.py +29 -14
  203. autogen/retrieve_utils.py +6 -7
  204. autogen/runtime_logging.py +5 -4
  205. autogen/token_count_utils.py +7 -4
  206. autogen/tools/contrib/time/time.py +0 -1
  207. autogen/tools/dependency_injection.py +5 -6
  208. autogen/tools/experimental/browser_use/browser_use.py +10 -10
  209. autogen/tools/experimental/code_execution/python_code_execution.py +5 -7
  210. autogen/tools/experimental/crawl4ai/crawl4ai.py +12 -15
  211. autogen/tools/experimental/deep_research/deep_research.py +9 -8
  212. autogen/tools/experimental/duckduckgo/duckduckgo_search.py +5 -11
  213. autogen/tools/experimental/firecrawl/firecrawl_tool.py +98 -115
  214. autogen/tools/experimental/google/authentication/credentials_local_provider.py +1 -1
  215. autogen/tools/experimental/google/drive/drive_functions.py +4 -4
  216. autogen/tools/experimental/google/drive/toolkit.py +5 -5
  217. autogen/tools/experimental/google_search/google_search.py +5 -5
  218. autogen/tools/experimental/google_search/youtube_search.py +5 -5
  219. autogen/tools/experimental/messageplatform/discord/discord.py +8 -12
  220. autogen/tools/experimental/messageplatform/slack/slack.py +14 -20
  221. autogen/tools/experimental/messageplatform/telegram/telegram.py +8 -12
  222. autogen/tools/experimental/perplexity/perplexity_search.py +18 -29
  223. autogen/tools/experimental/reliable/reliable.py +68 -74
  224. autogen/tools/experimental/searxng/searxng_search.py +20 -19
  225. autogen/tools/experimental/tavily/tavily_search.py +12 -19
  226. autogen/tools/experimental/web_search_preview/web_search_preview.py +13 -7
  227. autogen/tools/experimental/wikipedia/wikipedia.py +7 -10
  228. autogen/tools/function_utils.py +7 -7
  229. autogen/tools/tool.py +6 -5
  230. autogen/types.py +2 -2
  231. autogen/version.py +1 -1
  232. ag2-0.9.6.dist-info/RECORD +0 -421
  233. autogen/llm_config.py +0 -385
  234. {ag2-0.9.6.dist-info → ag2-0.9.8.post1.dist-info}/WHEEL +0 -0
  235. {ag2-0.9.6.dist-info → ag2-0.9.8.post1.dist-info}/licenses/LICENSE +0 -0
  236. {ag2-0.9.6.dist-info → ag2-0.9.8.post1.dist-info}/licenses/NOTICE.md +0 -0
@@ -4,7 +4,7 @@
4
4
 
5
5
  import asyncio
6
6
  from datetime import datetime, timedelta
7
- from typing import Annotated, Any, Optional, Tuple, Union
7
+ from typing import Annotated, Any
8
8
 
9
9
  from .....doc_utils import export_module
10
10
  from .....import_utils import optional_import_block, require_optional_import
@@ -26,8 +26,7 @@ class SlackSendTool(Tool):
26
26
  """Sends a message to a Slack channel."""
27
27
 
28
28
  def __init__(self, *, bot_token: str, channel_id: str) -> None:
29
- """
30
- Initialize the SlackSendTool.
29
+ """Initialize the SlackSendTool.
31
30
 
32
31
  Args:
33
32
  bot_token: Bot User OAuth Token starting with "xoxb-".
@@ -40,8 +39,7 @@ class SlackSendTool(Tool):
40
39
  bot_token: Annotated[str, Depends(on(bot_token))],
41
40
  channel_id: Annotated[str, Depends(on(channel_id))],
42
41
  ) -> Any:
43
- """
44
- Sends a message to a Slack channel.
42
+ """Sends a message to a Slack channel.
45
43
 
46
44
  Args:
47
45
  message: The message to send to the channel.
@@ -93,8 +91,7 @@ class SlackRetrieveTool(Tool):
93
91
  """Retrieves messages from a Slack channel."""
94
92
 
95
93
  def __init__(self, *, bot_token: str, channel_id: str) -> None:
96
- """
97
- Initialize the SlackRetrieveTool.
94
+ """Initialize the SlackRetrieveTool.
98
95
 
99
96
  Args:
100
97
  bot_token: Bot User OAuth Token starting with "xoxb-".
@@ -105,15 +102,14 @@ class SlackRetrieveTool(Tool):
105
102
  bot_token: Annotated[str, Depends(on(bot_token))],
106
103
  channel_id: Annotated[str, Depends(on(channel_id))],
107
104
  messages_since: Annotated[
108
- Union[str, None],
105
+ str | None,
109
106
  "Date to retrieve messages from (ISO format) OR Slack message ID. If None, retrieves latest messages.",
110
107
  ] = None,
111
108
  maximum_messages: Annotated[
112
- Union[int, None], "Maximum number of messages to retrieve. If None, retrieves all messages since date."
109
+ int | None, "Maximum number of messages to retrieve. If None, retrieves all messages since date."
113
110
  ] = None,
114
111
  ) -> Any:
115
- """
116
- Retrieves messages from a Discord channel.
112
+ """Retrieves messages from a Discord channel.
117
113
 
118
114
  Args:
119
115
  bot_token: The bot token to use for Discord. (uses dependency injection)
@@ -198,8 +194,7 @@ class SlackRetrieveRepliesTool(Tool):
198
194
  """Retrieves replies to a specific Slack message from both threads and the channel."""
199
195
 
200
196
  def __init__(self, *, bot_token: str, channel_id: str) -> None:
201
- """
202
- Initialize the SlackRetrieveRepliesTool.
197
+ """Initialize the SlackRetrieveRepliesTool.
203
198
 
204
199
  Args:
205
200
  bot_token: Bot User OAuth Token starting with "xoxb-".
@@ -211,7 +206,7 @@ class SlackRetrieveRepliesTool(Tool):
211
206
  bot_token: Annotated[str, Depends(on(bot_token))],
212
207
  channel_id: Annotated[str, Depends(on(channel_id))],
213
208
  min_replies: Annotated[
214
- Optional[int],
209
+ int | None,
215
210
  "Minimum number of replies to wait for before returning (thread + channel). If None, returns immediately.",
216
211
  ] = None,
217
212
  timeout_seconds: Annotated[
@@ -222,8 +217,7 @@ class SlackRetrieveRepliesTool(Tool):
222
217
  bool, "Whether to include messages in the channel after the original message."
223
218
  ] = True,
224
219
  ) -> Any:
225
- """
226
- Retrieves replies to a specific Slack message, from both threads and the main channel.
220
+ """Retrieves replies to a specific Slack message, from both threads and the main channel.
227
221
 
228
222
  Args:
229
223
  message_ts: The timestamp (ts) identifier of the parent message.
@@ -238,7 +232,7 @@ class SlackRetrieveRepliesTool(Tool):
238
232
  web_client = WebClient(token=bot_token)
239
233
 
240
234
  # Function to get current thread replies
241
- async def get_thread_replies() -> tuple[Optional[list[dict[str, Any]]], Optional[str]]:
235
+ async def get_thread_replies() -> tuple[list[dict[str, Any]] | None, str | None]:
242
236
  try:
243
237
  response = web_client.conversations_replies(
244
238
  channel=channel_id,
@@ -258,7 +252,7 @@ class SlackRetrieveRepliesTool(Tool):
258
252
  return None, f"Thread reply retrieval failed, exception: {e}"
259
253
 
260
254
  # 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]]:
255
+ async def get_channel_messages() -> tuple[list[dict[str, Any]] | None, str | None]:
262
256
  try:
263
257
  response = web_client.conversations_history(
264
258
  channel=channel_id,
@@ -286,8 +280,8 @@ class SlackRetrieveRepliesTool(Tool):
286
280
  return None, f"Channel message retrieval failed, exception: {e}"
287
281
 
288
282
  # 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]
283
+ async def get_all_replies() -> tuple[
284
+ list[dict[str, Any]] | None, list[dict[str, Any]] | None, str | None
291
285
  ]:
292
286
  thread_replies, thread_error = await get_thread_replies()
293
287
  if thread_error:
@@ -92,8 +92,7 @@ class TelegramSendTool(BaseTelegramTool, Tool):
92
92
  """Sends a message to a Telegram channel, group, or user."""
93
93
 
94
94
  def __init__(self, *, api_id: str, api_hash: str, chat_id: str) -> None:
95
- """
96
- Initialize the TelegramSendTool.
95
+ """Initialize the TelegramSendTool.
97
96
 
98
97
  Args:
99
98
  api_id: Telegram API ID from https://my.telegram.org/apps.
@@ -106,8 +105,7 @@ class TelegramSendTool(BaseTelegramTool, Tool):
106
105
  message: Annotated[str, "Message to send to the chat."],
107
106
  chat_id: Annotated[str, Depends(on(chat_id))],
108
107
  ) -> Any:
109
- """
110
- Sends a message to a Telegram chat.
108
+ """Sends a message to a Telegram chat.
111
109
 
112
110
  Args:
113
111
  message: The message to send.
@@ -124,7 +122,7 @@ class TelegramSendTool(BaseTelegramTool, Tool):
124
122
  message[i : i + (MAX_MESSAGE_LENGTH - 1)]
125
123
  for i in range(0, len(message), (MAX_MESSAGE_LENGTH - 1))
126
124
  ]
127
- first_message: Union[Message, None] = None # type: ignore[no-any-unimported]
125
+ first_message: Message | None = None # type: ignore[no-any-unimported]
128
126
 
129
127
  for i, chunk in enumerate(chunks):
130
128
  sent = await client.send_message(
@@ -163,8 +161,7 @@ class TelegramRetrieveTool(BaseTelegramTool, Tool):
163
161
  """Retrieves messages from a Telegram channel."""
164
162
 
165
163
  def __init__(self, *, api_id: str, api_hash: str, chat_id: str) -> None:
166
- """
167
- Initialize the TelegramRetrieveTool.
164
+ """Initialize the TelegramRetrieveTool.
168
165
 
169
166
  Args:
170
167
  api_id: Telegram API ID from https://my.telegram.org/apps.
@@ -177,16 +174,15 @@ class TelegramRetrieveTool(BaseTelegramTool, Tool):
177
174
  async def telegram_retrieve_messages(
178
175
  chat_id: Annotated[str, Depends(on(chat_id))],
179
176
  messages_since: Annotated[
180
- Union[str, None],
177
+ str | None,
181
178
  "Date to retrieve messages from (ISO format) OR message ID. If None, retrieves latest messages.",
182
179
  ] = None,
183
180
  maximum_messages: Annotated[
184
- Union[int, None], "Maximum number of messages to retrieve. If None, retrieves all messages since date."
181
+ int | None, "Maximum number of messages to retrieve. If None, retrieves all messages since date."
185
182
  ] = None,
186
- search: Annotated[Union[str, None], "Optional string to search for in messages."] = None,
183
+ search: Annotated[str | None, "Optional string to search for in messages."] = None,
187
184
  ) -> Any:
188
- """
189
- Retrieves messages from a Telegram chat.
185
+ """Retrieves messages from a Telegram chat.
190
186
 
191
187
  Args:
192
188
  chat_id: The ID of the chat. (uses dependency injection)
@@ -1,5 +1,4 @@
1
- """
2
- Module: perplexity_search_tool
1
+ """Module: perplexity_search_tool
3
2
  Copyright (c) 2023 - 2025, AG2ai, Inc., AG2ai open-source projects maintainers and core contributors
4
3
  SPDX-License-Identifier: Apache-2.0
5
4
 
@@ -9,7 +8,7 @@ It defines data models for responses and a tool for executing web and conversati
9
8
 
10
9
  import json
11
10
  import os
12
- from typing import Any, Optional, Union
11
+ from typing import Any
13
12
 
14
13
  import requests
15
14
  from pydantic import BaseModel, ValidationError
@@ -18,8 +17,7 @@ from autogen.tools import Tool
18
17
 
19
18
 
20
19
  class Message(BaseModel):
21
- """
22
- Represents a message in the chat conversation.
20
+ """Represents a message in the chat conversation.
23
21
 
24
22
  Attributes:
25
23
  role (str): The role of the message sender (e.g., "system", "user").
@@ -31,8 +29,7 @@ class Message(BaseModel):
31
29
 
32
30
 
33
31
  class Usage(BaseModel):
34
- """
35
- Model representing token usage details.
32
+ """Model representing token usage details.
36
33
 
37
34
  Attributes:
38
35
  prompt_tokens (int): The number of tokens used for the prompt.
@@ -48,8 +45,7 @@ class Usage(BaseModel):
48
45
 
49
46
 
50
47
  class Choice(BaseModel):
51
- """
52
- Represents one choice in the response from the Perplexity API.
48
+ """Represents one choice in the response from the Perplexity API.
53
49
 
54
50
  Attributes:
55
51
  index (int): The index of this choice.
@@ -63,8 +59,7 @@ class Choice(BaseModel):
63
59
 
64
60
 
65
61
  class PerplexityChatCompletionResponse(BaseModel):
66
- """
67
- Represents the full chat completion response from the Perplexity API.
62
+ """Represents the full chat completion response from the Perplexity API.
68
63
 
69
64
  Attributes:
70
65
  id (str): Unique identifier for the response.
@@ -86,8 +81,7 @@ class PerplexityChatCompletionResponse(BaseModel):
86
81
 
87
82
 
88
83
  class SearchResponse(BaseModel):
89
- """
90
- Represents the response from a search query.
84
+ """Represents the response from a search query.
91
85
 
92
86
  Attributes:
93
87
  content (Optional[str]): The textual content returned from the search.
@@ -95,14 +89,13 @@ class SearchResponse(BaseModel):
95
89
  error (Optional[str]): An error message if the search failed.
96
90
  """
97
91
 
98
- content: Union[str, None]
99
- citations: Union[list[str], None]
100
- error: Union[str, None]
92
+ content: str | None
93
+ citations: list[str] | None
94
+ error: str | None
101
95
 
102
96
 
103
97
  class PerplexitySearchTool(Tool):
104
- """
105
- Tool for interacting with the Perplexity AI search API.
98
+ """Tool for interacting with the Perplexity AI search API.
106
99
 
107
100
  This tool uses the Perplexity API to perform web search, news search,
108
101
  and conversational search, returning concise and precise responses.
@@ -118,12 +111,11 @@ class PerplexitySearchTool(Tool):
118
111
  def __init__(
119
112
  self,
120
113
  model: str = "sonar",
121
- api_key: Optional[str] = None,
114
+ api_key: str | None = None,
122
115
  max_tokens: int = 1000,
123
- search_domain_filter: Optional[list[str]] = None,
116
+ search_domain_filter: list[str] | None = None,
124
117
  ):
125
- """
126
- Initializes a new instance of the PerplexitySearchTool.
118
+ """Initializes a new instance of the PerplexitySearchTool.
127
119
 
128
120
  Args:
129
121
  model (str, optional): The model to use. Defaults to "sonar".
@@ -150,10 +142,9 @@ class PerplexitySearchTool(Tool):
150
142
 
151
143
  @staticmethod
152
144
  def _validate_tool_config(
153
- model: str, api_key: Union[str, None], max_tokens: int, search_domain_filter: Union[list[str], None]
145
+ model: str, api_key: str | None, max_tokens: int, search_domain_filter: list[str] | None
154
146
  ) -> None:
155
- """
156
- Validates the configuration parameters for the search tool.
147
+ """Validates the configuration parameters for the search tool.
157
148
 
158
149
  Args:
159
150
  model (str): The model to use.
@@ -175,8 +166,7 @@ class PerplexitySearchTool(Tool):
175
166
  raise ValueError("search_domain_filter must be a list")
176
167
 
177
168
  def _execute_query(self, payload: dict[str, Any]) -> "PerplexityChatCompletionResponse":
178
- """
179
- Executes a query by sending a POST request to the Perplexity API.
169
+ """Executes a query by sending a POST request to the Perplexity API.
180
170
 
181
171
  Args:
182
172
  payload (dict[str, Any]): The payload to send in the API request.
@@ -223,8 +213,7 @@ class PerplexitySearchTool(Tool):
223
213
  return perp_resp
224
214
 
225
215
  def search(self, query: str) -> "SearchResponse":
226
- """
227
- Perform a search query using the Perplexity AI API.
216
+ """Perform a search query using the Perplexity AI API.
228
217
 
229
218
  Constructs the payload, executes the query, and parses the response to return
230
219
  a concise search result along with any provided citations.
@@ -14,7 +14,8 @@ import json
14
14
  import logging
15
15
  import time
16
16
  import warnings
17
- from typing import Annotated, Any, Callable, Dict, List, Optional, Tuple, Type, Union
17
+ from collections.abc import Callable
18
+ from typing import Annotated, Any
18
19
 
19
20
  from pydantic import BaseModel, ConfigDict, Field, ValidationError
20
21
 
@@ -61,13 +62,13 @@ class ExecutionAttempt(BaseModel):
61
62
 
62
63
  model_config = ConfigDict(arbitrary_types_allowed=True)
63
64
  timestamp: float = Field(default_factory=time.time)
64
- attempt_args: List[Any] = Field(default_factory=list)
65
- attempt_kwargs: Dict[str, Any] = Field(default_factory=dict)
66
- hypothesis: Optional[str] = None
67
- error: Optional[str] = None
68
- result_data: Optional[Any] = None
69
- result_str: Optional[str] = None
70
- validation: Optional[ValidationResult] = None
65
+ attempt_args: list[Any] = Field(default_factory=list)
66
+ attempt_kwargs: dict[str, Any] = Field(default_factory=dict)
67
+ hypothesis: str | None = None
68
+ error: str | None = None
69
+ result_data: Any | None = None
70
+ result_str: str | None = None
71
+ validation: ValidationResult | None = None
71
72
 
72
73
  @property
73
74
  def did_execute_successfully(self) -> bool:
@@ -87,14 +88,12 @@ class ReliableToolContext(BaseModel):
87
88
  task: str
88
89
  reliable_tool_name: str
89
90
  start_time: float = Field(default_factory=time.time)
90
- dynamic_validation_input: Optional[str] = None
91
- attempts: List[ExecutionAttempt] = Field(default_factory=list)
92
- initial_messages: Optional[List[dict[str, Any]]] = Field(
91
+ dynamic_validation_input: str | None = None
92
+ attempts: list[ExecutionAttempt] = Field(default_factory=list)
93
+ initial_messages: list[dict[str, Any]] | None = Field(
93
94
  default=None, description="Initial messages provided to the tool run."
94
95
  )
95
- initial_ground_truth: Optional[List[str]] = Field(
96
- default=None, description="Initial ground truth strings provided."
97
- )
96
+ initial_ground_truth: list[str] | None = Field(default=None, description="Initial ground truth strings provided.")
98
97
 
99
98
  @property
100
99
  def attempt_count(self) -> int:
@@ -102,7 +101,7 @@ class ReliableToolContext(BaseModel):
102
101
  return len(self.attempts)
103
102
 
104
103
  @property
105
- def latest_attempt(self) -> Optional[ExecutionAttempt]:
104
+ def latest_attempt(self) -> ExecutionAttempt | None:
106
105
  """Return the most recent attempt, if any."""
107
106
  return self.attempts[-1] if self.attempts else None
108
107
 
@@ -143,8 +142,8 @@ class SuccessfulExecutionParameters(BaseModel):
143
142
  """Holds the arguments of a successful tool function execution."""
144
143
 
145
144
  model_config = ConfigDict(arbitrary_types_allowed=True)
146
- attempt_args: List[Any]
147
- attempt_kwargs: Dict[str, Any]
145
+ attempt_args: list[Any]
146
+ attempt_kwargs: dict[str, Any]
148
147
 
149
148
 
150
149
  class ToolExecutionDetails(BaseModel):
@@ -153,14 +152,14 @@ class ToolExecutionDetails(BaseModel):
153
152
  model_config = ConfigDict(arbitrary_types_allowed=True)
154
153
  task: str
155
154
  is_overall_successful: bool
156
- failure_reason: Optional[str] = None
157
- successful_parameters: Optional[SuccessfulExecutionParameters] = None
155
+ failure_reason: str | None = None
156
+ successful_parameters: SuccessfulExecutionParameters | None = None
158
157
  final_tool_context: ReliableToolContext
159
158
 
160
159
 
161
160
  def _configure_llm_for_structured_output(
162
- llm_config: Optional[Union[LLMConfig, dict[str, Any]]], structured_output_type: Type[BaseModel]
163
- ) -> Union[LLMConfig, dict[str, Any]]: # Return type changed, False is no longer a valid return
161
+ llm_config: LLMConfig | dict[str, Any] | None, structured_output_type: type[BaseModel]
162
+ ) -> LLMConfig | dict[str, Any]: # Return type changed, False is no longer a valid return
164
163
  """Configure LLM config for structured output using a Pydantic model."""
165
164
  if llm_config is None or llm_config is False:
166
165
  raise ValueError("LLMConfig cannot be None or False for structured output.")
@@ -174,7 +173,7 @@ def _configure_llm_for_structured_output(
174
173
 
175
174
  response_format_set = False
176
175
 
177
- def _set_format_and_remove_conflicts(config_item: Union[LLMConfig, Dict[str, Any]]) -> None:
176
+ def _set_format_and_remove_conflicts(config_item: LLMConfig | dict[str, Any]) -> None:
178
177
  nonlocal response_format_set
179
178
  conflicting_keys = ["tools", "tool_choice", "functions"]
180
179
  removed_keys = []
@@ -192,7 +191,7 @@ def _configure_llm_for_structured_output(
192
191
  for key in conflicting_keys:
193
192
  if hasattr(config_item, key) and getattr(config_item, key, None):
194
193
  # Try setting to None or empty list/dict as appropriate
195
- default_empty: Optional[List[str]] = [] if key in ["tools", "functions"] else None
194
+ default_empty: list[str] | None = [] if key in ["tools", "functions"] else None
196
195
  setattr(config_item, key, default_empty)
197
196
  removed_keys.append(key)
198
197
  else:
@@ -243,7 +242,7 @@ def _configure_llm_for_structured_output(
243
242
  return llm_config_obj
244
243
 
245
244
 
246
- def _get_last_non_empty_message_content(messages: Optional[List[dict[str, Any]]]) -> Optional[str]:
245
+ def _get_last_non_empty_message_content(messages: list[dict[str, Any]] | None) -> str | None:
247
246
  """Get content of the last message with non-empty content."""
248
247
  if not messages:
249
248
  return None
@@ -342,7 +341,7 @@ Current Task:
342
341
 
343
342
 
344
343
  def get_validator_prompt(
345
- task: str, base_validator_system_message: str, dynamic_validation_addition: Optional[str] = None
344
+ task: str, base_validator_system_message: str, dynamic_validation_addition: str | None = None
346
345
  ) -> str:
347
346
  """Generate the system prompt for the internal validator agent."""
348
347
  dynamic_section = (
@@ -517,7 +516,7 @@ def reliable_function_wrapper(
517
516
  class ReliableToolError(Exception):
518
517
  """Custom exception for errors during ReliableTool execution."""
519
518
 
520
- def __init__(self, message: str, final_context: Optional[ReliableToolContext] = None):
519
+ def __init__(self, message: str, final_context: ReliableToolContext | None = None):
521
520
  super().__init__(message)
522
521
  self.final_context = final_context
523
522
 
@@ -529,19 +528,18 @@ class ReliableTool(Tool):
529
528
  def __init__(
530
529
  self,
531
530
  name: str,
532
- func_or_tool: Union[Callable[..., Any], Tool],
533
- runner_llm_config: Union[LLMConfig, dict[str, Any]],
534
- validator_llm_config: Union[LLMConfig, dict[str, Any]],
535
- description: Optional[str] = None,
531
+ func_or_tool: Callable[..., Any] | Tool,
532
+ runner_llm_config: LLMConfig | dict[str, Any],
533
+ validator_llm_config: LLMConfig | dict[str, Any],
534
+ description: str | None = None,
536
535
  system_message_addition_for_tool_calling: str = "",
537
536
  system_message_addition_for_result_validation: str = "",
538
537
  max_tool_invocations: int = 3,
539
538
  enable_dynamic_validation: bool = False,
540
- messages: Optional[List[dict[str, Any]]] = None,
541
- ground_truth: Optional[List[str]] = None,
539
+ messages: list[dict[str, Any]] | None = None,
540
+ ground_truth: list[str] | None = None,
542
541
  ) -> None:
543
- """
544
- A ReliableTool wraps an existing function or tool.
542
+ """A ReliableTool wraps an existing function or tool.
545
543
  When the ReliableTool is invoked, it kicks off an internal Group Chat where a Runner
546
544
  and Validator agent will iteratively invoke the wrapped function or tool until
547
545
  *the output of a single invocation of the original function or tool satisfies the provided validation criteria.*
@@ -703,9 +701,7 @@ class ReliableTool(Tool):
703
701
  if not is_async:
704
702
  if enable_dynamic:
705
703
 
706
- def sync_entry_point_with_validation(
707
- task: str, validation_prompt_addition: Optional[str] = None
708
- ) -> Any:
704
+ def sync_entry_point_with_validation(task: str, validation_prompt_addition: str | None = None) -> Any:
709
705
  return self.run(task=task, validation_prompt_addition=validation_prompt_addition)
710
706
 
711
707
  return sync_entry_point_with_validation
@@ -719,7 +715,7 @@ class ReliableTool(Tool):
719
715
  if enable_dynamic:
720
716
 
721
717
  async def async_entry_point_with_validation(
722
- task: str, validation_prompt_addition: Optional[str] = None
718
+ task: str, validation_prompt_addition: str | None = None
723
719
  ) -> Any:
724
720
  return await self.a_run(task=task, validation_prompt_addition=validation_prompt_addition)
725
721
 
@@ -731,9 +727,7 @@ class ReliableTool(Tool):
731
727
 
732
728
  return async_entry_point_without_validation
733
729
 
734
- def _extract_func_details(
735
- self, func_or_tool: Union[Callable[..., Any], Tool]
736
- ) -> Tuple[Callable[..., Any], str, str]:
730
+ def _extract_func_details(self, func_or_tool: Callable[..., Any] | Tool) -> tuple[Callable[..., Any], str, str]:
737
731
  default_desc_template = "Executes the '{name}' function."
738
732
  if isinstance(func_or_tool, Tool):
739
733
  func = getattr(func_or_tool, "func", None)
@@ -806,8 +800,8 @@ class ReliableTool(Tool):
806
800
  self._runner.register_hook(hookable_method="process_message_before_send", hook=self._ensure_function_call_hook)
807
801
 
808
802
  def _validator_structured_output_hook(
809
- self, sender: Agent, message: Union[dict[str, Any], str], recipient: Agent, silent: bool
810
- ) -> Union[dict[str, Any], str]:
803
+ self, sender: Agent, message: dict[str, Any] | str, recipient: Agent, silent: bool
804
+ ) -> dict[str, Any] | str:
811
805
  if not isinstance(message, str):
812
806
  logger.error(
813
807
  f"Validator Hook: Expected a JSON string message from LLM, but got {type(message)}. Content: {str(message)[:200]}"
@@ -885,8 +879,8 @@ class ReliableTool(Tool):
885
879
  return final_messages
886
880
 
887
881
  def _ensure_function_call_hook(
888
- self, sender: Agent, message: Union[dict[str, Any], str], recipient: Agent, silent: bool
889
- ) -> Union[dict[str, Any], str]:
882
+ self, sender: Agent, message: dict[str, Any] | str, recipient: Agent, silent: bool
883
+ ) -> dict[str, Any] | str:
890
884
  if sender.name != self._runner_name:
891
885
  return message
892
886
 
@@ -941,8 +935,8 @@ class ReliableTool(Tool):
941
935
  self,
942
936
  task: str,
943
937
  initial_context_vars: ContextVariables, # Renamed for clarity
944
- dynamic_validation_str: Optional[str] = None,
945
- ) -> Tuple[ChatResult, ContextVariables, Agent]:
938
+ dynamic_validation_str: str | None = None,
939
+ ) -> tuple[ChatResult, ContextVariables, Agent]:
946
940
  internal_tool_name = f"{self.INTERNAL_TOOL_NAME_PREFIX}{self._original_func_name}"
947
941
 
948
942
  # update_system_message should not fail if agent is properly initialized
@@ -1008,9 +1002,9 @@ class ReliableTool(Tool):
1008
1002
  self,
1009
1003
  task: str,
1010
1004
  current_context_variables: ContextVariables,
1011
- validation_prompt_addition: Optional[str] = None,
1012
- messages: Optional[list[dict[str, Any]]] = None,
1013
- ground_truth: Optional[List[str]] = None,
1005
+ validation_prompt_addition: str | None = None,
1006
+ messages: list[dict[str, Any]] | None = None,
1007
+ ground_truth: list[str] | None = None,
1014
1008
  ) -> ReliableToolContext:
1015
1009
  """Initializes or updates the ReliableToolContext for the current run."""
1016
1010
  effective_messages = copy.deepcopy(messages) if messages is not None else self._init_messages
@@ -1029,10 +1023,10 @@ class ReliableTool(Tool):
1029
1023
  def _process_run(
1030
1024
  self,
1031
1025
  task: str,
1032
- context_variables: Optional[ContextVariables] = None,
1033
- validation_prompt_addition: Optional[str] = None,
1034
- messages: Optional[list[dict[str, Any]]] = None,
1035
- ground_truth: Optional[List[str]] = None,
1026
+ context_variables: ContextVariables | None = None,
1027
+ validation_prompt_addition: str | None = None,
1028
+ messages: list[dict[str, Any]] | None = None,
1029
+ ground_truth: list[str] | None = None,
1036
1030
  ) -> Any:
1037
1031
  current_context_variables = context_variables if context_variables is not None else ContextVariables()
1038
1032
  if not isinstance(current_context_variables, ContextVariables):
@@ -1082,10 +1076,10 @@ class ReliableTool(Tool):
1082
1076
  def run(
1083
1077
  self,
1084
1078
  task: str,
1085
- context_variables: Optional[ContextVariables] = None,
1086
- validation_prompt_addition: Optional[str] = None,
1087
- messages: Optional[list[dict[str, Any]]] = None,
1088
- ground_truth: Optional[List[str]] = None,
1079
+ context_variables: ContextVariables | None = None,
1080
+ validation_prompt_addition: str | None = None,
1081
+ messages: list[dict[str, Any]] | None = None,
1082
+ ground_truth: list[str] | None = None,
1089
1083
  ) -> Any:
1090
1084
  if self._is_original_func_async:
1091
1085
  raise TypeError(f"Sync 'run()' called for async tool '{self.name}'. Use 'a_run()'.")
@@ -1100,10 +1094,10 @@ class ReliableTool(Tool):
1100
1094
  async def a_run(
1101
1095
  self,
1102
1096
  task: str,
1103
- context_variables: Optional[ContextVariables] = None,
1104
- validation_prompt_addition: Optional[str] = None,
1105
- messages: Optional[list[dict[str, Any]]] = None,
1106
- ground_truth: Optional[List[str]] = None,
1097
+ context_variables: ContextVariables | None = None,
1098
+ validation_prompt_addition: str | None = None,
1099
+ messages: list[dict[str, Any]] | None = None,
1100
+ ground_truth: list[str] | None = None,
1107
1101
  ) -> Any:
1108
1102
  if not self._is_original_func_async:
1109
1103
  warnings.warn(
@@ -1127,10 +1121,10 @@ class ReliableTool(Tool):
1127
1121
  def _process_run_with_details(
1128
1122
  self,
1129
1123
  task: str,
1130
- context_variables: Optional[ContextVariables] = None,
1131
- validation_prompt_addition: Optional[str] = None,
1132
- messages: Optional[list[dict[str, Any]]] = None,
1133
- ground_truth: Optional[List[str]] = None,
1124
+ context_variables: ContextVariables | None = None,
1125
+ validation_prompt_addition: str | None = None,
1126
+ messages: list[dict[str, Any]] | None = None,
1127
+ ground_truth: list[str] | None = None,
1134
1128
  ) -> ToolExecutionDetails:
1135
1129
  current_context_variables = context_variables if context_variables is not None else ContextVariables()
1136
1130
  if not isinstance(current_context_variables, ContextVariables):
@@ -1251,10 +1245,10 @@ class ReliableTool(Tool):
1251
1245
  def run_and_get_details(
1252
1246
  self,
1253
1247
  task: str,
1254
- context_variables: Optional[ContextVariables] = None,
1255
- validation_prompt_addition: Optional[str] = None,
1256
- messages: Optional[list[dict[str, Any]]] = None,
1257
- ground_truth: Optional[List[str]] = None,
1248
+ context_variables: ContextVariables | None = None,
1249
+ validation_prompt_addition: str | None = None,
1250
+ messages: list[dict[str, Any]] | None = None,
1251
+ ground_truth: list[str] | None = None,
1258
1252
  ) -> ToolExecutionDetails:
1259
1253
  if self._is_original_func_async:
1260
1254
  raise TypeError(
@@ -1272,10 +1266,10 @@ class ReliableTool(Tool):
1272
1266
  async def a_run_and_get_details(
1273
1267
  self,
1274
1268
  task: str,
1275
- context_variables: Optional[ContextVariables] = None,
1276
- validation_prompt_addition: Optional[str] = None,
1277
- messages: Optional[list[dict[str, Any]]] = None,
1278
- ground_truth: Optional[List[str]] = None,
1269
+ context_variables: ContextVariables | None = None,
1270
+ validation_prompt_addition: str | None = None,
1271
+ messages: list[dict[str, Any]] | None = None,
1272
+ ground_truth: list[str] | None = None,
1279
1273
  ) -> ToolExecutionDetails:
1280
1274
  if not self._is_original_func_async:
1281
1275
  warnings.warn(