@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
package/src/agent/llm.ts
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import * as openai from "./openAI";
|
|
2
|
-
import { OpenAI } from "openai";
|
|
3
|
-
|
|
4
|
-
export const XALIA_APP_HEADER = {
|
|
5
|
-
"HTTP-Referer": "https://xalia.ai",
|
|
6
|
-
"X-Title": "Xalia",
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
export type ContentPartImage = openai.ChatCompletionContentPartImage;
|
|
10
|
-
|
|
11
|
-
// For now, internally we only support "function" tool call requests, not
|
|
12
|
-
// "custom" (impacts AssistantMessageParam).
|
|
13
|
-
export type MessageToolCall = OpenAI.ChatCompletionMessageFunctionToolCall;
|
|
14
|
-
|
|
15
|
-
// ChatCompletionAssistantMessageParam, but with only "function" tool calls.
|
|
16
|
-
export interface AssistantMessageParam
|
|
17
|
-
extends openai.ChatCompletionAssistantMessageParam {
|
|
18
|
-
tool_calls?: Array<MessageToolCall>;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export type UserMessageParam = openai.ChatCompletionUserMessageParam;
|
|
22
|
-
|
|
23
|
-
// Tool call results `ToolMessageParam` are only "function" results for now
|
|
24
|
-
export interface ToolMessageParam
|
|
25
|
-
extends OpenAI.ChatCompletionToolMessageParam {
|
|
26
|
-
_meta?: Record<string, string>;
|
|
27
|
-
structuredContent?: unknown;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export type MessageParam =
|
|
31
|
-
| OpenAI.Chat.Completions.ChatCompletionSystemMessageParam
|
|
32
|
-
| AssistantMessageParam
|
|
33
|
-
| UserMessageParam
|
|
34
|
-
| ToolMessageParam;
|
|
35
|
-
|
|
36
|
-
// The tool description type
|
|
37
|
-
|
|
38
|
-
export type ToolDescriptor = OpenAI.Chat.Completions.ChatCompletionFunctionTool;
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
*
|
|
42
|
-
*/
|
|
43
|
-
export interface Message /* WithReasoning */
|
|
44
|
-
extends openai.ChatCompletionMessage {
|
|
45
|
-
reasoning?: string;
|
|
46
|
-
tool_calls?: Array<MessageToolCall>;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// export interface Message extends MessageWithReasoning {}
|
|
50
|
-
|
|
51
|
-
// Extend ChatCompletionChoice to only hold function tool calls
|
|
52
|
-
export interface Choice extends openai.ChatCompletionChoice {
|
|
53
|
-
message: Message;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Extends ChatCompletion to only hold function tool calls.
|
|
57
|
-
export interface Completion extends openai.ChatCompletion {
|
|
58
|
-
choices: Array<Choice>;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export interface ILLM {
|
|
62
|
-
getModel(): string;
|
|
63
|
-
|
|
64
|
-
getUrl(): string;
|
|
65
|
-
|
|
66
|
-
getConversationResponse(
|
|
67
|
-
messages: MessageParam[],
|
|
68
|
-
tools?: ToolDescriptor[],
|
|
69
|
-
onMessage?: (msg: string, end: boolean) => Promise<void>,
|
|
70
|
-
onReasoning?: (reasoning: string) => Promise<void>
|
|
71
|
-
): Promise<{ stop: (msg: string) => void; completion: Promise<Completion> }>;
|
|
72
|
-
|
|
73
|
-
setModel(model: string): void;
|
|
74
|
-
}
|
|
@@ -1,541 +0,0 @@
|
|
|
1
|
-
import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
|
|
2
|
-
import {
|
|
3
|
-
SSEClientTransport,
|
|
4
|
-
SSEClientTransportOptions,
|
|
5
|
-
} from "@modelcontextprotocol/sdk/client/sse.js";
|
|
6
|
-
import {
|
|
7
|
-
StreamableHTTPClientTransport,
|
|
8
|
-
StreamableHTTPClientTransportOptions,
|
|
9
|
-
} from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
10
|
-
import { Client as McpClient } from "@modelcontextprotocol/sdk/client/index.js";
|
|
11
|
-
import { Tool, Resource } from "@modelcontextprotocol/sdk/types.js";
|
|
12
|
-
|
|
13
|
-
import { McpServerSettings, getLogger } from "@xalia/xmcp/sdk";
|
|
14
|
-
export type { McpServerSettings } from "@xalia/xmcp/sdk";
|
|
15
|
-
|
|
16
|
-
import { TokenAuth } from "./tokenAuth";
|
|
17
|
-
import { strict as assert } from "assert";
|
|
18
|
-
import { ToolDescriptor } from "./llm";
|
|
19
|
-
import { ToolCallResult } from "./agent";
|
|
20
|
-
|
|
21
|
-
const logger = getLogger();
|
|
22
|
-
|
|
23
|
-
export type McpServerToolCallMetaData = {
|
|
24
|
-
"xalia/mcpServerName": string;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
const mcpServerToolCallMetaKeys: (keyof McpServerToolCallMetaData)[] = [
|
|
28
|
-
"xalia/mcpServerName",
|
|
29
|
-
];
|
|
30
|
-
|
|
31
|
-
export function isMcpServerToolCallMetaData(
|
|
32
|
-
meta: unknown
|
|
33
|
-
): meta is McpServerToolCallMetaData {
|
|
34
|
-
return (
|
|
35
|
-
!!meta &&
|
|
36
|
-
typeof meta === "object" &&
|
|
37
|
-
mcpServerToolCallMetaKeys.every((k) => k in meta)
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export type McpServerToolCallResult = ToolCallResult<McpServerToolCallMetaData>;
|
|
42
|
-
|
|
43
|
-
export type VerifiedMcpToolCall = {
|
|
44
|
-
mcpServerName: string;
|
|
45
|
-
toolName: string;
|
|
46
|
-
args: unknown;
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
export type ResourceContent = {
|
|
50
|
-
_meta?: Record<string, unknown>;
|
|
51
|
-
uri: string;
|
|
52
|
-
mimeType?: string;
|
|
53
|
-
text?: string;
|
|
54
|
-
blob?: string;
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
/// Callback into an Mcp server
|
|
58
|
-
export type McpCallback = { (args: string): Promise<McpServerToolCallResult> };
|
|
59
|
-
|
|
60
|
-
/// Map of tool name to callback
|
|
61
|
-
export type McpCallbacks = Map<string, McpCallback>;
|
|
62
|
-
|
|
63
|
-
/// List of tool names that are enabled. We keep it as a map in the runtime
|
|
64
|
-
/// object, so that we can quickly add and remove arbitrary entries. (The
|
|
65
|
-
/// AgentProfile keeps this as a flat list).
|
|
66
|
-
export type EnabledToolsMap = Map<string, boolean>;
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* The (read-only) McpServerInfo to expose to external classes. Callers
|
|
70
|
-
* should not modify this data directly. Only through the McpServerManager
|
|
71
|
-
* class.
|
|
72
|
-
*/
|
|
73
|
-
export class McpServerInfo {
|
|
74
|
-
private readonly name: string;
|
|
75
|
-
private readonly tools: Tool[]; // TODO: May not need both tools and toolsMap
|
|
76
|
-
private readonly resources: Resource[];
|
|
77
|
-
private readonly toolsMap: { [toolName: string]: Tool };
|
|
78
|
-
protected enabledToolsMap: EnabledToolsMap;
|
|
79
|
-
|
|
80
|
-
constructor(name: string, tools: Tool[], resources: Resource[]) {
|
|
81
|
-
const toolsMap: { [toolName: string]: Tool } = {};
|
|
82
|
-
|
|
83
|
-
for (const mcpTool of tools) {
|
|
84
|
-
const toolName = mcpTool.name;
|
|
85
|
-
toolsMap[toolName] = mcpTool;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
this.name = name;
|
|
89
|
-
this.tools = tools;
|
|
90
|
-
this.resources = resources;
|
|
91
|
-
this.toolsMap = toolsMap;
|
|
92
|
-
this.enabledToolsMap = new Map();
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
public getName(): string {
|
|
96
|
-
return this.name;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
public getEnabledTools(): EnabledToolsMap {
|
|
100
|
-
return this.enabledToolsMap;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
public getTools(): Tool[] {
|
|
104
|
-
return this.tools;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
public getResources(): Resource[] {
|
|
108
|
-
return this.resources;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
public getTool(toolName: string): Tool | undefined {
|
|
112
|
-
return this.toolsMap[toolName];
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Instance of McpServerInfo which supports setting tool state. Intended for
|
|
118
|
-
* IMcpServerManager implementations, not for client code.
|
|
119
|
-
*/
|
|
120
|
-
export class McpServerInfoRW extends McpServerInfo {
|
|
121
|
-
public enableTool(toolName: string) {
|
|
122
|
-
this.enabledToolsMap.set(toolName, true);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
public disableTool(toolName: string) {
|
|
126
|
-
this.enabledToolsMap.delete(toolName);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* The internal class holds server info and allows it to be updated. Managed
|
|
132
|
-
* by McpServerManager. Do not access these methods except via the
|
|
133
|
-
* McpServerManager.
|
|
134
|
-
*/
|
|
135
|
-
class McpServerInfoInternal extends McpServerInfoRW {
|
|
136
|
-
private readonly client: McpClient;
|
|
137
|
-
private readonly callbacks: McpCallbacks;
|
|
138
|
-
|
|
139
|
-
constructor(
|
|
140
|
-
name: string,
|
|
141
|
-
client: McpClient,
|
|
142
|
-
tools: Tool[],
|
|
143
|
-
resources: Resource[]
|
|
144
|
-
) {
|
|
145
|
-
super(name, tools, resources);
|
|
146
|
-
|
|
147
|
-
logger.debug(`[McpServerInfoInternal] tools: ${JSON.stringify(tools)}`);
|
|
148
|
-
|
|
149
|
-
const callbacks: McpCallbacks = new Map();
|
|
150
|
-
|
|
151
|
-
for (const mcpTool of tools) {
|
|
152
|
-
const toolName = mcpTool.name;
|
|
153
|
-
|
|
154
|
-
// Create callback
|
|
155
|
-
const callback = async (
|
|
156
|
-
argStr: string
|
|
157
|
-
): Promise<McpServerToolCallResult> => {
|
|
158
|
-
logger.debug(
|
|
159
|
-
`cb for ${toolName} invoked with args (${typeof argStr}): ` +
|
|
160
|
-
JSON.stringify(argStr)
|
|
161
|
-
);
|
|
162
|
-
|
|
163
|
-
const argsObj: unknown = JSON.parse(argStr);
|
|
164
|
-
const toolResult = await client.callTool({
|
|
165
|
-
name: toolName,
|
|
166
|
-
arguments: argsObj as Record<string, unknown>,
|
|
167
|
-
});
|
|
168
|
-
logger.debug(
|
|
169
|
-
`cb for ${toolName} returned: ${JSON.stringify(toolResult)}`
|
|
170
|
-
);
|
|
171
|
-
|
|
172
|
-
assert(typeof toolResult === "object");
|
|
173
|
-
const content = toolResult.content as { [a: number]: unknown };
|
|
174
|
-
assert(typeof content === "object");
|
|
175
|
-
assert(content);
|
|
176
|
-
const content0 = content[0] as { text: string };
|
|
177
|
-
assert(typeof content0 === "object");
|
|
178
|
-
const content0Text = content0.text;
|
|
179
|
-
assert(typeof content0Text === "string");
|
|
180
|
-
|
|
181
|
-
const meta: Record<string, string> = (toolResult._meta ||
|
|
182
|
-
{}) as McpServerToolCallMetaData;
|
|
183
|
-
meta["xalia/mcpServerName"] = this.getName();
|
|
184
|
-
assert(isMcpServerToolCallMetaData(meta));
|
|
185
|
-
|
|
186
|
-
return {
|
|
187
|
-
response: content0Text,
|
|
188
|
-
_meta: meta,
|
|
189
|
-
...(toolResult.structuredContent
|
|
190
|
-
? { structuredContent: toolResult.structuredContent }
|
|
191
|
-
: {}),
|
|
192
|
-
};
|
|
193
|
-
};
|
|
194
|
-
|
|
195
|
-
callbacks.set(toolName, callback);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
this.client = client;
|
|
199
|
-
this.callbacks = callbacks;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
public async shutdown(): Promise<void> {
|
|
203
|
-
await this.client.close();
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
public getCallback(toolName: string): McpCallback | undefined {
|
|
207
|
-
return this.callbacks.get(toolName);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
public async readResource(uri: string): Promise<ResourceContent[]> {
|
|
211
|
-
const res = await this.client.readResource({
|
|
212
|
-
uri,
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
logger.info(`readResource: got: ${JSON.stringify(res)}`);
|
|
216
|
-
return res.contents;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* The client's interface to a manager which has mcp servers assigned to it,
|
|
222
|
-
* and can then query them for their tools, enable/disbale spercific tools and
|
|
223
|
-
* remove servers completely.
|
|
224
|
-
*
|
|
225
|
-
* This interface says nothing about communication with a specific agent. It
|
|
226
|
-
* only defines the client-facing interactions.
|
|
227
|
-
*/
|
|
228
|
-
export interface IMcpServerManager {
|
|
229
|
-
hasMcpServer(mcpServerName: string): boolean;
|
|
230
|
-
getMcpServerNames(): string[];
|
|
231
|
-
getMcpServer(mcpServerName: string): McpServerInfo;
|
|
232
|
-
|
|
233
|
-
removeMcpServer(mcpServerName: string): Promise<void>;
|
|
234
|
-
enableAllTools(mcpServerName: string): void;
|
|
235
|
-
disableAllTools(mcpServerName: string): void;
|
|
236
|
-
enableTool(mcpServerName: string, toolName: string): void;
|
|
237
|
-
disableTool(mcpServerName: string, toolName: string): void;
|
|
238
|
-
|
|
239
|
-
shutdown(): Promise<void>;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
/**
|
|
243
|
-
* Manage a set of MCP servers, where the tools for each server have an
|
|
244
|
-
* 'enabled' flag. Tools are disabled by default. The set of enabled tools
|
|
245
|
-
* over all servers is exposed as a single list of OpenAI functions.
|
|
246
|
-
*/
|
|
247
|
-
export class McpServerManager implements IMcpServerManager {
|
|
248
|
-
private mcpServers = new Map<string, McpServerInfoInternal>();
|
|
249
|
-
private enabledToolsDirty: boolean = true;
|
|
250
|
-
private enabledOpenAITools: ToolDescriptor[] = [];
|
|
251
|
-
|
|
252
|
-
public async shutdown() {
|
|
253
|
-
await Promise.all(
|
|
254
|
-
Array.from(this.mcpServers.entries()).map(([name, server]) => {
|
|
255
|
-
logger.debug(`shutting down: ${name}...`);
|
|
256
|
-
return server.shutdown();
|
|
257
|
-
})
|
|
258
|
-
);
|
|
259
|
-
|
|
260
|
-
this.mcpServers.clear();
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
public hasMcpServer(mcpServerName: string): boolean {
|
|
264
|
-
return this.mcpServers.has(mcpServerName);
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
public getMcpServerNames(): string[] {
|
|
268
|
-
return Array.from(this.mcpServers.keys());
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
public getMcpServer(mcpServerName: string): McpServerInfo {
|
|
272
|
-
return this.getMcpServerInternal(mcpServerName);
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
public async addMcpServerWithTransport(
|
|
276
|
-
mcpServerName: string,
|
|
277
|
-
transport: Transport,
|
|
278
|
-
tools?: Tool[]
|
|
279
|
-
): Promise<void> {
|
|
280
|
-
const client = new McpClient({
|
|
281
|
-
name: "@xalia/agent",
|
|
282
|
-
version: "1.0.0",
|
|
283
|
-
});
|
|
284
|
-
|
|
285
|
-
try {
|
|
286
|
-
await client.connect(transport);
|
|
287
|
-
} catch (e) {
|
|
288
|
-
// Ensure the socket is closed so the process can exit if there is an
|
|
289
|
-
// error at connection time.
|
|
290
|
-
await client.close();
|
|
291
|
-
throw e;
|
|
292
|
-
}
|
|
293
|
-
await this.addMcpServerWithClient(client, mcpServerName, tools);
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
public async addMcpServerWithSSEUrl(
|
|
297
|
-
mcpServerName: string,
|
|
298
|
-
url: string,
|
|
299
|
-
apiKey?: string,
|
|
300
|
-
tools?: Tool[]
|
|
301
|
-
): Promise<void> {
|
|
302
|
-
logger.debug(`Adding mcp server ${mcpServerName}: ${url}`);
|
|
303
|
-
const sseTransportOptions: SSEClientTransportOptions = {};
|
|
304
|
-
if (apiKey) {
|
|
305
|
-
sseTransportOptions.authProvider = new TokenAuth(apiKey);
|
|
306
|
-
}
|
|
307
|
-
const urlO = new URL(url);
|
|
308
|
-
const transport = new SSEClientTransport(urlO, sseTransportOptions);
|
|
309
|
-
return this.addMcpServerWithTransport(mcpServerName, transport, tools);
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
public async addMcpServerWithStreamableHTTPUrl(
|
|
313
|
-
mcpServerName: string,
|
|
314
|
-
url: string,
|
|
315
|
-
apiKey?: string
|
|
316
|
-
): Promise<void> {
|
|
317
|
-
logger.debug(`Adding mcp (s-http) server ${mcpServerName}: ${url}`);
|
|
318
|
-
const transportOptions: StreamableHTTPClientTransportOptions = {};
|
|
319
|
-
if (apiKey) {
|
|
320
|
-
transportOptions.authProvider = new TokenAuth(apiKey);
|
|
321
|
-
}
|
|
322
|
-
const urlO = new URL(url);
|
|
323
|
-
const transport = new StreamableHTTPClientTransport(urlO, transportOptions);
|
|
324
|
-
return this.addMcpServerWithTransport(mcpServerName, transport);
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
/**
|
|
328
|
-
* Add MCP server from an already connected McpClient.
|
|
329
|
-
*/
|
|
330
|
-
public async addMcpServerWithClient(
|
|
331
|
-
client: McpClient,
|
|
332
|
-
mcpServerName: string,
|
|
333
|
-
tools?: Tool[]
|
|
334
|
-
): Promise<void> {
|
|
335
|
-
try {
|
|
336
|
-
// TODO: require the tools to be passed in.
|
|
337
|
-
|
|
338
|
-
const resourcesP = client.listResources().catch((err: unknown) => {
|
|
339
|
-
logger.warn(
|
|
340
|
-
`resources ${mcpServerName}: ${JSON.stringify(err)} ${String(err)}`
|
|
341
|
-
);
|
|
342
|
-
return { resources: [] };
|
|
343
|
-
});
|
|
344
|
-
if (!tools) {
|
|
345
|
-
const mcpTools = await client.listTools();
|
|
346
|
-
tools = mcpTools.tools;
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
const resources: Resource[] = (await resourcesP).resources;
|
|
350
|
-
this.mcpServers.set(
|
|
351
|
-
mcpServerName,
|
|
352
|
-
new McpServerInfoInternal(mcpServerName, client, tools, resources)
|
|
353
|
-
);
|
|
354
|
-
} catch (e) {
|
|
355
|
-
await client.close();
|
|
356
|
-
throw e;
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
public async removeMcpServer(mcpServerName: string): Promise<void> {
|
|
361
|
-
const server = this.getMcpServerInternal(mcpServerName);
|
|
362
|
-
this.mcpServers.delete(mcpServerName);
|
|
363
|
-
await server.shutdown();
|
|
364
|
-
this.enabledToolsDirty = true;
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
public enableAllTools(mcpServerName: string) {
|
|
368
|
-
logger.debug(`enableAllTools: ${mcpServerName}`);
|
|
369
|
-
const server = this.getMcpServerInternal(mcpServerName);
|
|
370
|
-
for (const tool of server.getTools()) {
|
|
371
|
-
logger.debug(`enable: ${tool.name}`);
|
|
372
|
-
server.enableTool(tool.name);
|
|
373
|
-
}
|
|
374
|
-
this.enabledToolsDirty = true;
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
public disableAllTools(mcpServerName: string) {
|
|
378
|
-
logger.debug(`disableAllTools: ${mcpServerName}`);
|
|
379
|
-
const server = this.getMcpServerInternal(mcpServerName);
|
|
380
|
-
for (const tool of server.getTools()) {
|
|
381
|
-
logger.debug(`disable: ${tool.name}`);
|
|
382
|
-
server.disableTool(tool.name);
|
|
383
|
-
}
|
|
384
|
-
this.enabledToolsDirty = true;
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
public enableTool(mcpServerName: string, toolName: string) {
|
|
388
|
-
logger.debug(`enableTool: ${mcpServerName} ${toolName}`);
|
|
389
|
-
const server = this.getMcpServerInternal(mcpServerName);
|
|
390
|
-
server.enableTool(toolName);
|
|
391
|
-
this.enabledToolsDirty = true;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
public disableTool(mcpServerName: string, toolName: string) {
|
|
395
|
-
const server = this.getMcpServerInternal(mcpServerName);
|
|
396
|
-
server.disableTool(toolName);
|
|
397
|
-
this.enabledToolsDirty = true;
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
public getOpenAITools(): ToolDescriptor[] {
|
|
401
|
-
if (this.enabledToolsDirty) {
|
|
402
|
-
this.enabledOpenAITools = computeOpenAIToolList(this.mcpServers);
|
|
403
|
-
this.enabledToolsDirty = false;
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
return this.enabledOpenAITools;
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
public verifyToolCall(
|
|
410
|
-
qualifiedToolName: string,
|
|
411
|
-
args: unknown
|
|
412
|
-
): VerifiedMcpToolCall {
|
|
413
|
-
const [mcpServerName, toolName] = splitQualifiedName(qualifiedToolName);
|
|
414
|
-
logger.debug(`invoke: qualified: ${qualifiedToolName}`);
|
|
415
|
-
logger.debug(
|
|
416
|
-
`invoke: mcpServerName: ${mcpServerName}, toolName: ${toolName}`
|
|
417
|
-
);
|
|
418
|
-
logger.debug(`invoke: args: ${JSON.stringify(args)}`);
|
|
419
|
-
|
|
420
|
-
const server = this.getMcpServerInternal(mcpServerName);
|
|
421
|
-
const cb = server.getCallback(toolName);
|
|
422
|
-
if (!cb) {
|
|
423
|
-
throw new Error(`Unknown tool ${qualifiedToolName}`);
|
|
424
|
-
}
|
|
425
|
-
return {
|
|
426
|
-
mcpServerName,
|
|
427
|
-
toolName,
|
|
428
|
-
args,
|
|
429
|
-
};
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
/**
|
|
433
|
-
* Note the `qualifiedToolName` is the full `{mcpServerName}/{toolName}` as
|
|
434
|
-
* in the openai spec.
|
|
435
|
-
*/
|
|
436
|
-
public async invoke(toolCall: VerifiedMcpToolCall): Promise<ToolCallResult> {
|
|
437
|
-
const server = this.getMcpServerInternal(toolCall.mcpServerName);
|
|
438
|
-
const cb = server.getCallback(toolCall.toolName);
|
|
439
|
-
if (!cb) {
|
|
440
|
-
throw new Error(`Unknown tool ${toolCall.toolName}`);
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
return cb(JSON.stringify(toolCall.args));
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
public async getResource(
|
|
447
|
-
serverName: string,
|
|
448
|
-
uri: string
|
|
449
|
-
): Promise<ResourceContent[]> {
|
|
450
|
-
const server = this.getMcpServerInternal(serverName);
|
|
451
|
-
return server.readResource(uri);
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
/**
|
|
455
|
-
* "Settings" refers to the set of added servers and enabled tools.
|
|
456
|
-
*/
|
|
457
|
-
public getMcpServerSettings(): McpServerSettings {
|
|
458
|
-
const config: McpServerSettings = {};
|
|
459
|
-
|
|
460
|
-
// NOTE: on load, entries of the form:
|
|
461
|
-
//
|
|
462
|
-
// <server>: []
|
|
463
|
-
//
|
|
464
|
-
// may be interpreted as "all tools for <server>". If the client has left
|
|
465
|
-
// a server with no tools enabled, we mark it as disabled.
|
|
466
|
-
|
|
467
|
-
for (const [serverName, server] of this.mcpServers) {
|
|
468
|
-
const tools = Array.from(server.getEnabledTools().keys());
|
|
469
|
-
if (tools.length > 0) {
|
|
470
|
-
config[serverName] = tools;
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
return config;
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
private getMcpServerInternal(mcpServerName: string): McpServerInfoInternal {
|
|
478
|
-
const server = this.mcpServers.get(mcpServerName);
|
|
479
|
-
if (server) {
|
|
480
|
-
return server;
|
|
481
|
-
}
|
|
482
|
-
throw Error(`[getMcpServerInternal] unknown server ${mcpServerName}`);
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
export function computeQualifiedName(
|
|
487
|
-
mcpServerName: string,
|
|
488
|
-
toolName: string
|
|
489
|
-
): string {
|
|
490
|
-
return `${mcpServerName}__${toolName}`;
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
export function splitQualifiedName(
|
|
494
|
-
qualifiedToolName: string
|
|
495
|
-
): [string, string] {
|
|
496
|
-
const delimIdx = qualifiedToolName.indexOf("__");
|
|
497
|
-
if (delimIdx < 0) {
|
|
498
|
-
throw Error(`invalid qualified name: ${qualifiedToolName}`);
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
return [
|
|
502
|
-
qualifiedToolName.slice(0, delimIdx),
|
|
503
|
-
qualifiedToolName.slice(delimIdx + 2),
|
|
504
|
-
];
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
export function computeOpenAIToolList(
|
|
508
|
-
mcpServers: Map<string, McpServerInfoInternal>
|
|
509
|
-
): ToolDescriptor[] {
|
|
510
|
-
const openaiTools: ToolDescriptor[] = [];
|
|
511
|
-
|
|
512
|
-
for (const [mcpServerName, mcpServer] of mcpServers) {
|
|
513
|
-
const tools = mcpServer.getTools();
|
|
514
|
-
const enabled = mcpServer.getEnabledTools();
|
|
515
|
-
|
|
516
|
-
for (const mcpTool of tools) {
|
|
517
|
-
const toolName = mcpTool.name;
|
|
518
|
-
if (enabled.get(toolName)) {
|
|
519
|
-
const qualifiedName = computeQualifiedName(mcpServerName, toolName);
|
|
520
|
-
const openaiTool = mcpToolToOpenAITool(mcpTool, qualifiedName);
|
|
521
|
-
openaiTools.push(openaiTool);
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
return openaiTools;
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
export function mcpToolToOpenAITool(
|
|
530
|
-
tool: Tool,
|
|
531
|
-
qualifiedName?: string
|
|
532
|
-
): ToolDescriptor {
|
|
533
|
-
return {
|
|
534
|
-
type: "function",
|
|
535
|
-
function: {
|
|
536
|
-
name: qualifiedName || tool.name,
|
|
537
|
-
description: tool.description,
|
|
538
|
-
parameters: tool.inputSchema,
|
|
539
|
-
},
|
|
540
|
-
};
|
|
541
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { IAgentEventHandler } from "./iAgentEventHandler";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Trivial IAgentEventHandler implementation which does not track any messages
|
|
5
|
-
* and does not allow tool calls.
|
|
6
|
-
*/
|
|
7
|
-
export const NULL_AGENT_EVENT_HANDLER: IAgentEventHandler = {
|
|
8
|
-
onCompletion: (): void => {},
|
|
9
|
-
onImage: (): void => {},
|
|
10
|
-
onToolCallResult: (): void => {},
|
|
11
|
-
onAgentMessage: (): Promise<void> => {
|
|
12
|
-
return new Promise<void>((r) => {
|
|
13
|
-
r();
|
|
14
|
-
});
|
|
15
|
-
},
|
|
16
|
-
onReasoning: (): Promise<void> => {
|
|
17
|
-
return new Promise<void>((r) => {
|
|
18
|
-
r();
|
|
19
|
-
});
|
|
20
|
-
},
|
|
21
|
-
onToolCall: (): Promise<boolean> => {
|
|
22
|
-
return new Promise((r) => {
|
|
23
|
-
r(false);
|
|
24
|
-
});
|
|
25
|
-
},
|
|
26
|
-
};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { IPlatform } from "../agent/iplatform";
|
|
2
|
-
|
|
3
|
-
export const NULL_PLATFORM: IPlatform = {
|
|
4
|
-
openUrl: () => {
|
|
5
|
-
throw new Error("null_platform openUrl called");
|
|
6
|
-
},
|
|
7
|
-
load: (): Promise<string> => {
|
|
8
|
-
throw new Error("null_platform load called");
|
|
9
|
-
},
|
|
10
|
-
renderHTML: (): Promise<void> => {
|
|
11
|
-
throw new Error("null_platform renderHTML called");
|
|
12
|
-
},
|
|
13
|
-
};
|