Skip to content

Commit

Permalink
Merge pull request #93 from harishmohanraj/fix-upstream-conflicts-2
Browse files Browse the repository at this point in the history
Fix upstream conflicts 2
  • Loading branch information
harishmohanraj authored Jan 22, 2025
2 parents 75468ad + 536efe5 commit 9af6fd0
Show file tree
Hide file tree
Showing 15 changed files with 355 additions and 59 deletions.
11 changes: 11 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,17 @@ repos:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: no-commit-to-branch
- repo: local
hooks:
- id: build-setup-scripts
name: build setup scripts
entry: "scripts/pre-commit-build-setup-files.sh"
language: python
# language_version: python3.9
types: [python]
require_serial: true
verbose: true
additional_dependencies: ['jinja2', 'toml', 'ruff']
- repo: local
hooks:
- id: lint
Expand Down
13 changes: 11 additions & 2 deletions autogen/agentchat/conversable_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,6 @@ def __init__(
code_execution_config.copy() if hasattr(code_execution_config, "copy") else code_execution_config
)

self._validate_name(name)
self._name = name
# a dictionary of conversations, default value is list
if chat_messages is None:
self._oai_messages = defaultdict(list)
Expand All @@ -191,6 +189,8 @@ def __init__(
) from e

self._validate_llm_config(llm_config)
self._validate_name(name)
self._name = name

if logging_enabled():
log_new_agent(self, locals())
Expand Down Expand Up @@ -286,6 +286,15 @@ def __init__(
}

def _validate_name(self, name: str) -> None:
if not self.llm_config or "config_list" not in self.llm_config or len(self.llm_config["config_list"]) == 0:
return

config_list = self.llm_config.get("config_list")
# The validation is currently done only for openai endpoints
# (other ones do not have the issue with whitespace in the name)
if "api_type" in config_list[0] and config_list[0]["api_type"] != "openai":
return

# Validation for name using regex to detect any whitespace
if re.search(r"\s", name):
raise ValueError(f"The name of the agent cannot contain any whitespace. The name provided is: '{name}'")
Expand Down
13 changes: 6 additions & 7 deletions autogen/coding/func_with_reqs.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
#
# Portions derived from https://github.com/microsoft/autogen are under the MIT License.
# SPDX-License-Identifier: MIT
from __future__ import annotations

import functools
import importlib
Expand All @@ -20,7 +19,7 @@
P = ParamSpec("P")


def _to_code(func: FunctionWithRequirements[T, P] | Callable[P, T] | FunctionWithRequirementsStr) -> str:
def _to_code(func: Union["FunctionWithRequirements[T, P]", Callable[P, T], "FunctionWithRequirementsStr"]) -> str:
if isinstance(func, FunctionWithRequirementsStr):
return func.func

Expand All @@ -40,7 +39,7 @@ class Alias:
@dataclass
class ImportFromModule:
module: str
imports: list[str | Alias]
imports: list[Union[str, Alias]]


Import = Union[str, ImportFromModule, Alias]
Expand All @@ -53,7 +52,7 @@ def _import_to_str(im: Import) -> str:
return f"import {im.name} as {im.alias}"
else:

def to_str(i: str | Alias) -> str:
def to_str(i: Union[str, Alias]) -> str:
if isinstance(i, str):
return i
else:
Expand Down Expand Up @@ -123,7 +122,7 @@ class FunctionWithRequirements(Generic[T, P]):
@classmethod
def from_callable(
cls, func: Callable[P, T], python_packages: list[str] = [], global_imports: list[Import] = []
) -> FunctionWithRequirements[T, P]:
) -> "FunctionWithRequirements[T, P]":
return cls(python_packages=python_packages, global_imports=global_imports, func=func)

@staticmethod
Expand Down Expand Up @@ -162,7 +161,7 @@ def wrapper(func: Callable[P, T]) -> FunctionWithRequirements[T, P]:


