@artinet/sdk 0.6.0-preview.3 → 0.6.0
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 +100 -50
- package/dist/browser/browser.d.ts +2 -7
- package/dist/browser/browser.js +2 -7
- package/dist/browser/config/observability.d.ts +1 -1
- package/dist/browser/create/message-builder.d.ts +1 -1
- package/dist/browser/create/message-builder.js +19 -7
- package/dist/browser/create/task-builder.js +1 -1
- package/dist/browser/messenger/index.d.ts +1 -0
- package/dist/browser/messenger/index.js +1 -0
- package/dist/browser/messenger/messenger.d.ts +119 -0
- package/dist/browser/messenger/messenger.js +245 -0
- package/dist/browser/types/a2a/a2a.d.ts +38 -20
- package/dist/browser/types/a2a/a2a.js +0 -1
- package/dist/browser/types/core/core.d.ts +4 -2
- package/dist/browser/types/index.d.ts +0 -1
- package/dist/browser/types/index.js +0 -1
- package/dist/browser/types/storage.d.ts +2 -14
- package/dist/browser/types/storage.js +0 -4
- package/dist/browser/utils/{common/constants.d.ts → constants.d.ts} +1 -1
- package/dist/{utils/common → browser/utils}/constants.js +1 -1
- package/dist/browser/utils/{common/errors.d.ts → errors.d.ts} +17 -36
- package/dist/browser/utils/errors.js +76 -0
- package/dist/browser/utils/index.d.ts +6 -0
- package/dist/browser/utils/index.js +6 -0
- package/dist/{utils/common → browser/utils}/parse.js +1 -1
- package/dist/{utils/common → browser/utils}/schema-validation.js +2 -2
- package/dist/config/index.d.ts +1 -1
- package/dist/config/observability.d.ts +1 -1
- package/dist/create/agent-builder.d.ts +1 -1
- package/dist/create/create.d.ts +19 -20
- package/dist/create/create.js +33 -101
- package/dist/create/message-builder.d.ts +1 -1
- package/dist/create/message-builder.js +19 -7
- package/dist/create/task-builder.js +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/messenger/index.d.ts +1 -0
- package/dist/messenger/index.js +1 -0
- package/dist/messenger/messenger.d.ts +119 -0
- package/dist/messenger/messenger.js +251 -0
- package/dist/server/adapters/a2a_request_handler.d.ts +889 -0
- package/dist/server/adapters/a2a_request_handler.js +241 -0
- package/dist/server/adapters/loadable.d.ts +7 -0
- package/dist/server/adapters/loadable.js +73 -0
- package/dist/server/adapters/notifications.d.ts +26 -0
- package/dist/server/adapters/notifications.js +77 -0
- package/dist/server/express/server.d.ts +11 -19
- package/dist/server/express/server.js +29 -64
- package/dist/server/express/utils.d.ts +14 -0
- package/dist/server/express/{errors.js → utils.js} +22 -0
- package/dist/server/index.d.ts +4 -1
- package/dist/server/index.js +4 -1
- package/dist/server/params.d.ts +115 -0
- package/dist/server/params.js +21 -0
- package/dist/services/a2a/factory/context.d.ts +2 -1
- package/dist/services/a2a/factory/context.js +4 -3
- package/dist/services/a2a/factory/handler.d.ts +1 -1
- package/dist/services/a2a/factory/handler.js +7 -6
- package/dist/services/a2a/factory/service.d.ts +1 -1
- package/dist/services/a2a/factory/service.js +2 -2
- package/dist/services/a2a/factory/state-machine.js +9 -6
- package/dist/services/a2a/handlers/cancel-task.d.ts +1 -1
- package/dist/services/a2a/handlers/get-task.d.ts +1 -1
- package/dist/services/a2a/handlers/resubscribe-task.d.ts +2 -2
- package/dist/services/a2a/handlers/send-message.d.ts +1 -1
- package/dist/services/a2a/handlers/stream-message.d.ts +2 -2
- package/dist/services/a2a/handlers/update.js +2 -2
- package/dist/services/a2a/index.d.ts +0 -1
- package/dist/services/a2a/index.js +0 -1
- package/dist/services/a2a/managers.js +2 -1
- package/dist/services/a2a/messenger.d.ts +1 -1
- package/dist/services/a2a/messenger.js +1 -1
- package/dist/services/a2a/service.d.ts +26 -21
- package/dist/services/a2a/service.js +160 -92
- package/dist/services/a2a/state-machine.d.ts +1 -1
- package/dist/services/a2a/state-machine.js +2 -1
- package/dist/services/a2a/streams.js +1 -1
- package/dist/services/core/manager.d.ts +5 -0
- package/dist/services/core/manager.js +6 -0
- package/dist/services/mcp/service.js +1 -1
- package/dist/{utils/storage → storage}/file.d.ts +4 -2
- package/dist/{utils/storage → storage}/file.js +5 -4
- package/dist/storage/index.d.ts +1 -0
- package/dist/storage/index.js +2 -0
- package/dist/storage/sqlite.d.ts +353 -0
- package/dist/storage/sqlite.js +85 -0
- package/dist/transport/trpc/a2a/factory/router.d.ts +16 -16
- package/dist/transport/trpc/a2a/routes/info.d.ts +2 -2
- package/dist/transport/trpc/a2a/routes/message/route.d.ts +3 -3
- package/dist/transport/trpc/a2a/routes/message/route.js +2 -2
- package/dist/transport/trpc/a2a/routes/tasks/route.d.ts +4 -4
- package/dist/transport/trpc/a2a/routes/tasks/route.js +3 -3
- package/dist/types/a2a/a2a.d.ts +38 -20
- package/dist/types/a2a/a2a.js +0 -1
- package/dist/types/core/core.d.ts +4 -2
- package/dist/types/index.d.ts +0 -1
- package/dist/types/index.js +0 -1
- package/dist/types/storage.d.ts +2 -14
- package/dist/types/storage.js +0 -4
- package/dist/utils/{common/constants.d.ts → constants.d.ts} +1 -1
- package/dist/{browser/utils/common → utils}/constants.js +1 -1
- package/dist/utils/{common/errors.d.ts → errors.d.ts} +17 -36
- package/dist/utils/errors.js +80 -0
- package/dist/utils/index.d.ts +6 -10
- package/dist/utils/index.js +6 -10
- package/dist/utils/parse.d.ts +7 -0
- package/dist/utils/parse.js +14 -0
- package/dist/utils/schema-validation.d.ts +2 -0
- package/dist/utils/schema-validation.js +12 -0
- package/package.json +35 -22
- package/dist/browser/client/a2a-client.d.ts +0 -127
- package/dist/browser/client/a2a-client.js +0 -233
- package/dist/browser/client/index.d.ts +0 -1
- package/dist/browser/client/index.js +0 -1
- package/dist/browser/transport/rpc/parser.d.ts +0 -15
- package/dist/browser/transport/rpc/parser.js +0 -49
- package/dist/browser/transport/rpc/rpc-client.d.ts +0 -80
- package/dist/browser/transport/rpc/rpc-client.js +0 -189
- package/dist/browser/transport/streaming/event-stream.d.ts +0 -25
- package/dist/browser/transport/streaming/event-stream.js +0 -100
- package/dist/browser/types/client.d.ts +0 -133
- package/dist/browser/types/client.js +0 -5
- package/dist/browser/utils/common/errors.js +0 -95
- package/dist/client/a2a-client.d.ts +0 -127
- package/dist/client/a2a-client.js +0 -237
- package/dist/client/index.d.ts +0 -1
- package/dist/client/index.js +0 -1
- package/dist/server/express/errors.d.ts +0 -9
- package/dist/server/express/index.d.ts +0 -3
- package/dist/server/express/index.js +0 -3
- package/dist/server/express/middeware.d.ts +0 -7
- package/dist/server/express/middeware.js +0 -121
- package/dist/transport/index.d.ts +0 -3
- package/dist/transport/index.js +0 -4
- package/dist/transport/rpc/parser.d.ts +0 -15
- package/dist/transport/rpc/parser.js +0 -49
- package/dist/transport/rpc/rpc-client.d.ts +0 -80
- package/dist/transport/rpc/rpc-client.js +0 -189
- package/dist/transport/streaming/event-stream.d.ts +0 -25
- package/dist/transport/streaming/event-stream.js +0 -100
- package/dist/types/client.d.ts +0 -133
- package/dist/types/client.js +0 -5
- package/dist/utils/common/errors.js +0 -98
- /package/dist/{utils/common → browser/utils}/parse.d.ts +0 -0
- /package/dist/{utils/common → browser/utils}/schema-validation.d.ts +0 -0
- /package/dist/browser/utils/{common/utils.d.ts → utils.d.ts} +0 -0
- /package/dist/browser/utils/{common/utils.js → utils.js} +0 -0
- /package/dist/utils/{common/utils.d.ts → utils.d.ts} +0 -0
- /package/dist/utils/{common/utils.js → utils.js} +0 -0
- /package/dist/utils/{common/zAsyncIterable-v3.d.ts → zAsyncIterable-v3.d.ts} +0 -0
- /package/dist/utils/{common/zAsyncIterable-v3.js → zAsyncIterable-v3.js} +0 -0
- /package/dist/utils/{common/zAsyncIterable.d.ts → zAsyncIterable.d.ts} +0 -0
- /package/dist/utils/{common/zAsyncIterable.js → zAsyncIterable.js} +0 -0
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2025 The Artinet Project
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
import { A2AError, DefaultPushNotificationSender, } from "@a2a-js/sdk/server";
|
|
6
|
+
import { A2A } from "../../types/index.js";
|
|
7
|
+
import { PushNotifications } from "./notifications.js";
|
|
8
|
+
import { logger } from "../../config/index.js";
|
|
9
|
+
import { SystemError, validateSchema } from "../../utils/index.js";
|
|
10
|
+
/**We want to avoid pulling @a2a-js/sdk logic into our business logic. */
|
|
11
|
+
const toServiceOptions = (context, notify) => {
|
|
12
|
+
return {
|
|
13
|
+
userId: context?.user?.userName,
|
|
14
|
+
extensions: context?.activatedExtensions?.map((extension) => ({
|
|
15
|
+
uri: extension,
|
|
16
|
+
})) ?? [],
|
|
17
|
+
notifier: notify,
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
const toA2AError = (error) => {
|
|
21
|
+
if (error instanceof A2AError) {
|
|
22
|
+
return error;
|
|
23
|
+
}
|
|
24
|
+
if (error instanceof SystemError) {
|
|
25
|
+
return new A2AError(error.code, error.message, error.data, error.taskId);
|
|
26
|
+
}
|
|
27
|
+
return error;
|
|
28
|
+
};
|
|
29
|
+
const isGetTaskPushNotificationConfigParam = (params) => {
|
|
30
|
+
return A2A.GetTaskPushNotificationConfigParamSchema.safeParse(params).success;
|
|
31
|
+
};
|
|
32
|
+
const paramsRequired = (params) => {
|
|
33
|
+
if (!params || Object.keys(params).length === 0) {
|
|
34
|
+
throw A2AError.invalidParams("Params Required");
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
const validateParams = async (schema, params) => {
|
|
38
|
+
paramsRequired(params);
|
|
39
|
+
return await validateSchema(schema, params);
|
|
40
|
+
};
|
|
41
|
+
export class Native {
|
|
42
|
+
_service;
|
|
43
|
+
_pushNotifications;
|
|
44
|
+
_extendAgentCard;
|
|
45
|
+
constructor(_service, _pushNotifications, _extendAgentCard) {
|
|
46
|
+
this._service = _service;
|
|
47
|
+
this._pushNotifications = _pushNotifications;
|
|
48
|
+
this._extendAgentCard = _extendAgentCard;
|
|
49
|
+
}
|
|
50
|
+
get service() {
|
|
51
|
+
return this._service;
|
|
52
|
+
}
|
|
53
|
+
async getAgentCard() {
|
|
54
|
+
return await this.service.getAgentCard();
|
|
55
|
+
}
|
|
56
|
+
async getTask(params, context) {
|
|
57
|
+
if (!params || Object.keys(params).length === 0) {
|
|
58
|
+
throw A2AError.invalidParams("Params Required");
|
|
59
|
+
}
|
|
60
|
+
return await this.service
|
|
61
|
+
.getTask(params, toServiceOptions(context))
|
|
62
|
+
.catch((error) => {
|
|
63
|
+
throw toA2AError(error);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
async cancelTask(params, context) {
|
|
67
|
+
paramsRequired(params);
|
|
68
|
+
return await this.service
|
|
69
|
+
.cancelTask(params, toServiceOptions(context))
|
|
70
|
+
.catch((error) => {
|
|
71
|
+
throw toA2AError(error);
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
async sendMessage(params, context) {
|
|
75
|
+
paramsRequired(params);
|
|
76
|
+
return await this.service
|
|
77
|
+
.sendMessage(params, toServiceOptions(context, {
|
|
78
|
+
notify: this.notify,
|
|
79
|
+
register: this.registerConfig,
|
|
80
|
+
}))
|
|
81
|
+
.catch((error) => {
|
|
82
|
+
throw toA2AError(error);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
async *sendMessageStream(params, context) {
|
|
86
|
+
paramsRequired(params);
|
|
87
|
+
try {
|
|
88
|
+
yield* this.service.sendMessageStream(params, toServiceOptions(context, {
|
|
89
|
+
notify: this.notify,
|
|
90
|
+
register: this.registerConfig,
|
|
91
|
+
}));
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
throw toA2AError(error);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
async *resubscribe(params, context) {
|
|
98
|
+
paramsRequired(params);
|
|
99
|
+
try {
|
|
100
|
+
yield* this.service.resubscribe(params, toServiceOptions(context, {
|
|
101
|
+
notify: this.notify,
|
|
102
|
+
register: this.registerConfig,
|
|
103
|
+
}));
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
throw toA2AError(error);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
get pushNotifications() {
|
|
110
|
+
return this._pushNotifications;
|
|
111
|
+
}
|
|
112
|
+
async pushNotificationsEnabled(taskId) {
|
|
113
|
+
if (!(await this._service.getAgentCard())?.capabilities?.pushNotifications ||
|
|
114
|
+
!this.pushNotifications) {
|
|
115
|
+
throw A2AError.pushNotificationNotSupported();
|
|
116
|
+
}
|
|
117
|
+
if (taskId && !(await this._service.tasks.has(taskId))) {
|
|
118
|
+
throw A2AError.taskNotFound(taskId ?? "Unknown task");
|
|
119
|
+
}
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
async setTaskPushNotificationConfig(_params, _context) {
|
|
123
|
+
const params = await validateParams(A2A.TaskPushNotificationConfigSchema, _params);
|
|
124
|
+
await this.pushNotificationsEnabled(params.taskId);
|
|
125
|
+
const { taskId, pushNotificationConfig } = params;
|
|
126
|
+
pushNotificationConfig.id = pushNotificationConfig.id ?? taskId;
|
|
127
|
+
await this.pushNotifications.save(taskId, pushNotificationConfig);
|
|
128
|
+
logger.debug("Setting push notification config for task: ", {
|
|
129
|
+
taskId,
|
|
130
|
+
pushNotificationConfigId: pushNotificationConfig.id,
|
|
131
|
+
});
|
|
132
|
+
return {
|
|
133
|
+
taskId,
|
|
134
|
+
pushNotificationConfig,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
async getTaskPushNotificationConfig(_params, _context) {
|
|
138
|
+
const params = await validateParams(A2A.GetTaskPushNotificationConfigParamsSchema, _params);
|
|
139
|
+
await this.pushNotificationsEnabled(params.id);
|
|
140
|
+
const { id: taskId } = params;
|
|
141
|
+
const configs = await this.pushNotifications.load(taskId);
|
|
142
|
+
if (!configs) {
|
|
143
|
+
throw A2AError.internalError(`Push notification config not found for task: ${taskId}`);
|
|
144
|
+
}
|
|
145
|
+
let configId = taskId;
|
|
146
|
+
if (isGetTaskPushNotificationConfigParam(params) &&
|
|
147
|
+
params.pushNotificationConfigId) {
|
|
148
|
+
configId = params.pushNotificationConfigId;
|
|
149
|
+
}
|
|
150
|
+
const pushNotificationConfig = configs.find((config) => config.id === configId);
|
|
151
|
+
if (!pushNotificationConfig) {
|
|
152
|
+
throw A2AError.internalError(`Push notification config not found for task: ${taskId} and config: ${configId}`);
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
taskId,
|
|
156
|
+
pushNotificationConfig,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
async listTaskPushNotificationConfigs(_params, _context) {
|
|
160
|
+
const params = await validateParams(A2A.ListTaskPushNotificationConfigParamsSchema, _params);
|
|
161
|
+
await this.pushNotificationsEnabled(params.id);
|
|
162
|
+
const { id: taskId } = params;
|
|
163
|
+
const configs = await this.pushNotifications.load(taskId);
|
|
164
|
+
if (!configs) {
|
|
165
|
+
return [];
|
|
166
|
+
}
|
|
167
|
+
return configs.map((pushNotificationConfig) => ({
|
|
168
|
+
taskId,
|
|
169
|
+
pushNotificationConfig,
|
|
170
|
+
}));
|
|
171
|
+
}
|
|
172
|
+
async deleteTaskPushNotificationConfig(_params, _context) {
|
|
173
|
+
const params = await validateParams(A2A.DeleteTaskPushNotificationConfigParamsSchema, _params);
|
|
174
|
+
await this.pushNotificationsEnabled(params.id);
|
|
175
|
+
const { id: taskId } = params;
|
|
176
|
+
await this.pushNotifications.delete(taskId);
|
|
177
|
+
}
|
|
178
|
+
registerConfig = async (taskId, config) => {
|
|
179
|
+
await this.pushNotificationsEnabled(taskId);
|
|
180
|
+
await this.pushNotifications?.save(taskId, config);
|
|
181
|
+
};
|
|
182
|
+
notify = async (task, _update, _context) => {
|
|
183
|
+
const enabled = await this.pushNotificationsEnabled(task.id)
|
|
184
|
+
.then(() => true)
|
|
185
|
+
.catch(() => {
|
|
186
|
+
logger.warn("Push notifications not enabled for task: ", {
|
|
187
|
+
taskId: task.id,
|
|
188
|
+
});
|
|
189
|
+
return false;
|
|
190
|
+
});
|
|
191
|
+
if (!enabled) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
return await this.pushNotifications.send(task);
|
|
195
|
+
};
|
|
196
|
+
async getAuthenticatedExtendedAgentCard(context) {
|
|
197
|
+
if (!(await this.getAgentCard()).supportsAuthenticatedExtendedCard) {
|
|
198
|
+
throw A2AError.unsupportedOperation("Agent does not support authenticated extended card.");
|
|
199
|
+
}
|
|
200
|
+
if (!this._extendAgentCard) {
|
|
201
|
+
throw A2AError.authenticatedExtendedCardNotConfigured();
|
|
202
|
+
}
|
|
203
|
+
if (typeof this._extendAgentCard === "function") {
|
|
204
|
+
return await this._extendAgentCard(context);
|
|
205
|
+
}
|
|
206
|
+
if (context?.user?.isAuthenticated) {
|
|
207
|
+
return this._extendAgentCard;
|
|
208
|
+
}
|
|
209
|
+
return await this.getAgentCard();
|
|
210
|
+
}
|
|
211
|
+
static create(service, _pushNotifications, extendAgentCard) {
|
|
212
|
+
if (!_pushNotifications) {
|
|
213
|
+
const pushNotifications = new PushNotifications();
|
|
214
|
+
pushNotifications.sender = new DefaultPushNotificationSender(pushNotifications);
|
|
215
|
+
return new Native(service, pushNotifications, extendAgentCard);
|
|
216
|
+
}
|
|
217
|
+
if (_pushNotifications instanceof PushNotifications) {
|
|
218
|
+
return new Native(service, _pushNotifications, extendAgentCard);
|
|
219
|
+
}
|
|
220
|
+
const pushNotifications = new PushNotifications(_pushNotifications?.store);
|
|
221
|
+
pushNotifications.sender =
|
|
222
|
+
_pushNotifications?.sender ??
|
|
223
|
+
new DefaultPushNotificationSender(pushNotifications);
|
|
224
|
+
return new Native(service, pushNotifications, extendAgentCard);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* native adapter for `@a2a-js/sdk`
|
|
229
|
+
* @param service - The service to wrap
|
|
230
|
+
* @param pushNotifications - (optional) arguments for creating {@link PushNotifications}
|
|
231
|
+
* @param extendAgentCard - (optional) The extend agent card/provider to use
|
|
232
|
+
* @returns A {@link A2ARequestHandler} instance
|
|
233
|
+
* @example
|
|
234
|
+
* ```typescript
|
|
235
|
+
* const agent = cr8("Custom Agent")
|
|
236
|
+
* .text("Hello!")
|
|
237
|
+
* .agent;
|
|
238
|
+
* const nativeAdapter = native(agent, pushNotifications, extendAgentCard);
|
|
239
|
+
* ```
|
|
240
|
+
*/
|
|
241
|
+
export const native = Native.create;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2025 The Artinet Project
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
import { A2A } from "../../types/index.js";
|
|
6
|
+
import { logger } from "../../config/index.js";
|
|
7
|
+
import { handleUpdate } from "../../services/a2a/handlers/update.js";
|
|
8
|
+
import { v4 } from "uuid";
|
|
9
|
+
import { getCurrentTimestamp } from "../../utils/utils.js";
|
|
10
|
+
class LoadManager {
|
|
11
|
+
_loadable;
|
|
12
|
+
constructor(_loadable) {
|
|
13
|
+
this._loadable = _loadable;
|
|
14
|
+
}
|
|
15
|
+
async get(id, _context) {
|
|
16
|
+
return await this._loadable.load(id, _context);
|
|
17
|
+
}
|
|
18
|
+
async set(id, data, context) {
|
|
19
|
+
return await this._loadable.save(data, context, id);
|
|
20
|
+
}
|
|
21
|
+
async delete(id) {
|
|
22
|
+
logger.warn("Delete not supported for loadable", { id });
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
async has(id) {
|
|
26
|
+
return (await this._loadable.load(id)) !== undefined;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
class TaskManager extends LoadManager {
|
|
30
|
+
constructor(_loadable) {
|
|
31
|
+
super(_loadable);
|
|
32
|
+
}
|
|
33
|
+
async update(context, update) {
|
|
34
|
+
logger.info(`TaskManager[update]: updating task`, {
|
|
35
|
+
taskId: context.taskId,
|
|
36
|
+
});
|
|
37
|
+
logger.debug(`TaskManager[update]: update`, { update });
|
|
38
|
+
logger.debug(`TaskManager[update]: context`, { context });
|
|
39
|
+
const task = await handleUpdate({
|
|
40
|
+
context,
|
|
41
|
+
task: await context.getTask(),
|
|
42
|
+
update,
|
|
43
|
+
});
|
|
44
|
+
logger.debug(`TaskManager[update]: task`, task);
|
|
45
|
+
await this.set(task.id, task);
|
|
46
|
+
return task;
|
|
47
|
+
}
|
|
48
|
+
async create(params) {
|
|
49
|
+
if (params.id) {
|
|
50
|
+
const task = await this.get(params.id);
|
|
51
|
+
if (task) {
|
|
52
|
+
return task;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
logger.info(`TaskManager[create]: creating task`, { id: params.id });
|
|
56
|
+
const task = {
|
|
57
|
+
...params,
|
|
58
|
+
id: params.id ?? v4(),
|
|
59
|
+
contextId: params.contextId ?? v4(),
|
|
60
|
+
kind: "task",
|
|
61
|
+
status: {
|
|
62
|
+
state: A2A.TaskState.submitted,
|
|
63
|
+
timestamp: getCurrentTimestamp(),
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
logger.debug(`TaskManager[create]:`, { taskId: task.id });
|
|
67
|
+
await this.set(task.id, task);
|
|
68
|
+
return task;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
export const tasks = (taskStore) => {
|
|
72
|
+
return new TaskManager(taskStore);
|
|
73
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2025 The Artinet Project
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
import { PushNotificationStore, PushNotificationSender } from "@a2a-js/sdk/server";
|
|
6
|
+
import { A2A, core } from "../../types/index.js";
|
|
7
|
+
import { Manager } from "../../services/core/manager.js";
|
|
8
|
+
export interface Notifications extends core.Manager<A2A.PushNotificationConfig[]> {
|
|
9
|
+
save: (taskId: string, pushNotificationConfig: A2A.PushNotificationConfig) => Promise<void>;
|
|
10
|
+
load: (taskId: string) => Promise<A2A.PushNotificationConfig[]>;
|
|
11
|
+
delete: (taskId: string, configId?: string) => Promise<void>;
|
|
12
|
+
send: (task: A2A.Task) => Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
/** Cached Push Notifications Manager */
|
|
15
|
+
export declare class PushNotifications extends Manager<A2A.PushNotificationConfig[]> implements Notifications {
|
|
16
|
+
private readonly _store;
|
|
17
|
+
private _sender;
|
|
18
|
+
constructor(store?: PushNotificationStore, sender?: PushNotificationSender);
|
|
19
|
+
get store(): PushNotificationStore | undefined;
|
|
20
|
+
get sender(): PushNotificationSender | undefined;
|
|
21
|
+
set sender(sender: PushNotificationSender | undefined);
|
|
22
|
+
save(taskId: string, pushNotificationConfig: A2A.PushNotificationConfig): Promise<void>;
|
|
23
|
+
load(taskId: string): Promise<A2A.PushNotificationConfig[]>;
|
|
24
|
+
delete(taskId: string, configId?: string): Promise<void>;
|
|
25
|
+
send(task: A2A.Task): Promise<void>;
|
|
26
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2025 The Artinet Project
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
import { InMemoryPushNotificationStore, } from "@a2a-js/sdk/server";
|
|
6
|
+
import { Manager } from "../../services/core/manager.js";
|
|
7
|
+
/** Cached Push Notifications Manager */
|
|
8
|
+
export class PushNotifications
|
|
9
|
+
//May be more efficient to use a Record/Map instead of an array
|
|
10
|
+
extends Manager {
|
|
11
|
+
_store;
|
|
12
|
+
_sender;
|
|
13
|
+
constructor(store, sender) {
|
|
14
|
+
if (store && store instanceof InMemoryPushNotificationStore) {
|
|
15
|
+
/** We snatch its internal store to avoid creating a new Map and doubling memory usage */
|
|
16
|
+
super(store?.store);
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
super();
|
|
20
|
+
}
|
|
21
|
+
this._store = store;
|
|
22
|
+
this._sender = sender;
|
|
23
|
+
}
|
|
24
|
+
get store() {
|
|
25
|
+
return this._store;
|
|
26
|
+
}
|
|
27
|
+
get sender() {
|
|
28
|
+
return this._sender;
|
|
29
|
+
}
|
|
30
|
+
set sender(sender) {
|
|
31
|
+
this._sender = sender;
|
|
32
|
+
}
|
|
33
|
+
async save(taskId, pushNotificationConfig) {
|
|
34
|
+
pushNotificationConfig.id = pushNotificationConfig.id ?? taskId;
|
|
35
|
+
/** Cache the configs in memory for faster access */
|
|
36
|
+
const configs = await this.get(taskId);
|
|
37
|
+
await this.set(taskId, [
|
|
38
|
+
...(configs?.filter(
|
|
39
|
+
/**
|
|
40
|
+
* Since this is pure memory we can stomach the heavy filter operation for now,
|
|
41
|
+
* and its unlikely that an individual task will have excessive configs.
|
|
42
|
+
* @note Consider adding a warning when the filter operation is called with a large number of configs.
|
|
43
|
+
*/
|
|
44
|
+
(config) => config.id !== pushNotificationConfig.id) ?? []),
|
|
45
|
+
pushNotificationConfig,
|
|
46
|
+
]);
|
|
47
|
+
return await this.store?.save(taskId, pushNotificationConfig);
|
|
48
|
+
}
|
|
49
|
+
async load(taskId) {
|
|
50
|
+
let configs = await this.get(taskId);
|
|
51
|
+
/**
|
|
52
|
+
* Cache the configs in memory for faster access regardless of the storage layer.
|
|
53
|
+
* @note this may be removed once we have a persistant storage layer plugin.
|
|
54
|
+
*/
|
|
55
|
+
if (!configs || configs.length === 0) {
|
|
56
|
+
configs = await this.store?.load(taskId);
|
|
57
|
+
if (configs && configs.length > 0) {
|
|
58
|
+
await this.set(taskId, configs);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return configs ?? [];
|
|
62
|
+
}
|
|
63
|
+
async delete(taskId, configId) {
|
|
64
|
+
if (configId) {
|
|
65
|
+
await this.set(taskId, (await this.get(taskId))?.filter((config) => config.id !== configId) ??
|
|
66
|
+
[]);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
/**We dont need to maintain backward compatibility, so we can just delete all configs for the task*/
|
|
70
|
+
await super.delete(taskId);
|
|
71
|
+
}
|
|
72
|
+
await this.store?.delete(taskId, configId);
|
|
73
|
+
}
|
|
74
|
+
async send(task) {
|
|
75
|
+
return await this.sender?.send(task);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -3,31 +3,19 @@
|
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
import express from "express";
|
|
6
|
-
import { A2A } from "../../types/index.js";
|
|
7
|
-
import { Agent } from "../../services/a2a/index.js";
|
|
8
|
-
import { ServiceParams as CreateAgentParams } from "../../services/index.js";
|
|
9
6
|
import { CorsOptions } from "cors";
|
|
10
|
-
|
|
7
|
+
import { ServerParams as BaseServerParams } from "../params.js";
|
|
8
|
+
export type ServerParams = BaseServerParams & {
|
|
11
9
|
app?: express.Express;
|
|
12
10
|
corsOptions?: CorsOptions;
|
|
13
|
-
|
|
14
|
-
port?: number;
|
|
15
|
-
/**
|
|
16
|
-
* Your agentCard must have supportsAuthenticatedExtendedCard set to true
|
|
17
|
-
*/
|
|
18
|
-
extendedAgentCard?: A2A.AgentCard;
|
|
19
|
-
agent: Agent | CreateAgentParams;
|
|
20
|
-
agentCardPath?: string;
|
|
21
|
-
register?: boolean;
|
|
22
|
-
}
|
|
23
|
-
export declare function rpcParser(req: express.Request, res: express.Response, next: express.NextFunction): void;
|
|
11
|
+
};
|
|
24
12
|
/**
|
|
25
13
|
* @note Best used with the `cr8` builder.
|
|
26
14
|
* @param {ServerParams} params - The server parameters
|
|
27
15
|
* @returns {ExpressAgentServer} - The express agent server
|
|
28
16
|
* @example
|
|
29
17
|
* ```typescript
|
|
30
|
-
* const { app, agent, start } =
|
|
18
|
+
* const { app, agent, start } = serve({
|
|
31
19
|
* agent: cr8("MyAgent")
|
|
32
20
|
* .text("Hello, world!")
|
|
33
21
|
* .agent,
|
|
@@ -35,9 +23,13 @@ export declare function rpcParser(req: express.Request, res: express.Response, n
|
|
|
35
23
|
* });
|
|
36
24
|
* ```
|
|
37
25
|
*/
|
|
38
|
-
export declare function
|
|
26
|
+
export declare function serve({ app, basePath, agentCardPath, agent, corsOptions, extendedAgentCard, register, port, userBuilder, }: ServerParams): {
|
|
39
27
|
app: express.Express;
|
|
40
|
-
agent: Agent;
|
|
28
|
+
agent: import("../../index.js").Agent;
|
|
41
29
|
start: (_port?: number) => import("node:http").Server<typeof import("node:http").IncomingMessage, typeof import("node:http").ServerResponse>;
|
|
42
30
|
};
|
|
43
|
-
|
|
31
|
+
/**
|
|
32
|
+
* @deprecated Use `cr8.serve` instead.
|
|
33
|
+
*/
|
|
34
|
+
export declare const createAgentServer: typeof serve;
|
|
35
|
+
export type ExpressAgentServer = ReturnType<typeof serve>;
|
|
@@ -3,58 +3,18 @@
|
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
import express from "express";
|
|
6
|
-
import { createAgent, Service, } from "../../services/index.js";
|
|
7
6
|
import cors from "cors";
|
|
8
|
-
import { jsonRPCMiddleware } from "./middeware.js";
|
|
9
|
-
import { errorHandler } from "./errors.js";
|
|
10
7
|
import { logger } from "../../config/index.js";
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
express.json()(req, res, (err) => {
|
|
15
|
-
if (!req.body || typeof req.body !== "object") {
|
|
16
|
-
return next(A2AError.parseError(`Invalid request body: ${formatJson(req.body)}`));
|
|
17
|
-
}
|
|
18
|
-
if (err) {
|
|
19
|
-
if (err instanceof SyntaxError &&
|
|
20
|
-
"status" in err &&
|
|
21
|
-
err.status === 400 &&
|
|
22
|
-
"body" in err) {
|
|
23
|
-
return next(A2AError.parseError(`Invalid request body: ${formatJson(req.body)}`));
|
|
24
|
-
}
|
|
25
|
-
return next(err);
|
|
26
|
-
}
|
|
27
|
-
next();
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
const isParams = (agentOrParams) => {
|
|
31
|
-
return (agentOrParams &&
|
|
32
|
-
typeof agentOrParams === "object" &&
|
|
33
|
-
"engine" in agentOrParams &&
|
|
34
|
-
typeof agentOrParams.engine === "function" &&
|
|
35
|
-
"agentCard" in agentOrParams &&
|
|
36
|
-
typeof agentOrParams.agentCard === "object");
|
|
37
|
-
};
|
|
38
|
-
const ensureAgent = (agentOrParams) => {
|
|
39
|
-
if (agentOrParams instanceof Service) {
|
|
40
|
-
return agentOrParams;
|
|
41
|
-
}
|
|
42
|
-
else if (isParams(agentOrParams)) {
|
|
43
|
-
return createAgent(agentOrParams);
|
|
44
|
-
}
|
|
45
|
-
throw new Error("invalid agent or params");
|
|
46
|
-
};
|
|
47
|
-
const registerAgent = async (agentCard) => {
|
|
48
|
-
logger.debug("registerAgent: not implemented", { agentCard });
|
|
49
|
-
return Promise.resolve(agentCard);
|
|
50
|
-
};
|
|
8
|
+
import { native } from "../adapters/a2a_request_handler.js";
|
|
9
|
+
import { jsonRpcHandler, UserBuilder } from "@a2a-js/sdk/server/express";
|
|
10
|
+
import { ensureAgent, registerAgent, } from "../params.js";
|
|
51
11
|
/**
|
|
52
12
|
* @note Best used with the `cr8` builder.
|
|
53
13
|
* @param {ServerParams} params - The server parameters
|
|
54
14
|
* @returns {ExpressAgentServer} - The express agent server
|
|
55
15
|
* @example
|
|
56
16
|
* ```typescript
|
|
57
|
-
* const { app, agent, start } =
|
|
17
|
+
* const { app, agent, start } = serve({
|
|
58
18
|
* agent: cr8("MyAgent")
|
|
59
19
|
* .text("Hello, world!")
|
|
60
20
|
* .agent,
|
|
@@ -62,38 +22,39 @@ const registerAgent = async (agentCard) => {
|
|
|
62
22
|
* });
|
|
63
23
|
* ```
|
|
64
24
|
*/
|
|
65
|
-
export function
|
|
25
|
+
export function serve({ app = express(), basePath = "/", agentCardPath = "/.well-known/agent-card.json", agent, corsOptions, extendedAgentCard, register = false, port, userBuilder = UserBuilder.noAuthentication, }) {
|
|
66
26
|
const agentInstance = ensureAgent(agent);
|
|
67
|
-
|
|
27
|
+
/**
|
|
28
|
+
* Now that agents are services we can wrap them in any kind of transport layer
|
|
29
|
+
* or in express we can use json-rpc, but we could also use websockets, etc
|
|
30
|
+
*/
|
|
31
|
+
agentInstance.getAgentCard().then((card) => {
|
|
32
|
+
const url = new URL(card.url);
|
|
33
|
+
if (!url.pathname.startsWith(basePath)) {
|
|
34
|
+
logger.warn(`AgentCard may be misconfigured: URL pathname ${url.pathname} does not start with base path ${basePath}, this may cause issues with the client.`);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
const router = express.Router();
|
|
38
|
+
router.use(cors(corsOptions));
|
|
68
39
|
if (agentCardPath !== "/.well-known/agent-card.json") {
|
|
69
|
-
// mount at the root for compliance with RFC8615 standard
|
|
70
40
|
// todo: align with emerging multi-agent standards
|
|
71
|
-
|
|
41
|
+
router.use(`/.well-known/agent-card.json`, (_, res) => {
|
|
72
42
|
res.json(agentInstance.agentCard);
|
|
73
43
|
});
|
|
74
44
|
}
|
|
75
|
-
|
|
45
|
+
router.use(`${agentCardPath}`, (_, res) => {
|
|
76
46
|
// mount at the custom path
|
|
77
47
|
res.json(agentInstance.agentCard);
|
|
78
48
|
});
|
|
79
49
|
// mount at the old agent card path for backwards compatibility
|
|
80
|
-
|
|
50
|
+
router.use(`/.well-known/agent.json`, (_, res) => {
|
|
81
51
|
res.json(agentInstance.agentCard);
|
|
82
52
|
});
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
//a standard express middleware to handle json-rpc requests
|
|
89
|
-
app.post(basePath, rpcParser, async (req, res, next) => {
|
|
90
|
-
const { jsonrpc } = req.body;
|
|
91
|
-
if (jsonrpc !== "2.0") {
|
|
92
|
-
return next(A2AError.invalidRequest("Invalid JSON-RPC request"));
|
|
93
|
-
}
|
|
94
|
-
return await jsonRPCMiddleware(agentInstance, req, res, next, extendedAgentCard);
|
|
95
|
-
});
|
|
96
|
-
app.use(errorHandler);
|
|
53
|
+
router.use(jsonRpcHandler({
|
|
54
|
+
requestHandler: native(agentInstance, undefined, extendedAgentCard),
|
|
55
|
+
userBuilder: userBuilder,
|
|
56
|
+
}));
|
|
57
|
+
app.use(basePath, router);
|
|
97
58
|
/** this is an example of using trpc as express middleware
|
|
98
59
|
app.use(
|
|
99
60
|
`${basePath}`,
|
|
@@ -128,3 +89,7 @@ export function createAgentServer({ app = express(), basePath = "/", agentCardPa
|
|
|
128
89
|
};
|
|
129
90
|
return { app, agent: agentInstance, start };
|
|
130
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* @deprecated Use `cr8.serve` instead.
|
|
94
|
+
*/
|
|
95
|
+
export const createAgentServer = serve;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2025 The Artinet Project
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*
|
|
5
|
+
* @archive Helper utilities for express servers.
|
|
6
|
+
* @note We recommend using the @a2a-js/sdk/express middleware instead as these utilities will no longer be robustly maintained.
|
|
7
|
+
*/
|
|
8
|
+
import { type ErrorRequestHandler } from "express";
|
|
9
|
+
import express from "express";
|
|
10
|
+
export declare function rpcParser(req: express.Request, res: express.Response, next: express.NextFunction): void;
|
|
11
|
+
/**
|
|
12
|
+
* Express error handler middleware.
|
|
13
|
+
*/
|
|
14
|
+
export declare const errorHandler: ErrorRequestHandler;
|
|
@@ -1,11 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Copyright 2025 The Artinet Project
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*
|
|
5
|
+
* @archive Helper utilities for express servers.
|
|
6
|
+
* @note We recommend using the @a2a-js/sdk/express middleware instead as these utilities will no longer be robustly maintained.
|
|
4
7
|
*/
|
|
5
8
|
import { SystemError } from "../../utils/index.js";
|
|
6
9
|
import { logger } from "../../config/index.js";
|
|
7
10
|
import escapeHtml from "escape-html";
|
|
8
11
|
import { A2AError } from "@a2a-js/sdk/server";
|
|
12
|
+
import { formatJson } from "../../utils/index.js";
|
|
13
|
+
import express from "express";
|
|
14
|
+
export function rpcParser(req, res, next) {
|
|
15
|
+
express.json()(req, res, (err) => {
|
|
16
|
+
if (!req.body || typeof req.body !== "object") {
|
|
17
|
+
return next(A2AError.parseError(`Invalid request body: ${formatJson(req.body)}`));
|
|
18
|
+
}
|
|
19
|
+
if (err) {
|
|
20
|
+
if (err instanceof SyntaxError &&
|
|
21
|
+
"status" in err &&
|
|
22
|
+
err.status === 400 &&
|
|
23
|
+
"body" in err) {
|
|
24
|
+
return next(A2AError.parseError(`Invalid request body: ${formatJson(req.body)}`));
|
|
25
|
+
}
|
|
26
|
+
return next(err);
|
|
27
|
+
}
|
|
28
|
+
next();
|
|
29
|
+
});
|
|
30
|
+
}
|
|
9
31
|
/**
|
|
10
32
|
* Express error handler middleware.
|
|
11
33
|
*/
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1 +1,4 @@
|
|
|
1
|
-
export
|
|
1
|
+
export { native } from "./adapters/a2a_request_handler.js";
|
|
2
|
+
export { tasks } from "./adapters/loadable.js";
|
|
3
|
+
export { serve, type ServerParams, type ExpressAgentServer, createAgentServer, } from "./express/server.js";
|
|
4
|
+
export { rpcParser, errorHandler } from "./express/utils.js";
|
package/dist/server/index.js
CHANGED
|
@@ -1 +1,4 @@
|
|
|
1
|
-
export
|
|
1
|
+
export { native } from "./adapters/a2a_request_handler.js";
|
|
2
|
+
export { tasks } from "./adapters/loadable.js";
|
|
3
|
+
export { serve, createAgentServer, } from "./express/server.js";
|
|
4
|
+
export { rpcParser, errorHandler } from "./express/utils.js";
|