mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[Security AI Assistant] Improve clear conversation requests efficiency. (#179590)
Improved the number of request for clear conversation functionality.
This commit is contained in:
parent
7b45c42563
commit
1c2679158c
16 changed files with 277 additions and 227 deletions
|
@ -27,7 +27,6 @@ const setUserPrompt = jest.fn();
|
|||
const sendMessage = jest.fn();
|
||||
const removeLastMessage = jest.fn();
|
||||
const clearConversation = jest.fn();
|
||||
const refresh = jest.fn();
|
||||
const setCurrentConversation = jest.fn();
|
||||
|
||||
export const testProps: UseChatSendProps = {
|
||||
|
@ -47,7 +46,6 @@ export const testProps: UseChatSendProps = {
|
|||
setPromptTextPreview,
|
||||
setSelectedPromptContexts,
|
||||
setUserPrompt,
|
||||
refresh,
|
||||
setCurrentConversation,
|
||||
};
|
||||
const robotMessage = { response: 'Response message from the robot', isError: false };
|
||||
|
@ -71,6 +69,7 @@ describe('use chat send', () => {
|
|||
});
|
||||
});
|
||||
it('handleOnChatCleared clears the conversation', async () => {
|
||||
(clearConversation as jest.Mock).mockReturnValueOnce(testProps.currentConversation);
|
||||
const { result } = renderHook(() => useChatSend(testProps), {
|
||||
wrapper: TestProviders,
|
||||
});
|
||||
|
@ -80,8 +79,8 @@ describe('use chat send', () => {
|
|||
expect(setUserPrompt).toHaveBeenCalledWith('');
|
||||
expect(setSelectedPromptContexts).toHaveBeenCalledWith({});
|
||||
await waitFor(() => {
|
||||
expect(clearConversation).toHaveBeenCalledWith(testProps.currentConversation.id);
|
||||
expect(refresh).toHaveBeenCalled();
|
||||
expect(clearConversation).toHaveBeenCalledWith(testProps.currentConversation);
|
||||
expect(setCurrentConversation).toHaveBeenCalled();
|
||||
});
|
||||
expect(setEditingSystemPromptId).toHaveBeenCalledWith(defaultSystemPrompt.id);
|
||||
});
|
||||
|
|
|
@ -28,7 +28,6 @@ export interface UseChatSendProps {
|
|||
React.SetStateAction<Record<string, SelectedPromptContext>>
|
||||
>;
|
||||
setUserPrompt: React.Dispatch<React.SetStateAction<string | null>>;
|
||||
refresh: () => Promise<Conversation | undefined>;
|
||||
setCurrentConversation: React.Dispatch<React.SetStateAction<Conversation>>;
|
||||
}
|
||||
|
||||
|
@ -56,7 +55,6 @@ export const useChatSend = ({
|
|||
setPromptTextPreview,
|
||||
setSelectedPromptContexts,
|
||||
setUserPrompt,
|
||||
refresh,
|
||||
setCurrentConversation,
|
||||
}: UseChatSendProps): UseChatSend => {
|
||||
const {
|
||||
|
@ -209,15 +207,16 @@ export const useChatSend = ({
|
|||
setPromptTextPreview('');
|
||||
setUserPrompt('');
|
||||
setSelectedPromptContexts({});
|
||||
await clearConversation(currentConversation.id);
|
||||
await refresh();
|
||||
|
||||
const updatedConversation = await clearConversation(currentConversation);
|
||||
if (updatedConversation) {
|
||||
setCurrentConversation(updatedConversation);
|
||||
}
|
||||
setEditingSystemPromptId(defaultSystemPromptId);
|
||||
}, [
|
||||
allSystemPrompts,
|
||||
clearConversation,
|
||||
currentConversation,
|
||||
refresh,
|
||||
setCurrentConversation,
|
||||
setEditingSystemPromptId,
|
||||
setPromptTextPreview,
|
||||
setSelectedPromptContexts,
|
||||
|
|
|
@ -458,7 +458,6 @@ const AssistantComponent: React.FC<Props> = ({
|
|||
selectedPromptContexts,
|
||||
setSelectedPromptContexts,
|
||||
setCurrentConversation,
|
||||
refresh: refetchCurrentConversation,
|
||||
});
|
||||
|
||||
const chatbotComments = useMemo(
|
||||
|
|
|
@ -39,7 +39,7 @@ interface SetApiConfigProps {
|
|||
}
|
||||
|
||||
interface UseConversation {
|
||||
clearConversation: (conversationId: string) => Promise<void>;
|
||||
clearConversation: (conversation: Conversation) => Promise<Conversation | undefined>;
|
||||
getDefaultConversation: ({ cTitle, messages }: CreateConversationProps) => Conversation;
|
||||
deleteConversation: (conversationId: string) => void;
|
||||
removeLastMessage: (conversationId: string) => Promise<Message[] | undefined>;
|
||||
|
@ -83,18 +83,17 @@ export const useConversation = (): UseConversation => {
|
|||
);
|
||||
|
||||
const clearConversation = useCallback(
|
||||
async (conversationId: string) => {
|
||||
const conversation = await getConversationById({ http, id: conversationId, toasts });
|
||||
if (conversation && conversation.apiConfig) {
|
||||
async (conversation: Conversation) => {
|
||||
if (conversation.apiConfig) {
|
||||
const defaultSystemPromptId = getDefaultSystemPrompt({
|
||||
allSystemPrompts,
|
||||
conversation,
|
||||
})?.id;
|
||||
|
||||
await updateConversation({
|
||||
return updateConversation({
|
||||
http,
|
||||
toasts,
|
||||
conversationId,
|
||||
conversationId: conversation.id,
|
||||
apiConfig: { ...conversation.apiConfig, defaultSystemPromptId },
|
||||
messages: [],
|
||||
replacements: [],
|
||||
|
|
|
@ -13,10 +13,10 @@ import {
|
|||
ConversationResponse,
|
||||
ConversationUpdateProps,
|
||||
} from '@kbn/elastic-assistant-common';
|
||||
import { SearchEsConversationSchema } from '../ai_assistant_data_clients/conversations/types';
|
||||
import { EsConversationSchema } from '../ai_assistant_data_clients/conversations/types';
|
||||
|
||||
export const getConversationSearchEsMock = () => {
|
||||
const searchResponse: estypes.SearchResponse<SearchEsConversationSchema> = {
|
||||
const searchResponse: estypes.SearchResponse<EsConversationSchema> = {
|
||||
took: 3,
|
||||
timed_out: false,
|
||||
_shards: {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import { httpServerMock } from '@kbn/core/server/mocks';
|
||||
import { getConversationSearchEsMock } from './conversations_schema.mock';
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import { SearchEsConversationSchema } from '../ai_assistant_data_clients/conversations/types';
|
||||
import { EsConversationSchema } from '../ai_assistant_data_clients/conversations/types';
|
||||
import { FindResponse } from '../ai_assistant_data_clients/find';
|
||||
import { ConversationResponse } from '@kbn/elastic-assistant-common';
|
||||
import { SearchEsPromptsSchema } from '../ai_assistant_data_clients/prompts/types';
|
||||
|
@ -20,20 +20,19 @@ export const responseMock = {
|
|||
create: httpServerMock.createResponseFactory,
|
||||
};
|
||||
|
||||
export const getEmptyFindResult = (): FindResponse<SearchEsConversationSchema> => ({
|
||||
export const getEmptyFindResult = (): FindResponse<EsConversationSchema> => ({
|
||||
page: 1,
|
||||
perPage: 1,
|
||||
total: 0,
|
||||
data: getBasicEmptySearchResponse(),
|
||||
});
|
||||
|
||||
export const getFindConversationsResultWithSingleHit =
|
||||
(): FindResponse<SearchEsConversationSchema> => ({
|
||||
page: 1,
|
||||
perPage: 1,
|
||||
total: 1,
|
||||
data: getConversationSearchEsMock(),
|
||||
});
|
||||
export const getFindConversationsResultWithSingleHit = (): FindResponse<EsConversationSchema> => ({
|
||||
page: 1,
|
||||
perPage: 1,
|
||||
total: 1,
|
||||
data: getConversationSearchEsMock(),
|
||||
});
|
||||
|
||||
export const getFindPromptsResultWithSingleHit = (): FindResponse<SearchEsPromptsSchema> => ({
|
||||
page: 1,
|
||||
|
@ -50,17 +49,16 @@ export const getFindAnonymizationFieldsResultWithSingleHit =
|
|||
data: getAnonymizationFieldsSearchEsMock(),
|
||||
});
|
||||
|
||||
export const getBasicEmptySearchResponse =
|
||||
(): estypes.SearchResponse<SearchEsConversationSchema> => ({
|
||||
took: 1,
|
||||
timed_out: false,
|
||||
_shards: { total: 1, successful: 1, skipped: 0, failed: 0 },
|
||||
hits: {
|
||||
hits: [],
|
||||
total: { relation: 'eq', value: 0 },
|
||||
max_score: 0,
|
||||
},
|
||||
});
|
||||
export const getBasicEmptySearchResponse = (): estypes.SearchResponse<EsConversationSchema> => ({
|
||||
took: 1,
|
||||
timed_out: false,
|
||||
_shards: { total: 1, successful: 1, skipped: 0, failed: 0 },
|
||||
hits: {
|
||||
hits: [],
|
||||
total: { relation: 'eq', value: 0 },
|
||||
max_score: 0,
|
||||
},
|
||||
});
|
||||
|
||||
export const getConversationResponseMock = (
|
||||
timestamp: string = new Date().toISOString()
|
||||
|
|
|
@ -9,7 +9,7 @@ import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-m
|
|||
import { createConversation } from './create_conversation';
|
||||
import { loggingSystemMock } from '@kbn/core-logging-server-mocks';
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import { SearchEsConversationSchema } from './types';
|
||||
import { EsConversationSchema } from './types';
|
||||
import { getConversation } from './get_conversation';
|
||||
import { ConversationCreateProps, ConversationResponse } from '@kbn/elastic-assistant-common';
|
||||
import { AuthenticatedUser } from '@kbn/security-plugin-types-common';
|
||||
|
@ -66,54 +66,53 @@ export const getConversationResponseMock = (): ConversationResponse => ({
|
|||
],
|
||||
});
|
||||
|
||||
export const getSearchConversationMock =
|
||||
(): estypes.SearchResponse<SearchEsConversationSchema> => ({
|
||||
_scroll_id: '123',
|
||||
_shards: {
|
||||
failed: 0,
|
||||
skipped: 0,
|
||||
successful: 0,
|
||||
total: 0,
|
||||
},
|
||||
hits: {
|
||||
hits: [
|
||||
{
|
||||
_id: '1',
|
||||
_index: '',
|
||||
_score: 0,
|
||||
_source: {
|
||||
'@timestamp': '2020-04-20T15:25:31.830Z',
|
||||
created_at: '2020-04-20T15:25:31.830Z',
|
||||
title: 'title-1',
|
||||
updated_at: '2020-04-20T15:25:31.830Z',
|
||||
messages: [],
|
||||
category: 'assistant',
|
||||
id: '1',
|
||||
namespace: 'default',
|
||||
is_default: true,
|
||||
exclude_from_last_conversation_storage: false,
|
||||
api_config: {
|
||||
connector_id: 'c1',
|
||||
default_system_prompt_id: 'prompt-1',
|
||||
model: 'test',
|
||||
provider: 'Azure OpenAI',
|
||||
},
|
||||
users: [
|
||||
{
|
||||
id: '1111',
|
||||
name: 'elastic',
|
||||
},
|
||||
],
|
||||
replacements: undefined,
|
||||
export const getSearchConversationMock = (): estypes.SearchResponse<EsConversationSchema> => ({
|
||||
_scroll_id: '123',
|
||||
_shards: {
|
||||
failed: 0,
|
||||
skipped: 0,
|
||||
successful: 0,
|
||||
total: 0,
|
||||
},
|
||||
hits: {
|
||||
hits: [
|
||||
{
|
||||
_id: '1',
|
||||
_index: '',
|
||||
_score: 0,
|
||||
_source: {
|
||||
'@timestamp': '2020-04-20T15:25:31.830Z',
|
||||
created_at: '2020-04-20T15:25:31.830Z',
|
||||
title: 'title-1',
|
||||
updated_at: '2020-04-20T15:25:31.830Z',
|
||||
messages: [],
|
||||
category: 'assistant',
|
||||
id: '1',
|
||||
namespace: 'default',
|
||||
is_default: true,
|
||||
exclude_from_last_conversation_storage: false,
|
||||
api_config: {
|
||||
connector_id: 'c1',
|
||||
default_system_prompt_id: 'prompt-1',
|
||||
model: 'test',
|
||||
provider: 'Azure OpenAI',
|
||||
},
|
||||
users: [
|
||||
{
|
||||
id: '1111',
|
||||
name: 'elastic',
|
||||
},
|
||||
],
|
||||
replacements: undefined,
|
||||
},
|
||||
],
|
||||
max_score: 0,
|
||||
total: 1,
|
||||
},
|
||||
timed_out: false,
|
||||
took: 10,
|
||||
});
|
||||
},
|
||||
],
|
||||
max_score: 0,
|
||||
total: 1,
|
||||
},
|
||||
timed_out: false,
|
||||
took: 10,
|
||||
});
|
||||
|
||||
describe('createConversation', () => {
|
||||
let logger: ReturnType<typeof loggingSystemMock.createLogger>;
|
||||
|
|
|
@ -9,7 +9,7 @@ import type { Logger } from '@kbn/core/server';
|
|||
import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks';
|
||||
import { getConversation } from './get_conversation';
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import { SearchEsConversationSchema } from './types';
|
||||
import { EsConversationSchema } from './types';
|
||||
import { loggingSystemMock } from '@kbn/core-logging-server-mocks';
|
||||
import { ConversationResponse } from '@kbn/elastic-assistant-common';
|
||||
import { AuthenticatedUser } from '@kbn/security-plugin-types-common';
|
||||
|
@ -51,57 +51,56 @@ const mockUser1 = {
|
|||
},
|
||||
} as AuthenticatedUser;
|
||||
|
||||
export const getSearchConversationMock =
|
||||
(): estypes.SearchResponse<SearchEsConversationSchema> => ({
|
||||
_scroll_id: '123',
|
||||
_shards: {
|
||||
failed: 0,
|
||||
skipped: 0,
|
||||
successful: 0,
|
||||
total: 0,
|
||||
},
|
||||
hits: {
|
||||
hits: [
|
||||
{
|
||||
_id: '1',
|
||||
_index: '',
|
||||
_score: 0,
|
||||
_source: {
|
||||
'@timestamp': '2020-04-20T15:25:31.830Z',
|
||||
created_at: '2020-04-20T15:25:31.830Z',
|
||||
title: 'title-1',
|
||||
updated_at: '2020-04-20T15:25:31.830Z',
|
||||
messages: [],
|
||||
id: '1',
|
||||
namespace: 'default',
|
||||
is_default: true,
|
||||
exclude_from_last_conversation_storage: false,
|
||||
api_config: {
|
||||
connector_id: 'c1',
|
||||
default_system_prompt_id: 'prompt-1',
|
||||
model: 'test',
|
||||
provider: 'Azure OpenAI',
|
||||
},
|
||||
summary: {
|
||||
content: 'test',
|
||||
},
|
||||
category: 'assistant',
|
||||
users: [
|
||||
{
|
||||
id: '1111',
|
||||
name: 'elastic',
|
||||
},
|
||||
],
|
||||
replacements: undefined,
|
||||
export const getSearchConversationMock = (): estypes.SearchResponse<EsConversationSchema> => ({
|
||||
_scroll_id: '123',
|
||||
_shards: {
|
||||
failed: 0,
|
||||
skipped: 0,
|
||||
successful: 0,
|
||||
total: 0,
|
||||
},
|
||||
hits: {
|
||||
hits: [
|
||||
{
|
||||
_id: '1',
|
||||
_index: '',
|
||||
_score: 0,
|
||||
_source: {
|
||||
'@timestamp': '2020-04-20T15:25:31.830Z',
|
||||
created_at: '2020-04-20T15:25:31.830Z',
|
||||
title: 'title-1',
|
||||
updated_at: '2020-04-20T15:25:31.830Z',
|
||||
messages: [],
|
||||
id: '1',
|
||||
namespace: 'default',
|
||||
is_default: true,
|
||||
exclude_from_last_conversation_storage: false,
|
||||
api_config: {
|
||||
connector_id: 'c1',
|
||||
default_system_prompt_id: 'prompt-1',
|
||||
model: 'test',
|
||||
provider: 'Azure OpenAI',
|
||||
},
|
||||
summary: {
|
||||
content: 'test',
|
||||
},
|
||||
category: 'assistant',
|
||||
users: [
|
||||
{
|
||||
id: '1111',
|
||||
name: 'elastic',
|
||||
},
|
||||
],
|
||||
replacements: undefined,
|
||||
},
|
||||
],
|
||||
max_score: 0,
|
||||
total: 1,
|
||||
},
|
||||
timed_out: false,
|
||||
took: 10,
|
||||
});
|
||||
},
|
||||
],
|
||||
max_score: 0,
|
||||
total: 1,
|
||||
},
|
||||
timed_out: false,
|
||||
took: 10,
|
||||
});
|
||||
|
||||
describe('getConversation', () => {
|
||||
let loggerMock: Logger;
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
import { ElasticsearchClient, Logger } from '@kbn/core/server';
|
||||
import { ConversationResponse } from '@kbn/elastic-assistant-common';
|
||||
import { AuthenticatedUser } from '@kbn/security-plugin/common';
|
||||
import { SearchEsConversationSchema } from './types';
|
||||
import { transformESToConversations } from './transforms';
|
||||
import { EsConversationSchema } from './types';
|
||||
import { transformESSearchToConversations } from './transforms';
|
||||
|
||||
export interface GetConversationParams {
|
||||
esClient: ElasticsearchClient;
|
||||
|
@ -47,7 +47,7 @@ export const getConversation = async ({
|
|||
]
|
||||
: [];
|
||||
try {
|
||||
const response = await esClient.search<SearchEsConversationSchema>({
|
||||
const response = await esClient.search<EsConversationSchema>({
|
||||
body: {
|
||||
query: {
|
||||
bool: {
|
||||
|
@ -73,7 +73,7 @@ export const getConversation = async ({
|
|||
index: conversationIndex,
|
||||
seq_no_primary_term: true,
|
||||
});
|
||||
const conversation = transformESToConversations(response);
|
||||
const conversation = transformESSearchToConversations(response);
|
||||
return conversation[0] ?? null;
|
||||
} catch (err) {
|
||||
logger.error(`Error fetching conversation: ${err} with id: ${id}`);
|
||||
|
|
|
@ -11,10 +11,10 @@ import {
|
|||
Replacement,
|
||||
replaceOriginalValuesWithUuidValues,
|
||||
} from '@kbn/elastic-assistant-common';
|
||||
import { SearchEsConversationSchema } from './types';
|
||||
import { EsConversationSchema } from './types';
|
||||
|
||||
export const transformESToConversations = (
|
||||
response: estypes.SearchResponse<SearchEsConversationSchema>
|
||||
export const transformESSearchToConversations = (
|
||||
response: estypes.SearchResponse<EsConversationSchema>
|
||||
): ConversationResponse[] => {
|
||||
return response.hits.hits
|
||||
.filter((hit) => hit._source !== undefined)
|
||||
|
@ -75,3 +75,61 @@ export const transformESToConversations = (
|
|||
return conversation;
|
||||
});
|
||||
};
|
||||
|
||||
export const transformESToConversations = (
|
||||
response: EsConversationSchema[]
|
||||
): ConversationResponse[] => {
|
||||
return response.map((conversationSchema) => {
|
||||
const conversation: ConversationResponse = {
|
||||
timestamp: conversationSchema['@timestamp'],
|
||||
createdAt: conversationSchema.created_at,
|
||||
users:
|
||||
conversationSchema.users?.map((user) => ({
|
||||
id: user.id,
|
||||
name: user.name,
|
||||
})) ?? [],
|
||||
title: conversationSchema.title,
|
||||
category: conversationSchema.category,
|
||||
summary: conversationSchema.summary,
|
||||
...(conversationSchema.api_config
|
||||
? {
|
||||
apiConfig: {
|
||||
connectorId: conversationSchema.api_config.connector_id,
|
||||
defaultSystemPromptId: conversationSchema.api_config.default_system_prompt_id,
|
||||
model: conversationSchema.api_config.model,
|
||||
provider: conversationSchema.api_config.provider,
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
excludeFromLastConversationStorage: conversationSchema.exclude_from_last_conversation_storage,
|
||||
isDefault: conversationSchema.is_default,
|
||||
messages:
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
conversationSchema.messages?.map((message: Record<string, any>) => ({
|
||||
timestamp: message['@timestamp'],
|
||||
// always return anonymized data from the client
|
||||
content: replaceOriginalValuesWithUuidValues({
|
||||
messageContent: message.content,
|
||||
replacements: conversationSchema.replacements ?? [],
|
||||
}),
|
||||
...(message.is_error ? { isError: message.is_error } : {}),
|
||||
...(message.reader ? { reader: message.reader } : {}),
|
||||
role: message.role,
|
||||
...(message.trace_data
|
||||
? {
|
||||
traceData: {
|
||||
traceId: message.trace_data?.trace_id,
|
||||
transactionId: message.trace_data?.transaction_id,
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
})) ?? [],
|
||||
updatedAt: conversationSchema.updated_at,
|
||||
replacements: conversationSchema.replacements as Replacement[],
|
||||
namespace: conversationSchema.namespace,
|
||||
id: conversationSchema.id,
|
||||
};
|
||||
|
||||
return conversation;
|
||||
});
|
||||
};
|
||||
|
|
|
@ -14,7 +14,7 @@ import {
|
|||
Replacement,
|
||||
} from '@kbn/elastic-assistant-common';
|
||||
|
||||
export interface SearchEsConversationSchema {
|
||||
export interface EsConversationSchema {
|
||||
id: string;
|
||||
'@timestamp': string;
|
||||
created_at: string;
|
||||
|
|
|
@ -11,7 +11,7 @@ import { estypes } from '@elastic/elasticsearch';
|
|||
import { loggingSystemMock } from '@kbn/core-logging-server-mocks';
|
||||
import { ConversationResponse } from '@kbn/elastic-assistant-common';
|
||||
import { findDocuments } from './find';
|
||||
import { SearchEsConversationSchema } from './conversations/types';
|
||||
import { EsConversationSchema } from './conversations/types';
|
||||
|
||||
export const findDocumentsResponseMock = (): ConversationResponse => ({
|
||||
createdAt: '2020-04-20T15:25:31.830Z',
|
||||
|
@ -42,57 +42,56 @@ export const findDocumentsResponseMock = (): ConversationResponse => ({
|
|||
replacements: undefined,
|
||||
});
|
||||
|
||||
export const getSearchConversationMock =
|
||||
(): estypes.SearchResponse<SearchEsConversationSchema> => ({
|
||||
_scroll_id: '123',
|
||||
_shards: {
|
||||
failed: 0,
|
||||
skipped: 0,
|
||||
successful: 0,
|
||||
total: 0,
|
||||
},
|
||||
hits: {
|
||||
hits: [
|
||||
{
|
||||
_id: '1',
|
||||
_index: '',
|
||||
_score: 0,
|
||||
_source: {
|
||||
'@timestamp': '2020-04-20T15:25:31.830Z',
|
||||
created_at: '2020-04-20T15:25:31.830Z',
|
||||
title: 'title-1',
|
||||
updated_at: '2020-04-20T15:25:31.830Z',
|
||||
messages: [],
|
||||
id: '1',
|
||||
namespace: 'default',
|
||||
is_default: true,
|
||||
exclude_from_last_conversation_storage: false,
|
||||
api_config: {
|
||||
connector_id: 'c1',
|
||||
default_system_prompt_id: 'prompt-1',
|
||||
model: 'test',
|
||||
provider: 'Azure OpenAI',
|
||||
},
|
||||
summary: {
|
||||
content: 'test',
|
||||
},
|
||||
category: 'assistant',
|
||||
users: [
|
||||
{
|
||||
id: '1111',
|
||||
name: 'elastic',
|
||||
},
|
||||
],
|
||||
replacements: undefined,
|
||||
export const getSearchConversationMock = (): estypes.SearchResponse<EsConversationSchema> => ({
|
||||
_scroll_id: '123',
|
||||
_shards: {
|
||||
failed: 0,
|
||||
skipped: 0,
|
||||
successful: 0,
|
||||
total: 0,
|
||||
},
|
||||
hits: {
|
||||
hits: [
|
||||
{
|
||||
_id: '1',
|
||||
_index: '',
|
||||
_score: 0,
|
||||
_source: {
|
||||
'@timestamp': '2020-04-20T15:25:31.830Z',
|
||||
created_at: '2020-04-20T15:25:31.830Z',
|
||||
title: 'title-1',
|
||||
updated_at: '2020-04-20T15:25:31.830Z',
|
||||
messages: [],
|
||||
id: '1',
|
||||
namespace: 'default',
|
||||
is_default: true,
|
||||
exclude_from_last_conversation_storage: false,
|
||||
api_config: {
|
||||
connector_id: 'c1',
|
||||
default_system_prompt_id: 'prompt-1',
|
||||
model: 'test',
|
||||
provider: 'Azure OpenAI',
|
||||
},
|
||||
summary: {
|
||||
content: 'test',
|
||||
},
|
||||
category: 'assistant',
|
||||
users: [
|
||||
{
|
||||
id: '1111',
|
||||
name: 'elastic',
|
||||
},
|
||||
],
|
||||
replacements: undefined,
|
||||
},
|
||||
],
|
||||
max_score: 0,
|
||||
total: 1,
|
||||
},
|
||||
timed_out: false,
|
||||
took: 10,
|
||||
});
|
||||
},
|
||||
],
|
||||
max_score: 0,
|
||||
total: 1,
|
||||
},
|
||||
timed_out: false,
|
||||
took: 10,
|
||||
});
|
||||
|
||||
describe('findDocuments', () => {
|
||||
let loggerMock: Logger;
|
||||
|
|
|
@ -28,7 +28,7 @@ interface WriterBulkResponse {
|
|||
errors: BulkOperationError[];
|
||||
docs_created: string[];
|
||||
docs_deleted: string[];
|
||||
docs_updated: string[];
|
||||
docs_updated: unknown[];
|
||||
took: number;
|
||||
}
|
||||
|
||||
|
@ -78,13 +78,13 @@ export class DocumentsDataWriter implements DocumentsDataWriter {
|
|||
errors: errors ? this.formatErrorsResponse(items) : [],
|
||||
docs_created: items
|
||||
.filter((item) => item.create?.status === 201 || item.create?.status === 200)
|
||||
.map((item) => item.create?._id ?? ''),
|
||||
.map((item) => item.create?._id),
|
||||
docs_deleted: items
|
||||
.filter((item) => item.delete?.status === 201 || item.delete?.status === 200)
|
||||
.map((item) => item.delete?._id ?? ''),
|
||||
.map((item) => item.delete?._id),
|
||||
docs_updated: items
|
||||
.filter((item) => item.update?.status === 201 || item.update?.status === 200)
|
||||
.map((item) => item.update?._id ?? ''),
|
||||
.map((item) => item.update?.get?._source),
|
||||
took,
|
||||
} as WriterBulkResponse;
|
||||
} catch (e) {
|
||||
|
@ -170,6 +170,7 @@ export class DocumentsDataWriter implements DocumentsDataWriter {
|
|||
update: {
|
||||
_id: document.id,
|
||||
_index: responseToUpdate?.hits.hits.find((c) => c._id === document.id)?._index,
|
||||
_source: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
|
@ -74,14 +74,14 @@ describe('Perform bulk action route', () => {
|
|||
expect(response.status).toEqual(200);
|
||||
expect(response.body).toEqual({
|
||||
success: true,
|
||||
conversations_count: 2,
|
||||
conversations_count: 3,
|
||||
attributes: {
|
||||
results: someBulkActionResults(),
|
||||
summary: {
|
||||
failed: 0,
|
||||
skipped: 0,
|
||||
succeeded: 2,
|
||||
total: 2,
|
||||
succeeded: 3,
|
||||
total: 3,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -94,7 +94,7 @@ describe('Perform bulk action route', () => {
|
|||
(await clients.elasticAssistant.getAIAssistantConversationsDataClient.getWriter())
|
||||
.bulk as jest.Mock
|
||||
).mockResolvedValue({
|
||||
docs_created: [mockConversation, mockConversation],
|
||||
docs_created: ['49403909-ca9b-49ba-9d7a-7e5320e68d04'],
|
||||
docs_updated: [],
|
||||
docs_deleted: [],
|
||||
errors: [
|
||||
|
@ -130,9 +130,9 @@ describe('Perform bulk action route', () => {
|
|||
attributes: {
|
||||
summary: {
|
||||
failed: 3,
|
||||
succeeded: 2,
|
||||
succeeded: 1,
|
||||
skipped: 0,
|
||||
total: 5,
|
||||
total: 4,
|
||||
},
|
||||
errors: [
|
||||
{
|
||||
|
|
|
@ -26,12 +26,15 @@ import { ElasticAssistantPluginRouter } from '../../types';
|
|||
import { buildResponse } from '../utils';
|
||||
import { getUpdateScript } from '../../ai_assistant_data_clients/conversations/helpers';
|
||||
import { transformToCreateScheme } from '../../ai_assistant_data_clients/conversations/create_conversation';
|
||||
import { transformESToConversations } from '../../ai_assistant_data_clients/conversations/transforms';
|
||||
import {
|
||||
transformESToConversations,
|
||||
transformESSearchToConversations,
|
||||
} from '../../ai_assistant_data_clients/conversations/transforms';
|
||||
import {
|
||||
UpdateConversationSchema,
|
||||
transformToUpdateScheme,
|
||||
} from '../../ai_assistant_data_clients/conversations/update_conversation';
|
||||
import { SearchEsConversationSchema } from '../../ai_assistant_data_clients/conversations/types';
|
||||
import { EsConversationSchema } from '../../ai_assistant_data_clients/conversations/types';
|
||||
|
||||
export interface BulkOperationError {
|
||||
message: string;
|
||||
|
@ -163,7 +166,7 @@ export const bulkActionConversationsRoute = (
|
|||
}
|
||||
|
||||
if (body.create && body.create.length > 0) {
|
||||
const result = await dataClient?.findDocuments<SearchEsConversationSchema>({
|
||||
const result = await dataClient?.findDocuments<EsConversationSchema>({
|
||||
perPage: 100,
|
||||
page: 1,
|
||||
filter: `users:{ id: "${authenticatedUser?.profile_uid}" } AND (${body.create
|
||||
|
@ -174,7 +177,7 @@ export const bulkActionConversationsRoute = (
|
|||
if (result?.data != null && result.total > 0) {
|
||||
return assistantResponse.error({
|
||||
statusCode: 409,
|
||||
body: `conversations titles: "${transformESToConversations(result.data)
|
||||
body: `conversations titles: "${transformESSearchToConversations(result.data)
|
||||
.map((c) => c.title)
|
||||
.join(',')}" already exists`,
|
||||
});
|
||||
|
@ -199,23 +202,20 @@ export const bulkActionConversationsRoute = (
|
|||
getUpdateScript: (document: UpdateConversationSchema) =>
|
||||
getUpdateScript({ conversation: document, isPatch: true }),
|
||||
});
|
||||
|
||||
const created = await dataClient?.findDocuments<SearchEsConversationSchema>({
|
||||
page: 1,
|
||||
perPage: 1000,
|
||||
filter: docsCreated.map((c) => `id:${c}`).join(' OR '),
|
||||
fields: ['id'],
|
||||
});
|
||||
const updated = await dataClient?.findDocuments<SearchEsConversationSchema>({
|
||||
page: 1,
|
||||
perPage: 1000,
|
||||
filter: docsUpdated.map((c) => `id:${c}`).join(' OR '),
|
||||
fields: ['id'],
|
||||
});
|
||||
const created =
|
||||
docsCreated.length > 0
|
||||
? await dataClient?.findDocuments<EsConversationSchema>({
|
||||
page: 1,
|
||||
perPage: 100,
|
||||
filter: docsCreated.map((c) => `_id:${c}`).join(' OR '),
|
||||
})
|
||||
: undefined;
|
||||
|
||||
return buildBulkResponse(response, {
|
||||
updated: updated?.data ? transformESToConversations(updated?.data) : [],
|
||||
created: created?.data ? transformESToConversations(created?.data) : [],
|
||||
updated: docsUpdated
|
||||
? transformESToConversations(docsUpdated as EsConversationSchema[])
|
||||
: [],
|
||||
created: created?.data ? transformESSearchToConversations(created?.data) : [],
|
||||
deleted: docsDeleted ?? [],
|
||||
errors,
|
||||
});
|
||||
|
|
|
@ -19,8 +19,8 @@ import {
|
|||
import { buildRouteValidationWithZod } from '@kbn/elastic-assistant-common/impl/schemas/common';
|
||||
import { ElasticAssistantPluginRouter } from '../../types';
|
||||
import { buildResponse } from '../utils';
|
||||
import { SearchEsConversationSchema } from '../../ai_assistant_data_clients/conversations/types';
|
||||
import { transformESToConversations } from '../../ai_assistant_data_clients/conversations/transforms';
|
||||
import { EsConversationSchema } from '../../ai_assistant_data_clients/conversations/types';
|
||||
import { transformESSearchToConversations } from '../../ai_assistant_data_clients/conversations/transforms';
|
||||
|
||||
export const findUserConversationsRoute = (router: ElasticAssistantPluginRouter) => {
|
||||
router.versioned
|
||||
|
@ -49,7 +49,7 @@ export const findUserConversationsRoute = (router: ElasticAssistantPluginRouter)
|
|||
const currentUser = ctx.elasticAssistant.getCurrentUser();
|
||||
|
||||
const additionalFilter = query.filter ? ` AND ${query.filter}` : '';
|
||||
const result = await dataClient?.findDocuments<SearchEsConversationSchema>({
|
||||
const result = await dataClient?.findDocuments<EsConversationSchema>({
|
||||
perPage: query.per_page,
|
||||
page: query.page,
|
||||
sortField: query.sort_field,
|
||||
|
@ -64,7 +64,7 @@ export const findUserConversationsRoute = (router: ElasticAssistantPluginRouter)
|
|||
perPage: result.perPage,
|
||||
page: result.page,
|
||||
total: result.total,
|
||||
data: transformESToConversations(result.data),
|
||||
data: transformESSearchToConversations(result.data),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue