Skip to content

Commit df86cbb

Browse files
authored
[Security solution] AI Assistant prompt clean up (elastic#217058)
1 parent 9488bff commit df86cbb

File tree

9 files changed

+340
-314
lines changed

9 files changed

+340
-314
lines changed

x-pack/platform/packages/shared/kbn-elastic-assistant/impl/assistant/api/prompts/bulk_update_prompts.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export const bulkUpdatePrompts = async (
2020
http: HttpSetup,
2121
prompts: PerformPromptsBulkActionRequestBody,
2222
toasts?: IToasts
23-
) => {
23+
): Promise<PerformPromptsBulkActionResponse | { success: false }> => {
2424
try {
2525
const result = await http.fetch<PerformPromptsBulkActionResponse>(
2626
ELASTIC_AI_ASSISTANT_PROMPTS_URL_BULK_ACTION,
@@ -56,5 +56,6 @@ export const bulkUpdatePrompts = async (
5656
},
5757
}),
5858
});
59+
return { success: false };
5960
}
6061
};

x-pack/platform/packages/shared/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/system_prompt_editor.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ export const SystemPromptEditorComponent: React.FC<Props> = ({
5555
// Prompt
5656
const promptContent = useMemo(
5757
// Fixing Cursor Jump in text area
58-
() => systemPromptSettings.find((sp) => sp.id === selectedSystemPrompt?.id)?.content ?? '',
59-
[selectedSystemPrompt?.id, systemPromptSettings]
58+
() => selectedSystemPrompt?.content ?? '',
59+
[selectedSystemPrompt?.content]
6060
);
6161
// Conversations this system prompt should be a default for
6262
const conversationOptions = useMemo(() => Object.values(conversations), [conversations]);

x-pack/platform/packages/shared/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/index.tsx

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -111,15 +111,17 @@ const SystemPromptSettingsManagementComponent = ({ connectors, defaultConnector
111111

112112
const handleSave = useCallback(
113113
async (param?: { callback?: () => void }) => {
114-
const { conversationUpdates } = await saveSystemPromptSettings();
115-
await saveConversationsSettings(conversationUpdates);
116-
await refetchPrompts();
117-
await refetchSystemPromptConversations();
118-
toasts?.addSuccess({
119-
iconType: 'check',
120-
title: SETTINGS_UPDATED_TOAST_TITLE,
121-
});
122-
param?.callback?.();
114+
const { success, conversationUpdates } = await saveSystemPromptSettings();
115+
if (success) {
116+
await saveConversationsSettings(conversationUpdates);
117+
await refetchPrompts();
118+
await refetchSystemPromptConversations();
119+
toasts?.addSuccess({
120+
iconType: 'check',
121+
title: SETTINGS_UPDATED_TOAST_TITLE,
122+
});
123+
param?.callback?.();
124+
}
123125
},
124126
[
125127
refetchPrompts,

x-pack/platform/packages/shared/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings/quick_prompt_editor.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ const QuickPromptSettingsEditorComponent = ({
4444
// Prompt
4545
const promptContent = useMemo(
4646
// Fixing Cursor Jump in text area
47-
() => quickPromptSettings.find((p) => p.id === selectedQuickPrompt?.id)?.content ?? '',
48-
[selectedQuickPrompt?.id, quickPromptSettings]
47+
() => selectedQuickPrompt?.content ?? '',
48+
[selectedQuickPrompt?.content]
4949
);
5050

5151
const setDefaultPromptColor = useCallback((): string => {

x-pack/platform/packages/shared/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management/index.tsx

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,16 +51,19 @@ const QuickPromptSettingsManagementComponent = () => {
5151
currentAppId,
5252
http,
5353
promptsLoaded,
54+
toasts,
5455
});
5556

5657
const handleSave = useCallback(
5758
async (param?: { callback?: () => void }) => {
58-
await saveQuickPromptSettings();
59-
toasts?.addSuccess({
60-
iconType: 'check',
61-
title: SETTINGS_UPDATED_TOAST_TITLE,
62-
});
63-
param?.callback?.();
59+
const didSucceed = await saveQuickPromptSettings();
60+
if (didSucceed) {
61+
toasts?.addSuccess({
62+
iconType: 'check',
63+
title: SETTINGS_UPDATED_TOAST_TITLE,
64+
});
65+
param?.callback?.();
66+
}
6467
},
6568
[saveQuickPromptSettings, toasts]
6669
);

x-pack/platform/packages/shared/kbn-elastic-assistant/impl/assistant/settings/use_settings_updater/use_quick_prompt_updater.test.ts

Lines changed: 123 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,17 @@
88
import { renderHook, act } from '@testing-library/react';
99
import { HttpSetup } from '@kbn/core-http-browser';
1010
import { useQuickPromptUpdater } from './use_quick_prompt_updater';
11-
import { FindPromptsResponse, PromptResponse } from '@kbn/elastic-assistant-common';
12-
11+
import { FindPromptsResponse, PromptResponse, PromptTypeEnum } from '@kbn/elastic-assistant-common';
12+
import { bulkUpdatePrompts } from '../../../..';
13+
import { IToasts } from '@kbn/core-notifications-browser';
1314
const mockHttp = {} as HttpSetup;
15+
jest.mock('../../../..');
16+
jest.mock('../../quick_prompts/quick_prompt_settings/helpers', () => {
17+
return {
18+
getRandomEuiColor: jest.fn(() => '#61A2FF'),
19+
};
20+
});
21+
const mockBulkUpdatePrompts = bulkUpdatePrompts as jest.Mock;
1422
const quickPrompt: PromptResponse = {
1523
timestamp: '2025-02-24T18:13:51.851Z',
1624
users: [{ id: 'u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0', name: 'elastic' }],
@@ -57,11 +65,19 @@ const mockAllPrompts: FindPromptsResponse = {
5765
},
5866
],
5967
};
68+
const mockToasts = {
69+
addSuccess: jest.fn(),
70+
addDanger: jest.fn(),
71+
} as unknown as IToasts;
6072

6173
describe('useQuickPromptUpdater', () => {
74+
beforeEach(() => {
75+
jest.clearAllMocks();
76+
});
6277
it('should initialize with quick prompts', () => {
6378
const { result } = renderHook(() =>
6479
useQuickPromptUpdater({
80+
toasts: mockToasts,
6581
allPrompts: mockAllPrompts,
6682
currentAppId: 'securitySolutionUI',
6783
http: mockHttp,
@@ -76,6 +92,7 @@ describe('useQuickPromptUpdater', () => {
7692
it('should select a quick prompt by id', () => {
7793
const { result } = renderHook(() =>
7894
useQuickPromptUpdater({
95+
toasts: mockToasts,
7996
allPrompts: mockAllPrompts,
8097
currentAppId: 'securitySolutionUI',
8198
http: mockHttp,
@@ -93,6 +110,7 @@ describe('useQuickPromptUpdater', () => {
93110
it('should add a new quick prompt when selecting by name', () => {
94111
const { result } = renderHook(() =>
95112
useQuickPromptUpdater({
113+
toasts: mockToasts,
96114
allPrompts: mockAllPrompts,
97115
currentAppId: 'securitySolutionUI',
98116
http: mockHttp,
@@ -104,13 +122,21 @@ describe('useQuickPromptUpdater', () => {
104122
result.current.onQuickPromptSelect('New Quick Prompt');
105123
});
106124

107-
expect(result.current.quickPromptSettings).toHaveLength(3);
108-
expect(result.current.quickPromptSettings[2].name).toBe('New Quick Prompt');
125+
expect(result.current.selectedQuickPrompt).toEqual({
126+
name: 'New Quick Prompt',
127+
id: '',
128+
content: '',
129+
color: '#61A2FF',
130+
categories: [],
131+
promptType: PromptTypeEnum.quick,
132+
consumer: 'securitySolutionUI',
133+
});
109134
});
110135

111136
it('should change the content of a selected quick prompt', () => {
112137
const { result } = renderHook(() =>
113138
useQuickPromptUpdater({
139+
toasts: mockToasts,
114140
allPrompts: mockAllPrompts,
115141
currentAppId: 'securitySolutionUI',
116142
http: mockHttp,
@@ -132,6 +158,7 @@ describe('useQuickPromptUpdater', () => {
132158
it('should update prompt color', () => {
133159
const { result } = renderHook(() =>
134160
useQuickPromptUpdater({
161+
toasts: mockToasts,
135162
allPrompts: mockAllPrompts,
136163
currentAppId: 'securitySolutionUI',
137164
http: mockHttp,
@@ -156,6 +183,7 @@ describe('useQuickPromptUpdater', () => {
156183
it('should reset quick prompt settings', () => {
157184
const { result } = renderHook(() =>
158185
useQuickPromptUpdater({
186+
toasts: mockToasts,
159187
allPrompts: mockAllPrompts,
160188
currentAppId: 'securitySolutionUI',
161189
http: mockHttp,
@@ -167,12 +195,101 @@ describe('useQuickPromptUpdater', () => {
167195
result.current.onQuickPromptSelect('New Quick Prompt');
168196
});
169197

170-
expect(result.current.quickPromptSettings).toHaveLength(3);
198+
expect(result.current.selectedQuickPrompt?.name).toEqual('New Quick Prompt');
171199

172200
act(() => {
173201
result.current.resetQuickPromptSettings();
174202
});
203+
expect(result.current.selectedQuickPrompt).toEqual(undefined);
204+
});
205+
it('should delete a quick prompt by id', async () => {
206+
const { result } = renderHook(() =>
207+
useQuickPromptUpdater({
208+
toasts: mockToasts,
209+
allPrompts: mockAllPrompts,
210+
currentAppId: 'securitySolutionUI',
211+
http: mockHttp,
212+
promptsLoaded: true,
213+
})
214+
);
175215

176-
expect(result.current.quickPromptSettings).toHaveLength(2);
216+
act(() => {
217+
result.current.onQuickPromptDelete('OZ4qOZUBqnYEVX-cWulv');
218+
});
219+
await act(async () => {
220+
await result.current.saveQuickPromptSettings();
221+
});
222+
223+
expect(mockBulkUpdatePrompts).toHaveBeenCalledWith(
224+
mockHttp,
225+
{
226+
delete: { ids: ['OZ4qOZUBqnYEVX-cWulv'] },
227+
},
228+
mockToasts
229+
);
230+
});
231+
232+
it('should change the context of a selected quick prompt', () => {
233+
const { result } = renderHook(() =>
234+
useQuickPromptUpdater({
235+
toasts: mockToasts,
236+
allPrompts: mockAllPrompts,
237+
currentAppId: 'securitySolutionUI',
238+
http: mockHttp,
239+
promptsLoaded: true,
240+
})
241+
);
242+
243+
act(() => {
244+
result.current.onQuickPromptSelect('OZ4qOZUBqnYEVX-cWulv');
245+
});
246+
247+
act(() => {
248+
result.current.onQuickPromptContextChange([
249+
{ category: 'new-category', description: 'text', tooltip: 'hi' },
250+
]);
251+
});
252+
253+
expect(result.current.selectedQuickPrompt?.categories).toEqual(['new-category']);
254+
});
255+
256+
it('should save quick prompt settings', async () => {
257+
const { result } = renderHook(() =>
258+
useQuickPromptUpdater({
259+
toasts: mockToasts,
260+
allPrompts: mockAllPrompts,
261+
currentAppId: 'securitySolutionUI',
262+
http: mockHttp,
263+
promptsLoaded: true,
264+
})
265+
);
266+
267+
act(() => {
268+
result.current.onQuickPromptSelect('OZ4qOZUBqnYEVX-cWulv');
269+
});
270+
271+
act(() => {
272+
result.current.onPromptContentChange('Updated content');
273+
});
274+
await act(async () => {
275+
await result.current.saveQuickPromptSettings();
276+
});
277+
expect(mockBulkUpdatePrompts).toHaveBeenCalledWith(
278+
mockHttp,
279+
{
280+
create: [
281+
{
282+
categories: [],
283+
color: '#61A2FF',
284+
consumer: 'securitySolutionUI',
285+
content: 'Updated content',
286+
id: '',
287+
name: 'OZ4qOZUBqnYEVX-cWulv',
288+
promptType: 'quick',
289+
},
290+
],
291+
},
292+
mockToasts
293+
);
177294
});
178295
});

0 commit comments

Comments
 (0)