@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,443 @@
1
+ import { Tool } from "@modelcontextprotocol/sdk/types.js";
2
+ import { strict as assert } from "assert";
3
+ import { v4 as uuidv4 } from "uuid";
4
+
5
+ import {
6
+ AgentProfile,
7
+ McpServerBrief,
8
+ SavedAgentProfile,
9
+ getLogger,
10
+ } from "@xalia/xmcp/sdk";
11
+
12
+ import { ISkillManager } from "../../agent/sudoMcpServerManager";
13
+ import { McpServerInfo, McpServerInfoRW } from "../../agent/mcpServerManager";
14
+ import { ChatCompletionMessageParam, IConversation } from "../../agent/agent";
15
+
16
+ import {
17
+ ClientSessionMessage,
18
+ ClientSessionMessageData,
19
+ ServerSessionScopedMessage,
20
+ ServerSessionInfo,
21
+ ClientSetWorkspace,
22
+ ClientToServer,
23
+ } from "../protocol/messages";
24
+ import { SessionParticipantMap } from "../data/dataModels";
25
+ import { createSessionParticipantMap } from "../data/database";
26
+ import { ISessionMessageSender } from "./interfaces";
27
+ import { IMessageSender } from "./connection";
28
+
29
+ const logger = getLogger();
30
+
31
+ class RemoteSudoMcpServerManager implements ISkillManager {
32
+ private sender: ISessionMessageSender;
33
+ private briefs: McpServerBrief[];
34
+ private briefsMap = new Map<string, McpServerBrief>();
35
+ private mcpServers = new Map<string, McpServerInfoRW>();
36
+
37
+ constructor(sender: ISessionMessageSender, briefs: McpServerBrief[]) {
38
+ this.sender = sender;
39
+ this.briefs = briefs;
40
+ briefs.forEach((b) => {
41
+ this.briefsMap.set(b.name, b);
42
+ });
43
+ }
44
+
45
+ hasMcpServer(mcpServerName: string): boolean {
46
+ return this.mcpServers.has(mcpServerName);
47
+ }
48
+
49
+ getMcpServerNames(): string[] {
50
+ return Array.from(this.mcpServers.keys());
51
+ }
52
+
53
+ getMcpServer(mcpServerName: string): McpServerInfo {
54
+ const server = this.mcpServers.get(mcpServerName);
55
+ if (server) {
56
+ return server;
57
+ }
58
+ throw Error(`[getMcpServer] unknown server ${mcpServerName}`);
59
+ }
60
+
61
+ // eslint-disable-next-line @typescript-eslint/require-await
62
+ async removeMcpServer(mcpServerName: string): Promise<void> {
63
+ if (!this.mcpServers.has(mcpServerName)) {
64
+ logger.info(
65
+ `[removeMcpServer] mcpServers: ${JSON.stringify(this.mcpServers)}`
66
+ );
67
+ throw Error(`no server ${mcpServerName} (removeMcpServer)`);
68
+ }
69
+
70
+ this.sender.sendSessionMessage({
71
+ type: "remove_mcp_server",
72
+ server_name: mcpServerName,
73
+ });
74
+ }
75
+
76
+ enableAllTools(mcpServerName: string): void {
77
+ if (!this.mcpServers.has(mcpServerName)) {
78
+ throw Error(`no server ${mcpServerName} (enableAllTools)`);
79
+ }
80
+
81
+ this.sender.sendSessionMessage({
82
+ type: "enable_all_mcp_server_tools",
83
+ server_name: mcpServerName,
84
+ });
85
+ }
86
+
87
+ disableAllTools(mcpServerName: string): void {
88
+ if (!this.mcpServers.has(mcpServerName)) {
89
+ throw Error(`no server ${mcpServerName} (disableAllTools)`);
90
+ }
91
+
92
+ this.sender.sendSessionMessage({
93
+ type: "disable_all_mcp_server_tools",
94
+ server_name: mcpServerName,
95
+ });
96
+ }
97
+
98
+ enableTool(mcpServerName: string, toolName: string): void {
99
+ const server = this.mcpServers.get(mcpServerName);
100
+ if (!server) {
101
+ throw Error(`no server ${mcpServerName} (enableTool)`);
102
+ }
103
+ const tools = server.getTool(toolName);
104
+ if (!tools) {
105
+ throw Error(`no tool ${toolName} on server ${mcpServerName}`);
106
+ }
107
+
108
+ this.sender.sendSessionMessage({
109
+ type: "enable_mcp_server_tool",
110
+ server_name: mcpServerName,
111
+ tool: toolName,
112
+ });
113
+ }
114
+
115
+ disableTool(mcpServerName: string, toolName: string): void {
116
+ const server = this.mcpServers.get(mcpServerName);
117
+ if (!server) {
118
+ throw Error(`no server ${mcpServerName} (disableTool)`);
119
+ }
120
+ const tools = server.getTool(toolName);
121
+ if (!tools) {
122
+ throw Error(`no tool ${toolName} on server ${mcpServerName}`);
123
+ }
124
+
125
+ this.sender.sendSessionMessage({
126
+ type: "disable_mcp_server_tool",
127
+ server_name: mcpServerName,
128
+ tool: toolName,
129
+ });
130
+ }
131
+
132
+ onMcpServerAdded(
133
+ mcpServerName: string,
134
+ tools: Tool[],
135
+ enabled_tools: string[]
136
+ ) {
137
+ logger.debug(
138
+ `[onMcpServerAdded]: ${mcpServerName}, tools: ${JSON.stringify(tools)}` +
139
+ `, enabled: ${JSON.stringify(enabled_tools)}`
140
+ );
141
+
142
+ const mcpServerInfo = new McpServerInfoRW(tools);
143
+ for (const tool of enabled_tools) {
144
+ mcpServerInfo.enableTool(tool);
145
+ }
146
+ this.mcpServers.set(mcpServerName, mcpServerInfo);
147
+ }
148
+
149
+ onMcpServerRemoved(mcpServerName: string) {
150
+ this.mcpServers.delete(mcpServerName);
151
+ }
152
+
153
+ onMcpServerToolEnabled(mcpServerName: string, toolName: string) {
154
+ const server = this.mcpServers.get(mcpServerName);
155
+ if (!server) {
156
+ throw Error(`no server ${mcpServerName} (onMcpServerToolEnabled)`);
157
+ }
158
+ const tools = server.getTool(toolName);
159
+ if (!tools) {
160
+ throw Error(`no tool ${toolName} on server ${mcpServerName}`);
161
+ }
162
+
163
+ server.enableTool(toolName);
164
+ }
165
+
166
+ onMcpServerToolDisabled(mcpServerName: string, toolName: string) {
167
+ const server = this.mcpServers.get(mcpServerName);
168
+ if (!server) {
169
+ throw Error(`no server ${mcpServerName} (onMcpServerToolDisabled)`);
170
+ }
171
+ const tools = server.getTool(toolName);
172
+ if (!tools) {
173
+ throw Error(`no tool ${toolName} on server ${mcpServerName}`);
174
+ }
175
+
176
+ server.disableTool(toolName);
177
+ }
178
+
179
+ getServerBriefs(): McpServerBrief[] {
180
+ return this.briefs;
181
+ }
182
+
183
+ // eslint-disable-next-line @typescript-eslint/require-await
184
+ async addMcpServer(server_name: string, enable_all: boolean): Promise<void> {
185
+ if (!this.briefsMap.has(server_name)) {
186
+ throw Error(`no such server ${server_name} (addMcpServer)`);
187
+ }
188
+
189
+ this.sender.sendSessionMessage({
190
+ type: "add_mcp_server",
191
+ server_name,
192
+ enable_all,
193
+ });
194
+ }
195
+
196
+ hasServer(server_name: string): boolean {
197
+ return this.briefsMap.has(server_name);
198
+ }
199
+
200
+ async shutdown(): Promise<void> {}
201
+ }
202
+
203
+ export class SessionClient implements ISessionMessageSender, IConversation {
204
+ private smsm: RemoteSudoMcpServerManager;
205
+ private systemPrompt: string;
206
+ private model: string;
207
+
208
+ public constructor(
209
+ private sessionUUID: string,
210
+ private savedAgentProfile: SavedAgentProfile,
211
+ private sender: IMessageSender<ClientToServer>,
212
+ serverBriefs: McpServerBrief[],
213
+ private participants: SessionParticipantMap
214
+ ) {
215
+ this.sender = sender;
216
+ this.smsm = new RemoteSudoMcpServerManager(this, serverBriefs);
217
+ this.systemPrompt = "";
218
+ this.model = "";
219
+ this.participants = participants;
220
+ }
221
+
222
+ public getSessionUUID(): string {
223
+ return this.sessionUUID;
224
+ }
225
+
226
+ public getSudoMcpServerManager(): ISkillManager {
227
+ return this.smsm;
228
+ }
229
+
230
+ public getConversation(): ChatCompletionMessageParam[] {
231
+ throw new Error("unimpl: getConversation");
232
+ }
233
+
234
+ public getAgentProfile(): AgentProfile {
235
+ return this.savedAgentProfile.profile;
236
+ }
237
+
238
+ public getAgentUuid(): string {
239
+ return this.savedAgentProfile.uuid;
240
+ }
241
+
242
+ getSavedAgentProfile(): SavedAgentProfile {
243
+ return this.savedAgentProfile;
244
+ }
245
+
246
+ getSystemPrompt(): string {
247
+ return this.systemPrompt;
248
+ }
249
+
250
+ setSystemPrompt(system_prompt: string): void {
251
+ // Don't set system prompt here. Wait until we get confirmation from the
252
+ // server.
253
+ this.sendSessionMessage({ type: "set_system_prompt", system_prompt });
254
+ }
255
+
256
+ getModel(): string {
257
+ return this.model;
258
+ }
259
+
260
+ setModel(model: string): void {
261
+ // Don't set model here. Wait until we get confirmation from the server.
262
+ this.sendSessionMessage({ type: "set_model", model });
263
+ }
264
+
265
+ userMessage(msg?: string, imageB64?: string): void {
266
+ assert(msg || imageB64, "Either message or image must be provided");
267
+
268
+ this.sendSessionMessage({ type: "msg", message: msg, imageB64 });
269
+ }
270
+
271
+ resetConversation(): void {
272
+ throw new Error("resetConversation not implemented for ChatClient");
273
+ }
274
+
275
+ shutdown(): Promise<void> {
276
+ throw new Error("shutdown not implemented for ChatClient");
277
+ }
278
+
279
+ getParticipants(): SessionParticipantMap {
280
+ return this.participants;
281
+ }
282
+
283
+ /**
284
+ * Sets auto-approval preference for a specific tool.
285
+ */
286
+ setAutoApproval(
287
+ serverName: string,
288
+ toolName: string,
289
+ autoApprove: boolean
290
+ ): void {
291
+ const smsm = this.getSudoMcpServerManager();
292
+ if (!smsm.hasMcpServer(serverName)) {
293
+ throw Error(`server ${serverName} not added (setAutoApproval)`);
294
+ }
295
+ const server = smsm.getMcpServer(serverName);
296
+ const tool = server.getTool(toolName);
297
+ if (!tool) {
298
+ throw Error(`no tool ${toolName} on server ${serverName}`);
299
+ }
300
+
301
+ this.sendSessionMessage({
302
+ type: "set_auto_approval",
303
+ server_name: serverName,
304
+ tool: toolName,
305
+ auto_approve: autoApprove,
306
+ });
307
+ }
308
+
309
+ /**
310
+ * Send a generic message (for compatibility)
311
+ */
312
+ public sendMessage(message: { type: string; message: string }): void {
313
+ throw new Error(`Unsupported message type: ${message.type}`);
314
+ }
315
+
316
+ /**
317
+ * The caller sees a message `ServerApproveToolCall`, at which point it
318
+ * should prompt the user for permission to run the tool. The result of
319
+ * that prompt should be passed here.
320
+ */
321
+ toolCallApprovalResult(
322
+ id: string,
323
+ result: boolean,
324
+ auto_approve: boolean
325
+ ): void {
326
+ this.sendSessionMessage({
327
+ type: "tool_call_approval_result",
328
+ id,
329
+ result,
330
+ auto_approve,
331
+ });
332
+ }
333
+
334
+ // Implementation of IMessageSender interface
335
+ public sendSessionMessage(message: ClientSessionMessageData): void {
336
+ const enrichedMessage: ClientSessionMessage = {
337
+ ...message,
338
+ client_message_id: uuidv4(),
339
+ session_id: this.sessionUUID,
340
+ };
341
+
342
+ this.sender.send(enrichedMessage);
343
+ }
344
+
345
+ public updateSessionInfo(sessionInfo: ServerSessionInfo): void {
346
+ // TODO: Implement this
347
+ // throw new Error("[SessionClient.updateSessionInfo] not implemented");
348
+ const infoStr = JSON.stringify(sessionInfo.workspace);
349
+ logger.debug(`[SessionClient] ignoring session info: ${infoStr}`);
350
+ }
351
+
352
+ public setWorkspace(
353
+ message: string | undefined,
354
+ imageB64: string | undefined
355
+ ): void {
356
+ const msg: ClientSetWorkspace = {
357
+ type: "set_workspace",
358
+ message,
359
+ imageB64,
360
+ };
361
+ this.sendSessionMessage(msg);
362
+ }
363
+
364
+ /**
365
+ * Set MCP server configuration.
366
+ */
367
+ public setMcpServerConfig(
368
+ server_name: string,
369
+ config: Record<string, string>
370
+ ): void {
371
+ this.sendSessionMessage({
372
+ type: "set_mcp_server_config",
373
+ server_name,
374
+ config,
375
+ });
376
+ }
377
+
378
+ public deleteMcpServerConfig(server_name: string): void {
379
+ this.sendSessionMessage({
380
+ type: "set_mcp_server_config",
381
+ server_name,
382
+ });
383
+ }
384
+
385
+ handleMessage(message: ServerSessionScopedMessage): void {
386
+ switch (message.type) {
387
+ //
388
+ // State updates
389
+ //
390
+
391
+ case "mcp_server_added":
392
+ this.smsm.onMcpServerAdded(
393
+ message.server_name,
394
+ message.tools,
395
+ message.enabled_tools
396
+ );
397
+ break;
398
+ case "mcp_server_removed":
399
+ this.smsm.onMcpServerRemoved(message.server_name);
400
+ break;
401
+ case "mcp_server_tool_enabled":
402
+ this.smsm.onMcpServerToolEnabled(message.server_name, message.tool);
403
+ break;
404
+ case "mcp_server_tool_disabled":
405
+ this.smsm.onMcpServerToolDisabled(message.server_name, message.tool);
406
+ break;
407
+ case "system_prompt_updated":
408
+ this.systemPrompt = message.system_prompt;
409
+ break;
410
+ case "model_updated":
411
+ this.model = message.model;
412
+ break;
413
+ case "session_info":
414
+ // Update participants if we receive session_info again
415
+ if ("participants" in message) {
416
+ this.participants = createSessionParticipantMap(message.participants);
417
+ }
418
+ break;
419
+ case "user_added":
420
+ this.participants.set(message.user_uuid, {
421
+ user_uuid: message.user_uuid,
422
+ nickname: message.nickname,
423
+ email: message.email,
424
+ role: message.role,
425
+ });
426
+ break;
427
+ case "user_removed":
428
+ this.participants.delete(message.user_uuid);
429
+ break;
430
+
431
+ //
432
+ // Ignore other messages - the owner (the UI layer) can handle them at
433
+ // its discretion.
434
+ //
435
+
436
+ default:
437
+ logger.debug(
438
+ `[handleMessageInternal]: ignoring message: ${message.type}`
439
+ );
440
+ break;
441
+ }
442
+ }
443
+ }
@@ -0,0 +1,29 @@
1
+ import { ClientTeamInfo } from "./chatClient";
2
+ import { AgentSessionData } from "../data/dataModels";
3
+
4
+ export interface ITeamManager {
5
+ /**
6
+ * Get the map of teams, keys are team UUIDs
7
+ */
8
+ getTeams(): Map<string, ClientTeamInfo>;
9
+
10
+ /**
11
+ * Get the current team ID
12
+ */
13
+ getCurrentTeamId(): string | undefined;
14
+
15
+ /**
16
+ * Get the current team info
17
+ */
18
+ getCurrentTeamInfo(): ClientTeamInfo | undefined;
19
+
20
+ /**
21
+ * Set the current team ID
22
+ */
23
+ setCurrentTeamId(teamUuid: string): void;
24
+
25
+ /**
26
+ * Get the agent session map of a user
27
+ */
28
+ getUserAgentSessionMap(): Map<string, AgentSessionData>;
29
+ }
@@ -1,15 +1,19 @@
1
1
  // TODO:
