* Resolve (and cache) an agent card. The card is resolved by trying the SDK * default well-known path, the legacy pre-0.3 path, and finally the URL itself * (some agents serve the card at the same URL they serve requests). Resolution * uses a short timeout so a hanging agent fails fast; successfu
( agentUrl: string, resolvedIP: string, signal?: AbortSignal )
| 157 | * cached per URL so subsequent operations skip the discovery round-trips. |
| 158 | */ |
| 159 | async function resolveAgentCard( |
| 160 | agentUrl: string, |
| 161 | resolvedIP: string, |
| 162 | signal?: AbortSignal |
| 163 | ): Promise<AgentCard> { |
| 164 | const cached = getCachedCard(agentUrl) |
| 165 | if (cached) return cached |
| 166 | |
| 167 | const resolver = new DefaultAgentCardResolver({ |
| 168 | fetchImpl: createPinnedFetch(resolvedIP, { timeout: CARD_RESOLUTION_TIMEOUT_MS, signal }), |
| 169 | }) |
| 170 | let lastError: unknown |
| 171 | for (const path of CARD_CANDIDATE_PATHS) { |
| 172 | try { |
| 173 | const card = await resolver.resolve(agentUrl, path) |
| 174 | cacheCard(agentUrl, card) |
| 175 | return card |
| 176 | } catch (error) { |
| 177 | lastError = error |
| 178 | logger.debug('Agent card resolution failed', { |
| 179 | agentUrl, |
| 180 | path, |
| 181 | error: toError(error).message, |
| 182 | }) |
| 183 | } |
| 184 | } |
| 185 | throw toError(lastError) |
| 186 | } |
| 187 | |
| 188 | /** |
| 189 | * Create an A2A client for an external agent URL. The URL is validated against |
no test coverage detected