@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
|
@@ -67,6 +67,53 @@ const TEST_TRAILING_USAGE = [
|
|
|
67
67
|
},
|
|
68
68
|
},
|
|
69
69
|
];
|
|
70
|
+
const AGGREGATED_MESSAGE = {
|
|
71
|
+
id: "gen-1753923406-nsIKHyFRoJqkUntBnQTw",
|
|
72
|
+
choices: [
|
|
73
|
+
{
|
|
74
|
+
message: {
|
|
75
|
+
content: "test",
|
|
76
|
+
role: "assistant",
|
|
77
|
+
refusal: null,
|
|
78
|
+
tool_calls: undefined,
|
|
79
|
+
},
|
|
80
|
+
finish_reason: "stop",
|
|
81
|
+
index: 0,
|
|
82
|
+
logprobs: null,
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
created: 1753923406,
|
|
86
|
+
model: "openai/gpt-4o",
|
|
87
|
+
object: "chat.completion",
|
|
88
|
+
service_tier: undefined,
|
|
89
|
+
system_fingerprint: "fp_a288987b44",
|
|
90
|
+
usage: {
|
|
91
|
+
completion_tokens: 50,
|
|
92
|
+
prompt_tokens: 271,
|
|
93
|
+
total_tokens: 321,
|
|
94
|
+
completion_tokens_details: { reasoning_tokens: 0 },
|
|
95
|
+
prompt_tokens_details: { cached_tokens: 0 },
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
const TEST_TRAILING_USAGE_WITH_3_CHUNKS = [
|
|
99
|
+
{
|
|
100
|
+
...TEST_TRAILING_USAGE[0],
|
|
101
|
+
choices: [
|
|
102
|
+
{
|
|
103
|
+
delta: { content: "test", role: "assistant" },
|
|
104
|
+
finish_reason: null,
|
|
105
|
+
index: 0,
|
|
106
|
+
logprobs: null,
|
|
107
|
+
},
|
|
108
|
+
],
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
...TEST_TRAILING_USAGE[1],
|
|
112
|
+
choices: [{ ...TEST_TRAILING_USAGE[1].choices[0], finish_reason: "stop" }],
|
|
113
|
+
usage: undefined,
|
|
114
|
+
},
|
|
115
|
+
{ ...TEST_TRAILING_USAGE[1], choices: [] },
|
|
116
|
+
];
|
|
70
117
|
describe("OpenAI Streaming", () => {
|
|
71
118
|
it("should support standard termination", async function () {
|
|
72
119
|
const chunks = TEST_STANDARD;
|
|
@@ -101,33 +148,14 @@ describe("OpenAI Streaming", () => {
|
|
|
101
148
|
(0, chai_1.expect)(chunks.length).eql(2);
|
|
102
149
|
const { initMessage } = (0, openAILLMStreaming_1.initializeCompletion)(chunks[0]);
|
|
103
150
|
(0, openAILLMStreaming_1.updateCompletion)(initMessage, chunks[1]);
|
|
104
|
-
(0, chai_1.expect)(initMessage).eql(
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
},
|
|
114
|
-
finish_reason: "stop",
|
|
115
|
-
index: 0,
|
|
116
|
-
logprobs: null,
|
|
117
|
-
},
|
|
118
|
-
],
|
|
119
|
-
created: 1753923406,
|
|
120
|
-
model: "openai/gpt-4o",
|
|
121
|
-
object: "chat.completion",
|
|
122
|
-
service_tier: undefined,
|
|
123
|
-
system_fingerprint: "fp_a288987b44",
|
|
124
|
-
usage: {
|
|
125
|
-
completion_tokens: 50,
|
|
126
|
-
prompt_tokens: 271,
|
|
127
|
-
total_tokens: 321,
|
|
128
|
-
completion_tokens_details: { reasoning_tokens: 0 },
|
|
129
|
-
prompt_tokens_details: { cached_tokens: 0 },
|
|
130
|
-
},
|
|
131
|
-
});
|
|
151
|
+
(0, chai_1.expect)(initMessage).eql(AGGREGATED_MESSAGE);
|
|
152
|
+
});
|
|
153
|
+
it("should support trailing usage with 3 chunks", async function () {
|
|
154
|
+
const chunks = TEST_TRAILING_USAGE_WITH_3_CHUNKS;
|
|
155
|
+
(0, chai_1.expect)(chunks.length).eql(3);
|
|
156
|
+
const { initMessage } = (0, openAILLMStreaming_1.initializeCompletion)(chunks[0]);
|
|
157
|
+
(0, openAILLMStreaming_1.updateCompletion)(initMessage, chunks[1]);
|
|
158
|
+
(0, openAILLMStreaming_1.updateCompletion)(initMessage, chunks[2]);
|
|
159
|
+
(0, chai_1.expect)(initMessage).eql(AGGREGATED_MESSAGE);
|
|
132
160
|
});
|
|
133
161
|
});
|
|
@@ -6,38 +6,35 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.prettyPrintTool = prettyPrintTool;
|
|
7
7
|
const chai_1 = require("chai");
|
|
8
8
|
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
-
const mcpServerManager_1 = require("../agent/mcpServerManager");
|
|
10
9
|
const sudoMcpServerManager_1 = require("../agent/sudoMcpServerManager");
|
|
11
|
-
let
|
|
10
|
+
let manager = undefined;
|
|
12
11
|
async function getServerManagers() {
|
|
13
|
-
if (!
|
|
14
|
-
|
|
15
|
-
const sm = await sudoMcpServerManager_1.SkillManager.initialize(tm, (_url) => {
|
|
12
|
+
if (!manager) {
|
|
13
|
+
manager = await sudoMcpServerManager_1.SkillManager.initialize((_url) => {
|
|
16
14
|
throw "unexpected call to openUrl";
|
|
17
15
|
}, sudoMcpServerManager_1.LOCAL_SERVER_URL, "dummy_key");
|
|
18
|
-
managers = [tm, sm];
|
|
19
16
|
}
|
|
20
|
-
return
|
|
17
|
+
return manager;
|
|
21
18
|
}
|
|
22
19
|
async function shutdownAll() {
|
|
23
|
-
if (
|
|
24
|
-
await
|
|
20
|
+
if (manager) {
|
|
21
|
+
await manager.shutdown();
|
|
25
22
|
}
|
|
26
|
-
|
|
23
|
+
manager = undefined;
|
|
27
24
|
}
|
|
28
25
|
describe("SudoMcpServerManager", async () => {
|
|
29
26
|
it("should fetch servers from deployed backend", async () => {
|
|
30
|
-
const
|
|
27
|
+
const sm = await getServerManagers();
|
|
31
28
|
const serverBriefs = sm.getServerBriefs();
|
|
32
29
|
(0, chai_1.expect)(serverBriefs.length).greaterThan(0);
|
|
33
30
|
}).timeout(10000);
|
|
34
31
|
it("should fetch tools for a server", async () => {
|
|
35
|
-
const
|
|
32
|
+
const sm = await getServerManagers();
|
|
36
33
|
const tools = await sm.getServerTools("sudomcp_simplecalc");
|
|
37
34
|
(0, chai_1.expect)(tools.length).greaterThan(0);
|
|
38
35
|
}).timeout(10000);
|
|
39
36
|
it("should add a new MCP server", async () => {
|
|
40
|
-
const
|
|
37
|
+
const sm = await getServerManagers();
|
|
41
38
|
await sm.addMcpServer("sudomcp_simplecalc", true);
|
|
42
39
|
const serverBriefs = sm.getServerBriefs();
|
|
43
40
|
(0, chai_1.expect)(serverBriefs.some((brief) => brief.name === "sudomcp_simplecalc")).eql(true);
|
|
@@ -42,6 +42,7 @@ const tool_1 = require("@xalia/xmcp/tool");
|
|
|
42
42
|
const sdk_1 = require("@xalia/xmcp/sdk");
|
|
43
43
|
const client_1 = require("../chat/client");
|
|
44
44
|
const server_1 = require("../chat/server");
|
|
45
|
+
const messages_1 = require("../chat/messages");
|
|
45
46
|
const prompt_1 = require("./prompt");
|
|
46
47
|
const options = __importStar(require("./options"));
|
|
47
48
|
const commandPrompt_1 = require("./commandPrompt");
|
|
@@ -162,7 +163,12 @@ function getCLIOnMessage() {
|
|
|
162
163
|
process_1.stdout.write(`[${msg.from}]: ${msg.message}\n`);
|
|
163
164
|
break;
|
|
164
165
|
case "agent_msg":
|
|
165
|
-
|
|
166
|
+
{
|
|
167
|
+
const text = (0, messages_1.decodeAssistantMessageParam)(msg.message);
|
|
168
|
+
if (text) {
|
|
169
|
+
process_1.stdout.write(`[AGENT]: ${text}\n`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
166
172
|
break;
|
|
167
173
|
case "agent_msg_chunk":
|
|
168
174
|
if (startMsg) {
|
|
@@ -84,17 +84,17 @@ class CommandPrompt {
|
|
|
84
84
|
break;
|
|
85
85
|
}
|
|
86
86
|
try {
|
|
87
|
-
await this.runCommand(agent, sudoMcpServerManager
|
|
87
|
+
await this.runCommand(agent, sudoMcpServerManager, cmds);
|
|
88
88
|
}
|
|
89
89
|
catch (e) {
|
|
90
90
|
console.log(`ERROR: ${e}`);
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
|
-
async runCommand(agent,
|
|
94
|
+
async runCommand(agent, sudoMcpServerManager, cmds) {
|
|
95
95
|
switch (cmds[0]) {
|
|
96
96
|
case "lt":
|
|
97
|
-
this.listTools(
|
|
97
|
+
this.listTools(sudoMcpServerManager);
|
|
98
98
|
break;
|
|
99
99
|
case "ls":
|
|
100
100
|
this.listServers(sudoMcpServerManager);
|
|
@@ -103,22 +103,22 @@ class CommandPrompt {
|
|
|
103
103
|
await this.addServer(sudoMcpServerManager, cmds[1]);
|
|
104
104
|
break;
|
|
105
105
|
case "rs":
|
|
106
|
-
await
|
|
106
|
+
await sudoMcpServerManager.removeMcpServer(cmds[1]);
|
|
107
107
|
break;
|
|
108
108
|
case "e":
|
|
109
|
-
|
|
109
|
+
sudoMcpServerManager.enableTool(cmds[1], cmds[2]);
|
|
110
110
|
console.log(`Enabled tool ${cmds[2]} for server ${cmds[1]}`);
|
|
111
111
|
break;
|
|
112
112
|
case "d":
|
|
113
|
-
|
|
113
|
+
sudoMcpServerManager.disableTool(cmds[1], cmds[2]);
|
|
114
114
|
console.log(`Disabled tool ${cmds[2]} for server ${cmds[1]}`);
|
|
115
115
|
break;
|
|
116
116
|
case "ea":
|
|
117
|
-
|
|
117
|
+
sudoMcpServerManager.enableAllTools(cmds[1]);
|
|
118
118
|
console.log(`Enabled all tools for server ${cmds[1]}`);
|
|
119
119
|
break;
|
|
120
120
|
case "da":
|
|
121
|
-
|
|
121
|
+
sudoMcpServerManager.disableAllTools(cmds[1]);
|
|
122
122
|
console.log(`Disabled all tools for server ${cmds[1]}`);
|
|
123
123
|
break;
|
|
124
124
|
case "wc":
|
|
@@ -189,10 +189,9 @@ Have you installed server ${serverName} using the SudoMCP CLI tool?`;
|
|
|
189
189
|
throw e;
|
|
190
190
|
}
|
|
191
191
|
}
|
|
192
|
-
const msm = sudoMcpServerManager.getMcpServerManager();
|
|
193
192
|
console.log(`Added server: ${serverName} (enabled all tools).`);
|
|
194
193
|
console.log(`Current tool list:`);
|
|
195
|
-
this.listTools(
|
|
194
|
+
this.listTools(sudoMcpServerManager);
|
|
196
195
|
}
|
|
197
196
|
writeConversation(agent, fileName) {
|
|
198
197
|
const conversation = agent.getConversation();
|
package/package.json
CHANGED
package/src/agent/agent.ts
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import * as dotenv from "dotenv";
|
|
2
2
|
import { OpenAI } from "openai";
|
|
3
3
|
import { McpServerManager } from "./mcpServerManager";
|
|
4
|
-
import {
|
|
5
|
-
ChatCompletionContentPart,
|
|
6
|
-
ChatCompletionUserMessageParam,
|
|
7
|
-
} from "openai/resources.mjs";
|
|
4
|
+
import { ChatCompletionContentPart } from "openai/resources.mjs";
|
|
8
5
|
import { strict as assert } from "assert";
|
|
9
6
|
import { ILLM } from "./llm";
|
|
10
7
|
import { AgentProfile, getLogger } from "@xalia/xmcp/sdk";
|
|
@@ -19,6 +16,12 @@ export type ChatCompletionMessageParam = OpenAI.ChatCompletionMessageParam;
|
|
|
19
16
|
export type ChatCompletionMessageToolCall =
|
|
20
17
|
OpenAI.ChatCompletionMessageToolCall;
|
|
21
18
|
|
|
19
|
+
export type ChatCompletionAssistantMessageParam =
|
|
20
|
+
OpenAI.ChatCompletionAssistantMessageParam;
|
|
21
|
+
|
|
22
|
+
export type ChatCompletionUserMessageParam =
|
|
23
|
+
OpenAI.ChatCompletionUserMessageParam;
|
|
24
|
+
|
|
22
25
|
// Role: If content, give it to UI
|
|
23
26
|
export type OnMessageCB = {
|
|
24
27
|
(msg: string, msgEnd: boolean): Promise<void>;
|
|
@@ -41,6 +44,8 @@ export interface IConversation {
|
|
|
41
44
|
setSystemPrompt(systemPrompt: string): void;
|
|
42
45
|
getModel(): string;
|
|
43
46
|
setModel(model: string): void;
|
|
47
|
+
|
|
48
|
+
shutdown(): Promise<void>;
|
|
44
49
|
}
|
|
45
50
|
|
|
46
51
|
dotenv.config();
|
|
@@ -132,7 +137,12 @@ export class Agent implements IConversation {
|
|
|
132
137
|
if (!userMessage) {
|
|
133
138
|
return undefined;
|
|
134
139
|
}
|
|
140
|
+
return this.userMessageRaw(userMessage);
|
|
141
|
+
}
|
|
135
142
|
|
|
143
|
+
public async userMessageRaw(
|
|
144
|
+
userMessage: ChatCompletionUserMessageParam
|
|
145
|
+
): Promise<ChatCompletionMessageParam | undefined> {
|
|
136
146
|
this.messages.push(userMessage);
|
|
137
147
|
let completion = await this.chatCompletion();
|
|
138
148
|
|
package/src/agent/agentUtils.ts
CHANGED
|
@@ -34,7 +34,7 @@ async function createAgent(
|
|
|
34
34
|
platform: IPlatform,
|
|
35
35
|
openaiApiKey: string | undefined,
|
|
36
36
|
stream: boolean = false,
|
|
37
|
-
mcpServerManager
|
|
37
|
+
mcpServerManager: McpServerManager
|
|
38
38
|
): Promise<Agent> {
|
|
39
39
|
let llm: ILLM | undefined;
|
|
40
40
|
|
|
@@ -90,26 +90,9 @@ export async function createAgentWithSkills(
|
|
|
90
90
|
conversation: OpenAI.ChatCompletionMessageParam[] | undefined,
|
|
91
91
|
stream: boolean = false
|
|
92
92
|
): Promise<[Agent, SkillManager]> {
|
|
93
|
-
// Create agent
|
|
94
|
-
logger.debug("[createAgentAndSudoMcpServerManager] creating agent ...");
|
|
95
|
-
const agent = await createAgent(
|
|
96
|
-
llmUrl,
|
|
97
|
-
agentProfile.model,
|
|
98
|
-
agentProfile.system_prompt,
|
|
99
|
-
onMessage,
|
|
100
|
-
onToolCall,
|
|
101
|
-
platform,
|
|
102
|
-
llmApiKey,
|
|
103
|
-
stream
|
|
104
|
-
);
|
|
105
|
-
if (conversation) {
|
|
106
|
-
agent.setConversation(conversation);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
93
|
// Init SudoMcpServerManager
|
|
110
94
|
logger.debug("[createAgentWithSkills] creating SudoMcpServerManager.");
|
|
111
95
|
const sudoMcpServerManager = await SkillManager.initialize(
|
|
112
|
-
agent.getMcpServerManager(),
|
|
113
96
|
platform.openUrl,
|
|
114
97
|
sudomcpConfig.backend_url,
|
|
115
98
|
sudomcpConfig.api_key,
|
|
@@ -121,7 +104,19 @@ export async function createAgentWithSkills(
|
|
|
121
104
|
);
|
|
122
105
|
await sudoMcpServerManager.restoreMcpSettings(agentProfile.mcp_settings);
|
|
123
106
|
|
|
124
|
-
|
|
107
|
+
// Create agent using the McpServerManager just created
|
|
108
|
+
const agent = await createAgentFromSkillManager(
|
|
109
|
+
llmUrl,
|
|
110
|
+
agentProfile,
|
|
111
|
+
onMessage,
|
|
112
|
+
onToolCall,
|
|
113
|
+
platform,
|
|
114
|
+
llmApiKey,
|
|
115
|
+
sudoMcpServerManager,
|
|
116
|
+
conversation,
|
|
117
|
+
stream
|
|
118
|
+
);
|
|
119
|
+
|
|
125
120
|
return [agent, sudoMcpServerManager];
|
|
126
121
|
}
|
|
127
122
|
|
|
@@ -137,8 +132,7 @@ export async function createAgentFromSkillManager(
|
|
|
137
132
|
stream: boolean = false
|
|
138
133
|
): Promise<Agent> {
|
|
139
134
|
// Create agent
|
|
140
|
-
logger.debug("[
|
|
141
|
-
const mcpServerManager = skillManager.getMcpServerManager();
|
|
135
|
+
logger.debug("[createAgentFromSkillManager] creating agent ...");
|
|
142
136
|
const agent = await createAgent(
|
|
143
137
|
llmUrl,
|
|
144
138
|
agentProfile.model,
|
|
@@ -148,13 +142,13 @@ export async function createAgentFromSkillManager(
|
|
|
148
142
|
platform,
|
|
149
143
|
llmApiKey,
|
|
150
144
|
stream,
|
|
151
|
-
|
|
145
|
+
skillManager
|
|
152
146
|
);
|
|
153
147
|
if (conversation) {
|
|
154
148
|
agent.setConversation(conversation);
|
|
155
149
|
}
|
|
156
150
|
|
|
157
|
-
logger.debug("[
|
|
151
|
+
logger.debug("[createAgentFromSkillManager] done");
|
|
158
152
|
return agent;
|
|
159
153
|
}
|
|
160
154
|
|
|
@@ -151,6 +151,8 @@ export interface IMcpServerManager {
|
|
|
151
151
|
disableAllTools(mcpServerName: string): void;
|
|
152
152
|
enableTool(mcpServerName: string, toolName: string): void;
|
|
153
153
|
disableTool(mcpServerName: string, toolName: string): void;
|
|
154
|
+
|
|
155
|
+
shutdown(): Promise<void>;
|
|
154
156
|
}
|
|
155
157
|
|
|
156
158
|
/**
|
|
@@ -186,7 +188,7 @@ export class McpServerManager implements IMcpServerManager {
|
|
|
186
188
|
return this.getMcpServerInternal(mcpServerName);
|
|
187
189
|
}
|
|
188
190
|
|
|
189
|
-
public async
|
|
191
|
+
public async addMcpServerWithSSEUrl(
|
|
190
192
|
mcpServerName: string,
|
|
191
193
|
url: string,
|
|
192
194
|
apiKey?: string,
|
|
@@ -316,9 +316,10 @@ function initializeCompletionChoices(
|
|
|
316
316
|
chunkChoices: OpenAI.Chat.Completions.ChatCompletionChunk.Choice[]
|
|
317
317
|
): { choices: OpenAI.Chat.Completions.ChatCompletion.Choice[]; done: boolean } {
|
|
318
318
|
// Technically, one choice could be done and the other still have some
|
|
319
|
-
// content to stream. We keep it simple for now and
|
|
320
|
-
//
|
|
321
|
-
// done.
|
|
319
|
+
// content to stream. We keep it simple for now and allow zero or one
|
|
320
|
+
// choice per chunk, which allows us to mark everything as done if any
|
|
321
|
+
// choice we hit is done. Zero choices can occur in usage-only chunks at
|
|
322
|
+
// the end of the stream.
|
|
322
323
|
assert(chunkChoices.length < 2);
|
|
323
324
|
|
|
324
325
|
let msgDone = false;
|
|
@@ -339,10 +340,11 @@ function updateCompletionChoices(
|
|
|
339
340
|
chunkChoices: OpenAI.Chat.Completions.ChatCompletionChunk.Choice[]
|
|
340
341
|
): boolean {
|
|
341
342
|
// Technically, one choice could be done and the other still have some
|
|
342
|
-
// content to stream. We keep it simple for now and
|
|
343
|
-
//
|
|
344
|
-
// done.
|
|
345
|
-
|
|
343
|
+
// content to stream. We keep it simple for now and allow zero or one
|
|
344
|
+
// choice per chunk, which allows us to mark everything as done if any
|
|
345
|
+
// choice we hit is done. Zero choices can occur in usage-only chunks at
|
|
346
|
+
// the end of the stream.
|
|
347
|
+
assert(chunkChoices.length < 2);
|
|
346
348
|
assert(completionChoices.length === 1);
|
|
347
349
|
|
|
348
350
|
let msgDone = false;
|
|
@@ -481,6 +483,9 @@ export class OpenAILLMStreaming implements ILLM {
|
|
|
481
483
|
messages,
|
|
482
484
|
tools,
|
|
483
485
|
stream: true,
|
|
486
|
+
stream_options: {
|
|
487
|
+
include_usage: true,
|
|
488
|
+
},
|
|
484
489
|
});
|
|
485
490
|
|
|
486
491
|
// Check the type casting above
|
|
@@ -507,6 +512,8 @@ export class OpenAILLMStreaming implements ILLM {
|
|
|
507
512
|
|
|
508
513
|
if (onMessage) {
|
|
509
514
|
// Inform the call of a message fragment if it contains any text.
|
|
515
|
+
// Note: chunks may have zero choices (e.g., usage-only chunks), so
|
|
516
|
+
// we safely access the first choice.
|
|
510
517
|
|
|
511
518
|
const delta = chunk.choices[0]?.delta;
|
|
512
519
|
if (delta?.content) {
|
|
@@ -40,11 +40,10 @@ class SanitizedServerBrief extends McpServerBrief {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
|
-
*
|
|
44
|
-
*
|
|
43
|
+
* An McpServerManager which can list a set of servers, and enable them in
|
|
44
|
+
* response to requests.
|
|
45
45
|
*/
|
|
46
|
-
export interface ISkillManager {
|
|
47
|
-
getMcpServerManager(): IMcpServerManager;
|
|
46
|
+
export interface ISkillManager extends IMcpServerManager {
|
|
48
47
|
getServerBriefs(): McpServerBrief[];
|
|
49
48
|
|
|
50
49
|
/**
|
|
@@ -55,15 +54,16 @@ export interface ISkillManager {
|
|
|
55
54
|
* is enabled.
|
|
56
55
|
*/
|
|
57
56
|
addMcpServer(serverName: string, enableAll: boolean): Promise<void>;
|
|
57
|
+
|
|
58
|
+
shutdown(): Promise<void>;
|
|
58
59
|
}
|
|
59
60
|
|
|
60
61
|
/**
|
|
61
62
|
* Manages access to the catalogue of servers hosted by sudomcp. Supports
|
|
62
63
|
* adding these servers to McpServerManager.
|
|
63
64
|
*/
|
|
64
|
-
export class SkillManager implements ISkillManager {
|
|
65
|
+
export class SkillManager extends McpServerManager implements ISkillManager {
|
|
65
66
|
private constructor(
|
|
66
|
-
private mcpServerManager: McpServerManager,
|
|
67
67
|
private apiClient: ApiClient,
|
|
68
68
|
private serverBriefs: SanitizedServerBrief[],
|
|
69
69
|
private serverBriefsMap: { [serverName: string]: SanitizedServerBrief },
|
|
@@ -75,14 +75,15 @@ export class SkillManager implements ISkillManager {
|
|
|
75
75
|
) => void,
|
|
76
76
|
// Redirect to this page after successful authorization
|
|
77
77
|
private authorized_url: string | undefined
|
|
78
|
-
) {
|
|
78
|
+
) {
|
|
79
|
+
super();
|
|
80
|
+
}
|
|
79
81
|
|
|
80
82
|
/**
|
|
81
83
|
* Initialize an ApiClient to interface with SudoMCP backend and
|
|
82
84
|
* fetch the current list of ServerBriefs.
|
|
83
85
|
*/
|
|
84
86
|
public static async initialize(
|
|
85
|
-
mcpServerManager: McpServerManager,
|
|
86
87
|
openUrl: (
|
|
87
88
|
url: string,
|
|
88
89
|
authResultP: Promise<boolean>,
|
|
@@ -102,7 +103,6 @@ export class SkillManager implements ISkillManager {
|
|
|
102
103
|
|
|
103
104
|
const [mcpServers, mcpServersMap] = buildServersList(servers);
|
|
104
105
|
return new SkillManager(
|
|
105
|
-
mcpServerManager,
|
|
106
106
|
apiClient,
|
|
107
107
|
mcpServers,
|
|
108
108
|
mcpServersMap,
|
|
@@ -112,6 +112,10 @@ export class SkillManager implements ISkillManager {
|
|
|
112
112
|
);
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
public async shutdown(): Promise<void> {
|
|
116
|
+
return super.shutdown();
|
|
117
|
+
}
|
|
118
|
+
|
|
115
119
|
/// TODO: Bit awkward that we have to restore via this class, but it's the
|
|
116
120
|
/// only class which knows how to restore (restart) the mcp servers.
|
|
117
121
|
public async restoreMcpSettings(
|
|
@@ -143,13 +147,13 @@ export class SkillManager implements ISkillManager {
|
|
|
143
147
|
}
|
|
144
148
|
if (enabled.length === 0) {
|
|
145
149
|
logger.debug(` restoring "${serverName}": (all tools)`);
|
|
146
|
-
this.
|
|
150
|
+
this.enableAllTools(serverName);
|
|
147
151
|
return;
|
|
148
152
|
}
|
|
149
153
|
|
|
150
154
|
logger.debug(` restoring "${serverName}": ${JSON.stringify(enabled)}`);
|
|
151
155
|
for (const toolName of enabled) {
|
|
152
|
-
this.
|
|
156
|
+
this.enableTool(serverName, toolName);
|
|
153
157
|
}
|
|
154
158
|
};
|
|
155
159
|
Object.entries(mcpConfig).map((e) => enableTools(e));
|
|
@@ -174,10 +178,6 @@ export class SkillManager implements ISkillManager {
|
|
|
174
178
|
return this.serverBriefs;
|
|
175
179
|
}
|
|
176
180
|
|
|
177
|
-
public getMcpServerManager(): McpServerManager {
|
|
178
|
-
return this.mcpServerManager;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
181
|
/**
|
|
182
182
|
* Return tool list for a given MCP server. Queries the backend
|
|
183
183
|
* if necessary and caches the result.
|
|
@@ -219,10 +219,9 @@ export class SkillManager implements ISkillManager {
|
|
|
219
219
|
this.authorized_url
|
|
220
220
|
);
|
|
221
221
|
|
|
222
|
-
|
|
223
|
-
await msm.addMcpServerWithClient(client, serverName, tools);
|
|
222
|
+
await this.addMcpServerWithClient(client, serverName, tools);
|
|
224
223
|
if (enableAll) {
|
|
225
|
-
|
|
224
|
+
this.enableAllTools(serverName);
|
|
226
225
|
}
|
|
227
226
|
}
|
|
228
227
|
|