ag2 0.9.7__py3-none-any.whl → 0.9.9__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.7.dist-info → ag2-0.9.9.dist-info}/METADATA +102 -75
  2. ag2-0.9.9.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 +292 -290
  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 +60 -63
  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 +38 -27
  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 +2 -1
  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 +113 -139
  186. autogen/oai/client_utils.py +3 -3
  187. autogen/oai/cohere.py +34 -11
  188. autogen/oai/gemini.py +39 -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 +19 -9
  200. autogen/oai/openai_responses.py +40 -17
  201. autogen/oai/openai_utils.py +48 -38
  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 +8 -6
  230. autogen/types.py +2 -2
  231. autogen/version.py +1 -1
  232. ag2-0.9.7.dist-info/RECORD +0 -421
  233. autogen/llm_config.py +0 -385
  234. {ag2-0.9.7.dist-info → ag2-0.9.9.dist-info}/WHEEL +0 -0
  235. {ag2-0.9.7.dist-info → ag2-0.9.9.dist-info}/licenses/LICENSE +0 -0
  236. {ag2-0.9.7.dist-info → ag2-0.9.9.dist-info}/licenses/NOTICE.md +0 -0
@@ -0,0 +1,384 @@
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 functools
6
+ import json
7
+ import re
8
+ from collections.abc import Iterable
9
+ from contextvars import ContextVar
10
+ from pathlib import Path
11
+ from typing import Annotated, Any, Literal, TypeAlias
12
+
13
+ from pydantic import BaseModel, ConfigDict, Field
14
+
15
+ from autogen.oai.anthropic import AnthropicEntryDict, AnthropicLLMConfigEntry
16
+ from autogen.oai.bedrock import BedrockEntryDict, BedrockLLMConfigEntry
17
+ from autogen.oai.cerebras import CerebrasEntryDict, CerebrasLLMConfigEntry
18
+ from autogen.oai.client import (
19
+ AzureOpenAIEntryDict,
20
+ AzureOpenAILLMConfigEntry,
21
+ DeepSeekEntyDict,
22
+ DeepSeekLLMConfigEntry,
23
+ OpenAIEntryDict,
24
+ OpenAILLMConfigEntry,
25
+ OpenAIResponsesLLMConfigEntry,
26
+ )
27
+ from autogen.oai.cohere import CohereEntryDict, CohereLLMConfigEntry
28
+ from autogen.oai.gemini import GeminiEntryDict, GeminiLLMConfigEntry
29
+ from autogen.oai.groq import GroqEntryDict, GroqLLMConfigEntry
30
+ from autogen.oai.mistral import MistralEntryDict, MistralLLMConfigEntry
31
+ from autogen.oai.ollama import OllamaEntryDict, OllamaLLMConfigEntry
32
+ from autogen.oai.together import TogetherEntryDict, TogetherLLMConfigEntry
33
+
34
+ from ..doc_utils import export_module
35
+ from .entry import ApplicationConfig, LLMConfigEntry
36
+
37
+
38
+ # Meta class to allow LLMConfig.current and LLMConfig.default to be used as class properties
39
+ class MetaLLMConfig(type):
40
+ def __init__(cls, *args: Any, **kwargs: Any) -> None:
41
+ pass
42
+
43
+ @property
44
+ def current(cls) -> "LLMConfig":
45
+ current_llm_config = LLMConfig.get_current_llm_config(llm_config=None)
46
+ if current_llm_config is None:
47
+ raise ValueError("No current LLMConfig set. Are you inside a context block?")
48
+ return current_llm_config # type: ignore[return-value]
49
+
50
+ @property
51
+ def default(cls) -> "LLMConfig":
52
+ return cls.current
53
+
54
+
55
+ ConfigItem: TypeAlias = (
56
+ LLMConfigEntry
57
+ | AnthropicEntryDict
58
+ | BedrockEntryDict
59
+ | CerebrasEntryDict
60
+ | CohereEntryDict
61
+ | AzureOpenAIEntryDict
62
+ | OpenAIEntryDict
63
+ | DeepSeekEntyDict
64
+ | MistralEntryDict
65
+ | GroqEntryDict
66
+ | OllamaEntryDict
67
+ | GeminiEntryDict
68
+ | TogetherEntryDict
69
+ | dict[str, Any]
70
+ )
71
+
72
+
73
+ @export_module("autogen")
74
+ class LLMConfig(metaclass=MetaLLMConfig):
75
+ _current_llm_config: ContextVar["LLMConfig"] = ContextVar("current_llm_config")
76
+
77
+ def __init__(
78
+ self,
79
+ *,
80
+ top_p: float | None = None,
81
+ temperature: float | None = None,
82
+ max_tokens: int | None = None,
83
+ config_list: Iterable[ConfigItem] | dict[str, Any] = (),
84
+ check_every_ms: int | None = None,
85
+ allow_format_str_template: bool | None = None,
86
+ response_format: str | dict[str, Any] | BaseModel | type[BaseModel] | None = None,
87
+ timeout: int | None = None,
88
+ seed: int | None = None,
89
+ cache_seed: int | None = None,
90
+ parallel_tool_calls: bool | None = None,
91
+ tools: Iterable[Any] = (),
92
+ functions: Iterable[Any] = (),
93
+ routing_method: Literal["fixed_order", "round_robin"] | None = None,
94
+ **kwargs: Any,
95
+ ) -> None:
96
+ """Initializes the LLMConfig object.
97
+
98
+ Args:
99
+ config_list: A list of LLM configuration entries or dictionaries.
100
+ temperature: The sampling temperature for LLM generation.
101
+ check_every_ms: The interval (in milliseconds) to check for updates
102
+ allow_format_str_template: Whether to allow format string templates.
103
+ response_format: The format of the response (e.g., JSON, text).
104
+ timeout: The timeout for LLM requests in seconds.
105
+ seed: The random seed for reproducible results.
106
+ cache_seed: The seed for caching LLM responses.
107
+ parallel_tool_calls: Whether to enable parallel tool calls.
108
+ tools: A list of tools available for the LLM.
109
+ functions: A list of functions available for the LLM.
110
+ max_tokens: The maximum number of tokens to generate.
111
+ top_p: The nucleus sampling probability.
112
+ routing_method: The method used to route requests (e.g., fixed_order, round_robin).
113
+ **kwargs: Additional keyword arguments for future extensions.
114
+
115
+ Examples:
116
+ ```python
117
+ # Example 1: create config from `kwargs` options
118
+ config = LLMConfig(
119
+ model="gpt-4o-mini",
120
+ api_key=os.environ["OPENAI_API_KEY"],
121
+ )
122
+
123
+ # Example 2: create config from `config_list` dictionary
124
+ config = LLMConfig(
125
+ config_list={
126
+ "model": "gpt-4o-mini",
127
+ "api_key": os.environ["OPENAI_API_KEY"],
128
+ }
129
+ )
130
+
131
+ # Example 3: create config from `config_list` list
132
+ config = LLMConfig(
133
+ config_list=[
134
+ {
135
+ "model": "gpt-4o-mini",
136
+ "api_key": os.environ["OPENAI_API_KEY"],
137
+ },
138
+ {
139
+ "model": "gpt-4",
140
+ "api_key": os.environ["OPENAI_API_KEY"],
141
+ },
142
+ ]
143
+ )
144
+ ```
145
+ """
146
+ app_config = ApplicationConfig(
147
+ max_tokens=max_tokens,
148
+ top_p=top_p,
149
+ temperature=temperature,
150
+ )
151
+
152
+ application_level_options = app_config.model_dump(exclude_none=True)
153
+
154
+ final_config_list: list[LLMConfigEntry | dict[str, Any]] = []
155
+
156
+ if isinstance(config_list, dict):
157
+ config_list = [config_list]
158
+
159
+ for c in filter(bool, (*config_list, kwargs)):
160
+ if isinstance(c, LLMConfigEntry):
161
+ final_config_list.append(c.apply_application_config(app_config))
162
+ continue
163
+
164
+ else:
165
+ final_config_list.append({
166
+ "api_type": "openai", # default api_type
167
+ **application_level_options,
168
+ **c,
169
+ })
170
+
171
+ self._model = _LLMConfig(
172
+ **application_level_options,
173
+ config_list=final_config_list,
174
+ check_every_ms=check_every_ms,
175
+ seed=seed,
176
+ allow_format_str_template=allow_format_str_template,
177
+ response_format=response_format,
178
+ timeout=timeout,
179
+ cache_seed=cache_seed,
180
+ tools=tools or [],
181
+ functions=functions or [],
182
+ parallel_tool_calls=parallel_tool_calls,
183
+ routing_method=routing_method,
184
+ )
185
+
186
+ # used by BaseModel to create instance variables
187
+ def __enter__(self) -> "LLMConfig":
188
+ # Store previous context and set self as current
189
+ self._token = LLMConfig._current_llm_config.set(self)
190
+ return self
191
+
192
+ def __exit__(self, exc_type: type[Exception], exc_val: Exception, exc_tb: Any) -> None:
193
+ LLMConfig._current_llm_config.reset(self._token)
194
+
195
+ @classmethod
196
+ def get_current_llm_config(cls, llm_config: "LLMConfig | None" = None) -> "LLMConfig | None":
197
+ if llm_config is not None:
198
+ return llm_config
199
+ try:
200
+ return (LLMConfig._current_llm_config.get()).copy()
201
+ except LookupError:
202
+ return None
203
+
204
+ def _satisfies_criteria(self, value: Any, criteria_values: Any) -> bool:
205
+ if value is None:
206
+ return False
207
+
208
+ if isinstance(value, list):
209
+ return bool(set(value) & set(criteria_values)) # Non-empty intersection
210
+ else:
211
+ return value in criteria_values
212
+
213
+ @classmethod
214
+ def from_json(
215
+ cls,
216
+ *,
217
+ env: str | None = None,
218
+ path: str | Path | None = None,
219
+ file_location: str | None = None,
220
+ **kwargs: Any,
221
+ ) -> "LLMConfig":
222
+ from autogen.oai.openai_utils import config_list_from_json
223
+
224
+ if env is None and path is None:
225
+ raise ValueError("Either 'env' or 'path' must be provided")
226
+ if env is not None and path is not None:
227
+ raise ValueError("Only one of 'env' or 'path' can be provided")
228
+
229
+ config_list = config_list_from_json(
230
+ env_or_file=env if env is not None else str(path), file_location=file_location
231
+ )
232
+ return LLMConfig(config_list=config_list, **kwargs)
233
+
234
+ def where(self, *, exclude: bool = False, **kwargs: Any) -> "LLMConfig":
235
+ from autogen.oai.openai_utils import filter_config
236
+
237
+ filtered_config_list = filter_config(config_list=self.config_list, filter_dict=kwargs, exclude=exclude)
238
+ if len(filtered_config_list) == 0:
239
+ raise ValueError(f"No config found that satisfies the filter criteria: {kwargs}")
240
+
241
+ kwargs = self.model_dump()
242
+ kwargs["config_list"] = filtered_config_list
243
+
244
+ return LLMConfig(**kwargs)
245
+
246
+ # @functools.wraps(BaseModel.model_dump)
247
+ def model_dump(self, *args: Any, exclude_none: bool = True, **kwargs: Any) -> dict[str, Any]:
248
+ d = self._model.model_dump(*args, exclude_none=exclude_none, **kwargs)
249
+ return {k: v for k, v in d.items() if not (isinstance(v, list) and len(v) == 0)}
250
+
251
+ # @functools.wraps(BaseModel.model_dump_json)
252
+ def model_dump_json(self, *args: Any, exclude_none: bool = True, **kwargs: Any) -> str:
253
+ # return self._model.model_dump_json(*args, exclude_none=exclude_none, **kwargs)
254
+ d = self.model_dump(*args, exclude_none=exclude_none, **kwargs)
255
+ return json.dumps(d)
256
+
257
+ # @functools.wraps(BaseModel.model_validate)
258
+ def model_validate(self, *args: Any, **kwargs: Any) -> Any:
259
+ return self._model.model_validate(*args, **kwargs)
260
+
261
+ @functools.wraps(BaseModel.model_validate_json)
262
+ def model_validate_json(self, *args: Any, **kwargs: Any) -> Any:
263
+ return self._model.model_validate_json(*args, **kwargs)
264
+
265
+ @functools.wraps(BaseModel.model_validate_strings)
266
+ def model_validate_strings(self, *args: Any, **kwargs: Any) -> Any:
267
+ return self._model.model_validate_strings(*args, **kwargs)
268
+
269
+ def __eq__(self, value: Any) -> bool:
270
+ if not isinstance(value, LLMConfig):
271
+ return NotImplemented
272
+ return self._model == value._model
273
+
274
+ def _getattr(self, o: object, name: str) -> Any:
275
+ val = getattr(o, name)
276
+ return val
277
+
278
+ def get(self, key: str, default: Any | None = None) -> Any:
279
+ val = getattr(self._model, key, default)
280
+ return val
281
+
282
+ def __getitem__(self, key: str) -> Any:
283
+ try:
284
+ return self._getattr(self._model, key)
285
+ except AttributeError:
286
+ raise KeyError(f"Key '{key}' not found in {self.__class__.__name__}")
287
+
288
+ def __setitem__(self, key: str, value: Any) -> None:
289
+ try:
290
+ setattr(self._model, key, value)
291
+ except ValueError:
292
+ raise ValueError(f"'{self.__class__.__name__}' object has no field '{key}'")
293
+
294
+ def __getattr__(self, name: Any) -> Any:
295
+ try:
296
+ return self._getattr(self._model, name)
297
+ except AttributeError:
298
+ raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'")
299
+
300
+ def __setattr__(self, name: str, value: Any) -> None:
301
+ if name == "_model":
302
+ object.__setattr__(self, name, value)
303
+ else:
304
+ setattr(self._model, name, value)
305
+
306
+ def __contains__(self, key: str) -> bool:
307
+ return hasattr(self._model, key)
308
+
309
+ def __repr__(self) -> str:
310
+ d = self.model_dump()
311
+ r = [f"{k}={repr(v)}" for k, v in d.items()]
312
+
313
+ s = f"LLMConfig({', '.join(r)})"
314
+ # Replace any keys ending with 'key' or 'token' values with stars for security
315
+ s = re.sub(
316
+ r"(['\"])(\w*(key|token))\1:\s*(['\"])([^'\"]*)(?:\4)", r"\1\2\1: \4**********\4", s, flags=re.IGNORECASE
317
+ )
318
+ return s
319
+
320
+ def __copy__(self) -> "LLMConfig":
321
+ return LLMConfig(**self.model_dump())
322
+
323
+ def __deepcopy__(self, memo: dict[int, Any] | None = None) -> "LLMConfig":
324
+ return self.__copy__()
325
+
326
+ def copy(self) -> "LLMConfig":
327
+ return self.__copy__()
328
+
329
+ def deepcopy(self, memo: dict[int, Any] | None = None) -> "LLMConfig":
330
+ return self.__deepcopy__(memo)
331
+
332
+ def __str__(self) -> str:
333
+ return repr(self)
334
+
335
+ def items(self) -> Iterable[tuple[str, Any]]:
336
+ d = self.model_dump()
337
+ return d.items()
338
+
339
+ def keys(self) -> Iterable[str]:
340
+ d = self.model_dump()
341
+ return d.keys()
342
+
343
+ def values(self) -> Iterable[Any]:
344
+ d = self.model_dump()
345
+ return d.values()
346
+
347
+ _base_model_classes: dict[tuple[type["LLMConfigEntry"], ...], type[BaseModel]] = {}
348
+
349
+
350
+ class _LLMConfig(ApplicationConfig):
351
+ check_every_ms: int | None
352
+ seed: int | None
353
+ allow_format_str_template: bool | None
354
+ response_format: str | dict[str, Any] | BaseModel | type[BaseModel] | None
355
+ timeout: int | None
356
+ cache_seed: int | None
357
+ parallel_tool_calls: bool | None
358
+
359
+ tools: list[Any]
360
+ functions: list[Any]
361
+
362
+ config_list: list[ # type: ignore[valid-type]
363
+ Annotated[
364
+ AnthropicLLMConfigEntry
365
+ | CerebrasLLMConfigEntry
366
+ | BedrockLLMConfigEntry
367
+ | AzureOpenAILLMConfigEntry
368
+ | DeepSeekLLMConfigEntry
369
+ | OpenAILLMConfigEntry
370
+ | OpenAIResponsesLLMConfigEntry
371
+ | CohereLLMConfigEntry
372
+ | GeminiLLMConfigEntry
373
+ | GroqLLMConfigEntry
374
+ | MistralLLMConfigEntry
375
+ | OllamaLLMConfigEntry
376
+ | TogetherLLMConfigEntry,
377
+ Field(discriminator="api_type"),
378
+ ],
379
+ ] = Field(..., min_length=1)
380
+
381
+ routing_method: Literal["fixed_order", "round_robin"] | None
382
+
383
+ # Following field is configuration for pydantic to disallow extra fields
384
+ model_config = ConfigDict(extra="forbid")
@@ -0,0 +1,154 @@
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 re
6
+ from abc import ABC, abstractmethod
7
+ from collections.abc import Iterable, Mapping
8
+ from typing import Any
9
+
10
+ from httpx import Client as httpxClient
11
+ from pydantic import BaseModel, ConfigDict, Field, HttpUrl, SecretStr, ValidationInfo, field_serializer, field_validator
12
+ from typing_extensions import Required, TypedDict
13
+
14
+ from .client import ModelClient
15
+
16
+
17
+ class LLMConfigEntryDict(TypedDict, total=False):
18
+ api_type: Required[str]
19
+ model: str
20
+ max_tokens: int | None
21
+ top_p: float | None
22
+ temperature: float | None
23
+
24
+ api_key: SecretStr | None
25
+ api_version: str | None
26
+ base_url: HttpUrl | None
27
+ voice: str | None
28
+ http_client: httpxClient | None
29
+ model_client_cls: str | None
30
+ response_format: str | dict[str, Any] | BaseModel | type[BaseModel] | None
31
+ default_headers: Mapping[str, Any] | None
32
+ tags: list[str]
33
+
34
+
35
+ class ApplicationConfig(BaseModel):
36
+ max_tokens: int | None = Field(default=None, ge=0)
37
+ top_p: float | None = Field(default=None, gt=0, lt=1)
38
+ temperature: float | None = Field(default=None, ge=0, le=1)
39
+
40
+ @field_validator("top_p", mode="before")
41
+ @classmethod
42
+ def check_top_p(cls, v: float | None, info: ValidationInfo) -> float | None:
43
+ if v is not None and info.data.get("temperature") is not None:
44
+ raise ValueError("temperature and top_p cannot be set at the same time.")
45
+ return v
46
+
47
+ @field_validator("temperature", mode="before")
48
+ @classmethod
49
+ def check_temperature(cls, v: float | None, info: ValidationInfo) -> float | None:
50
+ if v is not None and info.data.get("top_p") is not None:
51
+ raise ValueError("temperature and top_p cannot be set at the same time.")
52
+ return v
53
+
54
+
55
+ class LLMConfigEntry(ApplicationConfig, ABC):
56
+ api_type: str
57
+ model: str = Field(..., min_length=1)
58
+
59
+ api_key: SecretStr | None = None
60
+ api_version: str | None = None
61
+ base_url: HttpUrl | None = None
62
+ voice: str | None = None
63
+ model_client_cls: str | None = None
64
+ http_client: httpxClient | None = None
65
+ response_format: str | dict[str, Any] | BaseModel | type[BaseModel] | None = None
66
+ default_headers: Mapping[str, Any] | None = None
67
+ tags: list[str] = Field(default_factory=list)
68
+
69
+ # Following field is configuration for pydantic to disallow extra fields
70
+ model_config = ConfigDict(extra="allow", arbitrary_types_allowed=True)
71
+
72
+ def apply_application_config(self, application_config: ApplicationConfig) -> "LLMConfigEntry":
73
+ """Apply application level configurations."""
74
+ # TODO: should create a new instance instead of mutating current one
75
+ self.max_tokens = self.max_tokens or application_config.max_tokens
76
+ self.top_p = self.top_p or application_config.top_p
77
+ self.temperature = self.temperature or application_config.temperature
78
+ return self
79
+
80
+ @abstractmethod
81
+ def create_client(self) -> "ModelClient": ...
82
+
83
+ @field_validator("base_url", mode="before")
84
+ @classmethod
85
+ def check_base_url(cls, v: HttpUrl | str | None, info: ValidationInfo) -> str | None:
86
+ if v is None: # Handle None case explicitly
87
+ return None
88
+ if not str(v).startswith("https://") and not str(v).startswith("http://"):
89
+ return f"http://{str(v)}"
90
+ return str(v)
91
+
92
+ @field_serializer("base_url", when_used="unless-none") # Ensure serializer also respects None
93
+ def serialize_base_url(self, v: HttpUrl | None) -> str | None:
94
+ return str(v) if v is not None else None
95
+
96
+ @field_serializer("api_key", when_used="unless-none")
97
+ def serialize_api_key(self, v: SecretStr) -> str:
98
+ return v.get_secret_value()
99
+
100
+ def model_dump(self, *args: Any, exclude_none: bool = True, **kwargs: Any) -> dict[str, Any]:
101
+ return BaseModel.model_dump(self, exclude_none=exclude_none, *args, **kwargs)
102
+
103
+ def model_dump_json(self, *args: Any, exclude_none: bool = True, **kwargs: Any) -> str:
104
+ return BaseModel.model_dump_json(self, exclude_none=exclude_none, *args, **kwargs)
105
+
106
+ def get(self, key: str, default: Any | None = None) -> Any:
107
+ val = getattr(self, key, default)
108
+ if isinstance(val, SecretStr):
109
+ return val.get_secret_value()
110
+ return val
111
+
112
+ def __getitem__(self, key: str) -> Any:
113
+ try:
114
+ val = getattr(self, key)
115
+ if isinstance(val, SecretStr):
116
+ return val.get_secret_value()
117
+ return val
118
+ except AttributeError:
119
+ raise KeyError(f"Key '{key}' not found in {self.__class__.__name__}")
120
+
121
+ def __setitem__(self, key: str, value: Any) -> None:
122
+ setattr(self, key, value)
123
+
124
+ def __contains__(self, key: str) -> bool:
125
+ return hasattr(self, key)
126
+
127
+ def items(self) -> Iterable[tuple[str, Any]]:
128
+ d = self.model_dump()
129
+ return d.items()
130
+
131
+ def keys(self) -> Iterable[str]:
132
+ d = self.model_dump()
133
+ return d.keys()
134
+
135
+ def values(self) -> Iterable[Any]:
136
+ d = self.model_dump()
137
+ return d.values()
138
+
139
+ def __repr__(self) -> str:
140
+ # Override to eliminate none values from the repr
141
+ d = self.model_dump()
142
+ r = [f"{k}={repr(v)}" for k, v in d.items()]
143
+
144
+ s = f"{self.__class__.__name__}({', '.join(r)})"
145
+
146
+ # Replace any keys ending with '_key' or '_token' values with stars for security
147
+ # This regex will match any key ending with '_key' or '_token' and its value, and replace the value with stars
148
+ # It also captures the type of quote used (single or double) and reuses it in the replacement
149
+ s = re.sub(r'(\w+_(key|token)\s*=\s*)([\'"]).*?\3', r"\1\3**********\3", s, flags=re.IGNORECASE)
150
+
151
+ return s
152
+
153
+ def __str__(self) -> str:
154
+ return repr(self)
@@ -9,7 +9,8 @@ from __future__ import annotations
9
9
  import sqlite3
