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, BoxIcon } from "lucide-react"; import { type LlmSchema } from "@langfuse/shared"; import { api } from "@/src/utils/api"; import useProjectIdFromURL from "@/src/hooks/useProjectIdFromURL"; import { CreateOrEditLLMSchemaDialog } from "@/src/features/playground/page/components/CreateOrEditLLMSchemaDialog"; import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, } from "@/src/components/ui/command"; import { type PlaygroundSchema } from "@/src/features/playground/page/types"; // Popover content component for use in CollapsibleSection action buttons export const StructuredOutputSchemaPopover = () => { const { structuredOutputSchema, setStructuredOutputSchema } = usePlaygroundContext(); const projectId = useProjectIdFromURL(); const { data: savedSchemas = [] } = api.llmSchemas.getAll.useQuery( { projectId: projectId as string, }, { enabled: Boolean(projectId), staleTime: 1000 * 60 * 5, // 5 minutes }, ); const isSchemaSaved = useCallback( (schema: PlaygroundSchema) => { return savedSchemas.some( (savedSchema) => savedSchema.id === schema.id && savedSchema.description === schema.description && JSON.stringify(savedSchema.schema) === JSON.stringify(schema.schema), ); }, [savedSchemas], ); const handleSelectSchema = (selectedLLMSchema: LlmSchema) => { if ( structuredOutputSchema && structuredOutputSchema.id === selectedLLMSchema.id ) { // Schema already selected, just update it setStructuredOutputSchema({ ...structuredOutputSchema, name: selectedLLMSchema.name, description: selectedLLMSchema.description, schema: selectedLLMSchema.schema as Record, existingLlmSchema: selectedLLMSchema, }); } else if ( structuredOutputSchema && structuredOutputSchema.name === selectedLLMSchema.name && !isSchemaSaved(structuredOutputSchema) ) { // Replace unsaved schema with same name setStructuredOutputSchema({ id: selectedLLMSchema.id, name: selectedLLMSchema.name, description: selectedLLMSchema.description, schema: selectedLLMSchema.schema as Record, existingLlmSchema: selectedLLMSchema, }); } else { // New schema const newPlaygroundSchema: PlaygroundSchema = { id: selectedLLMSchema.id, name: selectedLLMSchema.name, description: selectedLLMSchema.description, schema: selectedLLMSchema.schema as Record, existingLlmSchema: selectedLLMSchema, }; setStructuredOutputSchema(newPlaygroundSchema); } }; const handleRemoveSchema = () => { setStructuredOutputSchema(null); }; return ( No schemas found. {savedSchemas.map((schema) => ( handleSelectSchema(schema)} className="flex items-center justify-between px-1 py-2" >
{schema.name}
{schema.description}
handleRemoveSchema()} existingLlmSchema={schema} >
))}
); }; // Main component for embedding in CollapsibleSection content export const StructuredOutputSchemaSection = () => { const { structuredOutputSchema, setStructuredOutputSchema } = usePlaygroundContext(); const projectId = useProjectIdFromURL(); const { data: savedSchemas = [] } = api.llmSchemas.getAll.useQuery( { projectId: projectId as string, }, { enabled: Boolean(projectId), staleTime: 1000 * 60 * 5, // 5 minutes }, ); const isSchemaSaved = useCallback( (schema: PlaygroundSchema) => { return savedSchemas.some( (savedSchema) => savedSchema.id === schema.id && savedSchema.description === schema.description && JSON.stringify(savedSchema.schema) === JSON.stringify(schema.schema), ); }, [savedSchemas], ); useEffect(() => { if (structuredOutputSchema && !structuredOutputSchema.existingLlmSchema) { const matchingSavedSchema = savedSchemas.find( (savedSchema) => savedSchema.name === structuredOutputSchema.name, ); if (matchingSavedSchema) { setStructuredOutputSchema({ ...structuredOutputSchema, id: matchingSavedSchema.id, existingLlmSchema: matchingSavedSchema, }); } } }, [savedSchemas, structuredOutputSchema, setStructuredOutputSchema]); const handleSelectSchema = (selectedLLMSchema: LlmSchema) => { if ( structuredOutputSchema && structuredOutputSchema.id === selectedLLMSchema.id ) { // Schema already selected, just update it setStructuredOutputSchema({ ...structuredOutputSchema, name: selectedLLMSchema.name, description: selectedLLMSchema.description, schema: selectedLLMSchema.schema as Record, existingLlmSchema: selectedLLMSchema, }); } else if ( structuredOutputSchema && structuredOutputSchema.name === selectedLLMSchema.name && !isSchemaSaved(structuredOutputSchema) ) { // Replace unsaved schema with same name setStructuredOutputSchema({ id: selectedLLMSchema.id, name: selectedLLMSchema.name, description: selectedLLMSchema.description, schema: selectedLLMSchema.schema as Record, existingLlmSchema: selectedLLMSchema, }); } else { // New schema const newPlaygroundSchema: PlaygroundSchema = { id: selectedLLMSchema.id, name: selectedLLMSchema.name, description: selectedLLMSchema.description, schema: selectedLLMSchema.schema as Record, existingLlmSchema: selectedLLMSchema, }; setStructuredOutputSchema(newPlaygroundSchema); } }; const handleRemoveSchema = () => { setStructuredOutputSchema(null); }; return ( {!structuredOutputSchema ? (

No schema provided.

) : (
handleRemoveSchema()} existingLlmSchema={structuredOutputSchema.existingLlmSchema} defaultValues={ !isSchemaSaved(structuredOutputSchema) ? { name: structuredOutputSchema.name, description: structuredOutputSchema.description, schema: JSON.stringify( structuredOutputSchema.schema, null, 2, ), } : undefined } >

{structuredOutputSchema.name}

{!isSchemaSaved(structuredOutputSchema) ? ( Unsaved ) : null}

{structuredOutputSchema.description}

)}
); };