pub struct ShadowSentinel { /* private fields */ }Expand description
Orchestrates the persistent safety stream and LLM pre-execution probe.
ShadowSentinel is wrapped in Arc and shared between ShadowProbeExecutor instances
when tools run in parallel. All mutable state uses AtomicU32 to allow &self access
from concurrent tool dispatch without a Mutex.
§Turn lifecycle
advance_turn()— call once per turn before tool execution; resets the per-turn probe counter.check_tool_call()— call before each tool execution to probe high-risk calls.record_tool_event()— call after tool execution to persist the event.drain_pending()— call at session shutdown to await all queued persist writes.
§NEVER
Never expose the ShadowSentinel state or probe verdicts to LLM-visible context.
Implementations§
Source§impl ShadowSentinel
impl ShadowSentinel
Sourcepub fn new(
store: ShadowEventStore,
probe: Box<dyn SafetyProbe>,
config: ShadowSentinelConfig,
session_id: impl Into<SessionId>,
) -> Self
pub fn new( store: ShadowEventStore, probe: Box<dyn SafetyProbe>, config: ShadowSentinelConfig, session_id: impl Into<SessionId>, ) -> Self
Create a new ShadowSentinel.
§Arguments
store— persistent shadow event store.probe— safety probe implementation.config— subsystem configuration.session_id— current agent session identifier.
Sourcepub fn mcp_tool_ids_handle(&self) -> Arc<RwLock<HashSet<String>>> ⓘ
pub fn mcp_tool_ids_handle(&self) -> Arc<RwLock<HashSet<String>>> ⓘ
Returns the shared MCP tool-id set so the caller can populate it once MCP servers have
connected (mirrors TrustGateExecutor::mcp_tool_ids_handle).
Sourcepub fn classify_tool(&self, qualified_tool_id: &str) -> ToolRiskCategory
pub fn classify_tool(&self, qualified_tool_id: &str) -> ToolRiskCategory
Classify a fully-qualified tool id into a risk tier.
Pattern matching is prefix/glob-based against the configured probe_patterns.
For efficiency, we check common built-in names first before falling back to
glob matching against the configured patterns.
Sourcepub async fn check_tool_call(
&self,
qualified_tool_id: &str,
tool_args: &JsonValue,
turn_number: u64,
current_risk_level: &str,
) -> ProbeVerdict
pub async fn check_tool_call( &self, qualified_tool_id: &str, tool_args: &JsonValue, turn_number: u64, current_risk_level: &str, ) -> ProbeVerdict
Evaluate a proposed tool call and return a probe verdict.
Returns ProbeVerdict::Skip when:
- The tool is not in a high-risk category.
- The feature is disabled.
- The per-turn probe budget (
max_probes_per_turn) is exhausted.
ToolRiskCategory::ExfilCapable calls (#5749) draw from their own independent, higher
budget (2 * max_probes_per_turn) instead of the shared counter, so unrelated earlier
probes in the same turn can never wave one through — but the budget is still finite, not
unconditional. ToolRiskCategory::McpUnclassified calls (#5750) get a reduced share of
the shared budget — at least one slot is always reserved for keyword-matched
(higher-confidence) categories so a burst of low-signal MCP engagement cannot starve them
out within the same turn, at any max_probes_per_turn value.
This method takes &self so it can be called from parallel tool dispatch.
§Errors
Does not return errors; probe failures are handled internally (fail-open or
fail-closed depending on deny_on_timeout).
Sourcepub async fn record_tool_event(
&self,
qualified_tool_id: &str,
turn_number: u64,
risk_level: &str,
context_summary: &str,
)
pub async fn record_tool_event( &self, qualified_tool_id: &str, turn_number: u64, risk_level: &str, context_summary: &str, )
Persist a tool execution event in the shadow stream (fire-and-forget).
Called after a tool finishes execution to maintain the trajectory for future probes.
Sourcepub async fn drain_pending(&self)
pub async fn drain_pending(&self)
Await all queued fire-and-forget persist tasks.
Call once at session shutdown to ensure no DB writes are silently dropped. All errors have already been logged inside each task; this method only joins the handles.
Sourcepub fn advance_turn(&self)
pub fn advance_turn(&self)
Reset the per-turn probe counters.
Must be called once per turn BEFORE any tool calls, alongside
TrajectorySentinel::advance_turn().
Auto Trait Implementations§
impl !Freeze for ShadowSentinel
impl !RefUnwindSafe for ShadowSentinel
impl !UnwindSafe for ShadowSentinel
impl Send for ShadowSentinel
impl Sync for ShadowSentinel
impl Unpin for ShadowSentinel
impl UnsafeUnpin for ShadowSentinel
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request