import { Button } from "@/components/ui/button"; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from "@/components/ui/sheet"; import { Switch } from "@/components/ui/switch"; import { getErrorMessage, useCreateProviderMutation } from "@/lib/store"; import { BaseProvider, ModelProviderName } from "@/lib/types/config"; import { allowedRequestsSchema } from "@/lib/types/schemas"; import { cleanPathOverrides } from "@/lib/utils/validation"; import { zodResolver } from "@hookform/resolvers/zod"; import { useEffect } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; import { z } from "zod"; import { AllowedRequestsFields } from "../fragments/allowedRequestsFields"; const formSchema = z.object({ name: z.string().min(1), baseFormat: z.string().min(1), base_url: z.string().min(1, "Base URL is required").url("Must be a valid URL"), allowed_requests: allowedRequestsSchema, request_path_overrides: z.record(z.string(), z.string().optional()).optional(), is_key_less: z.boolean().optional(), }); type FormData = z.infer; export interface AddCustomProviderSheetContentProps { show?: boolean; onSave: (id: string) => void; onClose: () => void; } interface Props extends AddCustomProviderSheetContentProps { show: boolean; } export function AddCustomProviderSheetContent({ show = true, onClose, onSave }: AddCustomProviderSheetContentProps) { const [addProvider, { isLoading: isAddingProvider }] = useCreateProviderMutation(); const form = useForm({ resolver: zodResolver(formSchema), defaultValues: { name: "", baseFormat: "", base_url: "", allowed_requests: { text_completion: true, text_completion_stream: true, chat_completion: true, chat_completion_stream: true, responses: true, responses_stream: true, embedding: true, speech: true, speech_stream: true, transcription: true, transcription_stream: true, image_generation: true, image_generation_stream: true, image_edit: true, image_edit_stream: true, image_variation: true, rerank: true, ocr: true, ocr_stream: true, video_generation: true, video_retrieve: true, video_download: true, video_delete: true, video_list: true, video_remix: true, count_tokens: true, list_models: true, websocket_responses: true, realtime: false, }, request_path_overrides: undefined, is_key_less: false, }, }); useEffect(() => { if (show) { form.clearErrors(); } }, [show]); const onSubmit = (data: FormData) => { const payload = { provider: data.name as ModelProviderName, custom_provider_config: { base_provider_type: data.baseFormat as BaseProvider, allowed_requests: data.allowed_requests, request_path_overrides: cleanPathOverrides(data.request_path_overrides), is_key_less: data.is_key_less ?? false, }, network_config: { base_url: data.base_url, default_request_timeout_in_seconds: 30, max_retries: 0, retry_backoff_initial: 500, retry_backoff_max: 5000, }, }; addProvider(payload) .unwrap() .then((provider) => { onSave(provider.name); form.reset(); }) .catch((err) => { toast.error("Failed to add provider", { description: getErrorMessage(err), }); }); }; const baseFormat = form.watch("baseFormat") as BaseProvider; const isKeyLessDisabled = baseFormat === "bedrock"; return ( <> Add Custom Provider Enter the details of your custom provider.
( Name
)} /> ( Base Format
)} /> ( Base URL
)} /> {!isKeyLessDisabled && ( (

Whether the custom provider requires a key

)} /> )} {/* Allowed Requests Configuration */}
); } export default function AddCustomProviderSheet(props: Props) { return ( !open && props.onClose()}> ); }