Skip to content

[Security Solution] Bulk add alerts to Agent Builder chat#270904

Open
jonwalstedt wants to merge 13 commits into
elastic:mainfrom
jonwalstedt:17496-security-bulk-add-alerts-to-chat
Open

[Security Solution] Bulk add alerts to Agent Builder chat#270904
jonwalstedt wants to merge 13 commits into
elastic:mainfrom
jonwalstedt:17496-security-bulk-add-alerts-to-chat

Conversation

@jonwalstedt
Copy link
Copy Markdown
Contributor

@jonwalstedt jonwalstedt commented May 24, 2026

Summary

This PR is extracted from #270286 as the second of two stacked PRs. The first PR contains the needed changes in Agent Builder to support adding several attachments as a single batch to the chat. This followup adds the possibility bulk add Alerts to the chat.

What

Adds an "Add to chat" bulk action to the Kibana alerts table toolbar. Analysts can select up to 20 alerts and send them to the Agent Builder AI chat in a single click, where the agent receives the full alert details and can triage them.

Why

Security analysts frequently need to investigate multiple related alerts together. Switching between the alerts table and the AI chat to copy alert IDs manually is slow and error-prone. This feature closes that gap by making alert context available in chat at the point of investigation.

Stacked PR — depends on #270903 ([Agent Builder] Add AttachmentGroup and group_id to the attachment system). Do not merge this PR before #270903 lands.

Reviewers: to see only the security changes (without the agent-builder foundation), use this diff.

Closes https://github.com/elastic/security-team/issues/17496
Epic: https://github.com/elastic/security-team/issues/17311

Test plan available here

bulk-add-alerts2.mov

Changes

Attachment type

  • security.alerts attachment type — server-side ES fetch scoped to the active space, returns full alert source for each selected ID
  • get_alerts_by_id tool — fetches alert documents by ID for the agent to reason over
  • register_attachments.ts updated to register the new type

Client-side helpers

  • alertsToAttachmentGroup helper — chunks selected alert IDs into AttachmentGroup batches (max 20 per group)
  • helpers.tsx / helpers.test.tsx — updated to generate the group label and build attachment groups from alert selections

Bulk action wiring (4 surfaces)

  • x-pack/packages/response-ops/alerts-table — new addToChat bulk action in use_bulk_actions.ts; disableOnQuery: true prevents use with "Select all N" query mode
  • Alerts page (detections/components/alerts_table)
  • Cases alerts tab (cases/components/ease/table.tsx)
  • Rule Details alerts tab (tabs/alerts_tab/ease/table.tsx)
  • Attack Discovery alert summary (components/alert_summary/table/table.tsx)

Telemetry

  • alert_count EBT event added to use_report_add_to_chat.ts

Tests

  • use_bulk_actions.test.tsx — updated with add-to-chat cases
  • table_bulk_add_to_chat.test.tsx ×4 — one per surface
  • alerts.test.ts — attachment type server logic
  • get_alerts_by_id.test.ts — tool logic
  • bulk_add_alerts_to_chat.spec.ts — Scout E2E test
  • kbn-evals-suite-security-alert-triage — new eval package with alert_triage_quality.spec.ts and bulk_alerts_attachment_read.spec.ts

Infrastructure

  • .buildkite/pipelines/evals/evals.suites.json — registers the new eval suite
  • .github/CODEOWNERS — ownership for the new eval package
  • tsconfig.base.json, package.json, yarn.lock — new package wiring

Checklist

  • Any text added follows EUI's writing guidelines, uses sentence case text and includes i18n support
  • Documentation was added for features that require explanation or tutorials
  • Unit or functional tests were updated or added to match the most common scenarios
  • If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the docker list
  • This was checked for breaking HTTP API changes, and any breaking changes have been approved by the breaking-change committee. The release_note:breaking label should be applied in these situations.
  • Flaky Test Runner was used on any tests changed
  • The PR description includes the appropriate Release Notes section, and the correct release_note:* label is applied per the guidelines
  • Review the backport guidelines and apply applicable backport:* labels.

