From 704f9e900db05da229da746e56b10a09da7e62ea Mon Sep 17 00:00:00 2001 From: Benjamin Ironside Goldstein Date: Tue, 26 May 2026 15:38:18 -0700 Subject: [PATCH 1/2] Workflows: fix ai.agent examples in ai-driven-alert-triage.md, plus troubleshooting and ai-steps notes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sister fix to PR #6393 (which fixed the same two bugs on the RCA page). Applies Tinsae's pattern from the Slack thread to the alert-triage page, plus two general-purpose notes that #6393 left out of scope. Closes #6720. Changes: - ai-driven-alert-triage.md: four ai.agent blocks updated. prompt: -> message: (4 occurrences). agent-id: "{{ consts.agent_id }}" -> literal agent-id: elastic-ai-agent (4 occurrences). Dropped templated connector-id (4 occurrences) — the agent encodes its connector. Pruned the now-unused agent_id and connector_id keys from consts:. Updated the prerequisites bullet to call out elastic-ai-agent as the default and ask users to substitute their agent ID. - authoring-techniques/troubleshooting.md: new entry under "AI steps" covering templated top-level fields not resolving (agent-id, connector-id, inference-id, conversation-id). Links to the engine-side bug at elastic/security-team#17236. - steps/ai-steps.md: extended the existing kebab-case important admonition with a paragraph noting that top-level fields don't currently resolve Liquid templating. Co-authored-by: Cursor --- .../authoring-techniques/troubleshooting.md | 25 +++++++++++++++++++ explore-analyze/workflows/steps/ai-steps.md | 2 ++ .../ai-driven-alert-triage.md | 24 +++++++----------- 3 files changed, 36 insertions(+), 15 deletions(-) diff --git a/explore-analyze/workflows/authoring-techniques/troubleshooting.md b/explore-analyze/workflows/authoring-techniques/troubleshooting.md index 8efb2df63b..d05fcec431 100644 --- a/explore-analyze/workflows/authoring-techniques/troubleshooting.md +++ b/explore-analyze/workflows/authoring-techniques/troubleshooting.md @@ -281,6 +281,31 @@ The same pattern applies to `agent-id` and `inference-id` on AI steps. Refer to Refer to [`ai.summarize`](/explore-analyze/workflows/steps/ai-steps.md#ai-summarize). +### Templated `agent-id` or `connector-id` isn't substituted [workflows-ts-ai-top-level-templating] + +**Symptom.** An AI step fails because a referenced resource isn't found — for example, `agent not found`, `connector not found` — even though the value is correctly defined in `consts:`. + +**Cause.** Liquid templating only resolves inside the step's `with:` block. Top-level step fields — `agent-id`, `connector-id`, `inference-id`, `conversation-id`, alongside `name`, `type`, `if`, `foreach` — receive their string value as written. So `agent-id: "{{ consts.agent_id }}"` is sent to the runtime as the literal string `{{ consts.agent_id }}`, not substituted. + +**Resolution.** Use literal values in top-level fields. For `ai.agent`, drop `connector-id` entirely (the agent encodes its connector). For fields that need templating, place them inside `with:` in snake-case (for example, `conversation_id`). + +```yaml +# Wrong — Liquid in top-level fields isn't resolved +- type: ai.agent + agent-id: "{{ consts.agent_id }}" + connector-id: "{{ consts.connector_id }}" + with: + message: "..." + +# Right — literal top-level values +- type: ai.agent + agent-id: elastic-ai-agent + with: + message: "..." +``` + +Tracked engine-side at [elastic/security-team#17236](https://github.com/elastic/security-team/issues/17236). + ## Composition [workflows-ts-composition] ### `workflow.execute` rejects `workflow_id` [workflows-ts-workflow-id] diff --git a/explore-analyze/workflows/steps/ai-steps.md b/explore-analyze/workflows/steps/ai-steps.md index dad0649ed0..8e9d21d12a 100644 --- a/explore-analyze/workflows/steps/ai-steps.md +++ b/explore-analyze/workflows/steps/ai-steps.md @@ -26,6 +26,8 @@ AI steps let workflows call a large language model (LLM) for reasoning, classifi :::{important} `connector-id`, `agent-id`, and `inference-id` are **top-level step fields** (alongside `name`, `type`, `if`, `foreach`), written in **kebab-case**. They are not nested under `with`, and not `connectorId`. Inside `with`, most AI parameters use `camelCase` (`systemPrompt`, `maxLength`, `includeRationale`). Authentication-style references stay at the top level in kebab-case; content parameters stay inside `with` in camelCase. + +These top-level fields don't currently resolve Liquid templating — `agent-id: "{{ consts.agent_id }}"` is passed through literally, not substituted. Use literal values for these fields. Tracked at [elastic/security-team#17236](https://github.com/elastic/security-team/issues/17236). ::: ## `ai.prompt` [ai-prompt] diff --git a/explore-analyze/workflows/use-cases/security/automate-security-operations/ai-driven-alert-triage.md b/explore-analyze/workflows/use-cases/security/automate-security-operations/ai-driven-alert-triage.md index 3eda090645..aeed6acf56 100644 --- a/explore-analyze/workflows/use-cases/security/automate-security-operations/ai-driven-alert-triage.md +++ b/explore-analyze/workflows/use-cases/security/automate-security-operations/ai-driven-alert-triage.md @@ -25,7 +25,7 @@ If you're new to workflows, complete [Build your first workflow](/explore-analyz - **Permissions.** `All` on **Analytics > Workflows**, **Security > Cases**, and whatever Agent Builder privilege is required to invoke agents in your space. Refer to [{{kib}} privileges](/deploy-manage/users-roles/cluster-or-deployment-auth/kibana-privileges.md). - **Attack Discovery enabled.** Attack Discovery must be running in your {{elastic-sec}} deployment and producing findings. Refer to [Attack Discovery](/solutions/security/ai/attack-discovery.md). -- **Agent Builder agent.** A configured agent in {{agent-builder}} that can reason over security context. Use one of the built-in agents (for example, the Elastic AI Agent) or a [custom agent](/explore-analyze/ai-features/agent-builder/custom-agents.md). Note the agent ID. +- **Agent Builder agent.** A configured agent in {{agent-builder}} that can reason over security context. Use one of the built-in agents (for example, the Elastic AI Agent) or a [custom agent](/explore-analyze/ai-features/agent-builder/custom-agents.md). The examples use `elastic-ai-agent` as a default. Substitute your agent ID. - **Slack connector.** A Slack [connector](/deploy-manage/manage-connectors.md) or webhook URL for notifications. - **Attach the workflow to a rule.** After saving the workflow, attach it to the Attack Discovery detection rule or the rule group you want to triage. Refer to [Alert triggers](/explore-analyze/workflows/triggers/alert-triggers.md). @@ -129,11 +129,10 @@ Call the agent with the discovery context and a specific prompt. The agent retur ```yaml - name: triage type: ai.agent - agent-id: "{{ consts.agent_id }}" - connector-id: "{{ consts.connector_id }}" + agent-id: elastic-ai-agent create-conversation: false with: - prompt: | + message: | How should we remediate this attack? - Use your knowledge of Elastic Defend to generate remediation commands. @@ -164,11 +163,10 @@ Reuse the agent with a different prompt to get a one-to-two-sentence summary sui ```yaml - name: ai_summary type: ai.agent - agent-id: "{{ consts.agent_id }}" - connector-id: "{{ consts.connector_id }}" + agent-id: elastic-ai-agent create-conversation: false with: - prompt: | + message: | Produce a one-to-two-sentence summary of the attack below for a Slack notification. Wrap entity names like hostnames in backticks. Output only the summary, no preamble. @@ -251,8 +249,6 @@ triggers: enabled: true consts: - agent_id: "your-agent-id" - connector_id: "your-connector-id" slack_webhook: "https://hooks.slack.com/services/YOUR/WEBHOOK/URL" steps: @@ -299,11 +295,10 @@ steps: - name: triage type: ai.agent - agent-id: "{{ consts.agent_id }}" - connector-id: "{{ consts.connector_id }}" + agent-id: elastic-ai-agent create-conversation: false with: - prompt: | + message: | How should we remediate this attack? Reference Elastic Defend remediation commands, include a confidence score, and do not include citations or media. @@ -320,11 +315,10 @@ steps: - name: ai_summary type: ai.agent - agent-id: "{{ consts.agent_id }}" - connector-id: "{{ consts.connector_id }}" + agent-id: elastic-ai-agent create-conversation: false with: - prompt: | + message: | Produce a one-to-two-sentence summary of the attack below for a Slack notification. Wrap hostnames in backticks. Output only the summary. From 3aa9ee32ded7420e6b530ed546955e25ae98ab27 Mon Sep 17 00:00:00 2001 From: Benjamin Ironside Goldstein Date: Tue, 26 May 2026 16:45:53 -0700 Subject: [PATCH 2/2] Workflows: clarify Liquid-templating notes, reduce em-dash density Rewrites the prose in two places to be clearer for readers who don't yet have a strong Liquid mental model, and drops 4 em dashes per review feedback. - ai-steps.md admonition: replaces the abstract "don't currently resolve Liquid templating ... passed through literally" wording with a plain rule, a concrete contrast (what's written vs. what gets sent), and a positive correct-form example. - troubleshooting.md (workflows-ts-ai-top-level-templating): Symptom uses parentheses for the "agent or connector" examples instead of em-dash asides. Cause names the mechanism (Liquid expressions aren't evaluated outside `with:`) up front, drops the unhelpful name/type/if/foreach mention, and follows with the concrete "arrives at the API as literal text" example. The YAML comments inside the troubleshooting code block keep their em dashes to match the existing in-file convention. Co-authored-by: Cursor --- .../workflows/authoring-techniques/troubleshooting.md | 4 ++-- explore-analyze/workflows/steps/ai-steps.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/explore-analyze/workflows/authoring-techniques/troubleshooting.md b/explore-analyze/workflows/authoring-techniques/troubleshooting.md index d05fcec431..adbbd61c24 100644 --- a/explore-analyze/workflows/authoring-techniques/troubleshooting.md +++ b/explore-analyze/workflows/authoring-techniques/troubleshooting.md @@ -283,9 +283,9 @@ Refer to [`ai.summarize`](/explore-analyze/workflows/steps/ai-steps.md#ai-summar ### Templated `agent-id` or `connector-id` isn't substituted [workflows-ts-ai-top-level-templating] -**Symptom.** An AI step fails because a referenced resource isn't found — for example, `agent not found`, `connector not found` — even though the value is correctly defined in `consts:`. +**Symptom.** An AI step fails because a referenced resource (for example, an agent or connector) isn't found, even though the value is correctly defined in `consts:`. -**Cause.** Liquid templating only resolves inside the step's `with:` block. Top-level step fields — `agent-id`, `connector-id`, `inference-id`, `conversation-id`, alongside `name`, `type`, `if`, `foreach` — receive their string value as written. So `agent-id: "{{ consts.agent_id }}"` is sent to the runtime as the literal string `{{ consts.agent_id }}`, not substituted. +**Cause.** Liquid expressions are evaluated only inside the step's `with:` block. On fields outside `with:`, including `agent-id`, `connector-id`, `inference-id`, and `conversation-id`, the engine sends the text to the runtime as-is. So `agent-id: "{{ consts.agent_id }}"` arrives at the API as the literal text `{{ consts.agent_id }}`, instead of being substituted with the value of `consts.agent_id`. **Resolution.** Use literal values in top-level fields. For `ai.agent`, drop `connector-id` entirely (the agent encodes its connector). For fields that need templating, place them inside `with:` in snake-case (for example, `conversation_id`). diff --git a/explore-analyze/workflows/steps/ai-steps.md b/explore-analyze/workflows/steps/ai-steps.md index 8e9d21d12a..197cedc746 100644 --- a/explore-analyze/workflows/steps/ai-steps.md +++ b/explore-analyze/workflows/steps/ai-steps.md @@ -27,7 +27,7 @@ AI steps let workflows call a large language model (LLM) for reasoning, classifi :::{important} `connector-id`, `agent-id`, and `inference-id` are **top-level step fields** (alongside `name`, `type`, `if`, `foreach`), written in **kebab-case**. They are not nested under `with`, and not `connectorId`. Inside `with`, most AI parameters use `camelCase` (`systemPrompt`, `maxLength`, `includeRationale`). Authentication-style references stay at the top level in kebab-case; content parameters stay inside `with` in camelCase. -These top-level fields don't currently resolve Liquid templating — `agent-id: "{{ consts.agent_id }}"` is passed through literally, not substituted. Use literal values for these fields. Tracked at [elastic/security-team#17236](https://github.com/elastic/security-team/issues/17236). +Liquid expressions in these top-level fields aren't evaluated. For example, writing `agent-id: "{{ consts.agent_id }}"` sends the text `{{ consts.agent_id }}` to the API as-is, instead of substituting the value of `consts.agent_id`. Always use a literal value here (for example, `agent-id: elastic-ai-agent`). Tracked at [elastic/security-team#17236](https://github.com/elastic/security-team/issues/17236). ::: ## `ai.prompt` [ai-prompt]