Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
1fa50c8
Added new enums and applied them across the codebase. Removed types.t…
bartek-gralewicz Feb 19, 2026
e6276be
Apply further types changes. Resolve issues with missing structs.
bartek-gralewicz Feb 19, 2026
0bb1cdd
WIP: Updated types in the entire codebase. Needs revisiting due to so…
bartek-gralewicz Feb 20, 2026
a7512b1
Improved tests passing ratio for server unit tests.
bartek-gralewicz Feb 20, 2026
c1a8ea0
Applied multiple fixes to default_request_handler tests.
bartek-gralewicz Feb 20, 2026
adc42f7
Fixed all tests.
bartek-gralewicz Feb 20, 2026
38b67c9
Resolve issues in default_request_handler.spec.ts.
bartek-gralewicz Feb 20, 2026
d5d2983
Resolve all leftover build related issues.
bartek-gralewicz Feb 20, 2026
30cf6ae
Minor self-review cleanup and test restoring.
bartek-gralewicz Feb 20, 2026
f4ae1b9
Lint and formatting changes.
bartek-gralewicz Feb 20, 2026
c9baa85
Code assist suggestions.
bartek-gralewicz Feb 20, 2026
791e1e9
Gemini code review adaptations.
bartek-gralewicz Feb 20, 2026
92e43a3
Remove unused imports.
bartek-gralewicz Feb 23, 2026
12e18ae
Resolve lint issues in grpc_transport.ts.
bartek-gralewicz Feb 23, 2026
d14babf
Resolve current issues with failing unit tests.
bartek-gralewicz Feb 23, 2026
891b066
Resolve linter errors.
bartek-gralewicz Feb 23, 2026
3036435
Apply suggestions from gemini-code-review.
bartek-gralewicz Feb 23, 2026
e7f5fb9
Minor update to checking state in default_request_handler based on ge…
bartek-gralewicz Feb 23, 2026
ab9a627
Applied gemini code suggestion. Resolved leftover TODO in a unit test.
bartek-gralewicz Feb 23, 2026
a5e9d42
Update CI workflows to trigger checks when merging to an epic branch.
bartek-gralewicz Feb 24, 2026
10daa08
Minor changes to reduce unnecessary diffs. Restored some comments.
bartek-gralewicz Feb 24, 2026
ebeb89d
Disable TCK checks for epic branches.
bartek-gralewicz Feb 25, 2026
548a2bb
Removed non-agnostic classes from the transport. Moved format logic t…
bartek-gralewicz Mar 3, 2026
9f80c5f
Remove type specifications from grpc_transport.
bartek-gralewicz Mar 3, 2026
ea41ce7
Restore type agnosticity in a2a_request_handler.
bartek-gralewicz Mar 4, 2026
6fafc6b
Defined Base classes to reduce repetitions in json_rpc_types.js.
bartek-gralewicz Mar 4, 2026
37e145d
Update betterer results after adding Base types for Params.
bartek-gralewicz Mar 4, 2026
c64081a
Move msg/task conversion logic from client.ts to ToProto.
bartek-gralewicz Mar 9, 2026
5dc353d
Reuse extractTaskId method in client.ts.
bartek-gralewicz Mar 9, 2026
49a488a
Restructure imports and exports to keep transport related types in th…
bartek-gralewicz Mar 9, 2026
224504a
Minor formatting changes + code diff reduction.
bartek-gralewicz Mar 10, 2026
3ded9cb
Minor formatting changes + code diff reduction.
bartek-gralewicz Mar 10, 2026
e7c4df4
Minor formatting changes + code diff reduction.
bartek-gralewicz Mar 10, 2026
8fd779a
Apply changes from #346 bugfix PR.
bartek-gralewicz Mar 10, 2026
e8eb53d
Removed an empty echo parser in .
bartek-gralewicz Mar 10, 2026
27cbbae
Update src/client/transports/rest_transport.ts
bartek-gralewicz Mar 10, 2026
22875d4
Import types directly from index.js instead of /types/pb/a2a_types.js.
bartek-gralewicz Mar 10, 2026
16abc9d
Merge branch 'bgralewicz/proto_types' of github.com:a2aproject/a2a-js…
bartek-gralewicz Mar 11, 2026
b439d67
Removed most of JSON-RPC types and replaced them with proper PROTO ty…
bartek-gralewicz Mar 12, 2026
33fefd0
Remove redundant and unused FromProto and ToProto methods. Note: some…
bartek-gralewicz Mar 12, 2026
6ccf298
Remove redundant and unused FromProto and ToProto methods. Note: some…
bartek-gralewicz Mar 12, 2026
dd1c08a
Removed unwanted export for Base type interface.
bartek-gralewicz Mar 12, 2026
d66f1d4
Small diff reduction and import cleanup.
bartek-gralewicz Mar 13, 2026
c2129d3
Merge branch 'epic/1.0_breaking_changes' into bgralewicz/proto_types
bartek-gralewicz Mar 13, 2026
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
87 changes: 17 additions & 70 deletions .betterer.results

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions .github/workflows/build-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ name: Run Build Tests

