@xalia/agent 0.5.7 → 0.6.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.
Files changed (186) hide show
  1. package/README.md +23 -8
  2. package/dist/agent/src/agent/agent.js +176 -96
  3. package/dist/agent/src/agent/agentUtils.js +82 -59
  4. package/dist/agent/src/agent/compressingContextManager.js +102 -0
  5. package/dist/agent/src/agent/context.js +189 -0
  6. package/dist/agent/src/agent/dummyLLM.js +46 -5
  7. package/dist/agent/src/agent/mcpServerManager.js +23 -24
  8. package/dist/agent/src/agent/nullAgentEventHandler.js +21 -0
  9. package/dist/agent/src/agent/nullPlatform.js +14 -0
  10. package/dist/agent/src/agent/openAILLMStreaming.js +26 -14
  11. package/dist/agent/src/agent/promptProvider.js +63 -0
  12. package/dist/agent/src/agent/repeatLLM.js +5 -5
  13. package/dist/agent/src/agent/sudoMcpServerManager.js +23 -21
  14. package/dist/agent/src/agent/tokenAuth.js +7 -7
  15. package/dist/agent/src/agent/tools.js +1 -1
  16. package/dist/agent/src/chat/client/chatClient.js +733 -0
  17. package/dist/agent/src/chat/client/connection.js +209 -0
  18. package/dist/agent/src/chat/client/connection.test.js +188 -0
  19. package/dist/agent/src/chat/client/constants.js +5 -0
  20. package/dist/agent/src/chat/client/index.js +15 -0
  21. package/dist/agent/src/chat/client/interfaces.js +2 -0
  22. package/dist/agent/src/chat/client/responseHandler.js +105 -0
  23. package/dist/agent/src/chat/client/sessionClient.js +331 -0
  24. package/dist/agent/src/chat/client/teamManager.js +2 -0
  25. package/dist/agent/src/chat/{apiKeyManager.js → data/apiKeyManager.js} +4 -0
  26. package/dist/agent/src/chat/data/dataModels.js +2 -0
  27. package/dist/agent/src/chat/data/database.js +749 -0
  28. package/dist/agent/src/chat/data/dbMcpServerConfigs.js +47 -0
  29. package/dist/agent/src/chat/protocol/connectionMessages.js +5 -0
  30. package/dist/agent/src/chat/protocol/constants.js +50 -0
  31. package/dist/agent/src/chat/protocol/errors.js +22 -0
  32. package/dist/agent/src/chat/protocol/messages.js +110 -0
  33. package/dist/agent/src/chat/server/chatContextManager.js +405 -0
  34. package/dist/agent/src/chat/server/connectionManager.js +352 -0
  35. package/dist/agent/src/chat/server/connectionManager.test.js +159 -0
  36. package/dist/agent/src/chat/server/conversation.js +198 -0
  37. package/dist/agent/src/chat/server/errorUtils.js +23 -0
  38. package/dist/agent/src/chat/server/openSession.js +869 -0
  39. package/dist/agent/src/chat/server/server.js +177 -0
  40. package/dist/agent/src/chat/server/sessionFileManager.js +161 -0
  41. package/dist/agent/src/chat/server/sessionRegistry.js +700 -0
  42. package/dist/agent/src/chat/server/sessionRegistry.test.js +97 -0
  43. package/dist/agent/src/chat/server/test-utils/mockFactories.js +307 -0
  44. package/dist/agent/src/chat/server/tools.js +243 -0
  45. package/dist/agent/src/chat/utils/agentSessionMap.js +66 -0
  46. package/dist/agent/src/chat/utils/approvalManager.js +85 -0
  47. package/dist/agent/src/{utils → chat/utils}/asyncLock.js +3 -3
  48. package/dist/agent/src/chat/{asyncQueue.js → utils/asyncQueue.js} +12 -2
  49. package/dist/agent/src/chat/utils/htmlToText.js +84 -0
  50. package/dist/agent/src/chat/utils/multiAsyncQueue.js +42 -0
  51. package/dist/agent/src/chat/utils/search.js +145 -0
  52. package/dist/agent/src/chat/utils/userResolver.js +46 -0
  53. package/dist/agent/src/chat/utils/websocket.js +16 -0
  54. package/dist/agent/src/test/agent.test.js +332 -0
  55. package/dist/agent/src/test/approvalManager.test.js +58 -0
  56. package/dist/agent/src/test/chatContextManager.test.js +392 -0
  57. package/dist/agent/src/test/clientServerConnection.test.js +158 -0
  58. package/dist/agent/src/test/compressingContextManager.test.js +65 -0
  59. package/dist/agent/src/test/context.test.js +83 -0
  60. package/dist/agent/src/test/conversation.test.js +89 -0
  61. package/dist/agent/src/test/db.test.js +271 -83
  62. package/dist/agent/src/test/dbMcpServerConfigs.test.js +72 -0
  63. package/dist/agent/src/test/dbTestTools.js +99 -0
  64. package/dist/agent/src/test/imageLoad.test.js +8 -7
  65. package/dist/agent/src/test/mcpServerManager.test.js +23 -20
  66. package/dist/agent/src/test/multiAsyncQueue.test.js +101 -0
  67. package/dist/agent/src/test/openaiStreaming.test.js +64 -35
  68. package/dist/agent/src/test/prompt.test.js +5 -4
  69. package/dist/agent/src/test/promptProvider.test.js +28 -0
  70. package/dist/agent/src/test/responseHandler.test.js +61 -0
  71. package/dist/agent/src/test/sudoMcpServerManager.test.js +24 -25
  72. package/dist/agent/src/test/testTools.js +109 -0
  73. package/dist/agent/src/test/tools.test.js +31 -0
  74. package/dist/agent/src/tool/agentChat.js +21 -10
  75. package/dist/agent/src/tool/agentMain.js +1 -1
  76. package/dist/agent/src/tool/chatMain.js +241 -58
  77. package/dist/agent/src/tool/commandPrompt.js +22 -17
  78. package/dist/agent/src/tool/files.js +20 -16
  79. package/dist/agent/src/tool/nodePlatform.js +47 -3
  80. package/dist/agent/src/tool/options.js +4 -4
  81. package/dist/agent/src/tool/prompt.js +19 -13
  82. package/eslint.config.mjs +14 -1
  83. package/package.json +14 -6
  84. package/scripts/chat_server +8 -0
  85. package/scripts/setup_chat +7 -2
  86. package/scripts/shutdown_chat_server +3 -0
  87. package/scripts/test_chat +135 -17
  88. package/src/agent/agent.ts +283 -138
  89. package/src/agent/agentUtils.ts +143 -108
  90. package/src/agent/compressingContextManager.ts +164 -0
  91. package/src/agent/context.ts +268 -0
  92. package/src/agent/dummyLLM.ts +76 -8
  93. package/src/agent/iAgentEventHandler.ts +54 -0
  94. package/src/agent/iplatform.ts +1 -0
  95. package/src/agent/mcpServerManager.ts +35 -31
  96. package/src/agent/nullAgentEventHandler.ts +20 -0
  97. package/src/agent/nullPlatform.ts +13 -0
  98. package/src/agent/openAILLMStreaming.ts +26 -13
  99. package/src/agent/promptProvider.ts +87 -0
  100. package/src/agent/repeatLLM.ts +5 -5
  101. package/src/agent/sudoMcpServerManager.ts +30 -29
  102. package/src/agent/tokenAuth.ts +7 -7
  103. package/src/agent/tools.ts +3 -1
  104. package/src/chat/client/chatClient.ts +900 -0
  105. package/src/chat/client/connection.test.ts +241 -0
  106. package/src/chat/client/connection.ts +276 -0
  107. package/src/chat/client/constants.ts +3 -0
  108. package/src/chat/client/index.ts +18 -0
  109. package/src/chat/client/interfaces.ts +34 -0
  110. package/src/chat/client/responseHandler.ts +131 -0
  111. package/src/chat/client/sessionClient.ts +443 -0
  112. package/src/chat/client/teamManager.ts +29 -0
  113. package/src/chat/{apiKeyManager.ts → data/apiKeyManager.ts} +6 -2
  114. package/src/chat/data/dataModels.ts +85 -0
  115. package/src/chat/data/database.ts +982 -0
  116. package/src/chat/data/dbMcpServerConfigs.ts +59 -0
  117. package/src/chat/protocol/connectionMessages.ts +49 -0
  118. package/src/chat/protocol/constants.ts +55 -0
  119. package/src/chat/protocol/errors.ts +16 -0
  120. package/src/chat/protocol/messages.ts +682 -0
  121. package/src/chat/server/README.md +127 -0
  122. package/src/chat/server/chatContextManager.ts +612 -0
  123. package/src/chat/server/connectionManager.test.ts +266 -0
  124. package/src/chat/server/connectionManager.ts +541 -0
  125. package/src/chat/server/conversation.ts +269 -0
  126. package/src/chat/server/errorUtils.ts +28 -0
  127. package/src/chat/server/openSession.ts +1332 -0
  128. package/src/chat/server/server.ts +177 -0
  129. package/src/chat/server/sessionFileManager.ts +239 -0
  130. package/src/chat/server/sessionRegistry.test.ts +138 -0
  131. package/src/chat/server/sessionRegistry.ts +1064 -0
  132. package/src/chat/server/test-utils/mockFactories.ts +422 -0
  133. package/src/chat/server/tools.ts +265 -0
  134. package/src/chat/utils/agentSessionMap.ts +76 -0
  135. package/src/chat/utils/approvalManager.ts +111 -0
  136. package/src/{utils → chat/utils}/asyncLock.ts +3 -3
  137. package/src/chat/{asyncQueue.ts → utils/asyncQueue.ts} +14 -3
  138. package/src/chat/utils/htmlToText.ts +61 -0
  139. package/src/chat/utils/multiAsyncQueue.ts +52 -0
  140. package/src/chat/utils/search.ts +139 -0
  141. package/src/chat/utils/userResolver.ts +48 -0
  142. package/src/chat/utils/websocket.ts +16 -0
  143. package/src/test/agent.test.ts +487 -0
  144. package/src/test/approvalManager.test.ts +73 -0
  145. package/src/test/chatContextManager.test.ts +521 -0
  146. package/src/test/clientServerConnection.test.ts +207 -0
  147. package/src/test/compressingContextManager.test.ts +82 -0
  148. package/src/test/context.test.ts +105 -0
  149. package/src/test/conversation.test.ts +109 -0
  150. package/src/test/db.test.ts +358 -89
  151. package/src/test/dbMcpServerConfigs.test.ts +112 -0
  152. package/src/test/dbTestTools.ts +153 -0
  153. package/src/test/imageLoad.test.ts +7 -6
  154. package/src/test/mcpServerManager.test.ts +21 -16
  155. package/src/test/multiAsyncQueue.test.ts +125 -0
  156. package/src/test/openaiStreaming.test.ts +71 -36
  157. package/src/test/prompt.test.ts +4 -3
  158. package/src/test/promptProvider.test.ts +33 -0
  159. package/src/test/responseHandler.test.ts +78 -0
  160. package/src/test/sudoMcpServerManager.test.ts +32 -30
  161. package/src/test/testTools.ts +146 -0
  162. package/src/test/tools.test.ts +39 -0
  163. package/src/tool/agentChat.ts +26 -12
  164. package/src/tool/agentMain.ts +1 -1
  165. package/src/tool/chatMain.ts +292 -100
  166. package/src/tool/commandPrompt.ts +28 -19
  167. package/src/tool/files.ts +25 -19
  168. package/src/tool/nodePlatform.ts +52 -3
  169. package/src/tool/options.ts +4 -2
  170. package/src/tool/prompt.ts +22 -15
  171. package/test_data/dummyllm_script_crash.json +32 -0
  172. package/test_data/frog.png.b64 +1 -0
  173. package/vitest.config.ts +39 -0
  174. package/dist/agent/src/chat/client.js +0 -349
  175. package/dist/agent/src/chat/conversationManager.js +0 -392
  176. package/dist/agent/src/chat/db.js +0 -209
  177. package/dist/agent/src/chat/frontendClient.js +0 -74
  178. package/dist/agent/src/chat/server.js +0 -158
  179. package/src/chat/client.ts +0 -455
  180. package/src/chat/conversationManager.ts +0 -595
  181. package/src/chat/db.ts +0 -290
  182. package/src/chat/frontendClient.ts +0 -123
  183. package/src/chat/messages.ts +0 -235
  184. package/src/chat/server.ts +0 -177
  185. /package/dist/agent/src/{chat/messages.js → agent/iAgentEventHandler.js} +0 -0
  186. /package/{frog.png → test_data/frog.png} +0 -0
@@ -0,0 +1,266 @@
1
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment */
2
+ /* eslint-disable @typescript-eslint/no-unsafe-call */
3
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
4
+ import { ConnectionManager } from "./connectionManager";
5
+ import type { ClientToServer, ServerToClient } from "../protocol/messages";
6
+ import {
7
+ createMockApiKeyManager,
8
+ createMockSessionRegistry,
9
+ createMockWebSocket,
10
+ setupStandardMockBehaviors,
11
+ MOCK_USERS,
12
+ } from "./test-utils/mockFactories";
13
+ import {
14
+ ClientConnectionData,
15
+ ServerConnectionData,
16
+ } from "../protocol/connectionMessages";
17
+
18
+ // Mock dependencies
19
+ vi.mock("../data/apiKeyManager");
20
+ vi.mock("ws");
21
+
22
+ describe("ConnectionManager", () => {
23
+ let connectionManager: ConnectionManager<ClientToServer, ServerToClient>;
24
+ let mockApiKeyManager: ReturnType<typeof createMockApiKeyManager>;
25
+ let mockSessionRegistry: ReturnType<typeof createMockSessionRegistry>;
26
+ let mockWebSocket: ReturnType<typeof createMockWebSocket>;
27
+
28
+ beforeEach(() => {
29
+ vi.resetAllMocks();
30
+
31
+ // Create mocks using factories
32
+ mockApiKeyManager = createMockApiKeyManager();
33
+ mockSessionRegistry = createMockSessionRegistry();
34
+ mockWebSocket = createMockWebSocket();
35
+
36
+ // Setup standard behaviors
37
+ setupStandardMockBehaviors({
38
+ apiKeyManager: mockApiKeyManager,
39
+ });
40
+
41
+ // Create ConnectionManager instance using reflection
42
+ // to access private constructor. Since the constructor is private,
43
+ // we need to use type assertion
44
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
45
+ connectionManager = new (ConnectionManager as any)(
46
+ mockApiKeyManager.mock,
47
+ mockSessionRegistry.mock
48
+ );
49
+ });
50
+
51
+ afterEach(() => {
52
+ vi.restoreAllMocks();
53
+ });
54
+
55
+ describe("handleConnection", () => {
56
+ it("should send connection_ready after successful setup", async () => {
57
+ await connectionManager.handleConnection(
58
+ mockWebSocket.mock,
59
+ "valid-api-key",
60
+ { headers: {} }
61
+ );
62
+
63
+ // Wait for deferred send
64
+ await new Promise((resolve) => setImmediate(resolve));
65
+
66
+ expect(mockApiKeyManager.spies.verifyApiKey).toHaveBeenCalledWith(
67
+ "valid-api-key"
68
+ );
69
+ expect(mockWebSocket.spies.send).toHaveBeenCalledWith(
70
+ expect.stringMatching(/"t":"ready"/)
71
+ );
72
+ });
73
+
74
+ it("should reject connection with invalid API key", async () => {
75
+ await connectionManager.handleConnection(
76
+ mockWebSocket.mock,
77
+ "invalid-api-key"
78
+ );
79
+
80
+ expect(mockWebSocket.spies.close).toHaveBeenCalledWith(
81
+ 4000,
82
+ "Connection setup failed"
83
+ );
84
+ });
85
+
86
+ it("should setup WebSocket event handlers", async () => {
87
+ await connectionManager.handleConnection(
88
+ mockWebSocket.mock,
89
+ "valid-api-key"
90
+ );
91
+
92
+ expect(mockWebSocket.spies.on).toHaveBeenCalledWith(
93
+ "message",
94
+ expect.any(Function)
95
+ );
96
+ expect(mockWebSocket.spies.on).toHaveBeenCalledWith(
97
+ "close",
98
+ expect.any(Function)
99
+ );
100
+ expect(mockWebSocket.spies.on).toHaveBeenCalledWith(
101
+ "error",
102
+ expect.any(Function)
103
+ );
104
+ });
105
+ });
106
+
107
+ describe("user communication", () => {
108
+ beforeEach(async () => {
109
+ await connectionManager.handleConnection(
110
+ mockWebSocket.mock,
111
+ "valid-api-key"
112
+ );
113
+ });
114
+
115
+ it("should send messages to connected users", () => {
116
+ const testMessage: ServerConnectionData<ServerToClient> = {
117
+ t: "data",
118
+ d: {
119
+ type: "user_msg",
120
+ user_uuid: "user_1",
121
+ session_id: "session_1",
122
+ message: "message text",
123
+ message_idx: 12,
124
+ // connection_id: "test-123",
125
+ // user_uuid: MOCK_USERS.owner.uuid,
126
+ // client_message_id: "test-123",
127
+ },
128
+ };
129
+
130
+ connectionManager.sendToUsers(
131
+ new Set([MOCK_USERS.owner.uuid]),
132
+ testMessage.d
133
+ );
134
+
135
+ expect(mockWebSocket.spies.send).toHaveBeenCalledWith(
136
+ JSON.stringify(testMessage)
137
+ );
138
+ });
139
+
140
+ it("should return API key for connected user", () => {
141
+ const apiKey = connectionManager.getLiveUserApiKey(MOCK_USERS.owner.uuid);
142
+ expect(apiKey).toBe("valid-api-key");
143
+ });
144
+
145
+ it("should return undefined for non-existent user", () => {
146
+ const apiKey = connectionManager.getLiveUserApiKey(
147
+ MOCK_USERS.nonExistent.uuid
148
+ );
149
+ expect(apiKey).toBeUndefined();
150
+ });
151
+ });
152
+
153
+ describe("connection cleanup", () => {
154
+ beforeEach(async () => {
155
+ await connectionManager.handleConnection(
156
+ mockWebSocket.mock,
157
+ "valid-api-key"
158
+ );
159
+ });
160
+
161
+ it("should clean up connection state on close", () => {
162
+ // Get the close handler from mock calls
163
+ const closeHandlerCall = mockWebSocket.spies.on.mock.calls.find(
164
+ (call) => call[0] === "close"
165
+ );
166
+ expect(closeHandlerCall).toBeDefined();
167
+
168
+ if (closeHandlerCall) {
169
+ const closeHandler = closeHandlerCall[1];
170
+ closeHandler();
171
+ }
172
+
173
+ // After cleanup, API key should no longer be available
174
+ const apiKey = connectionManager.getLiveUserApiKey(MOCK_USERS.owner.uuid);
175
+ expect(apiKey).toBeUndefined();
176
+ });
177
+
178
+ it("should clean up connection state on error", () => {
179
+ // Get the error handler from mock calls
180
+ const errorHandlerCall = mockWebSocket.spies.on.mock.calls.find(
181
+ (call) => call[0] === "error"
182
+ );
183
+ expect(errorHandlerCall).toBeDefined();
184
+
185
+ if (errorHandlerCall) {
186
+ const errorHandler = errorHandlerCall[1];
187
+ errorHandler(new Error("WebSocket error"));
188
+ }
189
+
190
+ // After cleanup, API key should no longer be available
191
+ const apiKey = connectionManager.getLiveUserApiKey(MOCK_USERS.owner.uuid);
192
+ expect(apiKey).toBeUndefined();
193
+ });
194
+ });
195
+
196
+ describe("message routing", () => {
197
+ let messageHandler: (data: Buffer) => Promise<void>;
198
+
199
+ beforeEach(async () => {
200
+ await connectionManager.handleConnection(
201
+ mockWebSocket.mock,
202
+ "valid-api-key"
203
+ );
204
+
205
+ // Extract the message handler
206
+ const messageHandlerCall = mockWebSocket.spies.on.mock.calls.find(
207
+ (call) => call[0] === "message"
208
+ );
209
+ expect(messageHandlerCall).toBeDefined();
210
+ if (!messageHandlerCall) {
211
+ throw new Error("Message handler not found");
212
+ }
213
+ messageHandler = messageHandlerCall[1];
214
+ });
215
+
216
+ it("should route session_create to SessionRegistry", async () => {
217
+ mockSessionRegistry.spies.processMessage.mockResolvedValue(undefined);
218
+
219
+ const message: ClientConnectionData<ClientToServer> = {
220
+ t: "data",
221
+ d: {
222
+ type: "control_session_create",
223
+ title: "Test Session",
224
+ agent_profile_id: "agent-123",
225
+ client_message_id: "msg-123",
226
+ },
227
+ };
228
+
229
+ await messageHandler(Buffer.from(JSON.stringify(message)));
230
+
231
+ expect(mockSessionRegistry.spies.processMessage).toHaveBeenCalledWith(
232
+ expect.any(String), // connectionId
233
+ MOCK_USERS.owner.uuid,
234
+ message.d
235
+ );
236
+ });
237
+
238
+ it("should route session messages to SessionRegistry", async () => {
239
+ const message: ClientConnectionData<ClientToServer> = {
240
+ t: "data",
241
+ d: {
242
+ type: "msg",
243
+ session_id: "session-123",
244
+ message: "Hello world!",
245
+ client_message_id: "msg-123",
246
+ },
247
+ };
248
+
249
+ await messageHandler(Buffer.from(JSON.stringify(message)));
250
+
251
+ expect(mockSessionRegistry.spies.processMessage).toHaveBeenCalledWith(
252
+ expect.any(String), // connectionId
253
+ MOCK_USERS.owner.uuid,
254
+ message.d
255
+ );
256
+ });
257
+
258
+ it("should handle invalid JSON gracefully", async () => {
259
+ await messageHandler(Buffer.from("invalid json"));
260
+
261
+ expect(mockWebSocket.spies.send).toHaveBeenCalledWith(
262
+ expect.stringMatching(/"t":"error"/)
263
+ );
264
+ });
265
+ });
266
+ });