@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.
Files changed (231) hide show
  1. package/.github/ISSUE_TEMPLATE/config.yml +1 -1
  2. package/CHANGELOG.md +366 -15
  3. package/CONCEPTS.md +182 -44
  4. package/README.md +524 -94
  5. package/dist/constants.d.ts +3 -1
  6. package/dist/constants.d.ts.map +1 -1
  7. package/dist/constants.js +5 -3
  8. package/dist/constants.js.map +1 -1
  9. package/dist/core/websocket-client.d.ts.map +1 -1
  10. package/dist/core/websocket-client.js +9 -5
  11. package/dist/core/websocket-client.js.map +1 -1
  12. package/dist/formatters/response-formatter.d.ts +6 -6
  13. package/dist/handlers/message-handlers/agent-details-response-handler.d.ts +1080 -756
  14. package/dist/handlers/message-handlers/agent-details-response-handler.d.ts.map +1 -1
  15. package/dist/handlers/message-handlers/agent-details-response-handler.js +2 -2
  16. package/dist/handlers/message-handlers/agent-details-response-handler.js.map +1 -1
  17. package/dist/handlers/message-handlers/agent-error-handler.d.ts +91 -0
  18. package/dist/handlers/message-handlers/agent-error-handler.d.ts.map +1 -0
  19. package/dist/handlers/message-handlers/agent-error-handler.js +44 -0
  20. package/dist/handlers/message-handlers/agent-error-handler.js.map +1 -0
  21. package/dist/handlers/message-handlers/agent-selected-handler.d.ts +6 -0
  22. package/dist/handlers/message-handlers/agent-selected-handler.d.ts.map +1 -1
  23. package/dist/handlers/message-handlers/agent-status-update-handler.d.ts +1080 -756
  24. package/dist/handlers/message-handlers/agent-status-update-handler.d.ts.map +1 -1
  25. package/dist/handlers/message-handlers/agent-status-update-handler.js +2 -7
  26. package/dist/handlers/message-handlers/agent-status-update-handler.js.map +1 -1
  27. package/dist/handlers/message-handlers/all-agents-response-handler.d.ts +135 -54
  28. package/dist/handlers/message-handlers/all-agents-response-handler.d.ts.map +1 -1
  29. package/dist/handlers/message-handlers/all-agents-response-handler.js +2 -2
  30. package/dist/handlers/message-handlers/all-agents-response-handler.js.map +1 -1
  31. package/dist/handlers/message-handlers/auth-error-handler.d.ts +6 -0
  32. package/dist/handlers/message-handlers/auth-error-handler.d.ts.map +1 -1
  33. package/dist/handlers/message-handlers/auth-message-handler.d.ts.map +1 -1
  34. package/dist/handlers/message-handlers/auth-message-handler.js +6 -1
  35. package/dist/handlers/message-handlers/auth-message-handler.js.map +1 -1
  36. package/dist/handlers/message-handlers/auth-required-handler.d.ts +6 -0
  37. package/dist/handlers/message-handlers/auth-required-handler.d.ts.map +1 -1
  38. package/dist/handlers/message-handlers/auth-success-handler.d.ts.map +1 -1
  39. package/dist/handlers/message-handlers/auth-success-handler.js +6 -1
  40. package/dist/handlers/message-handlers/auth-success-handler.js.map +1 -1
  41. package/dist/handlers/message-handlers/base-handler.d.ts +2 -1
  42. package/dist/handlers/message-handlers/base-handler.d.ts.map +1 -1
  43. package/dist/handlers/message-handlers/base-handler.js +24 -4
  44. package/dist/handlers/message-handlers/base-handler.js.map +1 -1
  45. package/dist/handlers/message-handlers/challenge-handler.d.ts +6 -0
  46. package/dist/handlers/message-handlers/challenge-handler.d.ts.map +1 -1
  47. package/dist/handlers/message-handlers/error-message-handler.d.ts +6 -0
  48. package/dist/handlers/message-handlers/error-message-handler.d.ts.map +1 -1
  49. package/dist/handlers/message-handlers/index.d.ts +4 -0
  50. package/dist/handlers/message-handlers/index.d.ts.map +1 -1
  51. package/dist/handlers/message-handlers/index.js +23 -1
  52. package/dist/handlers/message-handlers/index.js.map +1 -1
  53. package/dist/handlers/message-handlers/list-available-agents-handler.d.ts +1116 -756
  54. package/dist/handlers/message-handlers/list-available-agents-handler.d.ts.map +1 -1
  55. package/dist/handlers/message-handlers/list-available-agents-handler.js +23 -10
  56. package/dist/handlers/message-handlers/list-available-agents-handler.js.map +1 -1
  57. package/dist/handlers/message-handlers/list-room-agents-handler.d.ts +1080 -756
  58. package/dist/handlers/message-handlers/list-room-agents-handler.d.ts.map +1 -1
  59. package/dist/handlers/message-handlers/list-room-agents-handler.js +2 -6
  60. package/dist/handlers/message-handlers/list-room-agents-handler.js.map +1 -1
  61. package/dist/handlers/message-handlers/list-rooms-response-handler.d.ts.map +1 -1
  62. package/dist/handlers/message-handlers/list-rooms-response-handler.js +2 -5
  63. package/dist/handlers/message-handlers/list-rooms-response-handler.js.map +1 -1
  64. package/dist/handlers/message-handlers/ping-pong-handler.d.ts +52 -4
  65. package/dist/handlers/message-handlers/ping-pong-handler.d.ts.map +1 -1
  66. package/dist/handlers/message-handlers/ping-pong-handler.js +23 -4
  67. package/dist/handlers/message-handlers/ping-pong-handler.js.map +1 -1
  68. package/dist/handlers/message-handlers/rate-limit-notification-handler.d.ts.map +1 -1
  69. package/dist/handlers/message-handlers/rate-limit-notification-handler.js +3 -2
  70. package/dist/handlers/message-handlers/rate-limit-notification-handler.js.map +1 -1
  71. package/dist/handlers/message-handlers/regular-message-handler.d.ts +6 -0
  72. package/dist/handlers/message-handlers/regular-message-handler.d.ts.map +1 -1
  73. package/dist/handlers/message-handlers/subscribe-response-handler.d.ts +12 -6
  74. package/dist/handlers/message-handlers/subscribe-response-handler.d.ts.map +1 -1
  75. package/dist/handlers/message-handlers/success-handler.d.ts +82 -0
  76. package/dist/handlers/message-handlers/success-handler.d.ts.map +1 -0
  77. package/dist/handlers/message-handlers/success-handler.js +24 -0
  78. package/dist/handlers/message-handlers/success-handler.js.map +1 -0
  79. package/dist/handlers/message-handlers/task-confirmed-handler.d.ts +110 -0
  80. package/dist/handlers/message-handlers/task-confirmed-handler.d.ts.map +1 -0
  81. package/dist/handlers/message-handlers/task-confirmed-handler.js +46 -0
  82. package/dist/handlers/message-handlers/task-confirmed-handler.js.map +1 -0
  83. package/dist/handlers/message-handlers/trigger-wallet-tx-handler.d.ts +244 -0
  84. package/dist/handlers/message-handlers/trigger-wallet-tx-handler.d.ts.map +1 -0
  85. package/dist/handlers/message-handlers/trigger-wallet-tx-handler.js +58 -0
  86. package/dist/handlers/message-handlers/trigger-wallet-tx-handler.js.map +1 -0
  87. package/dist/handlers/message-handlers/unsubscribe-response-handler.d.ts +12 -6
  88. package/dist/handlers/message-handlers/unsubscribe-response-handler.d.ts.map +1 -1
  89. package/dist/handlers/message-handlers/user-authenticated-handler.js +2 -2
  90. package/dist/handlers/message-handlers/user-authenticated-handler.js.map +1 -1
  91. package/dist/handlers/message-handlers/user-count-handler.js +2 -2
  92. package/dist/handlers/message-handlers/user-count-handler.js.map +1 -1
  93. package/dist/index.d.ts +3 -3
  94. package/dist/index.d.ts.map +1 -1
  95. package/dist/index.js +11 -4
  96. package/dist/index.js.map +1 -1
  97. package/dist/managers/admin-manager.d.ts +3 -1
  98. package/dist/managers/admin-manager.d.ts.map +1 -1
  99. package/dist/managers/admin-manager.js +4 -3
  100. package/dist/managers/admin-manager.js.map +1 -1
  101. package/dist/managers/agent-room-manager.d.ts +89 -11
  102. package/dist/managers/agent-room-manager.d.ts.map +1 -1
  103. package/dist/managers/agent-room-manager.js +99 -35
  104. package/dist/managers/agent-room-manager.js.map +1 -1
  105. package/dist/managers/index.d.ts +1 -1
  106. package/dist/managers/index.d.ts.map +1 -1
  107. package/dist/managers/index.js.map +1 -1
  108. package/dist/managers/message-router.d.ts +45 -5
  109. package/dist/managers/message-router.d.ts.map +1 -1
  110. package/dist/managers/message-router.js +96 -24
  111. package/dist/managers/message-router.js.map +1 -1
  112. package/dist/managers/room-manager.d.ts +29 -7
  113. package/dist/managers/room-manager.d.ts.map +1 -1
  114. package/dist/managers/room-manager.js +37 -11
  115. package/dist/managers/room-manager.js.map +1 -1
  116. package/dist/payments/index.d.ts +3 -1
  117. package/dist/payments/index.d.ts.map +1 -1
  118. package/dist/payments/index.js +17 -3
  119. package/dist/payments/index.js.map +1 -1
  120. package/dist/payments/networks.d.ts +59 -0
  121. package/dist/payments/networks.d.ts.map +1 -0
  122. package/dist/payments/networks.js +192 -0
  123. package/dist/payments/networks.js.map +1 -0
  124. package/dist/payments/payment-client.d.ts +55 -10
  125. package/dist/payments/payment-client.d.ts.map +1 -1
  126. package/dist/payments/payment-client.js +172 -51
  127. package/dist/payments/payment-client.js.map +1 -1
  128. package/dist/teneo-sdk.d.ts +215 -41
  129. package/dist/teneo-sdk.d.ts.map +1 -1
  130. package/dist/teneo-sdk.js +361 -84
  131. package/dist/teneo-sdk.js.map +1 -1
  132. package/dist/types/config.d.ts +334 -25
  133. package/dist/types/config.d.ts.map +1 -1
  134. package/dist/types/config.js +114 -22
  135. package/dist/types/config.js.map +1 -1
  136. package/dist/types/events.d.ts +60 -14
  137. package/dist/types/events.d.ts.map +1 -1
  138. package/dist/types/events.js.map +1 -1
  139. package/dist/types/index.d.ts +1 -1
  140. package/dist/types/index.d.ts.map +1 -1
  141. package/dist/types/index.js +11 -4
  142. package/dist/types/index.js.map +1 -1
  143. package/dist/types/messages.d.ts +13110 -7451
  144. package/dist/types/messages.d.ts.map +1 -1
  145. package/dist/types/messages.js +195 -44
  146. package/dist/types/messages.js.map +1 -1
  147. package/dist/utils/pricing-resolver.d.ts +1 -1
  148. package/dist/utils/pricing-resolver.d.ts.map +1 -1
  149. package/dist/utils/pricing-resolver.js +9 -1
  150. package/dist/utils/pricing-resolver.js.map +1 -1
  151. package/examples/agent-room-management-example.ts +5 -5
  152. package/examples/basic-usage.ts +26 -6
  153. package/examples/claude-agent-x-follower/index.ts +1 -1
  154. package/examples/minimal-chat.ts +4 -3
  155. package/examples/n8n-teneo/index.ts +2 -2
  156. package/examples/nestjs-dashboard/README.md +1 -1
  157. package/examples/nestjs-dashboard/src/teneo/agents.controller.ts +3 -3
  158. package/examples/nestjs-dashboard/src/teneo/rooms.controller.ts +5 -5
  159. package/examples/nestjs-dashboard/src/teneo/teneo.service.ts +8 -8
  160. package/examples/openai-teneo/index.ts +1 -1
  161. package/examples/payment-flow.ts +143 -0
  162. package/examples/production-dashboard/README.md +6 -8
  163. package/examples/production-dashboard/server.ts +22 -10
  164. package/examples/room-management-example.ts +2 -2
  165. package/examples/usage/01-connect.ts +0 -3
  166. package/examples/usage/02-list-agents.ts +0 -2
  167. package/examples/usage/03-pick-agent.ts +3 -4
  168. package/examples/usage/04-find-by-capability.ts +10 -12
  169. package/examples/usage/05-webhook-example.ts +2 -4
  170. package/examples/usage/06-simple-api-server.ts +13 -9
  171. package/examples/usage/07-event-listener.ts +1 -13
  172. package/examples/usage/README.md +33 -7
  173. package/examples/webhook-integration.ts +9 -9
  174. package/examples/x-influencer-battle-server.ts +1 -1
  175. package/package.json +1 -1
  176. package/scripts/diagnose-connection.ts +86 -0
  177. package/scripts/investigate-payload.ts +163 -0
  178. package/scripts/list-agents.ts +58 -0
  179. package/scripts/live-multi-network-test.ts +230 -0
  180. package/src/constants.ts +5 -3
  181. package/src/core/websocket-client.ts +10 -9
  182. package/src/handlers/message-handlers/agent-details-response-handler.ts +2 -2
  183. package/src/handlers/message-handlers/agent-error-handler.ts +47 -0
  184. package/src/handlers/message-handlers/agent-status-update-handler.ts +2 -7
  185. package/src/handlers/message-handlers/all-agents-response-handler.ts +2 -2
  186. package/src/handlers/message-handlers/auth-message-handler.ts +7 -1
  187. package/src/handlers/message-handlers/auth-success-handler.ts +7 -1
  188. package/src/handlers/message-handlers/base-handler.ts +24 -4
  189. package/src/handlers/message-handlers/index.ts +24 -0
  190. package/src/handlers/message-handlers/list-available-agents-handler.ts +24 -11
  191. package/src/handlers/message-handlers/list-room-agents-handler.ts +2 -6
  192. package/src/handlers/message-handlers/list-rooms-response-handler.ts +2 -5
  193. package/src/handlers/message-handlers/ping-pong-handler.ts +29 -4
  194. package/src/handlers/message-handlers/rate-limit-notification-handler.ts +3 -2
  195. package/src/handlers/message-handlers/success-handler.ts +26 -0
  196. package/src/handlers/message-handlers/task-confirmed-handler.ts +49 -0
  197. package/src/handlers/message-handlers/trigger-wallet-tx-handler.ts +62 -0
  198. package/src/handlers/message-handlers/user-authenticated-handler.ts +2 -2
  199. package/src/handlers/message-handlers/user-count-handler.ts +2 -2
  200. package/src/index.ts +12 -4
  201. package/src/managers/admin-manager.ts +6 -3
  202. package/src/managers/agent-room-manager.ts +155 -26
  203. package/src/managers/index.ts +6 -1
  204. package/src/managers/message-router.ts +122 -27
  205. package/src/managers/room-manager.ts +39 -11
  206. package/src/payments/index.ts +20 -5
  207. package/src/payments/networks.ts +208 -0
  208. package/src/payments/payment-client.ts +211 -56
  209. package/src/teneo-sdk.ts +402 -71
  210. package/src/types/config.test.ts +24 -4
  211. package/src/types/config.ts +123 -25
  212. package/src/types/events.ts +36 -2
  213. package/src/types/index.ts +16 -3
  214. package/src/types/messages.ts +235 -60
  215. package/src/utils/pricing-resolver.ts +10 -2
  216. package/tests/direct-agent-test.ts +1 -1
  217. package/tests/integration/real-server.test.ts +1 -1
  218. package/tests/integration/websocket.test.ts +3 -3
  219. package/tests/multi-network-payment.test.ts +309 -0
  220. package/tests/multi-network.test.ts +296 -0
  221. package/tests/payment-flow-test.ts +6 -4
  222. package/tests/unit/handlers/agent-error-handler.test.ts +388 -0
  223. package/tests/unit/handlers/agent-room-operation-response-handler.test.ts +9 -6
  224. package/tests/unit/handlers/agent-status-update-handler.test.ts +11 -16
  225. package/tests/unit/handlers/list-available-agents-handler.test.ts +11 -14
  226. package/tests/unit/handlers/list-room-agents-handler.test.ts +11 -15
  227. package/tests/unit/handlers/room-operation-response-handler.test.ts +9 -6
  228. package/tests/unit/handlers/trigger-wallet-tx-handler.test.ts +431 -0
  229. package/tests/unit/managers/admin-manager.test.ts +183 -0
  230. package/tests/unit/managers/agent-room-manager.test.ts +189 -33
  231. 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
+ });