@xalia/agent 0.6.0 → 0.6.2
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/dist/agent/src/agent/agent.js +103 -54
- package/dist/agent/src/agent/agentUtils.js +22 -21
- package/dist/agent/src/agent/compressingContextManager.js +3 -2
- package/dist/agent/src/agent/dummyLLM.js +1 -3
- package/dist/agent/src/agent/imageGenLLM.js +67 -0
- package/dist/agent/src/agent/imageGenerator.js +43 -0
- package/dist/agent/src/agent/llm.js +27 -0
- package/dist/agent/src/agent/mcpServerManager.js +18 -6
- package/dist/agent/src/agent/nullAgentEventHandler.js +6 -0
- package/dist/agent/src/agent/openAILLM.js +3 -3
- package/dist/agent/src/agent/openAILLMStreaming.js +41 -6
- package/dist/agent/src/chat/client/chatClient.js +84 -13
- package/dist/agent/src/chat/client/sessionClient.js +47 -6
- package/dist/agent/src/chat/client/sessionFiles.js +102 -0
- package/dist/agent/src/chat/data/apiKeyManager.js +38 -7
- package/dist/agent/src/chat/data/database.js +83 -70
- package/dist/agent/src/chat/data/dbSessionFileModels.js +49 -0
- package/dist/agent/src/chat/data/dbSessionFiles.js +76 -0
- package/dist/agent/src/chat/data/dbSessionMessages.js +57 -0
- package/dist/agent/src/chat/data/mimeTypes.js +44 -0
- package/dist/agent/src/chat/protocol/messages.js +21 -0
- package/dist/agent/src/chat/server/chatContextManager.js +14 -7
- package/dist/agent/src/chat/server/connectionManager.js +14 -36
- package/dist/agent/src/chat/server/connectionManager.test.js +2 -16
- package/dist/agent/src/chat/server/conversation.js +69 -45
- package/dist/agent/src/chat/server/imageGeneratorTools.js +111 -0
- package/dist/agent/src/chat/server/openSession.js +205 -43
- package/dist/agent/src/chat/server/server.js +5 -8
- package/dist/agent/src/chat/server/sessionFileManager.js +171 -38
- package/dist/agent/src/chat/server/sessionRegistry.js +199 -32
- package/dist/agent/src/chat/server/test-utils/mockFactories.js +12 -11
- package/dist/agent/src/chat/server/tools.js +27 -6
- package/dist/agent/src/chat/utils/multiAsyncQueue.js +9 -1
- package/dist/agent/src/test/agent.test.js +15 -11
- package/dist/agent/src/test/chatContextManager.test.js +4 -0
- package/dist/agent/src/test/clientServerConnection.test.js +2 -2
- package/dist/agent/src/test/db.test.js +33 -70
- package/dist/agent/src/test/dbSessionFiles.test.js +179 -0
- package/dist/agent/src/test/dbSessionMessages.test.js +67 -0
- package/dist/agent/src/test/dbTestTools.js +6 -5
- package/dist/agent/src/test/imageLoad.test.js +1 -1
- package/dist/agent/src/test/mcpServerManager.test.js +1 -1
- package/dist/agent/src/test/multiAsyncQueue.test.js +50 -0
- package/dist/agent/src/test/testTools.js +12 -0
- package/dist/agent/src/tool/agentChat.js +25 -6
- package/dist/agent/src/tool/agentMain.js +1 -1
- package/dist/agent/src/tool/chatMain.js +113 -4
- package/dist/agent/src/tool/commandPrompt.js +7 -3
- package/dist/agent/src/tool/files.js +23 -15
- package/dist/agent/src/tool/options.js +2 -2
- package/package.json +1 -1
- package/scripts/test_chat +124 -66
- package/src/agent/agent.ts +145 -38
- package/src/agent/agentUtils.ts +27 -21
- package/src/agent/compressingContextManager.ts +5 -4
- package/src/agent/context.ts +1 -1
- package/src/agent/dummyLLM.ts +1 -3
- package/src/agent/iAgentEventHandler.ts +15 -2
- package/src/agent/imageGenLLM.ts +99 -0
- package/src/agent/imageGenerator.ts +60 -0
- package/src/agent/llm.ts +128 -4
- package/src/agent/mcpServerManager.ts +26 -7
- package/src/agent/nullAgentEventHandler.ts +6 -0
- package/src/agent/openAILLM.ts +3 -8
- package/src/agent/openAILLMStreaming.ts +60 -14
- package/src/chat/client/chatClient.ts +119 -14
- package/src/chat/client/sessionClient.ts +75 -9
- package/src/chat/client/sessionFiles.ts +145 -0
- package/src/chat/data/apiKeyManager.ts +55 -7
- package/src/chat/data/dataModels.ts +16 -7
- package/src/chat/data/database.ts +107 -92
- package/src/chat/data/dbSessionFileModels.ts +91 -0
- package/src/chat/data/dbSessionFiles.ts +99 -0
- package/src/chat/data/dbSessionMessages.ts +68 -0
- package/src/chat/data/mimeTypes.ts +58 -0
- package/src/chat/protocol/messages.ts +127 -13
- package/src/chat/server/chatContextManager.ts +36 -13
- package/src/chat/server/connectionManager.test.ts +1 -22
- package/src/chat/server/connectionManager.ts +18 -53
- package/src/chat/server/conversation.ts +96 -57
- package/src/chat/server/imageGeneratorTools.ts +138 -0
- package/src/chat/server/openSession.ts +287 -49
- package/src/chat/server/server.ts +5 -11
- package/src/chat/server/sessionFileManager.ts +223 -63
- package/src/chat/server/sessionRegistry.ts +285 -41
- package/src/chat/server/test-utils/mockFactories.ts +13 -13
- package/src/chat/server/tools.ts +43 -8
- package/src/chat/utils/agentSessionMap.ts +2 -2
- package/src/chat/utils/multiAsyncQueue.ts +11 -1
- package/src/test/agent.test.ts +23 -14
- package/src/test/chatContextManager.test.ts +7 -2
- package/src/test/clientServerConnection.test.ts +3 -3
- package/src/test/compressingContextManager.test.ts +1 -1
- package/src/test/context.test.ts +2 -1
- package/src/test/conversation.test.ts +1 -1
- package/src/test/db.test.ts +41 -83
- package/src/test/dbSessionFiles.test.ts +258 -0
- package/src/test/dbSessionMessages.test.ts +85 -0
- package/src/test/dbTestTools.ts +9 -5
- package/src/test/imageLoad.test.ts +2 -2
- package/src/test/mcpServerManager.test.ts +3 -1
- package/src/test/multiAsyncQueue.test.ts +58 -0
- package/src/test/testTools.ts +15 -1
- package/src/tool/agentChat.ts +35 -7
- package/src/tool/agentMain.ts +7 -7
- package/src/tool/chatMain.ts +126 -5
- package/src/tool/commandPrompt.ts +10 -5
- package/src/tool/files.ts +30 -13
- package/src/tool/options.ts +1 -1
- package/test_data/dummyllm_script_image_gen.json +19 -0
- package/test_data/dummyllm_script_invoke_image_gen_tool.json +30 -0
- package/test_data/image_gen_test_profile.json +5 -0
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ChatSessionFileManager = exports.MemoryFileManager =
|
|
3
|
+
exports.ChatSessionFileManager = exports.MemoryFileManager = void 0;
|
|
4
4
|
exports.listFilesForLLM = listFilesForLLM;
|
|
5
5
|
exports.fileManagerTool = fileManagerTool;
|
|
6
6
|
const uuid_1 = require("uuid");
|
|
7
|
+
const assert_1 = require("assert");
|
|
7
8
|
const tools_1 = require("./tools");
|
|
8
|
-
|
|
9
|
+
const dbSessionFiles_1 = require("../data/dbSessionFiles");
|
|
10
|
+
const dbSessionFileModels_1 = require("../data/dbSessionFileModels");
|
|
9
11
|
/**
|
|
10
12
|
* In-memory implementation of ISessionFileManager
|
|
11
13
|
*/
|
|
12
14
|
class MemoryFileManager {
|
|
13
15
|
constructor() {
|
|
14
16
|
this.files = new Map();
|
|
15
|
-
this.
|
|
17
|
+
this.eventHandlers = [];
|
|
16
18
|
}
|
|
17
19
|
// ISessionFileManager.listFiles
|
|
18
20
|
listFiles() {
|
|
@@ -23,7 +25,22 @@ class MemoryFileManager {
|
|
|
23
25
|
return new Promise((r, e) => {
|
|
24
26
|
const entry = this.files.get(name);
|
|
25
27
|
if (entry) {
|
|
26
|
-
r(entry.
|
|
28
|
+
r(entry.data_url);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
e(new Error(`no such file ${name}`));
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
// ISessionFileManager.deleteFile
|
|
36
|
+
deleteFile(name) {
|
|
37
|
+
return new Promise((r, e) => {
|
|
38
|
+
if (this.files.has(name)) {
|
|
39
|
+
this.files.delete(name);
|
|
40
|
+
this.eventHandlers.forEach((eh) => {
|
|
41
|
+
eh.onFileDeleted(name);
|
|
42
|
+
});
|
|
43
|
+
r();
|
|
27
44
|
}
|
|
28
45
|
else {
|
|
29
46
|
e(new Error(`no such file ${name}`));
|
|
@@ -31,7 +48,7 @@ class MemoryFileManager {
|
|
|
31
48
|
});
|
|
32
49
|
}
|
|
33
50
|
// ISessionFileManager.addFile
|
|
34
|
-
putFileContent(name,
|
|
51
|
+
putFileContent(name, summary, data_url) {
|
|
35
52
|
return new Promise((r, e) => {
|
|
36
53
|
if (!name) {
|
|
37
54
|
name = (0, uuid_1.v4)();
|
|
@@ -43,29 +60,114 @@ class MemoryFileManager {
|
|
|
43
60
|
e(new Error("summary must no contain new-lines"));
|
|
44
61
|
}
|
|
45
62
|
else {
|
|
46
|
-
const
|
|
47
|
-
this.
|
|
63
|
+
const mime_type = (0, dbSessionFileModels_1.getSessionFileMimeTypeFromDataUrl)(data_url);
|
|
64
|
+
const is_new = !this.files.has(name);
|
|
65
|
+
const entry = { name, mime_type, summary, data_url };
|
|
66
|
+
this.eventHandlers.forEach((eh) => {
|
|
67
|
+
eh.onFileChanged(entry, is_new);
|
|
68
|
+
});
|
|
48
69
|
this.files.set(name, entry);
|
|
49
|
-
r(name);
|
|
70
|
+
r({ name, mime_type, summary });
|
|
50
71
|
}
|
|
51
72
|
});
|
|
52
73
|
}
|
|
53
74
|
// ISessionFileManager.setEventHandler
|
|
54
|
-
|
|
55
|
-
this.eventHandler
|
|
75
|
+
addEventHandler(eventHandler) {
|
|
76
|
+
this.eventHandlers.push(eventHandler);
|
|
56
77
|
}
|
|
57
78
|
}
|
|
58
79
|
exports.MemoryFileManager = MemoryFileManager;
|
|
59
80
|
/**
|
|
60
81
|
* Implementation of ISessionFileManager which can store files in the DB.
|
|
61
82
|
*/
|
|
62
|
-
class ChatSessionFileManager
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
83
|
+
class ChatSessionFileManager {
|
|
84
|
+
constructor(sfc, sessionUUID, fileMap) {
|
|
85
|
+
this.sessionUUID = sessionUUID;
|
|
86
|
+
this.sfc = sfc;
|
|
87
|
+
this.eventHandlers = [];
|
|
88
|
+
this.fileMap = fileMap;
|
|
89
|
+
this.fileDataCache = new Map();
|
|
90
|
+
}
|
|
91
|
+
static async init(db, sessionUUID) {
|
|
92
|
+
const sfc = db.createTypedClient(dbSessionFiles_1.DbSessionFiles);
|
|
93
|
+
const fileList = await sfc.getFilesForSession(sessionUUID);
|
|
94
|
+
const fileMap = new Map(fileList.map((f) => [f.name, f]));
|
|
95
|
+
return new ChatSessionFileManager(sfc, sessionUUID, fileMap);
|
|
96
|
+
}
|
|
97
|
+
listFiles() {
|
|
98
|
+
return Array.from(this.fileMap.values());
|
|
99
|
+
}
|
|
100
|
+
async getFileContent(name) {
|
|
101
|
+
const cached = this.fileDataCache.get(name);
|
|
102
|
+
if (cached) {
|
|
103
|
+
return cached;
|
|
104
|
+
}
|
|
105
|
+
if (!this.fileMap.has(name)) {
|
|
106
|
+
throw new Error(`no file '${name}' in session '${this.sessionUUID}'`);
|
|
107
|
+
}
|
|
108
|
+
const fileData = await this.sfc.getFileContent(this.sessionUUID, name);
|
|
109
|
+
if (!fileData) {
|
|
110
|
+
// logically should not happen
|
|
111
|
+
throw new Error(`empty file '${name}' in session '${this.sessionUUID}'`);
|
|
112
|
+
}
|
|
113
|
+
this.fileDataCache.set(name, fileData);
|
|
114
|
+
return fileData;
|
|
115
|
+
}
|
|
116
|
+
// ISessionFileManager.deleteFile
|
|
117
|
+
async deleteFile(name) {
|
|
118
|
+
if (this.fileMap.has(name)) {
|
|
119
|
+
this.fileMap.delete(name);
|
|
120
|
+
this.fileDataCache.delete(name);
|
|
121
|
+
await this.sfc.deleteFile(this.sessionUUID, name);
|
|
122
|
+
this.eventHandlers.forEach((eh) => {
|
|
123
|
+
eh.onFileDeleted(name);
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
throw new Error(`no file '${name}' in session '${this.sessionUUID}'`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// ISessionFileManager.addFile
|
|
131
|
+
async putFileContent(name, summary, data_url) {
|
|
132
|
+
if (!name) {
|
|
133
|
+
// TODO: have the LLM fill in the name?
|
|
134
|
+
name = (0, uuid_1.v4)();
|
|
135
|
+
}
|
|
136
|
+
// TODO: have the LLM create summary if missing?
|
|
137
|
+
// If we have an existing entry in the cache then update it, otherwise
|
|
138
|
+
// create a new one.
|
|
139
|
+
const mime_type = (0, dbSessionFileModels_1.getSessionFileMimeTypeFromDataUrl)(data_url);
|
|
140
|
+
const existingDesc = this.fileMap.get(name);
|
|
141
|
+
if (existingDesc) {
|
|
142
|
+
existingDesc.summary = summary;
|
|
143
|
+
existingDesc.mime_type = mime_type;
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
this.fileMap.set(name, { name, summary, mime_type });
|
|
147
|
+
}
|
|
148
|
+
const is_new = !this.fileMap.has(name);
|
|
149
|
+
this.fileDataCache.set(name, data_url);
|
|
150
|
+
await this.sfc.setFileContent(this.sessionUUID, name, summary, data_url);
|
|
151
|
+
this.eventHandlers.forEach((eh) => {
|
|
152
|
+
(0, assert_1.strict)(typeof name === "string");
|
|
153
|
+
eh.onFileChanged({ name, summary, mime_type, data_url }, is_new);
|
|
154
|
+
});
|
|
155
|
+
return { name, mime_type, summary };
|
|
156
|
+
}
|
|
157
|
+
// ISessionFileManager.setEventHandler
|
|
158
|
+
addEventHandler(eventHandler) {
|
|
159
|
+
this.eventHandlers.push(eventHandler);
|
|
160
|
+
}
|
|
161
|
+
clearAllFiles() {
|
|
162
|
+
this.fileMap.clear();
|
|
163
|
+
this.fileDataCache.clear();
|
|
164
|
+
return this.sfc.clearFiles(this.sessionUUID);
|
|
165
|
+
}
|
|
166
|
+
getSessionFileRelativeUrl(name) {
|
|
167
|
+
return `file+session:/./${name}`;
|
|
168
|
+
}
|
|
169
|
+
getSessionFileAbsoluteUrl(name) {
|
|
170
|
+
return `file+session://${this.sessionUUID}/${name}`;
|
|
69
171
|
}
|
|
70
172
|
}
|
|
71
173
|
exports.ChatSessionFileManager = ChatSessionFileManager;
|
|
@@ -79,7 +181,7 @@ function listFilesForLLM(fm) {
|
|
|
79
181
|
}
|
|
80
182
|
let summary = "Available files:\nname,type,summary\n";
|
|
81
183
|
for (const f of files) {
|
|
82
|
-
summary += `${f.name},${f.
|
|
184
|
+
summary += `${f.name},${f.mime_type},${f.summary || ""}\n`;
|
|
83
185
|
}
|
|
84
186
|
return summary;
|
|
85
187
|
}
|
|
@@ -87,7 +189,7 @@ const GET_FILE_CONTENT_TOOL = {
|
|
|
87
189
|
type: "function",
|
|
88
190
|
function: {
|
|
89
191
|
name: "get_file_content",
|
|
90
|
-
description: "Obtain
|
|
192
|
+
description: "Obtain contents of file listed in system prompt, as data-url",
|
|
91
193
|
parameters: {
|
|
92
194
|
type: "object",
|
|
93
195
|
properties: {
|
|
@@ -112,49 +214,80 @@ const PUT_FILE_CONTENT_TOOL = {
|
|
|
112
214
|
type: "string",
|
|
113
215
|
description: "File name",
|
|
114
216
|
},
|
|
115
|
-
file_type: {
|
|
116
|
-
type: "string",
|
|
117
|
-
enum: exports.SESSION_FILE_TYPES,
|
|
118
|
-
},
|
|
119
217
|
summary: {
|
|
120
218
|
type: "string",
|
|
121
219
|
description: "Content summary",
|
|
122
220
|
},
|
|
123
|
-
|
|
221
|
+
data_url: {
|
|
124
222
|
type: "string",
|
|
125
|
-
description: "Content
|
|
223
|
+
description: "Content data-url: `data:<mime-type>[;<format>],<encoding>`",
|
|
126
224
|
},
|
|
127
225
|
},
|
|
128
|
-
required: ["name", "
|
|
226
|
+
required: ["name", "summary", "data_url"],
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
};
|
|
230
|
+
const DELETE_FILE_CONTENT_TOOL = {
|
|
231
|
+
type: "function",
|
|
232
|
+
function: {
|
|
233
|
+
name: "delete_file_content",
|
|
234
|
+
description: "Delete file",
|
|
235
|
+
parameters: {
|
|
236
|
+
type: "object",
|
|
237
|
+
properties: {
|
|
238
|
+
name: {
|
|
239
|
+
type: "string",
|
|
240
|
+
description: "File name",
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
required: ["name"],
|
|
129
244
|
},
|
|
130
245
|
},
|
|
131
246
|
};
|
|
132
247
|
function fileManagerTool(fileManager) {
|
|
133
|
-
// get_file_content
|
|
134
|
-
|
|
248
|
+
// `get_file_content` tool
|
|
249
|
+
//
|
|
250
|
+
// LLM can read data from the file. To keep the context small, we overwrite
|
|
251
|
+
// the data with the session file url after the LLM has seen it.
|
|
252
|
+
const parseName = (0, tools_1.makeParseArgsFn)(["name"]);
|
|
135
253
|
const getFileContentFn = async (_agent, args) => {
|
|
136
|
-
const { name } =
|
|
254
|
+
const { name } = parseName(args);
|
|
137
255
|
const response = await fileManager.getFileContent(name);
|
|
138
|
-
|
|
256
|
+
const overwriteResponse = fileManager.getSessionFileRelativeUrl(name);
|
|
257
|
+
return { response, overwriteResponse };
|
|
139
258
|
};
|
|
140
|
-
// set_file_content
|
|
141
|
-
|
|
142
|
-
|
|
259
|
+
// `set_file_content` tool
|
|
260
|
+
//
|
|
261
|
+
// Allows LLM to write data (as a data-url) to the session file manager. The
|
|
262
|
+
// data is replaced by a session file url after being saved.
|
|
263
|
+
const putArgs = ["name", "summary", "data_url"];
|
|
264
|
+
const parseNameSummaryDataUrl = (0, tools_1.makeParseArgsFn)(putArgs);
|
|
143
265
|
const putFileContentFn = async (_, args) => {
|
|
144
|
-
const
|
|
145
|
-
const
|
|
146
|
-
|
|
266
|
+
const parsed = parseNameSummaryDataUrl(args);
|
|
267
|
+
const { name, summary, data_url } = parsed;
|
|
268
|
+
const desc = await fileManager.putFileContent(name, summary, data_url);
|
|
269
|
+
parsed.data_url = fileManager.getSessionFileRelativeUrl(name);
|
|
270
|
+
return { response: desc.name, overwriteArgs: JSON.stringify(parsed) };
|
|
271
|
+
};
|
|
272
|
+
// `delete_file_content` tool
|
|
273
|
+
//
|
|
274
|
+
// Allows LLM to write data (as a data-url) to the session file manager. The
|
|
275
|
+
// data is replaced by a session file url after being saved.
|
|
276
|
+
const deleteFileFn = async (_, args) => {
|
|
277
|
+
const { name } = parseName(args);
|
|
278
|
+
await fileManager.deleteFile(name);
|
|
279
|
+
return { response: "" };
|
|
147
280
|
};
|
|
148
|
-
|
|
281
|
+
return {
|
|
149
282
|
setup: (agent) => {
|
|
150
283
|
agent.addAgentTool(GET_FILE_CONTENT_TOOL, getFileContentFn);
|
|
151
284
|
agent.addAgentTool(PUT_FILE_CONTENT_TOOL, putFileContentFn);
|
|
285
|
+
agent.addAgentTool(DELETE_FILE_CONTENT_TOOL, deleteFileFn);
|
|
152
286
|
return new Promise((r) => {
|
|
153
287
|
r();
|
|
154
288
|
});
|
|
155
289
|
},
|
|
156
290
|
};
|
|
157
|
-
return provider;
|
|
158
291
|
}
|
|
159
292
|
function isSingleLine(str) {
|
|
160
293
|
return !/[\r\n]/.test(str);
|