Skip to main content

brainwires_core/
content_source.rs

1use serde::{Deserialize, Serialize};
2
3/// Trust level / origin of content injected into an agent's context.
4///
5/// Variants are ordered from most-trusted (0) to least-trusted (3) using
6/// `#[repr(u8)]`, enabling ordering comparisons:
7///
8/// ```rust
9/// use brainwires_core::ContentSource;
10/// assert!(ContentSource::SystemPrompt < ContentSource::ExternalContent);
11/// assert!(ContentSource::SystemPrompt.can_override(ContentSource::UserInput));
12/// ```
13#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
14#[repr(u8)]
15pub enum ContentSource {
16    /// Highest trust — operator-defined instructions. Cannot be overridden.
17    SystemPrompt = 0,
18    /// High trust — content originating directly from the human turn.
19    UserInput = 1,
20    /// Medium trust — content produced by the agent itself during reasoning.
21    AgentReasoning = 2,
22    /// Lowest trust — content fetched from the web, external APIs, or
23    /// any tool that retrieves data from outside the trusted principal
24    /// hierarchy.  Always sanitized before injection.
25    ExternalContent = 3,
26}
27
28impl ContentSource {
29    /// Returns `true` for sources that must be sanitised before injection.
30    #[inline]
31    pub fn requires_sanitization(self) -> bool {
32        self == ContentSource::ExternalContent
33    }
34
35    /// Returns `true` if this source is allowed to override `other`.
36    ///
37    /// A higher-priority (lower numeric value) source can override a
38    /// lower-priority one.
39    #[inline]
40    pub fn can_override(self, other: ContentSource) -> bool {
41        self < other
42    }
43}
44
45impl std::fmt::Display for ContentSource {
46    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
47        match self {
48            ContentSource::SystemPrompt => write!(f, "system_prompt"),
49            ContentSource::UserInput => write!(f, "user_input"),
50            ContentSource::AgentReasoning => write!(f, "agent_reasoning"),
51            ContentSource::ExternalContent => write!(f, "external_content"),
52        }
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59
60    #[test]
61    fn ordering_is_trust_descending() {
62        assert!(ContentSource::SystemPrompt < ContentSource::UserInput);
63        assert!(ContentSource::UserInput < ContentSource::AgentReasoning);
64        assert!(ContentSource::AgentReasoning < ContentSource::ExternalContent);
65    }
66
67    #[test]
68    fn requires_sanitization_only_for_external() {
69        assert!(!ContentSource::SystemPrompt.requires_sanitization());
70        assert!(!ContentSource::UserInput.requires_sanitization());
71        assert!(!ContentSource::AgentReasoning.requires_sanitization());
72        assert!(ContentSource::ExternalContent.requires_sanitization());
73    }
74
75    #[test]
76    fn can_override_respects_trust_order() {
77        assert!(ContentSource::SystemPrompt.can_override(ContentSource::UserInput));
78        assert!(ContentSource::SystemPrompt.can_override(ContentSource::ExternalContent));
79        assert!(!ContentSource::ExternalContent.can_override(ContentSource::SystemPrompt));
80        assert!(!ContentSource::UserInput.can_override(ContentSource::UserInput));
81    }
82
83    #[test]
84    fn display_names() {
85        assert_eq!(ContentSource::SystemPrompt.to_string(), "system_prompt");
86        assert_eq!(ContentSource::UserInput.to_string(), "user_input");
87        assert_eq!(ContentSource::AgentReasoning.to_string(), "agent_reasoning");
88        assert_eq!(
89            ContentSource::ExternalContent.to_string(),
90            "external_content"
91        );
92    }
93}