10
10
  import uuid
11
11
  from abc import ABC, abstractmethod
12
- from typing import TYPE_CHECKING, Any, Callable, TypeVar, Union
12
+ from collections.abc import Callable
13
+ from typing import TYPE_CHECKING, Any, TypeVar
13
14
 
14
15
  if TYPE_CHECKING:
15
16
  from openai import AzureOpenAI, OpenAI
@@ -18,8 +19,8 @@ if TYPE_CHECKING:
18
19
  from .. import Agent, ConversableAgent, OpenAIWrapper
19
20
 
20
21
  F = TypeVar("F", bound=Callable[..., Any])
21
- ConfigItem = dict[str, Union[str, list[str]]]
22
- LLMConfig = dict[str, Union[None, float, int, ConfigItem, list[ConfigItem]]]
22
+ ConfigItem = dict[str, str | list[str]]
23
+ LLMConfig = dict[str, None | float | int | ConfigItem | list[ConfigItem]]
23
24
 
24
25
 
25
26
  class BaseLogger(ABC):
@@ -11,7 +11,8 @@ import logging
11
11
  import os
12
12
  import threading
13
13
  import uuid
14
- from typing import TYPE_CHECKING, Any, Callable, TypeVar
14
+ from collections.abc import Callable
15
+ from typing import TYPE_CHECKING, Any, TypeVar
15
16
 
