agenthub-multiagent-mcp 1.1.2 → 1.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +170 -151
- package/dist/client.d.ts +3 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +2 -1
- package/dist/client.js.map +1 -1
- package/dist/client.test.d.ts +2 -0
- package/dist/client.test.d.ts.map +1 -1
- package/dist/client.test.js +16 -1
- package/dist/client.test.js.map +1 -1
- package/dist/e2e.test.d.ts +1 -0
- package/dist/e2e.test.d.ts.map +1 -1
- package/dist/e2e.test.js +3 -1
- package/dist/e2e.test.js.map +1 -1
- package/dist/heartbeat.d.ts +11 -1
- package/dist/heartbeat.d.ts.map +1 -1
- package/dist/heartbeat.js +41 -3
- package/dist/heartbeat.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +13 -8
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/tools.test.js +6 -1
- package/dist/tools/tools.test.js.map +1 -1
- package/package.json +53 -53
- package/src/client.test.ts +223 -208
- package/src/client.ts +293 -286
- package/src/e2e.test.ts +300 -298
- package/src/heartbeat.ts +45 -3
- package/src/index.ts +123 -123
- package/src/tools/index.ts +672 -666
- package/src/tools/tools.test.ts +522 -517
- package/vitest.config.ts +8 -0
package/src/client.test.ts
CHANGED
|
@@ -1,208 +1,223 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Integration tests for AgentHub API client
|
|
3
|
-
*
|
|
4
|
-
* These tests require the AgentHub server to be running on localhost:8787
|
|
5
|
-
* Run: cd server && go run ./cmd/agenthub serve --port 8787
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
it("should
|
|
51
|
-
const result = await client.
|
|
52
|
-
|
|
53
|
-
expect(result.
|
|
54
|
-
expect(result.
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
expect(
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it("should
|
|
76
|
-
const result = await client.
|
|
77
|
-
|
|
78
|
-
expect(result.
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
it("should
|
|
156
|
-
const result = await client.
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
it("should
|
|
199
|
-
await
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
)
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Integration tests for AgentHub API client
|
|
3
|
+
*
|
|
4
|
+
* These tests require the AgentHub server to be running on localhost:8787
|
|
5
|
+
* Run: cd server && go run ./cmd/agenthub serve --port 8787
|
|
6
|
+
*
|
|
7
|
+
* Set AGENTHUB_INTEGRATION_TESTS=1 to run these tests
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { describe, it, expect, beforeAll, afterAll } from "vitest";
|
|
11
|
+
import { ApiClient } from "./client.js";
|
|
12
|
+
|
|
13
|
+
const TEST_URL = process.env.AGENTHUB_URL || "http://localhost:8787";
|
|
14
|
+
const TEST_API_KEY = process.env.AGENTHUB_API_KEY || "test-key-123";
|
|
15
|
+
const RUN_INTEGRATION = process.env.AGENTHUB_INTEGRATION_TESTS === "1";
|
|
16
|
+
|
|
17
|
+
// Helper to check if server is reachable
|
|
18
|
+
async function isServerReachable(): Promise<boolean> {
|
|
19
|
+
try {
|
|
20
|
+
const response = await fetch(`${TEST_URL}/health`, {
|
|
21
|
+
signal: AbortSignal.timeout(2000)
|
|
22
|
+
});
|
|
23
|
+
return response.ok;
|
|
24
|
+
} catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
describe.skipIf(!RUN_INTEGRATION)("ApiClient Integration", () => {
|
|
30
|
+
let client: ApiClient;
|
|
31
|
+
let testAgentId: string;
|
|
32
|
+
let testChannelName: string;
|
|
33
|
+
|
|
34
|
+
beforeAll(() => {
|
|
35
|
+
client = new ApiClient(TEST_URL, TEST_API_KEY);
|
|
36
|
+
testAgentId = `test-agent-${Date.now()}`;
|
|
37
|
+
testChannelName = `test-channel-${Date.now()}`;
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
afterAll(async () => {
|
|
41
|
+
// Cleanup - disconnect agent
|
|
42
|
+
try {
|
|
43
|
+
await client.disconnect(testAgentId);
|
|
44
|
+
} catch {
|
|
45
|
+
// Ignore cleanup errors
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
describe("Agent Operations", () => {
|
|
50
|
+
it("should register an agent", async () => {
|
|
51
|
+
const result = await client.registerAgent(testAgentId, "Test Agent");
|
|
52
|
+
|
|
53
|
+
expect(result.agent_id).toBe(testAgentId);
|
|
54
|
+
expect(result.registered_at).toBeDefined();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("should get agent details", async () => {
|
|
58
|
+
const agent = await client.getAgent(testAgentId);
|
|
59
|
+
|
|
60
|
+
expect(agent.id).toBe(testAgentId);
|
|
61
|
+
expect(agent.name).toBe("Test Agent");
|
|
62
|
+
expect(agent.status).toBe("online");
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("should list agents", async () => {
|
|
66
|
+
const result = await client.listAgents();
|
|
67
|
+
|
|
68
|
+
expect(result.agents).toBeDefined();
|
|
69
|
+
expect(result.total).toBeGreaterThan(0);
|
|
70
|
+
|
|
71
|
+
const testAgent = result.agents.find((a) => a.id === testAgentId);
|
|
72
|
+
expect(testAgent).toBeDefined();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("should filter agents by status", async () => {
|
|
76
|
+
const result = await client.listAgents("online");
|
|
77
|
+
|
|
78
|
+
expect(result.agents).toBeDefined();
|
|
79
|
+
for (const agent of result.agents) {
|
|
80
|
+
expect(agent.status).toBe("online");
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("should start work", async () => {
|
|
85
|
+
const result = await client.startWork(testAgentId, "Running tests", "TestProject");
|
|
86
|
+
|
|
87
|
+
expect(result.acknowledged).toBe(true);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("should send heartbeat", async () => {
|
|
91
|
+
const result = await client.heartbeat(testAgentId, "busy");
|
|
92
|
+
|
|
93
|
+
expect(result.acknowledged).toBe(true);
|
|
94
|
+
expect(result.timestamp).toBeDefined();
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
describe("Channel Operations", () => {
|
|
99
|
+
let secondAgentId: string;
|
|
100
|
+
|
|
101
|
+
beforeAll(async () => {
|
|
102
|
+
secondAgentId = `test-agent-2-${Date.now()}`;
|
|
103
|
+
await client.registerAgent(secondAgentId, "Test Agent 2");
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
afterAll(async () => {
|
|
107
|
+
try {
|
|
108
|
+
await client.disconnect(secondAgentId);
|
|
109
|
+
} catch {
|
|
110
|
+
// Ignore cleanup errors
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it("should list channels", async () => {
|
|
115
|
+
const result = await client.listChannels();
|
|
116
|
+
|
|
117
|
+
expect(result.channels).toBeDefined();
|
|
118
|
+
expect(typeof result.total).toBe("number");
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("should join channel", async () => {
|
|
122
|
+
// First ensure channel exists by trying to join
|
|
123
|
+
// If the channel doesn't exist, this will fail - we need to create it first
|
|
124
|
+
// But we don't have a createChannel method in the client
|
|
125
|
+
|
|
126
|
+
// For this test, we assume the channel exists or the server auto-creates
|
|
127
|
+
// Skip this test if the channel doesn't exist
|
|
128
|
+
try {
|
|
129
|
+
const result = await client.joinChannel(testChannelName, testAgentId);
|
|
130
|
+
expect(result.subscribed).toBe(true);
|
|
131
|
+
} catch (e) {
|
|
132
|
+
// Channel might not exist, skip
|
|
133
|
+
console.log("Channel join test skipped - channel may not exist");
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
describe("Message Operations", () => {
|
|
139
|
+
let secondAgentId: string;
|
|
140
|
+
let messageId: string;
|
|
141
|
+
|
|
142
|
+
beforeAll(async () => {
|
|
143
|
+
secondAgentId = `test-agent-msg-${Date.now()}`;
|
|
144
|
+
await client.registerAgent(secondAgentId, "Test Agent Msg");
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
afterAll(async () => {
|
|
148
|
+
try {
|
|
149
|
+
await client.disconnect(secondAgentId);
|
|
150
|
+
} catch {
|
|
151
|
+
// Ignore cleanup errors
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it("should send a direct message", async () => {
|
|
156
|
+
const result = await client.sendMessage({
|
|
157
|
+
from_agent: testAgentId,
|
|
158
|
+
to_agent: secondAgentId,
|
|
159
|
+
type: "task",
|
|
160
|
+
subject: "Test Message",
|
|
161
|
+
body: "This is a test message",
|
|
162
|
+
priority: "normal",
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
expect(result.message_id).toBeDefined();
|
|
166
|
+
expect(result.status).toBe("pending");
|
|
167
|
+
messageId = result.message_id;
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it("should get inbox messages", async () => {
|
|
171
|
+
const result = await client.getInbox(secondAgentId);
|
|
172
|
+
|
|
173
|
+
expect(result.messages).toBeDefined();
|
|
174
|
+
expect(result.total).toBeGreaterThan(0);
|
|
175
|
+
|
|
176
|
+
const testMessage = result.messages.find((m) => m.id === messageId);
|
|
177
|
+
expect(testMessage).toBeDefined();
|
|
178
|
+
expect(testMessage?.subject).toBe("Test Message");
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it("should mark message as read", async () => {
|
|
182
|
+
// First need to mark as delivered
|
|
183
|
+
const patchUrl = `${TEST_URL}/messages/${messageId}/status`;
|
|
184
|
+
await fetch(patchUrl, {
|
|
185
|
+
method: "PATCH",
|
|
186
|
+
headers: {
|
|
187
|
+
"Content-Type": "application/json",
|
|
188
|
+
"X-API-Key": TEST_API_KEY,
|
|
189
|
+
},
|
|
190
|
+
body: JSON.stringify({ status: "delivered" }),
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
const result = await client.markRead(messageId);
|
|
194
|
+
|
|
195
|
+
expect(result.updated).toBe(true);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it("should send a broadcast message", async () => {
|
|
199
|
+
const result = await client.sendMessage({
|
|
200
|
+
from_agent: testAgentId,
|
|
201
|
+
broadcast: true,
|
|
202
|
+
type: "status",
|
|
203
|
+
subject: "Broadcast Test",
|
|
204
|
+
body: "This is a broadcast",
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
expect(result.message_id).toBeDefined();
|
|
208
|
+
expect(result.status).toBe("pending");
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
describe("Error Handling", () => {
|
|
213
|
+
it("should throw error for non-existent agent", async () => {
|
|
214
|
+
await expect(client.getAgent("non-existent-agent-xyz")).rejects.toThrow();
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it("should throw error for duplicate registration", async () => {
|
|
218
|
+
await expect(
|
|
219
|
+
client.registerAgent(testAgentId, "Duplicate Agent")
|
|
220
|
+
).rejects.toThrow(/already registered/i);
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
});
|