2
2
  // - lru-cache
3
3
 
4
- import { Database, UserData } from "./db";
4
+ import { Database, UserData } from "./database";
5
+ import { getLogger } from "@xalia/xmcp/sdk";
6
+
7
+ const logger = getLogger();
5
8
 
6
9
  export class ApiKeyManager {
7
10
  constructor(private db: Database) {}
8
11
 
9
12
  public async verifyApiKey(apiKey: string): Promise<UserData | undefined> {
10
13
  // TODO: Cache this
11
-
14
+ logger.info(`[ApiKeyManager] Verifying API key: ${apiKey}`);
12
15
  const userInfo = await this.db.getUserDataFromApiKey(apiKey);
16
+ logger.info(`[ApiKeyManager] User info: ${JSON.stringify(userInfo)}`);
13
17
  return userInfo;
14
18
 
15
19
  // if (apiKey.startsWith("dummy_key")) {
@@ -0,0 +1,85 @@
1
+ import { SavedAgentProfile } from "@xalia/xmcp/sdk";
2
+ import { ChatCompletionMessageParam } from "../../agent/agent";
3
+
4
+ export type UserMessageData = {
5
+ message?: string | undefined;
6
+ imageB64?: string | undefined;
7
+ };
8
+
9
+ export type TeamRole = "owner" | "participant";
10
+
11
+ export type TeamParticipant = {
12
+ user_uuid: string;
13
+ nickname: string;
14
+ email: string;
15
+ role: TeamRole;
16
+ };
17
+
18
+ export type SessionMessage = {
19
+ message_idx: number;
20
+ sender_uuid?: string;
21
+ is_for_llm: boolean;
22
+ content: ChatCompletionMessageParam;
23
+ };
24
+
25
+ export type LLMSessionMessage = {
26
+ message_idx: number;
27
+ sender_uuid: string;
28
+ content: ChatCompletionMessageParam;
29
+ };
30
+
31
+ /**
32
+ * Checkpoint data for a specific conversation.
33
+ */
34
+ export type SessionCheckpoint = {
35
+ /**
36
+ * Index of last message included in this checkpoint.
37
+ */
38
+ message_idx: number;
39
+ /**
40
+ * Summary of the conversation up to and including `message_idx`.
41
+ */
42
+ summary: string;
43
+ };
44
+
45
+ /**
46
+ * Session data required to create a new session.
47
+ */
48
+ export type SessionCreateData = {
49
+ session_uuid: string;
50
+ title: string;
51
+ agent_profile_uuid: string;
52
+ user_uuid: string;
53
+ team_uuid?: string | undefined;
54
+ workspace?: UserMessageData | undefined;
55
+ };
56
+
57
+ /**
58
+ * Data for existing session.
59
+ */
60
+ export type SessionData = SessionCreateData & {
61
+ updated_at: string;
62
+ };
63
+
64
+ export type AgentSessionData = {
65
+ agent_profile: SavedAgentProfile;
66
+ sessions: SessionData[];
67
+ updated_at: number;
68
+ };
69
+
70
+ /**
71
+ * Team sessions for ServerSessionList response
72
+ */
73
+ export type TeamInfo = {
74
+ team_uuid: string;
75
+ team_name: string;
76
+ owner_uuid: string;
77
+ participants: Array<TeamParticipant>;
78
+ sessions: Array<SessionData>;
79
+ agents: Array<SavedAgentProfile>;
80
+ };
81
+
82
+ /**
83
+ * Map from user_uuid to role
84
+ */
85
+ export type SessionParticipantMap = Map<string, TeamParticipant>;