@xalia/agent 0.6.9 → 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.
Files changed (199) hide show
  1. package/README.md +11 -0
  2. package/dist/agent/src/agent/agent.js +77 -18
  3. package/dist/agent/src/agent/agentUtils.js +3 -2
  4. package/dist/agent/src/agent/documentSummarizer.js +126 -0
  5. package/dist/agent/src/agent/dummyLLM.js +25 -22
  6. package/dist/agent/src/agent/imageGenLLM.js +22 -19
  7. package/dist/agent/src/agent/llm.js +1 -1
  8. package/dist/agent/src/agent/openAILLM.js +15 -12
  9. package/dist/agent/src/agent/openAILLMStreaming.js +68 -37
  10. package/dist/agent/src/agent/repeatLLM.js +16 -7
  11. package/dist/agent/src/agent/tokenCounter.js +390 -0
  12. package/dist/agent/src/agent/tokenCounter.test.js +206 -0
  13. package/dist/agent/src/agent/toolSettings.js +17 -0
  14. package/dist/agent/src/agent/tools/calculatorTool.js +45 -0
  15. package/dist/agent/src/agent/tools/contentExtractors/pdfToText.js +55 -0
  16. package/dist/agent/src/agent/tools/datetimeTool.js +38 -0
  17. package/dist/agent/src/agent/tools/fileManager/fileManagerTool.js +156 -0
  18. package/dist/agent/src/agent/tools/fileManager/index.js +31 -0
  19. package/dist/agent/src/agent/tools/fileManager/memoryFileManager.js +102 -0
  20. package/dist/agent/src/{chat/data → agent/tools/fileManager}/mimeTypes.js +3 -1
  21. package/dist/agent/src/agent/tools/fileManager/prompt.js +33 -0
  22. package/dist/agent/src/{chat/data/dbSessionFileModels.js → agent/tools/fileManager/types.js} +7 -0
  23. package/dist/agent/src/agent/tools/index.js +64 -0
  24. package/dist/agent/src/agent/tools/openUrlTool.js +57 -0
  25. package/dist/agent/src/agent/tools/renderTool.js +89 -0
  26. package/dist/agent/src/agent/tools/utils.js +61 -0
  27. package/dist/agent/src/{chat/utils/search.js → agent/tools/webSearch.js} +1 -2
  28. package/dist/agent/src/agent/tools/webSearchTool.js +40 -0
  29. package/dist/agent/src/chat/client/chatClient.js +28 -0
  30. package/dist/agent/src/chat/client/index.js +4 -1
  31. package/dist/agent/src/chat/client/sessionClient.js +28 -2
  32. package/dist/agent/src/chat/constants.js +8 -0
  33. package/dist/agent/src/chat/data/dbSessionFiles.js +11 -6
  34. package/dist/agent/src/chat/protocol/messages.js +5 -0
  35. package/dist/agent/src/chat/server/chatContextManager.js +45 -25
  36. package/dist/agent/src/chat/server/conversation.js +3 -0
  37. package/dist/agent/src/chat/server/imageGeneratorTools.js +20 -8
  38. package/dist/agent/src/chat/server/openAIRouterLLM.js +0 -3
  39. package/dist/agent/src/chat/server/openSession.js +218 -55
  40. package/dist/agent/src/chat/server/promptRefiner.js +86 -0
  41. package/dist/agent/src/chat/server/server.js +5 -1
  42. package/dist/agent/src/chat/server/sessionFileManager.js +22 -221
  43. package/dist/agent/src/chat/server/sessionRegistry.js +87 -0
  44. package/dist/agent/src/chat/server/titleGenerator.js +112 -0
  45. package/dist/agent/src/chat/server/titleGenerator.test.js +113 -0
  46. package/dist/agent/src/chat/server/tools.js +63 -287
  47. package/dist/agent/src/chat/utils/approvalManager.js +6 -3
  48. package/dist/agent/src/chat/utils/multiAsyncQueue.js +3 -0
  49. package/dist/agent/src/test/agent.test.js +16 -17
  50. package/dist/agent/src/test/chatContextManager.test.js +15 -3
  51. package/dist/agent/src/test/dbMcpServerConfigs.test.js +4 -4
  52. package/dist/agent/src/test/dbSessionFiles.test.js +17 -17
  53. package/dist/agent/src/test/testTools.js +6 -1
  54. package/dist/agent/src/test/tools.test.js +27 -9
  55. package/dist/agent/src/tool/agentChat.js +5 -2
  56. package/dist/agent/src/tool/chatMain.js +34 -7
  57. package/dist/agent/src/tool/commandPrompt.js +2 -2
  58. package/dist/agent/src/tool/files.js +7 -8
  59. package/package.json +8 -2
  60. package/.env.development +0 -1
  61. package/.prettierrc.json +0 -11
  62. package/dist/agent/src/agent/tools.js +0 -44
  63. package/eslint.config.mjs +0 -38
  64. package/scripts/chat_server +0 -8
  65. package/scripts/git_message +0 -31
  66. package/scripts/git_wip +0 -21
  67. package/scripts/pr_message +0 -18
  68. package/scripts/pr_review +0 -16
  69. package/scripts/setup_chat +0 -90
  70. package/scripts/shutdown_chat_server +0 -42
  71. package/scripts/start_chat_server +0 -24
  72. package/scripts/sudomcp_import +0 -23
  73. package/scripts/test_chat +0 -308
  74. package/src/agent/agent.ts +0 -624
  75. package/src/agent/agentUtils.ts +0 -285
  76. package/src/agent/compressingContextManager.ts +0 -129
  77. package/src/agent/context.ts +0 -265
  78. package/src/agent/contextWithWorkspace.ts +0 -162
  79. package/src/agent/dummyLLM.ts +0 -126
  80. package/src/agent/iAgentEventHandler.ts +0 -64
  81. package/src/agent/imageGenLLM.ts +0 -97
  82. package/src/agent/imageGenerator.ts +0 -45
  83. package/src/agent/iplatform.ts +0 -18
  84. package/src/agent/llm.ts +0 -74
  85. package/src/agent/mcpServerManager.ts +0 -541
  86. package/src/agent/nullAgentEventHandler.ts +0 -26
  87. package/src/agent/nullPlatform.ts +0 -13
  88. package/src/agent/openAI.ts +0 -123
  89. package/src/agent/openAILLM.ts +0 -95
  90. package/src/agent/openAILLMStreaming.ts +0 -609
  91. package/src/agent/promptProvider.ts +0 -87
  92. package/src/agent/repeatLLM.ts +0 -50
  93. package/src/agent/sudoMcpServerManager.ts +0 -361
  94. package/src/agent/tokenAuth.ts +0 -50
  95. package/src/agent/tools.ts +0 -57
  96. package/src/chat/client/chatClient.ts +0 -922
  97. package/src/chat/client/connection.test.ts +0 -241
  98. package/src/chat/client/connection.ts +0 -286
  99. package/src/chat/client/constants.ts +0 -1
  100. package/src/chat/client/index.ts +0 -18
  101. package/src/chat/client/interfaces.ts +0 -34
  102. package/src/chat/client/sessionClient.ts +0 -537
  103. package/src/chat/client/sessionFiles.ts +0 -142
  104. package/src/chat/client/teamManager.ts +0 -29
  105. package/src/chat/data/apiKeyManager.ts +0 -76
  106. package/src/chat/data/dataModels.ts +0 -101
  107. package/src/chat/data/database.ts +0 -997
  108. package/src/chat/data/dbMcpServerConfigs.ts +0 -59
  109. package/src/chat/data/dbSessionFileModels.ts +0 -113
  110. package/src/chat/data/dbSessionFiles.ts +0 -99
  111. package/src/chat/data/dbSessionMessages.ts +0 -102
  112. package/src/chat/data/mimeTypes.ts +0 -58
  113. package/src/chat/protocol/connectionMessages.ts +0 -49
  114. package/src/chat/protocol/constants.ts +0 -55
  115. package/src/chat/protocol/errors.ts +0 -16
  116. package/src/chat/protocol/messages.ts +0 -846
  117. package/src/chat/server/README.md +0 -127
  118. package/src/chat/server/chatContextManager.ts +0 -639
  119. package/src/chat/server/connectionManager.test.ts +0 -246
  120. package/src/chat/server/connectionManager.ts +0 -506
  121. package/src/chat/server/conversation.ts +0 -316
  122. package/src/chat/server/errorUtils.ts +0 -28
  123. package/src/chat/server/imageGeneratorTools.ts +0 -160
  124. package/src/chat/server/openAIRouterLLM.ts +0 -171
  125. package/src/chat/server/openSession.ts +0 -1689
  126. package/src/chat/server/openSessionMessageSender.ts +0 -4
  127. package/src/chat/server/server.ts +0 -175
  128. package/src/chat/server/sessionFileManager.ts +0 -422
  129. package/src/chat/server/sessionRegistry.test.ts +0 -137
  130. package/src/chat/server/sessionRegistry.ts +0 -1425
  131. package/src/chat/server/test-utils/mockFactories.ts +0 -422
  132. package/src/chat/server/tools.ts +0 -397
  133. package/src/chat/utils/agentSessionMap.ts +0 -76
  134. package/src/chat/utils/approvalManager.ts +0 -183
  135. package/src/chat/utils/asyncLock.ts +0 -43
  136. package/src/chat/utils/asyncQueue.ts +0 -62
  137. package/src/chat/utils/htmlToText.ts +0 -61
  138. package/src/chat/utils/multiAsyncQueue.ts +0 -62
  139. package/src/chat/utils/responseAwaiter.ts +0 -181
  140. package/src/chat/utils/search.ts +0 -139
  141. package/src/chat/utils/userResolver.ts +0 -48
  142. package/src/chat/utils/websocket.ts +0 -16
  143. package/src/index.ts +0 -0
  144. package/src/test/agent.test.ts +0 -590
  145. package/src/test/approvalManager.test.ts +0 -141
  146. package/src/test/chatContextManager.test.ts +0 -527
  147. package/src/test/clientServerConnection.test.ts +0 -205
  148. package/src/test/compressingContextManager.test.ts +0 -77
  149. package/src/test/context.test.ts +0 -150
  150. package/src/test/contextTestTools.ts +0 -95
  151. package/src/test/conversation.test.ts +0 -109
  152. package/src/test/db.test.ts +0 -363
  153. package/src/test/dbMcpServerConfigs.test.ts +0 -112
  154. package/src/test/dbSessionFiles.test.ts +0 -258
  155. package/src/test/dbSessionMessages.test.ts +0 -85
  156. package/src/test/dbTestTools.ts +0 -157
  157. package/src/test/imageLoad.test.ts +0 -15
  158. package/src/test/mcpServerManager.test.ts +0 -114
  159. package/src/test/multiAsyncQueue.test.ts +0 -183
  160. package/src/test/openaiStreaming.test.ts +0 -177
  161. package/src/test/prompt.test.ts +0 -27
  162. package/src/test/promptProvider.test.ts +0 -33
  163. package/src/test/responseAwaiter.test.ts +0 -103
  164. package/src/test/sudoMcpServerManager.test.ts +0 -63
  165. package/src/test/testTools.ts +0 -171
  166. package/src/test/tools.test.ts +0 -39
  167. package/src/tool/agentChat.ts +0 -194
  168. package/src/tool/agentMain.ts +0 -180
  169. package/src/tool/chatMain.ts +0 -594
  170. package/src/tool/commandPrompt.ts +0 -264
  171. package/src/tool/files.ts +0 -84
  172. package/src/tool/main.ts +0 -25
  173. package/src/tool/nodePlatform.ts +0 -73
  174. package/src/tool/options.ts +0 -144
  175. package/src/tool/prompt.ts +0 -101
  176. package/test_data/background_test_profile.json +0 -6
  177. package/test_data/background_test_script.json +0 -11
  178. package/test_data/dummyllm_script_crash.json +0 -32
  179. package/test_data/dummyllm_script_image_gen.json +0 -19
  180. package/test_data/dummyllm_script_image_gen_fe.json +0 -29
  181. package/test_data/dummyllm_script_invoke_image_gen_tool.json +0 -37
  182. package/test_data/dummyllm_script_render_tool.json +0 -29
  183. package/test_data/dummyllm_script_simplecalc.json +0 -28
  184. package/test_data/dummyllm_script_test_auto_approve.json +0 -81
  185. package/test_data/dummyllm_script_test_simplecalc_addition.json +0 -29
  186. package/test_data/frog.png +0 -0
  187. package/test_data/frog.png.b64 +0 -1
  188. package/test_data/git_message_profile.json +0 -4
  189. package/test_data/git_wip_system.txt +0 -5
  190. package/test_data/image_gen_test_profile.json +0 -5
  191. package/test_data/pr_message_profile.json +0 -4
  192. package/test_data/pr_review_profile.json +0 -4
  193. package/test_data/prompt_simplecalc.txt +0 -1
  194. package/test_data/simplecalc_profile.json +0 -4
  195. package/test_data/sudomcp_import_profile.json +0 -4
  196. package/test_data/test_script_profile.json +0 -8
  197. package/tsconfig.json +0 -13
  198. package/vitest.config.ts +0 -39
  199. /package/dist/agent/src/{chat/utils → agent/tools/contentExtractors}/htmlToText.js +0 -0
