@mailmodo/a2a 0.3.3 → 0.3.5
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 +272 -138
- package/dist/a2a_request_handler-DPkhsCMt.d.mts +37 -0
- package/dist/a2a_request_handler-DQfg1Q-R.d.ts +37 -0
- package/dist/auth-handler-DVLcl8yj.d.mts +209 -0
- package/dist/auth-handler-Gzpf3xHC.d.ts +209 -0
- package/dist/chunk-HZFUOBJQ.mjs +198 -0
- package/dist/chunk-LIEYEFQG.mjs +879 -0
- package/dist/chunk-LVD4GF26.mjs +262 -0
- package/dist/chunk-PHP7LM4Y.mjs +8 -0
- package/dist/chunk-UBRSFN2J.mjs +776 -0
- package/dist/client/index.d.mts +312 -0
- package/dist/client/index.d.ts +312 -0
- package/dist/client/index.js +1158 -0
- package/dist/client/index.mjs +367 -0
- package/dist/error-DExKs0Q3.d.mts +233 -0
- package/dist/error-j1vYKII2.d.ts +233 -0
- package/dist/index.d.mts +14 -2739
- package/dist/index.d.ts +14 -2739
- package/dist/index.js +1605 -1158
- package/dist/index.mjs +29 -1612
- package/dist/server/express/index.d.mts +25 -0
- package/dist/server/express/index.d.ts +25 -0
- package/dist/server/express/index.js +468 -0
- package/dist/server/express/index.mjs +10 -0
- package/dist/server/index.d.mts +26 -0
- package/dist/server/index.d.ts +26 -0
- package/dist/server/index.js +1173 -0
- package/dist/server/index.mjs +32 -0
- package/dist/types-Due_Cv6t.d.mts +2550 -0
- package/dist/types-Due_Cv6t.d.ts +2550 -0
- package/package.json +18 -11
package/dist/index.js
CHANGED
|
@@ -1,30 +1,9 @@
|
|
|
1
1
|
var __create = Object.create;
|
|
2
2
|
var __defProp = Object.defineProperty;
|
|
3
|
-
var __defProps = Object.defineProperties;
|
|
4
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
-
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
6
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
-
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
8
5
|
var __getProtoOf = Object.getPrototypeOf;
|
|
9
6
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
10
|
-
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
11
|
-
var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : Symbol.for("Symbol." + name);
|
|
12
|
-
var __typeError = (msg) => {
|
|
13
|
-
throw TypeError(msg);
|
|
14
|
-
};
|
|
15
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
16
|
-
var __spreadValues = (a, b) => {
|
|
17
|
-
for (var prop in b || (b = {}))
|
|
18
|
-
if (__hasOwnProp.call(b, prop))
|
|
19
|
-
__defNormalProp(a, prop, b[prop]);
|
|
20
|
-
if (__getOwnPropSymbols)
|
|
21
|
-
for (var prop of __getOwnPropSymbols(b)) {
|
|
22
|
-
if (__propIsEnum.call(b, prop))
|
|
23
|
-
__defNormalProp(a, prop, b[prop]);
|
|
24
|
-
}
|
|
25
|
-
return a;
|
|
26
|
-
};
|
|
27
|
-
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
28
7
|
var __export = (target, all) => {
|
|
29
8
|
for (var name in all)
|
|
30
9
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -46,70 +25,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
46
25
|
mod
|
|
47
26
|
));
|
|
48
27
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
49
|
-
var __async = (__this, __arguments, generator) => {
|
|
50
|
-
return new Promise((resolve, reject) => {
|
|
51
|
-
var fulfilled = (value) => {
|
|
52
|
-
try {
|
|
53
|
-
step(generator.next(value));
|
|
54
|
-
} catch (e) {
|
|
55
|
-
reject(e);
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
var rejected = (value) => {
|
|
59
|
-
try {
|
|
60
|
-
step(generator.throw(value));
|
|
61
|
-
} catch (e) {
|
|
62
|
-
reject(e);
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
66
|
-
step((generator = generator.apply(__this, __arguments)).next());
|
|
67
|
-
});
|
|
68
|
-
};
|
|
69
|
-
var __await = function(promise, isYieldStar) {
|
|
70
|
-
this[0] = promise;
|
|
71
|
-
this[1] = isYieldStar;
|
|
72
|
-
};
|
|
73
|
-
var __asyncGenerator = (__this, __arguments, generator) => {
|
|
74
|
-
var resume = (k, v, yes, no) => {
|
|
75
|
-
try {
|
|
76
|
-
var x = generator[k](v), isAwait = (v = x.value) instanceof __await, done = x.done;
|
|
77
|
-
Promise.resolve(isAwait ? v[0] : v).then((y) => isAwait ? resume(k === "return" ? k : "next", v[1] ? { done: y.done, value: y.value } : y, yes, no) : yes({ value: y, done })).catch((e) => resume("throw", e, yes, no));
|
|
78
|
-
} catch (e) {
|
|
79
|
-
no(e);
|
|
80
|
-
}
|
|
81
|
-
}, method = (k) => it[k] = (x) => new Promise((yes, no) => resume(k, x, yes, no)), it = {};
|
|
82
|
-
return generator = generator.apply(__this, __arguments), it[__knownSymbol("asyncIterator")] = () => it, method("next"), method("throw"), method("return"), it;
|
|
83
|
-
};
|
|
84
|
-
var __yieldStar = (value) => {
|
|
85
|
-
var obj = value[__knownSymbol("asyncIterator")], isAwait = false, method, it = {};
|
|
86
|
-
if (obj == null) {
|
|
87
|
-
obj = value[__knownSymbol("iterator")]();
|
|
88
|
-
method = (k) => it[k] = (x) => obj[k](x);
|
|
89
|
-
} else {
|
|
90
|
-
obj = obj.call(value);
|
|
91
|
-
method = (k) => it[k] = (v) => {
|
|
92
|
-
if (isAwait) {
|
|
93
|
-
isAwait = false;
|
|
94
|
-
if (k === "throw") throw v;
|
|
95
|
-
return v;
|
|
96
|
-
}
|
|
97
|
-
isAwait = true;
|
|
98
|
-
return {
|
|
99
|
-
done: false,
|
|
100
|
-
value: new __await(new Promise((resolve) => {
|
|
101
|
-
var x = obj[k](v);
|
|
102
|
-
if (!(x instanceof Object)) __typeError("Object expected");
|
|
103
|
-
resolve(x);
|
|
104
|
-
}), 1)
|
|
105
|
-
};
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
return it[__knownSymbol("iterator")] = () => it, method("next"), "throw" in obj ? method("throw") : it.throw = (x) => {
|
|
109
|
-
throw x;
|
|
110
|
-
}, "return" in obj && method("return"), it;
|
|
111
|
-
};
|
|
112
|
-
var __forAwait = (obj, it, method) => (it = obj[__knownSymbol("asyncIterator")]) ? it.call(obj) : (obj = obj[__knownSymbol("iterator")](), it = {}, method = (key, fn) => (fn = obj[key]) && (it[key] = (arg) => new Promise((yes, no, done) => (arg = fn.call(obj, arg), done = arg.done, Promise.resolve(arg.value).then((value) => yes({ value, done }), no)))), method("next"), method("return"), it);
|
|
113
28
|
|
|
114
29
|
// src/index.ts
|
|
115
30
|
var index_exports = {};
|
|
@@ -128,6 +43,7 @@ __export(index_exports, {
|
|
|
128
43
|
ResultManager: () => ResultManager,
|
|
129
44
|
createAuthenticatingFetchWithRetry: () => createAuthenticatingFetchWithRetry,
|
|
130
45
|
getCurrentTimestamp: () => getCurrentTimestamp,
|
|
46
|
+
getRequestedExtensions: () => getRequestedExtensions,
|
|
131
47
|
isArtifactUpdate: () => isArtifactUpdate,
|
|
132
48
|
isObject: () => isObject,
|
|
133
49
|
isTaskStatusUpdate: () => isTaskStatusUpdate
|
|
@@ -136,15 +52,23 @@ module.exports = __toCommonJS(index_exports);
|
|
|
136
52
|
|
|
137
53
|
// src/constants.ts
|
|
138
54
|
var AGENT_CARD_PATH = ".well-known/agent-card.json";
|
|
55
|
+
var HTTP_EXTENSION_HEADER = "X-A2A-Extensions";
|
|
139
56
|
|
|
140
57
|
// src/server/agent_execution/request_context.ts
|
|
141
58
|
var RequestContext = class {
|
|
142
|
-
|
|
59
|
+
userMessage;
|
|
60
|
+
taskId;
|
|
61
|
+
contextId;
|
|
62
|
+
task;
|
|
63
|
+
referenceTasks;
|
|
64
|
+
context;
|
|
65
|
+
constructor(userMessage, taskId, contextId, task, referenceTasks, context) {
|
|
143
66
|
this.userMessage = userMessage;
|
|
144
67
|
this.taskId = taskId;
|
|
145
68
|
this.contextId = contextId;
|
|
146
69
|
this.task = task;
|
|
147
70
|
this.referenceTasks = referenceTasks;
|
|
71
|
+
this.context = context;
|
|
148
72
|
}
|
|
149
73
|
};
|
|
150
74
|
|
|
@@ -164,9 +88,7 @@ var DefaultExecutionEventBus = class extends import_events.EventEmitter {
|
|
|
164
88
|
|
|
165
89
|
// src/server/events/execution_event_bus_manager.ts
|
|
166
90
|
var DefaultExecutionEventBusManager = class {
|
|
167
|
-
|
|
168
|
-
this.taskIdToBus = /* @__PURE__ */ new Map();
|
|
169
|
-
}
|
|
91
|
+
taskIdToBus = /* @__PURE__ */ new Map();
|
|
170
92
|
/**
|
|
171
93
|
* Creates or retrieves an existing ExecutionEventBus based on the taskId.
|
|
172
94
|
* @param taskId The ID of the task.
|
|
@@ -202,45 +124,46 @@ var DefaultExecutionEventBusManager = class {
|
|
|
202
124
|
|
|
203
125
|
// src/server/events/execution_event_queue.ts
|
|
204
126
|
var ExecutionEventQueue = class {
|
|
127
|
+
eventBus;
|
|
128
|
+
eventQueue = [];
|
|
129
|
+
resolvePromise;
|
|
130
|
+
stopped = false;
|
|
131
|
+
boundHandleEvent;
|
|
205
132
|
constructor(eventBus) {
|
|
206
|
-
this.eventQueue = [];
|
|
207
|
-
this.stopped = false;
|
|
208
|
-
this.handleEvent = (event) => {
|
|
209
|
-
if (this.stopped) return;
|
|
210
|
-
this.eventQueue.push(event);
|
|
211
|
-
if (this.resolvePromise) {
|
|
212
|
-
this.resolvePromise();
|
|
213
|
-
this.resolvePromise = void 0;
|
|
214
|
-
}
|
|
215
|
-
};
|
|
216
|
-
this.handleFinished = () => {
|
|
217
|
-
this.stop();
|
|
218
|
-
};
|
|
219
133
|
this.eventBus = eventBus;
|
|
220
134
|
this.eventBus.on("event", this.handleEvent);
|
|
221
135
|
this.eventBus.on("finished", this.handleFinished);
|
|
222
136
|
}
|
|
137
|
+
handleEvent = (event) => {
|
|
138
|
+
if (this.stopped) return;
|
|
139
|
+
this.eventQueue.push(event);
|
|
140
|
+
if (this.resolvePromise) {
|
|
141
|
+
this.resolvePromise();
|
|
142
|
+
this.resolvePromise = void 0;
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
handleFinished = () => {
|
|
146
|
+
this.stop();
|
|
147
|
+
};
|
|
223
148
|
/**
|
|
224
149
|
* Provides an async generator that yields events from the event bus.
|
|
225
150
|
* Stops when a Message event is received or a TaskStatusUpdateEvent with final=true is received.
|
|
226
151
|
*/
|
|
227
|
-
events() {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
break;
|
|
236
|
-
}
|
|
237
|
-
} else if (!this.stopped) {
|
|
238
|
-
yield new __await(new Promise((resolve) => {
|
|
239
|
-
this.resolvePromise = resolve;
|
|
240
|
-
}));
|
|
152
|
+
async *events() {
|
|
153
|
+
while (!this.stopped || this.eventQueue.length > 0) {
|
|
154
|
+
if (this.eventQueue.length > 0) {
|
|
155
|
+
const event = this.eventQueue.shift();
|
|
156
|
+
yield event;
|
|
157
|
+
if (event.kind === "message" || event.kind === "status-update" && event.final) {
|
|
158
|
+
this.handleFinished();
|
|
159
|
+
break;
|
|
241
160
|
}
|
|
161
|
+
} else if (!this.stopped) {
|
|
162
|
+
await new Promise((resolve) => {
|
|
163
|
+
this.resolvePromise = resolve;
|
|
164
|
+
});
|
|
242
165
|
}
|
|
243
|
-
}
|
|
166
|
+
}
|
|
244
167
|
}
|
|
245
168
|
/**
|
|
246
169
|
* Stops the event queue from processing further events.
|
|
@@ -269,12 +192,23 @@ function isTaskStatusUpdate(update) {
|
|
|
269
192
|
function isArtifactUpdate(update) {
|
|
270
193
|
return isObject(update) && "parts" in update;
|
|
271
194
|
}
|
|
195
|
+
function getRequestedExtensions(values) {
|
|
196
|
+
if (!values) {
|
|
197
|
+
return /* @__PURE__ */ new Set();
|
|
198
|
+
}
|
|
199
|
+
return new Set(
|
|
200
|
+
values.split(",").map((ext) => ext.trim()).filter((ext) => ext.length > 0)
|
|
201
|
+
);
|
|
202
|
+
}
|
|
272
203
|
|
|
273
204
|
// src/server/request_handler/default_request_handler.ts
|
|
274
205
|
var import_uuid = require("uuid");
|
|
275
206
|
|
|
276
207
|
// src/server/error.ts
|
|
277
208
|
var A2AError = class _A2AError extends Error {
|
|
209
|
+
code;
|
|
210
|
+
data;
|
|
211
|
+
taskId;
|
|
278
212
|
// Optional task ID context
|
|
279
213
|
constructor(code, message, data, taskId) {
|
|
280
214
|
super(message);
|
|
@@ -304,10 +238,7 @@ var A2AError = class _A2AError extends Error {
|
|
|
304
238
|
return new _A2AError(-32600, message, data);
|
|
305
239
|
}
|
|
306
240
|
static methodNotFound(method) {
|
|
307
|
-
return new _A2AError(
|
|
308
|
-
-32601,
|
|
309
|
-
`Method not found: ${method}`
|
|
310
|
-
);
|
|
241
|
+
return new _A2AError(-32601, `Method not found: ${method}`);
|
|
311
242
|
}
|
|
312
243
|
static invalidParams(message, data) {
|
|
313
244
|
return new _A2AError(-32602, message, data);
|
|
@@ -316,43 +247,29 @@ var A2AError = class _A2AError extends Error {
|
|
|
316
247
|
return new _A2AError(-32603, message, data);
|
|
317
248
|
}
|
|
318
249
|
static taskNotFound(taskId) {
|
|
319
|
-
return new _A2AError(
|
|
320
|
-
-32001,
|
|
321
|
-
`Task not found: ${taskId}`,
|
|
322
|
-
void 0,
|
|
323
|
-
taskId
|
|
324
|
-
);
|
|
250
|
+
return new _A2AError(-32001, `Task not found: ${taskId}`, void 0, taskId);
|
|
325
251
|
}
|
|
326
252
|
static taskNotCancelable(taskId) {
|
|
327
|
-
return new _A2AError(
|
|
328
|
-
-32002,
|
|
329
|
-
`Task not cancelable: ${taskId}`,
|
|
330
|
-
void 0,
|
|
331
|
-
taskId
|
|
332
|
-
);
|
|
253
|
+
return new _A2AError(-32002, `Task not cancelable: ${taskId}`, void 0, taskId);
|
|
333
254
|
}
|
|
334
255
|
static pushNotificationNotSupported() {
|
|
335
|
-
return new _A2AError(
|
|
336
|
-
-32003,
|
|
337
|
-
"Push Notification is not supported"
|
|
338
|
-
);
|
|
256
|
+
return new _A2AError(-32003, "Push Notification is not supported");
|
|
339
257
|
}
|
|
340
258
|
static unsupportedOperation(operation) {
|
|
341
|
-
return new _A2AError(
|
|
342
|
-
-32004,
|
|
343
|
-
`Unsupported operation: ${operation}`
|
|
344
|
-
);
|
|
259
|
+
return new _A2AError(-32004, `Unsupported operation: ${operation}`);
|
|
345
260
|
}
|
|
346
261
|
static authenticatedExtendedCardNotConfigured() {
|
|
347
|
-
return new _A2AError(
|
|
348
|
-
-32007,
|
|
349
|
-
`Extended card not configured.`
|
|
350
|
-
);
|
|
262
|
+
return new _A2AError(-32007, `Extended card not configured.`);
|
|
351
263
|
}
|
|
352
264
|
};
|
|
353
265
|
|
|
354
266
|
// src/server/result_manager.ts
|
|
355
267
|
var ResultManager = class {
|
|
268
|
+
taskStore;
|
|
269
|
+
currentTask;
|
|
270
|
+
latestUserMessage;
|
|
271
|
+
// To add to history if a new task is created
|
|
272
|
+
finalMessageResult;
|
|
356
273
|
// Stores the message if it's the final result
|
|
357
274
|
constructor(taskStore) {
|
|
358
275
|
this.taskStore = taskStore;
|
|
@@ -364,99 +281,117 @@ var ResultManager = class {
|
|
|
364
281
|
* Processes an agent execution event and updates the task store.
|
|
365
282
|
* @param event The agent execution event.
|
|
366
283
|
*/
|
|
367
|
-
processEvent(event) {
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
this.currentTask
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
284
|
+
async processEvent(event) {
|
|
285
|
+
if (event.kind === "message") {
|
|
286
|
+
this.finalMessageResult = event;
|
|
287
|
+
} else if (event.kind === "task") {
|
|
288
|
+
const taskEvent = event;
|
|
289
|
+
this.currentTask = { ...taskEvent };
|
|
290
|
+
if (this.latestUserMessage) {
|
|
291
|
+
if (!this.currentTask.history?.find(
|
|
292
|
+
(msg) => msg.messageId === this.latestUserMessage.messageId
|
|
293
|
+
)) {
|
|
294
|
+
this.currentTask.history = [this.latestUserMessage, ...this.currentTask.history || []];
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
await this.saveCurrentTask();
|
|
298
|
+
} else if (event.kind === "status-update") {
|
|
299
|
+
const updateEvent = event;
|
|
300
|
+
if (this.currentTask && this.currentTask.id === updateEvent.taskId) {
|
|
301
|
+
this.currentTask.status = updateEvent.status;
|
|
302
|
+
if (updateEvent.status.message) {
|
|
303
|
+
if (!this.currentTask.history?.find(
|
|
304
|
+
(msg) => msg.messageId === updateEvent.status.message.messageId
|
|
305
|
+
)) {
|
|
306
|
+
this.currentTask.history = [
|
|
307
|
+
...this.currentTask.history || [],
|
|
308
|
+
updateEvent.status.message
|
|
309
|
+
];
|
|
378
310
|
}
|
|
379
311
|
}
|
|
380
|
-
|
|
381
|
-
} else if (
|
|
382
|
-
const
|
|
383
|
-
if (
|
|
312
|
+
await this.saveCurrentTask();
|
|
313
|
+
} else if (!this.currentTask && updateEvent.taskId) {
|
|
314
|
+
const loaded = await this.taskStore.load(updateEvent.taskId);
|
|
315
|
+
if (loaded) {
|
|
316
|
+
this.currentTask = loaded;
|
|
384
317
|
this.currentTask.status = updateEvent.status;
|
|
385
318
|
if (updateEvent.status.message) {
|
|
386
|
-
if (!
|
|
387
|
-
|
|
319
|
+
if (!this.currentTask.history?.find(
|
|
320
|
+
(msg) => msg.messageId === updateEvent.status.message.messageId
|
|
321
|
+
)) {
|
|
322
|
+
this.currentTask.history = [
|
|
323
|
+
...this.currentTask.history || [],
|
|
324
|
+
updateEvent.status.message
|
|
325
|
+
];
|
|
388
326
|
}
|
|
389
327
|
}
|
|
390
|
-
|
|
391
|
-
} else
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
328
|
+
await this.saveCurrentTask();
|
|
329
|
+
} else {
|
|
330
|
+
console.warn(
|
|
331
|
+
`ResultManager: Received status update for unknown task ${updateEvent.taskId}`
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
} else if (event.kind === "artifact-update") {
|
|
336
|
+
const artifactEvent = event;
|
|
337
|
+
if (this.currentTask && this.currentTask.id === artifactEvent.taskId) {
|
|
338
|
+
if (!this.currentTask.artifacts) {
|
|
339
|
+
this.currentTask.artifacts = [];
|
|
340
|
+
}
|
|
341
|
+
const existingArtifactIndex = this.currentTask.artifacts.findIndex(
|
|
342
|
+
(art) => art.artifactId === artifactEvent.artifact.artifactId
|
|
343
|
+
);
|
|
344
|
+
if (existingArtifactIndex !== -1) {
|
|
345
|
+
if (artifactEvent.append) {
|
|
346
|
+
const existingArtifact = this.currentTask.artifacts[existingArtifactIndex];
|
|
347
|
+
existingArtifact.parts.push(...artifactEvent.artifact.parts);
|
|
348
|
+
if (artifactEvent.artifact.description)
|
|
349
|
+
existingArtifact.description = artifactEvent.artifact.description;
|
|
350
|
+
if (artifactEvent.artifact.name) existingArtifact.name = artifactEvent.artifact.name;
|
|
351
|
+
if (artifactEvent.artifact.metadata)
|
|
352
|
+
existingArtifact.metadata = {
|
|
353
|
+
...existingArtifact.metadata,
|
|
354
|
+
...artifactEvent.artifact.metadata
|
|
355
|
+
};
|
|
402
356
|
} else {
|
|
403
|
-
|
|
357
|
+
this.currentTask.artifacts[existingArtifactIndex] = artifactEvent.artifact;
|
|
404
358
|
}
|
|
359
|
+
} else {
|
|
360
|
+
this.currentTask.artifacts.push(artifactEvent.artifact);
|
|
405
361
|
}
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
362
|
+
await this.saveCurrentTask();
|
|
363
|
+
} else if (!this.currentTask && artifactEvent.taskId) {
|
|
364
|
+
const loaded = await this.taskStore.load(artifactEvent.taskId);
|
|
365
|
+
if (loaded) {
|
|
366
|
+
this.currentTask = loaded;
|
|
367
|
+
if (!this.currentTask.artifacts) this.currentTask.artifacts = [];
|
|
412
368
|
const existingArtifactIndex = this.currentTask.artifacts.findIndex(
|
|
413
369
|
(art) => art.artifactId === artifactEvent.artifact.artifactId
|
|
414
370
|
);
|
|
415
371
|
if (existingArtifactIndex !== -1) {
|
|
416
372
|
if (artifactEvent.append) {
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
if (artifactEvent.artifact.name) existingArtifact.name = artifactEvent.artifact.name;
|
|
421
|
-
if (artifactEvent.artifact.metadata) existingArtifact.metadata = __spreadValues(__spreadValues({}, existingArtifact.metadata), artifactEvent.artifact.metadata);
|
|
373
|
+
this.currentTask.artifacts[existingArtifactIndex].parts.push(
|
|
374
|
+
...artifactEvent.artifact.parts
|
|
375
|
+
);
|
|
422
376
|
} else {
|
|
423
377
|
this.currentTask.artifacts[existingArtifactIndex] = artifactEvent.artifact;
|
|
424
378
|
}
|
|
425
379
|
} else {
|
|
426
380
|
this.currentTask.artifacts.push(artifactEvent.artifact);
|
|
427
381
|
}
|
|
428
|
-
|
|
429
|
-
} else
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
if (!this.currentTask.artifacts) this.currentTask.artifacts = [];
|
|
434
|
-
const existingArtifactIndex = this.currentTask.artifacts.findIndex(
|
|
435
|
-
(art) => art.artifactId === artifactEvent.artifact.artifactId
|
|
436
|
-
);
|
|
437
|
-
if (existingArtifactIndex !== -1) {
|
|
438
|
-
if (artifactEvent.append) {
|
|
439
|
-
this.currentTask.artifacts[existingArtifactIndex].parts.push(...artifactEvent.artifact.parts);
|
|
440
|
-
} else {
|
|
441
|
-
this.currentTask.artifacts[existingArtifactIndex] = artifactEvent.artifact;
|
|
442
|
-
}
|
|
443
|
-
} else {
|
|
444
|
-
this.currentTask.artifacts.push(artifactEvent.artifact);
|
|
445
|
-
}
|
|
446
|
-
yield this.saveCurrentTask();
|
|
447
|
-
} else {
|
|
448
|
-
console.warn(`ResultManager: Received artifact update for unknown task ${artifactEvent.taskId}`);
|
|
449
|
-
}
|
|
382
|
+
await this.saveCurrentTask();
|
|
383
|
+
} else {
|
|
384
|
+
console.warn(
|
|
385
|
+
`ResultManager: Received artifact update for unknown task ${artifactEvent.taskId}`
|
|
386
|
+
);
|
|
450
387
|
}
|
|
451
388
|
}
|
|
452
|
-
}
|
|
389
|
+
}
|
|
453
390
|
}
|
|
454
|
-
saveCurrentTask() {
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
}
|
|
459
|
-
});
|
|
391
|
+
async saveCurrentTask() {
|
|
392
|
+
if (this.currentTask) {
|
|
393
|
+
await this.taskStore.save(this.currentTask);
|
|
394
|
+
}
|
|
460
395
|
}
|
|
461
396
|
/**
|
|
462
397
|
* Gets the final result, which could be a Message or a Task.
|
|
@@ -479,440 +414,623 @@ var ResultManager = class {
|
|
|
479
414
|
}
|
|
480
415
|
};
|
|
481
416
|
|
|
417
|
+
// src/server/push_notification/push_notification_store.ts
|
|
418
|
+
var InMemoryPushNotificationStore = class {
|
|
419
|
+
store = /* @__PURE__ */ new Map();
|
|
420
|
+
async save(taskId, pushNotificationConfig) {
|
|
421
|
+
const configs = this.store.get(taskId) || [];
|
|
422
|
+
if (!pushNotificationConfig.id) {
|
|
423
|
+
pushNotificationConfig.id = taskId;
|
|
424
|
+
}
|
|
425
|
+
const existingIndex = configs.findIndex((config) => config.id === pushNotificationConfig.id);
|
|
426
|
+
if (existingIndex !== -1) {
|
|
427
|
+
configs.splice(existingIndex, 1);
|
|
428
|
+
}
|
|
429
|
+
configs.push(pushNotificationConfig);
|
|
430
|
+
this.store.set(taskId, configs);
|
|
431
|
+
}
|
|
432
|
+
async load(taskId) {
|
|
433
|
+
const configs = this.store.get(taskId);
|
|
434
|
+
return configs || [];
|
|
435
|
+
}
|
|
436
|
+
async delete(taskId, configId) {
|
|
437
|
+
if (configId === void 0) {
|
|
438
|
+
configId = taskId;
|
|
439
|
+
}
|
|
440
|
+
const configs = this.store.get(taskId);
|
|
441
|
+
if (!configs) {
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
const configIndex = configs.findIndex((config) => config.id === configId);
|
|
445
|
+
if (configIndex !== -1) {
|
|
446
|
+
configs.splice(configIndex, 1);
|
|
447
|
+
}
|
|
448
|
+
if (configs.length === 0) {
|
|
449
|
+
this.store.delete(taskId);
|
|
450
|
+
} else {
|
|
451
|
+
this.store.set(taskId, configs);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
};
|
|
455
|
+
|
|
456
|
+
// src/server/push_notification/default_push_notification_sender.ts
|
|
457
|
+
var DefaultPushNotificationSender = class {
|
|
458
|
+
pushNotificationStore;
|
|
459
|
+
notificationChain;
|
|
460
|
+
options;
|
|
461
|
+
constructor(pushNotificationStore, options = {}) {
|
|
462
|
+
this.pushNotificationStore = pushNotificationStore;
|
|
463
|
+
this.notificationChain = /* @__PURE__ */ new Map();
|
|
464
|
+
this.options = {
|
|
465
|
+
timeout: 5e3,
|
|
466
|
+
tokenHeaderName: "X-A2A-Notification-Token",
|
|
467
|
+
...options
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
async send(task) {
|
|
471
|
+
const pushConfigs = await this.pushNotificationStore.load(task.id);
|
|
472
|
+
if (!pushConfigs || pushConfigs.length === 0) {
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
const lastPromise = this.notificationChain.get(task.id) ?? Promise.resolve();
|
|
476
|
+
const newPromise = lastPromise.then(async () => {
|
|
477
|
+
const dispatches = pushConfigs.map(async (pushConfig) => {
|
|
478
|
+
try {
|
|
479
|
+
await this._dispatchNotification(task, pushConfig);
|
|
480
|
+
} catch (error) {
|
|
481
|
+
console.error(
|
|
482
|
+
`Error sending push notification for task_id=${task.id} to URL: ${pushConfig.url}. Error:`,
|
|
483
|
+
error
|
|
484
|
+
);
|
|
485
|
+
}
|
|
486
|
+
});
|
|
487
|
+
await Promise.all(dispatches);
|
|
488
|
+
});
|
|
489
|
+
this.notificationChain.set(task.id, newPromise);
|
|
490
|
+
newPromise.finally(() => {
|
|
491
|
+
if (this.notificationChain.get(task.id) === newPromise) {
|
|
492
|
+
this.notificationChain.delete(task.id);
|
|
493
|
+
}
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
async _dispatchNotification(task, pushConfig) {
|
|
497
|
+
const url = pushConfig.url;
|
|
498
|
+
const controller = new AbortController();
|
|
499
|
+
const timeoutId = setTimeout(() => controller.abort(), this.options.timeout);
|
|
500
|
+
try {
|
|
501
|
+
const headers = {
|
|
502
|
+
"Content-Type": "application/json"
|
|
503
|
+
};
|
|
504
|
+
if (pushConfig.token) {
|
|
505
|
+
headers[this.options.tokenHeaderName] = pushConfig.token;
|
|
506
|
+
}
|
|
507
|
+
const response = await fetch(url, {
|
|
508
|
+
method: "POST",
|
|
509
|
+
headers,
|
|
510
|
+
body: JSON.stringify(task),
|
|
511
|
+
signal: controller.signal
|
|
512
|
+
});
|
|
513
|
+
if (!response.ok) {
|
|
514
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
515
|
+
}
|
|
516
|
+
console.info(`Push notification sent for task_id=${task.id} to URL: ${url}`);
|
|
517
|
+
} finally {
|
|
518
|
+
clearTimeout(timeoutId);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
};
|
|
522
|
+
|
|
523
|
+
// src/server/context.ts
|
|
524
|
+
var ServerCallContext = class {
|
|
525
|
+
_requestedExtensions;
|
|
526
|
+
_user;
|
|
527
|
+
_activatedExtensions;
|
|
528
|
+
constructor(requestedExtensions, user) {
|
|
529
|
+
this._requestedExtensions = requestedExtensions;
|
|
530
|
+
this._user = user;
|
|
531
|
+
}
|
|
532
|
+
get user() {
|
|
533
|
+
return this._user;
|
|
534
|
+
}
|
|
535
|
+
get activatedExtensions() {
|
|
536
|
+
return this._activatedExtensions;
|
|
537
|
+
}
|
|
538
|
+
get requestedExtensions() {
|
|
539
|
+
return this._requestedExtensions;
|
|
540
|
+
}
|
|
541
|
+
addActivatedExtension(uri) {
|
|
542
|
+
if (this._requestedExtensions?.has(uri)) {
|
|
543
|
+
if (!this._activatedExtensions) {
|
|
544
|
+
this._activatedExtensions = /* @__PURE__ */ new Set();
|
|
545
|
+
}
|
|
546
|
+
this._activatedExtensions.add(uri);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
};
|
|
550
|
+
|
|
482
551
|
// src/server/request_handler/default_request_handler.ts
|
|
483
552
|
var terminalStates = ["completed", "failed", "canceled", "rejected"];
|
|
484
553
|
var DefaultRequestHandler = class {
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
554
|
+
agentCard;
|
|
555
|
+
taskStore;
|
|
556
|
+
agentExecutor;
|
|
557
|
+
eventBusManager;
|
|
558
|
+
pushNotificationStore;
|
|
559
|
+
pushNotificationSender;
|
|
560
|
+
extendedAgentCardProvider;
|
|
561
|
+
constructor(agentCard, taskStore, agentExecutor, eventBusManager = new DefaultExecutionEventBusManager(), pushNotificationStore, pushNotificationSender, extendedAgentCardProvider) {
|
|
488
562
|
this.agentCard = agentCard;
|
|
489
563
|
this.taskStore = taskStore;
|
|
490
564
|
this.agentExecutor = agentExecutor;
|
|
491
565
|
this.eventBusManager = eventBusManager;
|
|
492
|
-
this.
|
|
566
|
+
this.extendedAgentCardProvider = extendedAgentCardProvider;
|
|
567
|
+
if (agentCard.capabilities.pushNotifications) {
|
|
568
|
+
this.pushNotificationStore = pushNotificationStore || new InMemoryPushNotificationStore();
|
|
569
|
+
this.pushNotificationSender = pushNotificationSender || new DefaultPushNotificationSender(this.pushNotificationStore);
|
|
570
|
+
}
|
|
493
571
|
}
|
|
494
|
-
getAgentCard() {
|
|
495
|
-
return
|
|
496
|
-
return this.agentCard;
|
|
497
|
-
});
|
|
572
|
+
async getAgentCard() {
|
|
573
|
+
return this.agentCard;
|
|
498
574
|
}
|
|
499
|
-
getAuthenticatedExtendedAgentCard() {
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
}
|
|
575
|
+
async getAuthenticatedExtendedAgentCard(context) {
|
|
576
|
+
if (!this.agentCard.supportsAuthenticatedExtendedCard) {
|
|
577
|
+
throw A2AError.unsupportedOperation("Agent does not support authenticated extended card.");
|
|
578
|
+
}
|
|
579
|
+
if (!this.extendedAgentCardProvider) {
|
|
580
|
+
throw A2AError.authenticatedExtendedCardNotConfigured();
|
|
581
|
+
}
|
|
582
|
+
if (typeof this.extendedAgentCardProvider === "function") {
|
|
583
|
+
return this.extendedAgentCardProvider(context);
|
|
584
|
+
}
|
|
585
|
+
if (context?.user?.isAuthenticated) {
|
|
586
|
+
return this.extendedAgentCardProvider;
|
|
587
|
+
}
|
|
588
|
+
return this.agentCard;
|
|
506
589
|
}
|
|
507
|
-
_createRequestContext(incomingMessage,
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
throw A2AError.taskNotFound(incomingMessage.taskId);
|
|
515
|
-
}
|
|
516
|
-
if (terminalStates.includes(task.status.state)) {
|
|
517
|
-
throw A2AError.invalidRequest(`Task ${task.id} is in a terminal state (${task.status.state}) and cannot be modified.`);
|
|
518
|
-
}
|
|
590
|
+
async _createRequestContext(incomingMessage, context) {
|
|
591
|
+
let task;
|
|
592
|
+
let referenceTasks;
|
|
593
|
+
if (incomingMessage.taskId) {
|
|
594
|
+
task = await this.taskStore.load(incomingMessage.taskId);
|
|
595
|
+
if (!task) {
|
|
596
|
+
throw A2AError.taskNotFound(incomingMessage.taskId);
|
|
519
597
|
}
|
|
520
|
-
if (
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
598
|
+
if (terminalStates.includes(task.status.state)) {
|
|
599
|
+
throw A2AError.invalidRequest(
|
|
600
|
+
`Task ${task.id} is in a terminal state (${task.status.state}) and cannot be modified.`
|
|
601
|
+
);
|
|
602
|
+
}
|
|
603
|
+
task.history = [...task.history || [], incomingMessage];
|
|
604
|
+
await this.taskStore.save(task);
|
|
605
|
+
}
|
|
606
|
+
const taskId = incomingMessage.taskId || (0, import_uuid.v4)();
|
|
607
|
+
if (incomingMessage.referenceTaskIds && incomingMessage.referenceTaskIds.length > 0) {
|
|
608
|
+
referenceTasks = [];
|
|
609
|
+
for (const refId of incomingMessage.referenceTaskIds) {
|
|
610
|
+
const refTask = await this.taskStore.load(refId);
|
|
611
|
+
if (refTask) {
|
|
612
|
+
referenceTasks.push(refTask);
|
|
613
|
+
} else {
|
|
614
|
+
console.warn(`Reference task ${refId} not found.`);
|
|
529
615
|
}
|
|
530
616
|
}
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
taskId,
|
|
538
|
-
contextId,
|
|
539
|
-
task,
|
|
540
|
-
referenceTasks
|
|
617
|
+
}
|
|
618
|
+
const contextId = incomingMessage.contextId || task?.contextId || (0, import_uuid.v4)();
|
|
619
|
+
if (context?.requestedExtensions) {
|
|
620
|
+
const agentCard = await this.getAgentCard();
|
|
621
|
+
const exposedExtensions = new Set(
|
|
622
|
+
agentCard.capabilities.extensions?.map((ext) => ext.uri) || []
|
|
541
623
|
);
|
|
542
|
-
|
|
624
|
+
const validExtensions = new Set(
|
|
625
|
+
Array.from(context.requestedExtensions).filter(
|
|
626
|
+
(extension) => exposedExtensions.has(extension)
|
|
627
|
+
)
|
|
628
|
+
);
|
|
629
|
+
context = new ServerCallContext(validExtensions, context.user);
|
|
630
|
+
}
|
|
631
|
+
const messageForContext = {
|
|
632
|
+
...incomingMessage,
|
|
633
|
+
contextId,
|
|
634
|
+
taskId
|
|
635
|
+
};
|
|
636
|
+
return new RequestContext(messageForContext, taskId, contextId, task, referenceTasks, context);
|
|
543
637
|
}
|
|
544
|
-
_processEvents(taskId, resultManager, eventQueue, options) {
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
638
|
+
async _processEvents(taskId, resultManager, eventQueue, options) {
|
|
639
|
+
let firstResultSent = false;
|
|
640
|
+
try {
|
|
641
|
+
for await (const event of eventQueue.events()) {
|
|
642
|
+
await resultManager.processEvent(event);
|
|
548
643
|
try {
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
644
|
+
await this._sendPushNotificationIfNeeded(event);
|
|
645
|
+
} catch (error) {
|
|
646
|
+
console.error(`Error sending push notification: ${error}`);
|
|
647
|
+
}
|
|
648
|
+
if (options?.firstResultResolver && !firstResultSent) {
|
|
649
|
+
let firstResult;
|
|
650
|
+
if (event.kind === "message") {
|
|
651
|
+
firstResult = event;
|
|
652
|
+
} else {
|
|
653
|
+
firstResult = resultManager.getCurrentTask();
|
|
558
654
|
}
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
try {
|
|
563
|
-
more && (temp = iter.return) && (yield temp.call(iter));
|
|
564
|
-
} finally {
|
|
565
|
-
if (error)
|
|
566
|
-
throw error[0];
|
|
655
|
+
if (firstResult) {
|
|
656
|
+
options.firstResultResolver(firstResult);
|
|
657
|
+
firstResultSent = true;
|
|
567
658
|
}
|
|
568
659
|
}
|
|
569
|
-
if ((options == null ? void 0 : options.firstResultRejector) && !firstResultSent) {
|
|
570
|
-
options.firstResultRejector(A2AError.internalError("Execution finished before a message or task was produced."));
|
|
571
|
-
}
|
|
572
|
-
} catch (error2) {
|
|
573
|
-
console.error(`Event processing loop failed for task ${taskId}:`, error2);
|
|
574
|
-
if ((options == null ? void 0 : options.firstResultRejector) && !firstResultSent) {
|
|
575
|
-
options.firstResultRejector(error2);
|
|
576
|
-
}
|
|
577
|
-
throw error2;
|
|
578
|
-
} finally {
|
|
579
|
-
this.eventBusManager.cleanupByTaskId(taskId);
|
|
580
|
-
}
|
|
581
|
-
});
|
|
582
|
-
}
|
|
583
|
-
sendMessage(params) {
|
|
584
|
-
return __async(this, null, function* () {
|
|
585
|
-
var _a;
|
|
586
|
-
const incomingMessage = params.message;
|
|
587
|
-
if (!incomingMessage.messageId) {
|
|
588
|
-
throw A2AError.invalidParams("message.messageId is required.");
|
|
589
660
|
}
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
const requestContext = yield this._createRequestContext(incomingMessage, taskId, false);
|
|
595
|
-
const finalMessageForAgent = requestContext.userMessage;
|
|
596
|
-
const eventBus = this.eventBusManager.createOrGetByTaskId(taskId);
|
|
597
|
-
const eventQueue = new ExecutionEventQueue(eventBus);
|
|
598
|
-
this.agentExecutor.execute(requestContext, eventBus).catch((err) => {
|
|
599
|
-
var _a2, _b, _c, _d, _e;
|
|
600
|
-
console.error(`Agent execution failed for message ${finalMessageForAgent.messageId}:`, err);
|
|
601
|
-
const errorTask = {
|
|
602
|
-
id: ((_a2 = requestContext.task) == null ? void 0 : _a2.id) || (0, import_uuid.v4)(),
|
|
603
|
-
// Use existing task ID or generate new
|
|
604
|
-
contextId: finalMessageForAgent.contextId,
|
|
605
|
-
status: {
|
|
606
|
-
state: "failed",
|
|
607
|
-
message: {
|
|
608
|
-
kind: "message",
|
|
609
|
-
role: "agent",
|
|
610
|
-
messageId: (0, import_uuid.v4)(),
|
|
611
|
-
parts: [{ kind: "text", text: `Agent execution error: ${err.message}` }],
|
|
612
|
-
taskId: (_b = requestContext.task) == null ? void 0 : _b.id,
|
|
613
|
-
contextId: finalMessageForAgent.contextId
|
|
614
|
-
},
|
|
615
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
616
|
-
},
|
|
617
|
-
history: ((_c = requestContext.task) == null ? void 0 : _c.history) ? [...requestContext.task.history] : [],
|
|
618
|
-
kind: "task"
|
|
619
|
-
};
|
|
620
|
-
if (finalMessageForAgent) {
|
|
621
|
-
if (!((_d = errorTask.history) == null ? void 0 : _d.find((m) => m.messageId === finalMessageForAgent.messageId))) {
|
|
622
|
-
(_e = errorTask.history) == null ? void 0 : _e.push(finalMessageForAgent);
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
eventBus.publish(errorTask);
|
|
626
|
-
eventBus.publish({
|
|
627
|
-
// And publish a final status update
|
|
628
|
-
kind: "status-update",
|
|
629
|
-
taskId: errorTask.id,
|
|
630
|
-
contextId: errorTask.contextId,
|
|
631
|
-
status: errorTask.status,
|
|
632
|
-
final: true
|
|
633
|
-
});
|
|
634
|
-
eventBus.finished();
|
|
635
|
-
});
|
|
636
|
-
if (isBlocking) {
|
|
637
|
-
yield this._processEvents(taskId, resultManager, eventQueue);
|
|
638
|
-
const finalResult = resultManager.getFinalResult();
|
|
639
|
-
if (!finalResult) {
|
|
640
|
-
throw A2AError.internalError("Agent execution finished without a result, and no task context found.");
|
|
641
|
-
}
|
|
642
|
-
return finalResult;
|
|
643
|
-
} else {
|
|
644
|
-
return new Promise((resolve, reject) => {
|
|
645
|
-
this._processEvents(taskId, resultManager, eventQueue, {
|
|
646
|
-
firstResultResolver: resolve,
|
|
647
|
-
firstResultRejector: reject
|
|
648
|
-
});
|
|
649
|
-
});
|
|
661
|
+
if (options?.firstResultRejector && !firstResultSent) {
|
|
662
|
+
options.firstResultRejector(
|
|
663
|
+
A2AError.internalError("Execution finished before a message or task was produced.")
|
|
664
|
+
);
|
|
650
665
|
}
|
|
651
|
-
})
|
|
666
|
+
} catch (error) {
|
|
667
|
+
console.error(`Event processing loop failed for task ${taskId}:`, error);
|
|
668
|
+
this._handleProcessingError(
|
|
669
|
+
error,
|
|
670
|
+
resultManager,
|
|
671
|
+
firstResultSent,
|
|
672
|
+
taskId,
|
|
673
|
+
options?.firstResultRejector
|
|
674
|
+
);
|
|
675
|
+
} finally {
|
|
676
|
+
this.eventBusManager.cleanupByTaskId(taskId);
|
|
677
|
+
}
|
|
652
678
|
}
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
679
|
+
async sendMessage(params, context) {
|
|
680
|
+
const incomingMessage = params.message;
|
|
681
|
+
if (!incomingMessage.messageId) {
|
|
682
|
+
throw A2AError.invalidParams("message.messageId is required.");
|
|
683
|
+
}
|
|
684
|
+
const isBlocking = params.configuration?.blocking !== false;
|
|
685
|
+
const resultManager = new ResultManager(this.taskStore);
|
|
686
|
+
resultManager.setContext(incomingMessage);
|
|
687
|
+
const requestContext = await this._createRequestContext(incomingMessage, context);
|
|
688
|
+
const taskId = requestContext.taskId;
|
|
689
|
+
const finalMessageForAgent = requestContext.userMessage;
|
|
690
|
+
if (params.configuration?.pushNotificationConfig && this.agentCard.capabilities.pushNotifications) {
|
|
691
|
+
await this.pushNotificationStore?.save(taskId, params.configuration.pushNotificationConfig);
|
|
692
|
+
}
|
|
693
|
+
const eventBus = this.eventBusManager.createOrGetByTaskId(taskId);
|
|
694
|
+
const eventQueue = new ExecutionEventQueue(eventBus);
|
|
695
|
+
this.agentExecutor.execute(requestContext, eventBus).catch((err) => {
|
|
696
|
+
console.error(`Agent execution failed for message ${finalMessageForAgent.messageId}:`, err);
|
|
697
|
+
const errorTask = {
|
|
698
|
+
id: requestContext.task?.id || (0, import_uuid.v4)(),
|
|
699
|
+
// Use existing task ID or generate new
|
|
700
|
+
contextId: finalMessageForAgent.contextId,
|
|
701
|
+
status: {
|
|
702
|
+
state: "failed",
|
|
703
|
+
message: {
|
|
704
|
+
kind: "message",
|
|
705
|
+
role: "agent",
|
|
706
|
+
messageId: (0, import_uuid.v4)(),
|
|
707
|
+
parts: [{ kind: "text", text: `Agent execution error: ${err.message}` }],
|
|
708
|
+
taskId: requestContext.task?.id,
|
|
709
|
+
contextId: finalMessageForAgent.contextId
|
|
685
710
|
},
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
const event = temp.value;
|
|
695
|
-
yield new __await(resultManager.processEvent(event));
|
|
696
|
-
yield event;
|
|
697
|
-
}
|
|
698
|
-
} catch (temp) {
|
|
699
|
-
error = [temp];
|
|
700
|
-
} finally {
|
|
701
|
-
try {
|
|
702
|
-
more && (temp = iter.return) && (yield new __await(temp.call(iter)));
|
|
703
|
-
} finally {
|
|
704
|
-
if (error)
|
|
705
|
-
throw error[0];
|
|
706
|
-
}
|
|
711
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
712
|
+
},
|
|
713
|
+
history: requestContext.task?.history ? [...requestContext.task.history] : [],
|
|
714
|
+
kind: "task"
|
|
715
|
+
};
|
|
716
|
+
if (finalMessageForAgent) {
|
|
717
|
+
if (!errorTask.history?.find((m) => m.messageId === finalMessageForAgent.messageId)) {
|
|
718
|
+
errorTask.history?.push(finalMessageForAgent);
|
|
707
719
|
}
|
|
708
|
-
} finally {
|
|
709
|
-
this.eventBusManager.cleanupByTaskId(taskId);
|
|
710
720
|
}
|
|
721
|
+
eventBus.publish(errorTask);
|
|
722
|
+
eventBus.publish({
|
|
723
|
+
// And publish a final status update
|
|
724
|
+
kind: "status-update",
|
|
725
|
+
taskId: errorTask.id,
|
|
726
|
+
contextId: errorTask.contextId,
|
|
727
|
+
status: errorTask.status,
|
|
728
|
+
final: true
|
|
729
|
+
});
|
|
730
|
+
eventBus.finished();
|
|
711
731
|
});
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
if (params.historyLength !== void 0 && params.historyLength >= 0) {
|
|
720
|
-
if (task.history) {
|
|
721
|
-
task.history = task.history.slice(-params.historyLength);
|
|
722
|
-
}
|
|
723
|
-
} else {
|
|
724
|
-
task.history = [];
|
|
732
|
+
if (isBlocking) {
|
|
733
|
+
await this._processEvents(taskId, resultManager, eventQueue);
|
|
734
|
+
const finalResult = resultManager.getFinalResult();
|
|
735
|
+
if (!finalResult) {
|
|
736
|
+
throw A2AError.internalError(
|
|
737
|
+
"Agent execution finished without a result, and no task context found."
|
|
738
|
+
);
|
|
725
739
|
}
|
|
726
|
-
return
|
|
727
|
-
}
|
|
740
|
+
return finalResult;
|
|
741
|
+
} else {
|
|
742
|
+
return new Promise((resolve, reject) => {
|
|
743
|
+
this._processEvents(taskId, resultManager, eventQueue, {
|
|
744
|
+
firstResultResolver: resolve,
|
|
745
|
+
firstResultRejector: reject
|
|
746
|
+
});
|
|
747
|
+
});
|
|
748
|
+
}
|
|
728
749
|
}
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
750
|
+
async *sendMessageStream(params, context) {
|
|
751
|
+
const incomingMessage = params.message;
|
|
752
|
+
if (!incomingMessage.messageId) {
|
|
753
|
+
throw A2AError.invalidParams("message.messageId is required for streaming.");
|
|
754
|
+
}
|
|
755
|
+
const resultManager = new ResultManager(this.taskStore);
|
|
756
|
+
resultManager.setContext(incomingMessage);
|
|
757
|
+
const requestContext = await this._createRequestContext(incomingMessage, context);
|
|
758
|
+
const taskId = requestContext.taskId;
|
|
759
|
+
const finalMessageForAgent = requestContext.userMessage;
|
|
760
|
+
const eventBus = this.eventBusManager.createOrGetByTaskId(taskId);
|
|
761
|
+
const eventQueue = new ExecutionEventQueue(eventBus);
|
|
762
|
+
if (params.configuration?.pushNotificationConfig && this.agentCard.capabilities.pushNotifications) {
|
|
763
|
+
await this.pushNotificationStore?.save(taskId, params.configuration.pushNotificationConfig);
|
|
764
|
+
}
|
|
765
|
+
this.agentExecutor.execute(requestContext, eventBus).catch((err) => {
|
|
766
|
+
console.error(
|
|
767
|
+
`Agent execution failed for stream message ${finalMessageForAgent.messageId}:`,
|
|
768
|
+
err
|
|
769
|
+
);
|
|
770
|
+
const errorTaskStatus = {
|
|
771
|
+
kind: "status-update",
|
|
772
|
+
taskId: requestContext.task?.id || (0, import_uuid.v4)(),
|
|
773
|
+
// Use existing or a placeholder
|
|
774
|
+
contextId: finalMessageForAgent.contextId,
|
|
775
|
+
status: {
|
|
776
|
+
state: "failed",
|
|
745
777
|
message: {
|
|
746
|
-
// Optional: Add a system message indicating cancellation
|
|
747
778
|
kind: "message",
|
|
748
779
|
role: "agent",
|
|
749
780
|
messageId: (0, import_uuid.v4)(),
|
|
750
|
-
parts: [{ kind: "text", text:
|
|
751
|
-
taskId: task
|
|
752
|
-
contextId:
|
|
781
|
+
parts: [{ kind: "text", text: `Agent execution error: ${err.message}` }],
|
|
782
|
+
taskId: requestContext.task?.id,
|
|
783
|
+
contextId: finalMessageForAgent.contextId
|
|
753
784
|
},
|
|
754
785
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
755
|
-
}
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
}
|
|
759
|
-
|
|
760
|
-
return latestTask;
|
|
786
|
+
},
|
|
787
|
+
final: true
|
|
788
|
+
// This will terminate the stream for the client
|
|
789
|
+
};
|
|
790
|
+
eventBus.publish(errorTaskStatus);
|
|
761
791
|
});
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
}
|
|
768
|
-
const task = yield this.taskStore.load(params.taskId);
|
|
769
|
-
if (!task) {
|
|
770
|
-
throw A2AError.taskNotFound(params.taskId);
|
|
771
|
-
}
|
|
772
|
-
const { taskId, pushNotificationConfig } = params;
|
|
773
|
-
if (!pushNotificationConfig.id) {
|
|
774
|
-
pushNotificationConfig.id = taskId;
|
|
792
|
+
try {
|
|
793
|
+
for await (const event of eventQueue.events()) {
|
|
794
|
+
await resultManager.processEvent(event);
|
|
795
|
+
await this._sendPushNotificationIfNeeded(event);
|
|
796
|
+
yield event;
|
|
775
797
|
}
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
this.pushNotificationConfigs.set(taskId, updatedConfigs);
|
|
780
|
-
return params;
|
|
781
|
-
});
|
|
798
|
+
} finally {
|
|
799
|
+
this.eventBusManager.cleanupByTaskId(taskId);
|
|
800
|
+
}
|
|
782
801
|
}
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
if (
|
|
790
|
-
|
|
791
|
-
}
|
|
792
|
-
const configs = this.pushNotificationConfigs.get(params.id) || [];
|
|
793
|
-
if (configs.length === 0) {
|
|
794
|
-
throw A2AError.internalError(`Push notification config not found for task ${params.id}.`);
|
|
795
|
-
}
|
|
796
|
-
let configId;
|
|
797
|
-
if ("pushNotificationConfigId" in params && params.pushNotificationConfigId) {
|
|
798
|
-
configId = params.pushNotificationConfigId;
|
|
799
|
-
} else {
|
|
800
|
-
configId = params.id;
|
|
801
|
-
}
|
|
802
|
-
const config = configs.find((c) => c.id === configId);
|
|
803
|
-
if (!config) {
|
|
804
|
-
throw A2AError.internalError(`Push notification config with id '${configId}' not found for task ${params.id}.`);
|
|
802
|
+
async getTask(params, _context) {
|
|
803
|
+
const task = await this.taskStore.load(params.id);
|
|
804
|
+
if (!task) {
|
|
805
|
+
throw A2AError.taskNotFound(params.id);
|
|
806
|
+
}
|
|
807
|
+
if (params.historyLength !== void 0 && params.historyLength >= 0) {
|
|
808
|
+
if (task.history) {
|
|
809
|
+
task.history = task.history.slice(-params.historyLength);
|
|
805
810
|
}
|
|
806
|
-
|
|
807
|
-
|
|
811
|
+
} else {
|
|
812
|
+
task.history = [];
|
|
813
|
+
}
|
|
814
|
+
return task;
|
|
808
815
|
}
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
}
|
|
816
|
+
async cancelTask(params, _context) {
|
|
817
|
+
const task = await this.taskStore.load(params.id);
|
|
818
|
+
if (!task) {
|
|
819
|
+
throw A2AError.taskNotFound(params.id);
|
|
820
|
+
}
|
|
821
|
+
const nonCancelableStates = ["completed", "failed", "canceled", "rejected"];
|
|
822
|
+
if (nonCancelableStates.includes(task.status.state)) {
|
|
823
|
+
throw A2AError.taskNotCancelable(params.id);
|
|
824
|
+
}
|
|
825
|
+
const eventBus = this.eventBusManager.getByTaskId(params.id);
|
|
826
|
+
if (eventBus) {
|
|
827
|
+
const eventQueue = new ExecutionEventQueue(eventBus);
|
|
828
|
+
await this.agentExecutor.cancelTask(params.id, eventBus);
|
|
829
|
+
await this._processEvents(params.id, new ResultManager(this.taskStore), eventQueue);
|
|
830
|
+
} else {
|
|
831
|
+
task.status = {
|
|
832
|
+
state: "canceled",
|
|
833
|
+
message: {
|
|
834
|
+
// Optional: Add a system message indicating cancellation
|
|
835
|
+
kind: "message",
|
|
836
|
+
role: "agent",
|
|
837
|
+
messageId: (0, import_uuid.v4)(),
|
|
838
|
+
parts: [{ kind: "text", text: "Task cancellation requested by user." }],
|
|
839
|
+
taskId: task.id,
|
|
840
|
+
contextId: task.contextId
|
|
841
|
+
},
|
|
842
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
843
|
+
};
|
|
844
|
+
task.history = [...task.history || [], task.status.message];
|
|
845
|
+
await this.taskStore.save(task);
|
|
846
|
+
}
|
|
847
|
+
const latestTask = await this.taskStore.load(params.id);
|
|
848
|
+
if (!latestTask) {
|
|
849
|
+
throw A2AError.internalError(`Task ${params.id} not found after cancellation.`);
|
|
850
|
+
}
|
|
851
|
+
if (latestTask.status.state != "canceled") {
|
|
852
|
+
throw A2AError.taskNotCancelable(params.id);
|
|
853
|
+
}
|
|
854
|
+
return latestTask;
|
|
824
855
|
}
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
const updatedConfigs = configs.filter((c) => c.id !== pushNotificationConfigId);
|
|
840
|
-
if (updatedConfigs.length === 0) {
|
|
841
|
-
this.pushNotificationConfigs.delete(taskId);
|
|
842
|
-
} else if (updatedConfigs.length < configs.length) {
|
|
843
|
-
this.pushNotificationConfigs.set(taskId, updatedConfigs);
|
|
844
|
-
}
|
|
845
|
-
});
|
|
856
|
+
async setTaskPushNotificationConfig(params, _context) {
|
|
857
|
+
if (!this.agentCard.capabilities.pushNotifications) {
|
|
858
|
+
throw A2AError.pushNotificationNotSupported();
|
|
859
|
+
}
|
|
860
|
+
const task = await this.taskStore.load(params.taskId);
|
|
861
|
+
if (!task) {
|
|
862
|
+
throw A2AError.taskNotFound(params.taskId);
|
|
863
|
+
}
|
|
864
|
+
const { taskId, pushNotificationConfig } = params;
|
|
865
|
+
if (!pushNotificationConfig.id) {
|
|
866
|
+
pushNotificationConfig.id = taskId;
|
|
867
|
+
}
|
|
868
|
+
await this.pushNotificationStore?.save(taskId, pushNotificationConfig);
|
|
869
|
+
return params;
|
|
846
870
|
}
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
871
|
+
async getTaskPushNotificationConfig(params, _context) {
|
|
872
|
+
if (!this.agentCard.capabilities.pushNotifications) {
|
|
873
|
+
throw A2AError.pushNotificationNotSupported();
|
|
874
|
+
}
|
|
875
|
+
const task = await this.taskStore.load(params.id);
|
|
876
|
+
if (!task) {
|
|
877
|
+
throw A2AError.taskNotFound(params.id);
|
|
878
|
+
}
|
|
879
|
+
const configs = await this.pushNotificationStore?.load(params.id) || [];
|
|
880
|
+
if (configs.length === 0) {
|
|
881
|
+
throw A2AError.internalError(`Push notification config not found for task ${params.id}.`);
|
|
882
|
+
}
|
|
883
|
+
let configId;
|
|
884
|
+
if ("pushNotificationConfigId" in params && params.pushNotificationConfigId) {
|
|
885
|
+
configId = params.pushNotificationConfigId;
|
|
886
|
+
} else {
|
|
887
|
+
configId = params.id;
|
|
888
|
+
}
|
|
889
|
+
const config = configs.find((c) => c.id === configId);
|
|
890
|
+
if (!config) {
|
|
891
|
+
throw A2AError.internalError(
|
|
892
|
+
`Push notification config with id '${configId}' not found for task ${params.id}.`
|
|
893
|
+
);
|
|
894
|
+
}
|
|
895
|
+
return { taskId: params.id, pushNotificationConfig: config };
|
|
896
|
+
}
|
|
897
|
+
async listTaskPushNotificationConfigs(params, _context) {
|
|
898
|
+
if (!this.agentCard.capabilities.pushNotifications) {
|
|
899
|
+
throw A2AError.pushNotificationNotSupported();
|
|
900
|
+
}
|
|
901
|
+
const task = await this.taskStore.load(params.id);
|
|
902
|
+
if (!task) {
|
|
903
|
+
throw A2AError.taskNotFound(params.id);
|
|
904
|
+
}
|
|
905
|
+
const configs = await this.pushNotificationStore?.load(params.id) || [];
|
|
906
|
+
return configs.map((config) => ({
|
|
907
|
+
taskId: params.id,
|
|
908
|
+
pushNotificationConfig: config
|
|
909
|
+
}));
|
|
910
|
+
}
|
|
911
|
+
async deleteTaskPushNotificationConfig(params, _context) {
|
|
912
|
+
if (!this.agentCard.capabilities.pushNotifications) {
|
|
913
|
+
throw A2AError.pushNotificationNotSupported();
|
|
914
|
+
}
|
|
915
|
+
const task = await this.taskStore.load(params.id);
|
|
916
|
+
if (!task) {
|
|
917
|
+
throw A2AError.taskNotFound(params.id);
|
|
918
|
+
}
|
|
919
|
+
const { id: taskId, pushNotificationConfigId } = params;
|
|
920
|
+
await this.pushNotificationStore?.delete(taskId, pushNotificationConfigId);
|
|
921
|
+
}
|
|
922
|
+
async *resubscribe(params, _context) {
|
|
923
|
+
if (!this.agentCard.capabilities.streaming) {
|
|
924
|
+
throw A2AError.unsupportedOperation("Streaming (and thus resubscription) is not supported.");
|
|
925
|
+
}
|
|
926
|
+
const task = await this.taskStore.load(params.id);
|
|
927
|
+
if (!task) {
|
|
928
|
+
throw A2AError.taskNotFound(params.id);
|
|
929
|
+
}
|
|
930
|
+
yield task;
|
|
931
|
+
const finalStates = ["completed", "failed", "canceled", "rejected"];
|
|
932
|
+
if (finalStates.includes(task.status.state)) {
|
|
933
|
+
return;
|
|
934
|
+
}
|
|
935
|
+
const eventBus = this.eventBusManager.getByTaskId(params.id);
|
|
936
|
+
if (!eventBus) {
|
|
937
|
+
console.warn(`Resubscribe: No active event bus for task ${params.id}.`);
|
|
938
|
+
return;
|
|
939
|
+
}
|
|
940
|
+
const eventQueue = new ExecutionEventQueue(eventBus);
|
|
941
|
+
try {
|
|
942
|
+
for await (const event of eventQueue.events()) {
|
|
943
|
+
if (event.kind === "status-update" && event.taskId === params.id) {
|
|
944
|
+
yield event;
|
|
945
|
+
} else if (event.kind === "artifact-update" && event.taskId === params.id) {
|
|
946
|
+
yield event;
|
|
947
|
+
} else if (event.kind === "task" && event.id === params.id) {
|
|
948
|
+
yield event;
|
|
888
949
|
}
|
|
889
|
-
} finally {
|
|
890
|
-
eventQueue.stop();
|
|
891
950
|
}
|
|
892
|
-
}
|
|
951
|
+
} finally {
|
|
952
|
+
eventQueue.stop();
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
async _sendPushNotificationIfNeeded(event) {
|
|
956
|
+
if (!this.agentCard.capabilities.pushNotifications) {
|
|
957
|
+
return;
|
|
958
|
+
}
|
|
959
|
+
let taskId = "";
|
|
960
|
+
if (event.kind == "task") {
|
|
961
|
+
const task2 = event;
|
|
962
|
+
taskId = task2.id;
|
|
963
|
+
} else {
|
|
964
|
+
taskId = event.taskId;
|
|
965
|
+
}
|
|
966
|
+
if (!taskId) {
|
|
967
|
+
console.error(`Task ID not found for event ${event.kind}.`);
|
|
968
|
+
return;
|
|
969
|
+
}
|
|
970
|
+
const task = await this.taskStore.load(taskId);
|
|
971
|
+
if (!task) {
|
|
972
|
+
console.error(`Task ${taskId} not found.`);
|
|
973
|
+
return;
|
|
974
|
+
}
|
|
975
|
+
this.pushNotificationSender?.send(task);
|
|
976
|
+
}
|
|
977
|
+
async _handleProcessingError(error, resultManager, firstResultSent, taskId, firstResultRejector) {
|
|
978
|
+
if (firstResultRejector && !firstResultSent) {
|
|
979
|
+
firstResultRejector(error);
|
|
980
|
+
return;
|
|
981
|
+
}
|
|
982
|
+
if (!firstResultRejector) {
|
|
983
|
+
throw error;
|
|
984
|
+
}
|
|
985
|
+
const currentTask = resultManager.getCurrentTask();
|
|
986
|
+
const errorMessage = error instanceof Error && error.message || "Unknown error";
|
|
987
|
+
if (currentTask) {
|
|
988
|
+
const statusUpdateFailed = {
|
|
989
|
+
taskId: currentTask.id,
|
|
990
|
+
contextId: currentTask.contextId,
|
|
991
|
+
status: {
|
|
992
|
+
state: "failed",
|
|
993
|
+
message: {
|
|
994
|
+
kind: "message",
|
|
995
|
+
role: "agent",
|
|
996
|
+
messageId: (0, import_uuid.v4)(),
|
|
997
|
+
parts: [{ kind: "text", text: `Event processing loop failed: ${errorMessage}` }],
|
|
998
|
+
taskId: currentTask.id,
|
|
999
|
+
contextId: currentTask.contextId
|
|
1000
|
+
},
|
|
1001
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1002
|
+
},
|
|
1003
|
+
kind: "status-update",
|
|
1004
|
+
final: true
|
|
1005
|
+
};
|
|
1006
|
+
try {
|
|
1007
|
+
await resultManager.processEvent(statusUpdateFailed);
|
|
1008
|
+
} catch (error2) {
|
|
1009
|
+
console.error(
|
|
1010
|
+
`Event processing loop failed for task ${taskId}: ${error2 instanceof Error && error2.message || "Unknown error"}`
|
|
1011
|
+
);
|
|
1012
|
+
}
|
|
1013
|
+
} else {
|
|
1014
|
+
console.error(`Event processing loop failed for task ${taskId}: ${errorMessage}`);
|
|
1015
|
+
}
|
|
893
1016
|
}
|
|
894
1017
|
};
|
|
895
1018
|
|
|
896
1019
|
// src/server/store.ts
|
|
897
1020
|
var InMemoryTaskStore = class {
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
return __async(this, null, function* () {
|
|
903
|
-
const entry = this.store.get(taskId);
|
|
904
|
-
return entry ? __spreadValues({}, entry) : void 0;
|
|
905
|
-
});
|
|
1021
|
+
store = /* @__PURE__ */ new Map();
|
|
1022
|
+
async load(taskId) {
|
|
1023
|
+
const entry = this.store.get(taskId);
|
|
1024
|
+
return entry ? { ...entry } : void 0;
|
|
906
1025
|
}
|
|
907
|
-
save(task) {
|
|
908
|
-
|
|
909
|
-
this.store.set(task.id, __spreadValues({}, task));
|
|
910
|
-
});
|
|
1026
|
+
async save(task) {
|
|
1027
|
+
this.store.set(task.id, { ...task });
|
|
911
1028
|
}
|
|
912
1029
|
};
|
|
913
1030
|
|
|
914
1031
|
// src/server/transports/jsonrpc_transport_handler.ts
|
|
915
1032
|
var JsonRpcTransportHandler = class {
|
|
1033
|
+
requestHandler;
|
|
916
1034
|
constructor(requestHandler) {
|
|
917
1035
|
this.requestHandler = requestHandler;
|
|
918
1036
|
}
|
|
@@ -921,156 +1039,556 @@ var JsonRpcTransportHandler = class {
|
|
|
921
1039
|
* For streaming methods, it returns an AsyncGenerator of JSONRPCResult.
|
|
922
1040
|
* For non-streaming methods, it returns a Promise of a single JSONRPCMessage (Result or ErrorResponse).
|
|
923
1041
|
*/
|
|
924
|
-
handle(requestBody) {
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
1042
|
+
async handle(requestBody, context) {
|
|
1043
|
+
let rpcRequest;
|
|
1044
|
+
try {
|
|
1045
|
+
if (typeof requestBody === "string") {
|
|
1046
|
+
rpcRequest = JSON.parse(requestBody);
|
|
1047
|
+
} else if (typeof requestBody === "object" && requestBody !== null) {
|
|
1048
|
+
rpcRequest = requestBody;
|
|
1049
|
+
} else {
|
|
1050
|
+
throw A2AError.parseError("Invalid request body type.");
|
|
1051
|
+
}
|
|
1052
|
+
if (!this.isRequestValid(rpcRequest)) {
|
|
1053
|
+
throw A2AError.invalidRequest("Invalid JSON-RPC Request.");
|
|
1054
|
+
}
|
|
1055
|
+
} catch (error) {
|
|
1056
|
+
const a2aError = error instanceof A2AError ? error : A2AError.parseError(
|
|
1057
|
+
error instanceof SyntaxError && error.message || "Failed to parse JSON request."
|
|
1058
|
+
);
|
|
1059
|
+
return {
|
|
1060
|
+
jsonrpc: "2.0",
|
|
1061
|
+
id: rpcRequest?.id !== void 0 ? rpcRequest.id : null,
|
|
1062
|
+
error: a2aError.toJSONRPCError()
|
|
1063
|
+
};
|
|
1064
|
+
}
|
|
1065
|
+
const { method, id: requestId = null } = rpcRequest;
|
|
1066
|
+
try {
|
|
1067
|
+
if (method !== "agent/getAuthenticatedExtendedCard" && !this.paramsAreValid(rpcRequest.params)) {
|
|
1068
|
+
throw A2AError.invalidParams(`Invalid method parameters.`);
|
|
1069
|
+
}
|
|
1070
|
+
if (method === "message/stream" || method === "tasks/resubscribe") {
|
|
1071
|
+
const params = rpcRequest.params;
|
|
1072
|
+
const agentCard = await this.requestHandler.getAgentCard();
|
|
1073
|
+
if (!agentCard.capabilities.streaming) {
|
|
1074
|
+
throw A2AError.unsupportedOperation(`Method ${method} requires streaming capability.`);
|
|
934
1075
|
}
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
1076
|
+
const agentEventStream = method === "message/stream" ? this.requestHandler.sendMessageStream(params, context) : this.requestHandler.resubscribe(params, context);
|
|
1077
|
+
return (async function* jsonRpcEventStream() {
|
|
1078
|
+
try {
|
|
1079
|
+
for await (const event of agentEventStream) {
|
|
1080
|
+
yield {
|
|
1081
|
+
jsonrpc: "2.0",
|
|
1082
|
+
id: requestId,
|
|
1083
|
+
// Use the original request ID for all streamed responses
|
|
1084
|
+
result: event
|
|
1085
|
+
};
|
|
1086
|
+
}
|
|
1087
|
+
} catch (streamError) {
|
|
1088
|
+
console.error(
|
|
1089
|
+
`Error in agent event stream for ${method} (request ${requestId}):`,
|
|
1090
|
+
streamError
|
|
1091
|
+
);
|
|
1092
|
+
throw streamError;
|
|
1093
|
+
}
|
|
1094
|
+
})();
|
|
1095
|
+
} else {
|
|
1096
|
+
let result;
|
|
1097
|
+
switch (method) {
|
|
1098
|
+
case "message/send":
|
|
1099
|
+
result = await this.requestHandler.sendMessage(rpcRequest.params, context);
|
|
1100
|
+
break;
|
|
1101
|
+
case "tasks/get":
|
|
1102
|
+
result = await this.requestHandler.getTask(rpcRequest.params, context);
|
|
1103
|
+
break;
|
|
1104
|
+
case "tasks/cancel":
|
|
1105
|
+
result = await this.requestHandler.cancelTask(rpcRequest.params, context);
|
|
1106
|
+
break;
|
|
1107
|
+
case "tasks/pushNotificationConfig/set":
|
|
1108
|
+
result = await this.requestHandler.setTaskPushNotificationConfig(
|
|
1109
|
+
rpcRequest.params,
|
|
1110
|
+
context
|
|
1111
|
+
);
|
|
1112
|
+
break;
|
|
1113
|
+
case "tasks/pushNotificationConfig/get":
|
|
1114
|
+
result = await this.requestHandler.getTaskPushNotificationConfig(
|
|
1115
|
+
rpcRequest.params,
|
|
1116
|
+
context
|
|
1117
|
+
);
|
|
1118
|
+
break;
|
|
1119
|
+
case "tasks/pushNotificationConfig/delete":
|
|
1120
|
+
await this.requestHandler.deleteTaskPushNotificationConfig(rpcRequest.params, context);
|
|
1121
|
+
result = null;
|
|
1122
|
+
break;
|
|
1123
|
+
case "tasks/pushNotificationConfig/list":
|
|
1124
|
+
result = await this.requestHandler.listTaskPushNotificationConfigs(
|
|
1125
|
+
rpcRequest.params,
|
|
1126
|
+
context
|
|
1127
|
+
);
|
|
1128
|
+
break;
|
|
1129
|
+
case "agent/getAuthenticatedExtendedCard":
|
|
1130
|
+
result = await this.requestHandler.getAuthenticatedExtendedAgentCard(context);
|
|
1131
|
+
break;
|
|
1132
|
+
default:
|
|
1133
|
+
throw A2AError.methodNotFound(method);
|
|
939
1134
|
}
|
|
940
|
-
} catch (error) {
|
|
941
|
-
const a2aError = error instanceof A2AError ? error : A2AError.parseError(error.message || "Failed to parse JSON request.");
|
|
942
1135
|
return {
|
|
943
1136
|
jsonrpc: "2.0",
|
|
944
|
-
id:
|
|
945
|
-
|
|
1137
|
+
id: requestId,
|
|
1138
|
+
result
|
|
946
1139
|
};
|
|
947
1140
|
}
|
|
948
|
-
|
|
1141
|
+
} catch (error) {
|
|
1142
|
+
let a2aError;
|
|
1143
|
+
if (error instanceof A2AError) {
|
|
1144
|
+
a2aError = error;
|
|
1145
|
+
} else {
|
|
1146
|
+
a2aError = A2AError.internalError(
|
|
1147
|
+
error instanceof Error && error.message || "An unexpected error occurred."
|
|
1148
|
+
);
|
|
1149
|
+
}
|
|
1150
|
+
return {
|
|
1151
|
+
jsonrpc: "2.0",
|
|
1152
|
+
id: requestId,
|
|
1153
|
+
error: a2aError.toJSONRPCError()
|
|
1154
|
+
};
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
// Validates the basic structure of a JSON-RPC request
|
|
1158
|
+
isRequestValid(rpcRequest) {
|
|
1159
|
+
if (rpcRequest.jsonrpc !== "2.0") {
|
|
1160
|
+
return false;
|
|
1161
|
+
}
|
|
1162
|
+
if ("id" in rpcRequest) {
|
|
1163
|
+
const id = rpcRequest.id;
|
|
1164
|
+
const isString = typeof id === "string";
|
|
1165
|
+
const isInteger = typeof id === "number" && Number.isInteger(id);
|
|
1166
|
+
const isNull = id === null;
|
|
1167
|
+
if (!isString && !isInteger && !isNull) {
|
|
1168
|
+
return false;
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
if (!rpcRequest.method || typeof rpcRequest.method !== "string") {
|
|
1172
|
+
return false;
|
|
1173
|
+
}
|
|
1174
|
+
return true;
|
|
1175
|
+
}
|
|
1176
|
+
// Validates that params is an object with non-empty string keys
|
|
1177
|
+
paramsAreValid(params) {
|
|
1178
|
+
if (typeof params !== "object" || params === null || Array.isArray(params)) {
|
|
1179
|
+
return false;
|
|
1180
|
+
}
|
|
1181
|
+
for (const key of Object.keys(params)) {
|
|
1182
|
+
if (key === "") {
|
|
1183
|
+
return false;
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
return true;
|
|
1187
|
+
}
|
|
1188
|
+
};
|
|
1189
|
+
|
|
1190
|
+
// src/errors.ts
|
|
1191
|
+
var TaskNotFoundError = class extends Error {
|
|
1192
|
+
constructor(message) {
|
|
1193
|
+
super(message ?? "Task not found");
|
|
1194
|
+
this.name = "TaskNotFoundError";
|
|
1195
|
+
}
|
|
1196
|
+
};
|
|
1197
|
+
var TaskNotCancelableError = class extends Error {
|
|
1198
|
+
constructor(message) {
|
|
1199
|
+
super(message ?? "Task cannot be canceled");
|
|
1200
|
+
this.name = "TaskNotCancelableError";
|
|
1201
|
+
}
|
|
1202
|
+
};
|
|
1203
|
+
var PushNotificationNotSupportedError = class extends Error {
|
|
1204
|
+
constructor(message) {
|
|
1205
|
+
super(message ?? "Push Notification is not supported");
|
|
1206
|
+
this.name = "PushNotificationNotSupportedError";
|
|
1207
|
+
}
|
|
1208
|
+
};
|
|
1209
|
+
var UnsupportedOperationError = class extends Error {
|
|
1210
|
+
constructor(message) {
|
|
1211
|
+
super(message ?? "This operation is not supported");
|
|
1212
|
+
this.name = "UnsupportedOperationError";
|
|
1213
|
+
}
|
|
1214
|
+
};
|
|
1215
|
+
var ContentTypeNotSupportedError = class extends Error {
|
|
1216
|
+
constructor(message) {
|
|
1217
|
+
super(message ?? "Incompatible content types");
|
|
1218
|
+
this.name = "ContentTypeNotSupportedError";
|
|
1219
|
+
}
|
|
1220
|
+
};
|
|
1221
|
+
var InvalidAgentResponseError = class extends Error {
|
|
1222
|
+
constructor(message) {
|
|
1223
|
+
super(message ?? "Invalid agent response type");
|
|
1224
|
+
this.name = "InvalidAgentResponseError";
|
|
1225
|
+
}
|
|
1226
|
+
};
|
|
1227
|
+
var AuthenticatedExtendedCardNotConfiguredError = class extends Error {
|
|
1228
|
+
constructor(message) {
|
|
1229
|
+
super(message ?? "Authenticated Extended Card not configured");
|
|
1230
|
+
this.name = "AuthenticatedExtendedCardNotConfiguredError";
|
|
1231
|
+
}
|
|
1232
|
+
};
|
|
1233
|
+
|
|
1234
|
+
// src/client/transports/json_rpc_transport.ts
|
|
1235
|
+
var JsonRpcTransport = class _JsonRpcTransport {
|
|
1236
|
+
customFetchImpl;
|
|
1237
|
+
endpoint;
|
|
1238
|
+
requestIdCounter = 1;
|
|
1239
|
+
constructor(options) {
|
|
1240
|
+
this.endpoint = options.endpoint;
|
|
1241
|
+
this.customFetchImpl = options.fetchImpl;
|
|
1242
|
+
}
|
|
1243
|
+
async sendMessage(params, options, idOverride) {
|
|
1244
|
+
const rpcResponse = await this._sendRpcRequest(
|
|
1245
|
+
"message/send",
|
|
1246
|
+
params,
|
|
1247
|
+
idOverride,
|
|
1248
|
+
options
|
|
1249
|
+
);
|
|
1250
|
+
return rpcResponse.result;
|
|
1251
|
+
}
|
|
1252
|
+
async *sendMessageStream(params, options) {
|
|
1253
|
+
yield* this._sendStreamingRequest("message/stream", params, options);
|
|
1254
|
+
}
|
|
1255
|
+
async setTaskPushNotificationConfig(params, options, idOverride) {
|
|
1256
|
+
const rpcResponse = await this._sendRpcRequest("tasks/pushNotificationConfig/set", params, idOverride, options);
|
|
1257
|
+
return rpcResponse.result;
|
|
1258
|
+
}
|
|
1259
|
+
async getTaskPushNotificationConfig(params, options, idOverride) {
|
|
1260
|
+
const rpcResponse = await this._sendRpcRequest("tasks/pushNotificationConfig/get", params, idOverride, options);
|
|
1261
|
+
return rpcResponse.result;
|
|
1262
|
+
}
|
|
1263
|
+
async listTaskPushNotificationConfig(params, options, idOverride) {
|
|
1264
|
+
const rpcResponse = await this._sendRpcRequest("tasks/pushNotificationConfig/list", params, idOverride, options);
|
|
1265
|
+
return rpcResponse.result;
|
|
1266
|
+
}
|
|
1267
|
+
async deleteTaskPushNotificationConfig(params, options, idOverride) {
|
|
1268
|
+
await this._sendRpcRequest("tasks/pushNotificationConfig/delete", params, idOverride, options);
|
|
1269
|
+
}
|
|
1270
|
+
async getTask(params, options, idOverride) {
|
|
1271
|
+
const rpcResponse = await this._sendRpcRequest(
|
|
1272
|
+
"tasks/get",
|
|
1273
|
+
params,
|
|
1274
|
+
idOverride,
|
|
1275
|
+
options
|
|
1276
|
+
);
|
|
1277
|
+
return rpcResponse.result;
|
|
1278
|
+
}
|
|
1279
|
+
async cancelTask(params, options, idOverride) {
|
|
1280
|
+
const rpcResponse = await this._sendRpcRequest(
|
|
1281
|
+
"tasks/cancel",
|
|
1282
|
+
params,
|
|
1283
|
+
idOverride,
|
|
1284
|
+
options
|
|
1285
|
+
);
|
|
1286
|
+
return rpcResponse.result;
|
|
1287
|
+
}
|
|
1288
|
+
async *resubscribeTask(params, options) {
|
|
1289
|
+
yield* this._sendStreamingRequest("tasks/resubscribe", params, options);
|
|
1290
|
+
}
|
|
1291
|
+
async callExtensionMethod(method, params, idOverride, options) {
|
|
1292
|
+
return await this._sendRpcRequest(
|
|
1293
|
+
method,
|
|
1294
|
+
params,
|
|
1295
|
+
idOverride,
|
|
1296
|
+
options
|
|
1297
|
+
);
|
|
1298
|
+
}
|
|
1299
|
+
_fetch(...args) {
|
|
1300
|
+
if (this.customFetchImpl) {
|
|
1301
|
+
return this.customFetchImpl(...args);
|
|
1302
|
+
}
|
|
1303
|
+
if (typeof fetch === "function") {
|
|
1304
|
+
return fetch(...args);
|
|
1305
|
+
}
|
|
1306
|
+
throw new Error(
|
|
1307
|
+
"A `fetch` implementation was not provided and is not available in the global scope. Please provide a `fetchImpl` in the A2ATransportOptions. "
|
|
1308
|
+
);
|
|
1309
|
+
}
|
|
1310
|
+
async _sendRpcRequest(method, params, idOverride, options) {
|
|
1311
|
+
const requestId = idOverride ?? this.requestIdCounter++;
|
|
1312
|
+
const rpcRequest = {
|
|
1313
|
+
jsonrpc: "2.0",
|
|
1314
|
+
method,
|
|
1315
|
+
params,
|
|
1316
|
+
id: requestId
|
|
1317
|
+
};
|
|
1318
|
+
const httpResponse = await this._fetchRpc(rpcRequest, "application/json", options?.signal);
|
|
1319
|
+
if (!httpResponse.ok) {
|
|
1320
|
+
let errorBodyText = "(empty or non-JSON response)";
|
|
1321
|
+
let errorJson;
|
|
949
1322
|
try {
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
1323
|
+
errorBodyText = await httpResponse.text();
|
|
1324
|
+
errorJson = JSON.parse(errorBodyText);
|
|
1325
|
+
} catch (e) {
|
|
1326
|
+
throw new Error(
|
|
1327
|
+
`HTTP error for ${method}! Status: ${httpResponse.status} ${httpResponse.statusText}. Response: ${errorBodyText}`,
|
|
1328
|
+
{ cause: e }
|
|
1329
|
+
);
|
|
1330
|
+
}
|
|
1331
|
+
if (errorJson.jsonrpc && errorJson.error) {
|
|
1332
|
+
throw _JsonRpcTransport.mapToError(errorJson);
|
|
1333
|
+
} else {
|
|
1334
|
+
throw new Error(
|
|
1335
|
+
`HTTP error for ${method}! Status: ${httpResponse.status} ${httpResponse.statusText}. Response: ${errorBodyText}`
|
|
1336
|
+
);
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
const rpcResponse = await httpResponse.json();
|
|
1340
|
+
if (rpcResponse.id !== requestId) {
|
|
1341
|
+
console.error(
|
|
1342
|
+
`CRITICAL: RPC response ID mismatch for method ${method}. Expected ${requestId}, got ${rpcResponse.id}.`
|
|
1343
|
+
);
|
|
1344
|
+
}
|
|
1345
|
+
if ("error" in rpcResponse) {
|
|
1346
|
+
throw _JsonRpcTransport.mapToError(rpcResponse);
|
|
1347
|
+
}
|
|
1348
|
+
return rpcResponse;
|
|
1349
|
+
}
|
|
1350
|
+
async _fetchRpc(rpcRequest, acceptHeader = "application/json", signal) {
|
|
1351
|
+
const requestInit = {
|
|
1352
|
+
method: "POST",
|
|
1353
|
+
headers: {
|
|
1354
|
+
"Content-Type": "application/json",
|
|
1355
|
+
Accept: acceptHeader
|
|
1356
|
+
},
|
|
1357
|
+
body: JSON.stringify(rpcRequest),
|
|
1358
|
+
signal
|
|
1359
|
+
};
|
|
1360
|
+
return this._fetch(this.endpoint, requestInit);
|
|
1361
|
+
}
|
|
1362
|
+
async *_sendStreamingRequest(method, params, options) {
|
|
1363
|
+
const clientRequestId = this.requestIdCounter++;
|
|
1364
|
+
const rpcRequest = {
|
|
1365
|
+
jsonrpc: "2.0",
|
|
1366
|
+
method,
|
|
1367
|
+
params,
|
|
1368
|
+
id: clientRequestId
|
|
1369
|
+
};
|
|
1370
|
+
const response = await this._fetchRpc(rpcRequest, "text/event-stream", options?.signal);
|
|
1371
|
+
if (!response.ok) {
|
|
1372
|
+
let errorBody = "";
|
|
1373
|
+
let errorJson;
|
|
1374
|
+
try {
|
|
1375
|
+
errorBody = await response.text();
|
|
1376
|
+
errorJson = JSON.parse(errorBody);
|
|
1377
|
+
} catch (e) {
|
|
1378
|
+
throw new Error(
|
|
1379
|
+
`HTTP error establishing stream for ${method}: ${response.status} ${response.statusText}. Response: ${errorBody || "(empty)"}`,
|
|
1380
|
+
{ cause: e }
|
|
1381
|
+
);
|
|
1382
|
+
}
|
|
1383
|
+
if (errorJson.error) {
|
|
1384
|
+
throw new Error(
|
|
1385
|
+
`HTTP error establishing stream for ${method}: ${response.status} ${response.statusText}. RPC Error: ${errorJson.error.message} (Code: ${errorJson.error.code})`
|
|
1386
|
+
);
|
|
1387
|
+
}
|
|
1388
|
+
throw new Error(
|
|
1389
|
+
`HTTP error establishing stream for ${method}: ${response.status} ${response.statusText}`
|
|
1390
|
+
);
|
|
1391
|
+
}
|
|
1392
|
+
if (!response.headers.get("Content-Type")?.startsWith("text/event-stream")) {
|
|
1393
|
+
throw new Error(
|
|
1394
|
+
`Invalid response Content-Type for SSE stream for ${method}. Expected 'text/event-stream'.`
|
|
1395
|
+
);
|
|
1396
|
+
}
|
|
1397
|
+
yield* this._parseA2ASseStream(response, clientRequestId);
|
|
1398
|
+
}
|
|
1399
|
+
async *_parseA2ASseStream(response, originalRequestId) {
|
|
1400
|
+
if (!response.body) {
|
|
1401
|
+
throw new Error("SSE response body is undefined. Cannot read stream.");
|
|
1402
|
+
}
|
|
1403
|
+
const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
|
|
1404
|
+
let buffer = "";
|
|
1405
|
+
let eventDataBuffer = "";
|
|
1406
|
+
try {
|
|
1407
|
+
while (true) {
|
|
1408
|
+
const { done, value } = await reader.read();
|
|
1409
|
+
if (done) {
|
|
1410
|
+
if (eventDataBuffer.trim()) {
|
|
1411
|
+
const result = this._processSseEventData(
|
|
1412
|
+
eventDataBuffer,
|
|
1413
|
+
originalRequestId
|
|
1414
|
+
);
|
|
1415
|
+
yield result;
|
|
966
1416
|
}
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
};
|
|
980
|
-
}
|
|
981
|
-
} catch (temp) {
|
|
982
|
-
error = [temp];
|
|
983
|
-
} finally {
|
|
984
|
-
try {
|
|
985
|
-
more && (temp = iter.return) && (yield new __await(temp.call(iter)));
|
|
986
|
-
} finally {
|
|
987
|
-
if (error)
|
|
988
|
-
throw error[0];
|
|
989
|
-
}
|
|
990
|
-
}
|
|
991
|
-
} catch (streamError) {
|
|
992
|
-
console.error(`Error in agent event stream for ${method} (request ${requestId}):`, streamError);
|
|
993
|
-
throw streamError;
|
|
994
|
-
}
|
|
995
|
-
});
|
|
996
|
-
}();
|
|
997
|
-
} else {
|
|
998
|
-
let result;
|
|
999
|
-
switch (method) {
|
|
1000
|
-
case "message/send":
|
|
1001
|
-
result = yield this.requestHandler.sendMessage(rpcRequest.params);
|
|
1002
|
-
break;
|
|
1003
|
-
case "tasks/get":
|
|
1004
|
-
result = yield this.requestHandler.getTask(rpcRequest.params);
|
|
1005
|
-
break;
|
|
1006
|
-
case "tasks/cancel":
|
|
1007
|
-
result = yield this.requestHandler.cancelTask(rpcRequest.params);
|
|
1008
|
-
break;
|
|
1009
|
-
case "tasks/pushNotificationConfig/set":
|
|
1010
|
-
result = yield this.requestHandler.setTaskPushNotificationConfig(
|
|
1011
|
-
rpcRequest.params
|
|
1012
|
-
);
|
|
1013
|
-
break;
|
|
1014
|
-
case "tasks/pushNotificationConfig/get":
|
|
1015
|
-
result = yield this.requestHandler.getTaskPushNotificationConfig(
|
|
1016
|
-
rpcRequest.params
|
|
1017
|
-
);
|
|
1018
|
-
break;
|
|
1019
|
-
case "tasks/pushNotificationConfig/delete":
|
|
1020
|
-
yield this.requestHandler.deleteTaskPushNotificationConfig(
|
|
1021
|
-
rpcRequest.params
|
|
1022
|
-
);
|
|
1023
|
-
result = null;
|
|
1024
|
-
break;
|
|
1025
|
-
case "tasks/pushNotificationConfig/list":
|
|
1026
|
-
result = yield this.requestHandler.listTaskPushNotificationConfigs(
|
|
1027
|
-
rpcRequest.params
|
|
1417
|
+
break;
|
|
1418
|
+
}
|
|
1419
|
+
buffer += value;
|
|
1420
|
+
let lineEndIndex;
|
|
1421
|
+
while ((lineEndIndex = buffer.indexOf("\n")) >= 0) {
|
|
1422
|
+
const line = buffer.substring(0, lineEndIndex).trim();
|
|
1423
|
+
buffer = buffer.substring(lineEndIndex + 1);
|
|
1424
|
+
if (line === "") {
|
|
1425
|
+
if (eventDataBuffer) {
|
|
1426
|
+
const result = this._processSseEventData(
|
|
1427
|
+
eventDataBuffer,
|
|
1428
|
+
originalRequestId
|
|
1028
1429
|
);
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1430
|
+
yield result;
|
|
1431
|
+
eventDataBuffer = "";
|
|
1432
|
+
}
|
|
1433
|
+
} else if (line.startsWith("data:")) {
|
|
1434
|
+
eventDataBuffer += line.substring(5).trimStart() + "\n";
|
|
1032
1435
|
}
|
|
1033
|
-
return {
|
|
1034
|
-
jsonrpc: "2.0",
|
|
1035
|
-
id: requestId,
|
|
1036
|
-
result
|
|
1037
|
-
};
|
|
1038
1436
|
}
|
|
1039
|
-
} catch (error) {
|
|
1040
|
-
const a2aError = error instanceof A2AError ? error : A2AError.internalError(error.message || "An unexpected error occurred.");
|
|
1041
|
-
return {
|
|
1042
|
-
jsonrpc: "2.0",
|
|
1043
|
-
id: requestId,
|
|
1044
|
-
error: a2aError.toJSONRPCError()
|
|
1045
|
-
};
|
|
1046
1437
|
}
|
|
1047
|
-
})
|
|
1438
|
+
} catch (error) {
|
|
1439
|
+
console.error(
|
|
1440
|
+
"Error reading or parsing SSE stream:",
|
|
1441
|
+
error instanceof Error && error.message || "Error unknown"
|
|
1442
|
+
);
|
|
1443
|
+
throw error;
|
|
1444
|
+
} finally {
|
|
1445
|
+
reader.releaseLock();
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
_processSseEventData(jsonData, originalRequestId) {
|
|
1449
|
+
if (!jsonData.trim()) {
|
|
1450
|
+
throw new Error("Attempted to process empty SSE event data.");
|
|
1451
|
+
}
|
|
1452
|
+
try {
|
|
1453
|
+
const sseJsonRpcResponse = JSON.parse(jsonData.replace(/\n$/, ""));
|
|
1454
|
+
const a2aStreamResponse = sseJsonRpcResponse;
|
|
1455
|
+
if (a2aStreamResponse.id !== originalRequestId) {
|
|
1456
|
+
console.warn(
|
|
1457
|
+
`SSE Event's JSON-RPC response ID mismatch. Client request ID: ${originalRequestId}, event response ID: ${a2aStreamResponse.id}.`
|
|
1458
|
+
);
|
|
1459
|
+
}
|
|
1460
|
+
if ("error" in a2aStreamResponse) {
|
|
1461
|
+
const err = a2aStreamResponse.error;
|
|
1462
|
+
throw new Error(
|
|
1463
|
+
`SSE event contained an error: ${err.message} (Code: ${err.code}) Data: ${JSON.stringify(err.data || {})}`
|
|
1464
|
+
);
|
|
1465
|
+
}
|
|
1466
|
+
if (!("result" in a2aStreamResponse) || typeof a2aStreamResponse.result === "undefined") {
|
|
1467
|
+
throw new Error(`SSE event JSON-RPC response is missing 'result' field. Data: ${jsonData}`);
|
|
1468
|
+
}
|
|
1469
|
+
return a2aStreamResponse.result;
|
|
1470
|
+
} catch (e) {
|
|
1471
|
+
if (e instanceof Error && (e.message.startsWith("SSE event contained an error") || e.message.startsWith("SSE event JSON-RPC response is missing 'result' field"))) {
|
|
1472
|
+
throw e;
|
|
1473
|
+
}
|
|
1474
|
+
console.error(
|
|
1475
|
+
"Failed to parse SSE event data string or unexpected JSON-RPC structure:",
|
|
1476
|
+
jsonData,
|
|
1477
|
+
e
|
|
1478
|
+
);
|
|
1479
|
+
throw new Error(
|
|
1480
|
+
`Failed to parse SSE event data: "${jsonData.substring(0, 100)}...". Original error: ${e instanceof Error && e.message || "Unknown error"}`
|
|
1481
|
+
);
|
|
1482
|
+
}
|
|
1483
|
+
}
|
|
1484
|
+
static mapToError(response) {
|
|
1485
|
+
switch (response.error.code) {
|
|
1486
|
+
case -32001:
|
|
1487
|
+
return new TaskNotFoundJSONRPCError(response);
|
|
1488
|
+
case -32002:
|
|
1489
|
+
return new TaskNotCancelableJSONRPCError(response);
|
|
1490
|
+
case -32003:
|
|
1491
|
+
return new PushNotificationNotSupportedJSONRPCError(response);
|
|
1492
|
+
case -32004:
|
|
1493
|
+
return new UnsupportedOperationJSONRPCError(response);
|
|
1494
|
+
case -32005:
|
|
1495
|
+
return new ContentTypeNotSupportedJSONRPCError(response);
|
|
1496
|
+
case -32006:
|
|
1497
|
+
return new InvalidAgentResponseJSONRPCError(response);
|
|
1498
|
+
case -32007:
|
|
1499
|
+
return new AuthenticatedExtendedCardNotConfiguredJSONRPCError(response);
|
|
1500
|
+
default:
|
|
1501
|
+
return new JSONRPCTransportError(response);
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
};
|
|
1505
|
+
var JSONRPCTransportError = class extends Error {
|
|
1506
|
+
constructor(errorResponse) {
|
|
1507
|
+
super(
|
|
1508
|
+
`JSON-RPC error: ${errorResponse.error.message} (Code: ${errorResponse.error.code}) Data: ${JSON.stringify(errorResponse.error.data || {})}`
|
|
1509
|
+
);
|
|
1510
|
+
this.errorResponse = errorResponse;
|
|
1511
|
+
}
|
|
1512
|
+
};
|
|
1513
|
+
var TaskNotFoundJSONRPCError = class extends TaskNotFoundError {
|
|
1514
|
+
constructor(errorResponse) {
|
|
1515
|
+
super();
|
|
1516
|
+
this.errorResponse = errorResponse;
|
|
1517
|
+
}
|
|
1518
|
+
};
|
|
1519
|
+
var TaskNotCancelableJSONRPCError = class extends TaskNotCancelableError {
|
|
1520
|
+
constructor(errorResponse) {
|
|
1521
|
+
super();
|
|
1522
|
+
this.errorResponse = errorResponse;
|
|
1523
|
+
}
|
|
1524
|
+
};
|
|
1525
|
+
var PushNotificationNotSupportedJSONRPCError = class extends PushNotificationNotSupportedError {
|
|
1526
|
+
constructor(errorResponse) {
|
|
1527
|
+
super();
|
|
1528
|
+
this.errorResponse = errorResponse;
|
|
1529
|
+
}
|
|
1530
|
+
};
|
|
1531
|
+
var UnsupportedOperationJSONRPCError = class extends UnsupportedOperationError {
|
|
1532
|
+
constructor(errorResponse) {
|
|
1533
|
+
super();
|
|
1534
|
+
this.errorResponse = errorResponse;
|
|
1535
|
+
}
|
|
1536
|
+
};
|
|
1537
|
+
var ContentTypeNotSupportedJSONRPCError = class extends ContentTypeNotSupportedError {
|
|
1538
|
+
constructor(errorResponse) {
|
|
1539
|
+
super();
|
|
1540
|
+
this.errorResponse = errorResponse;
|
|
1541
|
+
}
|
|
1542
|
+
};
|
|
1543
|
+
var InvalidAgentResponseJSONRPCError = class extends InvalidAgentResponseError {
|
|
1544
|
+
constructor(errorResponse) {
|
|
1545
|
+
super();
|
|
1546
|
+
this.errorResponse = errorResponse;
|
|
1547
|
+
}
|
|
1548
|
+
};
|
|
1549
|
+
var AuthenticatedExtendedCardNotConfiguredJSONRPCError = class extends AuthenticatedExtendedCardNotConfiguredError {
|
|
1550
|
+
constructor(errorResponse) {
|
|
1551
|
+
super();
|
|
1552
|
+
this.errorResponse = errorResponse;
|
|
1048
1553
|
}
|
|
1049
1554
|
};
|
|
1050
1555
|
|
|
1051
1556
|
// src/client/client.ts
|
|
1052
1557
|
var A2AClient = class _A2AClient {
|
|
1558
|
+
static emptyOptions = void 0;
|
|
1559
|
+
agentCardPromise;
|
|
1560
|
+
customFetchImpl;
|
|
1561
|
+
serviceEndpointUrl;
|
|
1562
|
+
// To be populated from AgentCard after fetchin
|
|
1563
|
+
// A2AClient is built around JSON-RPC types, so it will only support JSON-RPC transport, new client with transport agnostic interface is going to be created for multi-transport.
|
|
1564
|
+
// New transport abstraction isn't going to expose individual transport specific fields, so to keep returning JSON-RPC IDs here for compatibility,
|
|
1565
|
+
// keep counter here and pass it to JsonRpcTransport via an optional idOverride parameter (which is not visible via transport-agnostic A2ATransport interface).
|
|
1566
|
+
transport;
|
|
1567
|
+
requestIdCounter = 1;
|
|
1053
1568
|
/**
|
|
1054
1569
|
* Constructs an A2AClient instance from an AgentCard.
|
|
1055
1570
|
* @param agentCard The AgentCard object.
|
|
1056
1571
|
* @param options Optional. The options for the A2AClient including the fetch/auth implementation.
|
|
1057
1572
|
*/
|
|
1058
1573
|
constructor(agentCard, options) {
|
|
1059
|
-
this.
|
|
1060
|
-
this.customFetchImpl = options == null ? void 0 : options.fetchImpl;
|
|
1574
|
+
this.customFetchImpl = options?.fetchImpl;
|
|
1061
1575
|
if (typeof agentCard === "string") {
|
|
1062
|
-
console.warn(
|
|
1063
|
-
|
|
1576
|
+
console.warn(
|
|
1577
|
+
"Warning: Constructing A2AClient with a URL is deprecated. Please use A2AClient.fromCardUrl() instead."
|
|
1578
|
+
);
|
|
1579
|
+
this.agentCardPromise = this._fetchAndCacheAgentCard(agentCard, options?.agentCardPath);
|
|
1064
1580
|
} else {
|
|
1065
1581
|
if (!agentCard.url) {
|
|
1066
|
-
throw new Error(
|
|
1582
|
+
throw new Error(
|
|
1583
|
+
"Provided Agent Card does not contain a valid 'url' for the service endpoint."
|
|
1584
|
+
);
|
|
1067
1585
|
}
|
|
1068
1586
|
this.serviceEndpointUrl = agentCard.url;
|
|
1069
1587
|
this.agentCardPromise = Promise.resolve(agentCard);
|
|
1070
1588
|
}
|
|
1071
1589
|
}
|
|
1072
1590
|
/**
|
|
1073
|
-
* Dynamically resolves the fetch implementation to use for requests.
|
|
1591
|
+
* Dynamically resolves the fetch implementation to use for requests.
|
|
1074
1592
|
* Prefers a custom implementation if provided, otherwise falls back to the global fetch.
|
|
1075
1593
|
* @returns The fetch implementation.
|
|
1076
1594
|
* @param args Arguments to pass to the fetch implementation.
|
|
@@ -1093,97 +1611,36 @@ var A2AClient = class _A2AClient {
|
|
|
1093
1611
|
* @param options Optional. The options for the A2AClient including the fetch/auth implementation.
|
|
1094
1612
|
* @returns A Promise that resolves to a new A2AClient instance.
|
|
1095
1613
|
*/
|
|
1096
|
-
static fromCardUrl(agentCardUrl, options) {
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
* Helper method to make a generic JSON-RPC POST request.
|
|
1127
|
-
* @param method The RPC method name.
|
|
1128
|
-
* @param params The parameters for the RPC method.
|
|
1129
|
-
* @returns A Promise that resolves to the RPC response.
|
|
1130
|
-
*/
|
|
1131
|
-
_postRpcRequest(method, params) {
|
|
1132
|
-
return __async(this, null, function* () {
|
|
1133
|
-
const endpoint = yield this._getServiceEndpoint();
|
|
1134
|
-
const requestId = this.requestIdCounter++;
|
|
1135
|
-
const rpcRequest = {
|
|
1136
|
-
jsonrpc: "2.0",
|
|
1137
|
-
method,
|
|
1138
|
-
params,
|
|
1139
|
-
// Cast because TParams structure varies per method
|
|
1140
|
-
id: requestId
|
|
1141
|
-
};
|
|
1142
|
-
const httpResponse = yield this._fetchRpc(endpoint, rpcRequest);
|
|
1143
|
-
if (!httpResponse.ok) {
|
|
1144
|
-
let errorBodyText = "(empty or non-JSON response)";
|
|
1145
|
-
try {
|
|
1146
|
-
errorBodyText = yield httpResponse.text();
|
|
1147
|
-
const errorJson = JSON.parse(errorBodyText);
|
|
1148
|
-
if (errorJson.jsonrpc && errorJson.error) {
|
|
1149
|
-
return errorJson;
|
|
1150
|
-
} else if (!errorJson.jsonrpc && errorJson.error) {
|
|
1151
|
-
throw new Error(`RPC error for ${method}: ${errorJson.error.message} (Code: ${errorJson.error.code}, HTTP Status: ${httpResponse.status}) Data: ${JSON.stringify(errorJson.error.data || {})}`);
|
|
1152
|
-
} else if (!errorJson.jsonrpc) {
|
|
1153
|
-
throw new Error(`HTTP error for ${method}! Status: ${httpResponse.status} ${httpResponse.statusText}. Response: ${errorBodyText}`);
|
|
1154
|
-
}
|
|
1155
|
-
} catch (e) {
|
|
1156
|
-
if (e.message.startsWith("RPC error for") || e.message.startsWith("HTTP error for")) throw e;
|
|
1157
|
-
throw new Error(`HTTP error for ${method}! Status: ${httpResponse.status} ${httpResponse.statusText}. Response: ${errorBodyText}`);
|
|
1158
|
-
}
|
|
1159
|
-
}
|
|
1160
|
-
const rpcResponse = yield httpResponse.json();
|
|
1161
|
-
if (rpcResponse.id !== requestId) {
|
|
1162
|
-
console.error(`CRITICAL: RPC response ID mismatch for method ${method}. Expected ${requestId}, got ${rpcResponse.id}. This may lead to incorrect response handling.`);
|
|
1163
|
-
}
|
|
1164
|
-
return rpcResponse;
|
|
1165
|
-
});
|
|
1166
|
-
}
|
|
1167
|
-
/**
|
|
1168
|
-
* Internal helper method to fetch the RPC service endpoint.
|
|
1169
|
-
* @param url The URL to fetch.
|
|
1170
|
-
* @param rpcRequest The JSON-RPC request to send.
|
|
1171
|
-
* @param acceptHeader The Accept header to use. Defaults to "application/json".
|
|
1172
|
-
* @returns A Promise that resolves to the fetch HTTP response.
|
|
1173
|
-
*/
|
|
1174
|
-
_fetchRpc(url, rpcRequest, acceptHeader = "application/json") {
|
|
1175
|
-
return __async(this, null, function* () {
|
|
1176
|
-
const requestInit = {
|
|
1177
|
-
method: "POST",
|
|
1178
|
-
headers: {
|
|
1179
|
-
"Content-Type": "application/json",
|
|
1180
|
-
"Accept": acceptHeader
|
|
1181
|
-
// Expect JSON response for non-streaming requests
|
|
1182
|
-
},
|
|
1183
|
-
body: JSON.stringify(rpcRequest)
|
|
1184
|
-
};
|
|
1185
|
-
return this._fetch(url, requestInit);
|
|
1186
|
-
});
|
|
1614
|
+
static async fromCardUrl(agentCardUrl, options) {
|
|
1615
|
+
const fetchImpl = options?.fetchImpl;
|
|
1616
|
+
const requestInit = {
|
|
1617
|
+
headers: { Accept: "application/json" }
|
|
1618
|
+
};
|
|
1619
|
+
let response;
|
|
1620
|
+
if (fetchImpl) {
|
|
1621
|
+
response = await fetchImpl(agentCardUrl, requestInit);
|
|
1622
|
+
} else if (typeof fetch === "function") {
|
|
1623
|
+
response = await fetch(agentCardUrl, requestInit);
|
|
1624
|
+
} else {
|
|
1625
|
+
throw new Error(
|
|
1626
|
+
"A `fetch` implementation was not provided and is not available in the global scope. Please provide a `fetchImpl` in the A2AClientOptions. For earlier Node.js versions (pre-v18), you can use a library like `node-fetch`."
|
|
1627
|
+
);
|
|
1628
|
+
}
|
|
1629
|
+
if (!response.ok) {
|
|
1630
|
+
throw new Error(
|
|
1631
|
+
`Failed to fetch Agent Card from ${agentCardUrl}: ${response.status} ${response.statusText}`
|
|
1632
|
+
);
|
|
1633
|
+
}
|
|
1634
|
+
let agentCard;
|
|
1635
|
+
try {
|
|
1636
|
+
agentCard = await response.json();
|
|
1637
|
+
} catch (error) {
|
|
1638
|
+
console.error("Failed to parse Agent Card JSON:", error);
|
|
1639
|
+
throw new Error(
|
|
1640
|
+
`Failed to parse Agent Card JSON from ${agentCardUrl}. Original error: ${error.message}`
|
|
1641
|
+
);
|
|
1642
|
+
}
|
|
1643
|
+
return new _A2AClient(agentCard, options);
|
|
1187
1644
|
}
|
|
1188
1645
|
/**
|
|
1189
1646
|
* Sends a message to the agent.
|
|
@@ -1193,10 +1650,11 @@ var A2AClient = class _A2AClient {
|
|
|
1193
1650
|
* @param params The parameters for sending the message, including the message content and configuration.
|
|
1194
1651
|
* @returns A Promise resolving to SendMessageResponse, which can be a Message, Task, or an error.
|
|
1195
1652
|
*/
|
|
1196
|
-
sendMessage(params) {
|
|
1197
|
-
return
|
|
1198
|
-
|
|
1199
|
-
|
|
1653
|
+
async sendMessage(params) {
|
|
1654
|
+
return await this.invokeJsonRpc(
|
|
1655
|
+
(t, p, id) => t.sendMessage(p, _A2AClient.emptyOptions, id),
|
|
1656
|
+
params
|
|
1657
|
+
);
|
|
1200
1658
|
}
|
|
1201
1659
|
/**
|
|
1202
1660
|
* Sends a message to the agent and streams back responses using Server-Sent Events (SSE).
|
|
@@ -1207,42 +1665,15 @@ var A2AClient = class _A2AClient {
|
|
|
1207
1665
|
* @returns An AsyncGenerator yielding A2AStreamEventData (Message, Task, TaskStatusUpdateEvent, or TaskArtifactUpdateEvent).
|
|
1208
1666
|
* The generator throws an error if streaming is not supported or if an HTTP/SSE error occurs.
|
|
1209
1667
|
*/
|
|
1210
|
-
sendMessageStream(params) {
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
const rpcRequest = {
|
|
1220
|
-
// This is the initial JSON-RPC request to establish the stream
|
|
1221
|
-
jsonrpc: "2.0",
|
|
1222
|
-
method: "message/stream",
|
|
1223
|
-
params,
|
|
1224
|
-
id: clientRequestId
|
|
1225
|
-
};
|
|
1226
|
-
const response = yield new __await(this._fetchRpc(endpoint, rpcRequest, "text/event-stream"));
|
|
1227
|
-
if (!response.ok) {
|
|
1228
|
-
let errorBody = "";
|
|
1229
|
-
try {
|
|
1230
|
-
errorBody = yield new __await(response.text());
|
|
1231
|
-
const errorJson = JSON.parse(errorBody);
|
|
1232
|
-
if (errorJson.error) {
|
|
1233
|
-
throw new Error(`HTTP error establishing stream for message/stream: ${response.status} ${response.statusText}. RPC Error: ${errorJson.error.message} (Code: ${errorJson.error.code})`);
|
|
1234
|
-
}
|
|
1235
|
-
} catch (e) {
|
|
1236
|
-
if (e.message.startsWith("HTTP error establishing stream")) throw e;
|
|
1237
|
-
throw new Error(`HTTP error establishing stream for message/stream: ${response.status} ${response.statusText}. Response: ${errorBody || "(empty)"}`);
|
|
1238
|
-
}
|
|
1239
|
-
throw new Error(`HTTP error establishing stream for message/stream: ${response.status} ${response.statusText}`);
|
|
1240
|
-
}
|
|
1241
|
-
if (!((_b = response.headers.get("Content-Type")) == null ? void 0 : _b.startsWith("text/event-stream"))) {
|
|
1242
|
-
throw new Error("Invalid response Content-Type for SSE stream. Expected 'text/event-stream'.");
|
|
1243
|
-
}
|
|
1244
|
-
yield* __yieldStar(this._parseA2ASseStream(response, clientRequestId));
|
|
1245
|
-
});
|
|
1668
|
+
async *sendMessageStream(params) {
|
|
1669
|
+
const agentCard = await this.agentCardPromise;
|
|
1670
|
+
if (!agentCard.capabilities?.streaming) {
|
|
1671
|
+
throw new Error(
|
|
1672
|
+
"Agent does not support streaming (AgentCard.capabilities.streaming is not true)."
|
|
1673
|
+
);
|
|
1674
|
+
}
|
|
1675
|
+
const transport = await this._getOrCreateTransport();
|
|
1676
|
+
yield* transport.sendMessageStream(params);
|
|
1246
1677
|
}
|
|
1247
1678
|
/**
|
|
1248
1679
|
* Sets or updates the push notification configuration for a given task.
|
|
@@ -1250,192 +1681,102 @@ var A2AClient = class _A2AClient {
|
|
|
1250
1681
|
* @param params Parameters containing the taskId and the TaskPushNotificationConfig.
|
|
1251
1682
|
* @returns A Promise resolving to SetTaskPushNotificationConfigResponse.
|
|
1252
1683
|
*/
|
|
1253
|
-
setTaskPushNotificationConfig(params) {
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
throw new Error("Agent does not support push notifications (AgentCard.capabilities.pushNotifications is not true).");
|
|
1259
|
-
}
|
|
1260
|
-
return this._postRpcRequest(
|
|
1261
|
-
"tasks/pushNotificationConfig/set",
|
|
1262
|
-
params
|
|
1684
|
+
async setTaskPushNotificationConfig(params) {
|
|
1685
|
+
const agentCard = await this.agentCardPromise;
|
|
1686
|
+
if (!agentCard.capabilities?.pushNotifications) {
|
|
1687
|
+
throw new Error(
|
|
1688
|
+
"Agent does not support push notifications (AgentCard.capabilities.pushNotifications is not true)."
|
|
1263
1689
|
);
|
|
1264
|
-
}
|
|
1690
|
+
}
|
|
1691
|
+
return await this.invokeJsonRpc((t, p, id) => t.setTaskPushNotificationConfig(p, _A2AClient.emptyOptions, id), params);
|
|
1265
1692
|
}
|
|
1266
1693
|
/**
|
|
1267
1694
|
* Gets the push notification configuration for a given task.
|
|
1268
1695
|
* @param params Parameters containing the taskId.
|
|
1269
1696
|
* @returns A Promise resolving to GetTaskPushNotificationConfigResponse.
|
|
1270
1697
|
*/
|
|
1271
|
-
getTaskPushNotificationConfig(params) {
|
|
1272
|
-
return
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1698
|
+
async getTaskPushNotificationConfig(params) {
|
|
1699
|
+
return await this.invokeJsonRpc(
|
|
1700
|
+
(t, p, id) => t.getTaskPushNotificationConfig(p, _A2AClient.emptyOptions, id),
|
|
1701
|
+
params
|
|
1702
|
+
);
|
|
1703
|
+
}
|
|
1704
|
+
/**
|
|
1705
|
+
* Lists the push notification configurations for a given task.
|
|
1706
|
+
* @param params Parameters containing the taskId.
|
|
1707
|
+
* @returns A Promise resolving to ListTaskPushNotificationConfigResponse.
|
|
1708
|
+
*/
|
|
1709
|
+
async listTaskPushNotificationConfig(params) {
|
|
1710
|
+
return await this.invokeJsonRpc((t, p, id) => t.listTaskPushNotificationConfig(p, _A2AClient.emptyOptions, id), params);
|
|
1711
|
+
}
|
|
1712
|
+
/**
|
|
1713
|
+
* Deletes the push notification configuration for a given task.
|
|
1714
|
+
* @param params Parameters containing the taskId and push notification configuration ID.
|
|
1715
|
+
* @returns A Promise resolving to DeleteTaskPushNotificationConfigResponse.
|
|
1716
|
+
*/
|
|
1717
|
+
async deleteTaskPushNotificationConfig(params) {
|
|
1718
|
+
return await this.invokeJsonRpc((t, p, id) => t.deleteTaskPushNotificationConfig(p, _A2AClient.emptyOptions, id), params);
|
|
1278
1719
|
}
|
|
1279
1720
|
/**
|
|
1280
1721
|
* Retrieves a task by its ID.
|
|
1281
1722
|
* @param params Parameters containing the taskId and optional historyLength.
|
|
1282
1723
|
* @returns A Promise resolving to GetTaskResponse, which contains the Task object or an error.
|
|
1283
1724
|
*/
|
|
1284
|
-
getTask(params) {
|
|
1285
|
-
return
|
|
1286
|
-
|
|
1287
|
-
|
|
1725
|
+
async getTask(params) {
|
|
1726
|
+
return await this.invokeJsonRpc(
|
|
1727
|
+
(t, p, id) => t.getTask(p, _A2AClient.emptyOptions, id),
|
|
1728
|
+
params
|
|
1729
|
+
);
|
|
1288
1730
|
}
|
|
1289
1731
|
/**
|
|
1290
1732
|
* Cancels a task by its ID.
|
|
1291
1733
|
* @param params Parameters containing the taskId.
|
|
1292
1734
|
* @returns A Promise resolving to CancelTaskResponse, which contains the updated Task object or an error.
|
|
1293
1735
|
*/
|
|
1294
|
-
cancelTask(params) {
|
|
1295
|
-
return
|
|
1296
|
-
|
|
1297
|
-
|
|
1736
|
+
async cancelTask(params) {
|
|
1737
|
+
return await this.invokeJsonRpc(
|
|
1738
|
+
(t, p, id) => t.cancelTask(p, _A2AClient.emptyOptions, id),
|
|
1739
|
+
params
|
|
1740
|
+
);
|
|
1298
1741
|
}
|
|
1299
1742
|
/**
|
|
1300
|
-
*
|
|
1301
|
-
*
|
|
1302
|
-
*
|
|
1303
|
-
* @param
|
|
1304
|
-
* @
|
|
1743
|
+
* @template TExtensionParams The type of parameters for the custom extension method.
|
|
1744
|
+
* @template TExtensionResponse The type of response expected from the custom extension method.
|
|
1745
|
+
* This should extend JSONRPCResponse. This ensures the extension response is still a valid A2A response.
|
|
1746
|
+
* @param method Custom JSON-RPC method defined in the AgentCard's extensions.
|
|
1747
|
+
* @param params Extension paramters defined in the AgentCard's extensions.
|
|
1748
|
+
* @returns A Promise that resolves to the RPC response.
|
|
1305
1749
|
*/
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
throw new Error("Agent does not support streaming (required for tasks/resubscribe).");
|
|
1312
|
-
}
|
|
1313
|
-
const endpoint = yield new __await(this._getServiceEndpoint());
|
|
1314
|
-
const clientRequestId = this.requestIdCounter++;
|
|
1315
|
-
const rpcRequest = {
|
|
1316
|
-
// Initial JSON-RPC request to establish the stream
|
|
1317
|
-
jsonrpc: "2.0",
|
|
1318
|
-
method: "tasks/resubscribe",
|
|
1750
|
+
async callExtensionMethod(method, params) {
|
|
1751
|
+
const transport = await this._getOrCreateTransport();
|
|
1752
|
+
try {
|
|
1753
|
+
return await transport.callExtensionMethod(
|
|
1754
|
+
method,
|
|
1319
1755
|
params,
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
"Accept": "text/event-stream"
|
|
1327
|
-
},
|
|
1328
|
-
body: JSON.stringify(rpcRequest)
|
|
1329
|
-
}));
|
|
1330
|
-
if (!response.ok) {
|
|
1331
|
-
let errorBody = "";
|
|
1332
|
-
try {
|
|
1333
|
-
errorBody = yield new __await(response.text());
|
|
1334
|
-
const errorJson = JSON.parse(errorBody);
|
|
1335
|
-
if (errorJson.error) {
|
|
1336
|
-
throw new Error(`HTTP error establishing stream for tasks/resubscribe: ${response.status} ${response.statusText}. RPC Error: ${errorJson.error.message} (Code: ${errorJson.error.code})`);
|
|
1337
|
-
}
|
|
1338
|
-
} catch (e) {
|
|
1339
|
-
if (e.message.startsWith("HTTP error establishing stream")) throw e;
|
|
1340
|
-
throw new Error(`HTTP error establishing stream for tasks/resubscribe: ${response.status} ${response.statusText}. Response: ${errorBody || "(empty)"}`);
|
|
1341
|
-
}
|
|
1342
|
-
throw new Error(`HTTP error establishing stream for tasks/resubscribe: ${response.status} ${response.statusText}`);
|
|
1343
|
-
}
|
|
1344
|
-
if (!((_b = response.headers.get("Content-Type")) == null ? void 0 : _b.startsWith("text/event-stream"))) {
|
|
1345
|
-
throw new Error("Invalid response Content-Type for SSE stream on resubscribe. Expected 'text/event-stream'.");
|
|
1346
|
-
}
|
|
1347
|
-
yield* __yieldStar(this._parseA2ASseStream(response, clientRequestId));
|
|
1348
|
-
});
|
|
1349
|
-
}
|
|
1350
|
-
/**
|
|
1351
|
-
* Parses an HTTP response body as an A2A Server-Sent Event stream.
|
|
1352
|
-
* Each 'data' field of an SSE event is expected to be a JSON-RPC 2.0 Response object,
|
|
1353
|
-
* specifically a SendStreamingMessageResponse (or similar structure for resubscribe).
|
|
1354
|
-
* @param response The HTTP Response object whose body is the SSE stream.
|
|
1355
|
-
* @param originalRequestId The ID of the client's JSON-RPC request that initiated this stream.
|
|
1356
|
-
* Used to validate the `id` in the streamed JSON-RPC responses.
|
|
1357
|
-
* @returns An AsyncGenerator yielding the `result` field of each valid JSON-RPC success response from the stream.
|
|
1358
|
-
*/
|
|
1359
|
-
_parseA2ASseStream(response, originalRequestId) {
|
|
1360
|
-
return __asyncGenerator(this, null, function* () {
|
|
1361
|
-
if (!response.body) {
|
|
1362
|
-
throw new Error("SSE response body is undefined. Cannot read stream.");
|
|
1363
|
-
}
|
|
1364
|
-
const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
|
|
1365
|
-
let buffer = "";
|
|
1366
|
-
let eventDataBuffer = "";
|
|
1367
|
-
try {
|
|
1368
|
-
while (true) {
|
|
1369
|
-
const { done, value } = yield new __await(reader.read());
|
|
1370
|
-
if (done) {
|
|
1371
|
-
if (eventDataBuffer.trim()) {
|
|
1372
|
-
const result = this._processSseEventData(eventDataBuffer, originalRequestId);
|
|
1373
|
-
yield result;
|
|
1374
|
-
}
|
|
1375
|
-
break;
|
|
1376
|
-
}
|
|
1377
|
-
buffer += value;
|
|
1378
|
-
let lineEndIndex;
|
|
1379
|
-
while ((lineEndIndex = buffer.indexOf("\n")) >= 0) {
|
|
1380
|
-
const line = buffer.substring(0, lineEndIndex).trim();
|
|
1381
|
-
buffer = buffer.substring(lineEndIndex + 1);
|
|
1382
|
-
if (line === "") {
|
|
1383
|
-
if (eventDataBuffer) {
|
|
1384
|
-
const result = this._processSseEventData(eventDataBuffer, originalRequestId);
|
|
1385
|
-
yield result;
|
|
1386
|
-
eventDataBuffer = "";
|
|
1387
|
-
}
|
|
1388
|
-
} else if (line.startsWith("data:")) {
|
|
1389
|
-
eventDataBuffer += line.substring(5).trimStart() + "\n";
|
|
1390
|
-
} else if (line.startsWith(":")) {
|
|
1391
|
-
} else if (line.includes(":")) {
|
|
1392
|
-
}
|
|
1393
|
-
}
|
|
1394
|
-
}
|
|
1395
|
-
} catch (error) {
|
|
1396
|
-
console.error("Error reading or parsing SSE stream:", error.message);
|
|
1397
|
-
throw error;
|
|
1398
|
-
} finally {
|
|
1399
|
-
reader.releaseLock();
|
|
1756
|
+
this.requestIdCounter++
|
|
1757
|
+
);
|
|
1758
|
+
} catch (e) {
|
|
1759
|
+
const errorResponse = extractJSONRPCError(e);
|
|
1760
|
+
if (errorResponse) {
|
|
1761
|
+
return errorResponse;
|
|
1400
1762
|
}
|
|
1401
|
-
|
|
1763
|
+
throw e;
|
|
1764
|
+
}
|
|
1402
1765
|
}
|
|
1403
1766
|
/**
|
|
1404
|
-
*
|
|
1405
|
-
*
|
|
1406
|
-
*
|
|
1407
|
-
* @
|
|
1408
|
-
* @
|
|
1767
|
+
* Resubscribes to a task's event stream using Server-Sent Events (SSE).
|
|
1768
|
+
* This is used if a previous SSE connection for an active task was broken.
|
|
1769
|
+
* Requires the agent to support streaming (`capabilities.streaming: true` in AgentCard).
|
|
1770
|
+
* @param params Parameters containing the taskId.
|
|
1771
|
+
* @returns An AsyncGenerator yielding A2AStreamEventData (Message, Task, TaskStatusUpdateEvent, or TaskArtifactUpdateEvent).
|
|
1409
1772
|
*/
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1773
|
+
async *resubscribeTask(params) {
|
|
1774
|
+
const agentCard = await this.agentCardPromise;
|
|
1775
|
+
if (!agentCard.capabilities?.streaming) {
|
|
1776
|
+
throw new Error("Agent does not support streaming (required for tasks/resubscribe).");
|
|
1413
1777
|
}
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
const a2aStreamResponse = sseJsonRpcResponse;
|
|
1417
|
-
if (a2aStreamResponse.id !== originalRequestId) {
|
|
1418
|
-
console.warn(`SSE Event's JSON-RPC response ID mismatch. Client request ID: ${originalRequestId}, event response ID: ${a2aStreamResponse.id}.`);
|
|
1419
|
-
}
|
|
1420
|
-
if (this.isErrorResponse(a2aStreamResponse)) {
|
|
1421
|
-
const err = a2aStreamResponse.error;
|
|
1422
|
-
throw new Error(`SSE event contained an error: ${err.message} (Code: ${err.code}) Data: ${JSON.stringify(err.data || {})}`);
|
|
1423
|
-
}
|
|
1424
|
-
if (!("result" in a2aStreamResponse) || typeof a2aStreamResponse.result === "undefined") {
|
|
1425
|
-
throw new Error(`SSE event JSON-RPC response is missing 'result' field. Data: ${jsonData}`);
|
|
1426
|
-
}
|
|
1427
|
-
const successResponse = a2aStreamResponse;
|
|
1428
|
-
return successResponse.result;
|
|
1429
|
-
} catch (e) {
|
|
1430
|
-
if (e.message.startsWith("SSE event contained an error") || e.message.startsWith("SSE event JSON-RPC response is missing 'result' field")) {
|
|
1431
|
-
throw e;
|
|
1432
|
-
}
|
|
1433
|
-
console.error("Failed to parse SSE event data string or unexpected JSON-RPC structure:", jsonData, e);
|
|
1434
|
-
throw new Error(`Failed to parse SSE event data: "${jsonData.substring(0, 100)}...". Original error: ${e.message}`);
|
|
1435
|
-
}
|
|
1436
|
-
}
|
|
1437
|
-
isErrorResponse(response) {
|
|
1438
|
-
return "error" in response;
|
|
1778
|
+
const transport = await this._getOrCreateTransport();
|
|
1779
|
+
yield* transport.resubscribeTask(params);
|
|
1439
1780
|
}
|
|
1440
1781
|
////////////////////////////////////////////////////////////////////////////////
|
|
1441
1782
|
// Functions used to support old A2AClient Constructor to be deprecated soon
|
|
@@ -1446,7 +1787,16 @@ var A2AClient = class _A2AClient {
|
|
|
1446
1787
|
// * getAgentCard changed to this.agentCard
|
|
1447
1788
|
// * delete resolveAgentCardUrl(), _fetchAndCacheAgentCard(),
|
|
1448
1789
|
// agentCardPath from A2AClientOptions
|
|
1790
|
+
// * delete _getOrCreateTransport
|
|
1449
1791
|
////////////////////////////////////////////////////////////////////////////////
|
|
1792
|
+
async _getOrCreateTransport() {
|
|
1793
|
+
if (this.transport) {
|
|
1794
|
+
return this.transport;
|
|
1795
|
+
}
|
|
1796
|
+
const endpoint = await this._getServiceEndpoint();
|
|
1797
|
+
this.transport = new JsonRpcTransport({ fetchImpl: this.customFetchImpl, endpoint });
|
|
1798
|
+
return this.transport;
|
|
1799
|
+
}
|
|
1450
1800
|
/**
|
|
1451
1801
|
* Fetches the Agent Card from the agent's well-known URI and caches its service endpoint URL.
|
|
1452
1802
|
* This method is called by the constructor.
|
|
@@ -1454,51 +1804,53 @@ var A2AClient = class _A2AClient {
|
|
|
1454
1804
|
* @param agentCardPath path to the agent card, defaults to .well-known/agent-card.json
|
|
1455
1805
|
* @returns A Promise that resolves to the AgentCard.
|
|
1456
1806
|
*/
|
|
1457
|
-
_fetchAndCacheAgentCard(agentBaseUrl, agentCardPath) {
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
const agentCard = yield response.json();
|
|
1468
|
-
if (!agentCard.url) {
|
|
1469
|
-
throw new Error("Fetched Agent Card does not contain a valid 'url' for the service endpoint.");
|
|
1470
|
-
}
|
|
1471
|
-
this.serviceEndpointUrl = agentCard.url;
|
|
1472
|
-
return agentCard;
|
|
1473
|
-
} catch (error) {
|
|
1474
|
-
console.error("Error fetching or parsing Agent Card:", error);
|
|
1475
|
-
throw error;
|
|
1807
|
+
async _fetchAndCacheAgentCard(agentBaseUrl, agentCardPath) {
|
|
1808
|
+
try {
|
|
1809
|
+
const agentCardUrl = this.resolveAgentCardUrl(agentBaseUrl, agentCardPath);
|
|
1810
|
+
const response = await this._fetch(agentCardUrl, {
|
|
1811
|
+
headers: { Accept: "application/json" }
|
|
1812
|
+
});
|
|
1813
|
+
if (!response.ok) {
|
|
1814
|
+
throw new Error(
|
|
1815
|
+
`Failed to fetch Agent Card from ${agentCardUrl}: ${response.status} ${response.statusText}`
|
|
1816
|
+
);
|
|
1476
1817
|
}
|
|
1477
|
-
|
|
1818
|
+
const agentCard = await response.json();
|
|
1819
|
+
if (!agentCard.url) {
|
|
1820
|
+
throw new Error(
|
|
1821
|
+
"Fetched Agent Card does not contain a valid 'url' for the service endpoint."
|
|
1822
|
+
);
|
|
1823
|
+
}
|
|
1824
|
+
this.serviceEndpointUrl = agentCard.url;
|
|
1825
|
+
return agentCard;
|
|
1826
|
+
} catch (error) {
|
|
1827
|
+
console.error("Error fetching or parsing Agent Card:", error);
|
|
1828
|
+
throw error;
|
|
1829
|
+
}
|
|
1478
1830
|
}
|
|
1479
1831
|
/**
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
getAgentCard(agentBaseUrl, agentCardPath) {
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
return yield response.json();
|
|
1832
|
+
* Retrieves the Agent Card.
|
|
1833
|
+
* If an `agentBaseUrl` is provided, it fetches the card from that specific URL.
|
|
1834
|
+
* Otherwise, it returns the card fetched and cached during client construction.
|
|
1835
|
+
* @param agentBaseUrl Optional. The base URL of the agent to fetch the card from.
|
|
1836
|
+
* @param agentCardPath path to the agent card, defaults to .well-known/agent-card.json
|
|
1837
|
+
* If provided, this will fetch a new card, not use the cached one from the constructor's URL.
|
|
1838
|
+
* @returns A Promise that resolves to the AgentCard.
|
|
1839
|
+
*/
|
|
1840
|
+
async getAgentCard(agentBaseUrl, agentCardPath) {
|
|
1841
|
+
if (agentBaseUrl) {
|
|
1842
|
+
const agentCardUrl = this.resolveAgentCardUrl(agentBaseUrl, agentCardPath);
|
|
1843
|
+
const response = await this._fetch(agentCardUrl, {
|
|
1844
|
+
headers: { Accept: "application/json" }
|
|
1845
|
+
});
|
|
1846
|
+
if (!response.ok) {
|
|
1847
|
+
throw new Error(
|
|
1848
|
+
`Failed to fetch Agent Card from ${agentCardUrl}: ${response.status} ${response.statusText}`
|
|
1849
|
+
);
|
|
1499
1850
|
}
|
|
1500
|
-
return
|
|
1501
|
-
}
|
|
1851
|
+
return await response.json();
|
|
1852
|
+
}
|
|
1853
|
+
return this.agentCardPromise;
|
|
1502
1854
|
}
|
|
1503
1855
|
/**
|
|
1504
1856
|
* Determines the agent card URL based on the agent URL.
|
|
@@ -1512,41 +1864,73 @@ var A2AClient = class _A2AClient {
|
|
|
1512
1864
|
* Gets the RPC service endpoint URL. Ensures the agent card has been fetched first.
|
|
1513
1865
|
* @returns A Promise that resolves to the service endpoint URL string.
|
|
1514
1866
|
*/
|
|
1515
|
-
_getServiceEndpoint() {
|
|
1516
|
-
|
|
1517
|
-
if (this.serviceEndpointUrl) {
|
|
1518
|
-
return this.serviceEndpointUrl;
|
|
1519
|
-
}
|
|
1520
|
-
yield this.agentCardPromise;
|
|
1521
|
-
if (!this.serviceEndpointUrl) {
|
|
1522
|
-
throw new Error("Agent Card URL for RPC endpoint is not available. Fetching might have failed.");
|
|
1523
|
-
}
|
|
1867
|
+
async _getServiceEndpoint() {
|
|
1868
|
+
if (this.serviceEndpointUrl) {
|
|
1524
1869
|
return this.serviceEndpointUrl;
|
|
1525
|
-
}
|
|
1870
|
+
}
|
|
1871
|
+
await this.agentCardPromise;
|
|
1872
|
+
if (!this.serviceEndpointUrl) {
|
|
1873
|
+
throw new Error(
|
|
1874
|
+
"Agent Card URL for RPC endpoint is not available. Fetching might have failed."
|
|
1875
|
+
);
|
|
1876
|
+
}
|
|
1877
|
+
return this.serviceEndpointUrl;
|
|
1878
|
+
}
|
|
1879
|
+
async invokeJsonRpc(caller, params) {
|
|
1880
|
+
const transport = await this._getOrCreateTransport();
|
|
1881
|
+
const requestId = this.requestIdCounter++;
|
|
1882
|
+
try {
|
|
1883
|
+
const result = await caller(transport, params, requestId);
|
|
1884
|
+
return {
|
|
1885
|
+
id: requestId,
|
|
1886
|
+
jsonrpc: "2.0",
|
|
1887
|
+
result: result ?? null
|
|
1888
|
+
// JSON-RPC requires result property on success, it will be null for "void" methods.
|
|
1889
|
+
};
|
|
1890
|
+
} catch (e) {
|
|
1891
|
+
const errorResponse = extractJSONRPCError(e);
|
|
1892
|
+
if (errorResponse) {
|
|
1893
|
+
return errorResponse;
|
|
1894
|
+
}
|
|
1895
|
+
throw e;
|
|
1896
|
+
}
|
|
1526
1897
|
}
|
|
1527
1898
|
};
|
|
1899
|
+
function extractJSONRPCError(error) {
|
|
1900
|
+
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) {
|
|
1901
|
+
return error.errorResponse;
|
|
1902
|
+
} else {
|
|
1903
|
+
return void 0;
|
|
1904
|
+
}
|
|
1905
|
+
}
|
|
1528
1906
|
|
|
1529
1907
|
// src/client/auth-handler.ts
|
|
1530
1908
|
function createAuthenticatingFetchWithRetry(fetchImpl, authHandler) {
|
|
1531
|
-
function authFetch(url, init) {
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1909
|
+
async function authFetch(url, init) {
|
|
1910
|
+
const authHeaders = await authHandler.headers() || {};
|
|
1911
|
+
const mergedInit = {
|
|
1912
|
+
...init || {},
|
|
1913
|
+
headers: {
|
|
1914
|
+
...authHeaders,
|
|
1915
|
+
...init?.headers || {}
|
|
1916
|
+
}
|
|
1917
|
+
};
|
|
1918
|
+
let response = await fetchImpl(url, mergedInit);
|
|
1919
|
+
const updatedHeaders = await authHandler.shouldRetryWithHeaders(mergedInit, response);
|
|
1920
|
+
if (updatedHeaders) {
|
|
1921
|
+
const retryInit = {
|
|
1922
|
+
...init || {},
|
|
1923
|
+
headers: {
|
|
1924
|
+
...updatedHeaders,
|
|
1925
|
+
...init?.headers || {}
|
|
1546
1926
|
}
|
|
1927
|
+
};
|
|
1928
|
+
response = await fetchImpl(url, retryInit);
|
|
1929
|
+
if (response.ok && authHandler.onSuccessfulRetry) {
|
|
1930
|
+
await authHandler.onSuccessfulRetry(updatedHeaders);
|
|
1547
1931
|
}
|
|
1548
|
-
|
|
1549
|
-
|
|
1932
|
+
}
|
|
1933
|
+
return response;
|
|
1550
1934
|
}
|
|
1551
1935
|
Object.setPrototypeOf(authFetch, Object.getPrototypeOf(fetchImpl));
|
|
1552
1936
|
Object.defineProperties(authFetch, Object.getOwnPropertyDescriptors(fetchImpl));
|
|
@@ -1554,106 +1938,168 @@ function createAuthenticatingFetchWithRetry(fetchImpl, authHandler) {
|
|
|
1554
1938
|
}
|
|
1555
1939
|
|
|
1556
1940
|
// src/server/express/a2a_express_app.ts
|
|
1941
|
+
var import_express3 = __toESM(require("express"));
|
|
1942
|
+
|
|
1943
|
+
// src/server/express/json_rpc_handler.ts
|
|
1557
1944
|
var import_express = __toESM(require("express"));
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1945
|
+
|
|
1946
|
+
// src/server/authentication/user.ts
|
|
1947
|
+
var UnauthenticatedUser = class {
|
|
1948
|
+
get isAuthenticated() {
|
|
1949
|
+
return false;
|
|
1562
1950
|
}
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
try {
|
|
1594
|
-
try {
|
|
1595
|
-
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield iter.next()).done; more = false) {
|
|
1596
|
-
const event = temp.value;
|
|
1597
|
-
res.write(`id: ${(/* @__PURE__ */ new Date()).getTime()}
|
|
1951
|
+
get userName() {
|
|
1952
|
+
return "";
|
|
1953
|
+
}
|
|
1954
|
+
};
|
|
1955
|
+
|
|
1956
|
+
// src/server/express/json_rpc_handler.ts
|
|
1957
|
+
function jsonRpcHandler(options) {
|
|
1958
|
+
const jsonRpcTransportHandler = new JsonRpcTransportHandler(options.requestHandler);
|
|
1959
|
+
const router = import_express.default.Router();
|
|
1960
|
+
router.use(import_express.default.json(), jsonErrorHandler);
|
|
1961
|
+
router.post("/", async (req, res) => {
|
|
1962
|
+
try {
|
|
1963
|
+
const user = await options.userBuilder(req);
|
|
1964
|
+
const context = new ServerCallContext(
|
|
1965
|
+
getRequestedExtensions(req.header(HTTP_EXTENSION_HEADER)),
|
|
1966
|
+
user ?? new UnauthenticatedUser()
|
|
1967
|
+
);
|
|
1968
|
+
const rpcResponseOrStream = await jsonRpcTransportHandler.handle(req.body, context);
|
|
1969
|
+
if (context.activatedExtensions) {
|
|
1970
|
+
res.setHeader(HTTP_EXTENSION_HEADER, Array.from(context.activatedExtensions));
|
|
1971
|
+
}
|
|
1972
|
+
if (typeof rpcResponseOrStream?.[Symbol.asyncIterator] === "function") {
|
|
1973
|
+
const stream = rpcResponseOrStream;
|
|
1974
|
+
res.setHeader("Content-Type", "text/event-stream");
|
|
1975
|
+
res.setHeader("Cache-Control", "no-cache");
|
|
1976
|
+
res.setHeader("Connection", "keep-alive");
|
|
1977
|
+
res.flushHeaders();
|
|
1978
|
+
try {
|
|
1979
|
+
for await (const event of stream) {
|
|
1980
|
+
res.write(`id: ${(/* @__PURE__ */ new Date()).getTime()}
|
|
1598
1981
|
`);
|
|
1599
|
-
|
|
1982
|
+
res.write(`data: ${JSON.stringify(event)}
|
|
1600
1983
|
|
|
1601
1984
|
`);
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
res.status(500).json(errorResponse);
|
|
1624
|
-
} else {
|
|
1625
|
-
res.write(`id: ${(/* @__PURE__ */ new Date()).getTime()}
|
|
1985
|
+
}
|
|
1986
|
+
} catch (streamError) {
|
|
1987
|
+
console.error(`Error during SSE streaming (request ${req.body?.id}):`, streamError);
|
|
1988
|
+
let a2aError;
|
|
1989
|
+
if (streamError instanceof A2AError) {
|
|
1990
|
+
a2aError = streamError;
|
|
1991
|
+
} else {
|
|
1992
|
+
a2aError = A2AError.internalError(
|
|
1993
|
+
streamError instanceof Error && streamError.message || "Streaming error."
|
|
1994
|
+
);
|
|
1995
|
+
}
|
|
1996
|
+
const errorResponse = {
|
|
1997
|
+
jsonrpc: "2.0",
|
|
1998
|
+
id: req.body?.id || null,
|
|
1999
|
+
// Use original request ID if available
|
|
2000
|
+
error: a2aError.toJSONRPCError()
|
|
2001
|
+
};
|
|
2002
|
+
if (!res.headersSent) {
|
|
2003
|
+
res.status(500).json(errorResponse);
|
|
2004
|
+
} else {
|
|
2005
|
+
res.write(`id: ${(/* @__PURE__ */ new Date()).getTime()}
|
|
1626
2006
|
`);
|
|
1627
|
-
|
|
2007
|
+
res.write(`event: error
|
|
1628
2008
|
`);
|
|
1629
|
-
|
|
2009
|
+
res.write(`data: ${JSON.stringify(errorResponse)}
|
|
1630
2010
|
|
|
1631
2011
|
`);
|
|
1632
|
-
}
|
|
1633
|
-
} finally {
|
|
1634
|
-
if (!res.writableEnded) {
|
|
1635
|
-
res.end();
|
|
1636
|
-
}
|
|
1637
2012
|
}
|
|
1638
|
-
}
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
} catch (error2) {
|
|
1643
|
-
console.error("Unhandled error in A2AExpressApp POST handler:", error2);
|
|
1644
|
-
const a2aError = error2 instanceof A2AError ? error2 : A2AError.internalError("General processing error.");
|
|
1645
|
-
const errorResponse = {
|
|
1646
|
-
jsonrpc: "2.0",
|
|
1647
|
-
id: ((_c = req.body) == null ? void 0 : _c.id) || null,
|
|
1648
|
-
error: a2aError.toJSONRPCError()
|
|
1649
|
-
};
|
|
1650
|
-
if (!res.headersSent) {
|
|
1651
|
-
res.status(500).json(errorResponse);
|
|
1652
|
-
} else if (!res.writableEnded) {
|
|
1653
|
-
res.end();
|
|
2013
|
+
} finally {
|
|
2014
|
+
if (!res.writableEnded) {
|
|
2015
|
+
res.end();
|
|
2016
|
+
}
|
|
1654
2017
|
}
|
|
2018
|
+
} else {
|
|
2019
|
+
const rpcResponse = rpcResponseOrStream;
|
|
2020
|
+
res.status(200).json(rpcResponse);
|
|
1655
2021
|
}
|
|
1656
|
-
})
|
|
2022
|
+
} catch (error) {
|
|
2023
|
+
console.error("Unhandled error in JSON-RPC POST handler:", error);
|
|
2024
|
+
const a2aError = error instanceof A2AError ? error : A2AError.internalError("General processing error.");
|
|
2025
|
+
const errorResponse = {
|
|
2026
|
+
jsonrpc: "2.0",
|
|
2027
|
+
id: req.body?.id || null,
|
|
2028
|
+
error: a2aError.toJSONRPCError()
|
|
2029
|
+
};
|
|
2030
|
+
if (!res.headersSent) {
|
|
2031
|
+
res.status(500).json(errorResponse);
|
|
2032
|
+
} else if (!res.writableEnded) {
|
|
2033
|
+
res.end();
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
2036
|
+
});
|
|
2037
|
+
return router;
|
|
2038
|
+
}
|
|
2039
|
+
var jsonErrorHandler = (err, _req, res, next) => {
|
|
2040
|
+
if (err instanceof SyntaxError && "body" in err) {
|
|
2041
|
+
const a2aError = A2AError.parseError("Invalid JSON payload.");
|
|
2042
|
+
const errorResponse = {
|
|
2043
|
+
jsonrpc: "2.0",
|
|
2044
|
+
id: null,
|
|
2045
|
+
error: a2aError.toJSONRPCError()
|
|
2046
|
+
};
|
|
2047
|
+
return res.status(400).json(errorResponse);
|
|
2048
|
+
}
|
|
2049
|
+
next(err);
|
|
2050
|
+
};
|
|
2051
|
+
|
|
2052
|
+
// src/server/express/agent_card_handler.ts
|
|
2053
|
+
var import_express2 = __toESM(require("express"));
|
|
2054
|
+
function agentCardHandler(options) {
|
|
2055
|
+
const router = import_express2.default.Router();
|
|
2056
|
+
const provider = typeof options.agentCardProvider === "function" ? options.agentCardProvider : options.agentCardProvider.getAgentCard.bind(options.agentCardProvider);
|
|
2057
|
+
router.get("/", async (_req, res) => {
|
|
2058
|
+
try {
|
|
2059
|
+
const agentCard = await provider();
|
|
2060
|
+
res.json(agentCard);
|
|
2061
|
+
} catch (error) {
|
|
2062
|
+
console.error("Error fetching agent card:", error);
|
|
2063
|
+
res.status(500).json({ error: "Failed to retrieve agent card" });
|
|
2064
|
+
}
|
|
2065
|
+
});
|
|
2066
|
+
return router;
|
|
2067
|
+
}
|
|
2068
|
+
|
|
2069
|
+
// src/server/express/common.ts
|
|
2070
|
+
var UserBuilder = {
|
|
2071
|
+
NoAuthentication: () => Promise.resolve(new UnauthenticatedUser())
|
|
2072
|
+
};
|
|
2073
|
+
|
|
2074
|
+
// src/server/express/a2a_express_app.ts
|
|
2075
|
+
var A2AExpressApp = class {
|
|
2076
|
+
requestHandler;
|
|
2077
|
+
userBuilder;
|
|
2078
|
+
constructor(requestHandler, userBuilder = UserBuilder.NoAuthentication) {
|
|
2079
|
+
this.requestHandler = requestHandler;
|
|
2080
|
+
this.userBuilder = userBuilder;
|
|
2081
|
+
}
|
|
2082
|
+
/**
|
|
2083
|
+
* Adds A2A routes to an existing Express app.
|
|
2084
|
+
* @param app Optional existing Express app.
|
|
2085
|
+
* @param baseUrl The base URL for A2A endpoints (e.g., "/a2a/api").
|
|
2086
|
+
* @param middlewares Optional array of Express middlewares to apply to the A2A routes.
|
|
2087
|
+
* @param agentCardPath Optional custom path for the agent card endpoint (defaults to .well-known/agent-card.json).
|
|
2088
|
+
* @returns The Express app with A2A routes.
|
|
2089
|
+
*/
|
|
2090
|
+
setupRoutes(app, baseUrl = "", middlewares, agentCardPath = AGENT_CARD_PATH) {
|
|
2091
|
+
const router = import_express3.default.Router();
|
|
2092
|
+
router.use(import_express3.default.json(), jsonErrorHandler);
|
|
2093
|
+
if (middlewares && middlewares.length > 0) {
|
|
2094
|
+
router.use(middlewares);
|
|
2095
|
+
}
|
|
2096
|
+
router.use(
|
|
2097
|
+
jsonRpcHandler({
|
|
2098
|
+
requestHandler: this.requestHandler,
|
|
2099
|
+
userBuilder: this.userBuilder
|
|
2100
|
+
})
|
|
2101
|
+
);
|
|
2102
|
+
router.use(`/${agentCardPath}`, agentCardHandler({ agentCardProvider: this.requestHandler }));
|
|
1657
2103
|
app.use(baseUrl, router);
|
|
1658
2104
|
return app;
|
|
1659
2105
|
}
|
|
@@ -1674,6 +2120,7 @@ var A2AExpressApp = class {
|
|
|
1674
2120
|
ResultManager,
|
|
1675
2121
|
createAuthenticatingFetchWithRetry,
|
|
1676
2122
|
getCurrentTimestamp,
|
|
2123
|
+
getRequestedExtensions,
|
|
1677
2124
|
isArtifactUpdate,
|
|
1678
2125
|
isObject,
|
|
1679
2126
|
isTaskStatusUpdate
|