Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Interoperable protocol and implement tool import from multiple frameworks #197

Merged
merged 93 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
93 commits
Select commit Hold shift + click to select a range
94dd9d7
wip
davorrunje Dec 12, 2024
f112397
wip
davorrunje Dec 12, 2024
65b5452
Initial tools tutorial added
rjambrecic Dec 12, 2024
6e34fbf
Fix incorrect import from crewai
rjambrecic Dec 12, 2024
fc631c3
Merge pull request #205 from rjambrecic/add-tool-imports-upstream
davorrunje Dec 13, 2024
7b22f8b
refactoring
davorrunje Dec 13, 2024
43c7015
Upgrade pytest version to >=8.0.0
rjambrecic Dec 13, 2024
70663d1
Add missing tools and crewai tests
rjambrecic Dec 13, 2024
32e0aef
Add missing test_register_for_execution tools test
rjambrecic Dec 13, 2024
ce4db6c
Add crewai tools integration tutorial
rjambrecic Dec 13, 2024
c38a6d2
Add interop-crewai dependency to setup_ag2 and setup_autogen
rjambrecic Dec 13, 2024
a5482b8
Add interop-crewai dependency in the build.yml
rjambrecic Dec 13, 2024
2ed8126
Merge pull request #207 from rjambrecic/add-tool-imports-upstream
davorrunje Dec 13, 2024
a2aeca0
wip
davorrunje Dec 13, 2024
3af0402
Merge branch 'main' into add-tool-imports
davorrunje Dec 13, 2024
386bc19
docstring added to Tool class
davorrunje Dec 16, 2024
fb30486
docstring added to Tool class
davorrunje Dec 16, 2024
a1c352a
Merge remote-tracking branch 'origin/main' into add-tool-imports
davorrunje Dec 16, 2024
46227d4
restrict Python version for using crewai
davorrunje Dec 16, 2024
9de898e
bug fix
davorrunje Dec 16, 2024
2444445
CI refactoring
davorrunje Dec 16, 2024
c840d2c
Reason added to skipif
davorrunje Dec 16, 2024
2c4e561
import jupyter_kernel_gateway added to embedded ipyhon code executor
davorrunje Dec 16, 2024
63f3949
add interop-crewai target in CI for openai tests
davorrunje Dec 16, 2024
63e311c
Initial LangchainInteroperability implementation
rjambrecic Dec 16, 2024
4a30432
Update LangchainInteroperability tests
rjambrecic Dec 16, 2024
3eefd22
Update setup*.py files with interop-langchain
rjambrecic Dec 16, 2024
a8010e0
Update CI for interop-langchain tests
rjambrecic Dec 16, 2024
e6bec12
Added LLM guidance for tool description for args, added another demo
marklysze Dec 16, 2024
d8c5bac
Update crewai test for function description
marklysze Dec 17, 2024
668defe
Merge remote-tracking branch 'upstream/add-tool-imports' into add-lan…
rjambrecic Dec 17, 2024
f7b8b8b
Merge remote-tracking branch 'upstream/main' into add-langchain
rjambrecic Dec 17, 2024
3d759ee
Update langchain tools integration notebook
rjambrecic Dec 17, 2024
7d194fb
Update langchain tools integration notebook
rjambrecic Dec 17, 2024
a69a29b
Fix typo
rjambrecic Dec 17, 2024
d2f0c53
Clean notebooks output
rjambrecic Dec 17, 2024
296ce69
merge with main
davorrunje Dec 17, 2024
2efbb51
Merge pull request #219 from rjambrecic/add-langchain
davorrunje Dec 17, 2024
1b55bd7
new interop target introduced to simplify CI
davorrunje Dec 17, 2024
c9722b3
refactoring and test fix
davorrunje Dec 17, 2024
1ee6412
Testing pydantic ai tools
rjambrecic Dec 17, 2024
74332eb
Initial pydantic ai tools implementation
rjambrecic Dec 18, 2024
7a7b336
Override register_for_llm function for PydanticAITool
rjambrecic Dec 18, 2024
1740985
Add max_retries to pydantic ai tools interop
rjambrecic Dec 18, 2024
48fece4
Add test_dependency_injection_with_retry
rjambrecic Dec 18, 2024
b045ab1
Update PydanticAIInteroperability comments
rjambrecic Dec 18, 2024
59c0944
new Interoperability class added
davorrunje Dec 18, 2024
fd2b089
fixes
davorrunje Dec 18, 2024
79ea253
Add pydantic_retries.ipynb for pydantic debugging
rjambrecic Dec 18, 2024
89e1ac9
Initial pydantic ai tools notebook tutorial added
rjambrecic Dec 18, 2024
d0eab73
Add tools_pydantic_ai_tools_integration.ipynb tutorial notebook
rjambrecic Dec 18, 2024
64f0d28
Delete testing notebooks and fix type checks
rjambrecic Dec 18, 2024
c5da59d
Merge remote-tracking branch 'origin/main' into add-tool-imports-pyda…
rjambrecic Dec 18, 2024
c929a27
Merge remote-tracking branch 'origin/add-tool-imports' into add-tool-…
rjambrecic Dec 18, 2024
13cdc35
Fix pre-commit
rjambrecic Dec 18, 2024
4ba90f5
Merge pull request #230 from ag2ai/add-tool-imports-pydantic-ai2
davorrunje Dec 18, 2024
7261503
Fix tests
rjambrecic Dec 18, 2024
00ecd98
Fix tests
rjambrecic Dec 18, 2024
cce8f12
Merge pull request #232 from ag2ai/fix-tool-imports-tests
rjambrecic Dec 18, 2024
b4e991f
Fix tests
rjambrecic Dec 18, 2024
5a58008
Merge pull request #233 from ag2ai/fix-tool-imports-tests2
rjambrecic Dec 18, 2024
1cbbb8b
Add kwargs to convert_tool function
rjambrecic Dec 19, 2024
5507bf5
Raise exception if tool expects context but deps param isn't provided
rjambrecic Dec 19, 2024
c731506
Add tools_interoperability.ipynb
rjambrecic Dec 19, 2024
9737cc0
Merge remote-tracking branch 'origin/main' into add-tool-imports-refa…
rjambrecic Dec 19, 2024
659ca04
Add docstrings
rjambrecic Dec 19, 2024
56d5939
fixes
davorrunje Dec 19, 2024
ec6d6be
Merge remote-tracking branch 'origin/main' into add-tool-imports
davorrunje Dec 19, 2024
b41328f
Remove notebooks
rjambrecic Dec 19, 2024
166537e
Merge pull request #236 from ag2ai/add-tool-imports-refactoring-and-docs
davorrunje Dec 19, 2024
2f5462a
Merge branch 'add-tool-imports' into add-tool-imports-refactoring
davorrunje Dec 19, 2024
bfb19b7
fixing types
davorrunje Dec 19, 2024
7641855
refactoring
davorrunje Dec 19, 2024
0711072
WIP interoperability blog
rjambrecic Dec 19, 2024
94c2378
type fixing
davorrunje Dec 19, 2024
2de4a90
refactoring: making convert_tool a class method
davorrunje Dec 19, 2024
9ce614f
Refactoring and test_pydantic_ai_tool.py added
rjambrecic Dec 19, 2024
5adbb53
Merge pull request #237 from ag2ai/add-tool-imports-refactoring
davorrunje Dec 19, 2024
3f644d0
polishing
davorrunje Dec 19, 2024
d5f10ef
Merge pull request #238 from ag2ai/add-tool-imports-refactoring-rj
davorrunje Dec 19, 2024
4fe3a91
polishing
davorrunje Dec 19, 2024
919c04e
polishing
davorrunje Dec 19, 2024
c8cb516
Merge remote-tracking branch 'origin/add-tool-imports' into create-to…
rjambrecic Dec 19, 2024
4d3c079
Interoperability blog wip
rjambrecic Dec 19, 2024
88d6add
test fixing
davorrunje Dec 19, 2024
f080fb1
Update interoperability blog
rjambrecic Dec 19, 2024
4394aaf
Update interoperability blog
rjambrecic Dec 19, 2024
6d2ee6e
fix setup
davorrunje Dec 19, 2024
391cdbd
Merge remote-tracking branch 'origin/main' into add-tool-imports
davorrunje Dec 19, 2024
ba01c09
fix setup
davorrunje Dec 19, 2024
bd877d2
fix version of Pydantic AI
davorrunje Dec 19, 2024
ecf77c5
CI fix
davorrunje Dec 19, 2024
936406d
Merge pull request #239 from ag2ai/create-tools-interop-blog
davorrunje Dec 19, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,14 @@ jobs:
- name: Install packages and dependencies
run: |
python -m pip install --upgrade pip wheel
pip install -e .[cosmosdb]
pip install -e .[test,cosmosdb,interop]
python -c "import autogen"
pip install pytest-cov>=5 mock
- name: Install optional dependencies for code executors
# code executors and udfs auto skip without deps, so only run for python 3.11
if: matrix.python-version == '3.11'
run: |
pip install -e ".[jupyter-executor,test]"
pip install -e ".[jupyter-executor]"
python -m ipykernel install --user --name python3
- name: Set AUTOGEN_USE_DOCKER based on OS
shell: bash
Expand All @@ -97,11 +97,10 @@ jobs:
- name: Coverage with Redis
if: matrix.python-version == '3.10'
run: |
pip install -e .[test,redis,websockets]
pip install -e .[redis,websockets]
pytest test --ignore=test/agentchat/contrib --skip-openai --durations=10 --durations-min=1.0
- name: Test with Cosmos DB
run: |
pip install -e .[test,cosmosdb]
pytest test/cache/test_cosmos_db_cache.py --skip-openai --durations=10 --durations-min=1.0
- name: Upload coverage to Codecov
if: matrix.python-version == '3.10'
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/openai.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ jobs:
if: matrix.python-version == '3.9'
run: |
pip install docker
pip install -e .[redis]
pip install -e .[redis,interop]
- name: Coverage
if: matrix.python-version == '3.9'
env:
Expand Down
6 changes: 6 additions & 0 deletions =8
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Requirement already satisfied: pytest in ./.venv-3.9/lib/python3.9/site-packages (7.4.4)
Requirement already satisfied: iniconfig in ./.venv-3.9/lib/python3.9/site-packages (from pytest) (2.0.0)
Requirement already satisfied: packaging in ./.venv-3.9/lib/python3.9/site-packages (from pytest) (24.2)
Requirement already satisfied: pluggy<2.0,>=0.12 in ./.venv-3.9/lib/python3.9/site-packages (from pytest) (1.5.0)
Requirement already satisfied: exceptiongroup>=1.0.0rc8 in ./.venv-3.9/lib/python3.9/site-packages (from pytest) (1.2.2)
Requirement already satisfied: tomli>=1.0.0 in ./.venv-3.9/lib/python3.9/site-packages (from pytest) (2.2.1)
2 changes: 1 addition & 1 deletion autogen/agentchat/conversable_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -2600,7 +2600,7 @@ def update_function_signature(self, func_sig: Union[str, Dict], is_remove: None)

