refactor(agent): remove CrewAI agent support and update related configurations
This commit is contained in:
parent
2a80bdf7a3
commit
0ca6b4f3e9
@ -9,7 +9,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
### Added
|
||||
|
||||
- Add CrewAI agents
|
||||
- Add Task Agent for structured single-task execution
|
||||
- Improve context management in agent execution
|
||||
|
||||
|
36
README.md
36
README.md
@ -15,7 +15,6 @@ The Evo AI platform allows:
|
||||
- JWT authentication with email verification
|
||||
- **[Agent 2 Agent (A2A) Protocol Support](https://developers.googleblog.com/en/a2a-a-new-era-of-agent-interoperability/)**: Interoperability between AI agents following Google's A2A specification
|
||||
- **[Workflow Agent with LangGraph](https://www.langchain.com/langgraph)**: Building complex agent workflows with LangGraph and ReactFlow
|
||||
- **[CrewAI Agent Support](https://www.crewai.com/)**: Organizing agents into specialized crews with assigned tasks
|
||||
- **Secure API Key Management**: Encrypted storage of API keys with Fernet encryption
|
||||
- **Agent Organization**: Folder structure for organizing agents by categories
|
||||
|
||||
@ -154,40 +153,7 @@ Executes sub-agents in a custom workflow defined by a graph structure. This agen
|
||||
|
||||
The workflow structure is built using ReactFlow in the frontend, allowing visual creation and editing of complex agent workflows with nodes (representing agents or decision points) and edges (representing flow connections).
|
||||
|
||||
### 7. CrewAI Agent
|
||||
|
||||
Allows organizing agents into a "crew" with specific tasks assigned to each agent. Based on the CrewAI concept, where each agent has a specific responsibility to perform a more complex task collaboratively.
|
||||
|
||||
```json
|
||||
{
|
||||
"client_id": "{{client_id}}",
|
||||
"name": "research_crew",
|
||||
"type": "crew_ai",
|
||||
"folder_id": "folder_id (optional)",
|
||||
"config": {
|
||||
"tasks": [
|
||||
{
|
||||
"agent_id": "agent-uuid-1",
|
||||
"description": "Search for recent information on the topic",
|
||||
"expected_output": "Search report in JSON format"
|
||||
},
|
||||
{
|
||||
"agent_id": "agent-uuid-2",
|
||||
"description": "Analyze data and create visualizations",
|
||||
"expected_output": "Charts and analyses in HTML format"
|
||||
},
|
||||
{
|
||||
"agent_id": "agent-uuid-3",
|
||||
"description": "Write final report combining results",
|
||||
"expected_output": "Markdown document with complete analysis"
|
||||
}
|
||||
],
|
||||
"sub_agents": ["agent-uuid-4", "agent-uuid-5"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 8. Task Agent
|
||||
### 7. Task Agent
|
||||
|
||||
Executes a specific task using a target agent. Task Agent provides a streamlined approach for structured task execution, where the agent_id specifies which agent will process the task, and the task description can include dynamic content placeholders.
|
||||
|
||||
|
@ -51,7 +51,6 @@ dependencies = [
|
||||
"langgraph==0.4.1",
|
||||
"opentelemetry-sdk==1.33.0",
|
||||
"opentelemetry-exporter-otlp==1.33.0",
|
||||
"crewai==0.119.0",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
|
@ -24,8 +24,6 @@
|
||||
│ For any future changes to the code in this file, it is recommended to │
|
||||
│ include, together with the modification, the information of the developer │
|
||||
│ who changed it and the date of modification. │
|
||||
│ │
|
||||
│ @update: May 14, 2025 - Added support for crew_ai agent type │
|
||||
└──────────────────────────────────────────────────────────────────────────────┘
|
||||
"""
|
||||
|
||||
|
@ -238,12 +238,15 @@ class WorkflowConfig(BaseModel):
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class CrewAITask(BaseModel):
|
||||
"""Task configuration for Crew AI agents"""
|
||||
class AgentTask(BaseModel):
|
||||
"""Task configuration for agents"""
|
||||
|
||||
agent_id: Union[UUID, str] = Field(
|
||||
..., description="ID of the agent assigned to this task"
|
||||
)
|
||||
enabled_tools: Optional[List[str]] = Field(
|
||||
default_factory=list, description="List of tool names to be used in the task"
|
||||
)
|
||||
description: str = Field(..., description="Description of the task to be performed")
|
||||
expected_output: str = Field(..., description="Expected output from this task")
|
||||
|
||||
@ -260,17 +263,17 @@ class CrewAITask(BaseModel):
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class CrewAIConfig(BaseModel):
|
||||
"""Configuration for Crew AI agents"""
|
||||
class AgentConfig(BaseModel):
|
||||
"""Configuration for agents"""
|
||||
|
||||
tasks: List[CrewAITask] = Field(
|
||||
..., description="List of tasks to be performed by the crew"
|
||||
tasks: List[AgentTask] = Field(
|
||||
..., description="List of tasks to be performed by the agent"
|
||||
)
|
||||
api_key: Optional[str] = Field(
|
||||
default_factory=generate_api_key, description="API key for the Crew AI agent"
|
||||
default_factory=generate_api_key, description="API key for the agent"
|
||||
)
|
||||
sub_agents: Optional[List[UUID]] = Field(
|
||||
default_factory=list, description="List of IDs of sub-agents used in crew"
|
||||
default_factory=list, description="List of IDs of sub-agents used in agent"
|
||||
)
|
||||
|
||||
class Config:
|
||||
|
@ -33,7 +33,7 @@ from datetime import datetime
|
||||
from uuid import UUID
|
||||
import uuid
|
||||
import re
|
||||
from src.schemas.agent_config import LLMConfig, CrewAIConfig
|
||||
from src.schemas.agent_config import LLMConfig, AgentConfig
|
||||
|
||||
|
||||
class ClientBase(BaseModel):
|
||||
@ -98,7 +98,7 @@ class AgentBase(BaseModel):
|
||||
goal: Optional[str] = Field(None, description="Agent goal or objective")
|
||||
type: str = Field(
|
||||
...,
|
||||
description="Agent type (llm, sequential, parallel, loop, a2a, workflow, crew_ai, task)",
|
||||
description="Agent type (llm, sequential, parallel, loop, a2a, workflow, task)",
|
||||
)
|
||||
model: Optional[str] = Field(
|
||||
None, description="Agent model (required only for llm type)"
|
||||
@ -136,11 +136,10 @@ class AgentBase(BaseModel):
|
||||
"loop",
|
||||
"a2a",
|
||||
"workflow",
|
||||
"crew_ai",
|
||||
"task",
|
||||
]:
|
||||
raise ValueError(
|
||||
"Invalid agent type. Must be: llm, sequential, parallel, loop, a2a, workflow, crew_ai or task"
|
||||
"Invalid agent type. Must be: llm, sequential, parallel, loop, a2a, workflow or task"
|
||||
)
|
||||
return v
|
||||
|
||||
@ -200,7 +199,7 @@ class AgentBase(BaseModel):
|
||||
raise ValueError(
|
||||
f'Agent {values["type"]} must have at least one sub-agent'
|
||||
)
|
||||
elif values["type"] == "crew_ai" or values["type"] == "task":
|
||||
elif values["type"] == "task":
|
||||
if not isinstance(v, dict):
|
||||
raise ValueError(f'Invalid configuration for agent {values["type"]}')
|
||||
if "tasks" not in v:
|
||||
@ -217,7 +216,6 @@ class AgentBase(BaseModel):
|
||||
if field not in task:
|
||||
raise ValueError(f"Task missing required field: {field}")
|
||||
|
||||
# Validar sub_agents, se existir
|
||||
if "sub_agents" in v and v["sub_agents"] is not None:
|
||||
if not isinstance(v["sub_agents"], list):
|
||||
raise ValueError("sub_agents must be a list")
|
||||
|
@ -40,7 +40,6 @@ from src.services.custom_tools import CustomToolBuilder
|
||||
from src.services.mcp_service import MCPService
|
||||
from src.services.custom_agents.a2a_agent import A2ACustomAgent
|
||||
from src.services.custom_agents.workflow_agent import WorkflowAgent
|
||||
from src.services.custom_agents.crew_ai_agent import CrewAIAgent
|
||||
from src.services.custom_agents.task_agent import TaskAgent
|
||||
from src.services.apikey_service import get_decrypted_api_key
|
||||
from sqlalchemy.orm import Session
|
||||
@ -50,7 +49,7 @@ from google.adk.tools import load_memory
|
||||
from datetime import datetime
|
||||
import uuid
|
||||
|
||||
from src.schemas.agent_config import CrewAITask
|
||||
from src.schemas.agent_config import AgentTask
|
||||
|
||||
logger = setup_logger(__name__)
|
||||
|
||||
@ -74,7 +73,7 @@ class AgentBuilder:
|
||||
return agent_tools
|
||||
|
||||
async def _create_llm_agent(
|
||||
self, agent
|
||||
self, agent, enabled_tools: List[str] = []
|
||||
) -> Tuple[LlmAgent, Optional[AsyncExitStack]]:
|
||||
"""Create an LLM agent from the agent data."""
|
||||
# Get custom tools from the configuration
|
||||
@ -95,6 +94,10 @@ class AgentBuilder:
|
||||
# Combine all tools
|
||||
all_tools = custom_tools + mcp_tools + agent_tools
|
||||
|
||||
if enabled_tools:
|
||||
all_tools = [tool for tool in all_tools if tool.name in enabled_tools]
|
||||
logger.info(f"Enabled tools enabled. Total tools: {len(all_tools)}")
|
||||
|
||||
now = datetime.now()
|
||||
current_datetime = now.strftime("%d/%m/%Y %H:%M")
|
||||
current_day_of_week = now.strftime("%A")
|
||||
@ -200,6 +203,8 @@ class AgentBuilder:
|
||||
sub_agent, exit_stack = await self.build_a2a_agent(agent)
|
||||
elif agent.type == "workflow":
|
||||
sub_agent, exit_stack = await self.build_workflow_agent(agent)
|
||||
elif agent.type == "task":
|
||||
sub_agent, exit_stack = await self.build_task_agent(agent)
|
||||
elif agent.type == "sequential":
|
||||
sub_agent, exit_stack = await self.build_composite_agent(agent)
|
||||
elif agent.type == "parallel":
|
||||
@ -218,7 +223,7 @@ class AgentBuilder:
|
||||
return sub_agents
|
||||
|
||||
async def build_llm_agent(
|
||||
self, root_agent
|
||||
self, root_agent, enabled_tools: List[str] = []
|
||||
) -> Tuple[LlmAgent, Optional[AsyncExitStack]]:
|
||||
"""Build an LLM agent with its sub-agents."""
|
||||
logger.info("Creating LLM agent")
|
||||
@ -230,7 +235,9 @@ class AgentBuilder:
|
||||
)
|
||||
sub_agents = [agent for agent, _ in sub_agents_with_stacks]
|
||||
|
||||
root_llm_agent, exit_stack = await self._create_llm_agent(root_agent)
|
||||
root_llm_agent, exit_stack = await self._create_llm_agent(
|
||||
root_agent, enabled_tools
|
||||
)
|
||||
if sub_agents:
|
||||
root_llm_agent.sub_agents = sub_agents
|
||||
|
||||
@ -341,10 +348,11 @@ class AgentBuilder:
|
||||
# Convert tasks to the expected format by TaskAgent
|
||||
tasks = []
|
||||
for task_config in config.get("tasks", []):
|
||||
task = CrewAITask(
|
||||
task = AgentTask(
|
||||
agent_id=task_config.get("agent_id"),
|
||||
description=task_config.get("description", ""),
|
||||
expected_output=task_config.get("expected_output", ""),
|
||||
enabled_tools=task_config.get("enabled_tools", []),
|
||||
)
|
||||
tasks.append(task)
|
||||
|
||||
@ -362,57 +370,7 @@ class AgentBuilder:
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error building Task agent: {str(e)}")
|
||||
raise ValueError(f"Error building CrewAI agent: {str(e)}")
|
||||
|
||||
async def build_crew_ai_agent(
|
||||
self, root_agent: Agent
|
||||
) -> Tuple[CrewAIAgent, Optional[AsyncExitStack]]:
|
||||
"""Build a CrewAI agent with its sub-agents."""
|
||||
logger.info(f"Creating CrewAI agent: {root_agent.name}")
|
||||
|
||||
agent_config = root_agent.config or {}
|
||||
|
||||
# Verify if we have tasks configured
|
||||
if not agent_config.get("tasks"):
|
||||
raise ValueError("tasks are required for CrewAI agents")
|
||||
|
||||
try:
|
||||
# Get sub-agents if there are any
|
||||
sub_agents = []
|
||||
if root_agent.config.get("sub_agents"):
|
||||
sub_agents_with_stacks = await self._get_sub_agents(
|
||||
root_agent.config.get("sub_agents")
|
||||
)
|
||||
sub_agents = [agent for agent, _ in sub_agents_with_stacks]
|
||||
|
||||
# Additional configurations
|
||||
config = root_agent.config or {}
|
||||
|
||||
# Convert tasks to the expected format by CrewAIAgent
|
||||
tasks = []
|
||||
for task_config in config.get("tasks", []):
|
||||
task = CrewAITask(
|
||||
agent_id=task_config.get("agent_id"),
|
||||
description=task_config.get("description", ""),
|
||||
expected_output=task_config.get("expected_output", ""),
|
||||
)
|
||||
tasks.append(task)
|
||||
|
||||
# Create the CrewAI agent
|
||||
crew_ai_agent = CrewAIAgent(
|
||||
name=root_agent.name,
|
||||
tasks=tasks,
|
||||
db=self.db,
|
||||
sub_agents=sub_agents,
|
||||
)
|
||||
|
||||
logger.info(f"CrewAI agent created successfully: {root_agent.name}")
|
||||
|
||||
return crew_ai_agent, None
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error building CrewAI agent: {str(e)}")
|
||||
raise ValueError(f"Error building CrewAI agent: {str(e)}")
|
||||
raise ValueError(f"Error building Task agent: {str(e)}")
|
||||
|
||||
async def build_composite_agent(
|
||||
self, root_agent
|
||||
@ -477,26 +435,23 @@ class AgentBuilder:
|
||||
else:
|
||||
raise ValueError(f"Invalid agent type: {root_agent.type}")
|
||||
|
||||
async def build_agent(self, root_agent) -> Tuple[
|
||||
async def build_agent(self, root_agent, enabled_tools: List[str] = []) -> Tuple[
|
||||
LlmAgent
|
||||
| SequentialAgent
|
||||
| ParallelAgent
|
||||
| LoopAgent
|
||||
| A2ACustomAgent
|
||||
| WorkflowAgent
|
||||
| CrewAIAgent
|
||||
| TaskAgent,
|
||||
Optional[AsyncExitStack],
|
||||
]:
|
||||
"""Build the appropriate agent based on the type of the root agent."""
|
||||
if root_agent.type == "llm":
|
||||
return await self.build_llm_agent(root_agent)
|
||||
return await self.build_llm_agent(root_agent, enabled_tools)
|
||||
elif root_agent.type == "a2a":
|
||||
return await self.build_a2a_agent(root_agent)
|
||||
elif root_agent.type == "workflow":
|
||||
return await self.build_workflow_agent(root_agent)
|
||||
elif root_agent.type == "crew_ai":
|
||||
return await self.build_crew_ai_agent(root_agent)
|
||||
elif root_agent.type == "task":
|
||||
return await self.build_task_agent(root_agent)
|
||||
else:
|
||||
|
@ -202,7 +202,7 @@ async def create_agent(db: Session, agent: AgentCreate) -> Agent:
|
||||
if "api_key" not in agent.config or not agent.config["api_key"]:
|
||||
agent.config["api_key"] = generate_api_key()
|
||||
|
||||
elif agent.type == "crew_ai" or agent.type == "task":
|
||||
elif agent.type == "task":
|
||||
if not isinstance(agent.config, dict):
|
||||
agent.config = {}
|
||||
raise HTTPException(
|
||||
@ -682,8 +682,8 @@ async def update_agent(
|
||||
if "config" not in agent_data:
|
||||
agent_data["config"] = agent_config
|
||||
|
||||
if ("type" in agent_data and agent_data["type"] in ["crew_ai", "task"]) or (
|
||||
agent.type in ["crew_ai", "task"] and "config" in agent_data
|
||||
if ("type" in agent_data and agent_data["type"] in ["task"]) or (
|
||||
agent.type in ["task"] and "config" in agent_data
|
||||
):
|
||||
config = agent_data.get("config", {})
|
||||
if "tasks" not in config:
|
||||
|
@ -1,266 +0,0 @@
|
||||
"""
|
||||
┌──────────────────────────────────────────────────────────────────────────────┐
|
||||
│ @author: Davidson Gomes │
|
||||
│ @file: crew_ai_agent.py │
|
||||
│ Developed by: Davidson Gomes │
|
||||
│ Creation date: May 14, 2025 │
|
||||
│ Contact: contato@evolution-api.com │
|
||||
├──────────────────────────────────────────────────────────────────────────────┤
|
||||
│ @copyright © Evolution API 2025. All rights reserved. │
|
||||
│ Licensed under the Apache License, Version 2.0 │
|
||||
│ │
|
||||
│ You may not use this file except in compliance with the License. │
|
||||
│ You may obtain a copy of the License at │
|
||||
│ │
|
||||
│ http://www.apache.org/licenses/LICENSE-2.0 │
|
||||
│ │
|
||||
│ Unless required by applicable law or agreed to in writing, software │
|
||||
│ distributed under the License is distributed on an "AS IS" BASIS, │
|
||||
│ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. │
|
||||
│ See the License for the specific language governing permissions and │
|
||||
│ limitations under the License. │
|
||||
├──────────────────────────────────────────────────────────────────────────────┤
|
||||
│ @important │
|
||||
│ For any future changes to the code in this file, it is recommended to │
|
||||
│ include, together with the modification, the information of the developer │
|
||||
│ who changed it and the date of modification. │
|
||||
└──────────────────────────────────────────────────────────────────────────────┘
|
||||
"""
|
||||
|
||||
from attr import Factory
|
||||
from google.adk.agents import BaseAgent
|
||||
from google.adk.agents.invocation_context import InvocationContext
|
||||
from google.adk.events import Event
|
||||
from google.genai.types import Content, Part
|
||||
from src.services.agent_service import get_agent
|
||||
from src.services.apikey_service import get_decrypted_api_key
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from typing import AsyncGenerator, List
|
||||
|
||||
from src.schemas.agent_config import CrewAITask
|
||||
|
||||
from crewai import Agent, Task, Crew, LLM
|
||||
|
||||
|
||||
class CrewAIAgent(BaseAgent):
|
||||
"""
|
||||
Custom agent that implements the CrewAI protocol directly.
|
||||
|
||||
This agent implements the interaction with an external CrewAI service.
|
||||
"""
|
||||
|
||||
# Field declarations for Pydantic
|
||||
tasks: List[CrewAITask]
|
||||
db: Session
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
tasks: List[CrewAITask],
|
||||
db: Session,
|
||||
sub_agents: List[BaseAgent] = [],
|
||||
**kwargs,
|
||||
):
|
||||
"""
|
||||
Initialize the CrewAI agent.
|
||||
|
||||
Args:
|
||||
name: Agent name
|
||||
tasks: List of tasks to be executed
|
||||
db: Database session
|
||||
sub_agents: List of sub-agents to be executed after the CrewAI agent
|
||||
"""
|
||||
# Initialize base class
|
||||
super().__init__(
|
||||
name=name,
|
||||
tasks=tasks,
|
||||
db=db,
|
||||
sub_agents=sub_agents,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
def _generate_llm(self, model: str, api_key: str):
|
||||
"""
|
||||
Generate the LLM for the CrewAI agent.
|
||||
"""
|
||||
|
||||
return LLM(model=model, api_key=api_key)
|
||||
|
||||
def _agent_builder(self, agent_id: str):
|
||||
"""
|
||||
Build the CrewAI agent.
|
||||
"""
|
||||
agent = get_agent(self.db, agent_id)
|
||||
|
||||
if not agent:
|
||||
raise ValueError(f"Agent with id {agent_id} not found")
|
||||
|
||||
api_key = None
|
||||
|
||||
decrypted_key = get_decrypted_api_key(self.db, agent.api_key_id)
|
||||
if decrypted_key:
|
||||
api_key = decrypted_key
|
||||
else:
|
||||
raise ValueError(
|
||||
f"API key with ID {agent.api_key_id} not found or inactive"
|
||||
)
|
||||
|
||||
if not api_key:
|
||||
raise ValueError(f"API key for agent {agent.name} not found")
|
||||
|
||||
return Agent(
|
||||
role=agent.role,
|
||||
goal=agent.goal,
|
||||
backstory=agent.instruction,
|
||||
llm=self._generate_llm(agent.model, api_key),
|
||||
verbose=True,
|
||||
)
|
||||
|
||||
def _tasks_and_agents_builder(self):
|
||||
"""
|
||||
Build the CrewAI tasks.
|
||||
"""
|
||||
tasks = []
|
||||
agents = []
|
||||
for task in self.tasks:
|
||||
agent = self._agent_builder(task.agent_id)
|
||||
agents.append(agent)
|
||||
tasks.append(
|
||||
Task(
|
||||
description=task.description,
|
||||
expected_output=task.expected_output,
|
||||
agent=agent,
|
||||
)
|
||||
)
|
||||
return tasks, agents
|
||||
|
||||
def _crew_builder(self):
|
||||
"""
|
||||
Build the CrewAI crew.
|
||||
"""
|
||||
tasks, agents = self._tasks_and_agents_builder()
|
||||
return Crew(
|
||||
agents=agents,
|
||||
tasks=tasks,
|
||||
verbose=True,
|
||||
)
|
||||
|
||||
async def _run_async_impl(
|
||||
self, ctx: InvocationContext
|
||||
) -> AsyncGenerator[Event, None]:
|
||||
"""
|
||||
Implementation of the CrewAI.
|
||||
|
||||
This method follows the pattern of implementing custom agents,
|
||||
sending the user's message to the CrewAI service and monitoring the response.
|
||||
"""
|
||||
|
||||
try:
|
||||
# Extract the user's message from the context
|
||||
user_message = None
|
||||
|
||||
# Search for the user's message in the session events
|
||||
if ctx.session and hasattr(ctx.session, "events") and ctx.session.events:
|
||||
for event in reversed(ctx.session.events):
|
||||
if event.author == "user" and event.content and event.content.parts:
|
||||
user_message = event.content.parts[0].text
|
||||
print("Message found in session events")
|
||||
break
|
||||
|
||||
# Check in the session state if the message was not found in the events
|
||||
if not user_message and ctx.session and ctx.session.state:
|
||||
if "user_message" in ctx.session.state:
|
||||
user_message = ctx.session.state["user_message"]
|
||||
elif "message" in ctx.session.state:
|
||||
user_message = ctx.session.state["message"]
|
||||
|
||||
if not user_message:
|
||||
yield Event(
|
||||
author=self.name,
|
||||
content=Content(
|
||||
role="agent",
|
||||
parts=[Part(text="User message not found")],
|
||||
),
|
||||
)
|
||||
return
|
||||
|
||||
try:
|
||||
# Replace any {content} in the task descriptions with the user's input
|
||||
for task in self.tasks:
|
||||
task.description = task.description.replace(
|
||||
"{content}", user_message
|
||||
)
|
||||
|
||||
# Build the Crew
|
||||
crew = self._crew_builder()
|
||||
|
||||
# Start the agent status
|
||||
yield Event(
|
||||
author=self.name,
|
||||
content=Content(
|
||||
role="agent",
|
||||
parts=[Part(text=f"Starting CrewAI processing...")],
|
||||
),
|
||||
)
|
||||
|
||||
# Prepare inputs (if there are placeholders to replace)
|
||||
inputs = {"user_message": user_message}
|
||||
|
||||
# Notify the user that the processing is in progress
|
||||
yield Event(
|
||||
author=self.name,
|
||||
content=Content(
|
||||
role="agent",
|
||||
parts=[Part(text=f"Processing your request...")],
|
||||
),
|
||||
)
|
||||
|
||||
# Try first with kickoff() normally
|
||||
try:
|
||||
# If it fails, try with kickoff_async
|
||||
result = await crew.kickoff_async(inputs=inputs)
|
||||
print(f"Result of crew.kickoff_async(): {result}")
|
||||
except Exception as e:
|
||||
print(f"Error executing crew.kickoff_async(): {str(e)}")
|
||||
print("Trying alternative with crew.kickoff()")
|
||||
result = crew.kickoff(inputs=inputs)
|
||||
print(f"Result of crew.kickoff(): {result}")
|
||||
|
||||
# Create an event for the final result
|
||||
final_event = Event(
|
||||
author=self.name,
|
||||
content=Content(role="agent", parts=[Part(text=str(result))]),
|
||||
)
|
||||
|
||||
# Transmit the event to the client
|
||||
yield final_event
|
||||
|
||||
# Execute sub-agents
|
||||
for sub_agent in self.sub_agents:
|
||||
async for event in sub_agent.run_async(ctx):
|
||||
yield event
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Error sending request: {str(e)}"
|
||||
print(error_msg)
|
||||
print(f"Error type: {type(e).__name__}")
|
||||
print(f"Error details: {str(e)}")
|
||||
|
||||
yield Event(
|
||||
author=self.name,
|
||||
content=Content(role="agent", parts=[Part(text=error_msg)]),
|
||||
)
|
||||
return
|
||||
|
||||
except Exception as e:
|
||||
# Handle any uncaught error
|
||||
print(f"Error executing CrewAI agent: {str(e)}")
|
||||
yield Event(
|
||||
author=self.name,
|
||||
content=Content(
|
||||
role="agent",
|
||||
parts=[Part(text=f"Error interacting with CrewAI agent: {str(e)}")],
|
||||
),
|
||||
)
|
@ -33,13 +33,12 @@ from google.adk.agents.invocation_context import InvocationContext
|
||||
from google.adk.events import Event
|
||||
from google.genai.types import Content, Part
|
||||
from src.services.agent_service import get_agent
|
||||
from src.services.apikey_service import get_decrypted_api_key
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from typing import AsyncGenerator, List
|
||||
|
||||
from src.schemas.agent_config import CrewAITask
|
||||
from src.schemas.agent_config import AgentTask
|
||||
|
||||
|
||||
class TaskAgent(BaseAgent):
|
||||
@ -50,13 +49,13 @@ class TaskAgent(BaseAgent):
|
||||
"""
|
||||
|
||||
# Field declarations for Pydantic
|
||||
tasks: List[CrewAITask]
|
||||
tasks: List[AgentTask]
|
||||
db: Session
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
tasks: List[CrewAITask],
|
||||
tasks: List[AgentTask],
|
||||
db: Session,
|
||||
sub_agents: List[BaseAgent] = [],
|
||||
**kwargs,
|
||||
@ -132,6 +131,7 @@ class TaskAgent(BaseAgent):
|
||||
# Replace any {content} in the task descriptions with the user's input
|
||||
task = self.tasks[0]
|
||||
task.description = task.description.replace("{content}", user_message)
|
||||
task.enabled_tools = task.enabled_tools or []
|
||||
|
||||
agent = get_agent(self.db, task.agent_id)
|
||||
|
||||
@ -166,7 +166,9 @@ class TaskAgent(BaseAgent):
|
||||
|
||||
print(f"Building agent in Task agent: {agent.name}")
|
||||
agent_builder = AgentBuilder(self.db)
|
||||
root_agent, exit_stack = await agent_builder.build_agent(agent)
|
||||
root_agent, exit_stack = await agent_builder.build_agent(
|
||||
agent, task.enabled_tools
|
||||
)
|
||||
|
||||
# Store task instructions in context for reference by sub-agents
|
||||
ctx.session.state["task_instructions"] = task_message_instructions
|
||||
|
Loading…
Reference in New Issue
Block a user