@xalia/agent 0.6.4 → 0.6.6

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 (74) hide show
  1. package/dist/agent/src/agent/agent.js +12 -11
  2. package/dist/agent/src/agent/dummyLLM.js +24 -15
  3. package/dist/agent/src/agent/llm.js +0 -22
  4. package/dist/agent/src/agent/mcpServerManager.js +73 -15
  5. package/dist/agent/src/agent/openAI.js +32 -0
  6. package/dist/agent/src/agent/openAILLM.js +25 -1
  7. package/dist/agent/src/agent/openAILLMStreaming.js +8 -3
  8. package/dist/agent/src/agent/sudoMcpServerManager.js +22 -9
  9. package/dist/agent/src/chat/client/chatClient.js +2 -1
  10. package/dist/agent/src/chat/client/sessionClient.js +28 -3
  11. package/dist/agent/src/chat/data/dbSessionFileModels.js +10 -0
  12. package/dist/agent/src/chat/protocol/messages.js +1 -0
  13. package/dist/agent/src/chat/server/chatContextManager.js +4 -4
  14. package/dist/agent/src/chat/server/conversation.js +1 -1
  15. package/dist/agent/src/chat/server/imageGeneratorTools.js +7 -4
  16. package/dist/agent/src/chat/server/openSession.js +85 -12
  17. package/dist/agent/src/chat/server/sessionFileManager.js +17 -6
  18. package/dist/agent/src/chat/server/sessionRegistry.js +1 -1
  19. package/dist/agent/src/chat/server/tools.js +58 -10
  20. package/dist/agent/src/test/agent.test.js +26 -2
  21. package/dist/agent/src/test/chatContextManager.test.js +5 -5
  22. package/dist/agent/src/test/mcpServerManager.test.js +5 -1
  23. package/dist/agent/src/test/testTools.js +5 -2
  24. package/dist/agent/src/tool/chatMain.js +23 -3
  25. package/dist/agent/src/tool/files.js +0 -27
  26. package/package.json +3 -3
  27. package/scripts/test_chat +3 -1
  28. package/src/agent/agent.ts +53 -47
  29. package/src/agent/agentUtils.ts +7 -7
  30. package/src/agent/compressingContextManager.ts +4 -9
  31. package/src/agent/context.ts +28 -37
  32. package/src/agent/dummyLLM.ts +38 -28
  33. package/src/agent/iAgentEventHandler.ts +6 -9
  34. package/src/agent/imageGenLLM.ts +11 -5
  35. package/src/agent/llm.ts +41 -106
  36. package/src/agent/mcpServerManager.ts +145 -29
  37. package/src/agent/openAI.ts +123 -0
  38. package/src/agent/openAILLM.ts +52 -5
  39. package/src/agent/openAILLMStreaming.ts +36 -32
  40. package/src/agent/repeatLLM.ts +5 -6
  41. package/src/agent/sudoMcpServerManager.ts +48 -16
  42. package/src/agent/tools.ts +3 -5
  43. package/src/chat/client/chatClient.ts +3 -1
  44. package/src/chat/client/sessionClient.ts +47 -7
  45. package/src/chat/data/dataModels.ts +3 -3
  46. package/src/chat/data/dbSessionFileModels.ts +22 -0
  47. package/src/chat/protocol/messages.ts +39 -13
  48. package/src/chat/server/chatContextManager.ts +20 -24
  49. package/src/chat/server/conversation.ts +10 -10
  50. package/src/chat/server/imageGeneratorTools.ts +18 -9
  51. package/src/chat/server/openSession.ts +111 -22
  52. package/src/chat/server/sessionFileManager.ts +33 -10
  53. package/src/chat/server/sessionRegistry.ts +1 -1
  54. package/src/chat/server/tools.ts +77 -18
  55. package/src/chat/utils/approvalManager.ts +2 -2
  56. package/src/test/agent.test.ts +56 -31
  57. package/src/test/approvalManager.test.ts +2 -2
  58. package/src/test/chatContextManager.test.ts +11 -14
  59. package/src/test/compressingContextManager.test.ts +3 -3
  60. package/src/test/context.test.ts +3 -3
  61. package/src/test/conversation.test.ts +7 -7
  62. package/src/test/dbSessionMessages.test.ts +3 -3
  63. package/src/test/mcpServerManager.test.ts +10 -1
  64. package/src/test/testTools.ts +44 -33
  65. package/src/tool/agentChat.ts +10 -8
  66. package/src/tool/agentMain.ts +2 -2
  67. package/src/tool/chatMain.ts +38 -6
  68. package/src/tool/commandPrompt.ts +2 -4
  69. package/src/tool/files.ts +0 -34
  70. package/test_data/dummyllm_script_image_gen.json +27 -17
  71. package/test_data/dummyllm_script_invoke_image_gen_tool.json +9 -2
  72. package/test_data/dummyllm_script_render_tool.json +29 -0
  73. package/test_data/dummyllm_script_test_auto_approve.json +81 -0
  74. package/test_data/dummyllm_script_test_simplecalc_addition.json +29 -0
