use crate::errors::NoosResult;
use crate::inference::model::LocalModel;
use crate::types::intervention::{DeltaModulation, ForwardResult, InterventionDepth};
pub trait CognitiveModel: LocalModel {
fn intervention_depth(&self) -> InterventionDepth;
fn forward_cognitive(
&mut self,
tokens: &[u32],
position: usize,
delta_modulation: &DeltaModulation,
) -> NoosResult<ForwardResult>;
fn num_layers(&self) -> usize;
}
#[cfg(test)]
pub(crate) mod tests {
use super::*;
use crate::inference::model::tests::MockModel;
pub(crate) struct MockCognitiveModel {
inner: MockModel,
layers: usize,
depth: InterventionDepth,
}
impl MockCognitiveModel {
pub fn new(vocab_size: usize, layers: usize) -> Self {
Self {
inner: MockModel::new(vocab_size),
layers,
depth: InterventionDepth::ActivationAccess,
}
}
}
impl LocalModel for MockCognitiveModel {
fn forward(&mut self, tokens: &[u32], position: usize) -> NoosResult<Vec<f32>> {
self.inner.forward(tokens, position)
}
fn vocab_size(&self) -> usize {
self.inner.vocab_size()
}
fn reset_cache(&mut self) {
self.inner.reset_cache();
}
}
impl CognitiveModel for MockCognitiveModel {
fn intervention_depth(&self) -> InterventionDepth {
self.depth
}
fn forward_cognitive(
&mut self,
tokens: &[u32],
position: usize,
delta_modulation: &DeltaModulation,
) -> NoosResult<ForwardResult> {
let logits = self.inner.forward(tokens, position)?;
let modulated_layers: Vec<usize> = (0..self.layers)
.filter(|&l| delta_modulation.target.contains(l))
.collect();
let modulation_applied =
!modulated_layers.is_empty() && delta_modulation.gain_factor != 1.0;
Ok(ForwardResult {
logits,
modulation_applied,
modulated_layers,
applied_gain_factor: delta_modulation.gain_factor,
gate_delta_gain: None,
gate_alpha: None,
hs_stats: None,
})
}
fn num_layers(&self) -> usize {
self.layers
}
}
#[test]
fn mock_cognitive_model_reports_depth() {
let model = MockCognitiveModel::new(100, 64);
assert_eq!(model.intervention_depth(), InterventionDepth::ActivationAccess);
}
#[test]
fn mock_cognitive_model_applies_modulation() {
let mut model = MockCognitiveModel::new(100, 64);
let dm = DeltaModulation {
gain_factor: 1.2,
..DeltaModulation::default()
};
let result = model.forward_cognitive(&[1], 0, &dm).unwrap();
assert!(result.modulation_applied);
assert!(!result.modulated_layers.is_empty());
assert_eq!(result.applied_gain_factor, 1.2);
}
#[test]
fn mock_cognitive_model_no_modulation_at_unity() {
let mut model = MockCognitiveModel::new(100, 64);
let dm = DeltaModulation::default(); let result = model.forward_cognitive(&[1], 0, &dm).unwrap();
assert!(
!result.modulation_applied,
"Unity gain should not count as modulation"
);
}
#[test]
fn forward_result_tracks_correct_layers() {
let mut model = MockCognitiveModel::new(100, 64);
let dm = DeltaModulation {
gain_factor: 1.2,
target: crate::types::intervention::LayerTarget {
start_layer: 25,
end_layer: 38,
total_layers: 64,
},
..DeltaModulation::default()
};
let result = model.forward_cognitive(&[1], 0, &dm).unwrap();
assert_eq!(result.modulated_layers.len(), 14); assert_eq!(*result.modulated_layers.first().unwrap(), 25);
assert_eq!(*result.modulated_layers.last().unwrap(), 38);
}
#[test]
fn cognitive_model_still_works_as_local_model() {
let mut model = MockCognitiveModel::new(100, 64);
let logits = model.forward(&[1, 2, 3], 0).unwrap();
assert_eq!(logits.len(), 100);
}
}