diff --git a/app/client/src/pages/Settings/AddModelProviderButton.tsx b/app/client/src/pages/Settings/AddModelProviderButton.tsx index 4b6b558..a1207a6 100644 --- a/app/client/src/pages/Settings/AddModelProviderButton.tsx +++ b/app/client/src/pages/Settings/AddModelProviderButton.tsx @@ -1,6 +1,6 @@ import { useEffect, useState } from 'react'; import { PlusCircleOutlined } from '@ant-design/icons'; -import { Alert, Button, Form, Input, Modal, notification, Radio, Select } from 'antd'; +import { Alert, AutoComplete, Button, Form, Input, Modal, notification, Radio, Select } from 'antd'; import type { CheckboxGroupProps } from 'antd/es/checkbox'; import get from 'lodash/get'; import isEqual from 'lodash/isEqual'; @@ -10,15 +10,19 @@ import Loading from '../Evaluator/Loading'; export enum ModelProviderType { OPENAI = 'openai', + OPENAI_COMPATIBLE = 'openai_compatible', GEMINI = 'gemini', - CAII = 'caii' + CAII = 'caii', + AWS_BEDROCK = 'aws_bedrock' } -const modelProviderTypeOptions: CheckboxGroupProps['options'] = [ +export const modelProviderTypeOptions: CheckboxGroupProps['options'] = [ { label: 'OpenAI', value: 'openai' }, - // { label: 'CAII', value: 'caii' }, + { label: 'OpenAI Compatible', value: 'openai_compatible' }, { label: 'Gemini', value: 'gemini' }, + { label: 'AWS Bedrock', value: 'aws_bedrock' }, + { label: 'CAII', value: 'caii' }, ]; const OPENAI_MODELS = [ @@ -27,7 +31,7 @@ const OPENAI_MODELS = [ "gpt-4.1-nano" ]; -const OPENAI_MODELS_OPTIONS = OPENAI_MODELS.map((model: string) => ({ +export const OPENAI_MODELS_OPTIONS = OPENAI_MODELS.map((model: string) => ({ label: model, value: model })); @@ -38,7 +42,42 @@ const GEMINI_MODELS = [ "gemini-2.5-flash-lite" // June 2025 - cost-efficient ]; -const GEMINI_MODELS_OPTIONS = GEMINI_MODELS.map((model: string) => ({ +export const AWS_BEDROCK_MODELS = [ + "us.anthropic.claude-3-5-sonnet-20241022-v2:0", + "us.anthropic.claude-sonnet-4-5-20250929-v1:0", + "us.anthropic.claude-opus-4-1-20250805-v1:0", + "us.anthropic.claude-opus-4-20250514-v1:0", + "global.anthropic.claude-sonnet-4-20250514-v1:0", + "us.anthropic.claude-3-7-sonnet-20250219-v1:0", + "us.anthropic.claude-3-5-haiku-20241022-v1:0", + "anthropic.claude-3-5-sonnet-20240620-v1:0", + "anthropic.claude-3-haiku-20240307-v1:0", + "anthropic.claude-3-sonnet-20240229-v1:0", + "us.anthropic.claude-3-opus-20240229-v1:0", + "meta.llama3-8b-instruct-v1:0", + "meta.llama3-70b-instruct-v1:0", + "mistral.mistral-large-2402-v1:0", + "mistral.mistral-small-2402-v1:0", + "us.meta.llama3-2-11b-instruct-v1:0", + "us.meta.llama3-2-3b-instruct-v1:0", + "us.meta.llama3-2-90b-instruct-v1:0", + "us.meta.llama3-2-1b-instruct-v1:0", + "us.meta.llama3-1-8b-instruct-v1:0", + "us.meta.llama3-1-70b-instruct-v1:0", + "us.meta.llama3-3-70b-instruct-v1:0", + "us.mistral.pixtral-large-2502-v1:0", + "us.meta.llama4-scout-17b-instruct-v1:0", + "us.meta.llama4-maverick-17b-instruct-v1:0", + "mistral.mistral-7b-instruct-v0:2", + "mistral.mixtral-8x7b-instruct-v0:1" +]; + +export const AWS_BEDROCK_MODELS_OPTIONS = AWS_BEDROCK_MODELS.map((model: string) => ({ + label: model, + value: model +})); + +export const GEMINI_MODELS_OPTIONS = GEMINI_MODELS.map((model: string) => ({ label: model, value: model })); @@ -50,6 +89,7 @@ interface Props { const AddModelProviderButton: React.FC = ({ refetch }) => { const [form] = Form.useForm(); const [showModal, setShowModal] = useState(false); + const [modelProviderType, setModelProviderType] = useState(ModelProviderType.OPENAI); const [models, setModels] = useState(OPENAI_MODELS_OPTIONS); const mutation = useMutation({ mutationFn: addModelProvider @@ -106,10 +146,13 @@ const AddModelProviderButton: React.FC = ({ refetch }) => { const onChange = (e: any) => { const value = get(e, 'target.value'); + setModelProviderType(value as ModelProviderType); if (value === 'openai' && !isEqual(OPENAI_MODELS_OPTIONS, models)) { setModels(OPENAI_MODELS_OPTIONS); } else if (value === 'gemini' && !isEqual(GEMINI_MODELS_OPTIONS, models)) { setModels(GEMINI_MODELS_OPTIONS); + } else if (value === 'aws_bedrock' && !isEqual(GEMINI_MODELS_OPTIONS, models)) { + setModels(AWS_BEDROCK_MODELS_OPTIONS); } } @@ -146,7 +189,7 @@ const AddModelProviderButton: React.FC = ({ refetch }) => { defaultValue="openai" optionType="button" buttonStyle="solid" - style={{ width: '40%' }} + style={{ width: '100%', whiteSpace: 'nowrap' }} onChange={onChange} /> @@ -162,49 +205,97 @@ const AddModelProviderButton: React.FC = ({ refetch }) => { - + {'Enter Model Name '}, value: '' } + ].concat( + models + )} + placeholder={'Select Model'} + /> - + + } + {modelProviderType !== ModelProviderType.AWS_BEDROCK && modelProviderType !== ModelProviderType.CAII && - + - + + + } } diff --git a/app/client/src/pages/Settings/EditModelProvider.tsx b/app/client/src/pages/Settings/EditModelProvider.tsx index 0c786a4..c6dda9c 100644 --- a/app/client/src/pages/Settings/EditModelProvider.tsx +++ b/app/client/src/pages/Settings/EditModelProvider.tsx @@ -9,54 +9,8 @@ import { addModelProvider, useGetModelProvider } from './hooks'; import Loading from '../Evaluator/Loading'; import { CustomModel } from './SettingsPage'; import isEmpty from 'lodash/isEmpty'; +import { GEMINI_MODELS_OPTIONS, ModelProviderType, modelProviderTypeOptions, OPENAI_MODELS_OPTIONS } from './AddModelProviderButton'; -export enum ModelProviderType { - OPENAI = 'openai', - GEMINIE = 'gemini', - CAII = 'caii' -} - - -const modelProviderTypeOptions: CheckboxGroupProps['options'] = [ - { label: 'OpenAI', value: 'openai' }, - // { label: 'CAII', value: 'caii' }, - { label: 'Gemini', value: 'gemini' }, -]; - -const OPENAI_MODELS = [ - "gpt-4.1", // Latest GPT-4.1 series (April 2025) - "gpt-4.1-mini", - "gpt-4.1-nano", - "o3", // Latest reasoning models (April 2025) - "o4-mini", - "o3-mini", // January 2025 - "o1", // December 2024 - "gpt-4o", // November 2024 - "gpt-4o-mini", // July 2024 - "gpt-4-turbo", // April 2024 - "gpt-3.5-turbo" // Legacy but still widely used -]; - -const OPENAI_MODELS_OPTIONS = OPENAI_MODELS.map((model: string) => ({ - label: model, - value: model -})); - -const GEMINI_MODELS = [ - "gemini-2.5-pro", // June 2025 - most powerful thinking model - "gemini-2.5-flash", // June 2025 - best price-performance - "gemini-2.5-flash-lite", // June 2025 - cost-efficient - "gemini-2.0-flash", // February 2025 - next-gen features - "gemini-2.0-flash-lite", // February 2025 - low latency - "gemini-1.5-pro", // September 2024 - complex reasoning - "gemini-1.5-flash", // September 2024 - fast & versatile - "gemini-1.5-flash-8b" // October 2024 - lightweight -]; - -const GEMINI_MODELS_OPTIONS = GEMINI_MODELS.map((model: string) => ({ - label: model, - value: model -})); interface Props { refetch: () => void; @@ -66,7 +20,8 @@ interface Props { const EditModelProvider: React.FC = ({ model, refetch, onClose }) => { const [form] = Form.useForm(); - const modelProviderReq = useGetModelProvider(model.endpoint_id); + const [modelProviderType, setModelProviderType] = useState(ModelProviderType.OPENAI); + const modelProviderReq = useGetModelProvider(model); const [models, setModels] = useState(OPENAI_MODELS_OPTIONS); const mutation = useMutation({ mutationFn: addModelProvider @@ -75,9 +30,12 @@ const EditModelProvider: React.FC = ({ model, refetch, onClose }) => { useEffect(() => { if (!isEmpty(modelProviderReq.data)) { const endpoint = get(modelProviderReq, 'data.endpoint'); - form.setFieldsValue({ - ...endpoint - }); + if (!isEmpty(endpoint)) { + form.setFieldsValue({ + ...endpoint + }); + setModelProviderType(endpoint?.provider_type as ModelProviderType); + } } }, [modelProviderReq.data]); @@ -167,24 +125,24 @@ const EditModelProvider: React.FC = ({ model, refetch, onClose }) => { defaultValue="openai" optionType="button" buttonStyle="solid" - style={{ width: '40%' }} + style={{ width: '100%', whiteSpace: 'nowrap' }} onChange={onChange} /> - + - - } + {modelProviderType !== ModelProviderType.AWS_BEDROCK && modelProviderType !== ModelProviderType.CAII && - + - + + + } diff --git a/app/client/src/pages/Settings/SettingsPage.tsx b/app/client/src/pages/Settings/SettingsPage.tsx index 4913ffd..81fbd32 100644 --- a/app/client/src/pages/Settings/SettingsPage.tsx +++ b/app/client/src/pages/Settings/SettingsPage.tsx @@ -16,6 +16,7 @@ import { import { useMutation } from "@tanstack/react-query"; import { useState } from "react"; import EditModelProvider from "./EditModelProvider"; +import isEmpty from "lodash/isEmpty"; @@ -116,13 +117,12 @@ const SettingsPage: React.FC = () => { } const modelProvidersColumns = [{ - key: 'display_name', - title: 'Display Name', - dataIndex: 'display_name', + key: 'model_id', + title: 'Model ID', + dataIndex: 'model_id', width: 200, - sorter: sortItemsByKey('display_name') - - }, { + sorter: sortItemsByKey('model_id') + },{ key: 'provider_type', title: 'Provider Type', dataIndex: 'provider_type', @@ -131,6 +131,8 @@ const SettingsPage: React.FC = () => { render: (provider_type: string) => { if (provider_type === 'openai') { return 'OpenAI'; + } else if (provider_type === 'openai_compatible') { + return 'OpenAI Compatible'; } else if (provider_type === ModelProviderType.GEMINI) { return 'Gemini'; } else if (provider_type === ModelProviderType.CAII) { @@ -139,27 +141,30 @@ const SettingsPage: React.FC = () => { return 'N/A' } }, { - key: 'model_id', - title: 'Model ID', - dataIndex: 'model_id', - width: 200, - sorter: sortItemsByKey('model_id') - - }, { - key: 'created_at', - title: 'Created At', - dataIndex: 'created_at', - width: 200, - sorter: sortItemsByKey('created_at'), - render: (timestamp: string) => <>{timestamp == null ? 'N/A' : } - - }, { + // key: 'created_at', + // title: 'Created At', + // dataIndex: 'created_at', + // width: 200, + // sorter: sortItemsByKey('created_at'), + // render: (timestamp: string) => <>{timestamp == null ? 'N/A' : } + // }, { key: 'endpoint_url', title: 'Endpoint', dataIndex: 'endpoint_url', width: 300, sorter: sortItemsByKey('endpoint_url'), - render: (endpoint_url: string) => {endpoint_url} + render: (endpoint_url: string) => { + if (isEmpty(endpoint_url)) { + return 'N/A'; + } + + return ( + + {endpoint_url} + + ) + + } }, { title: 'Actions', width: 100, @@ -180,6 +185,7 @@ const SettingsPage: React.FC = () => { onEdit(model)} data-event-category="User Action" diff --git a/app/client/src/pages/Settings/hooks.ts b/app/client/src/pages/Settings/hooks.ts index 4269a73..951bbe5 100644 --- a/app/client/src/pages/Settings/hooks.ts +++ b/app/client/src/pages/Settings/hooks.ts @@ -1,4 +1,5 @@ import { useQuery } from "@tanstack/react-query"; +import { CustomModel } from "./SettingsPage"; const BASE_API_URL = import.meta.env.VITE_AMP_URL; @@ -12,22 +13,22 @@ const fetchFilteredModels = async () => { }; -export const deleteModelProvider = async ({ endpoint_id }) => { - const delete_resp = await fetch(`/custom_model_endpoints/${endpoint_id}`, { +export const deleteModelProvider = async ({ model }: { model: CustomModel }) => { + const delete_resp = await fetch(`/custom_model_endpoints/${model.model_id}/${model.provider_type}`, { method: 'DELETE' }); return await delete_resp.json(); } -export const getModelProvider = async ({ endpoint_id }) => { - const get_model_resp = await fetch(`/custom_model_endpoints/${endpoint_id}`, { +export const getModelProvider = async ({ model }: { model: CustomModel }) => { + const get_model_resp = await fetch(`/custom_model_endpoints/${model.model_id}/${model.provider_type}`, { method: 'GET' - }); - return await get_model_resp.json(); + }); + return await get_model_resp.json(); } -export const updateModelProvider = async ({ endpoint_id }) => { - const update_model_resp = await fetch(`/custom_model_endpoints/${endpoint_id}`, { +export const updateModelProvider = async ({ model }: { model: CustomModel }) => { + const update_model_resp = await fetch(`/custom_model_endpoints/${model.model_id}/${model.provider_type}`, { method: 'PUT' }); return await update_model_resp.json(); @@ -61,12 +62,12 @@ export const addModelProvider = async (params: any) => { return await model_filtered_resp.json(); } -export const useGetModelProvider = (endpoint_id) => { +export const useGetModelProvider = (model: CustomModel) => { const { data, isLoading, isError, refetch } = useQuery( { queryKey: ['getModelProvider'], - queryFn: () => getModelProvider({ endpoint_id }), + queryFn: () => getModelProvider({ model }), refetchInterval: 15000 } );