quorum-rs 0.8.0

Rust SDK and CLI for multi-agent deliberation systems — ships the `quorum` binary (run / status / trace / tui / init) plus the underlying agent, LLM, tool, prompt, and worker library.
Documentation
//! Pluggable detector for "leaked internal prompt" patterns in LLM output.
//!
//! This module defines the [`OutputLeakDetector`] trait. Concrete
//! implementations are supplied by callers; if no detector is attached
//! the agent runs without output guarding. Wire one in via
//! [`ProposerEvaluatorAgent::with_output_guard`](crate::agents::ProposerEvaluatorAgent::with_output_guard)
//! when constructing the agent.

use crate::middleware::{MiddlewareContext, MiddlewareVerdict};
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use std::fmt::Debug;

/// Per-category scan stats from an [`OutputLeakDetector::scan`] call.
///
/// Field names mirror the original `PromptExposureMiddleware::ScanResult` so
/// agents that previously consumed it can migrate without renaming.
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct OutputScanResult {
    pub hits: Vec<String>,
    pub xml_tag_hits: u32,
    pub tool_name_hits: u32,
    pub instruction_hits: u32,
    pub wrong_acronym_hits: u32,
    pub suspicion_score: f64,
    pub response_length_chars: u32,
}

impl OutputScanResult {
    /// Total indicators across all categories.
    pub fn hit_count(&self) -> u32 {
        self.xml_tag_hits + self.tool_name_hits + self.instruction_hits + self.wrong_acronym_hits
    }
}

/// Detector contract. `scan` returns raw stats (cheap, callable per-snippet);
/// `evaluate` runs the full verdict pipeline (threshold gates, suspicion-score
/// weighting, reason construction).
#[async_trait]
pub trait OutputLeakDetector: Send + Sync + Debug {
    /// Tally per-category indicators in `text`. Used by callers that want
    /// stats for telemetry independently of the block/pass decision.
    fn scan(&self, text: &str) -> OutputScanResult;

    /// Run the detector's verdict gate over a [`MiddlewareContext`].
    /// Returns Pass/Warn/Block with a reason string suitable for surfacing
    /// to operators.
    async fn evaluate(&self, ctx: &MiddlewareContext) -> MiddlewareVerdict;

    /// Strip leaked indicators from `text`, returning sanitized text that
    /// no longer scans as a leak. Used as a graceful fallback: when a block
    /// fires on already-recovered structured output, the caller redacts the
    /// user-visible fields and continues the deliberation instead of failing.
    ///
    /// Default: identity (fail-open) so detectors that don't implement
    /// redaction keep the pre-existing pass-through behaviour.
    fn redact(&self, text: &str) -> String {
        text.to_string()
    }
}