Elastic as pinned provider (#208133)

## Summary

The Inference Service team is expecting `Elastic` service as a pinned
service in the provider list.




https://github.com/user-attachments/assets/e919d9ea-ebfa-4388-8125-c11c26199c54


### Checklist

Check the PR satisfies following conditions. 

Reviewers should verify this PR satisfies this list as well.

- [X] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [ ] The PR description includes the appropriate Release Notes section,
and the correct `release_note:*` label is applied per the
[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
This commit is contained in:
Samiul Monir 2025-01-24 14:54:42 -05:00 committed by GitHub
parent 22c79ec5bc
commit e627634032
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 74 additions and 8 deletions

View file

@ -56,6 +56,18 @@ describe('Inference Services', () => {
expect(screen.getByTestId('euiSelectableList')).toBeInTheDocument();
});
it('renders Elastic at top', async () => {
render(
<MockFormProvider>
<InferenceServiceFormFields http={httpMock} toasts={notificationsMock.toasts} />
</MockFormProvider>
);
await userEvent.click(screen.getByTestId('provider-select'));
const listItems = screen.getAllByTestId('provider');
expect(listItems[0]).toHaveTextContent('Elastic');
});
it('renders selected provider fields - hugging_face', async () => {
render(
<MockFormProvider>

View file

@ -28,7 +28,7 @@ import { ConnectorFormSchema } from '@kbn/triggers-actions-ui-plugin/public';
import { HttpSetup, IToasts } from '@kbn/core/public';
import * as LABELS from '../translations';
import { Config, ConfigEntryView, Secrets } from '../types/types';
import { Config, ConfigEntryView, InferenceProvider, 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';
@ -56,6 +56,9 @@ export const InferenceServiceFormFields: React.FC<InferenceServicesProps> = ({
isEdit,
}) => {
const { data: providers, isLoading } = useProviders(http, toasts);
const [updatedProviders, setUpdatedProviders] = useState<InferenceProvider[] | undefined>(
undefined
);
const [isProviderPopoverOpen, setProviderPopoverOpen] = useState(false);
const [providerSchema, setProviderSchema] = useState<ConfigEntryView[]>([]);
const [taskTypeOptions, setTaskTypeOptions] = useState<TaskTypeOption[]>([]);
@ -117,7 +120,7 @@ export const InferenceServiceFormFields: React.FC<InferenceServicesProps> = ({
taskType,
});
const newProvider = providers?.find(
const newProvider = updatedProviders?.find(
(p) => p.service === (config.provider === '' ? providerSelected : config.provider)
);
if (newProvider) {
@ -152,12 +155,12 @@ export const InferenceServiceFormFields: React.FC<InferenceServicesProps> = ({
},
});
},
[config, providers, secrets, updateFieldValues]
[config, secrets, updateFieldValues, updatedProviders]
);
const onProviderChange = useCallback(
(provider?: string) => {
const newProvider = providers?.find((p) => p.service === provider);
const newProvider = updatedProviders?.find((p) => p.service === provider);
setTaskTypeOptions(getTaskTypeOptions(newProvider?.task_types ?? []));
if (newProvider?.task_types && newProvider?.task_types.length > 0) {
@ -202,7 +205,7 @@ export const InferenceServiceFormFields: React.FC<InferenceServicesProps> = ({
},
});
},
[config, onTaskTypeOptionsSelect, providers, updateFieldValues]
[config, onTaskTypeOptionsSelect, updateFieldValues, updatedProviders]
);
const onSetProviderConfigEntry = useCallback(
@ -281,9 +284,23 @@ export const InferenceServiceFormFields: React.FC<InferenceServicesProps> = ({
]
);
useEffect(() => {
if (providers) {
// Ensure the Elastic Inference Service (EIS) appears at the top of the providers list
const elasticServiceIndex = providers.findIndex((provider) => provider.service === 'elastic');
if (elasticServiceIndex !== -1) {
const elasticService = providers[elasticServiceIndex];
const remainingProviders = providers.filter((_, index) => index !== elasticServiceIndex);
setUpdatedProviders([elasticService, ...remainingProviders]);
} else {
setUpdatedProviders(providers);
}
}
}, [providers]);
useEffect(() => {
if (config?.provider && config?.taskType && isEdit) {
const newProvider = providers?.find((p) => p.service === config.provider);
const newProvider = updatedProviders?.find((p) => p.service === config.provider);
// Update connector providerSchema
const newProviderSchema: ConfigEntryView[] = newProvider
@ -294,7 +311,7 @@ export const InferenceServiceFormFields: React.FC<InferenceServicesProps> = ({
}
setSelectedTaskType(config.taskType);
}
}, [config, config?.provider, config?.taskType, isEdit, providers, selectedTaskType]);
}, [config, config?.provider, config?.taskType, isEdit, selectedTaskType, updatedProviders]);
useEffect(() => {
if (isSubmitting) {
@ -377,7 +394,7 @@ export const InferenceServiceFormFields: React.FC<InferenceServicesProps> = ({
className="rightArrowIcon"
>
<SelectableProvider
providers={providers ?? []}
providers={updatedProviders ?? []}
onClosePopover={closeProviderPopover}
onProviderChange={onProviderChange}
/>

View file

@ -110,6 +110,43 @@ export const mockProviders: InferenceProvider[] = [
},
},
},
{
service: 'elastic',
name: 'Elastic',
task_types: ['sparse_embedding', 'chat_completion'],
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: false,
type: FieldType.INTEGER,
supported_task_types: ['sparse_embedding', 'chat_completion'],
},
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: false,
type: FieldType.STRING,
supported_task_types: ['sparse_embedding', 'chat_completion'],
},
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: false,
type: FieldType.INTEGER,
supported_task_types: ['sparse_embedding'],
},
},
},
{
service: 'elasticsearch',
name: 'Elasticsearch',