From 246ef2a2383b87bd2798dda0d063c32da3b50fca Mon Sep 17 00:00:00 2001 From: Pierre Gayvallet Date: Wed, 18 Dec 2024 10:07:43 +0100 Subject: [PATCH] [8.x] [Inference Connector] Changed UI/UX due to the new RFC for the _inference/_service (#203363) (#204690) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Backport This will backport the following commits from `main` to `8.x`: - [[Inference Connector] Changed UI/UX due to the new RFC for the _inference/_service (#203363)](https://github.com/elastic/kibana/pull/203363) ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) Co-authored-by: Yuliia Naumenko --- .../translations/translations/fr-FR.json | 1 - .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - .../common/dynamic_config/types.ts | 23 +- .../common/inference/types.ts | 12 +- .../inference/additional_options_fields.tsx | 59 +- .../inference/connector.test.tsx | 676 +++++++++++++++--- .../connector_types/inference/connector.tsx | 113 +-- .../connector_types/inference/helpers.ts | 2 +- .../inference/hidden_fields.tsx | 29 - .../connector_configuration_field.tsx | 139 +--- .../connector_configuration_form_items.tsx | 71 +- .../connector_configuration_utils.ts | 4 - .../routes/get_inference_services.test.ts | 670 +++++++++++++++-- .../server/routes/get_inference_services.ts | 662 ++++++++++++++++- 15 files changed, 1915 insertions(+), 548 deletions(-) diff --git a/x-pack/platform/plugins/private/translations/translations/fr-FR.json b/x-pack/platform/plugins/private/translations/translations/fr-FR.json index 71022cb1093f0..8eed15c074814 100644 --- a/x-pack/platform/plugins/private/translations/translations/fr-FR.json +++ b/x-pack/platform/plugins/private/translations/translations/fr-FR.json @@ -45314,7 +45314,6 @@ "xpack.stackConnectors.components.inference.taskTypeDetailsLabel": "Paramètres des tâches", "xpack.stackConnectors.components.inference.taskTypeFieldLabel": "Type de tâche", "xpack.stackConnectors.components.inference.taskTypeHelpLabel": "Configurer la tâche d'inférence. Ces paramètres sont spécifiques au service et au modèle sélectionnés.", - "xpack.stackConnectors.components.inference.taskTypeLabel": "Type de tâche", "xpack.stackConnectors.components.inference.unableToFindProvidersQueryMessage": "Impossible de trouver des fournisseurs", "xpack.stackConnectors.components.jira.apiTokenTextFieldLabel": "Token d'API", "xpack.stackConnectors.components.jira.apiUrlTextFieldLabel": "URL", diff --git a/x-pack/platform/plugins/private/translations/translations/ja-JP.json b/x-pack/platform/plugins/private/translations/translations/ja-JP.json index 0e57dedbab133..cdef324ec015b 100644 --- a/x-pack/platform/plugins/private/translations/translations/ja-JP.json +++ b/x-pack/platform/plugins/private/translations/translations/ja-JP.json @@ -45163,7 +45163,6 @@ "xpack.stackConnectors.components.inference.taskTypeDetailsLabel": "タスク設定", "xpack.stackConnectors.components.inference.taskTypeFieldLabel": "タスクタイプ", "xpack.stackConnectors.components.inference.taskTypeHelpLabel": "推論タスクを構成します。これらの設定は、選択したサービスおよびモデルに固有です。", - "xpack.stackConnectors.components.inference.taskTypeLabel": "タスクタイプ", "xpack.stackConnectors.components.inference.unableToFindProvidersQueryMessage": "プロバイダーが見つかりません", "xpack.stackConnectors.components.jira.apiTokenTextFieldLabel": "APIトークン", "xpack.stackConnectors.components.jira.apiUrlTextFieldLabel": "URL", diff --git a/x-pack/platform/plugins/private/translations/translations/zh-CN.json b/x-pack/platform/plugins/private/translations/translations/zh-CN.json index 59ce51256ed17..9248e6848f1c9 100644 --- a/x-pack/platform/plugins/private/translations/translations/zh-CN.json +++ b/x-pack/platform/plugins/private/translations/translations/zh-CN.json @@ -45261,7 +45261,6 @@ "xpack.stackConnectors.components.inference.taskTypeDetailsLabel": "任务设置", "xpack.stackConnectors.components.inference.taskTypeFieldLabel": "任务类型", "xpack.stackConnectors.components.inference.taskTypeHelpLabel": "配置推理任务。这些设置特定于选定服务和模型。", - "xpack.stackConnectors.components.inference.taskTypeLabel": "任务类型", "xpack.stackConnectors.components.inference.unableToFindProvidersQueryMessage": "找不到提供商", "xpack.stackConnectors.components.jira.apiTokenTextFieldLabel": "API 令牌", "xpack.stackConnectors.components.jira.apiUrlTextFieldLabel": "URL", diff --git a/x-pack/plugins/stack_connectors/common/dynamic_config/types.ts b/x-pack/plugins/stack_connectors/common/dynamic_config/types.ts index 40e17a1989075..b5c73958294e1 100644 --- a/x-pack/plugins/stack_connectors/common/dynamic_config/types.ts +++ b/x-pack/plugins/stack_connectors/common/dynamic_config/types.ts @@ -5,15 +5,6 @@ * 2.0. */ -export enum DisplayType { - TEXTBOX = 'textbox', - TEXTAREA = 'textarea', - NUMERIC = 'numeric', - TOGGLE = 'toggle', - DROPDOWN = 'dropdown', - CHECKABLE = 'checkable', -} - export interface SelectOption { label: string; value: string; @@ -28,7 +19,6 @@ export interface Dependency { export enum FieldType { STRING = 'str', INTEGER = 'int', - LIST = 'list', BOOLEAN = 'bool', } @@ -44,21 +34,13 @@ export interface Validation { } export interface ConfigProperties { - category?: string; default_value: string | number | boolean | null; - depends_on: Dependency[]; - display: DisplayType; + description: string | null; label: string; - options?: SelectOption[]; - order?: number | null; - placeholder?: string; required: boolean; sensitive: boolean; - tooltip: string | null; + updatable: boolean; type: FieldType; - ui_restrictions: string[]; - validations: Validation[]; - value: string | number | boolean | null; } interface ConfigEntry extends ConfigProperties { @@ -68,4 +50,5 @@ interface ConfigEntry extends ConfigProperties { export interface ConfigEntryView extends ConfigEntry { isValid: boolean; validationErrors: string[]; + value: string | number | boolean | null; } diff --git a/x-pack/plugins/stack_connectors/common/inference/types.ts b/x-pack/plugins/stack_connectors/common/inference/types.ts index b9561efe24292..d8b846ce19422 100644 --- a/x-pack/plugins/stack_connectors/common/inference/types.ts +++ b/x-pack/plugins/stack_connectors/common/inference/types.ts @@ -40,14 +40,10 @@ export type StreamingResponse = TypeOf; export type FieldsConfiguration = Record; -export interface InferenceTaskType { - task_type: string; - configuration: FieldsConfiguration; -} - export interface InferenceProvider { - provider: string; - task_types: InferenceTaskType[]; + service: string; + name: string; + task_types: string[]; logo?: string; - configuration: FieldsConfiguration; + configurations: FieldsConfiguration; } diff --git a/x-pack/plugins/stack_connectors/public/connector_types/inference/additional_options_fields.tsx b/x-pack/plugins/stack_connectors/public/connector_types/inference/additional_options_fields.tsx index 7a3b1abfd800b..d36a8301f1726 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/inference/additional_options_fields.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/inference/additional_options_fields.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useMemo, useCallback } from 'react'; +import React, { useMemo } from 'react'; import { css } from '@emotion/react'; import { @@ -18,7 +18,6 @@ import { EuiTextColor, EuiButtonGroup, EuiPanel, - EuiHorizontalRule, EuiButtonEmpty, EuiCopy, EuiButton, @@ -55,7 +54,6 @@ interface AdditionalOptionsConnectorFieldsProps { onTaskTypeOptionsSelect: (taskType: string, provider?: string) => void; selectedTaskType?: string; taskTypeFormFields: ConfigEntryView[]; - taskTypeSchema: ConfigEntryView[]; taskTypeOptions: TaskTypeOption[]; } @@ -65,35 +63,13 @@ export const AdditionalOptionsConnectorFields: React.FC { const xsFontSize = useEuiFontSize('xs').fontSize; const { euiTheme } = useEuiTheme(); - const { setFieldValue, validateFields } = useFormContext(); - - const onSetTaskTypeConfigEntry = useCallback( - async (key: string, value: unknown) => { - if (taskTypeSchema) { - const entry: ConfigEntryView | undefined = taskTypeSchema.find( - (p: ConfigEntryView) => p.key === key - ); - if (entry) { - if (!config.taskTypeConfig) { - config.taskTypeConfig = {}; - } - const newConfig = { ...config.taskTypeConfig }; - newConfig[key] = value; - setFieldValue('config.taskTypeConfig', newConfig); - await validateFields(['config.taskTypeConfig']); - } - } - }, - [config, setFieldValue, taskTypeSchema, validateFields] - ); + const { setFieldValue } = useFormContext(); const taskTypeSettings = useMemo( () => @@ -103,7 +79,7 @@ export const AdditionalOptionsConnectorFields: React.FC @@ -116,7 +92,7 @@ export const AdditionalOptionsConnectorFields: React.FC @@ -135,18 +111,7 @@ export const AdditionalOptionsConnectorFields: React.FC - } - isInvalid={isInvalid} - error={errorMessage} - > + {isEdit || readOnly ? ( - - ) : null, [ selectedTaskType, - config?.taskType, + config.taskType, xsFontSize, euiTheme.colors, - taskTypeFormFields, - onSetTaskTypeConfigEntry, isEdit, readOnly, taskTypeOptions, @@ -276,7 +231,7 @@ export const AdditionalOptionsConnectorFields: React.FC +

= ({ readOnly, @@ -63,7 +58,6 @@ const InferenceAPIConnectorFields: React.FunctionComponent([]); const [taskTypeOptions, setTaskTypeOptions] = useState([]); const [selectedTaskType, setSelectedTaskType] = useState(DEFAULT_TASK_TYPE); - const [taskTypeFormFields, setTaskTypeFormFields] = useState([]); + const [taskTypeFormFields] = useState([]); const handleProviderClosePopover = useCallback(() => { setProviderPopoverOpen(false); @@ -111,69 +104,39 @@ const InferenceAPIConnectorFields: React.FunctionComponent { + (taskType: string) => { // Get task type settings - const currentProvider = providers?.find((p) => p.provider === (provider ?? config?.provider)); - const currentTaskTypes = currentProvider?.task_types; - const newTaskType = currentTaskTypes?.find((p) => p.task_type === taskType); - setSelectedTaskType(taskType); - // transform the schema - const newTaskTypeSchema = Object.keys(newTaskType?.configuration ?? {}).map((k) => ({ - key: k, - isValid: true, - ...newTaskType?.configuration[k], - })) as ConfigEntryView[]; - setTaskTypeSchema(newTaskTypeSchema); - - const configDefaults = Object.keys(newTaskType?.configuration ?? {}).reduce( - (res: Record, k) => { - if (newTaskType?.configuration[k] && !!newTaskType?.configuration[k].default_value) { - res[k] = newTaskType.configuration[k].default_value; - } else { - res[k] = null; - } - return res; - }, - {} - ); - updateFieldValues({ config: { taskType, - taskTypeConfig: configDefaults, }, }); - generateInferenceEndpointId( - { ...config, taskType, taskTypeConfig: configDefaults }, - setFieldValue - ); + generateInferenceEndpointId({ ...config, taskType }, setFieldValue); }, - [config, providers, setFieldValue, updateFieldValues] + [config, setFieldValue, updateFieldValues] ); const onProviderChange = useCallback( (provider?: string) => { - const newProvider = providers?.find((p) => p.provider === provider); + const newProvider = providers?.find((p) => p.service === provider); // Update task types list available for the selected provider - const providerTaskTypes = (newProvider?.task_types ?? []).map((t) => t.task_type); - setTaskTypeOptions(getTaskTypeOptions(providerTaskTypes)); - if (providerTaskTypes.length > 0) { - onTaskTypeOptionsSelect(providerTaskTypes[0], provider); + setTaskTypeOptions(getTaskTypeOptions(newProvider?.task_types ?? [])); + if (newProvider?.task_types && newProvider?.task_types.length > 0) { + onTaskTypeOptionsSelect(newProvider?.task_types[0]); } // Update connector providerSchema - const newProviderSchema = Object.keys(newProvider?.configuration ?? {}).map((k) => ({ + const newProviderSchema = Object.keys(newProvider?.configurations ?? {}).map((k) => ({ key: k, isValid: true, - ...newProvider?.configuration[k], + ...newProvider?.configurations[k], })) as ConfigEntryView[]; setProviderSchema(newProviderSchema); @@ -181,10 +144,10 @@ const InferenceAPIConnectorFields: React.FunctionComponent = {}; const defaultProviderSecrets: Record = {}; - Object.keys(newProvider?.configuration ?? {}).forEach((k) => { - if (!newProvider?.configuration[k].sensitive) { - if (newProvider?.configuration[k] && !!newProvider?.configuration[k].default_value) { - defaultProviderConfig[k] = newProvider.configuration[k].default_value; + Object.keys(newProvider?.configurations ?? {}).forEach((k) => { + if (!newProvider?.configurations[k].sensitive) { + if (newProvider?.configurations[k] && !!newProvider?.configurations[k].default_value) { + defaultProviderConfig[k] = newProvider.configurations[k].default_value; } else { defaultProviderConfig[k] = null; } @@ -195,7 +158,7 @@ const InferenceAPIConnectorFields: React.FunctionComponent { - const getTaskTypeSchema = (taskTypes: InferenceTaskType[]) => { - const newTaskType = taskTypes.find((p) => p.task_type === config?.taskType); - - // transform the schema - const newTaskTypeSchema = Object.keys(newTaskType?.configuration ?? {}).map((k) => ({ - key: k, - isValid: true, - ...newTaskType?.configuration[k], - })) as ConfigEntryView[]; - - setTaskTypeSchema(newTaskTypeSchema); - }; - if (config?.provider && isEdit) { - const newProvider = providers?.find((p) => p.provider === config.provider); + const newProvider = providers?.find((p) => p.service === config.provider); // Update connector providerSchema - const newProviderSchema = Object.keys(newProvider?.configuration ?? {}).map((k) => ({ + const newProviderSchema = Object.keys(newProvider?.configurations ?? {}).map((k) => ({ key: k, isValid: true, - ...newProvider?.configuration[k], + ...newProvider?.configurations[k], })) as ConfigEntryView[]; setProviderSchema(newProviderSchema); - - getTaskTypeSchema(newProvider?.task_types ?? []); } }, [config?.provider, config?.taskType, http, isEdit, providers]); @@ -250,31 +198,14 @@ const InferenceAPIConnectorFields: React.FunctionComponent (a.order ?? 0) - (b.order ?? 0)); setOptionalProviderFormFields(existingConfiguration.filter((p) => !p.required && !p.sensitive)); setRequiredProviderFormFields(existingConfiguration.filter((p) => p.required || p.sensitive)); }, [config?.providerConfig, providerSchema, secrets]); - useEffect(() => { - // Set values from the task type config to the schema - const existingTaskTypeConfiguration = taskTypeSchema - ? taskTypeSchema.map((item: ConfigEntryView) => { - const itemValue = item; - itemValue.isValid = true; - if (config?.taskTypeConfig) { - itemValue.value = config?.taskTypeConfig[item.key] as any; - } - return itemValue; - }) - : []; - existingTaskTypeConfiguration.sort((a, b) => (a.order ?? 0) - (b.order ?? 0)); - setTaskTypeFormFields(existingTaskTypeConfiguration); - }, [config, taskTypeSchema]); - const getProviderOptions = useCallback(() => { return providers?.map((p) => ({ - label: p.provider, - key: p.provider, + label: p.service, + key: p.service, })) as EuiSelectableOption[]; }, [providers]); @@ -433,7 +364,6 @@ const InferenceAPIConnectorFields: React.FunctionComponent @@ -449,7 +379,6 @@ const InferenceAPIConnectorFields: React.FunctionComponent ) : null} diff --git a/x-pack/plugins/stack_connectors/public/connector_types/inference/helpers.ts b/x-pack/plugins/stack_connectors/public/connector_types/inference/helpers.ts index 8638caa998eff..d3f324b55363a 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/inference/helpers.ts +++ b/x-pack/plugins/stack_connectors/public/connector_types/inference/helpers.ts @@ -72,7 +72,7 @@ export const getNonEmptyValidator = ( newSchema.push(field); }); - validationEventHandler(newSchema.sort((a, b) => (a.order ?? 0) - (b.order ?? 0))); + validationEventHandler(newSchema); if (hasErrors) { return { code: 'ERR_FIELD_MISSING', diff --git a/x-pack/plugins/stack_connectors/public/connector_types/inference/hidden_fields.tsx b/x-pack/plugins/stack_connectors/public/connector_types/inference/hidden_fields.tsx index f6df891b4b9c8..33215f6a83689 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/inference/hidden_fields.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/inference/hidden_fields.tsx @@ -57,32 +57,3 @@ export const getProviderConfigHiddenField = ( }} /> ); - -export const getTaskTypeConfigHiddenField = ( - taskTypeSchema: ConfigEntryView[], - setTaskTypeFormFields: React.Dispatch>, - isSubmitting: boolean -) => ( - { - const formFields = [ - ...requiredFormFields, - ...(taskTypeSchema ?? []).filter((f) => !f.required), - ]; - setTaskTypeFormFields(formFields.sort((a, b) => (a.order ?? 0) - (b.order ?? 0))); - }, - isSubmitting - ), - isBlocking: true, - }, - ], - }} - /> -); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/lib/dynamic_config/connector_configuration_field.tsx b/x-pack/plugins/stack_connectors/public/connector_types/lib/dynamic_config/connector_configuration_field.tsx index 5560c831c4a61..b6dc0972492bf 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/lib/dynamic_config/connector_configuration_field.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/lib/dynamic_config/connector_configuration_field.tsx @@ -13,19 +13,11 @@ import { EuiFieldPassword, EuiSwitch, EuiTextArea, - EuiFlexGroup, - EuiFlexItem, - EuiIcon, EuiFieldNumber, - EuiCheckableCard, - useGeneratedHtmlId, - EuiSpacer, - EuiSuperSelect, - EuiText, } from '@elastic/eui'; import { isEmpty } from 'lodash/fp'; -import { ConfigEntryView, DisplayType } from '../../../../common/dynamic_config/types'; +import { ConfigEntryView, FieldType } from '../../../../common/dynamic_config/types'; import { ensureBooleanType, ensureCorrectTyping, @@ -49,7 +41,7 @@ export const ConfigInputField: React.FC = ({ validateAndSetConfigValue, }) => { // eslint-disable-next-line @typescript-eslint/naming-convention - const { isValid, placeholder, value, default_value, key } = configEntry; + const { isValid, value, default_value, key } = configEntry; const [innerValue, setInnerValue] = useState( !value || value.toString().length === 0 ? default_value : value ); @@ -68,7 +60,6 @@ export const ConfigInputField: React.FC = ({ setInnerValue(event.target.value); validateAndSetConfigValue(event.target.value); }} - placeholder={placeholder} /> ); }; @@ -104,7 +95,7 @@ export const ConfigInputTextArea: React.FC = ({ validateAndSetConfigValue, }) => { // eslint-disable-next-line @typescript-eslint/naming-convention - const { isValid, placeholder, value, default_value, key } = configEntry; + const { isValid, value, default_value, key } = configEntry; const [innerValue, setInnerValue] = useState(value ?? default_value); useEffect(() => { setInnerValue(value ?? default_value); @@ -121,7 +112,6 @@ export const ConfigInputTextArea: React.FC = ({ setInnerValue(event.target.value); validateAndSetConfigValue(event.target.value); }} - placeholder={placeholder} /> ); }; @@ -132,7 +122,7 @@ export const ConfigNumberField: React.FC = ({ validateAndSetConfigValue, }) => { // eslint-disable-next-line @typescript-eslint/naming-convention - const { isValid, placeholder, value, default_value, key } = configEntry; + const { isValid, value, default_value, key } = configEntry; const [innerValue, setInnerValue] = useState(value ?? default_value); useEffect(() => { setInnerValue(!value || value.toString().length === 0 ? default_value : value); @@ -149,43 +139,10 @@ export const ConfigNumberField: React.FC = ({ setInnerValue(newValue); validateAndSetConfigValue(newValue); }} - placeholder={placeholder} /> ); }; -export const ConfigCheckableField: React.FC = ({ - configEntry, - validateAndSetConfigValue, -}) => { - const radioCardId = useGeneratedHtmlId({ prefix: 'radioCard' }); - // eslint-disable-next-line @typescript-eslint/naming-convention - const { value, options, default_value } = configEntry; - const [innerValue, setInnerValue] = useState(value ?? default_value); - useEffect(() => { - setInnerValue(value ?? default_value); - }, [default_value, value]); - return ( - <> - {options?.map((o) => ( - <> - { - setInnerValue(o.value); - validateAndSetConfigValue(o.value); - }} - /> - - - ))} - - ); -}; - export const ConfigSensitiveTextArea: React.FC = ({ isLoading, configEntry, @@ -230,44 +187,6 @@ export const ConfigInputPassword: React.FC = ({ ); }; -export const ConfigSelectField: React.FC = ({ - configEntry, - isLoading, - validateAndSetConfigValue, -}) => { - // eslint-disable-next-line @typescript-eslint/naming-convention - const { isValid, options, value, default_value } = configEntry; - const [innerValue, setInnerValue] = useState(value ?? default_value); - const optionsRes = options?.map((o) => ({ - value: o.value, - inputDisplay: ( - - {o.icon ? ( - - - - ) : null} - - {o.label} - - - ), - })); - return ( - { - setInnerValue(newValue); - validateAndSetConfigValue(newValue); - }} - /> - ); -}; - export const ConnectorConfigurationField: React.FC = ({ configEntry, isLoading, @@ -277,30 +196,10 @@ export const ConnectorConfigurationField: React.FC - ); - - case DisplayType.CHECKABLE: - return ( - - ); + const { key, type, sensitive } = configEntry; - case DisplayType.NUMERIC: + switch (type) { + case FieldType.INTEGER: return ( ); - case DisplayType.TEXTAREA: - const textarea = ( - - ); - - return sensitive ? ( - <> - - - ) : ( - textarea - ); - - case DisplayType.TOGGLE: + case FieldType.BOOLEAN: return ( { return ( {items.map((configEntry) => { - const { - depends_on: dependencies, - key, - display, - isValid, - label, - sensitive, - tooltip, - validationErrors, - required, - } = configEntry; + const { key, isValid, label, sensitive, description, validationErrors, required } = + configEntry; - const helpText = tooltip; + const helpText = description; // toggle and sensitive textarea labels go next to the element, not in the row - const rowLabel = - display === DisplayType.TOGGLE || (display === DisplayType.TEXTAREA && sensitive) ? ( - <> - ) : tooltip ? ( - - -

{label}

-
-
- ) : ( -

{label}

- ); + const rowLabel = description ? ( + + +

{label}

+
+
+ ) : ( +

{label}

+ ); const optionalLabel = !required ? ( @@ -74,31 +60,6 @@ export const ConnectorConfigurationFormItems: React.FC ) : undefined; - if (dependencies?.length > 0) { - return ( - - - - { - setConfigEntry(configEntry.key, value); - }} - /> - - - - ); - } return ( { - setConfigEntry(configEntry.key, value); + setConfigEntry(key, value); }} /> - {configEntry.sensitive ? ( + {sensitive ? ( <> ) : null} diff --git a/x-pack/plugins/stack_connectors/public/connector_types/lib/dynamic_config/connector_configuration_utils.ts b/x-pack/plugins/stack_connectors/public/connector_types/lib/dynamic_config/connector_configuration_utils.ts index cce5bc15fa56c..5e78903746aee 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/lib/dynamic_config/connector_configuration_utils.ts +++ b/x-pack/plugins/stack_connectors/public/connector_types/lib/dynamic_config/connector_configuration_utils.ts @@ -49,7 +49,3 @@ export const ensureIntType = (value: string | number | boolean | null): number | export const ensureBooleanType = (value: string | number | boolean | null): boolean => { return Boolean(value); }; - -export const hasUiRestrictions = (configEntry: Partial) => { - return (configEntry.ui_restrictions ?? []).length > 0; -}; diff --git a/x-pack/plugins/stack_connectors/server/routes/get_inference_services.test.ts b/x-pack/plugins/stack_connectors/server/routes/get_inference_services.test.ts index 50596028d80a8..9e1449a37f7ff 100644 --- a/x-pack/plugins/stack_connectors/server/routes/get_inference_services.test.ts +++ b/x-pack/plugins/stack_connectors/server/routes/get_inference_services.test.ts @@ -8,7 +8,7 @@ import { httpServiceMock, httpServerMock } from '@kbn/core/server/mocks'; import { coreMock } from '@kbn/core/server/mocks'; import { getInferenceServicesRoute } from './get_inference_services'; -import { DisplayType, FieldType } from '../../common/dynamic_config/types'; +import { FieldType } from '../../common/dynamic_config/types'; describe('getInferenceServicesRoute', () => { it('returns available service providers', async () => { @@ -17,100 +17,644 @@ describe('getInferenceServicesRoute', () => { const mockResult = [ { - provider: 'openai', - task_types: [ - { - task_type: 'completion', - configuration: { - user: { - display: DisplayType.TEXTBOX, - label: 'User', - order: 1, - required: false, - sensitive: false, - tooltip: 'Specifies the user issuing the request.', - type: FieldType.STRING, - validations: [], - value: '', - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - }, - }, - ], - configuration: { + service: 'cohere', + name: 'Cohere', + task_types: ['text_embedding', 'rerank', 'completion'], + configurations: { api_key: { - display: DisplayType.TEXTBOX, + default_value: null, + description: `API Key for the provider you're connecting to.`, + label: 'API Key', + required: true, + sensitive: true, + updatable: true, + type: FieldType.STRING, + }, + 'rate_limit.requests_per_minute': { + default_value: null, + description: 'Minimize the number of rate limit errors.', + label: 'Rate Limit', + required: false, + sensitive: false, + updatable: true, + type: FieldType.INTEGER, + }, + }, + }, + { + service: 'elastic', + name: 'Elastic', + task_types: ['sparse_embedding'], + configurations: { + 'rate_limit.requests_per_minute': { + default_value: null, + description: 'Minimize the number of rate limit errors.', + label: 'Rate Limit', + required: false, + sensitive: false, + updatable: true, + type: FieldType.INTEGER, + }, + model_id: { + default_value: null, + description: 'The name of the model to use for the inference task.', + label: 'Model ID', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + max_input_tokens: { + default_value: null, + description: 'Allows you to specify the maximum number of tokens per input.', + label: 'Maximum Input Tokens', + required: false, + sensitive: false, + updatable: true, + type: FieldType.INTEGER, + }, + }, + }, + { + service: 'watsonxai', + name: 'IBM Watsonx', + task_types: ['text_embedding'], + configurations: { + project_id: { + default_value: null, + description: '', + label: 'Project ID', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + model_id: { + default_value: null, + description: 'The name of the model to use for the inference task.', + label: 'Model ID', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + api_version: { + default_value: null, + description: 'The IBM Watsonx API version ID to use.', + label: 'API Version', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + max_input_tokens: { + default_value: null, + description: 'Allows you to specify the maximum number of tokens per input.', + label: 'Maximum Input Tokens', + required: false, + sensitive: false, + updatable: true, + type: FieldType.INTEGER, + }, + url: { + default_value: null, + description: '', + label: 'URL', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + }, + }, + { + service: 'azureaistudio', + name: 'Azure AI Studio', + task_types: ['text_embedding', 'completion'], + configurations: { + endpoint_type: { + default_value: null, + description: 'Specifies the type of endpoint that is used in your model deployment.', + label: 'Endpoint Type', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + provider: { + default_value: null, + description: 'The model provider for your deployment.', + label: 'Provider', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + api_key: { + default_value: null, + description: `API Key for the provider you're connecting to.`, + label: 'API Key', + required: true, + sensitive: true, + updatable: true, + type: FieldType.STRING, + }, + 'rate_limit.requests_per_minute': { + default_value: null, + description: 'Minimize the number of rate limit errors.', + label: 'Rate Limit', + required: false, + sensitive: false, + updatable: true, + type: FieldType.INTEGER, + }, + target: { + default_value: null, + description: 'The target URL of your Azure AI Studio model deployment.', + label: 'Target', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + }, + }, + { + service: 'hugging_face', + name: 'Hugging Face', + task_types: ['text_embedding', 'sparse_embedding'], + configurations: { + api_key: { + default_value: null, + description: `API Key for the provider you're connecting to.`, + label: 'API Key', + required: true, + sensitive: true, + updatable: true, + type: FieldType.STRING, + }, + 'rate_limit.requests_per_minute': { + default_value: null, + description: 'Minimize the number of rate limit errors.', + label: 'Rate Limit', + required: false, + sensitive: false, + updatable: true, + type: FieldType.INTEGER, + }, + url: { + default_value: 'https://api.openai.com/v1/embeddings', + description: 'The URL endpoint to use for the requests.', + label: 'URL', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + }, + }, + { + service: 'amazonbedrock', + name: 'Amazon Bedrock', + task_types: ['text_embedding', 'completion'], + configurations: { + secret_key: { + default_value: null, + description: 'A valid AWS secret key that is paired with the access_key.', + label: 'Secret Key', + required: true, + sensitive: true, + updatable: true, + type: FieldType.STRING, + }, + provider: { + default_value: null, + description: 'The model provider for your deployment.', + label: 'Provider', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + access_key: { + default_value: null, + description: 'A valid AWS access key that has permissions to use Amazon Bedrock.', + label: 'Access Key', + required: true, + sensitive: true, + updatable: true, + type: FieldType.STRING, + }, + model: { + default_value: null, + description: + 'The base model ID or an ARN to a custom model based on a foundational model.', + label: 'Model', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + 'rate_limit.requests_per_minute': { + default_value: null, + description: + 'By default, the amazonbedrock service sets the number of requests allowed per minute to 240.', + label: 'Rate Limit', + required: false, + sensitive: false, + updatable: true, + type: FieldType.INTEGER, + }, + region: { + default_value: null, + description: 'The region that your model or ARN is deployed in.', + label: 'Region', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + }, + }, + { + service: 'anthropic', + name: 'Anthropic', + task_types: ['completion'], + configurations: { + api_key: { + default_value: null, + description: `API Key for the provider you're connecting to.`, + label: 'API Key', + required: true, + sensitive: true, + updatable: true, + type: FieldType.STRING, + }, + 'rate_limit.requests_per_minute': { + default_value: null, + description: + 'By default, the anthropic service sets the number of requests allowed per minute to 50.', + label: 'Rate Limit', + required: false, + sensitive: false, + updatable: true, + type: FieldType.INTEGER, + }, + model_id: { + default_value: null, + description: 'The name of the model to use for the inference task.', + label: 'Model ID', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + }, + }, + { + service: 'googleaistudio', + name: 'Google AI Studio', + task_types: ['text_embedding', 'completion'], + configurations: { + api_key: { + default_value: null, + description: `API Key for the provider you're connecting to.`, label: 'API Key', - order: 3, required: true, sensitive: true, - tooltip: `The OpenAI API authentication key. For more details about generating OpenAI API keys, refer to the https://platform.openai.com/account/api-keys.`, + updatable: true, type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], + }, + 'rate_limit.requests_per_minute': { default_value: null, - depends_on: [], + description: 'Minimize the number of rate limit errors.', + label: 'Rate Limit', + required: false, + sensitive: false, + updatable: true, + type: FieldType.INTEGER, }, model_id: { - display: DisplayType.TEXTBOX, + default_value: null, + description: "ID of the LLM you're using.", label: 'Model ID', - order: 2, required: true, sensitive: false, - tooltip: 'The name of the model to use for the inference task.', + updatable: true, type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], + }, + }, + }, + { + service: 'elasticsearch', + name: 'Elasticsearch', + task_types: ['text_embedding', 'sparse_embedding', 'rerank'], + configurations: { + num_allocations: { + default_value: 1, + description: + 'The total number of allocations this model is assigned across machine learning nodes.', + label: 'Number Allocations', + required: true, + sensitive: false, + updatable: true, + type: FieldType.INTEGER, + }, + num_threads: { + default_value: 2, + description: + 'Sets the number of threads used by each model allocation during inference.', + label: 'Number Threads', + required: true, + sensitive: false, + updatable: true, + type: FieldType.INTEGER, + }, + model_id: { + default_value: '.multilingual-e5-small', + description: 'The name of the model to use for the inference task.', + label: 'Model ID', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + }, + }, + { + service: 'openai', + name: 'OpenAI', + task_types: ['text_embedding', 'completion'], + configurations: { + api_key: { default_value: null, - depends_on: [], + description: + 'The OpenAI API authentication key. For more details about generating OpenAI API keys, refer to the https://platform.openai.com/account/api-keys.', + label: 'API Key', + required: true, + sensitive: true, + updatable: true, + type: FieldType.STRING, }, organization_id: { - display: DisplayType.TEXTBOX, + default_value: null, + description: 'The unique identifier of your organization.', label: 'Organization ID', - order: 4, required: false, sensitive: false, - tooltip: 'The unique identifier of your organization.', + updatable: true, type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], + }, + 'rate_limit.requests_per_minute': { default_value: null, - depends_on: [], + description: + 'Default number of requests allowed per minute. For text_embedding is 3000. For completion is 500.', + label: 'Rate Limit', + required: false, + sensitive: false, + updatable: true, + type: FieldType.INTEGER, + }, + model_id: { + default_value: null, + description: 'The name of the model to use for the inference task.', + label: 'Model ID', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, }, url: { - display: DisplayType.TEXTBOX, + default_value: 'https://api.openai.com/v1/chat/completions', + description: + 'The OpenAI API endpoint URL. For more information on the URL, refer to the https://platform.openai.com/docs/api-reference.', label: 'URL', - order: 1, required: true, sensitive: false, - tooltip: - 'The OpenAI API endpoint URL. For more information on the URL, refer to the https://platform.openai.com/docs/api-reference.', + updatable: true, + type: FieldType.STRING, + }, + }, + }, + { + service: 'azureopenai', + name: 'Azure OpenAI', + task_types: ['text_embedding', 'completion'], + configurations: { + api_key: { + default_value: null, + description: `API Key for the provider you're connecting to.`, + label: 'API Key', + required: true, + sensitive: true, + updatable: true, + type: FieldType.STRING, + }, + entra_id: { + default_value: null, + description: 'You must provide either an API key or an Entra ID.', + label: 'Entra ID', + required: false, + sensitive: true, + updatable: true, type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: 'https://api.openai.com/v1/chat/completions', - depends_on: [], }, 'rate_limit.requests_per_minute': { - display: DisplayType.NUMERIC, - label: 'Rate limit', - order: 5, + default_value: null, + description: + 'The azureopenai service sets a default number of requests allowed per minute depending on the task type.', + label: 'Rate Limit', required: false, sensitive: false, - tooltip: - 'Default number of requests allowed per minute. For text_embedding is 3000. For completion is 500.', + updatable: true, type: FieldType.INTEGER, - validations: [], - value: null, - ui_restrictions: [], + }, + deployment_id: { + default_value: null, + description: 'The deployment name of your deployed models.', + label: 'Deployment ID', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + resource_name: { + default_value: null, + description: 'The name of your Azure OpenAI resource.', + label: 'Resource Name', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + api_version: { default_value: null, - depends_on: [], + description: 'The Azure API version ID to use.', + label: 'API Version', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + }, + }, + { + service: 'mistral', + name: 'Mistral', + task_types: ['text_embedding'], + configurations: { + api_key: { + default_value: null, + description: `API Key for the provider you're connecting to.`, + label: 'API Key', + required: true, + sensitive: true, + updatable: true, + type: FieldType.STRING, + }, + model: { + default_value: null, + description: + 'Refer to the Mistral models documentation for the list of available text embedding models.', + label: 'Model', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + 'rate_limit.requests_per_minute': { + default_value: null, + description: 'Minimize the number of rate limit errors.', + label: 'Rate Limit', + required: false, + sensitive: false, + updatable: true, + type: FieldType.INTEGER, + }, + max_input_tokens: { + default_value: null, + description: 'Allows you to specify the maximum number of tokens per input.', + label: 'Maximum Input Tokens', + required: false, + sensitive: false, + updatable: true, + type: FieldType.INTEGER, + }, + }, + }, + { + service: 'googlevertexai', + name: 'Google Vertex AI', + task_types: ['text_embedding', 'rerank'], + configurations: { + service_account_json: { + default_value: null, + description: "API Key for the provider you're connecting to.", + label: 'Credentials JSON', + required: true, + sensitive: true, + updatable: true, + type: FieldType.STRING, + }, + project_id: { + default_value: null, + description: + 'The GCP Project ID which has Vertex AI API(s) enabled. For more information on the URL, refer to the {geminiVertexAIDocs}.', + label: 'GCP Project', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + location: { + default_value: null, + description: + 'Please provide the GCP region where the Vertex AI API(s) is enabled. For more information, refer to the {geminiVertexAIDocs}.', + label: 'GCP Region', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + 'rate_limit.requests_per_minute': { + default_value: null, + description: 'Minimize the number of rate limit errors.', + label: 'Rate Limit', + required: false, + sensitive: false, + updatable: true, + type: FieldType.INTEGER, + }, + model_id: { + default_value: null, + description: `ID of the LLM you're using.`, + label: 'Model ID', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + }, + }, + { + service: 'alibabacloud-ai-search', + name: 'AlibabaCloud AI Search', + task_types: ['text_embedding', 'sparse_embedding', 'rerank', 'completion'], + configurations: { + workspace: { + default_value: null, + description: 'The name of the workspace used for the {infer} task.', + label: 'Workspace', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + api_key: { + default_value: null, + description: `A valid API key for the AlibabaCloud AI Search API.`, + label: 'API Key', + required: true, + sensitive: true, + updatable: true, + type: FieldType.STRING, + }, + service_id: { + default_value: null, + description: 'The name of the model service to use for the {infer} task.', + label: 'Project ID', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + host: { + default_value: null, + description: + 'The name of the host address used for the {infer} task. You can find the host address at https://opensearch.console.aliyun.com/cn-shanghai/rag/api-key[ the API keys section] of the documentation.', + label: 'Host', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + 'rate_limit.requests_per_minute': { + default_value: null, + description: 'Minimize the number of rate limit errors.', + label: 'Rate Limit', + required: false, + sensitive: false, + updatable: true, + type: FieldType.INTEGER, + }, + http_schema: { + default_value: null, + description: '', + label: 'HTTP Schema', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, }, }, }, diff --git a/x-pack/plugins/stack_connectors/server/routes/get_inference_services.ts b/x-pack/plugins/stack_connectors/server/routes/get_inference_services.ts index 1396072834261..005b565dff0d5 100644 --- a/x-pack/plugins/stack_connectors/server/routes/get_inference_services.ts +++ b/x-pack/plugins/stack_connectors/server/routes/get_inference_services.ts @@ -12,6 +12,7 @@ import { IKibanaResponse, KibanaResponseFactory, } from '@kbn/core/server'; +import { FieldType } from '../../common/dynamic_config/types'; import { InferenceProvider } from '../../common/inference/types'; import { INTERNAL_BASE_STACK_CONNECTORS_API_PATH } from '../../common'; @@ -32,15 +33,662 @@ export const getInferenceServicesRoute = (router: IRouter) => { req: KibanaRequest, res: KibanaResponseFactory ): Promise { - const esClient = (await ctx.core).elasticsearch.client.asInternalUser; + // Temporarily hard-coding the response until the real implementation is ready with the updated response - https://github.com/elastic/ml-team/issues/1428 - const response = await esClient.transport.request<{ - endpoints: InferenceProvider[]; - }>({ - method: 'GET', - path: `/_inference/_services`, - }); + // const esClient = (await ctx.core).elasticsearch.client.asInternalUser; + + // // eslint-disable-next-line @typescript-eslint/no-explicit-any + // const response = await esClient.transport.request({ + // method: 'GET', + // path: `/_inference/_services`, + // }); + + const response: InferenceProvider[] = [ + { + service: 'cohere', + name: 'Cohere', + task_types: ['text_embedding', 'rerank', 'completion'], + configurations: { + api_key: { + default_value: null, + description: `API Key for the provider you're connecting to.`, + label: 'API Key', + required: true, + sensitive: true, + updatable: true, + type: FieldType.STRING, + }, + 'rate_limit.requests_per_minute': { + default_value: null, + description: 'Minimize the number of rate limit errors.', + label: 'Rate Limit', + required: false, + sensitive: false, + updatable: true, + type: FieldType.INTEGER, + }, + }, + }, + { + service: 'elastic', + name: 'Elastic', + task_types: ['sparse_embedding'], + configurations: { + 'rate_limit.requests_per_minute': { + default_value: null, + description: 'Minimize the number of rate limit errors.', + label: 'Rate Limit', + required: false, + sensitive: false, + updatable: true, + type: FieldType.INTEGER, + }, + model_id: { + default_value: null, + description: 'The name of the model to use for the inference task.', + label: 'Model ID', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + max_input_tokens: { + default_value: null, + description: 'Allows you to specify the maximum number of tokens per input.', + label: 'Maximum Input Tokens', + required: false, + sensitive: false, + updatable: true, + type: FieldType.INTEGER, + }, + }, + }, + { + service: 'watsonxai', + name: 'IBM Watsonx', + task_types: ['text_embedding'], + configurations: { + project_id: { + default_value: null, + description: '', + label: 'Project ID', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + model_id: { + default_value: null, + description: 'The name of the model to use for the inference task.', + label: 'Model ID', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + api_version: { + default_value: null, + description: 'The IBM Watsonx API version ID to use.', + label: 'API Version', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + max_input_tokens: { + default_value: null, + description: 'Allows you to specify the maximum number of tokens per input.', + label: 'Maximum Input Tokens', + required: false, + sensitive: false, + updatable: true, + type: FieldType.INTEGER, + }, + url: { + default_value: null, + description: '', + label: 'URL', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + }, + }, + { + service: 'azureaistudio', + name: 'Azure AI Studio', + task_types: ['text_embedding', 'completion'], + configurations: { + endpoint_type: { + default_value: null, + description: 'Specifies the type of endpoint that is used in your model deployment.', + label: 'Endpoint Type', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + provider: { + default_value: null, + description: 'The model provider for your deployment.', + label: 'Provider', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + api_key: { + default_value: null, + description: `API Key for the provider you're connecting to.`, + label: 'API Key', + required: true, + sensitive: true, + updatable: true, + type: FieldType.STRING, + }, + 'rate_limit.requests_per_minute': { + default_value: null, + description: 'Minimize the number of rate limit errors.', + label: 'Rate Limit', + required: false, + sensitive: false, + updatable: true, + type: FieldType.INTEGER, + }, + target: { + default_value: null, + description: 'The target URL of your Azure AI Studio model deployment.', + label: 'Target', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + }, + }, + { + service: 'hugging_face', + name: 'Hugging Face', + task_types: ['text_embedding', 'sparse_embedding'], + configurations: { + api_key: { + default_value: null, + description: `API Key for the provider you're connecting to.`, + label: 'API Key', + required: true, + sensitive: true, + updatable: true, + type: FieldType.STRING, + }, + 'rate_limit.requests_per_minute': { + default_value: null, + description: 'Minimize the number of rate limit errors.', + label: 'Rate Limit', + required: false, + sensitive: false, + updatable: true, + type: FieldType.INTEGER, + }, + url: { + default_value: 'https://api.openai.com/v1/embeddings', + description: 'The URL endpoint to use for the requests.', + label: 'URL', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + }, + }, + { + service: 'amazonbedrock', + name: 'Amazon Bedrock', + task_types: ['text_embedding', 'completion'], + configurations: { + secret_key: { + default_value: null, + description: 'A valid AWS secret key that is paired with the access_key.', + label: 'Secret Key', + required: true, + sensitive: true, + updatable: true, + type: FieldType.STRING, + }, + provider: { + default_value: null, + description: 'The model provider for your deployment.', + label: 'Provider', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + access_key: { + default_value: null, + description: 'A valid AWS access key that has permissions to use Amazon Bedrock.', + label: 'Access Key', + required: true, + sensitive: true, + updatable: true, + type: FieldType.STRING, + }, + model: { + default_value: null, + description: + 'The base model ID or an ARN to a custom model based on a foundational model.', + label: 'Model', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + 'rate_limit.requests_per_minute': { + default_value: null, + description: + 'By default, the amazonbedrock service sets the number of requests allowed per minute to 240.', + label: 'Rate Limit', + required: false, + sensitive: false, + updatable: true, + type: FieldType.INTEGER, + }, + region: { + default_value: null, + description: 'The region that your model or ARN is deployed in.', + label: 'Region', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + }, + }, + { + service: 'anthropic', + name: 'Anthropic', + task_types: ['completion'], + configurations: { + api_key: { + default_value: null, + description: `API Key for the provider you're connecting to.`, + label: 'API Key', + required: true, + sensitive: true, + updatable: true, + type: FieldType.STRING, + }, + 'rate_limit.requests_per_minute': { + default_value: null, + description: + 'By default, the anthropic service sets the number of requests allowed per minute to 50.', + label: 'Rate Limit', + required: false, + sensitive: false, + updatable: true, + type: FieldType.INTEGER, + }, + model_id: { + default_value: null, + description: 'The name of the model to use for the inference task.', + label: 'Model ID', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + }, + }, + { + service: 'googleaistudio', + name: 'Google AI Studio', + task_types: ['text_embedding', 'completion'], + configurations: { + api_key: { + default_value: null, + description: `API Key for the provider you're connecting to.`, + label: 'API Key', + required: true, + sensitive: true, + updatable: true, + type: FieldType.STRING, + }, + 'rate_limit.requests_per_minute': { + default_value: null, + description: 'Minimize the number of rate limit errors.', + label: 'Rate Limit', + required: false, + sensitive: false, + updatable: true, + type: FieldType.INTEGER, + }, + model_id: { + default_value: null, + description: "ID of the LLM you're using.", + label: 'Model ID', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + }, + }, + { + service: 'elasticsearch', + name: 'Elasticsearch', + task_types: ['text_embedding', 'sparse_embedding', 'rerank'], + configurations: { + num_allocations: { + default_value: 1, + description: + 'The total number of allocations this model is assigned across machine learning nodes.', + label: 'Number Allocations', + required: true, + sensitive: false, + updatable: true, + type: FieldType.INTEGER, + }, + num_threads: { + default_value: 2, + description: + 'Sets the number of threads used by each model allocation during inference.', + label: 'Number Threads', + required: true, + sensitive: false, + updatable: true, + type: FieldType.INTEGER, + }, + model_id: { + default_value: '.multilingual-e5-small', + description: 'The name of the model to use for the inference task.', + label: 'Model ID', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + }, + }, + { + service: 'openai', + name: 'OpenAI', + task_types: ['text_embedding', 'completion'], + configurations: { + api_key: { + default_value: null, + description: + 'The OpenAI API authentication key. For more details about generating OpenAI API keys, refer to the https://platform.openai.com/account/api-keys.', + label: 'API Key', + required: true, + sensitive: true, + updatable: true, + type: FieldType.STRING, + }, + organization_id: { + default_value: null, + description: 'The unique identifier of your organization.', + label: 'Organization ID', + required: false, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + 'rate_limit.requests_per_minute': { + default_value: null, + description: + 'Default number of requests allowed per minute. For text_embedding is 3000. For completion is 500.', + label: 'Rate Limit', + required: false, + sensitive: false, + updatable: true, + type: FieldType.INTEGER, + }, + model_id: { + default_value: null, + description: 'The name of the model to use for the inference task.', + label: 'Model ID', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + url: { + default_value: 'https://api.openai.com/v1/chat/completions', + description: + 'The OpenAI API endpoint URL. For more information on the URL, refer to the https://platform.openai.com/docs/api-reference.', + label: 'URL', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + }, + }, + { + service: 'azureopenai', + name: 'Azure OpenAI', + task_types: ['text_embedding', 'completion'], + configurations: { + api_key: { + default_value: null, + description: `API Key for the provider you're connecting to.`, + label: 'API Key', + required: true, + sensitive: true, + updatable: true, + type: FieldType.STRING, + }, + entra_id: { + default_value: null, + description: 'You must provide either an API key or an Entra ID.', + label: 'Entra ID', + required: false, + sensitive: true, + updatable: true, + type: FieldType.STRING, + }, + 'rate_limit.requests_per_minute': { + default_value: null, + description: + 'The azureopenai service sets a default number of requests allowed per minute depending on the task type.', + label: 'Rate Limit', + required: false, + sensitive: false, + updatable: true, + type: FieldType.INTEGER, + }, + deployment_id: { + default_value: null, + description: 'The deployment name of your deployed models.', + label: 'Deployment ID', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + resource_name: { + default_value: null, + description: 'The name of your Azure OpenAI resource.', + label: 'Resource Name', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + api_version: { + default_value: null, + description: 'The Azure API version ID to use.', + label: 'API Version', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + }, + }, + { + service: 'mistral', + name: 'Mistral', + task_types: ['text_embedding'], + configurations: { + api_key: { + default_value: null, + description: `API Key for the provider you're connecting to.`, + label: 'API Key', + required: true, + sensitive: true, + updatable: true, + type: FieldType.STRING, + }, + model: { + default_value: null, + description: + 'Refer to the Mistral models documentation for the list of available text embedding models.', + label: 'Model', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + 'rate_limit.requests_per_minute': { + default_value: null, + description: 'Minimize the number of rate limit errors.', + label: 'Rate Limit', + required: false, + sensitive: false, + updatable: true, + type: FieldType.INTEGER, + }, + max_input_tokens: { + default_value: null, + description: 'Allows you to specify the maximum number of tokens per input.', + label: 'Maximum Input Tokens', + required: false, + sensitive: false, + updatable: true, + type: FieldType.INTEGER, + }, + }, + }, + { + service: 'googlevertexai', + name: 'Google Vertex AI', + task_types: ['text_embedding', 'rerank'], + configurations: { + service_account_json: { + default_value: null, + description: "API Key for the provider you're connecting to.", + label: 'Credentials JSON', + required: true, + sensitive: true, + updatable: true, + type: FieldType.STRING, + }, + project_id: { + default_value: null, + description: + 'The GCP Project ID which has Vertex AI API(s) enabled. For more information on the URL, refer to the {geminiVertexAIDocs}.', + label: 'GCP Project', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + location: { + default_value: null, + description: + 'Please provide the GCP region where the Vertex AI API(s) is enabled. For more information, refer to the {geminiVertexAIDocs}.', + label: 'GCP Region', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + 'rate_limit.requests_per_minute': { + default_value: null, + description: 'Minimize the number of rate limit errors.', + label: 'Rate Limit', + required: false, + sensitive: false, + updatable: true, + type: FieldType.INTEGER, + }, + model_id: { + default_value: null, + description: `ID of the LLM you're using.`, + label: 'Model ID', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + }, + }, + { + service: 'alibabacloud-ai-search', + name: 'AlibabaCloud AI Search', + task_types: ['text_embedding', 'sparse_embedding', 'rerank', 'completion'], + configurations: { + workspace: { + default_value: null, + description: 'The name of the workspace used for the {infer} task.', + label: 'Workspace', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + api_key: { + default_value: null, + description: `A valid API key for the AlibabaCloud AI Search API.`, + label: 'API Key', + required: true, + sensitive: true, + updatable: true, + type: FieldType.STRING, + }, + service_id: { + default_value: null, + description: 'The name of the model service to use for the {infer} task.', + label: 'Project ID', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + host: { + default_value: null, + description: + 'The name of the host address used for the {infer} task. You can find the host address at https://opensearch.console.aliyun.com/cn-shanghai/rag/api-key[ the API keys section] of the documentation.', + label: 'Host', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + 'rate_limit.requests_per_minute': { + default_value: null, + description: 'Minimize the number of rate limit errors.', + label: 'Rate Limit', + required: false, + sensitive: false, + updatable: true, + type: FieldType.INTEGER, + }, + http_schema: { + default_value: null, + description: '', + label: 'HTTP Schema', + required: true, + sensitive: false, + updatable: true, + type: FieldType.STRING, + }, + }, + }, + ]; + // TODO: replace transformative map to the real type coming from the _inference/_service return res.ok({ body: response, });