Skip to content

Commit

Permalink
Merge branch 'main' into k8s-code-executor
Browse files Browse the repository at this point in the history
  • Loading branch information
questcollector authored Aug 26, 2024
2 parents 87c841a + f44309b commit da2097e
Show file tree
Hide file tree
Showing 88 changed files with 4,917 additions and 104 deletions.
40 changes: 40 additions & 0 deletions .github/workflows/contrib-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -612,3 +612,43 @@ jobs:
with:
file: ./coverage.xml
flags: unittests

BedrockTest:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-2019]
python-version: ["3.9", "3.10", "3.11", "3.12"]
exclude:
- os: macos-latest
python-version: "3.9"
steps:
- uses: actions/checkout@v4
with:
lfs: true
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install packages and dependencies for all tests
run: |
python -m pip install --upgrade pip wheel
pip install pytest-cov>=5
- name: Install packages and dependencies for Amazon Bedrock
run: |
pip install -e .[boto3,test]
- name: Set AUTOGEN_USE_DOCKER based on OS
shell: bash
run: |
if [[ ${{ matrix.os }} != ubuntu-latest ]]; then
echo "AUTOGEN_USE_DOCKER=False" >> $GITHUB_ENV
fi
- name: Coverage
run: |
pytest test/oai/test_bedrock.py --skip-openai
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
file: ./coverage.xml
flags: unittests
2 changes: 1 addition & 1 deletion .github/workflows/dotnet-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest, macos-latest, windows-latest ]
os: [ ubuntu-latest, macos-latest ]
python-version: ["3.11"]
runs-on: ${{ matrix.os }}
timeout-minutes: 30
Expand Down
3 changes: 2 additions & 1 deletion CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@
| Beibin Li | [BeibinLi](https://github.com/BeibinLi) | Microsoft Research | alt-models | Yes | |
| Gagan Bansal | [gagb](https://github.com/gagb) | Microsoft Research | Complex Tasks | | |
| Adam Fourney | [afourney](https://github.com/afourney) | Microsoft Research | Complex Tasks | | |
| Ricky Loynd | [rickyloyn-microsoft](https://github.com/rickyloynd-microsoft) | Microsoft Research | Learning | | |
| Ricky Loynd | [rickyloynd-microsoft](https://github.com/rickyloynd-microsoft) | Microsoft Research | Teachability | | |
| Eric Zhu | [ekzhu](https://github.com/ekzhu) | Microsoft Research | Infra | | |
| Jack Gerrits | [jackgerrits](https://github.com/jackgerrits) | Microsoft Research | Infra | | |
| David Luong | [David Luong](https://github.com/DavidLuong98) | Microsoft | AutoGen.Net | | |


## I would like to join this list. How can I help the project?
Expand Down
3 changes: 1 addition & 2 deletions autogen/agentchat/contrib/capabilities/transform_messages.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import copy
from typing import Dict, List

from autogen import ConversableAgent

from ....formatting_utils import colored
from ...conversable_agent import ConversableAgent
from .transforms import MessageTransform


Expand Down
92 changes: 92 additions & 0 deletions autogen/agentchat/contrib/capabilities/transforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -445,3 +445,95 @@ def _compress_text(self, text: str) -> Tuple[str, int]:
def _validate_min_tokens(self, min_tokens: Optional[int]):
if min_tokens is not None and min_tokens <= 0:
raise ValueError("min_tokens must be greater than 0 or None")


class TextMessageContentName:
"""A transform for including the agent's name in the content of a message."""

def __init__(
self,
position: str = "start",
format_string: str = "{name}:\n",
deduplicate: bool = True,
filter_dict: Optional[Dict] = None,
exclude_filter: bool = True,
):
"""
Args:
position (str): The position to add the name to the content. The possible options are 'start' or 'end'. Defaults to 'start'.
format_string (str): The f-string to format the message name with. Use '{name}' as a placeholder for the agent's name. Defaults to '{name}:\n' and must contain '{name}'.
deduplicate (bool): Whether to deduplicate the formatted string so it doesn't appear twice (sometimes the LLM will add it to new messages itself). Defaults to True.
filter_dict (None or dict): A dictionary to filter out messages that you want/don't want to compress.
If None, no filters will be applied.
exclude_filter (bool): If exclude filter is True (the default value), messages that match the filter will be
excluded from compression. If False, messages that match the filter will be compressed.
"""

assert isinstance(position, str) and position is not None
assert position in ["start", "end"]
assert isinstance(format_string, str) and format_string is not None
assert "{name}" in format_string
assert isinstance(deduplicate, bool) and deduplicate is not None

self._position = position
self._format_string = format_string
self._deduplicate = deduplicate
self._filter_dict = filter_dict
self._exclude_filter = exclude_filter

# Track the number of messages changed for logging
self._messages_changed = 0

def apply_transform(self, messages: List[Dict]) -> List[Dict]:
"""Applies the name change to the message based on the position and format string.
Args:
messages (List[Dict]): A list of message dictionaries.
Returns:
List[Dict]: A list of dictionaries with the message content updated with names.
"""
# Make sure there is at least one message
if not messages:
return messages

messages_changed = 0
processed_messages = copy.deepcopy(messages)
for message in processed_messages:
# Some messages may not have content.
if not transforms_util.is_content_right_type(
message.get("content")
) or not transforms_util.is_content_right_type(message.get("name")):
continue

if not transforms_util.should_transform_message(message, self._filter_dict, self._exclude_filter):
continue

if transforms_util.is_content_text_empty(message["content"]) or transforms_util.is_content_text_empty(
message["name"]
):
continue

# Get and format the name in the content
content = message["content"]
formatted_name = self._format_string.format(name=message["name"])

if self._position == "start":
if not self._deduplicate or not content.startswith(formatted_name):
message["content"] = f"{formatted_name}{content}"

messages_changed += 1
else:
if not self._deduplicate or not content.endswith(formatted_name):
message["content"] = f"{content}{formatted_name}"

messages_changed += 1

self._messages_changed = messages_changed
return processed_messages

def get_logs(self, pre_transform_messages: List[Dict], post_transform_messages: List[Dict]) -> Tuple[str, bool]:
if self._messages_changed > 0:
return f"{self._messages_changed} message(s) changed to incorporate name.", True
else:
return "No messages changed to incorporate name.", False
2 changes: 1 addition & 1 deletion autogen/agentchat/contrib/vectordb/qdrant.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ def __init__(
kwargs: dict | Additional keyword arguments.
"""
self.client: QdrantClient = client or QdrantClient(location=":memory:")
self.embedding_function = FastEmbedEmbeddingFunction() or embedding_function
self.embedding_function = embedding_function or FastEmbedEmbeddingFunction()
self.collection_options = collection_options
self.content_payload_key = content_payload_key
self.metadata_payload_key = metadata_payload_key
Expand Down
40 changes: 35 additions & 5 deletions autogen/agentchat/groupchat.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import re
import sys
from dataclasses import dataclass, field
from typing import Callable, Dict, List, Literal, Optional, Tuple, Union
from typing import Any, Callable, Dict, List, Literal, Optional, Tuple, Union

from ..code_utils import content_str
from ..exception_utils import AgentNameConflict, NoEligibleSpeaker, UndefinedNextAgent
Expand All @@ -17,6 +17,12 @@
from .chat import ChatResult
from .conversable_agent import ConversableAgent

try:
# Non-core module
from .contrib.capabilities import transform_messages
except ImportError:
transform_messages = None

logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -76,6 +82,8 @@ def custom_speaker_selection_func(
of times until a single agent is returned or it exhausts the maximum attempts.
Applies only to "auto" speaker selection method.
Default is 2.
- select_speaker_transform_messages: (optional) the message transformations to apply to the nested select speaker agent-to-agent chat messages.
Takes a TransformMessages object, defaults to None and is only utilised when the speaker selection method is "auto".
- select_speaker_auto_verbose: whether to output the select speaker responses and selections
If set to True, the outputs from the two agents in the nested select speaker chat will be output, along with
whether the responses were successful, or not, in selecting an agent
Expand Down Expand Up @@ -132,6 +140,7 @@ def custom_speaker_selection_func(
The names are case-sensitive and should not be abbreviated or changed.
The only names that are accepted are {agentlist}.
Respond with ONLY the name of the speaker and DO NOT provide a reason."""
select_speaker_transform_messages: Optional[Any] = None
select_speaker_auto_verbose: Optional[bool] = False
role_for_select_speaker_messages: Optional[str] = "system"

Expand Down Expand Up @@ -249,6 +258,20 @@ def __post_init__(self):
elif self.max_retries_for_selecting_speaker < 0:
raise ValueError("max_retries_for_selecting_speaker must be greater than or equal to zero")

# Load message transforms here (load once for the Group Chat so we don't have to re-initiate it and it maintains the cache across subsequent select speaker calls)
self._speaker_selection_transforms = None
if self.select_speaker_transform_messages is not None:
if transform_messages is not None:
if isinstance(self.select_speaker_transform_messages, transform_messages.TransformMessages):
self._speaker_selection_transforms = self.select_speaker_transform_messages
else:
raise ValueError("select_speaker_transform_messages must be None or MessageTransforms.")
else:
logger.warning(
"TransformMessages could not be loaded, the 'select_speaker_transform_messages' transform"
"will not apply."
)

# Validate select_speaker_auto_verbose
if self.select_speaker_auto_verbose is None or not isinstance(self.select_speaker_auto_verbose, bool):
raise ValueError("select_speaker_auto_verbose cannot be None or non-bool")
Expand Down Expand Up @@ -655,6 +678,10 @@ def validate_speaker_name(recipient, messages, sender, config) -> Tuple[bool, Un
else:
start_message = messages[-1]

# Add the message transforms, if any, to the speaker selection agent
if self._speaker_selection_transforms is not None:
self._speaker_selection_transforms.add_to_agent(speaker_selection_agent)

# Run the speaker selection chat
result = checking_agent.initiate_chat(
speaker_selection_agent,
Expand Down Expand Up @@ -749,6 +776,10 @@ def validate_speaker_name(recipient, messages, sender, config) -> Tuple[bool, Un
else:
start_message = messages[-1]

# Add the message transforms, if any, to the speaker selection agent
if self._speaker_selection_transforms is not None:
self._speaker_selection_transforms.add_to_agent(speaker_selection_agent)

# Run the speaker selection chat
result = await checking_agent.a_initiate_chat(
speaker_selection_agent,
Expand Down Expand Up @@ -1264,11 +1295,10 @@ def resume(
if not message_speaker_agent and message["name"] == self.name:
message_speaker_agent = self

# Add previous messages to each agent (except their own messages and the last message, as we'll kick off the conversation with it)
# Add previous messages to each agent (except the last message, as we'll kick off the conversation with it)
if i != len(messages) - 1:
for agent in self._groupchat.agents:
if agent.name != message["name"]:
self.send(message, self._groupchat.agent_by_name(agent.name), request_reply=False, silent=True)
self.send(message, self._groupchat.agent_by_name(agent.name), request_reply=False, silent=True)

# Add previous message to the new groupchat, if it's an admin message the name may not match so add the message directly
if message_speaker_agent:
Expand Down Expand Up @@ -1310,7 +1340,7 @@ def resume(
async def a_resume(
self,
messages: Union[List[Dict], str],
remove_termination_string: Union[str, Callable[[str], str]],
remove_termination_string: Union[str, Callable[[str], str]] = None,
silent: Optional[bool] = False,
) -> Tuple[ConversableAgent, Dict]:
"""Resumes a group chat using the previous messages as a starting point, asynchronously. Requires the agents, group chat, and group chat manager to be established
Expand Down
8 changes: 4 additions & 4 deletions autogen/coding/func_with_reqs.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from dataclasses import dataclass, field
from importlib.abc import SourceLoader
from textwrap import dedent, indent
from typing import Any, Callable, Generic, List, TypeVar, Union
from typing import Any, Callable, Generic, List, Set, TypeVar, Union

from typing_extensions import ParamSpec

Expand Down Expand Up @@ -159,12 +159,12 @@ def _build_python_functions_file(
funcs: List[Union[FunctionWithRequirements[Any, P], Callable[..., Any], FunctionWithRequirementsStr]]
) -> str:
# First collect all global imports
global_imports = set()
global_imports: Set[str] = set()
for func in funcs:
if isinstance(func, (FunctionWithRequirements, FunctionWithRequirementsStr)):
global_imports.update(func.global_imports)
global_imports.update(map(_import_to_str, func.global_imports))

content = "\n".join(map(_import_to_str, global_imports)) + "\n\n"
content = "\n".join(global_imports) + "\n\n"

for func in funcs:
content += _to_code(func) + "\n\n"
Expand Down
2 changes: 2 additions & 0 deletions autogen/logger/file_logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
if TYPE_CHECKING:
from autogen import Agent, ConversableAgent, OpenAIWrapper
from autogen.oai.anthropic import AnthropicClient
from autogen.oai.bedrock import BedrockClient
from autogen.oai.cohere import CohereClient
from autogen.oai.gemini import GeminiClient
from autogen.oai.groq import GroqClient
Expand Down Expand Up @@ -215,6 +216,7 @@ def log_new_client(
| TogetherClient
| GroqClient
| CohereClient
| BedrockClient
),
wrapper: OpenAIWrapper,
init_args: Dict[str, Any],
Expand Down
2 changes: 2 additions & 0 deletions autogen/logger/sqlite_logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
if TYPE_CHECKING:
from autogen import Agent, ConversableAgent, OpenAIWrapper
from autogen.oai.anthropic import AnthropicClient
from autogen.oai.bedrock import BedrockClient
from autogen.oai.cohere import CohereClient
from autogen.oai.gemini import GeminiClient
from autogen.oai.groq import GroqClient
Expand Down Expand Up @@ -402,6 +403,7 @@ def log_new_client(
TogetherClient,
GroqClient,
CohereClient,
BedrockClient,
],
wrapper: OpenAIWrapper,
init_args: Dict[str, Any],
Expand Down
Loading

0 comments on commit da2097e

Please sign in to comment.