Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 26 additions & 36 deletions src/client/transports/json_rpc_transport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,8 @@ export class JsonRpcTransport implements Transport {

const rpcResponse: JSONRPCResponse = await httpResponse.json();
if (rpcResponse.id !== requestId) {
console.error(
`CRITICAL: RPC response ID mismatch for method ${method}. Expected ${requestId}, got ${rpcResponse.id}.`
throw new Error(
`JSON-RPC response ID mismatch for method ${method}. Expected ${requestId}, got ${rpcResponse.id}.`
);
Comment thread
ishymko marked this conversation as resolved.
}

Expand Down Expand Up @@ -316,46 +316,36 @@ export class JsonRpcTransport implements Transport {
if (!jsonData.trim()) {
throw new Error('Attempted to process empty SSE event data.');
}
try {
const sseJsonRpcResponse = JSON.parse(jsonData);
const a2aStreamResponse: JSONRPCResponse = sseJsonRpcResponse as JSONRPCResponse;

if (a2aStreamResponse.id !== originalRequestId) {
console.warn(
`SSE Event's JSON-RPC response ID mismatch. Client request ID: ${originalRequestId}, event response ID: ${a2aStreamResponse.id}.`
);
}

if ('error' in a2aStreamResponse) {
const err = a2aStreamResponse.error;
throw new Error(
`SSE event contained an error: ${err.message} (Code: ${err.code}) Data: ${JSON.stringify(err.data || {})}`,
{ cause: JsonRpcTransport.mapToError(a2aStreamResponse) }
);
}

if (!('result' in a2aStreamResponse) || typeof a2aStreamResponse.result === 'undefined') {
throw new Error(`SSE event JSON-RPC response is missing 'result' field. Data: ${jsonData}`);
}

return a2aStreamResponse.result as TStreamItem;
let a2aStreamResponse: JSONRPCResponse;
try {
a2aStreamResponse = JSON.parse(jsonData) as JSONRPCResponse;
} catch (e) {
if (
e instanceof Error &&
(e.message.startsWith('SSE event contained an error') ||
e.message.startsWith("SSE event JSON-RPC response is missing 'result' field"))
) {
throw e;
}
console.error(
'Failed to parse SSE event data string or unexpected JSON-RPC structure:',
jsonData,
e
throw new Error(
`Failed to parse SSE event data: "${jsonData.substring(0, 100)}...". Original error: ${(e instanceof Error && e.message) || 'Unknown error'}`,
{ cause: e }
);
}

if (a2aStreamResponse.id !== originalRequestId) {
throw new Error(
`Failed to parse SSE event data: "${jsonData.substring(0, 100)}...". Original error: ${(e instanceof Error && e.message) || 'Unknown error'}`
`JSON-RPC response ID mismatch in SSE event. Expected ${originalRequestId}, got ${a2aStreamResponse.id}.`
);
}

if ('error' in a2aStreamResponse) {
const err = a2aStreamResponse.error;
throw new Error(
`SSE event contained an error: ${err.message} (Code: ${err.code}) Data: ${JSON.stringify(err.data || {})}`,
{ cause: JsonRpcTransport.mapToError(a2aStreamResponse) }
);
}

if (!('result' in a2aStreamResponse) || typeof a2aStreamResponse.result === 'undefined') {
throw new Error(`SSE event JSON-RPC response is missing 'result' field. Data: ${jsonData}`);
}

return a2aStreamResponse.result as TStreamItem;
}

private static mapToError(response: JSONRPCErrorResponse): Error {
Expand Down