@@ -4,14 +4,14 @@ exports.Agent = exports.DEFAULT_LLM_URL = exports.AgentProfile = void 0;
4
4
  exports.createUserMessage = createUserMessage;
5
5
  exports.createUserMessageEnsure = createUserMessageEnsure;
6
6
  exports.completionToAssistantMessageParam = completionToAssistantMessageParam;
7
- const mcpServerManager_1 = require("./mcpServerManager");
8
7
  const assert_1 = require("assert");
9
- const sdk_1 = require("@xalia/xmcp/sdk");
10
- var sdk_2 = require("@xalia/xmcp/sdk");
11
- Object.defineProperty(exports, "AgentProfile", { enumerable: true, get: function () { return sdk_2.AgentProfile; } });
8
+ var sdk_1 = require("@xalia/xmcp/sdk");
9
+ Object.defineProperty(exports, "AgentProfile", { enumerable: true, get: function () { return sdk_1.AgentProfile; } });
10
+ const sdk_2 = require("@xalia/xmcp/sdk");
11
+ const mcpServerManager_1 = require("./mcpServerManager");
12
12
  exports.DEFAULT_LLM_URL = "http://localhost:5001/v1";
13
13
  const MAX_TOOL_CALL_RESPONSE_LENGTH = 4000;
14
- const logger = (0, sdk_1.getLogger)();
14
+ const logger = (0, sdk_2.getLogger)();
15
15
  class Agent {
16
16
  constructor(eventHandler, mcpServerManager, llm, contextManager) {
17
17
  /// The full list of tools, ready to pass to the LLM
@@ -31,7 +31,7 @@ class Agent {
31
31
  return this.mcpServerManager.shutdown();
32
32
  }
33
33
  getAgentProfile() {
34
- return new sdk_1.AgentProfile(this.llm.getModel(), this.getSystemPrompt(), this.mcpServerManager.getMcpServerSettings());
34
+ return new sdk_2.AgentProfile(this.llm.getModel(), this.getSystemPrompt(), this.mcpServerManager.getMcpServerSettings());
35
35
  }
36
36
  getConversation() {
37
37
  const llmMessages = this.contextManager.getLLMContext();
@@ -89,10 +89,11 @@ class Agent {
89
89
  role: "tool",
90
90
  tool_call_id: toolCall.id,
91
91
  content: result.response,
92
+ ...(result._meta ? { _meta: result._meta } : {}),
93
+ ...(result.structuredContent
94
+ ? { structuredContent: result.structuredContent }
95
+ : {}),
92
96
  };
93
- if (result.metadata) {
94
- toolResult.metadata = result.metadata;
95
- }
96
97
  context.push(toolResult);
97
98
  // If the tool call requested that its args be redacted, this can be
98
99
  // done now - before the next LLM invocation.
@@ -207,7 +208,7 @@ class Agent {
207
208
  /**
208
209
  * Handle the details of getting approval (if required), invoking the tool
209
210
  * handler, informing the IAgentEventHandler of the result, and returns the
210
- * OpenAI.ChatCompletionToolMessageParam to be used in the conversation.
211
+ * ChatCompletionToolMessageParam to be used in the conversation.
211
212
  */
212
213
  async doToolCall(toolCall) {
213
214
  // If the tool is and "agent" (internal) tool, we can just execute it.
@@ -237,7 +238,7 @@ class Agent {
237
238
  result = { response: "User denied tool request." };
238
239
  }
239
240
  else {
240
- result = { response: await this.mcpServerManager.invoke(tc) };
241
+ result = await this.mcpServerManager.invoke(tc);
241
242
  }
242
243
  logger.debug(`tool call result ${JSON.stringify(result)}`);
243
244
  }
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DummyLLM = void 0;
4
+ // import { OpenAI } from "openai";
4
5
  const assert_1 = require("assert");
5
6
  const sdk_1 = require("@xalia/xmcp/sdk");
6
7
  const logger = (0, sdk_1.getLogger)();
@@ -47,25 +48,33 @@ class DummyLLM {
47
48
  getUrl() {
48
49
  return "";
49
50
  }
50
- async getConversationResponse(messages, _tools, onMessage) {
51
+ async getConversationResponse(messages, _tools, onMessage, onReasoning) {
51
52
  await new Promise((r) => setTimeout(r, 0));
52
53
  (0, assert_1.strict)(this.idx < this.responses.length);
53
54
  this.lastRequest = messages;
54
- const response = this.responses[this.idx++];
55
- if (response.finish_reason === "error") {
56
- throw new Error(response.message);
57
- }
58
- if (onMessage) {
59
- const message = response.message;
60
- void onMessage(message.content || "", true);
55
+ for (;;) {
56
+ const response = this.responses[this.idx++];
57
+ if (response.finish_reason === "error") {
58
+ throw new Error(response.message);
59
+ }
60
+ if (response.finish_reason === "reasoning") {
61
+ if (onReasoning) {
62
+ await onReasoning(response.message);
63
+ }
64
+ continue;
65
+ }
66
+ if (onMessage) {
67
+ const message = response.message;
68
+ void onMessage(message.content || "", true);
69
+ }
70
+ return {
71
+ id: String(this.idx),
72
+ choices: [response],
73
+ created: Date.now(),
74
+ model: "dummyLlmModel",
75
+ object: "chat.completion",
76
+ };
61
77
  }
62
- return {
63
- id: String(this.idx),
64
- choices: [response],
65
- created: Date.now(),
66
- model: "dummyLlmModel",
67
- object: "chat.completion",
68
- };
69
78
  }
70
79
  setModel(_model) {
71
80
  (0, assert_1.strict)(false, "unexpected call to setModel");
@@ -1,29 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.XALIA_APP_HEADER = void 0;
4
- exports.choiceDeltaExtractReasoning = choiceDeltaExtractReasoning;
5
4
  exports.XALIA_APP_HEADER = {
6
5
  "HTTP-Referer": "xalia.ai",
7
6
  "X-Title": "Xalia",
8
7
  };
9
- function choiceDeltaExtractReasoning(delta) {
10
- if (delta.reasoning) {
11
- return delta.reasoning;
12
- }
13
- if (delta.reasoning_details) {
14
- let reasoning = "";
15
- for (const details of delta.reasoning_details) {
16
- if (details.type !== "reasoning.text") {
17
- throw new Error(`unexpected details.type: ${details.type}`);
18
- }
19
- if (details.text) {
20
- if (typeof details.text !== "string") {
21
- throw new Error(`unexpected typeof details.text: ${typeof details.text}`);
22
- }
23
- reasoning += details.text;
24
- }
25
- }
26
- return reasoning;
27
- }
28
- return undefined;
29
- }
@@ -1,38 +1,56 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.McpServerManager = exports.McpServerInfoRW = exports.McpServerInfo = void 0;
4
+ exports.isMcpServerToolCallMetaData = isMcpServerToolCallMetaData;
4
5
  exports.computeQualifiedName = computeQualifiedName;
5
6
  exports.splitQualifiedName = splitQualifiedName;
6
7
  exports.computeOpenAIToolList = computeOpenAIToolList;
7
8
  exports.mcpToolToOpenAITool = mcpToolToOpenAITool;
8
9
  const sse_js_1 = require("@modelcontextprotocol/sdk/client/sse.js");
10
+ const streamableHttp_js_1 = require("@modelcontextprotocol/sdk/client/streamableHttp.js");
9
11
  const index_js_1 = require("@modelcontextprotocol/sdk/client/index.js");
12
+ const sdk_1 = require("@xalia/xmcp/sdk");
10
13
  const tokenAuth_1 = require("./tokenAuth");
11
14
  const assert_1 = require("assert");
12
- const sdk_1 = require("@xalia/xmcp/sdk");
13
15
  const logger = (0, sdk_1.getLogger)();
16
+ const mcpServerToolCallMetaKeys = [
17
+ "xalia/mcpServerName",
18
+ ];
19
+ function isMcpServerToolCallMetaData(meta) {
20
+ return (!!meta &&
21
+ typeof meta === "object" &&
22
+ mcpServerToolCallMetaKeys.every((k) => k in meta));
23
+ }
14
24
  /**
15
25
  * The (read-only) McpServerInfo to expose to external classes. Callers
16
26
  * should not modify this data directly. Only through the McpServerManager
17
27
  * class.
18
28
  */
19
29
  class McpServerInfo {
20
- constructor(tools) {
30
+ constructor(name, tools, resources) {
21
31
  const toolsMap = {};
22
32
  for (const mcpTool of tools) {
23
33
  const toolName = mcpTool.name;
24
34
  toolsMap[toolName] = mcpTool;
25
35
  }
36
+ this.name = name;
26
37
  this.tools = tools;
38
+ this.resources = resources;
27
39
  this.toolsMap = toolsMap;
28
40
  this.enabledToolsMap = new Map();
29
41
  }
42
+ getName() {
43
+ return this.name;
44
+ }
30
45
  getEnabledTools() {
31
46
  return this.enabledToolsMap;
32
47
  }
33
48
  getTools() {
34
49
  return this.tools;
35
50
  }
51
+ getResources() {
52
+ return this.resources;
53
+ }
36
54
  getTool(toolName) {
37
55
  return this.toolsMap[toolName];
38
56
  }
@@ -57,8 +75,9 @@ exports.McpServerInfoRW = McpServerInfoRW;
57
75
  * McpServerManager.
58
76
  */
59
77
  class McpServerInfoInternal extends McpServerInfoRW {
60
- constructor(client, tools) {
61
- super(tools);
78
+ constructor(name, client, tools, resources) {
79
+ super(name, tools, resources);
80
+ logger.debug(`[McpServerInfoInternal] tools: ${JSON.stringify(tools)}`);
62
81
  const callbacks = new Map();
63
82
  for (const mcpTool of tools) {
64
83
  const toolName = mcpTool.name;
@@ -80,7 +99,17 @@ class McpServerInfoInternal extends McpServerInfoRW {
80
99
  (0, assert_1.strict)(typeof content0 === "object");
81
100
  const content0Text = content0.text;
82
101
  (0, assert_1.strict)(typeof content0Text === "string");
83
- return content0Text;
102
+ const meta = (toolResult._meta ||
103
+ {});
104
+ meta["xalia/mcpServerName"] = this.getName();
105
+ (0, assert_1.strict)(isMcpServerToolCallMetaData(meta));
106
+ return {
107
+ response: content0Text,
108
+ _meta: meta,
109
+ ...(toolResult.structuredContent
110
+ ? { structuredContent: toolResult.structuredContent }
111
+ : {}),
112
+ };
84
113
  };
85
114
  callbacks.set(toolName, callback);
86
115
  }
@@ -93,6 +122,13 @@ class McpServerInfoInternal extends McpServerInfoRW {
93
122
  getCallback(toolName) {
94
123
  return this.callbacks.get(toolName);
95
124
  }
125
+ async readResource(uri) {
126
+ const res = await this.client.readResource({
127
+ uri,
128
+ });
129
+ logger.info(`readResource: got: ${JSON.stringify(res)}`);
130
+ return res.contents;
131
+ }
96
132
  }
97
133
  /**
98
134
  * Manage a set of MCP servers, where the tools for each server have an
@@ -121,14 +157,7 @@ class McpServerManager {
121
157
  getMcpServer(mcpServerName) {
122
158
  return this.getMcpServerInternal(mcpServerName);
123
159
  }
124
- async addMcpServerWithSSEUrl(mcpServerName, url, apiKey, tools) {
125
- logger.debug(`Adding mcp server ${mcpServerName}: ${url}`);
126
- const sseTransportOptions = {};
127
- if (apiKey) {
128
- sseTransportOptions.authProvider = new tokenAuth_1.TokenAuth(apiKey);
129
- }
130
- const urlO = new URL(url);
131
- const transport = new sse_js_1.SSEClientTransport(urlO, sseTransportOptions);
160
+ async addMcpServerWithTransport(mcpServerName, transport, tools) {
132
161
  const client = new index_js_1.Client({
133
162
  name: "@xalia/agent",
134
163
  version: "1.0.0",
@@ -144,17 +173,42 @@ class McpServerManager {
144
173
  }
145
174
  await this.addMcpServerWithClient(client, mcpServerName, tools);
146
175
  }
176
+ async addMcpServerWithSSEUrl(mcpServerName, url, apiKey, tools) {
177
+ logger.debug(`Adding mcp server ${mcpServerName}: ${url}`);
178
+ const sseTransportOptions = {};
179
+ if (apiKey) {
180
+ sseTransportOptions.authProvider = new tokenAuth_1.TokenAuth(apiKey);
181
+ }
182
+ const urlO = new URL(url);
183
+ const transport = new sse_js_1.SSEClientTransport(urlO, sseTransportOptions);
184
+ return this.addMcpServerWithTransport(mcpServerName, transport, tools);
185
+ }
186
+ async addMcpServerWithStreamableHTTPUrl(mcpServerName, url, apiKey) {
187
+ logger.debug(`Adding mcp (s-http) server ${mcpServerName}: ${url}`);
188
+ const transportOptions = {};
189
+ if (apiKey) {
190
+ transportOptions.authProvider = new tokenAuth_1.TokenAuth(apiKey);
191
+ }
192
+ const urlO = new URL(url);
193
+ const transport = new streamableHttp_js_1.StreamableHTTPClientTransport(urlO, transportOptions);
194
+ return this.addMcpServerWithTransport(mcpServerName, transport);
195
+ }
147
196
  /**
148
197
  * Add MCP server from an already connected McpClient.
149
198
  */
150
199
  async addMcpServerWithClient(client, mcpServerName, tools) {
151
200
  try {
152
- // TODO; require the tools to be passed in.
201
+ // TODO: require the tools to be passed in.
202
+ const resourcesP = client.listResources().catch((err) => {
203
+ logger.warn(`resources ${mcpServerName}: ${JSON.stringify(err)} ${String(err)}`);
204
+ return { resources: [] };
205
+ });
153
206
  if (!tools) {
154
207
  const mcpTools = await client.listTools();
155
208
  tools = mcpTools.tools;
156
209
  }
157
- this.mcpServers.set(mcpServerName, new McpServerInfoInternal(client, tools));
210
+ const resources = (await resourcesP).resources;
211
+ this.mcpServers.set(mcpServerName, new McpServerInfoInternal(mcpServerName, client, tools, resources));
158
212
  }
159
213
  catch (e) {
160
214
  await client.close();
@@ -231,6 +285,10 @@ class McpServerManager {
231
285
  }
232
286
  return cb(JSON.stringify(toolCall.args));
233
287
  }
288
+ async getResource(serverName, uri) {
289
+ const server = this.getMcpServerInternal(serverName);
290
+ return server.readResource(uri);
291
+ }
234
292
  /**
235
293
  * "Settings" refers to the set of added servers and enabled tools.
236
294
  */
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.choiceDeltaExtractReasoning = choiceDeltaExtractReasoning;
4
+ // /**
5
+ // * A chat completion message with extra reasoning tokens.
6
+ // */
7
+ // export interface ChatCompletionMessageWithReasoning
8
+ // extends OpenAI.Chat.Completions.ChatCompletionMessage {
9
+ // reasoning?: string;
10
+ // }
11
+ // Util function to extract reasoning tokens
12
+ function choiceDeltaExtractReasoning(delta) {
13
+ if (delta.reasoning) {
14
+ return delta.reasoning;
15
+ }
16
+ if (delta.reasoning_details) {
17
+ let reasoning = "";
18
+ for (const details of delta.reasoning_details) {
19
+ if (details.type !== "reasoning.text") {
20
+ throw new Error(`unexpected details.type: ${details.type}`);
21
+ }
22
+ if (details.text) {
23
+ if (typeof details.text !== "string") {
24
+ throw new Error(`unexpected typeof details.text: ${typeof details.text}`);
25
+ }
26
+ reasoning += details.text;
27
+ }
28
+ }
29
+ return reasoning;
30
+ }
31
+ return undefined;
32
+ }
@@ -1,8 +1,32 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.OpenAILLM = void 0;
4
+ const assert_1 = require("assert");
4
5
  const llm_1 = require("./llm");
5
6
  const openai_1 = require("openai");
7
+ function toolCallFromOpenAi(toolCall) {
8
+ (0, assert_1.strict)(toolCall.type === "function");
9
+ return toolCall;
10
+ }
11
+ function messageFromOpenAi(message) {
12
+ return {
13
+ ...message,
14
+ tool_calls: message.tool_calls?.map(toolCallFromOpenAi),
15
+ };
16
+ }
17
+ function choicesFromOpenAI(choice) {
18
+ return {
19
+ ...choice,
20
+ message: messageFromOpenAi(choice.message),
21
+ // tool_calls: choice.tool_calls?.map(toolCallFromOpenAi),
22
+ };
23
+ }
24
+ function completionFromOpenAI(completion) {
25
+ return {
26
+ ...completion,
27
+ choices: completion.choices.map(choicesFromOpenAI),
28
+ };
29
+ }
6
30
  class OpenAILLM {
7
31
  constructor(apiKey, apiUrl, model) {
8
32
  this.openai = new openai_1.OpenAI({
@@ -34,7 +58,7 @@ class OpenAILLM {
34
58
  await onMessage(message.content, true);
35
59
  }
36
60
  }
37
- return completion;
61
+ return completionFromOpenAI(completion);
38
62
  }
39
63
  }
40
64
  exports.OpenAILLM = OpenAILLM;
@@ -7,6 +7,7 @@ const openai_1 = require("openai");
7
7
  const assert_1 = require("assert");
8
8
  const sdk_1 = require("@xalia/xmcp/sdk");
9
9
  const llm_1 = require("./llm");
10
+ const openAI_1 = require("./openAI");
10
11
  const logger = (0, sdk_1.getLogger)();
11
12
  function initialToolCallFunction(deltaFn) {
12
13
  // export interface ChatCompletionChunk.Choice.Delta.ToolCall.Function {
@@ -25,7 +26,8 @@ function initialToolCallFunction(deltaFn) {
25
26
  name: deltaFn?.name || "",
26
27
  };
27
28
  }
28
- function updateToolCallFunction(existingFn, deltaFn // eslint-disable-line
29
+ function updateToolCallFunction(existingFn, // eslint-disable-line
30
+ deltaFn // eslint-disable-line
29
31
  ) {
30
32
  // export interface ChatCompletionChunk.Choice.Delta.ToolCall.Function {
31
33
  // arguments?: string;
@@ -221,7 +223,7 @@ function updateCompletionMessage(message, delta) {
221
223
  message.tool_calls = updateToolCalls(message.tool_calls, t);
222
224
  }
223
225
  }
224
- const reasoning = (0, llm_1.choiceDeltaExtractReasoning)(delta);
226
+ const reasoning = (0, openAI_1.choiceDeltaExtractReasoning)(delta);
225
227
  if (reasoning) {
226
228
  updateReasoning(message, reasoning);
227
229
  }
@@ -355,6 +357,7 @@ function initializeCompletion(chunk) {
355
357
  model: chunk.model,
356
358
  object: "chat.completion",
357
359
  service_tier: chunk.service_tier,
360
+ // eslint-disable-next-line @typescript-eslint/no-deprecated
358
361
  system_fingerprint: chunk.system_fingerprint,
359
362
  usage: chunk.usage ?? undefined,
360
363
  },
@@ -388,7 +391,9 @@ function updateCompletion(completion, chunk) {
388
391
  (0, assert_1.strict)(completion.id === chunk.id);
389
392
  (0, assert_1.strict)(completion.model === chunk.model);
390
393
  completion.service_tier = completion.service_tier || chunk.service_tier;
394
+ // eslint-disable-next-line @typescript-eslint/no-deprecated
391
395
  completion.system_fingerprint =
396
+ // eslint-disable-next-line @typescript-eslint/no-deprecated
392
397
  completion.system_fingerprint || chunk.system_fingerprint;
393
398
  completion.usage = completion.usage || chunk.usage || undefined;
394
399
  return updateCompletionChoices(completion.choices, chunk.choices);
@@ -460,7 +465,7 @@ class OpenAILLMStreaming {
460
465
  if (onReasoning) {
461
466
  const delta = chunk.choices[0]
462
467
  ?.delta;
463
- const reasoning = (0, llm_1.choiceDeltaExtractReasoning)(delta);
468
+ const reasoning = (0, openAI_1.choiceDeltaExtractReasoning)(delta);
464
469
  if (reasoning) {
465
470
  await onReasoning(reasoning);
466
471
  }
@@ -4,6 +4,8 @@ exports.SkillManager = exports.LOCAL_SERVER_URL = void 0;
4
4
  const mcpServerManager_1 = require("./mcpServerManager");
5
5
  const sdk_1 = require("@xalia/xmcp/sdk");
6
6
  const index_js_1 = require("@modelcontextprotocol/sdk/client/index.js");
7
+ const DEVELOPMENT = process.env.DEVELOPMENT === "1";
8
+ const DEV_MCP_SERVER_URL = process.env.DEV_MCP_SERVER_URL || "http://localhost:8000/mcp";
7
9
  const logger = (0, sdk_1.getLogger)();
8
10
  exports.LOCAL_SERVER_URL = "http://localhost:5001";
9
11
  /**
@@ -47,6 +49,10 @@ class SkillManager extends mcpServerManager_1.McpServerManager {
47
49
  const apiClient = new sdk_1.ApiClient(sudoMcpUrl ?? sdk_1.DEFAULT_SERVER_URL, sudoMcpApiKey ?? "dummy_key");
48
50
  // Fetch server list
49
51
  const servers = await apiClient.listServers();
52
+ if (DEVELOPMENT) {
53
+ servers.push(new sdk_1.McpServerBrief("local_dev", "Local Dev Server", "A local mcp server using streamable-HTTP for development use. " +
54
+ `URL: ${DEV_MCP_SERVER_URL}`, false, {}, "", null, null, DEV_MCP_SERVER_URL));
55
+ }
50
56
  const [mcpServers, mcpServersMap] = buildServersList(servers);
51
57
  return new SkillManager(apiClient, mcpServers, mcpServersMap, new Map(), openUrl, authorized_url);
52
58
  }
@@ -126,15 +132,22 @@ class SkillManager extends mcpServerManager_1.McpServerManager {
126
132
  * transport. Validates the server's config schema, if applicable.
127
133
  */
128
134
  async addMcpServer(serverName, enableAll) {
129
- const tools = await this.getServerTools(serverName);
130
- const originalName = this.serverBriefsMap[serverName].originalName;
131
- const mcpserver = await this.apiClient.getDetails(originalName, "run");
132
- const client = new index_js_1.Client({
133
- name: "@xalia/agent",
134
- version: "1.0.0",
135
- });
136
- await connectServer(client, this.apiClient, mcpserver, this.openUrl, this.authorized_url);
137
- await this.addMcpServerWithClient(client, serverName, tools);
135
+ const brief = this.serverBriefsMap[serverName];
136
+ if (brief.url_override) {
137
+ // Assume no api key for now
138
+ await this.addMcpServerWithStreamableHTTPUrl(serverName, brief.url_override);
139
+ }
140
+ else {
141
+ const tools = await this.getServerTools(serverName);
142
+ const originalName = this.serverBriefsMap[serverName].originalName;
143
+ const mcpserver = await this.apiClient.getDetails(originalName, "run");
144
+ const client = new index_js_1.Client({
145
+ name: "@xalia/agent",
146
+ version: "1.0.0",
147
+ });
148
+ await connectServer(client, this.apiClient, mcpserver, this.openUrl, this.authorized_url);
149
+ await this.addMcpServerWithClient(client, serverName, tools);
150
+ }
138
151
  if (enableAll) {
139
152
  this.enableAllTools(serverName);
140
153
  }
@@ -366,7 +366,7 @@ class ChatClient {
366
366
  * @param templateName - the template name
367
367
  * @param teamUuid - the team uuid
368
368
  */
369
- createNewAgent(agentName, templateName, teamUuid) {
369
+ createNewAgent(agentName, templateName, teamUuid, model) {
370
370
  if (this.closed) {
371
371
  throw new Error("ChatClient is closed");
372
372
  }
@@ -376,6 +376,7 @@ class ChatClient {
376
376
  title: agentName,
377
377
  template_name: templateName,
378
378
  team_uuid: teamUuid,
379
+ model,
379
380
  });
380
381
  }
381
382
  catch (error) {
@@ -91,10 +91,10 @@ class RemoteSudoMcpServerManager {
91
91
  tool: toolName,
92
92
  });
93
93
  }
94
- onMcpServerAdded(mcpServerName, tools, enabled_tools) {
94
+ onMcpServerAdded(mcpServerName, tools, enabled_tools, resources) {
95
95
  logger.debug(`[onMcpServerAdded]: ${mcpServerName}, tools: ${JSON.stringify(tools)}` +
96
96
  `, enabled: ${JSON.stringify(enabled_tools)}`);
97
- const mcpServerInfo = new mcpServerManager_1.McpServerInfoRW(tools);
97
+ const mcpServerInfo = new mcpServerManager_1.McpServerInfoRW(mcpServerName, tools, resources);
98
98
  for (const tool of enabled_tools) {
99
99
  mcpServerInfo.enableTool(tool);
100
100
  }
@@ -205,6 +205,29 @@ class SessionClient {
205
205
  paused,
206
206
  });
207
207
  }
208
+ addMcpServerFromUrl(server_name, url) {
209
+ this.sendSessionMessage({
210
+ type: "add_mcp_server_from_url",
211
+ server_name,
212
+ url,
213
+ });
214
+ }
215
+ async getMcpResource(server_name, uri) {
216
+ const client_message_id = (0, uuid_1.v4)();
217
+ const resourceP = this.responseHandler.waitForResponse(client_message_id);
218
+ this.sender.send({
219
+ type: "get_mcp_resource",
220
+ session_id: this.sessionUUID,
221
+ client_message_id,
222
+ server_name,
223
+ uri,
224
+ });
225
+ const resourceMsg = await resourceP;
226
+ if (resourceMsg.type !== "mcp_resource") {
227
+ throw new Error(`unexpected response to resource req: ${JSON.stringify(resourceMsg)}`);
228
+ }
229
+ return resourceMsg.contents;
230
+ }
208
231
  userMessage(msg, imageB64) {
209
232
  (0, assert_1.strict)(msg || imageB64, "Either message or image must be provided");
210
233
  this.sendSessionMessage({ type: "msg", message: msg, imageB64 });
@@ -313,7 +336,7 @@ class SessionClient {
313
336
  // State updates
314
337
  //
315
338
  case "mcp_server_added":
316
- this.smsm.onMcpServerAdded(message.server_name, message.tools, message.enabled_tools);
339
+ this.smsm.onMcpServerAdded(message.server_name, message.tools, message.enabled_tools, message.resources);
317
340
  break;
318
341
  case "mcp_server_removed":
319
342
  this.smsm.onMcpServerRemoved(message.server_name);
@@ -344,6 +367,8 @@ class SessionClient {
344
367
  case "user_removed":
345
368
  this.participants.delete(message.user_uuid);
346
369
  break;
370
+ // Responses to requests which can be awaited
371
+ case "mcp_resource":
347
372
  case "session_shared":
348
373
  this.responseHandler.onMessage(message);
349
374
  break;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.EXTENSION_TO_SESSION_FILE_MIME_TYPE = exports.SESSION_FILE_TEXT_MIME_TYPES = exports.SESSION_FILE_MIME_TYPES = void 0;
4
4
  exports.isSessionFileMimeType = isSessionFileMimeType;
5
5
  exports.isSessionFileTextMimeType = isSessionFileTextMimeType;
6
+ exports.isFileMetaData = isFileMetaData;
6
7
  exports.getSessionFileMimeTypeFromDataUrl = getSessionFileMimeTypeFromDataUrl;
7
8
  exports.createSessionFileDataUrl = createSessionFileDataUrl;
8
9
  const mimeTypes_1 = require("./mimeTypes");
@@ -10,6 +11,7 @@ exports.SESSION_FILE_MIME_TYPES = [
10
11
  ...mimeTypes_1.IMAGE_MIME_TYPES,
11
12
  "text/plain",
12
13
  "text/markdown",
14
+ "text/html",
13
15
  "application/pdf",
14
16
  "image/svg+xml",
15
17
  ];
@@ -32,6 +34,14 @@ exports.EXTENSION_TO_SESSION_FILE_MIME_TYPE = {
32
34
  txt: "text/plain",
33
35
  md: "text/markdown",
34
36
  };
37
+ // Checks that the array of keys matches FileMetaData
38
+ const fileMetaKeys = [
39
+ "xalia/fileUri",
40
+ "xalia/fileMimeType",
41
+ ];
42
+ function isFileMetaData(meta) {
43
+ return (!!meta && typeof meta === "object" && fileMetaKeys.every((k) => k in meta));
44
+ }
35
45
  function getSessionFileMimeTypeFromDataUrl(data_url) {
36
46
  const mimeType = (0, mimeTypes_1.getMimeTypeFromDataUrl)(data_url);
37
47
  if (!isSessionFileMimeType(mimeType)) {
@@ -95,6 +95,7 @@ function isServerSessionScopedMessage(message) {
95
95
  case "approve_tool_call":
96
96
  case "render_html":
97
97
  case "session_shared":
98
+ case "mcp_resource":
98
99
  return true;
99
100
  default: {
100
101
  const _ = msg;
@@ -55,9 +55,9 @@ class ChatContextManager {
55
55
  // IContextManager.getLLMContext
56
56
  getLLMContext() {
57
57
  if (this.fileManagerDescriptionsDirty) {
58
- const filesSummary = (0, sessionFileManager_1.listFilesForLLM)(this.fileManager);
59
- logger.debug(`[ChatContextManager] filemanager summary:\n${filesSummary}`);
60
- this.llmContext.setPromptFragment("file_manager", filesSummary);
58
+ const prompt = (0, sessionFileManager_1.createSessionFilesManagerPrompt)(this.fileManager);
59
+ logger.debug(`[ChatContextManager] filemanager prompt:\n${prompt}`);
60
+ this.llmContext.setPromptFragment("file_manager", prompt);
61
61
  this.fileManagerDescriptionsDirty = false;
62
62
  }
63
63
  return this.llmContext.getLLMContext();
@@ -150,7 +150,7 @@ class ChatContextManager {
150
150
  // Compute the new llm messages
151
151
  const llmUserMessages = [];
152
152
  for (const msg of pendingUserMessages) {
153
- const userMsg = (0, agent_1.createUserMessage)(msg.message, msg.imageB64, msg.user_nickname);
153
+ const userMsg = (0, agent_1.createUserMessage)(msg.message, msg.imageB64, msg.user_uuid);
154
154
  if (userMsg) {
155
155
  llmUserMessages.push(userMsg);
156
156
  }
@@ -193,7 +193,7 @@ function chatToolResultMessageToSessionMessage(chatMessage) {
193
193
  };
194
194
  }
195
195
  function chatUserMessageToSessionMessage(chatMessage) {
196
- const userMsg = (0, agent_1.createUserMessage)(chatMessage.message, chatMessage.imageB64, chatMessage.user_nickname);
196
+ const userMsg = (0, agent_1.createUserMessage)(chatMessage.message, chatMessage.imageB64, chatMessage.user_uuid);
197
197
  (0, assert_1.strict)(userMsg);
198
198
  return {
199
199
  message_idx: chatMessage.message_idx,