Skip to content

Add refusal field to assistant conversations#243423

Merged
stephmilovic merged 9 commits intomainfrom
feature/refusal-field
Dec 19, 2025
Merged

Add refusal field to assistant conversations#243423
stephmilovic merged 9 commits intomainfrom
feature/refusal-field

Conversation

@jaybcee
Copy link
Member

@jaybcee jaybcee commented Nov 18, 2025

Summary

  • capture the LLM refusal reason in inference chunk aggregation and langchain responses
  • persist messages.refusal in the assistant conversation schema/field map so it is searchable in the data stream
  • cover the new path with tests and keep helper types in sync

Related to https://github.com/elastic/search-team/issues/10868

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds support for capturing and persisting LLM refusal reasons throughout the assistant conversation flow. When a model refuses to generate content (e.g., due to content filtering), the refusal reason is now captured from the LLM response, stored in the conversation data stream, and made searchable via the messages.refusal field.

Key changes:

  • Extended type definitions across the inference stack to include optional refusal field in messages, events, and API responses
  • Modified chunk aggregation logic to preserve refusal values from streaming responses
  • Updated conversation schema and field mappings to persist refusal data in Elasticsearch
  • Added LangChain adapter support to extract refusal from additional_kwargs

Reviewed changes

Copilot reviewed 24 out of 24 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
x-pack/platform/packages/shared/ai-infra/inference-common/src/chat_complete/messages.ts Added optional refusal field to AssistantMessage type definition
x-pack/platform/packages/shared/ai-infra/inference-common/src/chat_complete/events.ts Added optional refusal field to ChatCompletionMessageEvent and ChatCompletionChunkEvent
x-pack/platform/packages/shared/ai-infra/inference-common/src/chat_complete/api.ts Added optional refusal field to ChatCompleteResponse interface
x-pack/platform/plugins/shared/inference/server/chat_complete/adapters/openai/from_openai.ts Map OpenAI delta.refusal to chunk event's refusal field
x-pack/platform/plugins/shared/inference/server/chat_complete/utils/merge_chunks.ts Aggregate refusal values from chunks into final message
x-pack/platform/plugins/shared/inference/server/chat_complete/utils/chunks_into_message.ts Extract and conditionally include refusal in completion message event
x-pack/platform/plugins/shared/inference/server/chat_complete/utils/stream_to_response.ts Pass refusal field through to response object
x-pack/platform/plugins/shared/stack_connectors/server/connector_types/inference/helpers.ts Aggregate refusal from chunks in inference connector with initial null value
x-pack/platform/packages/shared/ai-infra/inference-langchain/src/chat_model/from_inference/chunks.ts Add refusal to AIMessageChunk's additional_kwargs when present in chunks
x-pack/platform/packages/shared/ai-infra/inference-langchain/src/chat_model/from_inference/messages.ts Convert inference response refusal to LangChain AIMessage additional_kwargs
x-pack/solutions/security/plugins/elastic_assistant/server/lib/langchain/executors/types.ts Added optional refusal parameter to OnLlmResponse callback type
x-pack/solutions/security/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/helpers.ts Extract refusal from AIMessage additional_kwargs in both streaming and invoke modes, pass to onLlmResponse
x-pack/solutions/security/plugins/elastic_assistant/server/routes/helpers.ts Added messageRefusal parameter to appendAssistantMessageToConversation and getMessageFromRawResponse functions
x-pack/solutions/security/plugins/elastic_assistant/server/routes/post_actions_connector_execute.ts Pass refusal from LLM response to message persistence logic
x-pack/solutions/security/plugins/elastic_assistant/server/routes/chat/chat_complete_route.ts Pass refusal from LLM response to message persistence via onLlmResponse callback
x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/field_maps_configuration.ts Added messages.refusal field mapping as non-required text field for searchability
x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/types.ts Added optional refusal field to EsConversationSchema and CreateMessageSchema interfaces
x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/update_conversation.ts Added optional refusal field to UpdateConversationSchema and conditionally include in transformed messages
x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/transforms.ts Conditionally include refusal when transforming ES documents to conversation responses
x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/create_conversation.ts Conditionally include refusal field when creating new conversation messages
x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/append_conversation_messages.ts Conditionally include refusal field when appending messages to conversations
x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/append_conversation_messages.test.ts Added test to verify refusal reason is preserved when present on messages
x-pack/platform/packages/shared/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.schema.yaml Added optional refusal field to Message schema with description
x-pack/platform/packages/shared/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.gen.ts Generated Zod schema with optional refusal string field for Message type
Comment on lines +12 to +15
const additionalKwargs = response.refusal ? { refusal: response.refusal } : undefined;
return new AIMessage({
content: response.content,
...(additionalKwargs ? { additional_kwargs: additionalKwargs } : {}),

This comment was marked as off-topic.

Comment on lines +156 to +160
const refusal =
typeof data.output?.additional_kwargs?.refusal === 'string'
? (data.output.additional_kwargs.refusal as string)
: undefined;
handleFinalContent({ finalResponse: data.output.content, refusal, isError: false });

This comment was marked as off-topic.

return {
role: 'assistant',
content: rawContent,
...(refusal ? { refusal } : {}),

This comment was marked as off-topic.

return {
type: ChatCompletionEventType.ChatCompletionMessage,
content,
...(refusal ? { refusal } : {}),

This comment was marked as off-topic.

Comment on lines +243 to +251
const refusal =
typeof lastMessage?.additional_kwargs?.refusal === 'string'
? (lastMessage.additional_kwargs.refusal as string)
: undefined;
if (onLlmResponse) {
await onLlmResponse({
content: output,
traceData,
...(refusal ? { refusal } : {}),

This comment was marked as off-topic.

Comment on lines +23 to +25
if (chunk.refusal) {
prev.refusal = chunk.refusal;
}

This comment was marked as off-topic.

return {
type: ChatCompletionEventType.ChatCompletionChunk,
content: delta.content ?? '',
refusal: delta.refusal ?? undefined,

This comment was marked as off-topic.

Comment on lines +50 to +52
if (chunk.choices[0].message.refusal) {
prev.choices[0].message.refusal = chunk.choices[0].message.refusal;
}

This comment was marked as off-topic.

Comment on lines +29 to +34
const additionalKwargs = chunk.refusal ? { refusal: chunk.refusal } : {};

return new AIMessageChunk({
content: chunk.content,
tool_call_chunks: toolCallChunks,
additional_kwargs: {},
additional_kwargs: additionalKwargs,

This comment was marked as off-topic.

@jaybcee jaybcee added the ci:project-deploy-security Create a Security Serverless Project label Dec 16, 2025
@kibanamachine
Copy link
Contributor

@jaybcee jaybcee added ci:cloud-deploy Create or update a Cloud deployment ci:cloud-redeploy Always create a new Cloud deployment labels Dec 16, 2025
@kibanamachine
Copy link
Contributor

Cloud deployment initiated, see credentials at: https://buildkite.com/elastic/kibana-deploy-cloud-from-pr/builds/614

@jaybcee jaybcee marked this pull request as ready for review December 17, 2025 18:45
@jaybcee jaybcee requested review from a team as code owners December 17, 2025 18:45
@stephmilovic stephmilovic added release_note:fix v9.3.0 v9.1.9 v8.19.9 backport:version Backport to applied version labels v9.2.4 v9.1.10 backport:all-open Backport to all branches that could still receive a release and removed v9.1.9 backport:version Backport to applied version labels v9.3.0 v8.19.9 v9.2.4 labels Dec 17, 2025
@elasticmachine
Copy link
Contributor

elasticmachine commented Dec 18, 2025

💔 Build Failed

Failed CI Steps

Test Failures

  • [job] [logs] FTR Configs #76 / Agent Builder agents Edit agent should edit agent name

Metrics [docs]

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
securitySolution 10.8MB 10.8MB +27.0B
Unknown metric groups

API count

id before after diff
@kbn/inference-common 341 342 +1

History

handleFinalContent({ finalResponse: data.output.content, isError: false });
const refusal =
typeof data.output?.additional_kwargs?.refusal === 'string'
? (data.output.additional_kwargs.refusal as string)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need as string here?

Copy link
Member

@qn895 qn895 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left a nit comment but LGTM 🎉

@stephmilovic stephmilovic merged commit fe9c9fd into main Dec 19, 2025
17 checks passed
@stephmilovic stephmilovic deleted the feature/refusal-field branch December 19, 2025 15:39
@kibanamachine
Copy link
Contributor

Starting backport for target branches: 8.19, 9.1, 9.2, 9.3

https://github.com/elastic/kibana/actions/runs/20374815667

kibanamachine pushed a commit to kibanamachine/kibana that referenced this pull request Dec 19, 2025
@kibanamachine
Copy link
Contributor

💔 Some backports could not be created

Status Branch Result
8.19 Backport failed because of merge conflicts
9.1 Backport failed because of merge conflicts
9.2 Backport failed because of merge conflicts
9.3

Note: Successful backport PRs will be merged automatically after passing CI.

Manual backport

To create the backport manually run:

node scripts/backport --pr 243423

Questions ?

Please refer to the Backport tool documentation

stephmilovic pushed a commit to stephmilovic/kibana that referenced this pull request Dec 19, 2025
(cherry picked from commit fe9c9fd)

# 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
stephmilovic pushed a commit to stephmilovic/kibana that referenced this pull request Dec 19, 2025
(cherry picked from commit fe9c9fd)

# Conflicts:
#	x-pack/platform/packages/shared/ai-infra/inference-common/src/chat_complete/events.ts
#	x-pack/platform/packages/shared/ai-infra/inference-common/src/chat_complete/messages.ts
#	x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/append_conversation_messages.test.ts
#	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
@stephmilovic
Copy link
Contributor

💚 All backports created successfully

Status Branch Result
9.2
9.1
8.19

Note: Successful backport PRs will be merged automatically after passing CI.

Questions ?

Please refer to the Backport tool documentation

stephmilovic pushed a commit to stephmilovic/kibana that referenced this pull request Dec 19, 2025
(cherry picked from commit fe9c9fd)

# Conflicts:
#	x-pack/platform/packages/shared/ai-infra/inference-common/src/chat_complete/events.ts
#	x-pack/platform/packages/shared/ai-infra/inference-common/src/chat_complete/messages.ts
#	x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/append_conversation_messages.test.ts
#	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
stephmilovic added a commit that referenced this pull request Dec 22, 2025
# Backport

This will backport the following commits from `main` to `8.19`:
- [Add refusal field to assistant conversations
(#243423)](#243423)

<!--- Backport version: 10.2.0 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sorenlouv/backport)

<!--BACKPORT [{"author":{"name":"Jason
Botzas-Coluni","email":"44372106+jaybcee@users.noreply.github.com"},"sourceCommit":{"committedDate":"2025-12-19T15:39:35Z","message":"Add
refusal field to assistant conversations
(#243423)","sha":"fe9c9fd75355732baf10cda2b70fe4bb9f36652b","branchLabelMapping":{"^v9.4.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:fix","backport:all-open","ci:cloud-deploy","ci:cloud-redeploy","ci:project-deploy-security","v9.4.0"],"title":"Add
refusal field to assistant
conversations","number":243423,"url":"https://github.com/elastic/kibana/pull/243423","mergeCommit":{"message":"Add
refusal field to assistant conversations
(#243423)","sha":"fe9c9fd75355732baf10cda2b70fe4bb9f36652b"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v9.4.0","branchLabelMappingKey":"^v9.4.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/243423","number":243423,"mergeCommit":{"message":"Add
refusal field to assistant conversations
(#243423)","sha":"fe9c9fd75355732baf10cda2b70fe4bb9f36652b"}},{"url":"https://github.com/elastic/kibana/pull/247135","number":247135,"branch":"9.3","state":"OPEN"}]}]
BACKPORT-->

---------

Co-authored-by: Jason Botzas-Coluni <44372106+jaybcee@users.noreply.github.com>
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
stephmilovic added a commit that referenced this pull request Dec 22, 2025
# Backport

This will backport the following commits from `main` to `9.1`:
- [Add refusal field to assistant conversations
(#243423)](#243423)

<!--- Backport version: 10.2.0 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sorenlouv/backport)

<!--BACKPORT [{"author":{"name":"Jason
Botzas-Coluni","email":"44372106+jaybcee@users.noreply.github.com"},"sourceCommit":{"committedDate":"2025-12-19T15:39:35Z","message":"Add
refusal field to assistant conversations
(#243423)","sha":"fe9c9fd75355732baf10cda2b70fe4bb9f36652b","branchLabelMapping":{"^v9.4.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:fix","backport:all-open","ci:cloud-deploy","ci:cloud-redeploy","ci:project-deploy-security","v9.4.0"],"title":"Add
refusal field to assistant
conversations","number":243423,"url":"https://github.com/elastic/kibana/pull/243423","mergeCommit":{"message":"Add
refusal field to assistant conversations
(#243423)","sha":"fe9c9fd75355732baf10cda2b70fe4bb9f36652b"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v9.4.0","branchLabelMappingKey":"^v9.4.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/243423","number":243423,"mergeCommit":{"message":"Add
refusal field to assistant conversations
(#243423)","sha":"fe9c9fd75355732baf10cda2b70fe4bb9f36652b"}},{"url":"https://github.com/elastic/kibana/pull/247135","number":247135,"branch":"9.3","state":"OPEN"}]}]
BACKPORT-->

---------

Co-authored-by: Jason Botzas-Coluni <44372106+jaybcee@users.noreply.github.com>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
stephmilovic added a commit that referenced this pull request Dec 22, 2025
# Backport

This will backport the following commits from `main` to `9.2`:
- [Add refusal field to assistant conversations
(#243423)](#243423)

<!--- Backport version: 10.2.0 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sorenlouv/backport)

<!--BACKPORT [{"author":{"name":"Jason
Botzas-Coluni","email":"44372106+jaybcee@users.noreply.github.com"},"sourceCommit":{"committedDate":"2025-12-19T15:39:35Z","message":"Add
refusal field to assistant conversations
(#243423)","sha":"fe9c9fd75355732baf10cda2b70fe4bb9f36652b","branchLabelMapping":{"^v9.4.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:fix","backport:all-open","ci:cloud-deploy","ci:cloud-redeploy","ci:project-deploy-security","v9.4.0"],"title":"Add
refusal field to assistant
conversations","number":243423,"url":"https://github.com/elastic/kibana/pull/243423","mergeCommit":{"message":"Add
refusal field to assistant conversations
(#243423)","sha":"fe9c9fd75355732baf10cda2b70fe4bb9f36652b"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v9.4.0","branchLabelMappingKey":"^v9.4.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/243423","number":243423,"mergeCommit":{"message":"Add
refusal field to assistant conversations
(#243423)","sha":"fe9c9fd75355732baf10cda2b70fe4bb9f36652b"}},{"url":"https://github.com/elastic/kibana/pull/247135","number":247135,"branch":"9.3","state":"OPEN"}]}]
BACKPORT-->

---------

Co-authored-by: Jason Botzas-Coluni <44372106+jaybcee@users.noreply.github.com>
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
kibanamachine added a commit that referenced this pull request Dec 23, 2025
# Backport

This will backport the following commits from `main` to `9.3`:
- [Add refusal field to assistant conversations
(#243423)](#243423)

<!--- Backport version: 9.6.6 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sorenlouv/backport)

<!--BACKPORT [{"author":{"name":"Jason
Botzas-Coluni","email":"44372106+jaybcee@users.noreply.github.com"},"sourceCommit":{"committedDate":"2025-12-19T15:39:35Z","message":"Add
refusal field to assistant conversations
(#243423)","sha":"fe9c9fd75355732baf10cda2b70fe4bb9f36652b","branchLabelMapping":{"^v9.4.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:fix","backport:all-open","ci:cloud-deploy","ci:cloud-redeploy","ci:project-deploy-security","v9.4.0"],"title":"Add
refusal field to assistant
conversations","number":243423,"url":"https://github.com/elastic/kibana/pull/243423","mergeCommit":{"message":"Add
refusal field to assistant conversations
(#243423)","sha":"fe9c9fd75355732baf10cda2b70fe4bb9f36652b"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v9.4.0","branchLabelMappingKey":"^v9.4.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/243423","number":243423,"mergeCommit":{"message":"Add
refusal field to assistant conversations
(#243423)","sha":"fe9c9fd75355732baf10cda2b70fe4bb9f36652b"}}]}]
BACKPORT-->

Co-authored-by: Jason Botzas-Coluni <44372106+jaybcee@users.noreply.github.com>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
CAWilson94 pushed a commit to CAWilson94/kibana that referenced this pull request Jan 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport:all-open Backport to all branches that could still receive a release ci:cloud-deploy Create or update a Cloud deployment ci:cloud-redeploy Always create a new Cloud deployment ci:project-deploy-security Create a Security Serverless Project release_note:fix v8.19.10 v9.1.10 v9.2.4 v9.3.0 v9.4.0

7 participants