# Core Action Steps

For common fields, string substitutions, metadata filters, caching, and execution order, see the [Agent Steps Overview](https://seclai.com/docs/agent-steps). For branching / looping / merging / approval primitives (gate, retry, for_each, if_else, switch, merge, human_in_the_loop), see [Control Flow Steps](https://seclai.com/docs/agent-steps/control).

---

## Text Step

Produces output from a template string with variable substitutions. This is the simplest way to construct formatted text, combine outputs from multiple steps, or create static content.

### Fields

| Field                     | Type   | Required | Default           | Description                                                                                                                                                        |
| ------------------------- | ------ | -------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| <code>template</code>     | string | Yes      | —                 | The template string to render. Supports all substitution variables.                                                                                                |
| <code>content_type</code> | enum   | No       | <code>null</code> | Output content type: <code>text/plain</code>, <code>text/html</code>, <code>application/json</code>, <code>application/xml</code>. When null, inherits from input. |

### Use Case Examples

**Composing a prompt from multiple sources:**

```
Here is the user's question:
{{agent.input}}

Here is the relevant context from our knowledge base:
{{step.retrieval.output}}

Here is the user's profile:
Name: {{metadata.user_name}}
Plan: {{metadata.plan}}
```

**Generating a JSON payload:**

Template:

```json
{
  "agent_id": "{{agent.id}}",
  "run_id": "{{agent.run_id}}",
  "result": "{{step.analysis.output}}",
  "timestamp": "{{datetime UTC}}"
}
```

Content type: `application/json`

*Figure: JSON payload composition — a prompt call analyzes the input, then a text step formats the result as a JSON payload for a webhook.*

**Creating an HTML report:**

Template:

```html
<h1>Daily Report — {{date America/New_York}}</h1>
<h2>Summary</h2>
<div>{{step.summary.output}}</div>
<h2>Key Findings</h2>
<div>{{step.findings.output}}</div>
<footer>Generated by {{agent.name}} at {{time America/New_York}}</footer>
```

Content type: `text/html`

*Figure: HTML report — parallel branches generate a summary and key findings, then a text step merges them into an HTML report.*

*Figure: Text Compose — a text step merges multiple step outputs into a formatted HTML report before display.*

### AI Assistant

The AI assistant can help generate text step templates. Describe what output you want, and it will create a template using the appropriate substitution variables based on your agent's step structure.

---

## Regex Replace Step

Transforms text using an ordered list of regex-based substitution rules. Each rule applies a pattern match and optional replacement to the step's input, and rules execute sequentially.

### Fields

| Field              | Type  | Required | Default | Description                                      |
| ------------------ | ----- | -------- | ------- | ------------------------------------------------ |
| <code>rules</code> | array | Yes      | —       | An ordered list of transformation rules to apply |

Each **rule** has:

| Field                     | Type   | Required | Default           | Description                                                                                                                                                               |
| ------------------------- | ------ | -------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| <code>pattern</code>      | string | Yes      | —                 | A regex pattern to match in the input text                                                                                                                                |
| <code>substitution</code> | string | No       | <code>null</code> | The replacement string. If <code>null</code>, matched text is removed. Supports regex capture groups (<code>\1</code>, <code>\2</code>, etc.) and substitution variables. |
| <code>comment</code>      | string | No       | <code>null</code> | A human-readable description of what this rule does                                                                                                                       |

Rules are applied sequentially — each rule operates on the result of the previous rule.

### Use Case Examples

**Clean HTML tags from text:**

| Pattern                  | Substitution       | Comment              |
| ------------------------ | ------------------ | -------------------- |
| <code>{'<[^>]+>'}</code> | _(empty)_          | Remove all HTML tags |
| <code>{'&amp;'}</code>   | <code>{'&'}</code> | Decode HTML entity   |
| <code>{'&lt;'}</code>    | <code>{'<'}</code> | Decode HTML entity   |
| <code>{'&gt;'}</code>    | <code>{'>'}</code> | Decode HTML entity   |

*Figure: Clean HTML — a web fetch retrieves raw HTML, then a regex replace step strips tags and decodes entities before analysis.*

**Extract email addresses:**

| Pattern            | Substitution                                 | Comment |
| ------------------ | -------------------------------------------- | ------- |
| <code>^.\*$</code> | _(use a prompt call for complex extraction)_ | —       |

**Normalize whitespace:**

| Pattern                  | Substitution      | Comment                        |
| ------------------------ | ----------------- | ------------------------------ |
| <code>\r\n</code>        | <code>\n</code>   | Normalize line endings         |
| <code>{'[ \\t]+'}</code> | <code> </code>    | Collapse multiple spaces/tabs  |
| <code>{'\\n{3,}'}</code> | <code>\n\n</code> | Collapse excessive blank lines |

*Figure: Normalize whitespace — the agent loads content, normalizes spacing, then extracts themes from clean text.*

**Redact sensitive data:**

| Pattern                                                              | Substitution                      | Comment                        |
| -------------------------------------------------------------------- | --------------------------------- | ------------------------------ |
| <code>{'\\b\\d{3}-\\d{2}-\\d{4}\\b'}</code>                          | <code>{'[SSN REDACTED]'}</code>   | Redact Social Security numbers |
| <code>{'\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z]{2,}\\b'}</code>  | <code>{'[EMAIL REDACTED]'}</code> | Redact email addresses         |
| <code>{'\\b\\d{4}[\\s-]?\\d{4}[\\s-]?\\d{4}[\\s-]?\\d{4}\\b'}</code> | <code>{'[CARD REDACTED]'}</code>  | Redact credit card numbers     |

*Figure: Redact PII — the agent loads content, redacts sensitive data with regex replace rules, and delivers a safe copy via email.*

*Figure: Regex Replace Clean — a regex replace step redacts PII before the content reaches the prompt call.*

### AI Assistant

The AI assistant can generate regex replace rules for you. Describe the transformation you want (e.g., "remove all URLs from the text" or "extract only the first paragraph"), and it will produce the appropriate regex patterns and substitutions.

The assistant generates rules with:

- `pattern` — The regex to match
- `substitution` — The replacement text (or null to remove)
- `comment` — An explanation of what the rule does

---

## Extract Content Step

Extracts structured content (JSON, XML, or HTML) from noisy LLM output and optionally converts the format. This is the preferred step for cleaning up LLM responses that contain structured data embedded in prose.

### Fields

| Field                        | Type   | Required | Description                                                                                                                                                                                                                                                                                                                                                                                                                         |
| ---------------------------- | ------ | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| <code>expected_format</code> | string | No       | <code>"json"</code>, <code>"xml"</code>, or <code>"html"</code> — the format to extract from the input                                                                                                                                                                                                                                                                                                                              |
| <code>query</code>           | string | No       | JSONPath (for json), XPath (for xml), or tag name (for html) to drill into content                                                                                                                                                                                                                                                                                                                                                  |
| <code>json_schema</code>     | object | No       | JSON Schema (Draft 2020-12) to validate the extracted JSON against. Only applies when <code>expected_format</code> is <code>"json"</code>; the step fails if the extracted JSON does not conform                                                                                                                                                                                                                                    |
| <code>xml_schema</code>      | string | No       | XML Schema Definition (XSD) to validate the extracted XML against. Only applies when <code>expected_format</code> is <code>"xml"</code>; the step fails if the extracted XML does not conform                                                                                                                                                                                                                                       |
| <code>convert_to</code>      | string | No       | <code>"html"</code>, <code>"markdown"</code>, or <code>"plain_text"</code> — optional format conversion after extraction. Only valid with <code>expected_format</code> <code>"html"</code> or no extraction; it is a no-op or lossy for <code>"json"</code>/<code>"xml"</code>, so the editor hides it, the AI assistant rejects it, and a definition that pairs it with <code>"json"</code>/<code>"xml"</code> is rejected on save |

### Use Case Examples

**Extract JSON from LLM output:**

`expected_format: "json"` — Finds and extracts the first valid JSON object or array from the text.

*Figure: Extract JSON — a prompt call produces JSON, the extract step cleans it, and the result is sent to a webhook.*

**Extract JSON with JSONPath query:**

`expected_format: "json"`, `query: "$.results[0].name"` — Extracts JSON and then drills into it using a JSONPath expression.

*Figure: Extract with JSONPath — a prompt call generates results, then JSONPath drills into the first result's name.*

**Validate extracted JSON against a schema:**

`expected_format: "json"`, `json_schema: { "type": "object", "required": ["id"] }` — Extracts JSON and fails the step unless it conforms to the supplied JSON Schema. Pair with a `query` to validate only the drilled-into value.

**Validate extracted XML against an XSD:**

`expected_format: "xml"`, `xml_schema: "<xs:schema …>…</xs:schema>"` — Extracts XML and fails the step unless it conforms to the supplied XML Schema Definition.

**Convert markdown to HTML:**

`convert_to: "html"` — Converts markdown content to HTML without extracting structured data.

**Extract HTML and convert to markdown:**

`expected_format: "html"`, `query: "article"`, `convert_to: "markdown"` — Extracts an HTML article tag and converts it to markdown.

*Figure: HTML to Markdown — a web fetch retrieves a page, then the extract step pulls the article tag and converts it to markdown.*

*Figure: Extract + Parse — a prompt call generates JSON output, and the extract step cleans and parses it for downstream use.*

---

## Extract Data Step

Uses an AI model with **progressive-disclosure tools** to derive insights from potentially large input content. Unlike a Prompt Call (which passes the full input in the prompt), the Extract Data step gives the model tools to incrementally inspect the input — making it ideal for large documents, feeds, or data dumps that might exceed context-window limits.

### Fields

| Field                               | Type                                                                                                                             | Required | Default                           | Description                                                                                                                                                                                                                                                                                                                                                                              |
| ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | -------- | --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| <code>prompt_template</code>        | string                                                                                                                           | Yes      | —                                 | Describes the desired analysis — what kind of insight to derive from the input (e.g. summary, topics, keywords, sentiment). Supports substitutions.                                                                                                                                                                                                                                      |
| <code>output_format</code>          | <code>"text"</code> \| <code>"markdown"</code> \| <code>"html"</code> \| <code>"json_object"</code> \| <code>"json_array"</code> | No       | <code>"text"</code>               | Controls the format of the model's response and the content type stamped on the step output (see [Output Content Type](#extract-data-output)). <code>text</code> forces plain text (no Markdown), <code>markdown</code> well-formed Markdown, <code>html</code> an HTML fragment; <code>json_object</code> and <code>json_array</code> instruct the model to produce strict JSON output. |
| <code>output_schema</code>          | object                                                                                                                           | No       | <code>null</code>                 | An optional JSON Schema describing the desired output structure. When provided, overrides <code>output_format</code> and instructs the model to conform to the schema.                                                                                                                                                                                                                   |
| <code>model</code>                  | enum                                                                                                                             | No       | Claude Haiku 4.5                  | The AI model to use. Must support tool calling. When omitted, the system selects a capable default.                                                                                                                                                                                                                                                                                      |
| <code>model_variant</code>          | string                                                                                                                           | No       | <code>null</code>                 | Model variant identifier, if applicable.                                                                                                                                                                                                                                                                                                                                                 |
| <code>auto_upgrade_strategy</code>  | enum                                                                                                                             | No       | <code>null</code> (inherit)       | Optional per-step lifecycle strategy override (<code>none</code>, <code>early_adopter</code>, <code>middle_of_road</code>, <code>cautious_adopter</code>).                                                                                                                                                                                                                               |
| <code>auto_rollback_enabled</code>  | boolean                                                                                                                          | No       | <code>null</code> (inherit)       | Optional per-step auto-rollback override for upgraded-model failures.                                                                                                                                                                                                                                                                                                                    |
| <code>auto_rollback_triggers</code> | array                                                                                                                            | No       | <code>null</code> (inherit)       | Optional per-step rollback trigger list (<code>agent_eval_fail</code>, <code>governance_flag</code>, <code>governance_block</code>, <code>agent_run_failed</code>).                                                                                                                                                                                                                      |
| <code>temperature</code>            | float                                                                                                                            | No       | <code>0.3</code>                  | Sampling temperature (0.0–1.0). Lower values produce more focused, deterministic output.                                                                                                                                                                                                                                                                                                 |
| <code>max_tokens</code>             | integer                                                                                                                          | No       | <code>null</code> (model default) | Maximum number of tokens in the model's response.                                                                                                                                                                                                                                                                                                                                        |

### When to Use Extract Data vs Prompt Call

| Consideration                | Prompt Call                                | Extract Data                                                    |
| ---------------------------- | ------------------------------------------ | --------------------------------------------------------------- |
| Input fits in context window | Pass it directly in the prompt             | Unnecessary overhead                                            |
| Input may be very large      | Risk of truncation or token-limit errors   | Model scans progressively via tools                             |
| Need structured JSON output  | Use <code>json_template</code> / JSON mode | Use <code>output_format</code> or <code>output_schema</code>    |
| Need a system prompt         | <code>system_template</code> field         | System prompt is auto-generated                                 |
| Need custom LLM tools        | Configure via <code>tools</code> field     | Not supported — uses built-in progressive-disclosure tools only |

**Rule of thumb:** If the input is small and you want full control over the prompt, use Prompt Call. If the input could be large and you want the model to intelligently scan it, use Extract Data.

### How It Works

1. The step receives the previous step's output (or agent input) as a content handle — a lazy abstraction that avoids loading everything into memory.

2. Three **built-in tools** are automatically provided to the model:

| Tool                          | Description                                                                              |
| ----------------------------- | ---------------------------------------------------------------------------------------- |
| <code>get_input_size</code>   | Returns byte size and approximate character count. Call first to plan scanning strategy. |
| <code>read_input_range</code> | Reads a byte-range slice of the input (max 50,000 bytes per call).                       |
| <code>search_input</code>     | Searches for lines matching a regex or plain-text pattern (max 50 matches).              |

3. An auto-generated **system prompt** tells the model to:
   - Call `get_input_size` first to understand the content volume.
   - For small content (< 50,000 bytes), read it all at once.
   - For larger content, scan progressively: read the beginning, search for key sections, and sample from different parts.
   - Produce the requested output directly — no meta-commentary.

4. The model iterates through tool calls until it has enough context, then produces the final output.

### Output Content Type

The model is instructed to honour the selected `output_format`, and the content type stamped on the step output matches it:

- **Plain text** (`output_format: "text"` with no `output_schema`) → `text/plain` (the model is told not to emit Markdown or HTML)
- **Markdown** (`output_format: "markdown"`) → `text/markdown`
- **HTML** (`output_format: "html"`) → `text/html` (an HTML fragment — no `<html>`/`<body>` wrapper)
- **Structured** (`output_format: "json_object"` or `"json_array"`, or any `output_schema`) → `application/json`

The content type propagates to downstream steps and outputs. In particular, a **Send Email** step whose input is `text/markdown` (with no HTML body template) renders the Markdown to HTML for the email body, and a `text/html` input is used as the HTML body directly — so a `markdown` or `html` Extract Data step feeds formatted email rather than raw markup.

### Use Case Examples

**Summarize an RSS feed:**

```
prompt_template: Summarize the key topics and themes from this RSS feed content.
                 Group related items together.
model: anthropic_claude_haiku_4_5
temperature: 0.3
```

*Figure: RSS summary — the extract data step processes RSS feed content to produce a brief with key articles.*

**Extract structured topics (JSON array):**

```
prompt_template: Extract all distinct topics mentioned in the input content.
output_format: json_array
model: anthropic_claude_haiku_4_5
temperature: 0.2
```

*Figure: Structured topics extraction — the extract data step extracts a JSON array of topics from content for downstream processing.*

**Full content analysis with JSON Schema:**

```
prompt_template: Analyze the input content and produce a structured report.
output_schema:
  type: object
  properties:
    summary:
      type: string
    topics:
      type: array
      items:
        type: string
    sentiment:
      type: string
      enum: [positive, negative, neutral, mixed]
    key_entities:
      type: array
      items:
        type: object
        properties:
          name:
            type: string
          type:
            type: string
  required: [summary, topics, sentiment]
model: anthropic_claude_haiku_4_5
temperature: 0.2
```

*Figure: Extract Data Analyze — the extract data step analyzes content and extracts structured data for downstream processing.*

### AI Assistant

The Extract Data step includes full **AI assistant** support. Click the **AI Assistant** button to describe what you want in natural language, and the assistant will generate the complete configuration — `prompt_template`, `output_format`, `output_schema`, `model`, `auto_upgrade_strategy`, `auto_rollback_enabled`, `auto_rollback_triggers`, `temperature`, and `max_tokens`.

The agent-level AI assistant (for generating full workflows) also understands the Extract Data step and will include it when the task involves analyzing large content.

### Attachments

Extract Data can analyze multi-modal inputs natively when the configured model supports the MIME (Claude 4.x, Nova, GPT-4o-class, Gemini). Reference attachments in `prompt_template` using the selector grammar:

- `{{attachments[0]}}` — the current step's input attachment at index 0
- `{{attachments[*.pdf]}}` — input attachments whose filename matches the glob
- `{{attachments[invoice.pdf]}}` — exact filename match
- `{{agent.attachments[…]}}` — the original trigger uploads
- `{{step.<id>.attachments[…]}}` — another `prompt_call` or `call_agent` step's multi-asset output

Each match is sent as a native media block when the resolved model supports the MIME; otherwise the OCR / transcript counterpart is stitched onto the prompt text (text-only models still get to "see" the attachment, just via extracted text). The inline placeholder itself is replaced with a `[attachment: name]` marker so the prompt can refer to attachments by name.

A template that doesn't reference any attachments sees none — uploads are narrowly visible to steps that declare a dependency.

---

## Evaluate Step

Scores a previous step's output using LLM-based criteria and emits structured JSON with `score`, `passed`, and `pass_threshold`.

Unlike Retry, this step does **not** re-run anything by itself. It is designed to produce an evaluation result that downstream steps (typically a Gate) can use for branching.

**Related steps:** [Gate](https://seclai.com/docs/agent-steps/control#gate-step) branches on the evaluation score. [Retry](https://seclai.com/docs/agent-steps/control#retry-step) re-runs the target step when a gate determines the score is too low.

### Fields

| Field                           | Type   | Required | Default           | Description                                                                                                                                       |
| ------------------------------- | ------ | -------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| <code>target_step_id</code>     | string | Yes      | —                 | The <code>id</code> of a previously executed step to evaluate. Must match <code>{'^[a-zA-Z0-9_-]+$'}</code>.                                      |
| <code>evaluation_prompt</code>  | string | Yes      | —                 | Natural-language rubric for scoring quality (accuracy, completeness, tone, etc.).                                                                 |
| <code>pass_threshold</code>     | float  | Yes      | —                 | Score cutoff (inclusive) for pass/fail. Range: <code>0.0</code> to <code>1.0</code>.                                                              |
| <code>evaluation_tier</code>    | enum   | No       | <code>null</code> | Optional evaluator model tier override (<code>fast</code>, <code>balanced</code>, <code>thorough</code>).                                         |
| <code>expectation_config</code> | object | No       | <code>null</code> | Optional structural constraints (<code>expected_format</code>, <code>contains</code>, <code>forbidden_phrases</code>, and similar rule settings). |

### Output Format

The step output is JSON with this shape:

```json
{
  "evaluated_step_id": "retrieval-1",
  "score": 0.82,
  "passed": true,
  "pass_threshold": 0.7,
  "explanation": "Meets criteria"
}
```

`passed` is computed from `score >= pass_threshold`.

### Best Practice: Pair with a Gate

To branch on evaluation quality, put a Gate after Evaluate Step and inspect the JSON output:

```
prompt_call (id: generate-report)
  └─ evaluate_step (target_step_id: generate-report, pass_threshold: 0.7)
       └─ gate (checks {{input}} for passed=true)
```

This keeps scoring and control flow separate: Evaluate Step scores, Gate decides what to do next.

*Figure: Evaluate + Gate pattern: the evaluate step scores the output, then a gate branches based on whether the score meets the threshold.*

### Attachments

When the target step is a `prompt_call` that emits images (e.g. via `gpt-image-1`, Gemini image-out, Nova image generation) or a `call_agent` whose sub-agent produces a multi-asset manifest, the evaluator can reason over the generated media directly. Reference attachments in `evaluation_prompt`:

- `{{step.<target_id>.attachments[0]}}` — the first image emitted by the target step
- `{{step.<target_id>.attachments[*.png]}}` — every PNG emitted by the target
- `{{agent.attachments[…]}}` — the original trigger uploads (useful when the rubric compares the target's output against an input image, PDF, etc.)
- `{{attachments[…]}}` — the current step's input manifest (rarely needed — eval reads its target via `target_step_id`)

Each match flows to the evaluator as a native media block when the resolved `evaluation_tier`'s model supports the MIME (Balanced and Thorough tiers do; Fast tier may not — text fallback kicks in automatically). Inline placeholders are replaced with `[attachment: name]` markers so the rubric can refer to them by name.

`{{step.<id>.attachments[…]}}` is only valid when `<id>` is a `prompt_call` or `call_agent` step — those are the only step types that emit a multi-asset manifest. Referencing the attachments of any other step type is a save-time error.

### Use Case Examples

**Evaluate + If/Else Gate — stream result on success, alert on failure:**

Use two mutually exclusive gates after the evaluate step to create an if/else branch. The "passed" gate streams the result to the user; the "failed" gate sends an email alert notifying an operator that the output quality was below threshold.

```
Step 1: Prompt Call (id: generate-report)
  Step 2: Evaluate Step (target: generate-report, pass_threshold: 0.7)
    Step 3a: Gate (passed = true)
      Step 4a: Streaming Result
    Step 3b: Gate (passed = false)
      Step 4b: Send Email — "Alert: report scored below quality threshold"
```

*Figure: Evaluate + If/Else Gate: the evaluate step scores quality, then two mutually exclusive gates branch — passing scores stream the result, failing scores send an email alert.*

**Evaluate + Gate + Retry — auto-improve on low scores:**

Combine all three steps to create a self-improving loop. The evaluate step scores the output, then two mutually exclusive gates branch on the result. The "passed" gate leads to a display result; the "failed" gate leads to a retry that re-runs the prompt call (up to 3 times). A merge whose `wait_for` names the display and retry branch tips recombines the flow.

```
Step 1: Prompt Call (id: generate-report)
  Step 2: Evaluate Step (target: generate-report, pass_threshold: 0.7)
    Step 3a: Gate (passed = true)
      Step 4a: Display Result (id: display)
    Step 3b: Gate (passed = false)
      Step 4b: Retry (id: retry, max: 3, target: generate-report)
  Step 6: Merge — merge final output (wait_for: [display, retry])
```

*Figure: Evaluate + Gate + Retry: the evaluate step scores quality, two mutually exclusive gates branch on pass/fail — passing scores display the result, failing scores retry up to 3 times.*

---

[← Back to Agent Steps Overview](https://seclai.com/docs/agent-steps)
