| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| export class A2AAgentError extends Error { |
| |
| readonly userMessage: string; |
| |
| readonly agentName: string; |
|
|
| constructor( |
| agentName: string, |
| message: string, |
| userMessage: string, |
| options?: ErrorOptions, |
| ) { |
| super(message, options); |
| this.name = 'A2AAgentError'; |
| this.agentName = agentName; |
| this.userMessage = userMessage; |
| } |
| } |
|
|
| |
| |
| |
| export class AgentCardNotFoundError extends A2AAgentError { |
| constructor(agentName: string, agentCardUrl: string) { |
| const message = `Agent card not found at ${agentCardUrl} (HTTP 404)`; |
| const userMessage = `Agent card not found (404) at ${agentCardUrl}. Verify the agent_card_url in your agent definition.`; |
| super(agentName, message, userMessage); |
| this.name = 'AgentCardNotFoundError'; |
| } |
| } |
|
|
| |
| |
| |
| |
| export class AgentCardAuthError extends A2AAgentError { |
| readonly statusCode: number; |
|
|
| constructor(agentName: string, agentCardUrl: string, statusCode: 401 | 403) { |
| const statusText = statusCode === 401 ? 'Unauthorized' : 'Forbidden'; |
| const message = `Agent card request returned ${statusCode} ${statusText} for ${agentCardUrl}`; |
| const userMessage = `Authentication failed (${statusCode} ${statusText}) at ${agentCardUrl}. Check the "auth" configuration in your agent definition.`; |
| super(agentName, message, userMessage); |
| this.name = 'AgentCardAuthError'; |
| this.statusCode = statusCode; |
| } |
| } |
|
|
| |
| |
| |
| |
| export class AgentAuthConfigMissingError extends A2AAgentError { |
| |
| readonly requiredAuth: string; |
| |
| readonly missingFields: string[]; |
|
|
| constructor( |
| agentName: string, |
| requiredAuth: string, |
| missingFields: string[], |
| ) { |
| const message = `Agent "${agentName}" requires authentication but none is configured`; |
| const userMessage = `Agent requires ${requiredAuth} but no auth is configured. Missing: ${missingFields.join(', ')}`; |
| super(agentName, message, userMessage); |
| this.name = 'AgentAuthConfigMissingError'; |
| this.requiredAuth = requiredAuth; |
| this.missingFields = missingFields; |
| } |
| } |
|
|
| |
| |
| |
| |
| export class AgentConnectionError extends A2AAgentError { |
| constructor(agentName: string, agentCardUrl: string, cause: unknown) { |
| const causeMessage = cause instanceof Error ? cause.message : String(cause); |
| const message = `Failed to connect to agent "${agentName}" at ${agentCardUrl}: ${causeMessage}`; |
| const userMessage = `Connection failed for ${agentCardUrl}: ${causeMessage}`; |
| super(agentName, message, userMessage, { cause }); |
| this.name = 'AgentConnectionError'; |
| } |
| } |
|
|
| |
| interface ErrorLikeObject { |
| message?: string; |
| code?: string; |
| status?: number; |
| statusCode?: number; |
| cause?: unknown; |
| } |
|
|
| |
| function isErrorLikeObject(val: unknown): val is ErrorLikeObject { |
| return typeof val === 'object' && val !== null; |
| } |
|
|
| |
| |
| |
| |
| |
| function collectErrorMessages(error: unknown): string { |
| const parts: string[] = []; |
| let current: unknown = error; |
| let depth = 0; |
| const maxDepth = 10; |
|
|
| while (current && depth < maxDepth) { |
| if (isErrorLikeObject(current)) { |
| |
| const obj = current; |
|
|
| if (current instanceof Error) { |
| parts.push(current.message); |
| } else if (typeof obj.message === 'string') { |
| parts.push(obj.message); |
| } |
|
|
| if (typeof obj.code === 'string') { |
| parts.push(obj.code); |
| } |
|
|
| if (typeof obj.status === 'number') { |
| parts.push(String(obj.status)); |
| } else if (typeof obj.statusCode === 'number') { |
| parts.push(String(obj.statusCode)); |
| } |
|
|
| current = obj.cause; |
| } else if (typeof current === 'string') { |
| parts.push(current); |
| break; |
| } else { |
| parts.push(String(current)); |
| break; |
| } |
| depth++; |
| } |
|
|
| return parts.join(' '); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| export function classifyAgentError( |
| agentName: string, |
| agentCardUrl: string, |
| error: unknown, |
| ): A2AAgentError { |
| |
| const fullErrorText = collectErrorMessages(error); |
|
|
| |
| |
| |
| if ( |
| /\b(ECONNREFUSED|ENOTFOUND|EHOSTUNREACH|ETIMEDOUT)\b/i.test(fullErrorText) |
| ) { |
| return new AgentConnectionError(agentName, agentCardUrl, error); |
| } |
|
|
| |
| if (/\b404\b|\bnot[\s_-]?found\b/i.test(fullErrorText)) { |
| return new AgentCardNotFoundError(agentName, agentCardUrl); |
| } |
|
|
| if (/\b401\b|unauthorized/i.test(fullErrorText)) { |
| return new AgentCardAuthError(agentName, agentCardUrl, 401); |
| } |
|
|
| if (/\b403\b|forbidden/i.test(fullErrorText)) { |
| return new AgentCardAuthError(agentName, agentCardUrl, 403); |
| } |
|
|
| |
| return new AgentConnectionError(agentName, agentCardUrl, error); |
| } |
|
|