kavachos 0.0.4 → 0.0.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/dist/a2a/index.d.ts +2341 -0
- package/dist/a2a/index.js +821 -0
- package/dist/a2a/index.js.map +1 -0
- package/dist/agent/index.d.ts +3 -3
- package/dist/agent/index.js +3 -2
- package/dist/audit/index.d.ts +2 -2
- package/dist/audit/index.js +2 -2
- package/dist/auth/index.d.ts +490 -92
- package/dist/auth/index.js +3 -2
- package/dist/chunk-3AZDFCQF.js +186 -0
- package/dist/chunk-3AZDFCQF.js.map +1 -0
- package/dist/{chunk-SJGSPIAD.js → chunk-4CANWZWP.js} +3 -3
- package/dist/{chunk-SJGSPIAD.js.map → chunk-4CANWZWP.js.map} +1 -1
- package/dist/{chunk-KL6XW4S4.js → chunk-62P5FJ34.js} +2375 -633
- package/dist/chunk-62P5FJ34.js.map +1 -0
- package/dist/chunk-ELGG2VW2.js +538 -0
- package/dist/chunk-ELGG2VW2.js.map +1 -0
- package/dist/{chunk-5DT4DN4Y.js → chunk-IS5FRKIS.js} +13 -13
- package/dist/chunk-IS5FRKIS.js.map +1 -0
- package/dist/{chunk-V66UUIA7.js → chunk-KNNJ4COO.js} +92 -3
- package/dist/chunk-KNNJ4COO.js.map +1 -0
- package/dist/{chunk-OVGNZ5OX.js → chunk-O7VQ2LQE.js} +6 -6
- package/dist/chunk-O7VQ2LQE.js.map +1 -0
- package/dist/index.d.ts +138 -5
- package/dist/index.js +564 -29
- package/dist/index.js.map +1 -1
- package/dist/mcp/index.d.ts +2 -2
- package/dist/mcp/index.js +11 -15
- package/dist/mcp/index.js.map +1 -1
- package/dist/permission/index.d.ts +3 -3
- package/dist/permission/index.js +3 -2
- package/dist/{types-Xk83hv4O.d.ts → types-BTui0HQU.d.ts} +1763 -98
- package/dist/vc/index.d.ts +800 -0
- package/dist/vc/index.js +5 -0
- package/dist/vc/index.js.map +1 -0
- package/package.json +17 -1
- package/dist/chunk-5DT4DN4Y.js.map +0 -1
- package/dist/chunk-KL6XW4S4.js.map +0 -1
- package/dist/chunk-OVGNZ5OX.js.map +0 -1
- package/dist/chunk-V66UUIA7.js.map +0 -1
- package/dist/{types-mwupB57A.d.ts → types-BuHrZcjE.d.ts} +2 -2
|
@@ -0,0 +1,821 @@
|
|
|
1
|
+
import { generateId } from '../chunk-3AZDFCQF.js';
|
|
2
|
+
import '../chunk-PZ5AY32C.js';
|
|
3
|
+
import * as jose from 'jose';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
|
|
6
|
+
var A2A_PROTOCOL_VERSION = "0.3";
|
|
7
|
+
var A2A_JSONRPC_VERSION = "2.0";
|
|
8
|
+
var A2A_WELL_KNOWN_PATH = "/.well-known/agent.json";
|
|
9
|
+
var A2A_ERROR_CODES = {
|
|
10
|
+
PARSE_ERROR: -32700,
|
|
11
|
+
INVALID_REQUEST: -32600,
|
|
12
|
+
METHOD_NOT_FOUND: -32601,
|
|
13
|
+
INVALID_PARAMS: -32602,
|
|
14
|
+
INTERNAL_ERROR: -32603,
|
|
15
|
+
// A2A-specific codes (application-defined range)
|
|
16
|
+
TASK_NOT_FOUND: -32001,
|
|
17
|
+
AGENT_NOT_FOUND: -32002,
|
|
18
|
+
AUTHENTICATION_REQUIRED: -32003,
|
|
19
|
+
PERMISSION_DENIED: -32004,
|
|
20
|
+
RATE_LIMITED: -32005,
|
|
21
|
+
TASK_ALREADY_COMPLETED: -32006
|
|
22
|
+
};
|
|
23
|
+
var A2A_METHODS = {
|
|
24
|
+
SEND_MESSAGE: "message/send",
|
|
25
|
+
SEND_STREAMING_MESSAGE: "message/stream",
|
|
26
|
+
GET_TASK: "tasks/get",
|
|
27
|
+
CANCEL_TASK: "tasks/cancel"
|
|
28
|
+
};
|
|
29
|
+
var A2ATextPartSchema = z.object({
|
|
30
|
+
type: z.literal("text"),
|
|
31
|
+
text: z.string()
|
|
32
|
+
});
|
|
33
|
+
var A2AFilePartSchema = z.object({
|
|
34
|
+
type: z.literal("file"),
|
|
35
|
+
fileUri: z.string(),
|
|
36
|
+
mimeType: z.string(),
|
|
37
|
+
name: z.string().optional()
|
|
38
|
+
});
|
|
39
|
+
var A2ADataPartSchema = z.object({
|
|
40
|
+
type: z.literal("data"),
|
|
41
|
+
mimeType: z.string(),
|
|
42
|
+
data: z.string()
|
|
43
|
+
});
|
|
44
|
+
var A2APartSchema = z.discriminatedUnion("type", [
|
|
45
|
+
A2ATextPartSchema,
|
|
46
|
+
A2AFilePartSchema,
|
|
47
|
+
A2ADataPartSchema
|
|
48
|
+
]);
|
|
49
|
+
var A2AMessageSchema = z.object({
|
|
50
|
+
id: z.string().min(1),
|
|
51
|
+
role: z.enum(["user", "agent"]),
|
|
52
|
+
parts: z.array(A2APartSchema).min(1),
|
|
53
|
+
createdAt: z.string(),
|
|
54
|
+
metadata: z.record(z.unknown()).optional(),
|
|
55
|
+
referenceTaskIds: z.array(z.string()).optional()
|
|
56
|
+
});
|
|
57
|
+
var A2ATaskStateSchema = z.enum([
|
|
58
|
+
"submitted",
|
|
59
|
+
"working",
|
|
60
|
+
"input-required",
|
|
61
|
+
"completed",
|
|
62
|
+
"failed",
|
|
63
|
+
"canceled",
|
|
64
|
+
"auth-required",
|
|
65
|
+
"rejected"
|
|
66
|
+
]);
|
|
67
|
+
var A2ATaskStatusSchema = z.object({
|
|
68
|
+
code: A2ATaskStateSchema,
|
|
69
|
+
message: z.string().optional(),
|
|
70
|
+
progress: z.number().min(0).max(100).optional()
|
|
71
|
+
});
|
|
72
|
+
var A2AArtifactSchema = z.object({
|
|
73
|
+
id: z.string().min(1),
|
|
74
|
+
name: z.string().optional(),
|
|
75
|
+
mimeType: z.string().optional(),
|
|
76
|
+
parts: z.array(A2APartSchema).min(1),
|
|
77
|
+
metadata: z.record(z.unknown()).optional(),
|
|
78
|
+
createdAt: z.string()
|
|
79
|
+
});
|
|
80
|
+
var A2ATaskSchema = z.object({
|
|
81
|
+
id: z.string().min(1),
|
|
82
|
+
contextId: z.string().min(1),
|
|
83
|
+
status: A2ATaskStatusSchema,
|
|
84
|
+
createdAt: z.string(),
|
|
85
|
+
updatedAt: z.string(),
|
|
86
|
+
history: z.array(A2AMessageSchema).optional(),
|
|
87
|
+
artifacts: z.array(A2AArtifactSchema).optional(),
|
|
88
|
+
metadata: z.record(z.unknown()).optional()
|
|
89
|
+
});
|
|
90
|
+
var A2AAgentSkillSchema = z.object({
|
|
91
|
+
id: z.string().min(1),
|
|
92
|
+
name: z.string().min(1),
|
|
93
|
+
description: z.string(),
|
|
94
|
+
inputSchema: z.record(z.unknown()).optional(),
|
|
95
|
+
outputSchema: z.record(z.unknown()).optional(),
|
|
96
|
+
supportedMediaTypes: z.array(z.string()).optional(),
|
|
97
|
+
tags: z.array(z.string()).optional()
|
|
98
|
+
});
|
|
99
|
+
var A2AAgentProviderSchema = z.object({
|
|
100
|
+
name: z.string().min(1),
|
|
101
|
+
email: z.string().optional(),
|
|
102
|
+
url: z.string().optional()
|
|
103
|
+
});
|
|
104
|
+
var A2AAgentCapabilitiesSchema = z.object({
|
|
105
|
+
streaming: z.boolean().optional(),
|
|
106
|
+
pushNotifications: z.boolean().optional(),
|
|
107
|
+
extendedAgentCard: z.boolean().optional()
|
|
108
|
+
});
|
|
109
|
+
var A2ASecuritySchemeBaseSchema = z.object({
|
|
110
|
+
description: z.string().optional()
|
|
111
|
+
});
|
|
112
|
+
var A2AApiKeySecuritySchemeSchema = A2ASecuritySchemeBaseSchema.extend({
|
|
113
|
+
type: z.literal("apiKey"),
|
|
114
|
+
name: z.string().min(1),
|
|
115
|
+
in: z.enum(["query", "header", "cookie"])
|
|
116
|
+
});
|
|
117
|
+
var A2AHttpSecuritySchemeSchema = A2ASecuritySchemeBaseSchema.extend({
|
|
118
|
+
type: z.literal("http"),
|
|
119
|
+
scheme: z.string().min(1),
|
|
120
|
+
bearerFormat: z.string().optional()
|
|
121
|
+
});
|
|
122
|
+
var A2AOAuth2FlowSchema = z.object({
|
|
123
|
+
authorizationUrl: z.string().optional(),
|
|
124
|
+
tokenUrl: z.string().optional(),
|
|
125
|
+
refreshUrl: z.string().optional(),
|
|
126
|
+
scopes: z.record(z.string())
|
|
127
|
+
});
|
|
128
|
+
var A2AOAuth2SecuritySchemeSchema = A2ASecuritySchemeBaseSchema.extend({
|
|
129
|
+
type: z.literal("oauth2"),
|
|
130
|
+
flows: z.object({
|
|
131
|
+
implicit: A2AOAuth2FlowSchema.optional(),
|
|
132
|
+
password: A2AOAuth2FlowSchema.optional(),
|
|
133
|
+
clientCredentials: A2AOAuth2FlowSchema.optional(),
|
|
134
|
+
authorizationCode: A2AOAuth2FlowSchema.optional(),
|
|
135
|
+
deviceCode: A2AOAuth2FlowSchema.optional()
|
|
136
|
+
})
|
|
137
|
+
});
|
|
138
|
+
var A2AOidcSecuritySchemeSchema = A2ASecuritySchemeBaseSchema.extend({
|
|
139
|
+
type: z.literal("openIdConnect"),
|
|
140
|
+
openIdConnectUrl: z.string().min(1)
|
|
141
|
+
});
|
|
142
|
+
var A2AMutualTlsSecuritySchemeSchema = A2ASecuritySchemeBaseSchema.extend({
|
|
143
|
+
type: z.literal("mutualTls")
|
|
144
|
+
});
|
|
145
|
+
var A2ASecuritySchemeSchema = z.discriminatedUnion("type", [
|
|
146
|
+
A2AApiKeySecuritySchemeSchema,
|
|
147
|
+
A2AHttpSecuritySchemeSchema,
|
|
148
|
+
A2AOAuth2SecuritySchemeSchema,
|
|
149
|
+
A2AOidcSecuritySchemeSchema,
|
|
150
|
+
A2AMutualTlsSecuritySchemeSchema
|
|
151
|
+
]);
|
|
152
|
+
var A2AAgentCardSignatureSchema = z.object({
|
|
153
|
+
algorithm: z.string().min(1),
|
|
154
|
+
signature: z.string().min(1),
|
|
155
|
+
keyId: z.string().min(1)
|
|
156
|
+
});
|
|
157
|
+
var A2AAgentCardSchema = z.object({
|
|
158
|
+
id: z.string().min(1),
|
|
159
|
+
name: z.string().min(1),
|
|
160
|
+
description: z.string(),
|
|
161
|
+
version: z.string().min(1),
|
|
162
|
+
protocolVersion: z.string().min(1),
|
|
163
|
+
url: z.string().url(),
|
|
164
|
+
provider: A2AAgentProviderSchema.optional(),
|
|
165
|
+
capabilities: A2AAgentCapabilitiesSchema.optional(),
|
|
166
|
+
skills: z.array(A2AAgentSkillSchema).min(1),
|
|
167
|
+
securitySchemes: z.record(A2ASecuritySchemeSchema).optional(),
|
|
168
|
+
security: z.array(z.record(z.array(z.string()))).optional(),
|
|
169
|
+
defaultInputModes: z.array(z.string()).optional(),
|
|
170
|
+
defaultOutputModes: z.array(z.string()).optional(),
|
|
171
|
+
documentationUrl: z.string().url().optional(),
|
|
172
|
+
signature: A2AAgentCardSignatureSchema.optional(),
|
|
173
|
+
metadata: z.record(z.unknown()).optional()
|
|
174
|
+
});
|
|
175
|
+
var A2ASendMessageConfigurationSchema = z.object({
|
|
176
|
+
acceptedOutputModes: z.array(z.string()).optional(),
|
|
177
|
+
historyLength: z.number().int().min(0).optional(),
|
|
178
|
+
returnImmediately: z.boolean().optional()
|
|
179
|
+
});
|
|
180
|
+
var A2ASendMessageParamsSchema = z.object({
|
|
181
|
+
message: A2AMessageSchema,
|
|
182
|
+
configuration: A2ASendMessageConfigurationSchema.optional(),
|
|
183
|
+
metadata: z.record(z.unknown()).optional()
|
|
184
|
+
});
|
|
185
|
+
var A2AGetTaskParamsSchema = z.object({
|
|
186
|
+
id: z.string().min(1),
|
|
187
|
+
historyLength: z.number().int().min(0).optional()
|
|
188
|
+
});
|
|
189
|
+
var A2ACancelTaskParamsSchema = z.object({
|
|
190
|
+
id: z.string().min(1),
|
|
191
|
+
metadata: z.record(z.unknown()).optional()
|
|
192
|
+
});
|
|
193
|
+
var A2AJsonRpcRequestSchema = z.object({
|
|
194
|
+
jsonrpc: z.literal("2.0"),
|
|
195
|
+
id: z.union([z.string(), z.number()]),
|
|
196
|
+
method: z.string().min(1),
|
|
197
|
+
params: z.unknown()
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
// src/a2a/agent-card.ts
|
|
201
|
+
function createAgentCard(input) {
|
|
202
|
+
const card = {
|
|
203
|
+
id: input.agent.id,
|
|
204
|
+
name: input.agent.name,
|
|
205
|
+
description: input.description,
|
|
206
|
+
version: input.version,
|
|
207
|
+
protocolVersion: A2A_PROTOCOL_VERSION,
|
|
208
|
+
url: input.url,
|
|
209
|
+
skills: input.skills
|
|
210
|
+
};
|
|
211
|
+
if (input.provider) card.provider = input.provider;
|
|
212
|
+
if (input.capabilities) card.capabilities = input.capabilities;
|
|
213
|
+
if (input.securitySchemes) card.securitySchemes = input.securitySchemes;
|
|
214
|
+
if (input.security) card.security = input.security;
|
|
215
|
+
if (input.defaultInputModes) card.defaultInputModes = input.defaultInputModes;
|
|
216
|
+
if (input.defaultOutputModes) card.defaultOutputModes = input.defaultOutputModes;
|
|
217
|
+
if (input.documentationUrl) card.documentationUrl = input.documentationUrl;
|
|
218
|
+
if (input.metadata) card.metadata = input.metadata;
|
|
219
|
+
return card;
|
|
220
|
+
}
|
|
221
|
+
function validateAgentCard(card) {
|
|
222
|
+
const parsed = A2AAgentCardSchema.safeParse(card);
|
|
223
|
+
if (!parsed.success) {
|
|
224
|
+
const issues = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`);
|
|
225
|
+
return {
|
|
226
|
+
success: false,
|
|
227
|
+
error: {
|
|
228
|
+
code: "A2A_INVALID_AGENT_CARD",
|
|
229
|
+
message: `Invalid Agent Card: ${issues.join("; ")}`,
|
|
230
|
+
details: { issues }
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
return { success: true, data: parsed.data };
|
|
235
|
+
}
|
|
236
|
+
async function signAgentCard(options) {
|
|
237
|
+
const { card, privateKey, algorithm = "ES256", keyId } = options;
|
|
238
|
+
try {
|
|
239
|
+
const { signature: _ignored, ...cardWithoutSignature } = card;
|
|
240
|
+
const payload = new TextEncoder().encode(JSON.stringify(cardWithoutSignature));
|
|
241
|
+
const key = "kty" in privateKey ? await jose.importJWK(privateKey, algorithm) : privateKey;
|
|
242
|
+
const kid = keyId ?? generateId();
|
|
243
|
+
const jws = await new jose.CompactSign(payload).setProtectedHeader({ alg: algorithm, kid }).sign(key);
|
|
244
|
+
const signedCard = {
|
|
245
|
+
...card,
|
|
246
|
+
signature: {
|
|
247
|
+
algorithm,
|
|
248
|
+
signature: jws,
|
|
249
|
+
keyId: kid
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
return { success: true, data: signedCard };
|
|
253
|
+
} catch (err) {
|
|
254
|
+
return {
|
|
255
|
+
success: false,
|
|
256
|
+
error: {
|
|
257
|
+
code: "A2A_SIGN_FAILED",
|
|
258
|
+
message: err instanceof Error ? err.message : "Failed to sign agent card"
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
async function verifyAgentCard(options) {
|
|
264
|
+
const { card, publicKey } = options;
|
|
265
|
+
if (!card.signature) {
|
|
266
|
+
return {
|
|
267
|
+
success: false,
|
|
268
|
+
error: {
|
|
269
|
+
code: "A2A_NO_SIGNATURE",
|
|
270
|
+
message: "Agent Card has no signature to verify"
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
try {
|
|
275
|
+
const { signature, ...cardWithoutSignature } = card;
|
|
276
|
+
const algorithm = signature.algorithm;
|
|
277
|
+
const key = "kty" in publicKey ? await jose.importJWK(publicKey, algorithm) : publicKey;
|
|
278
|
+
const { payload } = await jose.compactVerify(signature.signature, key);
|
|
279
|
+
const decoded = new TextDecoder().decode(payload);
|
|
280
|
+
const signedContent = JSON.parse(decoded);
|
|
281
|
+
const currentContent = JSON.stringify(cardWithoutSignature);
|
|
282
|
+
const parsedCurrentContent = JSON.parse(currentContent);
|
|
283
|
+
const matches = JSON.stringify(signedContent) === JSON.stringify(parsedCurrentContent);
|
|
284
|
+
return {
|
|
285
|
+
success: true,
|
|
286
|
+
data: { valid: matches, card }
|
|
287
|
+
};
|
|
288
|
+
} catch (err) {
|
|
289
|
+
return {
|
|
290
|
+
success: false,
|
|
291
|
+
error: {
|
|
292
|
+
code: "A2A_VERIFY_FAILED",
|
|
293
|
+
message: err instanceof Error ? err.message : "Failed to verify agent card signature"
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// src/a2a/client.ts
|
|
300
|
+
function createA2AClient(config) {
|
|
301
|
+
const fetchFn = config.fetch ?? globalThis.fetch;
|
|
302
|
+
const timeout = config.timeout ?? 3e4;
|
|
303
|
+
let cachedCard;
|
|
304
|
+
function getBaseUrl() {
|
|
305
|
+
if (typeof config.agent === "string") {
|
|
306
|
+
return config.agent.replace(/\/$/, "");
|
|
307
|
+
}
|
|
308
|
+
return config.agent.url.replace(/\/$/, "");
|
|
309
|
+
}
|
|
310
|
+
if (typeof config.agent !== "string") {
|
|
311
|
+
cachedCard = config.agent;
|
|
312
|
+
}
|
|
313
|
+
async function getAuthHeaders() {
|
|
314
|
+
if (!config.getAuthToken) return {};
|
|
315
|
+
const token = await config.getAuthToken();
|
|
316
|
+
return { Authorization: `Bearer ${token}` };
|
|
317
|
+
}
|
|
318
|
+
async function jsonRpcCall(method, params) {
|
|
319
|
+
const baseUrl = cachedCard?.url ?? getBaseUrl();
|
|
320
|
+
const authHeaders = await getAuthHeaders();
|
|
321
|
+
const controller = new AbortController();
|
|
322
|
+
const timer = setTimeout(() => controller.abort(), timeout);
|
|
323
|
+
try {
|
|
324
|
+
const response = await fetchFn(baseUrl, {
|
|
325
|
+
method: "POST",
|
|
326
|
+
headers: {
|
|
327
|
+
"Content-Type": "application/json",
|
|
328
|
+
...authHeaders
|
|
329
|
+
},
|
|
330
|
+
body: JSON.stringify({
|
|
331
|
+
jsonrpc: A2A_JSONRPC_VERSION,
|
|
332
|
+
id: generateId(),
|
|
333
|
+
method,
|
|
334
|
+
params
|
|
335
|
+
}),
|
|
336
|
+
signal: controller.signal
|
|
337
|
+
});
|
|
338
|
+
if (!response.ok) {
|
|
339
|
+
return {
|
|
340
|
+
success: false,
|
|
341
|
+
error: {
|
|
342
|
+
code: "A2A_HTTP_ERROR",
|
|
343
|
+
message: `HTTP ${response.status}: ${response.statusText}`
|
|
344
|
+
}
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
const body = await response.json();
|
|
348
|
+
if (body.error) {
|
|
349
|
+
return {
|
|
350
|
+
success: false,
|
|
351
|
+
error: {
|
|
352
|
+
code: `A2A_RPC_${body.error.code}`,
|
|
353
|
+
message: body.error.message,
|
|
354
|
+
details: body.error.data ? { data: body.error.data } : void 0
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
return { success: true, data: body.result };
|
|
359
|
+
} catch (err) {
|
|
360
|
+
if (err instanceof DOMException && err.name === "AbortError") {
|
|
361
|
+
return {
|
|
362
|
+
success: false,
|
|
363
|
+
error: {
|
|
364
|
+
code: "A2A_TIMEOUT",
|
|
365
|
+
message: `Request timed out after ${timeout}ms`
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
return {
|
|
370
|
+
success: false,
|
|
371
|
+
error: {
|
|
372
|
+
code: "A2A_REQUEST_FAILED",
|
|
373
|
+
message: err instanceof Error ? err.message : "Request failed"
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
} finally {
|
|
377
|
+
clearTimeout(timer);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
async function discover() {
|
|
381
|
+
if (cachedCard) {
|
|
382
|
+
return { success: true, data: cachedCard };
|
|
383
|
+
}
|
|
384
|
+
const baseUrl = getBaseUrl();
|
|
385
|
+
const url = `${baseUrl}${A2A_WELL_KNOWN_PATH}`;
|
|
386
|
+
const authHeaders = await getAuthHeaders();
|
|
387
|
+
const controller = new AbortController();
|
|
388
|
+
const timer = setTimeout(() => controller.abort(), timeout);
|
|
389
|
+
try {
|
|
390
|
+
const response = await fetchFn(url, {
|
|
391
|
+
method: "GET",
|
|
392
|
+
headers: authHeaders,
|
|
393
|
+
signal: controller.signal
|
|
394
|
+
});
|
|
395
|
+
if (!response.ok) {
|
|
396
|
+
return {
|
|
397
|
+
success: false,
|
|
398
|
+
error: {
|
|
399
|
+
code: "A2A_DISCOVERY_FAILED",
|
|
400
|
+
message: `Discovery failed: HTTP ${response.status}`
|
|
401
|
+
}
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
const body = await response.json();
|
|
405
|
+
const parsed = A2AAgentCardSchema.safeParse(body);
|
|
406
|
+
if (!parsed.success) {
|
|
407
|
+
return {
|
|
408
|
+
success: false,
|
|
409
|
+
error: {
|
|
410
|
+
code: "A2A_INVALID_AGENT_CARD",
|
|
411
|
+
message: `Invalid agent card: ${parsed.error.issues.map((i) => i.message).join("; ")}`
|
|
412
|
+
}
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
cachedCard = parsed.data;
|
|
416
|
+
return { success: true, data: cachedCard };
|
|
417
|
+
} catch (err) {
|
|
418
|
+
return {
|
|
419
|
+
success: false,
|
|
420
|
+
error: {
|
|
421
|
+
code: "A2A_DISCOVERY_FAILED",
|
|
422
|
+
message: err instanceof Error ? err.message : "Discovery request failed"
|
|
423
|
+
}
|
|
424
|
+
};
|
|
425
|
+
} finally {
|
|
426
|
+
clearTimeout(timer);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
async function sendMessage(params) {
|
|
430
|
+
return jsonRpcCall(A2A_METHODS.SEND_MESSAGE, params);
|
|
431
|
+
}
|
|
432
|
+
async function getTask(params) {
|
|
433
|
+
return jsonRpcCall(A2A_METHODS.GET_TASK, params);
|
|
434
|
+
}
|
|
435
|
+
async function cancelTask(params) {
|
|
436
|
+
return jsonRpcCall(A2A_METHODS.CANCEL_TASK, params);
|
|
437
|
+
}
|
|
438
|
+
async function* sendStreamingMessage(params) {
|
|
439
|
+
const baseUrl = cachedCard?.url ?? getBaseUrl();
|
|
440
|
+
const authHeaders = await getAuthHeaders();
|
|
441
|
+
const response = await fetchFn(baseUrl, {
|
|
442
|
+
method: "POST",
|
|
443
|
+
headers: {
|
|
444
|
+
"Content-Type": "application/json",
|
|
445
|
+
Accept: "text/event-stream",
|
|
446
|
+
...authHeaders
|
|
447
|
+
},
|
|
448
|
+
body: JSON.stringify({
|
|
449
|
+
jsonrpc: A2A_JSONRPC_VERSION,
|
|
450
|
+
id: generateId(),
|
|
451
|
+
method: A2A_METHODS.SEND_STREAMING_MESSAGE,
|
|
452
|
+
params
|
|
453
|
+
})
|
|
454
|
+
});
|
|
455
|
+
if (!response.ok || !response.body) {
|
|
456
|
+
throw new Error(`Streaming request failed: HTTP ${response.status}`);
|
|
457
|
+
}
|
|
458
|
+
const reader = response.body.getReader();
|
|
459
|
+
const decoder = new TextDecoder();
|
|
460
|
+
let buffer = "";
|
|
461
|
+
try {
|
|
462
|
+
while (true) {
|
|
463
|
+
const { done, value } = await reader.read();
|
|
464
|
+
if (done) break;
|
|
465
|
+
buffer += decoder.decode(value, { stream: true });
|
|
466
|
+
const lines = buffer.split("\n");
|
|
467
|
+
buffer = lines.pop() ?? "";
|
|
468
|
+
for (const line of lines) {
|
|
469
|
+
if (line.startsWith("data: ")) {
|
|
470
|
+
const data = line.slice(6).trim();
|
|
471
|
+
if (data === "[DONE]") return;
|
|
472
|
+
try {
|
|
473
|
+
yield JSON.parse(data);
|
|
474
|
+
} catch {
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
} finally {
|
|
480
|
+
reader.releaseLock();
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
return {
|
|
484
|
+
discover,
|
|
485
|
+
sendMessage,
|
|
486
|
+
getTask,
|
|
487
|
+
cancelTask,
|
|
488
|
+
sendStreamingMessage
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// src/a2a/server.ts
|
|
493
|
+
function createInMemoryTaskStore() {
|
|
494
|
+
const tasks = /* @__PURE__ */ new Map();
|
|
495
|
+
return {
|
|
496
|
+
async get(taskId) {
|
|
497
|
+
return tasks.get(taskId);
|
|
498
|
+
},
|
|
499
|
+
async set(taskId, task) {
|
|
500
|
+
tasks.set(taskId, task);
|
|
501
|
+
},
|
|
502
|
+
async delete(taskId) {
|
|
503
|
+
return tasks.delete(taskId);
|
|
504
|
+
}
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
function jsonRpcError(id, error) {
|
|
508
|
+
const body = {
|
|
509
|
+
jsonrpc: A2A_JSONRPC_VERSION,
|
|
510
|
+
id: id ?? 0,
|
|
511
|
+
error
|
|
512
|
+
};
|
|
513
|
+
return new Response(JSON.stringify(body), {
|
|
514
|
+
status: 200,
|
|
515
|
+
// JSON-RPC always returns 200
|
|
516
|
+
headers: { "Content-Type": "application/json" }
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
function jsonRpcSuccess(id, result) {
|
|
520
|
+
const body = {
|
|
521
|
+
jsonrpc: A2A_JSONRPC_VERSION,
|
|
522
|
+
id,
|
|
523
|
+
result
|
|
524
|
+
};
|
|
525
|
+
return new Response(JSON.stringify(body), {
|
|
526
|
+
status: 200,
|
|
527
|
+
headers: { "Content-Type": "application/json" }
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
function createA2AServer(config) {
|
|
531
|
+
const taskStore = config.taskStore ?? createInMemoryTaskStore();
|
|
532
|
+
async function audit(event) {
|
|
533
|
+
if (config.onAudit) {
|
|
534
|
+
await config.onAudit({
|
|
535
|
+
...event,
|
|
536
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
async function authenticate(request) {
|
|
541
|
+
if (!config.authenticate) {
|
|
542
|
+
return { agentId: null, error: null };
|
|
543
|
+
}
|
|
544
|
+
const agentId = await config.authenticate(request);
|
|
545
|
+
if (agentId === null) {
|
|
546
|
+
return {
|
|
547
|
+
agentId: null,
|
|
548
|
+
error: jsonRpcError(0, {
|
|
549
|
+
code: A2A_ERROR_CODES.AUTHENTICATION_REQUIRED,
|
|
550
|
+
message: "Authentication required"
|
|
551
|
+
})
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
return { agentId, error: null };
|
|
555
|
+
}
|
|
556
|
+
async function handleSendMessage(id, params, agentId) {
|
|
557
|
+
const parsed = A2ASendMessageParamsSchema.safeParse(params);
|
|
558
|
+
if (!parsed.success) {
|
|
559
|
+
await audit({
|
|
560
|
+
method: A2A_METHODS.SEND_MESSAGE,
|
|
561
|
+
agentId,
|
|
562
|
+
success: false,
|
|
563
|
+
error: "Invalid params"
|
|
564
|
+
});
|
|
565
|
+
return jsonRpcError(id, {
|
|
566
|
+
code: A2A_ERROR_CODES.INVALID_PARAMS,
|
|
567
|
+
message: `Invalid params: ${parsed.error.issues.map((i) => i.message).join("; ")}`
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
try {
|
|
571
|
+
const task = await config.handler.onMessage(parsed.data.message, parsed.data.configuration);
|
|
572
|
+
await taskStore.set(task.id, task);
|
|
573
|
+
await audit({
|
|
574
|
+
method: A2A_METHODS.SEND_MESSAGE,
|
|
575
|
+
agentId,
|
|
576
|
+
taskId: task.id,
|
|
577
|
+
success: true
|
|
578
|
+
});
|
|
579
|
+
return jsonRpcSuccess(id, task);
|
|
580
|
+
} catch (err) {
|
|
581
|
+
const message = err instanceof Error ? err.message : "Internal error";
|
|
582
|
+
await audit({
|
|
583
|
+
method: A2A_METHODS.SEND_MESSAGE,
|
|
584
|
+
agentId,
|
|
585
|
+
success: false,
|
|
586
|
+
error: message
|
|
587
|
+
});
|
|
588
|
+
return jsonRpcError(id, {
|
|
589
|
+
code: A2A_ERROR_CODES.INTERNAL_ERROR,
|
|
590
|
+
message
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
async function handleGetTask(id, params, agentId) {
|
|
595
|
+
const parsed = A2AGetTaskParamsSchema.safeParse(params);
|
|
596
|
+
if (!parsed.success) {
|
|
597
|
+
return jsonRpcError(id, {
|
|
598
|
+
code: A2A_ERROR_CODES.INVALID_PARAMS,
|
|
599
|
+
message: "Invalid params: id is required"
|
|
600
|
+
});
|
|
601
|
+
}
|
|
602
|
+
const task = await taskStore.get(parsed.data.id);
|
|
603
|
+
if (!task) {
|
|
604
|
+
await audit({
|
|
605
|
+
method: A2A_METHODS.GET_TASK,
|
|
606
|
+
agentId,
|
|
607
|
+
taskId: parsed.data.id,
|
|
608
|
+
success: false,
|
|
609
|
+
error: "Task not found"
|
|
610
|
+
});
|
|
611
|
+
return jsonRpcError(id, {
|
|
612
|
+
code: A2A_ERROR_CODES.TASK_NOT_FOUND,
|
|
613
|
+
message: `Task ${parsed.data.id} not found`
|
|
614
|
+
});
|
|
615
|
+
}
|
|
616
|
+
let result = task;
|
|
617
|
+
if (parsed.data.historyLength !== void 0 && task.history) {
|
|
618
|
+
const len = parsed.data.historyLength;
|
|
619
|
+
result = {
|
|
620
|
+
...task,
|
|
621
|
+
history: len === 0 ? [] : task.history.slice(-len)
|
|
622
|
+
};
|
|
623
|
+
}
|
|
624
|
+
await audit({
|
|
625
|
+
method: A2A_METHODS.GET_TASK,
|
|
626
|
+
agentId,
|
|
627
|
+
taskId: task.id,
|
|
628
|
+
success: true
|
|
629
|
+
});
|
|
630
|
+
return jsonRpcSuccess(id, result);
|
|
631
|
+
}
|
|
632
|
+
async function handleCancelTask(id, params, agentId) {
|
|
633
|
+
const parsed = A2ACancelTaskParamsSchema.safeParse(params);
|
|
634
|
+
if (!parsed.success) {
|
|
635
|
+
return jsonRpcError(id, {
|
|
636
|
+
code: A2A_ERROR_CODES.INVALID_PARAMS,
|
|
637
|
+
message: "Invalid params: id is required"
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
const existing = await taskStore.get(parsed.data.id);
|
|
641
|
+
if (!existing) {
|
|
642
|
+
await audit({
|
|
643
|
+
method: A2A_METHODS.CANCEL_TASK,
|
|
644
|
+
agentId,
|
|
645
|
+
taskId: parsed.data.id,
|
|
646
|
+
success: false,
|
|
647
|
+
error: "Task not found"
|
|
648
|
+
});
|
|
649
|
+
return jsonRpcError(id, {
|
|
650
|
+
code: A2A_ERROR_CODES.TASK_NOT_FOUND,
|
|
651
|
+
message: `Task ${parsed.data.id} not found`
|
|
652
|
+
});
|
|
653
|
+
}
|
|
654
|
+
if (existing.status.code === "completed" || existing.status.code === "failed" || existing.status.code === "canceled") {
|
|
655
|
+
await audit({
|
|
656
|
+
method: A2A_METHODS.CANCEL_TASK,
|
|
657
|
+
agentId,
|
|
658
|
+
taskId: existing.id,
|
|
659
|
+
success: false,
|
|
660
|
+
error: "Task already in terminal state"
|
|
661
|
+
});
|
|
662
|
+
return jsonRpcError(id, {
|
|
663
|
+
code: A2A_ERROR_CODES.TASK_ALREADY_COMPLETED,
|
|
664
|
+
message: `Task ${parsed.data.id} is already ${existing.status.code}`
|
|
665
|
+
});
|
|
666
|
+
}
|
|
667
|
+
if (config.handler.onCancel) {
|
|
668
|
+
try {
|
|
669
|
+
const canceled2 = await config.handler.onCancel(parsed.data.id);
|
|
670
|
+
await taskStore.set(canceled2.id, canceled2);
|
|
671
|
+
await audit({
|
|
672
|
+
method: A2A_METHODS.CANCEL_TASK,
|
|
673
|
+
agentId,
|
|
674
|
+
taskId: canceled2.id,
|
|
675
|
+
success: true
|
|
676
|
+
});
|
|
677
|
+
return jsonRpcSuccess(id, canceled2);
|
|
678
|
+
} catch (err) {
|
|
679
|
+
const message = err instanceof Error ? err.message : "Cancel failed";
|
|
680
|
+
await audit({
|
|
681
|
+
method: A2A_METHODS.CANCEL_TASK,
|
|
682
|
+
agentId,
|
|
683
|
+
taskId: parsed.data.id,
|
|
684
|
+
success: false,
|
|
685
|
+
error: message
|
|
686
|
+
});
|
|
687
|
+
return jsonRpcError(id, {
|
|
688
|
+
code: A2A_ERROR_CODES.INTERNAL_ERROR,
|
|
689
|
+
message
|
|
690
|
+
});
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
const canceled = {
|
|
694
|
+
...existing,
|
|
695
|
+
status: { code: "canceled", message: "Canceled by client" },
|
|
696
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
697
|
+
};
|
|
698
|
+
await taskStore.set(canceled.id, canceled);
|
|
699
|
+
await audit({
|
|
700
|
+
method: A2A_METHODS.CANCEL_TASK,
|
|
701
|
+
agentId,
|
|
702
|
+
taskId: canceled.id,
|
|
703
|
+
success: true
|
|
704
|
+
});
|
|
705
|
+
return jsonRpcSuccess(id, canceled);
|
|
706
|
+
}
|
|
707
|
+
function handleStreamingMessage(id, params, agentId) {
|
|
708
|
+
if (!config.handler.onMessageStream) {
|
|
709
|
+
return jsonRpcError(id, {
|
|
710
|
+
code: A2A_ERROR_CODES.METHOD_NOT_FOUND,
|
|
711
|
+
message: "Streaming not supported by this agent"
|
|
712
|
+
});
|
|
713
|
+
}
|
|
714
|
+
const parsed = A2ASendMessageParamsSchema.safeParse(params);
|
|
715
|
+
if (!parsed.success) {
|
|
716
|
+
return jsonRpcError(id, {
|
|
717
|
+
code: A2A_ERROR_CODES.INVALID_PARAMS,
|
|
718
|
+
message: "Invalid params"
|
|
719
|
+
});
|
|
720
|
+
}
|
|
721
|
+
const stream = config.handler.onMessageStream(parsed.data.message, parsed.data.configuration);
|
|
722
|
+
const encoder = new TextEncoder();
|
|
723
|
+
const readable = new ReadableStream({
|
|
724
|
+
async start(controller) {
|
|
725
|
+
try {
|
|
726
|
+
for await (const event of stream) {
|
|
727
|
+
const data = JSON.stringify(event);
|
|
728
|
+
controller.enqueue(encoder.encode(`data: ${data}
|
|
729
|
+
|
|
730
|
+
`));
|
|
731
|
+
}
|
|
732
|
+
controller.enqueue(encoder.encode("data: [DONE]\n\n"));
|
|
733
|
+
controller.close();
|
|
734
|
+
} catch (err) {
|
|
735
|
+
const errorData = JSON.stringify({
|
|
736
|
+
type: "error",
|
|
737
|
+
error: {
|
|
738
|
+
code: A2A_ERROR_CODES.INTERNAL_ERROR,
|
|
739
|
+
message: err instanceof Error ? err.message : "Stream error"
|
|
740
|
+
}
|
|
741
|
+
});
|
|
742
|
+
controller.enqueue(encoder.encode(`data: ${errorData}
|
|
743
|
+
|
|
744
|
+
`));
|
|
745
|
+
controller.close();
|
|
746
|
+
}
|
|
747
|
+
void audit({
|
|
748
|
+
method: A2A_METHODS.SEND_STREAMING_MESSAGE,
|
|
749
|
+
agentId,
|
|
750
|
+
success: true
|
|
751
|
+
});
|
|
752
|
+
}
|
|
753
|
+
});
|
|
754
|
+
return new Response(readable, {
|
|
755
|
+
status: 200,
|
|
756
|
+
headers: {
|
|
757
|
+
"Content-Type": "text/event-stream",
|
|
758
|
+
"Cache-Control": "no-cache",
|
|
759
|
+
Connection: "keep-alive"
|
|
760
|
+
}
|
|
761
|
+
});
|
|
762
|
+
}
|
|
763
|
+
async function handleRequest(request) {
|
|
764
|
+
const url = new URL(request.url);
|
|
765
|
+
if (request.method === "GET" && url.pathname.endsWith(A2A_WELL_KNOWN_PATH)) {
|
|
766
|
+
return new Response(JSON.stringify(config.agentCard), {
|
|
767
|
+
status: 200,
|
|
768
|
+
headers: { "Content-Type": "application/json" }
|
|
769
|
+
});
|
|
770
|
+
}
|
|
771
|
+
if (request.method !== "POST") {
|
|
772
|
+
return new Response("Method Not Allowed", { status: 405 });
|
|
773
|
+
}
|
|
774
|
+
const auth = await authenticate(request);
|
|
775
|
+
if (auth.error) return auth.error;
|
|
776
|
+
const agentId = auth.agentId;
|
|
777
|
+
let body;
|
|
778
|
+
try {
|
|
779
|
+
body = await request.json();
|
|
780
|
+
} catch {
|
|
781
|
+
return jsonRpcError(null, {
|
|
782
|
+
code: A2A_ERROR_CODES.PARSE_ERROR,
|
|
783
|
+
message: "Invalid JSON"
|
|
784
|
+
});
|
|
785
|
+
}
|
|
786
|
+
const envelope = A2AJsonRpcRequestSchema.safeParse(body);
|
|
787
|
+
if (!envelope.success) {
|
|
788
|
+
return jsonRpcError(null, {
|
|
789
|
+
code: A2A_ERROR_CODES.INVALID_REQUEST,
|
|
790
|
+
message: "Invalid JSON-RPC request"
|
|
791
|
+
});
|
|
792
|
+
}
|
|
793
|
+
const { id: reqId, method, params } = envelope.data;
|
|
794
|
+
switch (method) {
|
|
795
|
+
case A2A_METHODS.SEND_MESSAGE:
|
|
796
|
+
return handleSendMessage(reqId, params, agentId);
|
|
797
|
+
case A2A_METHODS.GET_TASK:
|
|
798
|
+
return handleGetTask(reqId, params, agentId);
|
|
799
|
+
case A2A_METHODS.CANCEL_TASK:
|
|
800
|
+
return handleCancelTask(reqId, params, agentId);
|
|
801
|
+
case A2A_METHODS.SEND_STREAMING_MESSAGE:
|
|
802
|
+
return handleStreamingMessage(reqId, params, agentId);
|
|
803
|
+
default:
|
|
804
|
+
await audit({
|
|
805
|
+
method,
|
|
806
|
+
agentId,
|
|
807
|
+
success: false,
|
|
808
|
+
error: "Method not found"
|
|
809
|
+
});
|
|
810
|
+
return jsonRpcError(reqId, {
|
|
811
|
+
code: A2A_ERROR_CODES.METHOD_NOT_FOUND,
|
|
812
|
+
message: `Unknown method: ${method}`
|
|
813
|
+
});
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
return { handleRequest, taskStore };
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
export { A2AAgentCapabilitiesSchema, A2AAgentCardSchema, A2AAgentCardSignatureSchema, A2AAgentProviderSchema, A2AAgentSkillSchema, A2AApiKeySecuritySchemeSchema, A2AArtifactSchema, A2ACancelTaskParamsSchema, A2ADataPartSchema, A2AFilePartSchema, A2AGetTaskParamsSchema, A2AHttpSecuritySchemeSchema, A2AJsonRpcRequestSchema, A2AMessageSchema, A2AMutualTlsSecuritySchemeSchema, A2AOAuth2FlowSchema, A2AOAuth2SecuritySchemeSchema, A2AOidcSecuritySchemeSchema, A2APartSchema, A2ASecuritySchemeSchema, A2ASendMessageConfigurationSchema, A2ASendMessageParamsSchema, A2ATaskSchema, A2ATaskStateSchema, A2ATaskStatusSchema, A2ATextPartSchema, A2A_ERROR_CODES, A2A_JSONRPC_VERSION, A2A_METHODS, A2A_PROTOCOL_VERSION, A2A_WELL_KNOWN_PATH, createA2AClient, createA2AServer, createAgentCard, signAgentCard, validateAgentCard, verifyAgentCard };
|
|
820
|
+
//# sourceMappingURL=index.js.map
|
|
821
|
+
//# sourceMappingURL=index.js.map
|