@xalia/agent 0.6.10 → 0.6.11
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/package.json +5 -2
- package/.env.development +0 -6
- package/.env.test +0 -7
- package/.prettierrc.json +0 -11
- package/context_system.md +0 -498
- package/eslint.config.mjs +0 -38
- package/scripts/chat_server +0 -8
- package/scripts/git_message +0 -31
- package/scripts/git_wip +0 -21
- package/scripts/pr_message +0 -18
- package/scripts/pr_review +0 -16
- package/scripts/setup_chat +0 -90
- package/scripts/shutdown_chat_server +0 -42
- package/scripts/start_chat_server +0 -24
- package/scripts/sudomcp_import +0 -23
- package/scripts/test_chat +0 -327
- package/src/agent/agent.ts +0 -699
- package/src/agent/agentUtils.ts +0 -286
- package/src/agent/compressingContextManager.ts +0 -129
- package/src/agent/context.ts +0 -265
- package/src/agent/contextWithWorkspace.ts +0 -162
- package/src/agent/documentSummarizer.ts +0 -157
- package/src/agent/dummyLLM.ts +0 -130
- package/src/agent/iAgentEventHandler.ts +0 -64
- package/src/agent/imageGenLLM.ts +0 -101
- package/src/agent/imageGenerator.ts +0 -45
- package/src/agent/iplatform.ts +0 -18
- package/src/agent/llm.ts +0 -74
- package/src/agent/mcpServerManager.ts +0 -541
- package/src/agent/nullAgentEventHandler.ts +0 -26
- package/src/agent/nullPlatform.ts +0 -13
- package/src/agent/openAI.ts +0 -123
- package/src/agent/openAILLM.ts +0 -99
- package/src/agent/openAILLMStreaming.ts +0 -648
- package/src/agent/promptProvider.ts +0 -87
- package/src/agent/repeatLLM.ts +0 -62
- package/src/agent/sudoMcpServerManager.ts +0 -361
- package/src/agent/test_data/harrypotter.txt +0 -6065
- package/src/agent/tokenAuth.ts +0 -50
- package/src/agent/tokenCounter.test.ts +0 -243
- package/src/agent/tokenCounter.ts +0 -483
- package/src/agent/toolSettings.ts +0 -24
- package/src/agent/tools/calculatorTool.ts +0 -50
- package/src/agent/tools/contentExtractors/htmlToText.ts +0 -61
- package/src/agent/tools/contentExtractors/pdfToText.ts +0 -60
- package/src/agent/tools/datetimeTool.ts +0 -41
- package/src/agent/tools/fileManager/fileManagerTool.ts +0 -199
- package/src/agent/tools/fileManager/index.ts +0 -50
- package/src/agent/tools/fileManager/memoryFileManager.ts +0 -120
- package/src/agent/tools/fileManager/mimeTypes.ts +0 -60
- package/src/agent/tools/fileManager/prompt.ts +0 -38
- package/src/agent/tools/fileManager/types.ts +0 -189
- package/src/agent/tools/index.ts +0 -49
- package/src/agent/tools/openUrlTool.ts +0 -62
- package/src/agent/tools/renderTool.ts +0 -92
- package/src/agent/tools/utils.ts +0 -74
- package/src/agent/tools/webSearch.ts +0 -138
- package/src/agent/tools/webSearchTool.ts +0 -44
- package/src/chat/client/chatClient.ts +0 -967
- package/src/chat/client/connection.test.ts +0 -241
- package/src/chat/client/connection.ts +0 -286
- package/src/chat/client/constants.ts +0 -1
- package/src/chat/client/index.ts +0 -21
- package/src/chat/client/interfaces.ts +0 -34
- package/src/chat/client/sessionClient.ts +0 -574
- package/src/chat/client/sessionFiles.ts +0 -142
- package/src/chat/client/teamManager.ts +0 -29
- package/src/chat/constants.ts +0 -6
- package/src/chat/data/apiKeyManager.ts +0 -76
- package/src/chat/data/dataModels.ts +0 -107
- package/src/chat/data/database.ts +0 -997
- package/src/chat/data/dbMcpServerConfigs.ts +0 -59
- package/src/chat/data/dbSessionFiles.ts +0 -107
- package/src/chat/data/dbSessionMessages.ts +0 -102
- package/src/chat/protocol/connectionMessages.ts +0 -49
- package/src/chat/protocol/constants.ts +0 -55
- package/src/chat/protocol/errors.ts +0 -16
- package/src/chat/protocol/messages.ts +0 -899
- package/src/chat/server/README.md +0 -127
- package/src/chat/server/chatContextManager.ts +0 -660
- package/src/chat/server/connectionManager.test.ts +0 -246
- package/src/chat/server/connectionManager.ts +0 -506
- package/src/chat/server/conversation.ts +0 -319
- package/src/chat/server/errorUtils.ts +0 -28
- package/src/chat/server/imageGeneratorTools.ts +0 -179
- package/src/chat/server/openAIRouterLLM.ts +0 -168
- package/src/chat/server/openSession.ts +0 -1945
- package/src/chat/server/openSessionMessageSender.ts +0 -4
- package/src/chat/server/promptRefiner.ts +0 -106
- package/src/chat/server/server.ts +0 -178
- package/src/chat/server/sessionFileManager.ts +0 -151
- package/src/chat/server/sessionRegistry.test.ts +0 -137
- package/src/chat/server/sessionRegistry.ts +0 -1553
- package/src/chat/server/test-utils/mockFactories.ts +0 -422
- package/src/chat/server/titleGenerator.test.ts +0 -103
- package/src/chat/server/titleGenerator.ts +0 -143
- package/src/chat/server/tools.ts +0 -170
- package/src/chat/utils/agentSessionMap.ts +0 -76
- package/src/chat/utils/approvalManager.ts +0 -189
- package/src/chat/utils/asyncLock.ts +0 -43
- package/src/chat/utils/asyncQueue.ts +0 -62
- package/src/chat/utils/multiAsyncQueue.ts +0 -66
- package/src/chat/utils/responseAwaiter.ts +0 -181
- package/src/chat/utils/userResolver.ts +0 -48
- package/src/chat/utils/websocket.ts +0 -16
- package/src/index.ts +0 -0
- package/src/test/agent.test.ts +0 -584
- package/src/test/approvalManager.test.ts +0 -141
- package/src/test/chatContextManager.test.ts +0 -552
- package/src/test/clientServerConnection.test.ts +0 -205
- package/src/test/compressingContextManager.test.ts +0 -77
- package/src/test/context.test.ts +0 -150
- package/src/test/contextTestTools.ts +0 -95
- package/src/test/conversation.test.ts +0 -109
- package/src/test/db.test.ts +0 -363
- package/src/test/dbMcpServerConfigs.test.ts +0 -112
- package/src/test/dbSessionFiles.test.ts +0 -258
- package/src/test/dbSessionMessages.test.ts +0 -85
- package/src/test/dbTestTools.ts +0 -157
- package/src/test/imageLoad.test.ts +0 -15
- package/src/test/mcpServerManager.test.ts +0 -114
- package/src/test/multiAsyncQueue.test.ts +0 -183
- package/src/test/openaiStreaming.test.ts +0 -177
- package/src/test/prompt.test.ts +0 -27
- package/src/test/promptProvider.test.ts +0 -33
- package/src/test/responseAwaiter.test.ts +0 -103
- package/src/test/sudoMcpServerManager.test.ts +0 -63
- package/src/test/testTools.ts +0 -176
- package/src/test/tools.test.ts +0 -64
- package/src/tool/agentChat.ts +0 -203
- package/src/tool/agentMain.ts +0 -180
- package/src/tool/chatMain.ts +0 -621
- package/src/tool/commandPrompt.ts +0 -264
- package/src/tool/files.ts +0 -82
- package/src/tool/main.ts +0 -25
- package/src/tool/nodePlatform.ts +0 -73
- package/src/tool/options.ts +0 -144
- package/src/tool/prompt.ts +0 -101
- package/test_data/background_test_profile.json +0 -6
- package/test_data/background_test_script.json +0 -11
- package/test_data/dummyllm_script_crash.json +0 -32
- package/test_data/dummyllm_script_image_gen.json +0 -19
- package/test_data/dummyllm_script_image_gen_fe.json +0 -29
- package/test_data/dummyllm_script_invoke_image_gen_tool.json +0 -37
- package/test_data/dummyllm_script_render_tool.json +0 -29
- package/test_data/dummyllm_script_simplecalc.json +0 -28
- package/test_data/dummyllm_script_test_auto_approve.json +0 -81
- package/test_data/dummyllm_script_test_simplecalc_addition.json +0 -29
- package/test_data/frog.png +0 -0
- package/test_data/frog.png.b64 +0 -1
- package/test_data/git_message_profile.json +0 -4
- package/test_data/git_wip_system.txt +0 -5
- package/test_data/image_gen_test_profile.json +0 -5
- package/test_data/pr_message_profile.json +0 -4
- package/test_data/pr_review_profile.json +0 -4
- package/test_data/prompt_simplecalc.txt +0 -1
- package/test_data/simplecalc_profile.json +0 -4
- package/test_data/sudomcp_import_profile.json +0 -4
- package/test_data/test_script_profile.json +0 -8
- package/tsconfig.json +0 -13
- package/vitest.config.ts +0 -39
|
@@ -1,574 +0,0 @@
|
|
|
1
|
-
import { Tool, Resource } 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 {
|
|
14
|
-
McpServerInfo,
|
|
15
|
-
McpServerInfoRW,
|
|
16
|
-
ResourceContent,
|
|
17
|
-
} from "../../agent/mcpServerManager";
|
|
18
|
-
import { IConversation } from "../../agent/agent";
|
|
19
|
-
import { MessageParam } from "../../agent/llm";
|
|
20
|
-
|
|
21
|
-
import {
|
|
22
|
-
ClientSessionMessage,
|
|
23
|
-
ClientSessionMessageData,
|
|
24
|
-
ServerSessionScopedMessage,
|
|
25
|
-
ClientSetWorkspace,
|
|
26
|
-
ClientToServer,
|
|
27
|
-
isServerSessionFileMessage,
|
|
28
|
-
} from "../protocol/messages";
|
|
29
|
-
import { SessionParticipantMap } from "../data/dataModels";
|
|
30
|
-
import { ISessionMessageSender } from "./interfaces";
|
|
31
|
-
import { IMessageSender } from "./connection";
|
|
32
|
-
import { SessionFiles } from "./sessionFiles";
|
|
33
|
-
import { SessionFileDescriptor } from "../../agent/tools/fileManager";
|
|
34
|
-
import { ResponseAwaiter } from "../utils/responseAwaiter";
|
|
35
|
-
|
|
36
|
-
const logger = getLogger();
|
|
37
|
-
|
|
38
|
-
class RemoteSudoMcpServerManager implements ISkillManager {
|
|
39
|
-
private sender: ISessionMessageSender;
|
|
40
|
-
private briefs: McpServerBrief[];
|
|
41
|
-
private briefsMap = new Map<string, McpServerBrief>();
|
|
42
|
-
private mcpServers = new Map<string, McpServerInfoRW>();
|
|
43
|
-
|
|
44
|
-
constructor(sender: ISessionMessageSender, briefs: McpServerBrief[]) {
|
|
45
|
-
this.sender = sender;
|
|
46
|
-
this.briefs = briefs;
|
|
47
|
-
briefs.forEach((b) => {
|
|
48
|
-
this.briefsMap.set(b.name, b);
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
hasMcpServer(mcpServerName: string): boolean {
|
|
53
|
-
return this.mcpServers.has(mcpServerName);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
getMcpServerNames(): string[] {
|
|
57
|
-
return Array.from(this.mcpServers.keys());
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
getMcpServer(mcpServerName: string): McpServerInfo {
|
|
61
|
-
const server = this.mcpServers.get(mcpServerName);
|
|
62
|
-
if (server) {
|
|
63
|
-
return server;
|
|
64
|
-
}
|
|
65
|
-
throw Error(`[getMcpServer] unknown server ${mcpServerName}`);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// eslint-disable-next-line @typescript-eslint/require-await
|
|
69
|
-
async removeMcpServer(mcpServerName: string): Promise<void> {
|
|
70
|
-
if (!this.mcpServers.has(mcpServerName)) {
|
|
71
|
-
logger.info(
|
|
72
|
-
`[removeMcpServer] mcpServers: ${JSON.stringify(this.mcpServers)}`
|
|
73
|
-
);
|
|
74
|
-
throw Error(`no server ${mcpServerName} (removeMcpServer)`);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
this.sender.sendSessionMessage({
|
|
78
|
-
type: "remove_mcp_server",
|
|
79
|
-
server_name: mcpServerName,
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
enableAllTools(mcpServerName: string): void {
|
|
84
|
-
if (!this.mcpServers.has(mcpServerName)) {
|
|
85
|
-
throw Error(`no server ${mcpServerName} (enableAllTools)`);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
this.sender.sendSessionMessage({
|
|
89
|
-
type: "enable_all_mcp_server_tools",
|
|
90
|
-
server_name: mcpServerName,
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
disableAllTools(mcpServerName: string): void {
|
|
95
|
-
if (!this.mcpServers.has(mcpServerName)) {
|
|
96
|
-
throw Error(`no server ${mcpServerName} (disableAllTools)`);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
this.sender.sendSessionMessage({
|
|
100
|
-
type: "disable_all_mcp_server_tools",
|
|
101
|
-
server_name: mcpServerName,
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
enableTool(mcpServerName: string, toolName: string): void {
|
|
106
|
-
const server = this.mcpServers.get(mcpServerName);
|
|
107
|
-
if (!server) {
|
|
108
|
-
throw Error(`no server ${mcpServerName} (enableTool)`);
|
|
109
|
-
}
|
|
110
|
-
const tools = server.getTool(toolName);
|
|
111
|
-
if (!tools) {
|
|
112
|
-
throw Error(`no tool ${toolName} on server ${mcpServerName}`);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
this.sender.sendSessionMessage({
|
|
116
|
-
type: "enable_mcp_server_tool",
|
|
117
|
-
server_name: mcpServerName,
|
|
118
|
-
tool: toolName,
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
disableTool(mcpServerName: string, toolName: string): void {
|
|
123
|
-
const server = this.mcpServers.get(mcpServerName);
|
|
124
|
-
if (!server) {
|
|
125
|
-
throw Error(`no server ${mcpServerName} (disableTool)`);
|
|
126
|
-
}
|
|
127
|
-
const tools = server.getTool(toolName);
|
|
128
|
-
if (!tools) {
|
|
129
|
-
throw Error(`no tool ${toolName} on server ${mcpServerName}`);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
this.sender.sendSessionMessage({
|
|
133
|
-
type: "disable_mcp_server_tool",
|
|
134
|
-
server_name: mcpServerName,
|
|
135
|
-
tool: toolName,
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
onMcpServerAdded(
|
|
140
|
-
mcpServerName: string,
|
|
141
|
-
tools: Tool[],
|
|
142
|
-
enabled_tools: string[],
|
|
143
|
-
resources: Resource[]
|
|
144
|
-
) {
|
|
145
|
-
logger.debug(
|
|
146
|
-
`[onMcpServerAdded]: ${mcpServerName}, tools: ${JSON.stringify(tools)}` +
|
|
147
|
-
`, enabled: ${JSON.stringify(enabled_tools)}`
|
|
148
|
-
);
|
|
149
|
-
|
|
150
|
-
const mcpServerInfo = new McpServerInfoRW(mcpServerName, tools, resources);
|
|
151
|
-
for (const tool of enabled_tools) {
|
|
152
|
-
mcpServerInfo.enableTool(tool);
|
|
153
|
-
}
|
|
154
|
-
this.mcpServers.set(mcpServerName, mcpServerInfo);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
onMcpServerRemoved(mcpServerName: string) {
|
|
158
|
-
this.mcpServers.delete(mcpServerName);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
onMcpServerToolEnabled(mcpServerName: string, toolName: string) {
|
|
162
|
-
const server = this.mcpServers.get(mcpServerName);
|
|
163
|
-
if (!server) {
|
|
164
|
-
throw Error(`no server ${mcpServerName} (onMcpServerToolEnabled)`);
|
|
165
|
-
}
|
|
166
|
-
const tools = server.getTool(toolName);
|
|
167
|
-
if (!tools) {
|
|
168
|
-
throw Error(`no tool ${toolName} on server ${mcpServerName}`);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
server.enableTool(toolName);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
onMcpServerToolDisabled(mcpServerName: string, toolName: string) {
|
|
175
|
-
const server = this.mcpServers.get(mcpServerName);
|
|
176
|
-
if (!server) {
|
|
177
|
-
throw Error(`no server ${mcpServerName} (onMcpServerToolDisabled)`);
|
|
178
|
-
}
|
|
179
|
-
const tools = server.getTool(toolName);
|
|
180
|
-
if (!tools) {
|
|
181
|
-
throw Error(`no tool ${toolName} on server ${mcpServerName}`);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
server.disableTool(toolName);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
getServerBriefs(): McpServerBrief[] {
|
|
188
|
-
return this.briefs;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
// eslint-disable-next-line @typescript-eslint/require-await
|
|
192
|
-
async addMcpServer(server_name: string, enable_all: boolean): Promise<void> {
|
|
193
|
-
if (!this.briefsMap.has(server_name)) {
|
|
194
|
-
throw Error(`no such server ${server_name} (addMcpServer)`);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
this.sender.sendSessionMessage({
|
|
198
|
-
type: "add_mcp_server",
|
|
199
|
-
server_name,
|
|
200
|
-
enable_all,
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
hasServer(server_name: string): boolean {
|
|
205
|
-
return this.briefsMap.has(server_name);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
async shutdown(): Promise<void> {}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
type ServerResponseMessages = Extract<
|
|
212
|
-
ServerSessionScopedMessage,
|
|
213
|
-
{ client_message_id?: string }
|
|
214
|
-
>;
|
|
215
|
-
|
|
216
|
-
export class SessionClient implements ISessionMessageSender, IConversation {
|
|
217
|
-
private readonly sessionUUID: string;
|
|
218
|
-
private readonly savedAgentProfile: SavedAgentProfile;
|
|
219
|
-
private readonly sender: IMessageSender<ClientToServer>;
|
|
220
|
-
private readonly smsm: RemoteSudoMcpServerManager;
|
|
221
|
-
private readonly sessionFiles: SessionFiles;
|
|
222
|
-
private readonly responseHandler: ResponseAwaiter<ServerResponseMessages>;
|
|
223
|
-
private participants: SessionParticipantMap;
|
|
224
|
-
private systemPrompt: string;
|
|
225
|
-
private model: string;
|
|
226
|
-
private agentPaused: boolean;
|
|
227
|
-
|
|
228
|
-
public constructor(
|
|
229
|
-
sessionUUID: string,
|
|
230
|
-
savedAgentProfile: SavedAgentProfile,
|
|
231
|
-
sender: IMessageSender<ClientToServer>,
|
|
232
|
-
serverBriefs: McpServerBrief[],
|
|
233
|
-
participants: SessionParticipantMap,
|
|
234
|
-
agentPaused: boolean
|
|
235
|
-
) {
|
|
236
|
-
const fileList: SessionFileDescriptor[] = []; // Pass in?
|
|
237
|
-
this.sessionUUID = sessionUUID;
|
|
238
|
-
this.savedAgentProfile = savedAgentProfile;
|
|
239
|
-
this.sender = sender;
|
|
240
|
-
this.smsm = new RemoteSudoMcpServerManager(this, serverBriefs);
|
|
241
|
-
this.sessionFiles = new SessionFiles(sessionUUID, fileList, sender);
|
|
242
|
-
this.responseHandler = ResponseAwaiter.init(
|
|
243
|
-
"session_error",
|
|
244
|
-
(msg: ServerResponseMessages) => msg.client_message_id
|
|
245
|
-
);
|
|
246
|
-
this.participants = participants;
|
|
247
|
-
this.systemPrompt = "";
|
|
248
|
-
this.model = "";
|
|
249
|
-
this.agentPaused = agentPaused;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
public getSessionUUID(): string {
|
|
253
|
-
return this.sessionUUID;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
/// This object can be queried to upload or download files, or get the
|
|
257
|
-
/// latest list. See `SessionFiles` for full usage.
|
|
258
|
-
public getSessionFiles(): SessionFiles {
|
|
259
|
-
return this.sessionFiles;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
public getSudoMcpServerManager(): ISkillManager {
|
|
263
|
-
return this.smsm;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
public getConversation(): MessageParam[] {
|
|
267
|
-
throw new Error("unimpl: getConversation");
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
public getAgentProfile(): AgentProfile {
|
|
271
|
-
return this.savedAgentProfile.profile;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
public getAgentUuid(): string {
|
|
275
|
-
return this.savedAgentProfile.uuid;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
getSavedAgentProfile(): SavedAgentProfile {
|
|
279
|
-
return this.savedAgentProfile;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
getSystemPrompt(): string {
|
|
283
|
-
return this.systemPrompt;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
setSystemPrompt(system_prompt: string): void {
|
|
287
|
-
// Don't set system prompt here. Wait until we get confirmation from the
|
|
288
|
-
// server.
|
|
289
|
-
this.sendSessionMessage({ type: "set_system_prompt", system_prompt });
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
getModel(): string {
|
|
293
|
-
return this.model;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
setModel(model: string): void {
|
|
297
|
-
// Don't set model here. Wait until we get confirmation from the server.
|
|
298
|
-
this.sendSessionMessage({ type: "set_model", model });
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
getAgentPaused(): boolean {
|
|
302
|
-
return this.agentPaused;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
setAgentPaused(paused: boolean) {
|
|
306
|
-
this.sendSessionMessage({
|
|
307
|
-
type: "set_agent_paused",
|
|
308
|
-
paused,
|
|
309
|
-
});
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
async getMcpResource(
|
|
313
|
-
server_name: string,
|
|
314
|
-
uri: string
|
|
315
|
-
): Promise<ResourceContent[]> {
|
|
316
|
-
const client_message_id = uuidv4();
|
|
317
|
-
const resourceP = this.responseHandler.waitForResponse(client_message_id);
|
|
318
|
-
this.sender.send({
|
|
319
|
-
type: "get_mcp_resource",
|
|
320
|
-
session_id: this.sessionUUID,
|
|
321
|
-
client_message_id,
|
|
322
|
-
server_name,
|
|
323
|
-
uri,
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
const resourceMsg = await resourceP;
|
|
327
|
-
if (resourceMsg.type !== "mcp_resource") {
|
|
328
|
-
throw new Error(
|
|
329
|
-
`unexpected response to resource req: ${JSON.stringify(resourceMsg)}`
|
|
330
|
-
);
|
|
331
|
-
}
|
|
332
|
-
return resourceMsg.contents;
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
userMessage(
|
|
336
|
-
msg?: string,
|
|
337
|
-
imageB64?: string,
|
|
338
|
-
attachedFiles?: { name: string; data_url: string }[]
|
|
339
|
-
): void {
|
|
340
|
-
assert(
|
|
341
|
-
msg || imageB64 || (attachedFiles && attachedFiles.length > 0),
|
|
342
|
-
"Either message, image, or attachedFiles must be provided"
|
|
343
|
-
);
|
|
344
|
-
|
|
345
|
-
this.sendSessionMessage({
|
|
346
|
-
type: "msg",
|
|
347
|
-
message: msg,
|
|
348
|
-
imageB64,
|
|
349
|
-
attachedFiles,
|
|
350
|
-
});
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
userMessageRaceMode(model: string, msg?: string, imageB64?: string): void {
|
|
354
|
-
assert(msg || imageB64, "Either message or image must be provided");
|
|
355
|
-
|
|
356
|
-
this.sendSessionMessage({
|
|
357
|
-
type: "msg",
|
|
358
|
-
message: msg,
|
|
359
|
-
imageB64,
|
|
360
|
-
race_mode: model,
|
|
361
|
-
});
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
raceModeResult(result: string, message_id: string): void {
|
|
365
|
-
this.sendSessionMessage({
|
|
366
|
-
type: "race_mode_result",
|
|
367
|
-
result,
|
|
368
|
-
message_id,
|
|
369
|
-
});
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
stop(): void {
|
|
373
|
-
this.sendSessionMessage({
|
|
374
|
-
type: "stop",
|
|
375
|
-
});
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
resetConversation(): void {
|
|
379
|
-
throw new Error("resetConversation not implemented for ChatClient");
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
shutdown(): Promise<void> {
|
|
383
|
-
throw new Error("shutdown not implemented for ChatClient");
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
getParticipants(): SessionParticipantMap {
|
|
387
|
-
return this.participants;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
/**
|
|
391
|
-
* Sets auto-approval preference for a specific tool.
|
|
392
|
-
*/
|
|
393
|
-
setAutoApproval(
|
|
394
|
-
serverName: string,
|
|
395
|
-
toolName: string,
|
|
396
|
-
autoApprove: boolean
|
|
397
|
-
): void {
|
|
398
|
-
const smsm = this.getSudoMcpServerManager();
|
|
399
|
-
if (!smsm.hasMcpServer(serverName)) {
|
|
400
|
-
throw Error(`server ${serverName} not added (setAutoApproval)`);
|
|
401
|
-
}
|
|
402
|
-
const server = smsm.getMcpServer(serverName);
|
|
403
|
-
const tool = server.getTool(toolName);
|
|
404
|
-
if (!tool) {
|
|
405
|
-
throw Error(`no tool ${toolName} on server ${serverName}`);
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
this.sendSessionMessage({
|
|
409
|
-
type: "set_auto_approval",
|
|
410
|
-
server_name: serverName,
|
|
411
|
-
tool: toolName,
|
|
412
|
-
auto_approve: autoApprove,
|
|
413
|
-
});
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
/**
|
|
417
|
-
* Send a generic message (for compatibility)
|
|
418
|
-
*/
|
|
419
|
-
public sendMessage(message: { type: string; message: string }): void {
|
|
420
|
-
throw new Error(`Unsupported message type: ${message.type}`);
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
/**
|
|
424
|
-
* The caller sees a message `ServerApproveToolCall`, at which point it
|
|
425
|
-
* should prompt the user for permission to run the tool. The result of
|
|
426
|
-
* that prompt should be passed here.
|
|
427
|
-
*/
|
|
428
|
-
toolCallApprovalResult(
|
|
429
|
-
id: string,
|
|
430
|
-
result: boolean,
|
|
431
|
-
auto_approve: boolean
|
|
432
|
-
): void {
|
|
433
|
-
this.sendSessionMessage({
|
|
434
|
-
type: "tool_call_approval_result",
|
|
435
|
-
id,
|
|
436
|
-
result,
|
|
437
|
-
auto_approve,
|
|
438
|
-
});
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
// Implementation of IMessageSender interface
|
|
442
|
-
public sendSessionMessage(message: ClientSessionMessageData): void {
|
|
443
|
-
const enrichedMessage: ClientSessionMessage = {
|
|
444
|
-
...message,
|
|
445
|
-
client_message_id: uuidv4(),
|
|
446
|
-
session_id: this.sessionUUID,
|
|
447
|
-
};
|
|
448
|
-
|
|
449
|
-
this.sender.send(enrichedMessage);
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
public setWorkspace(
|
|
453
|
-
message: string | undefined,
|
|
454
|
-
imageB64: string | undefined
|
|
455
|
-
): void {
|
|
456
|
-
const msg: ClientSetWorkspace = {
|
|
457
|
-
type: "set_workspace",
|
|
458
|
-
message,
|
|
459
|
-
imageB64,
|
|
460
|
-
};
|
|
461
|
-
this.sendSessionMessage(msg);
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
/**
|
|
465
|
-
* Set MCP server configuration.
|
|
466
|
-
*/
|
|
467
|
-
public setMcpServerConfig(
|
|
468
|
-
server_name: string,
|
|
469
|
-
config: Record<string, string>
|
|
470
|
-
): void {
|
|
471
|
-
this.sendSessionMessage({
|
|
472
|
-
type: "set_mcp_server_config",
|
|
473
|
-
server_name,
|
|
474
|
-
config,
|
|
475
|
-
});
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
public deleteMcpServerConfig(server_name: string): void {
|
|
479
|
-
this.sendSessionMessage({
|
|
480
|
-
type: "set_mcp_server_config",
|
|
481
|
-
server_name,
|
|
482
|
-
});
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
public async shareSession(): Promise<string> {
|
|
486
|
-
const msg: ClientToServer = {
|
|
487
|
-
type: "share_session",
|
|
488
|
-
client_message_id: uuidv4(),
|
|
489
|
-
session_id: this.sessionUUID,
|
|
490
|
-
};
|
|
491
|
-
|
|
492
|
-
this.sender.send(msg);
|
|
493
|
-
const response = await this.responseHandler.waitForResponse(
|
|
494
|
-
msg.client_message_id
|
|
495
|
-
);
|
|
496
|
-
if (response.type === "session_shared") {
|
|
497
|
-
return response.access_token;
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
throw new Error(`unexpected response to "share"session": ${response.type}`);
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
handleMessage(message: ServerSessionScopedMessage): void {
|
|
504
|
-
if (isServerSessionFileMessage(message)) {
|
|
505
|
-
this.sessionFiles.onMessage(message);
|
|
506
|
-
return;
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
switch (message.type) {
|
|
510
|
-
//
|
|
511
|
-
// State updates
|
|
512
|
-
//
|
|
513
|
-
|
|
514
|
-
case "mcp_server_added":
|
|
515
|
-
this.smsm.onMcpServerAdded(
|
|
516
|
-
message.server_name,
|
|
517
|
-
message.tools,
|
|
518
|
-
message.enabled_tools,
|
|
519
|
-
message.resources
|
|
520
|
-
);
|
|
521
|
-
break;
|
|
522
|
-
case "mcp_server_removed":
|
|
523
|
-
this.smsm.onMcpServerRemoved(message.server_name);
|
|
524
|
-
break;
|
|
525
|
-
case "mcp_server_tool_enabled":
|
|
526
|
-
this.smsm.onMcpServerToolEnabled(message.server_name, message.tool);
|
|
527
|
-
break;
|
|
528
|
-
case "mcp_server_tool_disabled":
|
|
529
|
-
this.smsm.onMcpServerToolDisabled(message.server_name, message.tool);
|
|
530
|
-
break;
|
|
531
|
-
case "system_prompt_updated":
|
|
532
|
-
this.systemPrompt = message.system_prompt;
|
|
533
|
-
break;
|
|
534
|
-
case "model_updated":
|
|
535
|
-
this.model = message.model;
|
|
536
|
-
break;
|
|
537
|
-
case "session_info":
|
|
538
|
-
// This is handled in the layer above, in the chatClient
|
|
539
|
-
break;
|
|
540
|
-
case "user_added":
|
|
541
|
-
this.participants.set(message.user_uuid, {
|
|
542
|
-
user_uuid: message.user_uuid,
|
|
543
|
-
nickname: message.nickname,
|
|
544
|
-
email: message.email,
|
|
545
|
-
role: message.role,
|
|
546
|
-
});
|
|
547
|
-
break;
|
|
548
|
-
case "user_removed":
|
|
549
|
-
this.participants.delete(message.user_uuid);
|
|
550
|
-
break;
|
|
551
|
-
|
|
552
|
-
// Responses to requests which can be awaited
|
|
553
|
-
case "mcp_resource":
|
|
554
|
-
case "session_shared":
|
|
555
|
-
this.responseHandler.onMessage(message);
|
|
556
|
-
break;
|
|
557
|
-
|
|
558
|
-
case "agent_paused":
|
|
559
|
-
this.agentPaused = message.paused;
|
|
560
|
-
break;
|
|
561
|
-
|
|
562
|
-
//
|
|
563
|
-
// Ignore other messages - the owner (the UI layer) can handle them at
|
|
564
|
-
// its discretion.
|
|
565
|
-
//
|
|
566
|
-
|
|
567
|
-
default:
|
|
568
|
-
logger.debug(
|
|
569
|
-
`[handleMessageInternal]: ignoring message: ${message.type}`
|
|
570
|
-
);
|
|
571
|
-
break;
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
}
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
import { v4 as uuidv4 } from "uuid";
|
|
2
|
-
import { strict as assert } from "assert";
|
|
3
|
-
|
|
4
|
-
import { getLogger } from "@xalia/xmcp/sdk";
|
|
5
|
-
import { SessionFileDescriptor } from "../../agent/tools/fileManager";
|
|
6
|
-
import {
|
|
7
|
-
ClientToServer,
|
|
8
|
-
ServerSessionFileContent,
|
|
9
|
-
ServerSessionFileMessage,
|
|
10
|
-
} from "../protocol/messages";
|
|
11
|
-
import { IMessageSender } from "./connection";
|
|
12
|
-
import { ResponseAwaiter } from "../utils/responseAwaiter";
|
|
13
|
-
|
|
14
|
-
const logger = getLogger();
|
|
15
|
-
|
|
16
|
-
/// Object for the UI to use to interact with the FileManager. If the UI
|
|
17
|
-
/// receives ServerSessionFileChanged or ServerSessionFileDeleted then it
|
|
18
|
-
/// should call `listFiles()` to get the new list of files, and optionally
|
|
19
|
-
/// request the latest content via `getFileContent`.
|
|
20
|
-
export class SessionFiles {
|
|
21
|
-
readonly sessionUUID: string;
|
|
22
|
-
readonly descriptors: Map<string, SessionFileDescriptor>;
|
|
23
|
-
readonly responseHandler: ResponseAwaiter<ServerSessionFileContent>;
|
|
24
|
-
readonly sender: IMessageSender<ClientToServer>;
|
|
25
|
-
|
|
26
|
-
constructor(
|
|
27
|
-
sessionUUID: string,
|
|
28
|
-
initialFileList: SessionFileDescriptor[],
|
|
29
|
-
sender: IMessageSender<ClientToServer>
|
|
30
|
-
) {
|
|
31
|
-
this.sessionUUID = sessionUUID;
|
|
32
|
-
this.descriptors = new Map(initialFileList.map((d) => [d.name, d]));
|
|
33
|
-
this.responseHandler = ResponseAwaiter.init(
|
|
34
|
-
undefined,
|
|
35
|
-
(msg) => msg.client_message_id
|
|
36
|
-
);
|
|
37
|
-
this.sender = sender;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
listFiles(): SessionFileDescriptor[] {
|
|
41
|
-
return Array.from(this.descriptors.values());
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Retrieve file contents.
|
|
46
|
-
*/
|
|
47
|
-
async getFileContent(name: string): Promise<string> {
|
|
48
|
-
const msg: ClientToServer = {
|
|
49
|
-
type: "session_file_get_content",
|
|
50
|
-
session_id: this.sessionUUID,
|
|
51
|
-
name,
|
|
52
|
-
client_message_id: uuidv4(),
|
|
53
|
-
};
|
|
54
|
-
this.sender.send(msg);
|
|
55
|
-
const response = await this.responseHandler.waitForResponse(
|
|
56
|
-
msg.client_message_id
|
|
57
|
-
);
|
|
58
|
-
if (response.name !== name) {
|
|
59
|
-
throw new Error(
|
|
60
|
-
`invalid name for file ${name}: ${JSON.stringify(response)}`
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
|
-
return response.data_url;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
deleteFile(name: string): void {
|
|
67
|
-
const msg: ClientToServer = {
|
|
68
|
-
type: "session_file_delete",
|
|
69
|
-
session_id: this.sessionUUID,
|
|
70
|
-
name,
|
|
71
|
-
client_message_id: uuidv4(),
|
|
72
|
-
};
|
|
73
|
-
this.sender.send(msg);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
putFileContent(
|
|
77
|
-
name: string | undefined,
|
|
78
|
-
summary: string | undefined,
|
|
79
|
-
data_url: string
|
|
80
|
-
): void {
|
|
81
|
-
// TODO: eventually, we could wait for a response which includes an AI
|
|
82
|
-
// assigned name.
|
|
83
|
-
assert(name, "for now, uploaded content must have a name");
|
|
84
|
-
|
|
85
|
-
const msg: ClientToServer = {
|
|
86
|
-
type: "session_file_put_content",
|
|
87
|
-
session_id: this.sessionUUID,
|
|
88
|
-
name,
|
|
89
|
-
summary,
|
|
90
|
-
data_url,
|
|
91
|
-
client_message_id: uuidv4(),
|
|
92
|
-
};
|
|
93
|
-
this.sender.send(msg);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
onMessage(msg: ServerSessionFileMessage) {
|
|
97
|
-
logger.debug(`[SessionFiles.onMessage]: msg: ${JSON.stringify(msg)}`);
|
|
98
|
-
switch (msg.type) {
|
|
99
|
-
case "session_file_changed":
|
|
100
|
-
this.descriptors.set(msg.descriptor.name, msg.descriptor);
|
|
101
|
-
break;
|
|
102
|
-
|
|
103
|
-
case "session_file_deleted":
|
|
104
|
-
this.descriptors.delete(msg.name);
|
|
105
|
-
break;
|
|
106
|
-
|
|
107
|
-
case "session_file_content":
|
|
108
|
-
this.responseHandler.onMessage(msg);
|
|
109
|
-
break;
|
|
110
|
-
|
|
111
|
-
default: {
|
|
112
|
-
const _: never = msg;
|
|
113
|
-
const msgStr = JSON.stringify(msg);
|
|
114
|
-
throw new Error(`[SessionFiles.onMessage] invalid message: ${msgStr}`);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
decodeSessionFileUrl(url: string): {
|
|
120
|
-
session_uuid: string;
|
|
121
|
-
name: string;
|
|
122
|
-
} {
|
|
123
|
-
const u = new URL(url);
|
|
124
|
-
if (u.protocol !== "file+session:") {
|
|
125
|
-
throw new Error(`unexpected protocol ${u.protocol} (file+session)`);
|
|
126
|
-
}
|
|
127
|
-
if (u.port || u.search || u.hash) {
|
|
128
|
-
throw new Error("badly formed session file url: ${url}");
|
|
129
|
-
}
|
|
130
|
-
return {
|
|
131
|
-
session_uuid: u.host || this.sessionUUID,
|
|
132
|
-
name: removeLeadingSlashes(u.pathname),
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
function removeLeadingSlashes(name: string): string {
|
|
138
|
-
while (name.startsWith("/")) {
|
|
139
|
-
name = name.slice(1);
|
|
140
|
-
}
|
|
141
|
-
return name;
|
|
142
|
-
}
|