import React, { useCallback, useEffect } from "react"; import { usePlaygroundContext } from "@/src/features/playground/page/context"; import { Button } from "@/src/components/ui/button"; import { ScrollArea } from "@/src/components/ui/scroll-area"; import { PlusIcon, PencilIcon, MinusCircle, WrenchIcon } from "lucide-react"; import { type LlmTool } from "@prisma/client"; import { api } from "@/src/utils/api"; import useProjectIdFromURL from "@/src/hooks/useProjectIdFromURL"; import { CreateOrEditLLMToolDialog } from "@/src/features/playground/page/components/CreateOrEditLLMToolDialog"; import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, } from "@/src/components/ui/command"; import { type PlaygroundTool } from "@/src/features/playground/page/types"; // Popover content component for use in CollapsibleSection action buttons export const PlaygroundToolsPopover = () => { const { setTools } = usePlaygroundContext(); const projectId = useProjectIdFromURL(); const { data: savedTools = [] } = api.llmTools.getAll.useQuery( { projectId: projectId as string, }, { enabled: Boolean(projectId), staleTime: 1000 * 60 * 5, // 5 minutes }, ); const handleSelectTool = (selectedLLMTool: LlmTool) => { setTools((prev: PlaygroundTool[]) => { let existingToolIndex = -1; existingToolIndex = prev.findIndex((t) => t.id === selectedLLMTool.id); if (existingToolIndex === -1) { const unsavedToolIndexWithSameName = prev.findIndex( (t) => t.name === selectedLLMTool.name, ); if (unsavedToolIndexWithSameName !== -1) { existingToolIndex = unsavedToolIndexWithSameName; } } const newTool: PlaygroundTool = { id: selectedLLMTool.id, name: selectedLLMTool.name, description: selectedLLMTool.description, parameters: selectedLLMTool.parameters as Record, existingLlmTool: selectedLLMTool, }; if (existingToolIndex !== -1) { const newTools = [...prev]; newTools[existingToolIndex] = newTool; return newTools; } return [...prev, newTool]; }); }; const handleRemoveTool = (toolId: string) => { setTools( (prev: PlaygroundTool[]) => prev.filter((t) => !(t.id === toolId)) as PlaygroundTool[], ); }; return ( No tools found. {savedTools.map((tool) => ( handleSelectTool(tool)} className="flex items-center justify-between px-1 py-2" >
{tool.name}
{tool.description}
handleRemoveTool(tool.id)} existingLlmTool={tool} >
))}
); }; // Main component for embedding in CollapsibleSection content export const PlaygroundTools = () => { const { tools, setTools } = usePlaygroundContext(); const projectId = useProjectIdFromURL(); const { data: savedTools = [] } = api.llmTools.getAll.useQuery( { projectId: projectId as string, }, { enabled: Boolean(projectId), staleTime: 1000 * 60 * 5, // 5 minutes }, ); const isToolSaved = useCallback( (tool: PlaygroundTool) => { return savedTools.some( (savedTool) => savedTool.id === tool.id && savedTool.description === tool.description && JSON.stringify(savedTool.parameters) === JSON.stringify(tool.parameters), ); }, [savedTools], ); useEffect(() => { tools.forEach((tool, index) => { if (!tool.existingLlmTool) { const matchingSavedTool = savedTools.find( (savedTool) => savedTool.name === tool.name, ); if (matchingSavedTool) { const newTools = [...tools]; newTools[index] = { ...tool, id: matchingSavedTool.id, existingLlmTool: matchingSavedTool, }; setTools(newTools); } } }); }, [savedTools, tools, setTools]); const handleSelectTool = (selectedLLMTool: LlmTool) => { setTools((prev: PlaygroundTool[]) => { let existingToolIndex = -1; existingToolIndex = prev.findIndex((t) => t.id === selectedLLMTool.id); if (existingToolIndex === -1) { const unsavedToolIndexWithSameName = prev.findIndex( (t) => t.name === selectedLLMTool.name, ); if (unsavedToolIndexWithSameName !== -1) { existingToolIndex = unsavedToolIndexWithSameName; } } const newTool: PlaygroundTool = { id: selectedLLMTool.id, name: selectedLLMTool.name, description: selectedLLMTool.description, parameters: selectedLLMTool.parameters as Record, existingLlmTool: selectedLLMTool, }; if (existingToolIndex !== -1) { const newTools = [...prev]; newTools[existingToolIndex] = newTool; return newTools; } return [...prev, newTool]; }); }; const handleRemoveTool = (toolId: string) => { setTools( (prev: PlaygroundTool[]) => prev.filter((t) => !(t.id === toolId)) as PlaygroundTool[], ); }; return ( {tools.length === 0 ? (

No tools attached.

) : (
{tools.map((tool) => ( handleRemoveTool(tool.id)} existingLlmTool={tool.existingLlmTool} defaultValues={ !isToolSaved(tool) ? { name: tool.name, description: tool.description, parameters: JSON.stringify(tool.parameters, null, 2), } : undefined } >

{tool.name}

{!isToolSaved(tool) ? ( Unsaved ) : null}

{tool.description}

))}
)}
); };