From 47b19ba29c707eabf6c2bc12e21b714aae91ebed Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Mon, 6 Jan 2025 20:22:20 -0800 Subject: [PATCH] [AI Connector] Migrates AI inference Connector to use a shared components from '@kbn/inference-endpoint-ui-common' (#204885) 1. Migrated stack-connector `.inference` to use share UI components https://github.com/elastic/kibana/pull/203204 2. Extended package `@kbn/inference-endpoint-ui-common` to support edit mode for the form of the connector, by adding the optional property `isEdit` to `InferenceServiceFormFields` component 3. Resolves flaky timing out test https://github.com/elastic/kibana/issues/205129 --------- Co-authored-by: Samiul Monir Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../kbn-inference-endpoint-ui-common/index.ts | 1 + .../components/additional_options_fields.tsx | 21 +- .../inference_service_form_fields.test.tsx | 21 +- .../inference_service_form_fields.tsx | 49 +- .../src}/hooks/use_providers.ts | 12 +- .../src/translations.ts | 7 + .../tsconfig.json | 7 +- .../translations/translations/fr-FR.json | 13 - .../translations/translations/ja-JP.json | 13 - .../translations/translations/zh-CN.json | 13 - .../inference/additional_options_fields.tsx | 315 -------- .../inference/connector.test.tsx | 241 +++--- .../connector_types/inference/connector.tsx | 372 +-------- .../providers/assets/images/alibaba_cloud.svg | 3 - .../assets/images/amazon_bedrock.svg | 11 - .../providers/assets/images/anthropic.svg | 3 - .../assets/images/azure_ai_studio.svg | 44 -- .../providers/assets/images/azure_open_ai.svg | 9 - .../providers/assets/images/cohere.svg | 9 - .../providers/assets/images/elastic.svg | 16 - .../assets/images/google_ai_studio.svg | 6 - .../providers/assets/images/hugging_face.svg | 10 - .../providers/assets/images/ibm_watsonx.svg | 3 - .../providers/assets/images/mistral.svg | 34 - .../providers/assets/images/open_ai.svg | 3 - .../providers/get_providers.test.tsx | 52 -- .../inference/providers/get_providers.ts | 40 - .../service_provider.test.tsx | 42 -- .../service_provider.tsx | 124 --- .../providers/selectable/index.test.tsx | 60 -- .../inference/providers/selectable/index.tsx | 145 ---- .../connector_configuration_field.tsx | 237 ------ .../connector_configuration_form_items.tsx | 97 --- .../connector_configuration_utils.ts | 51 -- .../shared/stack_connectors/server/plugin.ts | 7 +- .../routes/get_inference_services.test.ts | 677 ----------------- .../server/routes/get_inference_services.ts | 703 ------------------ .../stack_connectors/server/routes/index.ts | 1 - .../shared/stack_connectors/tsconfig.json | 2 +- .../add_inference_flyout_wrapper.test.tsx | 2 +- .../inference_form.tsx | 13 +- .../public/hooks/translations.ts | 7 - .../search_inference_endpoints/tsconfig.json | 1 - 43 files changed, 222 insertions(+), 3275 deletions(-) rename x-pack/{solutions/search/plugins/search_inference_endpoints/public => platform/packages/shared/kbn-inference-endpoint-ui-common/src}/hooks/use_providers.ts (98%) delete mode 100644 x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/additional_options_fields.tsx delete mode 100644 x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/alibaba_cloud.svg delete mode 100644 x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/amazon_bedrock.svg delete mode 100644 x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/anthropic.svg delete mode 100644 x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/azure_ai_studio.svg delete mode 100644 x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/azure_open_ai.svg delete mode 100644 x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/cohere.svg delete mode 100644 x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/elastic.svg delete mode 100644 x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/google_ai_studio.svg delete mode 100644 x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/hugging_face.svg delete mode 100644 x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/ibm_watsonx.svg delete mode 100644 x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/mistral.svg delete mode 100644 x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/open_ai.svg delete mode 100644 x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/get_providers.test.tsx delete mode 100644 x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/get_providers.ts delete mode 100644 x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/render_service_provider/service_provider.test.tsx delete mode 100644 x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/render_service_provider/service_provider.tsx delete mode 100644 x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/selectable/index.test.tsx delete mode 100644 x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/selectable/index.tsx delete mode 100644 x-pack/platform/plugins/shared/stack_connectors/public/connector_types/lib/dynamic_config/connector_configuration_field.tsx delete mode 100644 x-pack/platform/plugins/shared/stack_connectors/public/connector_types/lib/dynamic_config/connector_configuration_form_items.tsx delete mode 100644 x-pack/platform/plugins/shared/stack_connectors/public/connector_types/lib/dynamic_config/connector_configuration_utils.ts delete mode 100644 x-pack/platform/plugins/shared/stack_connectors/server/routes/get_inference_services.test.ts delete mode 100644 x-pack/platform/plugins/shared/stack_connectors/server/routes/get_inference_services.ts diff --git a/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/index.ts b/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/index.ts index a2abc5514bd05..0192b9623755c 100644 --- a/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/index.ts +++ b/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/index.ts @@ -6,5 +6,6 @@ */ export { InferenceServiceFormFields } from './src/components/inference_service_form_fields'; +export { useProviders } from './src/hooks/use_providers'; export * from './src/types/types'; diff --git a/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/components/additional_options_fields.tsx b/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/components/additional_options_fields.tsx index 381b15b78020f..e7fa0afce90e0 100644 --- a/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/components/additional_options_fields.tsx +++ b/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/components/additional_options_fields.tsx @@ -52,6 +52,7 @@ interface AdditionalOptionsFieldsProps { onTaskTypeOptionsSelect: (taskType: string, provider?: string) => void; selectedTaskType?: string; taskTypeOptions: TaskTypeOption[]; + isEdit?: boolean; } export const AdditionalOptionsFields: React.FC = ({ @@ -61,6 +62,7 @@ export const AdditionalOptionsFields: React.FC = ( selectedTaskType, onSetProviderConfigEntry, onTaskTypeOptionsSelect, + isEdit, }) => { const xsFontSize = useEuiFontSize('xs').fontSize; const { euiTheme } = useEuiTheme(); @@ -106,7 +108,18 @@ export const AdditionalOptionsFields: React.FC = ( return ( - {taskTypeOptions.length === 1 ? ( + {isEdit ? ( + + {config.taskType} + + ) : taskTypeOptions.length === 1 ? ( = ( selectedTaskType, config.taskType, xsFontSize, - euiTheme.colors, + euiTheme.colors.textSubdued, + euiTheme.colors.disabled, + euiTheme.colors.lightestShade, + euiTheme.colors.darkShade, + isEdit, taskTypeOptions, onTaskTypeOptionsSelect, ] diff --git a/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/components/inference_service_form_fields.test.tsx b/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/components/inference_service_form_fields.test.tsx index c5d19aa26919e..5c20bbecb6f1c 100644 --- a/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/components/inference_service_form_fields.test.tsx +++ b/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/components/inference_service_form_fields.test.tsx @@ -12,8 +12,10 @@ import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { Form, useForm } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; import { I18nProvider } from '@kbn/i18n-react'; +import { httpServiceMock } from '@kbn/core-http-browser-mocks'; +import { notificationServiceMock } from '@kbn/core-notifications-browser-mocks'; -const providers = [ +const mockProviders = [ { service: 'hugging_face', name: 'Hugging Face', @@ -110,6 +112,15 @@ const providers = [ }, ] as InferenceProvider[]; +jest.mock('../hooks/use_providers', () => ({ + useProviders: jest.fn(() => ({ + data: mockProviders, + })), +})); + +const httpMock = httpServiceMock.createStartContract(); +const notificationsMock = notificationServiceMock.createStartContract(); + const MockFormProvider = ({ children }: { children: React.ReactElement }) => { const { form } = useForm(); @@ -124,7 +135,7 @@ describe('Inference Services', () => { it('renders', () => { render( - + ); @@ -134,7 +145,7 @@ describe('Inference Services', () => { it('renders Selectable', async () => { render( - + ); @@ -145,7 +156,7 @@ describe('Inference Services', () => { it('renders selected provider fields - hugging_face', async () => { render( - + ); @@ -165,7 +176,7 @@ describe('Inference Services', () => { it('re-renders fields when selected to anthropic from hugging_face', async () => { render( - + ); diff --git a/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/components/inference_service_form_fields.tsx b/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/components/inference_service_form_fields.tsx index 98e4dfdd6afbc..22eb4fbadc901 100644 --- a/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/components/inference_service_form_fields.tsx +++ b/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/components/inference_service_form_fields.tsx @@ -26,8 +26,9 @@ import { import { FormattedMessage } from '@kbn/i18n-react'; import { ConnectorFormSchema } from '@kbn/triggers-actions-ui-plugin/public'; +import { HttpSetup, IToasts } from '@kbn/core/public'; import * as LABELS from '../translations'; -import { Config, ConfigEntryView, FieldType, InferenceProvider, Secrets } from '../types/types'; +import { Config, ConfigEntryView, FieldType, Secrets } from '../types/types'; import { SERVICE_PROVIDERS } from './providers/render_service_provider/service_provider'; import { DEFAULT_TASK_TYPE, ServiceProviderKeys } from '../constants'; import { SelectableProvider } from './providers/selectable'; @@ -36,12 +37,20 @@ import { ConfigurationFormItems } from './configuration/configuration_form_items import { AdditionalOptionsFields } from './additional_options_fields'; import { ProviderSecretHiddenField } from './hidden_fields/provider_secret_hidden_field'; import { ProviderConfigHiddenField } from './hidden_fields/provider_config_hidden_field'; +import { useProviders } from '../hooks/use_providers'; interface InferenceServicesProps { - providers: InferenceProvider[]; + http: HttpSetup; + toasts: IToasts; + isEdit?: boolean; } -export const InferenceServiceFormFields: React.FC = ({ providers }) => { +export const InferenceServiceFormFields: React.FC = ({ + http, + toasts, + isEdit, +}) => { + const { data: providers, isLoading } = useProviders(http, toasts); const [isProviderPopoverOpen, setProviderPopoverOpen] = useState(false); const [providerSchema, setProviderSchema] = useState([]); const [taskTypeOptions, setTaskTypeOptions] = useState([]); @@ -213,8 +222,9 @@ export const InferenceServiceFormFields: React.FC = ({ p const providerSuperSelect = useCallback( (isInvalid: boolean) => ( = ({ p onClick={toggleProviderPopover} data-test-subj="provider-select" isInvalid={isInvalid} + disabled={isEdit} onKeyDown={handleProviderKeyboardOpen} value={config?.provider ? providerName : ''} fullWidth @@ -239,16 +250,31 @@ export const InferenceServiceFormFields: React.FC = ({ p ), [ - config?.provider, - handleProviderKeyboardOpen, - toggleProviderPopover, - isProviderPopoverOpen, + isEdit, onClearProvider, + config?.provider, providerIcon, + toggleProviderPopover, + handleProviderKeyboardOpen, providerName, + isProviderPopoverOpen, ] ); + useEffect(() => { + if (config?.provider && isEdit) { + const newProvider = providers?.find((p) => p.service === config.provider); + // Update connector providerSchema + const newProviderSchema = Object.keys(newProvider?.configurations ?? {}).map((k) => ({ + key: k, + isValid: true, + ...newProvider?.configurations[k], + })) as ConfigEntryView[]; + + setProviderSchema(newProviderSchema); + } + }, [config?.provider, config?.taskType, isEdit, providers]); + useEffect(() => { if (isSubmitting) { validateFields(['config.providerConfig']); @@ -291,7 +317,7 @@ export const InferenceServiceFormFields: React.FC = ({ p setRequiredProviderFormFields(existingConfiguration.filter((p) => p.required || p.sensitive)); }, [config?.providerConfig, providerSchema, secrets]); - return ( + return !isLoading ? ( <> = ({ p className="rightArrowIcon" > @@ -355,6 +381,7 @@ export const InferenceServiceFormFields: React.FC = ({ p onTaskTypeOptionsSelect={onTaskTypeOptionsSelect} taskTypeOptions={taskTypeOptions} selectedTaskType={selectedTaskType} + isEdit={isEdit} /> @@ -371,5 +398,5 @@ export const InferenceServiceFormFields: React.FC = ({ p ) : null} - ); + ) : null; }; diff --git a/x-pack/solutions/search/plugins/search_inference_endpoints/public/hooks/use_providers.ts b/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/hooks/use_providers.ts similarity index 98% rename from x-pack/solutions/search/plugins/search_inference_endpoints/public/hooks/use_providers.ts rename to x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/hooks/use_providers.ts index 4bef4268c798f..260d61a2aade8 100644 --- a/x-pack/solutions/search/plugins/search_inference_endpoints/public/hooks/use_providers.ts +++ b/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/hooks/use_providers.ts @@ -7,10 +7,10 @@ import type { HttpSetup } from '@kbn/core-http-browser'; import { useQuery } from '@tanstack/react-query'; -import { FieldType, InferenceProvider } from '@kbn/inference-endpoint-ui-common'; import { KibanaServerError } from '@kbn/kibana-utils-plugin/common'; -import { useKibana } from './use_kibana'; -import * as i18n from './translations'; +import { IToasts } from '@kbn/core/public'; +import { FieldType, InferenceProvider } from '../..'; +import * as i18n from '../translations'; const getProviders = (http: HttpSetup): InferenceProvider[] => { return [ @@ -624,9 +624,7 @@ const getProviders = (http: HttpSetup): InferenceProvider[] => { ]; }; -export const useProviders = () => { - const { services } = useKibana(); - const toasts = services.notifications?.toasts; +export const useProviders = (http: HttpSetup, toasts: IToasts) => { const onErrorFn = (error: { body: KibanaServerError }) => { toasts?.addError(new Error(error.body.message), { title: i18n.GET_PROVIDERS_FAILED, @@ -635,7 +633,7 @@ export const useProviders = () => { }; const query = useQuery(['user-profile'], { - queryFn: () => getProviders(services.http), + queryFn: () => getProviders(http), staleTime: Infinity, refetchOnWindowFocus: false, onError: onErrorFn, diff --git a/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/translations.ts b/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/translations.ts index 6258fc94687fe..3c9bab9ecb6fe 100644 --- a/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/translations.ts +++ b/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/translations.ts @@ -127,3 +127,10 @@ export const RE_ENTER_SECRETS = (label: string) => { values: { label }, }); }; + +export const GET_PROVIDERS_FAILED = i18n.translate( + 'xpack.inferenceEndpointUICommon.hooks.unableToFindProvidersQueryMessage', + { + defaultMessage: 'Unable to find providers', + } +); diff --git a/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/tsconfig.json b/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/tsconfig.json index f306c4703b7a0..5c60ee4820e4a 100644 --- a/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/tsconfig.json +++ b/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/tsconfig.json @@ -21,6 +21,11 @@ "@kbn/i18n-react", "@kbn/search-connectors", "@kbn/es-ui-shared-plugin", - "@kbn/triggers-actions-ui-plugin" + "@kbn/triggers-actions-ui-plugin", + "@kbn/core-http-browser", + "@kbn/kibana-utils-plugin", + "@kbn/core", + "@kbn/core-http-browser-mocks", + "@kbn/core-notifications-browser-mocks" ] } 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 0274f9260b917..5c0f839ea211f 100644 --- a/x-pack/platform/plugins/private/translations/translations/fr-FR.json +++ b/x-pack/platform/plugins/private/translations/translations/fr-FR.json @@ -44983,35 +44983,22 @@ "xpack.stackConnectors.components.index.preconfiguredIndexHelpText": "Les documents sont indexés dans l'index {alertHistoryIndex}.", "xpack.stackConnectors.components.index.resetDefaultIndexLabel": "Réinitialiser l'index par défaut", "xpack.stackConnectors.components.index.selectMessageText": "Indexez les données dans Elasticsearch.", - "xpack.stackConnectors.components.inference.additionalOptionsLabel": "Options supplémentaires", "xpack.stackConnectors.components.inference.bodyCodeEditorAriaLabel": "Éditeur de code", "xpack.stackConnectors.components.inference.bodyFieldLabel": "Corps", "xpack.stackConnectors.components.inference.completionInputLabel": "Entrée", "xpack.stackConnectors.components.inference.completionInputTypeLabel": "Type d'entrée", - "xpack.stackConnectors.components.inference.config.optionalValue": "Facultatif", "xpack.stackConnectors.components.inference.connectorTypeTitle": "Connecteur IA", "xpack.stackConnectors.components.inference.copied.tooltip": "Copié !", "xpack.stackConnectors.components.inference.copy.tooltip": "Copier dans le presse-papiers", - "xpack.stackConnectors.components.inference.copyLabel": "Copier", "xpack.stackConnectors.components.inference.documentation": "Documentation de l'API d'inférence", "xpack.stackConnectors.components.inference.error.requiredProviderText": "Le fournisseur est requis.", - "xpack.stackConnectors.components.inference.inferenceEndpointHelpLabel": "Les points de terminaison d'inférence fournissent une méthode simplifiée pour utiliser cette configuration, en particulier à partir de l'API", - "xpack.stackConnectors.components.inference.inferenceEndpointLabel": "Point de terminaison d'inférence", - "xpack.stackConnectors.components.inference.inferenceIdHelpLabel": "Cet identifiant ne peut pas être modifié une fois créé.", "xpack.stackConnectors.components.inference.invalidActionText": "Nom d'action non valide.", "xpack.stackConnectors.components.inference.providerFieldLabel": "Fournisseur", - "xpack.stackConnectors.components.inference.providerLabel": "Service", - "xpack.stackConnectors.components.inference.providerOptionalSettingsHelpLabel": "Configurer le fournisseur d'inférence. Ces paramètres sont des paramètres de fournisseur facultatifs.", - "xpack.stackConnectors.components.inference.providerOptionalSettingsLabel": "Paramètres de service", "xpack.stackConnectors.components.inference.requiredGenericTextField": "{field} est obligatoire.", "xpack.stackConnectors.components.inference.rerankQueryLabel": "Recherche", - "xpack.stackConnectors.components.inference.selectable.providerSearch": "Recherche", "xpack.stackConnectors.components.inference.selectMessageText": "Envoyez des demandes aux fournisseurs d'IA tels qu'Amazon Bedrock, OpenAI et bien d'autres.", "xpack.stackConnectors.components.inference.selectProvider": "Sélectionner un service", - "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.unableToFindProvidersQueryMessage": "Impossible de trouver des fournisseurs", "xpack.stackConnectors.components.jira.apiTokenTextFieldLabel": "Token d'API", "xpack.stackConnectors.components.jira.apiUrlTextFieldLabel": "URL", "xpack.stackConnectors.components.jira.commentsTextAreaFieldLabel": "Commentaires supplémentaires", 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 19513093d5517..156eea59ff524 100644 --- a/x-pack/platform/plugins/private/translations/translations/ja-JP.json +++ b/x-pack/platform/plugins/private/translations/translations/ja-JP.json @@ -44833,35 +44833,22 @@ "xpack.stackConnectors.components.index.preconfiguredIndexHelpText": "ドキュメントは{alertHistoryIndex}インデックスにインデックスされます。", "xpack.stackConnectors.components.index.resetDefaultIndexLabel": "デフォルトのインデックスをリセット", "xpack.stackConnectors.components.index.selectMessageText": "データを Elasticsearch にインデックスしてください。", - "xpack.stackConnectors.components.inference.additionalOptionsLabel": "その他のオプション", "xpack.stackConnectors.components.inference.bodyCodeEditorAriaLabel": "コードエディター", "xpack.stackConnectors.components.inference.bodyFieldLabel": "本文", "xpack.stackConnectors.components.inference.completionInputLabel": "インプット", "xpack.stackConnectors.components.inference.completionInputTypeLabel": "入力タイプ", - "xpack.stackConnectors.components.inference.config.optionalValue": "オプション", "xpack.stackConnectors.components.inference.connectorTypeTitle": "AIコネクター", "xpack.stackConnectors.components.inference.copied.tooltip": "コピー完了", "xpack.stackConnectors.components.inference.copy.tooltip": "クリップボードにコピー", - "xpack.stackConnectors.components.inference.copyLabel": "コピー", "xpack.stackConnectors.components.inference.documentation": "推論APIドキュメント", "xpack.stackConnectors.components.inference.error.requiredProviderText": "プロバイダーは必須です。", - "xpack.stackConnectors.components.inference.inferenceEndpointHelpLabel": "推論エンドポイントは、特にAPIから、この構成を簡単に利用できる方法を提供します。", - "xpack.stackConnectors.components.inference.inferenceEndpointLabel": "推論エンドポイント", - "xpack.stackConnectors.components.inference.inferenceIdHelpLabel": "このIDは、作成すると、変更できません。", "xpack.stackConnectors.components.inference.invalidActionText": "無効なアクション名です。", "xpack.stackConnectors.components.inference.providerFieldLabel": "プロバイダー", - "xpack.stackConnectors.components.inference.providerLabel": "サービス", - "xpack.stackConnectors.components.inference.providerOptionalSettingsHelpLabel": "推論プロバイダーを構成します。これらの設定はオプションのプロバイダー設定です。", - "xpack.stackConnectors.components.inference.providerOptionalSettingsLabel": "サービス設定", "xpack.stackConnectors.components.inference.requiredGenericTextField": "{field}は必須です。", "xpack.stackConnectors.components.inference.rerankQueryLabel": "クエリー", - "xpack.stackConnectors.components.inference.selectable.providerSearch": "検索", "xpack.stackConnectors.components.inference.selectMessageText": "Amazon Bedrock、OpenAIなどのAIプロバイダーに要求を送信します。", "xpack.stackConnectors.components.inference.selectProvider": "サービスを選択", - "xpack.stackConnectors.components.inference.taskTypeDetailsLabel": "タスク設定", "xpack.stackConnectors.components.inference.taskTypeFieldLabel": "タスクタイプ", - "xpack.stackConnectors.components.inference.taskTypeHelpLabel": "推論タスクを構成します。これらの設定は、選択したサービスおよびモデルに固有です。", - "xpack.stackConnectors.components.inference.unableToFindProvidersQueryMessage": "プロバイダーが見つかりません", "xpack.stackConnectors.components.jira.apiTokenTextFieldLabel": "APIトークン", "xpack.stackConnectors.components.jira.apiUrlTextFieldLabel": "URL", "xpack.stackConnectors.components.jira.commentsTextAreaFieldLabel": "追加のコメント", 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 41bb4953fc45b..7f71645070f54 100644 --- a/x-pack/platform/plugins/private/translations/translations/zh-CN.json +++ b/x-pack/platform/plugins/private/translations/translations/zh-CN.json @@ -44170,35 +44170,22 @@ "xpack.stackConnectors.components.index.preconfiguredIndexHelpText": "文档已索引到 {alertHistoryIndex} 索引中。", "xpack.stackConnectors.components.index.resetDefaultIndexLabel": "重置默认索引", "xpack.stackConnectors.components.index.selectMessageText": "将数据索引到 Elasticsearch 中。", - "xpack.stackConnectors.components.inference.additionalOptionsLabel": "其他选项", "xpack.stackConnectors.components.inference.bodyCodeEditorAriaLabel": "代码编辑器", "xpack.stackConnectors.components.inference.bodyFieldLabel": "正文", "xpack.stackConnectors.components.inference.completionInputLabel": "输入", "xpack.stackConnectors.components.inference.completionInputTypeLabel": "输入类型", - "xpack.stackConnectors.components.inference.config.optionalValue": "可选", "xpack.stackConnectors.components.inference.connectorTypeTitle": "AI 连接器", "xpack.stackConnectors.components.inference.copied.tooltip": "已复制!", "xpack.stackConnectors.components.inference.copy.tooltip": "复制到剪贴板", - "xpack.stackConnectors.components.inference.copyLabel": "复制", "xpack.stackConnectors.components.inference.documentation": "推理 API 文档", "xpack.stackConnectors.components.inference.error.requiredProviderText": "'提供商'必填。", - "xpack.stackConnectors.components.inference.inferenceEndpointHelpLabel": "推理终端提供了使用此配置(特别是通过 API 使用)的简化方法", - "xpack.stackConnectors.components.inference.inferenceEndpointLabel": "推理终端", - "xpack.stackConnectors.components.inference.inferenceIdHelpLabel": "此 ID 一旦创建,将无法更改。", "xpack.stackConnectors.components.inference.invalidActionText": "操作名称无效。", "xpack.stackConnectors.components.inference.providerFieldLabel": "提供商", - "xpack.stackConnectors.components.inference.providerLabel": "服务", - "xpack.stackConnectors.components.inference.providerOptionalSettingsHelpLabel": "配置推理提供商。这些设置是可选的提供商设置。", - "xpack.stackConnectors.components.inference.providerOptionalSettingsLabel": "服务设置", "xpack.stackConnectors.components.inference.requiredGenericTextField": "{field} 必填。", "xpack.stackConnectors.components.inference.rerankQueryLabel": "查询", - "xpack.stackConnectors.components.inference.selectable.providerSearch": "搜索", "xpack.stackConnectors.components.inference.selectMessageText": "发送请求至 Amazon Bedrock、OpenAI 等 AI 提供商。", "xpack.stackConnectors.components.inference.selectProvider": "选择服务", - "xpack.stackConnectors.components.inference.taskTypeDetailsLabel": "任务设置", "xpack.stackConnectors.components.inference.taskTypeFieldLabel": "任务类型", - "xpack.stackConnectors.components.inference.taskTypeHelpLabel": "配置推理任务。这些设置特定于选定服务和模型。", - "xpack.stackConnectors.components.inference.unableToFindProvidersQueryMessage": "找不到提供商", "xpack.stackConnectors.components.jira.apiTokenTextFieldLabel": "API 令牌", "xpack.stackConnectors.components.jira.apiUrlTextFieldLabel": "URL", "xpack.stackConnectors.components.jira.commentsTextAreaFieldLabel": "其他注释", diff --git a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/additional_options_fields.tsx b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/additional_options_fields.tsx deleted file mode 100644 index 5862389e6ab80..0000000000000 --- a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/additional_options_fields.tsx +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useMemo } from 'react'; -import { css } from '@emotion/react'; - -import { - EuiFormRow, - EuiSpacer, - EuiTitle, - EuiAccordion, - EuiFieldText, - useEuiTheme, - EuiTextColor, - EuiButtonGroup, - EuiPanel, - EuiButtonEmpty, - EuiCopy, - EuiButton, - useEuiFontSize, -} from '@elastic/eui'; -import { - getFieldValidityAndErrorMessage, - UseField, - useFormContext, -} from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; -import { FormattedMessage } from '@kbn/i18n-react'; - -import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers'; -import { ConfigEntryView } from '../../../common/dynamic_config/types'; -import { ConnectorConfigurationFormItems } from '../lib/dynamic_config/connector_configuration_form_items'; -import * as i18n from './translations'; -import { DEFAULT_TASK_TYPE } from './constants'; -import { Config } from './types'; -import { TaskTypeOption } from './helpers'; - -// Custom trigger button CSS -const buttonCss = css` - &:hover { - text-decoration: none; - } -`; - -interface AdditionalOptionsConnectorFieldsProps { - config: Config; - readOnly: boolean; - isEdit: boolean; - optionalProviderFormFields: ConfigEntryView[]; - onSetProviderConfigEntry: (key: string, value: unknown) => Promise; - onTaskTypeOptionsSelect: (taskType: string, provider?: string) => void; - selectedTaskType?: string; - taskTypeFormFields: ConfigEntryView[]; - taskTypeOptions: TaskTypeOption[]; -} - -export const AdditionalOptionsConnectorFields: React.FC = ({ - config, - readOnly, - isEdit, - taskTypeOptions, - optionalProviderFormFields, - selectedTaskType, - onSetProviderConfigEntry, - onTaskTypeOptionsSelect, -}) => { - const xsFontSize = useEuiFontSize('xs').fontSize; - const { euiTheme } = useEuiTheme(); - const { setFieldValue } = useFormContext(); - - const taskTypeSettings = useMemo( - () => - selectedTaskType || config.taskType?.length ? ( - <> - -

- -

-
- -
- -
- - - {(field) => { - const { isInvalid, errorMessage } = getFieldValidityAndErrorMessage(field); - - return ( - - {isEdit || readOnly ? ( - - {config.taskType} - - ) : taskTypeOptions.length === 1 ? ( - onTaskTypeOptionsSelect(config.taskType)} - > - {config.taskType} - - ) : ( - onTaskTypeOptionsSelect(id)} - options={taskTypeOptions} - color="text" - type="single" - /> - )} - - ); - }} - - - ) : null, - [ - selectedTaskType, - config.taskType, - xsFontSize, - euiTheme.colors, - isEdit, - readOnly, - taskTypeOptions, - onTaskTypeOptionsSelect, - ] - ); - - const inferenceUri = useMemo(() => `_inference/${selectedTaskType}/`, [selectedTaskType]); - - return ( - - - - } - initialIsOpen={true} - > - - - {optionalProviderFormFields.length > 0 ? ( - <> - -

- -

-
- -
- -
- - - - - ) : null} - - {taskTypeSettings} - - -