self.client = OpenAIWrapper(**self.llm_config)

def update_tool_signature(self, tool_sig: Union[str, Dict], is_remove: None):
def update_tool_signature(self, tool_sig: Union[str, Dict], is_remove: bool):
"""update a tool_signature in the LLM configuration for tool_call.
Args:
Expand Down
4 changes: 3 additions & 1 deletion autogen/coding/jupyter/embedded_ipython_code_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@
import uuid
from pathlib import Path
from queue import Empty
from typing import Any, ClassVar, List
from typing import Any, List

# this is needed for CI to work. The import of this file should fail if jupyter-kernel-gateway is not installed
import jupyter_kernel_gateway
davorrunje marked this conversation as resolved.
Show resolved Hide resolved
from jupyter_client import KernelManager # type: ignore[attr-defined]
from jupyter_client.kernelspec import KernelSpecManager
from pydantic import BaseModel, Field, field_validator
Expand Down
12 changes: 12 additions & 0 deletions autogen/interop/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Copyright (c) 2023 - 2024, Owners of https://github.com/ag2ai
#
# SPDX-License-Identifier: Apache-2.0

from .crewai import CrewAIInteroperability
from .interoperability import Interoperability
from .interoperable import Interoperable
from .langchain import LangChainInteroperability
from .pydantic_ai import PydanticAIInteroperability
from .registry import register_interoperable_class

__all__ = ["Interoperability", "Interoperable", "register_interoperable_class"]
7 changes: 7 additions & 0 deletions autogen/interop/crewai/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Copyright (c) 2023 - 2024, Owners of https://github.com/ag2ai
#
# SPDX-License-Identifier: Apache-2.0

from .crewai import CrewAIInteroperability

__all__ = ["CrewAIInteroperability"]
83 changes: 83 additions & 0 deletions autogen/interop/crewai/crewai.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Copyright (c) 2023 - 2024, Owners of https://github.com/ag2ai
#
# SPDX-License-Identifier: Apache-2.0

import re
import sys
from typing import Any, Optional

from ...tools import Tool
from ..registry import register_interoperable_class

__all__ = ["CrewAIInteroperability"]


def _sanitize_name(s: str) -> str:
return re.sub(r"\W|^(?=\d)", "_", s)


@register_interoperable_class("crewai")
class CrewAIInteroperability:
"""
A class implementing the `Interoperable` protocol for converting CrewAI tools
to a general `Tool` format.

