@xalia/agent 0.5.7 → 0.5.8
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/dist/agent/src/agent/agent.js +3 -0
- package/dist/agent/src/agent/agentUtils.js +6 -12
- package/dist/agent/src/agent/mcpServerManager.js +1 -1
- package/dist/agent/src/agent/openAILLMStreaming.js +14 -7
- package/dist/agent/src/agent/sudoMcpServerManager.js +13 -13
- package/dist/agent/src/chat/client.js +24 -63
- package/dist/agent/src/chat/conversationManager.js +122 -12
- package/dist/agent/src/chat/db.js +9 -0
- package/dist/agent/src/chat/messages.js +27 -0
- package/dist/agent/src/chat/websocket.js +14 -0
- package/dist/agent/src/test/db.test.js +16 -0
- package/dist/agent/src/test/mcpServerManager.test.js +2 -2
- package/dist/agent/src/test/openaiStreaming.test.js +56 -28
- package/dist/agent/src/test/sudoMcpServerManager.test.js +10 -13
- package/dist/agent/src/tool/chatMain.js +7 -1
- package/dist/agent/src/tool/commandPrompt.js +9 -10
- package/package.json +1 -1
- package/src/agent/agent.ts +14 -4
- package/src/agent/agentUtils.ts +17 -23
- package/src/agent/mcpServerManager.ts +3 -1
- package/src/agent/openAILLMStreaming.ts +14 -7
- package/src/agent/sudoMcpServerManager.ts +17 -18
- package/src/chat/client.ts +35 -45
- package/src/chat/conversationManager.ts +147 -12
- package/src/chat/db.ts +14 -0
- package/src/chat/messages.ts +31 -0
- package/src/chat/websocket.ts +14 -0
- package/src/test/db.test.ts +22 -1
- package/src/test/mcpServerManager.test.ts +2 -2
- package/src/test/openaiStreaming.test.ts +64 -30
- package/src/test/sudoMcpServerManager.test.ts +11 -16
- package/src/tool/chatMain.ts +11 -2
- package/src/tool/commandPrompt.ts +8 -15
- package/dist/agent/src/chat/frontendClient.js +0 -74
- package/src/chat/frontendClient.ts +0 -123
|
@@ -2,51 +2,46 @@ import { expect } from "chai";
|
|
|
2
2
|
import chalk from "chalk";
|
|
3
3
|
import { Tool } from "@modelcontextprotocol/sdk/types.js";
|
|
4
4
|
|
|
5
|
-
import { McpServerManager } from "../agent/mcpServerManager";
|
|
6
5
|
import { SkillManager, LOCAL_SERVER_URL } from "../agent/sudoMcpServerManager";
|
|
7
6
|
|
|
8
|
-
let
|
|
7
|
+
let manager: SkillManager | undefined = undefined;
|
|
9
8
|
|
|
10
|
-
async function getServerManagers(): Promise<
|
|
11
|
-
if (!
|
|
12
|
-
|
|
13
|
-
const sm = await SkillManager.initialize(
|
|
14
|
-
tm,
|
|
9
|
+
async function getServerManagers(): Promise<SkillManager> {
|
|
10
|
+
if (!manager) {
|
|
11
|
+
manager = await SkillManager.initialize(
|
|
15
12
|
(_url: string) => {
|
|
16
13
|
throw "unexpected call to openUrl";
|
|
17
14
|
},
|
|
18
15
|
LOCAL_SERVER_URL,
|
|
19
16
|
"dummy_key"
|
|
20
17
|
);
|
|
21
|
-
|
|
22
|
-
managers = [tm, sm];
|
|
23
18
|
}
|
|
24
19
|
|
|
25
|
-
return
|
|
20
|
+
return manager;
|
|
26
21
|
}
|
|
27
22
|
|
|
28
23
|
async function shutdownAll() {
|
|
29
|
-
if (
|
|
30
|
-
await
|
|
24
|
+
if (manager) {
|
|
25
|
+
await manager.shutdown();
|
|
31
26
|
}
|
|
32
|
-
|
|
27
|
+
manager = undefined;
|
|
33
28
|
}
|
|
34
29
|
|
|
35
30
|
describe("SudoMcpServerManager", async () => {
|
|
36
31
|
it("should fetch servers from deployed backend", async () => {
|
|
37
|
-
const
|
|
32
|
+
const sm = await getServerManagers();
|
|
38
33
|
const serverBriefs = sm.getServerBriefs();
|
|
39
34
|
expect(serverBriefs.length).greaterThan(0);
|
|
40
35
|
}).timeout(10000);
|
|
41
36
|
|
|
42
37
|
it("should fetch tools for a server", async () => {
|
|
43
|
-
const
|
|
38
|
+
const sm = await getServerManagers();
|
|
44
39
|
const tools = await sm.getServerTools("sudomcp_simplecalc");
|
|
45
40
|
expect(tools.length).greaterThan(0);
|
|
46
41
|
}).timeout(10000);
|
|
47
42
|
|
|
48
43
|
it("should add a new MCP server", async () => {
|
|
49
|
-
const
|
|
44
|
+
const sm = await getServerManagers();
|
|
50
45
|
await sm.addMcpServer("sudomcp_simplecalc", true);
|
|
51
46
|
const serverBriefs = sm.getServerBriefs();
|
|
52
47
|
expect(
|
package/src/tool/chatMain.ts
CHANGED
|
@@ -17,7 +17,11 @@ import { getLogger } from "@xalia/xmcp/sdk";
|
|
|
17
17
|
import { IConversation } from "../agent/agent";
|
|
18
18
|
import { ChatClient } from "../chat/client";
|
|
19
19
|
import { runServer } from "../chat/server";
|
|
20
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
ClientUserMessage,
|
|
22
|
+
ServerToClient,
|
|
23
|
+
decodeAssistantMessageParam,
|
|
24
|
+
} from "../chat/messages";
|
|
21
25
|
|
|
22
26
|
import { IPrompt, Prompt, ScriptPrompt } from "./prompt";
|
|
23
27
|
import * as options from "./options";
|
|
@@ -177,7 +181,12 @@ function getCLIOnMessage(): (msg: ServerToClient) => void {
|
|
|
177
181
|
stdout.write(`[${msg.from}]: ${msg.message}\n`);
|
|
178
182
|
break;
|
|
179
183
|
case "agent_msg":
|
|
180
|
-
|
|
184
|
+
{
|
|
185
|
+
const text = decodeAssistantMessageParam(msg.message);
|
|
186
|
+
if (text) {
|
|
187
|
+
stdout.write(`[AGENT]: ${text}\n`);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
181
190
|
break;
|
|
182
191
|
case "agent_msg_chunk":
|
|
183
192
|
if (startMsg) {
|
|
@@ -64,12 +64,7 @@ export class CommandPrompt {
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
try {
|
|
67
|
-
await this.runCommand(
|
|
68
|
-
agent,
|
|
69
|
-
sudoMcpServerManager.getMcpServerManager(),
|
|
70
|
-
sudoMcpServerManager,
|
|
71
|
-
cmds
|
|
72
|
-
);
|
|
67
|
+
await this.runCommand(agent, sudoMcpServerManager, cmds);
|
|
73
68
|
} catch (e) {
|
|
74
69
|
console.log(`ERROR: ${e}`);
|
|
75
70
|
}
|
|
@@ -78,13 +73,12 @@ export class CommandPrompt {
|
|
|
78
73
|
|
|
79
74
|
async runCommand(
|
|
80
75
|
agent: IConversation,
|
|
81
|
-
mcpServerManager: IMcpServerManager,
|
|
82
76
|
sudoMcpServerManager: ISkillManager,
|
|
83
77
|
cmds: string[]
|
|
84
78
|
) {
|
|
85
79
|
switch (cmds[0]) {
|
|
86
80
|
case "lt":
|
|
87
|
-
this.listTools(
|
|
81
|
+
this.listTools(sudoMcpServerManager);
|
|
88
82
|
break;
|
|
89
83
|
case "ls":
|
|
90
84
|
this.listServers(sudoMcpServerManager);
|
|
@@ -93,22 +87,22 @@ export class CommandPrompt {
|
|
|
93
87
|
await this.addServer(sudoMcpServerManager, cmds[1]);
|
|
94
88
|
break;
|
|
95
89
|
case "rs":
|
|
96
|
-
await
|
|
90
|
+
await sudoMcpServerManager.removeMcpServer(cmds[1]);
|
|
97
91
|
break;
|
|
98
92
|
case "e":
|
|
99
|
-
|
|
93
|
+
sudoMcpServerManager.enableTool(cmds[1], cmds[2]);
|
|
100
94
|
console.log(`Enabled tool ${cmds[2]} for server ${cmds[1]}`);
|
|
101
95
|
break;
|
|
102
96
|
case "d":
|
|
103
|
-
|
|
97
|
+
sudoMcpServerManager.disableTool(cmds[1], cmds[2]);
|
|
104
98
|
console.log(`Disabled tool ${cmds[2]} for server ${cmds[1]}`);
|
|
105
99
|
break;
|
|
106
100
|
case "ea":
|
|
107
|
-
|
|
101
|
+
sudoMcpServerManager.enableAllTools(cmds[1]);
|
|
108
102
|
console.log(`Enabled all tools for server ${cmds[1]}`);
|
|
109
103
|
break;
|
|
110
104
|
case "da":
|
|
111
|
-
|
|
105
|
+
sudoMcpServerManager.disableAllTools(cmds[1]);
|
|
112
106
|
console.log(`Disabled all tools for server ${cmds[1]}`);
|
|
113
107
|
break;
|
|
114
108
|
case "wc":
|
|
@@ -183,10 +177,9 @@ Have you installed server ${serverName} using the SudoMCP CLI tool?`;
|
|
|
183
177
|
throw e;
|
|
184
178
|
}
|
|
185
179
|
}
|
|
186
|
-
const msm = sudoMcpServerManager.getMcpServerManager();
|
|
187
180
|
console.log(`Added server: ${serverName} (enabled all tools).`);
|
|
188
181
|
console.log(`Current tool list:`);
|
|
189
|
-
this.listTools(
|
|
182
|
+
this.listTools(sudoMcpServerManager);
|
|
190
183
|
}
|
|
191
184
|
|
|
192
185
|
writeConversation(agent: IConversation, fileName: string) {
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.FrontendChatClient = void 0;
|
|
4
|
-
class FrontendChatClient {
|
|
5
|
-
constructor(ws, onMessageCB, onConnectionClosedCB) {
|
|
6
|
-
this.ws = ws;
|
|
7
|
-
this.onMessageCB = onMessageCB;
|
|
8
|
-
this.onConnectionClosedCB = onConnectionClosedCB;
|
|
9
|
-
this.closed = false;
|
|
10
|
-
}
|
|
11
|
-
static async initWithParams(host, port, token, params, onMessageCB, onConnectionClosedCB) {
|
|
12
|
-
return new Promise((resolve, reject) => {
|
|
13
|
-
const urlParams = new URLSearchParams(params);
|
|
14
|
-
const url = `ws://${host}:${port}?${urlParams}`;
|
|
15
|
-
const ws = new WebSocket(url, [token]);
|
|
16
|
-
console.log("created ws");
|
|
17
|
-
const client = new FrontendChatClient(ws, onMessageCB, onConnectionClosedCB);
|
|
18
|
-
ws.onopen = async () => {
|
|
19
|
-
console.log("opened");
|
|
20
|
-
ws.onmessage = (ev) => {
|
|
21
|
-
try {
|
|
22
|
-
const msgData = ev.data;
|
|
23
|
-
if (typeof msgData !== "string") {
|
|
24
|
-
throw `expected "string" data, got ${typeof msgData}`;
|
|
25
|
-
}
|
|
26
|
-
console.debug(`[client.onmessage]: ${msgData}`);
|
|
27
|
-
const msg = JSON.parse(msgData);
|
|
28
|
-
client.onMessageCB(msg);
|
|
29
|
-
}
|
|
30
|
-
catch (e) {
|
|
31
|
-
client.close();
|
|
32
|
-
throw e;
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
resolve(client);
|
|
36
|
-
};
|
|
37
|
-
ws.onclose = (event) => {
|
|
38
|
-
console.log("closed");
|
|
39
|
-
console.log(`[client] WebSocket connection closed: ${JSON.stringify(event)}`);
|
|
40
|
-
client.closed = true;
|
|
41
|
-
onConnectionClosedCB();
|
|
42
|
-
};
|
|
43
|
-
ws.onerror = (error) => {
|
|
44
|
-
console.error("[client] WebSocket error:", error);
|
|
45
|
-
reject(error);
|
|
46
|
-
client.closed = true;
|
|
47
|
-
onConnectionClosedCB();
|
|
48
|
-
};
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
static async init(host, port, token, onMessageCB, onConnectionClosedCB, sessionId = "untitled", agentProfileId = undefined) {
|
|
52
|
-
const params = { session_id: sessionId };
|
|
53
|
-
if (agentProfileId) {
|
|
54
|
-
params["agent_profile_id"] = agentProfileId;
|
|
55
|
-
}
|
|
56
|
-
return FrontendChatClient.initWithParams(host, port, token, params, onMessageCB, onConnectionClosedCB);
|
|
57
|
-
}
|
|
58
|
-
sendMessage(message) {
|
|
59
|
-
if (this.closed) {
|
|
60
|
-
throw new Error("Cannot send message on closed connection");
|
|
61
|
-
}
|
|
62
|
-
const data = JSON.stringify(message);
|
|
63
|
-
this.ws.send(data);
|
|
64
|
-
}
|
|
65
|
-
close() {
|
|
66
|
-
this.closed = true;
|
|
67
|
-
this.onConnectionClosedCB();
|
|
68
|
-
this.ws.close();
|
|
69
|
-
}
|
|
70
|
-
isClosed() {
|
|
71
|
-
return this.closed;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
exports.FrontendChatClient = FrontendChatClient;
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import { ServerToClient, ClientToServer } from "./messages";
|
|
2
|
-
|
|
3
|
-
type OnMessageCallback = (msg: ServerToClient) => void;
|
|
4
|
-
type OnConnectionClosedCallback = () => void;
|
|
5
|
-
|
|
6
|
-
export class FrontendChatClient {
|
|
7
|
-
private ws: WebSocket;
|
|
8
|
-
private onMessageCB: OnMessageCallback;
|
|
9
|
-
private onConnectionClosedCB: OnConnectionClosedCallback;
|
|
10
|
-
private closed: boolean;
|
|
11
|
-
|
|
12
|
-
private constructor(
|
|
13
|
-
ws: WebSocket,
|
|
14
|
-
onMessageCB: OnMessageCallback,
|
|
15
|
-
onConnectionClosedCB: OnConnectionClosedCallback
|
|
16
|
-
) {
|
|
17
|
-
this.ws = ws;
|
|
18
|
-
this.onMessageCB = onMessageCB;
|
|
19
|
-
this.onConnectionClosedCB = onConnectionClosedCB;
|
|
20
|
-
this.closed = false;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
static async initWithParams(
|
|
24
|
-
host: string,
|
|
25
|
-
port: number,
|
|
26
|
-
token: string,
|
|
27
|
-
params: Record<string, string>,
|
|
28
|
-
onMessageCB: OnMessageCallback,
|
|
29
|
-
onConnectionClosedCB: OnConnectionClosedCallback
|
|
30
|
-
): Promise<FrontendChatClient> {
|
|
31
|
-
return new Promise((resolve, reject) => {
|
|
32
|
-
const urlParams = new URLSearchParams(params);
|
|
33
|
-
const url = `ws://${host}:${port}?${urlParams}`;
|
|
34
|
-
|
|
35
|
-
const ws = new WebSocket(url, [token]);
|
|
36
|
-
console.log("created ws");
|
|
37
|
-
|
|
38
|
-
const client = new FrontendChatClient(
|
|
39
|
-
ws,
|
|
40
|
-
onMessageCB,
|
|
41
|
-
onConnectionClosedCB
|
|
42
|
-
);
|
|
43
|
-
|
|
44
|
-
ws.onopen = async () => {
|
|
45
|
-
console.log("opened");
|
|
46
|
-
|
|
47
|
-
ws.onmessage = (ev: MessageEvent) => {
|
|
48
|
-
try {
|
|
49
|
-
const msgData = ev.data;
|
|
50
|
-
if (typeof msgData !== "string") {
|
|
51
|
-
throw `expected "string" data, got ${typeof msgData}`;
|
|
52
|
-
}
|
|
53
|
-
console.debug(`[client.onmessage]: ${msgData}`);
|
|
54
|
-
const msg: ServerToClient = JSON.parse(msgData);
|
|
55
|
-
client.onMessageCB(msg);
|
|
56
|
-
} catch (e) {
|
|
57
|
-
client.close();
|
|
58
|
-
throw e;
|
|
59
|
-
}
|
|
60
|
-
};
|
|
61
|
-
resolve(client);
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
ws.onclose = (event) => {
|
|
65
|
-
console.log("closed");
|
|
66
|
-
console.log(
|
|
67
|
-
`[client] WebSocket connection closed: ${JSON.stringify(event)}`
|
|
68
|
-
);
|
|
69
|
-
client.closed = true;
|
|
70
|
-
onConnectionClosedCB();
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
ws.onerror = (error) => {
|
|
74
|
-
console.error("[client] WebSocket error:", error);
|
|
75
|
-
reject(error);
|
|
76
|
-
|
|
77
|
-
client.closed = true;
|
|
78
|
-
onConnectionClosedCB();
|
|
79
|
-
};
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
public static async init(
|
|
84
|
-
host: string,
|
|
85
|
-
port: number,
|
|
86
|
-
token: string,
|
|
87
|
-
onMessageCB: OnMessageCallback,
|
|
88
|
-
onConnectionClosedCB: OnConnectionClosedCallback,
|
|
89
|
-
sessionId: string = "untitled",
|
|
90
|
-
agentProfileId: string | undefined = undefined
|
|
91
|
-
): Promise<FrontendChatClient> {
|
|
92
|
-
const params: Record<string, string> = { session_id: sessionId };
|
|
93
|
-
if (agentProfileId) {
|
|
94
|
-
params["agent_profile_id"] = agentProfileId;
|
|
95
|
-
}
|
|
96
|
-
return FrontendChatClient.initWithParams(
|
|
97
|
-
host,
|
|
98
|
-
port,
|
|
99
|
-
token,
|
|
100
|
-
params,
|
|
101
|
-
onMessageCB,
|
|
102
|
-
onConnectionClosedCB
|
|
103
|
-
);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
public sendMessage(message: ClientToServer): void {
|
|
107
|
-
if (this.closed) {
|
|
108
|
-
throw new Error("Cannot send message on closed connection");
|
|
109
|
-
}
|
|
110
|
-
const data = JSON.stringify(message);
|
|
111
|
-
this.ws.send(data);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
public close(): void {
|
|
115
|
-
this.closed = true;
|
|
116
|
-
this.onConnectionClosedCB();
|
|
117
|
-
this.ws.close();
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
public isClosed(): boolean {
|
|
121
|
-
return this.closed;
|
|
122
|
-
}
|
|
123
|
-
}
|