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

Update Langchain dependency to v0.2 #58

Merged
merged 10 commits into from
Jul 9, 2024
Merged
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
4 changes: 2 additions & 2 deletions examples/Blog with Images.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
"from motleycrew.storage import MotleyKuzuGraphStore\n",
"from motleycrew import MotleyCrew\n",
"from motleycrew.agents.crewai import CrewAIMotleyAgent\n",
"from motleycrew.agents.langchain.react import ReActMotleyAgent\n",
"from motleycrew.agents.langchain.tool_calling_react import ReActToolCallingAgent\n",
"from motleycrew.agents.llama_index import ReActLlamaIndexMotleyAgent\n",
"from motleycrew.tools.image.dall_e import DallEImageGeneratorTool\n",
"from motleycrew.common import configure_logging\n",
Expand Down Expand Up @@ -114,7 +114,7 @@
"outputs": [],
"source": [
"# You can give agents as tools to other agents\n",
"writer = ReActMotleyAgent(\n",
"writer = ReActToolCallingAgent(\n",
" name=\"AI writer agent\",\n",
" prompt_prefix=\"\"\"Conduct a comprehensive analysis of the latest advancements in AI in 2024.\n",
" Identify key trends, breakthrough technologies, and potential industry impacts.\n",
Expand Down
7 changes: 4 additions & 3 deletions examples/Math via python code with a single agent.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
"WORKING_DIR = Path(os.path.realpath(\".\"))\n",
"\n",
"\n",
"try: \n",
"try:\n",
" from motleycrew import MotleyCrew\n",
"except ImportError:\n",
" # if we are running this from source\n",
Expand Down Expand Up @@ -493,15 +493,15 @@
" backstory=\"\"\"You are a high school math teacher with a passion for problem-solving.\n",
"To solve a math problem, you first reason about it, step by step, then generate the code to solve it exactly,\n",
"using sympy, then use the REPL tool to evaluate that code, and then\n",
"use the output to generate a human-readable solution in LaTeX format. \n",
"use the output to generate a human-readable solution in LaTeX format.\n",
"Don't use dashes to indicate bullet points, don't output any backticks, just the LaTeX\"\"\",\n",
" verbose=True,\n",
" delegation=False,\n",
" tools=[repl_tool],\n",
")\n",
"\n",
"problems = [\n",
" \"Problem: If $725x + 727y = 1500$ and $729x+ 731y = 1508$, \"\n",
" \"If $725x + 727y = 1500$ and $729x+ 731y = 1508$, \"\n",
" \"what are the values of $x$, $y$, and $x - y$ ?\",\n",
"]\n",
"\n",
Expand All @@ -511,6 +511,7 @@
" name=\"solve math problem\",\n",
" description=f\"\"\"Create a nice human-readable solution to the following problem:\n",
" {problems[0]}\"\"\",\n",
" additional_params={\"expected_output\": \"human-readable solution in LaTeX format\"},\n",
" agent=solver,\n",
")\n",
"\n",
Expand Down
9 changes: 7 additions & 2 deletions examples/aider_code_generation.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,15 @@
def main():
crew = MotleyCrew()

git_repo_path = r"../../motleycrew-code-generation-example" # cloned repository path
git_repo_path = (
r"../../motleycrew-code-generation-example" # cloned repository path
)
tests_file = os.path.join(git_repo_path, "test_math_functions.py")
target_files = [tests_file]

aider_tool = AiderTool(fnames=target_files, git_dname=git_repo_path, auto_commits=False)
aider_tool = AiderTool(
fnames=target_files, git_dname=git_repo_path, auto_commits=False
)
shell_tool = ShellTool()

developer = CrewAIMotleyAgent(
Expand All @@ -59,6 +63,7 @@ def main():
f"After go to the directory {git_repo_path} and run created unit tests. "
f"If the tests were executed successfully, return the result of execution, "
f"if not, rewrite the tests and rerun them until they are working.",
additional_params={"expected_output": "result of tests execution"},
agent=developer,
)

Expand Down
6 changes: 0 additions & 6 deletions examples/blog_with_images.nblink

This file was deleted.

5 changes: 4 additions & 1 deletion examples/crewai_output_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ def main():

def check_output(output: str):
if "medicine" not in output.lower():
raise InvalidOutput("Add more information about AI applications in medicine.")
raise InvalidOutput(
"Add more information about AI applications in medicine."
)
return {"checked_output": output.lower()}

output_handler = StructuredTool.from_function(
Expand Down Expand Up @@ -58,6 +60,7 @@ def check_output(output: str):
description="""Conduct a comprehensive analysis of the latest advancements in AI in 2024.
Identify key trends, breakthrough technologies, and potential industry impacts.
Your final answer MUST be a full analysis report""",
additional_params={"expected_output": "full analysis report"},
agent=researcher,
)

Expand Down
4 changes: 2 additions & 2 deletions examples/delegation_demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from motleycrew.storage import MotleyKuzuGraphStore

from motleycrew.agents.crewai import CrewAIMotleyAgent
from motleycrew.agents.langchain.react import ReActMotleyAgent
from motleycrew.agents.langchain.tool_calling_react import ReActToolCallingAgent
from motleycrew.agents.llama_index import ReActLlamaIndexMotleyAgent
from motleycrew.tools.image.dall_e import DallEImageGeneratorTool
from motleycrew.common import configure_logging
Expand Down Expand Up @@ -56,7 +56,7 @@ def main():
)

