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

MotleyRunnable #41

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion motleycrew/agents/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from .langchain import LangchainMotleyAgent
from .crewai import CrewAIMotleyAgentParent
from .crewai import CrewAIMotleyAgent
from .llama_index import LlamaIndexMotleyAgent
4 changes: 1 addition & 3 deletions motleycrew/agents/crewai/crewai.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@
from langchain_core.runnables import RunnableConfig

from motleycrew.agents.parent import MotleyAgentParent
from motleycrew.agents.abstract_parent import MotleyAgentAbstractParent
from motleycrew.agents.crewai import CrewAIAgentWithConfig
from motleycrew.common import MotleySupportedTool
from motleycrew.common import MotleyAgentFactory
from motleycrew.common.utils import to_str
from motleycrew.tracking import add_default_callbacks_to_langchain_config
from motleycrew.common.utils import ensure_module_is_installed

Expand All @@ -23,7 +21,7 @@ def __init__(
self,
goal: str,
name: str | None = None,
agent_factory: MotleyAgentFactory | None = None,
agent_factory: MotleyAgentFactory[CrewAIAgentWithConfig] | None = None,
tools: Sequence[MotleySupportedTool] | None = None,
verbose: bool = False,
):
Expand Down
33 changes: 20 additions & 13 deletions motleycrew/agents/langchain/langchain.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
""" Module description """

from typing import Any, Optional, Sequence, Callable
from typing import Any, Optional, Sequence, Callable, Union

from langchain.agents import AgentExecutor
from langchain_core.runnables import RunnableConfig
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_core.chat_history import BaseChatMessageHistory, InMemoryChatMessageHistory
from langchain_core.language_models import BaseLanguageModel
from langchain_core.prompts.chat import ChatPromptTemplate
from langchain_core.prompts import BasePromptTemplate
from langchain_core.tools import BaseTool


from motleycrew.agents.parent import MotleyAgentParent
from motleycrew.agents.abstract_parent import MotleyAgentAbstractParent