- -

-
- -
- -
- - - - {(field) => { - const { isInvalid, errorMessage } = getFieldValidityAndErrorMessage(field); - - return ( - - } - > - { - setFieldValue('config.inferenceId', e.target.value); - }} - prepend={inferenceUri} - append={ - - {(copy) => ( - - - - )} - - } - /> - - ); - }} - -
-
- ); -}; - -// eslint-disable-next-line import/no-default-export -export { AdditionalOptionsConnectorFields as default }; diff --git a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/connector.test.tsx b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/connector.test.tsx index 5d20ff9595483..88889967d1dbf 100644 --- a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/connector.test.tsx +++ b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/connector.test.tsx @@ -9,37 +9,9 @@ import React from 'react'; import ConnectorFields from './connector'; import { ConnectorFormTestProvider } from '../lib/test_utils'; -import { render, waitFor } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { createStartServicesMock } from '@kbn/triggers-actions-ui-plugin/public/common/lib/kibana/kibana_react.mock'; -import { useProviders } from './providers/get_providers'; -import { FieldType } from '../../../common/dynamic_config/types'; - -jest.mock('./providers/get_providers'); - -const mockUseKibanaReturnValue = createStartServicesMock(); -jest.mock('@kbn/triggers-actions-ui-plugin/public/common/lib/kibana', () => ({ - __esModule: true, - useKibana: jest.fn(() => ({ - services: mockUseKibanaReturnValue, - })), -})); - -jest.mock('@faker-js/faker', () => { - const originalModule = jest.requireActual('@faker-js/faker'); - return { - ...originalModule, - faker: { - ...originalModule.faker, - string: { - ...originalModule.faker.string, - alpha: jest.fn().mockReturnValue('123'), - }, - }, - }; -}); - -const mockProviders = useProviders as jest.Mock; const providersSchemas = [ { @@ -54,7 +26,7 @@ const providersSchemas = [ required: true, sensitive: true, updatable: true, - type: FieldType.STRING, + type: 'string', }, 'rate_limit.requests_per_minute': { default_value: null, @@ -63,7 +35,7 @@ const providersSchemas = [ required: false, sensitive: false, updatable: true, - type: FieldType.INTEGER, + type: 'int', }, }, }, @@ -79,7 +51,7 @@ const providersSchemas = [ required: false, sensitive: false, updatable: true, - type: FieldType.INTEGER, + type: 'int', }, model_id: { default_value: null, @@ -88,7 +60,7 @@ const providersSchemas = [ required: true, sensitive: false, updatable: true, - type: FieldType.STRING, + type: 'string', }, max_input_tokens: { default_value: null, @@ -97,7 +69,7 @@ const providersSchemas = [ required: false, sensitive: false, updatable: true, - type: FieldType.INTEGER, + type: 'int', }, }, }, @@ -113,7 +85,7 @@ const providersSchemas = [ required: true, sensitive: false, updatable: true, - type: FieldType.STRING, + type: 'string', }, model_id: { default_value: null, @@ -122,7 +94,7 @@ const providersSchemas = [ required: true, sensitive: false, updatable: true, - type: FieldType.STRING, + type: 'string', }, api_version: { default_value: null, @@ -131,7 +103,7 @@ const providersSchemas = [ required: true, sensitive: false, updatable: true, - type: FieldType.STRING, + type: 'string', }, max_input_tokens: { default_value: null, @@ -140,7 +112,7 @@ const providersSchemas = [ required: false, sensitive: false, updatable: true, - type: FieldType.INTEGER, + type: 'int', }, url: { default_value: null, @@ -149,7 +121,7 @@ const providersSchemas = [ required: true, sensitive: false, updatable: true, - type: FieldType.STRING, + type: 'string', }, }, }, @@ -165,7 +137,7 @@ const providersSchemas = [ required: true, sensitive: false, updatable: true, - type: FieldType.STRING, + type: 'string', }, provider: { default_value: null, @@ -174,7 +146,7 @@ const providersSchemas = [ required: true, sensitive: false, updatable: true, - type: FieldType.STRING, + type: 'string', }, api_key: { default_value: null, @@ -183,7 +155,7 @@ const providersSchemas = [ required: true, sensitive: true, updatable: true, - type: FieldType.STRING, + type: 'string', }, 'rate_limit.requests_per_minute': { default_value: null, @@ -192,7 +164,7 @@ const providersSchemas = [ required: false, sensitive: false, updatable: true, - type: FieldType.INTEGER, + type: 'int', }, target: { default_value: null, @@ -201,7 +173,7 @@ const providersSchemas = [ required: true, sensitive: false, updatable: true, - type: FieldType.STRING, + type: 'string', }, }, }, @@ -217,7 +189,7 @@ const providersSchemas = [ required: true, sensitive: true, updatable: true, - type: FieldType.STRING, + type: 'string', }, 'rate_limit.requests_per_minute': { default_value: null, @@ -226,7 +198,7 @@ const providersSchemas = [ required: false, sensitive: false, updatable: true, - type: FieldType.INTEGER, + type: 'int', }, url: { default_value: 'https://api.openai.com/v1/embeddings', @@ -235,7 +207,7 @@ const providersSchemas = [ required: true, sensitive: false, updatable: true, - type: FieldType.STRING, + type: 'string', }, }, }, @@ -251,7 +223,7 @@ const providersSchemas = [ required: true, sensitive: true, updatable: true, - type: FieldType.STRING, + type: 'string', }, provider: { default_value: null, @@ -260,7 +232,7 @@ const providersSchemas = [ required: true, sensitive: false, updatable: true, - type: FieldType.STRING, + type: 'string', }, access_key: { default_value: null, @@ -269,7 +241,7 @@ const providersSchemas = [ required: true, sensitive: true, updatable: true, - type: FieldType.STRING, + type: 'string', }, model: { default_value: null, @@ -278,7 +250,7 @@ const providersSchemas = [ required: true, sensitive: false, updatable: true, - type: FieldType.STRING, + type: 'string', }, 'rate_limit.requests_per_minute': { default_value: null, @@ -288,7 +260,7 @@ const providersSchemas = [ required: false, sensitive: false, updatable: true, - type: FieldType.INTEGER, + type: 'int', }, region: { default_value: null, @@ -297,7 +269,7 @@ const providersSchemas = [ required: true, sensitive: false, updatable: true, - type: FieldType.STRING, + type: 'string', }, }, }, @@ -313,7 +285,7 @@ const providersSchemas = [ required: true, sensitive: true, updatable: true, - type: FieldType.STRING, + type: 'string', }, 'rate_limit.requests_per_minute': { default_value: null, @@ -323,7 +295,7 @@ const providersSchemas = [ required: false, sensitive: false, updatable: true, - type: FieldType.INTEGER, + type: 'int', }, model_id: { default_value: null, @@ -332,7 +304,7 @@ const providersSchemas = [ required: true, sensitive: false, updatable: true, - type: FieldType.STRING, + type: 'string', }, }, }, @@ -348,7 +320,7 @@ const providersSchemas = [ required: true, sensitive: true, updatable: true, - type: FieldType.STRING, + type: 'string', }, 'rate_limit.requests_per_minute': { default_value: null, @@ -357,7 +329,7 @@ const providersSchemas = [ required: false, sensitive: false, updatable: true, - type: FieldType.INTEGER, + type: 'int', }, model_id: { default_value: null, @@ -366,7 +338,7 @@ const providersSchemas = [ required: true, sensitive: false, updatable: true, - type: FieldType.STRING, + type: 'string', }, }, }, @@ -383,7 +355,7 @@ const providersSchemas = [ required: true, sensitive: false, updatable: true, - type: FieldType.INTEGER, + type: 'int', }, num_threads: { default_value: 2, @@ -392,7 +364,7 @@ const providersSchemas = [ required: true, sensitive: false, updatable: true, - type: FieldType.INTEGER, + type: 'int', }, model_id: { default_value: '.multilingual-e5-small', @@ -401,7 +373,7 @@ const providersSchemas = [ required: true, sensitive: false, updatable: true, - type: FieldType.STRING, + type: 'string', }, }, }, @@ -418,7 +390,7 @@ const providersSchemas = [ required: true, sensitive: true, updatable: true, - type: FieldType.STRING, + type: 'string', }, organization_id: { default_value: null, @@ -427,7 +399,7 @@ const providersSchemas = [ required: false, sensitive: false, updatable: true, - type: FieldType.STRING, + type: 'string', }, 'rate_limit.requests_per_minute': { default_value: null, @@ -437,7 +409,7 @@ const providersSchemas = [ required: false, sensitive: false, updatable: true, - type: FieldType.INTEGER, + type: 'int', }, model_id: { default_value: null, @@ -446,7 +418,7 @@ const providersSchemas = [ required: true, sensitive: false, updatable: true, - type: FieldType.STRING, + type: 'string', }, url: { default_value: 'https://api.openai.com/v1/chat/completions', @@ -456,7 +428,7 @@ const providersSchemas = [ required: true, sensitive: false, updatable: true, - type: FieldType.STRING, + type: 'string', }, }, }, @@ -472,7 +444,7 @@ const providersSchemas = [ required: true, sensitive: true, updatable: true, - type: FieldType.STRING, + type: 'string', }, entra_id: { default_value: null, @@ -481,7 +453,7 @@ const providersSchemas = [ required: false, sensitive: true, updatable: true, - type: FieldType.STRING, + type: 'string', }, 'rate_limit.requests_per_minute': { default_value: null, @@ -491,7 +463,7 @@ const providersSchemas = [ required: false, sensitive: false, updatable: true, - type: FieldType.INTEGER, + type: 'int', }, deployment_id: { default_value: null, @@ -500,7 +472,7 @@ const providersSchemas = [ required: true, sensitive: false, updatable: true, - type: FieldType.STRING, + type: 'string', }, resource_name: { default_value: null, @@ -509,7 +481,7 @@ const providersSchemas = [ required: true, sensitive: false, updatable: true, - type: FieldType.STRING, + type: 'string', }, api_version: { default_value: null, @@ -518,7 +490,7 @@ const providersSchemas = [ required: true, sensitive: false, updatable: true, - type: FieldType.STRING, + type: 'string', }, }, }, @@ -534,7 +506,7 @@ const providersSchemas = [ required: true, sensitive: true, updatable: true, - type: FieldType.STRING, + type: 'string', }, model: { default_value: null, @@ -544,7 +516,7 @@ const providersSchemas = [ required: true, sensitive: false, updatable: true, - type: FieldType.STRING, + type: 'string', }, 'rate_limit.requests_per_minute': { default_value: null, @@ -553,7 +525,7 @@ const providersSchemas = [ required: false, sensitive: false, updatable: true, - type: FieldType.INTEGER, + type: 'int', }, max_input_tokens: { default_value: null, @@ -562,7 +534,7 @@ const providersSchemas = [ required: false, sensitive: false, updatable: true, - type: FieldType.INTEGER, + type: 'int', }, }, }, @@ -578,7 +550,7 @@ const providersSchemas = [ required: true, sensitive: true, updatable: true, - type: FieldType.STRING, + type: 'string', }, project_id: { default_value: null, @@ -588,7 +560,7 @@ const providersSchemas = [ required: true, sensitive: false, updatable: true, - type: FieldType.STRING, + type: 'string', }, location: { default_value: null, @@ -598,7 +570,7 @@ const providersSchemas = [ required: true, sensitive: false, updatable: true, - type: FieldType.STRING, + type: 'string', }, 'rate_limit.requests_per_minute': { default_value: null, @@ -607,7 +579,7 @@ const providersSchemas = [ required: false, sensitive: false, updatable: true, - type: FieldType.INTEGER, + type: 'int', }, model_id: { default_value: null, @@ -616,7 +588,7 @@ const providersSchemas = [ required: true, sensitive: false, updatable: true, - type: FieldType.STRING, + type: 'string', }, }, }, @@ -632,7 +604,7 @@ const providersSchemas = [ required: true, sensitive: false, updatable: true, - type: FieldType.STRING, + type: 'string', }, api_key: { default_value: null, @@ -641,7 +613,7 @@ const providersSchemas = [ required: true, sensitive: true, updatable: true, - type: FieldType.STRING, + type: 'string', }, service_id: { default_value: null, @@ -650,7 +622,7 @@ const providersSchemas = [ required: true, sensitive: false, updatable: true, - type: FieldType.STRING, + type: 'string', }, host: { default_value: null, @@ -660,7 +632,7 @@ const providersSchemas = [ required: true, sensitive: false, updatable: true, - type: FieldType.STRING, + type: 'string', }, 'rate_limit.requests_per_minute': { default_value: null, @@ -669,7 +641,7 @@ const providersSchemas = [ required: false, sensitive: false, updatable: true, - type: FieldType.INTEGER, + type: 'int', }, http_schema: { default_value: null, @@ -678,12 +650,40 @@ const providersSchemas = [ required: true, sensitive: false, updatable: true, - type: FieldType.STRING, + type: 'string', }, }, }, ]; +const mockUseKibanaReturnValue = createStartServicesMock(); +jest.mock('@kbn/triggers-actions-ui-plugin/public/common/lib/kibana', () => ({ + __esModule: true, + useKibana: jest.fn(() => ({ + services: mockUseKibanaReturnValue, + })), +})); + +jest.mock('@faker-js/faker', () => { + const originalModule = jest.requireActual('@faker-js/faker'); + return { + ...originalModule, + faker: { + ...originalModule.faker, + string: { + ...originalModule.faker.string, + alpha: jest.fn().mockReturnValue('123'), + }, + }, + }; +}); + +jest.mock('@kbn/inference-endpoint-ui-common/src/hooks/use_providers', () => ({ + useProviders: jest.fn(() => ({ + data: providersSchemas, + })), +})); + const openAiConnector = { actionTypeId: '.inference', name: 'AI Connector', @@ -724,14 +724,7 @@ const googleaistudioConnector = { }; describe('ConnectorFields renders', () => { - beforeEach(() => { - jest.clearAllMocks(); - mockProviders.mockReturnValue({ - isLoading: false, - data: providersSchemas, - }); - }); - test('openai provider fields are rendered', async () => { + test('openai provider fields are rendered', () => { const { getAllByTestId } = render( {}} /> @@ -746,7 +739,7 @@ describe('ConnectorFields renders', () => { expect(getAllByTestId('taskTypeSelectDisabled')[0]).toHaveTextContent('completion'); }); - test('googleaistudio provider fields are rendered', async () => { + test('googleaistudio provider fields are rendered', () => { const { getAllByTestId } = render( {}} /> @@ -771,32 +764,37 @@ describe('ConnectorFields renders', () => { }); it('connector validation succeeds when connector config is valid', async () => { - const { getByTestId } = render( + render( - {}} /> + {}} /> ); - await userEvent.click(getByTestId('form-test-provide-submit')); - - await waitFor(async () => { - expect(onSubmit).toHaveBeenCalled(); - }); + await userEvent.type( + screen.getByTestId('api_key-password'), + '{selectall}{backspace}goodpassword' + ); + await userEvent.click(screen.getByTestId('form-test-provide-submit')); + expect(onSubmit).toHaveBeenCalled(); expect(onSubmit).toBeCalledWith({ data: { config: { - inferenceId: 'openai-completion-4fzzzxjylrx', ...openAiConnector.config, }, actionTypeId: openAiConnector.actionTypeId, name: openAiConnector.name, id: openAiConnector.id, isDeprecated: openAiConnector.isDeprecated, + secrets: { + providerSecrets: { + api_key: 'goodpassword', + }, + }, }, isValid: true, }); - }); + }, 60000); it('validates correctly if the provider config url is empty', async () => { const connector = { @@ -810,29 +808,23 @@ describe('ConnectorFields renders', () => { }, }; - const res = render( + render( {}} /> ); await userEvent.type( - res.getByTestId('api_key-password'), + screen.getByTestId('api_key-password'), '{selectall}{backspace}goodpassword' ); - await userEvent.click(res.getByTestId('form-test-provide-submit')); - await waitFor(async () => { - expect(onSubmit).toHaveBeenCalled(); - }); + await userEvent.click(screen.getByTestId('form-test-provide-submit')); + expect(onSubmit).toHaveBeenCalled(); expect(onSubmit).toHaveBeenCalledWith({ data: {}, isValid: false }); - }); + }, 60000); - const tests: Array<[string, string]> = [ - ['url-input', ''], - ['api_key-password', ''], - ]; - it.each(tests)('validates correctly %p', async (field, value) => { + it('validates correctly empty password field', async () => { const connector = { ...openAiConnector, config: { @@ -841,20 +833,17 @@ describe('ConnectorFields renders', () => { }, }; - const res = render( + render( {}} /> ); - await userEvent.type(res.getByTestId(field), `{selectall}{backspace}${value}`); - - await userEvent.click(res.getByTestId('form-test-provide-submit')); - await waitFor(async () => { - expect(onSubmit).toHaveBeenCalled(); - }); + await userEvent.type(screen.getByTestId('api_key-password'), `{selectall}{backspace}`); + await userEvent.click(screen.getByTestId('form-test-provide-submit')); + expect(onSubmit).toHaveBeenCalled(); expect(onSubmit).toHaveBeenCalledWith({ data: {}, isValid: false }); - }); + }, 60000); }); }); diff --git a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/connector.tsx b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/connector.tsx index 51fc2d2a3e9f7..261c2d5a34154 100644 --- a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/connector.tsx +++ b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/connector.tsx @@ -5,47 +5,12 @@ * 2.0. */ -import React, { useState, useEffect, useCallback, useMemo } from 'react'; -import { - EuiFormRow, - EuiSpacer, - EuiInputPopover, - EuiFieldText, - EuiFieldTextProps, - EuiSelectableOption, - EuiFormControlLayout, - keys, - EuiHorizontalRule, -} from '@elastic/eui'; -import { - getFieldValidityAndErrorMessage, - UseField, - useFormContext, - useFormData, -} from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { - ConnectorFormSchema, - type ActionConnectorFieldsProps, -} from '@kbn/triggers-actions-ui-plugin/public'; +import React from 'react'; +import { InferenceServiceFormFields } from '@kbn/inference-endpoint-ui-common'; +import { type ActionConnectorFieldsProps } from '@kbn/triggers-actions-ui-plugin/public'; import { useKibana } from '@kbn/triggers-actions-ui-plugin/public'; -import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers'; -import { ConfigEntryView } from '../../../common/dynamic_config/types'; -import { ServiceProviderKeys } from '../../../common/inference/constants'; -import { ConnectorConfigurationFormItems } from '../lib/dynamic_config/connector_configuration_form_items'; -import * as i18n from './translations'; -import { DEFAULT_TASK_TYPE } from './constants'; -import { SelectableProvider } from './providers/selectable'; -import { Config, Secrets } from './types'; -import { generateInferenceEndpointId, getTaskTypeOptions, TaskTypeOption } from './helpers'; -import { useProviders } from './providers/get_providers'; -import { SERVICE_PROVIDERS } from './providers/render_service_provider/service_provider'; -import { AdditionalOptionsConnectorFields } from './additional_options_fields'; -import { getProviderConfigHiddenField, getProviderSecretsHiddenField } from './hidden_fields'; - const InferenceAPIConnectorFields: React.FunctionComponent = ({ - readOnly, isEdit, }) => { const { @@ -53,336 +18,7 @@ const InferenceAPIConnectorFields: React.FunctionComponent>({ - watch: [ - 'secrets.providerSecrets', - 'config.taskType', - 'config.inferenceId', - 'config.provider', - 'config.providerConfig', - ], - }); - - const { data: providers, isLoading } = useProviders(http, toasts); - - const [isProviderPopoverOpen, setProviderPopoverOpen] = useState(false); - - const [providerSchema, setProviderSchema] = useState([]); - const [optionalProviderFormFields, setOptionalProviderFormFields] = useState( - [] - ); - const [requiredProviderFormFields, setRequiredProviderFormFields] = useState( - [] - ); - - const [taskTypeOptions, setTaskTypeOptions] = useState([]); - const [selectedTaskType, setSelectedTaskType] = useState(DEFAULT_TASK_TYPE); - const [taskTypeFormFields] = useState([]); - - const handleProviderClosePopover = useCallback(() => { - setProviderPopoverOpen(false); - }, []); - - const handleProviderPopover = useCallback(() => { - setProviderPopoverOpen((isOpen) => !isOpen); - }, []); - - const handleProviderKeyboardOpen: EuiFieldTextProps['onKeyDown'] = useCallback((event: any) => { - if (event.key === keys.ENTER) { - setProviderPopoverOpen(true); - } - }, []); - - useEffect(() => { - if (!isEdit && config && !config.inferenceId) { - generateInferenceEndpointId(config, setFieldValue); - } - }, [isEdit, setFieldValue, config]); - - useEffect(() => { - if (isSubmitting) { - validateFields(['config.providerConfig']); - validateFields(['secrets.providerSecrets']); - } - }, [isSubmitting, config, validateFields]); - - const onTaskTypeOptionsSelect = useCallback( - (taskType: string) => { - // Get task type settings - setSelectedTaskType(taskType); - - updateFieldValues({ - config: { - taskType, - }, - }); - generateInferenceEndpointId({ ...config, taskType }, setFieldValue); - }, - [config, setFieldValue, updateFieldValues] - ); - - const onProviderChange = useCallback( - (provider?: string) => { - const newProvider = providers?.find((p) => p.service === provider); - - // Update task types list available for the selected 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?.configurations ?? {}).map((k) => ({ - key: k, - isValid: true, - ...newProvider?.configurations[k], - })) as ConfigEntryView[]; - - setProviderSchema(newProviderSchema); - - const defaultProviderConfig: Record = {}; - const defaultProviderSecrets: Record = {}; - - 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; - } - } else { - defaultProviderSecrets[k] = null; - } - }); - - updateFieldValues({ - config: { - provider: newProvider?.service, - providerConfig: defaultProviderConfig, - }, - secrets: { - providerSecrets: defaultProviderSecrets, - }, - }); - }, - [onTaskTypeOptionsSelect, providers, updateFieldValues] - ); - - useEffect(() => { - if (config?.provider && isEdit) { - const newProvider = providers?.find((p) => p.service === config.provider); - // Update connector providerSchema - const newProviderSchema = Object.keys(newProvider?.configurations ?? {}).map((k) => ({ - key: k, - isValid: true, - ...newProvider?.configurations[k], - })) as ConfigEntryView[]; - - setProviderSchema(newProviderSchema); - } - }, [config?.provider, config?.taskType, http, isEdit, providers]); - - useEffect(() => { - // Set values from the provider secrets and config to the schema - const existingConfiguration = providerSchema - ? providerSchema.map((item: ConfigEntryView) => { - const itemValue = item; - itemValue.isValid = true; - if (item.sensitive && secrets?.providerSecrets) { - itemValue.value = secrets?.providerSecrets[item.key] as any; - } else if (config?.providerConfig) { - itemValue.value = config?.providerConfig[item.key] as any; - } - return itemValue; - }) - : []; - - setOptionalProviderFormFields(existingConfiguration.filter((p) => !p.required && !p.sensitive)); - setRequiredProviderFormFields(existingConfiguration.filter((p) => p.required || p.sensitive)); - }, [config?.providerConfig, providerSchema, secrets]); - - const getProviderOptions = useCallback(() => { - return providers?.map((p) => ({ - label: p.service, - key: p.service, - })) as EuiSelectableOption[]; - }, [providers]); - - const onSetProviderConfigEntry = useCallback( - async (key: string, value: unknown) => { - const entry: ConfigEntryView | undefined = providerSchema.find( - (p: ConfigEntryView) => p.key === key - ); - if (entry) { - if (entry.sensitive) { - if (!secrets.providerSecrets) { - secrets.providerSecrets = {}; - } - const newSecrets = { ...secrets.providerSecrets }; - newSecrets[key] = value; - setFieldValue('secrets.providerSecrets', newSecrets); - await validateFields(['secrets.providerSecrets']); - } else { - if (!config.providerConfig) { - config.providerConfig = {}; - } - const newConfig = { ...config.providerConfig }; - newConfig[key] = value; - setFieldValue('config.providerConfig', newConfig); - await validateFields(['config.providerConfig']); - } - } - }, - [config, providerSchema, secrets, setFieldValue, validateFields] - ); - - const onClearProvider = useCallback(() => { - onProviderChange(); - setFieldValue('config.taskType', ''); - setFieldValue('config.provider', ''); - }, [onProviderChange, setFieldValue]); - - const providerIcon = useMemo( - () => - Object.keys(SERVICE_PROVIDERS).includes(config?.provider) - ? SERVICE_PROVIDERS[config?.provider as ServiceProviderKeys].icon - : undefined, - [config?.provider] - ); - - const providerName = useMemo( - () => - Object.keys(SERVICE_PROVIDERS).includes(config?.provider) - ? SERVICE_PROVIDERS[config?.provider as ServiceProviderKeys].name - : config?.provider, - [config?.provider] - ); - - const providerSuperSelect = useCallback( - (isInvalid: boolean) => ( - - - - ), - [ - isEdit, - readOnly, - onClearProvider, - config?.provider, - providerIcon, - handleProviderPopover, - handleProviderKeyboardOpen, - providerName, - isProviderPopoverOpen, - ] - ); - - return ( - <> - - {(field) => { - const { isInvalid, errorMessage } = getFieldValidityAndErrorMessage(field); - const selectInput = providerSuperSelect(isInvalid); - return ( - - } - isInvalid={isInvalid} - error={errorMessage} - > - - - - - ); - }} - - {config?.provider ? ( - <> - - - - - - - {getProviderSecretsHiddenField( - providerSchema, - setRequiredProviderFormFields, - isSubmitting - )} - {getProviderConfigHiddenField( - providerSchema, - setRequiredProviderFormFields, - isSubmitting - )} - - ) : null} - - ); + return ; }; // eslint-disable-next-line import/no-default-export diff --git a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/alibaba_cloud.svg b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/alibaba_cloud.svg deleted file mode 100644 index 1ae552d509c3a..0000000000000 --- a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/alibaba_cloud.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/amazon_bedrock.svg b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/amazon_bedrock.svg deleted file mode 100644 index f8815d4f75ec5..0000000000000 --- a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/amazon_bedrock.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/anthropic.svg b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/anthropic.svg deleted file mode 100644 index c361cda86a7df..0000000000000 --- a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/anthropic.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/azure_ai_studio.svg b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/azure_ai_studio.svg deleted file mode 100644 index 405e182a10394..0000000000000 --- a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/azure_ai_studio.svg +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/azure_open_ai.svg b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/azure_open_ai.svg deleted file mode 100644 index 122c0c65af13c..0000000000000 --- a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/azure_open_ai.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/cohere.svg b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/cohere.svg deleted file mode 100644 index 69953809fec35..0000000000000 --- a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/cohere.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/elastic.svg b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/elastic.svg deleted file mode 100644 index e763c2e2f2ab6..0000000000000 --- a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/elastic.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - diff --git a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/google_ai_studio.svg b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/google_ai_studio.svg deleted file mode 100644 index b6e34ae15c9e4..0000000000000 --- a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/google_ai_studio.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/hugging_face.svg b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/hugging_face.svg deleted file mode 100644 index 87ac70c5a18f4..0000000000000 --- a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/hugging_face.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/ibm_watsonx.svg b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/ibm_watsonx.svg deleted file mode 100644 index 5883eff3884d6..0000000000000 --- a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/ibm_watsonx.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/mistral.svg b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/mistral.svg deleted file mode 100644 index f62258a327594..0000000000000 --- a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/mistral.svg +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/open_ai.svg b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/open_ai.svg deleted file mode 100644 index 9ddc8f8fd63b8..0000000000000 --- a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/assets/images/open_ai.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/get_providers.test.tsx b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/get_providers.test.tsx deleted file mode 100644 index 7ab81ee062638..0000000000000 --- a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/get_providers.test.tsx +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import React from 'react'; -import * as ReactQuery from '@tanstack/react-query'; -import { waitFor, renderHook } from '@testing-library/react'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import { httpServiceMock, notificationServiceMock } from '@kbn/core/public/mocks'; -import { useProviders } from './get_providers'; - -const http = httpServiceMock.createStartContract(); -const toasts = notificationServiceMock.createStartContract(); -const useQuerySpy = jest.spyOn(ReactQuery, 'useQuery'); - -beforeEach(() => jest.resetAllMocks()); - -const { getProviders } = jest.requireMock('./get_providers'); - -const queryClient = new QueryClient(); - -const wrapper = ({ children }: { children: React.ReactNode }) => ( - {children} -); - -describe('useProviders', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - - it('should call useQuery', async () => { - renderHook(() => useProviders(http, toasts.toasts), { - wrapper, - }); - - await waitFor(() => { - return expect(useQuerySpy).toBeCalled(); - }); - }); - - it('should return isError = true if api fails', async () => { - getProviders.mockResolvedValue('This is an error.'); - - renderHook(() => useProviders(http, toasts.toasts), { - wrapper, - }); - - await waitFor(() => expect(useQuerySpy).toHaveBeenCalled()); - }); -}); diff --git a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/get_providers.ts b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/get_providers.ts deleted file mode 100644 index badc0cb61030d..0000000000000 --- a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/get_providers.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { HttpSetup } from '@kbn/core-http-browser'; -import { i18n } from '@kbn/i18n'; -import { useQuery } from '@tanstack/react-query'; -import type { ToastsStart } from '@kbn/core-notifications-browser'; -import { INTERNAL_BASE_STACK_CONNECTORS_API_PATH } from '../../../../common'; -import { InferenceProvider } from '../../../../common/inference/types'; - -export const getProviders = async (http: HttpSetup): Promise => { - return await http.get(`${INTERNAL_BASE_STACK_CONNECTORS_API_PATH}/_inference/_services`); -}; - -export const useProviders = (http: HttpSetup, toasts: ToastsStart) => { - const onErrorFn = (error: Error) => { - if (error) { - toasts.addDanger( - i18n.translate( - 'xpack.stackConnectors.components.inference.unableToFindProvidersQueryMessage', - { - defaultMessage: 'Unable to find providers', - } - ) - ); - } - }; - - const query = useQuery(['user-profile'], { - queryFn: () => getProviders(http), - staleTime: Infinity, - refetchOnWindowFocus: false, - onError: onErrorFn, - }); - return query; -}; diff --git a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/render_service_provider/service_provider.test.tsx b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/render_service_provider/service_provider.test.tsx deleted file mode 100644 index 84a32286b7532..0000000000000 --- a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/render_service_provider/service_provider.test.tsx +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { render, screen } from '@testing-library/react'; -import React from 'react'; -import { ServiceProviderIcon, ServiceProviderName } from './service_provider'; -import { ServiceProviderKeys } from '../../../../../common/inference/constants'; - -jest.mock('../assets/images/elastic.svg', () => 'elasticIcon.svg'); -jest.mock('../assets/images/hugging_face.svg', () => 'huggingFaceIcon.svg'); -jest.mock('../assets/images/cohere.svg', () => 'cohereIcon.svg'); -jest.mock('../assets/images/open_ai.svg', () => 'openAIIcon.svg'); - -describe('ServiceProviderIcon component', () => { - it('renders Hugging Face icon and name when providerKey is hugging_face', () => { - render(); - const icon = screen.getByTestId('icon-service-provider-hugging_face'); - expect(icon).toBeInTheDocument(); - }); - - it('renders Open AI icon and name when providerKey is openai', () => { - render(); - const icon = screen.getByTestId('icon-service-provider-openai'); - expect(icon).toBeInTheDocument(); - }); -}); - -describe('ServiceProviderName component', () => { - it('renders Hugging Face icon and name when providerKey is hugging_face', () => { - render(); - expect(screen.getByText('Hugging Face')).toBeInTheDocument(); - }); - - it('renders Open AI icon and name when providerKey is openai', () => { - render(); - expect(screen.getByText('OpenAI')).toBeInTheDocument(); - }); -}); diff --git a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/render_service_provider/service_provider.tsx b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/render_service_provider/service_provider.tsx deleted file mode 100644 index 5eb8518a5ea15..0000000000000 --- a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/render_service_provider/service_provider.tsx +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiHighlight, EuiIcon } from '@elastic/eui'; -import React from 'react'; -import { ServiceProviderKeys } from '../../../../../common/inference/constants'; -import elasticIcon from '../assets/images/elastic.svg'; -import huggingFaceIcon from '../assets/images/hugging_face.svg'; -import cohereIcon from '../assets/images/cohere.svg'; -import openAIIcon from '../assets/images/open_ai.svg'; -import azureAIStudioIcon from '../assets/images/azure_ai_studio.svg'; -import azureOpenAIIcon from '../assets/images/azure_open_ai.svg'; -import googleAIStudioIcon from '../assets/images/google_ai_studio.svg'; -import mistralIcon from '../assets/images/mistral.svg'; -import amazonBedrockIcon from '../assets/images/amazon_bedrock.svg'; -import anthropicIcon from '../assets/images/anthropic.svg'; -import alibabaCloudIcon from '../assets/images/alibaba_cloud.svg'; -import ibmWatsonxIcon from '../assets/images/ibm_watsonx.svg'; - -interface ServiceProviderProps { - providerKey: ServiceProviderKeys; - searchValue?: string; -} - -export type ProviderSolution = 'Observability' | 'Security' | 'Search'; - -interface ServiceProviderRecord { - icon: string; - name: string; - solutions: ProviderSolution[]; -} - -export const SERVICE_PROVIDERS: Record = { - [ServiceProviderKeys.amazonbedrock]: { - icon: amazonBedrockIcon, - name: 'Amazon Bedrock', - solutions: ['Observability', 'Security', 'Search'], - }, - [ServiceProviderKeys.azureaistudio]: { - icon: azureAIStudioIcon, - name: 'Azure AI Studio', - solutions: ['Search'], - }, - [ServiceProviderKeys.azureopenai]: { - icon: azureOpenAIIcon, - name: 'Azure OpenAI', - solutions: ['Observability', 'Security', 'Search'], - }, - [ServiceProviderKeys.anthropic]: { - icon: anthropicIcon, - name: 'Anthropic', - solutions: ['Search'], - }, - [ServiceProviderKeys.cohere]: { - icon: cohereIcon, - name: 'Cohere', - solutions: ['Search'], - }, - [ServiceProviderKeys.elasticsearch]: { - icon: elasticIcon, - name: 'Elasticsearch', - solutions: ['Search'], - }, - [ServiceProviderKeys.googleaistudio]: { - icon: googleAIStudioIcon, - name: 'Google AI Studio', - solutions: ['Search'], - }, - [ServiceProviderKeys.googlevertexai]: { - icon: googleAIStudioIcon, - name: 'Google Vertex AI', - solutions: ['Observability', 'Security', 'Search'], - }, - [ServiceProviderKeys.hugging_face]: { - icon: huggingFaceIcon, - name: 'Hugging Face', - solutions: ['Search'], - }, - [ServiceProviderKeys.mistral]: { - icon: mistralIcon, - name: 'Mistral', - solutions: ['Search'], - }, - [ServiceProviderKeys.openai]: { - icon: openAIIcon, - name: 'OpenAI', - solutions: ['Observability', 'Security', 'Search'], - }, - [ServiceProviderKeys['alibabacloud-ai-search']]: { - icon: alibabaCloudIcon, - name: 'AlibabaCloud AI Search', - solutions: ['Search'], - }, - [ServiceProviderKeys.watsonxai]: { - icon: ibmWatsonxIcon, - name: 'IBM Watsonx', - solutions: ['Search'], - }, -}; - -export const ServiceProviderIcon: React.FC = ({ providerKey }) => { - const provider = SERVICE_PROVIDERS[providerKey]; - - return provider ? ( - - ) : null; -}; - -export const ServiceProviderName: React.FC = ({ - providerKey, - searchValue, -}) => { - const provider = SERVICE_PROVIDERS[providerKey]; - - return provider ? ( - {provider.name} - ) : ( - {providerKey} - ); -}; diff --git a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/selectable/index.test.tsx b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/selectable/index.test.tsx deleted file mode 100644 index f83d4bcd9ea4c..0000000000000 --- a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/selectable/index.test.tsx +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { EuiSelectableProps } from '@elastic/eui'; -import React from 'react'; -import type { ShallowWrapper } from 'enzyme'; -import { shallow } from 'enzyme'; - -import { SelectableProvider } from '.'; - -describe('SelectableProvider', () => { - const props = { - isLoading: false, - onClosePopover: jest.fn(), - onProviderChange: jest.fn(), - getSelectableOptions: jest.fn().mockReturnValue([]), - }; - - describe('should render', () => { - let wrapper: ShallowWrapper; - - describe('provider', () => { - beforeAll(() => { - wrapper = shallow(); - }); - - afterAll(() => { - jest.clearAllMocks(); - }); - - test('render placeholder', () => { - const searchProps: EuiSelectableProps['searchProps'] = wrapper - .find('[data-test-subj="selectable-provider-input"]') - .prop('searchProps'); - expect(searchProps?.placeholder).toEqual('Search'); - }); - }); - - describe('template', () => { - beforeAll(() => { - wrapper = shallow(); - }); - - afterAll(() => { - jest.clearAllMocks(); - }); - - test('render placeholder', () => { - const searchProps: EuiSelectableProps['searchProps'] = wrapper - .find('[data-test-subj="selectable-provider-input"]') - .prop('searchProps'); - expect(searchProps?.placeholder).toEqual('Search'); - }); - }); - }); -}); diff --git a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/selectable/index.tsx b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/selectable/index.tsx deleted file mode 100644 index fc31c9dd6c4f7..0000000000000 --- a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/providers/selectable/index.tsx +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { EuiSelectableOption, EuiSelectableProps } from '@elastic/eui'; -import { EuiSelectable, EuiFlexGroup, EuiFlexItem, EuiBadge } from '@elastic/eui'; -import React, { memo, useCallback, useMemo, useState } from 'react'; -import { i18n } from '@kbn/i18n'; -import { ServiceProviderKeys } from '../../../../../common/inference/constants'; -import { - ProviderSolution, - SERVICE_PROVIDERS, - ServiceProviderIcon, - ServiceProviderName, -} from '../render_service_provider/service_provider'; - -/** - * Modifies options by creating new property `providerTitle`(with value of `title`), and by setting `title` to undefined. - * Thus prevents appearing default browser tooltip on option hover (attribute `title` that gets rendered on li element) - * - * @param {EuiSelectableOption[]} options - * @returns {EuiSelectableOption[]} modified options - */ - -export interface SelectableProviderProps { - isLoading: boolean; - getSelectableOptions: (searchProviderValue?: string) => EuiSelectableOption[]; - onClosePopover: () => void; - onProviderChange: (provider?: string) => void; -} - -const SelectableProviderComponent: React.FC = ({ - isLoading, - getSelectableOptions, - onClosePopover, - onProviderChange, -}) => { - const [searchProviderValue, setSearchProviderValue] = useState(''); - const onSearchProvider = useCallback( - (val: string) => { - setSearchProviderValue(val); - }, - [setSearchProviderValue] - ); - - const renderProviderOption = useCallback>( - (option, searchValue) => { - const provider = Object.keys(SERVICE_PROVIDERS).includes(option.label) - ? SERVICE_PROVIDERS[option.label as ServiceProviderKeys] - : undefined; - - const supportedBySolutions = (provider && - provider.solutions.map((solution) => ( - - {solution} - - ))) ?? ( - - {'Search' as ProviderSolution} - - ); - return ( - - - - - - - - - - - - - - {supportedBySolutions} - - - - ); - }, - [] - ); - - const handleProviderChange = useCallback>( - (options) => { - const selectedProvider = options.filter((option) => option.checked === 'on'); - if (selectedProvider != null && selectedProvider.length > 0) { - onProviderChange(selectedProvider[0].label); - } - onClosePopover(); - }, - [onClosePopover, onProviderChange] - ); - - const EuiSelectableContent = useCallback>( - (list, search) => ( - <> - {search} - {list} - - ), - [] - ); - - const searchProps: EuiSelectableProps['searchProps'] = useMemo( - () => ({ - 'data-test-subj': 'provider-super-select-search-box', - placeholder: i18n.translate( - 'xpack.stackConnectors.components.inference.selectable.providerSearch', - { - defaultMessage: 'Search', - } - ), - onSearch: onSearchProvider, - incremental: false, - compressed: true, - fullWidth: true, - }), - [onSearchProvider] - ); - - return ( - - {EuiSelectableContent} - - ); -}; - -export const SelectableProvider = memo(SelectableProviderComponent); diff --git a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/lib/dynamic_config/connector_configuration_field.tsx b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/lib/dynamic_config/connector_configuration_field.tsx deleted file mode 100644 index b6dc0972492bf..0000000000000 --- a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/lib/dynamic_config/connector_configuration_field.tsx +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useEffect, useState } from 'react'; - -import { - EuiAccordion, - EuiFieldText, - EuiFieldPassword, - EuiSwitch, - EuiTextArea, - EuiFieldNumber, -} from '@elastic/eui'; - -import { isEmpty } from 'lodash/fp'; -import { ConfigEntryView, FieldType } from '../../../../common/dynamic_config/types'; -import { - ensureBooleanType, - ensureCorrectTyping, - ensureStringType, -} from './connector_configuration_utils'; - -interface ConnectorConfigurationFieldProps { - configEntry: ConfigEntryView; - isLoading: boolean; - setConfigValue: (value: number | string | boolean | null) => void; -} - -interface ConfigInputFieldProps { - configEntry: ConfigEntryView; - isLoading: boolean; - validateAndSetConfigValue: (value: string | boolean) => void; -} -export const ConfigInputField: React.FC = ({ - configEntry, - isLoading, - validateAndSetConfigValue, -}) => { - // eslint-disable-next-line @typescript-eslint/naming-convention - const { isValid, value, default_value, key } = configEntry; - const [innerValue, setInnerValue] = useState( - !value || value.toString().length === 0 ? default_value : value - ); - - useEffect(() => { - setInnerValue(!value || value.toString().length === 0 ? default_value : value); - }, [default_value, value]); - return ( - { - setInnerValue(event.target.value); - validateAndSetConfigValue(event.target.value); - }} - /> - ); -}; - -export const ConfigSwitchField: React.FC = ({ - configEntry, - isLoading, - validateAndSetConfigValue, -}) => { - // eslint-disable-next-line @typescript-eslint/naming-convention - const { label, value, default_value, key } = configEntry; - const [innerValue, setInnerValue] = useState(value ?? default_value); - useEffect(() => { - setInnerValue(value ?? default_value); - }, [default_value, value]); - return ( - {label}

} - onChange={(event) => { - setInnerValue(event.target.checked); - validateAndSetConfigValue(event.target.checked); - }} - /> - ); -}; - -export const ConfigInputTextArea: React.FC = ({ - isLoading, - configEntry, - validateAndSetConfigValue, -}) => { - // eslint-disable-next-line @typescript-eslint/naming-convention - const { isValid, value, default_value, key } = configEntry; - const [innerValue, setInnerValue] = useState(value ?? default_value); - useEffect(() => { - setInnerValue(value ?? default_value); - }, [default_value, value]); - return ( - { - setInnerValue(event.target.value); - validateAndSetConfigValue(event.target.value); - }} - /> - ); -}; - -export const ConfigNumberField: React.FC = ({ - configEntry, - isLoading, - validateAndSetConfigValue, -}) => { - // eslint-disable-next-line @typescript-eslint/naming-convention - const { isValid, value, default_value, key } = configEntry; - const [innerValue, setInnerValue] = useState(value ?? default_value); - useEffect(() => { - setInnerValue(!value || value.toString().length === 0 ? default_value : value); - }, [default_value, value]); - return ( - { - const newValue = isEmpty(event.target.value) ? '0' : event.target.value; - setInnerValue(newValue); - validateAndSetConfigValue(newValue); - }} - /> - ); -}; - -export const ConfigSensitiveTextArea: React.FC = ({ - isLoading, - configEntry, - validateAndSetConfigValue, -}) => { - const { key, label } = configEntry; - return ( - {label}

}> - -
- ); -}; - -export const ConfigInputPassword: React.FC = ({ - isLoading, - configEntry, - validateAndSetConfigValue, -}) => { - const { value, key } = configEntry; - const [innerValue, setInnerValue] = useState(value ?? null); - useEffect(() => { - setInnerValue(value ?? null); - }, [value]); - return ( - <> - { - setInnerValue(event.target.value); - validateAndSetConfigValue(event.target.value); - }} - /> - - ); -}; - -export const ConnectorConfigurationField: React.FC = ({ - configEntry, - isLoading, - setConfigValue, -}) => { - const validateAndSetConfigValue = (value: number | string | boolean) => { - setConfigValue(ensureCorrectTyping(configEntry.type, value)); - }; - - const { key, type, sensitive } = configEntry; - - switch (type) { - case FieldType.INTEGER: - return ( - - ); - - case FieldType.BOOLEAN: - return ( - - ); - - default: - return sensitive ? ( - - ) : ( - - ); - } -}; diff --git a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/lib/dynamic_config/connector_configuration_form_items.tsx b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/lib/dynamic_config/connector_configuration_form_items.tsx deleted file mode 100644 index ed564c247394c..0000000000000 --- a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/lib/dynamic_config/connector_configuration_form_items.tsx +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { - EuiCallOut, - EuiFlexGroup, - EuiFlexItem, - EuiFormRow, - EuiSpacer, - EuiText, -} from '@elastic/eui'; - -import { i18n } from '@kbn/i18n'; -import { ConfigEntryView } from '../../../../common/dynamic_config/types'; -import { ConnectorConfigurationField } from './connector_configuration_field'; - -interface ConnectorConfigurationFormItemsProps { - isLoading: boolean; - items: ConfigEntryView[]; - setConfigEntry: (key: string, value: string | number | boolean | null) => void; - direction?: 'column' | 'row' | 'rowReverse' | 'columnReverse' | undefined; - itemsGrow?: boolean; -} - -export const ConnectorConfigurationFormItems: React.FC = ({ - isLoading, - items, - setConfigEntry, - direction, -}) => { - return ( - - {items.map((configEntry) => { - const { key, isValid, label, sensitive, description, validationErrors, required } = - configEntry; - - const helpText = description; - // toggle and sensitive textarea labels go next to the element, not in the row - const rowLabel = description ? ( - - -

{label}

-
-
- ) : ( -

{label}

- ); - - const optionalLabel = !required ? ( - - {i18n.translate('xpack.stackConnectors.components.inference.config.optionalValue', { - defaultMessage: 'Optional', - })} - - ) : undefined; - - return ( - - - { - setConfigEntry(key, value); - }} - /> - - {sensitive ? ( - <> - - - - ) : null} - - ); - })} -
- ); -}; diff --git a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/lib/dynamic_config/connector_configuration_utils.ts b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/lib/dynamic_config/connector_configuration_utils.ts deleted file mode 100644 index 5e78903746aee..0000000000000 --- a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/lib/dynamic_config/connector_configuration_utils.ts +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ConfigProperties, FieldType } from '../../../../common/dynamic_config/types'; - -export type ConnectorConfigEntry = ConfigProperties & { key: string }; - -export const validIntInput = (value: string | number | boolean | null): boolean => { - // reject non integers (including x.0 floats), but don't validate if empty - return (value !== null || value !== '') && - (isNaN(Number(value)) || - !Number.isSafeInteger(Number(value)) || - ensureStringType(value).indexOf('.') >= 0) - ? false - : true; -}; - -export const ensureCorrectTyping = ( - type: FieldType, - value: string | number | boolean | null -): string | number | boolean | null => { - switch (type) { - case FieldType.INTEGER: - return validIntInput(value) ? ensureIntType(value) : value; - case FieldType.BOOLEAN: - return ensureBooleanType(value); - default: - return ensureStringType(value); - } -}; - -export const ensureStringType = (value: string | number | boolean | null): string => { - return value !== null ? String(value) : ''; -}; - -export const ensureIntType = (value: string | number | boolean | null): number | null => { - // int is null-safe to prevent empty values from becoming zeroes - if (value === null || value === '') { - return null; - } - - return parseInt(String(value), 10); -}; - -export const ensureBooleanType = (value: string | number | boolean | null): boolean => { - return Boolean(value); -}; diff --git a/x-pack/platform/plugins/shared/stack_connectors/server/plugin.ts b/x-pack/platform/plugins/shared/stack_connectors/server/plugin.ts index b20892938735b..aee84d963043d 100644 --- a/x-pack/platform/plugins/shared/stack_connectors/server/plugin.ts +++ b/x-pack/platform/plugins/shared/stack_connectors/server/plugin.ts @@ -8,11 +8,7 @@ import { PluginInitializerContext, Plugin, CoreSetup, Logger } from '@kbn/core/server'; import { PluginSetupContract as ActionsPluginSetupContract } from '@kbn/actions-plugin/server'; import { registerConnectorTypes } from './connector_types'; -import { - validSlackApiChannelsRoute, - getWellKnownEmailServiceRoute, - getInferenceServicesRoute, -} from './routes'; +import { validSlackApiChannelsRoute, getWellKnownEmailServiceRoute } from './routes'; import { ExperimentalFeatures, parseExperimentalConfigValue, @@ -43,7 +39,6 @@ export class StackConnectorsPlugin implements Plugin { getWellKnownEmailServiceRoute(router); validSlackApiChannelsRoute(router, actions.getActionsConfigurationUtilities(), this.logger); - getInferenceServicesRoute(router); registerConnectorTypes({ actions, diff --git a/x-pack/platform/plugins/shared/stack_connectors/server/routes/get_inference_services.test.ts b/x-pack/platform/plugins/shared/stack_connectors/server/routes/get_inference_services.test.ts deleted file mode 100644 index 9e1449a37f7ff..0000000000000 --- a/x-pack/platform/plugins/shared/stack_connectors/server/routes/get_inference_services.test.ts +++ /dev/null @@ -1,677 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { httpServiceMock, httpServerMock } from '@kbn/core/server/mocks'; -import { coreMock } from '@kbn/core/server/mocks'; -import { getInferenceServicesRoute } from './get_inference_services'; -import { FieldType } from '../../common/dynamic_config/types'; - -describe('getInferenceServicesRoute', () => { - it('returns available service providers', async () => { - const router = httpServiceMock.createRouter(); - const core = coreMock.createRequestHandlerContext(); - - const mockResult = [ - { - 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, - }, - }, - }, - ]; - core.elasticsearch.client.asInternalUser.transport.request.mockResolvedValue(mockResult); - - getInferenceServicesRoute(router); - - const [config, handler] = router.get.mock.calls[0]; - expect(config.path).toMatchInlineSnapshot(`"/internal/stack_connectors/_inference/_services"`); - - const mockResponse = httpServerMock.createResponseFactory(); - const mockRequest = httpServerMock.createKibanaRequest(); - await handler({ core }, mockRequest, mockResponse); - - expect(mockResponse.ok).toHaveBeenCalledWith({ - body: mockResult, - }); - }); -}); diff --git a/x-pack/platform/plugins/shared/stack_connectors/server/routes/get_inference_services.ts b/x-pack/platform/plugins/shared/stack_connectors/server/routes/get_inference_services.ts deleted file mode 100644 index 3c4a1b3aa1a35..0000000000000 --- a/x-pack/platform/plugins/shared/stack_connectors/server/routes/get_inference_services.ts +++ /dev/null @@ -1,703 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - IRouter, - RequestHandlerContext, - KibanaRequest, - 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'; - -export const getInferenceServicesRoute = (router: IRouter) => { - router.get( - { - path: `${INTERNAL_BASE_STACK_CONNECTORS_API_PATH}/_inference/_services`, - security: { - authz: { - enabled: false, - reason: - 'This route is opted out of authorization as it relies on ES authorization instead.', - }, - }, - options: { - access: 'internal', - }, - validate: false, - }, - handler - ); - - async function handler( - ctx: RequestHandlerContext, - req: KibanaRequest, - res: KibanaResponseFactory - ): Promise { - // Temporarily hard-coding the response until the real implementation is ready with the updated response - https://github.com/elastic/ml-team/issues/1428 - - // 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, - }); - } -}; diff --git a/x-pack/platform/plugins/shared/stack_connectors/server/routes/index.ts b/x-pack/platform/plugins/shared/stack_connectors/server/routes/index.ts index e64995e1a50ef..cd9857b2168ed 100644 --- a/x-pack/platform/plugins/shared/stack_connectors/server/routes/index.ts +++ b/x-pack/platform/plugins/shared/stack_connectors/server/routes/index.ts @@ -7,4 +7,3 @@ export { getWellKnownEmailServiceRoute } from './get_well_known_email_service'; export { validSlackApiChannelsRoute } from './valid_slack_api_channels'; -export { getInferenceServicesRoute } from './get_inference_services'; diff --git a/x-pack/platform/plugins/shared/stack_connectors/tsconfig.json b/x-pack/platform/plugins/shared/stack_connectors/tsconfig.json index 222fca24ad5fa..4b7b5cdad8bb5 100644 --- a/x-pack/platform/plugins/shared/stack_connectors/tsconfig.json +++ b/x-pack/platform/plugins/shared/stack_connectors/tsconfig.json @@ -42,8 +42,8 @@ "@kbn/utility-types", "@kbn/task-manager-plugin", "@kbn/alerting-types", - "@kbn/core-notifications-browser", "@kbn/response-ops-rule-form", + "@kbn/inference-endpoint-ui-common", ], "exclude": [ "target/**/*", diff --git a/x-pack/solutions/search/plugins/search_inference_endpoints/public/components/add_inference_endpoints/add_inference_flyout_wrapper.test.tsx b/x-pack/solutions/search/plugins/search_inference_endpoints/public/components/add_inference_endpoints/add_inference_flyout_wrapper.test.tsx index e21ea0d95eccb..3031bbe857656 100644 --- a/x-pack/solutions/search/plugins/search_inference_endpoints/public/components/add_inference_endpoints/add_inference_flyout_wrapper.test.tsx +++ b/x-pack/solutions/search/plugins/search_inference_endpoints/public/components/add_inference_endpoints/add_inference_flyout_wrapper.test.tsx @@ -22,7 +22,7 @@ jest.mock('../../hooks/use_add_endpoint', () => ({ }), })); -jest.mock('../../hooks/use_providers', () => ({ +jest.mock('@kbn/inference-endpoint-ui-common/src/hooks/use_providers', () => ({ useProviders: jest.fn(() => ({ data: mockProviders, })), diff --git a/x-pack/solutions/search/plugins/search_inference_endpoints/public/components/add_inference_endpoints/inference_form.tsx b/x-pack/solutions/search/plugins/search_inference_endpoints/public/components/add_inference_endpoints/inference_form.tsx index 4ed1a1090edb3..0972a6b5f2fe2 100644 --- a/x-pack/solutions/search/plugins/search_inference_endpoints/public/components/add_inference_endpoints/inference_form.tsx +++ b/x-pack/solutions/search/plugins/search_inference_endpoints/public/components/add_inference_endpoints/inference_form.tsx @@ -9,15 +9,19 @@ import { Form, useForm } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_l import React, { useCallback, useState } from 'react'; import { InferenceServiceFormFields } from '@kbn/inference-endpoint-ui-common'; import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; -import { useProviders } from '../../hooks/use_providers'; import * as i18n from './translations'; import { useAddEndpoint } from '../../hooks/use_add_endpoint'; import { InferenceEndpoint } from '../../types'; +import { useKibana } from '../../hooks/use_kibana'; interface InferenceFormProps { onSubmitSuccess: (state: boolean) => void; } export const InferenceForm: React.FC = ({ onSubmitSuccess }) => { + const { + http, + notifications: { toasts }, + } = useKibana().services; const [isLoading, setIsLoading] = useState(false); const onSuccess = useCallback(() => { setIsLoading(false); @@ -30,7 +34,6 @@ export const InferenceForm: React.FC = ({ onSubmitSuccess }) () => onSuccess(), () => onError() ); - const { data: providers } = useProviders(); const { form } = useForm(); const handleSubmit = useCallback(async () => { setIsLoading(true); @@ -45,9 +48,9 @@ export const InferenceForm: React.FC = ({ onSubmitSuccess }) } }, [addEndpoint, form]); - return providers ? ( + return (
- + @@ -65,5 +68,5 @@ export const InferenceForm: React.FC = ({ onSubmitSuccess }) - ) : null; + ); }; diff --git a/x-pack/solutions/search/plugins/search_inference_endpoints/public/hooks/translations.ts b/x-pack/solutions/search/plugins/search_inference_endpoints/public/hooks/translations.ts index d7a9680dd1667..d0b9eb66cdd93 100644 --- a/x-pack/solutions/search/plugins/search_inference_endpoints/public/hooks/translations.ts +++ b/x-pack/solutions/search/plugins/search_inference_endpoints/public/hooks/translations.ts @@ -28,10 +28,3 @@ export const ENDPOINT_CREATION_FAILED = i18n.translate( defaultMessage: 'Endpoint creation failed', } ); - -export const GET_PROVIDERS_FAILED = i18n.translate( - 'xpack.searchInferenceEndpoints.addEndpoint.unableToFindProvidersQueryMessage', - { - defaultMessage: 'Unable to find providers', - } -); diff --git a/x-pack/solutions/search/plugins/search_inference_endpoints/tsconfig.json b/x-pack/solutions/search/plugins/search_inference_endpoints/tsconfig.json index 7b8da3db70c9e..8909c20100eed 100644 --- a/x-pack/solutions/search/plugins/search_inference_endpoints/tsconfig.json +++ b/x-pack/solutions/search/plugins/search_inference_endpoints/tsconfig.json @@ -39,7 +39,6 @@ "@kbn/inference-endpoint-ui-common", "@kbn/es-ui-shared-plugin", "@kbn/search-connectors", - "@kbn/core-http-browser", "@kbn/safer-lodash-set" ], "exclude": [