@dexto/server 1.2.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/LICENSE +44 -0
- package/dist/a2a/adapters/index.cjs +42 -0
- package/dist/a2a/adapters/index.d.ts +10 -0
- package/dist/a2a/adapters/index.d.ts.map +1 -0
- package/dist/a2a/adapters/index.js +12 -0
- package/dist/a2a/adapters/message.cjs +193 -0
- package/dist/a2a/adapters/message.d.ts +50 -0
- package/dist/a2a/adapters/message.d.ts.map +1 -0
- package/dist/a2a/adapters/message.js +167 -0
- package/dist/a2a/adapters/state.cjs +57 -0
- package/dist/a2a/adapters/state.d.ts +36 -0
- package/dist/a2a/adapters/state.d.ts.map +1 -0
- package/dist/a2a/adapters/state.js +32 -0
- package/dist/a2a/adapters/task-view.cjs +85 -0
- package/dist/a2a/adapters/task-view.d.ts +58 -0
- package/dist/a2a/adapters/task-view.d.ts.map +1 -0
- package/dist/a2a/adapters/task-view.js +60 -0
- package/dist/a2a/index.cjs +51 -0
- package/dist/a2a/index.d.ts +15 -0
- package/dist/a2a/index.d.ts.map +1 -0
- package/dist/a2a/index.js +30 -0
- package/dist/a2a/jsonrpc/index.cjs +38 -0
- package/dist/a2a/jsonrpc/index.d.ts +11 -0
- package/dist/a2a/jsonrpc/index.d.ts.map +1 -0
- package/dist/a2a/jsonrpc/index.js +10 -0
- package/dist/a2a/jsonrpc/methods.cjs +183 -0
- package/dist/a2a/jsonrpc/methods.d.ts +110 -0
- package/dist/a2a/jsonrpc/methods.d.ts.map +1 -0
- package/dist/a2a/jsonrpc/methods.js +159 -0
- package/dist/a2a/jsonrpc/server.cjs +199 -0
- package/dist/a2a/jsonrpc/server.d.ts +100 -0
- package/dist/a2a/jsonrpc/server.d.ts.map +1 -0
- package/dist/a2a/jsonrpc/server.js +175 -0
- package/dist/a2a/jsonrpc/types.cjs +47 -0
- package/dist/a2a/jsonrpc/types.d.ts +91 -0
- package/dist/a2a/jsonrpc/types.d.ts.map +1 -0
- package/dist/a2a/jsonrpc/types.js +21 -0
- package/dist/a2a/types.cjs +16 -0
- package/dist/a2a/types.d.ts +250 -0
- package/dist/a2a/types.d.ts.map +1 -0
- package/dist/a2a/types.js +0 -0
- package/dist/approval/approval-coordinator.cjs +87 -0
- package/dist/approval/approval-coordinator.d.ts +52 -0
- package/dist/approval/approval-coordinator.d.ts.map +1 -0
- package/dist/approval/approval-coordinator.js +63 -0
- package/dist/approval/manual-approval-handler.cjs +100 -0
- package/dist/approval/manual-approval-handler.d.ts +32 -0
- package/dist/approval/manual-approval-handler.d.ts.map +1 -0
- package/dist/approval/manual-approval-handler.js +76 -0
- package/dist/events/a2a-sse-subscriber.cjs +271 -0
- package/dist/events/a2a-sse-subscriber.d.ts +94 -0
- package/dist/events/a2a-sse-subscriber.d.ts.map +1 -0
- package/dist/events/a2a-sse-subscriber.js +247 -0
- package/dist/events/types.cjs +16 -0
- package/dist/events/types.d.ts +15 -0
- package/dist/events/types.d.ts.map +1 -0
- package/dist/events/types.js +0 -0
- package/dist/events/webhook-subscriber.cjs +301 -0
- package/dist/events/webhook-subscriber.d.ts +64 -0
- package/dist/events/webhook-subscriber.d.ts.map +1 -0
- package/dist/events/webhook-subscriber.js +269 -0
- package/dist/events/webhook-types.cjs +16 -0
- package/dist/events/webhook-types.d.ts +91 -0
- package/dist/events/webhook-types.d.ts.map +1 -0
- package/dist/events/webhook-types.js +0 -0
- package/dist/hono/__tests__/test-fixtures.cjs +236 -0
- package/dist/hono/__tests__/test-fixtures.d.ts +65 -0
- package/dist/hono/__tests__/test-fixtures.d.ts.map +1 -0
- package/dist/hono/__tests__/test-fixtures.js +197 -0
- package/dist/hono/index.cjs +166 -0
- package/dist/hono/index.d.ts +2783 -0
- package/dist/hono/index.d.ts.map +1 -0
- package/dist/hono/index.js +141 -0
- package/dist/hono/middleware/auth.cjs +75 -0
- package/dist/hono/middleware/auth.d.ts +3 -0
- package/dist/hono/middleware/auth.d.ts.map +1 -0
- package/dist/hono/middleware/auth.js +51 -0
- package/dist/hono/middleware/cors.cjs +57 -0
- package/dist/hono/middleware/cors.d.ts +9 -0
- package/dist/hono/middleware/cors.d.ts.map +1 -0
- package/dist/hono/middleware/cors.js +33 -0
- package/dist/hono/middleware/error.cjs +131 -0
- package/dist/hono/middleware/error.d.ts +5 -0
- package/dist/hono/middleware/error.d.ts.map +1 -0
- package/dist/hono/middleware/error.js +105 -0
- package/dist/hono/middleware/redaction.cjs +45 -0
- package/dist/hono/middleware/redaction.d.ts +4 -0
- package/dist/hono/middleware/redaction.d.ts.map +1 -0
- package/dist/hono/middleware/redaction.js +20 -0
- package/dist/hono/node/index.cjs +139 -0
- package/dist/hono/node/index.d.ts +19 -0
- package/dist/hono/node/index.d.ts.map +1 -0
- package/dist/hono/node/index.js +115 -0
- package/dist/hono/routes/a2a-jsonrpc.cjs +119 -0
- package/dist/hono/routes/a2a-jsonrpc.d.ts +46 -0
- package/dist/hono/routes/a2a-jsonrpc.d.ts.map +1 -0
- package/dist/hono/routes/a2a-jsonrpc.js +95 -0
- package/dist/hono/routes/a2a-tasks.cjs +315 -0
- package/dist/hono/routes/a2a-tasks.d.ts +530 -0
- package/dist/hono/routes/a2a-tasks.d.ts.map +1 -0
- package/dist/hono/routes/a2a-tasks.js +291 -0
- package/dist/hono/routes/a2a.cjs +36 -0
- package/dist/hono/routes/a2a.d.ts +4 -0
- package/dist/hono/routes/a2a.d.ts.map +1 -0
- package/dist/hono/routes/a2a.js +12 -0
- package/dist/hono/routes/agents.cjs +735 -0
- package/dist/hono/routes/agents.d.ts +650 -0
- package/dist/hono/routes/agents.d.ts.map +1 -0
- package/dist/hono/routes/agents.js +711 -0
- package/dist/hono/routes/approvals.cjs +125 -0
- package/dist/hono/routes/approvals.d.ts +89 -0
- package/dist/hono/routes/approvals.d.ts.map +1 -0
- package/dist/hono/routes/approvals.js +101 -0
- package/dist/hono/routes/greeting.cjs +60 -0
- package/dist/hono/routes/greeting.d.ts +19 -0
- package/dist/hono/routes/greeting.d.ts.map +1 -0
- package/dist/hono/routes/greeting.js +36 -0
- package/dist/hono/routes/health.cjs +45 -0
- package/dist/hono/routes/health.d.ts +17 -0
- package/dist/hono/routes/health.d.ts.map +1 -0
- package/dist/hono/routes/health.js +21 -0
- package/dist/hono/routes/llm.cjs +298 -0
- package/dist/hono/routes/llm.d.ts +294 -0
- package/dist/hono/routes/llm.d.ts.map +1 -0
- package/dist/hono/routes/llm.js +287 -0
- package/dist/hono/routes/mcp.cjs +356 -0
- package/dist/hono/routes/mcp.d.ts +246 -0
- package/dist/hono/routes/mcp.d.ts.map +1 -0
- package/dist/hono/routes/mcp.js +332 -0
- package/dist/hono/routes/memory.cjs +192 -0
- package/dist/hono/routes/memory.d.ts +146 -0
- package/dist/hono/routes/memory.d.ts.map +1 -0
- package/dist/hono/routes/memory.js +168 -0
- package/dist/hono/routes/messages.cjs +320 -0
- package/dist/hono/routes/messages.d.ts +163 -0
- package/dist/hono/routes/messages.d.ts.map +1 -0
- package/dist/hono/routes/messages.js +296 -0
- package/dist/hono/routes/prompts.cjs +228 -0
- package/dist/hono/routes/prompts.d.ts +150 -0
- package/dist/hono/routes/prompts.d.ts.map +1 -0
- package/dist/hono/routes/prompts.js +204 -0
- package/dist/hono/routes/resources.cjs +110 -0
- package/dist/hono/routes/resources.d.ts +76 -0
- package/dist/hono/routes/resources.d.ts.map +1 -0
- package/dist/hono/routes/resources.js +86 -0
- package/dist/hono/routes/search.cjs +109 -0
- package/dist/hono/routes/search.d.ts +137 -0
- package/dist/hono/routes/search.d.ts.map +1 -0
- package/dist/hono/routes/search.js +85 -0
- package/dist/hono/routes/sessions.cjs +366 -0
- package/dist/hono/routes/sessions.d.ts +229 -0
- package/dist/hono/routes/sessions.d.ts.map +1 -0
- package/dist/hono/routes/sessions.js +342 -0
- package/dist/hono/routes/webhooks.cjs +228 -0
- package/dist/hono/routes/webhooks.d.ts +127 -0
- package/dist/hono/routes/webhooks.d.ts.map +1 -0
- package/dist/hono/routes/webhooks.js +204 -0
- package/dist/hono/schemas/responses.cjs +276 -0
- package/dist/hono/schemas/responses.d.ts +1418 -0
- package/dist/hono/schemas/responses.d.ts.map +1 -0
- package/dist/hono/schemas/responses.js +227 -0
- package/dist/hono/types.cjs +16 -0
- package/dist/hono/types.d.ts +6 -0
- package/dist/hono/types.d.ts.map +1 -0
- package/dist/hono/types.js +0 -0
- package/dist/index.cjs +38 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/mcp/mcp-handler.cjs +145 -0
- package/dist/mcp/mcp-handler.d.ts +14 -0
- package/dist/mcp/mcp-handler.d.ts.map +1 -0
- package/dist/mcp/mcp-handler.js +118 -0
- package/package.json +59 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var manual_approval_handler_exports = {};
|
|
20
|
+
__export(manual_approval_handler_exports, {
|
|
21
|
+
createManualApprovalHandler: () => createManualApprovalHandler
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(manual_approval_handler_exports);
|
|
24
|
+
var import_core = require("@dexto/core");
|
|
25
|
+
function createManualApprovalHandler(coordinator) {
|
|
26
|
+
const pendingApprovals = /* @__PURE__ */ new Map();
|
|
27
|
+
const handleApproval = (request) => {
|
|
28
|
+
return new Promise((resolve) => {
|
|
29
|
+
const effectiveTimeout = request.timeout;
|
|
30
|
+
const timer = setTimeout(() => {
|
|
31
|
+
cleanup();
|
|
32
|
+
pendingApprovals.delete(request.approvalId);
|
|
33
|
+
const timeoutResponse = {
|
|
34
|
+
approvalId: request.approvalId,
|
|
35
|
+
status: import_core.ApprovalStatus.CANCELLED,
|
|
36
|
+
sessionId: request.sessionId,
|
|
37
|
+
reason: import_core.DenialReason.TIMEOUT,
|
|
38
|
+
message: `Approval request timed out after ${effectiveTimeout}ms`,
|
|
39
|
+
timeoutMs: effectiveTimeout
|
|
40
|
+
};
|
|
41
|
+
coordinator.emitResponse(timeoutResponse);
|
|
42
|
+
resolve(timeoutResponse);
|
|
43
|
+
}, effectiveTimeout);
|
|
44
|
+
let cleanupListener = null;
|
|
45
|
+
const cleanup = () => {
|
|
46
|
+
clearTimeout(timer);
|
|
47
|
+
if (cleanupListener) {
|
|
48
|
+
cleanupListener();
|
|
49
|
+
cleanupListener = null;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
const listener = (res) => {
|
|
53
|
+
if (res.approvalId === request.approvalId) {
|
|
54
|
+
cleanup();
|
|
55
|
+
pendingApprovals.delete(request.approvalId);
|
|
56
|
+
resolve(res);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
coordinator.on("approval:response", listener);
|
|
60
|
+
cleanupListener = () => coordinator.off("approval:response", listener);
|
|
61
|
+
pendingApprovals.set(request.approvalId, {
|
|
62
|
+
cleanup,
|
|
63
|
+
resolve,
|
|
64
|
+
request
|
|
65
|
+
});
|
|
66
|
+
coordinator.emitRequest(request);
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
const handler = Object.assign(handleApproval, {
|
|
70
|
+
cancel: (approvalId) => {
|
|
71
|
+
const pending = pendingApprovals.get(approvalId);
|
|
72
|
+
if (pending) {
|
|
73
|
+
pending.cleanup();
|
|
74
|
+
pendingApprovals.delete(approvalId);
|
|
75
|
+
const cancelResponse = {
|
|
76
|
+
approvalId,
|
|
77
|
+
status: import_core.ApprovalStatus.CANCELLED,
|
|
78
|
+
sessionId: pending.request.sessionId,
|
|
79
|
+
reason: import_core.DenialReason.SYSTEM_CANCELLED,
|
|
80
|
+
message: "Approval request was cancelled"
|
|
81
|
+
};
|
|
82
|
+
coordinator.emitResponse(cancelResponse);
|
|
83
|
+
pending.resolve(cancelResponse);
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
cancelAll: () => {
|
|
87
|
+
for (const [approvalId] of pendingApprovals) {
|
|
88
|
+
handler.cancel?.(approvalId);
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
getPending: () => {
|
|
92
|
+
return Array.from(pendingApprovals.keys());
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
return handler;
|
|
96
|
+
}
|
|
97
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
98
|
+
0 && (module.exports = {
|
|
99
|
+
createManualApprovalHandler
|
|
100
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ApprovalHandler } from '@dexto/core';
|
|
2
|
+
import type { ApprovalCoordinator } from './approval-coordinator.js';
|
|
3
|
+
/**
|
|
4
|
+
* Creates a manual approval handler that uses ApprovalCoordinator for server communication.
|
|
5
|
+
*
|
|
6
|
+
* This handler emits `approval:request` and waits for `approval:response` via the coordinator,
|
|
7
|
+
* enabling SSE-based approval flows where:
|
|
8
|
+
* 1. Handler emits approval:request → Coordinator → SSE endpoint forwards to client
|
|
9
|
+
* 2. Client sends decision via POST /api/approvals/{approvalId}
|
|
10
|
+
* 3. API route emits approval:response → Coordinator → Handler resolves
|
|
11
|
+
*
|
|
12
|
+
* The returned handler implements the optional cancellation methods (cancel, cancelAll, getPending)
|
|
13
|
+
* for managing pending approval requests.
|
|
14
|
+
*
|
|
15
|
+
* Timeouts are handled per-request using the timeout value from ApprovalRequest, which
|
|
16
|
+
* is set by ApprovalManager based on the request type (tool confirmation vs elicitation).
|
|
17
|
+
*
|
|
18
|
+
* @param coordinator The approval coordinator for request/response communication
|
|
19
|
+
* @returns ApprovalHandler with cancellation support
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const coordinator = new ApprovalCoordinator();
|
|
24
|
+
* const handler = createManualApprovalHandler(coordinator);
|
|
25
|
+
* agent.setApprovalHandler(handler);
|
|
26
|
+
*
|
|
27
|
+
* // Later, cancel a specific approval (if handler supports it)
|
|
28
|
+
* handler.cancel?.('approval-id-123');
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export declare function createManualApprovalHandler(coordinator: ApprovalCoordinator): ApprovalHandler;
|
|
32
|
+
//# sourceMappingURL=manual-approval-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manual-approval-handler.d.ts","sourceRoot":"","sources":["../../src/approval/manual-approval-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAqC,MAAM,aAAa,CAAC;AAEtF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAErE;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,2BAA2B,CAAC,WAAW,EAAE,mBAAmB,GAAG,eAAe,CAiH7F"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { ApprovalStatus, DenialReason } from "@dexto/core";
|
|
2
|
+
function createManualApprovalHandler(coordinator) {
|
|
3
|
+
const pendingApprovals = /* @__PURE__ */ new Map();
|
|
4
|
+
const handleApproval = (request) => {
|
|
5
|
+
return new Promise((resolve) => {
|
|
6
|
+
const effectiveTimeout = request.timeout;
|
|
7
|
+
const timer = setTimeout(() => {
|
|
8
|
+
cleanup();
|
|
9
|
+
pendingApprovals.delete(request.approvalId);
|
|
10
|
+
const timeoutResponse = {
|
|
11
|
+
approvalId: request.approvalId,
|
|
12
|
+
status: ApprovalStatus.CANCELLED,
|
|
13
|
+
sessionId: request.sessionId,
|
|
14
|
+
reason: DenialReason.TIMEOUT,
|
|
15
|
+
message: `Approval request timed out after ${effectiveTimeout}ms`,
|
|
16
|
+
timeoutMs: effectiveTimeout
|
|
17
|
+
};
|
|
18
|
+
coordinator.emitResponse(timeoutResponse);
|
|
19
|
+
resolve(timeoutResponse);
|
|
20
|
+
}, effectiveTimeout);
|
|
21
|
+
let cleanupListener = null;
|
|
22
|
+
const cleanup = () => {
|
|
23
|
+
clearTimeout(timer);
|
|
24
|
+
if (cleanupListener) {
|
|
25
|
+
cleanupListener();
|
|
26
|
+
cleanupListener = null;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
const listener = (res) => {
|
|
30
|
+
if (res.approvalId === request.approvalId) {
|
|
31
|
+
cleanup();
|
|
32
|
+
pendingApprovals.delete(request.approvalId);
|
|
33
|
+
resolve(res);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
coordinator.on("approval:response", listener);
|
|
37
|
+
cleanupListener = () => coordinator.off("approval:response", listener);
|
|
38
|
+
pendingApprovals.set(request.approvalId, {
|
|
39
|
+
cleanup,
|
|
40
|
+
resolve,
|
|
41
|
+
request
|
|
42
|
+
});
|
|
43
|
+
coordinator.emitRequest(request);
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
const handler = Object.assign(handleApproval, {
|
|
47
|
+
cancel: (approvalId) => {
|
|
48
|
+
const pending = pendingApprovals.get(approvalId);
|
|
49
|
+
if (pending) {
|
|
50
|
+
pending.cleanup();
|
|
51
|
+
pendingApprovals.delete(approvalId);
|
|
52
|
+
const cancelResponse = {
|
|
53
|
+
approvalId,
|
|
54
|
+
status: ApprovalStatus.CANCELLED,
|
|
55
|
+
sessionId: pending.request.sessionId,
|
|
56
|
+
reason: DenialReason.SYSTEM_CANCELLED,
|
|
57
|
+
message: "Approval request was cancelled"
|
|
58
|
+
};
|
|
59
|
+
coordinator.emitResponse(cancelResponse);
|
|
60
|
+
pending.resolve(cancelResponse);
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
cancelAll: () => {
|
|
64
|
+
for (const [approvalId] of pendingApprovals) {
|
|
65
|
+
handler.cancel?.(approvalId);
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
getPending: () => {
|
|
69
|
+
return Array.from(pendingApprovals.keys());
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
return handler;
|
|
73
|
+
}
|
|
74
|
+
export {
|
|
75
|
+
createManualApprovalHandler
|
|
76
|
+
};
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var a2a_sse_subscriber_exports = {};
|
|
20
|
+
__export(a2a_sse_subscriber_exports, {
|
|
21
|
+
A2ASseEventSubscriber: () => A2ASseEventSubscriber
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(a2a_sse_subscriber_exports);
|
|
24
|
+
var import_events = require("events");
|
|
25
|
+
var import_core2 = require("@dexto/core");
|
|
26
|
+
class A2ASseEventSubscriber {
|
|
27
|
+
connections = /* @__PURE__ */ new Map();
|
|
28
|
+
eventBus;
|
|
29
|
+
globalAbortController;
|
|
30
|
+
/**
|
|
31
|
+
* Subscribe to agent event bus.
|
|
32
|
+
* Sets up global event listeners that broadcast to all SSE connections.
|
|
33
|
+
*
|
|
34
|
+
* @param eventBus Agent event bus to subscribe to
|
|
35
|
+
*/
|
|
36
|
+
subscribe(eventBus) {
|
|
37
|
+
this.globalAbortController?.abort();
|
|
38
|
+
this.globalAbortController = new AbortController();
|
|
39
|
+
const { signal } = this.globalAbortController;
|
|
40
|
+
const MAX_SHARED_SIGNAL_LISTENERS = 20;
|
|
41
|
+
(0, import_events.setMaxListeners)(MAX_SHARED_SIGNAL_LISTENERS, signal);
|
|
42
|
+
this.eventBus = eventBus;
|
|
43
|
+
eventBus.on(
|
|
44
|
+
"llm:thinking",
|
|
45
|
+
(payload) => {
|
|
46
|
+
this.broadcastToTask(payload.sessionId, "task.thinking", {
|
|
47
|
+
taskId: payload.sessionId
|
|
48
|
+
});
|
|
49
|
+
},
|
|
50
|
+
{ signal }
|
|
51
|
+
);
|
|
52
|
+
eventBus.on(
|
|
53
|
+
"llm:chunk",
|
|
54
|
+
(payload) => {
|
|
55
|
+
this.broadcastToTask(payload.sessionId, "task.chunk", {
|
|
56
|
+
taskId: payload.sessionId,
|
|
57
|
+
type: payload.chunkType,
|
|
58
|
+
content: payload.content,
|
|
59
|
+
isComplete: payload.isComplete
|
|
60
|
+
});
|
|
61
|
+
},
|
|
62
|
+
{ signal }
|
|
63
|
+
);
|
|
64
|
+
eventBus.on(
|
|
65
|
+
"llm:tool-call",
|
|
66
|
+
(payload) => {
|
|
67
|
+
this.broadcastToTask(payload.sessionId, "task.toolCall", {
|
|
68
|
+
taskId: payload.sessionId,
|
|
69
|
+
toolName: payload.toolName,
|
|
70
|
+
args: payload.args,
|
|
71
|
+
callId: payload.callId
|
|
72
|
+
});
|
|
73
|
+
},
|
|
74
|
+
{ signal }
|
|
75
|
+
);
|
|
76
|
+
eventBus.on(
|
|
77
|
+
"llm:tool-result",
|
|
78
|
+
(payload) => {
|
|
79
|
+
const data = {
|
|
80
|
+
taskId: payload.sessionId,
|
|
81
|
+
toolName: payload.toolName,
|
|
82
|
+
callId: payload.callId,
|
|
83
|
+
success: payload.success,
|
|
84
|
+
sanitized: payload.sanitized
|
|
85
|
+
};
|
|
86
|
+
if (payload.rawResult !== void 0) {
|
|
87
|
+
data.rawResult = payload.rawResult;
|
|
88
|
+
}
|
|
89
|
+
this.broadcastToTask(payload.sessionId, "task.toolResult", data);
|
|
90
|
+
},
|
|
91
|
+
{ signal }
|
|
92
|
+
);
|
|
93
|
+
eventBus.on(
|
|
94
|
+
"llm:response",
|
|
95
|
+
(payload) => {
|
|
96
|
+
this.broadcastToTask(payload.sessionId, "task.message", {
|
|
97
|
+
taskId: payload.sessionId,
|
|
98
|
+
message: {
|
|
99
|
+
role: "agent",
|
|
100
|
+
content: [{ type: "text", text: payload.content }],
|
|
101
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
102
|
+
},
|
|
103
|
+
tokenUsage: payload.tokenUsage,
|
|
104
|
+
provider: payload.provider,
|
|
105
|
+
model: payload.model
|
|
106
|
+
});
|
|
107
|
+
},
|
|
108
|
+
{ signal }
|
|
109
|
+
);
|
|
110
|
+
eventBus.on(
|
|
111
|
+
"llm:error",
|
|
112
|
+
(payload) => {
|
|
113
|
+
this.broadcastToTask(payload.sessionId, "task.error", {
|
|
114
|
+
taskId: payload.sessionId,
|
|
115
|
+
error: {
|
|
116
|
+
message: payload.error.message,
|
|
117
|
+
recoverable: payload.recoverable
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
},
|
|
121
|
+
{ signal }
|
|
122
|
+
);
|
|
123
|
+
eventBus.on(
|
|
124
|
+
"session:reset",
|
|
125
|
+
(payload) => {
|
|
126
|
+
this.broadcastToTask(payload.sessionId, "task.reset", {
|
|
127
|
+
taskId: payload.sessionId
|
|
128
|
+
});
|
|
129
|
+
},
|
|
130
|
+
{ signal }
|
|
131
|
+
);
|
|
132
|
+
import_core2.logger.debug("A2ASseEventSubscriber subscribed to agent events");
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Create a new SSE stream for a specific task.
|
|
136
|
+
*
|
|
137
|
+
* Returns a ReadableStream that emits SSE events for the task.
|
|
138
|
+
*
|
|
139
|
+
* @param taskId Task/Session ID to stream events for
|
|
140
|
+
* @returns ReadableStream for SSE connection
|
|
141
|
+
*/
|
|
142
|
+
createStream(taskId) {
|
|
143
|
+
const connectionId = `${taskId}-${Date.now()}`;
|
|
144
|
+
return new ReadableStream({
|
|
145
|
+
start: (controller) => {
|
|
146
|
+
const connection = {
|
|
147
|
+
taskId,
|
|
148
|
+
controller,
|
|
149
|
+
abortController: new AbortController(),
|
|
150
|
+
connectedAt: Date.now()
|
|
151
|
+
};
|
|
152
|
+
this.connections.set(connectionId, connection);
|
|
153
|
+
import_core2.logger.debug(`SSE connection opened for task ${taskId}`);
|
|
154
|
+
this.sendSSEEvent(controller, "connected", {
|
|
155
|
+
taskId,
|
|
156
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
157
|
+
});
|
|
158
|
+
const keepaliveInterval = setInterval(() => {
|
|
159
|
+
try {
|
|
160
|
+
this.sendSSEComment(controller, "keepalive");
|
|
161
|
+
} catch (_error) {
|
|
162
|
+
clearInterval(keepaliveInterval);
|
|
163
|
+
}
|
|
164
|
+
}, 3e4);
|
|
165
|
+
connection.abortController.signal.addEventListener("abort", () => {
|
|
166
|
+
clearInterval(keepaliveInterval);
|
|
167
|
+
});
|
|
168
|
+
},
|
|
169
|
+
cancel: () => {
|
|
170
|
+
const connection = this.connections.get(connectionId);
|
|
171
|
+
if (connection) {
|
|
172
|
+
connection.abortController.abort();
|
|
173
|
+
this.connections.delete(connectionId);
|
|
174
|
+
import_core2.logger.debug(`SSE connection closed for task ${taskId}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Broadcast an event to a specific task's SSE connections.
|
|
181
|
+
*
|
|
182
|
+
* @param taskId Task ID to broadcast to
|
|
183
|
+
* @param eventName SSE event name
|
|
184
|
+
* @param data Event data
|
|
185
|
+
*/
|
|
186
|
+
broadcastToTask(taskId, eventName, data) {
|
|
187
|
+
let sent = 0;
|
|
188
|
+
for (const [connectionId, connection] of this.connections.entries()) {
|
|
189
|
+
if (connection.taskId === taskId) {
|
|
190
|
+
try {
|
|
191
|
+
this.sendSSEEvent(connection.controller, eventName, data);
|
|
192
|
+
sent++;
|
|
193
|
+
} catch (error) {
|
|
194
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
195
|
+
import_core2.logger.warn(`Failed to send SSE event to ${connectionId}: ${errorMessage}`);
|
|
196
|
+
connection.abortController.abort();
|
|
197
|
+
this.connections.delete(connectionId);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
if (sent > 0) {
|
|
202
|
+
import_core2.logger.debug(`Broadcast ${eventName} to ${sent} SSE connection(s) for task ${taskId}`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Send an SSE event to a specific controller.
|
|
207
|
+
*
|
|
208
|
+
* Format: event: name\ndata: json\n\n
|
|
209
|
+
*
|
|
210
|
+
* @param controller Stream controller
|
|
211
|
+
* @param eventName Event name
|
|
212
|
+
* @param data Event data
|
|
213
|
+
*/
|
|
214
|
+
sendSSEEvent(controller, eventName, data) {
|
|
215
|
+
const event = `event: ${eventName}
|
|
216
|
+
data: ${JSON.stringify(data)}
|
|
217
|
+
|
|
218
|
+
`;
|
|
219
|
+
controller.enqueue(new TextEncoder().encode(event));
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Send an SSE comment (for keepalive).
|
|
223
|
+
*
|
|
224
|
+
* Format: : comment\n
|
|
225
|
+
*
|
|
226
|
+
* @param controller Stream controller
|
|
227
|
+
* @param comment Comment text
|
|
228
|
+
*/
|
|
229
|
+
sendSSEComment(controller, comment) {
|
|
230
|
+
const line = `: ${comment}
|
|
231
|
+
`;
|
|
232
|
+
controller.enqueue(new TextEncoder().encode(line));
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Close all connections and cleanup.
|
|
236
|
+
*/
|
|
237
|
+
cleanup() {
|
|
238
|
+
import_core2.logger.debug(`Cleaning up ${this.connections.size} SSE connections`);
|
|
239
|
+
for (const [_connectionId, connection] of this.connections.entries()) {
|
|
240
|
+
connection.abortController.abort();
|
|
241
|
+
try {
|
|
242
|
+
connection.controller.close();
|
|
243
|
+
} catch (_error) {
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
this.connections.clear();
|
|
247
|
+
this.globalAbortController?.abort();
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Get active connection count.
|
|
251
|
+
*/
|
|
252
|
+
getConnectionCount() {
|
|
253
|
+
return this.connections.size;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Get connection count for a specific task.
|
|
257
|
+
*/
|
|
258
|
+
getTaskConnectionCount(taskId) {
|
|
259
|
+
let count = 0;
|
|
260
|
+
for (const connection of this.connections.values()) {
|
|
261
|
+
if (connection.taskId === taskId) {
|
|
262
|
+
count++;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return count;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
269
|
+
0 && (module.exports = {
|
|
270
|
+
A2ASseEventSubscriber
|
|
271
|
+
});
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A2A SSE (Server-Sent Events) Event Subscriber
|
|
3
|
+
*
|
|
4
|
+
* Subscribes to agent events and streams them to SSE clients for A2A tasks.
|
|
5
|
+
* Uses standard SSE protocol (text/event-stream).
|
|
6
|
+
*
|
|
7
|
+
* Design:
|
|
8
|
+
* - Filters events by taskId/sessionId for targeted streaming
|
|
9
|
+
* - Uses standard SSE format: event: name\ndata: json\n\n
|
|
10
|
+
* - Supports multiple concurrent SSE connections
|
|
11
|
+
*/
|
|
12
|
+
import { AgentEventBus } from '@dexto/core';
|
|
13
|
+
/**
|
|
14
|
+
* A2A SSE Event Subscriber
|
|
15
|
+
*
|
|
16
|
+
* Manages Server-Sent Events connections for A2A Protocol task streaming.
|
|
17
|
+
*
|
|
18
|
+
* Usage:
|
|
19
|
+
* ```typescript
|
|
20
|
+
* const sseSubscriber = new A2ASseEventSubscriber();
|
|
21
|
+
* sseSubscriber.subscribe(agent.agentEventBus);
|
|
22
|
+
*
|
|
23
|
+
* // In route handler
|
|
24
|
+
* const stream = sseSubscriber.createStream(taskId);
|
|
25
|
+
* return new Response(stream, {
|
|
26
|
+
* headers: {
|
|
27
|
+
* 'Content-Type': 'text/event-stream',
|
|
28
|
+
* 'Cache-Control': 'no-cache',
|
|
29
|
+
* 'Connection': 'keep-alive'
|
|
30
|
+
* }
|
|
31
|
+
* });
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare class A2ASseEventSubscriber {
|
|
35
|
+
private connections;
|
|
36
|
+
private eventBus?;
|
|
37
|
+
private globalAbortController?;
|
|
38
|
+
/**
|
|
39
|
+
* Subscribe to agent event bus.
|
|
40
|
+
* Sets up global event listeners that broadcast to all SSE connections.
|
|
41
|
+
*
|
|
42
|
+
* @param eventBus Agent event bus to subscribe to
|
|
43
|
+
*/
|
|
44
|
+
subscribe(eventBus: AgentEventBus): void;
|
|
45
|
+
/**
|
|
46
|
+
* Create a new SSE stream for a specific task.
|
|
47
|
+
*
|
|
48
|
+
* Returns a ReadableStream that emits SSE events for the task.
|
|
49
|
+
*
|
|
50
|
+
* @param taskId Task/Session ID to stream events for
|
|
51
|
+
* @returns ReadableStream for SSE connection
|
|
52
|
+
*/
|
|
53
|
+
createStream(taskId: string): ReadableStream<Uint8Array>;
|
|
54
|
+
/**
|
|
55
|
+
* Broadcast an event to a specific task's SSE connections.
|
|
56
|
+
*
|
|
57
|
+
* @param taskId Task ID to broadcast to
|
|
58
|
+
* @param eventName SSE event name
|
|
59
|
+
* @param data Event data
|
|
60
|
+
*/
|
|
61
|
+
private broadcastToTask;
|
|
62
|
+
/**
|
|
63
|
+
* Send an SSE event to a specific controller.
|
|
64
|
+
*
|
|
65
|
+
* Format: event: name\ndata: json\n\n
|
|
66
|
+
*
|
|
67
|
+
* @param controller Stream controller
|
|
68
|
+
* @param eventName Event name
|
|
69
|
+
* @param data Event data
|
|
70
|
+
*/
|
|
71
|
+
private sendSSEEvent;
|
|
72
|
+
/**
|
|
73
|
+
* Send an SSE comment (for keepalive).
|
|
74
|
+
*
|
|
75
|
+
* Format: : comment\n
|
|
76
|
+
*
|
|
77
|
+
* @param controller Stream controller
|
|
78
|
+
* @param comment Comment text
|
|
79
|
+
*/
|
|
80
|
+
private sendSSEComment;
|
|
81
|
+
/**
|
|
82
|
+
* Close all connections and cleanup.
|
|
83
|
+
*/
|
|
84
|
+
cleanup(): void;
|
|
85
|
+
/**
|
|
86
|
+
* Get active connection count.
|
|
87
|
+
*/
|
|
88
|
+
getConnectionCount(): number;
|
|
89
|
+
/**
|
|
90
|
+
* Get connection count for a specific task.
|
|
91
|
+
*/
|
|
92
|
+
getTaskConnectionCount(taskId: string): number;
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=a2a-sse-subscriber.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"a2a-sse-subscriber.d.ts","sourceRoot":"","sources":["../../src/events/a2a-sse-subscriber.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAiB5C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,qBAAqB;IAC9B,OAAO,CAAC,WAAW,CAAyC;IAC5D,OAAO,CAAC,QAAQ,CAAC,CAAgB;IACjC,OAAO,CAAC,qBAAqB,CAAC,CAAkB;IAEhD;;;;;OAKG;IACH,SAAS,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI;IAkHxC;;;;;;;OAOG;IACH,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CAAC,UAAU,CAAC;IAiDxD;;;;;;OAMG;IACH,OAAO,CAAC,eAAe;IA0BvB;;;;;;;;OAQG;IACH,OAAO,CAAC,YAAY;IASpB;;;;;;;OAOG;IACH,OAAO,CAAC,cAAc;IAKtB;;OAEG;IACH,OAAO,IAAI,IAAI;IAgBf;;OAEG;IACH,kBAAkB,IAAI,MAAM;IAI5B;;OAEG;IACH,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;CASjD"}
|