@a2a-js/sdk 0.3.7 → 0.3.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -29,10 +29,28 @@ If you plan to use the Express integration (imports from `@a2a-js/sdk/server/exp
29
29
  npm install express
30
30
  ```
31
31
 
32
+ ### For gRPC Usage
33
+
34
+ If you plan to use the GRPC transport (imports from `@a2a-js/sdk/server/grpc` or `@a2a-js/sdk/client/grpc`), you must install the required peer dependencies:
35
+
36
+ ```bash
37
+ npm install @grpc/grpc-js @bufbuild/protobuf
38
+ ```
39
+
32
40
  You can also find some samples [here](https://github.com/a2aproject/a2a-js/tree/main/src/samples).
33
41
 
34
42
  ---
35
43
 
44
+ ## Compatibility
45
+
46
+ This SDK implements the A2A Protocol Specification [`v0.3.0`](https://a2a-protocol.org/v0.3.0/specification).
47
+
48
+ | Transport | Client | Server |
49
+ | :--- | :---: | :---: |
50
+ | **JSON-RPC** | ✅ | ✅ |
51
+ | **HTTP+JSON/REST** | ✅ | ✅ |
52
+ | **GRPC** (Node.js only) | ✅ | ✅ |
53
+
36
54
  ## Quickstart
37
55
 
38
56
  This example shows how to create a simple "Hello World" agent server and a client to interact with it.
@@ -44,6 +62,7 @@ The core of an A2A server is the `AgentExecutor`, which contains your agent's lo
44
62
  ```typescript
45
63
  // server.ts
46
64
  import express from 'express';
65
+ import { Server, ServerCredentials } from '@grpc/grpc-js';
47
66
  import { v4 as uuidv4 } from 'uuid';
48
67
  import { AgentCard, Message, AGENT_CARD_PATH } from '@a2a-js/sdk';
49
68
  import {
@@ -54,6 +73,7 @@ import {
54
73
  InMemoryTaskStore,
55
74
  } from '@a2a-js/sdk/server';
56
75
  import { agentCardHandler, jsonRpcHandler, restHandler, UserBuilder } from '@a2a-js/sdk/server/express';
76
+ import { grpcService, A2AService } from '@a2a-js/sdk/server/grpc';
57
77
 
58
78
  // 1. Define your agent's identity card.
59
79
  const helloAgentCard: AgentCard = {
@@ -71,6 +91,7 @@ const helloAgentCard: AgentCard = {
71
91
  additionalInterfaces: [
72
92
  { url: 'http://localhost:4000/a2a/jsonrpc', transport: 'JSONRPC' }, // Default JSON-RPC transport
73
93
  { url: 'http://localhost:4000/a2a/rest', transport: 'HTTP+JSON' }, // HTTP+JSON/REST transport
94
+ { url: 'localhost:4001', transport: 'GRPC' }, // GRPC transport
74
95
  ],
75
96
  };
76
97
 
@@ -113,6 +134,15 @@ app.use('/a2a/rest', restHandler({ requestHandler, userBuilder: UserBuilder.noAu
113
134
  app.listen(4000, () => {
114
135
  console.log(`🚀 Server started on http://localhost:4000`);
115
136
  });
137
+
138
+ const server = new Server();
139
+ server.addService(A2AService, grpcService({
140
+ requestHandler,
141
+ userBuilder: UserBuilder.noAuthentication,
142
+ }));
143
+ server.bindAsync(`localhost:4001`, ServerCredentials.createInsecure(), () => {
144
+ console.log(`🚀 Server started on localhost:4001`);
145
+ });
116
146
  ```
117
147
 
118
148
  ### Client: Sending a Message
@@ -153,6 +183,46 @@ async function run() {
153
183
  await run();
154
184
  ```
155
185
 
186
+ ### gRPC Client: Sending a Message
187
+
188
+ The [`ClientFactory`](src/client/factory.ts) has to be created explicitly passing the [`GrpcTransportFactory`](src/client/transports/grpc/grpc_transport.ts).
189
+
190
+ ```typescript
191
+ // client.ts
192
+ import { ClientFactory, ClientFactoryOptions } from '@a2a-js/sdk/client';
193
+ import { GrpcTransportFactory } from '@a2a-js/sdk/client/grpc';
194
+ import { Message, MessageSendParams, SendMessageSuccessResponse } from '@a2a-js/sdk';
195
+ import { v4 as uuidv4 } from 'uuid';
196
+
197
+ async function run() {
198
+ const factory = new ClientFactory({
199
+ transports: [new GrpcTransportFactory()]
200
+ });
201
+
202
+ // createFromUrl accepts baseUrl and optional path,
203
+ // (the default path is /.well-known/agent-card.json)
204
+ const client = await factory.createFromUrl('http://localhost:4000');
205
+
206
+ const sendParams: MessageSendParams = {
207
+ message: {
208
+ messageId: uuidv4(),
209
+ role: 'user',
210
+ parts: [{ kind: 'text', text: 'Hi there!' }],
211
+ kind: 'message',
212
+ },
213
+ };
214
+
215
+ try {
216
+ const response = await client.sendMessage(sendParams);
217
+ const result = response as Message;
218
+ console.log('Agent response:', result.parts[0].text); // "Hello, world!"
219
+ } catch(e) {
220
+ console.error('Error:', e);
221
+ }
222
+ }
223
+
224
+ await run();
225
+ ```
156
226
  ---
157
227
 
158
228
  ## A2A `Task` Support
@@ -56,56 +56,6 @@ var AuthenticatedExtendedCardNotConfiguredError = class extends Error {
56
56
  }
57
57
  };