This class takes a `CrewAITool` and converts it into a standard `Tool` object.
"""

@classmethod
def convert_tool(cls, tool: Any, **kwargs: Any) -> Tool:
"""
Converts a given CrewAI tool into a general `Tool` format.

This method ensures that the provided tool is a valid `CrewAITool`, sanitizes
the tool's name, processes its description, and prepares a function to interact
with the tool's arguments. It then returns a standardized `Tool` object.

Args:
tool (Any): The tool to convert, expected to be an instance of `CrewAITool`.
**kwargs (Any): Additional arguments, which are not supported by this method.

Returns:
Tool: A standardized `Tool` object converted from the CrewAI tool.

Raises:
ValueError: If the provided tool is not an instance of `CrewAITool`, or if
any additional arguments are passed.
"""
from crewai.tools import BaseTool as CrewAITool

if not isinstance(tool, CrewAITool):
raise ValueError(f"Expected an instance of `crewai.tools.BaseTool`, got {type(tool)}")
if kwargs:
raise ValueError(f"The CrewAIInteroperability does not support any additional arguments, got {kwargs}")

# needed for type checking
crewai_tool: CrewAITool = tool # type: ignore[no-any-unimported]

name = _sanitize_name(crewai_tool.name)
description = (
crewai_tool.description.split("Tool Description: ")[-1]
+ " (IMPORTANT: When using arguments, put them all in an `args` dictionary)"
)

def func(args: crewai_tool.args_schema) -> Any: # type: ignore[no-any-unimported]
return crewai_tool.run(**args.model_dump())

return Tool(
name=name,
description=description,
func=func,
)

@classmethod
def get_unsupported_reason(cls) -> Optional[str]:
if sys.version_info < (3, 10) or sys.version_info >= (3, 13):
return "This submodule is only supported for Python versions 3.10, 3.11, and 3.12"

try:
import crewai.tools
except ImportError:
return "Please install `interop-crewai` extra to use this module:\n\n\tpip install ag2[interop-crewai]"

return None
73 changes: 73 additions & 0 deletions autogen/interop/interoperability.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Copyright (c) 2023 - 2024, Owners of https://github.com/ag2ai
#
# SPDX-License-Identifier: Apache-2.0
from typing import Any, Dict, List, Type

from ..tools import Tool
from .interoperable import Interoperable
from .registry import InteroperableRegistry

__all__ = ["Interoperable"]


class Interoperability:
"""
A class to handle interoperability between different tool types.

