AUXteam commited on
Commit
22e6dc3
·
verified ·
1 Parent(s): 58d4730

Upload folder using huggingface_hub

Browse files
client_code.py ADDED
@@ -0,0 +1,340 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class OpenAIChatCompletionClient(BaseOpenAIChatCompletionClient, Component[OpenAIClientConfigurationConfigModel]):
2
+ """Chat completion client for OpenAI hosted models.
3
+
4
+ To use this client, you must install the `openai` extra:
5
+
6
+ .. code-block:: bash
7
+
8
+ pip install "autogen-ext[openai]"
9
+
10
+ You can also use this client for OpenAI-compatible ChatCompletion endpoints.
11
+ **Using this client for non-OpenAI models is not tested or guaranteed.**
12
+
13
+ For non-OpenAI models, please first take a look at our `community extensions <https://microsoft.github.io/autogen/dev/user-guide/extensions-user-guide/index.html>`_
14
+ for additional model clients.
15
+
16
+ Args:
17
+ model (str): Which OpenAI model to use.
18
+ api_key (optional, str): The API key to use. **Required if 'OPENAI_API_KEY' is not found in the environment variables.**
19
+ organization (optional, str): The organization ID to use.
20
+ base_url (optional, str): The base URL to use. **Required if the model is not hosted on OpenAI.**
21
+ timeout: (optional, float): The timeout for the request in seconds.
22
+ max_retries (optional, int): The maximum number of retries to attempt.
23
+ model_info (optional, ModelInfo): The capabilities of the model. **Required if the model name is not a valid OpenAI model.**
24
+ frequency_penalty (optional, float):
25
+ logit_bias: (optional, dict[str, int]):
26
+ max_tokens (optional, int):
27
+ n (optional, int):
28
+ presence_penalty (optional, float):
29
+ response_format (optional, Dict[str, Any]): the format of the response. Possible options are:
30
+
31
+ .. code-block:: text
32
+
33
+ # Text response, this is the default.
34
+ {"type": "text"}
35
+
36
+ .. code-block:: text
37
+
38
+ # JSON response, make sure to instruct the model to return JSON.
39
+ {"type": "json_object"}
40
+
41
+ .. code-block:: text
42
+
43
+ # Structured output response, with a pre-defined JSON schema.
44
+ {
45
+ "type": "json_schema",
46
+ "json_schema": {
47
+ "name": "name of the schema, must be an identifier.",
48
+ "description": "description for the model.",
49
+ # You can convert a Pydantic (v2) model to JSON schema
50
+ # using the `model_json_schema()` method.
51
+ "schema": "<the JSON schema itself>",
52
+ # Whether to enable strict schema adherence when
53
+ # generating the output. If set to true, the model will
54
+ # always follow the exact schema defined in the
55
+ # `schema` field. Only a subset of JSON Schema is
56
+ # supported when `strict` is `true`.
57
+ # To learn more, read
58
+ # https://platform.openai.com/docs/guides/structured-outputs.
59
+ "strict": False, # or True
60
+ },
61
+ }
62
+
63
+ It is recommended to use the `json_output` parameter in
64
+ :meth:`~autogen_ext.models.openai.BaseOpenAIChatCompletionClient.create` or
65
+ :meth:`~autogen_ext.models.openai.BaseOpenAIChatCompletionClient.create_stream`
66
+ methods instead of `response_format` for structured output.
67
+ The `json_output` parameter is more flexible and allows you to
68
+ specify a Pydantic model class directly.
69
+
70
+ seed (optional, int):
71
+ stop (optional, str | List[str]):
72
+ temperature (optional, float):
73
+ top_p (optional, float):
74
+ parallel_tool_calls (optional, bool): Whether to allow parallel tool calls. When not set, defaults to server behavior.
75
+ user (optional, str):
76
+ default_headers (optional, dict[str, str]): Custom headers; useful for authentication or other custom requirements.
77
+ add_name_prefixes (optional, bool): Whether to prepend the `source` value
78
+ to each :class:`~autogen_core.models.UserMessage` content. E.g.,
79
+ "this is content" becomes "Reviewer said: this is content."
80
+ This can be useful for models that do not support the `name` field in
81
+ message. Defaults to False.
82
+ include_name_in_message (optional, bool): Whether to include the `name` field
83
+ in user message parameters sent to the OpenAI API. Defaults to True. Set to False
84
+ for model providers that don't support the `name` field (e.g., Groq).
85
+ stream_options (optional, dict): Additional options for streaming. Currently only `include_usage` is supported.
86
+
87
+ Examples:
88
+
89
+ The following code snippet shows how to use the client with an OpenAI model:
90
+
91
+ .. code-block:: python
92
+
93
+ from autogen_ext.models.openai import OpenAIChatCompletionClient
94
+ from autogen_core.models import UserMessage
95
+
96
+ openai_client = OpenAIChatCompletionClient(
97
+ model="gpt-4o-2024-08-06",
98
+ # api_key="sk-...", # Optional if you have an OPENAI_API_KEY environment variable set.
99
+ )
100
+
101
+ result = await openai_client.create([UserMessage(content="What is the capital of France?", source="user")]) # type: ignore
102
+ print(result)
103
+
104
+ # Close the client when done.
105
+ # await openai_client.close()
106
+
107
+ To use the client with a non-OpenAI model, you need to provide the base URL of the model and the model info.
108
+ For example, to use Ollama, you can use the following code snippet:
109
+
110
+ .. code-block:: python
111
+
112
+ from autogen_ext.models.openai import OpenAIChatCompletionClient
113
+ from autogen_core.models import ModelFamily
114
+
115
+ custom_model_client = OpenAIChatCompletionClient(
116
+ model="deepseek-r1:1.5b",
117
+ base_url="http://localhost:11434/v1",
118
+ api_key="placeholder",
119
+ model_info={
120
+ "vision": False,
121
+ "function_calling": False,
122
+ "json_output": False,
123
+ "family": ModelFamily.R1,
124
+ "structured_output": True,
125
+ },
126
+ )
127
+
128
+ # Close the client when done.
129
+ # await custom_model_client.close()
130
+
131
+ To use streaming mode, you can use the following code snippet:
132
+
133
+ .. code-block:: python
134
+
135
+ import asyncio
136
+ from autogen_core.models import UserMessage
137
+ from autogen_ext.models.openai import OpenAIChatCompletionClient
138
+
139
+
140
+ async def main() -> None:
141
+ # Similar for AzureOpenAIChatCompletionClient.
142
+ model_client = OpenAIChatCompletionClient(model="gpt-4o") # assuming OPENAI_API_KEY is set in the environment.
143
+
144
+ messages = [UserMessage(content="Write a very short story about a dragon.", source="user")]
145
+
146
+ # Create a stream.
147
+ stream = model_client.create_stream(messages=messages)
148
+
149
+ # Iterate over the stream and print the responses.
150
+ print("Streamed responses:")
151
+ async for response in stream:
152
+ if isinstance(response, str):
153
+ # A partial response is a string.
154
+ print(response, flush=True, end="")
155
+ else:
156
+ # The last response is a CreateResult object with the complete message.
157
+ print("\\n\\n------------\\n")
158
+ print("The complete response:", flush=True)
159
+ print(response.content, flush=True)
160
+
161
+ # Close the client when done.
162
+ await model_client.close()
163
+
164
+
165
+ asyncio.run(main())
166
+
167
+ To use structured output as well as function calling, you can use the following code snippet:
168
+
169
+ .. code-block:: python
170
+
171
+ import asyncio
172
+ from typing import Literal
173
+
174
+ from autogen_core.models import (
175
+ AssistantMessage,
176
+ FunctionExecutionResult,
177
+ FunctionExecutionResultMessage,
178
+ SystemMessage,
179
+ UserMessage,
180
+ )
181
+ from autogen_core.tools import FunctionTool
182
+ from autogen_ext.models.openai import OpenAIChatCompletionClient
183
+ from pydantic import BaseModel
184
+
185
+
186
+ # Define the structured output format.
187
+ class AgentResponse(BaseModel):
188
+ thoughts: str
189
+ response: Literal["happy", "sad", "neutral"]
190
+
191
+
192
+ # Define the function to be called as a tool.
193
+ def sentiment_analysis(text: str) -> str:
194
+ \"\"\"Given a text, return the sentiment.\"\"\"
195
+ return "happy" if "happy" in text else "sad" if "sad" in text else "neutral"
196
+
197
+
198
+ # Create a FunctionTool instance with `strict=True`,
199
+ # which is required for structured output mode.
200
+ tool = FunctionTool(sentiment_analysis, description="Sentiment Analysis", strict=True)
201
+
202
+
203
+ async def main() -> None:
204
+ # Create an OpenAIChatCompletionClient instance.
205
+ model_client = OpenAIChatCompletionClient(model="gpt-4o-mini")
206
+
207
+ # Generate a response using the tool.
208
+ response1 = await model_client.create(
209
+ messages=[
210
+ SystemMessage(content="Analyze input text sentiment using the tool provided."),
211
+ UserMessage(content="I am happy.", source="user"),
212
+ ],
213
+ tools=[tool],
214
+ )
215
+ print(response1.content)
216
+ # Should be a list of tool calls.
217
+ # [FunctionCall(name="sentiment_analysis", arguments={"text": "I am happy."}, ...)]
218
+
219
+ assert isinstance(response1.content, list)
220
+ response2 = await model_client.create(
221
+ messages=[
222
+ SystemMessage(content="Analyze input text sentiment using the tool provided."),
223
+ UserMessage(content="I am happy.", source="user"),
224
+ AssistantMessage(content=response1.content, source="assistant"),
225
+ FunctionExecutionResultMessage(
226
+ content=[FunctionExecutionResult(content="happy", call_id=response1.content[0].id, is_error=False, name="sentiment_analysis")]
227
+ ),
228
+ ],
229
+ # Use the structured output format.
230
+ json_output=AgentResponse,
231
+ )
232
+ print(response2.content)
233
+ # Should be a structured output.
234
+ # {"thoughts": "The user is happy.", "response": "happy"}
235
+
236
+ # Close the client when done.
237
+ await model_client.close()
238
+
239
+ asyncio.run(main())
240
+
241
+
242
+ To load the client from a configuration, you can use the `load_component` method:
243
+
244
+ .. code-block:: python
245
+
246
+ from autogen_core.models import ChatCompletionClient
247
+
248
+ config = {
249
+ "provider": "OpenAIChatCompletionClient",
250
+ "config": {"model": "gpt-4o", "api_key": "REPLACE_WITH_YOUR_API_KEY"},
251
+ }
252
+
253
+ client = ChatCompletionClient.load_component(config)
254
+
255
+ To view the full list of available configuration options, see the :py:class:`OpenAIClientConfigurationConfigModel` class.
256
+
257
+ """
258
+
259
+ component_type = "model"
260
+ component_config_schema = OpenAIClientConfigurationConfigModel
261
+ component_provider_override = "autogen_ext.models.openai.OpenAIChatCompletionClient"
262
+
263
+ def __init__(self, **kwargs: Unpack[OpenAIClientConfiguration]):
264
+ if "model" not in kwargs:
265
+ raise ValueError("model is required for OpenAIChatCompletionClient")
266
+
267
+ model_capabilities: Optional[ModelCapabilities] = None # type: ignore
268
+ self._raw_config: Dict[str, Any] = dict(kwargs).copy()
269
+ copied_args = dict(kwargs).copy()
270
+
271
+ if "model_capabilities" in kwargs:
272
+ model_capabilities = kwargs["model_capabilities"]
273
+ del copied_args["model_capabilities"]
274
+
275
+ model_info: Optional[ModelInfo] = None
276
+ if "model_info" in kwargs:
277
+ model_info = kwargs["model_info"]
278
+ del copied_args["model_info"]
279
+
280
+ add_name_prefixes: bool = False
281
+ if "add_name_prefixes" in kwargs:
282
+ add_name_prefixes = kwargs["add_name_prefixes"]
283
+
284
+ include_name_in_message: bool = True
285
+ if "include_name_in_message" in kwargs:
286
+ include_name_in_message = kwargs["include_name_in_message"]
287
+
288
+ # Special handling for Gemini model.
289
+ assert "model" in copied_args and isinstance(copied_args["model"], str)
290
+ if copied_args["model"].startswith("gemini-"):
291
+ if "base_url" not in copied_args:
292
+ copied_args["base_url"] = _model_info.GEMINI_OPENAI_BASE_URL
293
+ if "api_key" not in copied_args and "GEMINI_API_KEY" in os.environ:
294
+ copied_args["api_key"] = os.environ["GEMINI_API_KEY"]
295
+ if copied_args["model"].startswith("claude-"):
296
+ if "base_url" not in copied_args:
297
+ copied_args["base_url"] = _model_info.ANTHROPIC_OPENAI_BASE_URL
298
+ if "api_key" not in copied_args and "ANTHROPIC_API_KEY" in os.environ:
299
+ copied_args["api_key"] = os.environ["ANTHROPIC_API_KEY"]
300
+ if copied_args["model"].startswith("Llama-"):
301
+ if "base_url" not in copied_args:
302
+ copied_args["base_url"] = _model_info.LLAMA_API_BASE_URL
303
+ if "api_key" not in copied_args and "LLAMA_API_KEY" in os.environ:
304
+ copied_args["api_key"] = os.environ["LLAMA_API_KEY"]
305
+
306
+ client = _openai_client_from_config(copied_args)
307
+ create_args = _create_args_from_config(copied_args)
308
+
309
+ super().__init__(
310
+ client=client,
311
+ create_args=create_args,
312
+ model_capabilities=model_capabilities,
313
+ model_info=model_info,
314
+ add_name_prefixes=add_name_prefixes,
315
+ include_name_in_message=include_name_in_message,
316
+ )
317
+
318
+ def __getstate__(self) -> Dict[str, Any]:
319
+ state = self.__dict__.copy()
320
+ state["_client"] = None
321
+ return state
322
+
323
+ def __setstate__(self, state: Dict[str, Any]) -> None:
324
+ self.__dict__.update(state)
325
+ self._client = _openai_client_from_config(state["_raw_config"])
326
+
327
+ def _to_config(self) -> OpenAIClientConfigurationConfigModel:
328
+ copied_config = self._raw_config.copy()
329
+ return OpenAIClientConfigurationConfigModel(**copied_config)
330
+
331
+ @classmethod
332
+ def _from_config(cls, config: OpenAIClientConfigurationConfigModel) -> Self:
333
+ copied_config = config.model_copy().model_dump(exclude_none=True)
334
+
335
+ # Handle api_key as SecretStr
336
+ if "api_key" in copied_config and isinstance(config.api_key, SecretStr):
337
+ copied_config["api_key"] = config.api_key.get_secret_value()
338
+
339
+ return cls(**copied_config)
340
+
config.yaml CHANGED
@@ -10,6 +10,7 @@ model_config_blablador: &client_blablador
10
  json_output: true
