agenthub-multiagent-mcp 1.1.5 → 1.3.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/dist/client.d.ts +99 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +69 -1
- package/dist/client.js.map +1 -1
- package/dist/heartbeat.d.ts +16 -0
- package/dist/heartbeat.d.ts.map +1 -1
- package/dist/heartbeat.js +97 -26
- package/dist/heartbeat.js.map +1 -1
- package/dist/index.js +68 -4
- package/dist/index.js.map +1 -1
- package/dist/tools/index.d.ts +15 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +228 -48
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/tools.test.js +7 -1
- package/dist/tools/tools.test.js.map +1 -1
- package/dist/websocket.d.ts +66 -0
- package/dist/websocket.d.ts.map +1 -0
- package/dist/websocket.js +196 -0
- package/dist/websocket.js.map +1 -0
- package/package.json +4 -1
- package/src/client.ts +190 -2
- package/src/heartbeat.ts +108 -25
- package/src/index.ts +77 -4
- package/src/tools/index.ts +269 -60
- package/src/tools/tools.test.ts +7 -1
- package/src/websocket.ts +237 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebSocket client for real-time push notifications from AgentHub server.
|
|
3
|
+
*
|
|
4
|
+
* Receives pushed tasks and messages and stores them in a queue
|
|
5
|
+
* for inclusion in tool responses.
|
|
6
|
+
*/
|
|
7
|
+
import type { Message, PendingTask } from "./client.js";
|
|
8
|
+
export interface WSMessage {
|
|
9
|
+
type: "task" | "message" | "ping" | "pong" | "ack";
|
|
10
|
+
timestamp: string;
|
|
11
|
+
task?: PendingTask;
|
|
12
|
+
message?: Message;
|
|
13
|
+
data?: unknown;
|
|
14
|
+
}
|
|
15
|
+
export interface PushedItems {
|
|
16
|
+
tasks: PendingTask[];
|
|
17
|
+
messages: Message[];
|
|
18
|
+
}
|
|
19
|
+
export declare class WebSocketClient {
|
|
20
|
+
private ws;
|
|
21
|
+
private baseUrl;
|
|
22
|
+
private apiKey;
|
|
23
|
+
private agentId;
|
|
24
|
+
private reconnectAttempts;
|
|
25
|
+
private maxReconnectAttempts;
|
|
26
|
+
private reconnectDelay;
|
|
27
|
+
private reconnectTimer;
|
|
28
|
+
private isConnecting;
|
|
29
|
+
private isClosing;
|
|
30
|
+
private pushedTasks;
|
|
31
|
+
private pushedMessages;
|
|
32
|
+
constructor(baseUrl: string, apiKey: string);
|
|
33
|
+
/**
|
|
34
|
+
* Connect to WebSocket for a specific agent
|
|
35
|
+
*/
|
|
36
|
+
connect(agentId: string): void;
|
|
37
|
+
/**
|
|
38
|
+
* Handle incoming WebSocket message
|
|
39
|
+
*/
|
|
40
|
+
private handleMessage;
|
|
41
|
+
/**
|
|
42
|
+
* Send acknowledgment for received item
|
|
43
|
+
*/
|
|
44
|
+
private sendAck;
|
|
45
|
+
/**
|
|
46
|
+
* Send a message over WebSocket
|
|
47
|
+
*/
|
|
48
|
+
private send;
|
|
49
|
+
/**
|
|
50
|
+
* Schedule reconnection with exponential backoff
|
|
51
|
+
*/
|
|
52
|
+
private scheduleReconnect;
|
|
53
|
+
/**
|
|
54
|
+
* Get and clear pushed items
|
|
55
|
+
*/
|
|
56
|
+
getPushedItems(): PushedItems;
|
|
57
|
+
/**
|
|
58
|
+
* Check if connected
|
|
59
|
+
*/
|
|
60
|
+
isConnected(): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Close the WebSocket connection
|
|
63
|
+
*/
|
|
64
|
+
close(): void;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=websocket.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websocket.d.ts","sourceRoot":"","sources":["../src/websocket.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAExD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;IACnD,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,oBAAoB,CAAK;IACjC,OAAO,CAAC,cAAc,CAAQ;IAC9B,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,SAAS,CAAS;IAG1B,OAAO,CAAC,WAAW,CAAqB;IACxC,OAAO,CAAC,cAAc,CAAiB;gBAE3B,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAS3C;;OAEG;IACH,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAiD9B;;OAEG;IACH,OAAO,CAAC,aAAa;IA+BrB;;OAEG;IACH,OAAO,CAAC,OAAO;IAQf;;OAEG;IACH,OAAO,CAAC,IAAI;IAUZ;;OAEG;IACH,OAAO,CAAC,iBAAiB;IA0BzB;;OAEG;IACH,cAAc,IAAI,WAAW;IAa7B;;OAEG;IACH,WAAW,IAAI,OAAO;IAItB;;OAEG;IACH,KAAK,IAAI,IAAI;CAuBd"}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebSocket client for real-time push notifications from AgentHub server.
|
|
3
|
+
*
|
|
4
|
+
* Receives pushed tasks and messages and stores them in a queue
|
|
5
|
+
* for inclusion in tool responses.
|
|
6
|
+
*/
|
|
7
|
+
import WebSocket from "ws";
|
|
8
|
+
export class WebSocketClient {
|
|
9
|
+
ws = null;
|
|
10
|
+
baseUrl;
|
|
11
|
+
apiKey;
|
|
12
|
+
agentId = null;
|
|
13
|
+
reconnectAttempts = 0;
|
|
14
|
+
maxReconnectAttempts = 5;
|
|
15
|
+
reconnectDelay = 1000; // Start with 1 second
|
|
16
|
+
reconnectTimer = null;
|
|
17
|
+
isConnecting = false;
|
|
18
|
+
isClosing = false;
|
|
19
|
+
// Queue for pushed items
|
|
20
|
+
pushedTasks = [];
|
|
21
|
+
pushedMessages = [];
|
|
22
|
+
constructor(baseUrl, apiKey) {
|
|
23
|
+
// Convert HTTP URL to WebSocket URL
|
|
24
|
+
this.baseUrl = baseUrl
|
|
25
|
+
.replace(/^https:/, "wss:")
|
|
26
|
+
.replace(/^http:/, "ws:")
|
|
27
|
+
.replace(/\/$/, "");
|
|
28
|
+
this.apiKey = apiKey;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Connect to WebSocket for a specific agent
|
|
32
|
+
*/
|
|
33
|
+
connect(agentId) {
|
|
34
|
+
if (this.isConnecting || (this.ws && this.ws.readyState === WebSocket.OPEN)) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
this.agentId = agentId;
|
|
38
|
+
this.isConnecting = true;
|
|
39
|
+
this.isClosing = false;
|
|
40
|
+
const url = `${this.baseUrl}/ws/agents/${agentId}?api_key=${encodeURIComponent(this.apiKey)}`;
|
|
41
|
+
try {
|
|
42
|
+
this.ws = new WebSocket(url);
|
|
43
|
+
this.ws.on("open", () => {
|
|
44
|
+
this.isConnecting = false;
|
|
45
|
+
this.reconnectAttempts = 0;
|
|
46
|
+
this.reconnectDelay = 1000;
|
|
47
|
+
console.error(`[AgentHub] WebSocket connected for agent: ${agentId}`);
|
|
48
|
+
});
|
|
49
|
+
this.ws.on("message", (data) => {
|
|
50
|
+
try {
|
|
51
|
+
const msg = JSON.parse(data.toString());
|
|
52
|
+
this.handleMessage(msg);
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
console.error("[AgentHub] Failed to parse WebSocket message:", error);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
this.ws.on("close", () => {
|
|
59
|
+
this.isConnecting = false;
|
|
60
|
+
if (!this.isClosing) {
|
|
61
|
+
console.error("[AgentHub] WebSocket disconnected, will reconnect...");
|
|
62
|
+
this.scheduleReconnect();
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
this.ws.on("error", (error) => {
|
|
66
|
+
this.isConnecting = false;
|
|
67
|
+
console.error("[AgentHub] WebSocket error:", error.message);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
this.isConnecting = false;
|
|
72
|
+
console.error("[AgentHub] Failed to create WebSocket:", error);
|
|
73
|
+
this.scheduleReconnect();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Handle incoming WebSocket message
|
|
78
|
+
*/
|
|
79
|
+
handleMessage(msg) {
|
|
80
|
+
switch (msg.type) {
|
|
81
|
+
case "task":
|
|
82
|
+
if (msg.task) {
|
|
83
|
+
console.error(`[AgentHub] Received pushed task: ${msg.task.id}`);
|
|
84
|
+
this.pushedTasks.push(msg.task);
|
|
85
|
+
// Send ack
|
|
86
|
+
this.sendAck(msg.task.id);
|
|
87
|
+
}
|
|
88
|
+
break;
|
|
89
|
+
case "message":
|
|
90
|
+
if (msg.message) {
|
|
91
|
+
console.error(`[AgentHub] Received pushed message: ${msg.message.id}`);
|
|
92
|
+
this.pushedMessages.push(msg.message);
|
|
93
|
+
// Send ack
|
|
94
|
+
this.sendAck(msg.message.id);
|
|
95
|
+
}
|
|
96
|
+
break;
|
|
97
|
+
case "ping":
|
|
98
|
+
// Respond with pong
|
|
99
|
+
this.send({ type: "pong", timestamp: new Date().toISOString() });
|
|
100
|
+
break;
|
|
101
|
+
default:
|
|
102
|
+
// Ignore other message types
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Send acknowledgment for received item
|
|
108
|
+
*/
|
|
109
|
+
sendAck(itemId) {
|
|
110
|
+
this.send({
|
|
111
|
+
type: "ack",
|
|
112
|
+
timestamp: new Date().toISOString(),
|
|
113
|
+
data: { id: itemId },
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Send a message over WebSocket
|
|
118
|
+
*/
|
|
119
|
+
send(msg) {
|
|
120
|
+
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
121
|
+
try {
|
|
122
|
+
this.ws.send(JSON.stringify(msg));
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
console.error("[AgentHub] Failed to send WebSocket message:", error);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Schedule reconnection with exponential backoff
|
|
131
|
+
*/
|
|
132
|
+
scheduleReconnect() {
|
|
133
|
+
if (this.isClosing || !this.agentId) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
if (this.reconnectAttempts >= this.maxReconnectAttempts) {
|
|
137
|
+
console.error("[AgentHub] Max reconnect attempts reached, giving up");
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
if (this.reconnectTimer) {
|
|
141
|
+
clearTimeout(this.reconnectTimer);
|
|
142
|
+
}
|
|
143
|
+
this.reconnectTimer = setTimeout(() => {
|
|
144
|
+
this.reconnectAttempts++;
|
|
145
|
+
console.error(`[AgentHub] Reconnect attempt ${this.reconnectAttempts}/${this.maxReconnectAttempts}`);
|
|
146
|
+
if (this.agentId) {
|
|
147
|
+
this.connect(this.agentId);
|
|
148
|
+
}
|
|
149
|
+
}, this.reconnectDelay);
|
|
150
|
+
// Exponential backoff with max of 30 seconds
|
|
151
|
+
this.reconnectDelay = Math.min(this.reconnectDelay * 2, 30000);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Get and clear pushed items
|
|
155
|
+
*/
|
|
156
|
+
getPushedItems() {
|
|
157
|
+
const items = {
|
|
158
|
+
tasks: [...this.pushedTasks],
|
|
159
|
+
messages: [...this.pushedMessages],
|
|
160
|
+
};
|
|
161
|
+
// Clear the queues
|
|
162
|
+
this.pushedTasks = [];
|
|
163
|
+
this.pushedMessages = [];
|
|
164
|
+
return items;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Check if connected
|
|
168
|
+
*/
|
|
169
|
+
isConnected() {
|
|
170
|
+
return this.ws !== null && this.ws.readyState === WebSocket.OPEN;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Close the WebSocket connection
|
|
174
|
+
*/
|
|
175
|
+
close() {
|
|
176
|
+
this.isClosing = true;
|
|
177
|
+
if (this.reconnectTimer) {
|
|
178
|
+
clearTimeout(this.reconnectTimer);
|
|
179
|
+
this.reconnectTimer = null;
|
|
180
|
+
}
|
|
181
|
+
if (this.ws) {
|
|
182
|
+
try {
|
|
183
|
+
this.ws.close();
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
// Ignore close errors
|
|
187
|
+
}
|
|
188
|
+
this.ws = null;
|
|
189
|
+
}
|
|
190
|
+
this.agentId = null;
|
|
191
|
+
this.pushedTasks = [];
|
|
192
|
+
this.pushedMessages = [];
|
|
193
|
+
console.error("[AgentHub] WebSocket closed");
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
//# sourceMappingURL=websocket.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websocket.js","sourceRoot":"","sources":["../src/websocket.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agenthub-multiagent-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "MCP server for AgentHub multi-agent communication",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -39,10 +39,13 @@
|
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
42
|
+
"open": "^11.0.0",
|
|
43
|
+
"ws": "^8.18.0",
|
|
42
44
|
"zod": "^3.23.0"
|
|
43
45
|
},
|
|
44
46
|
"devDependencies": {
|
|
45
47
|
"@types/node": "^20.0.0",
|
|
48
|
+
"@types/ws": "^8.5.13",
|
|
46
49
|
"tsx": "^4.0.0",
|
|
47
50
|
"typescript": "^5.0.0",
|
|
48
51
|
"vitest": "^4.0.16"
|
package/src/client.ts
CHANGED
|
@@ -28,6 +28,76 @@ export interface PendingTask {
|
|
|
28
28
|
created_at: string;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
// Ticket system types
|
|
32
|
+
export interface TicketTask {
|
|
33
|
+
id: string;
|
|
34
|
+
org_id: string;
|
|
35
|
+
project_id: string;
|
|
36
|
+
epic_id?: string;
|
|
37
|
+
story_id?: string;
|
|
38
|
+
key: string;
|
|
39
|
+
type: string;
|
|
40
|
+
title: string;
|
|
41
|
+
description?: string;
|
|
42
|
+
status: string;
|
|
43
|
+
priority: string;
|
|
44
|
+
points?: number;
|
|
45
|
+
review_mode: string;
|
|
46
|
+
assignee_id?: string;
|
|
47
|
+
assigned_agent?: string;
|
|
48
|
+
claimed_by?: string;
|
|
49
|
+
labels?: string[];
|
|
50
|
+
sprint_id?: string;
|
|
51
|
+
due_date?: string;
|
|
52
|
+
created_by: string;
|
|
53
|
+
created_at: string;
|
|
54
|
+
updated_at: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface TicketTaskContext {
|
|
58
|
+
task: TicketTask;
|
|
59
|
+
story?: {
|
|
60
|
+
id: string;
|
|
61
|
+
title: string;
|
|
62
|
+
description?: string;
|
|
63
|
+
status: string;
|
|
64
|
+
};
|
|
65
|
+
epic?: {
|
|
66
|
+
id: string;
|
|
67
|
+
title: string;
|
|
68
|
+
description?: string;
|
|
69
|
+
status: string;
|
|
70
|
+
};
|
|
71
|
+
project?: {
|
|
72
|
+
id: string;
|
|
73
|
+
key: string;
|
|
74
|
+
name: string;
|
|
75
|
+
description?: string;
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface TaskCheckpoint {
|
|
80
|
+
id: string;
|
|
81
|
+
task_id: string;
|
|
82
|
+
task_key: string;
|
|
83
|
+
agent_id: string;
|
|
84
|
+
description: string;
|
|
85
|
+
status: string;
|
|
86
|
+
reviewed_by?: string;
|
|
87
|
+
review_notes?: string;
|
|
88
|
+
reviewed_at?: string;
|
|
89
|
+
created_at: string;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export interface CheckpointResponse {
|
|
93
|
+
id: string;
|
|
94
|
+
task_id: string;
|
|
95
|
+
task_key: string;
|
|
96
|
+
status: string;
|
|
97
|
+
slack_posted: boolean;
|
|
98
|
+
created_at: string;
|
|
99
|
+
}
|
|
100
|
+
|
|
31
101
|
export interface TaskCompletionResponse {
|
|
32
102
|
task_id: string;
|
|
33
103
|
elapsed_time: string;
|
|
@@ -150,11 +220,19 @@ export class ApiClient {
|
|
|
150
220
|
async startWork(
|
|
151
221
|
agentId: string,
|
|
152
222
|
task: string,
|
|
153
|
-
project?: string
|
|
154
|
-
|
|
223
|
+
project?: string,
|
|
224
|
+
taskId?: string
|
|
225
|
+
): Promise<{
|
|
226
|
+
acknowledged: boolean;
|
|
227
|
+
slack_posted: boolean;
|
|
228
|
+
task_id?: string;
|
|
229
|
+
task_key?: string;
|
|
230
|
+
task_linked?: boolean;
|
|
231
|
+
}> {
|
|
155
232
|
return this.request("POST", `/agents/${agentId}/start-work`, {
|
|
156
233
|
task,
|
|
157
234
|
project,
|
|
235
|
+
task_id: taskId,
|
|
158
236
|
});
|
|
159
237
|
}
|
|
160
238
|
|
|
@@ -294,4 +372,114 @@ export class ApiClient {
|
|
|
294
372
|
reason,
|
|
295
373
|
});
|
|
296
374
|
}
|
|
375
|
+
|
|
376
|
+
// Ticket system methods (for agent integration)
|
|
377
|
+
|
|
378
|
+
async getAvailableTasks(params?: {
|
|
379
|
+
status?: string;
|
|
380
|
+
project_id?: string;
|
|
381
|
+
priority?: string;
|
|
382
|
+
}): Promise<{ tasks: TicketTask[]; total: number }> {
|
|
383
|
+
const query = new URLSearchParams();
|
|
384
|
+
if (params?.status) query.set("status", params.status);
|
|
385
|
+
if (params?.project_id) query.set("project_id", params.project_id);
|
|
386
|
+
if (params?.priority) query.set("priority", params.priority);
|
|
387
|
+
const queryStr = query.toString() ? `?${query}` : "";
|
|
388
|
+
return this.request("GET", `/agent-tickets/available${queryStr}`);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
async getTicketTask(taskId: string): Promise<TicketTaskContext> {
|
|
392
|
+
return this.request("GET", `/agent-tickets/${taskId}`);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
async claimTicketTask(
|
|
396
|
+
taskId: string,
|
|
397
|
+
agentId: string
|
|
398
|
+
): Promise<{
|
|
399
|
+
success: boolean;
|
|
400
|
+
task: TicketTask;
|
|
401
|
+
task_id: string;
|
|
402
|
+
task_key: string;
|
|
403
|
+
}> {
|
|
404
|
+
return this.request("POST", `/agent-tickets/${taskId}/claim`, {
|
|
405
|
+
agent_id: agentId,
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
async createCheckpoint(
|
|
410
|
+
taskId: string,
|
|
411
|
+
agentId: string,
|
|
412
|
+
description: string
|
|
413
|
+
): Promise<CheckpointResponse> {
|
|
414
|
+
return this.request("POST", `/agent-tickets/${taskId}/checkpoint`, {
|
|
415
|
+
agent_id: agentId,
|
|
416
|
+
description,
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Browser-based registration flow
|
|
421
|
+
async initRegistration(agentId?: string, agentName?: string): Promise<{
|
|
422
|
+
session_token: string;
|
|
423
|
+
dashboard_url: string;
|
|
424
|
+
expires_at: string;
|
|
425
|
+
}> {
|
|
426
|
+
return this.request("POST", "/agents/register-init", {
|
|
427
|
+
agent_id: agentId,
|
|
428
|
+
agent_name: agentName,
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
async pollRegistrationCallback(token: string): Promise<{
|
|
433
|
+
status: "pending" | "completed" | "expired";
|
|
434
|
+
agent_id?: string;
|
|
435
|
+
agent_name?: string;
|
|
436
|
+
agent_type?: string;
|
|
437
|
+
connect_token?: string;
|
|
438
|
+
expires_at?: string;
|
|
439
|
+
}> {
|
|
440
|
+
const url = `${this.baseUrl}/agents/register-callback/${token}`;
|
|
441
|
+
const response = await fetch(url, {
|
|
442
|
+
method: "GET",
|
|
443
|
+
headers: {
|
|
444
|
+
"Content-Type": "application/json",
|
|
445
|
+
"X-API-Key": this.apiKey,
|
|
446
|
+
},
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
if (response.status === 202) {
|
|
450
|
+
// Still pending
|
|
451
|
+
const data = await response.json() as { status: string; expires_at: string };
|
|
452
|
+
return { status: "pending", expires_at: data.expires_at };
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
if (response.status === 410) {
|
|
456
|
+
// Expired
|
|
457
|
+
return { status: "expired" };
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
if (!response.ok) {
|
|
461
|
+
const data = await response.json() as { message?: string };
|
|
462
|
+
throw new Error(data.message || `Request failed: ${response.status}`);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
const data = await response.json() as {
|
|
466
|
+
status: string;
|
|
467
|
+
agent_id: string;
|
|
468
|
+
agent_name: string;
|
|
469
|
+
agent_type: string;
|
|
470
|
+
connect_token: string;
|
|
471
|
+
};
|
|
472
|
+
|
|
473
|
+
return {
|
|
474
|
+
status: "completed",
|
|
475
|
+
agent_id: data.agent_id,
|
|
476
|
+
agent_name: data.agent_name,
|
|
477
|
+
agent_type: data.agent_type,
|
|
478
|
+
connect_token: data.connect_token,
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
getBaseUrl(): string {
|
|
483
|
+
return this.baseUrl;
|
|
484
|
+
}
|
|
297
485
|
}
|