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
autogen/llm_config.py DELETED
@@ -1,385 +0,0 @@
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 abc import ABC, abstractmethod
9
- from collections.abc import Iterable
10
- from contextvars import ContextVar
11
- from pathlib import Path
12
- from typing import TYPE_CHECKING, Annotated, Any, Literal, Mapping, Optional, Type, TypeVar, Union
13
-
14
- from httpx import Client as httpxClient
15
- from pydantic import BaseModel, ConfigDict, Field, HttpUrl, SecretStr, ValidationInfo, field_serializer, field_validator
16
-
17
- if TYPE_CHECKING:
18
- from .oai.client import ModelClient
19
-
20
- _KT = TypeVar("_KT")
21
- _VT = TypeVar("_VT")
22
-
23
- __all__ = [
24
- "LLMConfig",
25
- "LLMConfigEntry",
26
- "register_llm_config",
27
- ]
28
-
29
-
30
- def _add_default_api_type(d: dict[str, Any]) -> dict[str, Any]:
31
- if "api_type" not in d:
32
- d["api_type"] = "openai"
33
- return d
34
-
35
-
36
- # Meta class to allow LLMConfig.current and LLMConfig.default to be used as class properties
37
- class MetaLLMConfig(type):
38
- def __init__(cls, *args: Any, **kwargs: Any) -> None:
39
- pass
40
-
41
- @property
42
- def current(cls) -> "LLMConfig":
43
- current_llm_config = LLMConfig.get_current_llm_config(llm_config=None)
44
- if current_llm_config is None:
45
- raise ValueError("No current LLMConfig set. Are you inside a context block?")
46
- return current_llm_config # type: ignore[return-value]
47
-
48
- @property
49
- def default(cls) -> "LLMConfig":
50
- return cls.current
51
-
52
-
53
- class LLMConfig(metaclass=MetaLLMConfig):
54
- _current_llm_config: ContextVar["LLMConfig"] = ContextVar("current_llm_config")
55
-
56
- def __init__(self, **kwargs: Any) -> None:
57
- outside_properties = list((self._get_base_model_class()).model_json_schema()["properties"].keys())
58
- outside_properties.remove("config_list")
59
-
60
- if "config_list" in kwargs and isinstance(kwargs["config_list"], dict):
61
- kwargs["config_list"] = [kwargs["config_list"]]
62
-
63
- modified_kwargs = (
64
- kwargs
65
- if "config_list" in kwargs
66
- else {
67
- **{
68
- "config_list": [
69
- {k: v for k, v in kwargs.items() if k not in outside_properties},
70
- ]
71
- },
72
- **{k: v for k, v in kwargs.items() if k in outside_properties},
73
- }
74
- )
75
-
76
- modified_kwargs["config_list"] = [
77
- _add_default_api_type(v) if isinstance(v, dict) else v for v in modified_kwargs["config_list"]
78
- ]
79
- for x in ["max_tokens", "top_p"]:
80
- if x in modified_kwargs:
81
- modified_kwargs["config_list"] = [{**v, x: modified_kwargs[x]} for v in modified_kwargs["config_list"]]
82
- modified_kwargs.pop(x)
83
-
84
- self._model = self._get_base_model_class()(**modified_kwargs)
85
-
86
- # used by BaseModel to create instance variables
87
- def __enter__(self) -> "LLMConfig":
88
- # Store previous context and set self as current
89
- self._token = LLMConfig._current_llm_config.set(self)
90
- return self
91
-
92
- def __exit__(self, exc_type: Type[Exception], exc_val: Exception, exc_tb: Any) -> None:
93
- LLMConfig._current_llm_config.reset(self._token)
94
-
95
- @classmethod
96
- def get_current_llm_config(cls, llm_config: "Optional[LLMConfig]" = None) -> "Optional[LLMConfig]":
97
- if llm_config is not None:
98
- return llm_config
99
- try:
100
- return (LLMConfig._current_llm_config.get()).copy()
101
- except LookupError:
102
- return None
103
-
104
- def _satisfies_criteria(self, value: Any, criteria_values: Any) -> bool:
105
- if value is None:
106
- return False
107
-
108
- if isinstance(value, list):
109
- return bool(set(value) & set(criteria_values)) # Non-empty intersection
110
- else:
111
- return value in criteria_values
112
-
113
- @classmethod
114
- def from_json(
115
- cls,
116
- *,
117
- env: Optional[str] = None,
118
- path: Optional[Union[str, Path]] = None,
119
- file_location: Optional[str] = None,
120
- **kwargs: Any,
121
- ) -> "LLMConfig":
122
- from .oai.openai_utils import config_list_from_json
123
-
124
- if env is None and path is None:
125
- raise ValueError("Either 'env' or 'path' must be provided")
126
- if env is not None and path is not None:
127
- raise ValueError("Only one of 'env' or 'path' can be provided")
128
-
129
- config_list = config_list_from_json(
130
- env_or_file=env if env is not None else str(path), file_location=file_location
131
- )
132
- return LLMConfig(config_list=config_list, **kwargs)
133
-
134
- def where(self, *, exclude: bool = False, **kwargs: Any) -> "LLMConfig":
135
- from .oai.openai_utils import filter_config
136
-
137
- filtered_config_list = filter_config(config_list=self.config_list, filter_dict=kwargs, exclude=exclude)
138
- if len(filtered_config_list) == 0:
139
- raise ValueError(f"No config found that satisfies the filter criteria: {kwargs}")
140
-
141
- kwargs = self.model_dump()
142
- kwargs["config_list"] = filtered_config_list
143
-
144
- return LLMConfig(**kwargs)
145
-
146
- # @functools.wraps(BaseModel.model_dump)
147
- def model_dump(self, *args: Any, exclude_none: bool = True, **kwargs: Any) -> dict[str, Any]:
148
- d = self._model.model_dump(*args, exclude_none=exclude_none, **kwargs)
149
- return {k: v for k, v in d.items() if not (isinstance(v, list) and len(v) == 0)}
150
-
151
- # @functools.wraps(BaseModel.model_dump_json)
152
- def model_dump_json(self, *args: Any, exclude_none: bool = True, **kwargs: Any) -> str:
153
- # return self._model.model_dump_json(*args, exclude_none=exclude_none, **kwargs)
154
- d = self.model_dump(*args, exclude_none=exclude_none, **kwargs)
155
- return json.dumps(d)
156
-
157
- # @functools.wraps(BaseModel.model_validate)
158
- def model_validate(self, *args: Any, **kwargs: Any) -> Any:
159
- return self._model.model_validate(*args, **kwargs)
160
-
161
- @functools.wraps(BaseModel.model_validate_json)
162
- def model_validate_json(self, *args: Any, **kwargs: Any) -> Any:
163
- return self._model.model_validate_json(*args, **kwargs)
164
-
165
- @functools.wraps(BaseModel.model_validate_strings)
166
- def model_validate_strings(self, *args: Any, **kwargs: Any) -> Any:
167
- return self._model.model_validate_strings(*args, **kwargs)
168
-
169
- def __eq__(self, value: Any) -> bool:
170
- return hasattr(value, "_model") and self._model == value._model
171
-
172
- def _getattr(self, o: object, name: str) -> Any:
173
- val = getattr(o, name)
174
- return val
175
-
176
- def get(self, key: str, default: Optional[Any] = None) -> Any:
177
- val = getattr(self._model, key, default)
178
- return val
179
-
180
- def __getitem__(self, key: str) -> Any:
181
- try:
182
- return self._getattr(self._model, key)
183
- except AttributeError:
184
- raise KeyError(f"Key '{key}' not found in {self.__class__.__name__}")
185
-
186
- def __setitem__(self, key: str, value: Any) -> None:
187
- try:
188
- setattr(self._model, key, value)
189
- except ValueError:
190
- raise ValueError(f"'{self.__class__.__name__}' object has no field '{key}'")
191
-
192
- def __getattr__(self, name: Any) -> Any:
193
- try:
194
- return self._getattr(self._model, name)
195
- except AttributeError:
196
- raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'")
197
-
198
- def __setattr__(self, name: str, value: Any) -> None:
199
- if name == "_model":
200
- object.__setattr__(self, name, value)
201
- else:
202
- setattr(self._model, name, value)
203
-
204
- def __contains__(self, key: str) -> bool:
205
- return hasattr(self._model, key)
206
-
207
- def __repr__(self) -> str:
208
- d = self.model_dump()
209
- r = [f"{k}={repr(v)}" for k, v in d.items()]
210
-
211
- s = f"LLMConfig({', '.join(r)})"
212
- # Replace any keys ending with 'key' or 'token' values with stars for security
213
- s = re.sub(
214
- r"(['\"])(\w*(key|token))\1:\s*(['\"])([^'\"]*)(?:\4)", r"\1\2\1: \4**********\4", s, flags=re.IGNORECASE
215
- )
216
- return s
217
-
218
- def __copy__(self) -> "LLMConfig":
219
- return LLMConfig(**self.model_dump())
220
-
221
- def __deepcopy__(self, memo: Optional[dict[int, Any]] = None) -> "LLMConfig":
222
- return self.__copy__()
223
-
224
- def copy(self) -> "LLMConfig":
225
- return self.__copy__()
226
-
227
- def deepcopy(self, memo: Optional[dict[int, Any]] = None) -> "LLMConfig":
228
- return self.__deepcopy__(memo)
229
-
230
- def __str__(self) -> str:
231
- return repr(self)
232
-
233
- def items(self) -> Iterable[tuple[str, Any]]:
234
- d = self.model_dump()
235
- return d.items()
236
-
237
- def keys(self) -> Iterable[str]:
238
- d = self.model_dump()
239
- return d.keys()
240
-
241
- def values(self) -> Iterable[Any]:
242
- d = self.model_dump()
243
- return d.values()
244
-
245
- _base_model_classes: dict[tuple[Type["LLMConfigEntry"], ...], Type[BaseModel]] = {}
246
-
247
- @classmethod
248
- def _get_base_model_class(cls) -> Type["BaseModel"]:
249
- def _get_cls(llm_config_classes: tuple[Type[LLMConfigEntry], ...]) -> Type[BaseModel]:
250
- if llm_config_classes in LLMConfig._base_model_classes:
251
- return LLMConfig._base_model_classes[llm_config_classes]
252
-
253
- class _LLMConfig(BaseModel):
254
- temperature: Optional[float] = None
255
- check_every_ms: Optional[int] = None
256
- max_new_tokens: Optional[int] = None
257
- seed: Optional[int] = None
258
- allow_format_str_template: Optional[bool] = None
259
- response_format: Optional[Union[str, dict[str, Any], BaseModel, Type[BaseModel]]] = None
260
- timeout: Optional[int] = None
261
- cache_seed: Optional[int] = None
262
-
263
- tools: list[Any] = Field(default_factory=list)
264
- functions: list[Any] = Field(default_factory=list)
265
- parallel_tool_calls: Optional[bool] = None
266
-
267
- config_list: Annotated[ # type: ignore[valid-type]
268
- list[Annotated[Union[llm_config_classes], Field(discriminator="api_type")]],
269
- Field(default_factory=list, min_length=1),
270
- ]
271
- routing_method: Optional[Literal["fixed_order", "round_robin"]] = None
272
-
273
- # Following field is configuration for pydantic to disallow extra fields
274
- model_config = ConfigDict(extra="forbid")
275
-
276
- LLMConfig._base_model_classes[llm_config_classes] = _LLMConfig
277
-
278
- return _LLMConfig
279
-
280
- return _get_cls(tuple(_llm_config_classes))
281
-
282
-
283
- class LLMConfigEntry(BaseModel, ABC):
284
- api_type: str
285
- model: str = Field(..., min_length=1)
286
- api_key: Optional[SecretStr] = None
287
- api_version: Optional[str] = None
288
- max_tokens: Optional[int] = None
289
- base_url: Optional[HttpUrl] = None
290
- voice: Optional[str] = None
291
- model_client_cls: Optional[str] = None
292
- http_client: Optional[httpxClient] = None
293
- response_format: Optional[Union[str, dict[str, Any], BaseModel, Type[BaseModel]]] = None
294
- default_headers: Optional[Mapping[str, Any]] = None
295
- tags: list[str] = Field(default_factory=list)
296
-
297
- # Following field is configuration for pydantic to disallow extra fields
298
- model_config = ConfigDict(extra="forbid", arbitrary_types_allowed=True)
299
-
300
- @abstractmethod
301
- def create_client(self) -> "ModelClient": ...
302
-
303
- @field_validator("base_url", mode="before")
304
- @classmethod
305
- def check_base_url(cls, v: Any, info: ValidationInfo) -> Any:
306
- if v is None: # Handle None case explicitly
307
- return None
308
- if not str(v).startswith("https://") and not str(v).startswith("http://"):
309
- v = f"http://{str(v)}"
310
- return v
311
-
312
- @field_serializer("base_url", when_used="unless-none") # Ensure serializer also respects None
313
- def serialize_base_url(self, v: Any) -> Any:
314
- return str(v) if v is not None else None
315
-
316
- @field_serializer("api_key", when_used="unless-none")
317
- def serialize_api_key(self, v: SecretStr) -> Any:
318
- return v.get_secret_value()
319
-
320
- def model_dump(self, *args: Any, exclude_none: bool = True, **kwargs: Any) -> dict[str, Any]:
321
- return BaseModel.model_dump(self, exclude_none=exclude_none, *args, **kwargs)
322
-
323
- def model_dump_json(self, *args: Any, exclude_none: bool = True, **kwargs: Any) -> str:
324
- return BaseModel.model_dump_json(self, exclude_none=exclude_none, *args, **kwargs)
325
-
326
- def get(self, key: str, default: Optional[Any] = None) -> Any:
327
- val = getattr(self, key, default)
328
- if isinstance(val, SecretStr):
329
- return val.get_secret_value()
330
- return val
331
-
332
- def __getitem__(self, key: str) -> Any:
333
- try:
334
- val = getattr(self, key)
335
- if isinstance(val, SecretStr):
336
- return val.get_secret_value()
337
- return val
338
- except AttributeError:
339
- raise KeyError(f"Key '{key}' not found in {self.__class__.__name__}")
340
-
341
- def __setitem__(self, key: str, value: Any) -> None:
342
- setattr(self, key, value)
343
-
344
- def __contains__(self, key: str) -> bool:
345
- return hasattr(self, key)
346
-
347
- def items(self) -> Iterable[tuple[str, Any]]:
348
- d = self.model_dump()
349
- return d.items()
350
-
351
- def keys(self) -> Iterable[str]:
352
- d = self.model_dump()
353
- return d.keys()
354
-
355
- def values(self) -> Iterable[Any]:
356
- d = self.model_dump()
357
- return d.values()
358
-
359
- def __repr__(self) -> str:
360
- # Override to eliminate none values from the repr
361
- d = self.model_dump()
362
- r = [f"{k}={repr(v)}" for k, v in d.items()]
363
-
364
- s = f"{self.__class__.__name__}({', '.join(r)})"
365
-
366
- # Replace any keys ending with '_key' or '_token' values with stars for security
367
- # This regex will match any key ending with '_key' or '_token' and its value, and replace the value with stars
368
- # It also captures the type of quote used (single or double) and reuses it in the replacement
369
- s = re.sub(r'(\w+_(key|token)\s*=\s*)([\'"]).*?\3', r"\1\3**********\3", s, flags=re.IGNORECASE)
370
-
371
- return s
372
-
373
- def __str__(self) -> str:
374
- return repr(self)
375
-
376
-
377
- _llm_config_classes: list[Type[LLMConfigEntry]] = []
378
-
379
-
380
- def register_llm_config(cls: Type[LLMConfigEntry]) -> Type[LLMConfigEntry]:
381
- if isinstance(cls, type) and issubclass(cls, LLMConfigEntry):
382
- _llm_config_classes.append(cls)
383
- else:
384
- raise TypeError(f"Expected a subclass of LLMConfigEntry, got {cls}")
385
- return cls
File without changes