-
Notifications
You must be signed in to change notification settings - Fork 6.9k
Adding declarative HTTP tools to autogen ext #5181
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
Merged
+565
−5
Merged
Changes from all commits
Commits
Show all changes
46 commits
Select commit
Hold shift + click to select a range
57cbb2e
initial commit for declarative-mcp-tools
EItanya dd00059
update without local deps
EItanya db763d5
Merge branch 'main' of https://github.com/microsoft/autogen into decl…
EItanya 9c4a00b
remove MCP and add more http options
EItanya 95fc65e
unit tests are working
EItanya 3c1a8ce
Merge branch 'main' into declarative-mcp-tools
EItanya 7b644e2
works again with path params stuff
EItanya 873ac5c
add unit tests for the new path params stuff
EItanya dfb9b50
unit tests now fully passing with params, example works with httpbin …
EItanya 7395c0a
update docs for args
EItanya 98b0519
revert autogen studio
EItanya 4644bc8
formatting
EItanya 1773520
Merge branch 'main' into declarative-mcp-tools
EItanya 64c08a6
Merge branch 'main' into declarative-mcp-tools
EItanya 65b7c72
Merge branch 'main' into declarative-mcp-tools
EItanya 4f9901e
update deps
EItanya b55ac3e
merge with main
EItanya e6b14df
add respose_type and tests
EItanya 09f653f
run check
EItanya f572696
fix pyright checks
EItanya c6a1c38
make mypy happy
EItanya e6d1728
Merge branch 'main' into declarative-mcp-tools
EItanya 2e611c1
move the graphrag tests into a subdir to not leak conftest.py
EItanya c35d6a2
Merge branch 'main' into declarative-mcp-tools
EItanya ade7e65
Merge branch 'main' into declarative-mcp-tools
victordibia 3272eb3
Merge branch 'main' into declarative-mcp-tools
victordibia d6e176a
PR comments
EItanya ad30c83
Merge branch 'main' into declarative-mcp-tools
EItanya d25e119
udpate uv.lock
EItanya 0a51544
Merge branch 'main' into declarative-mcp-tools
ekzhu 58718a8
Merge branch 'main' of https://github.com/microsoft/autogen into decl…
EItanya 286a628
mypy finally passing
EItanya cade3e6
Merge branch 'main' of https://github.com/microsoft/autogen into decl…
EItanya 59f2139
Merge branch 'main' into declarative-mcp-tools
ekzhu a3a175e
Merge branch 'main' into declarative-mcp-tools
ekzhu 220ad3e
Merge branch 'main' into declarative-mcp-tools
ekzhu 2b48ea1
Merge branch 'main' into declarative-mcp-tools
ekzhu 4ad329e
merge with main
EItanya 07c526f
Merge branch 'declarative-mcp-tools' of github.com:EItanya/autogen in…
EItanya 6ccbcf1
ignore excluded mypy error
EItanya 405f3f6
fix import
EItanya 7853cfb
Merge branch 'main' into declarative-mcp-tools
EItanya bbae288
Merge branch 'main' into declarative-mcp-tools
EItanya 053c424
Merge branch 'main' into declarative-mcp-tools
ekzhu 03b14f9
format
ekzhu 0dea967
doc: update API reference and add documentation for http tool
ekzhu File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8 changes: 8 additions & 0 deletions
8
python/packages/autogen-core/docs/src/reference/python/autogen_ext.tools.http.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
autogen\_ext.tools.http | ||
======================= | ||
|
||
|
||
.. automodule:: autogen_ext.tools.http | ||
:members: | ||
:undoc-members: | ||
:show-inheritance: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
3 changes: 3 additions & 0 deletions
3
python/packages/autogen-ext/src/autogen_ext/tools/http/__init__.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from ._http_tool import HttpTool | ||
|
||
__all__ = ["HttpTool"] |
233 changes: 233 additions & 0 deletions
233
python/packages/autogen-ext/src/autogen_ext/tools/http/_http_tool.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,233 @@ | ||
import re | ||
from typing import Any, Literal, Optional, Type | ||
|
||
import httpx | ||
from autogen_core import CancellationToken, Component | ||
from autogen_core.tools import BaseTool | ||
from json_schema_to_pydantic import create_model | ||
from pydantic import BaseModel, Field | ||
from typing_extensions import Self | ||
|
||
|
||
class HttpToolConfig(BaseModel): | ||
name: str | ||
""" | ||
The name of the tool. | ||
""" | ||
description: Optional[str] | ||
""" | ||
A description of the tool. | ||
""" | ||
scheme: Literal["http", "https"] = "http" | ||
""" | ||
The scheme to use for the request. | ||
""" | ||
host: str | ||
""" | ||
The URL to send the request to. | ||
""" | ||
port: int | ||
""" | ||
The port to send the request to. | ||
""" | ||
path: str = Field(default="/") | ||
""" | ||
The path to send the request to. defaults to "/" | ||
The path can accept parameters, e.g. "/{param1}/{param2}". | ||
These parameters will be templated from the inputs args, any additional parameters will be added as query parameters or the body of the request. | ||
""" | ||
method: Optional[Literal["GET", "POST", "PUT", "DELETE", "PATCH"]] = "POST" | ||
""" | ||
The HTTP method to use, will default to POST if not provided. | ||
""" | ||
headers: Optional[dict[str, Any]] | ||
""" | ||
A dictionary of headers to send with the request. | ||
""" | ||
json_schema: dict[str, Any] | ||
victordibia marked this conversation as resolved.
Show resolved
Hide resolved
|
||
""" | ||
A JSON Schema object defining the expected parameters for the tool. | ||
Path parameters MUST also be included in the json_schema. They must also MUST be set to string | ||
""" | ||
return_type: Optional[Literal["text", "json"]] = "text" | ||
""" | ||
The type of response to return from the tool. | ||
""" | ||
|
||
|
||
class HttpTool(BaseTool[BaseModel, Any], Component[HttpToolConfig]): | ||
"""A wrapper for using an HTTP server as a tool. | ||
|
||
Args: | ||
name (str): The name of the tool. | ||
description (str, optional): A description of the tool. | ||
scheme (str): The scheme to use for the request. Must be either "http" or "https". | ||
host (str): The host to send the request to. | ||
port (int): The port to send the request to. | ||
path (str, optional): The path to send the request to. Defaults to "/". | ||
Can include path parameters like "/{param1}/{param2}" which will be templated from input args. | ||
method (str, optional): The HTTP method to use, will default to POST if not provided. | ||
Must be one of "GET", "POST", "PUT", "DELETE", "PATCH". | ||
headers (dict[str, Any], optional): A dictionary of headers to send with the request. | ||
json_schema (dict[str, Any]): A JSON Schema object defining the expected parameters for the tool. | ||
Path parameters must also be included in the schema and must be strings. | ||
return_type (Literal["text", "json"], optional): The type of response to return from the tool. | ||
Defaults to "text". | ||
|
||
ekzhu marked this conversation as resolved.
Show resolved
Hide resolved
|
||
.. note:: | ||
This tool requires the :code:`http-tool` extra for the :code:`autogen-ext` package. | ||
|
||
To install: | ||
|
||
.. code-block:: bash | ||
|
||
pip install -U "autogen-agentchat" "autogen-ext[http-tool]" | ||
|
||
Example: | ||
Simple use case:: | ||
|
||
import asyncio | ||
|
||
from autogen_agentchat.agents import AssistantAgent | ||
from autogen_agentchat.messages import TextMessage | ||
from autogen_core import CancellationToken | ||
from autogen_ext.models.openai import OpenAIChatCompletionClient | ||
from autogen_ext.tools.http import HttpTool | ||
|
||
# Define a JSON schema for a base64 decode tool | ||
base64_schema = { | ||
"type": "object", | ||
"properties": { | ||
"value": {"type": "string", "description": "The base64 value to decode"}, | ||
}, | ||
"required": ["value"], | ||
} | ||
|
||
# Create an HTTP tool for the httpbin API | ||
base64_tool = HttpTool( | ||
name="base64_decode", | ||
description="base64 decode a value", | ||
scheme="https", | ||
host="httpbin.org", | ||
port=443, | ||
path="/base64/{value}", | ||
method="GET", | ||
json_schema=base64_schema, | ||
) | ||
|
||
|
||
async def main(): | ||
# Create an assistant with the base64 tool | ||
model = OpenAIChatCompletionClient(model="gpt-4") | ||
assistant = AssistantAgent("base64_assistant", model_client=model, tools=[base64_tool]) | ||
|
||
# The assistant can now use the base64 tool to decode the string | ||
response = await assistant.on_messages( | ||
[TextMessage(content="Can you base64 decode the value 'YWJjZGU=', please?", source="user")], | ||
CancellationToken(), | ||
) | ||
print(response.chat_message.content) | ||
|
||
|
||
asyncio.run(main()) | ||
""" | ||
|
||
component_type = "tool" | ||
component_provider_override = "autogen_ext.tools.http.HttpTool" | ||
component_config_schema = HttpToolConfig | ||
|
||
def __init__( | ||
self, | ||
name: str, | ||
host: str, | ||
port: int, | ||
json_schema: dict[str, Any], | ||
headers: Optional[dict[str, Any]] = None, | ||
description: str = "HTTP tool", | ||
path: str = "/", | ||
scheme: Literal["http", "https"] = "http", | ||
method: Literal["GET", "POST", "PUT", "DELETE", "PATCH"] = "POST", | ||
return_type: Literal["text", "json"] = "text", | ||
) -> None: | ||
self.server_params = HttpToolConfig( | ||
name=name, | ||
description=description, | ||
host=host, | ||
port=port, | ||
path=path, | ||
scheme=scheme, | ||
method=method, | ||
headers=headers, | ||
json_schema=json_schema, | ||
return_type=return_type, | ||
) | ||
|
||
# Use regex to find all path parameters, we will need those later to template the path | ||
path_params = {match.group(1) for match in re.finditer(r"{([^}]*)}", path)} | ||
self._path_params = path_params | ||
|
||
# Create the input model from the modified schema | ||
input_model = create_model(json_schema) | ||
|
||
# Use Any as return type since HTTP responses can vary | ||
base_return_type: Type[Any] = object | ||
|
||
super().__init__(input_model, base_return_type, name, description) | ||
|
||
def _to_config(self) -> HttpToolConfig: | ||
copied_config = self.server_params.model_copy() | ||
return copied_config | ||
|
||
@classmethod | ||
def _from_config(cls, config: HttpToolConfig) -> Self: | ||
copied_config = config.model_copy().model_dump() | ||
return cls(**copied_config) | ||
|
||
async def run(self, args: BaseModel, cancellation_token: CancellationToken) -> Any: | ||
"""Execute the HTTP tool with the given arguments. | ||
|
||
Args: | ||
args: The validated input arguments | ||
cancellation_token: Token for cancelling the operation | ||
|
||
Returns: | ||
The response body from the HTTP call in JSON format | ||
|
||
Raises: | ||
Exception: If tool execution fails | ||
""" | ||
|
||
model_dump = args.model_dump() | ||
path_params = {k: v for k, v in model_dump.items() if k in self._path_params} | ||
# Remove path params from the model dump | ||
for k in self._path_params: | ||
model_dump.pop(k) | ||
|
||
path = self.server_params.path.format(**path_params) | ||
|
||
url = httpx.URL( | ||
scheme=self.server_params.scheme, | ||
host=self.server_params.host, | ||
port=self.server_params.port, | ||
path=path, | ||
) | ||
async with httpx.AsyncClient() as client: | ||
match self.server_params.method: | ||
case "GET": | ||
response = await client.get(url, params=model_dump) | ||
case "PUT": | ||
response = await client.put(url, json=model_dump) | ||
case "DELETE": | ||
response = await client.delete(url, params=model_dump) | ||
case "PATCH": | ||
response = await client.patch(url, json=model_dump) | ||
case _: # Default case POST | ||
response = await client.post(url, json=model_dump) | ||
|
||
match self.server_params.return_type: | ||
case "text": | ||
return response.text | ||
case "json": | ||
return response.json() | ||
case _: | ||
raise ValueError(f"Invalid return type: {self.server_params.return_type}") |
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
Empty file.
File renamed without changes.
File renamed without changes.
Empty file.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.