This class allows the conversion of tools to various interoperability classes and provides functionality
for retrieving and registering interoperability classes.
"""

registry = InteroperableRegistry.get_instance()

@classmethod
def convert_tool(cls, *, tool: Any, type: str, **kwargs: Any) -> Tool:
"""
Converts a given tool to an instance of a specified interoperability type.

Args:
tool (Any): The tool object to be converted.
type (str): The type of interoperability to convert the tool to.
**kwargs (Any): Additional arguments to be passed during conversion.

Returns:
Tool: The converted tool.

Raises:
ValueError: If the interoperability class for the provided type is not found.
"""
interop = cls.get_interoperability_class(type)
return interop.convert_tool(tool, **kwargs)

@classmethod
def get_interoperability_class(cls, type: str) -> Type[Interoperable]:
"""
Retrieves the interoperability class corresponding to the specified type.

Args:
type (str): The type of the interoperability class to retrieve.

Returns:
Type[Interoperable]: The interoperability class type.

Raises:
ValueError: If no interoperability class is found for the provided type.
"""
supported_types = cls.registry.get_supported_types()
if type not in supported_types:
supported_types_formated = ", ".join(["'t'" for t in supported_types])
raise ValueError(
f"Interoperability class {type} is not supported, supported types: {supported_types_formated}"
)

return cls.registry.get_class(type)

@classmethod
def get_supported_types(cls) -> List[str]:
"""
Returns a sorted list of all supported interoperability types.