@@ -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
- };
@@ -1,123 +0,0 @@
1
- import { OpenAI } from "openai";
2
-
3
- /**
4
- *
5
- * Extension to the OpenAI messages to support custom elements added by other
6
- * providers. These represent the data returned by from provider APIs, which
7
- * may not match our internal structures.
8
- *
9
- */
10
-
11
- export type ChatCompletionContentPartImage =
12
- OpenAI.Chat.Completions.ChatCompletionContentPartImage;
13
-
14
- export type ChatCompletionMessageToolCall =
15
- OpenAI.Chat.Completions.ChatCompletionMessageToolCall;
16
-
17
- // Extend the ChatCompletionMessage type with an `images` value, compatible
18
- // with google/gemini-2.5-flash-image-preview.
19
- export interface ChatCompletionMessage
20
- extends OpenAI.Chat.Completions.ChatCompletionMessage {
21
- images?: ChatCompletionContentPartImage[];
22
- }
23
-
24
- // Extend ChatCompletionChoice with messages containing images
25
- export interface ChatCompletionChoice
26
- extends OpenAI.Chat.Completions.ChatCompletion.Choice {
27
- message: ChatCompletionMessage;
28
- }
29
-
30
- // Extends ChatCompletion with Choices containing images
31
- export interface ChatCompletion extends OpenAI.Chat.Completions.ChatCompletion {
32
- choices: Array<ChatCompletionChoice>;
33
- }
34
-
35
- // TODO: Do we need these? They are input types, generally for convenience.
36
- // Instead, we could just make sure our internal types are compatible with the
37
- // OpenAI definition.
38
-
39
- // Expose for conveinence for now
40
-
41
- export type ChatCompletionAssistantMessageParam =
42
- OpenAI.ChatCompletionAssistantMessageParam;
43
-
44
- export type ChatCompletionContentPart = OpenAI.ChatCompletionContentPart;
45
-
46
- export type ChatCompletionUserMessageParam =
47
- OpenAI.ChatCompletionUserMessageParam;
48
-
49
- // export type ToolMessageParam = OpenAI.ChatCompletionToolMessageParam;
50
-
51
- // openrouter reasoning types
52
-
53
- export type ReasoningEffort = {
54
- effort?: OpenAI.ReasoningEffort;
55
- max_tokens?: never;
56
- };
57
-
58
- export type ReasoningMaxTokens = { effort?: never; max_tokens?: number };
59
-
60
- export type ReasoningExclude = { exclude?: boolean; enabled?: never };
61
-
62
- export type ReasoningEnabled = {
63
- exclude?: never;
64
- enabled?: boolean;
65
- };
66
-
67
- export type Reasoning = (ReasoningEffort | ReasoningMaxTokens) &
68
- (ReasoningExclude | ReasoningEnabled);
69
-
70
- export type ReasoningDetails = {
71
- type: "reasoning.text" | "<unknown>";
72
- text?: string;
73
- signature?: string;
74
- format?: string;
75
- index?: number;
76
- };
77
-
78
- /**
79
- * A (openrouter-specific) stream chunk possibly containing reasoning tokens.
80
- */
81
- export type ChatCompletionChunkChoiceDeltaWithReasoning =
82
- OpenAI.Chat.Completions.ChatCompletionChunk.Choice.Delta & {
83
- reasoning?: string;
84
- reasoning_details?: ReasoningDetails[];
85
- };
86
-
87
- // /**
88
- // * A chat completion message with extra reasoning tokens.
89
- // */
90
- // export interface ChatCompletionMessageWithReasoning
91
- // extends OpenAI.Chat.Completions.ChatCompletionMessage {
92
- // reasoning?: string;
93
- // }
94
-
95
- // Util function to extract reasoning tokens
96
-
97
- export function choiceDeltaExtractReasoning(
98
- delta: ChatCompletionChunkChoiceDeltaWithReasoning
99
- ): string | undefined {
100
- if (delta.reasoning) {
101
- return delta.reasoning;
102
- }
103
-
104
- if (delta.reasoning_details) {
105
- let reasoning = "";
106
- for (const details of delta.reasoning_details) {
107
- if (details.type !== "reasoning.text") {
108
- throw new Error(`unexpected details.type: ${details.type}`);
109
- }
110
- if (details.text) {
111
- if (typeof details.text !== "string") {
112
- throw new Error(
113
- `unexpected typeof details.text: ${typeof details.text}`
114
- );
115
- }
116
- reasoning += details.text;
117
- }
118
- }
119
- return reasoning;
120
- }
121
-
122
- return undefined;
123
- }