ag2 0.4b1__py3-none-any.whl → 0.4.2b1__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 (118) hide show
  1. ag2-0.4.2b1.dist-info/METADATA +19 -0
  2. ag2-0.4.2b1.dist-info/RECORD +6 -0
  3. ag2-0.4.2b1.dist-info/top_level.txt +1 -0
  4. ag2-0.4b1.dist-info/METADATA +0 -496
  5. ag2-0.4b1.dist-info/RECORD +0 -115
  6. ag2-0.4b1.dist-info/top_level.txt +0 -1
  7. autogen/__init__.py +0 -17
  8. autogen/_pydantic.py +0 -116
  9. autogen/agentchat/__init__.py +0 -42
  10. autogen/agentchat/agent.py +0 -142
  11. autogen/agentchat/assistant_agent.py +0 -85
  12. autogen/agentchat/chat.py +0 -306
  13. autogen/agentchat/contrib/__init__.py +0 -0
  14. autogen/agentchat/contrib/agent_builder.py +0 -787
  15. autogen/agentchat/contrib/agent_optimizer.py +0 -450
  16. autogen/agentchat/contrib/capabilities/__init__.py +0 -0
  17. autogen/agentchat/contrib/capabilities/agent_capability.py +0 -21
  18. autogen/agentchat/contrib/capabilities/generate_images.py +0 -297
  19. autogen/agentchat/contrib/capabilities/teachability.py +0 -406
  20. autogen/agentchat/contrib/capabilities/text_compressors.py +0 -72
  21. autogen/agentchat/contrib/capabilities/transform_messages.py +0 -92
  22. autogen/agentchat/contrib/capabilities/transforms.py +0 -565
  23. autogen/agentchat/contrib/capabilities/transforms_util.py +0 -120
  24. autogen/agentchat/contrib/capabilities/vision_capability.py +0 -217
  25. autogen/agentchat/contrib/captainagent.py +0 -487
  26. autogen/agentchat/contrib/gpt_assistant_agent.py +0 -545
  27. autogen/agentchat/contrib/graph_rag/__init__.py +0 -0
  28. autogen/agentchat/contrib/graph_rag/document.py +0 -24
  29. autogen/agentchat/contrib/graph_rag/falkor_graph_query_engine.py +0 -76
  30. autogen/agentchat/contrib/graph_rag/graph_query_engine.py +0 -50
  31. autogen/agentchat/contrib/graph_rag/graph_rag_capability.py +0 -56
  32. autogen/agentchat/contrib/img_utils.py +0 -390
  33. autogen/agentchat/contrib/llamaindex_conversable_agent.py +0 -123
  34. autogen/agentchat/contrib/llava_agent.py +0 -176
  35. autogen/agentchat/contrib/math_user_proxy_agent.py +0 -471
  36. autogen/agentchat/contrib/multimodal_conversable_agent.py +0 -128
  37. autogen/agentchat/contrib/qdrant_retrieve_user_proxy_agent.py +0 -325
  38. autogen/agentchat/contrib/retrieve_assistant_agent.py +0 -56
  39. autogen/agentchat/contrib/retrieve_user_proxy_agent.py +0 -701
  40. autogen/agentchat/contrib/society_of_mind_agent.py +0 -203
  41. autogen/agentchat/contrib/swarm_agent.py +0 -414
  42. autogen/agentchat/contrib/text_analyzer_agent.py +0 -76
  43. autogen/agentchat/contrib/tool_retriever.py +0 -114
  44. autogen/agentchat/contrib/vectordb/__init__.py +0 -0
  45. autogen/agentchat/contrib/vectordb/base.py +0 -243
  46. autogen/agentchat/contrib/vectordb/chromadb.py +0 -326
  47. autogen/agentchat/contrib/vectordb/mongodb.py +0 -559
  48. autogen/agentchat/contrib/vectordb/pgvectordb.py +0 -958
  49. autogen/agentchat/contrib/vectordb/qdrant.py +0 -334
  50. autogen/agentchat/contrib/vectordb/utils.py +0 -126
  51. autogen/agentchat/contrib/web_surfer.py +0 -305
  52. autogen/agentchat/conversable_agent.py +0 -2908
  53. autogen/agentchat/groupchat.py +0 -1668
  54. autogen/agentchat/user_proxy_agent.py +0 -109
  55. autogen/agentchat/utils.py +0 -207
  56. autogen/browser_utils.py +0 -291
  57. autogen/cache/__init__.py +0 -10
  58. autogen/cache/abstract_cache_base.py +0 -78
  59. autogen/cache/cache.py +0 -182
  60. autogen/cache/cache_factory.py +0 -85
  61. autogen/cache/cosmos_db_cache.py +0 -150
  62. autogen/cache/disk_cache.py +0 -109
  63. autogen/cache/in_memory_cache.py +0 -61
  64. autogen/cache/redis_cache.py +0 -128
  65. autogen/code_utils.py +0 -745
  66. autogen/coding/__init__.py +0 -22
  67. autogen/coding/base.py +0 -113
  68. autogen/coding/docker_commandline_code_executor.py +0 -262
  69. autogen/coding/factory.py +0 -45
  70. autogen/coding/func_with_reqs.py +0 -203
  71. autogen/coding/jupyter/__init__.py +0 -22
  72. autogen/coding/jupyter/base.py +0 -32
  73. autogen/coding/jupyter/docker_jupyter_server.py +0 -164
  74. autogen/coding/jupyter/embedded_ipython_code_executor.py +0 -182
  75. autogen/coding/jupyter/jupyter_client.py +0 -224
  76. autogen/coding/jupyter/jupyter_code_executor.py +0 -161
  77. autogen/coding/jupyter/local_jupyter_server.py +0 -168
  78. autogen/coding/local_commandline_code_executor.py +0 -410
  79. autogen/coding/markdown_code_extractor.py +0 -44
  80. autogen/coding/utils.py +0 -57
  81. autogen/exception_utils.py +0 -46
  82. autogen/extensions/__init__.py +0 -0
  83. autogen/formatting_utils.py +0 -76
  84. autogen/function_utils.py +0 -362
  85. autogen/graph_utils.py +0 -148
  86. autogen/io/__init__.py +0 -15
  87. autogen/io/base.py +0 -105
  88. autogen/io/console.py +0 -43
  89. autogen/io/websockets.py +0 -213
  90. autogen/logger/__init__.py +0 -11
  91. autogen/logger/base_logger.py +0 -140
  92. autogen/logger/file_logger.py +0 -287
  93. autogen/logger/logger_factory.py +0 -29
  94. autogen/logger/logger_utils.py +0 -42
  95. autogen/logger/sqlite_logger.py +0 -459
  96. autogen/math_utils.py +0 -356
  97. autogen/oai/__init__.py +0 -33
  98. autogen/oai/anthropic.py +0 -428
  99. autogen/oai/bedrock.py +0 -600
  100. autogen/oai/cerebras.py +0 -264
  101. autogen/oai/client.py +0 -1148
  102. autogen/oai/client_utils.py +0 -167
  103. autogen/oai/cohere.py +0 -453
  104. autogen/oai/completion.py +0 -1216
  105. autogen/oai/gemini.py +0 -469
  106. autogen/oai/groq.py +0 -281
  107. autogen/oai/mistral.py +0 -279
  108. autogen/oai/ollama.py +0 -576
  109. autogen/oai/openai_utils.py +0 -810
  110. autogen/oai/together.py +0 -343
  111. autogen/retrieve_utils.py +0 -487
  112. autogen/runtime_logging.py +0 -163
  113. autogen/token_count_utils.py +0 -257
  114. autogen/types.py +0 -20
  115. autogen/version.py +0 -7
  116. {ag2-0.4b1.dist-info → ag2-0.4.2b1.dist-info}/LICENSE +0 -0
  117. {ag2-0.4b1.dist-info → ag2-0.4.2b1.dist-info}/NOTICE.md +0 -0
  118. {ag2-0.4b1.dist-info → ag2-0.4.2b1.dist-info}/WHEEL +0 -0
