@xalia/agent 0.5.8 → 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 (185) hide show
  1. package/README.md +23 -8
  2. package/dist/agent/src/agent/agent.js +173 -96
  3. package/dist/agent/src/agent/agentUtils.js +82 -53
  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/iAgentEventHandler.js +2 -0
  8. package/dist/agent/src/agent/mcpServerManager.js +22 -23
  9. package/dist/agent/src/agent/nullAgentEventHandler.js +21 -0
  10. package/dist/agent/src/agent/nullPlatform.js +14 -0
  11. package/dist/agent/src/agent/openAILLMStreaming.js +12 -7
  12. package/dist/agent/src/agent/promptProvider.js +63 -0
  13. package/dist/agent/src/agent/repeatLLM.js +5 -5
  14. package/dist/agent/src/agent/sudoMcpServerManager.js +11 -9
  15. package/dist/agent/src/agent/tokenAuth.js +7 -7
  16. package/dist/agent/src/agent/tools.js +1 -1
  17. package/dist/agent/src/chat/client/chatClient.js +733 -0
  18. package/dist/agent/src/chat/client/connection.js +209 -0
  19. package/dist/agent/src/chat/client/connection.test.js +188 -0
  20. package/dist/agent/src/chat/client/constants.js +5 -0
  21. package/dist/agent/src/chat/client/index.js +15 -0
  22. package/dist/agent/src/chat/client/interfaces.js +2 -0
  23. package/dist/agent/src/chat/client/responseHandler.js +105 -0
  24. package/dist/agent/src/chat/client/sessionClient.js +331 -0
  25. package/dist/agent/src/chat/client/teamManager.js +2 -0
  26. package/dist/agent/src/chat/{apiKeyManager.js → data/apiKeyManager.js} +4 -0
  27. package/dist/agent/src/chat/data/dataModels.js +2 -0
  28. package/dist/agent/src/chat/data/database.js +749 -0
  29. package/dist/agent/src/chat/data/dbMcpServerConfigs.js +47 -0
  30. package/dist/agent/src/chat/protocol/connectionMessages.js +5 -0
  31. package/dist/agent/src/chat/protocol/constants.js +50 -0
  32. package/dist/agent/src/chat/protocol/errors.js +22 -0
  33. package/dist/agent/src/chat/protocol/messages.js +110 -0
  34. package/dist/agent/src/chat/server/chatContextManager.js +405 -0
  35. package/dist/agent/src/chat/server/connectionManager.js +352 -0
  36. package/dist/agent/src/chat/server/connectionManager.test.js +159 -0
  37. package/dist/agent/src/chat/server/conversation.js +198 -0
  38. package/dist/agent/src/chat/server/errorUtils.js +23 -0
  39. package/dist/agent/src/chat/server/openSession.js +869 -0
  40. package/dist/agent/src/chat/server/server.js +177 -0
  41. package/dist/agent/src/chat/server/sessionFileManager.js +161 -0
  42. package/dist/agent/src/chat/server/sessionRegistry.js +700 -0
  43. package/dist/agent/src/chat/server/sessionRegistry.test.js +97 -0
  44. package/dist/agent/src/chat/server/test-utils/mockFactories.js +307 -0
  45. package/dist/agent/src/chat/server/tools.js +243 -0
  46. package/dist/agent/src/chat/utils/agentSessionMap.js +66 -0
  47. package/dist/agent/src/chat/utils/approvalManager.js +85 -0
  48. package/dist/agent/src/{utils → chat/utils}/asyncLock.js +3 -3
  49. package/dist/agent/src/chat/{asyncQueue.js → utils/asyncQueue.js} +12 -2
  50. package/dist/agent/src/chat/utils/htmlToText.js +84 -0
  51. package/dist/agent/src/chat/utils/multiAsyncQueue.js +42 -0
  52. package/dist/agent/src/chat/utils/search.js +145 -0
  53. package/dist/agent/src/chat/utils/userResolver.js +46 -0
  54. package/dist/agent/src/chat/{websocket.js → utils/websocket.js} +2 -0
  55. package/dist/agent/src/test/agent.test.js +332 -0
  56. package/dist/agent/src/test/approvalManager.test.js +58 -0
  57. package/dist/agent/src/test/chatContextManager.test.js +392 -0
  58. package/dist/agent/src/test/clientServerConnection.test.js +158 -0
  59. package/dist/agent/src/test/compressingContextManager.test.js +65 -0
  60. package/dist/agent/src/test/context.test.js +83 -0
  61. package/dist/agent/src/test/conversation.test.js +89 -0
  62. package/dist/agent/src/test/db.test.js +262 -90
  63. package/dist/agent/src/test/dbMcpServerConfigs.test.js +72 -0
  64. package/dist/agent/src/test/dbTestTools.js +99 -0
  65. package/dist/agent/src/test/imageLoad.test.js +8 -7
  66. package/dist/agent/src/test/mcpServerManager.test.js +21 -18
  67. package/dist/agent/src/test/multiAsyncQueue.test.js +101 -0
  68. package/dist/agent/src/test/openaiStreaming.test.js +12 -11
  69. package/dist/agent/src/test/prompt.test.js +5 -4
  70. package/dist/agent/src/test/promptProvider.test.js +28 -0
  71. package/dist/agent/src/test/responseHandler.test.js +61 -0
  72. package/dist/agent/src/test/sudoMcpServerManager.test.js +14 -12
  73. package/dist/agent/src/test/testTools.js +109 -0
  74. package/dist/agent/src/test/tools.test.js +31 -0
  75. package/dist/agent/src/tool/agentChat.js +21 -10
  76. package/dist/agent/src/tool/agentMain.js +1 -1
  77. package/dist/agent/src/tool/chatMain.js +235 -58
  78. package/dist/agent/src/tool/commandPrompt.js +15 -9
  79. package/dist/agent/src/tool/files.js +20 -16
  80. package/dist/agent/src/tool/nodePlatform.js +47 -3
  81. package/dist/agent/src/tool/options.js +4 -4
  82. package/dist/agent/src/tool/prompt.js +19 -13
  83. package/eslint.config.mjs +14 -1
  84. package/package.json +14 -6
  85. package/scripts/chat_server +8 -0
  86. package/scripts/setup_chat +7 -2
  87. package/scripts/shutdown_chat_server +3 -0
  88. package/scripts/test_chat +135 -17
  89. package/src/agent/agent.ts +270 -135
  90. package/src/agent/agentUtils.ts +136 -95
  91. package/src/agent/compressingContextManager.ts +164 -0
  92. package/src/agent/context.ts +268 -0
  93. package/src/agent/dummyLLM.ts +76 -8
  94. package/src/agent/iAgentEventHandler.ts +54 -0
  95. package/src/agent/iplatform.ts +1 -0
  96. package/src/agent/mcpServerManager.ts +32 -30
  97. package/src/agent/nullAgentEventHandler.ts +20 -0
  98. package/src/agent/nullPlatform.ts +13 -0
  99. package/src/agent/openAILLMStreaming.ts +12 -6
  100. package/src/agent/promptProvider.ts +87 -0
  101. package/src/agent/repeatLLM.ts +5 -5
  102. package/src/agent/sudoMcpServerManager.ts +13 -11
  103. package/src/agent/tokenAuth.ts +7 -7
  104. package/src/agent/tools.ts +3 -1
  105. package/src/chat/client/chatClient.ts +900 -0
  106. package/src/chat/client/connection.test.ts +241 -0
  107. package/src/chat/client/connection.ts +276 -0
  108. package/src/chat/client/constants.ts +3 -0
  109. package/src/chat/client/index.ts +18 -0
  110. package/src/chat/client/interfaces.ts +34 -0
  111. package/src/chat/client/responseHandler.ts +131 -0
  112. package/src/chat/client/sessionClient.ts +443 -0
  113. package/src/chat/client/teamManager.ts +29 -0
  114. package/src/chat/{apiKeyManager.ts → data/apiKeyManager.ts} +6 -2
  115. package/src/chat/data/dataModels.ts +85 -0
  116. package/src/chat/data/database.ts +982 -0
  117. package/src/chat/data/dbMcpServerConfigs.ts +59 -0
  118. package/src/chat/protocol/connectionMessages.ts +49 -0
  119. package/src/chat/protocol/constants.ts +55 -0
  120. package/src/chat/protocol/errors.ts +16 -0
  121. package/src/chat/protocol/messages.ts +682 -0
  122. package/src/chat/server/README.md +127 -0
  123. package/src/chat/server/chatContextManager.ts +612 -0
  124. package/src/chat/server/connectionManager.test.ts +266 -0
  125. package/src/chat/server/connectionManager.ts +541 -0
  126. package/src/chat/server/conversation.ts +269 -0
  127. package/src/chat/server/errorUtils.ts +28 -0
  128. package/src/chat/server/openSession.ts +1332 -0
  129. package/src/chat/server/server.ts +177 -0
  130. package/src/chat/server/sessionFileManager.ts +239 -0
  131. package/src/chat/server/sessionRegistry.test.ts +138 -0
  132. package/src/chat/server/sessionRegistry.ts +1064 -0
  133. package/src/chat/server/test-utils/mockFactories.ts +422 -0
  134. package/src/chat/server/tools.ts +265 -0
  135. package/src/chat/utils/agentSessionMap.ts +76 -0
  136. package/src/chat/utils/approvalManager.ts +111 -0
  137. package/src/{utils → chat/utils}/asyncLock.ts +3 -3
  138. package/src/chat/{asyncQueue.ts → utils/asyncQueue.ts} +14 -3
  139. package/src/chat/utils/htmlToText.ts +61 -0
  140. package/src/chat/utils/multiAsyncQueue.ts +52 -0
  141. package/src/chat/utils/search.ts +139 -0
  142. package/src/chat/utils/userResolver.ts +48 -0
  143. package/src/chat/{websocket.ts → utils/websocket.ts} +2 -0
  144. package/src/test/agent.test.ts +487 -0
  145. package/src/test/approvalManager.test.ts +73 -0
  146. package/src/test/chatContextManager.test.ts +521 -0
  147. package/src/test/clientServerConnection.test.ts +207 -0
  148. package/src/test/compressingContextManager.test.ts +82 -0
  149. package/src/test/context.test.ts +105 -0
  150. package/src/test/conversation.test.ts +109 -0
  151. package/src/test/db.test.ts +351 -103
  152. package/src/test/dbMcpServerConfigs.test.ts +112 -0
  153. package/src/test/dbTestTools.ts +153 -0
  154. package/src/test/imageLoad.test.ts +7 -6
  155. package/src/test/mcpServerManager.test.ts +19 -14
  156. package/src/test/multiAsyncQueue.test.ts +125 -0
  157. package/src/test/openaiStreaming.test.ts +11 -10
  158. package/src/test/prompt.test.ts +4 -3
  159. package/src/test/promptProvider.test.ts +33 -0
  160. package/src/test/responseHandler.test.ts +78 -0
  161. package/src/test/sudoMcpServerManager.test.ts +22 -15
  162. package/src/test/testTools.ts +146 -0
  163. package/src/test/tools.test.ts +39 -0
  164. package/src/tool/agentChat.ts +26 -12
  165. package/src/tool/agentMain.ts +1 -1
  166. package/src/tool/chatMain.ts +283 -100
  167. package/src/tool/commandPrompt.ts +25 -9
  168. package/src/tool/files.ts +25 -19
  169. package/src/tool/nodePlatform.ts +52 -3
  170. package/src/tool/options.ts +4 -2
  171. package/src/tool/prompt.ts +22 -15
  172. package/test_data/dummyllm_script_crash.json +32 -0
  173. package/test_data/frog.png.b64 +1 -0
  174. package/vitest.config.ts +39 -0
  175. package/dist/agent/src/chat/client.js +0 -310
  176. package/dist/agent/src/chat/conversationManager.js +0 -502
  177. package/dist/agent/src/chat/db.js +0 -218
  178. package/dist/agent/src/chat/messages.js +0 -29
  179. package/dist/agent/src/chat/server.js +0 -158
  180. package/src/chat/client.ts +0 -445
  181. package/src/chat/conversationManager.ts +0 -730
  182. package/src/chat/db.ts +0 -304
  183. package/src/chat/messages.ts +0 -266
  184. package/src/chat/server.ts +0 -177
  185. /package/{frog.png → test_data/frog.png} +0 -0