from motleycrew.tools import MotleyTool
from motleycrew.tracking import add_default_callbacks_to_langchain_config
Expand All @@ -26,7 +25,7 @@ def __init__(
self,
description: str,
name: str | None = None,
agent_factory: MotleyAgentFactory | None = None,
agent_factory: MotleyAgentFactory[AgentExecutor] | None = None,
tools: Sequence[MotleySupportedTool] | None = None,
verbose: bool = False,
with_history: bool = False,
Expand Down Expand Up @@ -105,26 +104,31 @@ def invoke(
return output

@staticmethod
def from_function(
function: Callable[..., Any],
def from_creating_function(
creating_function: Callable[
[
BaseLanguageModel,
Sequence[BaseTool],
Union[BasePromptTemplate, Sequence[BasePromptTemplate], None],
],
Any,
],
description: str,
name: str | None = None,
llm: BaseLanguageModel | None = None,
delegation: bool | Sequence[MotleyAgentAbstractParent] = False,
tools: Sequence[MotleySupportedTool] | None = None,
prompt: ChatPromptTemplate | Sequence[ChatPromptTemplate] | None = None,
prompt: BasePromptTemplate | Sequence[BasePromptTemplate] | None = None,
require_tools: bool = False,
with_history: bool = False,
verbose: bool = False,
) -> "LangchainMotleyAgent":
"""Description

Args:
function (Callable):
creating_function (Callable):
description (str):
name (:obj:`str`, optional):
llm (:obj:`BaseLanguageModel`, optional):
delegation: (:obj:`bool`, :obj:`Sequence[MotleyAgentAbstractParent]`, optional):
tools (:obj:`Sequence[MotleySupportedTool]`, optional):
prompt (:obj:`ChatPromptTemplate`, :obj:`Sequence[ChatPromptTemplate]`, optional):
require_tools (bool):
Expand All @@ -139,10 +143,13 @@ def from_function(
if require_tools and not tools:
raise ValueError("You must provide at least one tool to the LangchainMotleyAgent")

def agent_factory(tools: dict[str, MotleyTool]):
for tool in tools:
MotleyTool.from_supported_tool(tool)

def agent_factory(tools: dict[str, MotleyTool]) -> AgentExecutor:
langchain_tools = [t.to_langchain_tool() for t in tools.values()]
# TODO: feed description into the agent's prompt
agent = function(llm=llm, tools=langchain_tools, prompt=prompt)
agent = creating_function(llm, langchain_tools, prompt)
agent_executor = AgentExecutor(
agent=agent,
tools=langchain_tools,
Expand Down
5 changes: 2 additions & 3 deletions motleycrew/agents/langchain/react.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from langchain_core.language_models import BaseLanguageModel
from langchain.agents import create_react_agent

from motleycrew.agents.abstract_parent import MotleyAgentAbstractParent
from motleycrew.agents.langchain.langchain import LangchainMotleyAgent
from motleycrew.common import MotleySupportedTool

Expand Down Expand Up @@ -33,13 +32,13 @@ def __new__(
if prompt is None:
# TODO: feed description into the agent's prompt
prompt = hub.pull("hwchase17/react")
return cls.from_function(
return cls.from_creating_function(
description=description,
name=name,
llm=llm,
tools=tools,
prompt=prompt,
function=create_react_agent,
creating_function=create_react_agent,
require_tools=True,
verbose=verbose,
)
4 changes: 2 additions & 2 deletions motleycrew/agents/langchain/tool_calling_react.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,13 +237,13 @@ def __new__(
llm (:obj:`BaseLanguageModel`, optional):
verbose (:obj:`bool`, optional):
"""
return cls.from_function(
return cls.from_creating_function(
description=goal,
name=name,
llm=llm,
tools=tools,
prompt=prompt,
function=create_tool_calling_react_agent,
creating_function=create_tool_calling_react_agent,
require_tools=True,
with_history=with_history,
verbose=verbose,
Expand Down
4 changes: 1 addition & 3 deletions motleycrew/agents/llama_index/llama_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
from langchain_core.runnables import RunnableConfig

from motleycrew.agents.parent import MotleyAgentParent
from motleycrew.agents.abstract_parent import MotleyAgentAbstractParent
from motleycrew.tasks import TaskUnit
from motleycrew.common import MotleySupportedTool
from motleycrew.common import MotleyAgentFactory
from motleycrew.common.utils import ensure_module_is_installed
Expand All @@ -21,7 +19,7 @@ def __init__(
self,
description: str,
name: str | None = None,
agent_factory: MotleyAgentFactory | None = None,
agent_factory: MotleyAgentFactory[AgentRunner] | None = None,
tools: Sequence[MotleySupportedTool] | None = None,
verbose: bool = False,
):
Expand Down
3 changes: 1 addition & 2 deletions motleycrew/agents/llama_index/llama_index_react.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
LLM = object

from motleycrew.agents.llama_index import LlamaIndexMotleyAgent
from motleycrew.agents.abstract_parent import MotleyAgentAbstractParent
from motleycrew.tools import MotleyTool
from motleycrew.common import MotleySupportedTool
from motleycrew.common import LLMFramework
Expand Down Expand Up @@ -40,7 +39,7 @@ def __init__(
if llm is None:
llm = init_llm(llm_framework=LLMFramework.LLAMA_INDEX)

def agent_factory(tools: dict[str, MotleyTool]):
def agent_factory(tools: dict[str, MotleyTool]) -> ReActAgent:
llama_index_tools = [t.to_llama_index_tool() for t in tools.values()]
# TODO: feed description into the agent's prompt
callbacks = get_default_callbacks_list(LLMFramework.LLAMA_INDEX)
Expand Down
Empty file.
33 changes: 31 additions & 2 deletions motleycrew/common/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
""" Module description"""
from typing import Any, Optional

from motleycrew.common import Defaults


Expand Down Expand Up @@ -76,8 +78,8 @@ def __str__(self):
return "Some integration tests failed: {}".format(self.test_names)


class ModuleNotInstalledException(Exception):
""" Not install module exception
class ModuleNotInstalled(Exception):
"""Module not installed

Args:
module_name (str): the name of the non-installed module
Expand All @@ -97,3 +99,30 @@ def __str__(self):
msg = "{}, {}".format(msg, self.install_command)

return "{}.".format(msg)


class InvalidToolInput(Exception):
"""Raised when the tool input is invalid"""

def __init__(self, tool: Any, input: Any, message: Optional[str] = None):
self.tool = tool
self.input = input
self.message = message

def __str__(self):
msg = "Invalid input `{}` for tool `{}`".format(self.input, self.tool_name)
if self.message:
msg = "{}: {}".format(msg, self.message)
return msg


class RunnableSchemaMismatch(Exception):
"""
Raised when the input schema of a runnable does not match the output schema
of the previous runnable
"""
def __init__(self, message: str):
self.message = message

def __str__(self):
return self.message
28 changes: 22 additions & 6 deletions motleycrew/common/types.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,34 @@
""" Module description"""
from typing import TYPE_CHECKING
from typing import Any
from typing import Protocol
from typing import TYPE_CHECKING, Any, Union, Protocol, TypeVar

if TYPE_CHECKING:
from langchain.tools import BaseTool

try:
from llama_index.core.tools import BaseTool as LlamaIndex__BaseTool
except ImportError:
LlamaIndex__BaseTool = "LlamaIndex__BaseTool"

from motleycrew.tools import MotleyTool
from motleycrew.agents.abstract_parent import MotleyAgentAbstractParent

else:
MotleyTool = "MotleyTool"
BaseTool = "BaseTool"
LlamaIndex__BaseTool = "LlamaIndex__BaseTool"
MotleyAgentAbstractParent = "MotleyAgentAbstractParent"


MotleySupportedTool = Union[MotleyTool, BaseTool, LlamaIndex__BaseTool, MotleyAgentAbstractParent]


MotleySupportedTool = Any # TODO: more specific typing for supported tools
AgentType = TypeVar("AgentType")


class MotleyAgentFactory(Protocol):
class MotleyAgentFactory(Protocol[AgentType]):
"""
Type protocol for an agent factory.
It is a function that accepts tools as an argument and returns an agent instance of an appropriate class.
"""

def __call__(self, tools: dict[str, "MotleyTool"]) -> Any: ...
def __call__(self, tools: dict[str, MotleyTool]) -> AgentType: ...
6 changes: 3 additions & 3 deletions motleycrew/common/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from urllib.parse import urlparse
from langchain_core.messages import BaseMessage

from motleycrew.common.exceptions import ModuleNotInstalledException
from motleycrew.common.exceptions import ModuleNotInstalled


def to_str(value: str | BaseMessage | Sequence[str] | Sequence[BaseMessage]) -> str:
Expand Down Expand Up @@ -75,8 +75,8 @@ def ensure_module_is_installed(module_name: str, install_command: str = None) ->
install_command (:obj:`str`, optional):

Raises:
ModuleNotInstalledException:
ModuleNotInstalled:
"""
module_path = sys.modules.get(module_name, None)
if module_path is None:
raise ModuleNotInstalledException(module_name, install_command)
raise ModuleNotInstalled(module_name, install_command)
1 change: 1 addition & 0 deletions motleycrew/runnable/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .runnable import MotleyRunnable
Loading