Files
2026-07-13 12:38:34 +08:00

120 lines
4.0 KiB
Python

import hashlib
import types
import typing as t
from inspect import Signature
import autogen
from autogen.agentchat.conversable_agent import ConversableAgent
from autogen_core.tools import FunctionTool
from composio.client.types import Tool
from composio.core.provider import AgenticProvider
from composio.core.provider.agentic import AgenticProviderExecuteFn
from composio.utils.shared import (
get_signature_format_from_schema_params,
normalize_tool_arguments,
reinstate_reserved_python_keywords,
substitute_reserved_python_keywords,
)
class AutogenProvider(
AgenticProvider[FunctionTool, list[FunctionTool]],
name="autogen",
):
"""
Composio toolset for Autogen framework.
"""
def _process_function_name_for_registration(
self,
input_string: str,
max_allowed_length: int = 64,
num_hash_char: int = 10,
):
"""
Process function name for proxy registration under given character length limitation.
"""
hash_hex = hashlib.sha256(input_string.encode(encoding="utf-8")).hexdigest()
hash_chars_to_attach = hash_hex[:10]
num_input_str_char = max_allowed_length - (num_hash_char + 1)
input_str_to_attach = input_string[-num_input_str_char:]
processed_name = input_str_to_attach + "_" + hash_chars_to_attach
return processed_name
def register_tools(
self,
caller: ConversableAgent,
executor: ConversableAgent,
tools: t.List[FunctionTool],
) -> None:
"""
Register tools to the proxy agents.
:param executor: Executor agent.
:param caller: Caller agent.
:param tools: List of tools to register.
"""
for tool in tools:
autogen.agentchat.register_function(
f=tool._func,
caller=caller,
executor=executor,
name=tool.name,
description=tool.description,
)
def wrap_tool(
self,
tool: Tool,
execute_tool: AgenticProviderExecuteFn,
) -> FunctionTool:
"""Wraps a composio tool as an Autogen FunctionTool."""
schema_params, keywords = substitute_reserved_python_keywords(
schema=tool.input_parameters
)
def execute_action(**kwargs: t.Any) -> t.Dict:
"""Placeholder function for executing action."""
kwargs = reinstate_reserved_python_keywords(
request=kwargs, keywords=keywords
)
# Normalize defensively so a stringified payload is coerced to a dict (issue #2406).
return execute_tool(
slug=tool.slug, arguments=normalize_tool_arguments(kwargs)
)
# Create function with proper signature
function = types.FunctionType(
code=execute_action.__code__,
globals=globals(),
closure=execute_action.__closure__,
name=self._process_function_name_for_registration(input_string=tool.slug),
)
# Set signature and annotations
params = get_signature_format_from_schema_params(
schema_params=schema_params,
skip_default=self.skip_default,
)
function.__doc__ = tool.description
setattr(function, "__signature__", Signature(parameters=params))
setattr(
function,
"__annotations__",
{p.name: p.annotation for p in params} | {"return": t.Dict[str, t.Any]},
)
return FunctionTool(
func=function,
description=tool.description,
name=self._process_function_name_for_registration(input_string=tool.slug),
)
def wrap_tools(
self,
tools: t.Sequence[Tool],
execute_tool: AgenticProviderExecuteFn,
) -> list[FunctionTool]:
"""Wraps array of composio tools as an Autogen FunctionTool."""
return [self.wrap_tool(tool=tool, execute_tool=execute_tool) for tool in tools]