Skip to content

Commit

Permalink
[Security Solution] Fixes Preconfigured Connectors not working with A…
Browse files Browse the repository at this point in the history
…ssistant (elastic#164900)

## Summary

Fixes Preconfigured Connectors not working with the Assistant, and also
ensures default `model` from connector will be used first if available
(instead of defaulting to `gpt-3.5-turbo`).

<p align="center">
<img width="500"
src="https://github.com/elastic/kibana/assets/2946766/637f5919-7560-40b0-a8db-681096e77ac0"
/>
</p> 

Note how `Model` is not displayed even though this is an OpenAI
connector:
<p align="center">
<img width="500"
src="https://github.com/elastic/kibana/assets/2946766/2c4bbe91-2851-48d7-8bfe-20e07db52155"
/>
</p> 

Additionally, resolves issue with Detection Rule Assistant CTA not
displaying correctly on some platforms/browsers. It now shows as a
`Chat` button to the right of the table tabs, matching the other
assistant CTA's throughout the application.

<p align="center">
<img width="500"
src="https://github.com/elastic/kibana/assets/2946766/9fcecd54-8e1a-423a-be05-7137632acbc4"
/>
</p> 

And lastly removes `Beta` title from callout since we're going GA in
`8.10` 🎉

<p align="center">
<img width="500"
src="https://github.com/elastic/kibana/assets/2946766/5beb379a-1bc7-4afc-b4bc-09f1d6085211"
/>
</p> 

Resolves:
elastic#163394 (comment)
Resolves: elastic#164819


### Checklist

Delete any items that are not applicable to this PR.

- [X] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)
- [ ]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
  • Loading branch information