def _build_python_functions_file(
funcs: list[FunctionWithRequirements[Any, P] | Callable[..., Any] | FunctionWithRequirementsStr],
funcs: list[Union[FunctionWithRequirements[Any, P], Callable[..., Any], FunctionWithRequirementsStr]],
) -> str:
# First collect all global imports
global_imports: set[str] = set()
Expand All @@ -178,7 +177,7 @@ def _build_python_functions_file(
return content


def to_stub(func: Callable[..., Any] | FunctionWithRequirementsStr) -> str:
def to_stub(func: Union[Callable[..., Any], FunctionWithRequirementsStr]) -> str:
"""Generate a stub for a function as a string
Args:
Expand Down
30 changes: 30 additions & 0 deletions autogen/oai/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import inspect
import logging
import re
import sys
import uuid
import warnings
Expand Down Expand Up @@ -289,6 +290,33 @@ def _format_content(content: str) -> str:
for choice in choices
]

@staticmethod
def _is_agent_name_error_message(message: str) -> bool:
pattern = re.compile(r"Invalid 'messages\[\d+\]\.name': string does not match pattern.")
return True if pattern.match(message) else False

@staticmethod
def _handle_openai_bad_request_error(func: Callable[..., Any]) -> Callable[..., Any]:
def wrapper(*args: Any, **kwargs: Any):
try:
return func(*args, **kwargs)
except openai.BadRequestError as e:
response_json = e.response.json()
# Check if the error message is related to the agent name. If so, raise a ValueError with a more informative message.
if "error" in response_json and "message" in response_json["error"]:
if OpenAIClient._is_agent_name_error_message(response_json["error"]["message"]):
error_message = (
f"This error typically occurs when the agent name contains invalid characters, such as spaces or special symbols.\n"
"Please ensure that your agent name follows the correct format and doesn't include any unsupported characters.\n"
"Check the agent name and try again.\n"
f"Here is the full BadRequestError from openai:\n{e.message}."
)
raise ValueError(error_message)

raise e

return wrapper

def create(self, params: dict[str, Any]) -> ChatCompletion:
"""Create a completion for a given config using openai's client.
Expand All @@ -313,6 +341,8 @@ def _create_or_parse(*args, **kwargs):
else:
completions = self._oai_client.chat.completions if "messages" in params else self._oai_client.completions # type: ignore [attr-defined]
create_or_parse = completions.create
# Wrap _create_or_parse with exception handling
create_or_parse = OpenAIClient._handle_openai_bad_request_error(create_or_parse)

# needs to be updated when the o3 is released to generalize
is_o1 = "model" in params and params["model"].startswith("o1")
Expand Down
22 changes: 11 additions & 11 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -180,15 +180,14 @@ bedrock = ["boto3>=1.34.149"]

# test dependencies
test = [
"ipykernel",
"nbconvert",
"nbformat",
"pre-commit",
"pytest-cov>=5",
"pytest-asyncio",
"pytest>=8,<9",
"pandas",
"fastapi>=0.115.0,<1",
"ipykernel==6.29.5",
"nbconvert==7.16.5",
"nbformat==5.10.4",
"pytest-cov==6.0.0",
"pytest-asyncio==0.25.2",
"pytest==8.3.4",
"pandas==2.2.3",
"fastapi==0.115.6",
]

# docs dependencies
Expand All @@ -212,8 +211,9 @@ lint = [
]

dev = [
"toml==0.10.2",
"pyautogen[lint,test,types,docs]",
"pre-commit==4.0.1",
"pre-commit==4.1.0",
"detect-secrets==1.5.0",
"uv==0.5.21",
]
Expand Down Expand Up @@ -271,7 +271,7 @@ fix = true
line-length = 120
target-version = 'py39'
#include = ["autogen", "test", "docs"]
#exclude = []
exclude = ["setup_*.py"]

[tool.ruff.lint]
# Enable Pyflakes `E` and `F` codes by default.
Expand Down
52 changes: 52 additions & 0 deletions scripts/build-setup-files.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#!/usr/bin/env python


# Copyright (c) 2023 - 2024, Owners of https://github.com/ag2ai
#
# SPDX-License-Identifier: Apache-2.0

from pathlib import Path

import toml
from jinja2 import Template


def get_optional_dependencies(pyproject_path: str) -> dict:
with open(pyproject_path, "r") as f:
pyproject_data = toml.load(f)

optional_dependencies = pyproject_data.get("project", {}).get("optional-dependencies", {})
return optional_dependencies


# Example usage
pyproject_path = Path(__file__).parent.joinpath("../pyproject.toml")
optional_dependencies = get_optional_dependencies(pyproject_path)
optional_groups = [group for group in optional_dependencies.keys()]

# for group, dependencies in optional_dependencies.items():
# print(f"Group: {group}")
# for dependency in dependencies:
# print(f" - {dependency}")

template_path = Path(__file__).parents[1].joinpath("setup.jinja")
assert template_path.exists()

with template_path.open("r") as f:
template_str = f.read()

if len(template_str) < 100:
raise ValueError("Template string is too short")

# Create a Jinja2 template object
template = Template(template_str)

for name in ["ag2", "autogen"]:
file_name = f"setup_{name}.py"
file_path = Path(__file__).parents[1].joinpath(file_name)
# Render the template with the optional dependencies
rendered_setup_py = template.render(optional_dependencies=optional_dependencies, name=name)

# Write the rendered setup.py to a file
with file_path.open("w") as setup_file:
setup_file.write(rendered_setup_py)
14 changes: 14 additions & 0 deletions scripts/pre-commit-build-setup-files.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/usr/bin/env bash

# taken from: https://jaredkhan.com/blog/mypy-pre-commit

# A script for running mypy,
# with all its dependencies installed.

set -o errexit

# Change directory to the project root directory.
cd "$(dirname "$0")"/..

./scripts/build-setup-files.py
ruff check -s setup_*.py
45 changes: 45 additions & 0 deletions setup.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Copyright (c) 2023 - 2024, Owners of https://github.com/ag2ai
#
# SPDX-License-Identifier: Apache-2.0

# this file is autogenerated, please do not edit it directly
# instead, edit the corresponding setup.jinja file and run the ./scripts/build-setup-files.py script

import os

import setuptools

here = os.path.abspath(os.path.dirname(__file__))

with open("README.md", "r", encoding="UTF-8") as fh:
long_description = fh.read()

# Get the code version
version = {}
with open(os.path.join(here, "autogen/version.py")) as fp:
exec(fp.read(), version)
__version__ = version["__version__"]

setuptools.setup(
name="{{ name }}",
version=__version__,
description="Alias package for pyautogen",
long_description=long_description,
long_description_content_type="text/markdown",
install_requires=["pyautogen==" + __version__],
extras_require={
{% for group, packages in optional_dependencies.items() -%}
"{{ group }}": ["pyautogen[{{ group }}]==" + __version__],
{% endfor %}
},
url="https://github.com/ag2ai/ag2",
author="Chi Wang & Qingyun Wu",
author_email="[email protected]",
classifiers=[
"Programming Language :: Python :: 3",
"License :: OSI Approved :: Apache Software License",
"Operating System :: OS Independent",
],
license="Apache Software License 2.0",
python_requires=">=3.9,<3.14",
)
29 changes: 18 additions & 11 deletions setup_ag2.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
#
# SPDX-License-Identifier: Apache-2.0

# this file is autogenerated, please do not edit it directly
# instead, edit the corresponding setup.jinja file and run the ./scripts/build-setup-files.py script

import os

import setuptools
Expand All @@ -25,15 +28,22 @@
long_description_content_type="text/markdown",
install_requires=["pyautogen==" + __version__],
extras_require={
"test": ["pyautogen[test]==" + __version__],
"blendsearch": ["pyautogen[blendsearch]==" + __version__],
"mathchat": ["pyautogen[mathchat]==" + __version__],
"flaml": ["pyautogen[flaml]==" + __version__],
"jupyter-executor": ["pyautogen[jupyter-executor]==" + __version__],
"retrievechat": ["pyautogen[retrievechat]==" + __version__],
"retrievechat-pgvector": ["pyautogen[retrievechat-pgvector]==" + __version__],
"retrievechat-mongodb": ["pyautogen[retrievechat-mongodb]==" + __version__],
"retrievechat-qdrant": ["pyautogen[retrievechat-qdrant]==" + __version__],
"graph-rag-falkor-db": ["pyautogen[graph-rag-falkor-db]==" + __version__],
"neo4j": ["pyautogen[neo4j]==" + __version__],
"twilio": ["pyautogen[twilio]==" + __version__],
"interop-crewai": ["pyautogen[interop-crewai]==" + __version__],
"interop-langchain": ["pyautogen[interop-langchain]==" + __version__],
"interop-pydantic-ai": ["pyautogen[interop-pydantic-ai]==" + __version__],
"interop": ["pyautogen[interop]==" + __version__],
"autobuild": ["pyautogen[autobuild]==" + __version__],
"blendsearch": ["pyautogen[blendsearch]==" + __version__],
"mathchat": ["pyautogen[mathchat]==" + __version__],
"captainagent": ["pyautogen[captainagent]==" + __version__],
"teachable": ["pyautogen[teachable]==" + __version__],
"lmm": ["pyautogen[lmm]==" + __version__],
Expand All @@ -44,8 +54,6 @@
"redis": ["pyautogen[redis]==" + __version__],
"cosmosdb": ["pyautogen[cosmosdb]==" + __version__],
"websockets": ["pyautogen[websockets]==" + __version__],
"jupyter-executor": ["pyautogen[jupyter-executor]==" + __version__],
"types": ["pyautogen[types]==" + __version__],
"long-context": ["pyautogen[long-context]==" + __version__],
"anthropic": ["pyautogen[anthropic]==" + __version__],
"cerebras": ["pyautogen[cerebras]==" + __version__],
Expand All @@ -54,13 +62,12 @@
"cohere": ["pyautogen[cohere]==" + __version__],
"ollama": ["pyautogen[ollama]==" + __version__],
"bedrock": ["pyautogen[bedrock]==" + __version__],
"twilio": ["pyautogen[twilio]==" + __version__],
"interop-crewai": ["pyautogen[interop-crewai]==" + __version__],
"interop-langchain": ["pyautogen[interop-langchain]==" + __version__],
"interop-pydantic-ai": ["pyautogen[interop-pydantic-ai]==" + __version__],
"interop": ["pyautogen[interop]==" + __version__],
"neo4j": ["pyautogen[neo4j]==" + __version__],
"test": ["pyautogen[test]==" + __version__],
"docs": ["pyautogen[docs]==" + __version__],
"types": ["pyautogen[types]==" + __version__],
"lint": ["pyautogen[lint]==" + __version__],
"dev": ["pyautogen[dev]==" + __version__],

},
url="https://github.com/ag2ai/ag2",
author="Chi Wang & Qingyun Wu",
Expand Down
Loading

0 comments on commit 9af6fd0

Please sign in to comment.