Skip to content

Commit

Permalink
feat: LLM and Code Execution options for Conversable Agent
Browse files Browse the repository at this point in the history
  • Loading branch information
hughlv committed Jul 14, 2024
1 parent 66157f4 commit 577e99c
Show file tree
Hide file tree
Showing 9 changed files with 305 additions and 86 deletions.
11 changes: 9 additions & 2 deletions api/app/templates/conversable_agent.j2
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# conversable_agents.j2
{% macro generate_conversable_agents(conversable_nodes) %}

import tempfile
temp_dir = tempfile.gettempdir()

# Conversable Agents
{% for node in conversable_nodes %}
node_{{ node.id }} = {{ node.data.class }}(
Expand All @@ -19,11 +23,14 @@ node_{{ node.id }} = {{ node.data.class }}(
{%- if node.data.human_input_mode %}
human_input_mode="{{ node.data.human_input_mode }}",
{%- endif %}
{%- if node.data.human_input_mode == 'ALWAYS' %}
{%- if node.data.disable_llm %}
llm_config=False,
{% else %}
{%- else %}
llm_config=llm_config,
{%- endif %}
{%- if node.data.enable_code_execution %}
code_execution_config={"use_docker": False, "work_dir": temp_dir}, # Simplified setting for code execution
{%- endif %}
)
{%- endfor %}
{% endmacro %}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,16 @@ import { useTranslations } from 'next-intl';
import { useProjectId } from '@/context/ProjectContext';
import { useProject } from '@/hooks';
import { Tool } from '@/store/projects';
import { RiCloseLine, RiDraggable, RiSettings3Line } from 'react-icons/ri';
import {
RiCloseLine,
RiDraggable,
RiSettings3Line,
RiToolsLine,
} from 'react-icons/ri';
import { TabGroup, TabList, Tab, TabPanels, TabPanel } from '@headlessui/react';
import GenericOption from '../option/Option';
import Tip from '@/components/Tip';
import Link from 'next/link';

const ItemType = {
TOOL: 'tool',
Expand All @@ -29,7 +38,7 @@ const AvailableTool = ({ tool }: any) => {
<div
ref={dragRef}
className={clsx(
'group flex items-center justify-between gap-2 p-2 border bg-base-content/10 border-base-content/40 rounded cursor-pointer',
'group flex items-center justify-between gap-2 p-2 border bg-base-content/10 border-base-content/40 rounded cursor-move',
{
'border-primary': isDragging,
}
Expand All @@ -39,9 +48,9 @@ const AvailableTool = ({ tool }: any) => {
<div className="font-bold">
{tool.name} {isDragging ? '👋' : ''}
</div>
<div className="text-xs">{tool.description}</div>
<div className="text-xs line-clamp-1">{tool.description}</div>
</div>
<RiDraggable />
<RiDraggable className="shrink-0" />
</div>
);
};
Expand All @@ -63,7 +72,7 @@ const AssignedTool = ({ scene, tool, onRemove }: any) => {
);
};

const DropZone = ({ onDrop, children }: any) => {
const DropZone = ({ onDrop, placeholder, children }: any) => {
const ref = useRef<HTMLDivElement>(null);
const [{ isOver }, drop] = useDrop({
accept: ItemType.TOOL,
Expand All @@ -85,19 +94,24 @@ const DropZone = ({ onDrop, children }: any) => {
<div
ref={ref}
className={clsx(
'flex w-full min-h-48 flex-wrap gap-2 p-2 border border-primary/20 rounded',
'flex w-full min-h-32 flex-wrap gap-1 p-1 border border-dashed border-primary/20 rounded',
{
'bg-gray-600': isOver,
}
)}
>
{children}
{children || (
<div className="flex w-full h-full justify-center items-center">
{placeholder}
</div>
)}
</div>
);
};

const ConversableAgentConfig = ({ nodeId, data, className, ...props }: any) => {
const t = useTranslations('option.ConversableAgentConfig');
const tGeneric = useTranslations('node.Generic');
const { projectId } = useProjectId();
const { project, updateProject } = useProject(projectId);

Expand Down Expand Up @@ -156,6 +170,156 @@ const ConversableAgentConfig = ({ nodeId, data, className, ...props }: any) => {
});
};

const ToolPanel = (
<div className="flex flex-col gap-2 w-full h-full">
<div className="py-4">{t('available-tools-tooltip')}</div>
<div className="flex h-full w-full gap-2">
<div className="flex w-64">
<div className="flex flex-col gap-2 w-full h-full">
<div className="flex items-center flex-0 justify-between w-full">
{t('available-tools')}
<Link
href={`/projects/${projectId}/tools`}
className="hover:text-primary"
>
<RiSettings3Line className="w-5 h-5" />
</Link>
</div>

<div className="flex flex-col gap-1 h-full p-1 border border-primary/20 rounded">
<div className="flex flex-col h-full items-center gap-1 overflow-y-auto ">
{project?.tools &&
project.tools.map((tool: Tool) => (
<AvailableTool key={tool.id} tool={tool} />
))}
{(!project?.tools || project?.tools?.length === 0) && (
<div className="flex flex-col gap-2 w-full h-full justify-center items-center">
<RiToolsLine className="w-10 h-10 opacity-40" />
<span className=" opacity-40">{t('no-tools')}</span>
<Link
href={`/projects/${projectId}/tools`}
className="btn btn-sm btn-primary btn-outline rounded mt-4"
>
{t('create-tools')}
</Link>
</div>
)}
</div>
</div>
</div>
</div>
<div className="flex flex-col gap-2 w-full">
<div className="flex items-center gap-2">
{t('tools-for-execution')}
<Tip content={t('tools-for-execution-tooltip')} />
</div>
<DropZone
placeholder={t('tools-for-execution-placeholder')}
onDrop={(toolId: string) => handleDrop(toolId, 'execution')}
>
{project?.tools &&
project.tools
.filter(tool =>
tool.assigned?.find(
a => a.scene === 'execution' && a.agent === nodeId
)
)
.map((tool: Tool) => (
<AssignedTool
key={tool.id}
scene="execution"
tool={tool}
onRemove={handleRemove}
/>
))}
</DropZone>
<div className="flex items-center gap-2">
{t('tools-for-llm')}
<Tip content={t('tools-for-llm-tooltip')} />
</div>
<DropZone
placeholder={t('tools-for-llm-placeholder')}
onDrop={(toolId: string) => handleDrop(toolId, 'llm')}
>
{project?.tools &&
project.tools
.filter(tool =>
tool.assigned?.find(
a => a.scene === 'llm' && a.agent === nodeId
)
)
.map((tool: Tool) => (
<AssignedTool
scene="llm"
key={tool.id}
tool={tool}
onRemove={handleRemove}
/>
))}
</DropZone>
</div>
</div>
</div>
);

const GeneralPanel = () => {
const GENERAL_OPTIONS = [
{
type: 'text',
name: 'description',
label: tGeneric('description'),
placeholder: tGeneric('description-placeholder'),
rows: 2,
},
{
type: 'text',
name: 'system_message',
label: tGeneric('system-message'),
placeholder: tGeneric('system-message-placeholder'),
rows: 2,
},
{
type: 'text',
name: 'termination_msg',
label: tGeneric('termination-msg'),
compact: true,
},
{
type: 'select',
name: 'human_input_mode',
label: tGeneric('human-input-mode'),
options: [
{ value: 'NEVER', label: tGeneric('input-mode-never') },
{ value: 'ALWAYS', label: tGeneric('input-mode-always') },
{ value: 'TERMINATE', label: tGeneric('input-mode-terminate') },
],
compact: true,
},
{
type: 'number',
name: 'max_consecutive_auto_reply',
label: tGeneric('max-consecutive-auto-reply'),
},
{
type: 'check',
name: 'disable_llm',
label: tGeneric('disable-llm'),
},
{
type: 'check',
name: 'enable_code_execution',
label: tGeneric('enable-code-execution'),
},
];
return (
<div className="flex flex-col gap-2 w-full h-full">
{GENERAL_OPTIONS.map((options, index) => (
<GenericOption key={index} nodeId={nodeId} data={data} {...options} />
))}
</div>
);
};

return (
<DndProvider backend={HTML5Backend}>
<PopupDialog
Expand All @@ -166,68 +330,23 @@ const ConversableAgentConfig = ({ nodeId, data, className, ...props }: any) => {
</div>
}
className={clsx(
'flex flex-col bg-gray-800/80 backgrop-blur-md min-h-96 border border-gray-700 shadow-box-lg shadow-gray-700',
'flex flex-col bg-gray-800/80 backgrop-blur-md border border-gray-700 shadow-box-lg shadow-gray-700',
className
)}
classNameTitle="border-b border-base-content/10"
classNameBody="flex flex-1 w-full h-full p-2 gap-2 text-sm overflow-y-auto"
classNameBody="flex flex-1 w-full h-full p-2 gap-2 min-h-96 max-h-[500px] text-sm overflow-y-auto"
{...props}
>
<div className="flex flex-col gap-2 w-full">
<div className="text-xs">{t('available-tools-tooltip')}</div>
<div className="flex h-full w-full flex-1 gap-2">
<div className="flex flex-col gap-2 h-full w-48 shrink-0">
<div>{t('available-tools')}</div>

<div className="flex flex-col flex-1 gap-1 h-full overflow-y-auto">
{project?.tools &&
project.tools.map((tool: Tool) => (
<AvailableTool key={tool.id} tool={tool} />
))}
</div>
</div>
<div className="flex flex-col gap-2 w-full">
<div>{t('tools-for-execution')}</div>
<DropZone
onDrop={(toolId: string) => handleDrop(toolId, 'execution')}
>
{project?.tools &&
project.tools
.filter(tool =>
tool.assigned?.find(
a => a.scene === 'execution' && a.agent === nodeId
)
)
.map((tool: Tool) => (
<AssignedTool
key={tool.id}
scene="execution"
tool={tool}
onRemove={handleRemove}
/>
))}
</DropZone>
<div>{t('tools-for-llm')}</div>
<DropZone onDrop={(toolId: string) => handleDrop(toolId, 'llm')}>
{project?.tools &&
project.tools
.filter(tool =>
tool.assigned?.find(
a => a.scene === 'llm' && a.agent === nodeId
)
)
.map((tool: Tool) => (
<AssignedTool
scene="llm"
key={tool.id}
tool={tool}
onRemove={handleRemove}
/>
))}
</DropZone>
</div>
</div>
</div>
<TabGroup className="w-full h-full">
<TabList className="w-full tabs tabs-bordered">
<Tab className="tab">{t('general')}</Tab>
<Tab className="tab">{t('tools')}</Tab>
</TabList>
<TabPanels className="p-2">
<TabPanel>{GeneralPanel}</TabPanel>
<TabPanel>{ToolPanel}</TabPanel>
</TabPanels>
</TabGroup>
</PopupDialog>
</DndProvider>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const ConversableAgent = ({ id, data, selected, ...props }: any) => {
'human_input_mode',
'max_consecutive_auto_reply',
'termination_msg',
'disable_llm',
]}
ports={[
{ type: 'input', name: 'input' },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,11 @@ const GenericNode = ({
name: 'max_consecutive_auto_reply',
label: t('max-consecutive-auto-reply'),
},
{
type: 'check',
name: 'disable_llm',
label: t('disable-llm'),
},
];

useEffect(() => {
Expand Down
Loading

0 comments on commit 577e99c

Please sign in to comment.