16
17
  from ..doc_utils import export_module
17
18
  from .base_logger import BaseLogger, LLMConfig
@@ -4,7 +4,7 @@
4
4
  #
5
5
  # Portions derived from https://github.com/microsoft/autogen are under the MIT License.
6
6
  # SPDX-License-Identifier: MIT
7
- from typing import Any, Literal, Optional
7
+ from typing import Any, Literal
8
8
 
9
9
  from ..doc_utils import export_module
10
10
  from .base_logger import BaseLogger
@@ -20,7 +20,7 @@ class LoggerFactory:
20
20
 
21
21
  @staticmethod
22
22
  def get_logger(
23
- logger_type: Literal["sqlite", "file"] = "sqlite", config: Optional[dict[str, Any]] = None
23
+ logger_type: Literal["sqlite", "file"] = "sqlite", config: dict[str, Any] | None = None
24
24
  ) -> BaseLogger:
25
25
  """Factory method to create logger objects.
26
26
 
@@ -7,7 +7,7 @@
7
7
  import inspect
8
8
  from datetime import datetime, timezone
9
9
  from pathlib import Path, PurePath
10
- from typing import Any, Union
10
+ from typing import Any
11
11
 
12
12
  __all__ = ("get_current_ts", "to_dict")
13
13
 
@@ -22,7 +22,7 @@ def get_current_ts() -> str:
22
22
 
23
23
 
24
24
  def to_dict(
25
- obj: Union[int, float, str, bool, dict[Any, Any], list[Any], tuple[Any, ...], Any],
25
+ obj: int | float | str | bool | dict[Any, Any] | list[Any] | tuple[Any, ...] | Any,
26
26
  exclude: tuple[str, ...] = (),
27
27
  no_recursive: tuple[Any, ...] = (),
28
28
  ) -> Any:
@@ -12,7 +12,8 @@ import os
12
12
  import sqlite3
13
13
  import threading
14
14
  import uuid
15
- from typing import TYPE_CHECKING, Any, Callable, TypeVar
15
+ from collections.abc import Callable
16
+ from typing import TYPE_CHECKING, Any, TypeVar
16
17
 
17
18
  from ..doc_utils import export_module
18
19
  from .base_logger import BaseLogger, LLMConfig
autogen/math_utils.py CHANGED
@@ -4,10 +4,9 @@
4
4
  #
5
5
  # Portions derived from https://github.com/microsoft/autogen are under the MIT License.
6
6
  # SPDX-License-Identifier: MIT
7
- from typing import Optional
8
7
 
9
8
 
10
- def remove_boxed(string: str) -> Optional[str]:
9
+ def remove_boxed(string: str) -> str | None:
11
10
  """Source: https://github.com/hendrycks/math
