Skip to content

Commit 0dbf6d1

Browse files
author
Davidson Gomes
committed
feat(agent): add support for CrewAI agents and update related configurations
1 parent 98c559e commit 0dbf6d1

15 files changed

+638
-11
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.0.10] - develop
9+
10+
### Added
11+
12+
- Add CrewAI agents
13+
814
## [0.0.9] - 2025-05-13
915

1016
### Added

README.md

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ The Evo AI platform allows:
1111
- Client management
1212
- MCP server configuration
1313
- Custom tools management
14+
- **[Google Agent Development Kit (ADK)](https://google.github.io/adk-docs/)**: Base framework for agent development, providing support for LLM Agents, Sequential Agents, Loop Agents, Parallel Agents and Custom Agents
1415
- JWT authentication with email verification
15-
- **Agent 2 Agent (A2A) Protocol Support**: Interoperability between AI agents following Google's A2A specification
16-
- **Workflow Agent with LangGraph**: Building complex agent workflows with LangGraph and ReactFlow
16+
- **[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
17+
- **[Workflow Agent with LangGraph](https://www.langchain.com/langgraph)**: Building complex agent workflows with LangGraph and ReactFlow
18+
- **[CrewAI Agent Support](https://www.crewai.com/)**: Organizing agents into specialized crews with assigned tasks
1719
- **Secure API Key Management**: Encrypted storage of API keys with Fernet encryption
1820
- **Agent Organization**: Folder structure for organizing agents by categories
1921

@@ -30,6 +32,8 @@ Agent based on language models like GPT-4, Claude, etc. Can be configured with t
3032
"client_id": "{{client_id}}",
3133
"name": "personal_assistant",
3234
"description": "Specialized personal assistant",
35+
"role": "Personal Assistant",
36+
"goal": "Help users with daily tasks and provide relevant information",
3337
"type": "llm",
3438
"model": "gpt-4",
3539
"api_key_id": "stored-api-key-uuid",
@@ -150,6 +154,39 @@ Executes sub-agents in a custom workflow defined by a graph structure. This agen
150154

151155
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).
152156

157+
### 7. CrewAI Agent
158+
159+
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.
160+
161+
```json
162+
{
163+
"client_id": "{{client_id}}",
164+
"name": "research_crew",
165+
"type": "crew_ai",
166+
"folder_id": "folder_id (optional)",
167+
"config": {
168+
"tasks": [
169+
{
170+
"agent_id": "agent-uuid-1",
171+
"description": "Search for recent information on the topic",
172+
"expected_output": "Search report in JSON format"
173+
},
174+
{
175+
"agent_id": "agent-uuid-2",
176+
"description": "Analyze data and create visualizations",
177+
"expected_output": "Charts and analyses in HTML format"
178+
},
179+
{
180+
"agent_id": "agent-uuid-3",
181+
"description": "Write final report combining results",
182+
"expected_output": "Markdown document with complete analysis"
183+
}
184+
],
185+
"sub_agents": ["agent-uuid-4", "agent-uuid-5"]
186+
}
187+
}
188+
```
189+
153190
### Common Characteristics
154191

155192
- All agent types can have sub-agents
@@ -355,7 +392,7 @@ Evo AI implements the Google's Agent 2 Agent (A2A) protocol, enabling seamless c
355392
- **Standardized Communication**: Agents can communicate using a common protocol regardless of their underlying implementation
356393
- **Interoperability**: Support for agents built with different frameworks and technologies
357394
- **Well-Known Endpoints**: Standardized endpoints for agent discovery and interaction
358-
- **Task Management**: Support for task-based interactions between agents
395+
- **Task Management**: Support for task creation, execution, and status tracking
359396
- **State Management**: Tracking of agent states and conversation history
360397
- **Authentication**: Secure API key-based authentication for agent interactions
361398

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
"""add_crew_ai_coluns_agents_table
2+
3+
Revision ID: 611d84e70bb2
4+
Revises: bdc5d363e2e1
5+
Create Date: 2025-05-14 07:31:08.741620
6+
7+
"""
8+
from typing import Sequence, Union
9+
10+
from alembic import op
11+
import sqlalchemy as sa
12+
13+
14+
# revision identifiers, used by Alembic.
15+
revision: str = '611d84e70bb2'
16+
down_revision: Union[str, None] = 'bdc5d363e2e1'
17+
branch_labels: Union[str, Sequence[str], None] = None
18+
depends_on: Union[str, Sequence[str], None] = None
19+
20+
21+
def upgrade() -> None:
22+
"""Upgrade schema."""
23+
# ### commands auto generated by Alembic - please adjust! ###
24+
op.add_column('agents', sa.Column('role', sa.String(), nullable=True))
25+
op.add_column('agents', sa.Column('goal', sa.Text(), nullable=True))
26+
# ### end Alembic commands ###
27+
28+
29+
def downgrade() -> None:
30+
"""Downgrade schema."""
31+
# ### commands auto generated by Alembic - please adjust! ###
32+
op.drop_column('agents', 'goal')
33+
op.drop_column('agents', 'role')
34+
# ### end Alembic commands ###
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
"""add_crew_ai_agent_type_agents_table
2+
3+
Revision ID: bdc5d363e2e1
4+
Revises: 6db4a526335b
5+
Create Date: 2025-05-14 06:23:14.701878
6+
7+
"""
8+
9+
from typing import Sequence, Union
10+
11+
from alembic import op
12+
import sqlalchemy as sa
13+
14+
15+
# revision identifiers, used by Alembic.
16+
revision: str = "bdc5d363e2e1"
17+
down_revision: Union[str, None] = "6db4a526335b"
18+
branch_labels: Union[str, Sequence[str], None] = None
19+
depends_on: Union[str, Sequence[str], None] = None
20+
21+
22+
def upgrade() -> None:
23+
"""Upgrade schema."""
24+
# ### commands auto generated by Alembic - please adjust! ###
25+
op.drop_constraint("check_agent_type", "agents", type_="check")
26+
op.create_check_constraint(
27+
"check_agent_type",
28+
"agents",
29+
"type IN ('llm', 'sequential', 'parallel', 'loop', 'a2a', 'workflow', 'crew_ai')",
30+
)
31+
# ### end Alembic commands ###
32+
33+
34+
def downgrade() -> None:
35+
"""Downgrade schema."""
36+
# ### commands auto generated by Alembic - please adjust! ###
37+
op.drop_constraint("check_agent_type", "agents", type_="check")
38+
op.create_check_constraint(
39+
"check_agent_type",
40+
"agents",
41+
"type IN ('llm', 'sequential', 'parallel', 'loop', 'a2a', 'workflow')",
42+
)
43+
# ### end Alembic commands ###

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ dependencies = [
5151
"langgraph==0.4.1",
5252
"opentelemetry-sdk==1.33.0",
5353
"opentelemetry-exporter-otlp==1.33.0",
54+
"crewai==0.119.0",
5455
]
5556

5657
[project.optional-dependencies]

src/api/agent_routes.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
│ For any future changes to the code in this file, it is recommended to │
2525
│ include, together with the modification, the information of the developer │
2626
│ who changed it and the date of modification. │
27+
│ │
28+
│ @update: May 14, 2025 - Added support for crew_ai agent type │
2729
└──────────────────────────────────────────────────────────────────────────────┘
2830
"""
2931

src/models/models.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ class Agent(Base):
100100
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
101101
client_id = Column(UUID(as_uuid=True), ForeignKey("clients.id", ondelete="CASCADE"))
102102
name = Column(String, nullable=False)
103+
role = Column(String, nullable=True)
104+
goal = Column(Text, nullable=True)
103105
description = Column(Text, nullable=True)
104106
type = Column(String, nullable=False)
105107
model = Column(String, nullable=True, default="")
@@ -121,7 +123,7 @@ class Agent(Base):
121123

122124
__table_args__ = (
123125
CheckConstraint(
124-
"type IN ('llm', 'sequential', 'parallel', 'loop', 'a2a', 'workflow')",
126+
"type IN ('llm', 'sequential', 'parallel', 'loop', 'a2a', 'workflow', 'crew_ai')",
125127
name="check_agent_type",
126128
),
127129
)

src/schemas/agent_config.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
from uuid import UUID
3333
import secrets
3434
import string
35+
import uuid
36+
from pydantic import validator
3537

3638

3739
class ToolConfig(BaseModel):
@@ -234,3 +236,42 @@ class WorkflowConfig(BaseModel):
234236

235237
class Config:
236238
from_attributes = True
239+
240+
241+
class CrewAITask(BaseModel):
242+
"""Task configuration for Crew AI agents"""
243+
244+
agent_id: Union[UUID, str] = Field(
245+
..., description="ID of the agent assigned to this task"
246+
)
247+
description: str = Field(..., description="Description of the task to be performed")
248+
expected_output: str = Field(..., description="Expected output from this task")
249+
250+
@validator("agent_id")
251+
def validate_agent_id(cls, v):
252+
if isinstance(v, str):
253+
try:
254+
return uuid.UUID(v)
255+
except ValueError:
256+
raise ValueError(f"Invalid UUID format for agent_id: {v}")
257+
return v
258+
259+
class Config:
260+
from_attributes = True
261+
262+
263+
class CrewAIConfig(BaseModel):
264+
"""Configuration for Crew AI agents"""
265+
266+
tasks: List[CrewAITask] = Field(
267+
..., description="List of tasks to be performed by the crew"
268+
)
269+
api_key: Optional[str] = Field(
270+
default_factory=generate_api_key, description="API key for the Crew AI agent"
271+
)
272+
sub_agents: Optional[List[UUID]] = Field(
273+
default_factory=list, description="List of IDs of sub-agents used in crew"
274+
)
275+
276+
class Config:
277+
from_attributes = True

src/schemas/schemas.py

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
from uuid import UUID
3434
import uuid
3535
import re
36-
from src.schemas.agent_config import LLMConfig
36+
from src.schemas.agent_config import LLMConfig, CrewAIConfig
3737

3838

3939
class ClientBase(BaseModel):
@@ -94,8 +94,11 @@ class AgentBase(BaseModel):
9494
None, description="Agent name (no spaces or special characters)"
9595
)
9696
description: Optional[str] = Field(None, description="Agent description")
97+
role: Optional[str] = Field(None, description="Agent role in the system")
98+
goal: Optional[str] = Field(None, description="Agent goal or objective")
9799
type: str = Field(
98-
..., description="Agent type (llm, sequential, parallel, loop, a2a, workflow)"
100+
...,
101+
description="Agent type (llm, sequential, parallel, loop, a2a, workflow, crew_ai)",
99102
)
100103
model: Optional[str] = Field(
101104
None, description="Agent model (required only for llm type)"
@@ -126,9 +129,17 @@ def validate_name(cls, v, values):
126129

127130
@validator("type")
128131
def validate_type(cls, v):
129-
if v not in ["llm", "sequential", "parallel", "loop", "a2a", "workflow"]:
132+
if v not in [
133+
"llm",
134+
"sequential",
135+
"parallel",
136+
"loop",
137+
"a2a",
138+
"workflow",
139+
"crew_ai",
140+
]:
130141
raise ValueError(
131-
"Invalid agent type. Must be: llm, sequential, parallel, loop, a2a or workflow"
142+
"Invalid agent type. Must be: llm, sequential, parallel, loop, a2a, workflow or crew_ai"
132143
)
133144
return v
134145

@@ -188,6 +199,33 @@ def validate_config(cls, v, values):
188199
raise ValueError(
189200
f'Agent {values["type"]} must have at least one sub-agent'
190201
)
202+
elif values["type"] == "crew_ai":
203+
if not isinstance(v, dict):
204+
raise ValueError(f'Invalid configuration for agent {values["type"]}')
205+
if "tasks" not in v:
206+
raise ValueError(f'Agent {values["type"]} must have tasks')
207+
if not isinstance(v["tasks"], list):
208+
raise ValueError("tasks must be a list")
209+
if not v["tasks"]:
210+
raise ValueError(f'Agent {values["type"]} must have at least one task')
211+
for task in v["tasks"]:
212+
if not isinstance(task, dict):
213+
raise ValueError("Each task must be a dictionary")
214+
required_fields = ["agent_id", "description", "expected_output"]
215+
for field in required_fields:
216+
if field not in task:
217+
raise ValueError(f"Task missing required field: {field}")
218+
219+
# Validar sub_agents, se existir
220+
if "sub_agents" in v and v["sub_agents"] is not None:
221+
if not isinstance(v["sub_agents"], list):
222+
raise ValueError("sub_agents must be a list")
223+
224+
try:
225+
# Convert the dictionary to CrewAIConfig
226+
v = CrewAIConfig(**v)
227+
except Exception as e:
228+
raise ValueError(f"Invalid Crew AI configuration for agent: {str(e)}")
191229

192230
return v
193231

0 commit comments

Comments
 (0)