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
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ To install with gRPC support:
uv add "a2a-sdk[grpc]"
```

To install with Kafka transport support:

```bash
uv add "a2a-sdk[kafka]"
```

To install with OpenTelemetry tracing support:

```bash
Expand Down Expand Up @@ -87,6 +93,12 @@ To install with gRPC support:
pip install "a2a-sdk[grpc]"
```

To install with Kafka transport support:

```bash
pip install "a2a-sdk[kafka]"
```

To install with OpenTelemetry tracing support:

```bash
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ sqlite = ["sqlalchemy[asyncio,aiosqlite]>=2.0.0"]
sql = ["sqlalchemy[asyncio,postgresql-asyncpg,aiomysql,aiosqlite]>=2.0.0"]
encryption = ["cryptography>=43.0.0"]
grpc = ["grpcio>=1.60", "grpcio-tools>=1.60", "grpcio_reflection>=1.7.0"]
kafka = ["aiokafka>=0.11.0"]
telemetry = ["opentelemetry-api>=1.33.0", "opentelemetry-sdk>=1.33.0"]

[project.urls]
Expand Down
31 changes: 31 additions & 0 deletions src/a2a/client/client_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@
except ImportError:
GrpcTransport = None # type: ignore # pyright: ignore

try:
from a2a.client.transports.kafka import KafkaClientTransport
except ImportError:
KafkaClientTransport = None # type: ignore # pyright: ignore


logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -97,6 +102,32 @@ def _register_defaults(
TransportProtocol.grpc,
GrpcTransport.create,
)
if TransportProtocol.kafka in supported:
if KafkaClientTransport is None:
raise ImportError(
'To use KafkaClient, its dependencies must be installed. '
'You can install them with \'pip install "a2a-sdk[kafka]"\''
)
self.register(
TransportProtocol.kafka,
self._create_kafka_transport,
)

def _create_kafka_transport(
self,
card: AgentCard,
url: str,
config: ClientConfig,
interceptors: list[ClientCallInterceptor],
) -> ClientTransport:
"""Create a Kafka transport that will auto-start when first used."""
# Create the transport using the existing create method
transport = KafkaClientTransport.create(card, url, config, interceptors)

# Mark the transport for auto-start when first used
transport._auto_start = True

return transport

def register(self, label: str, generator: TransportProducer) -> None:
"""Register a new transport producer for a given transport label."""
Expand Down
6 changes: 6 additions & 0 deletions src/a2a/client/transports/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,16 @@
except ImportError:
GrpcTransport = None # type: ignore

try:
from a2a.client.transports.kafka import KafkaClientTransport
except ImportError:
KafkaClientTransport = None # type: ignore


__all__ = [
'ClientTransport',
'GrpcTransport',
'JsonRpcTransport',
'KafkaClientTransport',
'RestTransport',
]
Comment on lines 19 to 25
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid exporting KafkaClientTransport when dependency is missing.

Currently KafkaClientTransport is always listed in __all__, but may be None when Kafka deps are absent. Conditionally exporting improves DX and avoids surprising None symbols.

Apply this minimal change to avoid exporting when unavailable:

 __all__ = [
     'ClientTransport',
     'GrpcTransport',
     'JsonRpcTransport',
-    'KafkaClientTransport',
     'RestTransport',
 ]

Then append this (outside the above block) to export conditionally:

# Append conditionally to avoid exposing None when import fails
if KafkaClientTransport is not None:
    __all__.append('KafkaClientTransport')
🤖 Prompt for AI Agents
In src/a2a/client/transports/__init__.py around lines 19 to 25,
KafkaClientTransport is always included in the __all__ list even when its
dependencies are missing and it is None. To fix this, remove
'KafkaClientTransport' from the initial __all__ list and then add a conditional
statement after that block to append 'KafkaClientTransport' to __all__ only if
KafkaClientTransport is not None. This prevents exporting a None symbol and
improves developer experience.

Loading