Skip to content

Commit

Permalink
Adjust importing process
Browse files Browse the repository at this point in the history
  • Loading branch information
timothycarambat committed Nov 21, 2024
1 parent 7abe3d8 commit 539abbb
Show file tree
Hide file tree
Showing 10 changed files with 131 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@ export default function MistralAiOptions({ settings }) {
className="bg-theme-settings-input-bg border-gray-500 text-white text-sm rounded-lg block w-full p-2.5"
>
<optgroup label="Available embedding models">
{[
"mistral-embed",
].map((model) => {
{["mistral-embed"].map((model) => {
return (
<option key={model} value={model}>
{model}
Expand Down
5 changes: 2 additions & 3 deletions frontend/src/locales/resources.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import Italian from "./it/common.js";
import Portuguese from "./pt_BR/common.js";
import Hebrew from "./he/common.js";
import Dutch from "./nl/common.js";
import Vietnamese from "./vn/common.js";
import Vietnamese from "./vn/common.js";
import TraditionalChinese from "./zh_TW/common.js";

export const defaultNS = "common";
Expand Down Expand Up @@ -66,8 +66,7 @@ export const resources = {
nl: {
common: Dutch,
},
vi: {
vi: {
common: Vietnamese,
},

};
3 changes: 1 addition & 2 deletions frontend/src/locales/vn/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,7 @@ const TRANSLATIONS = {
},
"password-reset": {
title: "Mật khẩu Đặt lại",
description:
"Cung cấp thông tin cần thiết dưới đây để đặt lại mật khẩu.",
description: "Cung cấp thông tin cần thiết dưới đây để đặt lại mật khẩu.",
"recovery-codes": "Mã khôi phục",
"recovery-code": "Mã khôi phục {{index}}",
"back-to-login": "Back to Đăng nhập",
Expand Down
14 changes: 14 additions & 0 deletions frontend/src/models/experimental/agentPlugins.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,20 @@ const AgentPlugins = {
return false;
});
},
deletePlugin: async function (hubId) {
return await fetch(`${API_BASE}/experimental/agent-plugins/${hubId}`, {
method: "DELETE",
headers: baseHeaders(),
})
.then((res) => {
if (!res.ok) throw new Error("Could not delete agent plugin config.");
return true;
})
.catch((e) => {
console.error(e);
return false;
});
},
};

export default AgentPlugins;
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import System from "@/models/system";
import showToast from "@/utils/toast";
import { Plug } from "@phosphor-icons/react";
import { useEffect, useState } from "react";
import { Gear, Plug } from "@phosphor-icons/react";
import { useEffect, useState, useRef } from "react";
import { sentenceCase } from "text-case";

/**
Expand Down Expand Up @@ -96,7 +96,7 @@ export default function ImportedSkillConfig({
useEffect(() => {
setHasChanges(
JSON.stringify(inputs) !==
JSON.stringify(inputsFromArgs(selectedSkill.setup_args))
JSON.stringify(inputsFromArgs(selectedSkill.setup_args))
);
}, [inputs]);

Expand All @@ -119,6 +119,10 @@ export default function ImportedSkillConfig({
<div className="peer-disabled:opacity-50 pointer-events-none peer h-6 w-11 rounded-full bg-[#CFCFD0] after:absolute after:left-[2px] after:top-[2px] after:h-5 after:w-5 after:rounded-full after:shadow-xl after:border-none after:bg-white after:box-shadow-md after:transition-all after:content-[''] peer-checked:bg-[#32D583] peer-checked:after:translate-x-full peer-checked:after:border-white peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-transparent"></div>
<span className="ml-3 text-sm font-medium"></span>
</label>
<ManageSkillMenu
config={config}
setImportedSkills={setImportedSkills}
/>
</div>
<p className="text-white text-opacity-60 text-xs font-medium py-1.5">
{config.description} by{" "}
Expand Down Expand Up @@ -178,3 +182,64 @@ export default function ImportedSkillConfig({
</>
);
}

function ManageSkillMenu({ config, setImportedSkills }) {
const [open, setOpen] = useState(false);
const menuRef = useRef(null);

async function deleteSkill() {
if (
!window.confirm(
"Are you sure you want to delete this skill? This action cannot be undone."
)
)
return;
const success = await System.experimentalFeatures.agentPlugins.deletePlugin(
config.hubId
);
if (success) {
setImportedSkills((prev) => prev.filter((s) => s.hubId !== config.hubId));
showToast("Skill deleted successfully.", "success");
setOpen(false);
} else {
showToast("Failed to delete skill.", "error");
}
}

useEffect(() => {
const handleClickOutside = (event) => {
if (menuRef.current && !menuRef.current.contains(event.target)) {
setOpen(false);
}
};

document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, []);

if (!config.hubId) return null;
return (
<div className="relative" ref={menuRef}>
<button
type="button"
onClick={() => setOpen(!open)}
className={`border-none transition duration-200 hover:rotate-90 outline-none ring-none ${open ? "rotate-90" : ""}`}
>
<Gear size={24} weight="bold" />
</button>
{open && (
<div className="absolute w-[100px] -top-1 left-7 mt-1 border-[1.5px] border-white/40 rounded-lg bg-theme-action-menu-bg flex flex-col shadow-[0_4px_14px_rgba(0,0,0,0.25)] text-white z-99 md:z-10">
<button
type="button"
onClick={deleteSkill}
className="border-none flex items-center rounded-lg gap-x-2 hover:bg-theme-action-menu-item-hover py-1.5 px-2 transition-colors duration-200 w-full text-left"
>
<span className="text-sm">Delete Skill</span>
</button>
</div>
)}
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ export default function SystemPrompt({ item, setStep }) {
</p>

<div className="flex flex-col gap-y-2">
<p className="text-white/60 light:text-theme-text-secondary font-semibold">Provided system prompt:</p>
<p className="text-white/60 light:text-theme-text-secondary font-semibold">
Provided system prompt:
</p>
<div className="w-full text-theme-text-primary text-md flex flex-col max-h-[calc(300px)] overflow-y-auto">
<p className="text-white/60 light:text-theme-text-secondary font-mono bg-zinc-900 light:bg-slate-200 px-2 py-1 rounded-md text-sm whitespace-pre-line">
{item.prompt}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export default function CommunityHubImportItemFlow() {
<div className="flex flex-col gap-y-[18px] mt-10 w-[360px] flex-shrink-0">
<SideBarSelection setStep={setStep} currentStep={step} />
</div>
<div className="overflow-y-auto pb-[74px] h-screen">
<div className="overflow-y-auto pb-[200px] h-screen no-scroll">
<div className="ml-8">
{StepPage.component({ settings, setSettings, setStep })}
</div>
Expand Down
15 changes: 15 additions & 0 deletions server/endpoints/experimental/imported-agent-plugins.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,21 @@ function importedAgentPluginEndpoints(app) {
}
}
);

app.delete(
"/experimental/agent-plugins/:hubId",
[validatedRequest, flexUserRoleValid([ROLES.admin])],
async (request, response) => {
try {
const { hubId } = request.params;
const result = ImportedPlugin.deletePlugin(hubId);
response.status(200).json(result);
} catch (e) {
console.error(e);
response.status(500).end();
}
}
);
}

module.exports = { importedAgentPluginEndpoints };
2 changes: 1 addition & 1 deletion server/utils/EmbeddingEngines/mistral/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@ class MistralEmbedder {

module.exports = {
MistralEmbedder,
};
};
29 changes: 25 additions & 4 deletions server/utils/agents/imported.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,20 @@ class ImportedPlugin {
return updatedConfig;
}

/**
* Deletes a plugin. Removes the entire folder of the object.
* @param {string} hubId - The hub ID of the plugin.
* @returns {boolean} - True if the plugin was deleted, false otherwise.
*/
static deletePlugin(hubId) {
if (!hubId) throw new Error("No plugin hubID passed.");
const pluginFolder = path.resolve(pluginsPath, normalizePath(hubId));
if (!this.isValidLocation(pluginFolder)) return;
fs.rmSync(pluginFolder, { recursive: true });
return true;
}

/**
/**
* Validates if the handler.js file exists for the given plugin.
* @param {string} hubId - The hub ID of the plugin.
Expand Down Expand Up @@ -195,6 +209,9 @@ class ImportedPlugin {
*/
static async importCommunityItemFromUrl(url, item) {
this.checkPluginFolderExists();
const hubId = item.id;
if (!hubId) return { success: false, error: "No hubId passed to import." };

const zipFilePath = path.resolve(pluginsPath, `${item.id}.zip`);
const pluginFile = item.manifest.files.find(
(file) => file.name === "plugin.json"
Expand All @@ -205,10 +222,6 @@ class ImportedPlugin {
error: "No plugin.json file found in manifest.",
};

const hubId = safeJsonParse(pluginFile.content).hubId || null;
if (!hubId)
return { success: false, error: "No hubId found in plugin.json." };

const pluginFolder = path.resolve(pluginsPath, normalizePath(hubId));
if (fs.existsSync(pluginFolder))
console.log(
Expand Down Expand Up @@ -262,6 +275,14 @@ class ImportedPlugin {
const zip = new AdmZip(zipFilePath);
zip.extractAllTo(pluginFolder);

// We want to make sure specific keys are set to the proper values for
// plugin.json so we read and overwrite the file with the proper values.
const pluginJsonPath = path.resolve(pluginFolder, "plugin.json");
const pluginJson = safeJsonParse(fs.readFileSync(pluginJsonPath, "utf8"));
pluginJson.active = false;
pluginJson.hubId = hubId;
fs.writeFileSync(pluginJsonPath, JSON.stringify(pluginJson, null, 2));

console.log(
`ImportedPlugin.importCommunityItemFromUrl - successfully imported plugin to agent-skills/${hubId}`
);
Expand Down

0 comments on commit 539abbb

Please sign in to comment.