Thank you for your interest in contributing to the A2A Adapters project! 🎉
This document provides guidelines and instructions for contributing. Whether you're fixing bugs, adding features, improving documentation, or creating new adapters, your contributions are welcome and appreciated!
- Code of Conduct
- How to Contribute
- Development Setup
- Coding Standards
- Pull Request Process
- Adding New Adapters
- Release Process
This project adheres to a code of conduct. By participating, you are expected to:
- Be respectful and considerate in your interactions
- Welcome newcomers and help them learn
- Focus on what is best for the community
- Show empathy towards other community members
We are committed to providing a welcoming and inspiring community for all.
Before reporting a bug:
- ✅ Check if the bug has already been reported in Issues
- ✅ Search closed issues - it might have been fixed already
- ✅ Try to reproduce the bug with the latest version
When creating a bug report, include:
- Clear title - Summarize the issue in one line
- Description - What happened vs what you expected
- Steps to reproduce - Minimal code example that demonstrates the bug
- Environment details:
- Python version (
python --version) - OS and version
- Package version (
pip show a2a-adapter) - Framework versions (if applicable)
- Python version (
- Error messages - Full traceback if available
- Screenshots - If applicable
Example bug report:
**Describe the bug**
The n8n adapter times out after 10 seconds even when timeout is set to 60.
**To Reproduce**
```python
adapter = await load_a2a_agent({
"adapter": "n8n",
"webhook_url": "...",
"timeout": 60
})
```Expected behavior Should wait up to 60 seconds before timing out.
Environment
- Python 3.11.5
- macOS 14.0
- a2a-adapter 0.1.0
### Suggesting Features
**Before suggesting a feature:**
1. ✅ Check [Issues](https://github.com/hybroai/a2a-adapter/issues) for existing feature requests
2. ✅ Consider if it fits the project's scope (A2A protocol adapter SDK)
3. ✅ Think about the API design and backward compatibility
**When suggesting a feature, include:**
- **Use case** - Why is this feature needed?
- **Proposed API** - How would users interact with it?
- **Implementation approach** - High-level design (optional)
- **Alternatives considered** - Other ways to solve the problem
- **Impact** - Breaking changes? New dependencies?
**Example feature request:**
```markdown
**Feature: AutoGen Adapter**
**Use case**
Enable AutoGen multi-agent systems to communicate via A2A protocol.
**Proposed API**
```python
adapter = await load_a2a_agent({
"adapter": "autogen",
"group_chat": autogen_group_chat_instance
})
Benefits
- Enables AutoGen agents in A2A ecosystems
- Follows existing adapter pattern
### Adding a New Framework Adapter
We welcome adapters for new agent frameworks! Here's how to add one:
#### 1. Create the Adapter File
Create `a2a_adapter/integrations/{framework}.py`:
```python
"""
{Framework} adapter for A2A Protocol.
"""
from ..base_adapter import AdapterMetadata, BaseA2AAdapter
class {Framework}Adapter(BaseA2AAdapter):
"""
Adapter for integrating {Framework} with A2A Protocol.
"""
def __init__(self, ..., name="", description=""):
# Initialize with framework-specific config
self._name = name
self._description = description
async def invoke(self, user_input: str, context_id: str | None = None, **kwargs) -> str:
# Call the framework and return a text response
result = await call_my_framework(user_input)
return str(result)
# Optional: streaming support
async def stream(self, user_input: str, context_id: str | None = None, **kwargs):
async for chunk in my_framework_stream(user_input):
yield str(chunk)
# Optional: metadata for AgentCard
def get_metadata(self) -> AdapterMetadata:
return AdapterMetadata(
name=self._name or "{Framework}Adapter",
description=self._description,
streaming=self.supports_streaming(),
)
# Optional: resource cleanup
async def close(self) -> None:
await self._client.aclose()
Add your adapter to the _BUILTIN_MAP in a2a_adapter/loader.py:
_BUILTIN_MAP = {
...
"{framework}": ("a2a_adapter.integrations.{framework}", "{Framework}Adapter"),
}Add to a2a_adapter/integrations/__init__.py:
__all__ = [
...,
"{Framework}Adapter",
]
def __getattr__(name: str):
...
elif name == "{Framework}Adapter":
from .{framework} import {Framework}Adapter
return {Framework}Adapter
...Add optional dependency:
[project.optional-dependencies]
{framework} = ["{framework}>=X.Y.Z"]Create examples/{framework}_agent.py:
"""
Example: {Framework} Agent Server
"""
from a2a_adapter import {Framework}Adapter, serve_agent
adapter = {Framework}Adapter(
# ... config ...
name="{Framework} Agent",
description="...",
)
serve_agent(adapter, port=800X)Create tests/unit/test_{framework}_adapter.py:
"""
Unit tests for {Framework}Adapter.
"""
import pytest
from a2a_adapter.integrations.{framework} import {Framework}Adapter
class TestInvoke:
@pytest.mark.asyncio
async def test_basic(self):
adapter = {Framework}Adapter(...)
result = await adapter.invoke("Hello")
assert isinstance(result, str)
class TestMetadata:
def test_default_metadata(self):
adapter = {Framework}Adapter(...)
meta = adapter.get_metadata()
assert meta.name- Add row to framework support table in README.md
- Document configuration options
- Add to loader documentation
Before submitting:
- ✅ Fork the repository
- ✅ Create a feature branch (
git checkout -b feature/amazing-feature) - ✅ Make your changes
- ✅ Run tests (
pytest) - ✅ Run linters (
black .,ruff check .) - ✅ Update documentation if needed
- ✅ Ensure all tests pass
PR Process:
- Push to your fork (
git push origin feature/amazing-feature) - Open a Pull Request on GitHub
- Fill out the PR template (see below)
- Wait for review - Maintainers will review your PR
- Address feedback - Make requested changes
- Get approval - Once approved, your PR will be merged!
When opening a PR, use this template:
## Description
Brief description of what this PR does.
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Related Issues
Fixes #123
Related to #456
## Testing
- [ ] Added tests for new functionality
- [ ] All existing tests pass
- [ ] Tested manually with examples
## Checklist
- [ ] Code follows project style guidelines
- [ ] Self-review completed
- [ ] Comments added for complex code
- [ ] Documentation updated
- [ ] No new warnings generated
- [ ] Tests added/updated- ✅ Keep changes focused - One feature/fix per PR
- ✅ Include tests - New functionality must have tests
- ✅ Update docs - README, docstrings, or examples
- ✅ Ensure tests pass - All CI checks must pass
- ✅ Follow code style - Use Black, Ruff, and type hints
- ✅ Write clear commits - Use conventional commit format
- ✅ Keep PRs small - Easier to review and merge
git clone git@github.com:hybroai/a2a-adapter.git
cd a2a-adapterpython -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate# Install package in editable mode with all dependencies
pip install -e ".[all,dev]"# Run all tests
pytest
# Run with coverage
pytest --cov=a2a_adapter --cov-report=html
# Run specific test file
pytest tests/unit/test_adapter.py
# Run with verbose output
pytest -v# Format code with Black
black a2a_adapter/ examples/ tests/
# Check with Ruff
ruff check a2a_adapter/ examples/ tests/
# Type checking with mypy
mypy a2a_adapter/a2a-adapter/
├── a2a_adapter/ # Main package
│ ├── __init__.py # Package exports + lazy imports
│ ├── base_adapter.py # BaseA2AAdapter + AdapterMetadata
│ ├── executor.py # AdapterAgentExecutor (bridge)
│ ├── server.py # to_a2a() / serve_agent() / build_agent_card()
│ ├── loader.py # load_adapter() / register_adapter()
│ ├── adapter.py # [deprecated] v0.1 BaseAgentAdapter
│ ├── client.py # [deprecated] v0.1 server helpers
│ └── integrations/ # Framework adapters
│ ├── n8n.py
│ ├── crewai.py
│ ├── langchain.py
│ ├── langgraph.py
│ ├── ollama.py # OllamaClient + OllamaAdapter
│ ├── openclaw.py
│ └── callable.py
├── examples/ # Usage examples
├── tests/ # Test suite
│ ├── unit/ # Unit tests
│ └── integration/ # Integration tests
├── pyproject.toml # Package configuration
├── README.md # User documentation
├── ARCHITECTURE.md # Technical documentation
└── CONTRIBUTING.md # This file
- Follow PEP 8
- Use Black for formatting (line length: 100)
- Use type hints where possible
- Write docstrings for public APIs (Google style)
def function_name(param1: str, param2: int) -> bool:
"""
Short description of function.
Longer description if needed, explaining the purpose,
behavior, and any important details.
Args:
param1: Description of param1
param2: Description of param2
Returns:
Description of return value
Raises:
ValueError: When something goes wrong
Example:
>>> result = function_name("test", 42)
>>> print(result)
True
"""
pass- Write tests for all new functionality
- Aim for >80% code coverage
- Use pytest fixtures for common setup
- Mock external dependencies (HTTP calls, framework APIs)
- Test both success and error cases
Follow Conventional Commits format:
type(scope): brief description
Longer explanation if needed
Fixes #123
Commit Types:
feat- New featurefix- Bug fixdocs- Documentation changesstyle- Code style changes (formatting, etc.)refactor- Code refactoringtest- Adding or updating testschore- Maintenance tasksperf- Performance improvementsci- CI/CD changes
Scopes: n8n, crewai, langchain, callable, loader, client, docs, tests, etc.
Good Examples:
feat(langchain): add streaming support
fix(n8n): handle timeout errors properly
docs(readme): update installation instructions
test(adapter): add tests for error handling
refactor(loader): simplify adapter loading logicBad Examples:
# Too vague
fix: bug fix
update: changes
# Missing scope
feat: add new feature
# Not following format
Fixed the bug in n8n adapter(For maintainers only)
- All tests passing
- Documentation updated
- CHANGELOG.md updated
- Version bumped in
pyproject.tomlanda2a_adapter/__init__.py - Release notes prepared
-
Update version
# Update pyproject.toml version = "0.1.1" # Update a2a_adapter/__init__.py __version__ = "0.1.1"
-
Update CHANGELOG.md
## [0.1.1] - 2024-01-15 - Added: New feature X - Fixed: Bug Y
-
Create release commit
git add pyproject.toml a2a_adapter/__init__.py CHANGELOG.md git commit -m "chore: release v0.1.1" -
Create and push tag
git tag v0.1.1 git push origin main --tags
-
Build and publish to PyPI
python -m build twine upload dist/* -
Create GitHub Release
- Go to GitHub Releases
- Create new release from tag
- Copy CHANGELOG entry
- Publish release
We follow Semantic Versioning:
- MAJOR - Breaking changes
- MINOR - New features (backward compatible)
- PATCH - Bug fixes (backward compatible)
Need help? We're here for you!
- 📚 Documentation - Read README.md and ARCHITECTURE.md
- 🐛 Issues - Check existing issues or create a new one
- 💬 Discussions - Ask questions in GitHub Discussions
- 📧 Contact - Reach out to maintainers via GitHub
We recommend creating GitHub issue and PR templates for better organization:
**Describe the bug**
A clear description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior.
**Expected behavior**
What you expected to happen.
**Environment**
- Python version:
- OS:
- Package version:
- Framework versions:
**Additional context**
Any other relevant information.**Is your feature request related to a problem?**
A clear description of the problem.
**Describe the solution you'd like**
A clear description of what you want to happen.
**Describe alternatives you've considered**
Other solutions or features you've considered.
**Additional context**
Any other relevant information.By contributing, you agree that your contributions will be licensed under the Apache License 2.0.
Contributors will be:
- Listed in the README (if desired)
- Credited in release notes
- Appreciated by the community! 🎉
Thank you for contributing to A2A Adapters! 🎉
Your contributions make this project better for everyone. We appreciate your time and effort!