mirror of
https://github.com/Mintplex-Labs/anything-llm
synced 2026-04-25 17:15:37 +02:00
* Powerpoint File Creation (#5278) * wip * download card * UI for downloading * move to fs system with endpoint to pull files * refactor UI * final-pass * remove save-file-browser skill and refactor * remove fileDownload event * reset * reset file * reset timeout * persist toggle * Txt creation (#5279) * wip * download card * UI for downloading * move to fs system with endpoint to pull files * refactor UI * final-pass * remove save-file-browser skill and refactor * remove fileDownload event * reset * reset file * reset timeout * wip * persist toggle * add arbitrary text creation file * Add PDF document generation with markdown formatting (#5283) add support for branding in bottom right corner refactor core utils and frontend rendering * Xlsx document creation (#5284) add Excel doc & sheet creation * Basic docx creation (#5285) * Basic docx creation * add test theme support + styling and title pages * simplify skill selection * handle TG attachments * send documents over tg * lazy import * pin deps * fix lock * i18n for file creation (#5286) i18n for file-creation connect #5280 * theme overhaul * Add PPTX subagent for better results * forgot files * Add PPTX subagent for better results (#5287) * Add PPTX subagent for better results * forgot files * make sub-agent use proper tool calling if it can and better UI hints
331 lines
11 KiB
JavaScript
331 lines
11 KiB
JavaScript
import React, { useEffect, useState, useRef } from "react";
|
|
import Toggle, { SimpleToggleSwitch } from "@/components/lib/Toggle";
|
|
import { Link } from "react-router-dom";
|
|
import { useTranslation, Trans } from "react-i18next";
|
|
import {
|
|
Warning,
|
|
File,
|
|
Files,
|
|
PencilSimple,
|
|
FloppyDisk,
|
|
FolderPlus,
|
|
FolderOpen,
|
|
ArrowsLeftRight,
|
|
MagnifyingGlass,
|
|
Info,
|
|
CircleNotch,
|
|
Copy,
|
|
} from "@phosphor-icons/react";
|
|
import Admin from "@/models/admin";
|
|
|
|
const getFileSystemSubSkills = (t) => {
|
|
return [
|
|
{
|
|
name: "filesystem-read-text-file",
|
|
title: t("agent.skill.filesystem.skills.read-text-file.title"),
|
|
description: t(
|
|
"agent.skill.filesystem.skills.read-text-file.description"
|
|
),
|
|
icon: File,
|
|
category: "read",
|
|
},
|
|
{
|
|
name: "filesystem-read-multiple-files",
|
|
title: t("agent.skill.filesystem.skills.read-multiple-files.title"),
|
|
description: t(
|
|
"agent.skill.filesystem.skills.read-multiple-files.description"
|
|
),
|
|
icon: Files,
|
|
category: "read",
|
|
},
|
|
{
|
|
name: "filesystem-list-directory",
|
|
title: t("agent.skill.filesystem.skills.list-directory.title"),
|
|
description: t(
|
|
"agent.skill.filesystem.skills.list-directory.description"
|
|
),
|
|
icon: FolderOpen,
|
|
category: "read",
|
|
},
|
|
{
|
|
name: "filesystem-search-files",
|
|
title: t("agent.skill.filesystem.skills.search-files.title"),
|
|
description: t("agent.skill.filesystem.skills.search-files.description"),
|
|
icon: MagnifyingGlass,
|
|
category: "read",
|
|
},
|
|
{
|
|
name: "filesystem-get-file-info",
|
|
title: t("agent.skill.filesystem.skills.get-file-info.title"),
|
|
description: t("agent.skill.filesystem.skills.get-file-info.description"),
|
|
icon: Info,
|
|
category: "read",
|
|
},
|
|
{
|
|
name: "filesystem-write-text-file",
|
|
title: t("agent.skill.filesystem.skills.write-text-file.title"),
|
|
description: t(
|
|
"agent.skill.filesystem.skills.write-text-file.description"
|
|
),
|
|
icon: FloppyDisk,
|
|
category: "write",
|
|
},
|
|
{
|
|
name: "filesystem-edit-file",
|
|
title: t("agent.skill.filesystem.skills.edit-file.title"),
|
|
description: t("agent.skill.filesystem.skills.edit-file.description"),
|
|
icon: PencilSimple,
|
|
category: "write",
|
|
},
|
|
{
|
|
name: "filesystem-create-directory",
|
|
title: t("agent.skill.filesystem.skills.create-directory.title"),
|
|
description: t(
|
|
"agent.skill.filesystem.skills.create-directory.description"
|
|
),
|
|
icon: FolderPlus,
|
|
category: "write",
|
|
},
|
|
{
|
|
name: "filesystem-copy-file",
|
|
title: t("agent.skill.filesystem.skills.copy-file.title"),
|
|
description: t("agent.skill.filesystem.skills.copy-file.description"),
|
|
icon: Copy,
|
|
category: "write",
|
|
},
|
|
{
|
|
name: "filesystem-move-file",
|
|
title: t("agent.skill.filesystem.skills.move-file.title"),
|
|
description: t("agent.skill.filesystem.skills.move-file.description"),
|
|
icon: ArrowsLeftRight,
|
|
category: "write",
|
|
},
|
|
];
|
|
};
|
|
|
|
export default function FileSystemSkillPanel({
|
|
title,
|
|
skill,
|
|
toggleSkill,
|
|
enabled = false,
|
|
disabled = false,
|
|
image,
|
|
icon,
|
|
setHasChanges,
|
|
hasChanges = false,
|
|
}) {
|
|
const { t } = useTranslation();
|
|
const [disabledSubSkills, setDisabledSubSkills] = useState([]);
|
|
const [loading, setLoading] = useState(true);
|
|
const prevHasChanges = useRef(hasChanges);
|
|
const FILESYSTEM_SUB_SKILLS = getFileSystemSubSkills(t);
|
|
|
|
useEffect(() => {
|
|
setLoading(true);
|
|
Admin.systemPreferencesByFields(["disabled_filesystem_skills"])
|
|
.then((res) =>
|
|
setDisabledSubSkills(res?.settings?.disabled_filesystem_skills ?? [])
|
|
)
|
|
.catch(() => setDisabledSubSkills([]))
|
|
.finally(() => setLoading(false));
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (prevHasChanges.current === true && hasChanges === false) {
|
|
Admin.systemPreferencesByFields(["disabled_filesystem_skills"])
|
|
.then((res) =>
|
|
setDisabledSubSkills(res?.settings?.disabled_filesystem_skills ?? [])
|
|
)
|
|
.catch(() => {});
|
|
}
|
|
prevHasChanges.current = hasChanges;
|
|
}, [hasChanges]);
|
|
|
|
function toggleSubSkill(subSkillName) {
|
|
setHasChanges(true);
|
|
setDisabledSubSkills((prev) => {
|
|
if (prev.includes(subSkillName)) {
|
|
return prev.filter((s) => s !== subSkillName);
|
|
}
|
|
return [...prev, subSkillName];
|
|
});
|
|
}
|
|
const readSkills = FILESYSTEM_SUB_SKILLS.filter((s) => s.category === "read");
|
|
const writeSkills = FILESYSTEM_SUB_SKILLS.filter(
|
|
(s) => s.category === "write"
|
|
);
|
|
|
|
return (
|
|
<div className="p-2">
|
|
<div className="flex flex-col gap-y-[18px] max-w-[500px]">
|
|
<div className="flex w-full justify-between items-center">
|
|
<div className="flex items-center gap-x-2">
|
|
{icon &&
|
|
React.createElement(icon, {
|
|
size: 24,
|
|
color: "var(--theme-text-primary)",
|
|
weight: "bold",
|
|
})}
|
|
<label
|
|
htmlFor="name"
|
|
className="text-theme-text-primary text-md font-bold"
|
|
>
|
|
{title}
|
|
</label>
|
|
</div>
|
|
<Toggle
|
|
size="lg"
|
|
enabled={enabled}
|
|
disabled={disabled}
|
|
onChange={() => toggleSkill(skill)}
|
|
/>
|
|
</div>
|
|
|
|
<img src={image} alt={title} className="w-full rounded-md" />
|
|
<WarningBanner />
|
|
<div className="flex flex-col gap-y-1">
|
|
<p className="text-theme-text-secondary text-opacity-60 text-xs font-medium">
|
|
{t("agent.skill.filesystem.description")}
|
|
</p>
|
|
<Link
|
|
to="/docs/guides/agent-skills/filesystem-agent"
|
|
target="_blank"
|
|
className="text-sky-400 hover:text-sky-500 text-xs font-medium underline"
|
|
>
|
|
{t("agent.skill.filesystem.learnMore")} →
|
|
</Link>
|
|
</div>
|
|
|
|
{enabled && (
|
|
<>
|
|
<input
|
|
name="system::disabled_filesystem_skills"
|
|
type="hidden"
|
|
value={disabledSubSkills.join(",")}
|
|
/>
|
|
<div className="flex flex-col mt-2 gap-y-4">
|
|
<div className="flex justify-between items-center">
|
|
<p className="text-theme-text-primary font-semibold text-sm">
|
|
{t("agent.skill.filesystem.configuration")}
|
|
</p>
|
|
</div>
|
|
{loading ? (
|
|
<div className="flex items-center justify-center py-4">
|
|
<CircleNotch
|
|
size={24}
|
|
className="animate-spin text-theme-text-primary"
|
|
/>
|
|
</div>
|
|
) : (
|
|
<>
|
|
<div className="flex flex-col gap-y-2">
|
|
<p className="text-theme-text-secondary text-xs font-medium uppercase tracking-wide">
|
|
{t("agent.skill.filesystem.readActions")}
|
|
</p>
|
|
<div className="flex flex-col gap-y-1">
|
|
{readSkills.map((subSkill) => (
|
|
<SubSkillRow
|
|
key={subSkill.name}
|
|
subSkill={subSkill}
|
|
disabled={disabledSubSkills.includes(subSkill.name)}
|
|
onToggle={() => toggleSubSkill(subSkill.name)}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex flex-col gap-y-2">
|
|
<p className="text-theme-text-secondary text-xs font-medium uppercase tracking-wide flex items-center gap-x-1">
|
|
<Warning
|
|
size={12}
|
|
className="text-orange-400"
|
|
weight="fill"
|
|
/>
|
|
{t("agent.skill.filesystem.writeActions")}
|
|
</p>
|
|
<div className="flex flex-col gap-y-1">
|
|
{writeSkills.map((subSkill) => (
|
|
<SubSkillRow
|
|
key={subSkill.name}
|
|
subSkill={subSkill}
|
|
disabled={disabledSubSkills.includes(subSkill.name)}
|
|
onToggle={() => toggleSubSkill(subSkill.name)}
|
|
isWriteOperation
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</>
|
|
)}
|
|
</div>
|
|
</>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function WarningBanner() {
|
|
return (
|
|
<div className="flex items-start gap-x-2.5 p-2.5 bg-orange-800/20 light:bg-orange-800/10 text-orange-400 light:text-orange-600 border border-orange-400/30 rounded-lg items-center">
|
|
<Warning size={20} className="flex-shrink-0 mt-0.5" weight="fill" />
|
|
<p className="text-xs font-medium">
|
|
<Trans
|
|
i18nKey="agent.skill.filesystem.warning"
|
|
components={{
|
|
link: (
|
|
<Link
|
|
to="/docs/guides/agent-skills/filesystem-agent"
|
|
target="_blank"
|
|
className="underline hover:text-orange-300 light:hover:text-orange-700"
|
|
/>
|
|
),
|
|
}}
|
|
/>
|
|
</p>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function SubSkillRow({ subSkill, disabled, onToggle, isWriteOperation }) {
|
|
const Icon = subSkill.icon;
|
|
return (
|
|
<div
|
|
className={`flex items-center justify-between p-2 rounded-lg border ${
|
|
disabled
|
|
? "bg-theme-bg-secondary/30 border-theme-sidebar-border/30"
|
|
: isWriteOperation
|
|
? "bg-orange-900/10 border-orange-400/20 light:bg-orange-800/10 text-orange-400 light:text-orange-600"
|
|
: "bg-theme-bg-secondary/50 border-theme-sidebar-border/50"
|
|
}`}
|
|
>
|
|
<div className="flex items-center gap-x-2">
|
|
<Icon
|
|
size={16}
|
|
className={
|
|
disabled
|
|
? "text-theme-text-secondary/50"
|
|
: isWriteOperation
|
|
? "text-orange-400"
|
|
: "text-theme-text-primary"
|
|
}
|
|
weight="bold"
|
|
/>
|
|
<div className="flex flex-col">
|
|
<span
|
|
className={`text-sm font-medium ${disabled ? "text-theme-text-secondary/50" : "text-theme-text-primary"}`}
|
|
>
|
|
{subSkill.title}
|
|
</span>
|
|
<span
|
|
className={`text-xs ${disabled ? "text-theme-text-secondary/40" : "text-theme-text-secondary"}`}
|
|
>
|
|
{subSkill.description}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<SimpleToggleSwitch enabled={!disabled} onChange={onToggle} size="md" />
|
|
</div>
|
|
);
|
|
}
|