Skip to content

Conversation

@tchapacan
Copy link
Contributor

@tchapacan tchapacan commented Oct 26, 2025

Description

Add HTTP+REST ServerSide Transport Support

  • Server: REST endpoints/routes addition by taking advantage of pre-existing express from the codebase. Following this doc and internally rerouting to each a2a handler method containing the buisness logic

Some part of the code has been generated using generative AI to speed up the development, I have reviewed it carefully, but this should be taken into account into the review. Keep in mind this is my first time contributing to the repo and this is an attempt to help a2a-js support REST (HTTP+JSON) as per describe in the a2a documentation. I'll be happy to refacto it during review process, don't hesitate to challenge it.


Thank you for opening a Pull Request!
Before submitting your PR, there are a few things you can do to make sure it goes smoothly:

  • Follow the CONTRIBUTING Guide.
  • Make your Pull Request title in the https://www.conventionalcommits.org/ specification.
    • Important Prefixes for release-please:
      • fix: which represents bug fixes, and correlates to a SemVer patch.
      • feat: represents a new feature, and correlates to a SemVer minor.
      • feat!:, or fix!:, refactor!:, etc., which represent a breaking change (indicated by the !) and will result in a SemVer major.
  • Ensure the tests and linter pass
  • Appropriate docs were updated (if necessary)

Re #137 🦕

Release-As: 0.3.6

@tchapacan tchapacan force-pushed the feat/implement-http+json branch from ab133cc to 530d5db Compare October 27, 2025 00:07
@ishymko
Copy link
Member

ishymko commented Oct 30, 2025

Thanks a lot @tchapacan for looking into this! Appreciate your effort to align this proposal with the existing infrastructure.

I actually think that current way of wiring it up with express followed in this repo worth changing to make it more modular and explicit, i.e.

const app = express();

// const a2aRequestHandler = ...
// const agentCard = ...

app.use('/.well-known/agent-card.json', agentCardHandler(agentCard));
app.use('/a2a/jsonrpc', jsonRpcHandler(a2aRequestHandler));
app.use('/a2a/api', restHandler(a2aRequestHandler));

This is just a sketch, but the idea is to provide ready to use routers which can be registered independently by the integration code, currently A2AExpressApp uses provided app only to register internal router under a provided basePath, effectively wrapping basic express API. I'll try to draft a PR with this so that REST can follow a new API.

In addition, current JSON-RPC implementation uses framework-agnostic JsonRpcTransportHandler (see also Python SDK) which is not the case for REST in this proposal. Maybe there is not much which can be made framework-agnostic for REST though, but it worth checking if we can make both transports consistent implementation-wise.

Similar applies to client, JSON-RPC specific implementation has to be factored out into some sort of a "transport" abstraction which can be implemented for REST as well (see Python). I'll try to prepare this as well.

And last but not least, we're setting up conformance tests from here: #159. Once SUT agent is ready, it'll be possible to validate REST transport as well.

@tchapacan
Copy link
Contributor Author

tchapacan commented Nov 1, 2025

Hello @ishymko ! No problem hope it helped a little, at least starting the job for REST support, and opening the discussion!

Yep, I like it too! It seems more modular and easier to understand/maintain in the end. And going with some modular middleware can be compatible with other framework such as fastify see this https://github.com/fastify/fastify-express.

I was thinking about going with the framework agnostic too, following the jsonRcpTransportHandler. But in the end I choose to leverage fully of express framework which does everything we need (routing, method, etc..), only caveats was the route like v1/message:stream where the regex is kind of necessary as it seems express don’t support this kind of route. In the end it only expose business logic from a2a handling method, into express middleware, I don’t see much to do rather than re-implementing what express does really great. I let you decide what would be best, I understand having consistency in the codebase is a plus too.

Agree for the client too, I’m not really happy with my implementation even if it was working, but it deserves some love to make it cleaner.

Good for the conformance test in the CI! Once this will be implemented, you can take advantage of this draft PR to test it.

