Skip to content

Commit ee8476e

Browse files
committed
Spelling/formatting
1 parent 6db2b51 commit ee8476e

File tree

8 files changed

+313
-163
lines changed

8 files changed

+313
-163
lines changed

.github/actions/spelling/allow.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,12 @@ langgraph
3636
lifecycles
3737
linting
3838
oauthoidc
39+
oidc
3940
opensource
4041
protoc
4142
pyi
4243
pyversions
44+
respx
4345
socio
4446
sse
4547
tagwords

src/a2a/client/__init__.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
22

33
"""Client-side components for interacting with an A2A agent."""
44

5-
from a2a.client.auth import (AuthInterceptor, CredentialService,
6-
InMemoryContextCredentialStore)
5+
from a2a.client.auth import (
6+
AuthInterceptor,
7+
CredentialService,
8+
InMemoryContextCredentialStore,
9+
)
710
from a2a.client.client import A2ACardResolver, A2AClient
811
from a2a.client.errors import (
912
A2AClientError,
@@ -14,17 +17,18 @@
1417
from a2a.client.helpers import create_text_message_object
1518
from a2a.client.middleware import ClientCallContext, ClientCallInterceptor
1619

20+
1721
__all__ = [
1822
'A2ACardResolver',
1923
'A2AClient',
2024
'A2AClientError',
2125
'A2AClientHTTPError',
2226
'A2AClientJSONError',
27+
'A2AGrpcClient',
2328
'AuthInterceptor',
2429
'ClientCallContext',
2530
'ClientCallInterceptor',
2631
'CredentialService',
2732
'InMemoryContextCredentialStore',
28-
'A2AGrpcClient',
2933
'create_text_message_object',
30-
]
34+
]

src/a2a/client/auth/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
from .credentials import CredentialService, InMemoryContextCredentialStore
44
from .interceptor import AuthInterceptor
55

6+
67
__all__ = [
8+
'AuthInterceptor',
79
'CredentialService',
810
'InMemoryContextCredentialStore',
9-
'AuthInterceptor',
10-
]
11+
]

src/a2a/client/auth/credentials.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,10 @@ async def get_credentials(
1717
"""
1818
Retrieves a credential (e.g., token) for a security scheme.
1919
"""
20-
pass
2120

2221

2322
class InMemoryContextCredentialStore(CredentialService):
24-
"""
25-
A simple in-memory store for session-keyed credentials.
23+
"""A simple in-memory store for session-keyed credentials.
2624
2725
This class uses the 'sessionId' from the ClientCallContext state to
2826
store and retrieve credentials...
@@ -48,4 +46,4 @@ async def set_credential(
4846
"""Method to populate the store."""
4947
if session_id not in self._store:
5048
self._store[session_id] = {}
51-
self._store[session_id][security_scheme_name] = credential
49+
self._store[session_id][security_scheme_name] = credential

src/a2a/client/auth/interceptor.py

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,26 @@
11
# a2a/client/auth/interceptor.py
22

33
import logging
4+
45
from typing import Any
56

67
from a2a.client.auth.credentials import CredentialService
78
from a2a.client.middleware import ClientCallContext, ClientCallInterceptor
8-
from a2a.types import (AgentCard, APIKeySecurityScheme, HTTPAuthSecurityScheme,
9-
In, OAuth2SecurityScheme, OpenIdConnectSecurityScheme)
9+
from a2a.types import (
10+
APIKeySecurityScheme,
11+
AgentCard,
12+
HTTPAuthSecurityScheme,
13+
In,
14+
OAuth2SecurityScheme,
15+
OpenIdConnectSecurityScheme,
16+
)
17+
1018

1119
logger = logging.getLogger(__name__)
1220

1321

1422
class AuthInterceptor(ClientCallInterceptor):
15-
"""
16-
An interceptor that automatically adds authentication details to requests
23+
"""An interceptor that automatically adds authentication details to requests
1724
based on the agent's security schemes.
1825
"""
1926

@@ -28,39 +35,51 @@ async def intercept(
2835
agent_card: AgentCard | None,
2936
context: ClientCallContext | None,
3037
) -> tuple[dict[str, Any], dict[str, Any]]:
31-
if not agent_card or not agent_card.security or not agent_card.securitySchemes:
38+
if (
39+
not agent_card
40+
or not agent_card.security
41+
or not agent_card.securitySchemes
42+
):
3243
return request_payload, http_kwargs
3344

3445
for requirement in agent_card.security:
35-
for scheme_name in requirement:
46+
for scheme_name in requirement:
3647
credential = await self._credential_service.get_credentials(
3748
scheme_name, context
3849
)
3950
if credential and scheme_name in agent_card.securitySchemes:
4051
scheme_def_union = agent_card.securitySchemes[scheme_name]
41-
if not scheme_def_union:
52+
if not scheme_def_union:
4253
continue
43-
scheme_def = scheme_def_union.root
54+
scheme_def = scheme_def_union.root
4455

4556
headers = http_kwargs.get('headers', {})
4657

4758
is_bearer_scheme = False
48-
if isinstance(scheme_def, HTTPAuthSecurityScheme) and scheme_def.scheme.lower() == 'bearer':
49-
is_bearer_scheme = True
50-
elif isinstance(scheme_def, (OAuth2SecurityScheme, OpenIdConnectSecurityScheme)):
59+
if (
60+
isinstance(scheme_def, HTTPAuthSecurityScheme)
61+
and scheme_def.scheme.lower() == 'bearer'
62+
) or isinstance(
63+
scheme_def,
64+
(OAuth2SecurityScheme, OpenIdConnectSecurityScheme),
65+
):
5166
is_bearer_scheme = True
5267

5368
if is_bearer_scheme:
54-
headers['Authorization'] = f"Bearer {credential}"
55-
logger.debug(f"Added Bearer token for scheme '{scheme_name}' (type: {scheme_def.type}).")
69+
headers['Authorization'] = f'Bearer {credential}'
70+
logger.debug(
71+
f"Added Bearer token for scheme '{scheme_name}' (type: {scheme_def.type})."
72+
)
5673
http_kwargs['headers'] = headers
5774
return request_payload, http_kwargs
58-
elif isinstance(scheme_def, APIKeySecurityScheme):
59-
if scheme_def.in_ == In.header:
75+
if isinstance(scheme_def, APIKeySecurityScheme):
76+
if scheme_def.in_ == In.header:
6077
headers[scheme_def.name] = credential
61-
logger.debug(f"Added API Key Header for scheme '{scheme_name}'.")
78+
logger.debug(
79+
f"Added API Key Header for scheme '{scheme_name}'."
80+
)
6281
http_kwargs['headers'] = headers
6382
return request_payload, http_kwargs
6483
# Note: API keys in query or cookie are not handled here.
65-
66-
return request_payload, http_kwargs
84+
85+
return request_payload, http_kwargs

src/a2a/client/client.py

Lines changed: 50 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,35 @@
11
import json
22
import logging
3+
34
from collections.abc import AsyncGenerator
45
from typing import Any
56
from uuid import uuid4
67

78
import httpx
9+
810
from httpx_sse import SSEError, aconnect_sse
911
from pydantic import ValidationError
1012

1113
from a2a.client.errors import A2AClientHTTPError, A2AClientJSONError
1214
from a2a.client.middleware import ClientCallContext, ClientCallInterceptor
13-
from a2a.types import (AgentCard, CancelTaskRequest, CancelTaskResponse,
14-
GetTaskPushNotificationConfigRequest,
15-
GetTaskPushNotificationConfigResponse, GetTaskRequest,
16-
GetTaskResponse, SendMessageRequest,
17-
SendMessageResponse, SendStreamingMessageRequest,
18-
SendStreamingMessageResponse,
19-
SetTaskPushNotificationConfigRequest,
20-
SetTaskPushNotificationConfigResponse)
15+
from a2a.types import (
16+
AgentCard,
17+
CancelTaskRequest,
18+
CancelTaskResponse,
19+
GetTaskPushNotificationConfigRequest,
20+
GetTaskPushNotificationConfigResponse,
21+
GetTaskRequest,
22+
GetTaskResponse,
23+
SendMessageRequest,
24+
SendMessageResponse,
25+
SendStreamingMessageRequest,
26+
SendStreamingMessageResponse,
27+
SetTaskPushNotificationConfigRequest,
28+
SetTaskPushNotificationConfigResponse,
29+
)
2130
from a2a.utils.telemetry import SpanKind, trace_class
2231

32+
2333
logger = logging.getLogger(__name__)
2434

2535

@@ -157,15 +167,18 @@ async def _apply_interceptors(
157167
final_request_payload = request_payload
158168

159169
for interceptor in self.interceptors:
160-
final_request_payload, final_http_kwargs = await interceptor.intercept(
170+
(
171+
final_request_payload,
172+
final_http_kwargs,
173+
) = await interceptor.intercept(
161174
method_name,
162175
final_request_payload,
163176
final_http_kwargs,
164177
self.agent_card,
165178
context,
166179
)
167180
return final_request_payload, final_http_kwargs
168-
181+
169182
@staticmethod
170183
async def get_client_from_agent_card_url(
171184
httpx_client: httpx.AsyncClient,
@@ -224,10 +237,13 @@ async def send_message(
224237
"""
225238
if not request.id:
226239
request.id = str(uuid4())
227-
240+
228241
# Apply interceptors before sending
229242
payload, modified_kwargs = await self._apply_interceptors(
230-
'message/send', request.model_dump(mode='json', exclude_none=True), http_kwargs, context
243+
'message/send',
244+
request.model_dump(mode='json', exclude_none=True),
245+
http_kwargs,
246+
context,
231247
)
232248
response_data = await self._send_request(payload, modified_kwargs)
233249
return SendMessageResponse(response_data)
@@ -261,9 +277,12 @@ async def send_message_streaming(
261277

262278
# Apply interceptors before sending
263279
payload, modified_kwargs = await self._apply_interceptors(
264-
'message/stream', request.model_dump(mode='json', exclude_none=True), http_kwargs, context
280+
'message/stream',
281+
request.model_dump(mode='json', exclude_none=True),
282+
http_kwargs,
283+
context,
265284
)
266-
285+
267286
modified_kwargs.setdefault('timeout', None)
268287

269288
async with aconnect_sse(
@@ -345,10 +364,13 @@ async def get_task(
345364
"""
346365
if not request.id:
347366
request.id = str(uuid4())
348-
367+
349368
# Apply interceptors before sending
350369
payload, modified_kwargs = await self._apply_interceptors(
351-
'tasks/get', request.model_dump(mode='json', exclude_none=True), http_kwargs, context
370+
'tasks/get',
371+
request.model_dump(mode='json', exclude_none=True),
372+
http_kwargs,
373+
context,
352374
)
353375
response_data = await self._send_request(payload, modified_kwargs)
354376
return GetTaskResponse(response_data)
@@ -386,7 +408,10 @@ async def cancel_task(
386408

387409
# Apply interceptors before sending
388410
payload, modified_kwargs = await self._apply_interceptors(
389-
'tasks/cancel', request.model_dump(mode='json', exclude_none=True), http_kwargs, context
411+
'tasks/cancel',
412+
request.model_dump(mode='json', exclude_none=True),
413+
http_kwargs,
414+
context,
390415
)
391416
response_data = await self._send_request(payload, modified_kwargs)
392417
return CancelTaskResponse(response_data)
@@ -417,7 +442,10 @@ async def set_task_callback(
417442

418443
# Apply interceptors before sending
419444
payload, modified_kwargs = await self._apply_interceptors(
420-
'tasks/pushNotificationConfig/set', request.model_dump(mode='json', exclude_none=True), http_kwargs, context
445+
'tasks/pushNotificationConfig/set',
446+
request.model_dump(mode='json', exclude_none=True),
447+
http_kwargs,
448+
context,
421449
)
422450
response_data = await self._send_request(payload, modified_kwargs)
423451
return SetTaskPushNotificationConfigResponse(response_data)
@@ -448,7 +476,10 @@ async def get_task_callback(
448476

449477
# Apply interceptors before sending
450478
payload, modified_kwargs = await self._apply_interceptors(
451-
'tasks/pushNotificationConfig/get', request.model_dump(mode='json', exclude_none=True), http_kwargs, context
479+
'tasks/pushNotificationConfig/get',
480+
request.model_dump(mode='json', exclude_none=True),
481+
http_kwargs,
482+
context,
452483
)
453484
response_data = await self._send_request(payload, modified_kwargs)
454485
return GetTaskPushNotificationConfigResponse(response_data)

src/a2a/client/middleware.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
from abc import ABC, abstractmethod
2-
from typing import Any, MutableMapping
2+
from collections.abc import MutableMapping
3+
from typing import Any
34

45
from pydantic import BaseModel, Field
56

67
from a2a.types import AgentCard
78

89

910
class ClientCallContext(BaseModel):
10-
"""
11-
A context passed with each client call, allowing for call-specific
11+
"""A context passed with each client call, allowing for call-specific
1212
configuration and data passing, such as authentication details or
1313
request deadlines.
1414
"""
15+
1516
state: MutableMapping[str, Any] = Field(default_factory=dict)
1617

1718

1819
class ClientCallInterceptor(ABC):
19-
"""
20-
An abstract base class for client-side call interceptors.
20+
"""An abstract base class for client-side call interceptors.
2121
2222
Interceptors can inspect and modify requests before they are sent,
2323
which is ideal for concerns like authentication, logging, or tracing.
@@ -29,8 +29,8 @@ async def intercept(
2929
method_name: str,
3030
request_payload: dict[str, Any],
3131
http_kwargs: dict[str, Any],
32-
agent_card: "AgentCard | None",
33-
context: "ClientCallContext | None",
32+
agent_card: 'AgentCard | None',
33+
context: 'ClientCallContext | None',
3434
) -> tuple[dict[str, Any], dict[str, Any]]:
3535
"""
3636
Intercepts a client call before the request is sent.
@@ -46,4 +46,3 @@ async def intercept(
4646
A tuple containing the (potentially modified) request_payload
4747
and http_kwargs.
4848
"""
49-
pass

0 commit comments

Comments
 (0)