on:
push:
branches: [ "main" ]
branches: [ "main", "epic/**" ]
pull_request:
branches: [ "main" ]
branches: [ "main", "epic/**" ]
paths-ignore:
- '**.md'
- 'LICENSE'
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: Run Linter & Formatter

on:
push:
branches: [ "main" ]
branches: [ "main", "epic/**" ]
pull_request:
branches: [ "main" ]
branches: [ "main", "epic/**" ]
paths-ignore:
- '**.md'
- 'LICENSE'
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ name: Run Unit Tests

on:
push:
branches: [ "main" ]
branches: [ "main", "epic/**" ]
pull_request:
branches: [ "main" ]
branches: [ "main", "epic/**" ]
paths-ignore:
- '**.md'
- 'LICENSE'
Expand Down
4 changes: 2 additions & 2 deletions src/a2a_response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import {
CancelTaskResponse,
SetTaskPushNotificationConfigResponse,
GetTaskPushNotificationConfigResponse,
JSONRPCErrorResponse,
ListTaskPushNotificationConfigSuccessResponse,
DeleteTaskPushNotificationConfigSuccessResponse,
GetAuthenticatedExtendedCardSuccessResponse,
} from './types.js';
JSONRPCErrorResponse,
} from './json_rpc_types.js';

/**
* Represents any valid JSON-RPC response defined in the A2A protocol.
Expand Down
2 changes: 1 addition & 1 deletion src/client/card-resolver.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AGENT_CARD_PATH } from '../constants.js';
import { AgentCard } from '../types.js';
import { AgentCard } from '../index.js';

export interface AgentCardResolverOptions {
path?: string;
Expand Down
183 changes: 61 additions & 122 deletions src/client/client.ts
Comment thread
bartek-gralewicz marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -1,26 +1,19 @@
import {
AgentCard,
JSONRPCResponse,
MessageSendParams,
SendMessageResponse,
TaskQueryParams,
GetTaskResponse,
TaskIdParams,
CancelTaskResponse,
TaskPushNotificationConfig, // Renamed from PushNotificationConfigParams for direct schema alignment
SetTaskPushNotificationConfigResponse,
GetTaskPushNotificationConfigResponse,
ListTaskPushNotificationConfigParams,
ListTaskPushNotificationConfigResponse,
DeleteTaskPushNotificationConfigResponse,
DeleteTaskPushNotificationConfigParams,
Message,
Task,
TaskArtifactUpdateEvent,
TaskStatusUpdateEvent,
A2ARequest,
JSONRPCErrorResponse,
} from '../types.js'; // Assuming schema.ts is in the same directory or appropriately pathed
CancelTaskRequest,
CreateTaskPushNotificationConfigRequest,
DeleteTaskPushNotificationConfigRequest,
GetTaskPushNotificationConfigRequest,
GetTaskRequest,
ListTaskPushNotificationConfigRequest,
SendMessageRequest,
TaskSubscriptionRequest,
} from '../index.js';
import { AGENT_CARD_PATH } from '../constants.js';
import { JsonRpcTransport } from './transports/json_rpc_transport.js';
import { RequestOptions } from './multitransport-client.js';
Expand Down Expand Up @@ -152,11 +145,9 @@ export class A2AClient {
* @param params The parameters for sending the message, including the message content and configuration.
* @returns A Promise resolving to SendMessageResponse, which can be a Message, Task, or an error.
*/
public async sendMessage(params: MessageSendParams): Promise<SendMessageResponse> {
return await this.invokeJsonRpc<MessageSendParams, SendMessageResponse>(
(t, p, id) => t.sendMessage(p, A2AClient.emptyOptions, id),
params
);
public async sendMessage(params: SendMessageRequest): Promise<SendMessageResult> {
const transport = await this._getOrCreateTransport();
return transport.sendMessage(params, A2AClient.emptyOptions, this.requestIdCounter++);
}

/**
Expand All @@ -169,7 +160,7 @@ export class A2AClient {
* The generator throws an error if streaming is not supported or if an HTTP/SSE error occurs.
*/
public async *sendMessageStream(
params: MessageSendParams
params: SendMessageRequest
): AsyncGenerator<A2AStreamEventData, void, undefined> {
const agentCard = await this.agentCardPromise; // Ensure agent card is fetched
if (!agentCard.capabilities?.streaming) {
Expand All @@ -189,18 +180,24 @@ export class A2AClient {
* @returns A Promise resolving to SetTaskPushNotificationConfigResponse.
*/
public async setTaskPushNotificationConfig(
params: TaskPushNotificationConfig
): Promise<SetTaskPushNotificationConfigResponse> {
params: CreateTaskPushNotificationConfigRequest
): Promise<TaskPushNotificationConfig> {
const agentCard = await this.agentCardPromise;
if (!agentCard.capabilities?.pushNotifications) {
throw new Error(
'Agent does not support push notifications (AgentCard.capabilities.pushNotifications is not true).'
);
}
return await this.invokeJsonRpc<
TaskPushNotificationConfig,
SetTaskPushNotificationConfigResponse
>((t, p, id) => t.setTaskPushNotificationConfig(p, A2AClient.emptyOptions, id), params);
if (!params.config?.pushNotificationConfig) {
throw new Error('Push notification configuration is required.');
}

const transport = await this._getOrCreateTransport();
return transport.setTaskPushNotificationConfig(
params,
A2AClient.emptyOptions,
this.requestIdCounter++
);
}

/**
Expand All @@ -209,11 +206,13 @@ export class A2AClient {
* @returns A Promise resolving to GetTaskPushNotificationConfigResponse.
*/
public async getTaskPushNotificationConfig(
params: TaskIdParams
): Promise<GetTaskPushNotificationConfigResponse> {
return await this.invokeJsonRpc<TaskIdParams, GetTaskPushNotificationConfigResponse>(
(t, p, id) => t.getTaskPushNotificationConfig(p, A2AClient.emptyOptions, id),
params
params: GetTaskPushNotificationConfigRequest
): Promise<TaskPushNotificationConfig> {
const transport = await this._getOrCreateTransport();
return transport.getTaskPushNotificationConfig(
params,
A2AClient.emptyOptions,
this.requestIdCounter++
);
}

Expand All @@ -223,12 +222,14 @@ export class A2AClient {
* @returns A Promise resolving to ListTaskPushNotificationConfigResponse.
*/
public async listTaskPushNotificationConfig(
params: ListTaskPushNotificationConfigParams
): Promise<ListTaskPushNotificationConfigResponse> {
return await this.invokeJsonRpc<
ListTaskPushNotificationConfigParams,
ListTaskPushNotificationConfigResponse
>((t, p, id) => t.listTaskPushNotificationConfig(p, A2AClient.emptyOptions, id), params);
params: ListTaskPushNotificationConfigRequest
): Promise<TaskPushNotificationConfig[]> {
const transport = await this._getOrCreateTransport();
return transport.listTaskPushNotificationConfig(
params,
A2AClient.emptyOptions,
this.requestIdCounter++
);
}

/**
Expand All @@ -237,36 +238,34 @@ export class A2AClient {
* @returns A Promise resolving to DeleteTaskPushNotificationConfigResponse.
*/
public async deleteTaskPushNotificationConfig(
params: DeleteTaskPushNotificationConfigParams
): Promise<DeleteTaskPushNotificationConfigResponse> {
return await this.invokeJsonRpc<
DeleteTaskPushNotificationConfigParams,
DeleteTaskPushNotificationConfigResponse
>((t, p, id) => t.deleteTaskPushNotificationConfig(p, A2AClient.emptyOptions, id), params);
params: DeleteTaskPushNotificationConfigRequest
): Promise<void> {
const transport = await this._getOrCreateTransport();
return transport.deleteTaskPushNotificationConfig(
params,
A2AClient.emptyOptions,
this.requestIdCounter++
);
}

/**
* Retrieves a task by its ID.
* @param params Parameters containing the taskId and optional historyLength.
* @returns A Promise resolving to GetTaskResponse, which contains the Task object or an error.
*/
public async getTask(params: TaskQueryParams): Promise<GetTaskResponse> {
return await this.invokeJsonRpc<TaskQueryParams, GetTaskResponse>(
(t, p, id) => t.getTask(p, A2AClient.emptyOptions, id),
params
);
public async getTask(params: GetTaskRequest): Promise<Task> {
const transport = await this._getOrCreateTransport();
return transport.getTask(params, A2AClient.emptyOptions, this.requestIdCounter++);
}

/**
* Cancels a task by its ID.
* @param params Parameters containing the taskId.
* @returns A Promise resolving to CancelTaskResponse, which contains the updated Task object or an error.
*/
public async cancelTask(params: TaskIdParams): Promise<CancelTaskResponse> {
return await this.invokeJsonRpc<TaskIdParams, CancelTaskResponse>(
(t, p, id) => t.cancelTask(p, A2AClient.emptyOptions, id),
params
);
public async cancelTask(params: CancelTaskRequest): Promise<Task> {
const transport = await this._getOrCreateTransport();
return transport.cancelTask(params, A2AClient.emptyOptions, this.requestIdCounter++);
}

/**
Expand All @@ -277,26 +276,16 @@ export class A2AClient {
* @param params Extension paramters defined in the AgentCard's extensions.
* @returns A Promise that resolves to the RPC response.
*/
public async callExtensionMethod<TExtensionParams, TExtensionResponse extends JSONRPCResponse>(
public async callExtensionMethod<TExtensionParams, TExtensionResponse>(
method: string,
params: TExtensionParams
) {
const transport = await this._getOrCreateTransport();
try {
return await transport.callExtensionMethod<TExtensionParams, TExtensionResponse>(
method,
params,
this.requestIdCounter++
);
} catch (e) {
// For compatibility, return JSON-RPC errors as errors instead of throwing transport-agnostic errors
// produced by JsonRpcTransport.
const errorResponse = extractJSONRPCError(e);
if (errorResponse) {
return errorResponse as TExtensionResponse;
}
throw e;
}
return await transport.callExtensionMethod<TExtensionParams, TExtensionResponse>(
method,
params,
this.requestIdCounter++
);
}

/**
Expand All @@ -307,7 +296,7 @@ export class A2AClient {
* @returns An AsyncGenerator yielding A2AStreamEventData (Message, Task, TaskStatusUpdateEvent, or TaskArtifactUpdateEvent).
*/
public async *resubscribeTask(
params: TaskIdParams
params: TaskSubscriptionRequest
): AsyncGenerator<A2AStreamEventData, void, undefined> {
const agentCard = await this.agentCardPromise;
if (!agentCard.capabilities?.streaming) {
Expand Down Expand Up @@ -434,54 +423,4 @@ export class A2AClient {
}
return this.serviceEndpointUrl;
}

private async invokeJsonRpc<TParams extends JsonRpcParams, TResponse extends JSONRPCResponse>(
caller: JsonRpcCaller<TParams, TResponse>,
params?: TParams
): Promise<TResponse> {
const transport = await this._getOrCreateTransport();
const requestId = this.requestIdCounter++;
try {
const result = await caller(transport, params, requestId);
return {
id: requestId,
jsonrpc: '2.0',
result: result ?? null, // JSON-RPC requires result property on success, it will be null for "void" methods.
} as TResponse;
} catch (e) {
// For compatibility, return JSON-RPC errors as response objects instead of throwing transport-agnostic errors
// produced by JsonRpcTransport.
const errorResponse = extractJSONRPCError(e);
if (errorResponse) {
return errorResponse as TResponse;
}
throw e;
}
}
}

function extractJSONRPCError(error: unknown): JSONRPCErrorResponse {
if (
error instanceof Object &&
'errorResponse' in error &&
error.errorResponse instanceof Object &&
'jsonrpc' in error.errorResponse &&
error.errorResponse.jsonrpc === '2.0' &&
'error' in error.errorResponse &&
error.errorResponse.error !== null
) {
return error.errorResponse as JSONRPCErrorResponse;
} else {
return undefined;
}
}

// Utility unexported types to properly factor out common "compatibility" logic via invokeJsonRpc.
type ParamsOf<T> = T extends { params: unknown } ? T['params'] : undefined;
type ResultOf<T> = T extends { result: unknown } ? T['result'] : void;
type JsonRpcParams = ParamsOf<A2ARequest>;
type JsonRpcCaller<TParams extends JsonRpcParams, TResponse extends JSONRPCResponse> = (
transport: JsonRpcTransport,
params: TParams,
idOverride: number
) => Promise<ResultOf<TResponse>>;
2 changes: 1 addition & 1 deletion src/client/factory.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { TransportProtocolName } from '../core.js';
import { AgentCard } from '../types.js';
import { AgentCard } from '../index.js';
import { AgentCardResolver } from './card-resolver.js';
import { Client, ClientConfig } from './multitransport-client.js';
import { JsonRpcTransportFactory } from './transports/json_rpc_transport.js';
Expand Down
2 changes: 1 addition & 1 deletion src/client/interceptors.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AgentCard } from '../types.js';
import { AgentCard } from '../index.js';
import { A2AStreamEventData } from './client.js';
import { Client } from './multitransport-client.js';
import { RequestOptions } from './multitransport-client.js';
Expand Down
Loading
Loading