If you need any help don’t hesitate, on the client part or server part, depending of my time I’ll be happy to help!

swapydapy pushed a commit that referenced this pull request Nov 13, 2025
# Description

As a preparation step for REST support proposed in #142, extract
Express.js handlers from `A2AExpressApp` to allow assembling your own
app using Express.js API directly for specifying individual paths and
middlewares, rather than wrapping it in `A2AExpressApp`:

```ts
// const a2aRequestHandler = . . .

const app = express();

// Minimal example:
app.use(`/${AGENT_CARD_PATH}`, agentCardHandler({ agentCardProvider: a2aRequestHandler }));
app.use(jsonRpcHandler({ requestHandler: a2aRequestHandler }));

// Advanced example:
app.use(myCustomMiddleware());
app.use('/.well-known/custom-agent-card.json', myCustomAgentCardMiddleware, agentCardHandler({ agentCardProvider: a2aRequestHandler }));
app.use('/a2a/jsonrpc', myJsonRpcMiddleware, jsonRpcHandler({ requestHandler: a2aRequestHandler }));
app.use('/a2a/api', restHandler({ requestHandler: a2aRequestHandler }));
```

No logic changes to existing handlers, they are moved as is. Also
`A2AExpressApp` is switched to use new handlers without behavior
changes.

**Note:** new functions **are not** exported via `index.ts` yet, it will
be done together with updating docs and examples once REST support is
done.

Re #137
@ishymko
Copy link
Member

ishymko commented Nov 13, 2025

Hi @tchapacan, thank you for you patience!

At this point server-side implementation should be good to proceed as #162 is merged and we also have TCK tests running.

Could you please merge with main and factor out the server side support in the same fashion as in #162? As you proposed in the description, splitting server and client here indeed will help a lot, so let's start with the server as client is not yet switched to multi-transport types.

Also please make sure to integrate with TCK tests. It should probably work with minimal changes to CLI arguments when SUT agent is updated with REST transport in agent card.

@tchapacan tchapacan force-pushed the feat/implement-http+json branch 4 times, most recently from 71285cd to 2e758e7 Compare November 14, 2025 23:59
@tchapacan
Copy link
Contributor Author

tchapacan commented Nov 15, 2025

Hello @ishymko! Thanks for following it up with #162 and the TCK testing, it seems clear!

I've rebased on main and tried to implement the server-side REST support following the same pattern as #162. Here's what I have done:

Server Side REST support:

  • Created httpRestHandler() in src/server/express/http_rest_handler.ts following the same pattern as jsonRpcHandler() and agentCardHandler()
  • Handlers are exported from src/server/express/index.ts and A2AExpressApp remains for backward compatibility
  • REST routes follow the pattern: /v1/message:send, /v1/message:stream, /v1/task/:taskId, etc.

TCK adaptation:

  • Updated tck/agent/index.ts to mount both transports using new middleware:
    • JSON-RPC at /a2a/jsonrpc
    • REST at /a2a/rest
  • Updated .github/workflows/run-tck.yaml to test both transports (cli argument and url changed)
  • Agent card now includes both transport URLs

Not sure if the implementation is correct for the TCK agent and the workflow (cli argument), I have tried to follow the docs from this repo but LMK if what I have done make sense to be sure testing is relevant. A2aExpress is not tested anymore here (deprecated) as I'm leveraging the new middleware and not sure if the combination between the agentCard (JSONRPC + REST) and the cli argument passed in the workflow are really OK.

Something I would like to highlight while I was testing my implementation with the TCK test :

I encountered an issue: the TCK cli for REST requests use snake_case (e.g., message_id, context_id), but internal TypeScript types use camelCase (e.g., messageId, contextId). This seems pretty standard and normal - REST APIs typically are snake_case but TypeScript uses camelCase here. That’s why the TCK test was failing during my first attempt. To overcome this I went this path and tried to :

