@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.
Files changed (35) hide show
  1. package/dist/agent/src/agent/agent.js +3 -0
  2. package/dist/agent/src/agent/agentUtils.js +6 -12
  3. package/dist/agent/src/agent/mcpServerManager.js +1 -1
  4. package/dist/agent/src/agent/openAILLMStreaming.js +14 -7
  5. package/dist/agent/src/agent/sudoMcpServerManager.js +13 -13
  6. package/dist/agent/src/chat/client.js +24 -63
  7. package/dist/agent/src/chat/conversationManager.js +122 -12
  8. package/dist/agent/src/chat/db.js +9 -0
  9. package/dist/agent/src/chat/messages.js +27 -0
  10. package/dist/agent/src/chat/websocket.js +14 -0
  11. package/dist/agent/src/test/db.test.js +16 -0
  12. package/dist/agent/src/test/mcpServerManager.test.js +2 -2
  13. package/dist/agent/src/test/openaiStreaming.test.js +56 -28
  14. package/dist/agent/src/test/sudoMcpServerManager.test.js +10 -13
  15. package/dist/agent/src/tool/chatMain.js +7 -1
  16. package/dist/agent/src/tool/commandPrompt.js +9 -10
  17. package/package.json +1 -1
  18. package/src/agent/agent.ts +14 -4
  19. package/src/agent/agentUtils.ts +17 -23
  20. package/src/agent/mcpServerManager.ts +3 -1
  21. package/src/agent/openAILLMStreaming.ts +14 -7
  22. package/src/agent/sudoMcpServerManager.ts +17 -18
  23. package/src/chat/client.ts +35 -45
  24. package/src/chat/conversationManager.ts +147 -12
  25. package/src/chat/db.ts +14 -0
  26. package/src/chat/messages.ts +31 -0
  27. package/src/chat/websocket.ts +14 -0
  28. package/src/test/db.test.ts +22 -1
  29. package/src/test/mcpServerManager.test.ts +2 -2
  30. package/src/test/openaiStreaming.test.ts +64 -30
  31. package/src/test/sudoMcpServerManager.test.ts +11 -16
  32. package/src/tool/chatMain.ts +11 -2
  33. package/src/tool/commandPrompt.ts +8 -15
  34. package/dist/agent/src/chat/frontendClient.js +0 -74
  35. 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 managers: [McpServerManager, SkillManager] | undefined = undefined;
7
+ let manager: SkillManager | undefined = undefined;
9
8
 
10
- async function getServerManagers(): Promise<[McpServerManager, SkillManager]> {
11
- if (!managers) {
12
- const tm = new McpServerManager();
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 managers;
20
+ return manager;
26
21
  }
27
22
 
28
23
  async function shutdownAll() {
29
- if (managers) {
30
- await managers[0].shutdown();
24
+ if (manager) {
25
+ await manager.shutdown();
31
26
  }
32
- managers = undefined;
27
+ manager = undefined;
33
28
  }
34
29
 
35
30
  describe("SudoMcpServerManager", async () => {
36
31
  it("should fetch servers from deployed backend", async () => {
37
- const [, sm] = await getServerManagers();
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 [, sm] = await getServerManagers();
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 [, sm] = await getServerManagers();
44
+ const sm = await getServerManagers();
50
45
  await sm.addMcpServer("sudomcp_simplecalc", true);
51
46
  const serverBriefs = sm.getServerBriefs();
52
47
  expect(
@@ -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 { ClientUserMessage, ServerToClient } from "../chat/messages";
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
- stdout.write(`[AGENT]: ${msg.message}\n`);
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(mcpServerManager);
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 mcpServerManager.removeMcpServer(cmds[1]);
90
+ await sudoMcpServerManager.removeMcpServer(cmds[1]);
97
91
  break;
98
92
  case "e":
99
- mcpServerManager.enableTool(cmds[1], cmds[2]);
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
- mcpServerManager.disableTool(cmds[1], cmds[2]);
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
- mcpServerManager.enableAllTools(cmds[1]);
101
+ sudoMcpServerManager.enableAllTools(cmds[1]);
108
102
  console.log(`Enabled all tools for server ${cmds[1]}`);
109
103
  break;
110
104
  case "da":
111
- mcpServerManager.disableAllTools(cmds[1]);
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(msm);
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
- }