diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index f4144cc6f2ba8..51320f55bca09 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -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 diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc index ee65cf41cc1b2..3aebfee0d2b4d 100644 --- a/docs/developer/plugin-list.asciidoc +++ b/docs/developer/plugin-list.asciidoc @@ -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. diff --git a/package.json b/package.json index baebf4f9ee630..af5b8057b76a6 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/tsconfig.base.json b/tsconfig.base.json index 2300b4e29609b..d01f6976835eb 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -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"], diff --git a/x-pack/platform/packages/shared/ai-infra/inference-common/src/connectors.ts b/x-pack/platform/packages/shared/ai-infra/inference-common/src/connectors.ts index da77d973614b5..630bfafdd1bc3 100644 --- a/x-pack/platform/packages/shared/ai-infra/inference-common/src/connectors.ts +++ b/x-pack/platform/packages/shared/ai-infra/inference-common/src/connectors.ts @@ -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); diff --git a/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/components/configuration/configuration_utils.test.ts b/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/components/configuration/configuration_utils.test.ts index 9345dcd002c32..5feda82430478 100644 --- a/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/components/configuration/configuration_utils.test.ts +++ b/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/components/configuration/configuration_utils.test.ts @@ -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', () => { 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 5c20bbecb6f1c..edf80bde790d8 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 @@ -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, @@ -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', @@ -47,6 +49,7 @@ const mockProviders = [ sensitive: false, updatable: true, type: FieldType.STRING, + supported_task_types: ['text_embedding', 'sparse_embedding'], }, }, }, @@ -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, @@ -72,6 +76,7 @@ const mockProviders = [ sensitive: false, updatable: true, type: FieldType.INTEGER, + supported_task_types: ['text_embedding', 'completion'], }, }, }, @@ -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, @@ -98,6 +104,7 @@ const mockProviders = [ sensitive: false, updatable: true, type: FieldType.INTEGER, + supported_task_types: ['completion'], }, model_id: { default_value: null, @@ -107,6 +114,7 @@ const mockProviders = [ sensitive: false, updatable: true, type: FieldType.STRING, + supported_task_types: ['completion'], }, }, }, 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 22eb4fbadc901..ef63d42522cab 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 @@ -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'; @@ -104,7 +109,7 @@ export const InferenceServiceFormFields: React.FC = ({ ); const onTaskTypeOptionsSelect = useCallback( - (taskType: string) => { + (taskType: string, providerSelected?: string) => { setSelectedTaskType(taskType); const inferenceId = generateInferenceEndpointId({ @@ -112,14 +117,42 @@ export const InferenceServiceFormFields: React.FC = ({ 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( @@ -128,41 +161,28 @@ export const InferenceServiceFormFields: React.FC = ({ 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 = {}; 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; + 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({ @@ -262,18 +282,19 @@ export const InferenceServiceFormFields: React.FC = ({ ); 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) { @@ -304,9 +325,10 @@ export const InferenceServiceFormFields: React.FC = ({ typeof configValue === 'string' || typeof configValue === 'number' || typeof configValue === 'boolean' || - configValue === null + configValue === null || + configValue === undefined ) { - itemValue.value = configValue; + itemValue.value = configValue ?? null; } } return itemValue; @@ -315,7 +337,7 @@ export const InferenceServiceFormFields: React.FC = ({ 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 ? ( <> diff --git a/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/components/providers/render_service_provider/service_provider.tsx b/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/components/providers/render_service_provider/service_provider.tsx index e50cfae1d30bc..e15fa03eaf15c 100644 --- a/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/components/providers/render_service_provider/service_provider.tsx +++ b/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/components/providers/render_service_provider/service_provider.tsx @@ -66,6 +66,11 @@ export const SERVICE_PROVIDERS: Record { - return [ - { - 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, - }, - }, - }, - { - 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: '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: '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: '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: '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: '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: '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: '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: '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: '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: '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, - }, - }, - }, - ]; +export const getProviders = async (http: HttpSetup): Promise => { + return await http.get(`/internal/_inference/_services`, { + version: INFERENCE_ENDPOINT_INTERNAL_API_VERSION, + }); }; export const useProviders = (http: HttpSetup, toasts: IToasts) => { diff --git a/x-pack/platform/plugins/shared/stack_connectors/common/dynamic_config/types.ts b/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/types/dynamic_config/types.ts similarity index 97% rename from x-pack/platform/plugins/shared/stack_connectors/common/dynamic_config/types.ts rename to x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/types/dynamic_config/types.ts index b5c73958294e1..66f72a5944a92 100644 --- a/x-pack/platform/plugins/shared/stack_connectors/common/dynamic_config/types.ts +++ b/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/types/dynamic_config/types.ts @@ -41,6 +41,7 @@ export interface ConfigProperties { sensitive: boolean; updatable: boolean; type: FieldType; + supported_task_types: string[]; } interface ConfigEntry extends ConfigProperties { diff --git a/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/types/types.ts b/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/types/types.ts index fc1f32b668811..7e9533cf047dc 100644 --- a/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/types/types.ts +++ b/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/types/types.ts @@ -4,24 +4,15 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { FieldType } from '@kbn/search-connectors'; - -export { FieldType } from '@kbn/search-connectors'; - -export interface ConfigProperties { - default_value: string | number | boolean | null; - description: string | null; - label: string; - required: boolean; - sensitive: boolean; - updatable: boolean; - type: FieldType; -} + +import { ConfigProperties } from './dynamic_config/types'; interface ConfigEntry extends ConfigProperties { key: string; } +export * from './dynamic_config/types'; + export interface ConfigEntryView extends ConfigEntry { isValid: boolean; validationErrors: string[]; @@ -30,6 +21,18 @@ export interface ConfigEntryView extends ConfigEntry { export type FieldsConfiguration = Record; +export interface Config { + taskType: string; + taskTypeConfig?: Record; + inferenceId: string; + provider: string; + providerConfig?: Record; +} + +export interface Secrets { + providerSecrets?: Record; +} + export interface InferenceProvider { service: string; name: string; @@ -37,7 +40,6 @@ export interface InferenceProvider { logo?: string; configurations: FieldsConfiguration; } - export interface Config { taskType: string; taskTypeConfig?: Record; @@ -49,3 +51,5 @@ export interface Config { export interface Secrets { providerSecrets?: Record; } + +export const INFERENCE_ENDPOINT_INTERNAL_API_VERSION = '1'; diff --git a/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/utils/helpers.ts b/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/utils/helpers.ts index 168d2fe37faa0..ae997a9c50759 100644 --- a/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/utils/helpers.ts +++ b/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/src/utils/helpers.ts @@ -7,7 +7,7 @@ import { ValidationFunc } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; import { isEmpty } from 'lodash/fp'; -import { Config, ConfigEntryView } from '../types/types'; +import { Config, ConfigEntryView, FieldType, InferenceProvider } from '../types/types'; import * as LABELS from '../translations'; export interface TaskTypeOption { @@ -78,3 +78,29 @@ export const getNonEmptyValidator = ( } }; }; + +export const mapProviderFields = ( + taskType: string, + newProvider: InferenceProvider +): ConfigEntryView[] => { + return Object.keys(newProvider.configurations ?? {}) + .filter((pk) => + (newProvider.configurations[pk].supported_task_types ?? [taskType]).includes(taskType) + ) + .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, + supported_task_types: newProvider.configurations[k].supported_task_types ?? [], + }) + ); +}; 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 5c60ee4820e4a..4e0641f48e7f5 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 @@ -19,7 +19,6 @@ "kbn_references": [ "@kbn/i18n", "@kbn/i18n-react", - "@kbn/search-connectors", "@kbn/es-ui-shared-plugin", "@kbn/triggers-actions-ui-plugin", "@kbn/core-http-browser", diff --git a/x-pack/platform/plugins/shared/inference_endpoint/README.md b/x-pack/platform/plugins/shared/inference_endpoint/README.md new file mode 100755 index 0000000000000..d0b1b394927cb --- /dev/null +++ b/x-pack/platform/plugins/shared/inference_endpoint/README.md @@ -0,0 +1,22 @@ +# inference-endpoint + +A Kibana plugin + +--- + +## Development + +See the [kibana contributing guide](https://github.com/elastic/kibana/blob/main/CONTRIBUTING.md) for instructions setting up your development environment. + +## Scripts + +
+
yarn kbn bootstrap
+
Execute this to install node_modules and setup the dependencies in your plugin and in Kibana
+ +
yarn plugin-helpers build
+
Execute this to create a distributable version of this plugin that can be installed in Kibana
+ +
yarn plugin-helpers dev --watch
+
Execute this to build your plugin ui browser side so Kibana could pick up when started in development
+
diff --git a/x-pack/platform/plugins/shared/inference_endpoint/common/index.ts b/x-pack/platform/plugins/shared/inference_endpoint/common/index.ts new file mode 100644 index 0000000000000..6cf5a0d3492c4 --- /dev/null +++ b/x-pack/platform/plugins/shared/inference_endpoint/common/index.ts @@ -0,0 +1,11 @@ +/* + * 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. + */ + +export const PLUGIN_ID = 'inferenceEndpoint'; +export const PLUGIN_NAME = 'inference-endpoint'; + +export const INFERENCE_ENDPOINT_INTERNAL_API_VERSION = '1'; diff --git a/x-pack/platform/plugins/shared/inference_endpoint/jest.config.js b/x-pack/platform/plugins/shared/inference_endpoint/jest.config.js new file mode 100644 index 0000000000000..8e115dfd25c9f --- /dev/null +++ b/x-pack/platform/plugins/shared/inference_endpoint/jest.config.js @@ -0,0 +1,22 @@ +/* + * 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. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../../..', + roots: [ + '/x-pack/platform/plugins/shared/inference_endpoint/server', + '/x-pack/platform/plugins/shared/inference_endpoint/common', + ], + setupFiles: [], + collectCoverage: true, + collectCoverageFrom: [ + '/x-pack/platform/plugins/shared/inference_endpoint/{server,common}/**/*.{js,ts,tsx}', + ], + + coverageReporters: ['html'], +}; diff --git a/x-pack/platform/plugins/shared/inference_endpoint/kibana.jsonc b/x-pack/platform/plugins/shared/inference_endpoint/kibana.jsonc new file mode 100644 index 0000000000000..2219b2e7c19c4 --- /dev/null +++ b/x-pack/platform/plugins/shared/inference_endpoint/kibana.jsonc @@ -0,0 +1,20 @@ +{ + "type": "plugin", + "id": "@kbn/inference-endpoint-plugin", + "owner": "@elastic/ml-ui", + "group": "platform", + "visibility": "shared", + "plugin": { + "id": "inferenceEndpoint", + "server": true, + "browser": false, + "configPath": ["xpack", "inference_endpoint"], + "requiredPlugins": [ + "navigation" + ], + "requiredBundles": [ + ], + "optionalPlugins": [], + "extraPublicDirs": [] + } +} diff --git a/x-pack/platform/plugins/shared/inference_endpoint/server/index.ts b/x-pack/platform/plugins/shared/inference_endpoint/server/index.ts new file mode 100644 index 0000000000000..55ac95e8f35c5 --- /dev/null +++ b/x-pack/platform/plugins/shared/inference_endpoint/server/index.ts @@ -0,0 +1,18 @@ +/* + * 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 { PluginInitializerContext } from '@kbn/core/server'; + +// This exports static code and TypeScript types, +// as well as, Kibana Platform `plugin()` initializer. + +export async function plugin(initializerContext: PluginInitializerContext) { + const { InferenceEndpointPlugin } = await import('./plugin'); + return new InferenceEndpointPlugin(initializerContext); +} + +export type { InferenceEndpointPluginSetup, InferenceEndpointPluginStart } from './types'; diff --git a/x-pack/platform/plugins/shared/inference_endpoint/server/plugin.ts b/x-pack/platform/plugins/shared/inference_endpoint/server/plugin.ts new file mode 100644 index 0000000000000..5b70075d04c29 --- /dev/null +++ b/x-pack/platform/plugins/shared/inference_endpoint/server/plugin.ts @@ -0,0 +1,44 @@ +/* + * 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 { + PluginInitializerContext, + CoreSetup, + CoreStart, + Plugin, + Logger, +} from '@kbn/core/server'; + +import type { InferenceEndpointPluginSetup, InferenceEndpointPluginStart } from './types'; +import { getInferenceServicesRoute } from './routes'; + +export class InferenceEndpointPlugin + implements Plugin +{ + private readonly logger: Logger; + + constructor(initializerContext: PluginInitializerContext) { + this.logger = initializerContext.logger.get(); + } + + public setup(core: CoreSetup) { + this.logger.debug('inference-endpoint: Setup'); + const router = core.http.createRouter(); + + // Register server side APIs + getInferenceServicesRoute(router, this.logger); + + return {}; + } + + public start(core: CoreStart) { + this.logger.debug('inference-endpoint: Started'); + return {}; + } + + public stop() {} +} diff --git a/x-pack/platform/plugins/shared/inference_endpoint/server/routes/index.ts b/x-pack/platform/plugins/shared/inference_endpoint/server/routes/index.ts new file mode 100644 index 0000000000000..ea0703834565d --- /dev/null +++ b/x-pack/platform/plugins/shared/inference_endpoint/server/routes/index.ts @@ -0,0 +1,52 @@ +/* + * 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 { IKibanaResponse, IRouter, RequestHandlerContext } from '@kbn/core/server'; +import { Logger } from '@kbn/logging'; +import { InferenceServicesGetResponse } from '../types'; +import { INFERENCE_ENDPOINT_INTERNAL_API_VERSION } from '../../common'; + +export const getInferenceServicesRoute = ( + router: IRouter, + logger: Logger +) => { + router.versioned + .get({ + access: 'internal', + path: '/internal/_inference/_services', + }) + .addVersion( + { + version: INFERENCE_ENDPOINT_INTERNAL_API_VERSION, + validate: {}, + }, + async ( + context, + request, + response + ): Promise> => { + try { + const esClient = (await context.core).elasticsearch.client.asInternalUser; + + const result = await esClient.transport.request({ + method: 'GET', + path: `/_inference/_services`, + }); + + return response.ok({ + body: result, + }); + } catch (err) { + logger.error(err); + return response.customError({ + body: { message: err.message }, + statusCode: err.statusCode, + }); + } + } + ); +}; diff --git a/x-pack/platform/plugins/shared/inference_endpoint/server/types.ts b/x-pack/platform/plugins/shared/inference_endpoint/server/types.ts new file mode 100644 index 0000000000000..d9b514757cc2b --- /dev/null +++ b/x-pack/platform/plugins/shared/inference_endpoint/server/types.ts @@ -0,0 +1,16 @@ +/* + * 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 { InferenceProvider } from '@kbn/inference-endpoint-ui-common'; + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface InferenceEndpointPluginSetup {} +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface InferenceEndpointPluginStart {} + +export interface InferenceServicesGetResponse { + endpoints: InferenceProvider[]; +} diff --git a/x-pack/platform/plugins/shared/inference_endpoint/tsconfig.json b/x-pack/platform/plugins/shared/inference_endpoint/tsconfig.json new file mode 100644 index 0000000000000..b7e56bd3d83f6 --- /dev/null +++ b/x-pack/platform/plugins/shared/inference_endpoint/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "../../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + }, + "include": [ + "__mocks__/**/*", + "common/**/*", + "public/**/*", + "server/**/*" + ], + "exclude": [ + "target/**/*", + ".storybook/**/*.js" + ], + "kbn_references": [ + "@kbn/core", + "@kbn/logging", + "@kbn/inference-endpoint-ui-common", + ] +} diff --git a/x-pack/platform/plugins/shared/stack_connectors/common/inference/constants.ts b/x-pack/platform/plugins/shared/stack_connectors/common/inference/constants.ts index c2f2e6713270b..1bafb17e77dab 100644 --- a/x-pack/platform/plugins/shared/stack_connectors/common/inference/constants.ts +++ b/x-pack/platform/plugins/shared/stack_connectors/common/inference/constants.ts @@ -28,6 +28,7 @@ export enum ServiceProviderKeys { anthropic = 'anthropic', watsonxai = 'watsonxai', 'alibabacloud-ai-search' = 'alibabacloud-ai-search', + elastic = 'elastic', } export const INFERENCE_CONNECTOR_ID = '.inference'; diff --git a/x-pack/platform/plugins/shared/stack_connectors/common/inference/types.ts b/x-pack/platform/plugins/shared/stack_connectors/common/inference/types.ts index 1593429792e07..739c6f5285d50 100644 --- a/x-pack/platform/plugins/shared/stack_connectors/common/inference/types.ts +++ b/x-pack/platform/plugins/shared/stack_connectors/common/inference/types.ts @@ -6,6 +6,7 @@ */ import { TypeOf } from '@kbn/config-schema'; +import type { ConfigProperties } from '@kbn/inference-endpoint-ui-common'; import { ConfigSchema, SecretsSchema, @@ -23,7 +24,6 @@ import { DashboardActionParamsSchema, DashboardActionResponseSchema, } from './schema'; -import { ConfigProperties } from '../dynamic_config/types'; export type Config = TypeOf; export type Secrets = TypeOf; @@ -49,11 +49,3 @@ export type DashboardActionParams = TypeOf; export type DashboardActionResponse = TypeOf; export type FieldsConfiguration = Record; - -export interface InferenceProvider { - service: string; - name: string; - task_types: string[]; - logo?: string; - configurations: FieldsConfiguration; -} 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 88889967d1dbf..d87ea1f7901b6 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 @@ -27,6 +27,7 @@ const providersSchemas = [ sensitive: true, updatable: true, type: 'string', + supported_task_types: ['text_embedding', 'rerank', 'completion'], }, 'rate_limit.requests_per_minute': { default_value: null, @@ -36,6 +37,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'int', + supported_task_types: ['text_embedding', 'rerank', 'completion'], }, }, }, @@ -52,6 +54,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'int', + supported_task_types: ['sparse_embedding'], }, model_id: { default_value: null, @@ -61,6 +64,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'string', + supported_task_types: ['sparse_embedding'], }, max_input_tokens: { default_value: null, @@ -70,6 +74,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'int', + supported_task_types: ['sparse_embedding'], }, }, }, @@ -86,6 +91,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'string', + supported_task_types: ['text_embedding'], }, model_id: { default_value: null, @@ -95,6 +101,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'string', + supported_task_types: ['text_embedding'], }, api_version: { default_value: null, @@ -104,6 +111,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'string', + supported_task_types: ['text_embedding'], }, max_input_tokens: { default_value: null, @@ -113,6 +121,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'int', + supported_task_types: ['text_embedding'], }, url: { default_value: null, @@ -122,6 +131,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'string', + supported_task_types: ['text_embedding'], }, }, }, @@ -138,6 +148,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'string', + supported_task_types: ['text_embedding', 'completion'], }, provider: { default_value: null, @@ -147,6 +158,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'string', + supported_task_types: ['text_embedding', 'completion'], }, api_key: { default_value: null, @@ -156,6 +168,7 @@ const providersSchemas = [ sensitive: true, updatable: true, type: 'string', + supported_task_types: ['text_embedding', 'completion'], }, 'rate_limit.requests_per_minute': { default_value: null, @@ -165,6 +178,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'int', + supported_task_types: ['text_embedding', 'completion'], }, target: { default_value: null, @@ -174,6 +188,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'string', + supported_task_types: ['text_embedding', 'completion'], }, }, }, @@ -190,6 +205,7 @@ const providersSchemas = [ sensitive: true, updatable: true, type: 'string', + supported_task_types: ['text_embedding', 'sparse_embedding'], }, 'rate_limit.requests_per_minute': { default_value: null, @@ -199,6 +215,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'int', + supported_task_types: ['text_embedding', 'sparse_embedding'], }, url: { default_value: 'https://api.openai.com/v1/embeddings', @@ -208,6 +225,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'string', + supported_task_types: ['text_embedding', 'sparse_embedding'], }, }, }, @@ -224,6 +242,7 @@ const providersSchemas = [ sensitive: true, updatable: true, type: 'string', + supported_task_types: ['text_embedding', 'completion'], }, provider: { default_value: null, @@ -233,6 +252,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'string', + supported_task_types: ['text_embedding', 'completion'], }, access_key: { default_value: null, @@ -242,6 +262,7 @@ const providersSchemas = [ sensitive: true, updatable: true, type: 'string', + supported_task_types: ['text_embedding', 'completion'], }, model: { default_value: null, @@ -251,6 +272,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'string', + supported_task_types: ['text_embedding', 'completion'], }, 'rate_limit.requests_per_minute': { default_value: null, @@ -261,6 +283,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'int', + supported_task_types: ['text_embedding', 'completion'], }, region: { default_value: null, @@ -270,6 +293,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'string', + supported_task_types: ['text_embedding', 'completion'], }, }, }, @@ -286,6 +310,7 @@ const providersSchemas = [ sensitive: true, updatable: true, type: 'string', + supported_task_types: ['completion'], }, 'rate_limit.requests_per_minute': { default_value: null, @@ -296,6 +321,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'int', + supported_task_types: ['completion'], }, model_id: { default_value: null, @@ -305,6 +331,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'string', + supported_task_types: ['completion'], }, }, }, @@ -321,6 +348,7 @@ const providersSchemas = [ sensitive: true, updatable: true, type: 'string', + supported_task_types: ['text_embedding', 'completion'], }, 'rate_limit.requests_per_minute': { default_value: null, @@ -330,6 +358,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'int', + supported_task_types: ['text_embedding', 'completion'], }, model_id: { default_value: null, @@ -339,6 +368,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'string', + supported_task_types: ['text_embedding', 'completion'], }, }, }, @@ -356,6 +386,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'int', + supported_task_types: ['text_embedding', 'sparse_embedding', 'rerank'], }, num_threads: { default_value: 2, @@ -365,6 +396,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'int', + supported_task_types: ['text_embedding', 'sparse_embedding', 'rerank'], }, model_id: { default_value: '.multilingual-e5-small', @@ -374,6 +406,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'string', + supported_task_types: ['text_embedding', 'sparse_embedding', 'rerank'], }, }, }, @@ -391,6 +424,7 @@ const providersSchemas = [ sensitive: true, updatable: true, type: 'string', + supported_task_types: ['text_embedding', 'completion'], }, organization_id: { default_value: null, @@ -400,6 +434,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'string', + supported_task_types: ['text_embedding', 'completion'], }, 'rate_limit.requests_per_minute': { default_value: null, @@ -410,6 +445,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'int', + supported_task_types: ['text_embedding', 'completion'], }, model_id: { default_value: null, @@ -419,6 +455,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'string', + supported_task_types: ['text_embedding', 'completion'], }, url: { default_value: 'https://api.openai.com/v1/chat/completions', @@ -429,6 +466,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'string', + supported_task_types: ['text_embedding', 'completion'], }, }, }, @@ -445,6 +483,7 @@ const providersSchemas = [ sensitive: true, updatable: true, type: 'string', + supported_task_types: ['text_embedding', 'completion'], }, entra_id: { default_value: null, @@ -454,6 +493,7 @@ const providersSchemas = [ sensitive: true, updatable: true, type: 'string', + supported_task_types: ['text_embedding', 'completion'], }, 'rate_limit.requests_per_minute': { default_value: null, @@ -464,6 +504,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'int', + supported_task_types: ['text_embedding', 'completion'], }, deployment_id: { default_value: null, @@ -473,6 +514,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'string', + supported_task_types: ['text_embedding', 'completion'], }, resource_name: { default_value: null, @@ -482,6 +524,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'string', + supported_task_types: ['text_embedding', 'completion'], }, api_version: { default_value: null, @@ -491,6 +534,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'string', + supported_task_types: ['text_embedding', 'completion'], }, }, }, @@ -507,6 +551,7 @@ const providersSchemas = [ sensitive: true, updatable: true, type: 'string', + supported_task_types: ['text_embedding'], }, model: { default_value: null, @@ -517,6 +562,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'string', + supported_task_types: ['text_embedding'], }, 'rate_limit.requests_per_minute': { default_value: null, @@ -526,6 +572,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'int', + supported_task_types: ['text_embedding'], }, max_input_tokens: { default_value: null, @@ -535,6 +582,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'int', + supported_task_types: ['text_embedding'], }, }, }, @@ -551,6 +599,7 @@ const providersSchemas = [ sensitive: true, updatable: true, type: 'string', + supported_task_types: ['text_embedding', 'rerank'], }, project_id: { default_value: null, @@ -561,6 +610,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'string', + supported_task_types: ['text_embedding', 'rerank'], }, location: { default_value: null, @@ -571,6 +621,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'string', + supported_task_types: ['text_embedding', 'rerank'], }, 'rate_limit.requests_per_minute': { default_value: null, @@ -580,6 +631,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'int', + supported_task_types: ['text_embedding', 'rerank'], }, model_id: { default_value: null, @@ -589,6 +641,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'string', + supported_task_types: ['text_embedding', 'rerank'], }, }, }, @@ -605,6 +658,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'string', + supported_task_types: ['text_embedding', 'sparse_embedding', 'rerank', 'completion'], }, api_key: { default_value: null, @@ -614,6 +668,7 @@ const providersSchemas = [ sensitive: true, updatable: true, type: 'string', + supported_task_types: ['text_embedding', 'sparse_embedding', 'rerank', 'completion'], }, service_id: { default_value: null, @@ -623,6 +678,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'string', + supported_task_types: ['text_embedding', 'sparse_embedding', 'rerank', 'completion'], }, host: { default_value: null, @@ -633,6 +689,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'string', + supported_task_types: ['text_embedding', 'sparse_embedding', 'rerank', 'completion'], }, 'rate_limit.requests_per_minute': { default_value: null, @@ -642,6 +699,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'int', + supported_task_types: ['text_embedding', 'sparse_embedding', 'rerank', 'completion'], }, http_schema: { default_value: null, @@ -651,6 +709,7 @@ const providersSchemas = [ sensitive: false, updatable: true, type: 'string', + supported_task_types: ['text_embedding', 'sparse_embedding', 'rerank', 'completion'], }, }, }, diff --git a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/helpers.ts b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/helpers.ts index d3f324b55363a..40006cb913be4 100644 --- a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/helpers.ts +++ b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/helpers.ts @@ -7,7 +7,7 @@ import { isEmpty } from 'lodash/fp'; import { ValidationFunc } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; -import { ConfigEntryView } from '../../../common/dynamic_config/types'; +import { ConfigEntryView } from '@kbn/inference-endpoint-ui-common'; import { Config } from './types'; import * as i18n from './translations'; diff --git a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/hidden_fields.tsx b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/hidden_fields.tsx index 33215f6a83689..ccb7a400aba0b 100644 --- a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/hidden_fields.tsx +++ b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/hidden_fields.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { HiddenField } from '@kbn/es-ui-shared-plugin/static/forms/components'; import { UseField } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; -import { ConfigEntryView } from '../../../common/dynamic_config/types'; +import { ConfigEntryView } from '@kbn/inference-endpoint-ui-common'; import { getNonEmptyValidator } from './helpers'; export const getProviderSecretsHiddenField = ( diff --git a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/params.test.tsx b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/params.test.tsx index ba094ec64f6bd..4e95f3d75c024 100644 --- a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/params.test.tsx +++ b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/params.test.tsx @@ -21,7 +21,7 @@ describe('Inference Params Fields renders', () => { actionConnector={{ actionTypeId: '.inference', config: { - taskType: 'completion', + taskType: 'chat_completion', }, id: 'test', isPreconfigured: false, @@ -80,19 +80,10 @@ describe('Inference Params Fields renders', () => { ); expect(editAction).toHaveBeenCalledTimes(2); if (provider === 'openai') { - expect(editAction).toHaveBeenCalledWith('subAction', SUB_ACTION.UNIFIED_COMPLETION, 0); + expect(editAction).toHaveBeenCalledWith('subAction', SUB_ACTION.COMPLETION, 0); expect(editAction).toHaveBeenCalledWith( 'subActionParams', - { - body: { - messages: [ - { - content: 'Hello world', - role: 'user', - }, - ], - }, - }, + { input: 'What is Elastic?' }, 0 ); } diff --git a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/params.tsx b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/params.tsx index be162e70493bc..463254fbea2f2 100644 --- a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/params.tsx +++ b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference/params.tsx @@ -36,9 +36,7 @@ const InferenceServiceParamsFields: React.FunctionComponent< if (!subAction) { editAction( 'subAction', - provider === 'openai' && taskType === 'completion' - ? SUB_ACTION.UNIFIED_COMPLETION - : taskType, + taskType === 'chat_completion' ? SUB_ACTION.UNIFIED_COMPLETION : taskType, index ); } @@ -50,9 +48,7 @@ const InferenceServiceParamsFields: React.FunctionComponent< 'subActionParams', { ...(DEFAULTS_BY_TASK_TYPE[ - provider === 'openai' && taskType === 'completion' - ? SUB_ACTION.UNIFIED_COMPLETION - : taskType + taskType === 'chat_completion' ? SUB_ACTION.UNIFIED_COMPLETION : taskType ] ?? {}), }, index diff --git a/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/inference/index.ts b/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/inference/index.ts index 5af6773d15fe9..d781cd6b90891 100644 --- a/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/inference/index.ts +++ b/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/inference/index.ts @@ -161,8 +161,16 @@ export const configValidator = (configObject: Config, validatorServices: Validat ); } + if (taskType === 'chat_completion' && !Object.keys(SUB_ACTION).includes('UNIFIED_COMPLETION')) { + throw new Error( + `Task type is not supported${ + taskType && taskType.length ? `: ${taskType}` : `` + } by Inference Endpoint.` + ); + } + if ( - !taskType.includes('completion') && + taskType !== 'chat_completion' && !Object.keys(SUB_ACTION).includes(taskType.toUpperCase()) ) { throw new Error( diff --git a/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/inference/inference.test.ts b/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/inference/inference.test.ts index e8ebf3a5cfaa3..d032c56773e32 100644 --- a/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/inference/inference.test.ts +++ b/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/inference/inference.test.ts @@ -59,7 +59,7 @@ describe('InferenceConnector', () => { services, }); - it('uses the completion task_type is supplied', async () => { + it('uses the chat_completion task_type is supplied', async () => { mockEsClient.transport.request.mockResolvedValue({ body: Readable.from([ `data: {"id":"chatcmpl-AbLKRuRMZCAcMMQdl96KMTUgAfZNg","choices":[{"delta":{"content":" you"},"index":0}],"model":"gpt-4o-2024-08-06","object":"chat.completion.chunk"}\n\n`, @@ -84,7 +84,7 @@ describe('InferenceConnector', () => { n: undefined, }, method: 'POST', - path: '_inference/completion/test/_unified', + path: '_inference/chat_completion/test/_unified', }, { asStream: true, meta: true } ); @@ -287,7 +287,7 @@ describe('InferenceConnector', () => { n: undefined, }, method: 'POST', - path: '_inference/completion/test/_unified', + path: '_inference/chat_completion/test/_unified', }, { asStream: true, meta: true } ); @@ -309,7 +309,7 @@ describe('InferenceConnector', () => { { body: { messages: [{ content: 'Hello world', role: 'user' }], n: undefined }, method: 'POST', - path: '_inference/completion/test/_unified', + path: '_inference/chat_completion/test/_unified', }, { asStream: true, meta: true, signal } ); diff --git a/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/inference/inference.ts b/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/inference/inference.ts index 5bb52a3160a45..0dd637cfa0895 100644 --- a/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/inference/inference.ts +++ b/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/inference/inference.ts @@ -187,7 +187,7 @@ export class InferenceConnector extends SubActionConnector { const response = await this.esClient.transport.request( { method: 'POST', - path: `_inference/completion/${this.inferenceId}/_unified`, + path: `_inference/chat_completion/${this.inferenceId}/_unified`, body: { ...params.body, n: undefined }, // exclude n param for now, constant is used on the inference API side }, { @@ -196,7 +196,6 @@ export class InferenceConnector extends SubActionConnector { signal: params.signal, } ); - // errors should be thrown as it will not be a stream response if (response.statusCode >= 400) { const error = await streamToString(response.body as unknown as Readable); diff --git a/x-pack/solutions/search/plugins/search_inference_endpoints/public/components/all_inference_endpoints/render_table_columns/render_service_provider/service_provider.tsx b/x-pack/solutions/search/plugins/search_inference_endpoints/public/components/all_inference_endpoints/render_table_columns/render_service_provider/service_provider.tsx index 74f15f22762f1..60be14246d522 100644 --- a/x-pack/solutions/search/plugins/search_inference_endpoints/public/components/all_inference_endpoints/render_table_columns/render_service_provider/service_provider.tsx +++ b/x-pack/solutions/search/plugins/search_inference_endpoints/public/components/all_inference_endpoints/render_table_columns/render_service_provider/service_provider.tsx @@ -59,6 +59,10 @@ export const SERVICE_PROVIDERS: Record { id: '6', actionTypeId: '.inference', isMissingSecrets: false, - config: { provider: 'openai', taskType: 'completion' }, + config: { provider: 'openai', taskType: 'chat_completion' }, }, ]; mockedLoadConnectors.mockResolvedValue(connectors); @@ -130,7 +130,7 @@ describe('useLoadConnectors', () => { actionTypeId: '.inference', config: { provider: 'openai', - taskType: 'completion', + taskType: 'chat_completion', }, id: '6', isMissingSecrets: false, diff --git a/yarn.lock b/yarn.lock index bd3b8a4330a62..54bbea3150e3e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5974,6 +5974,10 @@ version "0.0.0" uid "" +"@kbn/inference-endpoint-plugin@link:x-pack/platform/plugins/shared/inference_endpoint": + version "0.0.0" + uid "" + "@kbn/inference-endpoint-ui-common@link:x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common": version "0.0.0" uid ""