Identify risks

  • Data loss / corruption: None. The feature only reads alert documents from Elasticsearch; it never writes, updates, or deletes data.
  • Broken user workflows: Low. The bulk action is gated on isAgentBuilderEnabled so it is invisible in environments without the feature flag. disableOnQuery: true prevents accidental use with "Select all N" (unbounded) query mode, which would otherwise silently truncate to 20 alerts.
  • Regressions: Low. Changes to use_bulk_actions.ts in response-ops are additive. Each of the 4 wired surfaces has a dedicated test. The alerts-table package is shared across solutions, but the new action is conditionally rendered.
  • Performance: Low. The ES fetch is bounded to the caller-supplied alert IDs (max 20); no query scans. The agent receives alert data via AttachmentGroup which is flattened before being sent to the LLM.
  • Hard-to-test: The "Select all N" disable guard is tested at the unit level but not end-to-end across all surfaces — worth noting for QA.

Release note

Adds an "Add to chat" bulk action to the alerts table, enabling analysts to send selected alerts directly to the AI Agent chat for triage.

Suggested label: release_note:feature

@jonwalstedt jonwalstedt self-assigned this May 25, 2026
@jonwalstedt jonwalstedt added backport:skip This PR does not require backporting Team:Threat Hunting Security Solution Threat Hunting Team release_note:feature Makes this part of the condensed release notes v9.5.0 labels May 25, 2026
@jonwalstedt jonwalstedt force-pushed the 17496-security-bulk-add-alerts-to-chat branch from 55dad5f to 15ae981 Compare May 25, 2026 07:21
@jonwalstedt jonwalstedt marked this pull request as ready for review May 25, 2026 08:05
@jonwalstedt jonwalstedt requested review from a team as code owners May 25, 2026 08:05
@infra-vault-gh-plugin-prod
Copy link
Copy Markdown

Pinging @elastic/security-threat-hunting (Team:Threat Hunting)

@jonwalstedt jonwalstedt requested a review from tiansivive May 25, 2026 08:05
Copy link
Copy Markdown
Contributor

@fake-haris fake-haris left a comment

Choose a reason for hiding this comment

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

appex-qa changes LGTM

@elastic-vault-github-plugin-prod elastic-vault-github-plugin-prod Bot requested a review from a team as a code owner May 25, 2026 08:35
Copy link
Copy Markdown
Contributor

@tcalopes tcalopes left a comment

Choose a reason for hiding this comment

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

entity analytics changes LGTM

@jonwalstedt jonwalstedt force-pushed the 17496-security-bulk-add-alerts-to-chat branch from 1cc06fe to 78ba2f0 Compare May 25, 2026 19:18
Copy link
Copy Markdown
Contributor

@ymao1 ymao1 left a comment

Choose a reason for hiding this comment

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

Entity analytics changes LGTM. Code review only

@jonwalstedt jonwalstedt force-pushed the 17496-security-bulk-add-alerts-to-chat branch from 7759a86 to aeec2c7 Compare May 26, 2026 18:02
Comment thread x-pack/platform/plugins/shared/agent_builder/server/routes/chat.ts Fixed
Comment thread x-pack/platform/plugins/shared/agent_builder/server/routes/chat.ts Fixed
@jonwalstedt jonwalstedt force-pushed the 17496-security-bulk-add-alerts-to-chat branch from 3991efe to ebf8a14 Compare May 26, 2026 19:44
},
output: {
expected:
'The response should prioritise the critical PowerShell alert on workstation-42, ' +
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This says "critical PowerShell alert on workstation-42", but the generated critical alert (index 49) is "Memory Injection via Process Hollowing" on laptop-finance-07. Doesn't affect scoring (criteria don't reference it), but it's the reference shown in results — worth correcting so it's not misleading.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 486a151. Updated the expected string to match what index 49 actually generates: "Memory Injection via Process Hollowing" on laptop-finance-07. Also corrected the paired high-severity reference from "network-scanning" (medium) to "lateral-movement" (high, index 1).


const attachments = metadata?.attachments ?? [];

