diff --git a/docs/core-concepts/Agents.md b/docs/core-concepts/Agents.md index 773fe47ae..fc19d2fb4 100644 --- a/docs/core-concepts/Agents.md +++ b/docs/core-concepts/Agents.md @@ -25,7 +25,7 @@ description: What are crewAI Agents and how to use them. | **Max RPM** | The maximum number of requests per minute the agent can perform to avoid rate limits | | **Verbose** | This allow you to actually see what is going on during the Crew execution. | | **Allow Delegation** | Agents can delegate tasks or questions to one another, ensuring that each task is handled by the most suitable agent. | -| **Step Callback** | A function that is called after each step of the agent. This can be used to log the agent's actions or to perform other operations. | +| **Step Callback** | A function that is called after each step of the agent. This can be used to log the agent's actions or to perform other operations. It will overwrite the crew `step_callback` | ## Creating an Agent diff --git a/docs/core-concepts/Crews.md b/docs/core-concepts/Crews.md index 60e19d20a..da7742107 100644 --- a/docs/core-concepts/Crews.md +++ b/docs/core-concepts/Crews.md @@ -20,6 +20,7 @@ description: Understanding and utilizing crews in the crewAI framework. | **Max RPM** | Maximum requests per minute the crew adheres to during execution. | | **Language** | Language setting for the crew's operation. | | **Full Output** | Whether the crew should return the full output with all tasks outputs or just the final output. | +| **Step Callback** | A function that is called after each step of every agent. This can be used to log the agent's actions or to perform other operations, it won't override the agent specific `step_callback` | | **Share Crew** | Whether you want to share the complete crew infromation and execution with the crewAI team to make the library better, and allow us to train models. | diff --git a/src/crewai/crew.py b/src/crewai/crew.py index cfe908f55..e1609ccd9 100644 --- a/src/crewai/crew.py +++ b/src/crewai/crew.py @@ -38,6 +38,7 @@ class Crew(BaseModel): max_rpm: Maximum number of requests per minute for the crew execution to be respected. id: A unique identifier for the crew instance. full_output: Whether the crew should return the full output with all tasks outputs or just the final output. + step_callback: Callback to be executed after each step for every agents execution. share_crew: Whether you want to share the complete crew infromation and execution with crewAI to make the library better, and allow us to train models. _cache_handler: Handles caching for the crew's operations. """ @@ -61,7 +62,11 @@ class Crew(BaseModel): ) config: Optional[Union[Json, Dict[str, Any]]] = Field(default=None) id: UUID4 = Field(default_factory=uuid.uuid4, frozen=True) - share_crew: bool = Field(default=False) + share_crew: Optional[bool] = Field(default=False) + step_callback: Optional[Any] = Field( + default=None, + description="Callback to be executed after each step for all agents execution.", + ) max_rpm: Optional[int] = Field( default=None, description="Maximum number of requests per minute for the crew execution to be respected.", @@ -145,6 +150,7 @@ class Crew(BaseModel): "missing_keys_in_config", "Config should have 'agents' and 'tasks'.", {} ) + self.process = self.config.get("process", self.process) self.agents = [Agent(**agent) for agent in self.config["agents"]] self.tasks = [self._create_task(task) for task in self.config["tasks"]] @@ -169,6 +175,8 @@ class Crew(BaseModel): for agent in self.agents: agent.i18n = I18N(language=self.language) + if (self.step_callback) and (not agent.step_callback): + agent.step_callback = self.step_callback if self.process == Process.sequential: return self._run_sequential_process() diff --git a/tests/crew_test.py b/tests/crew_test.py index 0ace1b95b..74e2fc0a0 100644 --- a/tests/crew_test.py +++ b/tests/crew_test.py @@ -449,3 +449,71 @@ def test_async_task_execution(): crew.kickoff() start.assert_called() join.assert_called() + + +def test_set_agents_step_callback(): + from unittest.mock import patch + + researcher_agent = Agent( + role="Researcher", + goal="Make the best research and analysis on content about AI and AI agents", + backstory="You're an expert researcher, specialized in technology, software engineering, AI and startups. You work as a freelancer and is now working on doing research and analysis for a new customer.", + allow_delegation=False, + ) + + list_ideas = Task( + description="Give me a list of 5 interesting ideas to explore for na article, what makes them unique and interesting.", + expected_output="Bullet point list of 5 important events.", + agent=researcher_agent, + async_execution=True, + ) + + crew = Crew( + agents=[researcher_agent], + process=Process.sequential, + tasks=[list_ideas], + step_callback=lambda: None, + ) + + with patch.object(Agent, "execute_task") as execute: + execute.return_value = "ok" + crew.kickoff() + assert researcher_agent.step_callback is not None + + +def test_dont_set_agents_step_callback_if_already_set(): + from unittest.mock import patch + + def agent_callback(_): + pass + + def crew_callback(_): + pass + + researcher_agent = Agent( + role="Researcher", + goal="Make the best research and analysis on content about AI and AI agents", + backstory="You're an expert researcher, specialized in technology, software engineering, AI and startups. You work as a freelancer and is now working on doing research and analysis for a new customer.", + allow_delegation=False, + step_callback=agent_callback, + ) + + list_ideas = Task( + description="Give me a list of 5 interesting ideas to explore for na article, what makes them unique and interesting.", + expected_output="Bullet point list of 5 important events.", + agent=researcher_agent, + async_execution=True, + ) + + crew = Crew( + agents=[researcher_agent], + process=Process.sequential, + tasks=[list_ideas], + step_callback=crew_callback, + ) + + with patch.object(Agent, "execute_task") as execute: + execute.return_value = "ok" + crew.kickoff() + assert researcher_agent.step_callback is not crew_callback + assert researcher_agent.step_callback is agent_callback