@@ -1,502 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ConversationManager = exports.OpenSession = exports.UserAlreadyConnected = void 0;
4
- exports.userMessageToChatMessage = userMessageToChatMessage;
5
- exports.conversationToChatMessages = conversationToChatMessages;
6
- const uuid_1 = require("uuid");
7
- const assert_1 = require("assert");
8
- const sdk_1 = require("@xalia/xmcp/sdk");
9
- const agent_1 = require("../agent/agent");
10
- const agentUtils_1 = require("../agent/agentUtils");
11
- const asyncQueue_1 = require("./asyncQueue");
12
- const asyncLock_1 = require("../utils/asyncLock");
13
- const logger = (0, sdk_1.getLogger)();
14
- class UserAlreadyConnected extends Error {
15
- constructor() {
16
- super("User already connected to the conversation");
17
- }
18
- }
19
- exports.UserAlreadyConnected = UserAlreadyConnected;
20
- /**
21
- * Describes a Session (conversation) with connected participants.
22
- */
23
- class OpenSession {
24
- constructor(db, agent, sessionUUID, agentProfileUUID, sudoMcpServerManager, onEmpty) {
25
- this.db = db;
26
- this.agent = agent;
27
- this.sessionUUID = sessionUUID;
28
- this.agentProfileUUID = agentProfileUUID;
29
- this.skillManager = sudoMcpServerManager;
30
- this.onEmpty = onEmpty;
31
- this.connections = {};
32
- this.messageQueue = new asyncQueue_1.AsyncQueue((m) => this.onMessage(m));
33
- this.curAgentMsgId = undefined;
34
- }
35
- join(userName, ws) {
36
- if (this.connections[userName]) {
37
- throw new UserAlreadyConnected();
38
- }
39
- // Inform any other participants, then add the new WebSocket to the map.
40
- this.broadcast({ type: "user_joined", user: userName });
41
- this.connections[userName] = ws;
42
- // Send MCP server briefs first (client expects this)
43
- const briefs = this.skillManager.getServerBriefs();
44
- this.sendTo(userName, { type: "mcp_server_briefs", server_briefs: briefs });
45
- // Send conversation
46
- const conversation = this.agent.getConversation();
47
- const convMessages = conversationToChatMessages(conversation, userName);
48
- for (const chatMsg of convMessages) {
49
- this.sendTo(userName, chatMsg);
50
- }
51
- // Update the MSM state
52
- const agentProfile = this.agent.getAgentProfile();
53
- const msm = this.agent.getMcpServerManager();
54
- for (const server_name in agentProfile.mcp_settings) {
55
- const tools = msm.getMcpServer(server_name).getTools();
56
- const enabled_tools = agentProfile.mcp_settings[server_name];
57
- this.sendTo(userName, {
58
- type: "mcp_server_added",
59
- server_name,
60
- tools,
61
- enabled_tools,
62
- });
63
- }
64
- // Send system prompt and model
65
- this.sendTo(userName, {
66
- type: "system_prompt_updated",
67
- system_prompt: agentProfile.system_prompt,
68
- });
69
- if (agentProfile.model) {
70
- this.sendTo(userName, {
71
- type: "model_updated",
72
- model: agentProfile.model,
73
- });
74
- }
75
- ws.on("message", async (message) => {
76
- logger.debug(`[convMgr]: got message: (from ${userName}): ${message}`);
77
- const msgStr = message.toString();
78
- const msg = JSON.parse(msgStr);
79
- await this.messageQueue.enqueueAsync({ msg, from: userName });
80
- });
81
- ws.on("close", () => {
82
- logger.debug(`[convMgr]: ${userName} closed`);
83
- // Remove our connection then inform any other participants
84
- delete this.connections[userName];
85
- this.broadcast({ type: "user_left", user: userName });
86
- if (Object.keys(this.connections).length == 0) {
87
- this.onEmpty();
88
- }
89
- });
90
- }
91
- /**
92
- * Called once for each message. Messages are queued to avoid overlapping
93
- * calls to the LLM.
94
- */
95
- async onMessage(queuedMessage) {
96
- logger.debug(`[onMessage]: processing (${queuedMessage.from}) ` +
97
- `${JSON.stringify(queuedMessage.msg)}`);
98
- // In general, handlers return a message to be broadcast. Errors are
99
- // handled by returning an error to just the sender. Handlers can
100
- // also broadcast and send directly.
101
- try {
102
- const msg = queuedMessage.msg;
103
- let broadcastMsg = undefined;
104
- switch (msg.type) {
105
- case "msg":
106
- broadcastMsg = await this.onChatMessage(msg.message, queuedMessage.from);
107
- break;
108
- case "add_mcp_server":
109
- broadcastMsg = await this.onAddMcpServer(msg.server_name, msg.enable_all);
110
- break;
111
- case "remove_mcp_server":
112
- broadcastMsg = await this.onRemoveMcpServer(msg.server_name);
113
- break;
114
- case "enable_mcp_server_tool":
115
- broadcastMsg = await this.onEnableMcpServerTool(msg.server_name, msg.tool);
116
- break;
117
- case "disable_mcp_server_tool":
118
- broadcastMsg = await this.onDisableMcpServerTool(msg.server_name, msg.tool);
119
- break;
120
- case "enable_all_mcp_server_tools":
121
- broadcastMsg = await this.onEnableAllMcpServerTools(msg.server_name);
122
- break;
123
- case "disable_all_mcp_server_tools":
124
- broadcastMsg = await this.onDisableAllMcpServerTools(msg.server_name);
125
- break;
126
- case "set_system_prompt":
127
- broadcastMsg = await this.onSetSystemPrompt(msg.system_prompt);
128
- break;
129
- case "set_model":
130
- broadcastMsg = await this.onSetModel(msg.model);
131
- break;
132
- default:
133
- throw `unknown message: ${JSON.stringify(queuedMessage)}`;
134
- }
135
- if (broadcastMsg) {
136
- if (broadcastMsg instanceof Array) {
137
- broadcastMsg.map((msg) => this.broadcast(msg));
138
- }
139
- else {
140
- this.broadcast(broadcastMsg);
141
- }
142
- }
143
- }
144
- catch (err) {
145
- if (typeof err === "string") {
146
- this.sendTo(queuedMessage.from, { type: "error", message: err });
147
- }
148
- else {
149
- throw err;
150
- }
151
- }
152
- }
153
- async onAgentMessage(msg, end) {
154
- logger.debug(`[onAgentMessage] msg: ${msg}, end: ${end}`);
155
- (0, assert_1.strict)(this.curAgentMsgId);
156
- this.broadcast({
157
- type: "agent_msg_chunk",
158
- message_id: this.curAgentMsgId,
159
- message: msg,
160
- end,
161
- });
162
- }
163
- async onChatMessage(message,
164
- // imageB64: string | undefined,
165
- userToken) {
166
- // We manually broadcast the user's message here and start the agent
167
- // conversation, and then wait to get back all data from the agent before
168
- // processing further messages from clients.
169
- const msgId = (0, uuid_1.v4)();
170
- this.broadcast({
171
- type: "user_msg",
172
- message_id: msgId,
173
- message,
174
- // imageB64,
175
- from: userToken,
176
- });
177
- this.curAgentMsgId = `${msgId}-resp`;
178
- const userMessageParam = (0, agent_1.createUserMessage)(message,
179
- /*imageB64*/ undefined, userToken);
180
- if (!userMessageParam) {
181
- logger.debug(`ignoring empty message: ${message}`);
182
- return;
183
- }
184
- const assistantReply = await this.agent.userMessageRaw(userMessageParam);
185
- if (assistantReply) {
186
- // TODO: consider including all messages (including tool calls)
187
- // const newEntries = agent.getTrailingEntries(prevConvLength);
188
- // await this.db.sessionConversationAppend(this.sessionUUID, newEntries);
189
- const newEntries = [
190
- userMessageParam,
191
- assistantReply,
192
- ];
193
- await this.db.sessionConversationAppend(this.sessionUUID, newEntries);
194
- }
195
- }
196
- async onAddMcpServer(serverName, enableAll) {
197
- logger.info(`[onAddMcpServer]: Adding server ${serverName} (enable_all: ${enableAll})`);
198
- const mcpServerManager = this.agent.getMcpServerManager();
199
- if (mcpServerManager.hasMcpServer(serverName)) {
200
- throw `${serverName} already added`;
201
- }
202
- if (!this.skillManager.hasServer(serverName)) {
203
- throw `no such server: ${serverName}`;
204
- }
205
- await this.skillManager.addMcpServer(serverName, enableAll);
206
- mcpServerManager.enableAllTools(serverName);
207
- // Save changes to the AgentProfile
208
- await this.updateAgentProfile();
209
- // Broadcast the message to all participants.
210
- const server = mcpServerManager.getMcpServer(serverName);
211
- const tools = server.getTools();
212
- const enabled_tools = Object.keys(server.getEnabledTools());
213
- return {
214
- type: "mcp_server_added",
215
- server_name: serverName,
216
- tools,
217
- enabled_tools,
218
- };
219
- }
220
- async onRemoveMcpServer(server_name) {
221
- logger.info(`[onRemoveMcpServer]: Removing server ${server_name}`);
222
- const mcpServerManager = this.agent.getMcpServerManager();
223
- if (!mcpServerManager.hasMcpServer(server_name)) {
224
- throw `${server_name} not enabled`;
225
- }
226
- await mcpServerManager.removeMcpServer(server_name);
227
- await this.updateAgentProfile();
228
- return {
229
- type: "mcp_server_removed",
230
- server_name,
231
- };
232
- }
233
- async onEnableMcpServerTool(server_name, tool) {
234
- const msm = this.agent.getMcpServerManager();
235
- this.ensureMcpServerAndTool(msm, server_name, tool);
236
- msm.enableTool(server_name, tool);
237
- await this.updateAgentProfile();
238
- return { type: "mcp_server_tool_enabled", server_name, tool };
239
- }
240
- async onDisableMcpServerTool(server_name, tool) {
241
- const msm = this.agent.getMcpServerManager();
242
- this.ensureMcpServerAndTool(msm, server_name, tool);
243
- msm.disableTool(server_name, tool);
244
- await this.updateAgentProfile();
245
- return { type: "mcp_server_tool_disabled", server_name, tool };
246
- }
247
- async onEnableAllMcpServerTools(server_name) {
248
- // We reimplement the logic to enable any disabled tools so we can
249
- // construct messages along the way.
250
- const msm = this.agent.getMcpServerManager();
251
- const server = this.ensureMcpServer(msm, server_name);
252
- const enabledTools = server.getEnabledTools();
253
- const msgs = [];
254
- for (const tool of server.getTools()) {
255
- if (!enabledTools[tool.name]) {
256
- msm.enableTool(server_name, tool.name);
257
- msgs.push({
258
- type: "mcp_server_tool_enabled",
259
- server_name,
260
- tool: tool.name,
261
- });
262
- }
263
- }
264
- await this.updateAgentProfile();
265
- return msgs;
266
- }
267
- async onDisableAllMcpServerTools(server_name) {
268
- // We reimplement the logic to disable all enabled tools so we can
269
- // construct messages along the way.
270
- const msm = this.agent.getMcpServerManager();
271
- const server = this.ensureMcpServer(msm, server_name);
272
- const enabledTools = server.getEnabledTools();
273
- const msgs = [];
274
- for (const tool in enabledTools) {
275
- msm.disableTool(server_name, tool);
276
- msgs.push({ type: "mcp_server_tool_disabled", server_name, tool });
277
- }
278
- await this.updateAgentProfile();
279
- return msgs;
280
- }
281
- async onSetSystemPrompt(system_prompt) {
282
- this.agent.setSystemPrompt(system_prompt);
283
- await this.updateAgentProfile();
284
- return { type: "system_prompt_updated", system_prompt };
285
- }
286
- async onSetModel(model) {
287
- this.agent.setModel(model);
288
- await this.updateAgentProfile();
289
- return { type: "model_updated", model };
290
- }
291
- broadcast(msg) {
292
- logger.info(`[broadcast]: broadcast msg: ${JSON.stringify(msg)}`);
293
- const msgString = JSON.stringify(msg);
294
- for (const ws of Object.values(this.connections)) {
295
- ws.send(msgString);
296
- }
297
- }
298
- sendTo(userName, msg) {
299
- const ws = this.connections[userName];
300
- const msgString = JSON.stringify(msg);
301
- logger.info(`[sendTo]: (${userName}) msg: ${msgString}`);
302
- (0, assert_1.strict)(ws);
303
- ws.send(msgString);
304
- }
305
- ensureMcpServer(msm, serverName) {
306
- const server = msm.getMcpServer(serverName);
307
- if (!server) {
308
- throw `${serverName} not added`;
309
- }
310
- return server;
311
- }
312
- ensureMcpServerAndTool(msm, serverName, toolName) {
313
- const server = this.ensureMcpServer(msm, serverName);
314
- const tool = server.getTool(toolName);
315
- if (!tool) {
316
- throw `Tool ${toolName} on ${serverName} not found`;
317
- }
318
- return tool;
319
- }
320
- async updateAgentProfile() {
321
- const profile = this.agent.getAgentProfile();
322
- logger.debug(`[updateAgentProfile]: uuid: ${this.agentProfileUUID} profile: ` +
323
- JSON.stringify(profile));
324
- return this.db.updateAgentProfile(this.agentProfileUUID, profile);
325
- }
326
- }
327
- exports.OpenSession = OpenSession;
328
- /**
329
- * Handles forwarding of messages between all participants of a session, as
330
- * well as messages to/from and Agent.
331
- */
332
- class ConversationManager {
333
- constructor(db, llmUrl, xmcpUrl) {
334
- this.db = db;
335
- this.llmUrl = llmUrl;
336
- this.xmcpUrl = xmcpUrl;
337
- this.openSessionsLock = new asyncLock_1.AsyncLock();
338
- this.openSessions = {};
339
- }
340
- async join(sessionId, llmApiKey, xmcpApiKey, userData, ws) {
341
- await this.openSessionsLock.lockAndProcess(() => {
342
- return this.getOrCreateAndSubscribe(sessionId, llmApiKey, xmcpApiKey, userData.nickname || userData.uuid, ws);
343
- });
344
- }
345
- /**
346
- * Must be called while holding the openSessionsLock
347
- */
348
- async getOrCreateAndSubscribe(sessionId, llmApiKey, xmcpApiKey, userName, ws) {
349
- let openSession = this.openSessions[sessionId];
350
- if (openSession) {
351
- openSession.join(userName, ws);
352
- return openSession;
353
- }
354
- // Create a new session
355
- // TODO: The owner of llmApiKey and xmcpApiKey may not be the owner of the
356
- // session. Should we create the Agent and SudoMcpServerManager with the
357
- // session-owners api key?
358
- const onEmpty = () => {
359
- logger.debug(`session ${sessionId} empty. removing`);
360
- delete this.openSessions[sessionId];
361
- };
362
- const sessionData = await this.db.getSessionById(sessionId);
363
- if (!sessionData) {
364
- throw `no such session ${sessionId}`;
365
- }
366
- const conversation = sessionData.conversation;
367
- const agentProfileUUID = sessionData.agent_profile_uuid;
368
- const agentProfile = await this.db.getAgentProfileById(agentProfileUUID);
369
- if (!agentProfile) {
370
- throw `no such agent profile ${agentProfileUUID}`;
371
- }
372
- // TODO: store some owner data on the OpenSession object itself?
373
- const owner = await this.db.getUserFromUuid(sessionData.user_uuid);
374
- (0, assert_1.strict)(owner, `no owner for session ${JSON.stringify(sessionData)}`);
375
- const ownerUserName = owner.nickname;
376
- if (!ownerUserName) {
377
- throw (`user ${sessionData.user_uuid} has no user name - ` +
378
- "cannot create chat session");
379
- }
380
- // Access to the OpenSession (once it is iniailized
381
- const context = {};
382
- const platform = {
383
- openUrl: (url, _authResultP, display_name) => {
384
- // These requests are always passed to the original owner, since it is
385
- // his settings that will be used for all mcp servers.
386
- if (context.openSession) {
387
- const conn = openSession.connections[ownerUserName];
388
- if (conn) {
389
- openSession.sendTo(ownerUserName, {
390
- type: "open_url",
391
- url,
392
- display_name,
393
- });
394
- }
395
- else {
396
- throw `user ${ownerUserName} must authenticate`;
397
- }
398
- }
399
- else {
400
- throw `no open session ${sessionData.uuid}`;
401
- }
402
- },
403
- load: (_filename) => {
404
- throw "unimpl platform.load";
405
- },
406
- };
407
- const onMessage = async (msg, end) => {
408
- logger.debug(`[onMessage] msg: ${msg}, end: ${end}`);
409
- (0, assert_1.strict)(context.openSession);
410
- context.openSession.onAgentMessage(msg, end);
411
- };
412
- const onToolCall = async (toolCall) => {
413
- logger.debug(`[onToolCall] : ${JSON.stringify(toolCall)}`);
414
- (0, assert_1.strict)(context.openSession);
415
- context.openSession.broadcast({
416
- type: "agent_tool_call",
417
- message_id: toolCall.id,
418
- message: toolCall,
419
- });
420
- return true;
421
- };
422
- const xmcpConfig = sdk_1.Configuration.new(xmcpApiKey, this.xmcpUrl, false);
423
- const [agent, smsm] = await (0, agentUtils_1.createAgentWithSkills)(this.llmUrl, agentProfile, onMessage, onToolCall, platform, llmApiKey, xmcpConfig, undefined, conversation, true);
424
- openSession = new OpenSession(this.db, agent, sessionId, agentProfileUUID, smsm, onEmpty);
425
- context.openSession = openSession;
426
- this.openSessions[sessionId] = openSession;
427
- openSession.join(userName, ws);
428
- return openSession;
429
- }
430
- }
431
- exports.ConversationManager = ConversationManager;
432
- function userMessageToChatMessage(userMessage, message_id, defaultName) {
433
- const from = userMessage.name || defaultName;
434
- if (typeof userMessage.content === "string") {
435
- return {
436
- type: "user_msg",
437
- message_id,
438
- message: userMessage.content,
439
- from,
440
- };
441
- }
442
- let message = "";
443
- let image = undefined;
444
- for (const content of userMessage.content) {
445
- switch (content.type) {
446
- case "text":
447
- message += content.text;
448
- break;
449
- case "image_url":
450
- (0, assert_1.strict)(!image, "only one image per message supported");
451
- image = content.image_url;
452
- break;
453
- case "input_audio":
454
- throw "userMessageToChatMessage: audio content not supported";
455
- case "file":
456
- throw "userMessageToChatMessage: file content not supported";
457
- default:
458
- throw "userMessageToChatMessage: unexpected content.type";
459
- }
460
- }
461
- if (image) {
462
- throw "unimpl: image content";
463
- }
464
- return {
465
- type: "user_msg",
466
- message_id,
467
- message,
468
- from,
469
- };
470
- }
471
- function conversationToChatMessages(conversation, defaultName) {
472
- const msgs = [];
473
- for (const ccmp of conversation) {
474
- const message_id = `message_${msgs.length}`;
475
- switch (ccmp.role) {
476
- case "developer":
477
- throw "developer messages not handled yet";
478
- case "assistant":
479
- (0, assert_1.strict)(!ccmp.audio);
480
- if (ccmp.content) {
481
- msgs.push({
482
- type: "agent_msg",
483
- message: ccmp,
484
- message_id,
485
- });
486
- }
487
- // TODO: do we want to convert tool calls etc?
488
- break;
489
- case "user":
490
- {
491
- const msg = userMessageToChatMessage(ccmp, message_id, defaultName);
492
- if (msg) {
493
- msgs.push(msg);
494
- }
495
- }
496
- break;
497
- default:
498
- break;
499
- }
500
- }
501
- return msgs;
502
- }