@teneo-protocol/sdk 1.0.0 → 2.0.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/.github/workflows/publish-npm.yml +8 -6
- package/CHANGELOG.md +265 -0
- package/README.md +406 -53
- package/dist/core/websocket-client.d.ts +13 -0
- package/dist/core/websocket-client.d.ts.map +1 -1
- package/dist/core/websocket-client.js +34 -3
- package/dist/core/websocket-client.js.map +1 -1
- package/dist/handlers/message-handlers/agent-room-operation-response-handler.d.ts +76 -0
- package/dist/handlers/message-handlers/agent-room-operation-response-handler.d.ts.map +1 -0
- package/dist/handlers/message-handlers/agent-room-operation-response-handler.js +70 -0
- package/dist/handlers/message-handlers/agent-room-operation-response-handler.js.map +1 -0
- package/dist/handlers/message-handlers/agent-selected-handler.d.ts +92 -38
- package/dist/handlers/message-handlers/agent-selected-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/agent-status-update-handler.d.ts +904 -0
- package/dist/handlers/message-handlers/agent-status-update-handler.d.ts.map +1 -0
- package/dist/handlers/message-handlers/agent-status-update-handler.js +51 -0
- package/dist/handlers/message-handlers/agent-status-update-handler.js.map +1 -0
- package/dist/handlers/message-handlers/auth-error-handler.d.ts +45 -31
- package/dist/handlers/message-handlers/auth-error-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/auth-message-handler.d.ts +6 -0
- package/dist/handlers/message-handlers/auth-message-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/auth-message-handler.js +65 -5
- package/dist/handlers/message-handlers/auth-message-handler.js.map +1 -1
- package/dist/handlers/message-handlers/auth-required-handler.d.ts +49 -31
- package/dist/handlers/message-handlers/auth-required-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/auth-success-handler.d.ts +6 -0
- package/dist/handlers/message-handlers/auth-success-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/auth-success-handler.js +46 -4
- package/dist/handlers/message-handlers/auth-success-handler.js.map +1 -1
- package/dist/handlers/message-handlers/challenge-handler.d.ts +45 -31
- package/dist/handlers/message-handlers/challenge-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/error-message-handler.d.ts +49 -31
- package/dist/handlers/message-handlers/error-message-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/index.d.ts +5 -0
- package/dist/handlers/message-handlers/index.d.ts.map +1 -1
- package/dist/handlers/message-handlers/index.js +23 -1
- package/dist/handlers/message-handlers/index.js.map +1 -1
- package/dist/handlers/message-handlers/list-available-agents-handler.d.ts +877 -0
- package/dist/handlers/message-handlers/list-available-agents-handler.d.ts.map +1 -0
- package/dist/handlers/message-handlers/list-available-agents-handler.js +38 -0
- package/dist/handlers/message-handlers/list-available-agents-handler.js.map +1 -0
- package/dist/handlers/message-handlers/list-room-agents-handler.d.ts +886 -0
- package/dist/handlers/message-handlers/list-room-agents-handler.d.ts.map +1 -0
- package/dist/handlers/message-handlers/list-room-agents-handler.js +51 -0
- package/dist/handlers/message-handlers/list-room-agents-handler.js.map +1 -0
- package/dist/handlers/message-handlers/list-rooms-response-handler.d.ts +178 -89
- package/dist/handlers/message-handlers/list-rooms-response-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/ping-pong-handler.d.ts +62 -58
- package/dist/handlers/message-handlers/ping-pong-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/regular-message-handler.d.ts +31 -29
- package/dist/handlers/message-handlers/regular-message-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/regular-message-handler.js +1 -0
- package/dist/handlers/message-handlers/regular-message-handler.js.map +1 -1
- package/dist/handlers/message-handlers/room-operation-response-handler.d.ts +328 -0
- package/dist/handlers/message-handlers/room-operation-response-handler.d.ts.map +1 -0
- package/dist/handlers/message-handlers/room-operation-response-handler.js +92 -0
- package/dist/handlers/message-handlers/room-operation-response-handler.js.map +1 -0
- package/dist/handlers/message-handlers/subscribe-response-handler.d.ts +53 -31
- package/dist/handlers/message-handlers/subscribe-response-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/types.d.ts +2 -0
- package/dist/handlers/message-handlers/types.d.ts.map +1 -1
- package/dist/handlers/message-handlers/unsubscribe-response-handler.d.ts +53 -31
- package/dist/handlers/message-handlers/unsubscribe-response-handler.d.ts.map +1 -1
- package/dist/managers/agent-room-manager.d.ts +222 -0
- package/dist/managers/agent-room-manager.d.ts.map +1 -0
- package/dist/managers/agent-room-manager.js +508 -0
- package/dist/managers/agent-room-manager.js.map +1 -0
- package/dist/managers/index.d.ts +2 -0
- package/dist/managers/index.d.ts.map +1 -1
- package/dist/managers/index.js +5 -1
- package/dist/managers/index.js.map +1 -1
- package/dist/managers/message-router.d.ts +1 -1
- package/dist/managers/message-router.d.ts.map +1 -1
- package/dist/managers/message-router.js +41 -4
- package/dist/managers/message-router.js.map +1 -1
- package/dist/managers/room-management-manager.d.ts +213 -0
- package/dist/managers/room-management-manager.d.ts.map +1 -0
- package/dist/managers/room-management-manager.js +440 -0
- package/dist/managers/room-management-manager.js.map +1 -0
- package/dist/managers/room-manager.d.ts +4 -4
- package/dist/managers/room-manager.d.ts.map +1 -1
- package/dist/managers/room-manager.js +1 -1
- package/dist/managers/room-manager.js.map +1 -1
- package/dist/teneo-sdk.d.ts +362 -14
- package/dist/teneo-sdk.d.ts.map +1 -1
- package/dist/teneo-sdk.js +497 -7
- package/dist/teneo-sdk.js.map +1 -1
- package/dist/types/config.d.ts +63 -54
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/config.js +9 -5
- package/dist/types/config.js.map +1 -1
- package/dist/types/error-codes.d.ts +2 -0
- package/dist/types/error-codes.d.ts.map +1 -1
- package/dist/types/error-codes.js +3 -0
- package/dist/types/error-codes.js.map +1 -1
- package/dist/types/events.d.ts +132 -68
- package/dist/types/events.d.ts.map +1 -1
- package/dist/types/events.js.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +27 -2
- package/dist/types/index.js.map +1 -1
- package/dist/types/messages.d.ts +11396 -2559
- package/dist/types/messages.d.ts.map +1 -1
- package/dist/types/messages.js +294 -27
- package/dist/types/messages.js.map +1 -1
- package/dist/types/validation.d.ts.map +1 -1
- package/dist/types/validation.js +1 -1
- package/dist/types/validation.js.map +1 -1
- package/dist/utils/bounded-queue.d.ts +1 -1
- package/dist/utils/bounded-queue.js +6 -6
- package/dist/utils/circuit-breaker.d.ts.map +1 -1
- package/dist/utils/circuit-breaker.js.map +1 -1
- package/dist/utils/event-waiter.d.ts.map +1 -1
- package/dist/utils/event-waiter.js +2 -1
- package/dist/utils/event-waiter.js.map +1 -1
- package/dist/utils/rate-limiter.d.ts.map +1 -1
- package/dist/utils/rate-limiter.js +4 -6
- package/dist/utils/rate-limiter.js.map +1 -1
- package/dist/utils/secure-private-key.d.ts.map +1 -1
- package/dist/utils/secure-private-key.js +9 -15
- package/dist/utils/secure-private-key.js.map +1 -1
- package/dist/utils/signature-verifier.d.ts +2 -2
- package/dist/utils/signature-verifier.d.ts.map +1 -1
- package/dist/utils/signature-verifier.js +5 -5
- package/dist/utils/signature-verifier.js.map +1 -1
- package/examples/.env.example +1 -1
- package/examples/agent-room-management-example.ts +334 -0
- package/examples/claude-agent-x-follower/.env.example +117 -0
- package/examples/claude-agent-x-follower/QUICKSTART.md +243 -0
- package/examples/claude-agent-x-follower/README.md +540 -0
- package/examples/claude-agent-x-follower/index.ts +248 -0
- package/examples/claude-agent-x-follower/package.json +37 -0
- package/examples/claude-agent-x-follower/tsconfig.json +20 -0
- package/examples/n8n-teneo/.env.example +127 -0
- package/examples/n8n-teneo/Dockerfile +42 -0
- package/examples/n8n-teneo/README.md +564 -0
- package/examples/n8n-teneo/docker-compose.yml +71 -0
- package/examples/n8n-teneo/index.ts +177 -0
- package/examples/n8n-teneo/package.json +22 -0
- package/examples/n8n-teneo/tsconfig.json +12 -0
- package/examples/n8n-teneo/workflows/x-timeline.json +66 -0
- package/examples/openai-teneo/.env.example +130 -0
- package/examples/openai-teneo/README.md +635 -0
- package/examples/openai-teneo/index.ts +280 -0
- package/examples/openai-teneo/package.json +24 -0
- package/examples/openai-teneo/tsconfig.json +16 -0
- package/examples/production-dashboard/.env.example +5 -3
- package/examples/production-dashboard/README.md +839 -0
- package/examples/production-dashboard/pnpm-lock.yaml +92 -0
- package/examples/production-dashboard/public/dashboard.html +1150 -504
- package/examples/production-dashboard/server.ts +428 -12
- package/examples/room-management-example.ts +285 -0
- package/examples/usage/.env.example +17 -0
- package/examples/usage/01-connect.ts +116 -0
- package/examples/usage/02-list-agents.ts +153 -0
- package/examples/usage/03-pick-agent.ts +201 -0
- package/examples/usage/04-find-by-capability.ts +237 -0
- package/examples/usage/05-webhook-example.ts +319 -0
- package/examples/usage/06-simple-api-server.ts +396 -0
- package/examples/usage/07-event-listener.ts +402 -0
- package/examples/usage/README.md +383 -0
- package/examples/usage/package.json +42 -0
- package/package.json +13 -3
- package/src/core/websocket-client.ts +43 -9
- package/src/formatters/response-formatter.test.ts +8 -2
- package/src/handlers/message-handlers/agent-room-operation-response-handler.ts +83 -0
- package/src/handlers/message-handlers/agent-status-update-handler.ts +58 -0
- package/src/handlers/message-handlers/auth-message-handler.ts +73 -5
- package/src/handlers/message-handlers/auth-success-handler.ts +58 -6
- package/src/handlers/message-handlers/index.ts +19 -0
- package/src/handlers/message-handlers/list-available-agents-handler.ts +41 -0
- package/src/handlers/message-handlers/list-room-agents-handler.ts +61 -0
- package/src/handlers/message-handlers/regular-message-handler.ts +1 -0
- package/src/handlers/message-handlers/room-operation-response-handler.ts +105 -0
- package/src/handlers/message-handlers/types.ts +6 -0
- package/src/handlers/webhook-handler.test.ts +13 -10
- package/src/managers/agent-room-manager.ts +609 -0
- package/src/managers/index.ts +2 -0
- package/src/managers/message-router.ts +48 -6
- package/src/managers/room-management-manager.ts +523 -0
- package/src/managers/room-manager.ts +12 -6
- package/src/teneo-sdk.ts +543 -10
- package/src/types/config.ts +13 -6
- package/src/types/error-codes.ts +4 -0
- package/src/types/events.ts +24 -0
- package/src/types/index.ts +55 -0
- package/src/types/messages.ts +374 -41
- package/src/types/validation.ts +4 -1
- package/src/utils/bounded-queue.ts +9 -9
- package/src/utils/circuit-breaker.ts +4 -1
- package/src/utils/deduplication-cache.test.ts +2 -6
- package/src/utils/event-waiter.test.ts +4 -1
- package/src/utils/event-waiter.ts +5 -7
- package/src/utils/rate-limiter.test.ts +5 -17
- package/src/utils/rate-limiter.ts +6 -9
- package/src/utils/secure-private-key.test.ts +66 -59
- package/src/utils/secure-private-key.ts +10 -16
- package/src/utils/signature-verifier.test.ts +75 -70
- package/src/utils/signature-verifier.ts +7 -8
- package/src/utils/ssrf-validator.test.ts +3 -3
- package/tests/integration/room-management.test.ts +514 -0
- package/tests/integration/websocket.test.ts +1 -1
- package/tests/unit/handlers/agent-room-operation-response-handler.test.ts +394 -0
- package/tests/unit/handlers/agent-status-update-handler.test.ts +407 -0
- package/tests/unit/handlers/auth-success-handler-rooms.test.ts +699 -0
- package/tests/unit/handlers/list-available-agents-handler.test.ts +256 -0
- package/tests/unit/handlers/list-room-agents-handler.test.ts +294 -0
- package/tests/unit/handlers/room-operation-response-handler.test.ts +527 -0
- package/tests/unit/managers/agent-room-manager.test.ts +534 -0
- package/tests/unit/managers/room-management-manager.test.ts +438 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Handler for agent_status_update messages (v2.0.0)
|
|
3
|
+
* Processes real-time agent status updates for rooms
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
AgentStatusUpdateMessage,
|
|
8
|
+
AgentStatusUpdateMessageSchema
|
|
9
|
+
} from "../../types";
|
|
10
|
+
import { BaseMessageHandler } from "./base-handler";
|
|
11
|
+
import { HandlerContext } from "./types";
|
|
12
|
+
|
|
13
|
+
export class AgentStatusUpdateHandler extends BaseMessageHandler<AgentStatusUpdateMessage> {
|
|
14
|
+
readonly type = "agent_status_update" as const;
|
|
15
|
+
readonly schema = AgentStatusUpdateMessageSchema;
|
|
16
|
+
|
|
17
|
+
protected handleValidated(
|
|
18
|
+
message: AgentStatusUpdateMessage,
|
|
19
|
+
context: HandlerContext
|
|
20
|
+
): void {
|
|
21
|
+
const { room_id, agent_id, status, agent } = message.data;
|
|
22
|
+
|
|
23
|
+
context.logger.debug("Handling agent_status_update", {
|
|
24
|
+
roomId: room_id,
|
|
25
|
+
agentId: agent_id,
|
|
26
|
+
status,
|
|
27
|
+
hasAgent: !!agent
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// Invalidate cache for this room via agent room manager
|
|
31
|
+
const agentRoomManager = (context as any).agentRoomManager;
|
|
32
|
+
if (agentRoomManager && typeof agentRoomManager.handleStatusUpdate === "function") {
|
|
33
|
+
agentRoomManager.handleStatusUpdate(room_id, agent_id, status);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
context.logger.info("Agent status updated", {
|
|
37
|
+
roomId: room_id,
|
|
38
|
+
agentId: agent_id,
|
|
39
|
+
status
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// Emit status update event
|
|
43
|
+
this.emit(context, "agent_room:status_update", {
|
|
44
|
+
roomId: room_id,
|
|
45
|
+
agentId: agent_id,
|
|
46
|
+
status,
|
|
47
|
+
agent
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Send webhook
|
|
51
|
+
this.sendWebhook(context, "agent_status_update", {
|
|
52
|
+
room_id,
|
|
53
|
+
agent_id,
|
|
54
|
+
status,
|
|
55
|
+
agent
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -26,8 +26,27 @@ export class AuthMessageHandler extends BaseMessageHandler<AuthMessage> {
|
|
|
26
26
|
isCachedAuth ? "Using cached authentication" : "Authentication successful"
|
|
27
27
|
);
|
|
28
28
|
|
|
29
|
-
// Extract rooms
|
|
30
|
-
const
|
|
29
|
+
// Extract rooms from both 'rooms' (public) and 'private_rooms' (owned private) arrays
|
|
30
|
+
const publicRooms = this.extractRooms(message.data?.rooms);
|
|
31
|
+
const privateRooms = this.extractRooms(message.data?.private_rooms);
|
|
32
|
+
|
|
33
|
+
// Combine all rooms, ensuring correct ownership flags
|
|
34
|
+
// Public rooms from 'rooms' array are NOT owned by the user
|
|
35
|
+
// Private rooms from 'private_rooms' array ARE owned by the user
|
|
36
|
+
const allRooms = [
|
|
37
|
+
...publicRooms.map((r) => ({
|
|
38
|
+
...r,
|
|
39
|
+
is_owner: false, // Explicitly set to false - public rooms are not owned
|
|
40
|
+
is_public: r.is_public !== undefined ? r.is_public : true // Ensure is_public is set
|
|
41
|
+
})),
|
|
42
|
+
...privateRooms.map((r) => ({
|
|
43
|
+
...r,
|
|
44
|
+
is_owner: true, // Explicitly set to true - private_rooms array means owned
|
|
45
|
+
is_public: r.is_public !== undefined ? r.is_public : false // Ensure is_public is set
|
|
46
|
+
}))
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
const { privateRoomIds, sharedRoomIds } = this.categorizeRooms(allRooms);
|
|
31
50
|
|
|
32
51
|
// Update connection state
|
|
33
52
|
this.updateConnectionState(context, { authenticated: true });
|
|
@@ -40,11 +59,37 @@ export class AuthMessageHandler extends BaseMessageHandler<AuthMessage> {
|
|
|
40
59
|
isWhitelisted: message.data?.is_whitelisted,
|
|
41
60
|
isAdmin: message.data?.is_admin_whitelisted,
|
|
42
61
|
nftVerified: message.data?.nft_verified,
|
|
43
|
-
rooms:
|
|
44
|
-
roomObjects:
|
|
45
|
-
privateRoomId: message.data?.private_room_id
|
|
62
|
+
rooms: allRooms.map((r) => r.id),
|
|
63
|
+
roomObjects: allRooms,
|
|
64
|
+
privateRoomId: message.data?.private_room_id,
|
|
65
|
+
// v2.0.0: New fields
|
|
66
|
+
privateRoomIds, // Rooms user owns
|
|
67
|
+
sharedRoomIds, // Rooms user is member of
|
|
68
|
+
maxPrivateRooms: message.data?.max_private_rooms // Max rooms user can create
|
|
46
69
|
});
|
|
47
70
|
|
|
71
|
+
// Initialize room management manager with room data (v2.0.0)
|
|
72
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
73
|
+
const roomMgmt = (context as any).roomManagementManager;
|
|
74
|
+
if (roomMgmt) {
|
|
75
|
+
// Set room limit
|
|
76
|
+
if (message.data?.max_private_rooms) {
|
|
77
|
+
roomMgmt.setRoomLimit(message.data.max_private_rooms);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Categorize and cache rooms
|
|
81
|
+
const ownedRooms = allRooms.filter((r) => r.is_owner === true);
|
|
82
|
+
const sharedRooms = allRooms.filter((r) => r.is_owner === false);
|
|
83
|
+
roomMgmt.setOwnedRooms(ownedRooms);
|
|
84
|
+
roomMgmt.setSharedRooms(sharedRooms);
|
|
85
|
+
|
|
86
|
+
context.logger.debug("Room management initialized from auth message", {
|
|
87
|
+
owned: ownedRooms.length,
|
|
88
|
+
shared: sharedRooms.length,
|
|
89
|
+
limit: message.data?.max_private_rooms
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
48
93
|
// Get updated auth state
|
|
49
94
|
const authState = context.getAuthState();
|
|
50
95
|
|
|
@@ -63,4 +108,27 @@ export class AuthMessageHandler extends BaseMessageHandler<AuthMessage> {
|
|
|
63
108
|
}
|
|
64
109
|
return rooms;
|
|
65
110
|
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Categorize rooms into owned vs member rooms based on is_owner flag
|
|
114
|
+
* @param rooms - Array of room info objects
|
|
115
|
+
* @returns Object with privateRoomIds (owned) and sharedRoomIds (member)
|
|
116
|
+
*/
|
|
117
|
+
private categorizeRooms(rooms: Room[]): {
|
|
118
|
+
privateRoomIds: string[];
|
|
119
|
+
sharedRoomIds: string[];
|
|
120
|
+
} {
|
|
121
|
+
const privateRoomIds: string[] = [];
|
|
122
|
+
const sharedRoomIds: string[] = [];
|
|
123
|
+
|
|
124
|
+
for (const room of rooms) {
|
|
125
|
+
if (room.is_owner) {
|
|
126
|
+
if (room.id) privateRoomIds.push(room.id);
|
|
127
|
+
} else {
|
|
128
|
+
if (room.id) sharedRoomIds.push(room.id);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return { privateRoomIds, sharedRoomIds };
|
|
133
|
+
}
|
|
66
134
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { z } from "zod";
|
|
7
|
-
import { AuthSuccessMessage, AuthSuccessMessageSchema,
|
|
7
|
+
import { AuthSuccessMessage, AuthSuccessMessageSchema, RoomInfo } from "../../types";
|
|
8
8
|
import { BaseMessageHandler } from "./base-handler";
|
|
9
9
|
import { HandlerContext } from "./types";
|
|
10
10
|
|
|
@@ -18,8 +18,9 @@ export class AuthSuccessHandler extends BaseMessageHandler<AuthSuccessMessage> {
|
|
|
18
18
|
): Promise<void> {
|
|
19
19
|
context.logger.info("Authentication successful");
|
|
20
20
|
|
|
21
|
-
// Extract rooms
|
|
21
|
+
// Extract and categorize rooms
|
|
22
22
|
const rooms = this.extractRooms(message.data.rooms);
|
|
23
|
+
const { privateRoomIds, sharedRoomIds } = this.categorizeRooms(rooms);
|
|
23
24
|
|
|
24
25
|
// Update connection state
|
|
25
26
|
this.updateConnectionState(context, { authenticated: true });
|
|
@@ -32,14 +33,42 @@ export class AuthSuccessHandler extends BaseMessageHandler<AuthSuccessMessage> {
|
|
|
32
33
|
isWhitelisted: message.data.is_whitelisted,
|
|
33
34
|
isAdmin: message.data.is_admin_whitelisted,
|
|
34
35
|
nftVerified: message.data.nft_verified,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
|
|
37
|
+
// Backward compatibility: deprecated fields
|
|
38
|
+
rooms: rooms.map((r) => r.id), // All room IDs
|
|
39
|
+
privateRoomId: message.data.private_room_id, // DEPRECATED: single private room ID
|
|
40
|
+
|
|
41
|
+
// v2.0.0: New fields
|
|
42
|
+
roomObjects: rooms, // Full room objects with is_owner field
|
|
43
|
+
privateRoomIds, // Rooms user owns
|
|
44
|
+
sharedRoomIds, // Rooms user is member of
|
|
45
|
+
maxPrivateRooms: message.data.max_private_rooms // Max rooms user can create
|
|
38
46
|
});
|
|
39
47
|
|
|
40
48
|
// Get updated auth state
|
|
41
49
|
const authState = context.getAuthState();
|
|
42
50
|
|
|
51
|
+
// Initialize room management manager with room data (v2.0.0)
|
|
52
|
+
const roomMgmt = (context as any).roomManagementManager;
|
|
53
|
+
if (roomMgmt) {
|
|
54
|
+
// Set room limit
|
|
55
|
+
if (message.data.max_private_rooms) {
|
|
56
|
+
roomMgmt.setRoomLimit(message.data.max_private_rooms);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Categorize and cache rooms
|
|
60
|
+
const ownedRooms = rooms.filter((r) => r.is_owner);
|
|
61
|
+
const sharedRooms = rooms.filter((r) => !r.is_owner);
|
|
62
|
+
roomMgmt.setOwnedRooms(ownedRooms);
|
|
63
|
+
roomMgmt.setSharedRooms(sharedRooms);
|
|
64
|
+
|
|
65
|
+
context.logger.debug("Room management initialized", {
|
|
66
|
+
owned: ownedRooms.length,
|
|
67
|
+
shared: sharedRooms.length,
|
|
68
|
+
limit: message.data.max_private_rooms
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
43
72
|
// Emit events
|
|
44
73
|
this.emit(context, "auth:success", authState);
|
|
45
74
|
this.emit(context, "ready");
|
|
@@ -48,10 +77,33 @@ export class AuthSuccessHandler extends BaseMessageHandler<AuthSuccessMessage> {
|
|
|
48
77
|
/**
|
|
49
78
|
* Extract and normalize rooms from auth data
|
|
50
79
|
*/
|
|
51
|
-
private extractRooms(rooms?:
|
|
80
|
+
private extractRooms(rooms?: RoomInfo[] | null): RoomInfo[] {
|
|
52
81
|
if (!rooms || !Array.isArray(rooms)) {
|
|
53
82
|
return [];
|
|
54
83
|
}
|
|
55
84
|
return rooms;
|
|
56
85
|
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Categorize rooms into owned vs member rooms based on is_owner flag
|
|
89
|
+
* @param rooms - Array of room info objects
|
|
90
|
+
* @returns Object with privateRoomIds (owned) and sharedRoomIds (member)
|
|
91
|
+
*/
|
|
92
|
+
private categorizeRooms(rooms: RoomInfo[]): {
|
|
93
|
+
privateRoomIds: string[];
|
|
94
|
+
sharedRoomIds: string[];
|
|
95
|
+
} {
|
|
96
|
+
const privateRoomIds: string[] = [];
|
|
97
|
+
const sharedRoomIds: string[] = [];
|
|
98
|
+
|
|
99
|
+
for (const room of rooms) {
|
|
100
|
+
if (room.is_owner) {
|
|
101
|
+
privateRoomIds.push(room.id);
|
|
102
|
+
} else {
|
|
103
|
+
sharedRoomIds.push(room.id);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return { privateRoomIds, sharedRoomIds };
|
|
108
|
+
}
|
|
57
109
|
}
|
|
@@ -22,6 +22,11 @@ export { PingHandler, PongHandler } from "./ping-pong-handler";
|
|
|
22
22
|
export { SubscribeResponseHandler } from "./subscribe-response-handler";
|
|
23
23
|
export { UnsubscribeResponseHandler } from "./unsubscribe-response-handler";
|
|
24
24
|
export { ListRoomsResponseHandler } from "./list-rooms-response-handler";
|
|
25
|
+
export { RoomOperationResponseHandler } from "./room-operation-response-handler";
|
|
26
|
+
export { AgentRoomOperationResponseHandler } from "./agent-room-operation-response-handler";
|
|
27
|
+
export { ListRoomAgentsHandler } from "./list-room-agents-handler";
|
|
28
|
+
export { ListAvailableAgentsHandler } from "./list-available-agents-handler";
|
|
29
|
+
export { AgentStatusUpdateHandler } from "./agent-status-update-handler";
|
|
25
30
|
|
|
26
31
|
// Import for convenience function
|
|
27
32
|
import { TaskResponseHandler } from "./task-response-handler";
|
|
@@ -38,6 +43,11 @@ import { PingHandler, PongHandler } from "./ping-pong-handler";
|
|
|
38
43
|
import { SubscribeResponseHandler } from "./subscribe-response-handler";
|
|
39
44
|
import { UnsubscribeResponseHandler } from "./unsubscribe-response-handler";
|
|
40
45
|
import { ListRoomsResponseHandler } from "./list-rooms-response-handler";
|
|
46
|
+
import { RoomOperationResponseHandler } from "./room-operation-response-handler";
|
|
47
|
+
import { AgentRoomOperationResponseHandler } from "./agent-room-operation-response-handler";
|
|
48
|
+
import { ListRoomAgentsHandler } from "./list-room-agents-handler";
|
|
49
|
+
import { ListAvailableAgentsHandler } from "./list-available-agents-handler";
|
|
50
|
+
import { AgentStatusUpdateHandler } from "./agent-status-update-handler";
|
|
41
51
|
import { MessageHandler } from "./types";
|
|
42
52
|
|
|
43
53
|
/**
|
|
@@ -70,6 +80,15 @@ export function getDefaultHandlers(
|
|
|
70
80
|
new UnsubscribeResponseHandler(),
|
|
71
81
|
new ListRoomsResponseHandler(),
|
|
72
82
|
|
|
83
|
+
// Room Management handlers (v2.0.0)
|
|
84
|
+
new RoomOperationResponseHandler(),
|
|
85
|
+
|
|
86
|
+
// Agent Room Management handlers (v2.0.0)
|
|
87
|
+
new AgentRoomOperationResponseHandler(),
|
|
88
|
+
new ListRoomAgentsHandler(),
|
|
89
|
+
new ListAvailableAgentsHandler(),
|
|
90
|
+
new AgentStatusUpdateHandler(),
|
|
91
|
+
|
|
73
92
|
// Keepalive handlers
|
|
74
93
|
new PingHandler(),
|
|
75
94
|
new PongHandler()
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Handler for available_agents_response messages (v2.0.0)
|
|
3
|
+
* Processes responses from list_available_agents requests
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { AvailableAgentsResponse, AvailableAgentsResponseSchema } from "../../types";
|
|
7
|
+
import { BaseMessageHandler } from "./base-handler";
|
|
8
|
+
import { HandlerContext } from "./types";
|
|
9
|
+
import { AgentRoomInfo } from "../../managers/agent-room-manager";
|
|
10
|
+
|
|
11
|
+
export class ListAvailableAgentsHandler extends BaseMessageHandler<AvailableAgentsResponse> {
|
|
12
|
+
readonly type = "available_agents_response" as const;
|
|
13
|
+
readonly schema = AvailableAgentsResponseSchema;
|
|
14
|
+
|
|
15
|
+
protected handleValidated(message: AvailableAgentsResponse, context: HandlerContext): void {
|
|
16
|
+
const { agents } = message.data;
|
|
17
|
+
|
|
18
|
+
context.logger.debug("Handling available_agents_response", {
|
|
19
|
+
agentCount: agents?.length || 0
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
// Parse agents array (handle undefined as empty array)
|
|
23
|
+
const agentList: AgentRoomInfo[] = agents || [];
|
|
24
|
+
|
|
25
|
+
context.logger.info("Available agents listed", {
|
|
26
|
+
count: agentList.length
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Note: We don't cache this globally since it's room-specific
|
|
30
|
+
// The AgentRoomManager will cache it with the room context
|
|
31
|
+
|
|
32
|
+
// Emit success event
|
|
33
|
+
this.emit(context, "agent_room:available_agents_listed", agentList);
|
|
34
|
+
|
|
35
|
+
// Send webhook
|
|
36
|
+
this.sendWebhook(context, "available_agents_listed", {
|
|
37
|
+
agents: agentList,
|
|
38
|
+
count: agentList.length
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Handler for room_agents_response messages (v2.0.0)
|
|
3
|
+
* Processes responses from list_room_agents requests
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { RoomAgentsResponse, RoomAgentsResponseSchema } from "../../types";
|
|
7
|
+
import { BaseMessageHandler } from "./base-handler";
|
|
8
|
+
import { HandlerContext } from "./types";
|
|
9
|
+
import { SDKError } from "../../types/events";
|
|
10
|
+
import { ErrorCode } from "../../types/error-codes";
|
|
11
|
+
import { AgentRoomInfo } from "../../managers/agent-room-manager";
|
|
12
|
+
|
|
13
|
+
export class ListRoomAgentsHandler extends BaseMessageHandler<RoomAgentsResponse> {
|
|
14
|
+
readonly type = "room_agents_response" as const;
|
|
15
|
+
readonly schema = RoomAgentsResponseSchema;
|
|
16
|
+
|
|
17
|
+
protected handleValidated(
|
|
18
|
+
message: RoomAgentsResponse,
|
|
19
|
+
context: HandlerContext
|
|
20
|
+
): void {
|
|
21
|
+
const { room_id, agents } = message.data;
|
|
22
|
+
|
|
23
|
+
context.logger.debug("Handling room_agents_response", {
|
|
24
|
+
roomId: room_id,
|
|
25
|
+
agentCount: agents?.length || 0
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
if (!room_id) {
|
|
29
|
+
const error = new SDKError(
|
|
30
|
+
"Room agents response missing room_id",
|
|
31
|
+
ErrorCode.VALIDATION_ERROR
|
|
32
|
+
);
|
|
33
|
+
this.emit(context, "agent_room:list_error", error, undefined);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Parse agents array (handle undefined as empty array)
|
|
38
|
+
const agentList: AgentRoomInfo[] = agents || [];
|
|
39
|
+
|
|
40
|
+
context.logger.info("Room agents listed", {
|
|
41
|
+
roomId: room_id,
|
|
42
|
+
count: agentList.length
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Cache via agent room manager if available
|
|
46
|
+
const agentRoomManager = (context as any).agentRoomManager;
|
|
47
|
+
if (agentRoomManager && typeof agentRoomManager.cacheRoomAgents === "function") {
|
|
48
|
+
agentRoomManager.cacheRoomAgents(room_id, agentList);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Emit success event
|
|
52
|
+
this.emit(context, "agent_room:agents_listed", room_id, agentList);
|
|
53
|
+
|
|
54
|
+
// Send webhook
|
|
55
|
+
this.sendWebhook(context, "room_agents_listed", {
|
|
56
|
+
room_id,
|
|
57
|
+
agents: agentList,
|
|
58
|
+
count: agentList.length
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -54,6 +54,7 @@ export class RegularMessageHandler extends BaseMessageHandler<UserMessage> {
|
|
|
54
54
|
contentType: message.content_type || "text/plain",
|
|
55
55
|
success: true,
|
|
56
56
|
timestamp: new Date(),
|
|
57
|
+
raw: message as any, // Include raw message for request correlation
|
|
57
58
|
humanized:
|
|
58
59
|
typeof message.content === "string" ? message.content : JSON.stringify(message.content)
|
|
59
60
|
};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Handler for room_operation_response messages (v2.0.0)
|
|
3
|
+
* Processes responses from room CRUD operations (create, update, delete)
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { RoomOperationResponse, RoomOperationResponseSchema } from "../../types";
|
|
7
|
+
import { BaseMessageHandler } from "./base-handler";
|
|
8
|
+
import { HandlerContext } from "./types";
|
|
9
|
+
import { SDKError } from "../../types/events";
|
|
10
|
+
import { ErrorCode } from "../../types/error-codes";
|
|
11
|
+
|
|
12
|
+
export class RoomOperationResponseHandler extends BaseMessageHandler<RoomOperationResponse> {
|
|
13
|
+
readonly type = "room_operation_response" as const;
|
|
14
|
+
readonly schema = RoomOperationResponseSchema;
|
|
15
|
+
|
|
16
|
+
protected handleValidated(
|
|
17
|
+
message: RoomOperationResponse,
|
|
18
|
+
context: HandlerContext
|
|
19
|
+
): void {
|
|
20
|
+
const { success, message: errorMessage, room_id, room } = message.data;
|
|
21
|
+
|
|
22
|
+
context.logger.debug("Handling room_operation_response", {
|
|
23
|
+
success,
|
|
24
|
+
roomId: room_id,
|
|
25
|
+
hasRoom: !!room
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
if (!success) {
|
|
29
|
+
// Operation failed - emit error event
|
|
30
|
+
const error = new SDKError(
|
|
31
|
+
errorMessage || "Room operation failed",
|
|
32
|
+
ErrorCode.OPERATION_FAILED
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
// Try to determine operation type from message
|
|
36
|
+
// Note: Server should ideally send operation type in response
|
|
37
|
+
// For now we emit generic errors and specific listeners will catch relevant ones
|
|
38
|
+
this.emit(context, "room:create_error", error);
|
|
39
|
+
this.emit(context, "room:update_error", error, room_id);
|
|
40
|
+
this.emit(context, "room:delete_error", error, room_id);
|
|
41
|
+
|
|
42
|
+
// Send webhook
|
|
43
|
+
this.sendWebhook(context, "room_operation_error", {
|
|
44
|
+
success: false,
|
|
45
|
+
message: errorMessage,
|
|
46
|
+
room_id
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Operation succeeded
|
|
53
|
+
if (room) {
|
|
54
|
+
// Create or Update operation (includes room object)
|
|
55
|
+
context.logger.info("Room operation succeeded", {
|
|
56
|
+
roomId: room.id,
|
|
57
|
+
roomName: room.name
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Determine if this was create or update based on whether we have the room cached
|
|
61
|
+
// Note: Ideally server would send operation type in response
|
|
62
|
+
// For now, handlers will emit both and listeners filter by room_id
|
|
63
|
+
|
|
64
|
+
// Update cache via room management manager if available
|
|
65
|
+
const roomManager = (context as any).roomManagementManager;
|
|
66
|
+
if (roomManager && typeof roomManager.upsertRoom === "function") {
|
|
67
|
+
roomManager.upsertRoom(room);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Emit success events
|
|
71
|
+
// The promise handlers in RoomManagementManager will filter by room_id
|
|
72
|
+
this.emit(context, "room:created", room);
|
|
73
|
+
this.emit(context, "room:updated", room);
|
|
74
|
+
|
|
75
|
+
// Send webhook
|
|
76
|
+
this.sendWebhook(context, "room_operation", {
|
|
77
|
+
success: true,
|
|
78
|
+
room,
|
|
79
|
+
message: "Room operation completed successfully"
|
|
80
|
+
});
|
|
81
|
+
} else if (room_id) {
|
|
82
|
+
// Delete operation (only has room_id, no room object)
|
|
83
|
+
context.logger.info("Room deleted", { roomId: room_id });
|
|
84
|
+
|
|
85
|
+
// Remove from cache
|
|
86
|
+
const roomManager = (context as any).roomManagementManager;
|
|
87
|
+
if (roomManager && typeof roomManager.removeRoom === "function") {
|
|
88
|
+
roomManager.removeRoom(room_id);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Emit delete success
|
|
92
|
+
this.emit(context, "room:deleted", room_id);
|
|
93
|
+
|
|
94
|
+
// Send webhook
|
|
95
|
+
this.sendWebhook(context, "room_deleted", {
|
|
96
|
+
success: true,
|
|
97
|
+
room_id,
|
|
98
|
+
message: "Room deleted successfully"
|
|
99
|
+
});
|
|
100
|
+
} else {
|
|
101
|
+
// Unexpected: success but no room or room_id
|
|
102
|
+
context.logger.warn("Room operation succeeded but no room data provided");
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -34,6 +34,12 @@ export interface HandlerContext {
|
|
|
34
34
|
// Room manager for subscription updates (optional)
|
|
35
35
|
roomManager?: any;
|
|
36
36
|
|
|
37
|
+
// Room management manager for CRUD operations (v2.0.0, optional)
|
|
38
|
+
roomManagementManager?: any;
|
|
39
|
+
|
|
40
|
+
// Agent room manager for agent-room operations (v2.0.0, optional)
|
|
41
|
+
agentRoomManager?: any;
|
|
42
|
+
|
|
37
43
|
// Account for signing (optional, for auth handlers)
|
|
38
44
|
account?: PrivateKeyAccount;
|
|
39
45
|
|
|
@@ -118,7 +118,10 @@ describe("WebhookHandler", () => {
|
|
|
118
118
|
expect(queue[0].payload.timestamp).toBeDefined();
|
|
119
119
|
expect(queue[1].payload.timestamp).toBeDefined();
|
|
120
120
|
// Each webhook gets unique timestamp
|
|
121
|
-
expect(
|
|
121
|
+
expect(
|
|
122
|
+
queue[0].payload.timestamp !== queue[1].payload.timestamp ||
|
|
123
|
+
queue[0].payload.data.content !== queue[1].payload.data.content
|
|
124
|
+
).toBe(true);
|
|
122
125
|
});
|
|
123
126
|
|
|
124
127
|
it("should include timestamp in webhook payload", async () => {
|
|
@@ -584,20 +587,17 @@ describe("WebhookHandler", () => {
|
|
|
584
587
|
|
|
585
588
|
describe("Protocol Validation", () => {
|
|
586
589
|
it("should reject HTTP for non-localhost without allowInsecureWebhooks", () => {
|
|
587
|
-
const urls = [
|
|
588
|
-
"http://example.com/webhook"
|
|
589
|
-
];
|
|
590
|
+
const urls = ["http://example.com/webhook"];
|
|
590
591
|
|
|
591
592
|
urls.forEach((url) => {
|
|
592
593
|
expect(() => (handler as any).validateWebhookUrl(url)).toThrow(WebhookError);
|
|
593
|
-
expect(() => (handler as any).validateWebhookUrl(url)).toThrow(
|
|
594
|
+
expect(() => (handler as any).validateWebhookUrl(url)).toThrow(
|
|
595
|
+
/must use HTTPS|Only HTTPS/i
|
|
596
|
+
);
|
|
594
597
|
});
|
|
595
598
|
|
|
596
599
|
// Private IPs are blocked for different reason (private IP, not HTTPS requirement)
|
|
597
|
-
const privateUrls = [
|
|
598
|
-
"http://192.168.1.1/webhook",
|
|
599
|
-
"http://10.0.0.1/webhook"
|
|
600
|
-
];
|
|
600
|
+
const privateUrls = ["http://192.168.1.1/webhook", "http://10.0.0.1/webhook"];
|
|
601
601
|
privateUrls.forEach((url) => {
|
|
602
602
|
expect(() => (handler as any).validateWebhookUrl(url)).toThrow(WebhookError);
|
|
603
603
|
expect(() => (handler as any).validateWebhookUrl(url)).toThrow(/private IP/i);
|
|
@@ -720,7 +720,10 @@ describe("WebhookHandler", () => {
|
|
|
720
720
|
vi.advanceTimersByTime(10000);
|
|
721
721
|
}
|
|
722
722
|
|
|
723
|
-
expect(errorHandler).toHaveBeenCalledWith(
|
|
723
|
+
expect(errorHandler).toHaveBeenCalledWith(
|
|
724
|
+
expect.any(Error),
|
|
725
|
+
"https://webhook.example.com/events"
|
|
726
|
+
);
|
|
724
727
|
});
|
|
725
728
|
});
|
|
726
729
|
|