@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.
- package/.env.development +1 -0
- package/dist/agent/src/agent/agent.js +100 -77
- package/dist/agent/src/agent/agentUtils.js +21 -16
- package/dist/agent/src/agent/compressingContextManager.js +10 -14
- package/dist/agent/src/agent/context.js +101 -127
- package/dist/agent/src/agent/contextWithWorkspace.js +133 -0
- package/dist/agent/src/agent/imageGenLLM.js +0 -6
- package/dist/agent/src/agent/imageGenerator.js +2 -10
- package/dist/agent/src/agent/openAILLMStreaming.js +5 -2
- package/dist/agent/src/agent/sudoMcpServerManager.js +21 -9
- package/dist/agent/src/chat/client/chatClient.js +35 -2
- package/dist/agent/src/chat/client/connection.js +6 -1
- package/dist/agent/src/chat/client/sessionClient.js +0 -7
- package/dist/agent/src/chat/data/dbSessionMessages.js +11 -0
- package/dist/agent/src/chat/protocol/messages.js +4 -0
- package/dist/agent/src/chat/server/chatContextManager.js +149 -139
- package/dist/agent/src/chat/server/imageGeneratorTools.js +19 -8
- package/dist/agent/src/chat/server/openAIRouterLLM.js +114 -0
- package/dist/agent/src/chat/server/openSession.js +57 -58
- package/dist/agent/src/chat/server/server.js +6 -2
- package/dist/agent/src/chat/server/sessionRegistry.js +65 -6
- package/dist/agent/src/chat/server/sessionRegistry.test.js +1 -1
- package/dist/agent/src/chat/server/tools.js +52 -17
- package/dist/agent/src/test/chatContextManager.test.js +31 -29
- package/dist/agent/src/test/clientServerConnection.test.js +1 -2
- package/dist/agent/src/test/compressingContextManager.test.js +22 -36
- package/dist/agent/src/test/context.test.js +55 -17
- package/dist/agent/src/test/contextTestTools.js +87 -0
- package/dist/agent/src/tool/chatMain.js +22 -8
- package/package.json +1 -1
- package/scripts/test_chat +3 -0
- package/src/agent/agent.ts +170 -125
- package/src/agent/agentUtils.ts +31 -20
- package/src/agent/compressingContextManager.ts +13 -44
- package/src/agent/context.ts +165 -159
- package/src/agent/contextWithWorkspace.ts +162 -0
- package/src/agent/imageGenLLM.ts +0 -8
- package/src/agent/imageGenerator.ts +3 -18
- package/src/agent/openAILLMStreaming.ts +20 -3
- package/src/agent/sudoMcpServerManager.ts +41 -20
- package/src/chat/client/chatClient.ts +47 -3
- package/src/chat/client/connection.ts +11 -1
- package/src/chat/client/sessionClient.ts +0 -8
- package/src/chat/data/dataModels.ts +6 -0
- package/src/chat/data/dbSessionMessages.ts +34 -0
- package/src/chat/protocol/messages.ts +35 -8
- package/src/chat/server/chatContextManager.ts +210 -197
- package/src/chat/server/connectionManager.ts +1 -1
- package/src/chat/server/imageGeneratorTools.ts +31 -18
- package/src/chat/server/openAIRouterLLM.ts +171 -0
- package/src/chat/server/openSession.ts +87 -100
- package/src/chat/server/server.ts +6 -2
- package/src/chat/server/sessionFileManager.ts +5 -5
- package/src/chat/server/sessionRegistry.test.ts +0 -1
- package/src/chat/server/sessionRegistry.ts +100 -4
- package/src/chat/server/tools.ts +73 -35
- package/src/test/agent.test.ts +8 -7
- package/src/test/chatContextManager.test.ts +42 -37
- package/src/test/clientServerConnection.test.ts +0 -2
- package/src/test/compressingContextManager.test.ts +29 -34
- package/src/test/context.test.ts +59 -15
- package/src/test/contextTestTools.ts +95 -0
- 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
|
-
|
|
10
|
-
|
|
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
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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.
|
|
44
|
-
|
|
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.
|
|
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
|
|
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
|
});
|
package/src/test/context.test.ts
CHANGED
|
@@ -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/
|
|
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("
|
|
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
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
//
|
|
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.
|
|
38
|
-
|
|
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.
|
|
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
|
+
}
|
package/src/tool/chatMain.ts
CHANGED
|
@@ -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,
|
|
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
|
|
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
|
|
306
|
-
|
|
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
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
) {
|
|
400
|
-
|
|
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(
|