From 0b1693dad1dd448d9b82f713d30271ad5820e33d Mon Sep 17 00:00:00 2001 From: vizsatiz Date: Fri, 15 Nov 2024 22:24:33 +0530 Subject: [PATCH 1/7] Removed passing config around for better code building apis --- examples/build_agents_by_code.ipynb | 17 ++++-- flo_ai/builders/yaml_builder.py | 4 +- flo_ai/factory/agent_factory.py | 34 +++++++++--- flo_ai/models/delegate.py | 7 +++ flo_ai/models/flo_agent.py | 24 ++++----- flo_ai/models/flo_delegation_agent.py | 74 +++++++++++++-------------- flo_ai/models/flo_llm_agent.py | 25 ++++----- flo_ai/models/flo_node.py | 45 +++++++++++----- flo_ai/models/flo_reflection_agent.py | 29 ++++++----- flo_ai/models/flo_routed_team.py | 4 +- flo_ai/models/flo_team.py | 12 ++--- flo_ai/models/flo_tool_agent.py | 15 ++---- flo_ai/models/flo_transformer.py | 6 --- flo_ai/router/flo_linear.py | 2 +- flo_ai/router/flo_llm_router.py | 16 +++--- flo_ai/router/flo_router.py | 16 +++--- flo_ai/router/flo_router_factory.py | 2 +- 17 files changed, 184 insertions(+), 148 deletions(-) create mode 100644 flo_ai/models/delegate.py delete mode 100644 flo_ai/models/flo_transformer.py diff --git a/examples/build_agents_by_code.ipynb b/examples/build_agents_by_code.ipynb index e7fbabae..0a408fe3 100644 --- a/examples/build_agents_by_code.ipynb +++ b/examples/build_agents_by_code.ipynb @@ -28,8 +28,6 @@ "source": [ "from flo_ai import FloSupervisor, FloAgent, FloSession, FloTeam, FloLinear\n", "from langchain_openai import ChatOpenAI\n", - "# TODO router config needs fixing\n", - "from flo_ai.yaml.flo_team_builder import RouterConfig\n", "from langchain_community.tools.tavily_search.tool import TavilySearchResults\n", "from dotenv import load_dotenv\n", "\n", @@ -47,7 +45,20 @@ "cell_type": "code", "execution_count": 2, "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "AttributeError", + "evalue": "'str' object has no attribute 'job'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[2], line 7\u001b[0m\n\u001b[1;32m 1\u001b[0m llm \u001b[38;5;241m=\u001b[39m ChatOpenAI(temperature\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m0\u001b[39m, model_name\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mgpt-4o\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 2\u001b[0m session \u001b[38;5;241m=\u001b[39m FloSession(llm)\u001b[38;5;241m.\u001b[39mregister_tool(\n\u001b[1;32m 3\u001b[0m name\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mTavilySearchResults\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 4\u001b[0m tool\u001b[38;5;241m=\u001b[39mTavilySearchResults()\n\u001b[1;32m 5\u001b[0m )\n\u001b[0;32m----> 7\u001b[0m researcher \u001b[38;5;241m=\u001b[39m \u001b[43mFloAgent\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mBuilder\u001b[49m\u001b[43m(\u001b[49m\u001b[43msession\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mResearcher\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\n\u001b[1;32m 8\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mDo a research on the internet and find articles of relevent to the topic asked by the user\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m[\u001b[49m\u001b[43mTavilySearchResults\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241m.\u001b[39mbuild()\n\u001b[1;32m 9\u001b[0m blogger \u001b[38;5;241m=\u001b[39m FloAgent\u001b[38;5;241m.\u001b[39mBuilder(session, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mBlogWriter\u001b[39m\u001b[38;5;124m\"\u001b[39m, \n\u001b[1;32m 10\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mAble to write a blog using information provided\u001b[39m\u001b[38;5;124m\"\u001b[39m, [TavilySearchResults()])\u001b[38;5;241m.\u001b[39mbuild()\n\u001b[1;32m 12\u001b[0m marketing_team \u001b[38;5;241m=\u001b[39m FloTeam\u001b[38;5;241m.\u001b[39mBuilder(session, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mMarketing\u001b[39m\u001b[38;5;124m\"\u001b[39m, [researcher, blogger])\u001b[38;5;241m.\u001b[39mbuild()\n", + "File \u001b[0;32m~/Documents/hub/flo/flo_ai/models/flo_agent.py:40\u001b[0m, in \u001b[0;36mFloAgent.Builder.__init__\u001b[0;34m(self, session, config, tools, verbose, role, llm, on_error, model_name)\u001b[0m\n\u001b[1;32m 29\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m__init__\u001b[39m(\n\u001b[1;32m 30\u001b[0m \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m 31\u001b[0m session: FloSession,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 38\u001b[0m model_name: Union[\u001b[38;5;28mstr\u001b[39m, \u001b[38;5;28;01mNone\u001b[39;00m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdefault\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[1;32m 39\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m---> 40\u001b[0m prompt: Union[ChatPromptTemplate, \u001b[38;5;28mstr\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[43mconfig\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mjob\u001b[49m\n\u001b[1;32m 41\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mname: \u001b[38;5;28mstr\u001b[39m \u001b[38;5;241m=\u001b[39m config\u001b[38;5;241m.\u001b[39mname\n\u001b[1;32m 42\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mmodel_name \u001b[38;5;241m=\u001b[39m model_name\n", + "\u001b[0;31mAttributeError\u001b[0m: 'str' object has no attribute 'job'" + ] + } + ], "source": [ "llm = ChatOpenAI(temperature=0, model_name='gpt-4o')\n", "session = FloSession(llm).register_tool(\n", diff --git a/flo_ai/builders/yaml_builder.py b/flo_ai/builders/yaml_builder.py index 81cee6c8..8abf5bd2 100644 --- a/flo_ai/builders/yaml_builder.py +++ b/flo_ai/builders/yaml_builder.py @@ -39,7 +39,7 @@ def parse_and_build_subteams( validate_team(name_set, team_config, session) if team_config.agents: members = [AgentFactory.create(session, agent) for agent in team_config.agents] - flo_team = FloTeam.Builder(team_config, members=members).build() + flo_team = FloTeam.Builder(team_config.name, members=members).build() router = FloRouterFactory.create(session, team_config, flo_team) flo_routed_team = router.build_routed_team() else: @@ -47,7 +47,7 @@ def parse_and_build_subteams( for subteam in team_config.subteams: flo_subteam = parse_and_build_subteams(session, subteam, name_set) flo_teams.append(flo_subteam) - flo_team = FloTeam.Builder(team_config, members=flo_teams).build() + flo_team = FloTeam.Builder(team_config.name, members=flo_teams).build() router = FloRouterFactory.create(session, team_config, flo_team) flo_routed_team = router.build_routed_team() return flo_routed_team diff --git a/flo_ai/factory/agent_factory.py b/flo_ai/factory/agent_factory.py index 1b2ef557..32f82209 100644 --- a/flo_ai/factory/agent_factory.py +++ b/flo_ai/factory/agent_factory.py @@ -7,6 +7,9 @@ from flo_ai.models.flo_delegation_agent import FloDelegatorAgent from flo_ai.models.flo_tool_agent import FloToolAgent from flo_ai.error.flo_exception import FloException +from flo_ai.models.flo_team import FloTeam +from flo_ai.models.flo_member import FloMember +from flo_ai.models.flo_executable import ExecutableType from flo_ai.constants.common_constants import DOCUMENTATION_AGENT_ANCHOR from enum import Enum @@ -61,8 +64,10 @@ def __create_agentic_agent( tools = [tool_map[tool.name] for tool in agent.tools] flo_agent: FloAgent = FloAgent.Builder( session, - agent, - tools, + name=agent.name, + job=agent.job, + tools=tools, + role=agent.role, llm=agent_model, on_error=session.on_agent_error, model_name=agent.model, @@ -73,7 +78,12 @@ def __create_agentic_agent( def __create_llm_agent(session: FloSession, agent: AgentConfig) -> FloLLMAgent: agent_model = AgentFactory.__resolve_model(session, agent.model) builder = FloLLMAgent.Builder( - session, agent, llm=agent_model, model_name=agent.model + session, + name=agent.name, + job=agent.job, + role=agent.role, + llm=agent_model, + model_name=agent.model, ) llm_agent: FloLLMAgent = builder.build() return llm_agent @@ -82,7 +92,7 @@ def __create_llm_agent(session: FloSession, agent: AgentConfig) -> FloLLMAgent: def __create_runnable_agent(session: FloSession, agent: AgentConfig) -> FloLLMAgent: runnable = session.tools[agent.tools[0].name] return FloToolAgent.Builder( - session, agent, runnable, model_name=agent.model + session, agent.name, runnable, model_name=agent.model ).build() @staticmethod @@ -90,11 +100,23 @@ def __create_reflection_agent( session: FloSession, agent: AgentConfig ) -> FloReflectionAgent: agent_model = AgentFactory.__resolve_model(session, agent.model) - return FloReflectionAgent.Builder(session, agent, llm=agent_model).build() + return FloReflectionAgent.Builder( + session, + name=agent.name, + job=agent.job, + role=agent.role, + llm=agent_model, + model_name=agent.model, + ).build() @staticmethod def __create_delegator_agent( session: FloSession, agent: AgentConfig ) -> FloReflectionAgent: agent_model = AgentFactory.__resolve_model(session, agent.model) - return FloDelegatorAgent.Builder(session, agent, llm=agent_model).build() + # see if we can remodel this + members = [FloMember(x.name, ExecutableType.agentic) for x in agent.to] + to = FloTeam.Builder('delegator_team', members=members) + return FloDelegatorAgent.Builder( + session, agent.name, agent.job, to, llm=agent_model, model_name=agent.model + ).build() diff --git a/flo_ai/models/delegate.py b/flo_ai/models/delegate.py new file mode 100644 index 00000000..5826b8f3 --- /dev/null +++ b/flo_ai/models/delegate.py @@ -0,0 +1,7 @@ +from dataclasses import dataclass + + +@dataclass +class Delegate: + to: list[str] + retry: int diff --git a/flo_ai/models/flo_agent.py b/flo_ai/models/flo_agent.py index 12d59ef1..b0988237 100644 --- a/flo_ai/models/flo_agent.py +++ b/flo_ai/models/flo_agent.py @@ -7,41 +7,39 @@ from flo_ai.models.flo_executable import ExecutableFlo from flo_ai.state.flo_session import FloSession from typing import Union, Optional, Callable -from flo_ai.yaml.config import AgentConfig from flo_ai.models.flo_executable import ExecutableType class FloAgent(ExecutableFlo): def __init__( self, + name: str, agent: Runnable, executor: AgentExecutor, - config: AgentConfig, - model_nick_name: str, + model_name: str, ) -> None: - super().__init__(config.name, executor, ExecutableType.agentic) - self.model_name = model_nick_name + super().__init__(name, executor, ExecutableType.agentic) + self.model_name = model_name self.agent: Runnable = (agent,) self.executor: AgentExecutor = executor - self.config: AgentConfig = config class Builder: def __init__( self, session: FloSession, - config: AgentConfig, + name: str, + job: str, tools: list[BaseTool], - verbose: bool = True, role: Optional[str] = None, + verbose: bool = True, llm: Union[BaseLanguageModel, None] = None, on_error: Union[str, Callable] = True, model_name: Union[str, None] = 'default', ) -> None: - prompt: Union[ChatPromptTemplate, str] = config.job - self.name: str = config.name + prompt: Union[ChatPromptTemplate, str] = job + self.name: str = name self.model_name = model_name self.llm = llm if llm is not None else session.llm - self.config = config system_prompts = ( [('system', 'You are a {}'.format(role)), ('system', prompt)] if role is not None @@ -67,6 +65,4 @@ def build(self) -> AgentExecutor: return_intermediate_steps=True, handle_parsing_errors=self.on_error, ) - return FloAgent( - agent, executor, self.config, model_nick_name=self.model_name - ) + return FloAgent(self.name, agent, executor, model_name=self.model_name) diff --git a/flo_ai/models/flo_delegation_agent.py b/flo_ai/models/flo_delegation_agent.py index 7c39544e..a743be3e 100644 --- a/flo_ai/models/flo_delegation_agent.py +++ b/flo_ai/models/flo_delegation_agent.py @@ -1,32 +1,46 @@ from typing import Optional from langchain_core.runnables import Runnable -from flo_ai.yaml.config import AgentConfig from flo_ai.state.flo_session import FloSession -from flo_ai.models.flo_executable import ExecutableFlo +from flo_ai.models.flo_executable import ExecutableFlo, ExecutableType +from flo_ai.models.delegate import Delegate from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder -from flo_ai.models.flo_executable import ExecutableType -from langchain_core.output_parsers.openai_functions import JsonOutputFunctionsParser from langchain_core.language_models import BaseLanguageModel +from pydantic import BaseModel, Field +from langchain_core.output_parsers import JsonOutputParser + + +class NextAgent(BaseModel): + next: str = Field(description='Name of the next member to be called') class FloDelegatorAgent(ExecutableFlo): def __init__( - self, executor: Runnable, config: AgentConfig, model_name: str + self, + session: FloSession, + executor: Runnable, + delegate: Delegate, + name: str, + model_name: str, ) -> None: - super().__init__(config.name, executor, ExecutableType.delegator) - self.executor: Runnable = executor - self.config: AgentConfig = config + super().__init__(name, executor, ExecutableType.delegator) + self.session = session + self.delegate = delegate + self.executor = executor self.model_name = model_name class Builder: def __init__( self, session: FloSession, - agentConfig: AgentConfig, + name: str, + job: str, + to: Delegate, llm: Optional[BaseLanguageModel] = None, model_name: str = None, ) -> None: - self.config = agentConfig + self.session = session + self.name = name + self.to = to delegator_base_system_message = ( 'You are a delegator tasked with routing a conversation between the' ' following {member_type}: {members}. Given the following rules,' @@ -34,7 +48,8 @@ def __init__( ) self.model_name = model_name self.llm = session.llm if llm is None else llm - self.options = [x.name for x in agentConfig.to] + self.options = [x.name for x in to.members] + self.parser = JsonOutputParser(pydantic_object=NextAgent) self.llm_router_prompt = ChatPromptTemplate.from_messages( [ ('system', delegator_base_system_message), @@ -43,43 +58,24 @@ def __init__( ( 'system', 'Given the conversation above, who should act next?' - 'Select one of: {options}', + 'Select one of: {options} \n {format_instructions}', ), ] ).partial( options=str(self.options), members=', '.join(self.options), member_type='agents', - delegator_rules=agentConfig.job, + delegator_rules=job, + format_instructions=self.parser.get_format_instructions(), ) def build(self): - function_def = { - 'name': 'route', - 'description': 'Select the next role.', - 'parameters': { - 'title': 'routeSchema', - 'type': 'object', - 'properties': { - 'next': { - 'title': 'Next', - 'anyOf': [ - {'enum': self.options}, - ], - } - }, - 'required': ['next'], - }, - } - - chain = ( - self.llm_router_prompt - | self.llm.bind_functions( - functions=[function_def], function_call='route' - ) - | JsonOutputFunctionsParser() - ) + chain = self.llm_router_prompt | self.llm | self.parser return FloDelegatorAgent( - executor=chain, config=self.config, model_name=self.model_name + session=self.session, + name=self.name, + delegate=self.to, + executor=chain, + model_name=self.model_name, ) diff --git a/flo_ai/models/flo_llm_agent.py b/flo_ai/models/flo_llm_agent.py index fa6c83a7..125133ba 100644 --- a/flo_ai/models/flo_llm_agent.py +++ b/flo_ai/models/flo_llm_agent.py @@ -3,38 +3,36 @@ from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from flo_ai.models.flo_executable import ExecutableFlo from flo_ai.state.flo_session import FloSession -from typing import Union +from typing import Union, Optional from langchain_core.output_parsers import StrOutputParser -from flo_ai.yaml.config import AgentConfig from flo_ai.models.flo_executable import ExecutableType class FloLLMAgent(ExecutableFlo): - def __init__( - self, executor: Runnable, config: AgentConfig, model_name: str - ) -> None: - super().__init__(config.name, executor, ExecutableType.llm) + def __init__(self, name: str, executor: Runnable, model_name: str) -> None: + super().__init__(name, executor, ExecutableType.llm) self.executor: Runnable = executor - self.config: AgentConfig = config self.model_name: str = model_name class Builder: def __init__( self, session: FloSession, - config: AgentConfig, + name: str, + job: str, + role: Optional[str] = None, llm: Union[BaseLanguageModel, None] = None, model_name: str = None, ) -> None: self.model_name = model_name - prompt: Union[ChatPromptTemplate, str] = config.job + prompt: Union[ChatPromptTemplate, str] = job - self.name: str = config.name + self.name: str = name self.llm = llm if llm is not None else session.llm # TODO improve to add more context of what other agents are available system_prompts = ( - [('system', 'You are a {}'.format(config.role)), ('system', prompt)] - if config.role is not None + [('system', 'You are a {}'.format(role)), ('system', prompt)] + if role is not None else [('system', prompt)] ) system_prompts.append(MessagesPlaceholder(variable_name='messages')) @@ -43,8 +41,7 @@ def __init__( if isinstance(prompt, str) else prompt ) - self.config = config def build(self) -> Runnable: executor = self.prompt | self.llm | StrOutputParser() - return FloLLMAgent(executor, self.config, self.model_name) + return FloLLMAgent(self.name, executor, self.model_name) diff --git a/flo_ai/models/flo_node.py b/flo_ai/models/flo_node.py index 6bfd6aad..a5182c28 100644 --- a/flo_ai/models/flo_node.py +++ b/flo_ai/models/flo_node.py @@ -1,13 +1,14 @@ import functools from flo_ai.models.flo_agent import FloAgent +from flo_ai.models.flo_reflection_agent import FloReflectionAgent from flo_ai.models.flo_routed_team import FloRoutedTeam +from flo_ai.models.delegate import Delegate from langchain.agents import AgentExecutor from flo_ai.state.flo_state import TeamFloAgentState, STATE_NAME_MESSAGES from langchain_core.messages import HumanMessage -from flo_ai.yaml.config import AgentConfig, TeamConfig from flo_ai.models.flo_executable import ExecutableType from flo_ai.state.flo_session import FloSession -from typing import Union, Type, List +from typing import Optional, Type, List from flo_ai.state.flo_callbacks import FloAgentCallback, FloRouterCallback, FloCallback @@ -17,12 +18,12 @@ def __init__( func: functools.partial, name: str, kind: ExecutableType, - config: Union[AgentConfig | TeamConfig], + delegate: Optional[Delegate] = None, ) -> None: self.name = name self.func = func self.kind: ExecutableType = kind - self.config: Union[AgentConfig | TeamConfig] = config + self.delegate = delegate class Builder: def __init__(self, session: FloSession) -> None: @@ -33,11 +34,22 @@ def build_from_agent(self, flo_agent: FloAgent) -> 'FloNode': FloNode.Builder.__teamflo_agent_node, agent=flo_agent.runnable, name=flo_agent.name, - agent_config=flo_agent.config, session=self.session, model_name=flo_agent.model_name, ) - return FloNode(agent_func, flo_agent.name, flo_agent.type, flo_agent.config) + return FloNode(agent_func, flo_agent.name, flo_agent.type) + + def build_from_reflection(self, flo_agent: FloReflectionAgent) -> 'FloNode': + agent_func = functools.partial( + FloNode.Builder.__teamflo_agent_node, + agent=flo_agent.runnable, + name=flo_agent.name, + session=self.session, + model_name=flo_agent.model_name, + ) + return FloNode( + agent_func, flo_agent.name, flo_agent.type, delegate=flo_agent.delegate + ) def build_from_team(self, flo_team: FloRoutedTeam) -> 'FloNode': team_chain = ( @@ -56,20 +68,31 @@ def build_from_team(self, flo_team: FloRoutedTeam) -> 'FloNode': ), flo_team.name, flo_team.type, - flo_team.config, ) def build_from_router(self, flo_router) -> 'FloNode': router_func = functools.partial( FloNode.Builder.__teamflo_router_node, agent=flo_router.executor, - name=flo_router.router_name, - agent_config=flo_router.config, + name=flo_router.name, + session=self.session, + model_name=flo_router.model_name, + ) + return FloNode(router_func, flo_router.name, flo_router.type) + + def build_from_delegator(self, flo_router) -> 'FloNode': + router_func = functools.partial( + FloNode.Builder.__teamflo_router_node, + agent=flo_router.executor, + name=flo_router.name, session=self.session, model_name=flo_router.model_name, ) return FloNode( - router_func, flo_router.router_name, flo_router.type, flo_router.config + router_func, + flo_router.name, + flo_router.type, + delegate=flo_router.delegate, ) @staticmethod @@ -77,7 +100,6 @@ def __teamflo_agent_node( state: TeamFloAgentState, agent: AgentExecutor, name: str, - agent_config: AgentConfig, session: FloSession, model_name: str, ): @@ -128,7 +150,6 @@ def __teamflo_router_node( state: TeamFloAgentState, agent: AgentExecutor, name: str, - agent_config: AgentConfig, session: FloSession, model_name: str, ): diff --git a/flo_ai/models/flo_reflection_agent.py b/flo_ai/models/flo_reflection_agent.py index 94e85162..2f133d3a 100644 --- a/flo_ai/models/flo_reflection_agent.py +++ b/flo_ai/models/flo_reflection_agent.py @@ -1,42 +1,45 @@ -from typing import Union +from typing import Union, Optional from langchain_core.runnables import Runnable -from flo_ai.yaml.config import AgentConfig from flo_ai.state.flo_session import FloSession from flo_ai.models.flo_executable import ExecutableFlo from langchain_core.language_models import BaseLanguageModel from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from flo_ai.models.flo_executable import ExecutableType from langchain_core.output_parsers import StrOutputParser +from flo_ai.models.delegate import Delegate class FloReflectionAgent(ExecutableFlo): def __init__( - self, executor: Runnable, config: AgentConfig, model_name: str + self, name: str, executor: Runnable, model_name: str, delegate: Delegate ) -> None: - super().__init__(config.name, executor, ExecutableType.reflection) - self.config = config + super().__init__(name, executor, ExecutableType.reflection) self.model_name = model_name + self.delegate = delegate class Builder: def __init__( self, session: FloSession, - config: AgentConfig, + name: str, + job: str, + to: Delegate, + role: Optional[str] = None, llm: Union[BaseLanguageModel, None] = None, model_name: str = None, ) -> None: - prompt_message: Union[ChatPromptTemplate, str] = config.job - self.name: str = config.name + prompt_message: Union[ChatPromptTemplate, str] = job + self.name: str = name self.llm = llm if llm is not None else session.llm - self.config = config self.model_name = model_name + self.delegate = to system_prompts = ( [ - ('system', 'You are a {}'.format(config.role)), + ('system', 'You are a {}'.format(role)), ('system', prompt_message), ] - if config.role is not None + if role is not None else [('system', prompt_message)] ) system_prompts.append(MessagesPlaceholder(variable_name='messages')) @@ -48,4 +51,6 @@ def __init__( def build(self): executor = self.prompt | self.llm | StrOutputParser() - return FloReflectionAgent(executor, self.config, self.model_name) + return FloReflectionAgent( + self.name, executor, self.model_name, delegate=self.to + ) diff --git a/flo_ai/models/flo_routed_team.py b/flo_ai/models/flo_routed_team.py index 48fa0ff2..cc118af3 100644 --- a/flo_ai/models/flo_routed_team.py +++ b/flo_ai/models/flo_routed_team.py @@ -1,12 +1,10 @@ from flo_ai.models.flo_executable import ExecutableFlo from langgraph.graph.graph import CompiledGraph -from flo_ai.yaml.config import TeamConfig class FloRoutedTeam(ExecutableFlo): - def __init__(self, name: str, graph: CompiledGraph, config: TeamConfig) -> None: + def __init__(self, name: str, graph: CompiledGraph) -> None: super().__init__(name, graph) - self.config = config # Overridden for xray use, doesnt work in base class def draw(self, xray=True): diff --git a/flo_ai/models/flo_team.py b/flo_ai/models/flo_team.py index 7bc7db54..db0070a1 100644 --- a/flo_ai/models/flo_team.py +++ b/flo_ai/models/flo_team.py @@ -1,18 +1,16 @@ from flo_ai.models.flo_member import FloMember -from flo_ai.yaml.config import TeamConfig class FloTeam: - def __init__(self, team_config: TeamConfig, members: list[FloMember]) -> None: - self.name = team_config.name - self.config = team_config + def __init__(self, name: str, members: list[FloMember]) -> None: + self.name = name self.members = members class Builder: - def __init__(self, team_config: TeamConfig, members: list[FloMember]) -> None: - self.team_config = team_config + def __init__(self, name: str, members: list[FloMember]) -> None: + self.name = name self.members = members self.member_names = list(map(lambda x: x.name, self.members)) def build(self): - return FloTeam(team_config=self.team_config, members=self.members) + return FloTeam(name=self.name, members=self.members) diff --git a/flo_ai/models/flo_tool_agent.py b/flo_ai/models/flo_tool_agent.py index 18dc973b..e95ef200 100644 --- a/flo_ai/models/flo_tool_agent.py +++ b/flo_ai/models/flo_tool_agent.py @@ -1,31 +1,26 @@ from langchain_core.runnables import Runnable from flo_ai.models.flo_executable import ExecutableFlo from flo_ai.state.flo_session import FloSession -from flo_ai.yaml.config import AgentConfig from flo_ai.models.flo_executable import ExecutableType class FloToolAgent(ExecutableFlo): - def __init__( - self, executor: Runnable, config: AgentConfig, model_name: str - ) -> None: - super().__init__(config.name, executor, ExecutableType.tool) + def __init__(self, name: str, executor: Runnable, model_name: str) -> None: + super().__init__(name, executor, ExecutableType.tool) self.executor: Runnable = executor - self.config: AgentConfig = config self.model_name: str = model_name class Builder: def __init__( self, session: FloSession, - config: AgentConfig, + name: str, tool_runnable: Runnable, model_name: str, ) -> None: - self.name: str = config.name + self.name: str = name self.runnable = tool_runnable - self.config = config self.model_name = model_name def build(self) -> Runnable: - return FloToolAgent(self.runnable, self.configs, self, self.model_name) + return FloToolAgent(self.runnable, self, self.model_name) diff --git a/flo_ai/models/flo_transformer.py b/flo_ai/models/flo_transformer.py deleted file mode 100644 index 35d6e261..00000000 --- a/flo_ai/models/flo_transformer.py +++ /dev/null @@ -1,6 +0,0 @@ -from flo_ai.models.flo_node import FloNode - - -class FloTransformer(FloNode): - def __init__(self, func: object, name: str) -> None: - super().__init__(func, name) diff --git a/flo_ai/router/flo_linear.py b/flo_ai/router/flo_linear.py index 846e7529..4653a0c8 100644 --- a/flo_ai/router/flo_linear.py +++ b/flo_ai/router/flo_linear.py @@ -66,7 +66,7 @@ def build_graph(self): workflow_graph = workflow.compile() - return FloRoutedTeam(self.flo_team.name, workflow_graph, self.flo_team.config) + return FloRoutedTeam(self.flo_team.name, workflow_graph) class Builder: def __init__( diff --git a/flo_ai/router/flo_llm_router.py b/flo_ai/router/flo_llm_router.py index 66f319f3..40536e11 100644 --- a/flo_ai/router/flo_llm_router.py +++ b/flo_ai/router/flo_llm_router.py @@ -9,7 +9,6 @@ from flo_ai.models.flo_routed_team import FloRoutedTeam from langgraph.graph import StateGraph from flo_ai.state.flo_state import TeamFloAgentState -from flo_ai.yaml.config import TeamConfig from langchain_core.output_parsers import JsonOutputParser from pydantic import BaseModel, Field @@ -40,24 +39,25 @@ def build_graph(self): workflow = StateGraph(TeamFloAgentState) for flo_agent_node in flo_agent_nodes: workflow.add_node(flo_agent_node.name, flo_agent_node.func) - workflow.add_node(self.router_name, self.build_node(self).func) + + workflow.add_node(self.name, self.build_node(self).func) for member in self.member_names: - workflow.add_edge(member, self.router_name) - workflow.add_conditional_edges(self.router_name, self.router_fn) - workflow.set_entry_point(self.router_name) + workflow.add_edge(member, self.name) + workflow.add_conditional_edges(self.name, self.router_fn) + workflow.set_entry_point(self.name) workflow_graph = workflow.compile() - return FloRoutedTeam(self.flo_team.name, workflow_graph, self.flo_team.config) + return FloRoutedTeam(self.flo_team.name, workflow_graph) class Builder: def __init__( self, session: FloSession, - team_config: TeamConfig, + name: str, flo_team: FloTeam, router_prompt: ChatPromptTemplate = None, llm: Union[BaseLanguageModel, None] = None, ) -> None: - self.name = team_config.router.name + self.name = name self.session = session self.llm = llm if llm is not None else session.llm self.flo_team = flo_team diff --git a/flo_ai/router/flo_router.py b/flo_ai/router/flo_router.py index eb15388b..ee77f0b9 100644 --- a/flo_ai/router/flo_router.py +++ b/flo_ai/router/flo_router.py @@ -6,7 +6,6 @@ from flo_ai.state.flo_session import FloSession from flo_ai.models.flo_team import FloTeam from flo_ai.models.flo_member import FloMember -from flo_ai.yaml.config import TeamConfig from flo_ai.models.flo_routed_team import FloRoutedTeam from flo_ai.constants.prompt_constants import FLO_FINISH from flo_ai.models.flo_executable import ExecutableType @@ -28,17 +27,15 @@ def __init__( name: str, flo_team: FloTeam, executor, - config: TeamConfig = None, model_name: Union[str, None] = 'default', ): - self.router_name = name + self.name = name self.session: FloSession = session self.flo_team: FloTeam = flo_team self.members = flo_team.members self.member_names = [x.name for x in flo_team.members] self.type: ExecutableType = ExecutableType.router self.executor = executor - self.config = config self.model_name = model_name def build_routed_team(self) -> FloRoutedTeam: @@ -55,10 +52,9 @@ def build_node(self, flo_member: FloMember) -> FloNode: if flo_member.type == ExecutableType.team: return node_builder.build_from_team(flo_member) if flo_member.type == ExecutableType.delegator: - return FloNode( - flo_member.executor, flo_member.name, flo_member.type, flo_member.config - ) - node_builder = FloNode.Builder(self.session) + return node_builder.build_from_delegator(flo_member) + if flo_member.type == ExecutableType.reflection: + return node_builder.build_from_reflection(flo_member) return node_builder.build_from_agent(flo_member) def router_fn(self, state: TeamFloAgentState): @@ -84,7 +80,7 @@ def add_delegation_edge( delegation_node: FloNode, nextNode: Union[FloNode | str], ): - to_agent_names = [x.name for x in delegation_node.config.to] + to_agent_names = delegation_node.delegate.to delegation_node_name = delegation_node.name next_node_name = nextNode if isinstance(nextNode, str) else nextNode.name retry = delegation_node.config.retry or 1 @@ -134,7 +130,7 @@ def add_reflection_edge( reflection_node: FloNode, nextNode: Union[FloNode | str], ): - to_agent_name = reflection_node.config.to[0].name + to_agent_name = reflection_node.flo_team.members[0] retry = reflection_node.config.retry or 1 reflection_agent_name = reflection_node.name next = nextNode if isinstance(nextNode, str) else nextNode.name diff --git a/flo_ai/router/flo_router_factory.py b/flo_ai/router/flo_router_factory.py index 8ce6e5f5..ae2291f5 100644 --- a/flo_ai/router/flo_router_factory.py +++ b/flo_ai/router/flo_router_factory.py @@ -32,7 +32,7 @@ def create( elif router_kind == 'llm': return FloLLMRouter.Builder( session, - team_config, + team_config.router.name, flo_team, llm=router_model, model_nick_name=team_config.router.model, From 608608a9ffe20a232b70613ce1f0193a0fdb7a43 Mon Sep 17 00:00:00 2001 From: vizsatiz Date: Fri, 15 Nov 2024 22:44:11 +0530 Subject: [PATCH 2/7] Fixes after testing deletgator and reflection --- examples/reflection_example.py | 4 +- flo_ai/factory/agent_factory.py | 15 +++--- flo_ai/models/delegate.py | 2 +- flo_ai/models/flo_delegation_agent.py | 6 +-- flo_ai/models/flo_reflection_agent.py | 2 +- flo_ai/router/flo_linear.py | 72 +++++++++++---------------- flo_ai/router/flo_router.py | 6 +-- flo_ai/router/flo_router_factory.py | 2 +- 8 files changed, 48 insertions(+), 61 deletions(-) diff --git a/examples/reflection_example.py b/examples/reflection_example.py index 7a9ad7b9..9e03c329 100644 --- a/examples/reflection_example.py +++ b/examples/reflection_example.py @@ -46,5 +46,5 @@ flo: Flo = Flo.build(session, yaml=yaml_data) flo.draw_to_file('event.png', xray=True) -data = flo.invoke(input_prompt) -print((data['messages'][-1]).content) +# data = flo.invoke(input_prompt) +# print((data['messages'][-1]).content) diff --git a/flo_ai/factory/agent_factory.py b/flo_ai/factory/agent_factory.py index 32f82209..5ed8940c 100644 --- a/flo_ai/factory/agent_factory.py +++ b/flo_ai/factory/agent_factory.py @@ -7,9 +7,7 @@ from flo_ai.models.flo_delegation_agent import FloDelegatorAgent from flo_ai.models.flo_tool_agent import FloToolAgent from flo_ai.error.flo_exception import FloException -from flo_ai.models.flo_team import FloTeam -from flo_ai.models.flo_member import FloMember -from flo_ai.models.flo_executable import ExecutableType +from flo_ai.models.delegate import Delegate from flo_ai.constants.common_constants import DOCUMENTATION_AGENT_ANCHOR from enum import Enum @@ -106,6 +104,7 @@ def __create_reflection_agent( job=agent.job, role=agent.role, llm=agent_model, + to=Delegate([x.name for x in agent.to], agent.retry), model_name=agent.model, ).build() @@ -114,9 +113,11 @@ def __create_delegator_agent( session: FloSession, agent: AgentConfig ) -> FloReflectionAgent: agent_model = AgentFactory.__resolve_model(session, agent.model) - # see if we can remodel this - members = [FloMember(x.name, ExecutableType.agentic) for x in agent.to] - to = FloTeam.Builder('delegator_team', members=members) return FloDelegatorAgent.Builder( - session, agent.name, agent.job, to, llm=agent_model, model_name=agent.model + session, + agent.name, + agent.job, + delegate=Delegate([x.name for x in agent.to], agent.retry), + llm=agent_model, + model_name=agent.model, ).build() diff --git a/flo_ai/models/delegate.py b/flo_ai/models/delegate.py index 5826b8f3..62494b9b 100644 --- a/flo_ai/models/delegate.py +++ b/flo_ai/models/delegate.py @@ -4,4 +4,4 @@ @dataclass class Delegate: to: list[str] - retry: int + retry: int = 1 diff --git a/flo_ai/models/flo_delegation_agent.py b/flo_ai/models/flo_delegation_agent.py index a743be3e..93294bd1 100644 --- a/flo_ai/models/flo_delegation_agent.py +++ b/flo_ai/models/flo_delegation_agent.py @@ -34,13 +34,13 @@ def __init__( session: FloSession, name: str, job: str, - to: Delegate, + delegate: Delegate, llm: Optional[BaseLanguageModel] = None, model_name: str = None, ) -> None: self.session = session self.name = name - self.to = to + self.to = delegate delegator_base_system_message = ( 'You are a delegator tasked with routing a conversation between the' ' following {member_type}: {members}. Given the following rules,' @@ -48,7 +48,7 @@ def __init__( ) self.model_name = model_name self.llm = session.llm if llm is None else llm - self.options = [x.name for x in to.members] + self.options = delegate.to self.parser = JsonOutputParser(pydantic_object=NextAgent) self.llm_router_prompt = ChatPromptTemplate.from_messages( [ diff --git a/flo_ai/models/flo_reflection_agent.py b/flo_ai/models/flo_reflection_agent.py index 2f133d3a..4da9e527 100644 --- a/flo_ai/models/flo_reflection_agent.py +++ b/flo_ai/models/flo_reflection_agent.py @@ -52,5 +52,5 @@ def __init__( def build(self): executor = self.prompt | self.llm | StrOutputParser() return FloReflectionAgent( - self.name, executor, self.model_name, delegate=self.to + self.name, executor, self.model_name, delegate=self.delegate ) diff --git a/flo_ai/router/flo_linear.py b/flo_ai/router/flo_linear.py index 4653a0c8..492a24e7 100644 --- a/flo_ai/router/flo_linear.py +++ b/flo_ai/router/flo_linear.py @@ -1,4 +1,3 @@ -from flo_ai.yaml.config import TeamConfig from flo_ai.router.flo_router import FloRouter from langgraph.graph import StateGraph, END, START from flo_ai.state.flo_state import TeamFloAgentState @@ -9,72 +8,59 @@ class FloLinear(FloRouter): - def __init__(self, session: FloSession, config: TeamConfig, flo_team: FloTeam): + def __init__(self, session: FloSession, name: str, flo_team: FloTeam): super().__init__( session=session, - name=config.name, + name=name, flo_team=flo_team, executor=None, - config=config, model_name=None, ) - self.router_config = config.router def build_graph(self): flo_agent_nodes = [self.build_node(member) for member in self.members] - workflow = StateGraph(TeamFloAgentState) for flo_node in flo_agent_nodes: agent_name = flo_node.name workflow.add_node(agent_name, flo_node.func) - if self.router_config.edges is None: - start_node = flo_agent_nodes[0] - end_node = flo_agent_nodes[-1] - workflow.add_edge(START, start_node.name) - for i in range(len(flo_agent_nodes) - 1): - parent_node = flo_agent_nodes[i] - child_node = flo_agent_nodes[i + 1] - next_node = ( - flo_agent_nodes[i + 2] if (i + 2) < len(flo_agent_nodes) else END - ) - if parent_node.kind == ExecutableType.reflection: - self.add_reflection_edge(workflow, parent_node, child_node) - continue - if child_node.kind == ExecutableType.delegator: - self.add_delegation_edge( - workflow, parent_node, child_node, next_node - ) - continue + start_node = flo_agent_nodes[0] + end_node = flo_agent_nodes[-1] + workflow.add_edge(START, start_node.name) + for i in range(len(flo_agent_nodes) - 1): + parent_node = flo_agent_nodes[i] + child_node = flo_agent_nodes[i + 1] + next_node = ( + flo_agent_nodes[i + 2] if (i + 2) < len(flo_agent_nodes) else END + ) + if parent_node.kind == ExecutableType.reflection: + self.add_reflection_edge(workflow, parent_node, child_node) + continue + if child_node.kind == ExecutableType.delegator: + self.add_delegation_edge(workflow, parent_node, child_node, next_node) + continue - if ( - child_node.kind != ExecutableType.reflection - and parent_node.kind != ExecutableType.delegator - ): - workflow.add_edge(parent_node.name, child_node.name) + if ( + child_node.kind != ExecutableType.reflection + and parent_node.kind != ExecutableType.delegator + ): + workflow.add_edge(parent_node.name, child_node.name) - if end_node.kind == ExecutableType.reflection: - self.add_reflection_edge(workflow, end_node, END) - elif end_node.kind != ExecutableType.delegator: - workflow.add_edge(end_node.name, END) - else: - workflow.add_edge(START, self.router_config.start_node) - for edge in self.router_config.edges: - workflow.add_edge(edge[0], edge[1]) - workflow.add_edge(self.router_config.end_node, END) + if end_node.kind == ExecutableType.reflection: + self.add_reflection_edge(workflow, end_node, END) + elif end_node.kind != ExecutableType.delegator: + workflow.add_edge(end_node.name, END) workflow_graph = workflow.compile() return FloRoutedTeam(self.flo_team.name, workflow_graph) class Builder: - def __init__( - self, session: FloSession, config: TeamConfig, flo_team: FloTeam - ) -> None: - self.config = config + def __init__(self, session: FloSession, name: str, flo_team: FloTeam) -> None: + self.name = name self.session = session self.team = flo_team def build(self): - return FloLinear(self.session, self.config, self.team) + return FloLinear(self.session, self.name, self.team) diff --git a/flo_ai/router/flo_router.py b/flo_ai/router/flo_router.py index ee77f0b9..027b3fbf 100644 --- a/flo_ai/router/flo_router.py +++ b/flo_ai/router/flo_router.py @@ -83,7 +83,7 @@ def add_delegation_edge( to_agent_names = delegation_node.delegate.to delegation_node_name = delegation_node.name next_node_name = nextNode if isinstance(nextNode, str) else nextNode.name - retry = delegation_node.config.retry or 1 + retry = delegation_node.delegate.retry or 1 conditional_map = {} for agent_name in to_agent_names: @@ -130,8 +130,8 @@ def add_reflection_edge( reflection_node: FloNode, nextNode: Union[FloNode | str], ): - to_agent_name = reflection_node.flo_team.members[0] - retry = reflection_node.config.retry or 1 + to_agent_name = reflection_node.delegate.to[0] + retry = reflection_node.delegate.retry or 1 reflection_agent_name = reflection_node.name next = nextNode if isinstance(nextNode, str) else nextNode.name diff --git a/flo_ai/router/flo_router_factory.py b/flo_ai/router/flo_router_factory.py index ae2291f5..e57896f4 100644 --- a/flo_ai/router/flo_router_factory.py +++ b/flo_ai/router/flo_router_factory.py @@ -28,7 +28,7 @@ def create( model_nick_name=team_config.router.model, ).build() elif router_kind == 'linear': - return FloLinear.Builder(session, team_config, flo_team).build() + return FloLinear.Builder(session, team_config.name, flo_team).build() elif router_kind == 'llm': return FloLLMRouter.Builder( session, From bb17556764883a50423ff7886f0d213e4a7396f0 Mon Sep 17 00:00:00 2001 From: vizsatiz Date: Fri, 15 Nov 2024 23:00:18 +0530 Subject: [PATCH 3/7] Setup notebook to demostrate composability by code --- examples/build_agents_by_code.ipynb | 98 ++++++++++++++++++++--------- flo_ai/builders/yaml_builder.py | 4 +- flo_ai/models/flo_team.py | 13 +++- flo_ai/router/flo_router_factory.py | 2 +- flo_ai/router/flo_supervisor.py | 5 +- 5 files changed, 82 insertions(+), 40 deletions(-) diff --git a/examples/build_agents_by_code.ipynb b/examples/build_agents_by_code.ipynb index 0a408fe3..67be1aaf 100644 --- a/examples/build_agents_by_code.ipynb +++ b/examples/build_agents_by_code.ipynb @@ -43,22 +43,9 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "ename": "AttributeError", - "evalue": "'str' object has no attribute 'job'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[2], line 7\u001b[0m\n\u001b[1;32m 1\u001b[0m llm \u001b[38;5;241m=\u001b[39m ChatOpenAI(temperature\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m0\u001b[39m, model_name\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mgpt-4o\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 2\u001b[0m session \u001b[38;5;241m=\u001b[39m FloSession(llm)\u001b[38;5;241m.\u001b[39mregister_tool(\n\u001b[1;32m 3\u001b[0m name\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mTavilySearchResults\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 4\u001b[0m tool\u001b[38;5;241m=\u001b[39mTavilySearchResults()\n\u001b[1;32m 5\u001b[0m )\n\u001b[0;32m----> 7\u001b[0m researcher \u001b[38;5;241m=\u001b[39m \u001b[43mFloAgent\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mBuilder\u001b[49m\u001b[43m(\u001b[49m\u001b[43msession\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mResearcher\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\n\u001b[1;32m 8\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mDo a research on the internet and find articles of relevent to the topic asked by the user\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m[\u001b[49m\u001b[43mTavilySearchResults\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241m.\u001b[39mbuild()\n\u001b[1;32m 9\u001b[0m blogger \u001b[38;5;241m=\u001b[39m FloAgent\u001b[38;5;241m.\u001b[39mBuilder(session, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mBlogWriter\u001b[39m\u001b[38;5;124m\"\u001b[39m, \n\u001b[1;32m 10\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mAble to write a blog using information provided\u001b[39m\u001b[38;5;124m\"\u001b[39m, [TavilySearchResults()])\u001b[38;5;241m.\u001b[39mbuild()\n\u001b[1;32m 12\u001b[0m marketing_team \u001b[38;5;241m=\u001b[39m FloTeam\u001b[38;5;241m.\u001b[39mBuilder(session, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mMarketing\u001b[39m\u001b[38;5;124m\"\u001b[39m, [researcher, blogger])\u001b[38;5;241m.\u001b[39mbuild()\n", - "File \u001b[0;32m~/Documents/hub/flo/flo_ai/models/flo_agent.py:40\u001b[0m, in \u001b[0;36mFloAgent.Builder.__init__\u001b[0;34m(self, session, config, tools, verbose, role, llm, on_error, model_name)\u001b[0m\n\u001b[1;32m 29\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m__init__\u001b[39m(\n\u001b[1;32m 30\u001b[0m \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m 31\u001b[0m session: FloSession,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 38\u001b[0m model_name: Union[\u001b[38;5;28mstr\u001b[39m, \u001b[38;5;28;01mNone\u001b[39;00m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdefault\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[1;32m 39\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m---> 40\u001b[0m prompt: Union[ChatPromptTemplate, \u001b[38;5;28mstr\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[43mconfig\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mjob\u001b[49m\n\u001b[1;32m 41\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mname: \u001b[38;5;28mstr\u001b[39m \u001b[38;5;241m=\u001b[39m config\u001b[38;5;241m.\u001b[39mname\n\u001b[1;32m 42\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mmodel_name \u001b[38;5;241m=\u001b[39m model_name\n", - "\u001b[0;31mAttributeError\u001b[0m: 'str' object has no attribute 'job'" - ] - } - ], + "outputs": [], "source": [ "llm = ChatOpenAI(temperature=0, model_name='gpt-4o')\n", "session = FloSession(llm).register_tool(\n", @@ -66,10 +53,19 @@ " tool=TavilySearchResults()\n", ")\n", "\n", - "researcher = FloAgent.Builder(session, \"Researcher\", \n", - " \"Do a research on the internet and find articles of relevent to the topic asked by the user\", [TavilySearchResults()]).build()\n", - "blogger = FloAgent.Builder(session, \"BlogWriter\", \n", - " \"Able to write a blog using information provided\", [TavilySearchResults()]).build()\n", + "researcher = FloAgent.Builder(\n", + " session,\n", + " \"Researcher\", \n", + " \"Do a research on the internet and find articles of relevent to the topic asked by the user\", \n", + " [TavilySearchResults()]\n", + ").build()\n", + "\n", + "blogger = FloAgent.Builder(\n", + " session, \n", + " \"BlogWriter\", \n", + " \"Able to write a blog using information provided\", \n", + " [TavilySearchResults()]\n", + ").build()\n", "\n", "marketing_team = FloTeam.Builder(session, \"Marketing\", [researcher, blogger]).build()\n", "r1 = FloSupervisor.Builder(session, \"Head-of-Marketing\", marketing_team).build()\n", @@ -93,11 +89,24 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 7, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ - "draw_to_file(flo_team_1, \"dk.png\", True)" + "from IPython.display import Image, display\n", + "\n", + "display(Image(flo_team_1.draw()))" ] }, { @@ -109,32 +118,59 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 8, "metadata": {}, "outputs": [], "source": [ - "chief_editorial = FloAgent.Builder(session, \"Senior-Editor\", \n", - " \"Have a look at the article created and give editorial suggestions\", [TavilySearchResults()]).build()\n", + "chief_editorial = FloAgent.Builder(\n", + " session, \n", + " \"Senior-Editor\", \n", + " \"Have a look at the article created and give editorial suggestions\", \n", + " [TavilySearchResults()]\n", + ").build()\n", "\n", "edit_team = FloTeam.Builder(session, \"Editorial-Team\", [chief_editorial]).build()\n", "r2 = FloSupervisor.Builder(session, \"Editor-Team-Routing\", edit_team).build()\n", "\n", - "editorial_team = r2.build_routed_team()\n", - "draw_to_file(editorial_team, \"editorial.png\", True)" + "editorial_team = r2.build_routed_team()" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from IPython.display import Image, display\n", + "\n", + "display(Image(editorial_team.draw()))" ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ "journal_company = FloTeam.Builder(session, \"Newspaper\", [flo_team_1, editorial_team])\n", "\n", "# TODO fix router config\n", - "r3 = FloLinear.Builder(session,\n", - " journal_company, \n", - " RouterConfig(**{\"name\" :\"Serial\", \"kind\": \"linear\"})).build()\n", + "r3 = FloLinear.Builder(\n", + " session,\n", + " \"linear-router\",\n", + " journal_company\n", + ").build()\n", "\n", "master_team = r3.build_routed_team()" ] diff --git a/flo_ai/builders/yaml_builder.py b/flo_ai/builders/yaml_builder.py index 8abf5bd2..70a849e9 100644 --- a/flo_ai/builders/yaml_builder.py +++ b/flo_ai/builders/yaml_builder.py @@ -39,7 +39,7 @@ def parse_and_build_subteams( validate_team(name_set, team_config, session) if team_config.agents: members = [AgentFactory.create(session, agent) for agent in team_config.agents] - flo_team = FloTeam.Builder(team_config.name, members=members).build() + flo_team = FloTeam.Builder(session, team_config.name, members=members).build() router = FloRouterFactory.create(session, team_config, flo_team) flo_routed_team = router.build_routed_team() else: @@ -47,7 +47,7 @@ def parse_and_build_subteams( for subteam in team_config.subteams: flo_subteam = parse_and_build_subteams(session, subteam, name_set) flo_teams.append(flo_subteam) - flo_team = FloTeam.Builder(team_config.name, members=flo_teams).build() + flo_team = FloTeam.Builder(session, team_config.name, members=flo_teams).build() router = FloRouterFactory.create(session, team_config, flo_team) flo_routed_team = router.build_routed_team() return flo_routed_team diff --git a/flo_ai/models/flo_team.py b/flo_ai/models/flo_team.py index db0070a1..781c3c61 100644 --- a/flo_ai/models/flo_team.py +++ b/flo_ai/models/flo_team.py @@ -1,16 +1,23 @@ from flo_ai.models.flo_member import FloMember +from flo_ai.state.flo_session import FloSession class FloTeam: - def __init__(self, name: str, members: list[FloMember]) -> None: + def __init__( + self, session: FloSession, name: str, members: list[FloMember] + ) -> None: self.name = name self.members = members + self.session = session class Builder: - def __init__(self, name: str, members: list[FloMember]) -> None: + def __init__( + self, session: FloSession, name: str, members: list[FloMember] + ) -> None: self.name = name + self.session = session self.members = members self.member_names = list(map(lambda x: x.name, self.members)) def build(self): - return FloTeam(name=self.name, members=self.members) + return FloTeam(name=self.name, session=self.session, members=self.members) diff --git a/flo_ai/router/flo_router_factory.py b/flo_ai/router/flo_router_factory.py index e57896f4..c0e85ce9 100644 --- a/flo_ai/router/flo_router_factory.py +++ b/flo_ai/router/flo_router_factory.py @@ -22,7 +22,7 @@ def create( if router_kind == 'supervisor': return FloSupervisor.Builder( session, - team_config, + team_config.name, flo_team, llm=router_model, model_nick_name=team_config.router.model, diff --git a/flo_ai/router/flo_supervisor.py b/flo_ai/router/flo_supervisor.py index c1f731ba..31f957c6 100644 --- a/flo_ai/router/flo_supervisor.py +++ b/flo_ai/router/flo_supervisor.py @@ -6,7 +6,6 @@ from flo_ai.constants.prompt_constants import FLO_FINISH from flo_ai.router.flo_llm_router import FloLLMRouter from flo_ai.models.flo_team import FloTeam -from flo_ai.yaml.config import TeamConfig from langchain_core.output_parsers import JsonOutputParser from flo_ai.router.flo_llm_router import NextAgent @@ -40,12 +39,12 @@ class Builder: def __init__( self, session: FloSession, - team_config: TeamConfig, + name: str, flo_team: FloTeam, llm: Union[BaseLanguageModel, None] = None, model_nick_name: str = 'default', ) -> None: - self.name = team_config.router.name + self.name = name self.session = session self.llm = llm if llm is not None else session.llm self.model_name = model_nick_name From 2e7d0eef7c550d2c335a501f43ffe176da493463 Mon Sep 17 00:00:00 2001 From: vizsatiz Date: Fri, 15 Nov 2024 23:03:12 +0530 Subject: [PATCH 4/7] Fix for bug in linear team team --- flo_ai/models/flo_node.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/flo_ai/models/flo_node.py b/flo_ai/models/flo_node.py index a5182c28..8971861b 100644 --- a/flo_ai/models/flo_node.py +++ b/flo_ai/models/flo_node.py @@ -54,9 +54,7 @@ def build_from_reflection(self, flo_agent: FloReflectionAgent) -> 'FloNode': def build_from_team(self, flo_team: FloRoutedTeam) -> 'FloNode': team_chain = ( functools.partial( - FloNode.Builder.__teamflo_team_node, - members=flo_team.runnable.nodes, - session=self.session, + FloNode.Builder.__teamflo_team_node, members=flo_team.runnable.nodes ) | flo_team.runnable ) From 15a422f9ca0dd28b7a4abd11d6d3c85af6e0a48c Mon Sep 17 00:00:00 2001 From: vizsatiz Date: Sat, 16 Nov 2024 00:18:44 +0530 Subject: [PATCH 5/7] Renaming build team to flo --- examples/build_agents_by_code.ipynb | 212 ++++++++-------------------- flo_ai/builders/yaml_builder.py | 4 +- flo_ai/router/flo_router.py | 2 +- 3 files changed, 62 insertions(+), 156 deletions(-) diff --git a/examples/build_agents_by_code.ipynb b/examples/build_agents_by_code.ipynb index 67be1aaf..9860b76a 100644 --- a/examples/build_agents_by_code.ipynb +++ b/examples/build_agents_by_code.ipynb @@ -69,7 +69,7 @@ "\n", "marketing_team = FloTeam.Builder(session, \"Marketing\", [researcher, blogger]).build()\n", "r1 = FloSupervisor.Builder(session, \"Head-of-Marketing\", marketing_team).build()\n", - "flo_team_1 = r1.build_routed_team()\n" + "marketing_flo = r1.to_flo()\n" ] }, { @@ -89,7 +89,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -106,7 +106,7 @@ "source": [ "from IPython.display import Image, display\n", "\n", - "display(Image(flo_team_1.draw()))" + "display(Image(marketing_flo.draw()))" ] }, { @@ -118,7 +118,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -132,12 +132,12 @@ "edit_team = FloTeam.Builder(session, \"Editorial-Team\", [chief_editorial]).build()\n", "r2 = FloSupervisor.Builder(session, \"Editor-Team-Routing\", edit_team).build()\n", "\n", - "editorial_team = r2.build_routed_team()" + "editorial_flo = r2.to_flo()" ] }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -154,7 +154,7 @@ "source": [ "from IPython.display import Image, display\n", "\n", - "display(Image(editorial_team.draw()))" + "display(Image(editorial_flo.draw()))" ] }, { @@ -163,30 +163,42 @@ "metadata": {}, "outputs": [], "source": [ - "journal_company = FloTeam.Builder(session, \"Newspaper\", [flo_team_1, editorial_team])\n", + "journal_company = FloTeam.Builder(session, \"Newspaper\", [marketing_flo, editorial_flo])\n", "\n", - "# TODO fix router config\n", "r3 = FloLinear.Builder(\n", " session,\n", " \"linear-router\",\n", " journal_company\n", ").build()\n", "\n", - "master_team = r3.build_routed_team()" + "master_flo = r3.to_flo()" ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ - "draw_to_file(master_team, \"master.png\")" + "from IPython.display import Image, display\n", + "\n", + "display(Image(master_flo.draw()))" ] }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -197,172 +209,66 @@ "\n", "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", "\u001b[32;1m\u001b[1;3m\n", - "Invoking: `tavily_search_results_json` with `{'query': 'Cristiano Ronaldo biography'}`\n", + "Invoking: `tavily_search_results_json` with `{'query': 'Cristiano Ronaldo biography 2023'}`\n", "\n", "\n", - "\u001b[0m\u001b[36;1m\u001b[1;3m[{'url': 'https://www.liveabout.com/cristiano-ronaldo-3557502', 'content': 'Learn about the life and career of Cristiano Ronaldo, the Portuguese footballer who plays for Real Madrid and is one of the best players in the world. Find out his achievements, awards, records, and controversies in this comprehensive biography.'}, {'url': 'https://www.biographyonline.net/sport/football/cristiano-ronaldo.html', 'content': \"Learn about the life and career of Cristiano Ronaldo, one of the world's best footballers. From his early days in Portugal to his success at Manchester United, Real Madrid and Juventus, and his international achievements with Portugal.\"}, {'url': 'https://eurofootballer.com/who-is-cristiano-ronaldo-complete-biography-and-life-history/', 'content': \"Learn about the life and achievements of Cristiano Ronaldo, one of the world's best footballers. From his early days in Portugal to his record-breaking stints in England, Spain and Italy, and his current contract with Al-Nassr in Saudi Arabia.\"}, {'url': 'https://en.wikipedia.org/wiki/Career_of_Cristiano_Ronaldo', 'content': 'Learn about the life and achievements of Cristiano Ronaldo, one of the greatest footballers of all time. From his early days at Sporting CP to his record-breaking moves and awards, this article covers his career in detail.'}, {'url': 'https://www.britannica.com/biography/Cristiano-Ronaldo', 'content': 'He scored a total of 66 goals in 56 appearances with Madrid and the Portuguese national team in 2013 to earn his second world player of the year award (the FIFA World Player of the Year was renamed the FIFA Ballon d’Or in 2010). Endorsements and legal issues\\nRonaldo was one of the most well-known sports stars off the field, and numerous studies of athletes’ popularity showed that he was the most-beloved athlete in the world during his playing peak. In 2016 he helped Portugal win the European Championship, the country’s first major international tournament title, although he only played sparingly in the final because of a knee injury that he had sustained early in the match. Ronaldo came into the 2014 World Cup hot off of his second world player of the year win, but his play at the tournament was spotty, and the entire Portugal team struggled during a group-stage elimination. His extreme popularity made Ronaldo one of the highest-paid endorsers in sports history, and in November 2016 he became the third person (after basketball superstars Michael Jordan and LeBron James) to earn a “lifetime” contract from the sportswear company Nike.'}]\u001b[0m\u001b[32;1m\u001b[1;3m\n", - "Invoking: `tavily_search_results_json` with `{'query': 'Cristiano Ronaldo career achievements'}`\n", + "\u001b[0m\u001b[36;1m\u001b[1;3m[{'url': 'https://en.wikipedia.org/wiki/Cristiano_Ronaldo', 'content': 'After scoring in the following matches against Chelsea and Brentford, he was named the Premier League Player of the Month for April.[313]\\nHe finished the season with 24 goals in all competitions, 18 of those goals being in the Premier League, making him the third-highest goalscorer in the league behind Golden Boot winners Mohamed Salah and Son Heung-min, being named in the Premier League Team of the Year and the winner of United\\'s Sir Matt Busby Player of the Year award, given to the club\\'s best player from the previous season;[314][315] however, with United finishing in a disappointing sixth place and qualifying for the UEFA Europa League, Ronaldo went trophyless for the first time since 2010.[316]\\nAfter growing dissatisfaction with the direction of United on and off the field, Ronaldo missed the club\\'s pre-season tour of Thailand and Australia due to family reasons, amid reports of his desire to leave to join a club competing in the Champions League, despite incoming manager Erik ten Hag insisting that he was not for sale and was part of the club\\'s plans.[317] Ronaldo was awarded the Player of the Month award for February after scoring eight goals and assisting twice.[346] Ronaldo spent another season without winning a league title, as Al Nassr finished second in the league in the 2022–23 season.[347]\\nRonaldo\\'s signing for Al-Nassr resulted in increased popularity both domestically and internationally of the Saudi Pro League, with various European players such as Karim Benzema, Sadio Mané, N\\'Golo Kanté, Rúben Neves, Riyad Mahrez, Roberto Firmino and Neymar moving to the Saudi Pro League during the summer transfer window, crediting Ronaldo as one of the main factors for moving to the league.[348]\\nHe scored his first goal of the 2023–24 season in a 4–1 win over Union Monastirienne in the Arab Club Champions Cup on 31 July.[349] This unique role has been described by pundits as that of a \"false\", \"attacking\", or \"goalscoring winger\", as Ronaldo effectively almost functioned as a striker at times with his central runs into the penalty area, despite actually playing on the left flank.[488][493] From 2013 onwards, under manager Carlo Ancelotti, he effectively adapted his style to the physical effects of ageing with increasingly reduced off-the-ball movement and general involvement, completing fewer dribbles and passes per game, and instead focusing on short-distance creating and goalscoring.[487][494][495] Since 2017, Ronaldo adapted his style of play yet again to become more of a free-roaming centre forward under manager Zinedine Zidane, a role in which he continued to excel and maintain a prolific goalscoring record; in this position, he earned praise in the media for his intelligent movement both on and off the ball, positional sense, link-up play and finishing, as well as his ability to lose or anticipate his markers, find space in the box and score from few touches or opportunities.[496][497][498]\\n Ronaldo then missed United\\'s following matches before the World Cup break, with Ten Hag saying that Ronaldo was ill.[329]\\nOn 14 November, an interview with Piers Morgan was published, where Ronaldo said that he felt \"betrayed\" by Ten Hag and senior executives who wanted Ronaldo to leave the club, and accused the club of doubting him regarding the illness of his daughter that led him to miss pre-season, adding that he did not respect ten Hag \"because he doesn\\'t show respect for me\", leading him to be disappointed with the communication of the club.[330] Ronaldo claimed that ten Hag deliberately provoked him by first leaving him on the bench against City, and then wanting to bring him on in the final moments against Tottenham, but added that he regretted his decision to leave early.[330] Ronaldo ended his first season in English football by scoring the opening goal in United\\'s 3–0 win over Millwall in the 2004 FA Cup Final, earning his first trophy.[52] BBC pundit Alan Hansen described him as the star of the final.[53] The British press had been critical of Ronaldo during the season for his \"elaborate\" step-overs in trying to beat opponents,[54] but teammate Gary Neville said he was \"not a show pony, but the real thing\", and predicted he would become a world-class player.[55]\\n\"He has got the tricks and party pieces, we know that, but they\\'re not much good unless there is something at the end of it all.'}, {'url': 'https://www.forbes.com/profile/cristiano-ronaldo/', 'content': \"Compared To Cristiano Ronaldo After Clasico Heroics\\nFC Barcelona Star Ousmane Dembele Receives ‘Enormous’ $220 Million Offer To Join Ronaldo At Al-Nassr: Reports\\nFootball Superstar Cristiano Ronaldo Invests In Online Watch Marketplace Chrono24\\n2023 (So Far): Cristiano Ronaldo Is The Most Followed Person On Instagram\\nFC Barcelona Transfer Target Must Choose Catalans Or Joining Cristiano Ronaldo At Saudi Giants: Reports\\nCristiano Ronaldo Offers Himself To Real Madrid Bitter Rivals, Tells Al-Nassr He Wishes To Leave: Reports\\nJuventus Trial Latest: Prosecutor Resigns, Details Of “Secret” Cristiano Ronaldo Documents Revealed\\nSigning Of The Season? Cristiano Ronaldo\\n2023 The World's Highest-Paid Athletes Earnings\\nForbes Lists\\nMore on Forbes\\nNegotiations Underway As Saudis Offer $1.1 Billion For Serie A Club\\nOnly Behind Messi And Ronaldo: Sunil Chhetri Approaches Milestone At The AFC Asian Cup\\nLionel Messi Will Take On Cristiano Ronaldo Again This January\\nLionel Messi Announces He Will Play In Saudi Arabia Against Cristiano Ronaldo\\nForbes Daily: Henry Kissinger’s Atalanta’s Ademola Lookman Is Scoring Like Cristiano Ronaldo\\nThe Ghost Of Cristiano Ronaldo Will Haunt Manchester United’s Season\\nWhat Happens Next For Cristiano Ronaldo?\\nalso on forbes Influential And Controversial Legacy\\nCristiano Ronaldo Faces $1 Billion Class Action Lawsuit For Promoting Binance\\nJude Bellingham\"}, {'url': 'https://en.wikipedia.org/wiki/Career_of_Cristiano_Ronaldo', 'content': \"Cristiano Ronaldo is a Portuguese footballer who plays as a forward for and captains both Saudi Pro League club Al-Nassr and the Portugal national team.His individual achievements include five Ballon d'Or awards, the most for a European player. His exceptional goal-scoring ability, explosive speed, powerful knuckleball shots, and dribbling skills cemented his legacy as one of the greatest and\"}, {'url': 'https://www.thefamouspeople.com/profiles/cristiano-ronaldo-4103.php', 'content': 'Cape Verdean Portuguese\\nawards: Ballon d\\'Or - 2008 European Golden Shoe - 2015-2011-2008 FIFA World Player of the Year - 2009\\nPichichi Trophy - 2015-2014-2011 FIFA Puskás Award - 2009 UEFA Best Player in Europe Award - 2014 FIFA FIFPro World XI - 2012-2011-2010 UEFA Team of the Year - 2012-2011-2010\\nPFA Players\\' Player of the Year - 2007-2006 Premier League Player of the Month - 2008-2008-2006\\nPremier League Golden Boot - 2007 Best International Athlete ESPY Award - 2014 PFA Young Player of the Year - 2006 Premier League Player of the Season - 2007-2006 Onze d\\'Or - 2008 FWA Footballer of the Year - 2007-2006 PFA Fans\\' Player of the Year - 2007-2006 Goal 50 - 2012-2008 Trofeo Alfredo Di Stéfano - 2011 UEFA Club Footballer of the Year - 2007 World Soccer Player of the Year - 2008 UEFA Champions League Top Goalscorer - 2015-2014-2013 Bravo Award - 2004 PFA Team of the Year - 2008-2007-2006\\nLa Liga Player of the Month - 2013 Sir Matt Busby Player of the Year - 2007-2006-2003 BBC Overseas Sports Personality of the Year - 2014 LFP Most Valuable Player - 2013 Milliyet Sports Award for World Athlete of the Year - 2014 FifPro Special Young Player of the Year - 2005-2004 IFFHS World\\'s Best Top Division Goal Scorer - 2013 UEFA Club Forward of the Year - 2007 FIFA Ballon d\\'Or - 2015-2014\\nRecommended Birthday: February 5, 1985 (Aquarius)\\nBorn In: Funchal, Portugal\\nRecommended For You\\nNick Name: The Sultan Of The Stepover\\nGirlfriend: Georgina Rodríguez, Irina Shayk (2010–2015)\\nAlso Known As: Cristiano Ronaldo dos Santos Aveiro\\nAge: 39 Years, 39 Year Old Males\\nfather: José Dinis Aveiro\\nmother: Maria Dolores dos Santos Aveiro\\nsiblings: Elma Aveiro, Hugo Aveiro, Liliana Catia Aveiro\\nchildren: Alana Martina dos Santos Aveiro, Cristiano Ronaldo Jr., Eva Maria Dos Santos, Mateo Ronaldo\\nBorn Country: Portugal\\nQuotes By Cristiano Ronaldo\\nFootball Players\\nHeight: 6\\'2\" (188 cm), 6\\'2\" Males\\nAncestry: The following year he was named the captain of the national team but in the European Championships that followed the next year, he scored only one goal as the team crashed out in the quarter-finals.\\n In 2012, he was the main inspiration for the team as he scored three goals to lead the team to the semifinal of the European Championships but Portugal was knocked out by Spain yet again in a penalty shootout.\\n Cristiano Ronaldo became one of Manchester United’s most important players during his six-year stint at the club and during that time the club became one of the most successful clubs in Europe as it won three league titles on the trot as well as the UEFA Champions League in 2008.'}, {'url': 'https://www.sportskeeda.com/player/cristiano-ronaldo', 'content': 'Get all the latest news, stats, performance, facts, history and biography of Cristiano Ronaldo. Also Get all the latest moves, skills, goals scored and much more only at Sportskeeda.'}]\u001b[0m\u001b[32;1m\u001b[1;3mCristiano Ronaldo, often referred to as CR7, is a Portuguese footballer renowned for his exceptional talent and achievements in the world of soccer. Born on February 5, 1985, in Funchal, Portugal, Ronaldo has become one of the most celebrated athletes globally, known for his incredible goal-scoring ability, speed, and dribbling skills.\n", "\n", + "### Early Life and Career\n", "\n", - "\u001b[0m\u001b[36;1m\u001b[1;3m[{'url': 'https://en.wikipedia.org/wiki/List_of_career_achievements_by_Cristiano_Ronaldo', 'content': \"Inclusions in theoretical teams\\nSelections for international sportsperson of the year\\nInternational man of the match awards\\nOrders\\nMiscellaneous\\nRecords\\nGoalscoring statistics\\nClub\\n[494][495][496]\\nCountry\\nSource: Rec.Sport. Widely regarded as one of the greatest players of all time, Ronaldo holds the record for most goals and assists in the UEFA Champions League (140 and 42 respectively), and the record for most goals in the UEFA European Championship (14), its qualification stage (40), and the FIFA Club World Cup (7), as well as most goals scored in a UEFA Champions League season (17 in\\n2013-14), most international goals (128), and most appearances in a national team (204). Ronaldo with then President of the Community of Madrid, Cristina Cifuentes, during Champions League title celebrations in Madrid in 2016\\nRonaldo (second from the right) raising his hand in the air as Real Madrid celebrate winning the UEFA Champions League, on 26 May 2018\\nSee also\\nFootnotes\\nReferences\\nWorks cited\\nBiographies Contents\\nList of career achievements by Cristiano Ronaldo\\nPortuguese professional footballer\\nEponyms and public art\\nFilms\\nOver the course of his career, Portuguese footballer Cristiano Ronaldo has received five Ballon d'Or/FIFA Ballon d'Or awards,[a] the most for a European player. All in all he had won over 300 trophies and medals by January 2021, with some of them dating back to his childhood.[1]\\nCollective awards\\nFriendly competitions\\nIndividual honours\\nRonaldo has obtained many other minor achievements, awards and recognitions, by the major sport magazines and newspapers, which are not reported.\\n\"}, {'url': 'https://www.sportingnews.com/us/soccer/news/cristiano-ronaldo-career-trophies-how-many-has-cr7-won/sgkll9jwwmnkarutohgptsvj', 'content': \"In 2021, Ronaldo received The Best FIFA Special Award for Outstanding Career Achievement as he broke the record for most international goals scored by a male footballer. Ronaldo's time at ...\"}, {'url': 'https://www.transfermarkt.com/cristiano-ronaldo/erfolge/spieler/8198', 'content': 'This statistic shows the achievements of Al-Nasr Riad player Cristiano Ronaldo. ... #7 Cristiano Ronaldo. 3 5 1 5 4. Al-Nassr Saudi ... Career . Contact . About Us . TM-Team FAQ . Social media . Transfermarkt Company Projects ...'}, {'url': 'https://www.britannica.com/biography/Cristiano-Ronaldo', 'content': 'He scored a total of 66 goals in 56 appearances with Madrid and the Portuguese national team in 2013 to earn his second world player of the year award (the FIFA World Player of the Year was renamed the FIFA Ballon d’Or in 2010). Endorsements and legal issues\\nRonaldo was one of the most well-known sports stars off the field, and numerous studies of athletes’ popularity showed that he was the most-beloved athlete in the world during his playing peak. In 2016 he helped Portugal win the European Championship, the country’s first major international tournament title, although he only played sparingly in the final because of a knee injury that he had sustained early in the match. Ronaldo came into the 2014 World Cup hot off of his second world player of the year win, but his play at the tournament was spotty, and the entire Portugal team struggled during a group-stage elimination. His extreme popularity made Ronaldo one of the highest-paid endorsers in sports history, and in November 2016 he became the third person (after basketball superstars Michael Jordan and LeBron James) to earn a “lifetime” contract from the sportswear company Nike.'}, {'url': 'https://www.biographyonline.net/sport/football/cristiano-ronaldo.html', 'content': \"Cristiano Ronaldo is a Portuguese professional footballer who has played for Manchester United, Real Madrid, Juventus and Portugal. Along with Lionel Messi, he is regularly considered to be one of the top two players in the world. He became the world's most expensive player when Real Madrid signed him for 94 million Euros in 2009 from ...\"}]\u001b[0m\u001b[32;1m\u001b[1;3m\n", - "Invoking: `tavily_search_results_json` with `{'query': 'Cristiano Ronaldo personal life'}`\n", + "Ronaldo began his professional career with Sporting CP in Portugal before moving to Manchester United in 2003. During his time at Manchester United, he became one of the club's most important players, helping them secure three consecutive Premier League titles and a UEFA Champions League trophy in 2008. His performances earned him the Ballon d'Or in 2008, marking him as the world's best player.\n", "\n", + "### Real Madrid and Juventus\n", "\n", - "\u001b[0m\u001b[36;1m\u001b[1;3m[{'url': 'https://talksport.com/football/1752006/cristiano-ronaldo-georgina-rodriguez-family-children/', 'content': \"Ronaldo has been with Rodriguez since 2016 Credit: @cristiano Instagram Of course, there are also plenty of eyes on the superstar's personal life and his partner Georgina Rodriguez has become a ...\"}, {'url': 'https://www.sportskeeda.com/football/ronaldo-family', 'content': \"Learn about the Portuguese football legend's family, including his girlfriend Georgina Rodriguez, his twins Eva Maria and Mateo, and his son Cristiano Jr. Find out how he lost his father at a young age and who is the mother of his twins.\"}, {'url': 'https://people.com/parents/everything-to-know-about-cristiano-ronaldo-family-kids/', 'content': '\"\\nNow nearly 12 years old, Cristiano Jr. is taking after his father in more than just looks — he plays soccer just like Dad!\\nEva Maria and Mateo Ronaldo, 6\\nIn June 2017, Ronaldo welcomed twins Eva and Mateo via surrogate, sharing the happy news of their arrival in a Facebook post captioned, \"So happy to be able to hold the two new loves of my life 🙏❤. Everything to Know About Cristiano Ronaldo\\'s Family\\nCristiano Ronaldo shares his children with girlfriend Georgina Rodriguez\\nCristiano Ronaldo and Georgina Rodriguez are finding \"hope and happiness\" after the birth of their daughter and amid mourning the loss of their newborn son.\\n This year, I had the best and the worst moment of my life in an instant,\" she said, adding that Ronaldo \"encouraged\" her to start enjoying life again after the heavy loss. \"\\nMonths before the twins\\' arrival, Ronaldo began dating model Georgina Rodriguez, with the pair making their first public appearance at the Best FIFA Football Awards in January 2017.\\n \"After one week I say, \\'Let\\'s be upfront, and let\\'s be honest with the kids, let\\'s say that, Ángel, which is his name, he go to the Heaven.\\''}, {'url': 'https://www.thisisamericansoccer.com/cristiano-ronaldos-family/', 'content': 'Learn about the Ronaldo family tree, from his humble origins in Madeira to his global fame as a football legend. Discover how his parents, siblings, partner, and children shaped his character and supported his dreams.'}, {'url': 'https://en.wikipedia.org/wiki/Cristiano_Ronaldo', 'content': 'After scoring in the following matches against Chelsea and Brentford, he was named the Premier League Player of the Month for April.[313]\\nHe finished the season with 24 goals in all competitions, 18 of those goals being in the Premier League, making him the third-highest goalscorer in the league behind Golden Boot winners Mohamed Salah and Son Heung-min, being named in the Premier League Team of the Year and the winner of United\\'s Sir Matt Busby Player of the Year award, given to the club\\'s best player from the previous season;[314][315] however, with United finishing in a disappointing sixth place and qualifying for the UEFA Europa League, Ronaldo went trophyless for the first time since 2010.[316]\\nAfter growing dissatisfaction with the direction of United on and off the field, Ronaldo missed the club\\'s pre-season tour of Thailand and Australia due to family reasons, amid reports of his desire to leave to join a club competing in the Champions League, despite incoming manager Erik ten Hag insisting that he was not for sale and was part of the club\\'s plans.[317] Ronaldo was awarded the Player of the Month award for February after scoring eight goals and assisting twice.[346] Ronaldo spent another season without winning a league title, as Al Nassr finished second in the league in the 2022–23 season.[347]\\nRonaldo\\'s signing for Al-Nassr resulted in increased popularity both domestically and internationally of the Saudi Pro League, with various European players such as Karim Benzema, Sadio Mané, N\\'Golo Kanté, Rúben Neves, Riyad Mahrez, Roberto Firmino and Neymar moving to the Saudi Pro League during the summer transfer window, crediting Ronaldo as one of the main factors for moving to the league.[348]\\nHe scored his first goal of the 2023–24 season in a 4–1 win over Union Monastirienne in the Arab Club Champions Cup on 31 July.[349] This unique role has been described by pundits as that of a \"false\", \"attacking\", or \"goalscoring winger\", as Ronaldo effectively almost functioned as a striker at times with his central runs into the penalty area, despite actually playing on the left flank.[488][493] From 2013 onwards, under manager Carlo Ancelotti, he effectively adapted his style to the physical effects of ageing with increasingly reduced off-the-ball movement and general involvement, completing fewer dribbles and passes per game, and instead focusing on short-distance creating and goalscoring.[487][494][495] Since 2017, Ronaldo adapted his style of play yet again to become more of a free-roaming centre forward under manager Zinedine Zidane, a role in which he continued to excel and maintain a prolific goalscoring record; in this position, he earned praise in the media for his intelligent movement both on and off the ball, positional sense, link-up play and finishing, as well as his ability to lose or anticipate his markers, find space in the box and score from few touches or opportunities.[496][497][498]\\n Ronaldo then missed United\\'s following matches before the World Cup break, with Ten Hag saying that Ronaldo was ill.[329]\\nOn 14 November, an interview with Piers Morgan was published, where Ronaldo said that he felt \"betrayed\" by Ten Hag and senior executives who wanted Ronaldo to leave the club, and accused the club of doubting him regarding the illness of his daughter that led him to miss pre-season, adding that he did not respect ten Hag \"because he doesn\\'t show respect for me\", leading him to be disappointed with the communication of the club.[330] Ronaldo claimed that ten Hag deliberately provoked him by first leaving him on the bench against City, and then wanting to bring him on in the final moments against Tottenham, but added that he regretted his decision to leave early.[330] Ronaldo ended his first season in English football by scoring the opening goal in United\\'s 3–0 win over Millwall in the 2004 FA Cup Final, earning his first trophy.[52] BBC pundit Alan Hansen described him as the star of the final.[53] The British press had been critical of Ronaldo during the season for his \"elaborate\" step-overs in trying to beat opponents,[54] but teammate Gary Neville said he was \"not a show pony, but the real thing\", and predicted he would become a world-class player.[55]\\n\"He has got the tricks and party pieces, we know that, but they\\'re not much good unless there is something at the end of it all.'}]\u001b[0m\u001b[32;1m\u001b[1;3m### Cristiano Ronaldo: A Football Legend\n", + "In 2009, Ronaldo transferred to Real Madrid for a then-world record fee. At Real Madrid, he further cemented his legacy, winning four more Ballon d'Or awards and becoming the club's all-time leading scorer. His tenure at Real Madrid was marked by numerous titles, including four UEFA Champions League trophies.\n", "\n", - "#### Early Life and Career Beginnings\n", + "In 2018, Ronaldo moved to Juventus, where he continued to showcase his goal-scoring prowess, winning two Serie A titles and further enhancing his reputation as one of the greatest footballers of all time.\n", "\n", - "Cristiano Ronaldo dos Santos Aveiro, commonly known as Cristiano Ronaldo or CR7, was born on February 5, 1985, in Funchal, Madeira, Portugal. From a young age, Ronaldo displayed an extraordinary talent for football, which led him to join the youth academy of Sporting CP in Lisbon. His exceptional skills quickly caught the attention of scouts from top European clubs.\n", + "### Return to Manchester United and Move to Al-Nassr\n", "\n", - "#### Rise to Stardom\n", + "Ronaldo returned to Manchester United in 2021, where he continued to perform at a high level, finishing as the club's top scorer for the season. However, his second stint at the club was marred by dissatisfaction with the club's direction, leading to his departure.\n", "\n", - "Ronaldo's professional career began at Sporting CP, where he made his debut in the Primeira Liga at just 17 years old. His performance against Manchester United in a friendly match in 2003 was so impressive that it led to his transfer to the English club. At Manchester United, Ronaldo's career skyrocketed. Under the guidance of Sir Alex Ferguson, he developed into one of the best players in the world, winning three Premier League titles, a UEFA Champions League title, and his first Ballon d'Or in 2008.\n", + "In 2023, Ronaldo joined Al-Nassr in the Saudi Pro League. His signing significantly increased the league's popularity, attracting other high-profile players to the region. Despite not winning a league title with Al-Nassr, Ronaldo's influence on and off the field remains substantial.\n", "\n", - "#### Real Madrid Era\n", + "### International Career\n", "\n", - "In 2009, Ronaldo made a record-breaking transfer to Real Madrid for €94 million. His time at Real Madrid was marked by unprecedented success. He became the club's all-time top scorer, won four Champions League titles, and added four more Ballon d'Or awards to his collection. Ronaldo's rivalry with Lionel Messi during this period became one of the most talked-about aspects of modern football.\n", + "Ronaldo has been a pivotal figure for the Portugal national team, captaining them to victory in the 2016 UEFA European Championship and the 2019 UEFA Nations League. His international career is highlighted by his leadership and goal-scoring record, making him one of the most successful players in international football.\n", "\n", - "#### Juventus and Beyond\n", + "### Legacy and Influence\n", "\n", - "In 2018, Ronaldo transferred to Juventus for €100 million. He continued to break records and win titles, including two Serie A championships. In 2021, he returned to Manchester United, where he continued to perform at a high level. As of 2023, Ronaldo plays for Al-Nassr in Saudi Arabia, further expanding his global influence.\n", + "Cristiano Ronaldo's legacy extends beyond his on-field achievements. He is the most followed person on Instagram, reflecting his global influence and popularity. His career is characterized by his relentless pursuit of excellence, adaptability, and ability to perform at the highest level across different leagues and competitions.\n", "\n", - "#### International Career\n", - "\n", - "Ronaldo's international career with Portugal has been equally illustrious. He has scored the most goals in international football history and has made the most appearances for the Portuguese national team. His crowning achievement came in 2016 when he led Portugal to victory in the UEFA European Championship, the country's first major international tournament win.\n", - "\n", - "#### Personal Life\n", - "\n", - "Off the field, Ronaldo is known for his philanthropic efforts and business ventures. He has a long-term relationship with Georgina Rodriguez, and together they have a large family, including his son Cristiano Jr. and twins Eva Maria and Mateo. Ronaldo's personal life has been a subject of media attention, but he has managed to maintain a positive public image.\n", - "\n", - "#### Achievements and Records\n", - "\n", - "Ronaldo's list of achievements is extensive. He holds the record for the most goals and assists in the UEFA Champions League, the most goals in the UEFA European Championship, and the most international goals. He has won over 300 trophies and medals, including five Ballon d'Or awards, making him one of the most decorated players in football history.\n", - "\n", - "#### Legacy\n", - "\n", - "Cristiano Ronaldo's impact on football is immeasurable. He has set new standards for excellence and professionalism, inspiring countless young athletes around the world. His dedication, work ethic, and relentless pursuit of greatness have cemented his place as one of the greatest footballers of all time.\n", - "\n", - "#### Conclusion\n", - "\n", - "Cristiano Ronaldo's journey from a young boy in Madeira to a global football icon is a testament to his talent, hard work, and determination. His legacy will continue to influence the world of football for generations to come. Whether on the field or off it, Ronaldo's name will always be synonymous with greatness.\u001b[0m\n", + "Ronaldo's impact on football is profound, inspiring countless young athletes worldwide. His dedication to fitness, skill development, and competitive spirit continues to set a benchmark for aspiring footballers. As of 2023, Ronaldo remains a central figure in the sport, both as a player and a global icon.\u001b[0m\n", "\n", "\u001b[1m> Finished chain.\u001b[0m\n", "\n", "\n", "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", - "\u001b[32;1m\u001b[1;3m\n", - "Invoking: `tavily_search_results_json` with `{'query': 'Cristiano Ronaldo latest news 2023'}`\n", - "\n", - "\n", - "\u001b[0m\u001b[36;1m\u001b[1;3m[{'url': 'https://abcnews.go.com/Sports/cristiano-ronaldo-end-2023-worlds-top-goalscorer/story?id=106012559', 'content': \"Cristiano Ronaldo to end 2023 as world's top goalscorer - ABC News ABC News Cristiano Ronaldo is set to end the year as the world's top goalscorer after scoring his 54th goal of 2023 in Al Nassr's 4-1 victory at Al Taawoun in the Saudi Pro League on Saturday. Ronaldo's latest goal on Saturday came on the one-year anniversary of him signing for Saudi club Al Nassr, following his controversial exit from Manchester United. Al Nassr were leading 3-1 through goals from Marcelo Brozovic, Aymeric Laporte and Otavio\\xa0on Saturday when Ronaldo headed in from six yards out in the second minute of stoppage time. How to watch the Harris-Trump ABC News debate --------------------------------------------- * Sep 9, 9:01 AM ABC News Live ABC News Network © 2024 ABC News\"}, {'url': 'https://www.newsnow.co.uk/h/Sport/Football/International+Stars/Cristiano+Ronaldo', 'content': 'Latest headlines on Cristiano Ronaldo, one of the greatest ever footballers, goal scorers, and most successful players ever to kick a ball. ... About our Cristiano Ronaldo News Born in 1985, Cristiano Ronaldo is one of the greatest footballers of all-time. ... he missed the match against Al-Tai on 5 January 2023. Ronaldo played his first game ...'}, {'url': 'https://www.cnn.com/2023/12/12/sport/cristiano-ronaldo-50-goals-2023-spt-intl/index.html', 'content': 'CNN values your feedback\\nCristiano Ronaldo scores 50th goal of 2023 as potential Lionel Messi clash is announced\\nCristiano Ronaldo scored his 50th goal of the calendar year on Monday as Al Nassr advanced to the semifinals of the Saudi King Cup with a 5-2 victory against rival Al Shabab.\\n Lionel Messi says he is focused on playing at next year’s Copa América but doesn’t rule out appearing at 2026 World Cup\\nLast week, the 38-year-old forward played the 1,200th game of his professional career, scoring a league-leading 16th goal in the Saudi Pro League this season.\\n Cristiano Ronaldo says his long-standing ‘rivalry’ with Lionel Messi is over\\n“Great victory and I’m thrilled to announce my 50th goal in 2023, all thanks to the unwavering support of my teammates, fans, and my family!” Ronaldo netted his team’s fourth goal with a powerful strike in the 74th minute, continuing his impressive scoring rate since playing his first game in Saudi Arabia in January.\\n “We are excited to connect with new supporters in Saudi Arabia, and also hope people all over the world will be tuning in to see a pair of dream matches like these.”\\n'}, {'url': 'https://www.bbc.co.uk/sport/football/67688432', 'content': 'Cristiano Ronaldo scored his 50th goal in 2023 as Al-Nassr beat rivals Al-Shabab 5-2 to reach the semi-finals of the Saudi King Cup. The former Real Madrid and Manchester United forward got his ...'}, {'url': 'https://www.cnn.com/2023/05/28/football/lionel-messi-record-psg-ligue-1-title-spt-intl/index.html', 'content': 'There was another landmark in the long rivalry between Lionel Messi and Cristiano Ronaldo on Saturday. ... Published 9:01 AM EDT, Sun May 28, 2023 ... But this latest triumph masks an increasingly ...'}]\u001b[0m\u001b[32;1m\u001b[1;3m### Cristiano Ronaldo: A Football Legend\n", - "\n", - "#### Early Life and Career Beginnings\n", - "\n", - "Cristiano Ronaldo dos Santos Aveiro, commonly known as Cristiano Ronaldo or CR7, was born on February 5, 1985, in Funchal, Madeira, Portugal. From a young age, Ronaldo displayed an extraordinary talent for football, which led him to join the youth academy of Sporting CP in Lisbon. His exceptional skills quickly caught the attention of scouts from top European clubs.\n", - "\n", - "#### Rise to Stardom\n", - "\n", - "Ronaldo's professional career began at Sporting CP, where he made his debut in the Primeira Liga at just 17 years old. His performance against Manchester United in a friendly match in 2003 was so impressive that it led to his transfer to the English club. At Manchester United, Ronaldo's career skyrocketed. Under the guidance of Sir Alex Ferguson, he developed into one of the best players in the world, winning three Premier League titles, a UEFA Champions League title, and his first Ballon d'Or in 2008.\n", - "\n", - "#### Real Madrid Era\n", - "\n", - "In 2009, Ronaldo made a record-breaking transfer to Real Madrid for €94 million. His time at Real Madrid was marked by unprecedented success. He became the club's all-time top scorer, won four Champions League titles, and added four more Ballon d'Or awards to his collection. Ronaldo's rivalry with Lionel Messi during this period became one of the most talked-about aspects of modern football.\n", - "\n", - "#### Juventus and Beyond\n", - "\n", - "In 2018, Ronaldo transferred to Juventus for €100 million. He continued to break records and win titles, including two Serie A championships. In 2021, he returned to Manchester United, where he continued to perform at a high level. As of 2023, Ronaldo plays for Al-Nassr in Saudi Arabia, further expanding his global influence.\n", - "\n", - "#### International Career\n", - "\n", - "Ronaldo's international career with Portugal has been equally illustrious. He has scored the most goals in international football history and has made the most appearances for the Portuguese national team. His crowning achievement came in 2016 when he led Portugal to victory in the UEFA European Championship, the country's first major international tournament win.\n", - "\n", - "#### Personal Life\n", - "\n", - "Off the field, Ronaldo is known for his philanthropic efforts and business ventures. He has a long-term relationship with Georgina Rodriguez, and together they have a large family, including his son Cristiano Jr. and twins Eva Maria and Mateo. Ronaldo's personal life has been a subject of media attention, but he has managed to maintain a positive public image.\n", - "\n", - "#### Achievements and Records\n", - "\n", - "Ronaldo's list of achievements is extensive. He holds the record for the most goals and assists in the UEFA Champions League, the most goals in the UEFA European Championship, and the most international goals. He has won over 300 trophies and medals, including five Ballon d'Or awards, making him one of the most decorated players in football history.\n", - "\n", - "#### Latest Milestones in 2023\n", - "\n", - "As of 2023, Cristiano Ronaldo continues to break records and achieve new milestones. He is set to end the year as the world's top goalscorer, having scored his 54th goal of 2023 in Al Nassr's 4-1 victory at Al Taawoun in the Saudi Pro League. This goal came on the one-year anniversary of his signing with Al Nassr, following his controversial exit from Manchester United. Ronaldo also scored his 50th goal of the calendar year in a match against Al Shabab, leading Al Nassr to the semifinals of the Saudi King Cup. This year, he also played his 1,200th professional game, continuing to demonstrate his remarkable longevity and consistency.\n", - "\n", - "#### Legacy\n", - "\n", - "Cristiano Ronaldo's impact on football is immeasurable. He has set new standards for excellence and professionalism, inspiring countless young athletes around the world. His dedication, work ethic, and relentless pursuit of greatness have cemented his place as one of the greatest footballers of all time.\n", - "\n", - "#### Conclusion\n", - "\n", - "Cristiano Ronaldo's journey from a young boy in Madeira to a global football icon is a testament to his talent, hard work, and determination. His legacy will continue to influence the world of football for generations to come. Whether on the field or off it, Ronaldo's name will always be synonymous with greatness.\u001b[0m\n", - "\n", - "\u001b[1m> Finished chain.\u001b[0m\n", - "\n", - "\n", - "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", - "\u001b[32;1m\u001b[1;3m### Cristiano Ronaldo: A Football Legend\n", - "\n", - "#### Early Life and Career Beginnings\n", - "\n", - "Cristiano Ronaldo dos Santos Aveiro, commonly known as Cristiano Ronaldo or CR7, was born on February 5, 1985, in Funchal, Madeira, Portugal. From a young age, Ronaldo displayed an extraordinary talent for football, which led him to join the youth academy of Sporting CP in Lisbon. His exceptional skills quickly caught the attention of scouts from top European clubs.\n", - "\n", - "#### Rise to Stardom\n", - "\n", - "Ronaldo's professional career began at Sporting CP, where he made his debut in the Primeira Liga at just 17 years old. His performance against Manchester United in a friendly match in 2003 was so impressive that it led to his transfer to the English club. At Manchester United, Ronaldo's career skyrocketed. Under the guidance of Sir Alex Ferguson, he developed into one of the best players in the world, winning three Premier League titles, a UEFA Champions League title, and his first Ballon d'Or in 2008.\n", - "\n", - "#### Real Madrid Era\n", - "\n", - "In 2009, Ronaldo made a record-breaking transfer to Real Madrid for €94 million. His time at Real Madrid was marked by unprecedented success. He became the club's all-time top scorer, won four Champions League titles, and added four more Ballon d'Or awards to his collection. Ronaldo's rivalry with Lionel Messi during this period became one of the most talked-about aspects of modern football.\n", - "\n", - "#### Juventus and Beyond\n", - "\n", - "In 2018, Ronaldo transferred to Juventus for €100 million. He continued to break records and win titles, including two Serie A championships. In 2021, he returned to Manchester United, where he continued to perform at a high level. As of 2023, Ronaldo plays for Al-Nassr in Saudi Arabia, further expanding his global influence.\n", - "\n", - "#### International Career\n", - "\n", - "Ronaldo's international career with Portugal has been equally illustrious. He has scored the most goals in international football history and has made the most appearances for the Portuguese national team. His crowning achievement came in 2016 when he led Portugal to victory in the UEFA European Championship, the country's first major international tournament win.\n", - "\n", - "#### Personal Life\n", - "\n", - "Off the field, Ronaldo is known for his philanthropic efforts and business ventures. He has a long-term relationship with Georgina Rodriguez, and together they have a large family, including his son Cristiano Jr. and twins Eva Maria and Mateo. Ronaldo's personal life has been a subject of media attention, but he has managed to maintain a positive public image.\n", - "\n", - "#### Achievements and Records\n", - "\n", - "Ronaldo's list of achievements is extensive. He holds the record for the most goals and assists in the UEFA Champions League, the most goals in the UEFA European Championship, and the most international goals. He has won over 300 trophies and medals, including five Ballon d'Or awards, making him one of the most decorated players in football history.\n", - "\n", - "#### Latest Milestones in 2023\n", - "\n", - "As of 2023, Cristiano Ronaldo continues to break records and achieve new milestones. He is set to end the year as the world's top goalscorer, having scored his 54th goal of 2023 in Al Nassr's 4-1 victory at Al Taawoun in the Saudi Pro League. This goal came on the one-year anniversary of his signing with Al Nassr, following his controversial exit from Manchester United. Ronaldo also scored his 50th goal of the calendar year in a match against Al Shabab, leading Al Nassr to the semifinals of the Saudi King Cup. This year, he also played his 1,200th professional game, continuing to demonstrate his remarkable longevity and consistency.\n", - "\n", - "#### Legacy\n", - "\n", - "Cristiano Ronaldo's impact on football is immeasurable. He has set new standards for excellence and professionalism, inspiring countless young athletes around the world. His dedication, work ethic, and relentless pursuit of greatness have cemented his place as one of the greatest footballers of all time.\n", - "\n", - "#### Conclusion\n", + "\u001b[32;1m\u001b[1;3mCristiano Ronaldo, widely known as CR7, is a name synonymous with football excellence. Born on February 5, 1985, in Funchal, Portugal, Ronaldo has carved out a legendary career that has seen him become one of the most celebrated athletes in the world. His journey from a young boy in Madeira to a global football icon is a testament to his extraordinary talent, relentless work ethic, and unyielding determination.\n", "\n", - "Cristiano Ronaldo's journey from a young boy in Madeira to a global football icon is a testament to his talent, hard work, and determination. His legacy will continue to influence the world of football for generations to come. Whether on the field or off it, Ronaldo's name will always be synonymous with greatness.\n", + "### Early Life and Rise to Stardom\n", "\n", - "---\n", + "Ronaldo's football journey began at a young age when he joined the youth academy of Sporting CP in Lisbon. His prodigious talent quickly caught the attention of scouts, and in 2003, he made a high-profile move to Manchester United. Under the guidance of Sir Alex Ferguson, Ronaldo developed into one of the most exciting talents in the Premier League. His time at Manchester United was marked by numerous accolades, including three Premier League titles and a UEFA Champions League victory in 2008. That same year, he won his first Ballon d'Or, solidifying his status as the world's best player.\n", "\n", - "### Editorial Suggestions:\n", + "### Dominance at Real Madrid\n", "\n", - "1. **Introduction**: Consider adding a brief introductory paragraph that encapsulates Ronaldo's significance in football. This will set the stage for the detailed sections that follow.\n", + "In 2009, Ronaldo made a record-breaking transfer to Real Madrid, where he would spend the next nine years of his career. At Real Madrid, Ronaldo reached new heights, becoming the club's all-time leading scorer and winning four more Ballon d'Or awards. His tenure at the club was highlighted by four UEFA Champions League titles, including a historic three-peat from 2016 to 2018. Ronaldo's time in Madrid was characterized by his incredible goal-scoring ability, athleticism, and leadership on the field.\n", "\n", - "2. **Subheadings**: Ensure consistency in the formatting of subheadings. For example, \"Real Madrid Era\" could be \"The Real Madrid Era\" to match the style of \"Juventus and Beyond.\"\n", + "### Juventus and Beyond\n", "\n", - "3. **Transitions**: Add transitional sentences between sections to improve the flow of the article. For instance, a sentence at the end of the \"Rise to Stardom\" section could hint at his upcoming move to Real Madrid.\n", + "Ronaldo's next chapter took him to Juventus in 2018, where he continued to demonstrate his goal-scoring prowess. During his time in Italy, he won two Serie A titles and further cemented his legacy as one of the greatest footballers of all time. In 2021, Ronaldo made a sensational return to Manchester United, where he continued to perform at a high level, although his second stint at the club was marked by challenges and a desire for new opportunities.\n", "\n", - "4. **Details and Anecdotes**: Incorporate more personal anecdotes or lesser-known facts to make the article more engaging. For example, mention specific memorable matches or goals.\n", + "In 2023, Ronaldo joined Al-Nassr in the Saudi Pro League, a move that significantly boosted the league's profile and attracted other high-profile players to the region. Despite not securing a league title with Al-Nassr, Ronaldo's influence on and off the field remains substantial.\n", "\n", - "5. **Quotes**: Including quotes from Ronaldo, his coaches, or teammates can add depth and authenticity to the article.\n", + "### International Success\n", "\n", - "6. **Visuals**: If this article is intended for a digital platform, consider adding images, infographics, or videos to complement the text and provide a richer experience for the reader.\n", + "Ronaldo's impact extends to the international stage, where he has been a pivotal figure for the Portugal national team. He captained Portugal to their first major international trophy at the 2016 UEFA European Championship and followed it up with a victory in the 2019 UEFA Nations League. Ronaldo's leadership and goal-scoring record make him one of the most successful players in international football history.\n", "\n", - "7. **Sources and References**: If possible, cite sources or references for key statistics and claims, especially in the \"Achievements and Records\" and \"Latest Milestones in 2023\" sections.\n", + "### Legacy and Global Influence\n", "\n", - "8. **Conclusion**: The conclusion could be more impactful by summarizing his influence on both football and popular culture, and perhaps speculating on his future contributions to the sport.\n", + "Cristiano Ronaldo's legacy transcends his on-field achievements. He is the most followed person on Instagram, reflecting his global influence and popularity. His career is characterized by a relentless pursuit of excellence, adaptability, and the ability to perform at the highest level across different leagues and competitions.\n", "\n", - "By incorporating these suggestions, the article can become more comprehensive, engaging, and polished.\u001b[0m\n", + "Ronaldo's impact on football is profound, inspiring countless young athletes worldwide. His dedication to fitness, skill development, and competitive spirit continues to set a benchmark for aspiring footballers. As of 2023, Ronaldo remains a central figure in the sport, both as a player and a global icon, whose influence will be felt for generations to come.\u001b[0m\n", "\n", "\u001b[1m> Finished chain.\u001b[0m\n" ] @@ -370,18 +276,18 @@ { "data": { "text/plain": [ - "{'messages': [HumanMessage(content='Write an article about CR7'),\n", - " HumanMessage(content=\"### Cristiano Ronaldo: A Football Legend\\n\\n#### Early Life and Career Beginnings\\n\\nCristiano Ronaldo dos Santos Aveiro, commonly known as Cristiano Ronaldo or CR7, was born on February 5, 1985, in Funchal, Madeira, Portugal. From a young age, Ronaldo displayed an extraordinary talent for football, which led him to join the youth academy of Sporting CP in Lisbon. His exceptional skills quickly caught the attention of scouts from top European clubs.\\n\\n#### Rise to Stardom\\n\\nRonaldo's professional career began at Sporting CP, where he made his debut in the Primeira Liga at just 17 years old. His performance against Manchester United in a friendly match in 2003 was so impressive that it led to his transfer to the English club. At Manchester United, Ronaldo's career skyrocketed. Under the guidance of Sir Alex Ferguson, he developed into one of the best players in the world, winning three Premier League titles, a UEFA Champions League title, and his first Ballon d'Or in 2008.\\n\\n#### Real Madrid Era\\n\\nIn 2009, Ronaldo made a record-breaking transfer to Real Madrid for €94 million. His time at Real Madrid was marked by unprecedented success. He became the club's all-time top scorer, won four Champions League titles, and added four more Ballon d'Or awards to his collection. Ronaldo's rivalry with Lionel Messi during this period became one of the most talked-about aspects of modern football.\\n\\n#### Juventus and Beyond\\n\\nIn 2018, Ronaldo transferred to Juventus for €100 million. He continued to break records and win titles, including two Serie A championships. In 2021, he returned to Manchester United, where he continued to perform at a high level. As of 2023, Ronaldo plays for Al-Nassr in Saudi Arabia, further expanding his global influence.\\n\\n#### International Career\\n\\nRonaldo's international career with Portugal has been equally illustrious. He has scored the most goals in international football history and has made the most appearances for the Portuguese national team. His crowning achievement came in 2016 when he led Portugal to victory in the UEFA European Championship, the country's first major international tournament win.\\n\\n#### Personal Life\\n\\nOff the field, Ronaldo is known for his philanthropic efforts and business ventures. He has a long-term relationship with Georgina Rodriguez, and together they have a large family, including his son Cristiano Jr. and twins Eva Maria and Mateo. Ronaldo's personal life has been a subject of media attention, but he has managed to maintain a positive public image.\\n\\n#### Achievements and Records\\n\\nRonaldo's list of achievements is extensive. He holds the record for the most goals and assists in the UEFA Champions League, the most goals in the UEFA European Championship, and the most international goals. He has won over 300 trophies and medals, including five Ballon d'Or awards, making him one of the most decorated players in football history.\\n\\n#### Latest Milestones in 2023\\n\\nAs of 2023, Cristiano Ronaldo continues to break records and achieve new milestones. He is set to end the year as the world's top goalscorer, having scored his 54th goal of 2023 in Al Nassr's 4-1 victory at Al Taawoun in the Saudi Pro League. This goal came on the one-year anniversary of his signing with Al Nassr, following his controversial exit from Manchester United. Ronaldo also scored his 50th goal of the calendar year in a match against Al Shabab, leading Al Nassr to the semifinals of the Saudi King Cup. This year, he also played his 1,200th professional game, continuing to demonstrate his remarkable longevity and consistency.\\n\\n#### Legacy\\n\\nCristiano Ronaldo's impact on football is immeasurable. He has set new standards for excellence and professionalism, inspiring countless young athletes around the world. His dedication, work ethic, and relentless pursuit of greatness have cemented his place as one of the greatest footballers of all time.\\n\\n#### Conclusion\\n\\nCristiano Ronaldo's journey from a young boy in Madeira to a global football icon is a testament to his talent, hard work, and determination. His legacy will continue to influence the world of football for generations to come. Whether on the field or off it, Ronaldo's name will always be synonymous with greatness.\", name='BlogWriter-BEsx9'),\n", - " HumanMessage(content='### Cristiano Ronaldo: A Football Legend\\n\\n#### Early Life and Career Beginnings\\n\\nCristiano Ronaldo dos Santos Aveiro, commonly known as Cristiano Ronaldo or CR7, was born on February 5, 1985, in Funchal, Madeira, Portugal. From a young age, Ronaldo displayed an extraordinary talent for football, which led him to join the youth academy of Sporting CP in Lisbon. His exceptional skills quickly caught the attention of scouts from top European clubs.\\n\\n#### Rise to Stardom\\n\\nRonaldo\\'s professional career began at Sporting CP, where he made his debut in the Primeira Liga at just 17 years old. His performance against Manchester United in a friendly match in 2003 was so impressive that it led to his transfer to the English club. At Manchester United, Ronaldo\\'s career skyrocketed. Under the guidance of Sir Alex Ferguson, he developed into one of the best players in the world, winning three Premier League titles, a UEFA Champions League title, and his first Ballon d\\'Or in 2008.\\n\\n#### Real Madrid Era\\n\\nIn 2009, Ronaldo made a record-breaking transfer to Real Madrid for €94 million. His time at Real Madrid was marked by unprecedented success. He became the club\\'s all-time top scorer, won four Champions League titles, and added four more Ballon d\\'Or awards to his collection. Ronaldo\\'s rivalry with Lionel Messi during this period became one of the most talked-about aspects of modern football.\\n\\n#### Juventus and Beyond\\n\\nIn 2018, Ronaldo transferred to Juventus for €100 million. He continued to break records and win titles, including two Serie A championships. In 2021, he returned to Manchester United, where he continued to perform at a high level. As of 2023, Ronaldo plays for Al-Nassr in Saudi Arabia, further expanding his global influence.\\n\\n#### International Career\\n\\nRonaldo\\'s international career with Portugal has been equally illustrious. He has scored the most goals in international football history and has made the most appearances for the Portuguese national team. His crowning achievement came in 2016 when he led Portugal to victory in the UEFA European Championship, the country\\'s first major international tournament win.\\n\\n#### Personal Life\\n\\nOff the field, Ronaldo is known for his philanthropic efforts and business ventures. He has a long-term relationship with Georgina Rodriguez, and together they have a large family, including his son Cristiano Jr. and twins Eva Maria and Mateo. Ronaldo\\'s personal life has been a subject of media attention, but he has managed to maintain a positive public image.\\n\\n#### Achievements and Records\\n\\nRonaldo\\'s list of achievements is extensive. He holds the record for the most goals and assists in the UEFA Champions League, the most goals in the UEFA European Championship, and the most international goals. He has won over 300 trophies and medals, including five Ballon d\\'Or awards, making him one of the most decorated players in football history.\\n\\n#### Latest Milestones in 2023\\n\\nAs of 2023, Cristiano Ronaldo continues to break records and achieve new milestones. He is set to end the year as the world\\'s top goalscorer, having scored his 54th goal of 2023 in Al Nassr\\'s 4-1 victory at Al Taawoun in the Saudi Pro League. This goal came on the one-year anniversary of his signing with Al Nassr, following his controversial exit from Manchester United. Ronaldo also scored his 50th goal of the calendar year in a match against Al Shabab, leading Al Nassr to the semifinals of the Saudi King Cup. This year, he also played his 1,200th professional game, continuing to demonstrate his remarkable longevity and consistency.\\n\\n#### Legacy\\n\\nCristiano Ronaldo\\'s impact on football is immeasurable. He has set new standards for excellence and professionalism, inspiring countless young athletes around the world. His dedication, work ethic, and relentless pursuit of greatness have cemented his place as one of the greatest footballers of all time.\\n\\n#### Conclusion\\n\\nCristiano Ronaldo\\'s journey from a young boy in Madeira to a global football icon is a testament to his talent, hard work, and determination. His legacy will continue to influence the world of football for generations to come. Whether on the field or off it, Ronaldo\\'s name will always be synonymous with greatness.\\n\\n---\\n\\n### Editorial Suggestions:\\n\\n1. **Introduction**: Consider adding a brief introductory paragraph that encapsulates Ronaldo\\'s significance in football. This will set the stage for the detailed sections that follow.\\n\\n2. **Subheadings**: Ensure consistency in the formatting of subheadings. For example, \"Real Madrid Era\" could be \"The Real Madrid Era\" to match the style of \"Juventus and Beyond.\"\\n\\n3. **Transitions**: Add transitional sentences between sections to improve the flow of the article. For instance, a sentence at the end of the \"Rise to Stardom\" section could hint at his upcoming move to Real Madrid.\\n\\n4. **Details and Anecdotes**: Incorporate more personal anecdotes or lesser-known facts to make the article more engaging. For example, mention specific memorable matches or goals.\\n\\n5. **Quotes**: Including quotes from Ronaldo, his coaches, or teammates can add depth and authenticity to the article.\\n\\n6. **Visuals**: If this article is intended for a digital platform, consider adding images, infographics, or videos to complement the text and provide a richer experience for the reader.\\n\\n7. **Sources and References**: If possible, cite sources or references for key statistics and claims, especially in the \"Achievements and Records\" and \"Latest Milestones in 2023\" sections.\\n\\n8. **Conclusion**: The conclusion could be more impactful by summarizing his influence on both football and popular culture, and perhaps speculating on his future contributions to the sport.\\n\\nBy incorporating these suggestions, the article can become more comprehensive, engaging, and polished.', name='Senior-Editor-hoWOe')]}" + "{'messages': [HumanMessage(content='Write an article about CR7', additional_kwargs={}, response_metadata={}),\n", + " HumanMessage(content=\"Cristiano Ronaldo, widely known as CR7, is a name synonymous with football excellence. Born on February 5, 1985, in Funchal, Portugal, Ronaldo has carved out a legendary career that has seen him become one of the most celebrated athletes in the world. His journey from a young boy in Madeira to a global football icon is a testament to his extraordinary talent, relentless work ethic, and unyielding determination.\\n\\n### Early Life and Rise to Stardom\\n\\nRonaldo's football journey began at a young age when he joined the youth academy of Sporting CP in Lisbon. His prodigious talent quickly caught the attention of scouts, and in 2003, he made a high-profile move to Manchester United. Under the guidance of Sir Alex Ferguson, Ronaldo developed into one of the most exciting talents in the Premier League. His time at Manchester United was marked by numerous accolades, including three Premier League titles and a UEFA Champions League victory in 2008. That same year, he won his first Ballon d'Or, solidifying his status as the world's best player.\\n\\n### Dominance at Real Madrid\\n\\nIn 2009, Ronaldo made a record-breaking transfer to Real Madrid, where he would spend the next nine years of his career. At Real Madrid, Ronaldo reached new heights, becoming the club's all-time leading scorer and winning four more Ballon d'Or awards. His tenure at the club was highlighted by four UEFA Champions League titles, including a historic three-peat from 2016 to 2018. Ronaldo's time in Madrid was characterized by his incredible goal-scoring ability, athleticism, and leadership on the field.\\n\\n### Juventus and Beyond\\n\\nRonaldo's next chapter took him to Juventus in 2018, where he continued to demonstrate his goal-scoring prowess. During his time in Italy, he won two Serie A titles and further cemented his legacy as one of the greatest footballers of all time. In 2021, Ronaldo made a sensational return to Manchester United, where he continued to perform at a high level, although his second stint at the club was marked by challenges and a desire for new opportunities.\\n\\nIn 2023, Ronaldo joined Al-Nassr in the Saudi Pro League, a move that significantly boosted the league's profile and attracted other high-profile players to the region. Despite not securing a league title with Al-Nassr, Ronaldo's influence on and off the field remains substantial.\\n\\n### International Success\\n\\nRonaldo's impact extends to the international stage, where he has been a pivotal figure for the Portugal national team. He captained Portugal to their first major international trophy at the 2016 UEFA European Championship and followed it up with a victory in the 2019 UEFA Nations League. Ronaldo's leadership and goal-scoring record make him one of the most successful players in international football history.\\n\\n### Legacy and Global Influence\\n\\nCristiano Ronaldo's legacy transcends his on-field achievements. He is the most followed person on Instagram, reflecting his global influence and popularity. His career is characterized by a relentless pursuit of excellence, adaptability, and the ability to perform at the highest level across different leagues and competitions.\\n\\nRonaldo's impact on football is profound, inspiring countless young athletes worldwide. His dedication to fitness, skill development, and competitive spirit continues to set a benchmark for aspiring footballers. As of 2023, Ronaldo remains a central figure in the sport, both as a player and a global icon, whose influence will be felt for generations to come.\", additional_kwargs={}, response_metadata={}, name='BlogWriter'),\n", + " HumanMessage(content=\"Cristiano Ronaldo, widely known as CR7, is a name synonymous with football excellence. Born on February 5, 1985, in Funchal, Portugal, Ronaldo has carved out a legendary career that has seen him become one of the most celebrated athletes in the world. His journey from a young boy in Madeira to a global football icon is a testament to his extraordinary talent, relentless work ethic, and unyielding determination.\\n\\n### Early Life and Rise to Stardom\\n\\nRonaldo's football journey began at a young age when he joined the youth academy of Sporting CP in Lisbon. His prodigious talent quickly caught the attention of scouts, and in 2003, he made a high-profile move to Manchester United. Under the guidance of Sir Alex Ferguson, Ronaldo developed into one of the most exciting talents in the Premier League. His time at Manchester United was marked by numerous accolades, including three Premier League titles and a UEFA Champions League victory in 2008. That same year, he won his first Ballon d'Or, solidifying his status as the world's best player.\\n\\n### Dominance at Real Madrid\\n\\nIn 2009, Ronaldo made a record-breaking transfer to Real Madrid, where he would spend the next nine years of his career. At Real Madrid, Ronaldo reached new heights, becoming the club's all-time leading scorer and winning four more Ballon d'Or awards. His tenure at the club was highlighted by four UEFA Champions League titles, including a historic three-peat from 2016 to 2018. Ronaldo's time in Madrid was characterized by his incredible goal-scoring ability, athleticism, and leadership on the field.\\n\\n### Juventus and Beyond\\n\\nRonaldo's next chapter took him to Juventus in 2018, where he continued to demonstrate his goal-scoring prowess. During his time in Italy, he won two Serie A titles and further cemented his legacy as one of the greatest footballers of all time. In 2021, Ronaldo made a sensational return to Manchester United, where he continued to perform at a high level, although his second stint at the club was marked by challenges and a desire for new opportunities.\\n\\nIn 2023, Ronaldo joined Al-Nassr in the Saudi Pro League, a move that significantly boosted the league's profile and attracted other high-profile players to the region. Despite not securing a league title with Al-Nassr, Ronaldo's influence on and off the field remains substantial.\\n\\n### International Success\\n\\nRonaldo's impact extends to the international stage, where he has been a pivotal figure for the Portugal national team. He captained Portugal to their first major international trophy at the 2016 UEFA European Championship and followed it up with a victory in the 2019 UEFA Nations League. Ronaldo's leadership and goal-scoring record make him one of the most successful players in international football history.\\n\\n### Legacy and Global Influence\\n\\nCristiano Ronaldo's legacy transcends his on-field achievements. He is the most followed person on Instagram, reflecting his global influence and popularity. His career is characterized by a relentless pursuit of excellence, adaptability, and the ability to perform at the highest level across different leagues and competitions.\\n\\nRonaldo's impact on football is profound, inspiring countless young athletes worldwide. His dedication to fitness, skill development, and competitive spirit continues to set a benchmark for aspiring footballers. As of 2023, Ronaldo remains a central figure in the sport, both as a player and a global icon, whose influence will be felt for generations to come.\", additional_kwargs={}, response_metadata={})]}" ] }, - "execution_count": 8, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "master_team.invoke(\"Write an article about CR7\")" + "master_flo.invoke(\"Write an article about CR7\")" ] } ], diff --git a/flo_ai/builders/yaml_builder.py b/flo_ai/builders/yaml_builder.py index 70a849e9..e5da4276 100644 --- a/flo_ai/builders/yaml_builder.py +++ b/flo_ai/builders/yaml_builder.py @@ -41,7 +41,7 @@ def parse_and_build_subteams( members = [AgentFactory.create(session, agent) for agent in team_config.agents] flo_team = FloTeam.Builder(session, team_config.name, members=members).build() router = FloRouterFactory.create(session, team_config, flo_team) - flo_routed_team = router.build_routed_team() + flo_routed_team = router.to_flo() else: flo_teams = [] for subteam in team_config.subteams: @@ -49,7 +49,7 @@ def parse_and_build_subteams( flo_teams.append(flo_subteam) flo_team = FloTeam.Builder(session, team_config.name, members=flo_teams).build() router = FloRouterFactory.create(session, team_config, flo_team) - flo_routed_team = router.build_routed_team() + flo_routed_team = router.to_flo() return flo_routed_team diff --git a/flo_ai/router/flo_router.py b/flo_ai/router/flo_router.py index 027b3fbf..0ff77609 100644 --- a/flo_ai/router/flo_router.py +++ b/flo_ai/router/flo_router.py @@ -38,7 +38,7 @@ def __init__( self.executor = executor self.model_name = model_name - def build_routed_team(self) -> FloRoutedTeam: + def to_flo(self) -> FloRoutedTeam: return self.build_graph() @abstractmethod From 97ed75e1c6add218a8a458d7d76d84f60c7b007c Mon Sep 17 00:00:00 2001 From: vizsatiz Date: Sat, 16 Nov 2024 16:22:45 +0530 Subject: [PATCH 6/7] Demostrating combining teams and agents in code --- examples/build_agents_by_code.ipynb | 204 +++++++++++++++------------- examples/email_reply_agent.ipynb | 123 ++++------------- flo_ai/router/flo_router.py | 1 + 3 files changed, 137 insertions(+), 191 deletions(-) diff --git a/examples/build_agents_by_code.ipynb b/examples/build_agents_by_code.ipynb index 9860b76a..fa113b77 100644 --- a/examples/build_agents_by_code.ipynb +++ b/examples/build_agents_by_code.ipynb @@ -28,6 +28,8 @@ "source": [ "from flo_ai import FloSupervisor, FloAgent, FloSession, FloTeam, FloLinear\n", "from langchain_openai import ChatOpenAI\n", + "from flo_ai.models.flo_reflection_agent import FloReflectionAgent\n", + "from flo_ai.models.delegate import Delegate\n", "from langchain_community.tools.tavily_search.tool import TavilySearchResults\n", "from dotenv import load_dotenv\n", "\n", @@ -43,9 +45,19 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Edge : Researcher to Head-of-Marketing\n", + "Edge : BlogWriter to Head-of-Marketing\n", + "Edge : __start__ to Head-of-Marketing\n" + ] + } + ], "source": [ "llm = ChatOpenAI(temperature=0, model_name='gpt-4o')\n", "session = FloSession(llm).register_tool(\n", @@ -76,21 +88,6 @@ "cell_type": "code", "execution_count": 3, "metadata": {}, - "outputs": [], - "source": [ - "def draw_to_file(graph, filename: str, xray=False):\n", - " from PIL import Image as PILImage\n", - " import io\n", - " byte_image = graph.draw(xray)\n", - " with io.BytesIO(byte_image) as image_io:\n", - " image = PILImage.open(image_io)\n", - " image.save(filename)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, "outputs": [ { "data": { @@ -118,9 +115,18 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Edge : Senior-Editor to Editor-Team-Routing\n", + "Edge : __start__ to Editor-Team-Routing\n" + ] + } + ], "source": [ "chief_editorial = FloAgent.Builder(\n", " session, \n", @@ -137,7 +143,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": {}, "outputs": [ { @@ -159,9 +165,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Edge : __start__ to Marketing\n", + "Marketing\n", + "Editorial-Team\n", + "Edge : Marketing to Editorial-Team\n", + "Edge : Editorial-Team to __end__\n" + ] + } + ], "source": [ "journal_company = FloTeam.Builder(session, \"Newspaper\", [marketing_flo, editorial_flo])\n", "\n", @@ -176,7 +194,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": {}, "outputs": [ { @@ -196,6 +214,15 @@ "display(Image(master_flo.draw()))" ] }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "# master_flo.invoke(\"Write an article about CR7\")" + ] + }, { "cell_type": "code", "execution_count": null, @@ -205,89 +232,76 @@ "name": "stdout", "output_type": "stream", "text": [ - "\n", - "\n", - "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", - "\u001b[32;1m\u001b[1;3m\n", - "Invoking: `tavily_search_results_json` with `{'query': 'Cristiano Ronaldo biography 2023'}`\n", - "\n", - "\n", - "\u001b[0m\u001b[36;1m\u001b[1;3m[{'url': 'https://en.wikipedia.org/wiki/Cristiano_Ronaldo', 'content': 'After scoring in the following matches against Chelsea and Brentford, he was named the Premier League Player of the Month for April.[313]\\nHe finished the season with 24 goals in all competitions, 18 of those goals being in the Premier League, making him the third-highest goalscorer in the league behind Golden Boot winners Mohamed Salah and Son Heung-min, being named in the Premier League Team of the Year and the winner of United\\'s Sir Matt Busby Player of the Year award, given to the club\\'s best player from the previous season;[314][315] however, with United finishing in a disappointing sixth place and qualifying for the UEFA Europa League, Ronaldo went trophyless for the first time since 2010.[316]\\nAfter growing dissatisfaction with the direction of United on and off the field, Ronaldo missed the club\\'s pre-season tour of Thailand and Australia due to family reasons, amid reports of his desire to leave to join a club competing in the Champions League, despite incoming manager Erik ten Hag insisting that he was not for sale and was part of the club\\'s plans.[317] Ronaldo was awarded the Player of the Month award for February after scoring eight goals and assisting twice.[346] Ronaldo spent another season without winning a league title, as Al Nassr finished second in the league in the 2022–23 season.[347]\\nRonaldo\\'s signing for Al-Nassr resulted in increased popularity both domestically and internationally of the Saudi Pro League, with various European players such as Karim Benzema, Sadio Mané, N\\'Golo Kanté, Rúben Neves, Riyad Mahrez, Roberto Firmino and Neymar moving to the Saudi Pro League during the summer transfer window, crediting Ronaldo as one of the main factors for moving to the league.[348]\\nHe scored his first goal of the 2023–24 season in a 4–1 win over Union Monastirienne in the Arab Club Champions Cup on 31 July.[349] This unique role has been described by pundits as that of a \"false\", \"attacking\", or \"goalscoring winger\", as Ronaldo effectively almost functioned as a striker at times with his central runs into the penalty area, despite actually playing on the left flank.[488][493] From 2013 onwards, under manager Carlo Ancelotti, he effectively adapted his style to the physical effects of ageing with increasingly reduced off-the-ball movement and general involvement, completing fewer dribbles and passes per game, and instead focusing on short-distance creating and goalscoring.[487][494][495] Since 2017, Ronaldo adapted his style of play yet again to become more of a free-roaming centre forward under manager Zinedine Zidane, a role in which he continued to excel and maintain a prolific goalscoring record; in this position, he earned praise in the media for his intelligent movement both on and off the ball, positional sense, link-up play and finishing, as well as his ability to lose or anticipate his markers, find space in the box and score from few touches or opportunities.[496][497][498]\\n Ronaldo then missed United\\'s following matches before the World Cup break, with Ten Hag saying that Ronaldo was ill.[329]\\nOn 14 November, an interview with Piers Morgan was published, where Ronaldo said that he felt \"betrayed\" by Ten Hag and senior executives who wanted Ronaldo to leave the club, and accused the club of doubting him regarding the illness of his daughter that led him to miss pre-season, adding that he did not respect ten Hag \"because he doesn\\'t show respect for me\", leading him to be disappointed with the communication of the club.[330] Ronaldo claimed that ten Hag deliberately provoked him by first leaving him on the bench against City, and then wanting to bring him on in the final moments against Tottenham, but added that he regretted his decision to leave early.[330] Ronaldo ended his first season in English football by scoring the opening goal in United\\'s 3–0 win over Millwall in the 2004 FA Cup Final, earning his first trophy.[52] BBC pundit Alan Hansen described him as the star of the final.[53] The British press had been critical of Ronaldo during the season for his \"elaborate\" step-overs in trying to beat opponents,[54] but teammate Gary Neville said he was \"not a show pony, but the real thing\", and predicted he would become a world-class player.[55]\\n\"He has got the tricks and party pieces, we know that, but they\\'re not much good unless there is something at the end of it all.'}, {'url': 'https://www.forbes.com/profile/cristiano-ronaldo/', 'content': \"Compared To Cristiano Ronaldo After Clasico Heroics\\nFC Barcelona Star Ousmane Dembele Receives ‘Enormous’ $220 Million Offer To Join Ronaldo At Al-Nassr: Reports\\nFootball Superstar Cristiano Ronaldo Invests In Online Watch Marketplace Chrono24\\n2023 (So Far): Cristiano Ronaldo Is The Most Followed Person On Instagram\\nFC Barcelona Transfer Target Must Choose Catalans Or Joining Cristiano Ronaldo At Saudi Giants: Reports\\nCristiano Ronaldo Offers Himself To Real Madrid Bitter Rivals, Tells Al-Nassr He Wishes To Leave: Reports\\nJuventus Trial Latest: Prosecutor Resigns, Details Of “Secret” Cristiano Ronaldo Documents Revealed\\nSigning Of The Season? Cristiano Ronaldo\\n2023 The World's Highest-Paid Athletes Earnings\\nForbes Lists\\nMore on Forbes\\nNegotiations Underway As Saudis Offer $1.1 Billion For Serie A Club\\nOnly Behind Messi And Ronaldo: Sunil Chhetri Approaches Milestone At The AFC Asian Cup\\nLionel Messi Will Take On Cristiano Ronaldo Again This January\\nLionel Messi Announces He Will Play In Saudi Arabia Against Cristiano Ronaldo\\nForbes Daily: Henry Kissinger’s Atalanta’s Ademola Lookman Is Scoring Like Cristiano Ronaldo\\nThe Ghost Of Cristiano Ronaldo Will Haunt Manchester United’s Season\\nWhat Happens Next For Cristiano Ronaldo?\\nalso on forbes Influential And Controversial Legacy\\nCristiano Ronaldo Faces $1 Billion Class Action Lawsuit For Promoting Binance\\nJude Bellingham\"}, {'url': 'https://en.wikipedia.org/wiki/Career_of_Cristiano_Ronaldo', 'content': \"Cristiano Ronaldo is a Portuguese footballer who plays as a forward for and captains both Saudi Pro League club Al-Nassr and the Portugal national team.His individual achievements include five Ballon d'Or awards, the most for a European player. His exceptional goal-scoring ability, explosive speed, powerful knuckleball shots, and dribbling skills cemented his legacy as one of the greatest and\"}, {'url': 'https://www.thefamouspeople.com/profiles/cristiano-ronaldo-4103.php', 'content': 'Cape Verdean Portuguese\\nawards: Ballon d\\'Or - 2008 European Golden Shoe - 2015-2011-2008 FIFA World Player of the Year - 2009\\nPichichi Trophy - 2015-2014-2011 FIFA Puskás Award - 2009 UEFA Best Player in Europe Award - 2014 FIFA FIFPro World XI - 2012-2011-2010 UEFA Team of the Year - 2012-2011-2010\\nPFA Players\\' Player of the Year - 2007-2006 Premier League Player of the Month - 2008-2008-2006\\nPremier League Golden Boot - 2007 Best International Athlete ESPY Award - 2014 PFA Young Player of the Year - 2006 Premier League Player of the Season - 2007-2006 Onze d\\'Or - 2008 FWA Footballer of the Year - 2007-2006 PFA Fans\\' Player of the Year - 2007-2006 Goal 50 - 2012-2008 Trofeo Alfredo Di Stéfano - 2011 UEFA Club Footballer of the Year - 2007 World Soccer Player of the Year - 2008 UEFA Champions League Top Goalscorer - 2015-2014-2013 Bravo Award - 2004 PFA Team of the Year - 2008-2007-2006\\nLa Liga Player of the Month - 2013 Sir Matt Busby Player of the Year - 2007-2006-2003 BBC Overseas Sports Personality of the Year - 2014 LFP Most Valuable Player - 2013 Milliyet Sports Award for World Athlete of the Year - 2014 FifPro Special Young Player of the Year - 2005-2004 IFFHS World\\'s Best Top Division Goal Scorer - 2013 UEFA Club Forward of the Year - 2007 FIFA Ballon d\\'Or - 2015-2014\\nRecommended Birthday: February 5, 1985 (Aquarius)\\nBorn In: Funchal, Portugal\\nRecommended For You\\nNick Name: The Sultan Of The Stepover\\nGirlfriend: Georgina Rodríguez, Irina Shayk (2010–2015)\\nAlso Known As: Cristiano Ronaldo dos Santos Aveiro\\nAge: 39 Years, 39 Year Old Males\\nfather: José Dinis Aveiro\\nmother: Maria Dolores dos Santos Aveiro\\nsiblings: Elma Aveiro, Hugo Aveiro, Liliana Catia Aveiro\\nchildren: Alana Martina dos Santos Aveiro, Cristiano Ronaldo Jr., Eva Maria Dos Santos, Mateo Ronaldo\\nBorn Country: Portugal\\nQuotes By Cristiano Ronaldo\\nFootball Players\\nHeight: 6\\'2\" (188 cm), 6\\'2\" Males\\nAncestry: The following year he was named the captain of the national team but in the European Championships that followed the next year, he scored only one goal as the team crashed out in the quarter-finals.\\n In 2012, he was the main inspiration for the team as he scored three goals to lead the team to the semifinal of the European Championships but Portugal was knocked out by Spain yet again in a penalty shootout.\\n Cristiano Ronaldo became one of Manchester United’s most important players during his six-year stint at the club and during that time the club became one of the most successful clubs in Europe as it won three league titles on the trot as well as the UEFA Champions League in 2008.'}, {'url': 'https://www.sportskeeda.com/player/cristiano-ronaldo', 'content': 'Get all the latest news, stats, performance, facts, history and biography of Cristiano Ronaldo. Also Get all the latest moves, skills, goals scored and much more only at Sportskeeda.'}]\u001b[0m\u001b[32;1m\u001b[1;3mCristiano Ronaldo, often referred to as CR7, is a Portuguese footballer renowned for his exceptional talent and achievements in the world of soccer. Born on February 5, 1985, in Funchal, Portugal, Ronaldo has become one of the most celebrated athletes globally, known for his incredible goal-scoring ability, speed, and dribbling skills.\n", - "\n", - "### Early Life and Career\n", - "\n", - "Ronaldo began his professional career with Sporting CP in Portugal before moving to Manchester United in 2003. During his time at Manchester United, he became one of the club's most important players, helping them secure three consecutive Premier League titles and a UEFA Champions League trophy in 2008. His performances earned him the Ballon d'Or in 2008, marking him as the world's best player.\n", - "\n", - "### Real Madrid and Juventus\n", - "\n", - "In 2009, Ronaldo transferred to Real Madrid for a then-world record fee. At Real Madrid, he further cemented his legacy, winning four more Ballon d'Or awards and becoming the club's all-time leading scorer. His tenure at Real Madrid was marked by numerous titles, including four UEFA Champions League trophies.\n", - "\n", - "In 2018, Ronaldo moved to Juventus, where he continued to showcase his goal-scoring prowess, winning two Serie A titles and further enhancing his reputation as one of the greatest footballers of all time.\n", - "\n", - "### Return to Manchester United and Move to Al-Nassr\n", - "\n", - "Ronaldo returned to Manchester United in 2021, where he continued to perform at a high level, finishing as the club's top scorer for the season. However, his second stint at the club was marred by dissatisfaction with the club's direction, leading to his departure.\n", - "\n", - "In 2023, Ronaldo joined Al-Nassr in the Saudi Pro League. His signing significantly increased the league's popularity, attracting other high-profile players to the region. Despite not winning a league title with Al-Nassr, Ronaldo's influence on and off the field remains substantial.\n", - "\n", - "### International Career\n", - "\n", - "Ronaldo has been a pivotal figure for the Portugal national team, captaining them to victory in the 2016 UEFA European Championship and the 2019 UEFA Nations League. His international career is highlighted by his leadership and goal-scoring record, making him one of the most successful players in international football.\n", - "\n", - "### Legacy and Influence\n", - "\n", - "Cristiano Ronaldo's legacy extends beyond his on-field achievements. He is the most followed person on Instagram, reflecting his global influence and popularity. His career is characterized by his relentless pursuit of excellence, adaptability, and ability to perform at the highest level across different leagues and competitions.\n", - "\n", - "Ronaldo's impact on football is profound, inspiring countless young athletes worldwide. His dedication to fitness, skill development, and competitive spirit continues to set a benchmark for aspiring footballers. As of 2023, Ronaldo remains a central figure in the sport, both as a player and a global icon.\u001b[0m\n", - "\n", - "\u001b[1m> Finished chain.\u001b[0m\n", - "\n", - "\n", - "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", - "\u001b[32;1m\u001b[1;3mCristiano Ronaldo, widely known as CR7, is a name synonymous with football excellence. Born on February 5, 1985, in Funchal, Portugal, Ronaldo has carved out a legendary career that has seen him become one of the most celebrated athletes in the world. His journey from a young boy in Madeira to a global football icon is a testament to his extraordinary talent, relentless work ethic, and unyielding determination.\n", - "\n", - "### Early Life and Rise to Stardom\n", - "\n", - "Ronaldo's football journey began at a young age when he joined the youth academy of Sporting CP in Lisbon. His prodigious talent quickly caught the attention of scouts, and in 2003, he made a high-profile move to Manchester United. Under the guidance of Sir Alex Ferguson, Ronaldo developed into one of the most exciting talents in the Premier League. His time at Manchester United was marked by numerous accolades, including three Premier League titles and a UEFA Champions League victory in 2008. That same year, he won his first Ballon d'Or, solidifying his status as the world's best player.\n", - "\n", - "### Dominance at Real Madrid\n", - "\n", - "In 2009, Ronaldo made a record-breaking transfer to Real Madrid, where he would spend the next nine years of his career. At Real Madrid, Ronaldo reached new heights, becoming the club's all-time leading scorer and winning four more Ballon d'Or awards. His tenure at the club was highlighted by four UEFA Champions League titles, including a historic three-peat from 2016 to 2018. Ronaldo's time in Madrid was characterized by his incredible goal-scoring ability, athleticism, and leadership on the field.\n", - "\n", - "### Juventus and Beyond\n", - "\n", - "Ronaldo's next chapter took him to Juventus in 2018, where he continued to demonstrate his goal-scoring prowess. During his time in Italy, he won two Serie A titles and further cemented his legacy as one of the greatest footballers of all time. In 2021, Ronaldo made a sensational return to Manchester United, where he continued to perform at a high level, although his second stint at the club was marked by challenges and a desire for new opportunities.\n", - "\n", - "In 2023, Ronaldo joined Al-Nassr in the Saudi Pro League, a move that significantly boosted the league's profile and attracted other high-profile players to the region. Despite not securing a league title with Al-Nassr, Ronaldo's influence on and off the field remains substantial.\n", - "\n", - "### International Success\n", - "\n", - "Ronaldo's impact extends to the international stage, where he has been a pivotal figure for the Portugal national team. He captained Portugal to their first major international trophy at the 2016 UEFA European Championship and followed it up with a victory in the 2019 UEFA Nations League. Ronaldo's leadership and goal-scoring record make him one of the most successful players in international football history.\n", - "\n", - "### Legacy and Global Influence\n", - "\n", - "Cristiano Ronaldo's legacy transcends his on-field achievements. He is the most followed person on Instagram, reflecting his global influence and popularity. His career is characterized by a relentless pursuit of excellence, adaptability, and the ability to perform at the highest level across different leagues and competitions.\n", - "\n", - "Ronaldo's impact on football is profound, inspiring countless young athletes worldwide. His dedication to fitness, skill development, and competitive spirit continues to set a benchmark for aspiring footballers. As of 2023, Ronaldo remains a central figure in the sport, both as a player and a global icon, whose influence will be felt for generations to come.\u001b[0m\n", - "\n", - "\u001b[1m> Finished chain.\u001b[0m\n" + "Edge : __start__ to Marketing\n", + "Marketing\n", + "Editorial-Team\n", + "Edge : Marketing to Editorial-Team\n", + "Editorial-Team\n", + "journal-reflection\n", + "next node\n", + "__end__\n", + "add node\n", + "f/ReflectionManager\n", + "Edge : M to f/ReflectionManager\n", + "Edge : journal-reflection to M\n" ] }, + { + "ename": "ValueError", + "evalue": "Found edge starting at unknown node 'M'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[9], line 16\u001b[0m\n\u001b[1;32m 8\u001b[0m journal_company_with_reflection \u001b[38;5;241m=\u001b[39m FloTeam\u001b[38;5;241m.\u001b[39mBuilder(session, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mNewspaper\u001b[39m\u001b[38;5;124m\"\u001b[39m, [marketing_flo, editorial_flo, reflection_agent])\n\u001b[1;32m 10\u001b[0m r4 \u001b[38;5;241m=\u001b[39m FloLinear\u001b[38;5;241m.\u001b[39mBuilder(\n\u001b[1;32m 11\u001b[0m session,\n\u001b[1;32m 12\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mlinear-router\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 13\u001b[0m journal_company_with_reflection\n\u001b[1;32m 14\u001b[0m )\u001b[38;5;241m.\u001b[39mbuild()\n\u001b[0;32m---> 16\u001b[0m master_flo_with_reflection \u001b[38;5;241m=\u001b[39m \u001b[43mr4\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mto_flo\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/Documents/hub/flo/flo_ai/router/flo_router.py:42\u001b[0m, in \u001b[0;36mFloRouter.to_flo\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 41\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mto_flo\u001b[39m(\u001b[38;5;28mself\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m FloRoutedTeam:\n\u001b[0;32m---> 42\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mbuild_graph\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/Documents/hub/flo/flo_ai/router/flo_linear.py:57\u001b[0m, in \u001b[0;36mFloLinear.build_graph\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 54\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m end_node\u001b[38;5;241m.\u001b[39mkind \u001b[38;5;241m!=\u001b[39m ExecutableType\u001b[38;5;241m.\u001b[39mdelegator:\n\u001b[1;32m 55\u001b[0m workflow\u001b[38;5;241m.\u001b[39madd_edge(end_node\u001b[38;5;241m.\u001b[39mname, END)\n\u001b[0;32m---> 57\u001b[0m workflow_graph \u001b[38;5;241m=\u001b[39m \u001b[43mworkflow\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcompile\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 59\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m FloRoutedTeam(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mflo_team\u001b[38;5;241m.\u001b[39mname, workflow_graph)\n", + "File \u001b[0;32m~/Documents/hub/flo/.venv/lib/python3.11/site-packages/langgraph/graph/state.py:431\u001b[0m, in \u001b[0;36mStateGraph.compile\u001b[0;34m(self, checkpointer, store, interrupt_before, interrupt_after, debug)\u001b[0m\n\u001b[1;32m 428\u001b[0m interrupt_after \u001b[38;5;241m=\u001b[39m interrupt_after \u001b[38;5;129;01mor\u001b[39;00m []\n\u001b[1;32m 430\u001b[0m \u001b[38;5;66;03m# validate the graph\u001b[39;00m\n\u001b[0;32m--> 431\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mvalidate\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 432\u001b[0m \u001b[43m \u001b[49m\u001b[43minterrupt\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m(\u001b[49m\n\u001b[1;32m 433\u001b[0m \u001b[43m \u001b[49m\u001b[43m(\u001b[49m\u001b[43minterrupt_before\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mif\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43minterrupt_before\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m!=\u001b[39;49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43m*\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01melse\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43m[\u001b[49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m+\u001b[39;49m\u001b[43m \u001b[49m\u001b[43minterrupt_after\u001b[49m\n\u001b[1;32m 434\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43;01mif\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43minterrupt_after\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m!=\u001b[39;49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43m*\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\n\u001b[1;32m 435\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43;01melse\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43m[\u001b[49m\u001b[43m]\u001b[49m\n\u001b[1;32m 436\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 437\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 439\u001b[0m \u001b[38;5;66;03m# prepare output channels\u001b[39;00m\n\u001b[1;32m 440\u001b[0m output_channels \u001b[38;5;241m=\u001b[39m (\n\u001b[1;32m 441\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m__root__\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 442\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mschemas[\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39moutput]) \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m1\u001b[39m\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 448\u001b[0m ]\n\u001b[1;32m 449\u001b[0m )\n", + "File \u001b[0;32m~/Documents/hub/flo/.venv/lib/python3.11/site-packages/langgraph/graph/graph.py:370\u001b[0m, in \u001b[0;36mGraph.validate\u001b[0;34m(self, interrupt)\u001b[0m\n\u001b[1;32m 368\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m source \u001b[38;5;129;01min\u001b[39;00m all_sources:\n\u001b[1;32m 369\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m source \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mnodes \u001b[38;5;129;01mand\u001b[39;00m source \u001b[38;5;241m!=\u001b[39m START:\n\u001b[0;32m--> 370\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mFound edge starting at unknown node \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;132;01m{\u001b[39;00msource\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 372\u001b[0m \u001b[38;5;66;03m# assemble targets\u001b[39;00m\n\u001b[1;32m 373\u001b[0m all_targets \u001b[38;5;241m=\u001b[39m {end \u001b[38;5;28;01mfor\u001b[39;00m _, end \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_all_edges}\n", + "\u001b[0;31mValueError\u001b[0m: Found edge starting at unknown node 'M'" + ] + } + ], + "source": [ + "\n", + "reflection_agent = FloReflectionAgent.Builder(\n", + " session,\n", + " \"journal-reflection\",\n", + " \"You are critic who looks are the article and create a list of improvements that can be done.\",\n", + " Delegate(to=[\"Marketing\"], retry=1)\n", + ").build()\n", + "\n", + "journal_company_with_reflection = FloTeam.Builder(session, \"Newspaper\", [marketing_flo, editorial_flo, reflection_agent])\n", + "\n", + "r4 = FloLinear.Builder(\n", + " session,\n", + " \"linear-router\",\n", + " journal_company_with_reflection\n", + ").build()\n", + "\n", + "master_flo_with_reflection = r4.to_flo()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ { "data": { + "image/png": "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", "text/plain": [ - "{'messages': [HumanMessage(content='Write an article about CR7', additional_kwargs={}, response_metadata={}),\n", - " HumanMessage(content=\"Cristiano Ronaldo, widely known as CR7, is a name synonymous with football excellence. Born on February 5, 1985, in Funchal, Portugal, Ronaldo has carved out a legendary career that has seen him become one of the most celebrated athletes in the world. His journey from a young boy in Madeira to a global football icon is a testament to his extraordinary talent, relentless work ethic, and unyielding determination.\\n\\n### Early Life and Rise to Stardom\\n\\nRonaldo's football journey began at a young age when he joined the youth academy of Sporting CP in Lisbon. His prodigious talent quickly caught the attention of scouts, and in 2003, he made a high-profile move to Manchester United. Under the guidance of Sir Alex Ferguson, Ronaldo developed into one of the most exciting talents in the Premier League. His time at Manchester United was marked by numerous accolades, including three Premier League titles and a UEFA Champions League victory in 2008. That same year, he won his first Ballon d'Or, solidifying his status as the world's best player.\\n\\n### Dominance at Real Madrid\\n\\nIn 2009, Ronaldo made a record-breaking transfer to Real Madrid, where he would spend the next nine years of his career. At Real Madrid, Ronaldo reached new heights, becoming the club's all-time leading scorer and winning four more Ballon d'Or awards. His tenure at the club was highlighted by four UEFA Champions League titles, including a historic three-peat from 2016 to 2018. Ronaldo's time in Madrid was characterized by his incredible goal-scoring ability, athleticism, and leadership on the field.\\n\\n### Juventus and Beyond\\n\\nRonaldo's next chapter took him to Juventus in 2018, where he continued to demonstrate his goal-scoring prowess. During his time in Italy, he won two Serie A titles and further cemented his legacy as one of the greatest footballers of all time. In 2021, Ronaldo made a sensational return to Manchester United, where he continued to perform at a high level, although his second stint at the club was marked by challenges and a desire for new opportunities.\\n\\nIn 2023, Ronaldo joined Al-Nassr in the Saudi Pro League, a move that significantly boosted the league's profile and attracted other high-profile players to the region. Despite not securing a league title with Al-Nassr, Ronaldo's influence on and off the field remains substantial.\\n\\n### International Success\\n\\nRonaldo's impact extends to the international stage, where he has been a pivotal figure for the Portugal national team. He captained Portugal to their first major international trophy at the 2016 UEFA European Championship and followed it up with a victory in the 2019 UEFA Nations League. Ronaldo's leadership and goal-scoring record make him one of the most successful players in international football history.\\n\\n### Legacy and Global Influence\\n\\nCristiano Ronaldo's legacy transcends his on-field achievements. He is the most followed person on Instagram, reflecting his global influence and popularity. His career is characterized by a relentless pursuit of excellence, adaptability, and the ability to perform at the highest level across different leagues and competitions.\\n\\nRonaldo's impact on football is profound, inspiring countless young athletes worldwide. His dedication to fitness, skill development, and competitive spirit continues to set a benchmark for aspiring footballers. As of 2023, Ronaldo remains a central figure in the sport, both as a player and a global icon, whose influence will be felt for generations to come.\", additional_kwargs={}, response_metadata={}, name='BlogWriter'),\n", - " HumanMessage(content=\"Cristiano Ronaldo, widely known as CR7, is a name synonymous with football excellence. Born on February 5, 1985, in Funchal, Portugal, Ronaldo has carved out a legendary career that has seen him become one of the most celebrated athletes in the world. His journey from a young boy in Madeira to a global football icon is a testament to his extraordinary talent, relentless work ethic, and unyielding determination.\\n\\n### Early Life and Rise to Stardom\\n\\nRonaldo's football journey began at a young age when he joined the youth academy of Sporting CP in Lisbon. His prodigious talent quickly caught the attention of scouts, and in 2003, he made a high-profile move to Manchester United. Under the guidance of Sir Alex Ferguson, Ronaldo developed into one of the most exciting talents in the Premier League. His time at Manchester United was marked by numerous accolades, including three Premier League titles and a UEFA Champions League victory in 2008. That same year, he won his first Ballon d'Or, solidifying his status as the world's best player.\\n\\n### Dominance at Real Madrid\\n\\nIn 2009, Ronaldo made a record-breaking transfer to Real Madrid, where he would spend the next nine years of his career. At Real Madrid, Ronaldo reached new heights, becoming the club's all-time leading scorer and winning four more Ballon d'Or awards. His tenure at the club was highlighted by four UEFA Champions League titles, including a historic three-peat from 2016 to 2018. Ronaldo's time in Madrid was characterized by his incredible goal-scoring ability, athleticism, and leadership on the field.\\n\\n### Juventus and Beyond\\n\\nRonaldo's next chapter took him to Juventus in 2018, where he continued to demonstrate his goal-scoring prowess. During his time in Italy, he won two Serie A titles and further cemented his legacy as one of the greatest footballers of all time. In 2021, Ronaldo made a sensational return to Manchester United, where he continued to perform at a high level, although his second stint at the club was marked by challenges and a desire for new opportunities.\\n\\nIn 2023, Ronaldo joined Al-Nassr in the Saudi Pro League, a move that significantly boosted the league's profile and attracted other high-profile players to the region. Despite not securing a league title with Al-Nassr, Ronaldo's influence on and off the field remains substantial.\\n\\n### International Success\\n\\nRonaldo's impact extends to the international stage, where he has been a pivotal figure for the Portugal national team. He captained Portugal to their first major international trophy at the 2016 UEFA European Championship and followed it up with a victory in the 2019 UEFA Nations League. Ronaldo's leadership and goal-scoring record make him one of the most successful players in international football history.\\n\\n### Legacy and Global Influence\\n\\nCristiano Ronaldo's legacy transcends his on-field achievements. He is the most followed person on Instagram, reflecting his global influence and popularity. His career is characterized by a relentless pursuit of excellence, adaptability, and the ability to perform at the highest level across different leagues and competitions.\\n\\nRonaldo's impact on football is profound, inspiring countless young athletes worldwide. His dedication to fitness, skill development, and competitive spirit continues to set a benchmark for aspiring footballers. As of 2023, Ronaldo remains a central figure in the sport, both as a player and a global icon, whose influence will be felt for generations to come.\", additional_kwargs={}, response_metadata={})]}" + "" ] }, - "execution_count": 9, "metadata": {}, - "output_type": "execute_result" + "output_type": "display_data" } ], "source": [ - "master_flo.invoke(\"Write an article about CR7\")" + "from IPython.display import Image, display\n", + "\n", + "display(Image(master_flo_with_reflection.draw()))" ] } ], diff --git a/examples/email_reply_agent.ipynb b/examples/email_reply_agent.ipynb index 92d9f7a7..30c2c1e7 100644 --- a/examples/email_reply_agent.ipynb +++ b/examples/email_reply_agent.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 8, + "execution_count": 1, "metadata": {}, "outputs": [ { @@ -11,7 +11,7 @@ "True" ] }, - "execution_count": 8, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } @@ -34,7 +34,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -76,7 +76,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -116,7 +116,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -143,31 +143,16 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 5, "metadata": {}, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2024-11-06 10:24:00,066 - SESSION - INFO - New FloSession created with ID: eMUGLvOrp7dclQJZ\n", - "2024-11-06 10:24:00,148 - SESSION - INFO - Tool 'HousingLoanTool' registered for session eMUGLvOrp7dclQJZ\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "**********\n" - ] - }, { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 14, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -198,24 +183,16 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 6, "metadata": {}, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2024-11-06 10:24:03,385 - SESSION - INFO - Tool 'SendEmailTool' registered for session eMUGLvOrp7dclQJZ\n", - "2024-11-06 10:24:03,386 - SESSION - INFO - Tool 'FetchTransactionTool' registered for session eMUGLvOrp7dclQJZ\n" - ] - }, { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 15, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -239,7 +216,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 7, "metadata": {}, "outputs": [], "source": [ @@ -280,7 +257,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 8, "metadata": {}, "outputs": [], "source": [ @@ -320,7 +297,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 9, "metadata": {}, "outputs": [], "source": [ @@ -350,65 +327,29 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 10, "metadata": {}, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2024-11-06 10:24:15,166 - BUILDER - INFO - Building Flo instance from YAML\n", - "2024-11-06 10:24:15,192 - COMMON - INFO - Flo instance created for session eMUGLvOrp7dclQJZ\n", - "2024-11-06 10:24:15,193 - COMMON - INFO - Streaming query for session eMUGLvOrp7dclQJZ: \n", - "You are a support ticket handling agent. You are expected to understand the email, and perform the following steps:\n", - "\n", - "1. Reply asking for more information if there is missing information in the email\n", - "2. Perform the neccessary steps to required to answer the users question and reply the user query as email.\n", - "3. If are not able to come up with a answer just reply I dont know over the email\n", - "\n", - "Email:\n", - "\n", - "\n", - "Hi Tom,\n", - "\n", - "We have a failed transaction. Can you tell me more about why this failed.\n", - "\n", - "Transaction ID: 12123123432\n", - "\n", - "Thanks\n", - "Vishnu\n", - "\n" - ] - }, { "name": "stdout", "output_type": "stream", "text": [ - "----->\n", - "{'messages': [{'content': 'You are a supervisor tasked with managing a conversation between the following team members: EmailSender, TransactionFetcher, HousingLoanTeamLead. Given the following user request, respond with the worker to act next. Each worker will perform a task and respond with their results and status. When the users question is answered or the assigned task is finished, respond with FINISH. ', 'role': 'system'}, {'content': '\\nYou are a support ticket handling agent. You are expected to understand the email, and perform the following steps:\\n\\n1. Reply asking for more information if there is missing information in the email\\n2. Perform the neccessary steps to required to answer the users question and reply the user query as email.\\n3. If are not able to come up with a answer just reply I dont know over the email\\n\\nEmail:\\n\\n\\nHi Tom,\\n\\nWe have a failed transaction. Can you tell me more about why this failed.\\n\\nTransaction ID: 12123123432\\n\\nThanks\\nVishnu\\n', 'role': 'user'}, {'content': 'Given the conversation above, who should act next? Or should we FINISH if the task is already answered, Select one of: [\\'EmailSender\\', \\'TransactionFetcher\\', \\'HousingLoanTeamLead\\', \\'FINISH\\'] \\n The output should be formatted as a JSON instance that conforms to the JSON schema below.\\n\\nAs an example, for the schema {\"properties\": {\"foo\": {\"title\": \"Foo\", \"description\": \"a list of strings\", \"type\": \"array\", \"items\": {\"type\": \"string\"}}}, \"required\": [\"foo\"]}\\nthe object {\"foo\": [\"bar\", \"baz\"]} is a well-formatted instance of the schema. The object {\"properties\": {\"foo\": [\"bar\", \"baz\"]}} is not well-formatted.\\n\\nHere is the output schema:\\n```\\n{\"properties\": {\"next\": {\"title\": \"Next\", \"description\": \"Name of the next member to be called\", \"type\": \"string\"}}, \"required\": [\"next\"]}\\n```', 'role': 'system'}], 'model': 'gpt-4o-mini', 'frequency_penalty': NOT_GIVEN, 'function_call': NOT_GIVEN, 'functions': NOT_GIVEN, 'logit_bias': NOT_GIVEN, 'logprobs': NOT_GIVEN, 'max_completion_tokens': NOT_GIVEN, 'max_tokens': NOT_GIVEN, 'metadata': NOT_GIVEN, 'n': 1, 'parallel_tool_calls': NOT_GIVEN, 'presence_penalty': NOT_GIVEN, 'response_format': NOT_GIVEN, 'seed': NOT_GIVEN, 'service_tier': NOT_GIVEN, 'stop': NOT_GIVEN, 'store': NOT_GIVEN, 'stream': False, 'stream_options': NOT_GIVEN, 'temperature': 0.0, 'tool_choice': NOT_GIVEN, 'tools': NOT_GIVEN, 'top_logprobs': NOT_GIVEN, 'top_p': NOT_GIVEN, 'user': NOT_GIVEN}\n", - "----->\n", - "{'SupportSupervisor': {'next': 'TransactionFetcher'}}\n", + "{'SupportTicketHandler': {'next': 'TransactionFetcher'}}\n", "----\n", "\n", "\n", "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", - "----->\n", - "{'messages': [{'content': 'You are capable of fetching any kind of transactions from the database given transaction reference id', 'role': 'system'}, {'content': '\\nYou are a support ticket handling agent. You are expected to understand the email, and perform the following steps:\\n\\n1. Reply asking for more information if there is missing information in the email\\n2. Perform the neccessary steps to required to answer the users question and reply the user query as email.\\n3. If are not able to come up with a answer just reply I dont know over the email\\n\\nEmail:\\n\\n\\nHi Tom,\\n\\nWe have a failed transaction. Can you tell me more about why this failed.\\n\\nTransaction ID: 12123123432\\n\\nThanks\\nVishnu\\n', 'role': 'user'}], 'model': 'gpt-4o-mini', 'frequency_penalty': NOT_GIVEN, 'function_call': NOT_GIVEN, 'functions': NOT_GIVEN, 'logit_bias': NOT_GIVEN, 'logprobs': NOT_GIVEN, 'max_completion_tokens': NOT_GIVEN, 'max_tokens': NOT_GIVEN, 'metadata': NOT_GIVEN, 'n': 1, 'parallel_tool_calls': NOT_GIVEN, 'presence_penalty': NOT_GIVEN, 'response_format': NOT_GIVEN, 'seed': NOT_GIVEN, 'service_tier': NOT_GIVEN, 'stop': NOT_GIVEN, 'store': NOT_GIVEN, 'stream': True, 'stream_options': NOT_GIVEN, 'temperature': 0.0, 'tool_choice': NOT_GIVEN, 'tools': [{'type': 'function', 'function': {'name': 'fetch_transactions', 'description': 'useful for when you want to fetch the transaction details given reference number', 'parameters': {'properties': {'reference_number': {'description': 'The transaction reference number', 'type': 'string'}}, 'required': ['reference_number'], 'type': 'object'}}}], 'top_logprobs': NOT_GIVEN, 'top_p': NOT_GIVEN, 'user': NOT_GIVEN}\n", - "----->\n", "\u001b[32;1m\u001b[1;3m\n", "Invoking: `fetch_transactions` with `{'reference_number': '12123123432'}`\n", "\n", "\n", - "\u001b[0m\u001b[36;1m\u001b[1;3mThe transaction happened on 23/07/2024 IST and it failed because there was not enough balance in the account\u001b[0m----->\n", - "{'messages': [{'content': 'You are capable of fetching any kind of transactions from the database given transaction reference id', 'role': 'system'}, {'content': '\\nYou are a support ticket handling agent. You are expected to understand the email, and perform the following steps:\\n\\n1. Reply asking for more information if there is missing information in the email\\n2. Perform the neccessary steps to required to answer the users question and reply the user query as email.\\n3. If are not able to come up with a answer just reply I dont know over the email\\n\\nEmail:\\n\\n\\nHi Tom,\\n\\nWe have a failed transaction. Can you tell me more about why this failed.\\n\\nTransaction ID: 12123123432\\n\\nThanks\\nVishnu\\n', 'role': 'user'}, {'content': None, 'role': 'assistant', 'tool_calls': [{'type': 'function', 'id': 'call_gz8RGLLuebKNGo8t29nWXhPr', 'function': {'name': 'fetch_transactions', 'arguments': '{\"reference_number\": \"12123123432\"}'}}]}, {'content': 'The transaction happened on 23/07/2024 IST and it failed because there was not enough balance in the account', 'role': 'tool', 'tool_call_id': 'call_gz8RGLLuebKNGo8t29nWXhPr'}], 'model': 'gpt-4o-mini', 'frequency_penalty': NOT_GIVEN, 'function_call': NOT_GIVEN, 'functions': NOT_GIVEN, 'logit_bias': NOT_GIVEN, 'logprobs': NOT_GIVEN, 'max_completion_tokens': NOT_GIVEN, 'max_tokens': NOT_GIVEN, 'metadata': NOT_GIVEN, 'n': 1, 'parallel_tool_calls': NOT_GIVEN, 'presence_penalty': NOT_GIVEN, 'response_format': NOT_GIVEN, 'seed': NOT_GIVEN, 'service_tier': NOT_GIVEN, 'stop': NOT_GIVEN, 'store': NOT_GIVEN, 'stream': True, 'stream_options': NOT_GIVEN, 'temperature': 0.0, 'tool_choice': NOT_GIVEN, 'tools': [{'type': 'function', 'function': {'name': 'fetch_transactions', 'description': 'useful for when you want to fetch the transaction details given reference number', 'parameters': {'properties': {'reference_number': {'description': 'The transaction reference number', 'type': 'string'}}, 'required': ['reference_number'], 'type': 'object'}}}], 'top_logprobs': NOT_GIVEN, 'top_p': NOT_GIVEN, 'user': NOT_GIVEN}\n", - "----->\n", - "\u001b[32;1m\u001b[1;3mSubject: Re: Failed Transaction Inquiry\n", + "\u001b[0m\u001b[36;1m\u001b[1;3mThe transaction happened on 23/07/2024 IST and it failed because there was not enough balance in the account\u001b[0m\u001b[32;1m\u001b[1;3mSubject: Re: Failed Transaction Inquiry\n", "\n", "Hi Vishnu,\n", "\n", "Thank you for reaching out regarding the failed transaction.\n", "\n", - "The transaction with ID 12123123432 occurred on 23/07/2024 IST and unfortunately failed due to insufficient balance in the account.\n", + "The transaction with ID 12123123432 occurred on 23/07/2024 IST and failed due to insufficient balance in the account.\n", "\n", "If you have any further questions or need assistance with anything else, feel free to ask!\n", "\n", @@ -416,45 +357,35 @@ "Tom\u001b[0m\n", "\n", "\u001b[1m> Finished chain.\u001b[0m\n", - "{'TransactionFetcher': {'messages': [HumanMessage(content='Subject: Re: Failed Transaction Inquiry\\n\\nHi Vishnu,\\n\\nThank you for reaching out regarding the failed transaction.\\n\\nThe transaction with ID 12123123432 occurred on 23/07/2024 IST and unfortunately failed due to insufficient balance in the account.\\n\\nIf you have any further questions or need assistance with anything else, feel free to ask!\\n\\nBest regards, \\nTom', additional_kwargs={}, response_metadata={}, name='TransactionFetcher')]}}\n", + "{'TransactionFetcher': {'messages': [HumanMessage(content='Subject: Re: Failed Transaction Inquiry\\n\\nHi Vishnu,\\n\\nThank you for reaching out regarding the failed transaction.\\n\\nThe transaction with ID 12123123432 occurred on 23/07/2024 IST and failed due to insufficient balance in the account.\\n\\nIf you have any further questions or need assistance with anything else, feel free to ask!\\n\\nBest regards, \\nTom', additional_kwargs={}, response_metadata={}, name='TransactionFetcher')]}}\n", "----\n", - "----->\n", - "{'messages': [{'content': 'You are a supervisor tasked with managing a conversation between the following team members: EmailSender, TransactionFetcher, HousingLoanTeamLead. Given the following user request, respond with the worker to act next. Each worker will perform a task and respond with their results and status. When the users question is answered or the assigned task is finished, respond with FINISH. ', 'role': 'system'}, {'content': '\\nYou are a support ticket handling agent. You are expected to understand the email, and perform the following steps:\\n\\n1. Reply asking for more information if there is missing information in the email\\n2. Perform the neccessary steps to required to answer the users question and reply the user query as email.\\n3. If are not able to come up with a answer just reply I dont know over the email\\n\\nEmail:\\n\\n\\nHi Tom,\\n\\nWe have a failed transaction. Can you tell me more about why this failed.\\n\\nTransaction ID: 12123123432\\n\\nThanks\\nVishnu\\n', 'role': 'user'}, {'content': 'Subject: Re: Failed Transaction Inquiry\\n\\nHi Vishnu,\\n\\nThank you for reaching out regarding the failed transaction.\\n\\nThe transaction with ID 12123123432 occurred on 23/07/2024 IST and unfortunately failed due to insufficient balance in the account.\\n\\nIf you have any further questions or need assistance with anything else, feel free to ask!\\n\\nBest regards, \\nTom', 'name': 'TransactionFetcher', 'role': 'user'}, {'content': 'Given the conversation above, who should act next? Or should we FINISH if the task is already answered, Select one of: [\\'EmailSender\\', \\'TransactionFetcher\\', \\'HousingLoanTeamLead\\', \\'FINISH\\'] \\n The output should be formatted as a JSON instance that conforms to the JSON schema below.\\n\\nAs an example, for the schema {\"properties\": {\"foo\": {\"title\": \"Foo\", \"description\": \"a list of strings\", \"type\": \"array\", \"items\": {\"type\": \"string\"}}}, \"required\": [\"foo\"]}\\nthe object {\"foo\": [\"bar\", \"baz\"]} is a well-formatted instance of the schema. The object {\"properties\": {\"foo\": [\"bar\", \"baz\"]}} is not well-formatted.\\n\\nHere is the output schema:\\n```\\n{\"properties\": {\"next\": {\"title\": \"Next\", \"description\": \"Name of the next member to be called\", \"type\": \"string\"}}, \"required\": [\"next\"]}\\n```', 'role': 'system'}], 'model': 'gpt-4o-mini', 'frequency_penalty': NOT_GIVEN, 'function_call': NOT_GIVEN, 'functions': NOT_GIVEN, 'logit_bias': NOT_GIVEN, 'logprobs': NOT_GIVEN, 'max_completion_tokens': NOT_GIVEN, 'max_tokens': NOT_GIVEN, 'metadata': NOT_GIVEN, 'n': 1, 'parallel_tool_calls': NOT_GIVEN, 'presence_penalty': NOT_GIVEN, 'response_format': NOT_GIVEN, 'seed': NOT_GIVEN, 'service_tier': NOT_GIVEN, 'stop': NOT_GIVEN, 'store': NOT_GIVEN, 'stream': False, 'stream_options': NOT_GIVEN, 'temperature': 0.0, 'tool_choice': NOT_GIVEN, 'tools': NOT_GIVEN, 'top_logprobs': NOT_GIVEN, 'top_p': NOT_GIVEN, 'user': NOT_GIVEN}\n", - "----->\n", - "{'SupportSupervisor': {'next': 'EmailSender'}}\n", + "{'SupportTicketHandler': {'next': 'EmailSender'}}\n", "----\n", "\n", "\n", "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", - "----->\n", - "{'messages': [{'content': 'You are capable of sending the reply email but constructing a apt response', 'role': 'system'}, {'content': '\\nYou are a support ticket handling agent. You are expected to understand the email, and perform the following steps:\\n\\n1. Reply asking for more information if there is missing information in the email\\n2. Perform the neccessary steps to required to answer the users question and reply the user query as email.\\n3. If are not able to come up with a answer just reply I dont know over the email\\n\\nEmail:\\n\\n\\nHi Tom,\\n\\nWe have a failed transaction. Can you tell me more about why this failed.\\n\\nTransaction ID: 12123123432\\n\\nThanks\\nVishnu\\n', 'role': 'user'}, {'content': 'Subject: Re: Failed Transaction Inquiry\\n\\nHi Vishnu,\\n\\nThank you for reaching out regarding the failed transaction.\\n\\nThe transaction with ID 12123123432 occurred on 23/07/2024 IST and unfortunately failed due to insufficient balance in the account.\\n\\nIf you have any further questions or need assistance with anything else, feel free to ask!\\n\\nBest regards, \\nTom', 'name': 'TransactionFetcher', 'role': 'user'}], 'model': 'gpt-4o-mini', 'frequency_penalty': NOT_GIVEN, 'function_call': NOT_GIVEN, 'functions': NOT_GIVEN, 'logit_bias': NOT_GIVEN, 'logprobs': NOT_GIVEN, 'max_completion_tokens': NOT_GIVEN, 'max_tokens': NOT_GIVEN, 'metadata': NOT_GIVEN, 'n': 1, 'parallel_tool_calls': NOT_GIVEN, 'presence_penalty': NOT_GIVEN, 'response_format': NOT_GIVEN, 'seed': NOT_GIVEN, 'service_tier': NOT_GIVEN, 'stop': NOT_GIVEN, 'store': NOT_GIVEN, 'stream': True, 'stream_options': NOT_GIVEN, 'temperature': 0.0, 'tool_choice': NOT_GIVEN, 'tools': [{'type': 'function', 'function': {'name': 'email_triage', 'description': 'useful for when you need to send an email to someone', 'parameters': {'properties': {'email': {'description': 'The email text to be sent', 'type': 'string'}}, 'required': ['email'], 'type': 'object'}}}], 'top_logprobs': NOT_GIVEN, 'top_p': NOT_GIVEN, 'user': NOT_GIVEN}\n", - "----->\n", "\u001b[32;1m\u001b[1;3m\n", - "Invoking: `email_triage` with `{'email': 'Hi Vishnu,\\n\\nThank you for reaching out regarding the failed transaction.\\n\\nThe transaction with ID 12123123432 occurred on 23/07/2024 IST and unfortunately failed due to insufficient balance in the account.\\n\\nIf you have any further questions or need assistance with anything else, feel free to ask!\\n\\nBest regards,\\nTom'}`\n", + "Invoking: `email_triage` with `{'email': 'Subject: Re: Failed Transaction Inquiry\\n\\nHi Vishnu,\\n\\nThank you for reaching out regarding the failed transaction.\\n\\nThe transaction with ID 12123123432 occurred on 23/07/2024 IST and failed due to insufficient balance in the account.\\n\\nIf you have any further questions or need assistance with anything else, feel free to ask!\\n\\nBest regards,\\nTom'}`\n", + "\n", "\n", + "\u001b[0mSubject: Re: Failed Transaction Inquiry\n", "\n", - "\u001b[0mHi Vishnu,\n", + "Hi Vishnu,\n", "\n", "Thank you for reaching out regarding the failed transaction.\n", "\n", - "The transaction with ID 12123123432 occurred on 23/07/2024 IST and unfortunately failed due to insufficient balance in the account.\n", + "The transaction with ID 12123123432 occurred on 23/07/2024 IST and failed due to insufficient balance in the account.\n", "\n", "If you have any further questions or need assistance with anything else, feel free to ask!\n", "\n", "Best regards,\n", "Tom\n", - "\u001b[36;1m\u001b[1;3mEmail sent successfully\u001b[0m----->\n", - "{'messages': [{'content': 'You are capable of sending the reply email but constructing a apt response', 'role': 'system'}, {'content': '\\nYou are a support ticket handling agent. You are expected to understand the email, and perform the following steps:\\n\\n1. Reply asking for more information if there is missing information in the email\\n2. Perform the neccessary steps to required to answer the users question and reply the user query as email.\\n3. If are not able to come up with a answer just reply I dont know over the email\\n\\nEmail:\\n\\n\\nHi Tom,\\n\\nWe have a failed transaction. Can you tell me more about why this failed.\\n\\nTransaction ID: 12123123432\\n\\nThanks\\nVishnu\\n', 'role': 'user'}, {'content': 'Subject: Re: Failed Transaction Inquiry\\n\\nHi Vishnu,\\n\\nThank you for reaching out regarding the failed transaction.\\n\\nThe transaction with ID 12123123432 occurred on 23/07/2024 IST and unfortunately failed due to insufficient balance in the account.\\n\\nIf you have any further questions or need assistance with anything else, feel free to ask!\\n\\nBest regards, \\nTom', 'name': 'TransactionFetcher', 'role': 'user'}, {'content': None, 'role': 'assistant', 'tool_calls': [{'type': 'function', 'id': 'call_tRgauP6bKTaqWhtyZBx6RHVM', 'function': {'name': 'email_triage', 'arguments': '{\"email\": \"Hi Vishnu,\\\\n\\\\nThank you for reaching out regarding the failed transaction.\\\\n\\\\nThe transaction with ID 12123123432 occurred on 23/07/2024 IST and unfortunately failed due to insufficient balance in the account.\\\\n\\\\nIf you have any further questions or need assistance with anything else, feel free to ask!\\\\n\\\\nBest regards,\\\\nTom\"}'}}]}, {'content': 'Email sent successfully', 'role': 'tool', 'tool_call_id': 'call_tRgauP6bKTaqWhtyZBx6RHVM'}], 'model': 'gpt-4o-mini', 'frequency_penalty': NOT_GIVEN, 'function_call': NOT_GIVEN, 'functions': NOT_GIVEN, 'logit_bias': NOT_GIVEN, 'logprobs': NOT_GIVEN, 'max_completion_tokens': NOT_GIVEN, 'max_tokens': NOT_GIVEN, 'metadata': NOT_GIVEN, 'n': 1, 'parallel_tool_calls': NOT_GIVEN, 'presence_penalty': NOT_GIVEN, 'response_format': NOT_GIVEN, 'seed': NOT_GIVEN, 'service_tier': NOT_GIVEN, 'stop': NOT_GIVEN, 'store': NOT_GIVEN, 'stream': True, 'stream_options': NOT_GIVEN, 'temperature': 0.0, 'tool_choice': NOT_GIVEN, 'tools': [{'type': 'function', 'function': {'name': 'email_triage', 'description': 'useful for when you need to send an email to someone', 'parameters': {'properties': {'email': {'description': 'The email text to be sent', 'type': 'string'}}, 'required': ['email'], 'type': 'object'}}}], 'top_logprobs': NOT_GIVEN, 'top_p': NOT_GIVEN, 'user': NOT_GIVEN}\n", - "----->\n", - "\u001b[32;1m\u001b[1;3mI have sent the response to Vishnu regarding the failed transaction. If you need any further assistance, feel free to ask!\u001b[0m\n", + "\u001b[36;1m\u001b[1;3mEmail sent successfully\u001b[0m\u001b[32;1m\u001b[1;3mI have sent the response to Vishnu regarding the failed transaction. If you need any further assistance, feel free to ask!\u001b[0m\n", "\n", "\u001b[1m> Finished chain.\u001b[0m\n", "{'EmailSender': {'messages': [HumanMessage(content='I have sent the response to Vishnu regarding the failed transaction. If you need any further assistance, feel free to ask!', additional_kwargs={}, response_metadata={}, name='EmailSender')]}}\n", "----\n", - "----->\n", - "{'messages': [{'content': 'You are a supervisor tasked with managing a conversation between the following team members: EmailSender, TransactionFetcher, HousingLoanTeamLead. Given the following user request, respond with the worker to act next. Each worker will perform a task and respond with their results and status. When the users question is answered or the assigned task is finished, respond with FINISH. ', 'role': 'system'}, {'content': '\\nYou are a support ticket handling agent. You are expected to understand the email, and perform the following steps:\\n\\n1. Reply asking for more information if there is missing information in the email\\n2. Perform the neccessary steps to required to answer the users question and reply the user query as email.\\n3. If are not able to come up with a answer just reply I dont know over the email\\n\\nEmail:\\n\\n\\nHi Tom,\\n\\nWe have a failed transaction. Can you tell me more about why this failed.\\n\\nTransaction ID: 12123123432\\n\\nThanks\\nVishnu\\n', 'role': 'user'}, {'content': 'Subject: Re: Failed Transaction Inquiry\\n\\nHi Vishnu,\\n\\nThank you for reaching out regarding the failed transaction.\\n\\nThe transaction with ID 12123123432 occurred on 23/07/2024 IST and unfortunately failed due to insufficient balance in the account.\\n\\nIf you have any further questions or need assistance with anything else, feel free to ask!\\n\\nBest regards, \\nTom', 'name': 'TransactionFetcher', 'role': 'user'}, {'content': 'I have sent the response to Vishnu regarding the failed transaction. If you need any further assistance, feel free to ask!', 'name': 'EmailSender', 'role': 'user'}, {'content': 'Given the conversation above, who should act next? Or should we FINISH if the task is already answered, Select one of: [\\'EmailSender\\', \\'TransactionFetcher\\', \\'HousingLoanTeamLead\\', \\'FINISH\\'] \\n The output should be formatted as a JSON instance that conforms to the JSON schema below.\\n\\nAs an example, for the schema {\"properties\": {\"foo\": {\"title\": \"Foo\", \"description\": \"a list of strings\", \"type\": \"array\", \"items\": {\"type\": \"string\"}}}, \"required\": [\"foo\"]}\\nthe object {\"foo\": [\"bar\", \"baz\"]} is a well-formatted instance of the schema. The object {\"properties\": {\"foo\": [\"bar\", \"baz\"]}} is not well-formatted.\\n\\nHere is the output schema:\\n```\\n{\"properties\": {\"next\": {\"title\": \"Next\", \"description\": \"Name of the next member to be called\", \"type\": \"string\"}}, \"required\": [\"next\"]}\\n```', 'role': 'system'}], 'model': 'gpt-4o-mini', 'frequency_penalty': NOT_GIVEN, 'function_call': NOT_GIVEN, 'functions': NOT_GIVEN, 'logit_bias': NOT_GIVEN, 'logprobs': NOT_GIVEN, 'max_completion_tokens': NOT_GIVEN, 'max_tokens': NOT_GIVEN, 'metadata': NOT_GIVEN, 'n': 1, 'parallel_tool_calls': NOT_GIVEN, 'presence_penalty': NOT_GIVEN, 'response_format': NOT_GIVEN, 'seed': NOT_GIVEN, 'service_tier': NOT_GIVEN, 'stop': NOT_GIVEN, 'store': NOT_GIVEN, 'stream': False, 'stream_options': NOT_GIVEN, 'temperature': 0.0, 'tool_choice': NOT_GIVEN, 'tools': NOT_GIVEN, 'top_logprobs': NOT_GIVEN, 'top_p': NOT_GIVEN, 'user': NOT_GIVEN}\n", - "----->\n", - "{'SupportSupervisor': {'next': 'FINISH'}}\n", + "{'SupportTicketHandler': {'next': 'FINISH'}}\n", "----\n" ] } diff --git a/flo_ai/router/flo_router.py b/flo_ai/router/flo_router.py index 0ff77609..b9d34bc3 100644 --- a/flo_ai/router/flo_router.py +++ b/flo_ai/router/flo_router.py @@ -83,6 +83,7 @@ def add_delegation_edge( to_agent_names = delegation_node.delegate.to delegation_node_name = delegation_node.name next_node_name = nextNode if isinstance(nextNode, str) else nextNode.name + retry = delegation_node.delegate.retry or 1 conditional_map = {} From 0ca5d582da94ea4faaff867fdc08b11090816508 Mon Sep 17 00:00:00 2001 From: vizsatiz Date: Sat, 16 Nov 2024 18:14:33 +0530 Subject: [PATCH 7/7] RUnning delegator and reflection examples --- examples/delegator_example.py | 6 +++--- examples/reflection_example.py | 5 ++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/examples/delegator_example.py b/examples/delegator_example.py index 33cc592d..f7f2287c 100644 --- a/examples/delegator_example.py +++ b/examples/delegator_example.py @@ -46,6 +46,6 @@ ) flo: Flo = Flo.build(session, yaml=yaml_data) -flo.draw_to_file('delegate.png', xray=True) -# data = flo.invoke(input_prompt) -# print((data['messages'][-1]).content) +Flo.set_log_level('INFO') +data = flo.invoke(input_prompt) +print((data['messages'][-1]).content) diff --git a/examples/reflection_example.py b/examples/reflection_example.py index 9e03c329..203fdad1 100644 --- a/examples/reflection_example.py +++ b/examples/reflection_example.py @@ -45,6 +45,5 @@ ) flo: Flo = Flo.build(session, yaml=yaml_data) -flo.draw_to_file('event.png', xray=True) -# data = flo.invoke(input_prompt) -# print((data['messages'][-1]).content) +data = flo.invoke(input_prompt) +print((data['messages'][-1]).content)