Skip to content

Commit

Permalink
Merge pull request #396 from TransformerOptimus/add_permission
Browse files Browse the repository at this point in the history
Add permission dev
  • Loading branch information
I’m authored Jun 19, 2023
2 parents 413ab21 + b4dc41b commit 38a1995
Show file tree
Hide file tree
Showing 27 changed files with 684 additions and 113 deletions.
189 changes: 111 additions & 78 deletions gui/pages/Content/Agents/ActionConsole.js
Original file line number Diff line number Diff line change
@@ -1,83 +1,116 @@
import React from 'react';
import React, { useState, useEffect } from 'react';
import styles from './Agents.module.css';
import Image from "next/image";
import { updatePermissions } from '@/pages/api/DashboardService';

export default function ActionConsole() {
const actions = [
{
title: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
type: "text",
timeStamp: "2min ago"
},
{
title: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam.",
type: "boolean",
timeStamp: "2min ago"
},
{
title: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
type: "text",
timeStamp: "2min ago"
},
{
title: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam.",
type: "boolean",
timeStamp: "2min ago"
},
{
title: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
type: "text",
timeStamp: "2min ago"
},
{
title: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam.",
type: "boolean",
timeStamp: "2min ago"
}
]
export default function ActionConsole({ actions }) {
const [hiddenActions, setHiddenActions] = useState([]);
const [reasons, setReasons] = useState(actions.map(() => ''));
const [localActions, setLocalActions] = useState(actions);
const [denied, setDenied] = useState([]);
const [localActionIds, setLocalActionIds] = useState([]);

return (<>
<div className={styles.detail_body} style={{height:'auto'}}>
{actions.map((action, index) => (<div key={index} className={styles.history_box} style={{background:'#272335',padding:'15px',cursor:'default'}}>
{action.type === "notification" && <div>
<div>{action.title}</div>
</div>}
{action.type === "boolean" && <div style={{display:'flex',alignItems:'center',justifyContent:'space-between'}}>
<div style={{flex:'1'}}>{action.title}</div>
<div>
<button className="secondary_button" style={{marginLeft:'4px',padding:'5px',background:'transparent',border:'none'}}>
<Image width={20} height={21} src="/images/close.svg" alt="close-icon"/>
</button>
</div>
<div>
<button className="secondary_button" style={{marginLeft:'4px',padding:'5px'}}>
<Image width={20} height={21} src="/images/check.svg" alt="check-icon"/>
</button>
</div>
</div>}
{action.type === "text" && <div>
<div>{action.title}</div>
<div style={{marginTop:'10px',display:'flex',alignItems:'center',justifyContent:'space-between'}}>
<div style={{flex:'1'}}><input className="input_medium" type="text"/></div>
<div>
<button className="secondary_button" style={{marginLeft:'4px',padding:'5px',background:'transparent',border:'none'}}>
<Image width={20} height={21} src="/images/close.svg" alt="close-icon"/>
</button>
</div>
<div>
<button className="secondary_button" style={{marginLeft:'4px',padding:'5px'}}>
<Image width={20} height={21} src="/images/send.svg" alt="send-icon"/>
</button>
</div>
</div>
</div>}
<div style={{display:'flex',alignItems:'center',paddingLeft:'0',paddingBottom:'0'}} className={styles.tab_text}>
<div>
<Image width={12} height={12} src="/images/schedule.svg" alt="schedule-icon"/>
</div>
<div className={styles.history_info}>{action.timeStamp}</div>
</div>
</div>))}
</div>
</>)
useEffect(() => {
const updatedActions = actions.filter(
(action) => !localActionIds.includes(action.id)
);

if (updatedActions.length > 0) {
setLocalActions(
localActions.map((localAction) =>
updatedActions.find(({ id }) => id === localAction.id) || localAction
)
);

const updatedDenied = updatedActions.map(() => false);
const updatedReasons = updatedActions.map(() => '');

setDenied((prev) => prev.map((value, index) => updatedDenied[index] || value));
setReasons((prev) => prev.map((value, index) => updatedReasons[index] || value));

setLocalActionIds([...localActionIds, ...updatedActions.map(({ id }) => id)]);
}
}, [actions]);

const handleDeny = index => {
const newDeniedState = [...denied];
newDeniedState[index] = !newDeniedState[index];
setDenied(newDeniedState);
};

const formatDate = (dateString) => {
const now = new Date();
const date = new Date(dateString);
const seconds = Math.floor((now - date) / 1000);
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
const days = Math.floor(hours / 24);
const weeks = Math.floor(days / 7);
const months = Math.floor(days / 30);
const years = Math.floor(days / 365);

if (years > 0) return `${years} yr${years === 1 ? '' : 's'}`;
if (months > 0) return `${months} mon${months === 1 ? '' : 's'}`;
if (weeks > 0) return `${weeks} wk${weeks === 1 ? '' : 's'}`;
if (days > 0) return `${days} day${days === 1 ? '' : 's'}`;
if (hours > 0) return `${hours} hr${hours === 1 ? '' : 's'}`;
if (minutes > 0) return `${minutes} min${minutes === 1 ? '' : 's'}`;

return `${seconds} sec${seconds === 1 ? '' : 's'}`;
};

const handleSelection = (index, status, permissionId) => {
setHiddenActions([...hiddenActions, index]);

const data = {
status: status,
user_feedback: reasons[index],
};

updatePermissions(permissionId, data).then((response) => {
console.log("voila")
});
};

return (
<>
{actions.some(action => action.status === "PENDING") ? (<div className={styles.detail_body} style={{ height: "auto" }}>
{actions.map((action, index) => action.status === "PENDING" && !hiddenActions.includes(index) && (
<div key={index} className={styles.history_box} style={{ background: "#272335", padding: "16px", cursor: "default" }}>
<div style={{ display: "flex", flexDirection: 'column' }}>
<div>Tool <b>{action.tool_name}</b> is seeking for Permissions</div>
{denied[index] && (
<div style={{marginTop: '26px' }}>
<div>Provide Feedback <span style={{color: '#888888'}}>(Optional)</span></div>
<input style={{marginTop: '6px'}} type="text" value={reasons[index]} onChange={(e) => {const newReasons = [...reasons];newReasons[index] = e.target.value;setReasons(newReasons);}} placeholder="Enter your input here" className="input_medium" />
</div>
)}
{denied[index] ? (
<div style={{ display: "inline-flex", marginTop: '16px',gap: '8px' }}>
<button onClick={() => handleDeny(index)} className="secondary_button"><Image width={12} height={12} src="/images/undo.svg" alt="check-icon" /><span className={styles.text_12_n}>Go Back</span></button>
<button onClick={() => handleSelection(index, false, action.id)} className="secondary_button" style={{ marginLeft: "4px", padding: "5px", background: "transparent", border: "none" }}><span className={styles.text_12_n}>Proceed to Deny</span></button>
</div>
) : (
<div style={{ display: "inline-flex", marginTop: '16px',gap: '8px' }}>
<button onClick={() => handleSelection(index, true, action.id)} className="secondary_button"><Image width={12} height={12} src="/images/check.svg" alt="check-icon" /><span className={styles.text_12_n}>Approve</span></button>
<button onClick={() => handleDeny(index)} className="secondary_button" style={{ marginLeft: "4px", padding: "5px", background: "transparent", border: "none" }}><Image width={16} height={16} src="/images/close.svg" alt="close-icon" /><div className={styles.text_12_n}>Deny</div></button>
</div>
)}
</div>
<div style={{ display: "flex", alignItems: "center", paddingLeft: "0", paddingBottom: "0" }} className={styles.tab_text}>
<div>
<Image width={12} height={12} src="/images/schedule.svg" alt="schedule-icon" />
</div>
<div className={styles.history_info}>{formatDate(action.created_at)}</div>
</div>
</div>
))}
</div>):
(
<div style={{display:'flex',flexDirection:'column',alignItems:'center',marginTop:'40px'}}>
<Image width={150} height={60} src="/images/no_permissions.svg" alt="no permissions" />
<span className={styles.feed_title} style={{marginTop: '8px'}}>No Actions to Display!</span>
</div>)}
</>
);
}
3 changes: 2 additions & 1 deletion gui/pages/Content/Agents/ActivityFeed.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Image from "next/image";
import {formatTime} from "@/utils/utils";
import {EventBus} from "@/utils/eventBus";

export default function ActivityFeed({selectedRunId, selectedView}) {
export default function ActivityFeed({selectedRunId, selectedView, setFetchedData }) {
const [loadingText, setLoadingText] = useState("Thinking");
const [feeds, setFeeds] = useState([]);
const feedContainerRef = useRef(null);
Expand Down Expand Up @@ -65,6 +65,7 @@ export default function ActivityFeed({selectedRunId, selectedView}) {
const data = response.data;
setFeeds(data.feeds);
setRunStatus(data.status);
setFetchedData(data.permissions);
})
.catch((error) => {
console.error('Error fetching execution feeds:', error);
Expand Down
10 changes: 8 additions & 2 deletions gui/pages/Content/Agents/AgentCreate.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export default function AgentCreate({sendAgentData, selectedProjectId, fetchAgen
const databaseRef = useRef(null);
const [databaseDropdown, setDatabaseDropdown] = useState(false);

const permissions = ["God Mode"]
const permissions = ["God Mode","RESTRICTED (Will ask for permission before using any tool)"]
const [permission, setPermission] = useState(permissions[0]);
const permissionRef = useRef(null);
const [permissionDropdown, setPermissionDropdown] = useState(false);
Expand Down Expand Up @@ -339,6 +339,12 @@ export default function AgentCreate({sendAgentData, selectedProjectId, fetchAgen

setCreateClickable(false);

// if permission has word restricted change the permission to
let permission_type = permission;
if (permission.includes("RESTRICTED")) {
permission_type = "RESTRICTED";
}

const agentData = {
"name": agentName,
"project_id": selectedProjectId,
Expand All @@ -352,7 +358,7 @@ export default function AgentCreate({sendAgentData, selectedProjectId, fetchAgen
"iteration_interval": stepTime,
"model": model,
"max_iterations": maxIterations,
"permission_type": permission,
"permission_type": permission_type,
"LTM_DB": longTermMemory ? database : null,
"memory_window": rollingWindow
};
Expand Down
25 changes: 18 additions & 7 deletions gui/pages/Content/Agents/AgentWorkspace.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export default function AgentWorkspace({agentId, selectedView}) {
const [agentDetails, setAgentDetails] = useState(null)
const [agentExecutions, setAgentExecutions] = useState(null)
const [dropdown, setDropdown] = useState(false);
const [fetchedData, setFetchedData] = useState(null);
const [instructions, setInstructions] = useState(['']);

const addInstruction = () => {
Expand Down Expand Up @@ -216,18 +217,24 @@ export default function AgentWorkspace({agentId, selectedView}) {
</div>
</div>
<div className={styles.detail_body}>
{leftPanel === 'activity_feed' && <div className={styles.detail_content}><ActivityFeed selectedView={selectedView} selectedRunId={selectedRun?.id || 0}/></div>}
{leftPanel === 'activity_feed' && <div className={styles.detail_content}>
<ActivityFeed
selectedView={selectedView}
selectedRunId={selectedRun?.id || 0}
setFetchedData={setFetchedData} // Pass the setFetchedData function as a prop
/>
</div>}
{leftPanel === 'agent_type' && <div className={styles.detail_content}><TaskQueue selectedRunId={selectedRun?.id || 0}/></div>}
</div>
</div>
<div style={{width:'40%'}}>
<div className={styles.detail_top}>
<div style={{display:'flex',overflowX:'scroll'}}>
{/*<div>*/}
{/* <button onClick={() => setRightPanel('action_console')} className={styles.tab_button} style={rightPanel === 'action_console' ? {background:'#454254'} : {background:'transparent'}}>*/}
{/* Action Console*/}
{/* </button>*/}
{/*</div>*/}
<div>
<button onClick={() => setRightPanel('action_console')} className={styles.tab_button} style={rightPanel === 'action_console' ? {background:'#454254'} : {background:'transparent'}}>
Action Console
</button>
</div>
{/*<div>*/}
{/* <button onClick={() => setRightPanel('feedback')} className={styles.tab_button} style={rightPanel === 'feedback' ? {background:'#454254'} : {background:'transparent'}}>*/}
{/* Feedback*/}
Expand All @@ -251,7 +258,11 @@ export default function AgentWorkspace({agentId, selectedView}) {
</div>
</div>
<div className={styles.detail_body} style={{paddingRight:'0'}}>
{rightPanel === 'action_console' && agentDetails && agentDetails?.permission_type !== 'God Mode' && <div className={styles.detail_content}><ActionConsole/></div>}
{rightPanel === 'action_console' && agentDetails && agentDetails?.permission_type !== 'God Mode' && (
<div className={styles.detail_content}>
<ActionConsole key={JSON.stringify(fetchedData)} actions={fetchedData} />
</div>
)}
{rightPanel === 'details' && <div className={styles.detail_content}><Details agentDetails={agentDetails} tools={tools} runCount={agentExecutions?.length || 0}/></div>}
{rightPanel === 'resource_manager' && <div className={styles.detail_content}><ResourceManager agentId={agentId}/></div>}
</div>
Expand Down
12 changes: 11 additions & 1 deletion gui/pages/Content/Agents/Agents.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -344,4 +344,14 @@
font-size: 13px;
font-weight: 500;
font-family: 'Source Code Pro';
}
}

.text_12_n
{
font-style: normal;
font-weight: 400;
font-size: 12px;
line-height: 14px;
color: #FFFFFF;
margin-top: 2px;
}
5 changes: 4 additions & 1 deletion gui/pages/_app.css
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,10 @@ p {
border: 1px solid rgba(255, 255, 255, 0.14);
text-align: center;
padding: 5px 15px;
display: -webkit-box;
display: -webkit-flex;
flex-direction: row;
align-items: center;
gap: 6px;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
overflow: hidden;
Expand Down
4 changes: 4 additions & 0 deletions gui/pages/api/DashboardService.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,8 @@ export const fetchAgentTemplateConfigLocal = (templateId) => {

export const installAgentTemplate = (templateId) => {
return api.post(`agent_templates/download?agent_template_id=${templateId}`);
}

export const updatePermissions = (permissionId, data) => {
return api.put(`/agentexecutionpermissions/update/status/${permissionId}`, data)
}
3 changes: 3 additions & 0 deletions gui/public/images/check.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions gui/public/images/no_permissions.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions gui/public/images/undo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 38a1995

Please sign in to comment.