Skip to content

Commit e134e53

Browse files
Gl/feat/a2a refactor (#3793)
* feat: agent metaclass, refactor a2a to wrappers * feat: a2a schemas and utils * chore: move agent class, update imports * refactor: organize imports to avoid circularity, add a2a to console * feat: pass response_model through call chain * feat: add standard openapi spec serialization to tools and structured output * feat: a2a events * chore: add a2a to pyproject * docs: minimal base for learn docs * fix: adjust a2a conversation flow, allow llm to decide exit until max_retries * fix: inject agent skills into initial prompt * fix: format agent card as json in prompt * refactor: simplify A2A agent prompt formatting and improve skill display * chore: wide cleanup * chore: cleanup logic, add auth cache, use json for messages in prompt * chore: update docs * fix: doc snippets formatting * feat: optimize A2A agent card fetching and improve error reporting * chore: move imports to top of file * chore: refactor hasattr check * chore: add httpx-auth, update lockfile * feat: create base public api * chore: cleanup modules, add docstrings, types * fix: exclude extra fields in prompt * chore: update docs * tests: update to correct import * chore: lint for ruff, add missing import * fix: tweak openai streaming logic for response model * tests: add reimport for test * tests: add reimport for test * fix: don't set a2a attr if not set * fix: don't set a2a attr if not set * chore: update cassettes * tests: fix tests * fix: use instructor and dont pass response_format for litellm * chore: consolidate event listeners, add typing * fix: address race condition in test, update cassettes * tests: add correct mocks, rerun cassette for json * tests: update cassette * chore: regenerate cassette after new run * fix: make token manager access-safe * fix: make token manager access-safe * merge * chore: update test and cassete for output pydantic * fix: tweak to disallow deadlock * chore: linter * fix: adjust event ordering for threading * fix: use conditional for batch check * tests: tweak for emission * tests: simplify api + event check * fix: ensure non-function calling llms see json formatted string * tests: tweak message comparison * fix: use internal instructor for litellm structure responses --------- Co-authored-by: Mike Plachta <[email protected]>
1 parent e229ef4 commit e134e53

File tree

71 files changed

+9621
-4423
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+9621
-4423
lines changed
Lines changed: 291 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,291 @@
1+
---
2+
title: Agent-to-Agent (A2A) Protocol
3+
description: Enable CrewAI agents to delegate tasks to remote A2A-compliant agents for specialized handling
4+
icon: network-wired
5+
mode: "wide"
6+
---
7+
8+
## A2A Agent Delegation
9+
10+
CrewAI supports the Agent-to-Agent (A2A) protocol, allowing agents to delegate tasks to remote specialized agents. The agent's LLM automatically decides whether to handle a task directly or delegate to an A2A agent based on the task requirements.
11+
12+
<Note>
13+
A2A delegation requires the `a2a-sdk` package. Install with: `uv add 'crewai[a2a]'` or `pip install 'crewai[a2a]'`
14+
</Note>
15+
16+
## How It Works
17+
18+
When an agent is configured with A2A capabilities:
19+
20+
1. The LLM analyzes each task
21+
2. It decides to either:
22+
- Handle the task directly using its own capabilities
23+
- Delegate to a remote A2A agent for specialized handling
24+
3. If delegating, the agent communicates with the remote A2A agent through the protocol
25+
4. Results are returned to the CrewAI workflow
26+
27+
## Basic Configuration
28+
29+
Configure an agent for A2A delegation by setting the `a2a` parameter:
30+
31+
```python Code
32+
from crewai import Agent, Crew, Task
33+
from crewai.a2a import A2AConfig
34+
35+
agent = Agent(
36+
role="Research Coordinator",
37+
goal="Coordinate research tasks efficiently",
38+
backstory="Expert at delegating to specialized research agents",
39+
llm="gpt-4o",
40+
a2a=A2AConfig(
41+
endpoint="https://example.com/.well-known/agent-card.json",
42+
timeout=120,
43+
max_turns=10
44+
)
45+
)
46+
47+
task = Task(
48+
description="Research the latest developments in quantum computing",
49+
expected_output="A comprehensive research report",
50+
agent=agent
51+
)
52+
53+
crew = Crew(agents=[agent], tasks=[task], verbose=True)
54+
result = crew.kickoff()
55+
```
56+
57+
## Configuration Options
58+
59+
The `A2AConfig` class accepts the following parameters:
60+
61+
<ParamField path="endpoint" type="str" required>
62+
The A2A agent endpoint URL (typically points to `.well-known/agent-card.json`)
63+
</ParamField>
64+
65+
<ParamField path="auth" type="AuthScheme" default="None">
66+
Authentication scheme for the A2A agent. Supports Bearer tokens, OAuth2, API keys, and HTTP authentication.
67+
</ParamField>
68+
69+
<ParamField path="timeout" type="int" default="120">
70+
Request timeout in seconds
71+
</ParamField>
72+
73+
<ParamField path="max_turns" type="int" default="10">
74+
Maximum number of conversation turns with the A2A agent
75+
</ParamField>
76+
77+
<ParamField path="response_model" type="type[BaseModel]" default="None">
78+
Optional Pydantic model for requesting structured output from an A2A agent. A2A protocol does not
79+
enforce this, so an A2A agent does not need to honor this request.
80+
</ParamField>
81+
82+
<ParamField path="fail_fast" type="bool" default="True">
83+
Whether to raise an error immediately if agent connection fails. When `False`, the agent continues with available agents and informs the LLM about unavailable ones.
84+
</ParamField>
85+
86+
## Authentication
87+
88+
For A2A agents that require authentication, use one of the provided auth schemes:
89+
90+
<Tabs>
91+
<Tab title="Bearer Token">
92+
```python Code
93+
from crewai.a2a import A2AConfig
94+
from crewai.a2a.auth import BearerTokenAuth
95+
96+
agent = Agent(
97+
role="Secure Coordinator",
98+
goal="Coordinate tasks with secured agents",
99+
backstory="Manages secure agent communications",
100+
llm="gpt-4o",
101+
a2a=A2AConfig(
102+
endpoint="https://secure-agent.example.com/.well-known/agent-card.json",
103+
auth=BearerTokenAuth(token="your-bearer-token"),
104+
timeout=120
105+
)
106+
)
107+
```
108+
</Tab>
109+
110+
<Tab title="API Key">
111+
```python Code
112+
from crewai.a2a import A2AConfig
113+
from crewai.a2a.auth import APIKeyAuth
114+
115+
agent = Agent(
116+
role="API Coordinator",
117+
goal="Coordinate with API-based agents",
118+
backstory="Manages API-authenticated communications",
119+
llm="gpt-4o",
120+
a2a=A2AConfig(
121+
endpoint="https://api-agent.example.com/.well-known/agent-card.json",
122+
auth=APIKeyAuth(
123+
api_key="your-api-key",
124+
location="header", # or "query" or "cookie"
125+
name="X-API-Key"
126+
),
127+
timeout=120
128+
)
129+
)
130+
```
131+
</Tab>
132+
133+
<Tab title="OAuth2">
134+
```python Code
135+
from crewai.a2a import A2AConfig
136+
from crewai.a2a.auth import OAuth2ClientCredentials
137+
138+
agent = Agent(
139+
role="OAuth Coordinator",
140+
goal="Coordinate with OAuth-secured agents",
141+
backstory="Manages OAuth-authenticated communications",
142+
llm="gpt-4o",
143+
a2a=A2AConfig(
144+
endpoint="https://oauth-agent.example.com/.well-known/agent-card.json",
145+
auth=OAuth2ClientCredentials(
146+
token_url="https://auth.example.com/oauth/token",
147+
client_id="your-client-id",
148+
client_secret="your-client-secret",
149+
scopes=["read", "write"]
150+
),
151+
timeout=120
152+
)
153+
)
154+
```
155+
</Tab>
156+
157+
<Tab title="HTTP Basic">
158+
```python Code
159+
from crewai.a2a import A2AConfig
160+
from crewai.a2a.auth import HTTPBasicAuth
161+
162+
agent = Agent(
163+
role="Basic Auth Coordinator",
164+
goal="Coordinate with basic auth agents",
165+
backstory="Manages basic authentication communications",
166+
llm="gpt-4o",
167+
a2a=A2AConfig(
168+
endpoint="https://basic-agent.example.com/.well-known/agent-card.json",
169+
auth=HTTPBasicAuth(
170+
username="your-username",
171+
password="your-password"
172+
),
173+
timeout=120
174+
)
175+
)
176+
```
177+
</Tab>
178+
</Tabs>
179+
180+
## Multiple A2A Agents
181+
182+
Configure multiple A2A agents for delegation by passing a list:
183+
184+
```python Code
185+
from crewai.a2a import A2AConfig
186+
from crewai.a2a.auth import BearerTokenAuth
187+
188+
agent = Agent(
189+
role="Multi-Agent Coordinator",
190+
goal="Coordinate with multiple specialized agents",
191+
backstory="Expert at delegating to the right specialist",
192+
llm="gpt-4o",
193+
a2a=[
194+
A2AConfig(
195+
endpoint="https://research.example.com/.well-known/agent-card.json",
196+
timeout=120
197+
),
198+
A2AConfig(
199+
endpoint="https://data.example.com/.well-known/agent-card.json",
200+
auth=BearerTokenAuth(token="data-token"),
201+
timeout=90
202+
)
203+
]
204+
)
205+
```
206+
207+
The LLM will automatically choose which A2A agent to delegate to based on the task requirements.
208+
209+
## Error Handling
210+
211+
Control how agent connection failures are handled using the `fail_fast` parameter:
212+
213+
```python Code
214+
from crewai.a2a import A2AConfig
215+
216+
# Fail immediately on connection errors (default)
217+
agent = Agent(
218+
role="Research Coordinator",
219+
goal="Coordinate research tasks",
220+
backstory="Expert at delegation",
221+
llm="gpt-4o",
222+
a2a=A2AConfig(
223+
endpoint="https://research.example.com/.well-known/agent-card.json",
224+
fail_fast=True
225+
)
226+
)
227+
228+
# Continue with available agents
229+
agent = Agent(
230+
role="Multi-Agent Coordinator",
231+
goal="Coordinate with multiple agents",
232+
backstory="Expert at working with available resources",
233+
llm="gpt-4o",
234+
a2a=[
235+
A2AConfig(
236+
endpoint="https://primary.example.com/.well-known/agent-card.json",
237+
fail_fast=False
238+
),
239+
A2AConfig(
240+
endpoint="https://backup.example.com/.well-known/agent-card.json",
241+
fail_fast=False
242+
)
243+
]
244+
)
245+
```
246+
247+
When `fail_fast=False`:
248+
- If some agents fail, the LLM is informed which agents are unavailable and can delegate to working agents
249+
- If all agents fail, the LLM receives a notice about unavailable agents and handles the task directly
250+
- Connection errors are captured and included in the context for better decision-making
251+
252+
## Best Practices
253+
254+
<CardGroup cols={2}>
255+
<Card title="Set Appropriate Timeouts" icon="clock">
256+
Configure timeouts based on expected A2A agent response times. Longer-running tasks may need higher timeout values.
257+
</Card>
258+
259+
<Card title="Limit Conversation Turns" icon="comments">
260+
Use `max_turns` to prevent excessive back-and-forth. The agent will automatically conclude conversations before hitting the limit.
261+
</Card>
262+
263+
<Card title="Use Resilient Error Handling" icon="shield-check">
264+
Set `fail_fast=False` for production environments with multiple agents to gracefully handle connection failures and maintain workflow continuity.
265+
</Card>
266+
267+
<Card title="Secure Your Credentials" icon="lock">
268+
Store authentication tokens and credentials as environment variables, not in code.
269+
</Card>
270+
271+
<Card title="Monitor Delegation Decisions" icon="eye">
272+
Use verbose mode to observe when the LLM chooses to delegate versus handle tasks directly.
273+
</Card>
274+
</CardGroup>
275+
276+
## Supported Authentication Methods
277+
278+
- **Bearer Token** - Simple token-based authentication
279+
- **OAuth2 Client Credentials** - OAuth2 flow for machine-to-machine communication
280+
- **OAuth2 Authorization Code** - OAuth2 flow requiring user authorization
281+
- **API Key** - Key-based authentication (header, query param, or cookie)
282+
- **HTTP Basic** - Username/password authentication
283+
- **HTTP Digest** - Digest authentication (requires `httpx-auth` package)
284+
285+
## Learn More
286+
287+
For more information about the A2A protocol and reference implementations:
288+
289+
- [A2A Protocol Documentation](https://a2a-protocol.org)
290+
- [A2A Sample Implementations](https://github.com/a2aproject/a2a-samples)
291+
- [A2A Python SDK](https://github.com/a2aproject/a2a-python)

lib/crewai/pyproject.toml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,11 @@ azure-ai-inference = [
9393
anthropic = [
9494
"anthropic>=0.69.0",
9595
]
96-
# a2a = [
97-
# "a2a-sdk~=0.3.9",
98-
# "httpx-sse>=0.4.0",
99-
# ]
96+
a2a = [
97+
"a2a-sdk~=0.3.10",
98+
"httpx-auth>=0.23.1",
99+
"httpx-sse>=0.4.0",
100+
]
100101

101102

102103
[project.scripts]

lib/crewai/src/crewai/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import urllib.request
44
import warnings
55

6-
from crewai.agent import Agent
6+
from crewai.agent.core import Agent
77
from crewai.crew import Crew
88
from crewai.crews.crew_output import CrewOutput
99
from crewai.flow.flow import Flow
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
"""Agent-to-Agent (A2A) protocol communication module for CrewAI."""
2+
3+
from crewai.a2a.config import A2AConfig
4+
5+
6+
__all__ = ["A2AConfig"]
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
"""A2A authentication schemas."""
2+
3+
from crewai.a2a.auth.schemas import (
4+
APIKeyAuth,
5+
BearerTokenAuth,
6+
HTTPBasicAuth,
7+
HTTPDigestAuth,
8+
OAuth2AuthorizationCode,
9+
OAuth2ClientCredentials,
10+
)
11+
12+
13+
__all__ = [
14+
"APIKeyAuth",
15+
"BearerTokenAuth",
16+
"HTTPBasicAuth",
17+
"HTTPDigestAuth",
18+
"OAuth2AuthorizationCode",
19+
"OAuth2ClientCredentials",
20+
]

0 commit comments

Comments
 (0)