# You can give agents as tools to other agents
writer = ReActMotleyAgent(
writer = ReActToolCallingAgent(
name="AI writer agent",
prompt_prefix="You are an experienced writer with a passion for technology.",
description="Experienced writer with a passion for technology.",
Expand Down
45 changes: 33 additions & 12 deletions motleycrew/agents/crewai/agent_with_config.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
""" Module description """

from typing import Any, Optional, List

from langchain_core.runnables import RunnableConfig
Expand All @@ -8,12 +9,13 @@

try:
from crewai import Agent
from crewai.memory.contextual.contextual_memory import ContextualMemory
except ImportError:
Agent = object
ContextualMemory = object


class CrewAIAgentWithConfig(Agent):

def __init__(self, *args, **kwargs):
"""Subclass for CrewAI Agent that overrides the execute_task method to include a config parameter.

Expand All @@ -37,27 +39,48 @@ def execute_task(
"""Execute a task with the agent.

Args:
task (Any): Task to execute.
context (:obj:`str`, optional): Context to execute the task in.
tools (:obj:`List[Any]`, optional): Tools to use for the task.
config (:obj:`RunnableConfig`, optional): Runnable config.
task: Task to execute.
context: Context to execute the task in.
tools: Tools to use for the task.

Returns:
Any: Output of the agent
Output of the agent
"""
if self.tools_handler:
# type: ignore # Incompatible types in assignment (expression has type "dict[Never, Never]", variable has type "ToolCalling")
self.tools_handler.last_used_tool = {}

task_prompt = task.prompt()

if context:
task_prompt = self.i18n.slice("task_with_context").format(
task=task_prompt, context=context
)

tools = self._parse_tools(tools or self.tools)
if self.crew and self.crew.memory:
contextual_memory = ContextualMemory(
self.crew._short_term_memory,
self.crew._long_term_memory,
self.crew._entity_memory,
)
memory = contextual_memory.build_context_for_task(task, context)
if memory.strip() != "":
task_prompt += self.i18n.slice("memory").format(memory=memory)

tools = tools or self.tools
# type: ignore # Argument 1 to "_parse_tools" of "Agent" has incompatible type "list[Any] | None"; expected "list[Any]"
parsed_tools = self._parse_tools(tools or [])
self.create_agent_executor(tools=tools)
self.agent_executor.tools = tools
self.agent_executor.tools = parsed_tools
self.agent_executor.task = task
self.agent_executor.tools_description = render_text_description(tools)
self.agent_executor.tools_names = self.__tools_names(tools)

self.agent_executor.tools_description = render_text_description(parsed_tools)
self.agent_executor.tools_names = self.__tools_names(parsed_tools)

if self.crew and self.crew._train:
task_prompt = self._training_handler(task_prompt=task_prompt)
else:
task_prompt = self._use_trained_data(task_prompt=task_prompt)

result = self.agent_executor.invoke(
{
Expand All @@ -67,10 +90,8 @@ def execute_task(
},
config=config,
)["output"]

if self.max_rpm:
self._rpm_controller.stop_rpm_counter()

return result

@staticmethod
Expand Down
44 changes: 42 additions & 2 deletions motleycrew/agents/crewai/crewai.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from typing import Any, Optional, Sequence

from langchain_core.runnables import RunnableConfig
from langchain_core.tools import StructuredTool
from langchain_core.pydantic_v1 import BaseModel, Field

from motleycrew.agents.crewai import CrewAIAgentWithConfig
from motleycrew.agents.parent import MotleyAgentParent
Expand Down Expand Up @@ -45,7 +47,7 @@ def __init__(
if output_handler:
raise NotImplementedError(
"Output handler is not supported for CrewAI agents "
"because of the specificity of CrewAi's prompts."
"because of the specificity of CrewAI's prompts."
)

ensure_module_is_installed("crewai")
Expand Down Expand Up @@ -80,7 +82,15 @@ def invoke(
langchain_tools = [tool.to_langchain_tool() for tool in self.tools.values()]
config = add_default_callbacks_to_langchain_config(config)

crewai_task = CrewAI__Task(description=prompt)
additional_params = input.get("additional_params") or {}
expected_output = additional_params.get("expected_output")
if not expected_output:
raise ValueError("Expected output is required for CrewAI tasks")

crewai_task = CrewAI__Task(
description=prompt,
expected_output=expected_output,
)

output = self.agent.execute_task(
task=crewai_task,
Expand Down Expand Up @@ -145,3 +155,33 @@ def from_agent(
)
wrapped_agent._agent = agent
return wrapped_agent

def as_tool(self) -> MotleyTool:
if not self.description:
raise ValueError("Agent must have a description to be called as a tool")

class CrewAIAgentInputSchema(BaseModel):
prompt: str = Field(..., description="Prompt to be passed to the agent")
expected_output: str = Field(
..., description="Expected output of the agent"
)

def call_agent(prompt: str, expected_output: str):
return self.invoke(
{
"prompt": prompt,
"additional_params": {"expected_output": expected_output},
}
)

# To be specialized if we expect structured input
return MotleyTool.from_langchain_tool(
StructuredTool(
name=self.name.replace(
" ", "_"
).lower(), # OpenAI doesn't accept spaces in function names
description=self.description,
func=call_agent,
args_schema=CrewAIAgentInputSchema,
)
)
3 changes: 2 additions & 1 deletion motleycrew/agents/crewai/crewai_agent.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
""" Module description """

from typing import Optional, Any, Sequence

from motleycrew.tools import MotleyTool
Expand All @@ -23,7 +24,7 @@ def __init__(
output_handler: MotleySupportedTool | None = None,
verbose: bool = False,
):
""" Description
"""Description

Args:
role (str):
Expand Down
32 changes: 25 additions & 7 deletions motleycrew/agents/parent.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
""" Module description """

import inspect
from typing import TYPE_CHECKING, Optional, Sequence, Any, Callable, Dict, Union, Tuple
from typing import (
TYPE_CHECKING,
Optional,
Sequence,
Any,
Callable,
Dict,
Type,
Union,
Tuple,
)

from langchain_core.prompts.chat import ChatPromptTemplate, HumanMessage, SystemMessage
from langchain_core.runnables import Runnable
Expand Down Expand Up @@ -90,7 +100,9 @@ def compose_prompt(
prompt_messages.append(SystemMessage(content=self.prompt_prefix))

else:
raise ValueError("Agent description must be a string or a ChatPromptTemplate")
raise ValueError(
"Agent description must be a string or a ChatPromptTemplate"
)

if prompt:
if isinstance(prompt, ChatPromptTemplate):
Expand Down Expand Up @@ -180,9 +192,13 @@ def materialize(self):

if inspect.signature(self.agent_factory).parameters.get("output_handler"):
logger.info("Agent factory accepts output handler, passing it")
self._agent = self.agent_factory(tools=self.tools, output_handler=output_handler)
self._agent = self.agent_factory(
tools=self.tools, output_handler=output_handler
)
elif output_handler:
logger.info("Agent factory does not accept output handler, passing it as a tool")
logger.info(
"Agent factory does not accept output handler, passing it as a tool"
)
tools_with_output_handler = self.tools.copy()
tools_with_output_handler[output_handler.name] = output_handler
self._agent = self.agent_factory(tools=tools_with_output_handler)
Expand Down Expand Up @@ -226,11 +242,11 @@ def add_tools(self, tools: Sequence[MotleySupportedTool]):
if motley_tool.name not in self.tools:
self.tools[motley_tool.name] = motley_tool

def as_tool(self, input_schema: Optional[BaseModel] = None) -> MotleyTool:
def as_tool(self, input_schema: Optional[Type[BaseModel]] = None) -> MotleyTool:
"""Description

Args:
input_schema (:obj:`BaseModel`, optional):
input_schema (:obj:`Type[BaseModel]`, optional):

Returns:
MotleyTool:
Expand All @@ -250,7 +266,9 @@ def call_agent(*args, **kwargs):
# To be specialized if we expect structured input
return MotleyTool.from_langchain_tool(
Tool(
name=self.name,
name=self.name.replace(
" ", "_"
).lower(), # OpenAI doesn't accept spaces in function names
description=self.description,
func=call_agent,
args_schema=input_schema,
Expand Down
Loading
Loading