diff --git a/app/client/src/components/formControls/FunctionCallingConfigControl/components/FunctionCallingConfigForm.tsx b/app/client/src/components/formControls/FunctionCallingConfigControl/components/FunctionCallingConfigForm.tsx index 382af7eb85..6499bb8055 100644 --- a/app/client/src/components/formControls/FunctionCallingConfigControl/components/FunctionCallingConfigForm.tsx +++ b/app/client/src/components/formControls/FunctionCallingConfigControl/components/FunctionCallingConfigForm.tsx @@ -1,10 +1,34 @@ -import { Button, Text } from "@appsmith/ads"; -import React, { useCallback, useState } from "react"; +import { + Button, + Flex, + Icon, + Menu, + MenuContent, + MenuGroup, + MenuItem, + MenuSub, + MenuSubContent, + MenuSubTrigger, + MenuTrigger, + Text, +} from "@appsmith/ads"; +import React, { useCallback, useMemo, useState } from "react"; import type { FieldArrayFieldsProps } from "redux-form"; import styled from "styled-components"; import { v4 as uuid } from "uuid"; -import type { FunctionCallingConfigFormToolField } from "../types"; +import type { + FunctionCallingConfigFormToolField, + FunctionCallingEntityType, + FunctionCallingEntityTypeOption, +} from "../types"; import { FunctionCallingConfigToolField } from "./FunctionCallingConfigToolField"; +import { useSelector } from "react-redux"; +import { selectEntityOptions } from "./selectors"; +import { createNewJSCollection } from "actions/jsPaneActions"; +import { queryAddURL } from "ee/RouteBuilder"; +import history from "utils/history"; +import { useDispatch } from "react-redux"; +import { getCurrentPageId } from "selectors/editorSelectors"; export interface FunctionCallingConfigFormProps { formName: string; @@ -29,19 +53,48 @@ export const FunctionCallingConfigForm = ({ formName, }: FunctionCallingConfigFormProps) => { const [newlyAddedId, setNewlyAddedId] = useState(null); + const options = useSelector(selectEntityOptions); + const dispatch = useDispatch(); + const pageId = useSelector(getCurrentPageId); - const handleAddFunctionButtonClick = useCallback(() => { - const id = uuid(); + // Get existing entity IDs from the agentFunctions, excluding the currently selected value + const existingEntityIds = useMemo(() => { + const agentFunctionIds = new Set(Object.keys(options.agentFunctions)); - fields.push({ - id, - description: "", - entityId: "", - isApprovalRequired: false, - entityType: "Query", - }); - setNewlyAddedId(id); - }, [fields]); + return agentFunctionIds; + }, [options.agentFunctions]); + + // Filter query items to exclude existing entities + const filteredQueryItems = useMemo(() => { + return options.Query.filter((item) => !existingEntityIds.has(item.value)); + }, [options.Query, existingEntityIds]); + + // Filter JS collection items + const filteredJSCollections = useMemo(() => { + return options.JSCollections.map((collection) => ({ + ...collection, + // Filter out functions that are already used + functions: collection.functions.filter( + (func) => !existingEntityIds.has(func.value), + ), + })).filter((collection) => collection.functions.length > 0); + }, [options.JSCollections, existingEntityIds]); + + const handleAddFunctionButtonClick = useCallback( + (option: FunctionCallingEntityTypeOption) => { + const id = uuid(); + + fields.push({ + id, + description: "", + entityId: option.value, + isApprovalRequired: false, + entityType: option.optionGroupType as FunctionCallingEntityType, + }); + setNewlyAddedId(id); + }, + [fields], + ); const handleRemoveToolButtonClick = useCallback( (index: number) => { @@ -54,17 +107,100 @@ export const FunctionCallingConfigForm = ({ <>
- Function calls + Function Calls - + + + + + + {/* Create new options */} + + history.push(queryAddURL({}))}> + + + New Query + + + + dispatch( + createNewJSCollection( + pageId, + "AI_QUERY_FUNCTION_CALLING_CONFIG", + "onToolCall", + ), + ) + } + > + + + New JS Object + + + + + {/* Query options group */} + {options.Query.length > 0 && ( + + {filteredQueryItems.map((option) => ( + handleAddFunctionButtonClick(option)} + > + + {option.icon && + (typeof option.icon === "string" ? ( + + ) : ( + option.icon + ))} + {option.label} + + + ))} + + )} + + {/* JS Collections group with nested functions */} + {options.JSCollections.length > 0 && ( + + + {filteredJSCollections.map((collection) => ( + + + + {collection.icon && + (typeof collection.icon === "string" ? ( + + ) : ( + collection.icon + ))} + {collection.name} + + + + {collection.functions.map((jsFunction) => ( + + handleAddFunctionButtonClick(jsFunction) + } + > + {jsFunction.label} + + ))} + + + ))} + + + )} + +
{fields.length > 0 && ( diff --git a/app/client/src/components/formControls/FunctionCallingConfigControl/components/FunctionCallingMenuField.tsx b/app/client/src/components/formControls/FunctionCallingConfigControl/components/FunctionCallingMenuField.tsx index 77f1ac2352..2976404372 100644 --- a/app/client/src/components/formControls/FunctionCallingConfigControl/components/FunctionCallingMenuField.tsx +++ b/app/client/src/components/formControls/FunctionCallingConfigControl/components/FunctionCallingMenuField.tsx @@ -18,12 +18,8 @@ import type { FunctionCallingEntityType, FunctionCallingEntityTypeOption, } from "../types"; -import { useSelector, useDispatch } from "react-redux"; +import { useSelector } from "react-redux"; import { selectEntityOptions } from "./selectors"; -import history from "utils/history"; -import { queryAddURL } from "ee/RouteBuilder"; -import { createNewJSCollection } from "actions/jsPaneActions"; -import { getCurrentPageId } from "selectors/editorSelectors"; interface FunctionCallingMenuFieldProps { children?: React.ReactNode; @@ -86,9 +82,6 @@ const FunctionCallingMenuFieldRender = (props: FieldRenderProps) => { const { autoFocus, children, disabled, input, onValueChange } = props; const options = useSelector(selectEntityOptions); - const dispatch = useDispatch(); - const pageId = useSelector(getCurrentPageId); - // Get existing entity IDs from the agentFunctions, excluding the currently selected value const existingEntityIds = useMemo(() => { const agentFunctionIds = new Set(Object.keys(options.agentFunctions)); @@ -166,32 +159,6 @@ const FunctionCallingMenuFieldRender = (props: FieldRenderProps) => { - {/* Create new options */} - - history.push(queryAddURL({}))}> - - - New Query - - - - dispatch( - createNewJSCollection( - pageId, - "AI_QUERY_FUNCTION_CALLING_CONFIG", - "onToolCall", - ), - ) - } - > - - - New JS Object - - - - {/* Query options group */} {filteredQueryItems.length > 0 && (