12
11
  Extract the text within a \\boxed`{...}` environment.
13
12
 
@@ -28,7 +27,7 @@ def remove_boxed(string: str) -> Optional[str]:
28
27
  return None
29
28
 
30
29
 
31
- def last_boxed_only_string(string: str) -> Optional[str]:
30
+ def last_boxed_only_string(string: str) -> str | None:
32
31
  """Source: https://github.com/hendrycks/math
33
32
  Extract the last \\boxed`{...}` or \\fbox`{...}` element from a string.
34
33
  """
@@ -239,7 +238,7 @@ def _strip_string(string: str) -> str:
239
238
  return string
240
239
 
241
240
 
242
- def get_answer(solution: Optional[str]) -> Optional[str]:
241
+ def get_answer(solution: str | None) -> str | None:
243
242
  if solution is None:
244
243
  return None
245
244
  last_boxed = last_boxed_only_string(solution)
@@ -251,7 +250,7 @@ def get_answer(solution: Optional[str]) -> Optional[str]:
251
250
  return answer
252
251
 
253
252
 
254
- def is_equiv(str1: Optional[str], str2: Optional[str]) -> float:
253
+ def is_equiv(str1: str | None, str2: str | None) -> float:
255
254
  """Returns (as a float) whether two strings containing math are equivalent up to differences of formatting in
256
255
  - units
257
256
  - fractions