Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[8.x] [AI Connector] Migrates AI inference Connector to use a shared components from '@kbn/inference-endpoint-ui-common' (#204885) #205671

Open
wants to merge 1 commit into
base: 8.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ interface AdditionalOptionsFieldsProps {
onTaskTypeOptionsSelect: (taskType: string, provider?: string) => void;
selectedTaskType?: string;
taskTypeOptions: TaskTypeOption[];
isEdit?: boolean;
}

export const AdditionalOptionsFields: React.FC<AdditionalOptionsFieldsProps> = ({
Expand All @@ -61,6 +62,7 @@ export const AdditionalOptionsFields: React.FC<AdditionalOptionsFieldsProps> = (
selectedTaskType,
onSetProviderConfigEntry,
onTaskTypeOptionsSelect,
isEdit,
}) => {
const xsFontSize = useEuiFontSize('xs').fontSize;
const { euiTheme } = useEuiTheme();
Expand Down Expand Up @@ -106,7 +108,18 @@ export const AdditionalOptionsFields: React.FC<AdditionalOptionsFieldsProps> = (

return (
<EuiFormRow id="taskType" fullWidth isInvalid={isInvalid} error={errorMessage}>
{taskTypeOptions.length === 1 ? (
{isEdit ? (
<EuiButton
css={{
background: euiTheme.colors.disabled,
color: euiTheme.colors.lightestShade,
}}
data-test-subj="taskTypeSelectDisabled"
isDisabled
>
{config.taskType}
</EuiButton>
) : taskTypeOptions.length === 1 ? (
<EuiButton
css={{
background: euiTheme.colors.darkShade,
Expand Down Expand Up @@ -140,7 +153,11 @@ export const AdditionalOptionsFields: React.FC<AdditionalOptionsFieldsProps> = (
selectedTaskType,
config.taskType,
xsFontSize,
euiTheme.colors,
euiTheme.colors.textSubdued,
euiTheme.colors.disabled,
euiTheme.colors.lightestShade,
euiTheme.colors.darkShade,
isEdit,
taskTypeOptions,
onTaskTypeOptionsSelect,
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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();

Expand All @@ -124,7 +135,7 @@ describe('Inference Services', () => {
it('renders', () => {
render(
<MockFormProvider>
<InferenceServiceFormFields providers={providers} />
<InferenceServiceFormFields http={httpMock} toasts={notificationsMock.toasts} />
</MockFormProvider>
);

Expand All @@ -134,7 +145,7 @@ describe('Inference Services', () => {
it('renders Selectable', async () => {
render(
<MockFormProvider>
<InferenceServiceFormFields providers={providers} />
<InferenceServiceFormFields http={httpMock} toasts={notificationsMock.toasts} />
</MockFormProvider>
);

Expand All @@ -145,7 +156,7 @@ describe('Inference Services', () => {
it('renders selected provider fields - hugging_face', async () => {
render(
<MockFormProvider>
<InferenceServiceFormFields providers={providers} />
<InferenceServiceFormFields http={httpMock} toasts={notificationsMock.toasts} />
</MockFormProvider>
);

Expand All @@ -165,7 +176,7 @@ describe('Inference Services', () => {
it('re-renders fields when selected to anthropic from hugging_face', async () => {
render(
<MockFormProvider>
<InferenceServiceFormFields providers={providers} />
<InferenceServiceFormFields http={httpMock} toasts={notificationsMock.toasts} />
</MockFormProvider>
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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<InferenceServicesProps> = ({ providers }) => {
export const InferenceServiceFormFields: React.FC<InferenceServicesProps> = ({
http,
toasts,
isEdit,
}) => {
const { data: providers, isLoading } = useProviders(http, toasts);
const [isProviderPopoverOpen, setProviderPopoverOpen] = useState(false);
const [providerSchema, setProviderSchema] = useState<ConfigEntryView[]>([]);
const [taskTypeOptions, setTaskTypeOptions] = useState<TaskTypeOption[]>([]);
Expand Down Expand Up @@ -213,8 +222,9 @@ export const InferenceServiceFormFields: React.FC<InferenceServicesProps> = ({ p
const providerSuperSelect = useCallback(
(isInvalid: boolean) => (
<EuiFormControlLayout
clear={{ onClick: onClearProvider }}
clear={isEdit ? undefined : { onClick: onClearProvider }}
isDropdown
isDisabled={isEdit}
isInvalid={isInvalid}
fullWidth
icon={!config?.provider ? { type: 'sparkles', side: 'left' } : providerIcon}
Expand All @@ -223,6 +233,7 @@ export const InferenceServiceFormFields: React.FC<InferenceServicesProps> = ({ p
onClick={toggleProviderPopover}
data-test-subj="provider-select"
isInvalid={isInvalid}
disabled={isEdit}
onKeyDown={handleProviderKeyboardOpen}
value={config?.provider ? providerName : ''}
fullWidth
Expand All @@ -239,16 +250,31 @@ export const InferenceServiceFormFields: React.FC<InferenceServicesProps> = ({ p
</EuiFormControlLayout>
),
[
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']);
Expand Down Expand Up @@ -291,7 +317,7 @@ export const InferenceServiceFormFields: React.FC<InferenceServicesProps> = ({ p
setRequiredProviderFormFields(existingConfiguration.filter((p) => p.required || p.sensitive));
}, [config?.providerConfig, providerSchema, secrets]);

return (
return !isLoading ? (
<>
<UseField
path="config.provider"
Expand Down Expand Up @@ -329,7 +355,7 @@ export const InferenceServiceFormFields: React.FC<InferenceServicesProps> = ({ p
className="rightArrowIcon"
>
<SelectableProvider
providers={providers}
providers={providers ?? []}
onClosePopover={closeProviderPopover}
onProviderChange={onProviderChange}
/>
Expand All @@ -355,6 +381,7 @@ export const InferenceServiceFormFields: React.FC<InferenceServicesProps> = ({ p
onTaskTypeOptionsSelect={onTaskTypeOptionsSelect}
taskTypeOptions={taskTypeOptions}
selectedTaskType={selectedTaskType}
isEdit={isEdit}
/>
<EuiSpacer size="m" />
<EuiHorizontalRule margin="xs" />
Expand All @@ -371,5 +398,5 @@ export const InferenceServiceFormFields: React.FC<InferenceServicesProps> = ({ p
</>
) : null}
</>
);
) : null;
};
Original file line number Diff line number Diff line change
Expand Up @@ -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 [
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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',
}
);
Original file line number Diff line number Diff line change
Expand Up @@ -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"
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -45168,35 +45168,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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45017,35 +45017,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": "追加のコメント",
Expand Down
Loading