sokuto_server/guardrails/
attention.rs1pub const ATTN_MASK_ALLOW: f32 = 0.0;
16pub const ATTN_MASK_BLOCK: f32 = -10000.0;
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub enum SegmentType {
22 System,
24 User,
26 Padding,
28}
29
30#[derive(Debug, Clone, PartialEq)]
32pub struct AttentionIsolationConfig {
33 pub enabled: bool,
35 pub block_bias: f32,
37}
38
39impl Default for AttentionIsolationConfig {
40 fn default() -> Self {
41 Self {
42 enabled: true,
43 block_bias: ATTN_MASK_BLOCK,
44 }
45 }
46}
47
48pub fn build_segment_isolated_attention_mask(
59 segments: &[SegmentType],
60 config: &AttentionIsolationConfig,
61) -> Vec<Vec<f32>> {
62 let len = segments.len();
63 let mut mask = vec![vec![ATTN_MASK_ALLOW; len]; len];
64
65 if !config.enabled {
66 for row in mask.iter_mut() {
68 for (j, seg) in segments.iter().enumerate() {
69 if *seg == SegmentType::Padding {
70 row[j] = config.block_bias;
71 }
72 }
73 }
74 return mask;
75 }
76
77 for (i, &query_seg) in segments.iter().enumerate() {
78 for (j, &key_seg) in segments.iter().enumerate() {
79 if key_seg == SegmentType::Padding {
80 mask[i][j] = config.block_bias;
82 } else if query_seg == SegmentType::User && key_seg == SegmentType::System {
83 mask[i][j] = config.block_bias;
85 } else {
86 mask[i][j] = ATTN_MASK_ALLOW;
88 }
89 }
90 }
91
92 mask
93}
94
95pub fn build_flat_attention_mask(
105 sys_len: usize,
106 user_len: usize,
107 pad_len: usize,
108 config: &AttentionIsolationConfig,
109) -> Vec<f32> {
110 let total_len = sys_len + user_len + pad_len;
111 let mut flat = vec![ATTN_MASK_ALLOW; total_len * total_len];
112
113 let block_val = if config.enabled {
114 config.block_bias
115 } else {
116 ATTN_MASK_ALLOW
117 };
118
119 for i in 0..total_len {
120 let is_query_user = i >= sys_len && i < sys_len + user_len;
121
122 for j in 0..total_len {
123 let idx = i * total_len + j;
124 let is_key_system = j < sys_len;
125 let is_key_pad = j >= sys_len + user_len;
126
127 if is_key_pad {
128 flat[idx] = config.block_bias;
129 } else if config.enabled && is_query_user && is_key_system {
130 flat[idx] = block_val;
132 } else {
133 flat[idx] = ATTN_MASK_ALLOW;
134 }
135 }
136 }
137
138 flat
139}
140
141#[cfg(test)]
142mod tests {
143 use super::*;
144
145 #[test]
146 fn test_segment_isolated_attention_mask_behavior() {
147 let config = AttentionIsolationConfig::default();
148 let segments = vec![
149 SegmentType::System, SegmentType::System, SegmentType::User, SegmentType::User, SegmentType::Padding, ];
155
156 let mask = build_segment_isolated_attention_mask(&segments, &config);
157
158 assert_eq!(mask[0][1], ATTN_MASK_ALLOW);
160 assert_eq!(mask[0][2], ATTN_MASK_ALLOW);
162 assert_eq!(mask[2][3], ATTN_MASK_ALLOW);
164
165 assert_eq!(mask[2][0], ATTN_MASK_BLOCK);
167 assert_eq!(mask[2][1], ATTN_MASK_BLOCK);
168 assert_eq!(mask[3][0], ATTN_MASK_BLOCK);
169 assert_eq!(mask[3][1], ATTN_MASK_BLOCK);
170
171 assert_eq!(mask[0][4], ATTN_MASK_BLOCK);
173 assert_eq!(mask[2][4], ATTN_MASK_BLOCK);
174 }
175
176 #[test]
177 fn test_flat_attention_mask_parity() {
178 let config = AttentionIsolationConfig::default();
179 let sys_len = 2;
180 let user_len = 2;
181 let pad_len = 1;
182 let total = sys_len + user_len + pad_len;
183
184 let flat = build_flat_attention_mask(sys_len, user_len, pad_len, &config);
185 assert_eq!(flat.len(), total * total);
186
187 assert_eq!(flat[2 * total], ATTN_MASK_BLOCK);
189 assert_eq!(flat[2], ATTN_MASK_ALLOW);
191 assert_eq!(flat[4], ATTN_MASK_BLOCK);
193 }
194}