Implement a transformation middleware in (src/server/express/utils.ts) used internally in httpRestHandler that will:

  • Transforms incoming keys from bodies REST requests: snake_case → camelCase
  • Transforms outgoing key from bodies of responses: camelCase → snake_case

Implementation is quite loose and based on regex, so not sure it's 100% safe to go this path, but at least it solve the TCK tests failing (locally, but partially in the CI)

Even with this modification, I have some inconsistency between my local run of a2a-tck which are passing :

./run_tck.py --sut-url http://localhost:41241/a2a/rest --category mandatory --transports rest --transport-strategy prefer_rest --verbose
======================================================================
🚀 Running MANDATORY tests
Description: Mandatory A2A compliance tests
======================================================================

Command: a2a-tck/.venv/bin/python3 -m pytest tests/mandatory/protocol/ --sut-url=http://localhost:41241/a2a/rest --test-scope=all --tb=short -m mandatory_protocol -v --transport-strategy prefer_rest --transports rest --enable-equivalence-testing

================================================================================================ test session starts =================================================================================================
platform darwin -- Python 3.14.0, pytest-9.0.1, pluggy-1.6.0 -- a2a-tck/.venv/bin/python3
cachedir: .pytest_cache
metadata: {'Python': '3.14.0', 'Platform': 'macOS-15.6-arm64-arm-64bit-Mach-O', 'Packages': {'pytest': '9.0.1', 'pluggy': '1.6.0'}, 'Plugins': {'anyio': '4.11.0', 'json-report': '1.5.0', 'metadata': '3.1.1', 'asyncio': '1.3.0'}}
rootdir: a2a-tck
configfile: pyproject.toml
plugins: anyio-4.11.0, json-report-1.5.0, metadata-3.1.1, asyncio-1.3.0
asyncio: mode=Mode.AUTO, debug=False, asyncio_default_fixture_loop_scope=None, asyncio_default_test_loop_scope=function
collected 35 items / 14 deselected / 21 selected

tests/mandatory/protocol/test_a2a_v030_new_methods.py::TestAuthenticatedExtendedCard::test_authenticated_extended_card_method_exists SKIPPED (SUT does not support authenticated extended card)                [  4%]
tests/mandatory/protocol/test_a2a_v030_new_methods.py::TestAuthenticatedExtendedCard::test_authenticated_extended_card_without_auth SKIPPED (SUT does not support authenticated extended card)                 [  9%]
tests/mandatory/protocol/test_a2a_v030_new_methods.py::TestMethodMappingCompliance::test_core_method_mapping_compliance PASSED                                                                                 [ 14%]
tests/mandatory/protocol/test_a2a_v030_new_methods.py::TestMethodMappingCompliance::test_transport_specific_method_naming PASSED                                                                               [ 19%]
tests/mandatory/protocol/test_a2a_v030_transport_compliance.py::test_transport_compliance_validation PASSED                                                                                                    [ 23%]
tests/mandatory/protocol/test_a2a_v030_transport_compliance.py::test_required_method_availability PASSED                                                                                                       [ 28%]
tests/mandatory/protocol/test_a2a_v030_transport_compliance.py::test_transport_specific_features PASSED                                                                                                        [ 33%]
tests/mandatory/protocol/test_a2a_v030_transport_compliance.py::test_multi_transport_method_mapping SKIPPED (Multi-transport method mapping requires 2+ transports)                                            [ 38%]
tests/mandatory/protocol/test_a2a_v030_transport_compliance.py::test_comprehensive_a2a_v030_compliance PASSED                                                                                                  [ 42%]
tests/mandatory/protocol/test_agent_card.py::test_agent_card_available PASSED                                                                                                                                  [ 47%]
tests/mandatory/protocol/test_agent_card.py::test_mandatory_fields_present PASSED                                                                                                                              [ 52%]
tests/mandatory/protocol/test_agent_card.py::test_mandatory_field_types PASSED                                                                                                                                 [ 57%]
tests/mandatory/protocol/test_message_send_method.py::test_message_send_valid_text PASSED                                                                                                                      [ 61%]
tests/mandatory/protocol/test_message_send_method.py::test_message_send_invalid_params PASSED                                                                                                                  [ 66%]
tests/mandatory/protocol/test_message_send_method.py::test_message_send_continue_task PASSED                                                                                                                   [ 71%]
tests/mandatory/protocol/test_state_transitions.py::test_task_history_length PASSED                                                                                                                            [ 76%]
tests/mandatory/protocol/test_tasks_cancel_method.py::test_tasks_cancel_valid PASSED                                                                                                                           [ 80%]
tests/mandatory/protocol/test_tasks_cancel_method.py::test_tasks_cancel_nonexistent PASSED                                                                                                                     [ 85%]
tests/mandatory/protocol/test_tasks_get_method.py::test_tasks_get_valid PASSED                                                                                                                                 [ 90%]
tests/mandatory/protocol/test_tasks_get_method.py::test_tasks_get_with_history_length PASSED                                                                                                                   [ 95%]
tests/mandatory/protocol/test_tasks_get_method.py::test_tasks_get_nonexistent PASSED                                                                                                                           [100%]

