@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.
- package/README.md +23 -8
- package/dist/agent/src/agent/agent.js +173 -96
- package/dist/agent/src/agent/agentUtils.js +82 -53
- package/dist/agent/src/agent/compressingContextManager.js +102 -0
- package/dist/agent/src/agent/context.js +189 -0
- package/dist/agent/src/agent/dummyLLM.js +46 -5
- package/dist/agent/src/agent/iAgentEventHandler.js +2 -0
- package/dist/agent/src/agent/mcpServerManager.js +22 -23
- package/dist/agent/src/agent/nullAgentEventHandler.js +21 -0
- package/dist/agent/src/agent/nullPlatform.js +14 -0
- package/dist/agent/src/agent/openAILLMStreaming.js +12 -7
- package/dist/agent/src/agent/promptProvider.js +63 -0
- package/dist/agent/src/agent/repeatLLM.js +5 -5
- package/dist/agent/src/agent/sudoMcpServerManager.js +11 -9
- package/dist/agent/src/agent/tokenAuth.js +7 -7
- package/dist/agent/src/agent/tools.js +1 -1
- package/dist/agent/src/chat/client/chatClient.js +733 -0
- package/dist/agent/src/chat/client/connection.js +209 -0
- package/dist/agent/src/chat/client/connection.test.js +188 -0
- package/dist/agent/src/chat/client/constants.js +5 -0
- package/dist/agent/src/chat/client/index.js +15 -0
- package/dist/agent/src/chat/client/interfaces.js +2 -0
- package/dist/agent/src/chat/client/responseHandler.js +105 -0
- package/dist/agent/src/chat/client/sessionClient.js +331 -0
- package/dist/agent/src/chat/client/teamManager.js +2 -0
- package/dist/agent/src/chat/{apiKeyManager.js → data/apiKeyManager.js} +4 -0
- package/dist/agent/src/chat/data/dataModels.js +2 -0
- package/dist/agent/src/chat/data/database.js +749 -0
- package/dist/agent/src/chat/data/dbMcpServerConfigs.js +47 -0
- package/dist/agent/src/chat/protocol/connectionMessages.js +5 -0
- package/dist/agent/src/chat/protocol/constants.js +50 -0
- package/dist/agent/src/chat/protocol/errors.js +22 -0
- package/dist/agent/src/chat/protocol/messages.js +110 -0
- package/dist/agent/src/chat/server/chatContextManager.js +405 -0
- package/dist/agent/src/chat/server/connectionManager.js +352 -0
- package/dist/agent/src/chat/server/connectionManager.test.js +159 -0
- package/dist/agent/src/chat/server/conversation.js +198 -0
- package/dist/agent/src/chat/server/errorUtils.js +23 -0
- package/dist/agent/src/chat/server/openSession.js +869 -0
- package/dist/agent/src/chat/server/server.js +177 -0
- package/dist/agent/src/chat/server/sessionFileManager.js +161 -0
- package/dist/agent/src/chat/server/sessionRegistry.js +700 -0
- package/dist/agent/src/chat/server/sessionRegistry.test.js +97 -0
- package/dist/agent/src/chat/server/test-utils/mockFactories.js +307 -0
- package/dist/agent/src/chat/server/tools.js +243 -0
- package/dist/agent/src/chat/utils/agentSessionMap.js +66 -0
- package/dist/agent/src/chat/utils/approvalManager.js +85 -0
- package/dist/agent/src/{utils → chat/utils}/asyncLock.js +3 -3
- package/dist/agent/src/chat/{asyncQueue.js → utils/asyncQueue.js} +12 -2
- package/dist/agent/src/chat/utils/htmlToText.js +84 -0
- package/dist/agent/src/chat/utils/multiAsyncQueue.js +42 -0
- package/dist/agent/src/chat/utils/search.js +145 -0
- package/dist/agent/src/chat/utils/userResolver.js +46 -0
- package/dist/agent/src/chat/{websocket.js → utils/websocket.js} +2 -0
- package/dist/agent/src/test/agent.test.js +332 -0
- package/dist/agent/src/test/approvalManager.test.js +58 -0
- package/dist/agent/src/test/chatContextManager.test.js +392 -0
- package/dist/agent/src/test/clientServerConnection.test.js +158 -0
- package/dist/agent/src/test/compressingContextManager.test.js +65 -0
- package/dist/agent/src/test/context.test.js +83 -0
- package/dist/agent/src/test/conversation.test.js +89 -0
- package/dist/agent/src/test/db.test.js +262 -90
- package/dist/agent/src/test/dbMcpServerConfigs.test.js +72 -0
- package/dist/agent/src/test/dbTestTools.js +99 -0
- package/dist/agent/src/test/imageLoad.test.js +8 -7
- package/dist/agent/src/test/mcpServerManager.test.js +21 -18
- package/dist/agent/src/test/multiAsyncQueue.test.js +101 -0
- package/dist/agent/src/test/openaiStreaming.test.js +12 -11
- package/dist/agent/src/test/prompt.test.js +5 -4
- package/dist/agent/src/test/promptProvider.test.js +28 -0
- package/dist/agent/src/test/responseHandler.test.js +61 -0
- package/dist/agent/src/test/sudoMcpServerManager.test.js +14 -12
- package/dist/agent/src/test/testTools.js +109 -0
- package/dist/agent/src/test/tools.test.js +31 -0
- package/dist/agent/src/tool/agentChat.js +21 -10
- package/dist/agent/src/tool/agentMain.js +1 -1
- package/dist/agent/src/tool/chatMain.js +235 -58
- package/dist/agent/src/tool/commandPrompt.js +15 -9
- package/dist/agent/src/tool/files.js +20 -16
- package/dist/agent/src/tool/nodePlatform.js +47 -3
- package/dist/agent/src/tool/options.js +4 -4
- package/dist/agent/src/tool/prompt.js +19 -13
- package/eslint.config.mjs +14 -1
- package/package.json +14 -6
- package/scripts/chat_server +8 -0
- package/scripts/setup_chat +7 -2
- package/scripts/shutdown_chat_server +3 -0
- package/scripts/test_chat +135 -17
- package/src/agent/agent.ts +270 -135
- package/src/agent/agentUtils.ts +136 -95
- package/src/agent/compressingContextManager.ts +164 -0
- package/src/agent/context.ts +268 -0
- package/src/agent/dummyLLM.ts +76 -8
- package/src/agent/iAgentEventHandler.ts +54 -0
- package/src/agent/iplatform.ts +1 -0
- package/src/agent/mcpServerManager.ts +32 -30
- package/src/agent/nullAgentEventHandler.ts +20 -0
- package/src/agent/nullPlatform.ts +13 -0
- package/src/agent/openAILLMStreaming.ts +12 -6
- package/src/agent/promptProvider.ts +87 -0
- package/src/agent/repeatLLM.ts +5 -5
- package/src/agent/sudoMcpServerManager.ts +13 -11
- package/src/agent/tokenAuth.ts +7 -7
- package/src/agent/tools.ts +3 -1
- package/src/chat/client/chatClient.ts +900 -0
- package/src/chat/client/connection.test.ts +241 -0
- package/src/chat/client/connection.ts +276 -0
- package/src/chat/client/constants.ts +3 -0
- package/src/chat/client/index.ts +18 -0
- package/src/chat/client/interfaces.ts +34 -0
- package/src/chat/client/responseHandler.ts +131 -0
- package/src/chat/client/sessionClient.ts +443 -0
- package/src/chat/client/teamManager.ts +29 -0
- package/src/chat/{apiKeyManager.ts → data/apiKeyManager.ts} +6 -2
- package/src/chat/data/dataModels.ts +85 -0
- package/src/chat/data/database.ts +982 -0
- package/src/chat/data/dbMcpServerConfigs.ts +59 -0
- package/src/chat/protocol/connectionMessages.ts +49 -0
- package/src/chat/protocol/constants.ts +55 -0
- package/src/chat/protocol/errors.ts +16 -0
- package/src/chat/protocol/messages.ts +682 -0
- package/src/chat/server/README.md +127 -0
- package/src/chat/server/chatContextManager.ts +612 -0
- package/src/chat/server/connectionManager.test.ts +266 -0
- package/src/chat/server/connectionManager.ts +541 -0
- package/src/chat/server/conversation.ts +269 -0
- package/src/chat/server/errorUtils.ts +28 -0
- package/src/chat/server/openSession.ts +1332 -0
- package/src/chat/server/server.ts +177 -0
- package/src/chat/server/sessionFileManager.ts +239 -0
- package/src/chat/server/sessionRegistry.test.ts +138 -0
- package/src/chat/server/sessionRegistry.ts +1064 -0
- package/src/chat/server/test-utils/mockFactories.ts +422 -0
- package/src/chat/server/tools.ts +265 -0
- package/src/chat/utils/agentSessionMap.ts +76 -0
- package/src/chat/utils/approvalManager.ts +111 -0
- package/src/{utils → chat/utils}/asyncLock.ts +3 -3
- package/src/chat/{asyncQueue.ts → utils/asyncQueue.ts} +14 -3
- package/src/chat/utils/htmlToText.ts +61 -0
- package/src/chat/utils/multiAsyncQueue.ts +52 -0
- package/src/chat/utils/search.ts +139 -0
- package/src/chat/utils/userResolver.ts +48 -0
- package/src/chat/{websocket.ts → utils/websocket.ts} +2 -0
- package/src/test/agent.test.ts +487 -0
- package/src/test/approvalManager.test.ts +73 -0
- package/src/test/chatContextManager.test.ts +521 -0
- package/src/test/clientServerConnection.test.ts +207 -0
- package/src/test/compressingContextManager.test.ts +82 -0
- package/src/test/context.test.ts +105 -0
- package/src/test/conversation.test.ts +109 -0
- package/src/test/db.test.ts +351 -103
- package/src/test/dbMcpServerConfigs.test.ts +112 -0
- package/src/test/dbTestTools.ts +153 -0
- package/src/test/imageLoad.test.ts +7 -6
- package/src/test/mcpServerManager.test.ts +19 -14
- package/src/test/multiAsyncQueue.test.ts +125 -0
- package/src/test/openaiStreaming.test.ts +11 -10
- package/src/test/prompt.test.ts +4 -3
- package/src/test/promptProvider.test.ts +33 -0
- package/src/test/responseHandler.test.ts +78 -0
- package/src/test/sudoMcpServerManager.test.ts +22 -15
- package/src/test/testTools.ts +146 -0
- package/src/test/tools.test.ts +39 -0
- package/src/tool/agentChat.ts +26 -12
- package/src/tool/agentMain.ts +1 -1
- package/src/tool/chatMain.ts +283 -100
- package/src/tool/commandPrompt.ts +25 -9
- package/src/tool/files.ts +25 -19
- package/src/tool/nodePlatform.ts +52 -3
- package/src/tool/options.ts +4 -2
- package/src/tool/prompt.ts +22 -15
- package/test_data/dummyllm_script_crash.json +32 -0
- package/test_data/frog.png.b64 +1 -0
- package/vitest.config.ts +39 -0
- package/dist/agent/src/chat/client.js +0 -310
- package/dist/agent/src/chat/conversationManager.js +0 -502
- package/dist/agent/src/chat/db.js +0 -218
- package/dist/agent/src/chat/messages.js +0 -29
- package/dist/agent/src/chat/server.js +0 -158
- package/src/chat/client.ts +0 -445
- package/src/chat/conversationManager.ts +0 -730
- package/src/chat/db.ts +0 -304
- package/src/chat/messages.ts +0 -266
- package/src/chat/server.ts +0 -177
- /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
|
-
}
|