58
58
 
59
- // src/sse_utils.ts
60
- var SSE_HEADERS = {
61
- "Content-Type": "text/event-stream",
62
- "Cache-Control": "no-cache",
63
- Connection: "keep-alive",
64
- "X-Accel-Buffering": "no"
65
- // Disable buffering in nginx
66
- };
67
- function formatSSEEvent(event) {
68
- return `data: ${JSON.stringify(event)}
69
-
70
- `;
71
- }
72
- function formatSSEErrorEvent(error) {
73
- return `event: error
74
- data: ${JSON.stringify(error)}
75
-
76
- `;
77
- }
78
- async function* parseSseStream(response) {
79
- if (!response.body) {
80
- throw new Error("SSE response body is undefined. Cannot read stream.");
81
- }
82
- let buffer = "";
83
- let eventType = "message";
84
- let eventData = "";
85
- for await (const value of response.body.pipeThrough(new TextDecoderStream())) {
86
- buffer += value;
87
- let lineEndIndex;
88
- while ((lineEndIndex = buffer.indexOf("\n")) >= 0) {
89
- const line = buffer.substring(0, lineEndIndex).trim();
90
- buffer = buffer.substring(lineEndIndex + 1);
91
- if (line === "") {
92
- if (eventData) {
93
- yield { type: eventType, data: eventData };
94
- eventData = "";
95
- eventType = "message";
96
- }
97
- } else if (line.startsWith("event:")) {
98
- eventType = line.substring("event:".length).trim();
99
- } else if (line.startsWith("data:")) {
100
- eventData = line.substring("data:".length).trim();
101
- }
102
- }
103
- }
104
- if (eventData) {
105
- yield { type: eventType, data: eventData };
106
- }
107
- }
108
-
109
59
  export {
110
60
  A2A_ERROR_CODE,
111
61
  TaskNotFoundError,
@@ -114,9 +64,5 @@ export {
114
64
  UnsupportedOperationError,
115
65
  ContentTypeNotSupportedError,
116
66
  InvalidAgentResponseError,
117
- AuthenticatedExtendedCardNotConfiguredError,
118
- SSE_HEADERS,
119
- formatSSEEvent,
120
- formatSSEErrorEvent,
121
- parseSseStream
67
+ AuthenticatedExtendedCardNotConfiguredError
122
68
  };
@@ -0,0 +1,41 @@
1
+ import {
2
+ Extensions
3
+ } from "./chunk-ZX6KNMCP.js";
4
+
5
+ // src/server/context.ts
6
+ var ServerCallContext = class {
7
+ _requestedExtensions;
8
+ _user;
9
+ _activatedExtensions;
10
+ constructor(requestedExtensions, user) {
11
+ this._requestedExtensions = requestedExtensions;
12
+ this._user = user;
13
+ }
14
+ get user() {
15
+ return this._user;
16
+ }
17
+ get activatedExtensions() {
18
+ return this._activatedExtensions;
19
+ }
20
+ get requestedExtensions() {
21
+ return this._requestedExtensions;
22
+ }
23
+ addActivatedExtension(uri) {
24
+ this._activatedExtensions = Extensions.createFrom(this._activatedExtensions, uri);
25
+ }
26
+ };
27
+
28
+ // src/server/authentication/user.ts
29
+ var UnauthenticatedUser = class {
30
+ get isAuthenticated() {
31
+ return false;
32
+ }
33
+ get userName() {
34
+ return "";
35
+ }
36
+ };
37
+
38
+ export {
39
+ ServerCallContext,
40
+ UnauthenticatedUser
41
+ };