=================================================================================== 18 passed, 3 skipped, 14 deselected in 34.81s ====================================================================================

And the one in the CI that are failing example => https://github.com/a2aproject/a2a-js/actions/runs/19397175092/job/55498766100?pr=142

Might need your help about this to understand what I'm doing wrong ?

Performance Impact:
I've tried to do a simple load testing with autocannon using the v1/message:send route (to make sure it wasn't killing performance, even If the inference time would always be way greater) :

  • Test config (tried to be the closest to a realistic scenario): 20 concurrent connections, 30s duration, pipelining set to 1 (sequential message)
  • result show ~5-10% performance overhead from the transformation middleware (check below)
  • Note: I had to comment this line in the TCK agent's for the processing fake delay to have relevant metrics during the load test

With middleware :

Running 30s test @ http://localhost:41241/a2a/rest/v1/message:send
20 connections

┌─────────┬──────┬──────┬───────┬──────┬─────────┬─────────┬────────┐
│ Stat    │ 2.5% │ 50%  │ 97.5% │ 99%  │ Avg     │ Stdev   │ Max    │
├─────────┼──────┼──────┼───────┼──────┼─────────┼─────────┼────────┤
│ Latency │ 1 ms │ 2 ms │ 8 ms  │ 9 ms │ 2.45 ms │ 3.97 ms │ 135 ms │
└─────────┴──────┴──────┴───────┴──────┴─────────┴─────────┴────────┘
┌───────────┬─────────┬─────────┬─────────┬─────────┬──────────┬──────────┬─────────┐
│ Stat      │ 1%      │ 2.5%    │ 50%     │ 97.5%   │ Avg      │ Stdev    │ Min     │
├───────────┼─────────┼─────────┼─────────┼─────────┼──────────┼──────────┼─────────┤
│ Req/Sec   │ 3 017   │ 3 017   │ 7 139   │ 7 775   │ 6 715,44 │ 1 073,88 │ 3 016   │
├───────────┼─────────┼─────────┼─────────┼─────────┼──────────┼──────────┼─────────┤
│ Bytes/Sec │ 4.13 MB │ 4.13 MB │ 9.78 MB │ 10.6 MB │ 9.19 MB  │ 1.47 MB  │ 4.13 MB │
└───────────┴─────────┴─────────┴─────────┴─────────┴──────────┴──────────┴─────────┘
┌──────┬────────┐
│ Code │ Count  │
├──────┼────────┤
│ 201  │ 201453 │
└──────┴────────┘

Req/Bytes counts sampled once per second.
# of samples: 30

201k requests in 30.02s, 276 MB read

Without middleware :

Running 30s test @ http://localhost:41241/a2a/rest/v1/message:send
20 connections