spong authored Aug 28, 2023
1 parent 3835392 commit 5f9651e
Show file tree
Hide file tree
Showing 12 changed files with 157 additions and 176 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export const AssistantTitle: React.FC<{
const content = useMemo(
() => (
<FormattedMessage
defaultMessage="The Elastic AI Assistant is currently in beta. For more information on the assistant feature and its usage, please reference the {documentationLink}."
defaultMessage="Responses from AI systems may not always be entirely accurate. For more information on the assistant feature and its usage, please reference the {documentationLink}."
id="xpack.elasticAssistant.assistant.technicalPreview.tooltipContent"
values={{
documentationLink,
Expand Down Expand Up @@ -99,7 +99,6 @@ export const AssistantTitle: React.FC<{
anchorPosition="rightUp"
>
<EuiText data-test-subj="tooltipContent" grow={false} css={{ maxWidth: '400px' }}>
<h4>{i18n.TOOLTIP_TITLE}</h4>
<EuiText size={'s'}>
<p>{content}</p>
</EuiText>
Expand All @@ -112,7 +111,6 @@ export const AssistantTitle: React.FC<{
<ConnectorSelectorInline
isDisabled={isDisabled || selectedConversation === undefined}
onConnectorModalVisibilityChange={() => {}}
onConnectorSelectionChange={() => {}}
selectedConnectorId={selectedConnectorId}
selectedConversation={selectedConversation}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import { ModelSelector } from '../../../connectorland/models/model_selector/mode
import { UseAssistantContext } from '../../../assistant_context';
import { ConversationSelectorSettings } from '../conversation_selector_settings';
import { getDefaultSystemPrompt } from '../../use_conversation/helpers';
import { useLoadConnectors } from '../../../connectorland/use_load_connectors';
import { getGenAiConfig } from '../../../connectorland/helpers';

export interface ConversationSettingsProps {
actionTypeRegistry: ActionTypeRegistryContract;
Expand Down Expand Up @@ -63,6 +65,8 @@ export const ConversationSettings: React.FC<ConversationSettingsProps> = React.m
return getDefaultSystemPrompt({ allSystemPrompts, conversation: selectedConversation });
}, [allSystemPrompts, selectedConversation]);

const { data: connectors, isSuccess: areConnectorsFetched } = useLoadConnectors({ http });

// Conversation callbacks
// When top level conversation selection changes
const onConversationSelectionChange = useCallback(
Expand Down Expand Up @@ -131,27 +135,33 @@ export const ConversationSettings: React.FC<ConversationSettingsProps> = React.m
[selectedConversation, setUpdatedConversationSettings]
);

const selectedConnectorId = useMemo(
() => selectedConversation?.apiConfig.connectorId,
[selectedConversation?.apiConfig.connectorId]
);
const selectedConnector = useMemo(() => {
const selectedConnectorId = selectedConversation?.apiConfig.connectorId;
if (areConnectorsFetched) {
return connectors?.find((c) => c.id === selectedConnectorId);
}
return undefined;
}, [areConnectorsFetched, connectors, selectedConversation?.apiConfig.connectorId]);

const selectedProvider = useMemo(
() => selectedConversation?.apiConfig.provider,
[selectedConversation?.apiConfig.provider]
);

const handleOnConnectorSelectionChange = useCallback(
(connectorId: string, provider: OpenAiProviderType) => {
(connector) => {
if (selectedConversation != null) {
const config = getGenAiConfig(connector);

setUpdatedConversationSettings((prev) => ({
...prev,
[selectedConversation.id]: {
...selectedConversation,
apiConfig: {
...selectedConversation.apiConfig,
connectorId,
provider,
connectorId: connector?.id,
provider: config?.apiProvider,
model: config?.defaultModel,
},
},
}));
Expand All @@ -160,10 +170,11 @@ export const ConversationSettings: React.FC<ConversationSettingsProps> = React.m
[selectedConversation, setUpdatedConversationSettings]
);

const selectedModel = useMemo(
() => selectedConversation?.apiConfig.model,
[selectedConversation?.apiConfig.model]
);
const selectedModel = useMemo(() => {
const connectorModel = getGenAiConfig(selectedConnector)?.defaultModel;
// Prefer conversation configuration over connector default
return selectedConversation?.apiConfig.model ?? connectorModel;
}, [selectedConnector, selectedConversation?.apiConfig.model]);

const handleOnModelSelectionChange = useCallback(
(model?: string) => {
Expand Down Expand Up @@ -244,23 +255,24 @@ export const ConversationSettings: React.FC<ConversationSettingsProps> = React.m
isDisabled={selectedConversation == null}
onConnectorModalVisibilityChange={() => {}}
onConnectorSelectionChange={handleOnConnectorSelectionChange}
selectedConnectorId={selectedConnectorId}
selectedConnectorId={selectedConnector?.id}
/>
</EuiFormRow>

{selectedProvider === OpenAiProviderType.OpenAi && (
<EuiFormRow
data-test-subj="model-field"
display="rowCompressed"
label={i18nModel.MODEL_TITLE}
helpText={i18nModel.HELP_LABEL}
>
<ModelSelector
onModelSelectionChange={handleOnModelSelectionChange}
selectedModel={selectedModel}
/>
</EuiFormRow>
)}
{selectedConnector?.isPreconfigured === false &&
selectedProvider === OpenAiProviderType.OpenAi && (
<EuiFormRow
data-test-subj="model-field"
display="rowCompressed"
label={i18nModel.MODEL_TITLE}
helpText={i18nModel.HELP_LABEL}
>
<ModelSelector
onModelSelectionChange={handleOnModelSelectionChange}
selectedModel={selectedModel}
/>
</EuiFormRow>
)}
</>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,6 @@ export const API_ERROR = i18n.translate('xpack.elasticAssistant.assistant.apiErr
'An error occurred sending your message. If the problem persists, please test the connector configuration.',
});

export const TOOLTIP_TITLE = i18n.translate(
'xpack.elasticAssistant.assistant.technicalPreview.tooltipTitle',
{
defaultMessage: 'Beta',
}
);

export const TOOLTIP_ARIA_LABEL = i18n.translate(
'xpack.elasticAssistant.documentationLinks.ariaLabel',
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,24 @@ import {
} from '@kbn/triggers-actions-ui-plugin/public';

import { HttpSetup } from '@kbn/core-http-browser';
import { ActionConnectorProps } from '@kbn/triggers-actions-ui-plugin/public/types';
import { ConnectorAddModal } from '@kbn/triggers-actions-ui-plugin/public/common/constants';
import {
GEN_AI_CONNECTOR_ID,
OpenAiProviderType,
} from '@kbn/stack-connectors-plugin/public/common';
import { GEN_AI_CONNECTOR_ID } from '@kbn/stack-connectors-plugin/public/common';
import { useLoadConnectors } from '../use_load_connectors';
import * as i18n from '../translations';
import { useLoadActionTypes } from '../use_load_action_types';
import { useAssistantContext } from '../../assistant_context';
import { getGenAiConfig } from '../helpers';

export const ADD_NEW_CONNECTOR = 'ADD_NEW_CONNECTOR';
interface Props {
actionTypeRegistry: ActionTypeRegistryContract;
http: HttpSetup;
isDisabled?: boolean;
onConnectorSelectionChange: (connectorId: string, provider: OpenAiProviderType) => void;
onConnectorSelectionChange: (connector: ActionConnector | undefined) => void;
selectedConnectorId?: string;
onConnectorModalVisibilityChange?: (isVisible: boolean) => void;
}

interface Config {
apiProvider: string;
}

export const ConnectorSelector: React.FC<Props> = React.memo(
({
actionTypeRegistry,
Expand Down Expand Up @@ -95,18 +88,19 @@ export const ConnectorSelector: React.FC<Props> = React.memo(
const connectorOptions = useMemo(() => {
return (
connectors?.map((connector) => {
const apiProvider: string | undefined = (
connector as ActionConnectorProps<Config, unknown>
)?.config?.apiProvider;
const apiProvider = getGenAiConfig(connector)?.apiProvider;
const connectorDetails = connector.isPreconfigured
? i18n.PRECONFIGURED_CONNECTOR
: apiProvider;
return {
value: connector.id,
inputDisplay: connector.name,
dropdownDisplay: (
<React.Fragment key={connector.id}>
<strong>{connector.name}</strong>
{apiProvider && (
<EuiText size="s" color="subdued">
<p>{apiProvider}</p>
{connectorDetails && (
<EuiText size="xs" color="subdued">
<p>{connectorDetails}</p>
</EuiText>
)}
</React.Fragment>
Expand Down Expand Up @@ -138,10 +132,8 @@ export const ConnectorSelector: React.FC<Props> = React.memo(
return;
}

const apiProvider = (
connectors?.find((c) => c.id === connectorId) as ActionConnectorProps<Config, unknown>
)?.config.apiProvider as OpenAiProviderType;
onConnectorSelectionChange(connectorId, apiProvider);
const connector = connectors?.find((c) => c.id === connectorId);
onConnectorSelectionChange(connector);
},
[connectors, onConnectorSelectionChange, onConnectorModalVisibilityChange]
);
Expand All @@ -162,12 +154,8 @@ export const ConnectorSelector: React.FC<Props> = React.memo(
<ConnectorAddModal
actionType={actionType}
onClose={cleanupAndCloseModal}
postSaveEventHandler={(savedAction: ActionConnector) => {
onConnectorSelectionChange(
savedAction.id,
(savedAction as ActionConnectorProps<Config, unknown>)?.config
.apiProvider as OpenAiProviderType
);
postSaveEventHandler={(connector: ActionConnector) => {
onConnectorSelectionChange(connector);
refetchConnectors?.();
cleanupAndCloseModal();
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ describe('ConnectorSelectorInline', () => {
<ConnectorSelectorInline
isDisabled={false}
onConnectorModalVisibilityChange={noop}
onConnectorSelectionChange={noop}
selectedConnectorId={undefined}
selectedConversation={undefined}
/>
Expand All @@ -85,7 +84,6 @@ describe('ConnectorSelectorInline', () => {
<ConnectorSelectorInline
isDisabled={false}
onConnectorModalVisibilityChange={noop}
onConnectorSelectionChange={noop}
selectedConnectorId={'missing-connector-id'}
selectedConversation={conversation}
/>
Expand All @@ -105,7 +103,6 @@ describe('ConnectorSelectorInline', () => {
<ConnectorSelectorInline
isDisabled={false}
onConnectorModalVisibilityChange={noop}
onConnectorSelectionChange={noop}
selectedConnectorId={mockConnectors[0].id}
selectedConversation={conversation}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import React, { useCallback, useMemo, useState } from 'react';

import { ActionConnector } from '@kbn/triggers-actions-ui-plugin/public';

import { ActionConnectorProps } from '@kbn/triggers-actions-ui-plugin/public/types';
import { ConnectorAddModal } from '@kbn/triggers-actions-ui-plugin/public/common/constants';
import {
GEN_AI_CONNECTOR_ID,
Expand All @@ -23,20 +22,16 @@ import * as i18n from '../translations';
import { useLoadActionTypes } from '../use_load_action_types';
import { useAssistantContext } from '../../assistant_context';
import { useConversation } from '../../assistant/use_conversation';
import { getGenAiConfig } from '../helpers';

export const ADD_NEW_CONNECTOR = 'ADD_NEW_CONNECTOR';
interface Props {
isDisabled?: boolean;
onConnectorSelectionChange: (connectorId: string, provider: OpenAiProviderType) => void;
selectedConnectorId?: string;
selectedConversation?: Conversation;
onConnectorModalVisibilityChange?: (isVisible: boolean) => void;
}

interface Config {
apiProvider: string;
}

const inputContainerClassName = css`
height: 32px;
Expand Down Expand Up @@ -82,7 +77,6 @@ export const ConnectorSelectorInline: React.FC<Props> = React.memo(
onConnectorModalVisibilityChange,
selectedConnectorId,
selectedConversation,
onConnectorSelectionChange,
}) => {
const [isOpen, setIsOpen] = useState<boolean>(false);
const { actionTypeRegistry, assistantAvailability, http } = useAssistantContext();
Expand Down Expand Up @@ -136,9 +130,10 @@ export const ConnectorSelectorInline: React.FC<Props> = React.memo(
const connectorOptions = useMemo(() => {
return (
connectors?.map((connector) => {
const apiProvider: string | undefined = (
connector as ActionConnectorProps<Config, unknown>
)?.config?.apiProvider;
const apiProvider = getGenAiConfig(connector)?.apiProvider;
const connectorDetails = connector.isPreconfigured
? i18n.PRECONFIGURED_CONNECTOR
: apiProvider;
return {
value: connector.id,
inputDisplay: (
Expand All @@ -149,9 +144,9 @@ export const ConnectorSelectorInline: React.FC<Props> = React.memo(
dropdownDisplay: (
<React.Fragment key={connector.id}>
<strong>{connector.name}</strong>
{apiProvider && (
{connectorDetails && (
<EuiText size="xs" color="subdued">
<p>{apiProvider}</p>
<p>{connectorDetails}</p>
</EuiText>
)}
</React.Fragment>
Expand Down Expand Up @@ -182,7 +177,7 @@ export const ConnectorSelectorInline: React.FC<Props> = React.memo(
const handleOnBlur = useCallback(() => setIsOpen(false), []);

const onChange = useCallback(
(connectorId: string, apiProvider?: OpenAiProviderType) => {
(connectorId: string, apiProvider?: OpenAiProviderType, model?: string) => {
setIsOpen(false);

if (connectorId === ADD_NEW_CONNECTOR) {
Expand All @@ -191,31 +186,22 @@ export const ConnectorSelectorInline: React.FC<Props> = React.memo(
return;
}

const provider =
apiProvider ??
((connectors?.find((c) => c.id === connectorId) as ActionConnectorProps<Config, unknown>)
?.config.apiProvider as OpenAiProviderType);

const connector = connectors?.find((c) => c.id === connectorId);
const config = getGenAiConfig(connector);
if (selectedConversation != null) {
setApiConfig({
conversationId: selectedConversation.id,
apiConfig: {
...selectedConversation.apiConfig,
connectorId,
provider,
// With the inline component, prefer config args to handle 'new connector' case
provider: apiProvider ?? config?.apiProvider,
model: model ?? config?.defaultModel,
},
});
}

onConnectorSelectionChange(connectorId, provider);
},
[
connectors,
selectedConversation,
onConnectorSelectionChange,
onConnectorModalVisibilityChange,
setApiConfig,
]
[connectors, selectedConversation, onConnectorModalVisibilityChange, setApiConfig]
);

const placeholderComponent = useMemo(
Expand Down Expand Up @@ -276,11 +262,9 @@ export const ConnectorSelectorInline: React.FC<Props> = React.memo(
<ConnectorAddModal
actionType={actionType}
onClose={cleanupAndCloseModal}
postSaveEventHandler={(savedAction: ActionConnector) => {
const provider = (savedAction as ActionConnectorProps<Config, unknown>)?.config
.apiProvider as OpenAiProviderType;
onChange(savedAction.id, provider);
onConnectorSelectionChange(savedAction.id, provider);
postSaveEventHandler={(connector: ActionConnector) => {
const config = getGenAiConfig(connector);
onChange(connector.id, config?.apiProvider, config?.defaultModel);
refetchConnectors?.();
cleanupAndCloseModal();
}}
Expand Down
Loading

0 comments on commit 5f9651e

Please sign in to comment.