Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
d143501
add ability to hide internal specified fields
alvarezmelissa87 May 30, 2025
ee4c273
ensure fields are in config but hidden in UI
alvarezmelissa87 Jun 3, 2025
0971e5b
add helptext callout for max allocations
alvarezmelissa87 Jun 4, 2025
757c886
always enable adaptive allocations for elasticsearch service on serve…
alvarezmelissa87 Jun 5, 2025
33cb73e
ensure AiConnector shows changes for es service on serverless
alvarezmelissa87 Jun 7, 2025
12d2156
[CI] Auto-commit changed files from 'node scripts/styled_components_m…
kibanamachine Jun 10, 2025
30c35bf
implement final design for max allocations
alvarezmelissa87 Jun 16, 2025
ff20071
Merge branch 'main' into ml-inference-endpoints-remove-allocations-fi…
elasticmachine Jun 16, 2025
8b4f714
remove unused file
alvarezmelissa87 Jun 16, 2025
43a6ef2
remove serverless from connector context and pass as prop
alvarezmelissa87 Jun 16, 2025
508f511
ensure number field min is 0 and fix type
alvarezmelissa87 Jun 17, 2025
e62853c
Merge branch 'main' into ml-inference-endpoints-remove-allocations-fi…
elasticmachine Jun 23, 2025
ebff5bc
update isServerless naming. Add titular component registry
alvarezmelissa87 Jun 23, 2025
6b7b65e
ensure updates apply to index management endpoint flyout
alvarezmelissa87 Jun 23, 2025
df79a52
fix circular dependency
alvarezmelissa87 Jun 24, 2025
7fd43eb
remove function reference for function that no longer exists
alvarezmelissa87 Jun 24, 2025
253730d
ensure data is always defined
alvarezmelissa87 Jun 24, 2025
f19094a
update jest tests
alvarezmelissa87 Jun 24, 2025
6a18001
Merge branch 'main' into ml-inference-endpoints-remove-allocations-fi…
elasticmachine Jun 24, 2025
2c9edf2
use props instead of custom css in text component
alvarezmelissa87 Jun 25, 2025
a47f4c4
ensure values show correctly on edit
alvarezmelissa87 Jun 25, 2025
1e4dd5a
change to isServerless. data manipulation to serializer/deserializer.…
alvarezmelissa87 Jun 26, 2025
82c3ef5
fix types
alvarezmelissa87 Jun 27, 2025
670417b
remove unused prop
alvarezmelissa87 Jun 27, 2025
df866a8
Merge branch 'main' into ml-inference-endpoints-remove-allocations-fi…
elasticmachine Jun 27, 2025
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 @@ -34,7 +34,7 @@ import { FormattedMessage } from '@kbn/i18n-react';
import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers';
import { ConfigurationFormItems } from './configuration/configuration_form_items';
import * as LABELS from '../translations';
import { DEFAULT_TASK_TYPE } from '../constants';
import { DEFAULT_TASK_TYPE, internalProviderKeys } from '../constants';
import { Config, ConfigEntryView } from '../types/types';
import { TaskTypeOption } from '../utils/helpers';

