import React from 'react'; import { useSelector } from 'react-redux'; import userService from '../api/services/userService'; import ArrowLeft from '../assets/arrow-left.svg'; import CircleCheck from '../assets/circle-check.svg'; import CircleX from '../assets/circle-x.svg'; import Trash from '../assets/trash.svg'; import Dropdown from '../components/Dropdown'; import Input from '../components/Input'; import ToggleSwitch from '../components/ToggleSwitch'; import AddActionModal from '../modals/AddActionModal'; import { ActiveState } from '../models/misc'; import { selectToken } from '../preferences/preferenceSlice'; import { APIActionType, APIToolType, UserToolType } from './types'; import { useTranslation } from 'react-i18next'; export default function ToolConfig({ tool, setTool, handleGoBack, }: { tool: UserToolType | APIToolType; setTool: (tool: UserToolType | APIToolType) => void; handleGoBack: () => void; }) { const token = useSelector(selectToken); const [authKey, setAuthKey] = React.useState( 'token' in tool.config ? tool.config.token : '', ); const [actionModalState, setActionModalState] = React.useState('INACTIVE'); const { t } = useTranslation(); const handleCheckboxChange = (actionIndex: number, property: string) => { setTool({ ...tool, actions: 'actions' in tool ? tool.actions.map((action, index) => { if (index === actionIndex) { return { ...action, parameters: { ...action.parameters, properties: { ...action.parameters.properties, [property]: { ...action.parameters.properties[property], filled_by_llm: !action.parameters.properties[property].filled_by_llm, }, }, }, }; } return action; }) : [], }); }; const handleSaveChanges = () => { userService .updateTool( { id: tool.id, name: tool.name, displayName: tool.displayName, description: tool.description, config: tool.name === 'api_tool' ? tool.config : { token: authKey }, actions: 'actions' in tool ? tool.actions : [], status: tool.status, }, token, ) .then(() => { handleGoBack(); }); }; const handleDelete = () => { userService.deleteTool({ id: tool.id }, token).then(() => { handleGoBack(); }); }; const handleAddNewAction = (actionName: string) => { const newAction: APIActionType = { name: actionName, method: 'GET', url: '', description: '', body: { properties: {}, type: 'object', }, headers: { properties: {}, type: 'object', }, query_params: { properties: {}, type: 'object', }, active: true, }; const toolCopy = tool as APIToolType; setTool({ ...toolCopy, config: { ...toolCopy.config, actions: { ...toolCopy.config.actions, [actionName]: newAction }, }, }); }; return (

Back to all tools

Type

{tool.name}

{Object.keys(tool?.config).length !== 0 && tool.name !== 'api_tool' && (

Authentication

)}
{Object.keys(tool?.config).length !== 0 && tool.name !== 'api_tool' && (
setAuthKey(e.target.value)} borderVariant="thin" placeholder={t('modals.configTool.apiKeyPlaceholder')} />
)}

Actions

{tool.name === 'api_tool' ? ( ) : (
{'actions' in tool && tool.actions.map((action, actionIndex) => { return (

{action.name}

{ setTool({ ...tool, actions: tool.actions.map((act, index) => { if (index === actionIndex) { return { ...act, active: checked }; } return act; }), }); }} size="small" id={`actionToggle-${actionIndex}`} />
{ setTool({ ...tool, actions: tool.actions.map((act, index) => { if (index === actionIndex) { return { ...act, description: e.target.value, }; } return act; }), }); }} borderVariant="thin" />
{Object.entries(action.parameters?.properties).map( (param, index) => { const uniqueKey = `${actionIndex}-${param[0]}`; return ( ); }, )}
Field Name Field Type Filled by LLM FIeld description Value
{param[0]} {param[1].type} { setTool({ ...tool, actions: tool.actions.map( (act, index) => { if (index === actionIndex) { return { ...act, parameters: { ...act.parameters, properties: { ...act.parameters .properties, [param[0]]: { ...act.parameters .properties[param[0]], description: e.target.value, }, }, }, }; } return act; }, ), }); }} > { setTool({ ...tool, actions: tool.actions.map( (act, index) => { if (index === actionIndex) { return { ...act, parameters: { ...act.parameters, properties: { ...act.parameters .properties, [param[0]]: { ...act.parameters .properties[param[0]], value: e.target.value, }, }, }, }; } return act; }, ), }); }} >
); })}
)}
); } function APIToolConfig({ tool, setTool, }: { tool: APIToolType; setTool: (tool: APIToolType) => void; }) { const [apiTool, setApiTool] = React.useState(tool); const handleActionChange = ( actionName: string, updatedAction: APIActionType, ) => { setApiTool((prevApiTool) => { const updatedActions = { ...prevApiTool.config.actions }; updatedActions[actionName] = updatedAction; return { ...prevApiTool, config: { ...prevApiTool.config, actions: updatedActions }, }; }); }; const handleActionToggle = (actionName: string) => { setApiTool((prevApiTool) => { const updatedActions = { ...prevApiTool.config.actions }; const updatedAction = { ...updatedActions[actionName] }; updatedAction.active = !updatedAction.active; updatedActions[actionName] = updatedAction; return { ...prevApiTool, config: { ...prevApiTool.config, actions: updatedActions }, }; }); }; React.useEffect(() => { setApiTool(tool); }, [tool]); React.useEffect(() => { setTool(apiTool); }, [apiTool]); return (
{apiTool.config.actions && Object.entries(apiTool.config.actions).map( ([actionName, action], actionIndex) => { return (

{action.name}

handleActionToggle(actionName)} size="small" id={`actionToggle-${actionIndex}`} />
URL { setApiTool((prevApiTool) => { const updatedActions = { ...prevApiTool.config.actions, }; const updatedAction = { ...updatedActions[actionName], }; updatedAction.url = e.target.value; updatedActions[actionName] = updatedAction; return { ...prevApiTool, config: { ...prevApiTool.config, actions: updatedActions, }, }; }); }} borderVariant="thin" placeholder="Enter url" >
Method { setApiTool((prevApiTool) => { const updatedActions = { ...prevApiTool.config.actions, }; const updatedAction = { ...updatedActions[actionName], }; updatedAction.method = value as | 'GET' | 'POST' | 'PUT' | 'DELETE'; updatedActions[actionName] = updatedAction; return { ...prevApiTool, config: { ...prevApiTool.config, actions: updatedActions, }, }; }); }} size="w-56" rounded="3xl" border="border" />
Description { setApiTool((prevApiTool) => { const updatedActions = { ...prevApiTool.config.actions, }; const updatedAction = { ...updatedActions[actionName], }; updatedAction.description = e.target.value; updatedActions[actionName] = updatedAction; return { ...prevApiTool, config: { ...prevApiTool.config, actions: updatedActions, }, }; }); }} borderVariant="thin" placeholder="Enter description" >
); }, )}
); } function APIActionTable({ apiAction, handleActionChange, }: { apiAction: APIActionType; handleActionChange: ( actionName: string, updatedAction: APIActionType, ) => void; }) { const [action, setAction] = React.useState(apiAction); const [newPropertyKey, setNewPropertyKey] = React.useState(''); const [addingPropertySection, setAddingPropertySection] = React.useState< 'headers' | 'query_params' | 'body' | null >(null); const [editingPropertyKey, setEditingPropertyKey] = React.useState<{ section: 'headers' | 'query_params' | 'body' | null; oldKey: string | null; }>({ section: null, oldKey: null }); const handlePropertyChange = ( section: 'headers' | 'query_params' | 'body', key: string, field: 'value' | 'description' | 'filled_by_llm', value: string | number | boolean, ) => { setAction((prevAction) => { const updatedProperties = { ...prevAction[section].properties, [key]: { ...prevAction[section].properties[key], [field]: value, }, }; return { ...prevAction, [section]: { ...prevAction[section], properties: updatedProperties, }, }; }); }; const handleAddPropertyStart = ( section: 'headers' | 'query_params' | 'body', ) => { setEditingPropertyKey({ section: null, oldKey: null }); setAddingPropertySection(section); setNewPropertyKey(''); }; const handleAddPropertyCancel = () => { setAddingPropertySection(null); setNewPropertyKey(''); }; const handleAddProperty = () => { if (addingPropertySection && newPropertyKey.trim() !== '') { setAction((prevAction) => { const updatedProperties = { ...prevAction[addingPropertySection].properties, [newPropertyKey.trim()]: { type: 'string', description: '', value: '', filled_by_llm: false, }, }; return { ...prevAction, [addingPropertySection]: { ...prevAction[addingPropertySection], properties: updatedProperties, }, }; }); setNewPropertyKey(''); setAddingPropertySection(null); } }; const handleRenamePropertyStart = ( section: 'headers' | 'query_params' | 'body', oldKey: string, ) => { setAddingPropertySection(null); setEditingPropertyKey({ section, oldKey }); setNewPropertyKey(oldKey); }; const handleRenamePropertyCancel = () => { setEditingPropertyKey({ section: null, oldKey: null }); setNewPropertyKey(''); }; const handleRenameProperty = () => { if ( editingPropertyKey.section && editingPropertyKey.oldKey && newPropertyKey.trim() !== '' && newPropertyKey.trim() !== editingPropertyKey.oldKey ) { setAction((prevAction) => { const { section, oldKey } = editingPropertyKey; if (section && oldKey) { const { [oldKey]: oldProperty, ...restProperties } = prevAction[section].properties; const updatedProperties = { ...restProperties, [newPropertyKey.trim()]: oldProperty, }; return { ...prevAction, [section]: { ...prevAction[section], properties: updatedProperties, }, }; } return prevAction; }); setEditingPropertyKey({ section: null, oldKey: null }); setNewPropertyKey(''); } }; const handlePorpertyDelete = ( section: 'headers' | 'query_params' | 'body', key: string, ) => { setAction((prevAction) => { const { [key]: deletedProperty, ...restProperties } = prevAction[section].properties; return { ...prevAction, [section]: { ...prevAction[section], properties: restProperties, }, }; }); }; React.useEffect(() => { setAction(apiAction); }, [apiAction]); React.useEffect(() => { handleActionChange(action.name, action); }, [action]); const renderPropertiesTable = ( section: 'headers' | 'query_params' | 'body', ) => { return ( <> {Object.entries(action[section].properties).map( ([key, param], index) => ( {editingPropertyKey.section === section && editingPropertyKey.oldKey === key ? (
setNewPropertyKey(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') { handleRenameProperty(); } }} />
) : ( handleRenamePropertyStart(section, key)} readOnly /> )} {param.type} handlePropertyChange( section, key, 'description', e.target.value, ) } > handlePropertyChange(section, key, 'value', e.target.value) } className={`rounded-lg border border-silver bg-transparent px-2 py-1 text-sm outline-none dark:border-silver/40 ${param.filled_by_llm ? 'opacity-50' : ''}`} > ), )} {addingPropertySection === section ? ( setNewPropertyKey(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') { handleAddProperty(); } }} placeholder="New property key" className="flex w-full min-w-[130.5px] items-start rounded-lg border border-silver bg-transparent px-2 py-1 text-sm outline-none dark:border-silver/40" /> ) : ( )} ); }; return (

Headers

{renderPropertiesTable('headers')}
Name Type Filled by LLM Description Value

Query Parameters

{renderPropertiesTable('query_params')}
Name Type Filled by LLM Description Value

Body

{renderPropertiesTable('body')}
Name Type Filled by LLM Description Value
); }