<!-- https://avertgate.com/docs/runtime-loop · How it works -->

# Runtime loop

AvertGate runs the same loop on every tool call: cheap deterministic checks first, then the semantic model when needed.

#### Intercept

Agent id, session id, tool name and arguments are captured; the session's trajectory is loaded.

#### Request inspection (before the tool runs)

Policy, egress scan and loop breaker run in order. The policy decision is made here; if the arguments carry secrets/PII the call is stopped. Optionally the AI Guard analyses intent.

#### Execute

The allowed call is forwarded to the real tool and the result is received.

#### Response inspection (after the tool runs)

The returned result is treated as untrusted content and scanned for indirect prompt injection.

#### Return and record

The clean result goes back to the agent. The full event (with redacted arguments) is appended to the chained audit log.

## Why two phases?

The **request phase** governs what the agent is *about to do*. The **response phase** inspects what *comes back*: tool results, retrieved documents and web content are the untrusted channel through which indirect prompt injection reaches the agent. The two cannot be collapsed into one step; an attack usually enters in the response phase and can only be neutralised at the request phase.

## Order and cost

| Step | Kind | Typical time |
| --- | --- | --- |
| Policy, egress/ingress regex, loop breaker | Deterministic, local | < 2 ms |
| AI Guard (optional) | Semantic model | ~50–100 ms (TypeSafe AI Jev) |

If a deterministic step already stops a call, the model is never called. The model is consulted only for content that passed the cheap checks and is long enough.

## What happens in the request and response phases?

Every call produces one final decision and **one audit event**. The outcome depends on where the call stopped:

| Situation | Does the tool run? | What the agent gets | Audit record |
| --- | --- | --- | --- |
| Request phase ALLOW, response clean | Yes | The tool's result | `ALLOW` |
| Request phase BLOCK | **No** | A safe error message | `BLOCK` + reason + rule |
| Request phase ESCALATE, approved | Yes, after approval | The tool's result (if the response scan passes) | Final decision |
| Request phase ESCALATE, denied / timed out / Slack error | **No** | A safe error message | `BLOCK` |
| Request passed, **response suspicious** (injection signal) | **Yes, it already ran** | The result is *withheld from the agent*; a safe error comes back | `BLOCK` (reason: ingress scan) |

> **A response-phase block is not an undo**: By the time a response is judged suspicious, the tool call has already happened. AvertGate cannot reverse its effect; it only stops the poisoned content from reaching the agent. Control irreversible actions in the request phase (`allow: false`, `constraints`, `require_approval`). See [Risk tiers](/docs/risk-tiers).

In shadow mode nothing is blocked in either phase; the outcome is only recorded as `SHADOW_BLOCK` / `SHADOW_ESCALATE` and the result reaches the agent unchanged.

## Fail-closed: what happens on errors?

If an inspector fails (network, timeout, parse error) AvertGate never silently allows. Behaviour by situation (`fail_closed` defaults to `true`):

| Situation | `fail_closed: true` (default) | `fail_closed: false` | Shadow mode |
| --- | --- | --- | --- |
| Policy cannot be loaded / parsed at start | The gateway **does not start** (exits with an error). There is no policy-less operation. | Same |  |
| Policy reload fails while running (broken file) | The active policy is **kept**; the reload error is logged as a warning. | Same |  |
| Request inspector errors (egress scan, AI Guard layer 1 timeout) | `BLOCK` | The check is skipped, the call continues | `SHADOW_BLOCK` recorded, call continues |
| Response inspector errors (ingress scan, AI Guard layer 2) | `BLOCK`: the tool ran, the result is withheld | The result reaches the agent | `SHADOW_BLOCK` recorded, result delivered |
| Human approval: denial, timeout (default 120 s) or Slack error | `BLOCK`: always, regardless of this setting. | No wait, `SHADOW_ESCALATE` recorded |  |
| Tool (upstream) errors | The agent gets a "tool execution failed" error; the event is recorded as `BLOCK`. | Same |  |
| Connection to the dashboard is lost | Tool calls are **not affected**. Event shipping logs a warning and drops the failed batch; at most 500 events are buffered in memory. The local audit log keeps being written. | Same |  |

Keep `fail_closed: true` in production. Use `false` only as a deliberate decision when an inspector outage is judged worse than a coverage gap.
