Skip to content

Commit

Permalink
[Inference AI Connector] Added elastic provider for EIS and enhanceme…
Browse files Browse the repository at this point in the history
…nts (elastic#205672)

## Summary

Current PR creates a new platform shared plugin named
`inference_endpoint` to expose in Kibana the new internal API
`_inference/_services`, which returns the list of inference providers
with the configuration settings.

Changed `@kbn/inference_endpoint_ui_common` package to fetch dynamically
the list of providers by using the route introduced in
`inference_endpoint` plugin.
Added fields settings filter based on the selected task in the
`supported_task_types`.

Cleaned up the types consolidating all in the package
`@kbn/inference_endpoint_ui_common`.
Changed .inference connector to use `unified_completion` subAction for
selected `chat_completion` task type.

---------

Co-authored-by: kibanamachine <[email protected]>
Co-authored-by: pgayvallet <[email protected]>
  • Loading branch information
3 people authored Jan 23, 2025
1 parent c6e9821 commit 7f98b6b
Show file tree
Hide file tree
Showing 41 changed files with 521 additions and 711 deletions.
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -883,6 +883,7 @@ x-pack/platform/plugins/shared/fleet @elastic/fleet
x-pack/platform/plugins/shared/global_search @elastic/appex-sharedux
x-pack/platform/plugins/shared/index_management @elastic/kibana-management
x-pack/platform/plugins/shared/inference @elastic/appex-ai-infra
x-pack/platform/plugins/shared/inference_endpoint @elastic/ml-ui
x-pack/platform/plugins/shared/ingest_pipelines @elastic/kibana-management
x-pack/platform/plugins/shared/integration_assistant @elastic/security-scalability
x-pack/platform/plugins/shared/lens @elastic/kibana-visualizations
Expand Down
4 changes: 4 additions & 0 deletions docs/developer/plugin-list.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,10 @@ Index Management by running this series of requests in Console:
external LLM APIs. Its goals are:
|{kib-repo}blob/{branch}/x-pack/platform/plugins/shared/inference_endpoint/README.md[inferenceEndpoint]
|A Kibana plugin
|{kib-repo}blob/{branch}/x-pack/solutions/observability/plugins/infra/README.md[infra]
|This is the home of the infra plugin, which aims to provide a solution for
the infrastructure monitoring use-case within Kibana.
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,7 @@
"@kbn/index-management-shared-types": "link:x-pack/platform/packages/shared/index-management/index_management_shared_types",
"@kbn/index-patterns-test-plugin": "link:test/plugin_functional/plugins/index_patterns",
"@kbn/inference-common": "link:x-pack/platform/packages/shared/ai-infra/inference-common",
"@kbn/inference-endpoint-plugin": "link:x-pack/platform/plugins/shared/inference_endpoint",
"@kbn/inference-endpoint-ui-common": "link:x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common",
"@kbn/inference-plugin": "link:x-pack/platform/plugins/shared/inference",
"@kbn/inference_integration_flyout": "link:x-pack/platform/packages/private/ml/inference_integration_flyout",
Expand Down
2 changes: 2 additions & 0 deletions tsconfig.base.json
Original file line number Diff line number Diff line change
Expand Up @@ -1062,6 +1062,8 @@
"@kbn/inference_integration_flyout/*": ["x-pack/platform/packages/private/ml/inference_integration_flyout/*"],
"@kbn/inference-common": ["x-pack/platform/packages/shared/ai-infra/inference-common"],
"@kbn/inference-common/*": ["x-pack/platform/packages/shared/ai-infra/inference-common/*"],
"@kbn/inference-endpoint-plugin": ["x-pack/platform/plugins/shared/inference_endpoint"],
"@kbn/inference-endpoint-plugin/*": ["x-pack/platform/plugins/shared/inference_endpoint/*"],
"@kbn/inference-endpoint-ui-common": ["x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common"],
"@kbn/inference-endpoint-ui-common/*": ["x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/*"],
"@kbn/inference-plugin": ["x-pack/platform/plugins/shared/inference"],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export enum InferenceConnectorType {
Inference = '.inference',
}

export const COMPLETION_TASK_TYPE = 'completion';
export const COMPLETION_TASK_TYPE = 'chat_completion';

const allSupportedConnectorTypes = Object.values(InferenceConnectorType);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 2.0.
*/

import { FieldType } from '@kbn/search-connectors/types';
import { FieldType } from '../../types/types';
import { ensureBooleanType, ensureCorrectTyping, ensureStringType } from './configuration_utils';

describe('configuration utils', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const mockProviders = [
sensitive: true,
updatable: true,
type: FieldType.STRING,
supported_task_types: ['text_embedding', 'sparse_embedding'],
},
'rate_limit.requests_per_minute': {
default_value: null,
Expand All @@ -38,6 +39,7 @@ const mockProviders = [
sensitive: false,
updatable: true,
type: FieldType.INTEGER,
supported_task_types: ['text_embedding', 'sparse_embedding'],
},
url: {
default_value: 'https://api.openai.com/v1/embeddings',
Expand All @@ -47,6 +49,7 @@ const mockProviders = [
sensitive: false,
updatable: true,
type: FieldType.STRING,
supported_task_types: ['text_embedding', 'sparse_embedding'],
},
},
},
Expand All @@ -63,6 +66,7 @@ const mockProviders = [
sensitive: true,
updatable: true,
type: FieldType.STRING,
supported_task_types: ['text_embedding', 'rerank', 'completion'],
},
'rate_limit.requests_per_minute': {
default_value: null,
Expand All @@ -72,6 +76,7 @@ const mockProviders = [
sensitive: false,
updatable: true,
type: FieldType.INTEGER,
supported_task_types: ['text_embedding', 'completion'],
},
},
},
Expand All @@ -88,6 +93,7 @@ const mockProviders = [
sensitive: true,
updatable: true,
type: FieldType.STRING,
supported_task_types: ['completion'],
},
'rate_limit.requests_per_minute': {
default_value: null,
Expand All @@ -98,6 +104,7 @@ const mockProviders = [
sensitive: false,
updatable: true,
type: FieldType.INTEGER,
supported_task_types: ['completion'],
},
model_id: {
default_value: null,
Expand All @@ -107,6 +114,7 @@ const mockProviders = [
sensitive: false,
updatable: true,
type: FieldType.STRING,
supported_task_types: ['completion'],
},
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,16 @@ 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, Secrets } from '../types/types';
import { Config, ConfigEntryView, 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';
import { TaskTypeOption, generateInferenceEndpointId, getTaskTypeOptions } from '../utils/helpers';
import {
TaskTypeOption,
generateInferenceEndpointId,
getTaskTypeOptions,
mapProviderFields,
} from '../utils/helpers';
import { ConfigurationFormItems } from './configuration/configuration_form_items';
import { AdditionalOptionsFields } from './additional_options_fields';
import { ProviderSecretHiddenField } from './hidden_fields/provider_secret_hidden_field';
Expand Down Expand Up @@ -104,22 +109,50 @@ export const InferenceServiceFormFields: React.FC<InferenceServicesProps> = ({
);

const onTaskTypeOptionsSelect = useCallback(
(taskType: string) => {
(taskType: string, providerSelected?: string) => {
setSelectedTaskType(taskType);

const inferenceId = generateInferenceEndpointId({
...config,
taskType,
});

const newProvider = providers?.find(
(p) => p.service === (config.provider === '' ? providerSelected : config.provider)
);
if (newProvider) {
const newProviderSchema: ConfigEntryView[] = mapProviderFields(taskType, newProvider);
setProviderSchema(newProviderSchema);
}

// Update config and secrets with the new set of fields + keeps the entered data for a common
const newConfig = { ...(config.providerConfig ?? {}) };
const newSecrets = { ...(secrets?.providerSecrets ?? {}) };
Object.keys(config.providerConfig ?? {}).forEach((k) => {
if (!newProvider?.configurations[k].supported_task_types.includes(taskType)) {
delete newConfig[k];
}
});
if (secrets && secrets?.providerSecrets) {
Object.keys(secrets.providerSecrets).forEach((k) => {
if (!newProvider?.configurations[k].supported_task_types.includes(taskType)) {
delete newSecrets[k];
}
});
}

updateFieldValues({
config: {
taskType,
inferenceId,
providerConfig: newConfig,
},
secrets: {
providerSecrets: newSecrets,
},
});
},
[config, updateFieldValues]
[config, providers, secrets, updateFieldValues]
);

const onProviderChange = useCallback(
Expand All @@ -128,41 +161,28 @@ export const InferenceServiceFormFields: React.FC<InferenceServicesProps> = ({

setTaskTypeOptions(getTaskTypeOptions(newProvider?.task_types ?? []));
if (newProvider?.task_types && newProvider?.task_types.length > 0) {
onTaskTypeOptionsSelect(newProvider?.task_types[0]);
onTaskTypeOptionsSelect(newProvider?.task_types[0], provider);
}

const newProviderSchema: ConfigEntryView[] = Object.keys(
newProvider?.configurations ?? {}
).map(
(k): ConfigEntryView => ({
key: k,
isValid: true,
validationErrors: [],
value: newProvider?.configurations[k].default_value ?? null,
default_value: newProvider?.configurations[k].default_value ?? null,
description: newProvider?.configurations[k].description ?? null,
label: newProvider?.configurations[k].label ?? '',
required: newProvider?.configurations[k].required ?? false,
sensitive: newProvider?.configurations[k].sensitive ?? false,
updatable: newProvider?.configurations[k].updatable ?? false,
type: newProvider?.configurations[k].type ?? FieldType.STRING,
})
);

setProviderSchema(newProviderSchema);

const defaultProviderConfig: Record<string, unknown> = {};
const defaultProviderSecrets: Record<string, unknown> = {};

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;
const newProviderSchema: ConfigEntryView[] = newProvider
? mapProviderFields(newProvider.task_types[0], newProvider)
: [];
if (newProvider) {
setProviderSchema(newProviderSchema);
}

newProviderSchema.forEach((fieldConfig) => {
if (!fieldConfig.sensitive) {
if (fieldConfig && !!fieldConfig.default_value) {
defaultProviderConfig[fieldConfig.key] = fieldConfig.default_value;
} else {
defaultProviderConfig[k] = null;
defaultProviderConfig[fieldConfig.key] = null;
}
} else {
defaultProviderSecrets[k] = null;
defaultProviderSecrets[fieldConfig.key] = null;
}
});
const inferenceId = generateInferenceEndpointId({
Expand Down Expand Up @@ -262,18 +282,19 @@ export const InferenceServiceFormFields: React.FC<InferenceServicesProps> = ({
);

useEffect(() => {
if (config?.provider && isEdit) {
if (config?.provider && config?.taskType && 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);
const newProviderSchema: ConfigEntryView[] = newProvider
? mapProviderFields(config.taskType, newProvider)
: [];
if (newProvider) {
setProviderSchema(newProviderSchema);
}
setSelectedTaskType(config.taskType);
}
}, [config?.provider, config?.taskType, isEdit, providers]);
}, [config, config?.provider, config?.taskType, isEdit, providers, selectedTaskType]);

useEffect(() => {
if (isSubmitting) {
Expand Down Expand Up @@ -304,9 +325,10 @@ export const InferenceServiceFormFields: React.FC<InferenceServicesProps> = ({
typeof configValue === 'string' ||
typeof configValue === 'number' ||
typeof configValue === 'boolean' ||
configValue === null
configValue === null ||
configValue === undefined
) {
itemValue.value = configValue;
itemValue.value = configValue ?? null;
}
}
return itemValue;
Expand All @@ -315,7 +337,7 @@ export const InferenceServiceFormFields: React.FC<InferenceServicesProps> = ({

setOptionalProviderFormFields(existingConfiguration.filter((p) => !p.required && !p.sensitive));
setRequiredProviderFormFields(existingConfiguration.filter((p) => p.required || p.sensitive));
}, [config?.providerConfig, providerSchema, secrets]);
}, [config?.providerConfig, providerSchema, secrets, selectedTaskType]);

return !isLoading ? (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ export const SERVICE_PROVIDERS: Record<ServiceProviderKeys, ServiceProviderRecor
name: 'Elasticsearch',
solutions: ['Search'],
},
[ServiceProviderKeys.elastic]: {
icon: elasticIcon,
name: 'Elastic',
solutions: ['Observability', 'Security', 'Search'],
},
[ServiceProviderKeys.googleaistudio]: {
icon: googleAIStudioIcon,
name: 'Google AI Studio',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const providers = [
sensitive: true,
updatable: true,
type: FieldType.STRING,
supported_task_types: ['text_embedding', 'sparse_embedding'],
},
'rate_limit.requests_per_minute': {
default_value: null,
Expand All @@ -33,6 +34,7 @@ const providers = [
sensitive: false,
updatable: true,
type: FieldType.INTEGER,
supported_task_types: ['text_embedding', 'sparse_embedding'],
},
url: {
default_value: 'https://api.openai.com/v1/embeddings',
Expand All @@ -42,6 +44,7 @@ const providers = [
sensitive: false,
updatable: true,
type: FieldType.STRING,
supported_task_types: ['text_embedding', 'sparse_embedding'],
},
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export enum ServiceProviderKeys {
azureaistudio = 'azureaistudio',
cohere = 'cohere',
elasticsearch = 'elasticsearch',
elastic = 'elastic',
googleaistudio = 'googleaistudio',
googlevertexai = 'googlevertexai',
hugging_face = 'hugging_face',
Expand Down
Loading

0 comments on commit 7f98b6b

Please sign in to comment.