Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 33 additions & 9 deletions docs/en/learn/bring-your-own-agent.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,8 @@ By implementing these methods, your `MyCustomConverterAdapter` ensures that stru
We provide out of the box adapters for the following frameworks:
1. LangGraph
2. OpenAI Agents
3. [AgentSpec](https://github.com/oracle/agent-spec)
- AgentSpec is a framework-agnostic declarative language for defining agentic systems. It defines building blocks for standalone agents and structured agentic workflows as well as common ways of composing them into multi-agent systems.

## Kicking off a crew with adapted agents:

Expand All @@ -331,14 +333,16 @@ import os
from typing import List

from crewai_tools import SerperDevTool
from src.crewai import Agent, Crew, Task
from crewai import Agent, Crew, Task
from langchain_openai import ChatOpenAI
from pyagentspec.agent import Agent
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Import shadowing causes wrong Agent class usage

The import from pyagentspec.agent import Agent on line 338 shadows the earlier import from crewai import Agent on line 336. When code_helper_agent = Agent(...) is created on line 348 with role, goal, and backstory parameters, it will incorrectly use pyagentspec.agent.Agent instead of crewai.Agent. The pyagentspec Agent class likely doesn't accept these parameters, causing a runtime error. The pyagentspec Agent import needs an alias like AgentSpecAgent.

Additional Locations (1)

Fix in Cursor Fix in Web

from pyagentspec.llms import OpenAiConfig
from pyagentspec.serialization import AgentSpecSerializer
from pydantic import BaseModel

from crewai.agents.agent_adapters.langgraph.langgraph_adapter import (
LangGraphAgentAdapter,
)
from crewai.agents.agent_adapters.langgraph.langgraph_adapter import LangGraphAgentAdapter
from crewai.agents.agent_adapters.openai_agents.openai_adapter import OpenAIAgentAdapter
from crewai.agents.agent_adapters.agentspec.agentspec_adapter import AgentSpecAgentAdapter

# CrewAI Agent
code_helper_agent = Agent(
Expand All @@ -348,6 +352,18 @@ code_helper_agent = Agent(
allow_delegation=False,
verbose=True,
)

# AgentSpec Agent Adapter
code_reviewer_agent = AgentSpecAgentAdapter(
agentspec_agent_json=AgentSpecSerializer().to_json(
Agent(
name="Code Reviewer",
system_prompt="""You are an experienced programmer who performs thorough code review. Given a code snippet, suggest helpful improvements.""",
llm_config=OpenAiConfig(name="openai-gpt-4o", model_id="gpt-4o"),
)
)
)

# OpenAI Agent Adapter
link_finder_agent = OpenAIAgentAdapter(
role="Link Finder",
Expand All @@ -373,13 +389,20 @@ class Code(BaseModel):
code: str


task = Task(
task_write_code = Task(
description="Give an answer to the coding question: {task}",
expected_output="A thorough answer to the coding question: {task}",
agent=code_helper_agent,
output_json=Code,
)
task2 = Task(

task_review_code = Task(
description="Provide thorough helpful review for the generated code",
expected_output="A thorough review for the generated code",
agent=code_reviewer_agent,
)

task_find_links = Task(
description="Find links to resources that can help with coding tasks. Use the serper tool to find resources that can help.",
expected_output="A list of links to resources that can help with coding tasks",
agent=link_finder_agent,
Expand All @@ -391,16 +414,17 @@ class Report(BaseModel):
links: List[str]


task3 = Task(
task_generate_report = Task(
description="Report the results of the tasks.",
expected_output="A report of the results of the tasks. this is the code produced and then the links to the resources that can help with the coding task.",
agent=reporter_agent,
output_json=Report,
)

# Use in CrewAI
crew = Crew(
agents=[code_helper_agent, link_finder_agent, reporter_agent],
tasks=[task, task2, task3],
agents=[code_helper_agent, code_reviewer_agent, link_finder_agent, reporter_agent],
tasks=[task_write_code, task_review_code, task_find_links, task_generate_report],
verbose=True,
)

Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
from pydantic import Field, PrivateAttr
from typing import Any, Optional, Dict, Union, Callable, List

from crewai.agents.agent_builder.base_agent import BaseAgent
from crewai.agents.agent_adapters.base_agent_adapter import BaseAgentAdapter
from crewai import Agent as CrewAIAgent
from crewai.tools.base_tool import BaseTool, Tool as CrewAITool
from crewai.utilities.import_utils import import_and_validate_definition
from crewai.utilities.types import LLMMessage


class AgentSpecAgentAdapter(BaseAgentAdapter):
"""
Adapter that lets CrewAI import agents defined using Oracle's AgentSpec specification language.
(https://github.com/oracle/agent-spec.git)

This adapter wraps around the crewaiagentspecadapter which provides all required
conversion methods for loading an AgentSpec representation into a CrewAI Agent.
(https://github.com/oracle/agent-spec/tree/main/adapters/crewaiagentspecadapter)

When the conversion is done, this adapter delegates required methods to corresponding
methods of the underlying converted agent.

Supported features:
- ReAct-style agents
- Tools

Not currently supported:
- Flows
- Multi-agent patterns

Installation:
1) git clone https://github.com/oracle/agent-spec.git
2) cd agent-spec
3) pip install pyagentspec
4) pip install adapters/crewaiagentspecadapter
"""

_crewai_agent: CrewAIAgent = PrivateAttr()
function_calling_llm: Any = Field(default=None)
step_callback: Any = Field(default=None)

def __init__(
self,
agentspec_agent_json: str,
tool_registry: Optional[Dict[str, Union[Callable, CrewAITool]]] = None,
**kwargs: Any,
):
agent_spec_loader: type[Any] = import_and_validate_definition(
"crewai_agentspec_adapter.AgentSpecLoader"
)
loader = agent_spec_loader(tool_registry=tool_registry)
crewai_agent = loader.load_json(agentspec_agent_json)

init_kwargs = {
"role": getattr(crewai_agent, "role", "AgentSpec Agent"),
"goal": getattr(crewai_agent, "goal", "Execute tasks defined by AgentSpec"),
"backstory": getattr(
crewai_agent, "backstory", "Adapter wrapper around AgentSpec-generated CrewAI agent"
),
"llm": getattr(crewai_agent, "llm", None),
"function_calling_llm": getattr(crewai_agent, "llm", None),
"tools": getattr(crewai_agent, "tools", None),
"verbose": getattr(crewai_agent, "verbose", False),
"max_iter": getattr(crewai_agent, "max_iter", 25),
}
init_kwargs.update(kwargs or {})
super().__init__(**{k: v for k, v in init_kwargs.items() if v is not None})

self.function_calling_llm = getattr(crewai_agent, "llm", None)
self._crewai_agent = crewai_agent


# --- Abstract methods of BaseAgentAdapter ---

def configure_tools(self, tools: list[BaseTool] | None = None) -> None:
# Nothing to do, tools were already converted by AgentSpecLoader
pass

@property
def last_messages(self) -> list[LLMMessage]:
return self._crewai_agent.last_messages


# --- Abstract methods of BaseAgent ---
# We just delegate to the underlying agent's methods, since it's all already
# created by AgentSpecLoader (the output is crewai.Agent which is derived from BaseAgent)

def execute_task(
self,
task: Any,
context: Optional[str] = None,
tools: Optional[List[Any]] = None,
) -> Any:
return self._crewai_agent.execute_task(task, context=context, tools=tools)

def create_agent_executor(self, tools: Optional[List[Any]] = None) -> None:
self._crewai_agent.create_agent_executor(tools=tools)

def get_delegation_tools(self, agents: List[BaseAgent]) -> List[Any]:
return self._crewai_agent.get_delegation_tools(agents)

def get_platform_tools(self, apps: List[Any]) -> List[Any]:
return self._crewai_agent.get_platform_tools(apps)

def get_mcp_tools(self, mcps: List[Any]) -> List[Any]:
return self._crewai_agent.get_mcp_tools(mcps)