autogen/oai/bedrock.py DELETED
@@ -1,600 +0,0 @@
1
- """
2
- Create a compatible client for the Amazon Bedrock Converse API.
3
-
4
- Example usage:
5
- Install the `boto3` package by running `pip install --upgrade boto3`.
6
- - https://docs.aws.amazon.com/bedrock/latest/userguide/conversation-inference.html
7
-
8
- import autogen
9
-
10
- config_list = [
11
- {
12
- "api_type": "bedrock",
13
- "model": "meta.llama3-1-8b-instruct-v1:0",
14
- "aws_region": "us-west-2",
15
- "aws_access_key": "",
16
- "aws_secret_key": "",
17
- "price" : [0.003, 0.015]
18
- }
19
- ]
20
-
21
- assistant = autogen.AssistantAgent("assistant", llm_config={"config_list": config_list})
22
-
23
- """
24
-
25
- from __future__ import annotations
26
-
27
- import base64
28
- import json
29
- import os
30
- import re
31
- import time
32
- import warnings
33
- from typing import Any, Dict, List, Literal, Tuple
34
-
35
- import boto3
36
- import requests
37
- from botocore.config import Config
38
- from openai.types.chat import ChatCompletion, ChatCompletionMessageToolCall
39
- from openai.types.chat.chat_completion import ChatCompletionMessage, Choice
40
- from openai.types.completion_usage import CompletionUsage
41
-
42
- from autogen.oai.client_utils import validate_parameter
43
-
44
-
45
- class BedrockClient:
46
- """Client for Amazon's Bedrock Converse API."""
47
-
48
- _retries = 5
49
-
50
- def __init__(self, **kwargs: Any):
51
- """
52
- Initialises BedrockClient for Amazon's Bedrock Converse API
53
- """
54
- self._aws_access_key = kwargs.get("aws_access_key", None)
55
- self._aws_secret_key = kwargs.get("aws_secret_key", None)
56
- self._aws_session_token = kwargs.get("aws_session_token", None)
57
- self._aws_region = kwargs.get("aws_region", None)
58
- self._aws_profile_name = kwargs.get("aws_profile_name", None)
59
-
60
- if not self._aws_access_key:
61
- self._aws_access_key = os.getenv("AWS_ACCESS_KEY")
62
-
63
- if not self._aws_secret_key:
64
- self._aws_secret_key = os.getenv("AWS_SECRET_KEY")
65
-
66
- if not self._aws_session_token:
67
- self._aws_session_token = os.getenv("AWS_SESSION_TOKEN")
68
-
69
- if not self._aws_region:
70
- self._aws_region = os.getenv("AWS_REGION")
71
-
72
- if self._aws_region is None:
73
- raise ValueError("Region is required to use the Amazon Bedrock API.")
74
-
75
- # Initialize Bedrock client, session, and runtime
76
- bedrock_config = Config(
77
- region_name=self._aws_region,
78
- signature_version="v4",
79
- retries={"max_attempts": self._retries, "mode": "standard"},
80
- )
81
-
82
- session = boto3.Session(
83
- aws_access_key_id=self._aws_access_key,
84
- aws_secret_access_key=self._aws_secret_key,
85
- aws_session_token=self._aws_session_token,
86
- profile_name=self._aws_profile_name,
87
- )
88
-
89
- self.bedrock_runtime = session.client(service_name="bedrock-runtime", config=bedrock_config)
90
-
91
- def message_retrieval(self, response):
92
- """Retrieve the messages from the response."""
93
- return [choice.message for choice in response.choices]
94
-
95
- def parse_custom_params(self, params: Dict[str, Any]):
96
- """
97
- Parses custom parameters for logic in this client class
98
- """
99
-
100
- # Should we separate system messages into its own request parameter, default is True
101
- # This is required because not all models support a system prompt (e.g. Mistral Instruct).
102
- self._supports_system_prompts = params.get("supports_system_prompts", True)
103
-
104
- def parse_params(self, params: Dict[str, Any]) -> tuple[Dict[str, Any], Dict[str, Any]]:
105
- """
106
- Loads the valid parameters required to invoke Bedrock Converse
107
- Returns a tuple of (base_params, additional_params)
108
- """
109
-
110
- base_params = {}
111
- additional_params = {}
112
-
113
- # Amazon Bedrock base model IDs are here:
114
- # https://docs.aws.amazon.com/bedrock/latest/userguide/model-ids.html
115
- self._model_id = params.get("model", None)
116
- assert self._model_id, "Please provide the 'model` in the config_list to use Amazon Bedrock"
117
-
118
- # Parameters vary based on the model used.
119
- # As we won't cater for all models and parameters, it's the developer's
120
- # responsibility to implement the parameters and they will only be
121
- # included if the developer has it in the config.
122
- #
123
- # Important:
124
- # No defaults will be used (as they can vary per model)
125
- # No ranges will be used (as they can vary)
126
- # We will cover all the main parameters but there may be others
127
- # that need to be added later
128
- #
129
- # Here are some pages that show the parameters available for different models
130
- # https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-titan-text.html
131
- # https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-anthropic-claude-text-completion.html
132
- # https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-cohere-command-r-plus.html
133
- # https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-meta.html
134
- # https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-mistral-chat-completion.html
135
-
136
- # Here are the possible "base" parameters and their suitable types
137
- base_parameters = [["temperature", (float, int)], ["topP", (float, int)], ["maxTokens", (int)]]
138
-
139
- for param_name, suitable_types in base_parameters:
140
- if param_name in params:
141
- base_params[param_name] = validate_parameter(
142
- params, param_name, suitable_types, False, None, None, None
143
- )
144
-
145
- # Here are the possible "model-specific" parameters and their suitable types, known as additional parameters
146
- additional_parameters = [
147
- ["top_p", (float, int)],
148
- ["top_k", (int)],
149
- ["k", (int)],
150
- ["seed", (int)],
151
- ]
152
-
153
- for param_name, suitable_types in additional_parameters:
154
- if param_name in params:
155
- additional_params[param_name] = validate_parameter(
156
- params, param_name, suitable_types, False, None, None, None
157
- )
158
-
159
- # Streaming
160
- if "stream" in params:
161
- self._streaming = params["stream"]
162
- else:
163
- self._streaming = False
164
-
165
- # For this release we will not support streaming as many models do not support streaming with tool use
166
- if self._streaming:
167
- warnings.warn(
168
- "Streaming is not currently supported, streaming will be disabled.",
169
- UserWarning,
170
- )
171
- self._streaming = False
172
-
173
- return base_params, additional_params
174
-
175
- def create(self, params):
176
- """Run Amazon Bedrock inference and return AutoGen response"""
177
-
178
- # Set custom client class settings
179
- self.parse_custom_params(params)
180
-
181
- # Parse the inference parameters
182
- base_params, additional_params = self.parse_params(params)
183
-
184
- has_tools = "tools" in params
185
- messages = oai_messages_to_bedrock_messages(params["messages"], has_tools, self._supports_system_prompts)
186
-
187
- if self._supports_system_prompts:
188
- system_messages = extract_system_messages(params["messages"])
189
-
190
- tool_config = format_tools(params["tools"] if has_tools else [])
191
-
192
- request_args = {"messages": messages, "modelId": self._model_id}
193
-
194
- # Base and additional args
195
- if len(base_params) > 0:
196
- request_args["inferenceConfig"] = base_params
197
-
198
- if len(additional_params) > 0:
199
- request_args["additionalModelRequestFields"] = additional_params
200
-
201
- if self._supports_system_prompts:
202
- request_args["system"] = system_messages
203
-
204
- if len(tool_config["tools"]) > 0:
205
- request_args["toolConfig"] = tool_config
206
-
207
- response = self.bedrock_runtime.converse(**request_args)
208
- if response is None:
209
- raise RuntimeError(f"Failed to get response from Bedrock after retrying {self._retries} times.")
210
-
211
- finish_reason = convert_stop_reason_to_finish_reason(response["stopReason"])
212
- response_message = response["output"]["message"]
213
-
214
- if finish_reason == "tool_calls":
215
- tool_calls = format_tool_calls(response_message["content"])
216
- # text = ""
217
- else:
218
- tool_calls = None
219
-
220
- text = ""
221
- for content in response_message["content"]:
222
- if "text" in content:
223
- text = content["text"]
224
- # NOTE: other types of output may be dealt with here
225
-
226
- message = ChatCompletionMessage(role="assistant", content=text, tool_calls=tool_calls)
227
-
228
- response_usage = response["usage"]
229
- usage = CompletionUsage(
230
- prompt_tokens=response_usage["inputTokens"],
231
- completion_tokens=response_usage["outputTokens"],
232
- total_tokens=response_usage["totalTokens"],
233
- )
234
-
235
- return ChatCompletion(
236
- id=response["ResponseMetadata"]["RequestId"],
237
- choices=[Choice(finish_reason=finish_reason, index=0, message=message)],
238
- created=int(time.time()),
239
- model=self._model_id,
240
- object="chat.completion",
241
- usage=usage,
242
- )
243
-
244
- def cost(self, response: ChatCompletion) -> float:
245
- """Calculate the cost of the response."""
246
- return calculate_cost(response.usage.prompt_tokens, response.usage.completion_tokens, response.model)
247
-
248
- @staticmethod
249
- def get_usage(response) -> Dict:
250
- """Get the usage of tokens and their cost information."""
251
- return {
252
- "prompt_tokens": response.usage.prompt_tokens,
253
- "completion_tokens": response.usage.completion_tokens,
254
- "total_tokens": response.usage.total_tokens,
255
- "cost": response.cost,
256
- "model": response.model,
257
- }
258
-
259
-
260
- def extract_system_messages(messages: List[dict]) -> List:
261
- """Extract the system messages from the list of messages.
262
-
263
- Args:
264
- messages (list[dict]): List of messages.
265
-
266
- Returns:
267
- List[SystemMessage]: List of System messages.
268
- """
269
-
270
- """
271
- system_messages = [message.get("content")[0]["text"] for message in messages if message.get("role") == "system"]
272
- return system_messages # ''.join(system_messages)
273
- """
274
-
275
- for message in messages:
276
- if message.get("role") == "system":
277
- if isinstance(message["content"], str):
278
- return [{"text": message.get("content")}]
279
- else:
280
- return [{"text": message.get("content")[0]["text"]}]
281
- return []
282
-
283
-
284
- def oai_messages_to_bedrock_messages(
285
- messages: List[Dict[str, Any]], has_tools: bool, supports_system_prompts: bool
286
- ) -> List[Dict]:
287
- """
288
- Convert messages from OAI format to Bedrock format.
289
- We correct for any specific role orders and types, etc.
290
- AWS Bedrock requires messages to alternate between user and assistant roles. This function ensures that the messages
291
- are in the correct order and format for Bedrock by inserting "Please continue" messages as needed.
292
- This is the same method as the one in the Autogen Anthropic client
293
- """
294
-
295
- # Track whether we have tools passed in. If not, tool use / result messages should be converted to text messages.
296
- # Bedrock requires a tools parameter with the tools listed, if there are other messages with tool use or tool results.
297
- # This can occur when we don't need tool calling, such as for group chat speaker selection
298
-
299
- # Convert messages to Bedrock compliant format
300
-
301
- # Take out system messages if the model supports it, otherwise leave them in.
302
- if supports_system_prompts:
303
- messages = [x for x in messages if not x["role"] == "system"]
304
- else:
305
- # Replace role="system" with role="user"
306
- for msg in messages:
307
- if msg["role"] == "system":
308
- msg["role"] = "user"
309
-
310
- processed_messages = []
311
-
312
- # Used to interweave user messages to ensure user/assistant alternating
313
- user_continue_message = {"content": [{"text": "Please continue."}], "role": "user"}
314
- assistant_continue_message = {
315
- "content": [{"text": "Please continue."}],
316
- "role": "assistant",
317
- }
318
-
319
- tool_use_messages = 0
320
- tool_result_messages = 0
321
- last_tool_use_index = -1
322
- last_tool_result_index = -1
323
- # user_role_index = 0 if supports_system_prompts else 1 # If system prompts are supported, messages start with user, otherwise they'll be the second message
324
- for message in messages:
325
- # New messages will be added here, manage role alternations
326
- expected_role = "user" if len(processed_messages) % 2 == 0 else "assistant"
327
-
328
- if "tool_calls" in message:
329
- # Map the tool call options to Bedrock's format
330
- tool_uses = []
331
- tool_names = []
332
- for tool_call in message["tool_calls"]:
333
- tool_uses.append(
334
- {
335
- "toolUse": {
336
- "toolUseId": tool_call["id"],
337
- "name": tool_call["function"]["name"],
338
- "input": json.loads(tool_call["function"]["arguments"]),
339
- }
340
- }
341
- )
342
- if has_tools:
343
- tool_use_messages += 1
344
- tool_names.append(tool_call["function"]["name"])
345
-
346
- if expected_role == "user":
347
- # Insert an extra user message as we will append an assistant message
348
- processed_messages.append(user_continue_message)
349
-
350
- if has_tools:
351
- processed_messages.append({"role": "assistant", "content": tool_uses})
352
- last_tool_use_index = len(processed_messages) - 1
353
- else:
354
- # Not using tools, so put in a plain text message
355
- processed_messages.append(
356
- {
357
- "role": "assistant",
358
- "content": [
359
- {"text": f"Some internal function(s) that could be used: [{', '.join(tool_names)}]"}
360
- ],
361
- }
362
- )
363
- elif "tool_call_id" in message:
364
- if has_tools:
365
- # Map the tool usage call to tool_result for Bedrock
366
- tool_result = {
367
- "toolResult": {
368
- "toolUseId": message["tool_call_id"],
369
- "content": [{"text": message["content"]}],
370
- }
371
- }
372
-
373
- # If the previous message also had a tool_result, add it to that
374
- # Otherwise append a new message
375
- if last_tool_result_index == len(processed_messages) - 1:
376
- processed_messages[-1]["content"].append(tool_result)
377
- else:
378
- if expected_role == "assistant":
379
- # Insert an extra assistant message as we will append a user message
380
- processed_messages.append(assistant_continue_message)
381
-
382
- processed_messages.append({"role": "user", "content": [tool_result]})
383
- last_tool_result_index = len(processed_messages) - 1
384
-
385
- tool_result_messages += 1
386
- else:
387
- # Not using tools, so put in a plain text message
388
- processed_messages.append(
389
- {
390
- "role": "user",
391
- "content": [{"text": f"Running the function returned: {message['content']}"}],
392
- }
393
- )
394
- elif message["content"] == "":
395
- # Ignoring empty messages
396
- pass
397
- else:
398
- if expected_role != message["role"] and not (len(processed_messages) == 0 and message["role"] == "system"):
399
- # Inserting the alternating continue message (ignore if it's the first message and a system message)
400
- processed_messages.append(
401
- user_continue_message if expected_role == "user" else assistant_continue_message
402
- )
403
-
404
- processed_messages.append(
405
- {
406
- "role": message["role"],
407
- "content": parse_content_parts(message=message),
408
- }
409
- )
410
-
411
- # We'll replace the last tool_use if there's no tool_result (occurs if we finish the conversation before running the function)
412
- if has_tools and tool_use_messages != tool_result_messages:
413
- processed_messages[last_tool_use_index] = assistant_continue_message
414
-
415
- # name is not a valid field on messages
416
- for message in processed_messages:
417
- if "name" in message:
418
- message.pop("name", None)
419
-
420
- # Note: When using reflection_with_llm we may end up with an "assistant" message as the last message and that may cause a blank response
421
- # So, if the last role is not user, add a 'user' continue message at the end
422
- if processed_messages[-1]["role"] != "user":
423
- processed_messages.append(user_continue_message)
424
-
425
- return processed_messages
426
-
427
-
428
- def parse_content_parts(
429
- message: Dict[str, Any],
430
- ) -> List[dict]:
431
- content: str | List[Dict[str, Any]] = message.get("content")
432
- if isinstance(content, str):
433
- return [
434
- {
435
- "text": content,
436
- }
437
- ]
438
- content_parts = []
439
- for part in content:
440
- # part_content: Dict = part.get("content")
441
- if "text" in part: # part_content:
442
- content_parts.append(
443
- {
444
- "text": part.get("text"),
445
- }
446
- )
447
- elif "image_url" in part: # part_content:
448
- image_data, content_type = parse_image(part.get("image_url").get("url"))
449
- content_parts.append(
450
- {
451
- "image": {
452
- "format": content_type[6:], # image/
453
- "source": {"bytes": image_data},
454
- },
455
- }
456
- )
457
- else:
458
- # Ignore..
459
- continue
460
- return content_parts
461
-
462
-
463
- def parse_image(image_url: str) -> Tuple[bytes, str]:
464
- """Try to get the raw data from an image url.
465
-
466
- Ref: https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_ImageSource.html
467
- returns a tuple of (Image Data, Content Type)
468
- """
469
- pattern = r"^data:(image/[a-z]*);base64,\s*"
470
- content_type = re.search(pattern, image_url)
471
- # if already base64 encoded.
472
- # Only supports 'image/jpeg', 'image/png', 'image/gif' or 'image/webp'
473
- if content_type:
474
- image_data = re.sub(pattern, "", image_url)
475
- return base64.b64decode(image_data), content_type.group(1)
476
-
477
- # Send a request to the image URL
478
- response = requests.get(image_url)
479
- # Check if the request was successful
480
- if response.status_code == 200:
481
-
482
- content_type = response.headers.get("Content-Type")
483
- if not content_type.startswith("image"):
484
- content_type = "image/jpeg"
485
- # Get the image content
486
- image_content = response.content
487
- return image_content, content_type
488
- else:
489
- raise RuntimeError("Unable to access the image url")
490
-
491
-
492
- def format_tools(tools: List[Dict[str, Any]]) -> Dict[Literal["tools"], List[Dict[str, Any]]]:
493
- converted_schema = {"tools": []}
494
-
495
- for tool in tools:
496
- if tool["type"] == "function":
497
- function = tool["function"]
498
- converted_tool = {
499
- "toolSpec": {
500
- "name": function["name"],
501
- "description": function["description"],
502
- "inputSchema": {"json": {"type": "object", "properties": {}, "required": []}},
503
- }
504
- }
505
-
506
- for prop_name, prop_details in function["parameters"]["properties"].items():
507
- converted_tool["toolSpec"]["inputSchema"]["json"]["properties"][prop_name] = {
508
- "type": prop_details["type"],
509
- "description": prop_details.get("description", ""),
510
- }
511
- if "enum" in prop_details:
512
- converted_tool["toolSpec"]["inputSchema"]["json"]["properties"][prop_name]["enum"] = prop_details[
513
- "enum"
514
- ]
515
- if "default" in prop_details:
516
- converted_tool["toolSpec"]["inputSchema"]["json"]["properties"][prop_name]["default"] = (
517
- prop_details["default"]
518
- )
519
-
520
- if "required" in function["parameters"]:
521
- converted_tool["toolSpec"]["inputSchema"]["json"]["required"] = function["parameters"]["required"]
522
-
523
- converted_schema["tools"].append(converted_tool)
524
-
525
- return converted_schema
526
-
527
-
528
- def format_tool_calls(content):
529
- """Converts Converse API response tool calls to AutoGen format"""
530
- tool_calls = []
531
- for tool_request in content:
532
- if "toolUse" in tool_request:
533
- tool = tool_request["toolUse"]
534
-
535
- tool_calls.append(
536
- ChatCompletionMessageToolCall(
537
- id=tool["toolUseId"],
538
- function={
539
- "name": tool["name"],
540
- "arguments": json.dumps(tool["input"]),
541
- },
542
- type="function",
543
- )
544
- )
545
- return tool_calls
546
-
547
-
548
- def convert_stop_reason_to_finish_reason(
549
- stop_reason: str,
550
- ) -> Literal["stop", "length", "tool_calls", "content_filter"]:
551
- """
552
- Converts Bedrock finish reasons to our finish reasons, according to OpenAI:
553
-
554
- - stop: if the model hit a natural stop point or a provided stop sequence,
555
- - length: if the maximum number of tokens specified in the request was reached,
556
- - content_filter: if content was omitted due to a flag from our content filters,
557
- - tool_calls: if the model called a tool
558
- """
559
- if stop_reason:
560
- finish_reason_mapping = {
561
- "tool_use": "tool_calls",
562
- "finished": "stop",
563
- "end_turn": "stop",
564
- "max_tokens": "length",
565
- "stop_sequence": "stop",
566
- "complete": "stop",
567
- "content_filtered": "content_filter",
568
- }
569
- return finish_reason_mapping.get(stop_reason.lower(), stop_reason.lower())
570
-
571
- warnings.warn(f"Unsupported stop reason: {stop_reason}", UserWarning)
572
- return None
573
-
574
-
575
- # NOTE: As this will be quite dynamic, it's expected that the developer will use the "price" parameter in their config
576
- # These may be removed.
577
- PRICES_PER_K_TOKENS = {
578
- "meta.llama3-8b-instruct-v1:0": (0.0003, 0.0006),
579
- "meta.llama3-70b-instruct-v1:0": (0.00265, 0.0035),
580
- "mistral.mistral-7b-instruct-v0:2": (0.00015, 0.0002),
581
- "mistral.mixtral-8x7b-instruct-v0:1": (0.00045, 0.0007),
582
- "mistral.mistral-large-2402-v1:0": (0.004, 0.012),
583
- "mistral.mistral-small-2402-v1:0": (0.001, 0.003),
584
- }
585
-
586
-
587
- def calculate_cost(input_tokens: int, output_tokens: int, model_id: str) -> float:
588
- """Calculate the cost of the completion using the Bedrock pricing."""
589
-
590
- if model_id in PRICES_PER_K_TOKENS:
591
- input_cost_per_k, output_cost_per_k = PRICES_PER_K_TOKENS[model_id]
592
- input_cost = (input_tokens / 1000) * input_cost_per_k
593
- output_cost = (output_tokens / 1000) * output_cost_per_k
594
- return input_cost + output_cost
595
- else:
596
- warnings.warn(
597
- f'Cannot get the costs for {model_id}. The cost will be 0. In your config_list, add field {{"price" : [prompt_price_per_1k, completion_token_price_per_1k]}} for customized pricing.',
598
- UserWarning,
599
- )
600
- return 0