mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[Security solution] AI Assistant prompt clean up (#217058)
This commit is contained in:
parent
9488bff6b8
commit
df86cbbd72
9 changed files with 342 additions and 316 deletions
|
@ -20,7 +20,7 @@ export const bulkUpdatePrompts = async (
|
|||
http: HttpSetup,
|
||||
prompts: PerformPromptsBulkActionRequestBody,
|
||||
toasts?: IToasts
|
||||
) => {
|
||||
): Promise<PerformPromptsBulkActionResponse | { success: false }> => {
|
||||
try {
|
||||
const result = await http.fetch<PerformPromptsBulkActionResponse>(
|
||||
ELASTIC_AI_ASSISTANT_PROMPTS_URL_BULK_ACTION,
|
||||
|
@ -56,5 +56,6 @@ export const bulkUpdatePrompts = async (
|
|||
},
|
||||
}),
|
||||
});
|
||||
return { success: false };
|
||||
}
|
||||
};
|
||||
|
|
|
@ -55,8 +55,8 @@ export const SystemPromptEditorComponent: React.FC<Props> = ({
|
|||
// Prompt
|
||||
const promptContent = useMemo(
|
||||
// Fixing Cursor Jump in text area
|
||||
() => systemPromptSettings.find((sp) => sp.id === selectedSystemPrompt?.id)?.content ?? '',
|
||||
[selectedSystemPrompt?.id, systemPromptSettings]
|
||||
() => selectedSystemPrompt?.content ?? '',
|
||||
[selectedSystemPrompt?.content]
|
||||
);
|
||||
// Conversations this system prompt should be a default for
|
||||
const conversationOptions = useMemo(() => Object.values(conversations), [conversations]);
|
||||
|
|
|
@ -111,15 +111,17 @@ const SystemPromptSettingsManagementComponent = ({ connectors, defaultConnector
|
|||
|
||||
const handleSave = useCallback(
|
||||
async (param?: { callback?: () => void }) => {
|
||||
const { conversationUpdates } = await saveSystemPromptSettings();
|
||||
await saveConversationsSettings(conversationUpdates);
|
||||
await refetchPrompts();
|
||||
await refetchSystemPromptConversations();
|
||||
toasts?.addSuccess({
|
||||
iconType: 'check',
|
||||
title: SETTINGS_UPDATED_TOAST_TITLE,
|
||||
});
|
||||
param?.callback?.();
|
||||
const { success, conversationUpdates } = await saveSystemPromptSettings();
|
||||
if (success) {
|
||||
await saveConversationsSettings(conversationUpdates);
|
||||
await refetchPrompts();
|
||||
await refetchSystemPromptConversations();
|
||||
toasts?.addSuccess({
|
||||
iconType: 'check',
|
||||
title: SETTINGS_UPDATED_TOAST_TITLE,
|
||||
});
|
||||
param?.callback?.();
|
||||
}
|
||||
},
|
||||
[
|
||||
refetchPrompts,
|
||||
|
|
|
@ -44,8 +44,8 @@ const QuickPromptSettingsEditorComponent = ({
|
|||
// Prompt
|
||||
const promptContent = useMemo(
|
||||
// Fixing Cursor Jump in text area
|
||||
() => quickPromptSettings.find((p) => p.id === selectedQuickPrompt?.id)?.content ?? '',
|
||||
[selectedQuickPrompt?.id, quickPromptSettings]
|
||||
() => selectedQuickPrompt?.content ?? '',
|
||||
[selectedQuickPrompt?.content]
|
||||
);
|
||||
|
||||
const setDefaultPromptColor = useCallback((): string => {
|
||||
|
|
|
@ -51,16 +51,19 @@ const QuickPromptSettingsManagementComponent = () => {
|
|||
currentAppId,
|
||||
http,
|
||||
promptsLoaded,
|
||||
toasts,
|
||||
});
|
||||
|
||||
const handleSave = useCallback(
|
||||
async (param?: { callback?: () => void }) => {
|
||||
await saveQuickPromptSettings();
|
||||
toasts?.addSuccess({
|
||||
iconType: 'check',
|
||||
title: SETTINGS_UPDATED_TOAST_TITLE,
|
||||
});
|
||||
param?.callback?.();
|
||||
const didSucceed = await saveQuickPromptSettings();
|
||||
if (didSucceed) {
|
||||
toasts?.addSuccess({
|
||||
iconType: 'check',
|
||||
title: SETTINGS_UPDATED_TOAST_TITLE,
|
||||
});
|
||||
param?.callback?.();
|
||||
}
|
||||
},
|
||||
[saveQuickPromptSettings, toasts]
|
||||
);
|
||||
|
|
|
@ -8,9 +8,17 @@
|
|||
import { renderHook, act } from '@testing-library/react';
|
||||
import { HttpSetup } from '@kbn/core-http-browser';
|
||||
import { useQuickPromptUpdater } from './use_quick_prompt_updater';
|
||||
import { FindPromptsResponse, PromptResponse } from '@kbn/elastic-assistant-common';
|
||||
|
||||
import { FindPromptsResponse, PromptResponse, PromptTypeEnum } from '@kbn/elastic-assistant-common';
|
||||
import { bulkUpdatePrompts } from '../../../..';
|
||||
import { IToasts } from '@kbn/core-notifications-browser';
|
||||
const mockHttp = {} as HttpSetup;
|
||||
jest.mock('../../../..');
|
||||
jest.mock('../../quick_prompts/quick_prompt_settings/helpers', () => {
|
||||
return {
|
||||
getRandomEuiColor: jest.fn(() => '#61A2FF'),
|
||||
};
|
||||
});
|
||||
const mockBulkUpdatePrompts = bulkUpdatePrompts as jest.Mock;
|
||||
const quickPrompt: PromptResponse = {
|
||||
timestamp: '2025-02-24T18:13:51.851Z',
|
||||
users: [{ id: 'u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0', name: 'elastic' }],
|
||||
|
@ -57,11 +65,19 @@ const mockAllPrompts: FindPromptsResponse = {
|
|||
},
|
||||
],
|
||||
};
|
||||
const mockToasts = {
|
||||
addSuccess: jest.fn(),
|
||||
addDanger: jest.fn(),
|
||||
} as unknown as IToasts;
|
||||
|
||||
describe('useQuickPromptUpdater', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
it('should initialize with quick prompts', () => {
|
||||
const { result } = renderHook(() =>
|
||||
useQuickPromptUpdater({
|
||||
toasts: mockToasts,
|
||||
allPrompts: mockAllPrompts,
|
||||
currentAppId: 'securitySolutionUI',
|
||||
http: mockHttp,
|
||||
|
@ -76,6 +92,7 @@ describe('useQuickPromptUpdater', () => {
|
|||
it('should select a quick prompt by id', () => {
|
||||
const { result } = renderHook(() =>
|
||||
useQuickPromptUpdater({
|
||||
toasts: mockToasts,
|
||||
allPrompts: mockAllPrompts,
|
||||
currentAppId: 'securitySolutionUI',
|
||||
http: mockHttp,
|
||||
|
@ -93,6 +110,7 @@ describe('useQuickPromptUpdater', () => {
|
|||
it('should add a new quick prompt when selecting by name', () => {
|
||||
const { result } = renderHook(() =>
|
||||
useQuickPromptUpdater({
|
||||
toasts: mockToasts,
|
||||
allPrompts: mockAllPrompts,
|
||||
currentAppId: 'securitySolutionUI',
|
||||
http: mockHttp,
|
||||
|
@ -104,13 +122,21 @@ describe('useQuickPromptUpdater', () => {
|
|||
result.current.onQuickPromptSelect('New Quick Prompt');
|
||||
});
|
||||
|
||||
expect(result.current.quickPromptSettings).toHaveLength(3);
|
||||
expect(result.current.quickPromptSettings[2].name).toBe('New Quick Prompt');
|
||||
expect(result.current.selectedQuickPrompt).toEqual({
|
||||
name: 'New Quick Prompt',
|
||||
id: '',
|
||||
content: '',
|
||||
color: '#61A2FF',
|
||||
categories: [],
|
||||
promptType: PromptTypeEnum.quick,
|
||||
consumer: 'securitySolutionUI',
|
||||
});
|
||||
});
|
||||
|
||||
it('should change the content of a selected quick prompt', () => {
|
||||
const { result } = renderHook(() =>
|
||||
useQuickPromptUpdater({
|
||||
toasts: mockToasts,
|
||||
allPrompts: mockAllPrompts,
|
||||
currentAppId: 'securitySolutionUI',
|
||||
http: mockHttp,
|
||||
|
@ -132,6 +158,7 @@ describe('useQuickPromptUpdater', () => {
|
|||
it('should update prompt color', () => {
|
||||
const { result } = renderHook(() =>
|
||||
useQuickPromptUpdater({
|
||||
toasts: mockToasts,
|
||||
allPrompts: mockAllPrompts,
|
||||
currentAppId: 'securitySolutionUI',
|
||||
http: mockHttp,
|
||||
|
@ -156,6 +183,7 @@ describe('useQuickPromptUpdater', () => {
|
|||
it('should reset quick prompt settings', () => {
|
||||
const { result } = renderHook(() =>
|
||||
useQuickPromptUpdater({
|
||||
toasts: mockToasts,
|
||||
allPrompts: mockAllPrompts,
|
||||
currentAppId: 'securitySolutionUI',
|
||||
http: mockHttp,
|
||||
|
@ -167,12 +195,101 @@ describe('useQuickPromptUpdater', () => {
|
|||
result.current.onQuickPromptSelect('New Quick Prompt');
|
||||
});
|
||||
|
||||
expect(result.current.quickPromptSettings).toHaveLength(3);
|
||||
expect(result.current.selectedQuickPrompt?.name).toEqual('New Quick Prompt');
|
||||
|
||||
act(() => {
|
||||
result.current.resetQuickPromptSettings();
|
||||
});
|
||||
expect(result.current.selectedQuickPrompt).toEqual(undefined);
|
||||
});
|
||||
it('should delete a quick prompt by id', async () => {
|
||||
const { result } = renderHook(() =>
|
||||
useQuickPromptUpdater({
|
||||
toasts: mockToasts,
|
||||
allPrompts: mockAllPrompts,
|
||||
currentAppId: 'securitySolutionUI',
|
||||
http: mockHttp,
|
||||
promptsLoaded: true,
|
||||
})
|
||||
);
|
||||
|
||||
expect(result.current.quickPromptSettings).toHaveLength(2);
|
||||
act(() => {
|
||||
result.current.onQuickPromptDelete('OZ4qOZUBqnYEVX-cWulv');
|
||||
});
|
||||
await act(async () => {
|
||||
await result.current.saveQuickPromptSettings();
|
||||
});
|
||||
|
||||
expect(mockBulkUpdatePrompts).toHaveBeenCalledWith(
|
||||
mockHttp,
|
||||
{
|
||||
delete: { ids: ['OZ4qOZUBqnYEVX-cWulv'] },
|
||||
},
|
||||
mockToasts
|
||||
);
|
||||
});
|
||||
|
||||
it('should change the context of a selected quick prompt', () => {
|
||||
const { result } = renderHook(() =>
|
||||
useQuickPromptUpdater({
|
||||
toasts: mockToasts,
|
||||
allPrompts: mockAllPrompts,
|
||||
currentAppId: 'securitySolutionUI',
|
||||
http: mockHttp,
|
||||
promptsLoaded: true,
|
||||
})
|
||||
);
|
||||
|
||||
act(() => {
|
||||
result.current.onQuickPromptSelect('OZ4qOZUBqnYEVX-cWulv');
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.onQuickPromptContextChange([
|
||||
{ category: 'new-category', description: 'text', tooltip: 'hi' },
|
||||
]);
|
||||
});
|
||||
|
||||
expect(result.current.selectedQuickPrompt?.categories).toEqual(['new-category']);
|
||||
});
|
||||
|
||||
it('should save quick prompt settings', async () => {
|
||||
const { result } = renderHook(() =>
|
||||
useQuickPromptUpdater({
|
||||
toasts: mockToasts,
|
||||
allPrompts: mockAllPrompts,
|
||||
currentAppId: 'securitySolutionUI',
|
||||
http: mockHttp,
|
||||
promptsLoaded: true,
|
||||
})
|
||||
);
|
||||
|
||||
act(() => {
|
||||
result.current.onQuickPromptSelect('OZ4qOZUBqnYEVX-cWulv');
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.onPromptContentChange('Updated content');
|
||||
});
|
||||
await act(async () => {
|
||||
await result.current.saveQuickPromptSettings();
|
||||
});
|
||||
expect(mockBulkUpdatePrompts).toHaveBeenCalledWith(
|
||||
mockHttp,
|
||||
{
|
||||
create: [
|
||||
{
|
||||
categories: [],
|
||||
color: '#61A2FF',
|
||||
consumer: 'securitySolutionUI',
|
||||
content: 'Updated content',
|
||||
id: '',
|
||||
name: 'OZ4qOZUBqnYEVX-cWulv',
|
||||
promptType: 'quick',
|
||||
},
|
||||
],
|
||||
},
|
||||
mockToasts
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { FindPromptsResponse, PromptResponse, PromptTypeEnum } from '@kbn/elastic-assistant-common';
|
||||
import { PerformPromptsBulkActionRequestBody as PromptsPerformBulkActionRequestBody } from '@kbn/elastic-assistant-common/impl/schemas/prompts/bulk_crud_prompts_route.gen';
|
||||
import { HttpSetup } from '@kbn/core-http-browser';
|
||||
|
@ -43,35 +43,24 @@ export const useQuickPromptUpdater = ({
|
|||
const [promptsBulkActions, setPromptsBulkActions] = useState<PromptsPerformBulkActionRequestBody>(
|
||||
{}
|
||||
);
|
||||
const [selectedQuickPromptId, setSelectedQuickPromptId] = useState<string | undefined>();
|
||||
const [selectedQuickPrompt, setSelectedQuickPrompt] = useState<PromptResponse | undefined>();
|
||||
const [quickPromptSettings, setUpdatedQuickPromptSettings] = useState<PromptResponse[]>(
|
||||
allPrompts.data.filter((p) => p.promptType === PromptTypeEnum.quick)
|
||||
);
|
||||
|
||||
const selectedQuickPrompt: PromptResponse | undefined = useMemo(
|
||||
() => quickPromptSettings.find((qp) => qp.id === selectedQuickPromptId),
|
||||
[quickPromptSettings, selectedQuickPromptId]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
// Update quick prompts settings when prompts are loaded
|
||||
if (promptsLoaded) {
|
||||
setUpdatedQuickPromptSettings((prev) => {
|
||||
const prevIds = prev.map((p) => p.id);
|
||||
return [
|
||||
...prev,
|
||||
...allPrompts.data.filter(
|
||||
(p) => p.promptType === PromptTypeEnum.quick && !prevIds.includes(p.id)
|
||||
),
|
||||
];
|
||||
});
|
||||
setUpdatedQuickPromptSettings([
|
||||
...allPrompts.data.filter((p) => p.promptType === PromptTypeEnum.quick),
|
||||
]);
|
||||
}
|
||||
}, [allPrompts.data, promptsLoaded]);
|
||||
|
||||
const onQuickPromptSelect = useCallback(
|
||||
(quickPrompt?: PromptResponse | string, color?: string) => {
|
||||
if (quickPrompt == null) {
|
||||
return setSelectedQuickPromptId(undefined);
|
||||
return setSelectedQuickPrompt(undefined);
|
||||
}
|
||||
const isNew = typeof quickPrompt === 'string';
|
||||
const qpColor = color ? color : isNew ? getRandomEuiColor() : quickPrompt.color;
|
||||
|
@ -87,12 +76,6 @@ export const useQuickPromptUpdater = ({
|
|||
}
|
||||
: quickPrompt;
|
||||
|
||||
setUpdatedQuickPromptSettings((prev) =>
|
||||
!prev.some((sp) => sp.id === newSelectedQuickPrompt.id)
|
||||
? [...prev, newSelectedQuickPrompt]
|
||||
: prev
|
||||
);
|
||||
|
||||
if (isNew) {
|
||||
setPromptsBulkActions((prev) => ({
|
||||
...prev,
|
||||
|
@ -105,7 +88,7 @@ export const useQuickPromptUpdater = ({
|
|||
}));
|
||||
}
|
||||
|
||||
setSelectedQuickPromptId(newSelectedQuickPrompt.id);
|
||||
setSelectedQuickPrompt(newSelectedQuickPrompt);
|
||||
},
|
||||
[currentAppId, promptsBulkActions.create]
|
||||
);
|
||||
|
@ -113,115 +96,82 @@ export const useQuickPromptUpdater = ({
|
|||
const onPromptContentChange = useCallback(
|
||||
(newValue: string) => {
|
||||
if (selectedQuickPrompt != null) {
|
||||
setUpdatedQuickPromptSettings((prev): PromptResponse[] =>
|
||||
prev.map((sp): PromptResponse => {
|
||||
if (sp.id === selectedQuickPrompt.id) {
|
||||
return {
|
||||
...sp,
|
||||
content: newValue,
|
||||
};
|
||||
}
|
||||
return sp;
|
||||
})
|
||||
);
|
||||
const existingPrompt = quickPromptSettings.find((qp) => qp.id === selectedQuickPrompt.id);
|
||||
if (existingPrompt) {
|
||||
const newBulkActions = {
|
||||
...promptsBulkActions,
|
||||
...(selectedQuickPrompt.id !== ''
|
||||
? {
|
||||
update: [
|
||||
...(promptsBulkActions.update ?? []).filter(
|
||||
(p) => p.id !== selectedQuickPrompt.id
|
||||
),
|
||||
{
|
||||
...selectedQuickPrompt,
|
||||
content: newValue,
|
||||
},
|
||||
],
|
||||
}
|
||||
: {
|
||||
create: [
|
||||
...(promptsBulkActions.create ?? []).filter(
|
||||
(p) => p.name !== selectedQuickPrompt.name
|
||||
),
|
||||
{
|
||||
...selectedQuickPrompt,
|
||||
content: newValue,
|
||||
},
|
||||
],
|
||||
}),
|
||||
};
|
||||
setPromptsBulkActions(newBulkActions);
|
||||
}
|
||||
setSelectedQuickPrompt({
|
||||
...selectedQuickPrompt,
|
||||
content: newValue,
|
||||
});
|
||||
const newBulkActions = {
|
||||
...promptsBulkActions,
|
||||
...(selectedQuickPrompt.id !== ''
|
||||
? {
|
||||
update: [
|
||||
...(promptsBulkActions.update ?? []).filter(
|
||||
(p) => p.id !== selectedQuickPrompt.id
|
||||
),
|
||||
{
|
||||
...selectedQuickPrompt,
|
||||
content: newValue,
|
||||
},
|
||||
],
|
||||
}
|
||||
: {
|
||||
create: [
|
||||
...(promptsBulkActions.create ?? []).filter(
|
||||
(p) => p.name !== selectedQuickPrompt.name
|
||||
),
|
||||
{
|
||||
...selectedQuickPrompt,
|
||||
content: newValue,
|
||||
},
|
||||
],
|
||||
}),
|
||||
};
|
||||
setPromptsBulkActions(newBulkActions);
|
||||
}
|
||||
},
|
||||
[promptsBulkActions, selectedQuickPrompt, quickPromptSettings]
|
||||
[promptsBulkActions, selectedQuickPrompt]
|
||||
);
|
||||
|
||||
const onQuickPromptContextChange = useCallback(
|
||||
(pc: PromptContextTemplate[]) => {
|
||||
if (selectedQuickPrompt != null) {
|
||||
setUpdatedQuickPromptSettings((prev) => {
|
||||
const alreadyExists = prev.some((qp) => qp.name === selectedQuickPrompt.name);
|
||||
|
||||
if (alreadyExists) {
|
||||
return prev.map((qp) => {
|
||||
if (qp.name === selectedQuickPrompt.name) {
|
||||
return {
|
||||
...qp,
|
||||
categories: pc.map((p) => p.category),
|
||||
};
|
||||
}
|
||||
return qp;
|
||||
});
|
||||
}
|
||||
return prev;
|
||||
setSelectedQuickPrompt({
|
||||
...selectedQuickPrompt,
|
||||
categories: pc.map((p) => p.category),
|
||||
});
|
||||
setPromptsBulkActions({
|
||||
...promptsBulkActions,
|
||||
...(selectedQuickPrompt.id !== ''
|
||||
? {
|
||||
update: [
|
||||
...(promptsBulkActions.update ?? []).filter(
|
||||
(p) => p.id !== selectedQuickPrompt.id
|
||||
),
|
||||
{
|
||||
...selectedQuickPrompt,
|
||||
categories: pc.map((p) => p.category),
|
||||
},
|
||||
],
|
||||
}
|
||||
: {
|
||||
create: [
|
||||
...(promptsBulkActions.create ?? []).filter(
|
||||
(p) => p.name !== selectedQuickPrompt.name
|
||||
),
|
||||
{
|
||||
...selectedQuickPrompt,
|
||||
categories: pc.map((p) => p.category),
|
||||
},
|
||||
],
|
||||
}),
|
||||
});
|
||||
|
||||
const existingPrompt = quickPromptSettings.find((sp) => sp.id === selectedQuickPrompt.id);
|
||||
if (existingPrompt) {
|
||||
setPromptsBulkActions({
|
||||
...promptsBulkActions,
|
||||
...(selectedQuickPrompt.id !== ''
|
||||
? {
|
||||
update: [
|
||||
...(promptsBulkActions.update ?? []).filter(
|
||||
(p) => p.id !== selectedQuickPrompt.id
|
||||
),
|
||||
{
|
||||
...selectedQuickPrompt,
|
||||
categories: pc.map((p) => p.category),
|
||||
},
|
||||
],
|
||||
}
|
||||
: {
|
||||
create: [
|
||||
...(promptsBulkActions.create ?? []).filter(
|
||||
(p) => p.name !== selectedQuickPrompt.name
|
||||
),
|
||||
{
|
||||
...selectedQuickPrompt,
|
||||
categories: pc.map((p) => p.category),
|
||||
},
|
||||
],
|
||||
}),
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
[
|
||||
promptsBulkActions,
|
||||
quickPromptSettings,
|
||||
selectedQuickPrompt,
|
||||
setPromptsBulkActions,
|
||||
setUpdatedQuickPromptSettings,
|
||||
]
|
||||
[promptsBulkActions, selectedQuickPrompt, setPromptsBulkActions]
|
||||
);
|
||||
|
||||
const onQuickPromptDelete = useCallback(
|
||||
(id: string) => {
|
||||
setUpdatedQuickPromptSettings((prev) => prev.filter((qp) => qp.id !== id));
|
||||
setPromptsBulkActions({
|
||||
...promptsBulkActions,
|
||||
delete: {
|
||||
|
@ -235,68 +185,45 @@ export const useQuickPromptUpdater = ({
|
|||
const onQuickPromptColorChange = useCallback<EuiSetColorMethod>(
|
||||
(color) => {
|
||||
if (selectedQuickPrompt != null) {
|
||||
setUpdatedQuickPromptSettings((prev) => {
|
||||
const alreadyExists = prev.some((qp) => qp.name === selectedQuickPrompt.name);
|
||||
|
||||
if (alreadyExists) {
|
||||
return prev.map((qp) => {
|
||||
if (qp.name === selectedQuickPrompt.name) {
|
||||
return {
|
||||
...qp,
|
||||
color,
|
||||
};
|
||||
}
|
||||
return qp;
|
||||
});
|
||||
}
|
||||
return prev;
|
||||
setSelectedQuickPrompt({
|
||||
...selectedQuickPrompt,
|
||||
color,
|
||||
});
|
||||
setPromptsBulkActions({
|
||||
...promptsBulkActions,
|
||||
...(selectedQuickPrompt.id !== ''
|
||||
? {
|
||||
update: [
|
||||
...(promptsBulkActions.update ?? []).filter(
|
||||
(p) => p.id !== selectedQuickPrompt.id
|
||||
),
|
||||
{
|
||||
...selectedQuickPrompt,
|
||||
color,
|
||||
},
|
||||
],
|
||||
}
|
||||
: {
|
||||
create: [
|
||||
...(promptsBulkActions.create ?? []).filter(
|
||||
(p) => p.name !== selectedQuickPrompt.name
|
||||
),
|
||||
{
|
||||
...selectedQuickPrompt,
|
||||
color,
|
||||
},
|
||||
],
|
||||
}),
|
||||
});
|
||||
const existingPrompt = quickPromptSettings.find((sp) => sp.id === selectedQuickPrompt.id);
|
||||
if (existingPrompt) {
|
||||
setPromptsBulkActions({
|
||||
...promptsBulkActions,
|
||||
...(selectedQuickPrompt.id !== ''
|
||||
? {
|
||||
update: [
|
||||
...(promptsBulkActions.update ?? []).filter(
|
||||
(p) => p.id !== selectedQuickPrompt.id
|
||||
),
|
||||
{
|
||||
...selectedQuickPrompt,
|
||||
color,
|
||||
},
|
||||
],
|
||||
}
|
||||
: {
|
||||
create: [
|
||||
...(promptsBulkActions.create ?? []).filter(
|
||||
(p) => p.name !== selectedQuickPrompt.name
|
||||
),
|
||||
{
|
||||
...selectedQuickPrompt,
|
||||
color,
|
||||
},
|
||||
],
|
||||
}),
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
[
|
||||
promptsBulkActions,
|
||||
quickPromptSettings,
|
||||
selectedQuickPrompt,
|
||||
setPromptsBulkActions,
|
||||
setUpdatedQuickPromptSettings,
|
||||
]
|
||||
[promptsBulkActions, selectedQuickPrompt, setPromptsBulkActions]
|
||||
);
|
||||
|
||||
const resetQuickPromptSettings = useCallback((): void => {
|
||||
setPromptsBulkActions({});
|
||||
setUpdatedQuickPromptSettings(
|
||||
allPrompts.data.filter((p) => p.promptType === PromptTypeEnum.quick)
|
||||
);
|
||||
}, [allPrompts]);
|
||||
setSelectedQuickPrompt(undefined);
|
||||
}, []);
|
||||
|
||||
const saveQuickPromptSettings = useCallback(async (): Promise<boolean> => {
|
||||
const hasBulkPrompts =
|
||||
|
@ -304,8 +231,9 @@ export const useQuickPromptUpdater = ({
|
|||
const bulkPromptsResult = hasBulkPrompts
|
||||
? await bulkUpdatePrompts(http, promptsBulkActions, toasts)
|
||||
: undefined;
|
||||
resetQuickPromptSettings();
|
||||
return bulkPromptsResult?.success ?? false;
|
||||
}, [http, promptsBulkActions, toasts]);
|
||||
}, [http, promptsBulkActions, resetQuickPromptSettings, toasts]);
|
||||
|
||||
return {
|
||||
onPromptContentChange,
|
||||
|
|
|
@ -160,7 +160,7 @@ describe('useSystemPromptUpdater', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('should delete a system prompt by ID', () => {
|
||||
it('should delete a system prompt by ID', async () => {
|
||||
const { result } = renderHook(() => useSystemPromptUpdater(defaultParams), {
|
||||
wrapper: TestProviders,
|
||||
});
|
||||
|
@ -169,9 +169,20 @@ describe('useSystemPromptUpdater', () => {
|
|||
result.current.onSystemPromptSelect({ ...defaultPrompt, id: '1' });
|
||||
});
|
||||
|
||||
expect(result.current.selectedSystemPrompt).toEqual({
|
||||
consumer: 'app-id',
|
||||
content: '',
|
||||
conversations: [],
|
||||
id: '1',
|
||||
name: 'New Prompt',
|
||||
promptType: 'system',
|
||||
});
|
||||
act(() => {
|
||||
result.current.onSystemPromptDelete('1');
|
||||
});
|
||||
await act(async () => {
|
||||
await result.current.saveSystemPromptSettings();
|
||||
});
|
||||
|
||||
expect(result.current.selectedSystemPrompt).toBeUndefined();
|
||||
});
|
||||
|
|
|
@ -80,11 +80,9 @@ export const useSystemPromptUpdater = ({
|
|||
{}
|
||||
);
|
||||
// System Prompt Selection State
|
||||
const [selectedSystemPromptId, setSelectedSystemPromptId] = useState<string | undefined>();
|
||||
|
||||
const selectedSystemPrompt: SystemPromptSettings | undefined = useMemo(() => {
|
||||
return systemPromptSettingsUpdates.find((sp) => sp.id === selectedSystemPromptId);
|
||||
}, [selectedSystemPromptId, systemPromptSettingsUpdates]);
|
||||
const [selectedSystemPrompt, setSelectedSystemPrompt] = useState<
|
||||
SystemPromptSettings | undefined
|
||||
>();
|
||||
|
||||
const systemPrompts = useMemo(() => {
|
||||
return allPrompts.data.filter((p) => p.promptType === PromptTypeEnum.system);
|
||||
|
@ -135,7 +133,7 @@ export const useSystemPromptUpdater = ({
|
|||
const onSystemPromptSelect = useCallback(
|
||||
(systemPrompt?: SystemPromptSettings | string) => {
|
||||
if (systemPrompt == null) {
|
||||
return setSelectedSystemPromptId(undefined);
|
||||
return setSelectedSystemPrompt(undefined);
|
||||
}
|
||||
const isNew = typeof systemPrompt === 'string';
|
||||
const newSelectedSystemPrompt: SystemPromptSettings = isNew
|
||||
|
@ -149,12 +147,6 @@ export const useSystemPromptUpdater = ({
|
|||
}
|
||||
: systemPrompt;
|
||||
|
||||
setSystemPromptSettingsUpdates((prev) =>
|
||||
!prev.some((sp) => sp.id === newSelectedSystemPrompt.id)
|
||||
? [...prev, newSelectedSystemPrompt]
|
||||
: prev
|
||||
);
|
||||
|
||||
if (isNew) {
|
||||
setPromptsBulkActions((prev) => ({
|
||||
...prev,
|
||||
|
@ -163,14 +155,13 @@ export const useSystemPromptUpdater = ({
|
|||
}));
|
||||
}
|
||||
|
||||
setSelectedSystemPromptId(newSelectedSystemPrompt.id);
|
||||
setSelectedSystemPrompt(newSelectedSystemPrompt);
|
||||
},
|
||||
[currentAppId]
|
||||
);
|
||||
|
||||
const onSystemPromptDelete = useCallback(
|
||||
(id: string) => {
|
||||
setSystemPromptSettingsUpdates((prev) => prev.filter((sp) => sp.id !== id));
|
||||
setPromptsBulkActions({
|
||||
...promptsBulkActions,
|
||||
delete: {
|
||||
|
@ -184,52 +175,41 @@ export const useSystemPromptUpdater = ({
|
|||
const onPromptContentChange = useCallback(
|
||||
(newValue: string) => {
|
||||
if (selectedSystemPrompt != null) {
|
||||
setSystemPromptSettingsUpdates((prev): SystemPromptSettings[] =>
|
||||
prev.map((sp): SystemPromptSettings => {
|
||||
if (sp.id === selectedSystemPrompt.id) {
|
||||
return {
|
||||
...sp,
|
||||
content: newValue,
|
||||
};
|
||||
}
|
||||
return sp;
|
||||
})
|
||||
);
|
||||
const existingPrompt = systemPromptSettingsUpdates.find(
|
||||
(sp) => sp.id === selectedSystemPrompt.id
|
||||
);
|
||||
if (existingPrompt) {
|
||||
const newBulkActions = {
|
||||
...promptsBulkActions,
|
||||
...(selectedSystemPrompt.id !== ''
|
||||
? {
|
||||
update: [
|
||||
...(promptsBulkActions.update ?? []).filter(
|
||||
(p) => p.id !== selectedSystemPrompt.id
|
||||
),
|
||||
{
|
||||
...selectedSystemPrompt,
|
||||
content: newValue,
|
||||
},
|
||||
],
|
||||
}
|
||||
: {
|
||||
create: [
|
||||
...(promptsBulkActions.create ?? []).filter(
|
||||
(p) => p.name !== selectedSystemPrompt.name
|
||||
),
|
||||
{
|
||||
...selectedSystemPrompt,
|
||||
content: newValue,
|
||||
},
|
||||
],
|
||||
}),
|
||||
};
|
||||
setPromptsBulkActions(newBulkActions);
|
||||
}
|
||||
setSelectedSystemPrompt({
|
||||
...selectedSystemPrompt,
|
||||
content: newValue,
|
||||
});
|
||||
|
||||
const newBulkActions = {
|
||||
...promptsBulkActions,
|
||||
...(selectedSystemPrompt.id !== ''
|
||||
? {
|
||||
update: [
|
||||
...(promptsBulkActions.update ?? []).filter(
|
||||
(p) => p.id !== selectedSystemPrompt.id
|
||||
),
|
||||
{
|
||||
...selectedSystemPrompt,
|
||||
content: newValue,
|
||||
},
|
||||
],
|
||||
}
|
||||
: {
|
||||
create: [
|
||||
...(promptsBulkActions.create ?? []).filter(
|
||||
(p) => p.name !== selectedSystemPrompt.name
|
||||
),
|
||||
{
|
||||
...selectedSystemPrompt,
|
||||
content: newValue,
|
||||
},
|
||||
],
|
||||
}),
|
||||
};
|
||||
setPromptsBulkActions(newBulkActions);
|
||||
}
|
||||
},
|
||||
[promptsBulkActions, selectedSystemPrompt, systemPromptSettingsUpdates]
|
||||
[promptsBulkActions, selectedSystemPrompt]
|
||||
);
|
||||
|
||||
const onNewConversationDefaultChange = useCallback(
|
||||
|
@ -249,13 +229,9 @@ export const useSystemPromptUpdater = ({
|
|||
const shouldUpdateSelectedSystemPrompt = selectedSystemPrompt?.id !== '';
|
||||
|
||||
if (selectedSystemPrompt != null) {
|
||||
setSystemPromptSettingsUpdates((prev) => {
|
||||
return prev.map((pp) => {
|
||||
return {
|
||||
...pp,
|
||||
isNewConversationDefault: selectedSystemPrompt.id === pp.id && isChecked,
|
||||
};
|
||||
});
|
||||
setSelectedSystemPrompt({
|
||||
...selectedSystemPrompt,
|
||||
isNewConversationDefault: isChecked,
|
||||
});
|
||||
// Update and Create prompts can happen at the same time, as we have to unchecked the previous default prompt
|
||||
// Each prompt can be updated or created
|
||||
|
@ -308,12 +284,9 @@ export const useSystemPromptUpdater = ({
|
|||
|
||||
const onConversationSelectionChange = useCallback(
|
||||
(currentPromptConversations: Conversation[]) => {
|
||||
const originalSelectedSystemPrompt = systemPromptSettings.find(
|
||||
(sp) => sp.id === selectedSystemPromptId
|
||||
);
|
||||
const currentPromptConversationIds = currentPromptConversations.map((convo) => convo.id);
|
||||
const removals =
|
||||
originalSelectedSystemPrompt?.conversations.filter(
|
||||
selectedSystemPrompt?.conversations.filter(
|
||||
(c) => !currentPromptConversationIds.includes(c.id)
|
||||
) ?? [];
|
||||
let cRemovals: Conversation[] = [];
|
||||
|
@ -338,17 +311,10 @@ export const useSystemPromptUpdater = ({
|
|||
convo.apiConfig?.defaultSystemPromptId;
|
||||
|
||||
if (selectedSystemPrompt != null) {
|
||||
setSystemPromptSettingsUpdates((prev) =>
|
||||
prev.map((sp) => {
|
||||
if (sp.id === selectedSystemPrompt.id) {
|
||||
return {
|
||||
...sp,
|
||||
conversations: currentPromptConversations,
|
||||
};
|
||||
}
|
||||
return sp;
|
||||
})
|
||||
);
|
||||
setSelectedSystemPrompt({
|
||||
...selectedSystemPrompt,
|
||||
conversations: currentPromptConversations,
|
||||
});
|
||||
let updatedConversationsSettingsBulkActions = { create: {}, update: {} };
|
||||
Object.values(currentPromptConversations).forEach((convo) => {
|
||||
const getApiConfigWithSelectedPrompt = (): ApiConfig | {} => {
|
||||
|
@ -439,7 +405,6 @@ export const useSystemPromptUpdater = ({
|
|||
[
|
||||
systemPromptSettings,
|
||||
selectedSystemPrompt,
|
||||
selectedSystemPromptId,
|
||||
setConversationsSettingsBulkActions,
|
||||
defaultConnector,
|
||||
connectors,
|
||||
|
@ -447,9 +412,10 @@ export const useSystemPromptUpdater = ({
|
|||
);
|
||||
|
||||
const resetSystemPromptSettings = useCallback((): void => {
|
||||
setSystemPromptSettingsUpdates(systemPromptSettings);
|
||||
setConversationsSettingsBulkActions({});
|
||||
setPromptsBulkActions({});
|
||||
}, [systemPromptSettings]);
|
||||
setSelectedSystemPrompt(undefined);
|
||||
}, [setConversationsSettingsBulkActions]);
|
||||
|
||||
const saveSystemPromptSettings = useCallback(async (): Promise<{
|
||||
success: boolean;
|
||||
|
@ -463,36 +429,30 @@ export const useSystemPromptUpdater = ({
|
|||
: undefined;
|
||||
let conversationUpdates;
|
||||
if (
|
||||
bulkPromptsResult?.attributes?.results?.created?.length &&
|
||||
conversationsSettingsBulkActions.update &&
|
||||
Object.keys(conversationsSettingsBulkActions.update).length &&
|
||||
bulkPromptsResult?.success
|
||||
// no prompt update or prompt update succeeded
|
||||
(!bulkPromptsResult || bulkPromptsResult?.success) &&
|
||||
conversationsSettingsBulkActions?.update
|
||||
) {
|
||||
const updatesWithNewIds = conversationsSettingsBulkActions.update
|
||||
? Object.entries(conversationsSettingsBulkActions.update).reduce((acc, [key, value]) => {
|
||||
if (value.apiConfig?.defaultSystemPromptId === '') {
|
||||
// only creating one at a time
|
||||
const createdPrompt = bulkPromptsResult?.attributes?.results?.created[0];
|
||||
if (createdPrompt) {
|
||||
return {
|
||||
...acc,
|
||||
[key]: {
|
||||
...value,
|
||||
apiConfig: { ...value.apiConfig, defaultSystemPromptId: createdPrompt.id },
|
||||
},
|
||||
};
|
||||
const updatesWithNewIds =
|
||||
conversationsSettingsBulkActions.update &&
|
||||
bulkPromptsResult?.attributes?.results?.created?.length
|
||||
? Object.entries(conversationsSettingsBulkActions.update).reduce((acc, [key, value]) => {
|
||||
if (value.apiConfig?.defaultSystemPromptId === '') {
|
||||
// only creating one at a time
|
||||
const createdPrompt = bulkPromptsResult?.attributes?.results?.created[0];
|
||||
if (createdPrompt) {
|
||||
return {
|
||||
...acc,
|
||||
[key]: {
|
||||
...value,
|
||||
apiConfig: { ...value.apiConfig, defaultSystemPromptId: createdPrompt.id },
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
return acc;
|
||||
}, {})
|
||||
: {};
|
||||
setConversationsSettingsBulkActions({
|
||||
...conversationsSettingsBulkActions,
|
||||
update: {
|
||||
...conversationsSettingsBulkActions.update,
|
||||
...updatesWithNewIds,
|
||||
},
|
||||
});
|
||||
return acc;
|
||||
}, {})
|
||||
: {};
|
||||
conversationUpdates = {
|
||||
...conversationsSettingsBulkActions,
|
||||
update: {
|
||||
|
@ -501,13 +461,17 @@ export const useSystemPromptUpdater = ({
|
|||
},
|
||||
};
|
||||
}
|
||||
setPromptsBulkActions({});
|
||||
return { success: bulkPromptsResult?.success ?? false, conversationUpdates };
|
||||
resetSystemPromptSettings();
|
||||
return {
|
||||
// if no bulk update status, only conversations need to update so return success === true
|
||||
success: bulkPromptsResult?.success ?? true,
|
||||
conversationUpdates,
|
||||
};
|
||||
}, [
|
||||
conversationsSettingsBulkActions,
|
||||
http,
|
||||
promptsBulkActions,
|
||||
setConversationsSettingsBulkActions,
|
||||
resetSystemPromptSettings,
|
||||
toasts,
|
||||
]);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue