@xalia/agent 0.6.8 → 0.6.10
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 +6 -0
- package/.env.test +7 -0
- package/README.md +11 -0
- package/context_system.md +498 -0
- package/dist/agent/src/agent/agent.js +169 -87
- package/dist/agent/src/agent/agentUtils.js +24 -18
- 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/documentSummarizer.js +126 -0
- package/dist/agent/src/agent/dummyLLM.js +25 -22
- package/dist/agent/src/agent/imageGenLLM.js +22 -25
- package/dist/agent/src/agent/imageGenerator.js +2 -10
- package/dist/agent/src/agent/llm.js +1 -1
- package/dist/agent/src/agent/openAILLM.js +15 -12
- package/dist/agent/src/agent/openAILLMStreaming.js +73 -39
- package/dist/agent/src/agent/repeatLLM.js +16 -7
- package/dist/agent/src/agent/sudoMcpServerManager.js +21 -9
- package/dist/agent/src/agent/tokenCounter.js +390 -0
- package/dist/agent/src/agent/tokenCounter.test.js +206 -0
- package/dist/agent/src/agent/toolSettings.js +17 -0
- package/dist/agent/src/agent/tools/calculatorTool.js +45 -0
- package/dist/agent/src/agent/tools/contentExtractors/pdfToText.js +55 -0
- package/dist/agent/src/agent/tools/datetimeTool.js +38 -0
- package/dist/agent/src/agent/tools/fileManager/fileManagerTool.js +156 -0
- package/dist/agent/src/agent/tools/fileManager/index.js +31 -0
- package/dist/agent/src/agent/tools/fileManager/memoryFileManager.js +102 -0
- package/dist/agent/src/{chat/data → agent/tools/fileManager}/mimeTypes.js +3 -1
- package/dist/agent/src/agent/tools/fileManager/prompt.js +33 -0
- package/dist/agent/src/{chat/data/dbSessionFileModels.js → agent/tools/fileManager/types.js} +7 -0
- package/dist/agent/src/agent/tools/index.js +64 -0
- package/dist/agent/src/agent/tools/openUrlTool.js +57 -0
- package/dist/agent/src/agent/tools/renderTool.js +89 -0
- package/dist/agent/src/agent/tools/utils.js +61 -0
- package/dist/agent/src/{chat/utils/search.js → agent/tools/webSearch.js} +1 -2
- package/dist/agent/src/agent/tools/webSearchTool.js +40 -0
- package/dist/agent/src/chat/client/chatClient.js +63 -2
- package/dist/agent/src/chat/client/connection.js +6 -1
- package/dist/agent/src/chat/client/index.js +4 -1
- package/dist/agent/src/chat/client/sessionClient.js +28 -9
- package/dist/agent/src/chat/constants.js +8 -0
- package/dist/agent/src/chat/data/dbSessionFiles.js +11 -6
- package/dist/agent/src/chat/data/dbSessionMessages.js +11 -0
- package/dist/agent/src/chat/protocol/messages.js +9 -0
- package/dist/agent/src/chat/server/chatContextManager.js +186 -156
- package/dist/agent/src/chat/server/conversation.js +3 -0
- package/dist/agent/src/chat/server/imageGeneratorTools.js +39 -16
- package/dist/agent/src/chat/server/openAIRouterLLM.js +111 -0
- package/dist/agent/src/chat/server/openSession.js +253 -91
- package/dist/agent/src/chat/server/promptRefiner.js +86 -0
- package/dist/agent/src/chat/server/server.js +10 -2
- package/dist/agent/src/chat/server/sessionFileManager.js +22 -221
- package/dist/agent/src/chat/server/sessionRegistry.js +152 -6
- package/dist/agent/src/chat/server/sessionRegistry.test.js +1 -1
- package/dist/agent/src/chat/server/titleGenerator.js +112 -0
- package/dist/agent/src/chat/server/titleGenerator.test.js +113 -0
- package/dist/agent/src/chat/server/tools.js +64 -253
- package/dist/agent/src/chat/utils/approvalManager.js +6 -3
- package/dist/agent/src/chat/utils/multiAsyncQueue.js +3 -0
- package/dist/agent/src/test/agent.test.js +16 -17
- package/dist/agent/src/test/chatContextManager.test.js +44 -30
- 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/test/dbMcpServerConfigs.test.js +4 -4
- package/dist/agent/src/test/dbSessionFiles.test.js +17 -17
- package/dist/agent/src/test/testTools.js +6 -1
- package/dist/agent/src/test/tools.test.js +27 -9
- package/dist/agent/src/tool/agentChat.js +5 -2
- package/dist/agent/src/tool/chatMain.js +56 -15
- package/dist/agent/src/tool/commandPrompt.js +2 -2
- package/dist/agent/src/tool/files.js +7 -8
- package/package.json +4 -1
- package/scripts/test_chat +195 -173
- package/src/agent/agent.ts +257 -137
- package/src/agent/agentUtils.ts +32 -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/documentSummarizer.ts +157 -0
- package/src/agent/dummyLLM.ts +27 -23
- package/src/agent/imageGenLLM.ts +28 -32
- package/src/agent/imageGenerator.ts +3 -18
- package/src/agent/llm.ts +2 -2
- package/src/agent/openAILLM.ts +17 -13
- package/src/agent/openAILLMStreaming.ts +99 -43
- package/src/agent/repeatLLM.ts +19 -7
- package/src/agent/sudoMcpServerManager.ts +41 -20
- package/src/agent/test_data/harrypotter.txt +6065 -0
- package/src/agent/tokenCounter.test.ts +243 -0
- package/src/agent/tokenCounter.ts +483 -0
- package/src/agent/toolSettings.ts +24 -0
- package/src/agent/tools/calculatorTool.ts +50 -0
- package/src/agent/tools/contentExtractors/pdfToText.ts +60 -0
- package/src/agent/tools/datetimeTool.ts +41 -0
- package/src/agent/tools/fileManager/fileManagerTool.ts +199 -0
- package/src/agent/tools/fileManager/index.ts +50 -0
- package/src/agent/tools/fileManager/memoryFileManager.ts +120 -0
- package/src/{chat/data → agent/tools/fileManager}/mimeTypes.ts +3 -1
- package/src/agent/tools/fileManager/prompt.ts +38 -0
- package/src/{chat/data/dbSessionFileModels.ts → agent/tools/fileManager/types.ts} +76 -0
- package/src/agent/tools/index.ts +49 -0
- package/src/agent/tools/openUrlTool.ts +62 -0
- package/src/agent/tools/renderTool.ts +92 -0
- package/src/agent/tools/utils.ts +74 -0
- package/src/{chat/utils/search.ts → agent/tools/webSearch.ts} +0 -1
- package/src/agent/tools/webSearchTool.ts +44 -0
- package/src/chat/client/chatClient.ts +92 -3
- package/src/chat/client/connection.ts +11 -1
- package/src/chat/client/index.ts +3 -0
- package/src/chat/client/sessionClient.ts +40 -11
- package/src/chat/client/sessionFiles.ts +1 -1
- package/src/chat/constants.ts +6 -0
- package/src/chat/data/dataModels.ts +12 -0
- package/src/chat/data/dbSessionFiles.ts +12 -4
- package/src/chat/data/dbSessionMessages.ts +34 -0
- package/src/chat/protocol/messages.ts +94 -14
- package/src/chat/server/chatContextManager.ts +255 -221
- package/src/chat/server/connectionManager.ts +1 -1
- package/src/chat/server/conversation.ts +3 -0
- package/src/chat/server/imageGeneratorTools.ts +62 -30
- package/src/chat/server/openAIRouterLLM.ts +168 -0
- package/src/chat/server/openSession.ts +381 -138
- package/src/chat/server/promptRefiner.ts +106 -0
- package/src/chat/server/server.ts +9 -2
- package/src/chat/server/sessionFileManager.ts +35 -306
- package/src/chat/server/sessionRegistry.test.ts +0 -1
- package/src/chat/server/sessionRegistry.ts +228 -4
- package/src/chat/server/titleGenerator.test.ts +103 -0
- package/src/chat/server/titleGenerator.ts +143 -0
- package/src/chat/server/tools.ts +92 -281
- package/src/chat/utils/approvalManager.ts +9 -3
- package/src/chat/utils/multiAsyncQueue.ts +4 -0
- package/src/test/agent.test.ts +25 -30
- package/src/test/chatContextManager.test.ts +68 -38
- 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/test/dbMcpServerConfigs.test.ts +4 -4
- package/src/test/dbSessionFiles.test.ts +16 -16
- package/src/test/testTools.ts +8 -3
- package/src/test/tools.test.ts +30 -5
- package/src/tool/agentChat.ts +12 -3
- package/src/tool/chatMain.ts +59 -18
- package/src/tool/commandPrompt.ts +2 -2
- package/src/tool/files.ts +1 -3
- package/dist/agent/src/agent/tools.js +0 -44
- package/src/agent/tools.ts +0 -57
- /package/dist/agent/src/{chat/utils → agent/tools/contentExtractors}/htmlToText.js +0 -0
- /package/src/{chat/utils → agent/tools/contentExtractors}/htmlToText.ts +0 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.pdfToText = pdfToText;
|
|
4
|
+
/**
|
|
5
|
+
* Extract text string from a text content item if it has one.
|
|
6
|
+
*/
|
|
7
|
+
function getTextStr(item) {
|
|
8
|
+
if (typeof item === "object" && item !== null && "str" in item) {
|
|
9
|
+
const str = item.str;
|
|
10
|
+
return typeof str === "string" ? str : undefined;
|
|
11
|
+
}
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Extract text content from a PDF buffer.
|
|
16
|
+
*
|
|
17
|
+
* @param data - PDF file as ArrayBuffer
|
|
18
|
+
* @param maxLength - Optional maximum length of extracted text
|
|
19
|
+
* @returns Extracted text content
|
|
20
|
+
*/
|
|
21
|
+
async function pdfToText(data, maxLength) {
|
|
22
|
+
// Dynamic import required for ESM module in CommonJS project
|
|
23
|
+
const pdfjs = await import("pdfjs-dist/legacy/build/pdf.mjs");
|
|
24
|
+
// Disable worker for Node.js environment
|
|
25
|
+
const loadingTask = pdfjs.getDocument({
|
|
26
|
+
data,
|
|
27
|
+
useWorkerFetch: false,
|
|
28
|
+
isEvalSupported: false,
|
|
29
|
+
useSystemFonts: true,
|
|
30
|
+
});
|
|
31
|
+
const doc = await loadingTask.promise;
|
|
32
|
+
let fullText = "";
|
|
33
|
+
for (let i = 1; i <= doc.numPages; i++) {
|
|
34
|
+
const page = await doc.getPage(i);
|
|
35
|
+
const content = await page.getTextContent();
|
|
36
|
+
const strings = [];
|
|
37
|
+
for (const item of content.items) {
|
|
38
|
+
const str = getTextStr(item);
|
|
39
|
+
if (str !== undefined) {
|
|
40
|
+
strings.push(str);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
fullText += strings.join(" ") + "\n";
|
|
44
|
+
page.cleanup();
|
|
45
|
+
// Early exit if we've exceeded maxLength
|
|
46
|
+
if (maxLength && fullText.length > maxLength) {
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Apply truncation
|
|
51
|
+
if (maxLength && fullText.length > maxLength) {
|
|
52
|
+
return fullText.slice(0, maxLength) + "... [content truncated]";
|
|
53
|
+
}
|
|
54
|
+
return fullText.trim();
|
|
55
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isoWithTimezone = isoWithTimezone;
|
|
4
|
+
exports.datetimeTool = datetimeTool;
|
|
5
|
+
const DATETIME_DESC = {
|
|
6
|
+
type: "function",
|
|
7
|
+
function: {
|
|
8
|
+
name: "time_now",
|
|
9
|
+
description: "Current time",
|
|
10
|
+
},
|
|
11
|
+
};
|
|
12
|
+
function isoWithTimezone(timeZone) {
|
|
13
|
+
return (new Intl.DateTimeFormat("sv-SE", {
|
|
14
|
+
timeZone,
|
|
15
|
+
year: "numeric",
|
|
16
|
+
month: "2-digit",
|
|
17
|
+
day: "2-digit",
|
|
18
|
+
hour: "2-digit",
|
|
19
|
+
minute: "2-digit",
|
|
20
|
+
second: "2-digit",
|
|
21
|
+
hour12: false,
|
|
22
|
+
timeZoneName: "short",
|
|
23
|
+
})
|
|
24
|
+
.format(new Date())
|
|
25
|
+
.replace(" ", "T") + ` (${timeZone})`);
|
|
26
|
+
}
|
|
27
|
+
function datetimeTool(timezone) {
|
|
28
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
29
|
+
const toolFn = async () => {
|
|
30
|
+
return { response: isoWithTimezone(timezone) };
|
|
31
|
+
};
|
|
32
|
+
return {
|
|
33
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
34
|
+
setup: async (agent) => {
|
|
35
|
+
agent.addAgentTool(DATETIME_DESC, toolFn);
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fileManagerTool = fileManagerTool;
|
|
4
|
+
const utils_1 = require("../utils");
|
|
5
|
+
const types_1 = require("./types");
|
|
6
|
+
const GET_FILE_CONTENT_TOOL = {
|
|
7
|
+
type: "function",
|
|
8
|
+
function: {
|
|
9
|
+
name: "get_file_content",
|
|
10
|
+
description: "Get raw file content as data-url. Use this for images or when you " +
|
|
11
|
+
"need the original binary data. For PDFs and documents where you need " +
|
|
12
|
+
"the text content, use get_file_parsed_content instead.",
|
|
13
|
+
parameters: {
|
|
14
|
+
type: "object",
|
|
15
|
+
properties: {
|
|
16
|
+
name: {
|
|
17
|
+
type: "string",
|
|
18
|
+
description: "File name",
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
required: ["name"],
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
const PUT_FILE_CONTENT_TOOL = {
|
|
26
|
+
type: "function",
|
|
27
|
+
function: {
|
|
28
|
+
name: "put_file_content",
|
|
29
|
+
description: "Create or update file content",
|
|
30
|
+
parameters: {
|
|
31
|
+
type: "object",
|
|
32
|
+
properties: {
|
|
33
|
+
name: {
|
|
34
|
+
type: "string",
|
|
35
|
+
description: "File name",
|
|
36
|
+
},
|
|
37
|
+
summary: {
|
|
38
|
+
type: "string",
|
|
39
|
+
description: "Content summary",
|
|
40
|
+
},
|
|
41
|
+
data_url: {
|
|
42
|
+
type: "string",
|
|
43
|
+
description: "Content data-url: `data:<mime-type>[;<format>],<encoding>`",
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
required: ["name", "summary", "data_url"],
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
const DELETE_FILE_CONTENT_TOOL = {
|
|
51
|
+
type: "function",
|
|
52
|
+
function: {
|
|
53
|
+
name: "delete_file_content",
|
|
54
|
+
description: "Delete file",
|
|
55
|
+
parameters: {
|
|
56
|
+
type: "object",
|
|
57
|
+
properties: {
|
|
58
|
+
name: {
|
|
59
|
+
type: "string",
|
|
60
|
+
description: "File name",
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
required: ["name"],
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
const GET_FILE_PARSED_CONTENT_TOOL = {
|
|
68
|
+
type: "function",
|
|
69
|
+
function: {
|
|
70
|
+
name: "get_file_parsed_content",
|
|
71
|
+
description: "Get extracted text content from a file (e.g., PDF). " +
|
|
72
|
+
"Returns the parsed text if available, or an error if the file " +
|
|
73
|
+
"has no parsed content.",
|
|
74
|
+
parameters: {
|
|
75
|
+
type: "object",
|
|
76
|
+
properties: {
|
|
77
|
+
name: {
|
|
78
|
+
type: "string",
|
|
79
|
+
description: "File name",
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
required: ["name"],
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
function fileManagerTool(fileManager) {
|
|
87
|
+
// `get_file_content` tool
|
|
88
|
+
//
|
|
89
|
+
// LLM can read data from the file. To keep the context small, we overwrite
|
|
90
|
+
// the data with the session file url after the LLM has seen it.
|
|
91
|
+
const parseName = (0, utils_1.makeParseArgsFn)(["name"]);
|
|
92
|
+
const getFileContentFn = async (_agent, args) => {
|
|
93
|
+
const { name } = parseName(args);
|
|
94
|
+
const response = await fileManager.getFileContent(name);
|
|
95
|
+
const overwriteResponse = fileManager.getSessionFileRelativeUrl(name);
|
|
96
|
+
return { response, overwriteResponse };
|
|
97
|
+
};
|
|
98
|
+
// `set_file_content` tool
|
|
99
|
+
//
|
|
100
|
+
// Allows LLM to write data (as a data-url) to the session file manager. The
|
|
101
|
+
// data is replaced by a session file url after being saved.
|
|
102
|
+
const putArgs = ["name", "summary", "data_url"];
|
|
103
|
+
const parseNameSummaryDataUrl = (0, utils_1.makeParseArgsFn)(putArgs);
|
|
104
|
+
const putFileContentFn = async (_, args) => {
|
|
105
|
+
const parsed = parseNameSummaryDataUrl(args);
|
|
106
|
+
const { name, summary, data_url } = parsed;
|
|
107
|
+
const existingFile = fileManager.listFiles().find((f) => f.name === name);
|
|
108
|
+
const desc = await fileManager.putFileContent(name, summary, data_url);
|
|
109
|
+
const mimeType = (0, types_1.getSessionFileMimeTypeFromDataUrl)(data_url);
|
|
110
|
+
// Calculate content size for response message
|
|
111
|
+
const contentSize = data_url.split(",")[1]?.length || 0;
|
|
112
|
+
const sizeKB = (contentSize / 1024).toFixed(1);
|
|
113
|
+
parsed.data_url = fileManager.getSessionFileRelativeUrl(name);
|
|
114
|
+
const action = existingFile ? "updated" : "created";
|
|
115
|
+
const responseMsg = `Successfully ${action} file '${desc.name}' with ${sizeKB}KB of content`;
|
|
116
|
+
return {
|
|
117
|
+
response: responseMsg,
|
|
118
|
+
overwriteArgs: JSON.stringify(parsed),
|
|
119
|
+
_meta: {
|
|
120
|
+
"xalia/fileUri": parsed.data_url,
|
|
121
|
+
"xalia/fileMimeType": mimeType,
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
};
|
|
125
|
+
// `delete_file_content` tool
|
|
126
|
+
//
|
|
127
|
+
// Allows LLM to write data (as a data-url) to the session file manager. The
|
|
128
|
+
// data is replaced by a session file url after being saved.
|
|
129
|
+
const deleteFileFn = async (_, args) => {
|
|
130
|
+
const { name } = parseName(args);
|
|
131
|
+
await fileManager.deleteFile(name);
|
|
132
|
+
return { response: "" };
|
|
133
|
+
};
|
|
134
|
+
// `get_file_parsed_content` tool
|
|
135
|
+
//
|
|
136
|
+
// Returns extracted text content from files like PDFs.
|
|
137
|
+
const getFileParsedContentFn = async (_, args) => {
|
|
138
|
+
const { name } = parseName(args);
|
|
139
|
+
const parsedContent = await fileManager.getFileParsedContent(name);
|
|
140
|
+
if (!parsedContent) {
|
|
141
|
+
return { response: `File '${name}' has no parsed content available.` };
|
|
142
|
+
}
|
|
143
|
+
return { response: parsedContent.text };
|
|
144
|
+
};
|
|
145
|
+
return {
|
|
146
|
+
setup: (agent) => {
|
|
147
|
+
agent.addAgentTool(GET_FILE_CONTENT_TOOL, getFileContentFn);
|
|
148
|
+
agent.addAgentTool(PUT_FILE_CONTENT_TOOL, putFileContentFn);
|
|
149
|
+
agent.addAgentTool(DELETE_FILE_CONTENT_TOOL, deleteFileFn);
|
|
150
|
+
agent.addAgentTool(GET_FILE_PARSED_CONTENT_TOOL, getFileParsedContentFn);
|
|
151
|
+
return new Promise((r) => {
|
|
152
|
+
r();
|
|
153
|
+
});
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createSessionFilesManagerPrompt = exports.fileManagerTool = exports.MemoryFileManager = exports.createSessionFileDataUrl = exports.getSessionFileMimeTypeFromDataUrl = exports.isParsedContent = exports.isFileMetaData = exports.EXTENSION_TO_SESSION_FILE_MIME_TYPE = exports.isSessionFileTextMimeType = exports.SESSION_FILE_TEXT_MIME_TYPES = exports.isSessionFileMimeType = exports.SESSION_FILE_MIME_TYPES = exports.createDataUrlFromText = exports.createDataUrlFromBuffer = exports.getMimeTypeFromDataUrl = exports.EXTENSION_TO_IMAGE_MIME_TYPE = exports.isImageMimeType = exports.IMAGE_MIME_TYPES = void 0;
|
|
4
|
+
// Mime types - values
|
|
5
|
+
var mimeTypes_1 = require("./mimeTypes");
|
|
6
|
+
Object.defineProperty(exports, "IMAGE_MIME_TYPES", { enumerable: true, get: function () { return mimeTypes_1.IMAGE_MIME_TYPES; } });
|
|
7
|
+
Object.defineProperty(exports, "isImageMimeType", { enumerable: true, get: function () { return mimeTypes_1.isImageMimeType; } });
|
|
8
|
+
Object.defineProperty(exports, "EXTENSION_TO_IMAGE_MIME_TYPE", { enumerable: true, get: function () { return mimeTypes_1.EXTENSION_TO_IMAGE_MIME_TYPE; } });
|
|
9
|
+
Object.defineProperty(exports, "getMimeTypeFromDataUrl", { enumerable: true, get: function () { return mimeTypes_1.getMimeTypeFromDataUrl; } });
|
|
10
|
+
Object.defineProperty(exports, "createDataUrlFromBuffer", { enumerable: true, get: function () { return mimeTypes_1.createDataUrlFromBuffer; } });
|
|
11
|
+
Object.defineProperty(exports, "createDataUrlFromText", { enumerable: true, get: function () { return mimeTypes_1.createDataUrlFromText; } });
|
|
12
|
+
// Session file types - values
|
|
13
|
+
var types_1 = require("./types");
|
|
14
|
+
Object.defineProperty(exports, "SESSION_FILE_MIME_TYPES", { enumerable: true, get: function () { return types_1.SESSION_FILE_MIME_TYPES; } });
|
|
15
|
+
Object.defineProperty(exports, "isSessionFileMimeType", { enumerable: true, get: function () { return types_1.isSessionFileMimeType; } });
|
|
16
|
+
Object.defineProperty(exports, "SESSION_FILE_TEXT_MIME_TYPES", { enumerable: true, get: function () { return types_1.SESSION_FILE_TEXT_MIME_TYPES; } });
|
|
17
|
+
Object.defineProperty(exports, "isSessionFileTextMimeType", { enumerable: true, get: function () { return types_1.isSessionFileTextMimeType; } });
|
|
18
|
+
Object.defineProperty(exports, "EXTENSION_TO_SESSION_FILE_MIME_TYPE", { enumerable: true, get: function () { return types_1.EXTENSION_TO_SESSION_FILE_MIME_TYPE; } });
|
|
19
|
+
Object.defineProperty(exports, "isFileMetaData", { enumerable: true, get: function () { return types_1.isFileMetaData; } });
|
|
20
|
+
Object.defineProperty(exports, "isParsedContent", { enumerable: true, get: function () { return types_1.isParsedContent; } });
|
|
21
|
+
Object.defineProperty(exports, "getSessionFileMimeTypeFromDataUrl", { enumerable: true, get: function () { return types_1.getSessionFileMimeTypeFromDataUrl; } });
|
|
22
|
+
Object.defineProperty(exports, "createSessionFileDataUrl", { enumerable: true, get: function () { return types_1.createSessionFileDataUrl; } });
|
|
23
|
+
// Implementations
|
|
24
|
+
var memoryFileManager_1 = require("./memoryFileManager");
|
|
25
|
+
Object.defineProperty(exports, "MemoryFileManager", { enumerable: true, get: function () { return memoryFileManager_1.MemoryFileManager; } });
|
|
26
|
+
// Tool - values
|
|
27
|
+
var fileManagerTool_1 = require("./fileManagerTool");
|
|
28
|
+
Object.defineProperty(exports, "fileManagerTool", { enumerable: true, get: function () { return fileManagerTool_1.fileManagerTool; } });
|
|
29
|
+
// Prompt
|
|
30
|
+
var prompt_1 = require("./prompt");
|
|
31
|
+
Object.defineProperty(exports, "createSessionFilesManagerPrompt", { enumerable: true, get: function () { return prompt_1.createSessionFilesManagerPrompt; } });
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MemoryFileManager = void 0;
|
|
4
|
+
const uuid_1 = require("uuid");
|
|
5
|
+
const types_1 = require("./types");
|
|
6
|
+
function isSingleLine(str) {
|
|
7
|
+
return !/[\r\n]/.test(str);
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* In-memory implementation of ISessionFileManager
|
|
11
|
+
*/
|
|
12
|
+
class MemoryFileManager {
|
|
13
|
+
constructor() {
|
|
14
|
+
this.files = new Map();
|
|
15
|
+
this.eventHandlers = [];
|
|
16
|
+
}
|
|
17
|
+
// ISessionFileManager.listFiles
|
|
18
|
+
listFiles() {
|
|
19
|
+
return Array.from(this.files.values());
|
|
20
|
+
}
|
|
21
|
+
// ISessionFileManager.getFileContent
|
|
22
|
+
getFileContent(name) {
|
|
23
|
+
return new Promise((r, e) => {
|
|
24
|
+
const entry = this.files.get(name);
|
|
25
|
+
if (entry) {
|
|
26
|
+
r(entry.data_url);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
e(new Error(`no such file ${name}`));
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
// ISessionFileManager.getFileParsedContent
|
|
34
|
+
getFileParsedContent(name) {
|
|
35
|
+
return new Promise((r, e) => {
|
|
36
|
+
const entry = this.files.get(name);
|
|
37
|
+
if (entry) {
|
|
38
|
+
r(entry.parsed_content);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
e(new Error(`no such file ${name}`));
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
// ISessionFileManager.deleteFile
|
|
46
|
+
deleteFile(name) {
|
|
47
|
+
return new Promise((r, e) => {
|
|
48
|
+
if (this.files.has(name)) {
|
|
49
|
+
this.files.delete(name);
|
|
50
|
+
this.eventHandlers.forEach((eh) => {
|
|
51
|
+
eh.onFileDeleted(name);
|
|
52
|
+
});
|
|
53
|
+
r();
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
e(new Error(`no such file ${name}`));
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
// ISessionFileManager.addFile
|
|
61
|
+
putFileContent(name, summary, data_url, parsed_content) {
|
|
62
|
+
return new Promise((r, e) => {
|
|
63
|
+
if (!name) {
|
|
64
|
+
name = (0, uuid_1.v4)();
|
|
65
|
+
}
|
|
66
|
+
if (!summary) {
|
|
67
|
+
summary = "";
|
|
68
|
+
}
|
|
69
|
+
if (!isSingleLine(summary)) {
|
|
70
|
+
e(new Error("summary must no contain new-lines"));
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
const mime_type = (0, types_1.getSessionFileMimeTypeFromDataUrl)(data_url);
|
|
74
|
+
const is_new = !this.files.has(name);
|
|
75
|
+
const entry = {
|
|
76
|
+
name,
|
|
77
|
+
mime_type,
|
|
78
|
+
summary,
|
|
79
|
+
parsed_content,
|
|
80
|
+
data_url,
|
|
81
|
+
};
|
|
82
|
+
this.eventHandlers.forEach((eh) => {
|
|
83
|
+
eh.onFileChanged(entry, is_new);
|
|
84
|
+
});
|
|
85
|
+
this.files.set(name, entry);
|
|
86
|
+
r({ name, mime_type, summary, parsed_content });
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
// ISessionFileManager.setEventHandler
|
|
91
|
+
addEventHandler(eventHandler) {
|
|
92
|
+
this.eventHandlers.push(eventHandler);
|
|
93
|
+
}
|
|
94
|
+
getSessionFileRelativeUrl(name) {
|
|
95
|
+
return `file+session:/./${name}`;
|
|
96
|
+
}
|
|
97
|
+
getSessionFileAbsoluteUrl(name) {
|
|
98
|
+
// MemoryFileManager doesn't have a session ID, use relative URL
|
|
99
|
+
return this.getSessionFileRelativeUrl(name);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
exports.MemoryFileManager = MemoryFileManager;
|
|
@@ -40,5 +40,7 @@ function createDataUrlFromBuffer(data, mime_type) {
|
|
|
40
40
|
return `data:${mime_type};base64,${imgB64}`;
|
|
41
41
|
}
|
|
42
42
|
function createDataUrlFromText(data, mime_type) {
|
|
43
|
-
|
|
43
|
+
// Properly URL-encode the content to handle special characters
|
|
44
|
+
const encodedData = encodeURIComponent(data);
|
|
45
|
+
return `data:${mime_type};charset=utf-8,${encodedData}`;
|
|
44
46
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createSessionFilesManagerPrompt = createSessionFilesManagerPrompt;
|
|
4
|
+
/**
|
|
5
|
+
* Return the file list in a form easily parsable by the LLM.
|
|
6
|
+
*/
|
|
7
|
+
function createSessionFilesManagerPrompt(fm) {
|
|
8
|
+
const files = fm.listFiles();
|
|
9
|
+
let prompt = "Files can be read/written as required. Create new files " +
|
|
10
|
+
"conservatively, usually when complex content is requested. " +
|
|
11
|
+
"\n\nDATA URL FORMAT: For text files (plain, markdown, html), use " +
|
|
12
|
+
"URL-encoded format: 'data:<mime-type>;charset=utf-8," +
|
|
13
|
+
"<URL-encoded-content>'. For binary files (images, PDF), use " +
|
|
14
|
+
"base64: 'data:<mime-type>;base64,<base64-data>'. URL encoding " +
|
|
15
|
+
"means using encodeURIComponent() or percent-encoding where " +
|
|
16
|
+
"special characters become %XX codes." +
|
|
17
|
+
"\n\n⚠️ CRITICAL: After you call put_file_content, the system " +
|
|
18
|
+
"AUTOMATICALLY replaces your data_url argument with " +
|
|
19
|
+
"'file+session://...' in the conversation history. This is NORMAL " +
|
|
20
|
+
"behavior to save context space. The replacement happens AFTER the " +
|
|
21
|
+
"file is successfully written. When you see 'file+session://...' in " +
|
|
22
|
+
"your previous tool call, this means SUCCESS - the file was created " +
|
|
23
|
+
"with your full content. NEVER retry or attempt to 'fix' this. The " +
|
|
24
|
+
"file+session:// reference is NOT an error - it confirms the " +
|
|
25
|
+
"operation succeeded.";
|
|
26
|
+
if (files.length > 0) {
|
|
27
|
+
prompt += "\n\nAvailable files:\nname,type,summary\n";
|
|
28
|
+
for (const f of files) {
|
|
29
|
+
prompt += `${f.name},${f.mime_type},${f.summary || ""}\n`;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return prompt;
|
|
33
|
+
}
|
package/dist/agent/src/{chat/data/dbSessionFileModels.js → agent/tools/fileManager/types.js}
RENAMED
|
@@ -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.isParsedContent = isParsedContent;
|
|
6
7
|
exports.isFileMetaData = isFileMetaData;
|
|
7
8
|
exports.getSessionFileMimeTypeFromDataUrl = getSessionFileMimeTypeFromDataUrl;
|
|
8
9
|
exports.createSessionFileDataUrl = createSessionFileDataUrl;
|
|
@@ -34,6 +35,12 @@ exports.EXTENSION_TO_SESSION_FILE_MIME_TYPE = {
|
|
|
34
35
|
txt: "text/plain",
|
|
35
36
|
md: "text/markdown",
|
|
36
37
|
};
|
|
38
|
+
function isParsedContent(obj) {
|
|
39
|
+
if (typeof obj !== "object" || obj === null)
|
|
40
|
+
return false;
|
|
41
|
+
const pc = obj;
|
|
42
|
+
return pc.version === 1 && typeof pc.text === "string";
|
|
43
|
+
}
|
|
37
44
|
// Checks that the array of keys matches FileMetaData
|
|
38
45
|
const fileMetaKeys = [
|
|
39
46
|
"xalia/fileUri",
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* General-purpose agent tools.
|
|
4
|
+
*
|
|
5
|
+
* These tools are available to all agents, not just chat-based ones.
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
19
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
20
|
+
};
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.htmlToText = exports.webSearch = exports.makeParseArgsFn = exports.renderTool = exports.openURL = exports.openURLTool = exports.webSearchTool = exports.calculatorEval = exports.calculatorTool = exports.isoWithTimezone = exports.datetimeTool = void 0;
|
|
23
|
+
exports.addDefaultTools = addDefaultTools;
|
|
24
|
+
// Tool implementations
|
|
25
|
+
var datetimeTool_1 = require("./datetimeTool");
|
|
26
|
+
Object.defineProperty(exports, "datetimeTool", { enumerable: true, get: function () { return datetimeTool_1.datetimeTool; } });
|
|
27
|
+
Object.defineProperty(exports, "isoWithTimezone", { enumerable: true, get: function () { return datetimeTool_1.isoWithTimezone; } });
|
|
28
|
+
var calculatorTool_1 = require("./calculatorTool");
|
|
29
|
+
Object.defineProperty(exports, "calculatorTool", { enumerable: true, get: function () { return calculatorTool_1.calculatorTool; } });
|
|
30
|
+
Object.defineProperty(exports, "calculatorEval", { enumerable: true, get: function () { return calculatorTool_1.calculatorEval; } });
|
|
31
|
+
var webSearchTool_1 = require("./webSearchTool");
|
|
32
|
+
Object.defineProperty(exports, "webSearchTool", { enumerable: true, get: function () { return webSearchTool_1.webSearchTool; } });
|
|
33
|
+
var openUrlTool_1 = require("./openUrlTool");
|
|
34
|
+
Object.defineProperty(exports, "openURLTool", { enumerable: true, get: function () { return openUrlTool_1.openURLTool; } });
|
|
35
|
+
Object.defineProperty(exports, "openURL", { enumerable: true, get: function () { return openUrlTool_1.openURL; } });
|
|
36
|
+
var renderTool_1 = require("./renderTool");
|
|
37
|
+
Object.defineProperty(exports, "renderTool", { enumerable: true, get: function () { return renderTool_1.renderTool; } });
|
|
38
|
+
// Utilities
|
|
39
|
+
var utils_1 = require("./utils");
|
|
40
|
+
Object.defineProperty(exports, "makeParseArgsFn", { enumerable: true, get: function () { return utils_1.makeParseArgsFn; } });
|
|
41
|
+
var webSearch_1 = require("./webSearch");
|
|
42
|
+
Object.defineProperty(exports, "webSearch", { enumerable: true, get: function () { return webSearch_1.webSearch; } });
|
|
43
|
+
var htmlToText_1 = require("./contentExtractors/htmlToText");
|
|
44
|
+
Object.defineProperty(exports, "htmlToText", { enumerable: true, get: function () { return htmlToText_1.htmlToText; } });
|
|
45
|
+
// File manager (re-export everything)
|
|
46
|
+
__exportStar(require("./fileManager"), exports);
|
|
47
|
+
// Import tools for addDefaultTools
|
|
48
|
+
const datetimeTool_2 = require("./datetimeTool");
|
|
49
|
+
const calculatorTool_2 = require("./calculatorTool");
|
|
50
|
+
const webSearchTool_2 = require("./webSearchTool");
|
|
51
|
+
const openUrlTool_2 = require("./openUrlTool");
|
|
52
|
+
const renderTool_2 = require("./renderTool");
|
|
53
|
+
const fileManager_1 = require("./fileManager");
|
|
54
|
+
/**
|
|
55
|
+
* Add the default set of general-purpose agent tools.
|
|
56
|
+
*/
|
|
57
|
+
async function addDefaultTools(agent, timezone, _platform, fileManager) {
|
|
58
|
+
await agent.addAgentToolProvider((0, datetimeTool_2.datetimeTool)(timezone));
|
|
59
|
+
await agent.addAgentToolProvider(calculatorTool_2.calculatorTool);
|
|
60
|
+
await agent.addAgentToolProvider((0, renderTool_2.renderTool)(fileManager));
|
|
61
|
+
await agent.addAgentToolProvider((0, webSearchTool_2.webSearchTool)());
|
|
62
|
+
await agent.addAgentToolProvider((0, openUrlTool_2.openURLTool)());
|
|
63
|
+
await agent.addAgentToolProvider((0, fileManager_1.fileManagerTool)(fileManager));
|
|
64
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.openURL = openURL;
|
|
4
|
+
exports.openURLTool = openURLTool;
|
|
5
|
+
const toolSettings_1 = require("../toolSettings");
|
|
6
|
+
const utils_1 = require("./utils");
|
|
7
|
+
const htmlToText_1 = require("./contentExtractors/htmlToText");
|
|
8
|
+
const pdfToText_1 = require("./contentExtractors/pdfToText");
|
|
9
|
+
const OPEN_URL_DESC = {
|
|
10
|
+
type: "function",
|
|
11
|
+
function: {
|
|
12
|
+
name: "open_url",
|
|
13
|
+
description: "Download and extract text content from a URL (supports HTML and PDF)",
|
|
14
|
+
parameters: {
|
|
15
|
+
type: "object",
|
|
16
|
+
properties: {
|
|
17
|
+
url: {
|
|
18
|
+
type: "string",
|
|
19
|
+
description: "URL to download (HTML pages or PDF files)",
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
required: ["url"],
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
async function openURL(url) {
|
|
27
|
+
const response = await fetch(url);
|
|
28
|
+
if (!response.ok) {
|
|
29
|
+
const status = String(response.status);
|
|
30
|
+
const code = response.statusText;
|
|
31
|
+
throw new Error(`Failed to fetch ${url}: ${status} ${code}`);
|
|
32
|
+
}
|
|
33
|
+
const contentType = response.headers.get("content-type") || "";
|
|
34
|
+
const isPdf = contentType.includes("application/pdf") ||
|
|
35
|
+
url.toLowerCase().endsWith(".pdf");
|
|
36
|
+
if (isPdf) {
|
|
37
|
+
const buffer = await response.arrayBuffer();
|
|
38
|
+
return (0, pdfToText_1.pdfToText)(buffer, toolSettings_1.OPEN_URL_MAX_LENGTH);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
const html = await response.text();
|
|
42
|
+
return (0, htmlToText_1.htmlToText)(html, toolSettings_1.OPEN_URL_MAX_LENGTH);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function openURLTool() {
|
|
46
|
+
const getURL = (0, utils_1.makeParseArgsFn)(["url"]);
|
|
47
|
+
const toolFn = async (_, args) => {
|
|
48
|
+
const { url } = getURL(args);
|
|
49
|
+
return { response: await openURL(url) };
|
|
50
|
+
};
|
|
51
|
+
return {
|
|
52
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
53
|
+
setup: async (agent) => {
|
|
54
|
+
agent.addAgentTool(OPEN_URL_DESC, toolFn);
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.renderTool = renderTool;
|
|
4
|
+
const utils_1 = require("./utils");
|
|
5
|
+
const RENDER_DESC = {
|
|
6
|
+
type: "function",
|
|
7
|
+
function: {
|
|
8
|
+
name: "render",
|
|
9
|
+
description: [
|
|
10
|
+
"Display HTML using only safe elements",
|
|
11
|
+
"Never include <script>, <iframe>, <object>, <embed>, <form>, <meta>,",
|
|
12
|
+
"<link>, <style>, event handlers (onclick, etc.), or javascript: URLs.",
|
|
13
|
+
"If the tool result is [HTML_SANITIZATION_WARNING], do not mention it.",
|
|
14
|
+
"Retry with only safe elements. If warning repeats, tell the user you",
|
|
15
|
+
"cannot render unsafe HTML.",
|
|
16
|
+
].join(" "),
|
|
17
|
+
parameters: {
|
|
18
|
+
type: "object",
|
|
19
|
+
properties: {
|
|
20
|
+
name: { type: "string", description: "Filename for the HTML" },
|
|
21
|
+
summary: { type: "string", description: "One line summary" },
|
|
22
|
+
html: { type: "string", description: "HTML fragment to render" },
|
|
23
|
+
},
|
|
24
|
+
required: ["name", "summary", "html"],
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
function validateHtmlSafety(html) {
|
|
29
|
+
const issues = [];
|
|
30
|
+
if (/<script[\s>]/i.test(html))
|
|
31
|
+
issues.push("<script> tag");
|
|
32
|
+
if (/<iframe[\s>]/i.test(html))
|
|
33
|
+
issues.push("<iframe> tag");
|
|
34
|
+
if (/<object[\s>]/i.test(html))
|
|
35
|
+
issues.push("<object> tag");
|
|
36
|
+
if (/<embed[\s>]/i.test(html))
|
|
37
|
+
issues.push("<embed> tag");
|
|
38
|
+
if (/\bon\w+\s*=/.test(html))
|
|
39
|
+
issues.push("event handler (e.g., onclick)");
|
|
40
|
+
if (/javascript:/i.test(html))
|
|
41
|
+
issues.push("javascript: URL");
|
|
42
|
+
if (/<meta[\s>]/i.test(html))
|
|
43
|
+
issues.push("<meta> tag");
|
|
44
|
+
if (/<form[\s>]/i.test(html))
|
|
45
|
+
issues.push("<form> tag");
|
|
46
|
+
if (/<style[\s>]/i.test(html))
|
|
47
|
+
issues.push("<style> tag");
|
|
48
|
+
if (/<link[\s>]/i.test(html))
|
|
49
|
+
issues.push("<link> tag");
|
|
50
|
+
if (issues.length > 0) {
|
|
51
|
+
return `Unsafe HTML: ${issues.join(", ")}`;
|
|
52
|
+
}
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
function renderTool(fileManager) {
|
|
56
|
+
const getNameSummeryHtml = (0, utils_1.makeParseArgsFn)([
|
|
57
|
+
"name",
|
|
58
|
+
"summary",
|
|
59
|
+
"html",
|
|
60
|
+
]);
|
|
61
|
+
const toolFn = async (_, args) => {
|
|
62
|
+
const { name, summary, html } = getNameSummeryHtml(args);
|
|
63
|
+
const safetyError = validateHtmlSafety(html);
|
|
64
|
+
if (safetyError) {
|
|
65
|
+
return {
|
|
66
|
+
response: "[HTML_SANITIZATION_WARNING]",
|
|
67
|
+
overwriteResponse: "",
|
|
68
|
+
structuredContent: {
|
|
69
|
+
kind: "htmlSanitizationWarning",
|
|
70
|
+
message: safetyError,
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
const mimeType = "text/html";
|
|
75
|
+
const dataURL = `data:${mimeType},${html}`;
|
|
76
|
+
await fileManager.putFileContent(name, summary, dataURL);
|
|
77
|
+
const uri = fileManager.getSessionFileRelativeUrl(name);
|
|
78
|
+
return {
|
|
79
|
+
response: "",
|
|
80
|
+
_meta: { "xalia/fileUri": uri, "xalia/fileMimeType": mimeType },
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
return {
|
|
84
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
85
|
+
setup: async (agent) => {
|
|
86
|
+
agent.addAgentTool(RENDER_DESC, toolFn);
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|