| 78 | } |
| 79 | |
| 80 | private async tryA2A(agent: Agent, startTime: number): Promise<AgentHealth> { |
| 81 | try { |
| 82 | // Check for A2A agent card at /.well-known/agent.json |
| 83 | const agentCardUrl = `${agent.url.replace(/\/$/, "")}/.well-known/agent.json`; |
| 84 | const response = await fetch(agentCardUrl, { |
| 85 | headers: { 'User-Agent': AAO_UA_HEALTH_CHECK }, |
| 86 | signal: AbortSignal.timeout(5000), |
| 87 | }); |
| 88 | |
| 89 | if (!response.ok) { |
| 90 | return { |
| 91 | online: false, |
| 92 | checked_at: new Date().toISOString(), |
| 93 | error: `A2A agent card not found (HTTP ${response.status})`, |
| 94 | }; |
| 95 | } |
| 96 | |
| 97 | const agentCard = (await response.json()) as any; |
| 98 | const responseTime = Date.now() - startTime; |
| 99 | |
| 100 | // Agent card exists, agent supports A2A |
| 101 | const toolsCount = agentCard.tools?.length || agentCard.capabilities?.length || 0; |
| 102 | |
| 103 | return { |
| 104 | online: true, |
| 105 | checked_at: new Date().toISOString(), |
| 106 | response_time_ms: responseTime, |
| 107 | tools_count: toolsCount, |
| 108 | }; |
| 109 | } catch (error) { |
| 110 | return { |
| 111 | online: false, |
| 112 | checked_at: new Date().toISOString(), |
| 113 | error: error instanceof Error ? error.message : "A2A connection failed", |
| 114 | }; |
| 115 | } |
| 116 | } |
| 117 | |
| 118 | async getStats(agent: Agent): Promise<AgentStats> { |
| 119 | const cached = this.statsCache.get(agent.url); |