mirror of
https://github.com/Mintplex-Labs/anything-llm
synced 2026-04-26 01:25:15 +02:00
* wip * collector parse fixes * refactor for class and also operation for reading * add skill management panel * management panel + lint * management panel + lint * Hide skill in non-docker context * add ask-prompt for edit tool calls * fix dep * fix execa pkg (unused in codebase) * simplify search with ripgrep only and build deps * Fs skill i18n (#5264) i18n * add copy file support * fix translations
158 lines
6.0 KiB
JavaScript
158 lines
6.0 KiB
JavaScript
const path = require("path");
|
|
const filesystem = require("./lib.js");
|
|
|
|
module.exports.FilesystemReadMultipleFiles = {
|
|
name: "filesystem-read-multiple-files",
|
|
plugin: function () {
|
|
return {
|
|
name: "filesystem-read-multiple-files",
|
|
setup(aibitat) {
|
|
aibitat.function({
|
|
super: aibitat,
|
|
name: this.name,
|
|
description:
|
|
"Read multiple files at once when you know their exact paths. " +
|
|
"Supports many file types: text, code, PDFs, Word docs, audio/video (transcribed to text), and more. " +
|
|
"Image files (png, jpg, jpeg, gif, webp, svg, bmp) are automatically attached for you to view and analyze visually. " +
|
|
"IMPORTANT: If you don't know the file paths, use 'filesystem-search-files' first " +
|
|
"with 'includeFileContents: true' to find and read files in one step. " +
|
|
"Each file's content is returned with its path. Failed reads won't stop the operation.",
|
|
examples: [
|
|
{
|
|
prompt: "Read both the package.json and README.md files",
|
|
call: JSON.stringify({ paths: ["package.json", "README.md"] }),
|
|
},
|
|
{
|
|
prompt: "Compare the config files in dev and prod folders",
|
|
call: JSON.stringify({
|
|
paths: ["dev/config.json", "prod/config.json"],
|
|
}),
|
|
},
|
|
{
|
|
prompt: "Show me all the screenshots",
|
|
call: JSON.stringify({
|
|
paths: ["screenshot1.png", "screenshot2.png"],
|
|
}),
|
|
},
|
|
],
|
|
parameters: {
|
|
$schema: "http://json-schema.org/draft-07/schema#",
|
|
type: "object",
|
|
properties: {
|
|
paths: {
|
|
type: "array",
|
|
items: { type: "string" },
|
|
minItems: 1,
|
|
description:
|
|
"Array of file paths to read. Each path must be a string pointing to a valid file within allowed directories.",
|
|
},
|
|
},
|
|
required: ["paths"],
|
|
additionalProperties: false,
|
|
},
|
|
handler: async function ({ paths = [] }) {
|
|
try {
|
|
this.super.handlerProps.log(
|
|
`Using the filesystem-read-multiple-files tool.`
|
|
);
|
|
|
|
if (!Array.isArray(paths) || paths.length === 0) {
|
|
return "Error: At least one file path must be provided.";
|
|
}
|
|
|
|
this.super.introspect(
|
|
`${this.caller}: Reading ${paths.length} files`
|
|
);
|
|
|
|
const results = await Promise.all(
|
|
paths.map(async (filePath) => {
|
|
try {
|
|
const validPath = await filesystem.validatePath(filePath);
|
|
const filename = path.basename(validPath);
|
|
|
|
if (filesystem.isImageFile(validPath)) {
|
|
const attachment =
|
|
await filesystem.readImageAsAttachment(validPath);
|
|
if (attachment) {
|
|
this.super.addToolAttachment?.(attachment);
|
|
return {
|
|
filePath,
|
|
content: `[Image "${filename}" attached for viewing]`,
|
|
success: true,
|
|
isImage: true,
|
|
};
|
|
}
|
|
return {
|
|
filePath,
|
|
content: `Error - Could not read image file`,
|
|
success: false,
|
|
};
|
|
}
|
|
|
|
const content = await filesystem.readFileContent(validPath);
|
|
|
|
this.super.addCitation?.({
|
|
id: `fs-${Buffer.from(validPath).toString("base64url").slice(0, 32)}`,
|
|
title: filename,
|
|
text: content,
|
|
chunkSource: validPath,
|
|
score: null,
|
|
});
|
|
|
|
return { filePath, content, success: true };
|
|
} catch (error) {
|
|
return {
|
|
filePath,
|
|
content: `Error - ${error.message}`,
|
|
success: false,
|
|
};
|
|
}
|
|
})
|
|
);
|
|
|
|
const combinedContent = results
|
|
.map((r) =>
|
|
r.success
|
|
? `${r.filePath}:\n${r.content}\n`
|
|
: `${r.filePath}: ${r.content}`
|
|
)
|
|
.join("\n---\n");
|
|
|
|
const { content: finalContent, wasTruncated } =
|
|
filesystem.truncateContentForContext(
|
|
combinedContent,
|
|
this.super,
|
|
"[Content truncated - combined files exceed context limit. Consider reading fewer files at once.]"
|
|
);
|
|
|
|
if (wasTruncated) {
|
|
this.super.introspect(
|
|
`${this.caller}: Combined content was truncated to fit context limit`
|
|
);
|
|
}
|
|
|
|
const imageCount = results.filter((r) => r.isImage).length;
|
|
const textCount = results.filter(
|
|
(r) => r.success && !r.isImage
|
|
).length;
|
|
let introspectMsg = `Successfully processed ${paths.length} files`;
|
|
if (imageCount > 0) {
|
|
introspectMsg += ` (${imageCount} image${imageCount > 1 ? "s" : ""} attached, ${textCount} text file${textCount !== 1 ? "s" : ""} read)`;
|
|
}
|
|
this.super.introspect(introspectMsg);
|
|
|
|
return finalContent;
|
|
} catch (e) {
|
|
this.super.handlerProps.log(
|
|
`filesystem-read-multiple-files error: ${e.message}`
|
|
);
|
|
this.super.introspect(`Error: ${e.message}`);
|
|
return `Error reading files: ${e.message}`;
|
|
}
|
|
},
|
|
});
|
|
},
|
|
};
|
|
},
|
|
};
|