11
  family: "unknown"
12
  structured_output: false
 
13
  max_retries: 10
14
 
15
  model_config_blablador_fast: &client_blablador_fast
@@ -24,6 +25,7 @@ model_config_blablador_fast: &client_blablador_fast
24
  json_output: true
25
  family: "unknown"
26
  structured_output: false
 
27
  max_retries: 10
28
 
29
  orchestrator_client: *client_blablador
 
10
  json_output: true
11
  family: "unknown"
12
  structured_output: false
13
+ include_name_in_message: false
14
  max_retries: 10
15
 
16
  model_config_blablador_fast: &client_blablador_fast
 
25
  json_output: true
26
  family: "unknown"
27
  structured_output: false
28
+ include_name_in_message: false
29
  max_retries: 10
30
 
31
  orchestrator_client: *client_blablador
src/magentic_ui/magentic_ui_config.py CHANGED
@@ -49,7 +49,8 @@ class ModelClientConfigs(BaseModel):
49
  "json_output": True,
50
  "family": "unknown",
51
  "structured_output": False,
52
- }
 
53
  },
54
  "max_retries": 10,
55
  }
@@ -69,7 +70,8 @@ class ModelClientConfigs(BaseModel):
69
  "family": "unknown",
70
  "structured_output": False,
71
  "multiple_system_messages": False,
72
- }
 
73
  },
74
  "max_retries": 10,
75
  }
@@ -86,7 +88,8 @@ class ModelClientConfigs(BaseModel):
86
  "json_output": True,
87
  "family": "unknown",
88
  "structured_output": False,
89
- }
 
90
  },
91
  "max_retries": 10,
92
  }
 
49
  "json_output": True,
50
  "family": "unknown",
51
  "structured_output": False,
52
+ },
53
+ "include_name_in_message": False
54
  },
55
  "max_retries": 10,
56
  }
 
70
  "family": "unknown",
71
  "structured_output": False,
72
  "multiple_system_messages": False,
73
+ },
74
+ "include_name_in_message": False
75
  },
76
  "max_retries": 10,
77
  }
 
88
  "json_output": True,
89
  "family": "unknown",
90
  "structured_output": False,
91
+ },
92
+ "include_name_in_message": False
93
  },
94
  "max_retries": 10,
95
  }