Expand Down Expand Up @@ -183,26 +183,25 @@ export const AdditionalOptionsFields: React.FC<AdditionalOptionsFieldsProps> = (
<EuiPanel hasBorder={true}>
{optionalProviderFormFields.length > 0 ? (
<>
<EuiTitle size="xxs" data-test-subj="provider-optional-settings-label">
<h4>
<FormattedMessage
id="xpack.inferenceEndpointUICommon.components.additionalInfo.providerOptionalSettingsLabel"
defaultMessage="Service settings"
/>
</h4>
</EuiTitle>
<EuiText
css={css`
font-size: ${xsFontSize};
color: ${euiTheme.colors.textSubdued};
`}
>
<FormattedMessage
id="xpack.inferenceEndpointUICommon.components.additionalInfo.providerOptionalSettingsHelpLabel"
defaultMessage="Configure the inference provider. These settings are optional provider settings."
/>
</EuiText>
<EuiSpacer size="m" />
{internalProviderKeys.includes(config.provider) ? null : (
<>
<EuiTitle size="xxs" data-test-subj="provider-optional-settings-label">
<h4>
<FormattedMessage
id="xpack.inferenceEndpointUICommon.components.additionalInfo.providerOptionalSettingsLabel"
defaultMessage="Service settings"
/>
</h4>
</EuiTitle>
<EuiText color="subdued" size="xs">
<FormattedMessage
id="xpack.inferenceEndpointUICommon.components.additionalInfo.providerOptionalSettingsHelpLabel"
defaultMessage="Configure the inference provider. These settings are optional provider settings."
/>
</EuiText>
<EuiSpacer size="m" />
</>
)}
<ConfigurationFormItems
isLoading={false}
direction="column"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* 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, { FC, useState } from 'react';
import {
EuiButtonIcon,
EuiFlexGroup,
EuiFlexItem,
EuiPopover,
EuiPopoverTitle,
EuiSpacer,
EuiTitle,
EuiText,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { i18n } from '@kbn/i18n';

export const AdaptiveAllocationsTitle: FC = () => {
const [isPopoverOpen, setIsPopoverOpen] = useState(false);

return (
<>
<EuiFlexGroup alignItems="center" gutterSize="none">
<EuiFlexItem grow={false}>
<EuiTitle size="xxs" data-test-subj="maxNumberOfAllocationsDetailsLabel">
<h5>
<FormattedMessage
id="xpack.inferenceEndpointUICommon.components.adaptiveResourcesTitle"
defaultMessage="Adaptive resources"
/>
</h5>
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiPopover
anchorPosition="upCenter"
button={
<EuiButtonIcon
color="text"
size="xs"
onClick={() => setIsPopoverOpen(!isPopoverOpen)}
iconType="info"
aria-label={i18n.translate(
'xpack.inferenceEndpointUICommon.components.adaptiveResourcesAriaLabel',
{
defaultMessage: 'Open adaptive resources information popover',
}
)}
/>
}
isOpen={isPopoverOpen}
closePopover={() => setIsPopoverOpen(false)}
>
<EuiPopoverTitle>
<FormattedMessage
id="xpack.inferenceEndpointUICommon.components.sectionPopoverTitle"
defaultMessage="Adaptive resources"
/>
</EuiPopoverTitle>
<div style={{ width: '300px' }}>
Comment thread
darnautov marked this conversation as resolved.
<EuiText size="s">
<p>
<FormattedMessage
id="xpack.inferenceEndpointUICommon.components.sectionPopoverFirstParagraph"
defaultMessage="The number of allocations scales automatically, based on load. Resources scale up when the load increases and scale down when the load decreases. We scale down to 0 <bold>after 24 hours of no inference calls</bold> to the endpoint to <bold>optimize cost and performance</bold>."
values={{
bold: (str) => <strong>{str}</strong>,
}}
/>
</p>
<p>
<FormattedMessage
id="xpack.inferenceEndpointUICommon.components.sectionPopoverSecondParagraph"
defaultMessage="Subsequent inference calls may return errors for a few second, until resources are available again to service inference requests."
/>
</p>
<p>
<FormattedMessage
id="xpack.inferenceEndpointUICommon.components.sectionPopoverThirdParagraph"
defaultMessage="You can optionally set the maximum number of allocations. Autoscaling will occur dynamically between zero and maximum available or the user set maximum."
/>
</p>
</EuiText>
</div>
</EuiPopover>
</EuiFlexItem>
</EuiFlexGroup>
<EuiText color="subdued" size="xs">
<FormattedMessage
id="xpack.inferenceEndpointUICommon.components.adaptiveResourcesDescription"
defaultMessage="The number of allocations scales automatically, based on load."
/>
</EuiText>
<EuiSpacer size="m" />
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
EuiAccordion,
EuiFieldText,
EuiFieldPassword,
EuiFormControlLayout,
EuiSwitch,
EuiTextArea,
EuiFieldNumber,
Expand Down Expand Up @@ -127,18 +128,29 @@ export const ConfigNumberField: React.FC<ConfigInputFieldProps> = ({
setInnerValue(!value || value.toString().length === 0 ? defaultValue : value);
}, [defaultValue, value]);
return (
<EuiFieldNumber
<EuiFormControlLayout
fullWidth
disabled={isLoading || (isEdit && !updatable) || isPreconfigured}
data-test-subj={`${key}-number`}
value={innerValue as number}
isInvalid={!isValid}
onChange={(event) => {
const newValue = isEmpty(event.target.value) ? '0' : event.target.value;
setInnerValue(newValue);
validateAndSetConfigValue(newValue);
clear={{
onClick: (e) => {
validateAndSetConfigValue('');
setInnerValue('');
},
}}
/>
>
<EuiFieldNumber
min={0}
fullWidth
disabled={isLoading || (isEdit && !updatable) || isPreconfigured}
data-test-subj={`${key}-number`}
value={innerValue as number}
isInvalid={!isValid}
onChange={(event) => {
const newValue = isEmpty(event.target.value) ? '0' : event.target.value;
setInnerValue(newValue);
validateAndSetConfigValue(newValue);
}}
/>
</EuiFormControlLayout>
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {

import { ConfigEntryView } from '../../types/types';
import { ConfigurationField } from './configuration_field';
import { ConfigFieldTitularComponent } from './titular_component_registry';
import * as LABELS from '../../translations';

interface ConfigurationFormItemsProps {
Expand Down Expand Up @@ -81,6 +82,7 @@ export const ConfigurationFormItems: React.FC<ConfigurationFormItemsProps> = ({

return (
<EuiFlexItem key={key}>
<ConfigFieldTitularComponent configKey={key} />
<EuiFormRow
label={rowLabel}
fullWidth
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* 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, { FC } from 'react';
import { MAX_NUMBER_OF_ALLOCATIONS } from '../../constants';
import { AdaptiveAllocationsTitle } from './adaptive_allocations_title';

const titularComponents: Record<string, FC> = {
[MAX_NUMBER_OF_ALLOCATIONS]: AdaptiveAllocationsTitle,
};

export const ConfigFieldTitularComponent = ({ configKey }: { configKey: string }) => {
const Component = titularComponents[configKey];

if (!Component) {
return null;
}
return <Component /> ?? null;
Comment thread
Samiul-TheSoccerFan marked this conversation as resolved.
};
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,80 @@ import {
useGeneratedHtmlId,
} from '@elastic/eui';
import React, { useCallback } from 'react';

import { HttpSetup, IToasts } from '@kbn/core/public';
import { Form, useForm } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
import * as LABELS from '../translations';
import type { InferenceEndpoint } from '../types/types';
import { InferenceServiceFormFields } from './inference_service_form_fields';
import { useInferenceEndpointMutation } from '../hooks/use_inference_endpoint_mutation';

const MIN_ALLOCATIONS = 0;
const DEFAULT_NUM_THREADS = 1;

const formDeserializer = (data: InferenceEndpoint) => {
if (
data?.config?.providerConfig &&
data?.config?.providerConfig['adaptive_allocations.max_number_of_allocations']
) {
// remove num_allocations and num_threads from the data as form does not expect it
const {
num_allocations: numAllocations,
num_threads: numThreads,
...restOfProviderConfig
} = data.config.providerConfig;
return {
...data,
config: {
...data.config,
providerConfig: {
...restOfProviderConfig,
max_number_of_allocations:
restOfProviderConfig['adaptive_allocations.max_number_of_allocations'],
},
},
};
}

return data;
};

// This serializer is used to transform the form data before sending it to the server
const formSerializer = (formData: InferenceEndpoint) => {
if (
// explicit check to see if this field exists as it only exists in serverless
formData.config?.providerConfig?.max_number_of_allocations !== undefined
) {
const providerConfig = formData.config?.providerConfig;
const { max_number_of_allocations: maxAllocations, ...restProviderConfig } =
providerConfig || {};

return {
...formData,
config: {
...formData.config,
providerConfig: {
...restProviderConfig,
adaptive_allocations: {
enabled: true,
min_number_of_allocations: MIN_ALLOCATIONS,
...(maxAllocations ? { max_number_of_allocations: maxAllocations } : {}),
},
// Temporary solution until the endpoint is updated to no longer require it and to set its own default for this value
num_threads: DEFAULT_NUM_THREADS,
},
},
};
}

return formData;
};

interface InferenceFlyoutWrapperProps {
onFlyoutClose: () => void;
http: HttpSetup;
toasts: IToasts;
isEdit?: boolean;
enforceAdaptiveAllocations?: boolean;
onSubmitSuccess?: (inferenceId: string) => void;
inferenceEndpoint?: InferenceEndpoint;
}
Expand All @@ -41,6 +102,7 @@ export const InferenceFlyoutWrapper: React.FC<InferenceFlyoutWrapperProps> = ({
http,
toasts,
isEdit,
enforceAdaptiveAllocations = false,
onSubmitSuccess,
inferenceEndpoint,
}) => {
Expand Down Expand Up @@ -68,6 +130,8 @@ export const InferenceFlyoutWrapper: React.FC<InferenceFlyoutWrapperProps> = ({
providerSecrets: {},
},
},
serializer: formSerializer,
deserializer: formDeserializer,
});
const handleSubmit = useCallback(async () => {
const { isValid, data } = await form.submit();
Expand Down Expand Up @@ -98,6 +162,7 @@ export const InferenceFlyoutWrapper: React.FC<InferenceFlyoutWrapperProps> = ({
http={http}
toasts={toasts}
isEdit={isEdit}
enforceAdaptiveAllocations={enforceAdaptiveAllocations}
isPreconfigured={isPreconfigured}
/>
<EuiSpacer size="m" />
Expand Down
Loading