@xalia/agent 0.6.8 → 0.6.9

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 (63) hide show
  1. package/.env.development +1 -0
  2. package/dist/agent/src/agent/agent.js +100 -77
  3. package/dist/agent/src/agent/agentUtils.js +21 -16
  4. package/dist/agent/src/agent/compressingContextManager.js +10 -14
  5. package/dist/agent/src/agent/context.js +101 -127
  6. package/dist/agent/src/agent/contextWithWorkspace.js +133 -0
  7. package/dist/agent/src/agent/imageGenLLM.js +0 -6
  8. package/dist/agent/src/agent/imageGenerator.js +2 -10
  9. package/dist/agent/src/agent/openAILLMStreaming.js +5 -2
  10. package/dist/agent/src/agent/sudoMcpServerManager.js +21 -9
  11. package/dist/agent/src/chat/client/chatClient.js +35 -2
  12. package/dist/agent/src/chat/client/connection.js +6 -1
  13. package/dist/agent/src/chat/client/sessionClient.js +0 -7
  14. package/dist/agent/src/chat/data/dbSessionMessages.js +11 -0
  15. package/dist/agent/src/chat/protocol/messages.js +4 -0
  16. package/dist/agent/src/chat/server/chatContextManager.js +149 -139
  17. package/dist/agent/src/chat/server/imageGeneratorTools.js +19 -8
  18. package/dist/agent/src/chat/server/openAIRouterLLM.js +114 -0
  19. package/dist/agent/src/chat/server/openSession.js +57 -58
  20. package/dist/agent/src/chat/server/server.js +6 -2
  21. package/dist/agent/src/chat/server/sessionRegistry.js +65 -6
  22. package/dist/agent/src/chat/server/sessionRegistry.test.js +1 -1
  23. package/dist/agent/src/chat/server/tools.js +52 -17
  24. package/dist/agent/src/test/chatContextManager.test.js +31 -29
  25. package/dist/agent/src/test/clientServerConnection.test.js +1 -2
  26. package/dist/agent/src/test/compressingContextManager.test.js +22 -36
  27. package/dist/agent/src/test/context.test.js +55 -17
  28. package/dist/agent/src/test/contextTestTools.js +87 -0
  29. package/dist/agent/src/tool/chatMain.js +22 -8
  30. package/package.json +1 -1
  31. package/scripts/test_chat +3 -0
  32. package/src/agent/agent.ts +170 -125
  33. package/src/agent/agentUtils.ts +31 -20
  34. package/src/agent/compressingContextManager.ts +13 -44
  35. package/src/agent/context.ts +165 -159
  36. package/src/agent/contextWithWorkspace.ts +162 -0
  37. package/src/agent/imageGenLLM.ts +0 -8
  38. package/src/agent/imageGenerator.ts +3 -18
  39. package/src/agent/openAILLMStreaming.ts +20 -3
  40. package/src/agent/sudoMcpServerManager.ts +41 -20
  41. package/src/chat/client/chatClient.ts +47 -3
  42. package/src/chat/client/connection.ts +11 -1
  43. package/src/chat/client/sessionClient.ts +0 -8
  44. package/src/chat/data/dataModels.ts +6 -0
  45. package/src/chat/data/dbSessionMessages.ts +34 -0
  46. package/src/chat/protocol/messages.ts +35 -8
  47. package/src/chat/server/chatContextManager.ts +210 -197
  48. package/src/chat/server/connectionManager.ts +1 -1
  49. package/src/chat/server/imageGeneratorTools.ts +31 -18
  50. package/src/chat/server/openAIRouterLLM.ts +171 -0
  51. package/src/chat/server/openSession.ts +87 -100
  52. package/src/chat/server/server.ts +6 -2
  53. package/src/chat/server/sessionFileManager.ts +5 -5
  54. package/src/chat/server/sessionRegistry.test.ts +0 -1
  55. package/src/chat/server/sessionRegistry.ts +100 -4
  56. package/src/chat/server/tools.ts +73 -35
  57. package/src/test/agent.test.ts +8 -7
  58. package/src/test/chatContextManager.test.ts +42 -37
  59. package/src/test/clientServerConnection.test.ts +0 -2
  60. package/src/test/compressingContextManager.test.ts +29 -34
  61. package/src/test/context.test.ts +59 -15
  62. package/src/test/contextTestTools.ts +95 -0
  63. package/src/tool/chatMain.ts +26 -12
@@ -4,50 +4,45 @@ import {
4
4
  CompressingContextManager,
5
5
  createCheckpointMessage,
6
6
  } from "../agent/compressingContextManager";
7
- import { MessageParam } from "../agent/llm";
8
-
9
- const MESSAGES: MessageParam[] = [
10
- { role: "user", content: "msg200" },
11
- { role: "assistant", content: "msg300" },
12
- { role: "user", content: "msg400" },
13
- {
14
- role: "assistant",
15
- content: "msg500",
16
- tool_calls: [
17
- {
18
- id: "tool_call_0",
19
- type: "function",
20
- function: { name: "tool1", arguments: "" },
21
- },
22
- ],
23
- },
24
- {
25
- role: "tool",
26
- content: "msg501",
27
- tool_call_id: "tool_call_0",
28
- },
29
- { role: "assistant", content: "msg502" },
30
- ];
7
+ import { ILLM, MessageParam, UserMessageParam } from "../agent/llm";
8
+ import { MESSAGES, basicContextTest } from "./contextTestTools";
9
+ import { createLLM } from "../agent/agentUtils";
10
+ import { IPlatform } from "../agent/iplatform";
31
11
 
32
12
  describe("Compression context", () => {
33
- it("context compression", async function () {
13
+ it("context compression (basic)", async function () {
34
14
  const ccm = new CompressingContextManager(
35
15
  "sys_prompt",
36
16
  [],
37
- "", // llmUrl
38
- "repeat", // llmModel
39
- "" // llmApiKey
17
+ () => undefined as unknown as Promise<ILLM> // getLLM
18
+ );
19
+ await basicContextTest(ccm);
20
+ });
21
+
22
+ it("context compression", async function () {
23
+ const llm = await createLLM(
24
+ "",
25
+ "",
26
+ "repeat",
27
+ false,
28
+ undefined as unknown as IPlatform
29
+ );
30
+ const ccm = new CompressingContextManager("sys_prompt", [], () =>
31
+ Promise.resolve(llm)
40
32
  );
41
33
 
42
34
  // Add first 2 messages
43
- ccm.addMessages(MESSAGES.slice(0, 2));
44
- ccm.commit();
35
+ let tx = await ccm.startTx([MESSAGES[0] as UserMessageParam]);
36
+ tx.addMessage(MESSAGES[1]);
37
+ await ccm.commit(tx);
45
38
 
46
39
  // Start the compression
47
40
  const compressionP = ccm.compress();
48
41
 
49
42
  // Add more messages and update system prompt
50
- ccm.addMessages(MESSAGES.slice(2));
43
+ tx = await ccm.startTx([MESSAGES[2] as UserMessageParam]);
44
+ tx.addMessages(MESSAGES.slice(3));
45
+ await ccm.commit(tx);
51
46
  ccm.setAgentPrompt("New system prompt");
52
47
 
53
48
  // Wait for compression to complete, then get the new context
@@ -74,9 +69,9 @@ describe("Compression context", () => {
74
69
  expect(summary).eql(expectSummary);
75
70
  expect(context).eql(expectContext);
76
71
 
77
- // Pending messages shoudl still be intact
72
+ // // Pending messages should still be intact
78
73
 
79
- const pending = ccm.getPending();
80
- expect(pending).eql(MESSAGES.slice(2));
74
+ // const pending = ccm.getPending();
75
+ // expect(pending).eql(MESSAGES.slice(2));
81
76
  });
82
77
  });
@@ -1,10 +1,12 @@
1
1
  import { expect } from "vitest";
2
2
  import { strict as assert } from "assert";
3
3
 
4
- import { ContextManagerWithWorkspace } from "../agent/context";
4
+ import { ContextManagerWithWorkspace } from "../agent/contextWithWorkspace";
5
5
  import { createUserMessage } from "../agent/agent";
6
- import { MessageParam } from "../agent/llm";
6
+ import { MessageParam, UserMessageParam } from "../agent/llm";
7
7
  import { SystemPromptProvider } from "../agent/promptProvider";
8
+ import { ContextManager } from "../agent/context";
9
+ import { basicContextTest } from "./contextTestTools";
8
10
 
9
11
  describe("ContextManagerWithWorkspace", () => {
10
12
  const msgs: MessageParam[] = [
@@ -14,34 +16,61 @@ describe("ContextManagerWithWorkspace", () => {
14
16
  { role: "assistant", content: "message D" },
15
17
  ];
16
18
 
17
- it("should correctly manage messages", function () {
19
+ it("context (basic)", async function () {
20
+ const cm = new ContextManager("sys_prompt", []);
21
+ await basicContextTest(cm);
22
+ });
23
+
24
+ it("context with workspace (basic)", async function () {
25
+ const cm = new ContextManagerWithWorkspace("sys_prompt", []);
26
+ await basicContextTest(cm);
27
+ });
28
+
29
+ it("should correctly manage messages", async function () {
18
30
  const cm = new ContextManagerWithWorkspace("sys_msg", msgs.slice(0, 2));
19
31
 
20
- // set workspace and add new messages
32
+ // set workspace and add new user and assistant messages
21
33
  cm.setWorkspace({ role: "user", content: "workspace1" });
22
- cm.addMessages(msgs.slice(2));
23
34
 
24
- // context with workspace
25
- const ctx1 = cm.getLLMContext();
26
- expect(ctx1).eql([
35
+ const ctxTx1 = await cm.startTx([msgs[2] as UserMessageParam]);
36
+ ctxTx1.addMessage(msgs[3]);
37
+
38
+ // context writer. workspace should be before first assistant message
39
+ expect(ctxTx1.getLLMContext()).eql([
27
40
  { role: "system", content: "sys_msg" },
28
- ...msgs,
41
+ ...msgs.slice(0, 3),
42
+ { role: "user", content: "workspace1" },
43
+ ...msgs.slice(3),
44
+ ]);
45
+
46
+ // original cm unchanged
47
+ expect(cm.getLLMContext()).eql([
48
+ { role: "system", content: "sys_msg" },
49
+ ...msgs.slice(0, 2),
29
50
  { role: "user", content: "workspace1" },
30
51
  ]);
31
52
 
32
- // context with new message and workspace
53
+ // Commit
54
+ await cm.commit(ctxTx1);
55
+
56
+ // write new messages
33
57
  const lastMsg: MessageParam = {
34
58
  role: "user",
35
59
  content: "hello",
36
60
  };
37
- cm.addMessage(lastMsg);
38
- const ctx2 = cm.getLLMContext();
39
- expect(ctx2).eql([
61
+ const ctxTx2 = await cm.startTx([lastMsg]);
62
+ expect(ctxTx2.getLLMContext()).eql([
40
63
  { role: "system", content: "sys_msg" },
41
64
  ...msgs,
42
65
  lastMsg,
43
66
  { role: "user", content: "workspace1" },
44
67
  ]);
68
+ expect(cm.getLLMContext()).eql([
69
+ { role: "system", content: "sys_msg" },
70
+ ...msgs,
71
+ { role: "user", content: "workspace1" },
72
+ ]);
73
+ await cm.commit(ctxTx2);
45
74
 
46
75
  // context without workspace
47
76
  cm.setWorkspace(undefined);
@@ -72,7 +101,7 @@ describe("ContextManagerWithWorkspace", () => {
72
101
  expect(llmContext[0].content).eql("global\nagent_prompt\nFRAG1");
73
102
  });
74
103
 
75
- it("handles rich workspace messages", function () {
104
+ it("handles rich workspace messages", async function () {
76
105
  const cm = new ContextManagerWithWorkspace("sys_msg", msgs.slice(0, 2));
77
106
 
78
107
  expect(cm.getLLMContext()).eql([
@@ -97,7 +126,22 @@ describe("ContextManagerWithWorkspace", () => {
97
126
  wsMsg,
98
127
  ]);
99
128
 
100
- cm.addMessages(msgs.slice(2));
129
+ const ctxTx = await cm.startTx([msgs[2] as UserMessageParam]);
130
+ expect(ctxTx.getLLMContext()).eql([
131
+ { role: "system", content: "sys_msg" },
132
+ ...msgs.slice(0, 3),
133
+ wsMsg,
134
+ ]);
135
+ ctxTx.addMessage(msgs[3]);
136
+ expect(ctxTx.getLLMContext()).eql([
137
+ { role: "system", content: "sys_msg" },
138
+ ...msgs.slice(0, 3),
139
+ wsMsg,
140
+ msgs[3],
141
+ ]);
142
+ expect(ctxTx.newMessages()).eql(msgs.slice(2, 4));
143
+
144
+ await cm.commit(ctxTx);
101
145
 
102
146
  // context with workspace
103
147
  const ctx1 = cm.getLLMContext();
@@ -0,0 +1,95 @@
1
+ import { expect } from "vitest";
2
+
3
+ import { IContextManager } from "../agent/context";
4
+ import { MessageParam, UserMessageParam } from "../agent/llm";
5
+
6
+ export const MESSAGES: MessageParam[] = [
7
+ { role: "user", content: "msg200" },
8
+ { role: "assistant", content: "msg300" },
9
+ { role: "user", content: "msg400" },
10
+ {
11
+ role: "assistant",
12
+ content: "msg500",
13
+ tool_calls: [
14
+ {
15
+ id: "tool_call_0",
16
+ type: "function",
17
+ function: { name: "tool1", arguments: "" },
18
+ },
19
+ ],
20
+ },
21
+ {
22
+ role: "tool",
23
+ content: "msg501",
24
+ tool_call_id: "tool_call_0",
25
+ },
26
+ { role: "assistant", content: "msg502" },
27
+ ];
28
+
29
+ export async function basicContextTest(cm: IContextManager) {
30
+ expect(cm.getAgentPrompt()).eql("sys_prompt");
31
+
32
+ // Add first 2 messages
33
+ let tx = await cm.startTx([MESSAGES[0] as UserMessageParam]);
34
+ tx.addMessage(MESSAGES[1]);
35
+ expect(tx.getLLMContext()).eql([
36
+ {
37
+ role: "system",
38
+ content: "sys_prompt",
39
+ },
40
+ MESSAGES[0],
41
+ MESSAGES[1],
42
+ ]);
43
+ await cm.commit(tx);
44
+
45
+ // Add more messages
46
+ tx = await cm.startTx([MESSAGES[2] as UserMessageParam]);
47
+ expect(tx.getLLMContext()).eql([
48
+ {
49
+ role: "system",
50
+ content: "sys_prompt",
51
+ },
52
+ MESSAGES[0],
53
+ MESSAGES[1],
54
+ MESSAGES[2],
55
+ ]);
56
+ tx.addMessages(MESSAGES.slice(3));
57
+ expect(tx.getLLMContext()).eql([
58
+ {
59
+ role: "system",
60
+ content: "sys_prompt",
61
+ },
62
+ MESSAGES[0],
63
+ MESSAGES[1],
64
+ MESSAGES[2],
65
+ MESSAGES[3],
66
+ MESSAGES[4],
67
+ MESSAGES[5],
68
+ ]);
69
+ await cm.commit(tx);
70
+
71
+ // Update system prompt
72
+ cm.setAgentPrompt("New system prompt");
73
+
74
+ // Wait for compression to complete, then get the new context
75
+ const context = cm.getLLMContext();
76
+
77
+ // Expect
78
+ // - callback happened
79
+ // - new context is as expected
80
+
81
+ const expectContext: MessageParam[] = [
82
+ {
83
+ role: "system",
84
+ content: "New system prompt",
85
+ },
86
+ MESSAGES[0], // 400
87
+ MESSAGES[1], // 500
88
+ MESSAGES[2], // 400
89
+ MESSAGES[3], // 500
90
+ MESSAGES[4], // 501
91
+ MESSAGES[5], // 502
92
+ ];
93
+
94
+ expect(context).eql(expectContext);
95
+ }
@@ -121,7 +121,6 @@ const server = command({
121
121
  }),
122
122
  supabaseUrl: options.supabaseUrl,
123
123
  supabaseKey: options.supabaseKey,
124
- llmUrl: options.llmUrl,
125
124
  xmcpUrl: options.xmcpUrl,
126
125
  pidFile: options.pidFile,
127
126
  },
@@ -130,7 +129,6 @@ const server = command({
130
129
  port,
131
130
  supabaseUrl,
132
131
  supabaseKey,
133
- llmUrl,
134
132
  xmcpUrl,
135
133
  pidFile,
136
134
  }): Promise<void> => {
@@ -138,7 +136,7 @@ const server = command({
138
136
  fs.writeFileSync(pidFile, process.pid.toString());
139
137
  }
140
138
 
141
- void runServer(port, supabaseUrl, supabaseKey, llmUrl, xmcpUrl);
139
+ void runServer(port, supabaseUrl, supabaseKey, xmcpUrl);
142
140
  },
143
141
  });
144
142
 
@@ -224,7 +222,9 @@ const client = command({
224
222
  ${chalk.yellow("/get-file <name>")} Get file contents
225
223
  ${chalk.yellow("/share-session <file>")} Share and write access token
226
224
  ${chalk.yellow("/pause-agent <0|1>")} Pause (or unpause) the agent
227
- ${chalk.yellow("/add-mcp-server-url <server-name> <url>")} Add MCP server
225
+ ${chalk.yellow("/add-custom-mcp-server <server-name> <url>")} Add MCP server
226
+ ${chalk.yellow("/remove-custom-mcp-server <server-name>")} Remove MCP server
227
+ ${chalk.yellow("/list-custom-mcp-servers")} list custom mcp servers
228
228
  ${chalk.yellow("/get-resource <server-name> <uri>")} get MCP server resource
229
229
  `;
230
230
 
@@ -302,8 +302,14 @@ const client = command({
302
302
  case "pause-agent":
303
303
  pauseAgent(sessionClient, cmds[1]);
304
304
  break;
305
- case "add-mcp-server-url":
306
- addMcpServerFromUrl(sessionClient, cmds[1], cmds[2]);
305
+ case "add-custom-mcp-server":
306
+ addCustomMcpServer(client, cmds[1], cmds[2]);
307
+ break;
308
+ case "remove-custom-mcp-server":
309
+ removeCustomMcpServer(client, cmds[1]);
310
+ break;
311
+ case "list-custom-mcp-servers":
312
+ listCustomMcpServers(client);
307
313
  break;
308
314
  case "get-resource":
309
315
  await getResource(sessionClient, cmds[1], cmds[2]);
@@ -392,12 +398,20 @@ function pauseAgent(sessionClient: SessionClient, pause: string) {
392
398
  sessionClient.setAgentPaused(!!parseInt(pause));
393
399
  }
394
400
 
395
- function addMcpServerFromUrl(
396
- sessionClient: SessionClient,
397
- name: string,
398
- url: string
399
- ) {
400
- sessionClient.addMcpServerFromUrl(name, url);
401
+ function addCustomMcpServer(chatClient: ChatClient, name: string, url: string) {
402
+ chatClient.addCustomMcpServer(name, "Temporary description", url);
403
+ }
404
+
405
+ function removeCustomMcpServer(chatClient: ChatClient, name: string) {
406
+ chatClient.removeCustomMcpServer(name);
407
+ }
408
+
409
+ function listCustomMcpServers(chatClient: ChatClient) {
410
+ const customMcpServers: Record<string, string> =
411
+ chatClient.getCustomMcpServers();
412
+ console.log(
413
+ `Custom mcp serevrs:\n${JSON.stringify(customMcpServers, undefined, 2)}`
414
+ );
401
415
  }
402
416
 
403
417
  async function getResource(