From d6acbad73f04cfd413d32192cefa8bc613185de7 Mon Sep 17 00:00:00 2001 From: Jason Botzas-Coluni <44372106+jaybcee@users.noreply.github.com> Date: Fri, 19 Dec 2025 10:39:35 -0500 Subject: [PATCH 1/5] Add refusal field to assistant conversations (#243423) (cherry picked from commit fe9c9fd75355732baf10cda2b70fe4bb9f36652b) # Conflicts: # x-pack/solutions/security/plugins/elastic_assistant/server/lib/langchain/executors/types.ts # x-pack/solutions/security/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/helpers.ts # x-pack/solutions/security/plugins/elastic_assistant/server/routes/chat/chat_complete_route.ts # x-pack/solutions/security/plugins/elastic_assistant/server/routes/post_actions_connector_execute.ts --- oas_docs/output/kibana.serverless.yaml | 3 +++ oas_docs/output/kibana.yaml | 3 +++ .../inference-common/src/chat_complete/api.ts | 4 ++++ .../src/chat_complete/events.ts | 8 +++++++ .../src/chat_complete/messages.ts | 4 ++++ .../src/chat_model/from_inference/chunks.ts | 4 +++- .../src/chat_model/from_inference/messages.ts | 2 ++ ...sistant_api_2023_10_31.bundled.schema.yaml | 3 +++ ...sistant_api_2023_10_31.bundled.schema.yaml | 3 +++ .../conversations/common_attributes.gen.ts | 4 ++++ .../common_attributes.schema.yaml | 3 +++ .../adapters/openai/from_openai.ts | 1 + .../utils/chunks_into_message.ts | 3 ++- .../chat_complete/utils/merge_chunks.ts | 4 ++++ .../chat_complete/utils/stream_to_response.ts | 1 + .../connector_types/inference/helpers.ts | 4 ++++ .../append_conversation_messages.test.ts | 23 +++++++++++++++++++ .../append_conversation_messages.ts | 1 + .../conversations/create_conversation.ts | 1 + .../conversations/field_maps_configuration.ts | 5 ++++ .../conversations/transforms.ts | 1 + .../conversations/types.ts | 2 ++ .../conversations/update_conversation.ts | 2 ++ .../server/lib/langchain/executors/types.ts | 3 ++- .../graphs/default_assistant_graph/helpers.ts | 17 ++++++++++---- .../server/routes/chat/chat_complete_route.ts | 4 +++- .../server/routes/helpers.ts | 6 +++++ .../routes/post_actions_connector_execute.ts | 4 +++- 28 files changed, 114 insertions(+), 9 deletions(-) diff --git a/oas_docs/output/kibana.serverless.yaml b/oas_docs/output/kibana.serverless.yaml index e604a035844fb..35723ce94245d 100644 --- a/oas_docs/output/kibana.serverless.yaml +++ b/oas_docs/output/kibana.serverless.yaml @@ -72151,6 +72151,9 @@ components: reader: $ref: '#/components/schemas/Security_AI_Assistant_API_Reader' description: Message content. + refusal: + description: Refusal reason returned by the model when content is filtered. + type: string role: $ref: '#/components/schemas/Security_AI_Assistant_API_MessageRole' description: Message role. diff --git a/oas_docs/output/kibana.yaml b/oas_docs/output/kibana.yaml index b1a829072fbd7..1e732fd07eba4 100644 --- a/oas_docs/output/kibana.yaml +++ b/oas_docs/output/kibana.yaml @@ -82877,6 +82877,9 @@ components: reader: $ref: '#/components/schemas/Security_AI_Assistant_API_Reader' description: Message content. + refusal: + description: Refusal reason returned by the model when content is filtered. + type: string role: $ref: '#/components/schemas/Security_AI_Assistant_API_MessageRole' description: Message role. diff --git a/x-pack/platform/packages/shared/ai-infra/inference-common/src/chat_complete/api.ts b/x-pack/platform/packages/shared/ai-infra/inference-common/src/chat_complete/api.ts index dff09b87feb04..6890ca3446a4a 100644 --- a/x-pack/platform/packages/shared/ai-infra/inference-common/src/chat_complete/api.ts +++ b/x-pack/platform/packages/shared/ai-infra/inference-common/src/chat_complete/api.ts @@ -197,6 +197,10 @@ export interface ChatCompleteResponse< * The text content of the LLM response. */ content: string; + /** + * Optional refusal reason returned by the model when content is filtered. + */ + refusal?: string; /** * The eventual tool calls performed by the LLM. */ diff --git a/x-pack/platform/packages/shared/ai-infra/inference-common/src/chat_complete/events.ts b/x-pack/platform/packages/shared/ai-infra/inference-common/src/chat_complete/events.ts index 6d42329fac396..df1a38ebb7aaa 100644 --- a/x-pack/platform/packages/shared/ai-infra/inference-common/src/chat_complete/events.ts +++ b/x-pack/platform/packages/shared/ai-infra/inference-common/src/chat_complete/events.ts @@ -32,6 +32,10 @@ export type ChatCompletionMessageEvent { + const additionalKwargs = response.refusal ? { refusal: response.refusal } : undefined; return new AIMessage({ content: response.content, + ...(additionalKwargs ? { additional_kwargs: additionalKwargs } : {}), tool_calls: response.toolCalls.map((toolCall) => { return { id: toolCall.toolCallId, diff --git a/x-pack/platform/packages/shared/kbn-elastic-assistant-common/docs/openapi/ess/elastic_assistant_api_2023_10_31.bundled.schema.yaml b/x-pack/platform/packages/shared/kbn-elastic-assistant-common/docs/openapi/ess/elastic_assistant_api_2023_10_31.bundled.schema.yaml index afc478426ac6d..55d9e7a0a8f1c 100644 --- a/x-pack/platform/packages/shared/kbn-elastic-assistant-common/docs/openapi/ess/elastic_assistant_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/platform/packages/shared/kbn-elastic-assistant-common/docs/openapi/ess/elastic_assistant_api_2023_10_31.bundled.schema.yaml @@ -2837,6 +2837,9 @@ components: reader: $ref: '#/components/schemas/Reader' description: Message content. + refusal: + description: Refusal reason returned by the model when content is filtered. + type: string role: $ref: '#/components/schemas/MessageRole' description: Message role. diff --git a/x-pack/platform/packages/shared/kbn-elastic-assistant-common/docs/openapi/serverless/elastic_assistant_api_2023_10_31.bundled.schema.yaml b/x-pack/platform/packages/shared/kbn-elastic-assistant-common/docs/openapi/serverless/elastic_assistant_api_2023_10_31.bundled.schema.yaml index 15fab477cff8e..e48088304f1e2 100644 --- a/x-pack/platform/packages/shared/kbn-elastic-assistant-common/docs/openapi/serverless/elastic_assistant_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/platform/packages/shared/kbn-elastic-assistant-common/docs/openapi/serverless/elastic_assistant_api_2023_10_31.bundled.schema.yaml @@ -2837,6 +2837,9 @@ components: reader: $ref: '#/components/schemas/Reader' description: Message content. + refusal: + description: Refusal reason returned by the model when content is filtered. + type: string role: $ref: '#/components/schemas/MessageRole' description: Message role. diff --git a/x-pack/platform/packages/shared/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.gen.ts b/x-pack/platform/packages/shared/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.gen.ts index facfc0674e071..2dc435b0a2c44 100644 --- a/x-pack/platform/packages/shared/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.gen.ts +++ b/x-pack/platform/packages/shared/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.gen.ts @@ -244,6 +244,10 @@ export const Message = z.object({ * Message content. */ content: z.string(), + /** + * Refusal reason returned by the model when content is filtered. + */ + refusal: z.string().optional(), /** * Message content. */ diff --git a/x-pack/platform/packages/shared/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.schema.yaml b/x-pack/platform/packages/shared/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.schema.yaml index c43f6a06097ae..74d4fa3a4d462 100644 --- a/x-pack/platform/packages/shared/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.schema.yaml +++ b/x-pack/platform/packages/shared/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.schema.yaml @@ -251,6 +251,9 @@ components: type: string description: Message content. example: 'Hello, how can I assist you today?' + refusal: + type: string + description: Refusal reason returned by the model when content is filtered. reader: $ref: '#/components/schemas/Reader' description: Message content. diff --git a/x-pack/platform/plugins/shared/inference/server/chat_complete/adapters/openai/from_openai.ts b/x-pack/platform/plugins/shared/inference/server/chat_complete/adapters/openai/from_openai.ts index 12815144d599b..813054f878176 100644 --- a/x-pack/platform/plugins/shared/inference/server/chat_complete/adapters/openai/from_openai.ts +++ b/x-pack/platform/plugins/shared/inference/server/chat_complete/adapters/openai/from_openai.ts @@ -18,6 +18,7 @@ export function chunkFromOpenAI(chunk: OpenAI.ChatCompletionChunk): ChatCompleti return { type: ChatCompletionEventType.ChatCompletionChunk, content: delta.content ?? '', + refusal: delta.refusal ?? undefined, tool_calls: delta.tool_calls?.map((toolCall) => { return { diff --git a/x-pack/platform/plugins/shared/inference/server/chat_complete/utils/chunks_into_message.ts b/x-pack/platform/plugins/shared/inference/server/chat_complete/utils/chunks_into_message.ts index 06ccdba3c6338..545c224fc7d5f 100644 --- a/x-pack/platform/plugins/shared/inference/server/chat_complete/utils/chunks_into_message.ts +++ b/x-pack/platform/plugins/shared/inference/server/chat_complete/utils/chunks_into_message.ts @@ -45,7 +45,7 @@ export function chunksIntoMessage({ logger.debug(() => `Received completed message: ${JSON.stringify(concatenatedChunk)}`); - const { content, tool_calls: toolCalls } = concatenatedChunk; + const { content, refusal, tool_calls: toolCalls } = concatenatedChunk; const activeSpan = trace.getActiveSpan(); if (activeSpan) { setChoice(activeSpan, { content, toolCalls }); @@ -59,6 +59,7 @@ export function chunksIntoMessage({ return { type: ChatCompletionEventType.ChatCompletionMessage, content, + ...(refusal ? { refusal } : {}), toolCalls: validatedToolCalls, }; }) diff --git a/x-pack/platform/plugins/shared/inference/server/chat_complete/utils/merge_chunks.ts b/x-pack/platform/plugins/shared/inference/server/chat_complete/utils/merge_chunks.ts index e3e1304d2247e..d2760616260a0 100644 --- a/x-pack/platform/plugins/shared/inference/server/chat_complete/utils/merge_chunks.ts +++ b/x-pack/platform/plugins/shared/inference/server/chat_complete/utils/merge_chunks.ts @@ -9,6 +9,7 @@ import type { ChatCompletionChunkEvent, UnvalidatedToolCall } from '@kbn/inferen interface UnvalidatedMessage { content: string; + refusal?: string; tool_calls: UnvalidatedToolCall[]; } @@ -19,6 +20,9 @@ export const mergeChunks = (chunks: ChatCompletionChunkEvent[]): UnvalidatedMess const message = chunks.reduce( (prev, chunk) => { prev.content += chunk.content ?? ''; + if (chunk.refusal) { + prev.refusal = chunk.refusal; + } chunk.tool_calls?.forEach((toolCall) => { let prevToolCall = prev.tool_calls[toolCall.index]; diff --git a/x-pack/platform/plugins/shared/inference/server/chat_complete/utils/stream_to_response.ts b/x-pack/platform/plugins/shared/inference/server/chat_complete/utils/stream_to_response.ts index ca414855d4cf3..15bf1d22f3390 100644 --- a/x-pack/platform/plugins/shared/inference/server/chat_complete/utils/stream_to_response.ts +++ b/x-pack/platform/plugins/shared/inference/server/chat_complete/utils/stream_to_response.ts @@ -35,6 +35,7 @@ export const streamToResponse = return { content: messageEvent.content, + refusal: messageEvent.refusal, toolCalls: messageEvent.toolCalls, tokens: tokenEvent?.tokens, deanonymized_input: messageEvent.deanonymized_input, diff --git a/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/inference/helpers.ts b/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/inference/helpers.ts index 05faf03a6ff3f..74728cddf0dd1 100644 --- a/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/inference/helpers.ts +++ b/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/inference/helpers.ts @@ -47,6 +47,9 @@ export function chunksIntoMessage(obs$: Observable) (prev, chunk) => { if (chunk.choices.length > 0 && !chunk.usage) { prev.choices[0].message.content += chunk.choices[0].message.content ?? ''; + if (chunk.choices[0].message.refusal) { + prev.choices[0].message.refusal = chunk.choices[0].message.refusal; + } chunk.choices[0].message.tool_calls?.forEach((toolCall) => { if (toolCall.index !== undefined) { @@ -89,6 +92,7 @@ export function chunksIntoMessage(obs$: Observable) { message: { content: '', + refusal: null, role: 'assistant', }, }, diff --git a/x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/append_conversation_messages.test.ts b/x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/append_conversation_messages.test.ts index d87fad534046b..bda2d9bf32e8d 100644 --- a/x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/append_conversation_messages.test.ts +++ b/x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/append_conversation_messages.test.ts @@ -326,6 +326,29 @@ describe('appendConversationMessages', () => { ); }); + it('preserves refusal reason when present on messages', async () => { + const messageWithRefusal = createMockMessage({ + refusal: 'Detected harmful input content: INSULTS', + }); + setupSuccessfulTest(); + + await callAppendConversationMessages([messageWithRefusal]); + + expect(dataWriter.bulk).toHaveBeenCalledWith( + expect.objectContaining({ + documentsToUpdate: expect.arrayContaining([ + expect.objectContaining({ + messages: expect.arrayContaining([ + expect.objectContaining({ + refusal: 'Detected harmful input content: INSULTS', + }), + ]), + }), + ]), + }) + ); + }); + it('generates UUID for messages without id', async () => { const messageWithoutId = createMockMessage({ id: undefined }); setupSuccessfulTest(); diff --git a/x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/append_conversation_messages.ts b/x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/append_conversation_messages.ts index e22dc733fb086..de5bf8e3645f7 100644 --- a/x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/append_conversation_messages.ts +++ b/x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/append_conversation_messages.ts @@ -106,6 +106,7 @@ export const transformToUpdateScheme = ( '@timestamp': message.timestamp, id: message.id ?? uuidv4(), content: message.content, + ...(message.refusal ? { refusal: message.refusal } : {}), is_error: message.isError, reader: message.reader, role: message.role, diff --git a/x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/create_conversation.ts b/x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/create_conversation.ts index c5759e78b36b6..5cfe8a6294b5f 100644 --- a/x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/create_conversation.ts +++ b/x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/create_conversation.ts @@ -96,6 +96,7 @@ export const transformToCreateScheme = ( '@timestamp': message.timestamp, id: message.id ?? uuidv4(), content: message.content, + ...(message.refusal ? { refusal: message.refusal } : {}), is_error: message.isError, reader: message.reader, role: message.role, diff --git a/x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/field_maps_configuration.ts b/x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/field_maps_configuration.ts index ffc771c71b94d..546a8ea580947 100644 --- a/x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/field_maps_configuration.ts +++ b/x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/field_maps_configuration.ts @@ -92,6 +92,11 @@ export const conversationsFieldMap: FieldMap = { array: false, required: false, }, + 'messages.refusal': { + type: 'text', + array: false, + required: false, + }, 'messages.reader': { type: 'object', array: false, diff --git a/x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/transforms.ts b/x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/transforms.ts index 70d882f7e4d81..a9121328b0471 100644 --- a/x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/transforms.ts +++ b/x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/transforms.ts @@ -51,6 +51,7 @@ export const transformESToConversation = ( messageContent: message.content, replacements, }), + ...(message.refusal ? { refusal: message.refusal } : {}), ...(message.is_error ? { isError: message.is_error } : {}), ...(message.reader ? { reader: message.reader } : {}), ...(message.user ? { user: message.user } : {}), diff --git a/x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/types.ts b/x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/types.ts index 882284fdd811e..ad3aee8d62a71 100644 --- a/x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/types.ts +++ b/x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/types.ts @@ -27,6 +27,7 @@ export interface EsConversationSchema { '@timestamp': string; id?: string; content: string; + refusal?: string; reader?: Reader; role: MessageRole; is_error?: boolean; @@ -73,6 +74,7 @@ export interface CreateMessageSchema { '@timestamp': string; id: string; content: string; + refusal?: string; reader?: Reader; role: MessageRole; is_error?: boolean; diff --git a/x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/update_conversation.ts b/x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/update_conversation.ts index 863005b73f607..e8ce802c1857b 100644 --- a/x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/update_conversation.ts +++ b/x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/update_conversation.ts @@ -29,6 +29,7 @@ export interface UpdateConversationSchema { '@timestamp': string; id: string; content: string; + refusal?: string; reader?: Reader; role: MessageRole; is_error?: boolean; @@ -136,6 +137,7 @@ export const transformToUpdateScheme = ( '@timestamp': message.timestamp, id: message.id ?? uuidv4(), content: message.content, + ...(message.refusal ? { refusal: message.refusal } : {}), is_error: message.isError, reader: message.reader, role: message.role, diff --git a/x-pack/solutions/security/plugins/elastic_assistant/server/lib/langchain/executors/types.ts b/x-pack/solutions/security/plugins/elastic_assistant/server/lib/langchain/executors/types.ts index b796e083a7fb8..786969b0e1695 100644 --- a/x-pack/solutions/security/plugins/elastic_assistant/server/lib/langchain/executors/types.ts +++ b/x-pack/solutions/security/plugins/elastic_assistant/server/lib/langchain/executors/types.ts @@ -35,7 +35,8 @@ import type { AIAssistantDataClient } from '../../../ai_assistant_data_clients'; export type OnLlmResponse = ( content: string, traceData?: Message['traceData'], - isError?: boolean + isError?: boolean, + refusal?: string ) => Promise; export interface AssistantDataClients { diff --git a/x-pack/solutions/security/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/helpers.ts b/x-pack/solutions/security/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/helpers.ts index fec6508efe682..d4588120f124d 100644 --- a/x-pack/solutions/security/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/helpers.ts +++ b/x-pack/solutions/security/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/helpers.ts @@ -74,7 +74,7 @@ export const streamGraph = async ({ } = streamFactory<{ type: string; payload: string }>(request.headers, logger, false, false); let didEnd = false; - const handleStreamEnd = (finalResponse: string, isError = false) => { + const handleStreamEnd = (finalResponse: string, isError = false, refusal?: string) => { if (didEnd) { return; } @@ -95,7 +95,8 @@ export const streamGraph = async ({ transactionId: streamingSpan?.transaction?.ids?.['transaction.id'], traceId: streamingSpan?.ids?.['trace.id'], }, - isError + isError, + refusal ).catch(() => {}); } streamEnd(); @@ -135,7 +136,11 @@ export const streamGraph = async ({ !data.output.lc_kwargs?.tool_calls?.length && !didEnd ) { - handleStreamEnd(data.output.content); + const refusal = + typeof data.output?.additional_kwargs?.refusal === 'string' + ? (data.output.additional_kwargs.refusal as string) + : undefined; + handleStreamEnd(data.output.content, false, refusal); } else if ( // This is the end of one model invocation but more message will follow as there are tool calls. If this chunk contains text content, add a newline separator to the stream to visually separate the chunks. event === 'on_chat_model_end' && @@ -215,8 +220,12 @@ export const invokeGraph = async ({ const lastMessage = result.messages[result.messages.length - 1]; const output = lastMessage.text; const conversationId = result.conversationId; + const refusal = + typeof lastMessage?.additional_kwargs?.refusal === 'string' + ? (lastMessage.additional_kwargs.refusal as string) + : undefined; if (onLlmResponse) { - await onLlmResponse(output, traceData); + await onLlmResponse(output, traceData, false, refusal); } return { output, traceData, conversationId }; diff --git a/x-pack/solutions/security/plugins/elastic_assistant/server/routes/chat/chat_complete_route.ts b/x-pack/solutions/security/plugins/elastic_assistant/server/routes/chat/chat_complete_route.ts index 345d3bb20f202..4f20178128cb5 100644 --- a/x-pack/solutions/security/plugins/elastic_assistant/server/routes/chat/chat_complete_route.ts +++ b/x-pack/solutions/security/plugins/elastic_assistant/server/routes/chat/chat_complete_route.ts @@ -212,7 +212,8 @@ export const chatCompleteRoute = ( const onLlmResponse = async ( content: string, traceData: Message['traceData'] = {}, - isError = false + isError = false, + refusal ): Promise => { if (conversationId && conversationsDataClient) { const { prunedContent, prunedContentReferencesStore } = pruneContentReferences( @@ -224,6 +225,7 @@ export const chatCompleteRoute = ( conversationId, conversationsDataClient, messageContent: prunedContent, + messageRefusal: refusal, replacements: latestReplacements, isError, traceData, diff --git a/x-pack/solutions/security/plugins/elastic_assistant/server/routes/helpers.ts b/x-pack/solutions/security/plugins/elastic_assistant/server/routes/helpers.ts index b68853b19e887..77cfa9f6d14f7 100644 --- a/x-pack/solutions/security/plugins/elastic_assistant/server/routes/helpers.ts +++ b/x-pack/solutions/security/plugins/elastic_assistant/server/routes/helpers.ts @@ -107,11 +107,13 @@ export const getPluginNameFromRequest = ({ export const getMessageFromRawResponse = ({ rawContent, metadata, + refusal, isError, traceData, }: { rawContent?: string; metadata?: MessageMetadata; + refusal?: string; traceData?: TraceData; isError?: boolean; }): Message => { @@ -120,6 +122,7 @@ export const getMessageFromRawResponse = ({ return { role: 'assistant', content: rawContent, + ...(refusal ? { refusal } : {}), timestamp: dateTimeString, metadata, isError, @@ -177,6 +180,7 @@ export const getSystemPromptFromUserConversation = async ({ export interface AppendAssistantMessageToConversationParams { conversationsDataClient: AIAssistantConversationsDataClient; messageContent: string; + messageRefusal?: string; replacements: Replacements; conversationId: string; contentReferences: ContentReferences; @@ -186,6 +190,7 @@ export interface AppendAssistantMessageToConversationParams { export const appendAssistantMessageToConversation = async ({ conversationsDataClient, messageContent, + messageRefusal, replacements, conversationId, contentReferences, @@ -209,6 +214,7 @@ export const appendAssistantMessageToConversation = async ({ messageContent, replacements, }), + refusal: messageRefusal, metadata: !isEmpty(metadata) ? metadata : undefined, traceData, isError, diff --git a/x-pack/solutions/security/plugins/elastic_assistant/server/routes/post_actions_connector_execute.ts b/x-pack/solutions/security/plugins/elastic_assistant/server/routes/post_actions_connector_execute.ts index 916461a7999f0..ba28346c62bf1 100644 --- a/x-pack/solutions/security/plugins/elastic_assistant/server/routes/post_actions_connector_execute.ts +++ b/x-pack/solutions/security/plugins/elastic_assistant/server/routes/post_actions_connector_execute.ts @@ -162,7 +162,8 @@ export const postActionsConnectorExecuteRoute = ( onLlmResponse = async ( content: string, traceData: Message['traceData'] = {}, - isError = false + isError = false, + refusal ): Promise => { if (conversationsDataClient && conversationId) { const { prunedContent, prunedContentReferencesStore } = pruneContentReferences( @@ -174,6 +175,7 @@ export const postActionsConnectorExecuteRoute = ( conversationId, conversationsDataClient, messageContent: prunedContent, + messageRefusal: refusal, replacements: latestReplacements, isError, traceData, From 75c93cfeb3e873b2737d2f169d515a7fe45fb203 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 19 Dec 2025 16:52:38 +0000 Subject: [PATCH 2/5] Changes from node scripts/regenerate_moon_projects.js --update --- src/platform/packages/shared/kbn-saved-search-component/moon.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/platform/packages/shared/kbn-saved-search-component/moon.yml b/src/platform/packages/shared/kbn-saved-search-component/moon.yml index 3df29d85636e6..adc4b79d1f8c6 100644 --- a/src/platform/packages/shared/kbn-saved-search-component/moon.yml +++ b/src/platform/packages/shared/kbn-saved-search-component/moon.yml @@ -27,6 +27,7 @@ dependsOn: - '@kbn/i18n' - '@kbn/presentation-publishing' - '@kbn/saved-search-plugin' + - '@kbn/unified-data-table' tags: - shared-browser - package From eca2bb894dfc336539393953c108f87b84628d8f Mon Sep 17 00:00:00 2001 From: Steph Milovic Date: Fri, 19 Dec 2025 10:20:46 -0700 Subject: [PATCH 3/5] type fixing --- .../server/routes/chat/chat_complete_route.ts | 2 +- .../plugins/elastic_assistant/server/routes/helpers.ts | 3 ++- .../server/routes/post_actions_connector_execute.ts | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/x-pack/solutions/security/plugins/elastic_assistant/server/routes/chat/chat_complete_route.ts b/x-pack/solutions/security/plugins/elastic_assistant/server/routes/chat/chat_complete_route.ts index 4f20178128cb5..96b7b80f8e421 100644 --- a/x-pack/solutions/security/plugins/elastic_assistant/server/routes/chat/chat_complete_route.ts +++ b/x-pack/solutions/security/plugins/elastic_assistant/server/routes/chat/chat_complete_route.ts @@ -213,7 +213,7 @@ export const chatCompleteRoute = ( content: string, traceData: Message['traceData'] = {}, isError = false, - refusal + refusal?: string ): Promise => { if (conversationId && conversationsDataClient) { const { prunedContent, prunedContentReferencesStore } = pruneContentReferences( diff --git a/x-pack/solutions/security/plugins/elastic_assistant/server/routes/helpers.ts b/x-pack/solutions/security/plugins/elastic_assistant/server/routes/helpers.ts index 77cfa9f6d14f7..47587f15b6b0a 100644 --- a/x-pack/solutions/security/plugins/elastic_assistant/server/routes/helpers.ts +++ b/x-pack/solutions/security/plugins/elastic_assistant/server/routes/helpers.ts @@ -257,7 +257,8 @@ export interface LangChainExecuteParams { onLlmResponse?: ( content: string, traceData?: Message['traceData'], - isError?: boolean + isError?: boolean, + refusal?: string ) => Promise; response: KibanaResponseFactory; responseLanguage?: string; diff --git a/x-pack/solutions/security/plugins/elastic_assistant/server/routes/post_actions_connector_execute.ts b/x-pack/solutions/security/plugins/elastic_assistant/server/routes/post_actions_connector_execute.ts index ba28346c62bf1..4e775047aa0b4 100644 --- a/x-pack/solutions/security/plugins/elastic_assistant/server/routes/post_actions_connector_execute.ts +++ b/x-pack/solutions/security/plugins/elastic_assistant/server/routes/post_actions_connector_execute.ts @@ -163,7 +163,7 @@ export const postActionsConnectorExecuteRoute = ( content: string, traceData: Message['traceData'] = {}, isError = false, - refusal + refusal?: string ): Promise => { if (conversationsDataClient && conversationId) { const { prunedContent, prunedContentReferencesStore } = pruneContentReferences( From 722efdb47e1fb3c507ead2be3f0969b87df95e35 Mon Sep 17 00:00:00 2001 From: Steph Milovic Date: Fri, 19 Dec 2025 12:24:43 -0700 Subject: [PATCH 4/5] fix test --- .../graphs/default_assistant_graph/helpers.test.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/x-pack/solutions/security/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/helpers.test.ts b/x-pack/solutions/security/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/helpers.test.ts index 22f892537da6d..a4177a44b3589 100644 --- a/x-pack/solutions/security/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/helpers.test.ts +++ b/x-pack/solutions/security/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/helpers.test.ts @@ -109,7 +109,8 @@ describe('streamGraph', () => { expect(mockOnLlmResponse).toHaveBeenCalledWith( 'final message', { transactionId: 'transactionId', traceId: 'traceId' }, - false + false, + undefined ); }); }); @@ -178,7 +179,8 @@ describe('streamGraph', () => { expect(mockOnLlmResponse).toHaveBeenCalledWith( 'content', { transactionId: 'transactionId', traceId: 'traceId' }, - false + false, + undefined ); }); }); @@ -240,7 +242,8 @@ describe('streamGraph', () => { expect(mockOnLlmResponse).toHaveBeenCalledWith( 'Look at these rare IP addresses.', { transactionId: 'transactionId', traceId: 'traceId' }, - false + false, + undefined ); }); }; From 80b027ff1355017694c07cfe8862171fc6a7102a Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 22 Dec 2025 17:05:00 +0000 Subject: [PATCH 5/5] Changes from node scripts/regenerate_moon_projects.js --update --- .../elasticsearch/server-internal/moon.yml | 1 + .../elasticsearch/server-utils/moon.yml | 45 +++++++++++++++++++ .../migration-server-internal/moon.yml | 1 + .../platform/plugins/shared/alerting/moon.yml | 1 + x-pack/platform/plugins/shared/cases/moon.yml | 2 +- .../plugins/shared/entity_manager/moon.yml | 1 + .../platform/plugins/shared/streams/moon.yml | 1 + .../plugins/observability/moon.yml | 1 + .../observability/plugins/slo/moon.yml | 1 + .../security/packages/index-adapter/moon.yml | 1 + .../plugins/security_solution/moon.yml | 1 + 11 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 src/core/packages/elasticsearch/server-utils/moon.yml diff --git a/src/core/packages/elasticsearch/server-internal/moon.yml b/src/core/packages/elasticsearch/server-internal/moon.yml index 2473d36be883a..fe2c994f8cf87 100644 --- a/src/core/packages/elasticsearch/server-internal/moon.yml +++ b/src/core/packages/elasticsearch/server-internal/moon.yml @@ -31,6 +31,7 @@ dependsOn: - '@kbn/core-http-server-internal' - '@kbn/core-execution-context-server-internal' - '@kbn/core-elasticsearch-server' + - '@kbn/core-elasticsearch-server-utils' - '@kbn/core-elasticsearch-client-server-internal' - '@kbn/core-test-helpers-deprecations-getters' - '@kbn/config' diff --git a/src/core/packages/elasticsearch/server-utils/moon.yml b/src/core/packages/elasticsearch/server-utils/moon.yml new file mode 100644 index 0000000000000..76b0c45fadeb2 --- /dev/null +++ b/src/core/packages/elasticsearch/server-utils/moon.yml @@ -0,0 +1,45 @@ +# This file is generated by the @kbn/moon package. Any manual edits will be erased! +# To extend this, write your extensions/overrides to 'moon.extend.yml' +# then regenerate this file with: 'node scripts/regenerate_moon_projects.js --update --filter @kbn/core-elasticsearch-server-utils' + +$schema: https://moonrepo.dev/schemas/project.json +id: '@kbn/core-elasticsearch-server-utils' +type: unknown +owners: + defaultOwner: '@elastic/kibana-core' +toolchain: + default: node +language: typescript +project: + name: '@kbn/core-elasticsearch-server-utils' + description: Moon project for @kbn/core-elasticsearch-server-utils + channel: '' + owner: '@elastic/kibana-core' + metadata: + sourceRoot: src/core/packages/elasticsearch/server-utils +dependsOn: + - '@kbn/core-elasticsearch-client-server-mocks' +tags: + - shared-common + - package + - prod + - group-platform + - shared + - jest-unit-tests +fileGroups: + src: + - '**/*.ts' + - '!target/**/*' +tasks: + jest: + args: + - '--config' + - $projectRoot/jest.config.js + inputs: + - '@group(src)' + jestCI: + args: + - '--config' + - $projectRoot/jest.config.js + inputs: + - '@group(src)' diff --git a/src/core/packages/saved-objects/migration-server-internal/moon.yml b/src/core/packages/saved-objects/migration-server-internal/moon.yml index 1293c0ba0ce17..be14d4f1d47fa 100644 --- a/src/core/packages/saved-objects/migration-server-internal/moon.yml +++ b/src/core/packages/saved-objects/migration-server-internal/moon.yml @@ -22,6 +22,7 @@ dependsOn: - '@kbn/std' - '@kbn/core-doc-links-server' - '@kbn/core-elasticsearch-server' + - '@kbn/core-elasticsearch-server-utils' - '@kbn/core-elasticsearch-client-server-internal' - '@kbn/core-saved-objects-common' - '@kbn/core-saved-objects-server' diff --git a/x-pack/platform/plugins/shared/alerting/moon.yml b/x-pack/platform/plugins/shared/alerting/moon.yml index 4107c5770997e..80873025a94c9 100644 --- a/x-pack/platform/plugins/shared/alerting/moon.yml +++ b/x-pack/platform/plugins/shared/alerting/moon.yml @@ -85,6 +85,7 @@ dependsOn: - '@kbn/elastic-assistant-common' - '@kbn/response-ops-recurring-schedule-form' - '@kbn/licensing-types' + - '@kbn/core-elasticsearch-server-utils' - '@kbn/es-types' - '@kbn/lazy-object' - '@kbn/react-query' diff --git a/x-pack/platform/plugins/shared/cases/moon.yml b/x-pack/platform/plugins/shared/cases/moon.yml index 0cc3c8ebe6597..1fe58df468291 100644 --- a/x-pack/platform/plugins/shared/cases/moon.yml +++ b/x-pack/platform/plugins/shared/cases/moon.yml @@ -89,13 +89,13 @@ dependsOn: - '@kbn/monaco' - '@kbn/code-editor' - '@kbn/logging' - - '@kbn/core-elasticsearch-client-server-mocks' - '@kbn/core-test-helpers-model-versions' - '@kbn/alerting-types' - '@kbn/elastic-assistant-common' - '@kbn/test' - '@kbn/dev-utils' - '@kbn/tooling-log' + - '@kbn/core-elasticsearch-server-utils' - '@kbn/licensing-types' - '@kbn/lazy-object' - '@kbn/setup-node-env' diff --git a/x-pack/platform/plugins/shared/entity_manager/moon.yml b/x-pack/platform/plugins/shared/entity_manager/moon.yml index 8005af16e5ef2..6bc5b9243a165 100644 --- a/x-pack/platform/plugins/shared/entity_manager/moon.yml +++ b/x-pack/platform/plugins/shared/entity_manager/moon.yml @@ -39,6 +39,7 @@ dependsOn: - '@kbn/core-saved-objects-server' - '@kbn/features-plugin' - '@kbn/zod-helpers' + - '@kbn/core-elasticsearch-server-utils' tags: - plugin - prod diff --git a/x-pack/platform/plugins/shared/streams/moon.yml b/x-pack/platform/plugins/shared/streams/moon.yml index 4f7c500a3af0c..1766d50506cff 100644 --- a/x-pack/platform/plugins/shared/streams/moon.yml +++ b/x-pack/platform/plugins/shared/streams/moon.yml @@ -62,6 +62,7 @@ dependsOn: - '@kbn/grok-heuristics' - '@kbn/streamlang' - '@kbn/licensing-types' + - '@kbn/core-elasticsearch-server-utils' - '@kbn/safer-lodash-set' - '@kbn/sse-utils' - '@kbn/global-search-plugin' diff --git a/x-pack/solutions/observability/plugins/observability/moon.yml b/x-pack/solutions/observability/plugins/observability/moon.yml index 07c7b9f3422d3..72b20f199b139 100644 --- a/x-pack/solutions/observability/plugins/observability/moon.yml +++ b/x-pack/solutions/observability/plugins/observability/moon.yml @@ -137,6 +137,7 @@ dependsOn: - '@kbn/deeplinks-management' - '@kbn/content-management-content-editor' - '@kbn/saved-objects-tagging-plugin' + - '@kbn/core-elasticsearch-server-utils' - '@kbn/core-http-browser-mocks' - '@kbn/react-query' tags: diff --git a/x-pack/solutions/observability/plugins/slo/moon.yml b/x-pack/solutions/observability/plugins/slo/moon.yml index de9a722f87dd5..b8154d6df9a80 100644 --- a/x-pack/solutions/observability/plugins/slo/moon.yml +++ b/x-pack/solutions/observability/plugins/slo/moon.yml @@ -114,6 +114,7 @@ dependsOn: - '@kbn/lock-manager' - '@kbn/object-utils' - '@kbn/licensing-types' + - '@kbn/core-elasticsearch-server-utils' - '@kbn/deeplinks-analytics' - '@kbn/content-management-plugin' - '@kbn/dashboards-selector' diff --git a/x-pack/solutions/security/packages/index-adapter/moon.yml b/x-pack/solutions/security/packages/index-adapter/moon.yml index 4cb3d21df099c..96b56d1fda408 100644 --- a/x-pack/solutions/security/packages/index-adapter/moon.yml +++ b/x-pack/solutions/security/packages/index-adapter/moon.yml @@ -22,6 +22,7 @@ dependsOn: - '@kbn/std' - '@kbn/safer-lodash-set' - '@kbn/logging-mocks' + - '@kbn/core-elasticsearch-server-utils' tags: - shared-server - package diff --git a/x-pack/solutions/security/plugins/security_solution/moon.yml b/x-pack/solutions/security/plugins/security_solution/moon.yml index 555d08757701d..2bd02b8e325f5 100644 --- a/x-pack/solutions/security/plugins/security_solution/moon.yml +++ b/x-pack/solutions/security/plugins/security_solution/moon.yml @@ -251,6 +251,7 @@ dependsOn: - '@kbn/core-lifecycle-server-mocks' - '@kbn/licensing-types' - '@kbn/core-metrics-server' + - '@kbn/core-elasticsearch-server-utils' - '@kbn/rrule' - '@kbn/core-analytics-server-mocks' - '@kbn/object-utils'