11import dataclasses
2- import json
32import logging
43
54from abc import ABC , abstractmethod
65from collections .abc import AsyncIterator , Callable , Coroutine
7- from typing import TYPE_CHECKING , Any
6+ from typing import Any
87
98import httpx
109
11- from pydantic import ValidationError
12-
13-
14- # Attempt to import the optional module
15- try :
16- from grpc .aio import Channel
17- except ImportError :
18- # If grpc.aio is not available, define a dummy type for type checking.
19- # This dummy type will only be used by type checkers.
20- if TYPE_CHECKING :
21-
22- class Channel : # type: ignore[no-redef]
23- """Dummy class for type hinting when grpc.aio is not available."""
24-
25- else :
26- Channel = None # At runtime, pd will be None if the import failed.
27-
28- from a2a .client .errors import (
29- A2AClientHTTPError ,
30- A2AClientJSONError ,
31- )
3210from a2a .client .middleware import ClientCallContext , ClientCallInterceptor
11+ from a2a .client .optionals import Channel
3312from a2a .types import (
3413 AgentCard ,
3514 GetTaskPushNotificationConfigParams ,
@@ -43,100 +22,11 @@ class Channel: # type: ignore[no-redef]
4322 TaskStatusUpdateEvent ,
4423 TransportProtocol ,
4524)
46- from a2a .utils .constants import AGENT_CARD_WELL_KNOWN_PATH
4725
4826
4927logger = logging .getLogger (__name__ )
5028
5129
52- class A2ACardResolver :
53- """Agent Card resolver."""
54-
55- def __init__ (
56- self ,
57- httpx_client : httpx .AsyncClient ,
58- base_url : str ,
59- agent_card_path : str = AGENT_CARD_WELL_KNOWN_PATH ,
60- ) -> None :
61- """Initializes the A2ACardResolver.
62-
63- Args:
64- httpx_client: An async HTTP client instance (e.g., httpx.AsyncClient).
65- base_url: The base URL of the agent's host.
66- agent_card_path: The path to the agent card endpoint, relative to the base URL.
67- """
68- self .base_url = base_url .rstrip ('/' )
69- self .agent_card_path = agent_card_path .lstrip ('/' )
70- self .httpx_client = httpx_client
71-
72- async def get_agent_card (
73- self ,
74- relative_card_path : str | None = None ,
75- http_kwargs : dict [str , Any ] | None = None ,
76- ) -> AgentCard :
77- """Fetches an agent card from a specified path relative to the base_url.
78-
79- If relative_card_path is None, it defaults to the resolver's configured
80- agent_card_path (for the public agent card).
81-
82- Args:
83- relative_card_path: Optional path to the agent card endpoint,
84- relative to the base URL. If None, uses the default public
85- agent card path.
86- http_kwargs: Optional dictionary of keyword arguments to pass to the
87- underlying httpx.get request.
88-
89- Returns:
90- An `AgentCard` object representing the agent's capabilities.
91-
92- Raises:
93- A2AClientHTTPError: If an HTTP error occurs during the request.
94- A2AClientJSONError: If the response body cannot be decoded as JSON
95- or validated against the AgentCard schema.
96- """
97- if relative_card_path is None :
98- # Use the default public agent card path configured during initialization
99- path_segment = self .agent_card_path
100- else :
101- path_segment = relative_card_path .lstrip ('/' )
102-
103- target_url = f'{ self .base_url } /{ path_segment } '
104-
105- try :
106- response = await self .httpx_client .get (
107- target_url ,
108- ** (http_kwargs or {}),
109- )
110- response .raise_for_status ()
111- agent_card_data = response .json ()
112- logger .info (
113- 'Successfully fetched agent card data from %s: %s' ,
114- target_url ,
115- agent_card_data ,
116- )
117- agent_card = AgentCard .model_validate (agent_card_data )
118- except httpx .HTTPStatusError as e :
119- raise A2AClientHTTPError (
120- e .response .status_code ,
121- f'Failed to fetch agent card from { target_url } : { e } ' ,
122- ) from e
123- except json .JSONDecodeError as e :
124- raise A2AClientJSONError (
125- f'Failed to parse JSON for agent card from { target_url } : { e } '
126- ) from e
127- except httpx .RequestError as e :
128- raise A2AClientHTTPError (
129- 503 ,
130- f'Network communication error fetching agent card from { target_url } : { e } ' ,
131- ) from e
132- except ValidationError as e : # Pydantic validation error
133- raise A2AClientJSONError (
134- f'Failed to validate agent card structure from { target_url } : { e .json ()} '
135- ) from e
136-
137- return agent_card
138-
139-
14030@dataclasses .dataclass
14131class ClientConfig :
14232 """Configuration class for the A2AClient Factory."""
0 commit comments