Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import { HttpSetup } from '@kbn/core-http-browser';
import { FormattedMessage } from '@kbn/i18n-react';
import { OpenAiProviderType } from '@kbn/stack-connectors-plugin/public/common';
import { noop } from 'lodash/fp';
import { PromptResponse } from '@kbn/elastic-assistant-common';
import { Conversation } from '../../../..';
import type { PromptResponse } from '@kbn/elastic-assistant-common';
import { Conversation, useAssistantContext } from '../../../..';
import * as i18n from './translations';
import * as i18nModel from '../../../connectorland/models/model_selector/translations';

Expand Down Expand Up @@ -52,8 +52,10 @@ export const ConversationSettingsEditor: React.FC<ConversationSettingsEditorProp
setConversationSettings,
setConversationsSettingsBulkActions,
}) => {
const { settings } = useAssistantContext();
const { data: connectors, isSuccess: areConnectorsFetched } = useLoadConnectors({
http,
settings,
});
const selectedSystemPrompt = useMemo(() => {
return getDefaultSystemPrompt({ allSystemPrompts, conversation: selectedConversation });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import {
getOptionalRequestParams,
mergeBaseWithPersistedConversations,
} from './helpers';
import { AIConnector } from '../connectorland/connector_selector';
import type { AIConnector } from '../connectorland/connector_selector';
import type { SettingsStart } from '@kbn/core-ui-settings-browser';
import { GEN_AI_SETTINGS_DEFAULT_AI_CONNECTOR } from '@kbn/management-settings-ids';

describe('helpers', () => {
describe('getDefaultConnector', () => {
Expand All @@ -29,41 +31,97 @@ describe('helpers', () => {
apiUrl: 'https://api.openai.com/v1/chat/completions',
},
};

const connector2: AIConnector = {
...defaultConnector,
id: 'c7f91dc0-2197-11ee-aded-897192c5d633',
name: 'OpenAI',
config: {
apiProvider: 'OpenAI 2',
apiUrl: 'https://api.openai.com/v1/chat/completions',
},
};

const clientGet = jest.fn();

const settings = {
client: {
get: clientGet,
},
} as unknown as SettingsStart;

beforeEach(() => {
jest.clearAllMocks();
clientGet.mockImplementation((key: string) => {
return undefined;
});
});

it('should return undefined if connectors array is undefined', () => {
const connectors = undefined;
const result = getDefaultConnector(connectors);
const result = getDefaultConnector(connectors, settings);

expect(result).toBeUndefined();
});

it('should return undefined if connectors array is empty', () => {
const connectors: AIConnector[] = [];
const result = getDefaultConnector(connectors);
const result = getDefaultConnector(connectors, settings);

expect(result).toBeUndefined();
});

it('should return the connector id if there is only one connector', () => {
it('should return the first connector if there is only one connector available', () => {
const connectors: AIConnector[] = [defaultConnector];
const result = getDefaultConnector(connectors);
const result = getDefaultConnector(connectors, settings);

expect(result).toBe(connectors[0]);
});

it('should return the connector id if there are multiple connectors', () => {
const connectors: AIConnector[] = [
defaultConnector,
{
...defaultConnector,
id: 'c7f91dc0-2197-11ee-aded-897192c5d633',
name: 'OpenAI',
config: {
apiProvider: 'OpenAI 2',
apiUrl: 'https://api.openai.com/v1/chat/completions',
},
},
];
const result = getDefaultConnector(connectors);
it('should return the default connector if there are multiple connectors and default connector is defined', () => {
clientGet.mockImplementation((key: string) => {
if (key === GEN_AI_SETTINGS_DEFAULT_AI_CONNECTOR) {
return defaultConnector.id;
}
return undefined;
});
const connectors: AIConnector[] = [defaultConnector, connector2];
const result = getDefaultConnector(connectors, settings);
expect(result).toBe(defaultConnector);
});

it('should return the default connector if there are multiple connectors and default connector is defined but they are in a different order', () => {
clientGet.mockImplementation((key: string) => {
if (key === GEN_AI_SETTINGS_DEFAULT_AI_CONNECTOR) {
return defaultConnector.id;
}
return undefined;
});
const connectors: AIConnector[] = [connector2, defaultConnector];
const result = getDefaultConnector(connectors, settings);
expect(result).toBe(defaultConnector);
});

it('should return the first connector if there are multiple connectors and no default connector is defined', () => {
clientGet.mockImplementation(() => {
return undefined;
});

const connectors: AIConnector[] = [connector2, defaultConnector];
const result = getDefaultConnector(connectors, settings);
expect(result).toBe(connectors[0]);
});

it('should return the first connector if there are multiple connectors and a default connector is defined but it does not exist', () => {
clientGet.mockImplementation((key: string) => {
if (key === GEN_AI_SETTINGS_DEFAULT_AI_CONNECTOR) {
return 'randomConnectorIdThatDoesNotExist';
}
return undefined;
});

const connectors: AIConnector[] = [connector2, defaultConnector];
const result = getDefaultConnector(connectors, settings);
expect(result).toBe(connectors[0]);
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
*/

import { isEmpty, some } from 'lodash';
import { AIConnector } from '../connectorland/connector_selector';
import { FetchConnectorExecuteResponse, FetchConversationsResponse } from './api';
import { Conversation } from '../..';
import type { SettingsStart } from '@kbn/core-ui-settings-browser';
import { GEN_AI_SETTINGS_DEFAULT_AI_CONNECTOR } from '@kbn/management-settings-ids';
import type { AIConnector } from '../connectorland/connector_selector';
import type { FetchConnectorExecuteResponse, FetchConversationsResponse } from './api';
import type { ClientMessage } from '../assistant_context/types';
import { Conversation } from '../..';

export const getMessageFromRawResponse = (
rawResponse: FetchConnectorExecuteResponse
Expand Down Expand Up @@ -59,13 +61,30 @@ export const mergeBaseWithPersistedConversations = (
* @param connectors
*/
export const getDefaultConnector = (
connectors: AIConnector[] | undefined
connectors: AIConnector[] | undefined,
settings: SettingsStart
): AIConnector | undefined => {
const defaultAiConnectorId = settings.client.get<string>(
GEN_AI_SETTINGS_DEFAULT_AI_CONNECTOR,
undefined
);

const validConnectors = connectors?.filter((connector) => !connector.isMissingSecrets);
const defaultConnector = validConnectors?.find(
(connector) => connector.id === defaultAiConnectorId
);

if (defaultConnector) {
// If the user has set a default connector setting, and that connector exists, use it
return defaultConnector;
}

if (validConnectors?.length) {
// In case the default connector is not set or is invalid, return the first valid connector
return validConnectors[0];
}

// If no valid connectors are available, return undefined
return undefined;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ const AssistantComponent: React.FC<Props> = ({
showAnonymizedValues,
setContentReferencesVisible,
setShowAnonymizedValues,
settings,
} = useAssistantContext();

const [selectedPromptContexts, setSelectedPromptContexts] = useState<
Expand Down Expand Up @@ -131,8 +132,12 @@ const AssistantComponent: React.FC<Props> = ({
// Connector details
const { data: connectors, isFetchedAfterMount: isFetchedConnectors } = useLoadConnectors({
http,
settings,
});
const defaultConnector = useMemo(() => getDefaultConnector(connectors), [connectors]);
const defaultConnector = useMemo(
() => getDefaultConnector(connectors, settings),
[connectors, settings]
);
const {
currentConversation,
currentSystemPrompt,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,27 @@ const setSelectedSettingsTab = jest.fn();
const mockContext = {
basePromptContexts: MOCK_QUICK_PROMPTS,
setSelectedSettingsTab,
http: {},
http: {
get: jest.fn(),
},
selectedSettingsTab: 'CONVERSATIONS_TAB',
assistantAvailability: {
isAssistantEnabled: true,
},
settings: {
client: {
get: jest.fn((key) => {
if (key === 'genAiSettings:defaultAIConnector') {
return 'c5f91dc0-2197-11ee-aded-897192c5d6f5';
}
if (key === 'genAiSettings:defaultAIConnectorDefaultOnly') {
return false;
}
return undefined;
}),
},
},
assistantFeatures: { assistantModelEvaluation: true },
};
const onClose = jest.fn();
const onSave = jest.fn().mockResolvedValue(() => {});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ export const AssistantSettings: React.FC<Props> = React.memo(
conversations,
conversationsLoaded,
}) => {
const { http, toasts, selectedSettingsTab, setSelectedSettingsTab } = useAssistantContext();
const { http, toasts, selectedSettingsTab, setSelectedSettingsTab, settings } =
useAssistantContext();

useEffect(() => {
if (selectedSettingsTab == null) {
Expand All @@ -89,6 +90,7 @@ export const AssistantSettings: React.FC<Props> = React.memo(

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

const {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ import {
import { mockSystemPrompts } from '../../mock/system_prompt';
import { DataViewsContract } from '@kbn/data-views-plugin/public';
import { SettingsStart } from '@kbn/core-ui-settings-browser';
import {
GEN_AI_SETTINGS_DEFAULT_AI_CONNECTOR,
GEN_AI_SETTINGS_DEFAULT_AI_CONNECTOR_DEFAULT_ONLY,
} from '@kbn/management-settings-ids';

const mockConversations = {
[alertConvo.title]: alertConvo,
Expand All @@ -50,6 +54,20 @@ const mockContext = {
assistantAvailability: {
isAssistantEnabled: true,
},
settings: {
client: {
get: jest.fn((key) => {
if (key === GEN_AI_SETTINGS_DEFAULT_AI_CONNECTOR) {
return 'c5f91dc0-2197-11ee-aded-897192c5d6f5';
}
if (key === GEN_AI_SETTINGS_DEFAULT_AI_CONNECTOR_DEFAULT_ONLY) {
return false;
}
return undefined;
}),
},
},
navigateToApp: jest.fn(),
};

const mockDataViews = {
Expand All @@ -62,7 +80,11 @@ const testProps = {
dataViews: mockDataViews,
onTabChange,
currentTab: CONNECTORS_TAB,
settings: {} as SettingsStart,
settings: {
client: {
get: jest.fn(),
},
} as unknown as SettingsStart,
};
jest.mock('../../assistant_context');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,12 @@ export const AssistantSettingsManagement: React.FC<Props> = React.memo(
} = useAssistantContext();
const { data: connectors } = useLoadConnectors({
http,
settings,
});
const defaultConnector = useMemo(() => getDefaultConnector(connectors), [connectors]);
const defaultConnector = useMemo(
() => getDefaultConnector(connectors, settings),
[connectors, settings]
);

const { euiTheme } = useEuiTheme();
const headerIconShadow = useEuiShadow('s');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,9 @@ const AS_PLAIN_TEXT: EuiComboBoxSingleSelectionShape = { asPlainText: true };
* Evaluation Settings -- development-only feature for evaluating models
*/
export const EvaluationSettings: React.FC = React.memo(() => {
const { actionTypeRegistry, http, setTraceOptions, toasts, traceOptions } = useAssistantContext();
const { data: connectors } = useLoadConnectors({ http, inferenceEnabled: true });
const { actionTypeRegistry, http, setTraceOptions, toasts, traceOptions, settings } =
useAssistantContext();
const { data: connectors } = useLoadConnectors({ http, inferenceEnabled: true, settings });
const { mutate: performEvaluation, isLoading: isPerformingEvaluation } = usePerformEvaluation({
http,
toasts,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ const mockUseAssistantContext = {
registerPromptContext: jest.fn(),
showAssistantOverlay: jest.fn(),
unRegisterPromptContext: jest.fn(),
settings: {
client: {
get: jest.fn(),
},
},
};
jest.mock('../../assistant_context', () => {
const original = jest.requireActual('../../assistant_context');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,17 @@ export const useAssistantOverlay = (
*/
replacements?: Replacements | null
): UseAssistantOverlay => {
const { http, inferenceEnabled } = useAssistantContext();
const { http, inferenceEnabled, settings } = useAssistantContext();
const { data: connectors } = useLoadConnectors({
http,
inferenceEnabled,
settings,
});

const defaultConnector = useMemo(() => getDefaultConnector(connectors), [connectors]);
const defaultConnector = useMemo(
() => getDefaultConnector(connectors, settings),
[connectors, settings]
);
const apiConfig = useMemo(() => getGenAiConfig(defaultConnector), [defaultConnector]);

const { createConversation } = useConversation();
Expand Down
Loading