@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.
- package/README.md +23 -8
- package/dist/agent/src/agent/agent.js +176 -96
- package/dist/agent/src/agent/agentUtils.js +82 -59
- 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/mcpServerManager.js +23 -24
- 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 +26 -14
- 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 +23 -21
- 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/utils/websocket.js +16 -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 +271 -83
- 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 +23 -20
- package/dist/agent/src/test/multiAsyncQueue.test.js +101 -0
- package/dist/agent/src/test/openaiStreaming.test.js +64 -35
- 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 +24 -25
- 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 +241 -58
- package/dist/agent/src/tool/commandPrompt.js +22 -17
- 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 +283 -138
- package/src/agent/agentUtils.ts +143 -108
- 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 +35 -31
- package/src/agent/nullAgentEventHandler.ts +20 -0
- package/src/agent/nullPlatform.ts +13 -0
- package/src/agent/openAILLMStreaming.ts +26 -13
- package/src/agent/promptProvider.ts +87 -0
- package/src/agent/repeatLLM.ts +5 -5
- package/src/agent/sudoMcpServerManager.ts +30 -29
- 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/utils/websocket.ts +16 -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 +358 -89
- 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 +21 -16
- package/src/test/multiAsyncQueue.test.ts +125 -0
- package/src/test/openaiStreaming.test.ts +71 -36
- 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 +32 -30
- 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 +292 -100
- package/src/tool/commandPrompt.ts +28 -19
- 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 -349
- package/dist/agent/src/chat/conversationManager.js +0 -392
- package/dist/agent/src/chat/db.js +0 -209
- package/dist/agent/src/chat/frontendClient.js +0 -74
- package/dist/agent/src/chat/server.js +0 -158
- package/src/chat/client.ts +0 -455
- package/src/chat/conversationManager.ts +0 -595
- package/src/chat/db.ts +0 -290
- package/src/chat/frontendClient.ts +0 -123
- package/src/chat/messages.ts +0 -235
- package/src/chat/server.ts +0 -177
- /package/dist/agent/src/{chat/messages.js → agent/iAgentEventHandler.js} +0 -0
- /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 "./
|
|
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>;
|