@a2a-js/sdk 0.3.5 → 0.3.7
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 +225 -187
- package/dist/a2a_request_handler-B3LxMq3P.d.cts +49 -0
- package/dist/a2a_request_handler-BuP9LgXH.d.ts +49 -0
- package/dist/chunk-3QDLXHKS.js +8 -0
- package/dist/{chunk-SY3G7ITG.js → chunk-LTPINR5K.js} +81 -56
- package/dist/chunk-SJNAG4AL.js +122 -0
- package/dist/chunk-ZX6KNMCP.js +38 -0
- package/dist/client/index.cjs +1304 -265
- package/dist/client/index.d.cts +477 -48
- package/dist/client/index.d.ts +477 -48
- package/dist/client/index.js +1165 -257
- package/dist/{types-DNKcmF0f.d.cts → extensions-DvruCIzw.d.cts} +28 -1
- package/dist/{types-DNKcmF0f.d.ts → extensions-DvruCIzw.d.ts} +28 -1
- package/dist/index.cjs +42 -2
- package/dist/index.d.cts +7 -3
- package/dist/index.d.ts +7 -3
- package/dist/index.js +9 -3
- package/dist/server/express/index.cjs +757 -146
- package/dist/server/express/index.d.cts +83 -6
- package/dist/server/express/index.d.ts +83 -6
- package/dist/server/express/index.js +620 -92
- package/dist/server/index.cjs +486 -142
- package/dist/server/index.d.cts +100 -33
- package/dist/server/index.d.ts +100 -33
- package/dist/server/index.js +379 -88
- package/package.json +21 -22
- package/dist/a2a_request_handler-B5t-IxgA.d.ts +0 -17
- package/dist/a2a_request_handler-DUvKWfix.d.cts +0 -17
- package/dist/chunk-67JNQ6TZ.js +0 -6
package/dist/server/index.js
CHANGED
|
@@ -1,35 +1,218 @@
|
|
|
1
1
|
import {
|
|
2
2
|
A2AError,
|
|
3
|
-
JsonRpcTransportHandler
|
|
4
|
-
|
|
3
|
+
JsonRpcTransportHandler,
|
|
4
|
+
ServerCallContext,
|
|
5
|
+
UnauthenticatedUser
|
|
6
|
+
} from "../chunk-LTPINR5K.js";
|
|
7
|
+
import "../chunk-ZX6KNMCP.js";
|
|
5
8
|
|
|
6
9
|
// src/server/agent_execution/request_context.ts
|
|
7
10
|
var RequestContext = class {
|
|
8
11
|
userMessage;
|
|
9
|
-
task;
|
|
10
|
-
referenceTasks;
|
|
11
12
|
taskId;
|
|
12
13
|
contextId;
|
|
13
|
-
|
|
14
|
+
task;
|
|
15
|
+
referenceTasks;
|
|
16
|
+
context;
|
|
17
|
+
constructor(userMessage, taskId, contextId, task, referenceTasks, context) {
|
|
14
18
|
this.userMessage = userMessage;
|
|
15
19
|
this.taskId = taskId;
|
|
16
20
|
this.contextId = contextId;
|
|
17
21
|
this.task = task;
|
|
18
22
|
this.referenceTasks = referenceTasks;
|
|
23
|
+
this.context = context;
|
|
19
24
|
}
|
|
20
25
|
};
|
|
21
26
|
|
|
22
27
|
// src/server/events/execution_event_bus.ts
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
constructor() {
|
|
26
|
-
super();
|
|
28
|
+
var CustomEventImpl = typeof CustomEvent !== "undefined" ? CustomEvent : class CustomEventPolyfill extends Event {
|
|
29
|
+
detail;
|
|
30
|
+
constructor(type, eventInitDict) {
|
|
31
|
+
super(type, eventInitDict);
|
|
32
|
+
this.detail = eventInitDict?.detail ?? null;
|
|
27
33
|
}
|
|
34
|
+
};
|
|
35
|
+
function isAgentExecutionCustomEvent(e) {
|
|
36
|
+
return e instanceof CustomEventImpl;
|
|
37
|
+
}
|
|
38
|
+
var DefaultExecutionEventBus = class extends EventTarget {
|
|
39
|
+
// Separate storage for each event type - both use the interface's Listener type
|
|
40
|
+
// but are invoked differently (with event payload vs. no arguments)
|
|
41
|
+
eventListeners = /* @__PURE__ */ new Map();
|
|
42
|
+
finishedListeners = /* @__PURE__ */ new Map();
|
|
28
43
|
publish(event) {
|
|
29
|
-
this.
|
|
44
|
+
this.dispatchEvent(new CustomEventImpl("event", { detail: event }));
|
|
30
45
|
}
|
|
31
46
|
finished() {
|
|
32
|
-
this.
|
|
47
|
+
this.dispatchEvent(new Event("finished"));
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* EventEmitter-compatible 'on' method.
|
|
51
|
+
* Wraps the listener to extract event detail from CustomEvent.
|
|
52
|
+
* Supports multiple registrations of the same listener (like EventEmitter).
|
|
53
|
+
* @param eventName The event name to listen for.
|
|
54
|
+
* @param listener The callback function to invoke when the event is emitted.
|
|
55
|
+
* @returns This instance for method chaining.
|
|
56
|
+
*/
|
|
57
|
+
on(eventName, listener) {
|
|
58
|
+
if (eventName === "event") {
|
|
59
|
+
this.addEventListenerInternal(listener);
|
|
60
|
+
} else {
|
|
61
|
+
this.addFinishedListenerInternal(listener);
|
|
62
|
+
}
|
|
63
|
+
return this;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* EventEmitter-compatible 'off' method.
|
|
67
|
+
* Uses the stored wrapped listener for proper removal.
|
|
68
|
+
* Removes at most one instance of a listener per call (like EventEmitter).
|
|
69
|
+
* @param eventName The event name to stop listening for.
|
|
70
|
+
* @param listener The callback function to remove.
|
|
71
|
+
* @returns This instance for method chaining.
|
|
72
|
+
*/
|
|
73
|
+
off(eventName, listener) {
|
|
74
|
+
if (eventName === "event") {
|
|
75
|
+
this.removeEventListenerInternal(listener);
|
|
76
|
+
} else {
|
|
77
|
+
this.removeFinishedListenerInternal(listener);
|
|
78
|
+
}
|
|
79
|
+
return this;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* EventEmitter-compatible 'once' method.
|
|
83
|
+
* Listener is automatically removed after first invocation.
|
|
84
|
+
* Supports multiple registrations of the same listener (like EventEmitter).
|
|
85
|
+
* @param eventName The event name to listen for once.
|
|
86
|
+
* @param listener The callback function to invoke when the event is emitted.
|
|
87
|
+
* @returns This instance for method chaining.
|
|
88
|
+
*/
|
|
89
|
+
once(eventName, listener) {
|
|
90
|
+
if (eventName === "event") {
|
|
91
|
+
this.addEventListenerOnceInternal(listener);
|
|
92
|
+
} else {
|
|
93
|
+
this.addFinishedListenerOnceInternal(listener);
|
|
94
|
+
}
|
|
95
|
+
return this;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* EventEmitter-compatible 'removeAllListeners' method.
|
|
99
|
+
* Removes all listeners for a specific event or all events.
|
|
100
|
+
* @param eventName Optional event name to remove listeners for. If omitted, removes all.
|
|
101
|
+
* @returns This instance for method chaining.
|
|
102
|
+
*/
|
|
103
|
+
removeAllListeners(eventName) {
|
|
104
|
+
if (eventName === void 0 || eventName === "event") {
|
|
105
|
+
for (const wrappedListeners of this.eventListeners.values()) {
|
|
106
|
+
for (const wrapped of wrappedListeners) {
|
|
107
|
+
this.removeEventListener("event", wrapped);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
this.eventListeners.clear();
|
|
111
|
+
}
|
|
112
|
+
if (eventName === void 0 || eventName === "finished") {
|
|
113
|
+
for (const wrappedListeners of this.finishedListeners.values()) {
|
|
114
|
+
for (const wrapped of wrappedListeners) {
|
|
115
|
+
this.removeEventListener("finished", wrapped);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
this.finishedListeners.clear();
|
|
119
|
+
}
|
|
120
|
+
return this;
|
|
121
|
+
}
|
|
122
|
+
// ========================
|
|
123
|
+
// Helper methods for listener tracking
|
|
124
|
+
// ========================
|
|
125
|
+
/**
|
|
126
|
+
* Adds a wrapped listener to the tracking map.
|
|
127
|
+
*/
|
|
128
|
+
trackListener(listenerMap, listener, wrapped) {
|
|
129
|
+
const existing = listenerMap.get(listener);
|
|
130
|
+
if (existing) {
|
|
131
|
+
existing.push(wrapped);
|
|
132
|
+
} else {
|
|
133
|
+
listenerMap.set(listener, [wrapped]);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Removes a wrapped listener from the tracking map (for once cleanup).
|
|
138
|
+
*/
|
|
139
|
+
untrackWrappedListener(listenerMap, listener, wrapped) {
|
|
140
|
+
const wrappedList = listenerMap.get(listener);
|
|
141
|
+
if (wrappedList && wrappedList.length > 0) {
|
|
142
|
+
const index = wrappedList.indexOf(wrapped);
|
|
143
|
+
if (index !== -1) {
|
|
144
|
+
wrappedList.splice(index, 1);
|
|
145
|
+
if (wrappedList.length === 0) {
|
|
146
|
+
listenerMap.delete(listener);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
// ========================
|
|
152
|
+
// Internal methods for 'event' listeners
|
|
153
|
+
// ========================
|
|
154
|
+
addEventListenerInternal(listener) {
|
|
155
|
+
const wrapped = (e) => {
|
|
156
|
+
if (!isAgentExecutionCustomEvent(e)) {
|
|
157
|
+
throw new Error('Internal error: expected CustomEvent for "event" type');
|
|
158
|
+
}
|
|
159
|
+
listener.call(this, e.detail);
|
|
160
|
+
};
|
|
161
|
+
this.trackListener(this.eventListeners, listener, wrapped);
|
|
162
|
+
this.addEventListener("event", wrapped);
|
|
163
|
+
}
|
|
164
|
+
removeEventListenerInternal(listener) {
|
|
165
|
+
const wrappedList = this.eventListeners.get(listener);
|
|
166
|
+
if (wrappedList && wrappedList.length > 0) {
|
|
167
|
+
const wrapped = wrappedList.pop();
|
|
168
|
+
if (wrappedList.length === 0) {
|
|
169
|
+
this.eventListeners.delete(listener);
|
|
170
|
+
}
|
|
171
|
+
this.removeEventListener("event", wrapped);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
addEventListenerOnceInternal(listener) {
|
|
175
|
+
const wrapped = (e) => {
|
|
176
|
+
if (!isAgentExecutionCustomEvent(e)) {
|
|
177
|
+
throw new Error('Internal error: expected CustomEvent for "event" type');
|
|
178
|
+
}
|
|
179
|
+
this.untrackWrappedListener(this.eventListeners, listener, wrapped);
|
|
180
|
+
listener.call(this, e.detail);
|
|
181
|
+
};
|
|
182
|
+
this.trackListener(this.eventListeners, listener, wrapped);
|
|
183
|
+
this.addEventListener("event", wrapped, { once: true });
|
|
184
|
+
}
|
|
185
|
+
// ========================
|
|
186
|
+
// Internal methods for 'finished' listeners
|
|
187
|
+
// ========================
|
|
188
|
+
// The interface declares listeners as (event: AgentExecutionEvent) => void,
|
|
189
|
+
// but for 'finished' events they are invoked with no arguments (EventEmitter behavior).
|
|
190
|
+
// We use Function.prototype.call to invoke with `this` as the event bus (matching
|
|
191
|
+
// EventEmitter semantics) and no arguments, which is type-safe.
|
|
192
|
+
addFinishedListenerInternal(listener) {
|
|
193
|
+
const wrapped = () => {
|
|
194
|
+
listener.call(this);
|
|
195
|
+
};
|
|
196
|
+
this.trackListener(this.finishedListeners, listener, wrapped);
|
|
197
|
+
this.addEventListener("finished", wrapped);
|
|
198
|
+
}
|
|
199
|
+
removeFinishedListenerInternal(listener) {
|
|
200
|
+
const wrappedList = this.finishedListeners.get(listener);
|
|
201
|
+
if (wrappedList && wrappedList.length > 0) {
|
|
202
|
+
const wrapped = wrappedList.pop();
|
|
203
|
+
if (wrappedList.length === 0) {
|
|
204
|
+
this.finishedListeners.delete(listener);
|
|
205
|
+
}
|
|
206
|
+
this.removeEventListener("finished", wrapped);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
addFinishedListenerOnceInternal(listener) {
|
|
210
|
+
const wrapped = () => {
|
|
211
|
+
this.untrackWrappedListener(this.finishedListeners, listener, wrapped);
|
|
212
|
+
listener.call(this);
|
|
213
|
+
};
|
|
214
|
+
this.trackListener(this.finishedListeners, listener, wrapped);
|
|
215
|
+
this.addEventListener("finished", wrapped, { once: true });
|
|
33
216
|
}
|
|
34
217
|
};
|
|
35
218
|
|
|
@@ -39,7 +222,7 @@ var DefaultExecutionEventBusManager = class {
|
|
|
39
222
|
/**
|
|
40
223
|
* Creates or retrieves an existing ExecutionEventBus based on the taskId.
|
|
41
224
|
* @param taskId The ID of the task.
|
|
42
|
-
* @returns An instance of
|
|
225
|
+
* @returns An instance of ExecutionEventBus.
|
|
43
226
|
*/
|
|
44
227
|
createOrGetByTaskId(taskId) {
|
|
45
228
|
if (!this.taskIdToBus.has(taskId)) {
|
|
@@ -50,7 +233,7 @@ var DefaultExecutionEventBusManager = class {
|
|
|
50
233
|
/**
|
|
51
234
|
* Retrieves an existing ExecutionEventBus based on the taskId.
|
|
52
235
|
* @param taskId The ID of the task.
|
|
53
|
-
* @returns An instance of
|
|
236
|
+
* @returns An instance of ExecutionEventBus or undefined if not found.
|
|
54
237
|
*/
|
|
55
238
|
getByTaskId(taskId) {
|
|
56
239
|
return this.taskIdToBus.get(taskId);
|
|
@@ -132,13 +315,15 @@ import { v4 as uuidv4 } from "uuid";
|
|
|
132
315
|
// src/server/result_manager.ts
|
|
133
316
|
var ResultManager = class {
|
|
134
317
|
taskStore;
|
|
318
|
+
serverCallContext;
|
|
135
319
|
currentTask;
|
|
136
320
|
latestUserMessage;
|
|
137
321
|
// To add to history if a new task is created
|
|
138
322
|
finalMessageResult;
|
|
139
323
|
// Stores the message if it's the final result
|
|
140
|
-
constructor(taskStore) {
|
|
324
|
+
constructor(taskStore, serverCallContext) {
|
|
141
325
|
this.taskStore = taskStore;
|
|
326
|
+
this.serverCallContext = serverCallContext;
|
|
142
327
|
}
|
|
143
328
|
setContext(latestUserMessage) {
|
|
144
329
|
this.latestUserMessage = latestUserMessage;
|
|
@@ -154,7 +339,9 @@ var ResultManager = class {
|
|
|
154
339
|
const taskEvent = event;
|
|
155
340
|
this.currentTask = { ...taskEvent };
|
|
156
341
|
if (this.latestUserMessage) {
|
|
157
|
-
if (!this.currentTask.history?.find(
|
|
342
|
+
if (!this.currentTask.history?.find(
|
|
343
|
+
(msg) => msg.messageId === this.latestUserMessage.messageId
|
|
344
|
+
)) {
|
|
158
345
|
this.currentTask.history = [this.latestUserMessage, ...this.currentTask.history || []];
|
|
159
346
|
}
|
|
160
347
|
}
|
|
@@ -164,24 +351,36 @@ var ResultManager = class {
|
|
|
164
351
|
if (this.currentTask && this.currentTask.id === updateEvent.taskId) {
|
|
165
352
|
this.currentTask.status = updateEvent.status;
|
|
166
353
|
if (updateEvent.status.message) {
|
|
167
|
-
if (!this.currentTask.history?.find(
|
|
168
|
-
|
|
354
|
+
if (!this.currentTask.history?.find(
|
|
355
|
+
(msg) => msg.messageId === updateEvent.status.message.messageId
|
|
356
|
+
)) {
|
|
357
|
+
this.currentTask.history = [
|
|
358
|
+
...this.currentTask.history || [],
|
|
359
|
+
updateEvent.status.message
|
|
360
|
+
];
|
|
169
361
|
}
|
|
170
362
|
}
|
|
171
363
|
await this.saveCurrentTask();
|
|
172
364
|
} else if (!this.currentTask && updateEvent.taskId) {
|
|
173
|
-
const loaded = await this.taskStore.load(updateEvent.taskId);
|
|
365
|
+
const loaded = await this.taskStore.load(updateEvent.taskId, this.serverCallContext);
|
|
174
366
|
if (loaded) {
|
|
175
367
|
this.currentTask = loaded;
|
|
176
368
|
this.currentTask.status = updateEvent.status;
|
|
177
369
|
if (updateEvent.status.message) {
|
|
178
|
-
if (!this.currentTask.history?.find(
|
|
179
|
-
|
|
370
|
+
if (!this.currentTask.history?.find(
|
|
371
|
+
(msg) => msg.messageId === updateEvent.status.message.messageId
|
|
372
|
+
)) {
|
|
373
|
+
this.currentTask.history = [
|
|
374
|
+
...this.currentTask.history || [],
|
|
375
|
+
updateEvent.status.message
|
|
376
|
+
];
|
|
180
377
|
}
|
|
181
378
|
}
|
|
182
379
|
await this.saveCurrentTask();
|
|
183
380
|
} else {
|
|
184
|
-
console.warn(
|
|
381
|
+
console.warn(
|
|
382
|
+
`ResultManager: Received status update for unknown task ${updateEvent.taskId}`
|
|
383
|
+
);
|
|
185
384
|
}
|
|
186
385
|
}
|
|
187
386
|
} else if (event.kind === "artifact-update") {
|
|
@@ -197,9 +396,14 @@ var ResultManager = class {
|
|
|
197
396
|
if (artifactEvent.append) {
|
|
198
397
|
const existingArtifact = this.currentTask.artifacts[existingArtifactIndex];
|
|
199
398
|
existingArtifact.parts.push(...artifactEvent.artifact.parts);
|
|
200
|
-
if (artifactEvent.artifact.description)
|
|
399
|
+
if (artifactEvent.artifact.description)
|
|
400
|
+
existingArtifact.description = artifactEvent.artifact.description;
|
|
201
401
|
if (artifactEvent.artifact.name) existingArtifact.name = artifactEvent.artifact.name;
|
|
202
|
-
if (artifactEvent.artifact.metadata)
|
|
402
|
+
if (artifactEvent.artifact.metadata)
|
|
403
|
+
existingArtifact.metadata = {
|
|
404
|
+
...existingArtifact.metadata,
|
|
405
|
+
...artifactEvent.artifact.metadata
|
|
406
|
+
};
|
|
203
407
|
} else {
|
|
204
408
|
this.currentTask.artifacts[existingArtifactIndex] = artifactEvent.artifact;
|
|
205
409
|
}
|
|
@@ -208,7 +412,7 @@ var ResultManager = class {
|
|
|
208
412
|
}
|
|
209
413
|
await this.saveCurrentTask();
|
|
210
414
|
} else if (!this.currentTask && artifactEvent.taskId) {
|
|
211
|
-
const loaded = await this.taskStore.load(artifactEvent.taskId);
|
|
415
|
+
const loaded = await this.taskStore.load(artifactEvent.taskId, this.serverCallContext);
|
|
212
416
|
if (loaded) {
|
|
213
417
|
this.currentTask = loaded;
|
|
214
418
|
if (!this.currentTask.artifacts) this.currentTask.artifacts = [];
|
|
@@ -217,7 +421,9 @@ var ResultManager = class {
|
|
|
217
421
|
);
|
|
218
422
|
if (existingArtifactIndex !== -1) {
|
|
219
423
|
if (artifactEvent.append) {
|
|
220
|
-
this.currentTask.artifacts[existingArtifactIndex].parts.push(
|
|
424
|
+
this.currentTask.artifacts[existingArtifactIndex].parts.push(
|
|
425
|
+
...artifactEvent.artifact.parts
|
|
426
|
+
);
|
|
221
427
|
} else {
|
|
222
428
|
this.currentTask.artifacts[existingArtifactIndex] = artifactEvent.artifact;
|
|
223
429
|
}
|
|
@@ -226,14 +432,16 @@ var ResultManager = class {
|
|
|
226
432
|
}
|
|
227
433
|
await this.saveCurrentTask();
|
|
228
434
|
} else {
|
|
229
|
-
console.warn(
|
|
435
|
+
console.warn(
|
|
436
|
+
`ResultManager: Received artifact update for unknown task ${artifactEvent.taskId}`
|
|
437
|
+
);
|
|
230
438
|
}
|
|
231
439
|
}
|
|
232
440
|
}
|
|
233
441
|
}
|
|
234
442
|
async saveCurrentTask() {
|
|
235
443
|
if (this.currentTask) {
|
|
236
|
-
await this.taskStore.save(this.currentTask);
|
|
444
|
+
await this.taskStore.save(this.currentTask, this.serverCallContext);
|
|
237
445
|
}
|
|
238
446
|
}
|
|
239
447
|
/**
|
|
@@ -321,7 +529,10 @@ var DefaultPushNotificationSender = class {
|
|
|
321
529
|
try {
|
|
322
530
|
await this._dispatchNotification(task, pushConfig);
|
|
323
531
|
} catch (error) {
|
|
324
|
-
console.error(
|
|
532
|
+
console.error(
|
|
533
|
+
`Error sending push notification for task_id=${task.id} to URL: ${pushConfig.url}. Error:`,
|
|
534
|
+
error
|
|
535
|
+
);
|
|
325
536
|
}
|
|
326
537
|
});
|
|
327
538
|
await Promise.all(dispatches);
|
|
@@ -364,18 +575,18 @@ var DefaultPushNotificationSender = class {
|
|
|
364
575
|
var terminalStates = ["completed", "failed", "canceled", "rejected"];
|
|
365
576
|
var DefaultRequestHandler = class {
|
|
366
577
|
agentCard;
|
|
367
|
-
extendedAgentCard;
|
|
368
578
|
taskStore;
|
|
369
579
|
agentExecutor;
|
|
370
580
|
eventBusManager;
|
|
371
581
|
pushNotificationStore;
|
|
372
582
|
pushNotificationSender;
|
|
373
|
-
|
|
583
|
+
extendedAgentCardProvider;
|
|
584
|
+
constructor(agentCard, taskStore, agentExecutor, eventBusManager = new DefaultExecutionEventBusManager(), pushNotificationStore, pushNotificationSender, extendedAgentCardProvider) {
|
|
374
585
|
this.agentCard = agentCard;
|
|
375
586
|
this.taskStore = taskStore;
|
|
376
587
|
this.agentExecutor = agentExecutor;
|
|
377
588
|
this.eventBusManager = eventBusManager;
|
|
378
|
-
this.
|
|
589
|
+
this.extendedAgentCardProvider = extendedAgentCardProvider;
|
|
379
590
|
if (agentCard.capabilities.pushNotifications) {
|
|
380
591
|
this.pushNotificationStore = pushNotificationStore || new InMemoryPushNotificationStore();
|
|
381
592
|
this.pushNotificationSender = pushNotificationSender || new DefaultPushNotificationSender(this.pushNotificationStore);
|
|
@@ -384,30 +595,42 @@ var DefaultRequestHandler = class {
|
|
|
384
595
|
async getAgentCard() {
|
|
385
596
|
return this.agentCard;
|
|
386
597
|
}
|
|
387
|
-
async getAuthenticatedExtendedAgentCard() {
|
|
388
|
-
if (!this.
|
|
598
|
+
async getAuthenticatedExtendedAgentCard(context) {
|
|
599
|
+
if (!this.agentCard.supportsAuthenticatedExtendedCard) {
|
|
600
|
+
throw A2AError.unsupportedOperation("Agent does not support authenticated extended card.");
|
|
601
|
+
}
|
|
602
|
+
if (!this.extendedAgentCardProvider) {
|
|
389
603
|
throw A2AError.authenticatedExtendedCardNotConfigured();
|
|
390
604
|
}
|
|
391
|
-
|
|
605
|
+
if (typeof this.extendedAgentCardProvider === "function") {
|
|
606
|
+
return this.extendedAgentCardProvider(context);
|
|
607
|
+
}
|
|
608
|
+
if (context?.user?.isAuthenticated) {
|
|
609
|
+
return this.extendedAgentCardProvider;
|
|
610
|
+
}
|
|
611
|
+
return this.agentCard;
|
|
392
612
|
}
|
|
393
|
-
async _createRequestContext(incomingMessage,
|
|
613
|
+
async _createRequestContext(incomingMessage, context) {
|
|
394
614
|
let task;
|
|
395
615
|
let referenceTasks;
|
|
396
616
|
if (incomingMessage.taskId) {
|
|
397
|
-
task = await this.taskStore.load(incomingMessage.taskId);
|
|
617
|
+
task = await this.taskStore.load(incomingMessage.taskId, context);
|
|
398
618
|
if (!task) {
|
|
399
619
|
throw A2AError.taskNotFound(incomingMessage.taskId);
|
|
400
620
|
}
|
|
401
621
|
if (terminalStates.includes(task.status.state)) {
|
|
402
|
-
throw A2AError.invalidRequest(
|
|
622
|
+
throw A2AError.invalidRequest(
|
|
623
|
+
`Task ${task.id} is in a terminal state (${task.status.state}) and cannot be modified.`
|
|
624
|
+
);
|
|
403
625
|
}
|
|
404
626
|
task.history = [...task.history || [], incomingMessage];
|
|
405
|
-
await this.taskStore.save(task);
|
|
627
|
+
await this.taskStore.save(task, context);
|
|
406
628
|
}
|
|
629
|
+
const taskId = incomingMessage.taskId || uuidv4();
|
|
407
630
|
if (incomingMessage.referenceTaskIds && incomingMessage.referenceTaskIds.length > 0) {
|
|
408
631
|
referenceTasks = [];
|
|
409
632
|
for (const refId of incomingMessage.referenceTaskIds) {
|
|
410
|
-
const refTask = await this.taskStore.load(refId);
|
|
633
|
+
const refTask = await this.taskStore.load(refId, context);
|
|
411
634
|
if (refTask) {
|
|
412
635
|
referenceTasks.push(refTask);
|
|
413
636
|
} else {
|
|
@@ -416,24 +639,33 @@ var DefaultRequestHandler = class {
|
|
|
416
639
|
}
|
|
417
640
|
}
|
|
418
641
|
const contextId = incomingMessage.contextId || task?.contextId || uuidv4();
|
|
642
|
+
if (context?.requestedExtensions) {
|
|
643
|
+
const agentCard = await this.getAgentCard();
|
|
644
|
+
const exposedExtensions = new Set(
|
|
645
|
+
agentCard.capabilities.extensions?.map((ext) => ext.uri) || []
|
|
646
|
+
);
|
|
647
|
+
const validExtensions = context.requestedExtensions.filter(
|
|
648
|
+
(extension) => exposedExtensions.has(extension)
|
|
649
|
+
);
|
|
650
|
+
context = new ServerCallContext(validExtensions, context.user);
|
|
651
|
+
}
|
|
419
652
|
const messageForContext = {
|
|
420
653
|
...incomingMessage,
|
|
421
|
-
contextId
|
|
422
|
-
};
|
|
423
|
-
return new RequestContext(
|
|
424
|
-
messageForContext,
|
|
425
|
-
taskId,
|
|
426
654
|
contextId,
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
);
|
|
655
|
+
taskId
|
|
656
|
+
};
|
|
657
|
+
return new RequestContext(messageForContext, taskId, contextId, task, referenceTasks, context);
|
|
430
658
|
}
|
|
431
|
-
async _processEvents(taskId, resultManager, eventQueue, options) {
|
|
659
|
+
async _processEvents(taskId, resultManager, eventQueue, context, options) {
|
|
432
660
|
let firstResultSent = false;
|
|
433
661
|
try {
|
|
434
662
|
for await (const event of eventQueue.events()) {
|
|
435
663
|
await resultManager.processEvent(event);
|
|
436
|
-
|
|
664
|
+
try {
|
|
665
|
+
await this._sendPushNotificationIfNeeded(event, context);
|
|
666
|
+
} catch (error) {
|
|
667
|
+
console.error(`Error sending push notification: ${error}`);
|
|
668
|
+
}
|
|
437
669
|
if (options?.firstResultResolver && !firstResultSent) {
|
|
438
670
|
let firstResult;
|
|
439
671
|
if (event.kind === "message") {
|
|
@@ -448,28 +680,33 @@ var DefaultRequestHandler = class {
|
|
|
448
680
|
}
|
|
449
681
|
}
|
|
450
682
|
if (options?.firstResultRejector && !firstResultSent) {
|
|
451
|
-
options.firstResultRejector(
|
|
683
|
+
options.firstResultRejector(
|
|
684
|
+
A2AError.internalError("Execution finished before a message or task was produced.")
|
|
685
|
+
);
|
|
452
686
|
}
|
|
453
687
|
} catch (error) {
|
|
454
688
|
console.error(`Event processing loop failed for task ${taskId}:`, error);
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
689
|
+
this._handleProcessingError(
|
|
690
|
+
error,
|
|
691
|
+
resultManager,
|
|
692
|
+
firstResultSent,
|
|
693
|
+
taskId,
|
|
694
|
+
options?.firstResultRejector
|
|
695
|
+
);
|
|
459
696
|
} finally {
|
|
460
697
|
this.eventBusManager.cleanupByTaskId(taskId);
|
|
461
698
|
}
|
|
462
699
|
}
|
|
463
|
-
async sendMessage(params) {
|
|
700
|
+
async sendMessage(params, context) {
|
|
464
701
|
const incomingMessage = params.message;
|
|
465
702
|
if (!incomingMessage.messageId) {
|
|
466
703
|
throw A2AError.invalidParams("message.messageId is required.");
|
|
467
704
|
}
|
|
468
705
|
const isBlocking = params.configuration?.blocking !== false;
|
|
469
|
-
const
|
|
470
|
-
const resultManager = new ResultManager(this.taskStore);
|
|
706
|
+
const resultManager = new ResultManager(this.taskStore, context);
|
|
471
707
|
resultManager.setContext(incomingMessage);
|
|
472
|
-
const requestContext = await this._createRequestContext(incomingMessage,
|
|
708
|
+
const requestContext = await this._createRequestContext(incomingMessage, context);
|
|
709
|
+
const taskId = requestContext.taskId;
|
|
473
710
|
const finalMessageForAgent = requestContext.userMessage;
|
|
474
711
|
if (params.configuration?.pushNotificationConfig && this.agentCard.capabilities.pushNotifications) {
|
|
475
712
|
await this.pushNotificationStore?.save(taskId, params.configuration.pushNotificationConfig);
|
|
@@ -514,30 +751,32 @@ var DefaultRequestHandler = class {
|
|
|
514
751
|
eventBus.finished();
|
|
515
752
|
});
|
|
516
753
|
if (isBlocking) {
|
|
517
|
-
await this._processEvents(taskId, resultManager, eventQueue);
|
|
754
|
+
await this._processEvents(taskId, resultManager, eventQueue, context);
|
|
518
755
|
const finalResult = resultManager.getFinalResult();
|
|
519
756
|
if (!finalResult) {
|
|
520
|
-
throw A2AError.internalError(
|
|
757
|
+
throw A2AError.internalError(
|
|
758
|
+
"Agent execution finished without a result, and no task context found."
|
|
759
|
+
);
|
|
521
760
|
}
|
|
522
761
|
return finalResult;
|
|
523
762
|
} else {
|
|
524
763
|
return new Promise((resolve, reject) => {
|
|
525
|
-
this._processEvents(taskId, resultManager, eventQueue, {
|
|
764
|
+
this._processEvents(taskId, resultManager, eventQueue, context, {
|
|
526
765
|
firstResultResolver: resolve,
|
|
527
766
|
firstResultRejector: reject
|
|
528
767
|
});
|
|
529
768
|
});
|
|
530
769
|
}
|
|
531
770
|
}
|
|
532
|
-
async *sendMessageStream(params) {
|
|
771
|
+
async *sendMessageStream(params, context) {
|
|
533
772
|
const incomingMessage = params.message;
|
|
534
773
|
if (!incomingMessage.messageId) {
|
|
535
774
|
throw A2AError.invalidParams("message.messageId is required for streaming.");
|
|
536
775
|
}
|
|
537
|
-
const
|
|
538
|
-
const resultManager = new ResultManager(this.taskStore);
|
|
776
|
+
const resultManager = new ResultManager(this.taskStore, context);
|
|
539
777
|
resultManager.setContext(incomingMessage);
|
|
540
|
-
const requestContext = await this._createRequestContext(incomingMessage,
|
|
778
|
+
const requestContext = await this._createRequestContext(incomingMessage, context);
|
|
779
|
+
const taskId = requestContext.taskId;
|
|
541
780
|
const finalMessageForAgent = requestContext.userMessage;
|
|
542
781
|
const eventBus = this.eventBusManager.createOrGetByTaskId(taskId);
|
|
543
782
|
const eventQueue = new ExecutionEventQueue(eventBus);
|
|
@@ -545,7 +784,10 @@ var DefaultRequestHandler = class {
|
|
|
545
784
|
await this.pushNotificationStore?.save(taskId, params.configuration.pushNotificationConfig);
|
|
546
785
|
}
|
|
547
786
|
this.agentExecutor.execute(requestContext, eventBus).catch((err) => {
|
|
548
|
-
console.error(
|
|
787
|
+
console.error(
|
|
788
|
+
`Agent execution failed for stream message ${finalMessageForAgent.messageId}:`,
|
|
789
|
+
err
|
|
790
|
+
);
|
|
549
791
|
const errorTaskStatus = {
|
|
550
792
|
kind: "status-update",
|
|
551
793
|
taskId: requestContext.task?.id || uuidv4(),
|
|
@@ -571,15 +813,15 @@ var DefaultRequestHandler = class {
|
|
|
571
813
|
try {
|
|
572
814
|
for await (const event of eventQueue.events()) {
|
|
573
815
|
await resultManager.processEvent(event);
|
|
574
|
-
await this._sendPushNotificationIfNeeded(event);
|
|
816
|
+
await this._sendPushNotificationIfNeeded(event, context);
|
|
575
817
|
yield event;
|
|
576
818
|
}
|
|
577
819
|
} finally {
|
|
578
820
|
this.eventBusManager.cleanupByTaskId(taskId);
|
|
579
821
|
}
|
|
580
822
|
}
|
|
581
|
-
async getTask(params) {
|
|
582
|
-
const task = await this.taskStore.load(params.id);
|
|
823
|
+
async getTask(params, context) {
|
|
824
|
+
const task = await this.taskStore.load(params.id, context);
|
|
583
825
|
if (!task) {
|
|
584
826
|
throw A2AError.taskNotFound(params.id);
|
|
585
827
|
}
|
|
@@ -592,8 +834,8 @@ var DefaultRequestHandler = class {
|
|
|
592
834
|
}
|
|
593
835
|
return task;
|
|
594
836
|
}
|
|
595
|
-
async cancelTask(params) {
|
|
596
|
-
const task = await this.taskStore.load(params.id);
|
|
837
|
+
async cancelTask(params, context) {
|
|
838
|
+
const task = await this.taskStore.load(params.id, context);
|
|
597
839
|
if (!task) {
|
|
598
840
|
throw A2AError.taskNotFound(params.id);
|
|
599
841
|
}
|
|
@@ -605,7 +847,12 @@ var DefaultRequestHandler = class {
|
|
|
605
847
|
if (eventBus) {
|
|
606
848
|
const eventQueue = new ExecutionEventQueue(eventBus);
|
|
607
849
|
await this.agentExecutor.cancelTask(params.id, eventBus);
|
|
608
|
-
await this._processEvents(
|
|
850
|
+
await this._processEvents(
|
|
851
|
+
params.id,
|
|
852
|
+
new ResultManager(this.taskStore, context),
|
|
853
|
+
eventQueue,
|
|
854
|
+
context
|
|
855
|
+
);
|
|
609
856
|
} else {
|
|
610
857
|
task.status = {
|
|
611
858
|
state: "canceled",
|
|
@@ -621,9 +868,9 @@ var DefaultRequestHandler = class {
|
|
|
621
868
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
622
869
|
};
|
|
623
870
|
task.history = [...task.history || [], task.status.message];
|
|
624
|
-
await this.taskStore.save(task);
|
|
871
|
+
await this.taskStore.save(task, context);
|
|
625
872
|
}
|
|
626
|
-
const latestTask = await this.taskStore.load(params.id);
|
|
873
|
+
const latestTask = await this.taskStore.load(params.id, context);
|
|
627
874
|
if (!latestTask) {
|
|
628
875
|
throw A2AError.internalError(`Task ${params.id} not found after cancellation.`);
|
|
629
876
|
}
|
|
@@ -632,11 +879,11 @@ var DefaultRequestHandler = class {
|
|
|
632
879
|
}
|
|
633
880
|
return latestTask;
|
|
634
881
|
}
|
|
635
|
-
async setTaskPushNotificationConfig(params) {
|
|
882
|
+
async setTaskPushNotificationConfig(params, context) {
|
|
636
883
|
if (!this.agentCard.capabilities.pushNotifications) {
|
|
637
884
|
throw A2AError.pushNotificationNotSupported();
|
|
638
885
|
}
|
|
639
|
-
const task = await this.taskStore.load(params.taskId);
|
|
886
|
+
const task = await this.taskStore.load(params.taskId, context);
|
|
640
887
|
if (!task) {
|
|
641
888
|
throw A2AError.taskNotFound(params.taskId);
|
|
642
889
|
}
|
|
@@ -647,11 +894,11 @@ var DefaultRequestHandler = class {
|
|
|
647
894
|
await this.pushNotificationStore?.save(taskId, pushNotificationConfig);
|
|
648
895
|
return params;
|
|
649
896
|
}
|
|
650
|
-
async getTaskPushNotificationConfig(params) {
|
|
897
|
+
async getTaskPushNotificationConfig(params, context) {
|
|
651
898
|
if (!this.agentCard.capabilities.pushNotifications) {
|
|
652
899
|
throw A2AError.pushNotificationNotSupported();
|
|
653
900
|
}
|
|
654
|
-
const task = await this.taskStore.load(params.id);
|
|
901
|
+
const task = await this.taskStore.load(params.id, context);
|
|
655
902
|
if (!task) {
|
|
656
903
|
throw A2AError.taskNotFound(params.id);
|
|
657
904
|
}
|
|
@@ -667,15 +914,17 @@ var DefaultRequestHandler = class {
|
|
|
667
914
|
}
|
|
668
915
|
const config = configs.find((c) => c.id === configId);
|
|
669
916
|
if (!config) {
|
|
670
|
-
throw A2AError.internalError(
|
|
917
|
+
throw A2AError.internalError(
|
|
918
|
+
`Push notification config with id '${configId}' not found for task ${params.id}.`
|
|
919
|
+
);
|
|
671
920
|
}
|
|
672
921
|
return { taskId: params.id, pushNotificationConfig: config };
|
|
673
922
|
}
|
|
674
|
-
async listTaskPushNotificationConfigs(params) {
|
|
923
|
+
async listTaskPushNotificationConfigs(params, context) {
|
|
675
924
|
if (!this.agentCard.capabilities.pushNotifications) {
|
|
676
925
|
throw A2AError.pushNotificationNotSupported();
|
|
677
926
|
}
|
|
678
|
-
const task = await this.taskStore.load(params.id);
|
|
927
|
+
const task = await this.taskStore.load(params.id, context);
|
|
679
928
|
if (!task) {
|
|
680
929
|
throw A2AError.taskNotFound(params.id);
|
|
681
930
|
}
|
|
@@ -685,22 +934,22 @@ var DefaultRequestHandler = class {
|
|
|
685
934
|
pushNotificationConfig: config
|
|
686
935
|
}));
|
|
687
936
|
}
|
|
688
|
-
async deleteTaskPushNotificationConfig(params) {
|
|
937
|
+
async deleteTaskPushNotificationConfig(params, context) {
|
|
689
938
|
if (!this.agentCard.capabilities.pushNotifications) {
|
|
690
939
|
throw A2AError.pushNotificationNotSupported();
|
|
691
940
|
}
|
|
692
|
-
const task = await this.taskStore.load(params.id);
|
|
941
|
+
const task = await this.taskStore.load(params.id, context);
|
|
693
942
|
if (!task) {
|
|
694
943
|
throw A2AError.taskNotFound(params.id);
|
|
695
944
|
}
|
|
696
945
|
const { id: taskId, pushNotificationConfigId } = params;
|
|
697
946
|
await this.pushNotificationStore?.delete(taskId, pushNotificationConfigId);
|
|
698
947
|
}
|
|
699
|
-
async *resubscribe(params) {
|
|
948
|
+
async *resubscribe(params, context) {
|
|
700
949
|
if (!this.agentCard.capabilities.streaming) {
|
|
701
950
|
throw A2AError.unsupportedOperation("Streaming (and thus resubscription) is not supported.");
|
|
702
951
|
}
|
|
703
|
-
const task = await this.taskStore.load(params.id);
|
|
952
|
+
const task = await this.taskStore.load(params.id, context);
|
|
704
953
|
if (!task) {
|
|
705
954
|
throw A2AError.taskNotFound(params.id);
|
|
706
955
|
}
|
|
@@ -729,7 +978,7 @@ var DefaultRequestHandler = class {
|
|
|
729
978
|
eventQueue.stop();
|
|
730
979
|
}
|
|
731
980
|
}
|
|
732
|
-
async _sendPushNotificationIfNeeded(event) {
|
|
981
|
+
async _sendPushNotificationIfNeeded(event, context) {
|
|
733
982
|
if (!this.agentCard.capabilities.pushNotifications) {
|
|
734
983
|
return;
|
|
735
984
|
}
|
|
@@ -744,13 +993,53 @@ var DefaultRequestHandler = class {
|
|
|
744
993
|
console.error(`Task ID not found for event ${event.kind}.`);
|
|
745
994
|
return;
|
|
746
995
|
}
|
|
747
|
-
const task = await this.taskStore.load(taskId);
|
|
996
|
+
const task = await this.taskStore.load(taskId, context);
|
|
748
997
|
if (!task) {
|
|
749
998
|
console.error(`Task ${taskId} not found.`);
|
|
750
999
|
return;
|
|
751
1000
|
}
|
|
752
1001
|
this.pushNotificationSender?.send(task);
|
|
753
1002
|
}
|
|
1003
|
+
async _handleProcessingError(error, resultManager, firstResultSent, taskId, firstResultRejector) {
|
|
1004
|
+
if (firstResultRejector && !firstResultSent) {
|
|
1005
|
+
firstResultRejector(error);
|
|
1006
|
+
return;
|
|
1007
|
+
}
|
|
1008
|
+
if (!firstResultRejector) {
|
|
1009
|
+
throw error;
|
|
1010
|
+
}
|
|
1011
|
+
const currentTask = resultManager.getCurrentTask();
|
|
1012
|
+
const errorMessage = error instanceof Error && error.message || "Unknown error";
|
|
1013
|
+
if (currentTask) {
|
|
1014
|
+
const statusUpdateFailed = {
|
|
1015
|
+
taskId: currentTask.id,
|
|
1016
|
+
contextId: currentTask.contextId,
|
|
1017
|
+
status: {
|
|
1018
|
+
state: "failed",
|
|
1019
|
+
message: {
|
|
1020
|
+
kind: "message",
|
|
1021
|
+
role: "agent",
|
|
1022
|
+
messageId: uuidv4(),
|
|
1023
|
+
parts: [{ kind: "text", text: `Event processing loop failed: ${errorMessage}` }],
|
|
1024
|
+
taskId: currentTask.id,
|
|
1025
|
+
contextId: currentTask.contextId
|
|
1026
|
+
},
|
|
1027
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1028
|
+
},
|
|
1029
|
+
kind: "status-update",
|
|
1030
|
+
final: true
|
|
1031
|
+
};
|
|
1032
|
+
try {
|
|
1033
|
+
await resultManager.processEvent(statusUpdateFailed);
|
|
1034
|
+
} catch (error2) {
|
|
1035
|
+
console.error(
|
|
1036
|
+
`Event processing loop failed for task ${taskId}: ${error2 instanceof Error && error2.message || "Unknown error"}`
|
|
1037
|
+
);
|
|
1038
|
+
}
|
|
1039
|
+
} else {
|
|
1040
|
+
console.error(`Event processing loop failed for task ${taskId}: ${errorMessage}`);
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
754
1043
|
};
|
|
755
1044
|
|
|
756
1045
|
// src/server/store.ts
|
|
@@ -775,5 +1064,7 @@ export {
|
|
|
775
1064
|
InMemoryTaskStore,
|
|
776
1065
|
JsonRpcTransportHandler,
|
|
777
1066
|
RequestContext,
|
|
778
|
-
ResultManager
|
|
1067
|
+
ResultManager,
|
|
1068
|
+
ServerCallContext,
|
|
1069
|
+
UnauthenticatedUser
|
|
779
1070
|
};
|