Loop Detection & Safety

ARES includes built-in safety mechanisms to prevent agents from getting stuck in infinite loops or crashing mid-execution.

Loop Detection

The LoopDetector monitors agent tool-calling conversations for repetitive patterns using a sliding-window hash approach.

How It Works

  1. Each agent response is hashed (after whitespace normalization)
  2. Hashes are stored in a sliding window (configurable size, default 10)
  3. When duplicate hashes exceed a threshold, a loop is detected
  4. The detector escalates through 3 tiers of intervention

Escalation Tiers

TierActionDescription
1InjectWarningAdds a system message warning the agent it's repeating itself
2ForceAlternativeForces the agent to take a different approach
3HaltAgentStops the agent entirely and returns an error to the caller

Configuration

#![allow(unused)]
fn main() {
use ares::agents::loop_detector::{LoopDetector, LoopDetectorConfig};

let config = LoopDetectorConfig {
    window_size: 10,        // Number of recent responses to track
    threshold: 3,           // Duplicates before triggering
    min_response_length: 20, // Ignore very short responses
};

let mut detector = LoopDetector::new(config);
}

Usage in Agents

Loop detection is automatically applied during multi-turn tool-calling conversations. The ConfigurableAgent checks the detector after each response.

Crash Recovery

The CheckpointManager provides state serialization for long-running agent tasks.

Checkpoints

#![allow(unused)]
fn main() {
use ares::agents::checkpoint::{CheckpointManager, Checkpoint};

let manager = CheckpointManager::new("/data/checkpoints");

// Save a checkpoint
let checkpoint = Checkpoint {
    session_id: "session-123".to_string(),
    step: 5,
    messages: vec![/* conversation history */],
    tool_calls: vec![/* pending tool calls */],
    partial_results: vec![/* results so far */],
    status: "in_progress".to_string(),
};
manager.save(&checkpoint)?;

// Resume from latest checkpoint
if let Some(restored) = manager.load_latest("session-123")? {
    // Continue from where we left off
}
}

Cleanup

Old checkpoints are cleaned up automatically based on age:

#![allow(unused)]
fn main() {
// Remove checkpoints older than 24 hours
manager.cleanup(Duration::from_secs(86400))?;
}

Emergency Stop

The emergency stop is a global kill switch that immediately rejects all agent requests with HTTP 503.

# Activate emergency stop
curl -X POST http://localhost:3000/api/admin/agents/emergency-stop \
  -H "X-Admin-Secret: your-admin-secret" \
  -H "Content-Type: application/json" \
  -d '{"active": true}'

# Deactivate
curl -X POST http://localhost:3000/api/admin/agents/emergency-stop \
  -H "X-Admin-Secret: your-admin-secret" \
  -H "Content-Type: application/json" \
  -d '{"active": false}'

When active, all /api/chat, /api/chat/stream, /v1/chat, and agent execution endpoints return:

{
  "error": "Emergency stop is active. All agent requests are suspended.",
  "code": "EMERGENCY_STOP"
}