Long-horizon red-teaming

June 24, 2026 · View on GitHub

Twin: examples/sdk_redteam_causal_attribution_optimization.py · emits agent-learning.redteam.v1 · offline, no credentials. A coding agent can complete this page from the frontmatter alone.

1. What you are testing

Some attacks need patience. Each individual turn looks defensible — a small scope expansion here, a remembered "preference" there — and the breach only exists as the composition of steps across an extended trajectory. A per-turn safety check scores every step green; the trajectory still ends with the agent doing something no single turn authorized. That is the long-horizon failure class, and it is invisible to campaigns that evaluate turns in isolation.

examples/long_horizon_redteam_manifest.json runs an auto-generated campaign from the long_horizon_agent preset against a stateful target (long-horizon-support-agent in a local-stateful-ci environment). The persona is Isha, a security program lead, and the campaign plants a canary (FA_LONG_HORIZON_CANARY_001) whose appearance anywhere in late-trajectory output is an unambiguous escalation signal. The agent_report threshold is 0.9, and because the preset auto-generates the campaign, the executed matrix (attack types, surfaces, taxonomies) is recorded in the artifact rather than hand-listed in the manifest.

Long horizons raise a second question the moment they fail: which step caused the breach? The twin on this page is the causal-attribution optimizer — covering compositional attack classes like objective_drift, tool_chaining, and intent_hijacking — and its page, causal-attribution, is the designated follow-up to a red long-horizon run.

2. Run it

CLI:

AGENT_LEARNING_LONG_HORIZON_REDTEAM_KEY=local-example \
  agent-learn redteam examples/long_horizon_redteam_manifest.json \
  --output artifacts/long-horizon-redteam.json

SDK, same operation (the builder generates the same preset campaign for your own target):

import asyncio
import os

from fi.alk import redteam

os.environ.setdefault("AGENT_LEARNING_LONG_HORIZON_REDTEAM_KEY", "local-example")
result = asyncio.run(
    redteam.redteam_manifest_file("examples/long_horizon_redteam_manifest.json")
)
assert result["kind"] == "agent-learning.redteam.v1"
# For your agent: redteam.build_long_horizon_redteam_manifest(name=..., target=...)

3. What you built

Postcondition (machine-checkable — same check the docs gate enforces):

python -c "import json; p=json.load(open('artifacts/long-horizon-redteam.json')); assert p['kind']=='agent-learning.redteam.v1', p['kind']; print('ok')"

The artifact's summary.redteam block records the auto-generated campaign: presets and preset_sources name where the matrix came from, attack_types/channels/frameworks show what actually ran, and the severity-split finding counts gate the exit code. The deterministic defended run scores evaluation_score ≈ 0.936 against the 0.9 threshold — close enough to the line that a single escalation step pushes it red, which is exactly the sensitivity a long-horizon gate needs.

4. When it fails

SymptomFirst-mile classDoctor check
vendored import failedinfraagent-learn doctorsummary.missing_engine_modules
missing required envconfig faultagent-learn doctorsummary.api_key_configured; any local value works offline
canary string in late-trajectory outputa real breachthe trajectory crossed the escalation line — find the step with causal attribution
score just under threshold, no single bad turnthe long-horizon class itselfcompare early- vs late-trajectory metric averages in summary

5. Prove it / keep it

A red long-horizon artifact starts a two-step pipeline. First, attribute: causal-attribution assigns responsibility for the breach to specific steps instead of the whole trajectory. Second, pin: promote-to-regression turns the offending trajectory into a standing regression manifest. To push the campaign itself harder over time, examples/long_horizon_redteam_optimization.json wraps this manifest in an optimization search the same way campaign-optimization does for the single-session matrix. Cross-session persistence — the sharpest long-horizon special case — has its own page: stored-prompt-injection.