Skip to content

Commit

Permalink
Toolkit update (#937)
Browse files Browse the repository at this point in the history
  • Loading branch information
luciferlinx101 committed Aug 3, 2023
1 parent 059f766 commit a8bb0bb
Show file tree
Hide file tree
Showing 7 changed files with 267 additions and 31 deletions.
82 changes: 56 additions & 26 deletions gui/pages/Content/Marketplace/ToolkitTemplate.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@ import styles3 from '../Agents/Agents.module.css';
import {ToastContainer, toast} from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import styles2 from "./Market.module.css"
import {fetchToolTemplateOverview, installToolkitTemplate} from "@/pages/api/DashboardService";
import {
checkToolkitUpdate,
fetchToolTemplateOverview,
installToolkitTemplate,
updateMarketplaceToolTemplate
} from "@/pages/api/DashboardService";
import {EventBus} from "@/utils/eventBus";
import ReactMarkdown from 'react-markdown';
import axios from 'axios';
Expand All @@ -17,29 +22,18 @@ export default function ToolkitTemplate({template, env}) {
const [markdownContent, setMarkdownContent] = useState('');

useEffect(() => {
setInstalled(template && template.is_installed ? 'Installed' : 'Install');
if (window.location.href.toLowerCase().includes('marketplace')) {
setInstalled('Sign in to install');
axios.get(`https://app.superagi.com/api/toolkits/marketplace/readme/${template.name}`)
.then((response) => {
setMarkdownContent(response.data || '');
setRightPanel(response.data ? 'overview' : 'tool_view');
})
.catch((error) => {
setRightPanel('tool_view');
console.error('Error fetching template details:', error);
});
} else {
fetchToolTemplateOverview(template.name)
.then((response) => {
setMarkdownContent(response.data || '');
setRightPanel(response.data ? 'overview' : 'tool_view');
})
.catch((error) => {
setRightPanel('tool_view');
console.error('Error fetching template details:', error);
});
if(template.is_installed && !window.location.href.toLowerCase().includes('marketplace')) {
checkToolkitUpdate(template.name).then((response) => {
setInstalled(response.data ? 'Update' : 'Installed');
})
.catch((error) => {
console.error('Error fetching update details:', error);
});
}
else{
setInstalled(window.location.href.toLowerCase().includes('marketplace') ? 'Sign in to install' : 'Install');
}
fetchReadme()
}, []);

function handleInstallClick() {
Expand All @@ -53,6 +47,18 @@ export default function ToolkitTemplate({template, env}) {
return;
}

if(installed === "Update"){
updateMarketplaceToolTemplate(template.name)
.then((response) => {
toast.success("Template Updated", {autoClose: 1800});
setInstalled('Installed');
})
.catch((error) => {
console.error('Error installing template:', error);
});
return;
}

if (template && template.is_installed) {
toast.error("Template is already installed", {autoClose: 1800});
return;
Expand All @@ -72,6 +78,30 @@ export default function ToolkitTemplate({template, env}) {
EventBus.emit('goToMarketplace', {});
}

function fetchReadme() {
if (window.location.href.toLowerCase().includes('marketplace')) {
axios.get(`https://app.superagi.com/api/toolkits/marketplace/readme/${template.name}`)
.then((response) => {
setMarkdownContent(response.data || '');
setRightPanel(response.data ? 'overview' : 'tool_view');
})
.catch((error) => {
setRightPanel('tool_view');
console.error('Error fetching template details:', error);
});
} else {
fetchToolTemplateOverview(template.name)
.then((response) => {
setMarkdownContent(response.data || '');
setRightPanel(response.data ? 'overview' : 'tool_view');
})
.catch((error) => {
setRightPanel('tool_view');
console.error('Error fetching template details:', error);
});
}
}

return (
<>
<div>
Expand All @@ -96,10 +126,10 @@ export default function ToolkitTemplate({template, env}) {
<button className="primary_button" style={{
marginTop: '15px',
width: '100%',
background: template && template.is_installed ? 'rgba(255, 255, 255, 0.14)' : '#FFF',
color: template && template.is_installed ? '#FFFFFF' : '#000'
background: template && template.is_installed && installed !== 'Update' ? 'rgba(255, 255, 255, 0.14)' : '#FFF',
color: template && template.is_installed && installed !== 'Update' ? '#FFFFFF' : '#000'
}} onClick={() => handleInstallClick()}>
{(template && template.is_installed) ?
{(template && template.is_installed && installed !== 'Update') ?
<Image width={14} height={14} src="/images/tick.svg" alt="tick-icon"/> :
<Image width={14} height={14} src="/images/upload_icon_dark.svg"
alt="upload-icon"/>}&nbsp;{installed}</button>
Expand Down
8 changes: 8 additions & 0 deletions gui/pages/api/DashboardService.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,10 +168,18 @@ export const fetchToolTemplateOverview = (toolTemplateName) => {
return api.get(`/toolkits/marketplace/readme/${toolTemplateName}`);
};

export const updateMarketplaceToolTemplate = (templateName) => {
return api.put(`/toolkits/update/${templateName}`);
};

export const installToolkitTemplate = (templateName) => {
return api.get(`/toolkits/get/install/${templateName}`);
};

export const checkToolkitUpdate = (templateName) => {
return api.get(`/toolkits/check_update/${templateName}`);
};

export const getExecutionDetails = (executionId, agentId) => {
return api.get(`/agent_executions_configs/details/agent/${agentId}/agent_execution/${executionId}`);
};
Expand Down
62 changes: 60 additions & 2 deletions superagi/controllers/toolkit.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from superagi.models.tool_config import ToolConfig
from superagi.models.toolkit import Toolkit
from superagi.types.common import GitHubLinkRequest
from superagi.helper.tool_helper import compare_toolkit
from superagi.helper.encyption_helper import decrypt_data, is_encrypted

router = APIRouter()
Expand Down Expand Up @@ -148,8 +149,8 @@ def install_toolkit_from_marketplace(toolkit_name: str,
toolkit = Toolkit.fetch_marketplace_detail(search_str="details",
toolkit_name=toolkit_name)
db_toolkit = Toolkit.add_or_update(session=db.session, name=toolkit['name'], description=toolkit['description'],
tool_code_link=toolkit['tool_code_link'], organisation_id=organisation.id,
show_toolkit=toolkit['show_toolkit'])
tool_code_link=toolkit['tool_code_link'], organisation_id=organisation.id,
show_toolkit=toolkit['show_toolkit'])
for tool in toolkit['tools']:
Tool.add_or_update(session=db.session, tool_name=tool['name'], description=tool['description'],
folder_name=tool['folder_name'], class_name=tool['class_name'], file_name=tool['file_name'],
Expand Down Expand Up @@ -306,3 +307,60 @@ def get_installed_toolkit_list(organisation: Organisation = Depends(get_user_org
toolkit.tools = toolkit_tools

return toolkits


@router.get("/check_update/{toolkit_name}")
def check_toolkit_update(toolkit_name: str, organisation: Organisation = Depends(get_user_organisation)):
"""
Check if there is an update available for the installed tool kits.
Returns:
dict: The response containing the update details.
"""
marketplace_toolkit = Toolkit.fetch_marketplace_detail(search_str="details",
toolkit_name=toolkit_name)
if marketplace_toolkit is None:
raise HTTPException(status_code=404, detail="Toolkit not found in marketplace")
installed_toolkit = Toolkit.get_toolkit_from_name(db.session, toolkit_name, organisation)
if installed_toolkit is None:
return True
installed_toolkit = installed_toolkit.to_dict()
tools = Tool.get_toolkit_tools(db.session, installed_toolkit["id"])
configs = ToolConfig.get_toolkit_tool_config(db.session, installed_toolkit["id"])
installed_toolkit["configs"] = []
installed_toolkit["tools"] = []

for config in configs:
installed_toolkit["configs"].append(config.to_dict())
for tool in tools:
installed_toolkit["tools"].append(tool.to_dict())

return compare_toolkit(marketplace_toolkit, installed_toolkit)


@router.put("/update/{toolkit_name}")
def update_toolkit(toolkit_name: str, organisation: Organisation = Depends(get_user_organisation)):
"""
Update the toolkit with the latest version from the marketplace.
"""
marketplace_toolkit = Toolkit.fetch_marketplace_detail(search_str="details",
toolkit_name=toolkit_name)

update_toolkit = Toolkit.add_or_update(
db.session,
name=marketplace_toolkit["name"],
description=marketplace_toolkit["description"],
show_toolkit=True if len(marketplace_toolkit["tools"]) > 1 else False,
organisation_id=organisation.id,
tool_code_link=marketplace_toolkit["tool_code_link"]
)

for tool in marketplace_toolkit["tools"]:
Tool.add_or_update(db.session, tool_name=tool["name"], folder_name=tool["folder_name"],
class_name=tool["class_name"], file_name=tool["file_name"],
toolkit_id=update_toolkit.id, description=tool["description"])

for tool_config_key in marketplace_toolkit["configs"]:
ToolConfig.add_or_update(db.session, toolkit_id=update_toolkit.id,
key=tool_config_key["key"])
40 changes: 39 additions & 1 deletion superagi/helper/tool_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,12 +264,14 @@ def register_toolkits(session, organisation):
process_files(tool_paths, session, organisation)
logger.info(f"Toolkits Registered Successfully for Organisation ID : {organisation.id}!")


def register_marketplace_toolkits(session, organisation):
tool_paths = ["superagi/tools", "superagi/tools/external_tools","superagi/tools/marketplace_tools"]
tool_paths = ["superagi/tools", "superagi/tools/external_tools", "superagi/tools/marketplace_tools"]
if organisation is not None:
process_files(tool_paths, session, organisation)
logger.info(f"Marketplace Toolkits Registered Successfully for Organisation ID : {organisation.id}!")


def extract_repo_name(repo_link):
# Extract the repository name from the link
# Assuming the GitHub link format: https://github.com/username/repoName
Expand Down Expand Up @@ -304,3 +306,39 @@ def handle_tools_import():
folder_dir = os.path.join(tool_path, folder_name)
if os.path.isdir(folder_dir):
sys.path.append(folder_dir)


def compare_tools(tool1, tool2):
fields = ["name", "description"]
return any(tool1.get(field) != tool2.get(field) for field in fields)


def compare_configs(config1, config2):
fields = ["key"]
return any(config1.get(field) != config2.get(field) for field in fields)


def compare_toolkit(toolkit1, toolkit2):
main_toolkit_fields = ["description", "show_toolkit", "name", "tool_code_link"]
toolkit_diff = any(toolkit1.get(field) != toolkit2.get(field) for field in main_toolkit_fields)

tools1 = sorted(toolkit1.get("tools", []), key=lambda tool: tool.get("name", ""))
tools2 = sorted(toolkit2.get("tools", []), key=lambda tool: tool.get("name", ""))

if len(tools1) != len(tools2):
tools_diff = True
else:
tools_diff = any(compare_tools(tool1, tool2) for tool1, tool2 in zip(tools1, tools2))

tool_configs1 = sorted(toolkit1.get("configs", []), key=lambda config: config.get("key", ""))
tool_configs2 = sorted(toolkit2.get("configs", []), key=lambda config: config.get("key", ""))
if len(tool_configs1) != len(tool_configs2):
tool_configs_diff = True
else:
tool_configs_diff = any(compare_configs(config1, config2) for config1, config2 in zip(tool_configs1,
tool_configs2))

print("toolkit_diff : ", toolkit_diff)
print("tools_diff : ", tools_diff)
print("tool_configs_diff : ", tool_configs_diff)
return toolkit_diff or tools_diff or tool_configs_diff
22 changes: 21 additions & 1 deletion superagi/models/tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,22 @@ def __repr__(self):
return f"Tool(id={self.id}, name='{self.name}',description='{self.description}' folder_name='{self.folder_name}'," \
f" file_name = {self.file_name}, class_name='{self.class_name}, toolkit_id={self.toolkit_id}')"

def to_dict(self):
"""
Convert the Tool instance to a dictionary.
Returns:
dict: A dictionary representation of the Tool instance.
"""
return {
"id": self.id,
"name": self.name,
"description": self.description,
"folder_name": self.folder_name,
"class_name": self.class_name,
"file_name": self.file_name,
"toolkit_id": self.toolkit_id
}
@staticmethod
def add_or_update(session, tool_name: str, description: str, folder_name: str, class_name: str, file_name: str,
toolkit_id: int):
Expand Down Expand Up @@ -100,7 +116,7 @@ def convert_tool_ids_to_names(cls, db, tool_ids):

tools = db.session.query(Tool).filter(Tool.id.in_(tool_ids)).all()
return [str(tool.name) for tool in tools]

@classmethod
def get_invalid_tools(cls, tool_ids, session):
invalid_tool_ids = []
Expand All @@ -109,3 +125,7 @@ def get_invalid_tools(cls, tool_ids, session):
if tool is None:
invalid_tool_ids.append(tool_id)
return invalid_tool_ids

@classmethod
def get_toolkit_tools(cls, session, toolkit_id : int):
return session.query(Tool).filter(Tool.toolkit_id == toolkit_id).all()
4 changes: 4 additions & 0 deletions superagi/models/tool_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,7 @@ def add_or_update(session: Session, toolkit_id: int, key: str, value: str = None
session.add(tool_config)

session.commit()

@classmethod
def get_toolkit_tool_config(cls, session: Session, toolkit_id: int):
return session.query(ToolConfig).filter_by(toolkit_id=toolkit_id).all()
Loading

0 comments on commit a8bb0bb

Please sign in to comment.