const raw = (await fetch('/api/agent_builder/converse', {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This converse task is duplicated across both specs. Other eval suites (e.g. entity-analytics) keep it in src/. Worth extracting a shared helper.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 486a151. Extracted the fetch('/api/agent_builder/converse', …) block to src/converse_task.ts as a shared callConverse helper. Both specs now call callConverse({ fetch, connectorId, question, attachments, log }). While at it, also extracted the AttachmentReadCompliance CODE evaluator to src/evaluators.ts so it can be shared between both specs as well (the e2e scenario added to alert_triage_quality.spec.ts needs it too).

connector,
evaluators,
executorClient,
traceEsClient,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

traceEsClient is threaded through but never used here. Remove?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 486a151. Removed traceEsClient from the createEvaluateAlertBatches parameter type, function destructuring, and fixture call. Also dropped the now-unused EsClient import.

@enriquesanchez-elastic
Copy link
Copy Markdown
Contributor

Some comments from evals point of view.

The suite registers ciLabels: ["evals:security-alert-triage"] in evals.suites.json, but that label isn't on the PR, so the eval CI gate never triggered. Since evals are non-deterministic and the criteria are LLM-graded, can we add the label and get a green run before merge?

The actual shipped path — bulk → summary mode → attachment_read → triage real alerts — has no end-to-end coverage.
- bulk_alerts_attachment_read.spec.ts hits summary mode (6 batches) but uses synthetic IDs that resolve to "not found", so it only proves the agent calls attachment_read, not that it reasons over what comes back.
- alert_triage_quality.spec.ts uses real data but only 5 batches → inline mode, so attachment_read is never exercised.

No grounding / anti-hallucination criterion. Both datasets only check positive recall ("mentions a critical alert", "names web-server-01"). With 16 real hostnames + procedural rule names, an invented host/rule would pass silently.

@MadameSheema
Copy link
Copy Markdown
Contributor

🤖 This is the output of the x-pack/solutions/security/plugins/security_solution/.agents/skills/scout-best-practices-reviewer skill, applied to the Scout test files in this PR.


Scout Best Practices Review

In scope: bulk_add_alerts_to_chat.spec.ts, fixtures/index.ts, alerts_table.ts (page object additions).
The kbn-evals-suite-security-alert-triage/evals/*.spec.ts files use a custom evaluate fixture framework (not spaceTest), so they are out of scope for this Scout review.


🚨 Blocker

  • Page objects — raw locator chains and UI interactions directly in spec file
    • Explanation: The Security Solution skill requires all UI interactions to be encapsulated in page object methods. Specs should only contain expect assertions, test.step calls, and page object method invocations. Here, the spec builds locators, traverses the DOM, and calls .check() / .click() inline. The alertsTable.getByTestId('ruleName').filter(...) pattern is also duplicated across both tests.
    • Evidence:
      • bulk_add_alerts_to_chat.spec.ts:86-89 — inline alertsTablePage.alertsTable.getByTestId('ruleName').filter({ hasText: ruleNames[0] }) (duplicated at 156-159)
      • bulk_add_alerts_to_chat.spec.ts:92-95alertCheckbox traversal and .check() in spec body
      • bulk_add_alerts_to_chat.spec.ts:175-179, 184page.testSubj.locator('agentBuilderConversation'), agentBuilderAttachmentPillsRow, agentBuilderConversationInputEditor, agentBuilderConversationInputSubmitButton all called directly in spec
    • Suggested change: Add a waitForRuleAlert(ruleName: string) method and a checkFirstAlertRow(ruleName: string) method to AlertsTablePage. Create a new AgentBuilderPage page object in kbn-scout-security/src/playwright/fixtures/test/page_objects/ with readonly locators for the conversation panel elements and a sendMessage() method. Register it in the pageObjects fixture.

⚠️ Major

  • Locator quality — XPath selector in spec

    • Explanation: XPath selectors are fragile and explicitly flagged by the skill as major. The existing AlertsTablePage.openAlertContextMenu() already handles similar DOM traversal via XPath inside the page object — but this new code bypasses it and uses XPath directly in the spec.
    • Evidence: bulk_add_alerts_to_chat.spec.ts:93.locator('xpath=ancestor::div[contains(@class,"euiDataGridRow")]')
    • Suggested change: Move this into a page object method, replacing the XPath with CSS: page.locator('div.euiDataGridRow:has([data-test-subj="ruleName"])').filter({ hasText: ruleName }) — or reuse/extend the existing openAlertContextMenu pattern.
  • Locator quality — EUI internal CSS class selector

    • Explanation: .euiCheckbox__input is an EUI-internal class that can change between EUI versions, making the test brittle.
    • Evidence: bulk_add_alerts_to_chat.spec.ts:94.locator('.euiCheckbox__input')
    • Suggested change: Use getByRole('checkbox') scoped to the row, or find a data-test-subj on the checkbox input.
  • Package imports — internal subpath import bypasses public API

    • Explanation: Importing from @kbn/scout-security/src/... couples the spec to the package's internal file structure and breaks if internals are reorganized. Only public entry points should be used.
    • Evidence: bulk_add_alerts_to_chat.spec.ts:11import { CUSTOM_QUERY_RULE } from '@kbn/scout-security/src/playwright/constants/detection_rules'
    • Suggested change: Export CUSTOM_QUERY_RULE from @kbn/scout-security's public barrel (index.ts) and import it from '@kbn/scout-security'.

📋 Minor

  • Tags — missing serverless coverage

    • Explanation: The suite only declares tags.stateful.classic. If the bulk add-to-chat feature is available on Serverless Security, serverless tags should be added. If it's intentionally excluded, a comment should document the reason.
    • Evidence: bulk_add_alerts_to_chat.spec.ts:54{ tag: [...tags.stateful.classic] }
    • Suggested change: If serverless is supported, add ...tags.serverless.security.complete (and other tiers as applicable). Otherwise add a comment: // Serverless excluded: agent builder feature not yet available on serverless.
  • Data cleanup — missing cleanStandardList() and defensive pre-test cleanup

    • Explanation: The Security skill requires scoutSpace.savedObjects.cleanStandardList() as a defensive catch-all in afterEach/afterAll. It also recommends calling the same cleanup methods at the top of beforeEach to handle leftover state from a previous failed run.
    • Evidence: bulk_add_alerts_to_chat.spec.ts:72-75afterEach only calls detectionRule.deleteAll() and detectionAlerts.deleteAll()
    • Suggested change:
      spaceTest.afterEach(async ({ apiServices, scoutSpace }) => {
        await apiServices.detectionRule.deleteAll();
        await apiServices.detectionAlerts.deleteAll();
        await scoutSpace.savedObjects.cleanStandardList();
      });
      And at the top of beforeEach, add the same cleanup calls before creating new rules.
  • Reuse-first — AGENT_BUILDER_ROLE duplicates WORKFLOW_ENABLED_ROLE

    • Explanation: AGENT_BUILDER_ROLE (lines 20-52) is structurally identical to WORKFLOW_ENABLED_ROLE in run_workflow_action.spec.ts — same ES index list, same privileges, same Kibana base: ['all']. This duplication will need to be kept in sync across both files.
    • Evidence: bulk_add_alerts_to_chat.spec.ts:20-52 vs run_workflow_action.spec.ts:18-50
    • Suggested change: Extract a shared constant (e.g., FULL_KIBANA_SECURITY_ROLE) to a plugin-local file like test/scout/ui/common/roles.ts, and import it in both specs.

💡 Nit

  • Fixture — static connector name not scoped to space/worker
    • Explanation: The connector name 'scout-llm-proxy' is hardcoded. The teardown filter c.name === 'scout-llm-proxy' is safe today because each worker gets its own space, but scoping the name to scoutSpace.id makes the intent explicit and guards against edge cases.
    • Evidence: fixtures/index.ts:31name: 'scout-llm-proxy'
    • Suggested change: name: `scout-llm-proxy-${scoutSpace.id}`

@jonwalstedt jonwalstedt added the evals:security-alert-triage Run the eval test suite for kbn-evals-suite-security-alert-triage label May 29, 2026
Copy link
Copy Markdown
Contributor

@js-jankisalvi js-jankisalvi left a comment

Choose a reason for hiding this comment

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

Verified response-ops related changes and added few comments, thanks.

Comment thread x-pack/platform/packages/shared/response-ops/alerts-table/types.ts
Comment thread x-pack/platform/packages/shared/response-ops/alerts-table/types.ts Outdated
@jonwalstedt
Copy link
Copy Markdown
Contributor Author

@MadameSheema Thanks for the Scout review — all points addressed in 1c4e3ad:

Blocker — page objects

  • Added waitForRuleAlert(ruleName) and checkAlertRowCheckbox(ruleName) to AlertsTablePage — all inline locator chains removed from spec
  • Created AgentBuilderPage page object (conversation, attachmentPillsRow, inputEditor, submitButton); registered in SecurityPageObjects; spec now uses agentBuilderPage.* throughout

Major — locator quality

  • XPath row traversal moved into checkAlertRowCheckbox() (consistent with existing openAlertContextMenu pattern in the page object)
  • .euiCheckbox__input replaced with getByRole('checkbox')
  • Internal subpath import fixed: CUSTOM_QUERY_RULE exported from @kbn/scout-security public index.ts; both specs import from '@kbn/scout-security'

Minor — tags: Added comment: // Serverless excluded: agent builder feature not yet available on serverless

Minor — cleanup: Added scoutSpace.savedObjects.cleanStandardList() to afterEach and defensive deleteAll calls at top of beforeEach

Minor — shared role: Extracted FULL_KIBANA_SECURITY_ROLE to test/scout/ui/common/roles.ts; both bulk_add_alerts_to_chat.spec.ts and run_workflow_action.spec.ts import from it

Nit — connector name: Scoped to scout-llm-proxy-${scoutSpace.id} in both creation and cleanup

Copy link
Copy Markdown
Contributor

@js-jankisalvi js-jankisalvi left a comment

Choose a reason for hiding this comment

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

Verified locally, Add to chat bulk action only appears on security solution alerts table. Response ops changes look good 👍

Comment thread .buildkite/pipelines/evals/evals.suites.json
@jonwalstedt jonwalstedt added the models:eis/anthropic-claude-4.6-sonnet Run LLM evals against model: eis/anthropic-claude-4.6-sonnet label May 29, 2026
dej611 pushed a commit to dej611/kibana that referenced this pull request May 29, 2026
…stem (elastic#270903)

# Summary
This PR is extracted from
[elastic#270286](elastic#270286) as the first of
two stacked PRs. This first PR contains the needed changes in Agent
Builder to support adding several attachments as a single batch to the
chat. This followup [PR](elastic#270904)
adds the possibility bulk add Alerts to the chat.

## What

This PR introduces `AttachmentGroup` as a client-side grouping primitive
and `group_id` as a first-class optional field on `Attachment`,
`VersionedAttachment`, and `AttachmentInput`. The group concept is
dissolved at the `flattenAttachments` serialization boundary —
individual items are stamped with `group_id` — and the full pipeline
(server routes, state manager, agent execution) threads the field
through to persistence and presentation.

## Why

Enables consumers (e.g. the Security Solution bulk-alerts feature) to
attach a batch of items as a single logical group, have them
deduplicated to one chip in chat history, and removed atomically. The
[follow-up PR](elastic#270904) shows the
first concrete use: bulk-adding alerts to chat. Without this platform
layer, each consumer would have to roll its own grouping and dedup
logic.

Per-attachment `maxContentLength` is introduced at the same time because
bulk alert documents (full ES source) can be large. A single global
truncation limit would either under-truncate small attachments or
over-truncate large ones. Delegating the limit to the attachment type
registration lets each type declare its own budget independently.

Closes: elastic/security-team#17544
Epic: elastic/security-team#17311

## Changes

**Types and contracts**
- `AttachmentGroup` type + `isAttachmentGroup` predicate added to
`versioned_attachment.ts`
- `group_id` and `description` optional fields added to `Attachment`,
`AttachmentInput`, and `VersionedAttachment`
- `plugin_contract.ts` exports updated to include `AttachmentGroup`
- `maxContentLength?: number` added to `AttachmentTypeDefinition` —
per-type inline truncation limit (characters), defaults to 10 000 if
absent.


**Client-side logic**
- `flatten_attachments.ts` — new canonical serialization boundary;
stamps `group_id` and `description` on group items
- `remove_attachment_from_list.ts` — handles group-id-based bulk removal
(removes all items sharing a `group_id`)
- `upsert_attachments_into_list.ts` — updated to handle
`AttachmentGroup` alongside `AttachmentInput`
- `build_optimistic_attachments.ts` — preserves `group_id` and
`description` on fallback attachments

**UI**
- `attachment_group_pill.tsx` — new chip component for rendering an
`AttachmentGroup` in the input row (same visual style as
`AttachmentPill`)
- `attachment_pills_row.tsx` / `conversation_input.tsx` — wired to
render `AttachmentGroupPill` for groups
- `round_attachment_references.tsx` — deduplicates attachment refs by
`group_id` (actor-filter check now correctly runs before the
`seenGroupIds` slot is consumed)

**Server pipeline**
- `chat.ts` — accepts and forwards `group_id` / `description` from
request body
- `validate_attachment.ts` — passes `group_id` and `description` through
to state manager
- `attachment_state_manager.ts` — persists `group_id` to
`VersionedAttachment`
- `prepare_conversation.ts` / `attachment_presentation.ts` — threads
`group_id` and per-attachment `maxContentLength` through to agent
execution
- `attachment_presentation.ts` — replaces the flat `maxContentLength`
config option with `resolveMaxContentLength?: (attachment) => number |
undefined`, a per-attachment resolver. `prepare_conversation.ts` wires
this to `attachmentsService.getTypeDefinition(type)?.maxContentLength`
so any attachment type can declare its own inline truncation limit via
its type registration.
- XML attribute `id` renamed to `attachment_id` in inline and summary
attachment nodes, and in the LLM instructions, to remove ambiguity.

**Tests**
- New: `flatten_attachments.test.ts`,
`remove_attachment_from_list.test.ts`, `versioned_attachment.test.ts`,
`round_attachment_references.test.tsx`
- Updated: `upsert_attachments_into_list.test.ts`,
`build_optimistic_attachments.test.ts`,
`attachment_presentation.test.ts`

### Checklist

- [x] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)
- [ ]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [ ] If a plugin configuration key changed, check if it needs to be
allowlisted in the cloud and added to the [docker
list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)
- [ ] This was checked for breaking HTTP API changes, and any breaking
changes have been approved by the breaking-change committee. The
`release_note:breaking` label should be applied in these situations.
- [ ] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed
- [x] The PR description includes the appropriate Release Notes section,
and the correct `release_note:*` label is applied per the
[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
- [x] Review the [backport
guidelines](https://docs.google.com/document/d/1VyN5k91e5OVumlc0Gb9RPa3h1ewuPE705nRtioPiTvY/edit?usp=sharing)
and apply applicable `backport:*` labels.

### Identify risks

- **Data loss / corruption:** Low. `group_id` and `description` are
optional fields appended to `VersionedAttachment`. Existing saved
conversations have neither field; all read paths guard on `!==
undefined`, so no migration is needed and existing data is unaffected.
- **Regressions:** Low. `AttachmentGroup` has no producers until the
follow-up security PR lands. All existing `AttachmentInput` paths are
unchanged. The `flattenAttachments` function is additive — it handles
both plain `AttachmentInput` and `AttachmentGroup` and existing call
sites have been updated.
- **Performance:** Negligible. The only new overhead is a `Set`-based
group-id dedup during `RoundAttachmentReferences` rendering.
- **Hard-to-test:** The actor-filter / `seenGroupIds` ordering edge case
(filter must run before consuming the Set slot) is subtle but is now
covered by a dedicated test.

### Release note

> No user-facing changes.

**Suggested label:** `release_note:skip`

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
@jonwalstedt
Copy link
Copy Markdown
Contributor Author

Thanks for the review @enriquesanchez-elastic, I've addressed your feedback, could you please take another look when you have a chance?

jonwalstedt and others added 13 commits May 31, 2026 20:50
Adds a "Add to chat" bulk action to the Kibana alerts table toolbar,
allowing analysts to select multiple security alerts and send them to
the Agent Builder AI chat in a single click.

- security.alerts attachment type with server-side ES fetch (space-scoped)
- alertsToAttachmentGroup helper chunks selections into batches of 20
- Bulk action wired across all 4 surfaces: Alerts page, Cases, Rule
  Details, and Attack Discovery
- disableOnQuery: true prevents use with "Select all N" query mode
- alert_count EBT telemetry event
- Scout E2E test and kbn-evals-suite-security-alert-triage eval package

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Addresses CodeQL unbounded-string alert: adds .max(512) to the z.string()
inside the alertIds array schema (ES _id values are at most 512 bytes).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…nt_builder/attachment_types/index.ts


Update casing in copy

Co-authored-by: Florent LB <florent.leborgne@elastic.co>
…nt_builder/attachment_types/index.ts


Update casing in copy

Co-authored-by: Florent LB <florent.leborgne@elastic.co>
…eedback

js-jankisalvi:
- Move ConversationAttachmentInput, OpenChatService, BulkAddToChatConfig
  exports below the last import in types.ts so all imports are contiguous
- Simplify ConversationAttachmentInput to interface { type: string } —
  the payload is only passed through to openChat so response-ops doesn't
  need to mirror the attachment schema; Record<string, unknown> &
  { type: string } was tried but breaks TypeScript index-signature
  compatibility for concrete types like AttachmentGroup
- Drop the redundant agentBuilderService guard in useBulkActions;
  useBulkAddToChatActions already returns [] when the service is absent

MadameSheema (Scout best-practices review):
- Add waitForRuleAlert() and checkAlertRowCheckbox() to AlertsTablePage,
  eliminating inline locator chains and the .euiCheckbox__input class
  selector from the spec
- Create AgentBuilderPage page object with conversation, attachmentPillsRow,
  inputEditor, and submitButton locators; register it in SecurityPageObjects
- Export CUSTOM_QUERY_RULE from @kbn/scout-security public barrel; both
  specs now import from '@kbn/scout-security' instead of the internal
  subpath
- Extract FULL_KIBANA_SECURITY_ROLE to test/scout/ui/common/roles.ts and
  import it in both specs, replacing the duplicate role definitions
- Add defensive pre-test cleanup at the top of beforeEach and
  scoutSpace.savedObjects.cleanStandardList() to afterEach
- Add comment explaining serverless tag exclusion
- Scope connector name to scoutSpace.id in the llmProxy fixture

Refs elastic#17496
… 30s

The attachment pills row renders one React context propagation cycle after
the outer conversation div becomes visible, so the default 10s timeout is
not reliable in slower CI environments. Adds waitForAttachmentPillsRow()
to AgentBuilderPage with an explicit 30s timeout.

Refs elastic#17496
The kbn-ftr-llm-proxy 30s timeout starts at intercept() call time.
When interceptors were registered at test start, slow CI steps
(waitForRuleAlert up to 60s, waitForAttachmentPillsRow up to 30s)
could exhaust the timeout before the submit button was ever clicked,
producing a spurious "Interceptor set_title timed out" failure.

Moving the registration to immediately before submitButton.click()
is safe because autoSendInitialMessage: false guarantees no LLM call
fires before the user submits.

Refs elastic#17496
Registers the suite alongside the other security evals so it runs
automatically in the weekly pipeline against the core model matrix.

Refs elastic#17496
…nnector

cleanStandardList() deletes saved objects of type 'action', which
includes the .gen-ai connector created by the worker-scoped llmProxy
fixture. Calling it in beforeEach destroyed the connector before the
test ran, making the bulk 'Add to chat' action invisible and causing
every subsequent step to fail.

The connector lifecycle is owned by llmProxy; this test only needs
targeted deleteAll() calls for the objects it creates.

Refs elastic#17496
@jonwalstedt jonwalstedt force-pushed the 17496-security-bulk-add-alerts-to-chat branch from 3219a16 to 8589d10 Compare May 31, 2026 18:50
@kibanamachine
Copy link
Copy Markdown
Contributor

kibanamachine commented May 31, 2026

💔 Build Failed

Failed CI Steps

Test Failures

  • [job] [logs] Scout Lane #9 - stateful-classic / default / local-stateful-classic - Bulk add alerts to chat - should open agent builder conversation with attachment chip and pre-filled prompt, and send multiple alerts to the LLM

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
securitySolution 9585 9586 +1

Async chunks

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

id before after diff
cases 2.4MB 2.4MB +781.0B
embeddableAlertsTable 1.2MB 1.2MB +783.0B
ml 5.6MB 5.6MB +781.0B
observability 2.1MB 2.1MB +781.0B
securitySolution 12.1MB 12.1MB +2.1KB
triggersActionsUi 2.6MB 2.6MB +781.0B
total +5.9KB

Page load bundle

Size of the bundles that are downloaded on every page load. Target size is below 100kb

id before after diff
securitySolution 159.8KB 160.3KB +552.0B

History

cc @jonwalstedt

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport:skip This PR does not require backporting evals:security-alert-triage Run the eval test suite for kbn-evals-suite-security-alert-triage models:eis/anthropic-claude-4.6-sonnet Run LLM evals against model: eis/anthropic-claude-4.6-sonnet release_note:feature Makes this part of the condensed release notes Team:Threat Hunting Security Solution Threat Hunting Team v9.5.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.