@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
@@ -1,392 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ConversationManager = exports.OpenSession = exports.UserAlreadyConnected = void 0;
4
- const uuid_1 = require("uuid");
5
- const assert_1 = require("assert");
6
- const sdk_1 = require("@xalia/xmcp/sdk");
7
- const agentUtils_1 = require("../agent/agentUtils");
8
- const asyncQueue_1 = require("./asyncQueue");
9
- const asyncLock_1 = require("../utils/asyncLock");
10
- const logger = (0, sdk_1.getLogger)();
11
- class UserAlreadyConnected extends Error {
12
- constructor() {
13
- super("User already connected to the conversation");
14
- }
15
- }
16
- exports.UserAlreadyConnected = UserAlreadyConnected;
17
- /**
18
- * Describes a Session (conversation) with connected participants.
19
- */
20
- class OpenSession {
21
- constructor(db, agent, sessionUUID, agentProfileUUID, sudoMcpServerManager, onEmpty) {
22
- this.db = db;
23
- this.agent = agent;
24
- this.sessionUUID = sessionUUID;
25
- this.agentProfileUUID = agentProfileUUID;
26
- this.skillManager = sudoMcpServerManager;
27
- this.onEmpty = onEmpty;
28
- this.connections = {};
29
- this.messageQueue = new asyncQueue_1.AsyncQueue((m) => this.onMessage(m));
30
- this.curAgentMsgId = undefined;
31
- }
32
- join(userName, ws) {
33
- if (this.connections[userName]) {
34
- throw new UserAlreadyConnected();
35
- }
36
- // Inform any other participants, and add the WebSocket to the map.
37
- this.broadcast({ type: "user_joined", user: userName });
38
- this.connections[userName] = ws;
39
- // TODO:
40
- //
41
- // - send conversation state (ServerHistory)
42
- const briefs = this.skillManager.getServerBriefs();
43
- this.sendTo(userName, { type: "mcp_server_briefs", server_briefs: briefs });
44
- const msm = this.agent.getMcpServerManager();
45
- const mcpServerNames = msm.getMcpServerNames();
46
- for (const serverName of mcpServerNames) {
47
- const info = msm.getMcpServer(serverName);
48
- this.sendTo(userName, {
49
- type: "mcp_server_added",
50
- server_name: serverName,
51
- tools: info.getTools(),
52
- enabled_tools: Object.keys(info.getEnabledTools()),
53
- });
54
- }
55
- ws.on("message", async (message) => {
56
- logger.debug(`[convMgr]: got message: (from ${userName}): ${message}`);
57
- const msgStr = message.toString();
58
- const msg = JSON.parse(msgStr);
59
- await this.messageQueue.enqueueAsync({ msg, from: userName });
60
- });
61
- ws.on("close", () => {
62
- logger.debug(`[convMgr]: ${userName} closed`);
63
- // Remove our connection then inform any other participants
64
- delete this.connections[userName];
65
- this.broadcast({ type: "user_left", user: userName });
66
- if (Object.keys(this.connections).length == 0) {
67
- this.onEmpty();
68
- }
69
- });
70
- }
71
- /**
72
- * Called once for each message. Messages are queued to avoid overlapping
73
- * calls to the LLM.
74
- */
75
- async onMessage(queuedMessage) {
76
- logger.debug(`[onMessage]: processing (${queuedMessage.from}) ` +
77
- `${JSON.stringify(queuedMessage.msg)}`);
78
- // In general, handlers return a message to be broadcast. Errors are
79
- // handled by returning an error to just the sender. Handlers can
80
- // also broadcast and send directly.
81
- try {
82
- const msg = queuedMessage.msg;
83
- let broadcastMsg = undefined;
84
- switch (msg.type) {
85
- case "msg":
86
- broadcastMsg = await this.onChatMessage(msg.message, queuedMessage.from);
87
- break;
88
- case "add_mcp_server":
89
- broadcastMsg = await this.onAddMcpServer(msg.server_name, msg.enable_all);
90
- break;
91
- case "remove_mcp_server":
92
- broadcastMsg = await this.onRemoveMcpServer(msg.server_name);
93
- break;
94
- case "enable_mcp_server_tool":
95
- broadcastMsg = await this.onEnableMcpServerTool(msg.server_name, msg.tool);
96
- break;
97
- case "disable_mcp_server_tool":
98
- broadcastMsg = await this.onDisableMcpServerTool(msg.server_name, msg.tool);
99
- break;
100
- case "enable_all_mcp_server_tools":
101
- broadcastMsg = await this.onEnableAllMcpServerTools(msg.server_name);
102
- break;
103
- case "disable_all_mcp_server_tools":
104
- broadcastMsg = await this.onDisableAllMcpServerTools(msg.server_name);
105
- break;
106
- case "set_system_prompt":
107
- broadcastMsg = await this.onSetSystemPrompt(msg.system_prompt);
108
- break;
109
- case "set_model":
110
- broadcastMsg = await this.onSetModel(msg.model);
111
- break;
112
- default:
113
- throw `unknown message: ${JSON.stringify(queuedMessage)}`;
114
- }
115
- if (broadcastMsg) {
116
- if (broadcastMsg instanceof Array) {
117
- broadcastMsg.map((msg) => this.broadcast(msg));
118
- }
119
- else {
120
- this.broadcast(broadcastMsg);
121
- }
122
- }
123
- }
124
- catch (err) {
125
- if (typeof err === "string") {
126
- this.sendTo(queuedMessage.from, { type: "error", message: err });
127
- }
128
- else {
129
- throw err;
130
- }
131
- }
132
- }
133
- async onAgentMessage(msg, end) {
134
- logger.debug(`[onAgentMessage] msg: ${msg}, end: ${end}`);
135
- (0, assert_1.strict)(this.curAgentMsgId);
136
- this.broadcast({
137
- type: "agent_msg_chunk",
138
- message_id: this.curAgentMsgId,
139
- message: msg,
140
- end,
141
- });
142
- }
143
- async onChatMessage(message, userToken) {
144
- // We manually broadcast the user's message here and start the agent
145
- // conversation, and then wait to get back all data from the agent before
146
- // processing further messages from clients.
147
- const msgId = (0, uuid_1.v4)();
148
- this.broadcast({
149
- type: "user_msg",
150
- message_id: msgId,
151
- message,
152
- from: userToken,
153
- });
154
- this.curAgentMsgId = `${msgId}-resp`;
155
- await this.agent.userMessageEx(message, undefined, userToken);
156
- }
157
- async onAddMcpServer(serverName, enableAll) {
158
- logger.info(`[onAddMcpServer]: Adding server ${serverName} (enable_all: ${enableAll})`);
159
- const mcpServerManager = this.agent.getMcpServerManager();
160
- if (mcpServerManager.hasMcpServer(serverName)) {
161
- throw `${serverName} already added`;
162
- }
163
- if (!this.skillManager.hasServer(serverName)) {
164
- throw `no such server: ${serverName}`;
165
- }
166
- await this.skillManager.addMcpServer(serverName, enableAll);
167
- mcpServerManager.enableAllTools(serverName);
168
- // Save changes to the AgentProfile
169
- await this.updateAgentProfile();
170
- // Broadcast the message to all participants.
171
- const server = mcpServerManager.getMcpServer(serverName);
172
- const tools = server.getTools();
173
- const enabled_tools = Object.keys(server.getEnabledTools());
174
- return {
175
- type: "mcp_server_added",
176
- server_name: serverName,
177
- tools,
178
- enabled_tools,
179
- };
180
- }
181
- async onRemoveMcpServer(server_name) {
182
- logger.info(`[onRemoveMcpServer]: Removing server ${server_name}`);
183
- const mcpServerManager = this.agent.getMcpServerManager();
184
- if (!mcpServerManager.hasMcpServer(server_name)) {
185
- throw `${server_name} not enabled`;
186
- }
187
- await mcpServerManager.removeMcpServer(server_name);
188
- await this.updateAgentProfile();
189
- return {
190
- type: "mcp_server_removed",
191
- server_name,
192
- };
193
- }
194
- async onEnableMcpServerTool(server_name, tool) {
195
- const msm = this.agent.getMcpServerManager();
196
- this.ensureMcpServerAndTool(msm, server_name, tool);
197
- msm.enableTool(server_name, tool);
198
- await this.updateAgentProfile();
199
- return { type: "mcp_server_tool_enabled", server_name, tool };
200
- }
201
- async onDisableMcpServerTool(server_name, tool) {
202
- const msm = this.agent.getMcpServerManager();
203
- this.ensureMcpServerAndTool(msm, server_name, tool);
204
- msm.disableTool(server_name, tool);
205
- await this.updateAgentProfile();
206
- return { type: "mcp_server_tool_disabled", server_name, tool };
207
- }
208
- async onEnableAllMcpServerTools(server_name) {
209
- // We reimplement the logic to enable any disabled tools so we can
210
- // construct messages along the way.
211
- const msm = this.agent.getMcpServerManager();
212
- const server = this.ensureMcpServer(msm, server_name);
213
- const enabledTools = server.getEnabledTools();
214
- const msgs = [];
215
- for (const tool of server.getTools()) {
216
- if (!enabledTools[tool.name]) {
217
- msm.enableTool(server_name, tool.name);
218
- msgs.push({
219
- type: "mcp_server_tool_enabled",
220
- server_name,
221
- tool: tool.name,
222
- });
223
- }
224
- }
225
- await this.updateAgentProfile();
226
- return msgs;
227
- }
228
- async onDisableAllMcpServerTools(server_name) {
229
- // We reimplement the logic to disable all enabled tools so we can
230
- // construct messages along the way.
231
- const msm = this.agent.getMcpServerManager();
232
- const server = this.ensureMcpServer(msm, server_name);
233
- const enabledTools = server.getEnabledTools();
234
- const msgs = [];
235
- for (const tool in enabledTools) {
236
- msm.disableTool(server_name, tool);
237
- msgs.push({ type: "mcp_server_tool_disabled", server_name, tool });
238
- }
239
- await this.updateAgentProfile();
240
- return msgs;
241
- }
242
- async onSetSystemPrompt(system_prompt) {
243
- this.agent.setSystemPrompt(system_prompt);
244
- await this.updateAgentProfile();
245
- return { type: "system_prompt_updated", system_prompt };
246
- }
247
- async onSetModel(model) {
248
- this.agent.setModel(model);
249
- await this.updateAgentProfile();
250
- return { type: "model_updated", model };
251
- }
252
- broadcast(msg) {
253
- logger.info(`[broadcast]: broadcast msg: ${JSON.stringify(msg)}`);
254
- const msgString = JSON.stringify(msg);
255
- for (const ws of Object.values(this.connections)) {
256
- ws.send(msgString);
257
- }
258
- }
259
- sendTo(userName, msg) {
260
- const ws = this.connections[userName];
261
- const msgString = JSON.stringify(msg);
262
- logger.info(`[sendTo]: (${userName}) msg: ${msgString}`);
263
- (0, assert_1.strict)(ws);
264
- ws.send(msgString);
265
- }
266
- ensureMcpServer(msm, serverName) {
267
- const server = msm.getMcpServer(serverName);
268
- if (!server) {
269
- throw `${serverName} not added`;
270
- }
271
- return server;
272
- }
273
- ensureMcpServerAndTool(msm, serverName, toolName) {
274
- const server = this.ensureMcpServer(msm, serverName);
275
- const tool = server.getTool(toolName);
276
- if (!tool) {
277
- throw `Tool ${toolName} on ${serverName} not found`;
278
- }
279
- return tool;
280
- }
281
- async updateAgentProfile() {
282
- const profile = this.agent.getAgentProfile();
283
- logger.debug(`[updateAgentProfile]: uuid: ${this.agentProfileUUID} profile: ` +
284
- JSON.stringify(profile));
285
- return this.db.updateAgentProfile(this.agentProfileUUID, profile);
286
- }
287
- }
288
- exports.OpenSession = OpenSession;
289
- /**
290
- * Handles forwarding of messages between all participants of a session, as
291
- * well as messages to/from and Agent.
292
- */
293
- class ConversationManager {
294
- constructor(db, llmUrl, xmcpUrl) {
295
- this.db = db;
296
- this.llmUrl = llmUrl;
297
- this.xmcpUrl = xmcpUrl;
298
- this.openSessionsLock = new asyncLock_1.AsyncLock();
299
- this.openSessions = {};
300
- }
301
- async join(sessionId, llmApiKey, xmcpApiKey, userData, ws) {
302
- await this.openSessionsLock.lockAndProcess(() => {
303
- return this.getOrCreateAndSubscribe(sessionId, llmApiKey, xmcpApiKey, userData.nickname || userData.uuid, ws);
304
- });
305
- }
306
- /**
307
- * Must be called while holding the openSessionsLock
308
- */
309
- async getOrCreateAndSubscribe(sessionId, llmApiKey, xmcpApiKey, userName, ws) {
310
- let openSession = this.openSessions[sessionId];
311
- if (openSession) {
312
- openSession.join(userName, ws);
313
- return openSession;
314
- }
315
- // Create a new session
316
- // TODO: The owner of llmApiKey and xmcpApiKey may not be the owner of the
317
- // session. Should we create the Agent and SudoMcpServerManager with the
318
- // session-owners api key?
319
- const onEmpty = () => {
320
- logger.debug(`session ${sessionId} empty. removing`);
321
- delete this.openSessions[sessionId];
322
- };
323
- const sessionData = await this.db.getSessionById(sessionId);
324
- if (!sessionData) {
325
- throw `no such session ${sessionId}`;
326
- }
327
- const conversation = sessionData.conversation;
328
- const agentProfileUUID = sessionData.agent_profile_uuid;
329
- const agentProfile = await this.db.getAgentProfileById(agentProfileUUID);
330
- if (!agentProfile) {
331
- throw `no such agent profile ${agentProfileUUID}`;
332
- }
333
- // TODO: store some owner data on the OpenSession object itself?
334
- const owner = await this.db.getUserFromUuid(sessionData.user_uuid);
335
- (0, assert_1.strict)(owner, `no owner for session ${JSON.stringify(sessionData)}`);
336
- const ownerUserName = owner.nickname;
337
- if (!ownerUserName) {
338
- throw (`user ${sessionData.user_uuid} has no user name - ` +
339
- "cannot create chat session");
340
- }
341
- // Access to the OpenSession (once it is iniailized
342
- const context = {};
343
- const platform = {
344
- openUrl: (url, _authResultP, display_name) => {
345
- // These requests are always passed to the original owner, since it is
346
- // his settings that will be used for all mcp servers.
347
- if (context.openSession) {
348
- const conn = openSession.connections[ownerUserName];
349
- if (conn) {
350
- openSession.sendTo(ownerUserName, {
351
- type: "open_url",
352
- url,
353
- display_name,
354
- });
355
- }
356
- else {
357
- throw `user ${ownerUserName} must authenticate`;
358
- }
359
- }
360
- else {
361
- throw `no open session ${sessionData.uuid}`;
362
- }
363
- },
364
- load: (_filename) => {
365
- throw "unimpl platform.load";
366
- },
367
- };
368
- const onMessage = async (msg, end) => {
369
- logger.debug(`[onMessage] msg: ${msg}, end: ${end}`);
370
- (0, assert_1.strict)(context.openSession);
371
- context.openSession.onAgentMessage(msg, end);
372
- };
373
- const onToolCall = async (toolCall) => {
374
- logger.debug(`[onToolCall] : ${JSON.stringify(toolCall)}`);
375
- (0, assert_1.strict)(context.openSession);
376
- context.openSession.broadcast({
377
- type: "agent_tool_call",
378
- message_id: toolCall.id,
379
- message: toolCall,
380
- });
381
- return true;
382
- };
383
- const xmcpConfig = sdk_1.Configuration.new(xmcpApiKey, this.xmcpUrl, false);
384
- const [agent, smsm] = await (0, agentUtils_1.createAgentWithSkills)(this.llmUrl, agentProfile, onMessage, onToolCall, platform, llmApiKey, xmcpConfig, undefined, conversation, true);
385
- openSession = new OpenSession(this.db, agent, sessionId, agentProfileUUID, smsm, onEmpty);
386
- context.openSession = openSession;
387
- this.openSessions[sessionId] = openSession;
388
- openSession.join(userName, ws);
389
- return openSession;
390
- }
391
- }
392
- exports.ConversationManager = ConversationManager;
@@ -1,209 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Database = exports.SUPABASE_LOCAL_KEY = exports.SUPABASE_LOCAL_URL = void 0;
4
- exports.resolveCompoundName = resolveCompoundName;
5
- const supabase_js_1 = require("@supabase/supabase-js");
6
- const sdk_1 = require("@xalia/xmcp/sdk");
7
- const logger = (0, sdk_1.getLogger)();
8
- exports.SUPABASE_LOCAL_URL = "http://127.0.0.1:54321";
9
- exports.SUPABASE_LOCAL_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiw" +
10
- "icm9sZSI6InNlcnZpY2Vfcm9sZSIsImV4cCI6MTk4MzgxMjk5Nn0.EGIM96RAZx35lJz" +
11
- "dJsyH-qQwv8Hdp7fsn3W0YpN81IU";
12
- /**
13
- * 'name' -> 'name'
14
- * 'space/name' -> ['space', 'name']
15
- */
16
- function resolveCompoundName(name) {
17
- const components = name.split("/");
18
- if (components.length === 1) {
19
- return name;
20
- }
21
- if (components.length !== 2) {
22
- throw "invalid compound name";
23
- }
24
- return components;
25
- }
26
- class Database {
27
- constructor(supabaseUrl, supabaseKey) {
28
- this.client = (0, supabase_js_1.createClient)(supabaseUrl, supabaseKey);
29
- }
30
- async getUserDataFromApiKey(apiKey) {
31
- const { data, error } = await this.client
32
- .from("api_keys")
33
- .select("user_uuid, users ( nickname )")
34
- .eq("api_key", apiKey)
35
- .maybeSingle();
36
- logger.debug(`[getUserDataFromApiKey]: got ${JSON.stringify({ data, error })}`);
37
- if (error) {
38
- throw error;
39
- }
40
- if (data === null) {
41
- return undefined;
42
- }
43
- return {
44
- uuid: data.user_uuid,
45
- nickname: data.users.nickname || `user ${data.user_uuid}`,
46
- };
47
- }
48
- async getUserFromUuid(user_uuid) {
49
- const { data, error } = await this.client
50
- .from("users")
51
- .select("*")
52
- .eq("uuid", user_uuid)
53
- .maybeSingle();
54
- if (error) {
55
- throw error;
56
- }
57
- return data;
58
- }
59
- async createUser(user_uuid, email, nickname, timezone) {
60
- const payload = {
61
- uuid: user_uuid,
62
- email,
63
- nickname,
64
- timezone: timezone || "UTC",
65
- };
66
- const { error } = await this.client.from("users").insert(payload);
67
- if (error) {
68
- throw error;
69
- }
70
- }
71
- async addApiKey(user_uuid, api_key, name, scopes, is_default = false) {
72
- const payload = {
73
- user_uuid,
74
- api_key,
75
- name,
76
- scopes,
77
- is_default,
78
- };
79
- const { data, error } = await this.client
80
- .from("api_keys")
81
- .insert(payload)
82
- .select("*")
83
- .maybeSingle();
84
- if (error) {
85
- throw error;
86
- }
87
- return data;
88
- }
89
- async getSavedAgentProfileById(agentProfileId) {
90
- const { data, error } = await this.client
91
- .from("agent_profiles")
92
- .select("*")
93
- .eq("uuid", agentProfileId)
94
- .maybeSingle();
95
- if (error) {
96
- throw error;
97
- }
98
- return data
99
- ? sdk_1.SavedAgentProfile.fromJSONObj(data)
100
- : undefined;
101
- }
102
- async getSavedAgentProfileByName(user_uuid, agentProfileName) {
103
- const { data, error } = await this.client
104
- .from("agent_profiles")
105
- .select("*")
106
- .eq("user_uuid", user_uuid)
107
- .eq("profile_name", agentProfileName)
108
- .maybeSingle();
109
- if (error) {
110
- throw error;
111
- }
112
- return data
113
- ? sdk_1.SavedAgentProfile.fromJSONObj(data)
114
- : undefined;
115
- }
116
- async getAgentProfileById(agentProfileId) {
117
- const { data, error } = await this.client
118
- .from("agent_profiles")
119
- .select("profile")
120
- .eq("uuid", agentProfileId)
121
- .maybeSingle();
122
- if (error) {
123
- throw error;
124
- }
125
- return data
126
- ? sdk_1.AgentProfile.fromJSONObj(data.profile)
127
- : undefined;
128
- }
129
- async createAgentProfile(user_uuid, profileName, profile) {
130
- const payload = {
131
- profile: profile,
132
- user_uuid,
133
- profile_name: profileName,
134
- };
135
- const { data, error } = await this.client
136
- .from("agent_profiles")
137
- .upsert(payload)
138
- .select("uuid");
139
- if (error) {
140
- throw error;
141
- }
142
- if (!data || !data[0] || !data[0].uuid) {
143
- return undefined;
144
- }
145
- return data[0].uuid;
146
- }
147
- async updateAgentProfile(uuid, profile) {
148
- const payload = {
149
- profile: profile,
150
- };
151
- const { error } = await this.client
152
- .from("agent_profiles")
153
- .update(payload)
154
- .eq("uuid", uuid);
155
- if (error) {
156
- throw error;
157
- }
158
- }
159
- async clearAgentProfiles() {
160
- await this.client.from("agent_profiles").delete().neq("uuid", "");
161
- }
162
- // TODO: is there a session model?
163
- async getSessionById(session_uuid) {
164
- const { data, error } = await this.client
165
- .from("sessions")
166
- .select("*")
167
- .eq("uuid", session_uuid)
168
- .maybeSingle();
169
- if (error) {
170
- throw error;
171
- }
172
- return data;
173
- }
174
- async getSessionByName(user_uuid, session_name) {
175
- const { data, error } = await this.client
176
- .from("sessions")
177
- .select("*")
178
- .eq("user_uuid", user_uuid)
179
- .eq("title", session_name)
180
- .maybeSingle();
181
- if (error) {
182
- throw error;
183
- }
184
- return data;
185
- }
186
- async createSession(user_uuid, title, agentProfileId) {
187
- const payload = {
188
- agent_profile_uuid: agentProfileId,
189
- user_uuid,
190
- title: title,
191
- conversation: [],
192
- };
193
- const { data, error } = await this.client
194
- .from("sessions")
195
- .upsert(payload)
196
- .select("uuid");
197
- if (error) {
198
- throw error;
199
- }
200
- if (!data || !data[0] || !data[0].uuid) {
201
- return undefined;
202
- }
203
- return data[0].uuid;
204
- }
205
- async clearSessions() {
206
- await this.client.from("sessions").delete().neq("uuid", "");
207
- }
208
- }
209
- exports.Database = Database;
@@ -1,74 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.FrontendChatClient = void 0;
4
- class FrontendChatClient {
5
- constructor(ws, onMessageCB, onConnectionClosedCB) {
6
- this.ws = ws;
7
- this.onMessageCB = onMessageCB;
8
- this.onConnectionClosedCB = onConnectionClosedCB;
9
- this.closed = false;
10
- }
11
- static async initWithParams(host, port, token, params, onMessageCB, onConnectionClosedCB) {
12
- return new Promise((resolve, reject) => {
13
- const urlParams = new URLSearchParams(params);
14
- const url = `ws://${host}:${port}?${urlParams}`;
15
- const ws = new WebSocket(url, [token]);
16
- console.log("created ws");
17
- const client = new FrontendChatClient(ws, onMessageCB, onConnectionClosedCB);
18
- ws.onopen = async () => {
19
- console.log("opened");
20
- ws.onmessage = (ev) => {
21
- try {
22
- const msgData = ev.data;
23
- if (typeof msgData !== "string") {
24
- throw `expected "string" data, got ${typeof msgData}`;
25
- }
26
- console.debug(`[client.onmessage]: ${msgData}`);
27
- const msg = JSON.parse(msgData);
28
- client.onMessageCB(msg);
29
- }
30
- catch (e) {
31
- client.close();
32
- throw e;
33
- }
34
- };
35
- resolve(client);
36
- };
37
- ws.onclose = (event) => {
38
- console.log("closed");
39
- console.log(`[client] WebSocket connection closed: ${JSON.stringify(event)}`);
40
- client.closed = true;
41
- onConnectionClosedCB();
42
- };
43
- ws.onerror = (error) => {
44
- console.error("[client] WebSocket error:", error);
45
- reject(error);
46
- client.closed = true;
47
- onConnectionClosedCB();
48
- };
49
- });
50
- }
51
- static async init(host, port, token, onMessageCB, onConnectionClosedCB, sessionId = "untitled", agentProfileId = undefined) {
52
- const params = { session_id: sessionId };
53
- if (agentProfileId) {
54
- params["agent_profile_id"] = agentProfileId;
55
- }
56
- return FrontendChatClient.initWithParams(host, port, token, params, onMessageCB, onConnectionClosedCB);
57
- }
58
- sendMessage(message) {
59
- if (this.closed) {
60
- throw new Error("Cannot send message on closed connection");
61
- }
62
- const data = JSON.stringify(message);
63
- this.ws.send(data);
64
- }
65
- close() {
66
- this.closed = true;
67
- this.onConnectionClosedCB();
68
- this.ws.close();
69
- }
70
- isClosed() {
71
- return this.closed;
72
- }
73
- }
74
- exports.FrontendChatClient = FrontendChatClient;