@cogitator-ai/a2a 0.3.10 → 0.4.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/LICENSE +21 -0
- package/README.md +64 -7
- package/dist/adapters/express.d.ts.map +1 -1
- package/dist/adapters/express.js +22 -22
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/fastify.d.ts.map +1 -1
- package/dist/adapters/fastify.js +23 -24
- package/dist/adapters/fastify.js.map +1 -1
- package/dist/adapters/hono.d.ts.map +1 -1
- package/dist/adapters/hono.js +25 -8
- package/dist/adapters/hono.js.map +1 -1
- package/dist/adapters/koa.d.ts.map +1 -1
- package/dist/adapters/koa.js +16 -23
- package/dist/adapters/koa.js.map +1 -1
- package/dist/adapters/next.d.ts.map +1 -1
- package/dist/adapters/next.js +22 -19
- package/dist/adapters/next.js.map +1 -1
- package/dist/adapters/shared.d.ts +18 -0
- package/dist/adapters/shared.d.ts.map +1 -0
- package/dist/adapters/shared.js +52 -0
- package/dist/adapters/shared.js.map +1 -0
- package/dist/adapters/sse-error-event.d.ts +3 -0
- package/dist/adapters/sse-error-event.d.ts.map +1 -0
- package/dist/adapters/sse-error-event.js +11 -0
- package/dist/adapters/sse-error-event.js.map +1 -0
- package/dist/agent-card.d.ts.map +1 -1
- package/dist/agent-card.js +15 -2
- package/dist/agent-card.js.map +1 -1
- package/dist/client.d.ts +24 -4
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +163 -83
- package/dist/client.js.map +1 -1
- package/dist/errors.d.ts +1 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +3 -0
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +6 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/json-rpc.d.ts +2 -2
- package/dist/json-rpc.d.ts.map +1 -1
- package/dist/json-rpc.js +11 -7
- package/dist/json-rpc.js.map +1 -1
- package/dist/push-notifications.d.ts +8 -1
- package/dist/push-notifications.d.ts.map +1 -1
- package/dist/push-notifications.js +178 -25
- package/dist/push-notifications.js.map +1 -1
- package/dist/redis-task-store.d.ts +1 -0
- package/dist/redis-task-store.d.ts.map +1 -1
- package/dist/redis-task-store.js +44 -4
- package/dist/redis-task-store.js.map +1 -1
- package/dist/server.d.ts +19 -2
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +287 -135
- package/dist/server.js.map +1 -1
- package/dist/task-manager.d.ts +27 -2
- package/dist/task-manager.d.ts.map +1 -1
- package/dist/task-manager.js +126 -36
- package/dist/task-manager.js.map +1 -1
- package/dist/task-store.d.ts +10 -0
- package/dist/task-store.d.ts.map +1 -1
- package/dist/task-store.js +28 -0
- package/dist/task-store.js.map +1 -1
- package/dist/types.d.ts +17 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -1
- package/package.json +14 -14
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { A2AServer } from '../server.js';
|
|
2
|
+
import type { A2AStreamEvent } from '../types.js';
|
|
3
|
+
export type HeaderValue = string | string[] | null | undefined;
|
|
4
|
+
/**
|
|
5
|
+
* A request streams only for the `message/stream` method; the Accept header
|
|
6
|
+
* alone does not switch a `message/send` request to SSE.
|
|
7
|
+
*/
|
|
8
|
+
export declare function isStreamRequest(body: unknown): boolean;
|
|
9
|
+
export declare function firstHeader(value: HeaderValue): string | undefined;
|
|
10
|
+
export declare function sseFrame(data: A2AStreamEvent | '[DONE]'): string;
|
|
11
|
+
export declare const SSE_HEADERS: Record<string, string>;
|
|
12
|
+
/**
|
|
13
|
+
* Drive a JSON-RPC stream and write SSE frames until it ends, the client
|
|
14
|
+
* disconnects (signal aborted) or a write fails. Errors are reported as a
|
|
15
|
+
* final failed status-update frame.
|
|
16
|
+
*/
|
|
17
|
+
export declare function pipeJsonRpcStream(server: A2AServer, body: unknown, authToken: string | undefined, signal: AbortSignal, write: (frame: string) => void | Promise<void>): Promise<void>;
|
|
18
|
+
//# sourceMappingURL=shared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/adapters/shared.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAGlD,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,GAAG,SAAS,CAAC;AAE/D;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAOtD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,CAGlE;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,cAAc,GAAG,QAAQ,GAAG,MAAM,CAEhE;AAED,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAK9C,CAAC;AAEF;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,OAAO,EACb,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,MAAM,EAAE,WAAW,EACnB,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAC7C,OAAO,CAAC,IAAI,CAAC,CAef"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { buildSseErrorEvent } from './sse-error-event.js';
|
|
2
|
+
/**
|
|
3
|
+
* A request streams only for the `message/stream` method; the Accept header
|
|
4
|
+
* alone does not switch a `message/send` request to SSE.
|
|
5
|
+
*/
|
|
6
|
+
export function isStreamRequest(body) {
|
|
7
|
+
return (typeof body === 'object' &&
|
|
8
|
+
body !== null &&
|
|
9
|
+
!Array.isArray(body) &&
|
|
10
|
+
body.method === 'message/stream');
|
|
11
|
+
}
|
|
12
|
+
export function firstHeader(value) {
|
|
13
|
+
if (Array.isArray(value))
|
|
14
|
+
return value[0];
|
|
15
|
+
return value ?? undefined;
|
|
16
|
+
}
|
|
17
|
+
export function sseFrame(data) {
|
|
18
|
+
return `data: ${typeof data === 'string' ? data : JSON.stringify(data)}\n\n`;
|
|
19
|
+
}
|
|
20
|
+
export const SSE_HEADERS = {
|
|
21
|
+
'Content-Type': 'text/event-stream',
|
|
22
|
+
'Cache-Control': 'no-cache',
|
|
23
|
+
Connection: 'keep-alive',
|
|
24
|
+
'X-Accel-Buffering': 'no',
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Drive a JSON-RPC stream and write SSE frames until it ends, the client
|
|
28
|
+
* disconnects (signal aborted) or a write fails. Errors are reported as a
|
|
29
|
+
* final failed status-update frame.
|
|
30
|
+
*/
|
|
31
|
+
export async function pipeJsonRpcStream(server, body, authToken, signal, write) {
|
|
32
|
+
try {
|
|
33
|
+
for await (const event of server.handleJsonRpcStream(body, authToken, signal)) {
|
|
34
|
+
if (signal.aborted)
|
|
35
|
+
return;
|
|
36
|
+
await write(sseFrame(event));
|
|
37
|
+
}
|
|
38
|
+
if (!signal.aborted)
|
|
39
|
+
await write(sseFrame('[DONE]'));
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
if (signal.aborted)
|
|
43
|
+
return;
|
|
44
|
+
try {
|
|
45
|
+
await write(sseFrame(buildSseErrorEvent(error)));
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/adapters/shared.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAI1D;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,IAAa;IAC3C,OAAO,CACL,OAAO,IAAI,KAAK,QAAQ;QACxB,IAAI,KAAK,IAAI;QACb,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QACnB,IAAgC,CAAC,MAAM,KAAK,gBAAgB,CAC9D,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAkB;IAC5C,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;IAC1C,OAAO,KAAK,IAAI,SAAS,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,IAA+B;IACtD,OAAO,SAAS,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/E,CAAC;AAED,MAAM,CAAC,MAAM,WAAW,GAA2B;IACjD,cAAc,EAAE,mBAAmB;IACnC,eAAe,EAAE,UAAU;IAC3B,UAAU,EAAE,YAAY;IACxB,mBAAmB,EAAE,IAAI;CAC1B,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,MAAiB,EACjB,IAAa,EACb,SAA6B,EAC7B,MAAmB,EACnB,KAA8C;IAE9C,IAAI,CAAC;QACH,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,MAAM,CAAC,mBAAmB,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,CAAC,EAAE,CAAC;YAC9E,IAAI,MAAM,CAAC,OAAO;gBAAE,OAAO;YAC3B,MAAM,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;QAC/B,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,OAAO;YAAE,MAAM,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;IACvD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,MAAM,CAAC,OAAO;YAAE,OAAO;QAC3B,IAAI,CAAC;YACH,MAAM,KAAK,CAAC,QAAQ,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACnD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO;QACT,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sse-error-event.d.ts","sourceRoot":"","sources":["../../src/adapters/sse-error-event.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,CASjE"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export function buildSseErrorEvent(error) {
|
|
2
|
+
const message = error instanceof Error ? error.message : 'Internal streaming error';
|
|
3
|
+
const timestamp = new Date().toISOString();
|
|
4
|
+
return {
|
|
5
|
+
type: 'status-update',
|
|
6
|
+
taskId: '',
|
|
7
|
+
status: { state: 'failed', timestamp, message },
|
|
8
|
+
timestamp,
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=sse-error-event.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sse-error-event.js","sourceRoot":"","sources":["../../src/adapters/sse-error-event.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,kBAAkB,CAAC,KAAc;IAC/C,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,0BAA0B,CAAC;IACpF,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC3C,OAAO;QACL,IAAI,EAAE,eAAe;QACrB,MAAM,EAAE,EAAE;QACV,MAAM,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE;QAC/C,SAAS;KACV,CAAC;AACJ,CAAC"}
|
package/dist/agent-card.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-card.d.ts","sourceRoot":"","sources":["../src/agent-card.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,IAAI,MAAM,EAAQ,MAAM,qBAAqB,CAAC;AACjE,OAAO,KAAK,EAAE,SAAS,EAAc,aAAa,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAExF,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IACxC,QAAQ,CAAC,EAAE,aAAa,CAAC;CAC1B;AAYD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,GAAG,SAAS,CAuBrF;AAED,MAAM,WAAW,uBAAuB;IACtC,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;CAChB;
|
|
1
|
+
{"version":3,"file":"agent-card.d.ts","sourceRoot":"","sources":["../src/agent-card.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,IAAI,MAAM,EAAQ,MAAM,qBAAqB,CAAC;AACjE,OAAO,KAAK,EAAE,SAAS,EAAc,aAAa,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAExF,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IACxC,QAAQ,CAAC,EAAE,aAAa,CAAC;CAC1B;AAYD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,GAAG,SAAS,CAuBrF;AAED,MAAM,WAAW,uBAAuB;IACtC,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;CAChB;AAkBD,wBAAgB,aAAa,CAC3B,IAAI,EAAE,SAAS,EACf,OAAO,EAAE,uBAAuB,GAC/B,SAAS,GAAG;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,CAKnC;AAED,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,SAAS,GAAG;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,EACxC,MAAM,EAAE,MAAM,GACb,OAAO,CAcT"}
|
package/dist/agent-card.js
CHANGED
|
@@ -29,9 +29,22 @@ export function generateAgentCard(agent, options) {
|
|
|
29
29
|
}
|
|
30
30
|
return card;
|
|
31
31
|
}
|
|
32
|
+
function sortedStringify(value) {
|
|
33
|
+
if (value === null || value === undefined || typeof value !== 'object') {
|
|
34
|
+
return JSON.stringify(value);
|
|
35
|
+
}
|
|
36
|
+
if (Array.isArray(value)) {
|
|
37
|
+
return `[${value.map((item) => sortedStringify(item)).join(',')}]`;
|
|
38
|
+
}
|
|
39
|
+
const sorted = Object.keys(value)
|
|
40
|
+
.sort((a, b) => a.localeCompare(b))
|
|
41
|
+
.map((key) => `${JSON.stringify(key)}:${sortedStringify(value[key])}`)
|
|
42
|
+
.join(',');
|
|
43
|
+
return `{${sorted}}`;
|
|
44
|
+
}
|
|
32
45
|
export function signAgentCard(card, options) {
|
|
33
46
|
const algorithm = options.algorithm ?? 'hmac-sha256';
|
|
34
|
-
const payload =
|
|
47
|
+
const payload = sortedStringify(card);
|
|
35
48
|
const signature = createHmac('sha256', options.secret).update(payload).digest('hex');
|
|
36
49
|
return { ...card, signature: `${algorithm}:${signature}` };
|
|
37
50
|
}
|
|
@@ -46,7 +59,7 @@ export function verifyAgentCardSignature(card, secret) {
|
|
|
46
59
|
if (algorithm !== 'hmac-sha256' || !sig)
|
|
47
60
|
return false;
|
|
48
61
|
const { signature: _, ...cardWithoutSig } = card;
|
|
49
|
-
const payload =
|
|
62
|
+
const payload = sortedStringify(cardWithoutSig);
|
|
50
63
|
const expected = createHmac('sha256', secret).update(payload).digest('hex');
|
|
51
64
|
const sigBuf = Buffer.from(sig, 'hex');
|
|
52
65
|
const expectedBuf = Buffer.from(expected, 'hex');
|
package/dist/agent-card.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-card.js","sourceRoot":"","sources":["../src/agent-card.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAU1D,SAAS,WAAW,CAAC,IAAU;IAC7B,OAAO;QACL,EAAE,EAAE,IAAI,CAAC,IAAI;QACb,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,UAAU,EAAE,CAAC,YAAY,EAAE,kBAAkB,CAAC;QAC9C,WAAW,EAAE,CAAC,YAAY,EAAE,kBAAkB,CAAC;KAChD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAa,EAAE,OAAyB;IACxE,MAAM,YAAY,GAAoB;QACpC,SAAS,EAAE,IAAI;QACf,iBAAiB,EAAE,KAAK;QACxB,GAAG,OAAO,CAAC,YAAY;KACxB,CAAC;IAEF,MAAM,IAAI,GAAc;QACtB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,WAAW,EAAE,KAAK,CAAC,MAAM,CAAC,WAAW;QACrC,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,OAAO,EAAE,KAAK;QACd,YAAY;QACZ,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC;QACpC,iBAAiB,EAAE,CAAC,YAAY,CAAC;QACjC,kBAAkB,EAAE,CAAC,YAAY,EAAE,kBAAkB,CAAC;KACvD,CAAC;IAEF,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACrB,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IACnC,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAOD,
|
|
1
|
+
{"version":3,"file":"agent-card.js","sourceRoot":"","sources":["../src/agent-card.ts"],"names":[],"mappings":"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"}
|
package/dist/client.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Tool } from '@cogitator-ai/types';
|
|
2
|
-
import type { AgentCard, ExtendedAgentCard, A2AMessage, A2ATask, A2AStreamEvent, A2AClientConfig, SendMessageConfiguration, TaskFilter, PushNotificationConfig } from './types.js';
|
|
2
|
+
import type { AgentCard, ExtendedAgentCard, A2AMessage, A2ATask, A2AStreamEvent, A2AClientConfig, SendMessageConfiguration, TaskFilter, PushNotificationConfig, TaskState } from './types.js';
|
|
3
3
|
export interface A2AToolOptions {
|
|
4
4
|
name?: string;
|
|
5
5
|
description?: string;
|
|
@@ -9,6 +9,16 @@ export interface A2AToolResult {
|
|
|
9
9
|
output: string;
|
|
10
10
|
success: boolean;
|
|
11
11
|
error?: string;
|
|
12
|
+
/** Remote task id, set when the task needs follow-up (e.g. input-required) */
|
|
13
|
+
taskId?: string;
|
|
14
|
+
/** Final state of the remote task */
|
|
15
|
+
state?: TaskState;
|
|
16
|
+
}
|
|
17
|
+
export interface A2ARequestOptions {
|
|
18
|
+
/** Cancels the request (and an in-flight stream) */
|
|
19
|
+
signal?: AbortSignal;
|
|
20
|
+
/** Overrides the client timeout for this request; for streams it is the idle timeout between events */
|
|
21
|
+
timeout?: number;
|
|
12
22
|
}
|
|
13
23
|
export declare class A2AClient {
|
|
14
24
|
private baseUrl;
|
|
@@ -19,11 +29,16 @@ export declare class A2AClient {
|
|
|
19
29
|
private cachedCard;
|
|
20
30
|
constructor(baseUrl: string, config?: A2AClientConfig);
|
|
21
31
|
agentCard(): Promise<AgentCard>;
|
|
22
|
-
|
|
23
|
-
|
|
32
|
+
refreshAgentCard(): Promise<AgentCard>;
|
|
33
|
+
sendMessage(message: A2AMessage, config?: SendMessageConfiguration, options?: A2ARequestOptions): Promise<A2ATask>;
|
|
34
|
+
/**
|
|
35
|
+
* Stream a message. The client timeout applies to the wait for the response
|
|
36
|
+
* and to the idle time between events, not to the total stream duration.
|
|
37
|
+
*/
|
|
38
|
+
sendMessageStream(message: A2AMessage, config?: SendMessageConfiguration, options?: A2ARequestOptions): AsyncGenerator<A2AStreamEvent>;
|
|
24
39
|
getTask(taskId: string, historyLength?: number): Promise<A2ATask>;
|
|
25
40
|
cancelTask(taskId: string): Promise<A2ATask>;
|
|
26
|
-
continueTask(taskId: string, text: string, config?: SendMessageConfiguration): Promise<A2ATask>;
|
|
41
|
+
continueTask(taskId: string, text: string, config?: SendMessageConfiguration, options?: A2ARequestOptions): Promise<A2ATask>;
|
|
27
42
|
listTasks(filter?: TaskFilter): Promise<A2ATask[]>;
|
|
28
43
|
asTool(options?: A2AToolOptions): Tool<{
|
|
29
44
|
task: string;
|
|
@@ -38,8 +53,13 @@ export declare class A2AClient {
|
|
|
38
53
|
task: string;
|
|
39
54
|
}, A2AToolResult>;
|
|
40
55
|
private rpc;
|
|
56
|
+
/**
|
|
57
|
+
* Surface a JSON-RPC error body when the server sent one with a non-2xx status
|
|
58
|
+
*/
|
|
59
|
+
private throwHttpError;
|
|
41
60
|
private httpGet;
|
|
42
61
|
private parseSSEStream;
|
|
62
|
+
private extractSseData;
|
|
43
63
|
private extractOutputFromTask;
|
|
44
64
|
private generateRequestId;
|
|
45
65
|
}
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAA2B,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/client.js
CHANGED
|
@@ -1,8 +1,23 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
1
2
|
import { z } from 'zod';
|
|
2
|
-
import {
|
|
3
|
+
import { isStreamFinalState } from './types.js';
|
|
3
4
|
import { A2AError } from './errors.js';
|
|
4
5
|
import * as errors from './errors.js';
|
|
5
6
|
import { verifyAgentCardSignature } from './agent-card.js';
|
|
7
|
+
function combineSignals(a, b) {
|
|
8
|
+
const controller = new AbortController();
|
|
9
|
+
for (const signal of [a, b]) {
|
|
10
|
+
if (signal.aborted) {
|
|
11
|
+
controller.abort(signal.reason);
|
|
12
|
+
return controller.signal;
|
|
13
|
+
}
|
|
14
|
+
signal.addEventListener('abort', () => controller.abort(signal.reason), {
|
|
15
|
+
once: true,
|
|
16
|
+
signal: controller.signal,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
return controller.signal;
|
|
20
|
+
}
|
|
6
21
|
export class A2AClient {
|
|
7
22
|
baseUrl;
|
|
8
23
|
headers;
|
|
@@ -21,63 +36,101 @@ export class A2AClient {
|
|
|
21
36
|
if (this.cachedCard)
|
|
22
37
|
return this.cachedCard;
|
|
23
38
|
const response = await this.httpGet(this.agentCardPath);
|
|
24
|
-
const data = await response.json();
|
|
39
|
+
const data = (await response.json());
|
|
40
|
+
let card;
|
|
25
41
|
if (Array.isArray(data)) {
|
|
26
42
|
if (data.length === 0) {
|
|
27
43
|
throw new A2AError(errors.internalError('Agent card response is empty array'));
|
|
28
44
|
}
|
|
29
|
-
|
|
45
|
+
card = data[0];
|
|
30
46
|
}
|
|
31
47
|
else {
|
|
32
|
-
|
|
48
|
+
card = data;
|
|
33
49
|
}
|
|
34
|
-
|
|
50
|
+
this.cachedCard = card;
|
|
51
|
+
return card;
|
|
35
52
|
}
|
|
36
|
-
async
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
53
|
+
async refreshAgentCard() {
|
|
54
|
+
this.cachedCard = null;
|
|
55
|
+
return this.agentCard();
|
|
56
|
+
}
|
|
57
|
+
async sendMessage(message, config, options) {
|
|
58
|
+
const result = await this.rpc('message/send', { message, configuration: config }, options);
|
|
41
59
|
return result;
|
|
42
60
|
}
|
|
43
|
-
|
|
61
|
+
/**
|
|
62
|
+
* Stream a message. The client timeout applies to the wait for the response
|
|
63
|
+
* and to the idle time between events, not to the total stream duration.
|
|
64
|
+
*/
|
|
65
|
+
async *sendMessageStream(message, config, options) {
|
|
44
66
|
const body = JSON.stringify({
|
|
45
67
|
jsonrpc: '2.0',
|
|
46
68
|
method: 'message/stream',
|
|
47
69
|
params: { message, configuration: config },
|
|
48
70
|
id: this.generateRequestId(),
|
|
49
71
|
});
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
72
|
+
const idleTimeout = options?.timeout ?? this.timeout;
|
|
73
|
+
const controller = new AbortController();
|
|
74
|
+
let timedOut = false;
|
|
75
|
+
let timer;
|
|
76
|
+
const armTimer = () => {
|
|
77
|
+
if (timer !== undefined)
|
|
78
|
+
clearTimeout(timer);
|
|
79
|
+
timer = setTimeout(() => {
|
|
80
|
+
timedOut = true;
|
|
81
|
+
controller.abort(new DOMException('A2A stream timed out', 'TimeoutError'));
|
|
82
|
+
}, idleTimeout);
|
|
83
|
+
};
|
|
84
|
+
const onExternalAbort = () => controller.abort(options?.signal?.reason);
|
|
85
|
+
if (options?.signal?.aborted)
|
|
86
|
+
onExternalAbort();
|
|
87
|
+
options?.signal?.addEventListener('abort', onExternalAbort, { once: true });
|
|
88
|
+
try {
|
|
89
|
+
armTimer();
|
|
90
|
+
const response = await fetch(`${this.baseUrl}${this.rpcPath}`, {
|
|
91
|
+
method: 'POST',
|
|
92
|
+
headers: {
|
|
93
|
+
'Content-Type': 'application/json',
|
|
94
|
+
Accept: 'text/event-stream',
|
|
95
|
+
...this.headers,
|
|
96
|
+
},
|
|
97
|
+
body,
|
|
98
|
+
signal: controller.signal,
|
|
99
|
+
});
|
|
100
|
+
if (!response.ok) {
|
|
101
|
+
await this.throwHttpError(response);
|
|
102
|
+
}
|
|
103
|
+
if (!response.body)
|
|
104
|
+
return;
|
|
105
|
+
yield* this.parseSSEStream(response.body, armTimer);
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
if (timedOut) {
|
|
109
|
+
throw new A2AError(errors.internalError(`Stream idle for more than ${idleTimeout}ms`));
|
|
110
|
+
}
|
|
111
|
+
throw error;
|
|
112
|
+
}
|
|
113
|
+
finally {
|
|
114
|
+
if (timer !== undefined)
|
|
115
|
+
clearTimeout(timer);
|
|
116
|
+
options?.signal?.removeEventListener('abort', onExternalAbort);
|
|
117
|
+
controller.abort();
|
|
62
118
|
}
|
|
63
|
-
if (!response.body)
|
|
64
|
-
return;
|
|
65
|
-
yield* this.parseSSEStream(response.body);
|
|
66
119
|
}
|
|
67
120
|
async getTask(taskId, historyLength) {
|
|
68
|
-
const result = await this.rpc('tasks/get', { id: taskId, historyLength });
|
|
121
|
+
const result = await this.rpc('tasks/get', historyLength === undefined ? { id: taskId } : { id: taskId, historyLength });
|
|
69
122
|
return result;
|
|
70
123
|
}
|
|
71
124
|
async cancelTask(taskId) {
|
|
72
125
|
const result = await this.rpc('tasks/cancel', { id: taskId });
|
|
73
126
|
return result;
|
|
74
127
|
}
|
|
75
|
-
async continueTask(taskId, text, config) {
|
|
128
|
+
async continueTask(taskId, text, config, options) {
|
|
76
129
|
return this.sendMessage({
|
|
77
130
|
role: 'user',
|
|
78
131
|
parts: [{ type: 'text', text }],
|
|
79
132
|
taskId,
|
|
80
|
-
}, config);
|
|
133
|
+
}, config, options);
|
|
81
134
|
}
|
|
82
135
|
async listTasks(filter) {
|
|
83
136
|
const result = (await this.rpc('tasks/list', filter ?? {}));
|
|
@@ -96,28 +149,36 @@ export class A2AClient {
|
|
|
96
149
|
parameters,
|
|
97
150
|
timeout: toolTimeout,
|
|
98
151
|
sideEffects: ['external'],
|
|
99
|
-
execute: async (params,
|
|
152
|
+
execute: async (params, context) => {
|
|
100
153
|
try {
|
|
101
154
|
const message = {
|
|
102
155
|
role: 'user',
|
|
103
156
|
parts: [{ type: 'text', text: params.task }],
|
|
104
157
|
};
|
|
105
|
-
const task = await this.sendMessage(message
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
158
|
+
const task = await this.sendMessage(message, undefined, {
|
|
159
|
+
signal: context?.signal,
|
|
160
|
+
timeout: toolTimeout,
|
|
161
|
+
});
|
|
162
|
+
const state = task.status.state;
|
|
163
|
+
const output = this.extractOutputFromTask(task);
|
|
164
|
+
if (state === 'completed') {
|
|
165
|
+
return { output, success: true, state };
|
|
109
166
|
}
|
|
110
|
-
if (
|
|
167
|
+
if (state === 'input-required') {
|
|
111
168
|
return {
|
|
112
|
-
output
|
|
169
|
+
output,
|
|
113
170
|
success: false,
|
|
114
|
-
error:
|
|
171
|
+
error: 'Remote agent requires more input to continue this task',
|
|
172
|
+
taskId: task.id,
|
|
173
|
+
state,
|
|
115
174
|
};
|
|
116
175
|
}
|
|
117
176
|
return {
|
|
118
|
-
output
|
|
177
|
+
output,
|
|
119
178
|
success: false,
|
|
120
|
-
error: `
|
|
179
|
+
error: task.status.message ?? `Remote task ended in state: ${state}`,
|
|
180
|
+
taskId: task.id,
|
|
181
|
+
state,
|
|
121
182
|
};
|
|
122
183
|
}
|
|
123
184
|
catch (error) {
|
|
@@ -173,13 +234,14 @@ export class A2AClient {
|
|
|
173
234
|
timeout: options?.timeout,
|
|
174
235
|
});
|
|
175
236
|
}
|
|
176
|
-
async rpc(method, params) {
|
|
237
|
+
async rpc(method, params, options) {
|
|
177
238
|
const body = JSON.stringify({
|
|
178
239
|
jsonrpc: '2.0',
|
|
179
240
|
method,
|
|
180
241
|
params,
|
|
181
242
|
id: this.generateRequestId(),
|
|
182
243
|
});
|
|
244
|
+
const timeoutSignal = AbortSignal.timeout(options?.timeout ?? this.timeout);
|
|
183
245
|
const response = await fetch(`${this.baseUrl}${this.rpcPath}`, {
|
|
184
246
|
method: 'POST',
|
|
185
247
|
headers: {
|
|
@@ -187,10 +249,10 @@ export class A2AClient {
|
|
|
187
249
|
...this.headers,
|
|
188
250
|
},
|
|
189
251
|
body,
|
|
190
|
-
signal:
|
|
252
|
+
signal: options?.signal ? combineSignals(options.signal, timeoutSignal) : timeoutSignal,
|
|
191
253
|
});
|
|
192
254
|
if (!response.ok) {
|
|
193
|
-
|
|
255
|
+
await this.throwHttpError(response);
|
|
194
256
|
}
|
|
195
257
|
const json = (await response.json());
|
|
196
258
|
if (json.error) {
|
|
@@ -198,17 +260,34 @@ export class A2AClient {
|
|
|
198
260
|
}
|
|
199
261
|
return json.result;
|
|
200
262
|
}
|
|
263
|
+
/**
|
|
264
|
+
* Surface a JSON-RPC error body when the server sent one with a non-2xx status
|
|
265
|
+
*/
|
|
266
|
+
async throwHttpError(response) {
|
|
267
|
+
const text = await response.text().catch(() => '');
|
|
268
|
+
try {
|
|
269
|
+
const parsed = JSON.parse(text);
|
|
270
|
+
if (parsed.error && typeof parsed.error.code === 'number') {
|
|
271
|
+
throw new A2AError(parsed.error);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
catch (error) {
|
|
275
|
+
if (error instanceof A2AError)
|
|
276
|
+
throw error;
|
|
277
|
+
}
|
|
278
|
+
throw new A2AError(errors.internalError(`HTTP ${response.status}: ${response.statusText}`));
|
|
279
|
+
}
|
|
201
280
|
async httpGet(path) {
|
|
202
281
|
const response = await fetch(`${this.baseUrl}${path}`, {
|
|
203
282
|
headers: this.headers,
|
|
204
283
|
signal: AbortSignal.timeout(this.timeout),
|
|
205
284
|
});
|
|
206
285
|
if (!response.ok) {
|
|
207
|
-
|
|
286
|
+
await this.throwHttpError(response);
|
|
208
287
|
}
|
|
209
288
|
return response;
|
|
210
289
|
}
|
|
211
|
-
async *parseSSEStream(body) {
|
|
290
|
+
async *parseSSEStream(body, onActivity) {
|
|
212
291
|
const reader = body.getReader();
|
|
213
292
|
const decoder = new TextDecoder();
|
|
214
293
|
let buffer = '';
|
|
@@ -217,64 +296,65 @@ export class A2AClient {
|
|
|
217
296
|
const { done, value } = await reader.read();
|
|
218
297
|
if (done)
|
|
219
298
|
break;
|
|
299
|
+
onActivity?.();
|
|
220
300
|
buffer += decoder.decode(value, { stream: true });
|
|
221
|
-
const
|
|
222
|
-
|
|
301
|
+
const pendingCarriageReturn = buffer.endsWith('\r');
|
|
302
|
+
const normalized = (pendingCarriageReturn ? buffer.slice(0, -1) : buffer).replace(/\r\n?/g, '\n');
|
|
303
|
+
const frames = normalized.split('\n\n');
|
|
304
|
+
buffer = (frames.pop() ?? '') + (pendingCarriageReturn ? '\r' : '');
|
|
223
305
|
for (const frame of frames) {
|
|
224
|
-
|
|
225
|
-
continue;
|
|
226
|
-
const lines = frame.split('\n');
|
|
227
|
-
const dataLines = [];
|
|
228
|
-
for (const line of lines) {
|
|
229
|
-
if (line.startsWith('data: ')) {
|
|
230
|
-
dataLines.push(line.slice(6));
|
|
231
|
-
}
|
|
232
|
-
else if (line.startsWith('data:')) {
|
|
233
|
-
dataLines.push(line.slice(5));
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
const data = dataLines.join('\n');
|
|
306
|
+
const data = this.extractSseData(frame);
|
|
237
307
|
if (!data || data === '[DONE]')
|
|
238
308
|
continue;
|
|
309
|
+
let event;
|
|
239
310
|
try {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
311
|
+
event = JSON.parse(data);
|
|
312
|
+
}
|
|
313
|
+
catch {
|
|
314
|
+
process.stderr.write(`[a2a] Failed to parse SSE event: ${data.slice(0, 200)}\n`);
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
yield event;
|
|
318
|
+
if (event.type === 'status-update' && isStreamFinalState(event.status.state)) {
|
|
319
|
+
return;
|
|
245
320
|
}
|
|
246
|
-
catch { }
|
|
247
321
|
}
|
|
248
322
|
}
|
|
249
323
|
}
|
|
250
324
|
finally {
|
|
325
|
+
await reader.cancel().catch(() => { });
|
|
251
326
|
reader.releaseLock();
|
|
252
327
|
}
|
|
253
328
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
return part.text;
|
|
260
|
-
}
|
|
329
|
+
extractSseData(frame) {
|
|
330
|
+
const dataLines = [];
|
|
331
|
+
for (const line of frame.split('\n')) {
|
|
332
|
+
if (line.startsWith('data:')) {
|
|
333
|
+
dataLines.push(line.slice(line.startsWith('data: ') ? 6 : 5));
|
|
261
334
|
}
|
|
262
335
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
336
|
+
return dataLines.join('\n');
|
|
337
|
+
}
|
|
338
|
+
extractOutputFromTask(task) {
|
|
339
|
+
const history = task.history ?? [];
|
|
340
|
+
for (let i = history.length - 1; i >= 0; i--) {
|
|
341
|
+
const msg = history[i];
|
|
342
|
+
if (msg.role === 'agent') {
|
|
343
|
+
const text = msg.parts.find((part) => part.type === 'text');
|
|
344
|
+
if (text)
|
|
345
|
+
return text.text;
|
|
272
346
|
}
|
|
273
347
|
}
|
|
274
|
-
|
|
348
|
+
const artifacts = task.artifacts ?? [];
|
|
349
|
+
for (let i = artifacts.length - 1; i >= 0; i--) {
|
|
350
|
+
const text = artifacts[i].parts.find((part) => part.type === 'text');
|
|
351
|
+
if (text)
|
|
352
|
+
return text.text;
|
|
353
|
+
}
|
|
354
|
+
return task.status.message ?? '';
|
|
275
355
|
}
|
|
276
356
|
generateRequestId() {
|
|
277
|
-
return `req_${
|
|
357
|
+
return `req_${randomUUID()}`;
|
|
278
358
|
}
|
|
279
359
|
}
|
|
280
360
|
//# sourceMappingURL=client.js.map
|