Returns:
List[str]: A sorted list of strings representing the supported interoperability types.
"""
return sorted(cls.registry.get_supported_types())
46 changes: 46 additions & 0 deletions autogen/interop/interoperable.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Copyright (c) 2023 - 2024, Owners of https://github.com/ag2ai
#
# SPDX-License-Identifier: Apache-2.0

from typing import Any, Optional, Protocol, runtime_checkable

from ..tools import Tool

__all__ = ["Interoperable"]


@runtime_checkable
class Interoperable(Protocol):
"""
A Protocol defining the interoperability interface for tool conversion.

This protocol ensures that any class implementing it provides the method
`convert_tool` to convert a given tool into a desired format or type.
"""

@classmethod
def convert_tool(cls, tool: Any, **kwargs: Any) -> Tool:
"""
Converts a given tool to a desired format or type.

This method should be implemented by any class adhering to the `Interoperable` protocol.

Args:
tool (Any): The tool object to be converted.
**kwargs (Any): Additional parameters to pass during the conversion process.

Returns:
Tool: The converted tool in the desired format or type.
"""
...

@classmethod
def get_unsupported_reason(cls) -> Optional[str]:
"""Returns the reason for the tool being unsupported.

This method should be implemented by any class adhering to the `Interoperable` protocol.

Returns:
str: The reason for the interoperability class being unsupported.
"""
...
7 changes: 7 additions & 0 deletions autogen/interop/langchain/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Copyright (c) 2023 - 2024, Owners of https://github.com/ag2ai
#
# SPDX-License-Identifier: Apache-2.0

from .langchain import LangChainInteroperability

__all__ = ["LangChainInteroperability"]
76 changes: 76 additions & 0 deletions autogen/interop/langchain/langchain.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Copyright (c) 2023 - 2024, Owners of https://github.com/ag2ai
#
# SPDX-License-Identifier: Apache-2.0

import sys
from typing import Any, Optional

from ...tools import Tool
from ..registry import register_interoperable_class

__all__ = ["LangChainInteroperability"]


@register_interoperable_class("langchain")
class LangChainInteroperability:
"""
A class implementing the `Interoperable` protocol for converting Langchain tools
into a general `Tool` format.

This class takes a `LangchainTool` and converts it into a standard `Tool` object,
ensuring compatibility between Langchain tools and other systems that expect
the `Tool` format.
"""

@classmethod
def convert_tool(cls, tool: Any, **kwargs: Any) -> Tool:
"""
Converts a given Langchain tool into a general `Tool` format.

This method verifies that the provided tool is a valid `LangchainTool`,
processes the tool's input and description, and returns a standardized
`Tool` object.

Args:
tool (Any): The tool to convert, expected to be an instance of `LangchainTool`.
**kwargs (Any): Additional arguments, which are not supported by this method.

Returns:
Tool: A standardized `Tool` object converted from the Langchain tool.

Raises:
ValueError: If the provided tool is not an instance of `LangchainTool`, or if
any additional arguments are passed.
"""
from langchain_core.tools import BaseTool as LangchainTool

if not isinstance(tool, LangchainTool):
raise ValueError(f"Expected an instance of `langchain_core.tools.BaseTool`, got {type(tool)}")
if kwargs:
raise ValueError(f"The LangchainInteroperability does not support any additional arguments, got {kwargs}")

# needed for type checking
langchain_tool: LangchainTool = tool # type: ignore

def func(tool_input: langchain_tool.args_schema) -> Any: # type: ignore
return langchain_tool.run(tool_input.model_dump())

return Tool(
name=langchain_tool.name,
description=langchain_tool.description,
func=func,
)

@classmethod
def get_unsupported_reason(cls) -> Optional[str]:
if sys.version_info < (3, 9):
return "This submodule is only supported for Python versions 3.9 and above"

try:
import langchain_core.tools
except ImportError:
return (
"Please install `interop-langchain` extra to use this module:\n\n\tpip install ag2[interop-langchain]"
)

return None
7 changes: 7 additions & 0 deletions autogen/interop/pydantic_ai/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Copyright (c) 2023 - 2024, Owners of https://github.com/ag2ai
#
# SPDX-License-Identifier: Apache-2.0

from .pydantic_ai import PydanticAIInteroperability

__all__ = ["PydanticAIInteroperability"]
Loading
Loading