┌─────────┬──────┬──────┬───────┬──────┬─────────┬─────────┬────────┐
│ Stat    │ 2.5% │ 50%  │ 97.5% │ 99%  │ Avg     │ Stdev   │ Max    │
├─────────┼──────┼──────┼───────┼──────┼─────────┼─────────┼────────┤
│ Latency │ 1 ms │ 1 ms │ 8 ms  │ 9 ms │ 2.13 ms │ 4.15 ms │ 169 ms │
└─────────┴──────┴──────┴───────┴──────┴─────────┴─────────┴────────┘
┌───────────┬─────────┬─────────┬─────────┬───────┬──────────┬──────────┬─────────┐
│ Stat      │ 1%      │ 2.5%    │ 50%     │ 97.5% │ Avg      │ Stdev    │ Min     │
├───────────┼─────────┼─────────┼─────────┼───────┼──────────┼──────────┼─────────┤
│ Req/Sec   │ 1 887   │ 1 887   │ 7 843   │ 8 123 │ 7 284,54 │ 1 407,15 │ 1 887   │
├───────────┼─────────┼─────────┼─────────┼───────┼──────────┼──────────┼─────────┤
│ Bytes/Sec │ 2.56 MB │ 2.56 MB │ 10.6 MB │ 11 MB │ 9.88 MB  │ 1.91 MB  │ 2.56 MB │
└───────────┴─────────┴─────────┴─────────┴───────┴──────────┴──────────┴─────────┘
┌──────┬────────┐
│ Code │ Count  │
├──────┼────────┤
│ 201  │ 218506 │
└──────┴────────┘

Req/Bytes counts sampled once per second.
# of samples: 30

219k requests in 30.02s, 297 MB read

I'm open to different approaches here and would like your guidance for the next steps:

  1. Should the a2a-tck compliance tests be changed to use camelCase for REST endpoints instead of snake_case?
  2. Should we introduce REST-specific types (e.g., RestMessageSendParams) with snake_case naming?
  3. Is the transformation middleware acceptable given the « apparently » ~5-10% overhead, or you prefer a different approach ?

Let me know what you think would be best! Happy to adjust the implementation, reorganize the code (convention naming etc..) and tests following your recommendations. But first I need a little help related to the a2a-tck issue I'm having.

@tchapacan tchapacan force-pushed the feat/implement-http+json branch 5 times, most recently from 0746260 to 3343f3a Compare November 17, 2025 09:03
@ishymko
Copy link
Member

ishymko commented Nov 17, 2025

Thank you @tchapacan! This is a very solid work! I'll get to review it properly once we have the testing sorted out, but I agree with the general approach.

On TCK
Can we do a single step via

./run_tck.py --sut-url URL --category mandatory \
  --transports jsonrpc,rest

(modified example Run per-transport single-client tests for JSON-RPC and gRPC, then equivalence from here)

This should also make use of additional interfaces you defined in the agent card, as transport specific base URLs should be discovered automatically from it without defining them explicitly as SUT URL.

As for the differences between CI run and local run: are you sure you're running against the same version of TCK locally? CI uses 0.3.0.beta3 tag from the a2a-tck repo. Also it can be due to some state leftovers from the JSON-RPC run... So worth running both locally to see if you can reproduce the CI failure. Please let me know if it doesn't help and I'll have another look.

On snake_case/camelCase
Yeah good catch, seems like other languages use underscores. It's actually not specified very well in the protocol spec itself. My vote is option 2: REST-specific types. It's a bit of boilerplate but draws a clear boundary between transport specific and core types. I agree with you that automatic conversion is not fully safe, also we may have more differences in the future.

@ishymko
Copy link
Member

ishymko commented Nov 19, 2025

Hi @tchapacan, as a heads up we've recently merged ESLint and Prettier integration (#183, #185) which caused substantial diffs across the whole codebase. Those are only formatting and "unused imports" kind of changes, so you should be good with just resolving all the conflicts in favor of your local state and applying npm run lint:fix on top of that.

