@teneo-protocol/sdk 2.2.2 → 3.0.1
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/ISSUE_TEMPLATE/config.yml +1 -1
- package/CHANGELOG.md +366 -15
- package/CONCEPTS.md +182 -44
- package/README.md +524 -94
- package/dist/constants.d.ts +3 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +5 -3
- package/dist/constants.js.map +1 -1
- package/dist/core/websocket-client.d.ts.map +1 -1
- package/dist/core/websocket-client.js +9 -5
- package/dist/core/websocket-client.js.map +1 -1
- package/dist/formatters/response-formatter.d.ts +6 -6
- package/dist/handlers/message-handlers/agent-details-response-handler.d.ts +1080 -756
- package/dist/handlers/message-handlers/agent-details-response-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/agent-details-response-handler.js +2 -2
- package/dist/handlers/message-handlers/agent-details-response-handler.js.map +1 -1
- package/dist/handlers/message-handlers/agent-error-handler.d.ts +91 -0
- package/dist/handlers/message-handlers/agent-error-handler.d.ts.map +1 -0
- package/dist/handlers/message-handlers/agent-error-handler.js +44 -0
- package/dist/handlers/message-handlers/agent-error-handler.js.map +1 -0
- package/dist/handlers/message-handlers/agent-selected-handler.d.ts +6 -0
- package/dist/handlers/message-handlers/agent-selected-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/agent-status-update-handler.d.ts +1080 -756
- package/dist/handlers/message-handlers/agent-status-update-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/agent-status-update-handler.js +2 -7
- package/dist/handlers/message-handlers/agent-status-update-handler.js.map +1 -1
- package/dist/handlers/message-handlers/all-agents-response-handler.d.ts +135 -54
- package/dist/handlers/message-handlers/all-agents-response-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/all-agents-response-handler.js +2 -2
- package/dist/handlers/message-handlers/all-agents-response-handler.js.map +1 -1
- package/dist/handlers/message-handlers/auth-error-handler.d.ts +6 -0
- package/dist/handlers/message-handlers/auth-error-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/auth-message-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/auth-message-handler.js +6 -1
- package/dist/handlers/message-handlers/auth-message-handler.js.map +1 -1
- package/dist/handlers/message-handlers/auth-required-handler.d.ts +6 -0
- package/dist/handlers/message-handlers/auth-required-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/auth-success-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/auth-success-handler.js +6 -1
- package/dist/handlers/message-handlers/auth-success-handler.js.map +1 -1
- package/dist/handlers/message-handlers/base-handler.d.ts +2 -1
- package/dist/handlers/message-handlers/base-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/base-handler.js +24 -4
- package/dist/handlers/message-handlers/base-handler.js.map +1 -1
- package/dist/handlers/message-handlers/challenge-handler.d.ts +6 -0
- package/dist/handlers/message-handlers/challenge-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/error-message-handler.d.ts +6 -0
- package/dist/handlers/message-handlers/error-message-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/index.d.ts +4 -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 +1116 -756
- package/dist/handlers/message-handlers/list-available-agents-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/list-available-agents-handler.js +23 -10
- package/dist/handlers/message-handlers/list-available-agents-handler.js.map +1 -1
- package/dist/handlers/message-handlers/list-room-agents-handler.d.ts +1080 -756
- package/dist/handlers/message-handlers/list-room-agents-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/list-room-agents-handler.js +2 -6
- package/dist/handlers/message-handlers/list-room-agents-handler.js.map +1 -1
- package/dist/handlers/message-handlers/list-rooms-response-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/list-rooms-response-handler.js +2 -5
- package/dist/handlers/message-handlers/list-rooms-response-handler.js.map +1 -1
- package/dist/handlers/message-handlers/ping-pong-handler.d.ts +52 -4
- package/dist/handlers/message-handlers/ping-pong-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/ping-pong-handler.js +23 -4
- package/dist/handlers/message-handlers/ping-pong-handler.js.map +1 -1
- package/dist/handlers/message-handlers/rate-limit-notification-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/rate-limit-notification-handler.js +3 -2
- package/dist/handlers/message-handlers/rate-limit-notification-handler.js.map +1 -1
- package/dist/handlers/message-handlers/regular-message-handler.d.ts +6 -0
- package/dist/handlers/message-handlers/regular-message-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/subscribe-response-handler.d.ts +12 -6
- package/dist/handlers/message-handlers/subscribe-response-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/success-handler.d.ts +82 -0
- package/dist/handlers/message-handlers/success-handler.d.ts.map +1 -0
- package/dist/handlers/message-handlers/success-handler.js +24 -0
- package/dist/handlers/message-handlers/success-handler.js.map +1 -0
- package/dist/handlers/message-handlers/task-confirmed-handler.d.ts +110 -0
- package/dist/handlers/message-handlers/task-confirmed-handler.d.ts.map +1 -0
- package/dist/handlers/message-handlers/task-confirmed-handler.js +46 -0
- package/dist/handlers/message-handlers/task-confirmed-handler.js.map +1 -0
- package/dist/handlers/message-handlers/trigger-wallet-tx-handler.d.ts +244 -0
- package/dist/handlers/message-handlers/trigger-wallet-tx-handler.d.ts.map +1 -0
- package/dist/handlers/message-handlers/trigger-wallet-tx-handler.js +58 -0
- package/dist/handlers/message-handlers/trigger-wallet-tx-handler.js.map +1 -0
- package/dist/handlers/message-handlers/unsubscribe-response-handler.d.ts +12 -6
- package/dist/handlers/message-handlers/unsubscribe-response-handler.d.ts.map +1 -1
- package/dist/handlers/message-handlers/user-authenticated-handler.js +2 -2
- package/dist/handlers/message-handlers/user-authenticated-handler.js.map +1 -1
- package/dist/handlers/message-handlers/user-count-handler.js +2 -2
- package/dist/handlers/message-handlers/user-count-handler.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -4
- package/dist/index.js.map +1 -1
- package/dist/managers/admin-manager.d.ts +3 -1
- package/dist/managers/admin-manager.d.ts.map +1 -1
- package/dist/managers/admin-manager.js +4 -3
- package/dist/managers/admin-manager.js.map +1 -1
- package/dist/managers/agent-room-manager.d.ts +89 -11
- package/dist/managers/agent-room-manager.d.ts.map +1 -1
- package/dist/managers/agent-room-manager.js +99 -35
- package/dist/managers/agent-room-manager.js.map +1 -1
- package/dist/managers/index.d.ts +1 -1
- package/dist/managers/index.d.ts.map +1 -1
- package/dist/managers/index.js.map +1 -1
- package/dist/managers/message-router.d.ts +45 -5
- package/dist/managers/message-router.d.ts.map +1 -1
- package/dist/managers/message-router.js +96 -24
- package/dist/managers/message-router.js.map +1 -1
- package/dist/managers/room-manager.d.ts +29 -7
- package/dist/managers/room-manager.d.ts.map +1 -1
- package/dist/managers/room-manager.js +37 -11
- package/dist/managers/room-manager.js.map +1 -1
- package/dist/payments/index.d.ts +3 -1
- package/dist/payments/index.d.ts.map +1 -1
- package/dist/payments/index.js +17 -3
- package/dist/payments/index.js.map +1 -1
- package/dist/payments/networks.d.ts +59 -0
- package/dist/payments/networks.d.ts.map +1 -0
- package/dist/payments/networks.js +192 -0
- package/dist/payments/networks.js.map +1 -0
- package/dist/payments/payment-client.d.ts +55 -10
- package/dist/payments/payment-client.d.ts.map +1 -1
- package/dist/payments/payment-client.js +172 -51
- package/dist/payments/payment-client.js.map +1 -1
- package/dist/teneo-sdk.d.ts +215 -41
- package/dist/teneo-sdk.d.ts.map +1 -1
- package/dist/teneo-sdk.js +361 -84
- package/dist/teneo-sdk.js.map +1 -1
- package/dist/types/config.d.ts +334 -25
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/config.js +114 -22
- package/dist/types/config.js.map +1 -1
- package/dist/types/events.d.ts +60 -14
- 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 +11 -4
- package/dist/types/index.js.map +1 -1
- package/dist/types/messages.d.ts +13110 -7451
- package/dist/types/messages.d.ts.map +1 -1
- package/dist/types/messages.js +195 -44
- package/dist/types/messages.js.map +1 -1
- package/dist/utils/pricing-resolver.d.ts +1 -1
- package/dist/utils/pricing-resolver.d.ts.map +1 -1
- package/dist/utils/pricing-resolver.js +9 -1
- package/dist/utils/pricing-resolver.js.map +1 -1
- package/examples/agent-room-management-example.ts +5 -5
- package/examples/basic-usage.ts +26 -6
- package/examples/claude-agent-x-follower/index.ts +1 -1
- package/examples/minimal-chat.ts +4 -3
- package/examples/n8n-teneo/index.ts +2 -2
- package/examples/nestjs-dashboard/README.md +1 -1
- package/examples/nestjs-dashboard/src/teneo/agents.controller.ts +3 -3
- package/examples/nestjs-dashboard/src/teneo/rooms.controller.ts +5 -5
- package/examples/nestjs-dashboard/src/teneo/teneo.service.ts +8 -8
- package/examples/openai-teneo/index.ts +1 -1
- package/examples/payment-flow.ts +143 -0
- package/examples/production-dashboard/README.md +6 -8
- package/examples/production-dashboard/server.ts +22 -10
- package/examples/room-management-example.ts +2 -2
- package/examples/usage/01-connect.ts +0 -3
- package/examples/usage/02-list-agents.ts +0 -2
- package/examples/usage/03-pick-agent.ts +3 -4
- package/examples/usage/04-find-by-capability.ts +10 -12
- package/examples/usage/05-webhook-example.ts +2 -4
- package/examples/usage/06-simple-api-server.ts +13 -9
- package/examples/usage/07-event-listener.ts +1 -13
- package/examples/usage/README.md +33 -7
- package/examples/webhook-integration.ts +9 -9
- package/examples/x-influencer-battle-server.ts +1 -1
- package/package.json +1 -1
- package/scripts/diagnose-connection.ts +86 -0
- package/scripts/investigate-payload.ts +163 -0
- package/scripts/list-agents.ts +58 -0
- package/scripts/live-multi-network-test.ts +230 -0
- package/src/constants.ts +5 -3
- package/src/core/websocket-client.ts +10 -9
- package/src/handlers/message-handlers/agent-details-response-handler.ts +2 -2
- package/src/handlers/message-handlers/agent-error-handler.ts +47 -0
- package/src/handlers/message-handlers/agent-status-update-handler.ts +2 -7
- package/src/handlers/message-handlers/all-agents-response-handler.ts +2 -2
- package/src/handlers/message-handlers/auth-message-handler.ts +7 -1
- package/src/handlers/message-handlers/auth-success-handler.ts +7 -1
- package/src/handlers/message-handlers/base-handler.ts +24 -4
- package/src/handlers/message-handlers/index.ts +24 -0
- package/src/handlers/message-handlers/list-available-agents-handler.ts +24 -11
- package/src/handlers/message-handlers/list-room-agents-handler.ts +2 -6
- package/src/handlers/message-handlers/list-rooms-response-handler.ts +2 -5
- package/src/handlers/message-handlers/ping-pong-handler.ts +29 -4
- package/src/handlers/message-handlers/rate-limit-notification-handler.ts +3 -2
- package/src/handlers/message-handlers/success-handler.ts +26 -0
- package/src/handlers/message-handlers/task-confirmed-handler.ts +49 -0
- package/src/handlers/message-handlers/trigger-wallet-tx-handler.ts +62 -0
- package/src/handlers/message-handlers/user-authenticated-handler.ts +2 -2
- package/src/handlers/message-handlers/user-count-handler.ts +2 -2
- package/src/index.ts +12 -4
- package/src/managers/admin-manager.ts +6 -3
- package/src/managers/agent-room-manager.ts +155 -26
- package/src/managers/index.ts +6 -1
- package/src/managers/message-router.ts +122 -27
- package/src/managers/room-manager.ts +39 -11
- package/src/payments/index.ts +20 -5
- package/src/payments/networks.ts +208 -0
- package/src/payments/payment-client.ts +211 -56
- package/src/teneo-sdk.ts +402 -71
- package/src/types/config.test.ts +24 -4
- package/src/types/config.ts +123 -25
- package/src/types/events.ts +36 -2
- package/src/types/index.ts +16 -3
- package/src/types/messages.ts +235 -60
- package/src/utils/pricing-resolver.ts +10 -2
- package/tests/direct-agent-test.ts +1 -1
- package/tests/integration/real-server.test.ts +1 -1
- package/tests/integration/websocket.test.ts +3 -3
- package/tests/multi-network-payment.test.ts +309 -0
- package/tests/multi-network.test.ts +296 -0
- package/tests/payment-flow-test.ts +6 -4
- package/tests/unit/handlers/agent-error-handler.test.ts +388 -0
- package/tests/unit/handlers/agent-room-operation-response-handler.test.ts +9 -6
- package/tests/unit/handlers/agent-status-update-handler.test.ts +11 -16
- package/tests/unit/handlers/list-available-agents-handler.test.ts +11 -14
- package/tests/unit/handlers/list-room-agents-handler.test.ts +11 -15
- package/tests/unit/handlers/room-operation-response-handler.test.ts +9 -6
- package/tests/unit/handlers/trigger-wallet-tx-handler.test.ts +431 -0
- package/tests/unit/managers/admin-manager.test.ts +183 -0
- package/tests/unit/managers/agent-room-manager.test.ts +189 -33
- package/tests/unit/sdk-new-methods.test.ts +221 -0
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for TriggerWalletTxHandler
|
|
3
|
+
* Tests handling of trigger_wallet_tx messages from the server
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, it, expect, beforeEach, vi } from "vitest";
|
|
7
|
+
import { TriggerWalletTxHandler } from "../../../src/handlers/message-handlers/trigger-wallet-tx-handler";
|
|
8
|
+
import { HandlerContext } from "../../../src/handlers/message-handlers/types";
|
|
9
|
+
import { Logger } from "../../../src/types";
|
|
10
|
+
|
|
11
|
+
describe("TriggerWalletTxHandler", () => {
|
|
12
|
+
let handler: TriggerWalletTxHandler;
|
|
13
|
+
let mockContext: HandlerContext;
|
|
14
|
+
let mockLogger: Logger;
|
|
15
|
+
let emitSpy: ReturnType<typeof vi.fn>;
|
|
16
|
+
let sendWebhookSpy: ReturnType<typeof vi.fn>;
|
|
17
|
+
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
// Create mock logger
|
|
20
|
+
mockLogger = {
|
|
21
|
+
debug: vi.fn(),
|
|
22
|
+
info: vi.fn(),
|
|
23
|
+
warn: vi.fn(),
|
|
24
|
+
error: vi.fn()
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// Create spies
|
|
28
|
+
emitSpy = vi.fn();
|
|
29
|
+
sendWebhookSpy = vi.fn().mockResolvedValue(undefined);
|
|
30
|
+
|
|
31
|
+
// Create mock context
|
|
32
|
+
mockContext = {
|
|
33
|
+
emit: emitSpy,
|
|
34
|
+
sendWebhook: sendWebhookSpy,
|
|
35
|
+
logger: mockLogger,
|
|
36
|
+
getConnectionState: vi.fn(),
|
|
37
|
+
getAuthState: vi.fn(),
|
|
38
|
+
updateConnectionState: vi.fn(),
|
|
39
|
+
updateAuthState: vi.fn(),
|
|
40
|
+
sendMessage: vi.fn()
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// Create handler instance
|
|
44
|
+
handler = new TriggerWalletTxHandler();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe("Handler Metadata", () => {
|
|
48
|
+
it("should have correct type", () => {
|
|
49
|
+
expect(handler.type).toBe("trigger_wallet_tx");
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("should have schema defined", () => {
|
|
53
|
+
expect(handler.schema).toBeDefined();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("should identify messages it can handle", () => {
|
|
57
|
+
const message = { type: "trigger_wallet_tx", data: {} };
|
|
58
|
+
expect(handler.canHandle(message as any)).toBe(true);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("should not handle other message types", () => {
|
|
62
|
+
const message = { type: "other_type", data: {} };
|
|
63
|
+
expect(handler.canHandle(message as any)).toBe(false);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
describe("Response Handling", () => {
|
|
68
|
+
it("should handle full message with all fields", async () => {
|
|
69
|
+
const message = {
|
|
70
|
+
type: "trigger_wallet_tx" as const,
|
|
71
|
+
from: "weather-agent",
|
|
72
|
+
data: {
|
|
73
|
+
task_id: "task-123",
|
|
74
|
+
tx: {
|
|
75
|
+
to: "0xRecipient",
|
|
76
|
+
value: "1000000000000000000",
|
|
77
|
+
data: "0xabcdef",
|
|
78
|
+
chainId: 1
|
|
79
|
+
},
|
|
80
|
+
description: "Pay for weather data",
|
|
81
|
+
optional: true
|
|
82
|
+
},
|
|
83
|
+
room: "room-456"
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
await handler.handle(message, mockContext);
|
|
87
|
+
|
|
88
|
+
// Should emit event
|
|
89
|
+
expect(emitSpy).toHaveBeenCalledWith("wallet:tx_requested", {
|
|
90
|
+
taskId: "task-123",
|
|
91
|
+
agentName: "weather-agent",
|
|
92
|
+
tx: {
|
|
93
|
+
to: "0xRecipient",
|
|
94
|
+
value: "1000000000000000000",
|
|
95
|
+
data: "0xabcdef",
|
|
96
|
+
chainId: 1
|
|
97
|
+
},
|
|
98
|
+
description: "Pay for weather data",
|
|
99
|
+
optional: true,
|
|
100
|
+
room: "room-456"
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// Should send webhook
|
|
104
|
+
expect(sendWebhookSpy).toHaveBeenCalledWith(
|
|
105
|
+
"wallet_tx_requested",
|
|
106
|
+
expect.objectContaining({
|
|
107
|
+
taskId: "task-123",
|
|
108
|
+
agentName: "weather-agent",
|
|
109
|
+
tx: {
|
|
110
|
+
to: "0xRecipient",
|
|
111
|
+
value: "1000000000000000000",
|
|
112
|
+
data: "0xabcdef",
|
|
113
|
+
chainId: 1
|
|
114
|
+
},
|
|
115
|
+
description: "Pay for weather data",
|
|
116
|
+
optional: true,
|
|
117
|
+
room: "room-456"
|
|
118
|
+
}),
|
|
119
|
+
undefined
|
|
120
|
+
);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("should handle minimal message with only required fields", async () => {
|
|
124
|
+
const message = {
|
|
125
|
+
type: "trigger_wallet_tx" as const,
|
|
126
|
+
data: {
|
|
127
|
+
task_id: "task-minimal",
|
|
128
|
+
tx: {
|
|
129
|
+
to: "0xTarget",
|
|
130
|
+
value: "0",
|
|
131
|
+
chainId: 42161
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
await handler.handle(message, mockContext);
|
|
137
|
+
|
|
138
|
+
// Should emit event with defaults
|
|
139
|
+
expect(emitSpy).toHaveBeenCalledWith("wallet:tx_requested", {
|
|
140
|
+
taskId: "task-minimal",
|
|
141
|
+
agentName: undefined,
|
|
142
|
+
tx: {
|
|
143
|
+
to: "0xTarget",
|
|
144
|
+
value: "0",
|
|
145
|
+
chainId: 42161
|
|
146
|
+
},
|
|
147
|
+
description: undefined,
|
|
148
|
+
optional: false,
|
|
149
|
+
room: undefined
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it("should handle message without optional tx.data field", async () => {
|
|
154
|
+
const message = {
|
|
155
|
+
type: "trigger_wallet_tx" as const,
|
|
156
|
+
from: "swap-agent",
|
|
157
|
+
data: {
|
|
158
|
+
task_id: "task-no-data",
|
|
159
|
+
tx: {
|
|
160
|
+
to: "0xContract",
|
|
161
|
+
value: "500000000000000000",
|
|
162
|
+
chainId: 10
|
|
163
|
+
},
|
|
164
|
+
description: "Simple ETH transfer"
|
|
165
|
+
},
|
|
166
|
+
room: "room-789"
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
await handler.handle(message, mockContext);
|
|
170
|
+
|
|
171
|
+
expect(emitSpy).toHaveBeenCalledWith("wallet:tx_requested", {
|
|
172
|
+
taskId: "task-no-data",
|
|
173
|
+
agentName: "swap-agent",
|
|
174
|
+
tx: {
|
|
175
|
+
to: "0xContract",
|
|
176
|
+
value: "500000000000000000",
|
|
177
|
+
chainId: 10
|
|
178
|
+
},
|
|
179
|
+
description: "Simple ETH transfer",
|
|
180
|
+
optional: false,
|
|
181
|
+
room: "room-789"
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
describe("Event Emission", () => {
|
|
187
|
+
it("should emit wallet:tx_requested with correct shape", async () => {
|
|
188
|
+
const message = {
|
|
189
|
+
type: "trigger_wallet_tx" as const,
|
|
190
|
+
from: "defi-agent",
|
|
191
|
+
data: {
|
|
192
|
+
task_id: "task-emit",
|
|
193
|
+
tx: {
|
|
194
|
+
to: "0xDeFiContract",
|
|
195
|
+
value: "2000000000000000000",
|
|
196
|
+
data: "0x1234",
|
|
197
|
+
chainId: 137
|
|
198
|
+
},
|
|
199
|
+
description: "Swap tokens",
|
|
200
|
+
optional: true
|
|
201
|
+
},
|
|
202
|
+
room: "room-emit"
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
await handler.handle(message, mockContext);
|
|
206
|
+
|
|
207
|
+
expect(emitSpy).toHaveBeenCalledWith("wallet:tx_requested", {
|
|
208
|
+
taskId: "task-emit",
|
|
209
|
+
agentName: "defi-agent",
|
|
210
|
+
tx: {
|
|
211
|
+
to: "0xDeFiContract",
|
|
212
|
+
value: "2000000000000000000",
|
|
213
|
+
data: "0x1234",
|
|
214
|
+
chainId: 137
|
|
215
|
+
},
|
|
216
|
+
description: "Swap tokens",
|
|
217
|
+
optional: true,
|
|
218
|
+
room: "room-emit"
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it("should default optional to false when not provided", async () => {
|
|
223
|
+
const message = {
|
|
224
|
+
type: "trigger_wallet_tx" as const,
|
|
225
|
+
from: "agent-no-optional",
|
|
226
|
+
data: {
|
|
227
|
+
task_id: "task-default",
|
|
228
|
+
tx: {
|
|
229
|
+
to: "0xAddr",
|
|
230
|
+
value: "100",
|
|
231
|
+
chainId: 1
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
await handler.handle(message, mockContext);
|
|
237
|
+
|
|
238
|
+
expect(emitSpy).toHaveBeenCalledWith(
|
|
239
|
+
"wallet:tx_requested",
|
|
240
|
+
expect.objectContaining({
|
|
241
|
+
optional: false
|
|
242
|
+
})
|
|
243
|
+
);
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
describe("Webhook", () => {
|
|
248
|
+
it("should send wallet_tx_requested webhook", async () => {
|
|
249
|
+
const message = {
|
|
250
|
+
type: "trigger_wallet_tx" as const,
|
|
251
|
+
from: "webhook-agent",
|
|
252
|
+
data: {
|
|
253
|
+
task_id: "task-webhook",
|
|
254
|
+
tx: {
|
|
255
|
+
to: "0xWebhookTarget",
|
|
256
|
+
value: "0",
|
|
257
|
+
chainId: 1
|
|
258
|
+
},
|
|
259
|
+
description: "Webhook test tx",
|
|
260
|
+
optional: false
|
|
261
|
+
},
|
|
262
|
+
room: "room-wh"
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
await handler.handle(message, mockContext);
|
|
266
|
+
|
|
267
|
+
expect(sendWebhookSpy).toHaveBeenCalledWith(
|
|
268
|
+
"wallet_tx_requested",
|
|
269
|
+
expect.objectContaining({
|
|
270
|
+
taskId: "task-webhook",
|
|
271
|
+
agentName: "webhook-agent",
|
|
272
|
+
tx: {
|
|
273
|
+
to: "0xWebhookTarget",
|
|
274
|
+
value: "0",
|
|
275
|
+
chainId: 1
|
|
276
|
+
},
|
|
277
|
+
description: "Webhook test tx",
|
|
278
|
+
optional: false,
|
|
279
|
+
room: "room-wh"
|
|
280
|
+
}),
|
|
281
|
+
undefined
|
|
282
|
+
);
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
it("should handle webhook failure gracefully", async () => {
|
|
286
|
+
const webhookError = new Error("Webhook failed");
|
|
287
|
+
sendWebhookSpy.mockRejectedValueOnce(webhookError);
|
|
288
|
+
|
|
289
|
+
const message = {
|
|
290
|
+
type: "trigger_wallet_tx" as const,
|
|
291
|
+
from: "fail-agent",
|
|
292
|
+
data: {
|
|
293
|
+
task_id: "task-fail",
|
|
294
|
+
tx: {
|
|
295
|
+
to: "0xFailTarget",
|
|
296
|
+
value: "0",
|
|
297
|
+
chainId: 1
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
// Should not throw
|
|
303
|
+
await handler.handle(message, mockContext);
|
|
304
|
+
|
|
305
|
+
// Should still emit event
|
|
306
|
+
expect(emitSpy).toHaveBeenCalledWith(
|
|
307
|
+
"wallet:tx_requested",
|
|
308
|
+
expect.objectContaining({
|
|
309
|
+
taskId: "task-fail"
|
|
310
|
+
})
|
|
311
|
+
);
|
|
312
|
+
});
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
describe("Message Validation", () => {
|
|
316
|
+
it("should handle invalid message structure (missing data)", async () => {
|
|
317
|
+
const invalidMessage = {
|
|
318
|
+
type: "trigger_wallet_tx"
|
|
319
|
+
// Missing data field
|
|
320
|
+
} as any;
|
|
321
|
+
|
|
322
|
+
await handler.handle(invalidMessage, mockContext);
|
|
323
|
+
|
|
324
|
+
// Should log validation warning at debug level (resilience pattern)
|
|
325
|
+
expect(mockLogger.debug).toHaveBeenCalledWith(
|
|
326
|
+
expect.stringContaining("trigger_wallet_tx message validation warning"),
|
|
327
|
+
expect.any(Object)
|
|
328
|
+
);
|
|
329
|
+
|
|
330
|
+
// Handler validates and logs specific warning message
|
|
331
|
+
expect(mockLogger.warn).toHaveBeenCalledWith(
|
|
332
|
+
"Invalid trigger_wallet_tx message: missing required fields",
|
|
333
|
+
expect.objectContaining({
|
|
334
|
+
hasData: false,
|
|
335
|
+
hasTaskId: false,
|
|
336
|
+
hasTx: false
|
|
337
|
+
})
|
|
338
|
+
);
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
it("should accept valid message with extra fields via passthrough", async () => {
|
|
342
|
+
const message = {
|
|
343
|
+
type: "trigger_wallet_tx" as const,
|
|
344
|
+
from: "extra-agent",
|
|
345
|
+
data: {
|
|
346
|
+
task_id: "task-extra",
|
|
347
|
+
tx: {
|
|
348
|
+
to: "0xExtra",
|
|
349
|
+
value: "0",
|
|
350
|
+
chainId: 1
|
|
351
|
+
},
|
|
352
|
+
extra_field: "should be kept",
|
|
353
|
+
another_extra: 123
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
// Should not throw
|
|
358
|
+
await handler.handle(message, mockContext);
|
|
359
|
+
|
|
360
|
+
expect(emitSpy).toHaveBeenCalledWith(
|
|
361
|
+
"wallet:tx_requested",
|
|
362
|
+
expect.objectContaining({
|
|
363
|
+
taskId: "task-extra",
|
|
364
|
+
agentName: "extra-agent"
|
|
365
|
+
})
|
|
366
|
+
);
|
|
367
|
+
});
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
describe("Debug Logging", () => {
|
|
371
|
+
it("should log at debug level", async () => {
|
|
372
|
+
const message = {
|
|
373
|
+
type: "trigger_wallet_tx" as const,
|
|
374
|
+
from: "log-agent",
|
|
375
|
+
data: {
|
|
376
|
+
task_id: "task-log",
|
|
377
|
+
tx: {
|
|
378
|
+
to: "0xLogTarget",
|
|
379
|
+
value: "999",
|
|
380
|
+
data: "0xdeadbeef",
|
|
381
|
+
chainId: 42161
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
await handler.handle(message, mockContext);
|
|
387
|
+
|
|
388
|
+
expect(mockLogger.debug).toHaveBeenCalledWith(
|
|
389
|
+
"Handling trigger_wallet_tx",
|
|
390
|
+
expect.objectContaining({
|
|
391
|
+
from: "log-agent",
|
|
392
|
+
taskId: "task-log",
|
|
393
|
+
tx: {
|
|
394
|
+
to: "0xLogTarget",
|
|
395
|
+
value: "999",
|
|
396
|
+
data: "0xdeadbeef",
|
|
397
|
+
chainId: 42161
|
|
398
|
+
}
|
|
399
|
+
})
|
|
400
|
+
);
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
it("should log at info level", async () => {
|
|
404
|
+
const message = {
|
|
405
|
+
type: "trigger_wallet_tx" as const,
|
|
406
|
+
from: "info-agent",
|
|
407
|
+
data: {
|
|
408
|
+
task_id: "task-info",
|
|
409
|
+
tx: {
|
|
410
|
+
to: "0xInfoTarget",
|
|
411
|
+
value: "12345",
|
|
412
|
+
chainId: 8453
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
await handler.handle(message, mockContext);
|
|
418
|
+
|
|
419
|
+
expect(mockLogger.info).toHaveBeenCalledWith(
|
|
420
|
+
"Wallet transaction requested",
|
|
421
|
+
expect.objectContaining({
|
|
422
|
+
agentName: "info-agent",
|
|
423
|
+
taskId: "task-info",
|
|
424
|
+
to: "0xInfoTarget",
|
|
425
|
+
value: "12345",
|
|
426
|
+
chainId: 8453
|
|
427
|
+
})
|
|
428
|
+
);
|
|
429
|
+
});
|
|
430
|
+
});
|
|
431
|
+
});
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for AdminManager
|
|
3
|
+
* Tests admin operations including listAllAgents with sortBy option
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, it, expect, beforeEach, vi } from "vitest";
|
|
7
|
+
import { AdminManager } from "../../../src/managers/admin-manager";
|
|
8
|
+
import { WebSocketClient } from "../../../src/core/websocket-client";
|
|
9
|
+
import { Logger } from "../../../src/types";
|
|
10
|
+
|
|
11
|
+
describe("AdminManager", () => {
|
|
12
|
+
let manager: AdminManager;
|
|
13
|
+
let mockWsClient: WebSocketClient;
|
|
14
|
+
let mockLogger: Logger;
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
mockLogger = {
|
|
18
|
+
debug: vi.fn(),
|
|
19
|
+
info: vi.fn(),
|
|
20
|
+
warn: vi.fn(),
|
|
21
|
+
error: vi.fn()
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
mockWsClient = {
|
|
25
|
+
isConnected: true,
|
|
26
|
+
sendMessage: vi.fn().mockResolvedValue(undefined)
|
|
27
|
+
} as any;
|
|
28
|
+
|
|
29
|
+
manager = new AdminManager(mockWsClient, mockLogger);
|
|
30
|
+
manager.setAdminStatus(true);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe("listAllAgents", () => {
|
|
34
|
+
const mockAgentsResponse = {
|
|
35
|
+
agents: [
|
|
36
|
+
{ agent_name: "Agent A", review_status: "public", is_banned: false },
|
|
37
|
+
{ agent_name: "Agent B", review_status: "private", is_banned: false }
|
|
38
|
+
],
|
|
39
|
+
total: 2,
|
|
40
|
+
offset: 0,
|
|
41
|
+
limit: 50,
|
|
42
|
+
has_more: false
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
it("should send sort_by when sortBy is 'a-z'", async () => {
|
|
46
|
+
const listPromise = manager.listAllAgents({ sortBy: "a-z" });
|
|
47
|
+
|
|
48
|
+
setTimeout(() => {
|
|
49
|
+
const call = (mockWsClient.sendMessage as ReturnType<typeof vi.fn>).mock.calls[0][0];
|
|
50
|
+
manager.handleAllAgentsResponse(mockAgentsResponse, call.request_id);
|
|
51
|
+
}, 10);
|
|
52
|
+
|
|
53
|
+
await listPromise;
|
|
54
|
+
|
|
55
|
+
const sentMessage = (mockWsClient.sendMessage as ReturnType<typeof vi.fn>).mock.calls[0][0];
|
|
56
|
+
expect(sentMessage).toMatchObject({
|
|
57
|
+
type: "list_all_agents",
|
|
58
|
+
sort_by: "a-z",
|
|
59
|
+
offset: 0,
|
|
60
|
+
limit: 50
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("should send sort_by when sortBy is 'requests'", async () => {
|
|
65
|
+
const listPromise = manager.listAllAgents({ sortBy: "requests" });
|
|
66
|
+
|
|
67
|
+
setTimeout(() => {
|
|
68
|
+
const call = (mockWsClient.sendMessage as ReturnType<typeof vi.fn>).mock.calls[0][0];
|
|
69
|
+
manager.handleAllAgentsResponse(mockAgentsResponse, call.request_id);
|
|
70
|
+
}, 10);
|
|
71
|
+
|
|
72
|
+
await listPromise;
|
|
73
|
+
|
|
74
|
+
const sentMessage = (mockWsClient.sendMessage as ReturnType<typeof vi.fn>).mock.calls[0][0];
|
|
75
|
+
expect(sentMessage).toMatchObject({
|
|
76
|
+
type: "list_all_agents",
|
|
77
|
+
sort_by: "requests",
|
|
78
|
+
offset: 0,
|
|
79
|
+
limit: 50
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("should not include sort_by when sortBy is undefined", async () => {
|
|
84
|
+
const listPromise = manager.listAllAgents({});
|
|
85
|
+
|
|
86
|
+
setTimeout(() => {
|
|
87
|
+
const call = (mockWsClient.sendMessage as ReturnType<typeof vi.fn>).mock.calls[0][0];
|
|
88
|
+
manager.handleAllAgentsResponse(mockAgentsResponse, call.request_id);
|
|
89
|
+
}, 10);
|
|
90
|
+
|
|
91
|
+
await listPromise;
|
|
92
|
+
|
|
93
|
+
const sentMessage = (mockWsClient.sendMessage as ReturnType<typeof vi.fn>).mock.calls[0][0];
|
|
94
|
+
expect(sentMessage).not.toHaveProperty("sort_by");
|
|
95
|
+
expect(sentMessage).toMatchObject({
|
|
96
|
+
type: "list_all_agents",
|
|
97
|
+
offset: 0,
|
|
98
|
+
limit: 50
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it("should not include sort_by when called with no options", async () => {
|
|
103
|
+
const listPromise = manager.listAllAgents();
|
|
104
|
+
|
|
105
|
+
setTimeout(() => {
|
|
106
|
+
const call = (mockWsClient.sendMessage as ReturnType<typeof vi.fn>).mock.calls[0][0];
|
|
107
|
+
manager.handleAllAgentsResponse(mockAgentsResponse, call.request_id);
|
|
108
|
+
}, 10);
|
|
109
|
+
|
|
110
|
+
await listPromise;
|
|
111
|
+
|
|
112
|
+
const sentMessage = (mockWsClient.sendMessage as ReturnType<typeof vi.fn>).mock.calls[0][0];
|
|
113
|
+
expect(sentMessage).not.toHaveProperty("sort_by");
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it("should send sort_by alongside other options", async () => {
|
|
117
|
+
const listPromise = manager.listAllAgents({
|
|
118
|
+
filter: "test",
|
|
119
|
+
offset: 10,
|
|
120
|
+
limit: 25,
|
|
121
|
+
sortBy: "a-z"
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
setTimeout(() => {
|
|
125
|
+
const call = (mockWsClient.sendMessage as ReturnType<typeof vi.fn>).mock.calls[0][0];
|
|
126
|
+
manager.handleAllAgentsResponse(
|
|
127
|
+
{ ...mockAgentsResponse, filter: "test", offset: 10, limit: 25 },
|
|
128
|
+
call.request_id
|
|
129
|
+
);
|
|
130
|
+
}, 10);
|
|
131
|
+
|
|
132
|
+
const result = await listPromise;
|
|
133
|
+
|
|
134
|
+
const sentMessage = (mockWsClient.sendMessage as ReturnType<typeof vi.fn>).mock.calls[0][0];
|
|
135
|
+
expect(sentMessage).toMatchObject({
|
|
136
|
+
type: "list_all_agents",
|
|
137
|
+
filter: "test",
|
|
138
|
+
offset: 10,
|
|
139
|
+
limit: 25,
|
|
140
|
+
sort_by: "a-z"
|
|
141
|
+
});
|
|
142
|
+
expect(result.offset).toBe(10);
|
|
143
|
+
expect(result.limit).toBe(25);
|
|
144
|
+
expect(result.filter).toBe("test");
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it("should resolve with correct result structure", async () => {
|
|
148
|
+
const listPromise = manager.listAllAgents({ sortBy: "requests" });
|
|
149
|
+
|
|
150
|
+
setTimeout(() => {
|
|
151
|
+
const call = (mockWsClient.sendMessage as ReturnType<typeof vi.fn>).mock.calls[0][0];
|
|
152
|
+
manager.handleAllAgentsResponse(mockAgentsResponse, call.request_id);
|
|
153
|
+
}, 10);
|
|
154
|
+
|
|
155
|
+
const result = await listPromise;
|
|
156
|
+
|
|
157
|
+
expect(result).toEqual({
|
|
158
|
+
agents: mockAgentsResponse.agents,
|
|
159
|
+
total: 2,
|
|
160
|
+
offset: 0,
|
|
161
|
+
limit: 50,
|
|
162
|
+
hasMore: false,
|
|
163
|
+
filter: undefined
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it("should reject if not connected", async () => {
|
|
168
|
+
mockWsClient.isConnected = false;
|
|
169
|
+
|
|
170
|
+
await expect(manager.listAllAgents({ sortBy: "a-z" })).rejects.toThrow(
|
|
171
|
+
"Not connected to Teneo Protocol"
|
|
172
|
+
);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it("should reject if not admin", async () => {
|
|
176
|
+
manager.setAdminStatus(false);
|
|
177
|
+
|
|
178
|
+
await expect(manager.listAllAgents({ sortBy: "a-z" })).rejects.toThrow(
|
|
179
|
+
"Admin privileges required"
|
|
180
|
+
);
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
});
|