ishymko added a commit that referenced this pull request Nov 19, 2025
# Description

Currently `A2AClient` defined in `client.ts` uses JSON-RPC types in its
interface, i.e. `sendMessage` uses
[`SendMessageResponse`](https://github.com/a2aproject/a2a-js/blob/e7e8f35d5d5356d30a13131dea0caff97be8cd53/src/client/client.ts#L207)
which contains [JSON-RPC fields like `id` and `jsonrpc`
version](https://github.com/a2aproject/a2a-js/blob/e7e8f35d5d5356d30a13131dea0caff97be8cd53/src/types.ts#L2177-L2190).
It was also the case for Python SDK which required introducing a new
[client.py](https://github.com/a2aproject/a2a-python/blob/main/src/a2a/client/client.py)
keeping the old one as
[legacy.py](https://github.com/a2aproject/a2a-python/blob/main/src/a2a/client/legacy.py)
for backward compatibility (see
[#348](a2aproject/a2a-python#348)).

As a first step of introducing a transport-agnostic client, extract
JSON-RPC specific logic into a transport abstraction and switch existing
`A2AClient` to it in a backward compatible way to take advantage of
existing tests.

**Note:** new types are not exported from `index.ts`, this will be done
once new client is ready.

# Changes

1. Define `A2ATransport` abstraction without using JSON-RPC types.
2. Implement `JsonRpcTransport` from existing `A2AClient`.
3. Use new `JsonRpcTransport` from `A2AClient` - new transports are
**not going** to be added into this client as it uses JSON-RPC types.
This is done in a backward compatible way, existing behavior is
preserved: returning JSON-RPC errors as objects, populating JSON-RPC
specific fields.
4. Define shared transport-agnostic errors for A2A specific errors
defined in [the
spec](https://a2a-protocol.org/latest/specification/#82-a2a-specific-errors).

Re #137, #142
@tchapacan
Copy link
Contributor Author

Hello @ishymko

Thanks for the heads-up! Will do for the rebase and the linting no problem about that!

I'm able to reproduce the behavior of the tck CI run by using the correct tag 0.3.0.beta3 locally! I missed the details to switch to the correct tag my bad sorry!

I was able to dig a little further and it seems the object message send by the tck cli is not same as the one expected by the server. Using the 0.3.0.beta3 tag it fails, but it seems to have been fixed in main branch, so maybe there is just a new release to perform?

Following the cli arguments you recommended and by performing some adjustment into the agentcard by following more rigorously this part of the spec, here what I got now :

./run_tck.py --sut-url URL --category mandatory --transports jsonrpc,rest

Using tag 0.3.0.beta3 (failing):

  • JSONRPC:
{
  kind: 'message',
  messageId: 'text-message-id-54f8f97e-994f-4270-8d35-55623ecf6c5f',
  role: 'user',
  parts: [ { kind: 'text', text: 'Hello from TCK!' } ],
  contextId: '16f7759f-7f57-469a-8e1c-54a169300150'
}
  • REST:
{
  messageId: 'text-message-id-394c0fa2-7548-4c9f-ab01-776bc8ec0426',
  role: 'ROLE_USER',
  content: [ { text: 'Hello from TCK!' } ],
  contextId: '8d0ac3ed-1fcf-45f1-920b-671a5a0f936f'
}

Using main branch (all good):

  • JSONRPC:
{
  kind: 'message',
  messageId: 'text-message-id-851f3e53-ac53-42ab-877d-5ac943b986e3',
  role: 'user',
  parts: [ { kind: 'text', text: 'Hello from TCK!' } ],
  contextId: '054bbefe-7e20-4abb-9974-de00f29f795d'
}
  • REST:
{
  messageId: 'text-message-id-458fd959-e5d9-4079-a88e-4ba1ca1a6aa3',
  role: 'ROLE_USER',
  parts: [ { text: 'Hello from TCK!' } ],
  contextId: '1a7060d9-23dc-4f4f-99e5-f5554dc66f31'
}

I will remove the transformation middleware in my next commits/push and try my best to propose some relevant type for REST, I'll work on it in the next days.

@tchapacan tchapacan force-pushed the feat/implement-http+json branch 6 times, most recently from 0a8cc83 to fde96cd Compare November 20, 2025 11:50
@ishymko
Copy link
Member

ishymko commented Nov 20, 2025

Hello @tchapacan!

Great catch on main vs 0.3.0.beta3! Seems like indeed it was using incorrect payload (content vs parts as in your example) which fails in our SUT agent

const textPart = message.parts.find((part) => part.kind === 'text');
at undefined.find and it got fixed in main. I don't see any new releases created in TCK, setting main in the workflow is fragile, as it'll be floating, can we set it to the fix commit directly for now (actions/checkout should support it)?

@tchapacan tchapacan force-pushed the feat/implement-http+json branch 2 times, most recently from e5aaa8b to 8821ab8 Compare November 21, 2025 19:41
@tchapacan
Copy link
Contributor Author

tchapacan commented Dec 7, 2025

Helo @ishymko, to summarize :

  • Tried to fix all your comments, and rebased, LMK if that's ok
  • Tried to implement :
    • input: both camelCase and snake-case accepted
    • output: only camelCase returned

I went this path to leverage the existing boilerplate method we have implemented (by cleaning some that weren't necessary anymore)

If the camelCase/snake-case input is to flaky and add some unecessary complexity according to the next version of the spec that will authorize only camelCase, I can remove it no worry.

Copy link
Member

@ishymko ishymko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @tchapacan, let's keep supporting both, I like it, I think it's reasonable given that the work was done already and it works in other SDKs now. As long as this adapter logic is not exported we're fine.

Left a few cleanup-like comments. I don't want to block on TCK SSE test failure as long as manual testing (via switching to per-session event) succeeds.

I am going to start updating the doc for upcoming release, will include this part as well (as it's easier to do everything together) and will tag you on the PR.

@tchapacan tchapacan force-pushed the feat/implement-http+json branch 4 times, most recently from b72a614 to 09d03b1 Compare December 8, 2025 22:16
@tchapacan
Copy link
Contributor Author

helo @ishymko, to summarize latest change :

  • rebased from main
  • tried to fixed all comment, it seems good unless we have forgotten some remaining stuff in the comments
  • updated and reorganized the tests to include the input(snake-case+camelCase) and output(camelCase)

I will follow-up the issue I have opened here a2aproject/a2a-tck#99 and take the responsibility to create an another PR later, to reintroduce the transports method in the github workflow for the capabilities

When the spec will evolve and if it make sense to restrict it to only camelCase as input and output, I can create an another PR in that sense if necessary.

Thanks for all the time you took reviewing it!

If you need help for the client transport part, I'll be happy to help as well !

Copy link
Member

@ishymko ishymko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot @tchapacan for this contribution and your due diligence during review process! Good action items on TCK side emerged from it.

Some final nit comments and I am going to merge it for the upcoming release (current plan is to push a 0.3.6 version this week). I don't think it's critical to include client support in the same release as they are independent.

As for client transport, your help will be greatly appreciated!

@tchapacan tchapacan force-pushed the feat/implement-http+json branch from 09d03b1 to d5a5033 Compare December 9, 2025 21:58
@tchapacan tchapacan force-pushed the feat/implement-http+json branch from d5a5033 to 7b3d0eb Compare December 9, 2025 22:26
@tchapacan
Copy link
Contributor Author

No problem @ishymko always a pleasure to help and thanks for your review! Will follow-up my issue in TCK. I have fixed all your comment and sync rebase from main.

Yes I don't see any issue to add server and client in different release, no problem!

I will create an another PR then for the client part. I see a lot of job has already been done in term of refacto and pattern in place. I suppose we will need to add a rest_transport.ts in client/transports, something like this :

export class RestTransport implements Transport {
...
}

And wire everything together following same pattern as for the JsonRpcTransport. But I haven't look into the details yet and we will discuss in the next PR for this. I didn't saw any PR for this one yet so unless it's planned on your side to do it, I can start in the next days.

@ishymko ishymko merged commit f20e662 into a2aproject:main Dec 10, 2025
6 checks passed
@ishymko
Copy link
Member

ishymko commented Dec 10, 2025

@tchapacan thanks again, merging the PR! 🚀

As for the client support: correct, the same approach should be followed for REST. See reference PRs for JSON-RPC: #198, #169. Note that current JSON-RPC transport implementation has some compatibility hacks to be used from the old client, there is no need for it for HTTP+JSON.

There is no TCK-like thing for client, but we have e2e.spec.ts to test both client and server assembled like external users would do it (using AgentExecutor as an extension point with everything else not mocked). Currently those tests provide partial coverage around the most critical part which is message sending, we should be able to run current tests for both transports with HTTP+JSON client.

Could you please comment on #137 that you're planning to open a PR for client support so that I can "assign" this issue to you to avoid duplicated effort from the community? Thank you!

ishymko added a commit that referenced this pull request Dec 10, 2025
🤖 I have created a release *beep* *boop*
---


## [0.3.6](v0.3.5...v0.3.6)
(2025-12-10)


### Features

* add support for extendedAgentCard on client side
([#234](#234))
([3073376](3073376))
* Add support for extension headers on client side
([#227](#227))
([8c57002](8c57002))
* implement client interceptors
([#223](#223))
([5694c22](5694c22))
* Implement extended card support on server side
([#197](#197))
([45014ac](45014ac))
* implement server http+json
([#142](#142))
([f20e662](f20e662))
* introduce AgentCardResolver
([#225](#225))
([ddaf7de](ddaf7de))
* introduce transport agnostic client
([#198](#198))
([94a9848](94a9848))
* server side support for extensions
([5ef7396](5ef7396))
* support authentication on server side
([#195](#195))
([9872d93](9872d93))


### Bug Fixes

* handle errors occurred in non-blocking sendMessage
([#187](#187))
([e55c0f4](e55c0f4))


### Miscellaneous Chores

* set version to 0.3.6
([#191](#191))
([3f8cea0](3f8cea0))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: Ivan Shymko <ishymko@google.com>
@tchapacan tchapacan mentioned this pull request Dec 15, 2025
4 tasks
ishymko added a commit that referenced this pull request Dec 17, 2025
# Description

Following continuation of this PR
#142, this one is related to
the implementation of the REST mode support for the client part of
**a2a-js** sdk. Following the same pattern as other sdk (agnostic
transport).

----

Thank you for opening a Pull Request!
Before submitting your PR, there are a few things you can do to make
sure it goes smoothly:

- [x] Follow the [`CONTRIBUTING`
Guide](https://github.com/google-a2a/a2a-js/blob/main/CONTRIBUTING.md).
- [x] Make your Pull Request title in the
<https://www.conventionalcommits.org/> specification.
- Important Prefixes for
[release-please](https://github.com/googleapis/release-please):
- `fix:` which represents bug fixes, and correlates to a
[SemVer](https://semver.org/) patch.
- `feat:` represents a new feature, and correlates to a SemVer minor.
- `feat!:`, or `fix!:`, `refactor!:`, etc., which represent a breaking
change (indicated by the `!`) and will result in a SemVer major.
- [x] Ensure the tests and linter pass
- [ ] Appropriate docs were updated (if necessary)

Fixes #137, fixes #175 🦕

Release-As: 0.3.7

Co-authored-by: Ivan Shymko <ishymko@google.com>
ishymko added a commit that referenced this pull request Dec 17, 2025
…REST (#274)

# Description

Follow-up for #142: authenticated agent card logic relies on context to
determine authentication status.

`src/server/transports/rest/rest_transport_handler.ts` is not exported,
so adding a required parameter is fine.

Re #137
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants