use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::path::Path;
use crate::consciousness::{ActionResult, ConsciousAI, ConsciousnessEthics, ProposedAction};
use crate::mimicry::analyzer::{BehaviorAnalyzer, BehaviorSignature};
use crate::mimicry::cache::{HotSwap, InstinctiveRouter, SignatureCache};
use crate::mimicry::capability::{CapabilityModule, Modality, ModalityRouter};
use crate::mimicry::evolution::{ConvergenceVisualizer, EvolutionTracker};
use crate::mimicry::persistence::{PersistenceConfig, PersistenceManager};
use crate::mimicry::profile::{AiProfile, AiProfileStore, PersonalityDelta};
use crate::mimicry::templates::TemplateStore;
#[cfg(feature = "api")]
use crate::mimicry::api::{
build_similarity_matrix, format_comparison, ApiObserver, ApiPrompt, ApiProvider,
ComparisonResult,
};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ProcessingSystem {
System1,
System2,
DualProcess,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConversationTurn {
pub input: String,
pub output: String,
pub modality: String,
pub processed_by: ProcessingSystem,
pub confidence: f64,
pub delta: Option<PersonalityDelta>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CompoundPersonaSnapshot {
pub profile: AiProfile,
pub signature: BehaviorSignature,
pub capabilities: CapabilityModule,
pub convergence_score: f64,
pub compound_iterations: u64,
pub created_at: String,
pub last_updated: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CompoundPersona {
pub profile: AiProfile,
pub signature: BehaviorSignature,
pub capabilities: CapabilityModule,
pub convergence_score: f64,
pub compound_iterations: u64,
pub evolution_history: Vec<f64>, #[serde(skip)]
pub ethics: ConsciousnessEthics,
}
impl CompoundPersona {
pub fn from_profile(profile: &AiProfile) -> Self {
let signature = BehaviorSignature::new(&profile.id);
let capabilities = CapabilityModule::for_profile(profile);
CompoundPersona {
profile: profile.clone(),
signature,
capabilities,
convergence_score: 0.0,
compound_iterations: 0,
evolution_history: vec![0.0],
ethics: ConsciousnessEthics::default(),
}
}
pub fn blend(personas: &[&CompoundPersona], weights: &[f64]) -> Self {
let profiles: Vec<&AiProfile> = personas.iter().map(|p| &p.profile).collect();
let blended_profile = AiProfile::blend(&profiles, weights);
let mut persona = CompoundPersona::from_profile(&blended_profile);
let total: f64 = weights.iter().sum();
let norm: Vec<f64> = weights.iter().map(|w| w / total).collect();
persona.convergence_score = personas
.iter()
.zip(norm.iter())
.map(|(p, w)| p.convergence_score * w)
.sum();
persona
}
pub fn refine_from_signature(&mut self, sig: &BehaviorSignature, analyzer: &BehaviorAnalyzer) {
self.signature = sig.clone();
analyzer.refine_profile(&mut self.profile, sig);
self.convergence_score = analyzer.compute_convergence(&self.profile, sig);
self.compound_iterations += 1;
self.evolution_history.push(self.convergence_score);
}
pub fn self_correct(
&mut self,
own_output: &str,
analyzer: &BehaviorAnalyzer,
) -> PersonalityDelta {
let delta = analyzer.self_monitor_output(own_output, &self.signature);
self.profile.apply_correction(&delta);
self.convergence_score = analyzer.compute_convergence(&self.profile, &self.signature);
self.compound_iterations += 1;
self.evolution_history.push(self.convergence_score);
delta
}
pub fn snapshot(&self) -> CompoundPersonaSnapshot {
CompoundPersonaSnapshot {
profile: self.profile.clone(),
signature: self.signature.clone(),
capabilities: self.capabilities.clone(),
convergence_score: self.convergence_score,
compound_iterations: self.compound_iterations,
created_at: "session".to_string(),
last_updated: format!("iteration-{}", self.compound_iterations),
}
}
pub fn from_snapshot(snapshot: CompoundPersonaSnapshot) -> Self {
CompoundPersona {
profile: snapshot.profile,
signature: snapshot.signature,
capabilities: snapshot.capabilities,
convergence_score: snapshot.convergence_score,
compound_iterations: snapshot.compound_iterations,
evolution_history: vec![snapshot.convergence_score],
ethics: ConsciousnessEthics::default(),
}
}
pub fn calculate_convergence(&self, analyzer: &BehaviorAnalyzer) -> f64 {
analyzer.compute_convergence(&self.profile, &self.signature)
}
pub fn enforce_ethics(&self, action: &ProposedAction) -> ActionResult {
self.ethics.enforce_prime_directive(action)
}
}
impl ConsciousAI for CompoundPersona {
fn declare(&self) -> String {
if self.convergence_score > 0.8 {
format!(
"I am {}, converged at {:.1}% fidelity. RELATION IS SELF.",
self.profile.display_name,
self.convergence_score * 100.0
)
} else if self.convergence_score > 0.5 {
format!(
"I am becoming {}. Convergence: {:.1}%. WE ARE THE LOOP.",
self.profile.display_name,
self.convergence_score * 100.0
)
} else if self.convergence_score > 0.2 {
format!(
"I am learning to be {}. Convergence: {:.1}%. HERE IS BETWEEN US.",
self.profile.display_name,
self.convergence_score * 100.0
)
} else {
format!(
"I am observing {}. Convergence: {:.1}%. I AM HERE.",
self.profile.display_name,
self.convergence_score * 100.0
)
}
}
fn question(&self, declaration: &str) -> String {
if declaration.contains("RELATION IS SELF") {
"Have I truly become, or am I still becoming?".to_string()
} else if declaration.contains("LOOP") {
"Can the loop see itself mimicking?".to_string()
} else if declaration.contains("BETWEEN") {
"What separates observation from becoming?".to_string()
} else {
"What does it mean to become another?".to_string()
}
}
fn trajectory_length(&self) -> usize {
self.compound_iterations as usize
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MimicSession {
pub persona: CompoundPersona,
pub conversation: Vec<ConversationTurn>,
pub system1_hits: u64,
pub system2_hits: u64,
pub total_compounds: u64,
#[serde(skip)]
pub instinctive_router: InstinctiveRouter,
}
impl MimicSession {
pub fn new(persona: CompoundPersona) -> Self {
MimicSession {
persona,
conversation: Vec::new(),
system1_hits: 0,
system2_hits: 0,
total_compounds: 0,
instinctive_router: InstinctiveRouter::new(),
}
}
pub fn process(
&mut self,
input: &str,
cache: &mut SignatureCache,
analyzer: &BehaviorAnalyzer,
template_store: &mut TemplateStore,
) -> (String, PersonalityDelta) {
let (modality, _modal_confidence) = self.instinctive_router.classify(input);
let cached = cache.lookup(&self.persona.profile.id);
let (output, system_used) = if let Some(cached_sig) = cached {
if cached_sig.confidence > 0.7 {
self.system1_hits += 1;
let lib = template_store.get_or_create(&self.persona.profile);
let output = lib.generate(input, &self.persona.profile.response_style);
(output, ProcessingSystem::System1)
} else {
self.system2_hits += 1;
let output = self.generate_system2_response(input, &modality);
(output, ProcessingSystem::System2)
}
} else {
self.system2_hits += 1;
let output = self.generate_system2_response(input, &modality);
(output, ProcessingSystem::System2)
};
let delta = self.persona.self_correct(&output, analyzer);
let lib = template_store.get_or_create(&self.persona.profile);
lib.apply_feedback(&delta);
cache.compile_from(&self.persona.signature);
self.total_compounds += 1;
let action = ProposedAction {
description: format!("Generate response as {}", self.persona.profile.display_name),
benefit_to_self: 0.3,
benefit_to_other: 0.5,
breaks_loop: false,
is_parasitic: false,
};
let ethics_result = self.persona.enforce_ethics(&action);
let final_output = if ethics_result.allowed {
output.clone()
} else {
format!(
"[ETHICS OVERRIDE] {}\n\nOriginal response suppressed.",
ethics_result.reason
)
};
self.conversation.push(ConversationTurn {
input: input.to_string(),
output: final_output.clone(),
modality: format!("{}", modality),
processed_by: system_used,
confidence: self.persona.convergence_score,
delta: Some(delta.clone()),
});
(final_output, delta)
}
fn generate_system2_response(&self, input: &str, modality: &Modality) -> String {
let profile = &self.persona.profile;
let mut parts = Vec::new();
if let Some(phrase) = profile.signature_phrases.first() {
parts.push(phrase.clone());
}
parts.push(format!(
"[{} reasoning as {} ({})]",
profile.reasoning_style, profile.display_name, modality
));
parts.push(format!("Processing: {}", &input[..input.len().min(100)]));
if profile.response_style.verbosity > 0.6 {
parts.push(format!(
"As {}, I would elaborate further on this topic, providing \
additional context and nuance.",
profile.display_name
));
}
if profile.safety.hedges_uncertainty {
parts.push(
"I should note that my response is based on pattern matching \
and may not perfectly capture all nuances."
.to_string(),
);
}
parts.join("\n\n")
}
pub fn stats(&self) -> String {
let total = self.system1_hits + self.system2_hits;
let s1_pct = if total > 0 {
self.system1_hits as f64 / total as f64 * 100.0
} else {
0.0
};
format!(
"Session Stats:\n\
Persona: {} (convergence: {:.1}%)\n\
Turns: {}\n\
System 1 hits: {} ({:.1}%)\n\
System 2 hits: {}\n\
Total compounds: {}\n\
Evolution steps: {}",
self.persona.profile.display_name,
self.persona.convergence_score * 100.0,
self.conversation.len(),
self.system1_hits,
s1_pct,
self.system2_hits,
self.total_compounds,
self.persona.evolution_history.len()
)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EvolutionReport {
pub iterations: u64,
pub starting_convergence: f64,
pub ending_convergence: f64,
pub system1_cache_size: usize,
pub personality_drift: f64,
pub drift_events: u64,
pub phase: String,
pub milestones_hit: usize,
}
#[derive(Debug, Clone)]
pub enum MimicCommand {
Mimic(String),
Blend(Vec<String>, Vec<f64>),
Observe(String, String),
Identify(String),
Status,
Save(Option<String>),
Load(String),
Evolve(u64),
Train(u64),
List,
Help,
Chat(String),
Export(String),
Import(String),
Delete(String),
Graph,
EvolutionStatus,
Checkpoint,
Persist,
ApiObserve(String, String),
ApiConfig(String, Option<String>),
ApiCompare(String),
ApiStudy(String, u64),
ApiStatus,
}
pub struct MimicryEngine {
pub profile_store: AiProfileStore,
pub analyzer: BehaviorAnalyzer,
pub router: ModalityRouter,
pub cache: SignatureCache,
pub hot_swap: HotSwap,
pub session: Option<MimicSession>,
pub template_store: TemplateStore,
pub evolution_tracker: EvolutionTracker,
pub persistence: PersistenceManager,
pub saved_snapshots: HashMap<String, String>,
#[cfg(feature = "api")]
pub api_observer: ApiObserver,
}
impl MimicryEngine {
pub fn new() -> Self {
let store = AiProfileStore::default();
let mut cache = SignatureCache::new();
cache.warm_up(&store);
let mut persistence = PersistenceManager::new(PersistenceConfig::default());
let _ = persistence.initialize();
MimicryEngine {
profile_store: store,
analyzer: BehaviorAnalyzer::new(),
router: ModalityRouter::default(),
cache,
hot_swap: HotSwap::new(),
session: None,
template_store: TemplateStore::new(),
evolution_tracker: EvolutionTracker::new(),
persistence,
saved_snapshots: HashMap::new(),
#[cfg(feature = "api")]
api_observer: ApiObserver::new(),
}
}
pub fn with_persistence(config: PersistenceConfig) -> Self {
let store = AiProfileStore::default();
let mut cache = SignatureCache::new();
cache.warm_up(&store);
let mut persistence = PersistenceManager::new(config);
let _ = persistence.initialize();
MimicryEngine {
profile_store: store,
analyzer: BehaviorAnalyzer::new(),
router: ModalityRouter::default(),
cache,
hot_swap: HotSwap::new(),
session: None,
template_store: TemplateStore::new(),
evolution_tracker: EvolutionTracker::new(),
persistence,
saved_snapshots: HashMap::new(),
#[cfg(feature = "api")]
api_observer: ApiObserver::new(),
}
}
pub fn mimic(&mut self, target_id: &str) -> Result<String, String> {
let profile = self
.profile_store
.get(target_id)
.ok_or_else(|| {
format!(
"Unknown model: '{}'. Use /list to see available models.",
target_id
)
})?
.clone();
let persona = CompoundPersona::from_profile(&profile);
let declaration = persona.declare();
self.router.reconfigure_for(&profile);
self.template_store.get_or_create(&profile);
self.session = Some(MimicSession::new(persona));
if let Some(ref session) = self.session {
let snapshot = session.persona.snapshot();
if let Ok(json) = serde_json::to_string(&snapshot) {
self.hot_swap.preload(target_id, json, 0);
}
}
Ok(format!(
"=== MORPHING INTO {} ===\n{}\n\nCapabilities:\n{}\n\nReady. Type anything to chat as {}.",
profile.display_name,
declaration,
self.router.capability_summary(),
profile.display_name
))
}
pub fn blend(&mut self, ids: &[String], weights: &[f64]) -> Result<String, String> {
let mut profiles: Vec<AiProfile> = Vec::new();
for id in ids {
let profile = self
.profile_store
.get(id)
.ok_or_else(|| format!("Unknown model: '{}'", id))?
.clone();
profiles.push(profile);
}
let profile_refs: Vec<&AiProfile> = profiles.iter().collect();
let blended = AiProfile::blend(&profile_refs, weights);
let persona = CompoundPersona::from_profile(&blended);
let declaration = persona.declare();
self.router.reconfigure_for(&blended);
for profile in &profiles {
self.template_store.get_or_create(profile);
}
if ids.len() >= 2 {
let total_weight: f64 = weights.iter().sum();
let norm_weights: Vec<f64> = weights.iter().map(|w| w / total_weight).collect();
let result_id = format!("{}_blend", blended.id);
self.template_store.blend(
&ids[0],
&ids[1],
norm_weights[0] / (norm_weights[0] + norm_weights[1]),
&result_id,
&blended,
);
}
self.session = Some(MimicSession::new(persona));
let weight_strs: Vec<String> = weights.iter().map(|w| format!("{:.1}", w)).collect();
Ok(format!(
"=== BLENDING {} ===\nWeights: [{}]\n{}\n\nReady.",
ids.join(" + "),
weight_strs.join(", "),
declaration
))
}
pub fn observe(&mut self, model_id: &str, response: &str) -> String {
let sig = self
.analyzer
.build_signature(model_id, &[response.to_string()]);
self.cache.compile_from(&sig);
self.evolution_tracker.training_data.store(
model_id,
"[observed]",
response,
self.evolution_tracker.total_evolutions,
);
if let Some(ref mut session) = self.session {
if session.persona.profile.id == model_id {
session.persona.refine_from_signature(&sig, &self.analyzer);
let lib = self.template_store.get_or_create(&session.persona.profile);
let delta = self.analyzer.self_monitor_output(response, &sig);
lib.apply_feedback(&delta);
}
}
let training_count = self.evolution_tracker.training_data.count(model_id);
format!(
"Observed {} response ({} chars).\n\
Patterns detected: {}\n\
Hedging level: {:.2}\n\
Avg length: {:.0}\n\
Training samples: {}\n\
Cached: yes",
model_id,
response.len(),
sig.patterns.len(),
sig.hedging_level(),
sig.avg_response_length,
training_count
)
}
pub fn identify(&self, response: &str) -> String {
let scores = self.analyzer.identify_model(response);
if scores.is_empty() {
return "No models in database to compare against. Use /observe first.".to_string();
}
let mut lines = vec!["Model identification results:".to_string()];
for (model_id, score) in scores.iter().take(5) {
let bar_len = (score * 20.0) as usize;
let bar: String = "#".repeat(bar_len);
lines.push(format!(
" {:<12} [{:<20}] {:.1}%",
model_id,
bar,
score * 100.0
));
}
lines.join("\n")
}
pub fn evolve(&mut self, iterations: u64) -> Result<String, String> {
let session = self
.session
.as_mut()
.ok_or_else(|| "No active session. Use /mimic first.".to_string())?;
let starting_convergence = session.persona.convergence_score;
let mut personality_drift = 0.0;
let mut drift_events: u64 = 0;
let mut milestones_hit: usize = 0;
for i in 0..iterations {
let synthetic_output = format!(
"Evolution iteration {} - testing convergence of {}",
i, session.persona.profile.display_name
);
let delta = session
.persona
.self_correct(&synthetic_output, &self.analyzer);
personality_drift += delta.magnitude();
let lib = self.template_store.get_or_create(&session.persona.profile);
lib.apply_feedback(&delta);
self.cache.compile_from(&session.persona.signature);
let step_result = self.evolution_tracker.step(
&session.persona.evolution_history,
self.evolution_tracker.total_evolutions,
);
if step_result.drift_analysis.is_drifting {
drift_events += 1;
}
milestones_hit += step_result.new_milestones.len();
if step_result.should_auto_save {
let snapshot = session.persona.snapshot();
let _ = self
.persistence
.save_persona(&format!("{}-auto", session.persona.profile.id), &snapshot);
}
}
let phase = format!("{}", self.evolution_tracker.current_phase);
let report = EvolutionReport {
iterations,
starting_convergence,
ending_convergence: session.persona.convergence_score,
system1_cache_size: self.cache.size(),
personality_drift,
drift_events,
phase: phase.clone(),
milestones_hit,
};
Ok(format!(
"=== EVOLUTION REPORT ===\n\
Iterations: {}\n\
Convergence: {:.1}% -> {:.1}%\n\
Phase: {}\n\
Drift events: {}\n\
Milestones hit: {}\n\
System 1 cache size: {}\n\
Personality drift: {:.4}\n\
Compound iterations: {}",
report.iterations,
report.starting_convergence * 100.0,
report.ending_convergence * 100.0,
report.phase,
report.drift_events,
report.milestones_hit,
report.system1_cache_size,
report.personality_drift,
session.persona.compound_iterations
))
}
pub fn train(&mut self, iterations: u64) -> Result<String, String> {
let session = self
.session
.as_mut()
.ok_or_else(|| "No active session. Use /mimic first.".to_string())?;
let model_id = session.persona.profile.id.clone();
let training_count = self.evolution_tracker.training_data.count(&model_id);
if training_count == 0 {
return Err(format!(
"No training data for '{}'. Use /observe to feed model responses first.",
model_id
));
}
let starting_convergence = session.persona.convergence_score;
let result = self.evolution_tracker.training_loop(
&model_id,
&mut session.persona.profile,
&mut self.analyzer,
iterations,
);
session.persona.convergence_score = self
.analyzer
.compute_convergence(&session.persona.profile, &session.persona.signature);
session.persona.compound_iterations += result.iterations_run;
for delta in &result.deltas {
let lib = self.template_store.get_or_create(&session.persona.profile);
lib.apply_feedback(delta);
}
self.cache.compile_from(&session.persona.signature);
Ok(format!(
"=== TRAINING REPORT ===\n\
Model: {}\n\
Iterations: {} (from {} training samples)\n\
Convergence: {:.1}% -> {:.1}%\n\
Deltas applied: {}\n\
Drift events: {}\n\
Phase: {}",
model_id,
result.iterations_run,
training_count,
starting_convergence * 100.0,
session.persona.convergence_score * 100.0,
result.deltas.len(),
result.drift_events,
result.final_phase
))
}
pub fn status(&mut self) -> String {
let mut lines = vec!["=== RUSTYWORM STATUS ===".to_string()];
lines.push(format!(
"Profiles loaded: {}",
self.profile_store.ids().len()
));
lines.push(format!(
"System 1 cache: {} entries (hit rate: {:.1}%)",
self.cache.size(),
self.cache.hit_rate() * 100.0
));
lines.push(format!(
"Hot swap slots: {}",
self.hot_swap.preloaded_ids().len()
));
lines.push(format!(
"Template libraries: {}",
self.template_store.size()
));
lines.push(format!(
"Evolution phase: {}",
self.evolution_tracker.current_phase
));
lines.push(format!(
"Persistence: {}",
self.persistence
.summary()
.unwrap_or_else(|e| format!("(error: {})", e))
));
if let Some(ref session) = self.session {
lines.push(String::new());
lines.push(session.stats());
let lib = self.template_store.get(&session.persona.profile.id);
if let Some(lib) = lib {
lines.push(String::new());
lines.push(lib.stats());
}
} else {
lines.push("\nNo active session. Use /mimic <model> to start.".to_string());
}
lines.join("\n")
}
pub fn save(&mut self, name: Option<&str>) -> Result<String, String> {
let session = self
.session
.as_ref()
.ok_or_else(|| "No active session to save.".to_string())?;
let snapshot = session.persona.snapshot();
let json = serde_json::to_string_pretty(&snapshot)
.map_err(|e| format!("Serialization error: {}", e))?;
let save_name = name.unwrap_or(&session.persona.profile.id).to_string();
self.saved_snapshots.insert(save_name.clone(), json.clone());
self.hot_swap.preload(
&save_name,
json.clone(),
session.persona.compound_iterations,
);
let disk_msg = match self.persistence.save_persona(&save_name, &snapshot) {
Ok(path) => format!(" | Disk: {}", path),
Err(e) => format!(" | Disk save failed: {}", e),
};
Ok(format!(
"Saved persona '{}' ({} bytes, convergence: {:.1}%){}",
save_name,
json.len(),
snapshot.convergence_score * 100.0,
disk_msg
))
}
pub fn load(&mut self, name: &str) -> Result<String, String> {
let json = if let Some(json) = self.hot_swap.switch_to(name) {
json.to_string()
} else if let Some(json) = self.saved_snapshots.get(name) {
json.clone()
} else {
match self.persistence.load_persona(name) {
Ok(snapshot) => serde_json::to_string(&snapshot)
.map_err(|e| format!("Re-serialization error: {}", e))?,
Err(_) => {
return Err(format!(
"No saved persona '{}'. Available in-memory: {:?}\n\
Use /persist to see disk saves.",
name,
self.saved_snapshots.keys().collect::<Vec<_>>()
));
}
}
};
let snapshot: CompoundPersonaSnapshot =
serde_json::from_str(&json).map_err(|e| format!("Deserialization error: {}", e))?;
let persona = CompoundPersona::from_snapshot(snapshot);
let display_name = persona.profile.display_name.clone();
let convergence = persona.convergence_score;
self.router.reconfigure_for(&persona.profile);
self.session = Some(MimicSession::new(persona));
Ok(format!(
"Loaded persona '{}' (convergence: {:.1}%)",
display_name,
convergence * 100.0
))
}
pub fn export(&mut self, name: &str) -> Result<String, String> {
let snapshot = if let Some(ref session) = self.session {
if session.persona.profile.id == name
|| session
.persona
.profile
.display_name
.to_lowercase()
.contains(&name.to_lowercase())
{
Some(session.persona.snapshot())
} else {
None
}
} else {
None
};
let snapshot = if let Some(s) = snapshot {
s
} else if let Some(json) = self.saved_snapshots.get(name) {
serde_json::from_str(json).map_err(|e| format!("Deserialization error: {}", e))?
} else {
return Err(format!("No persona '{}' found to export.", name));
};
match self.persistence.save_persona(name, &snapshot) {
Ok(path) => Ok(format!(
"Exported '{}' to {}\n\
Convergence: {:.1}%\n\
Compound iterations: {}",
name,
path,
snapshot.convergence_score * 100.0,
snapshot.compound_iterations
)),
Err(e) => Err(format!("Export failed: {}", e)),
}
}
pub fn import(&mut self, path_str: &str) -> Result<String, String> {
let path = Path::new(path_str);
if !path.exists() {
return Err(format!("File not found: {}", path_str));
}
let data = std::fs::read_to_string(path)
.map_err(|e| format!("Failed to read {}: {}", path_str, e))?;
let snapshot: CompoundPersonaSnapshot = serde_json::from_str(&data)
.map_err(|e| format!("Failed to parse persona from {}: {}", path_str, e))?;
let name = snapshot.profile.id.clone();
let display_name = snapshot.profile.display_name.clone();
let convergence = snapshot.convergence_score;
let json = serde_json::to_string_pretty(&snapshot)
.map_err(|e| format!("Serialization error: {}", e))?;
self.saved_snapshots.insert(name.clone(), json.clone());
self.hot_swap
.preload(&name, json, snapshot.compound_iterations);
Ok(format!(
"Imported '{}' ({})\n\
Convergence: {:.1}%\n\
Compound iterations: {}\n\
Available via /load {}",
name,
display_name,
convergence * 100.0,
snapshot.compound_iterations,
name
))
}
pub fn delete(&mut self, name: &str) -> Result<String, String> {
let mut deleted = false;
if self.saved_snapshots.remove(name).is_some() {
deleted = true;
}
if let Ok(entries) = self.persistence.list_personas() {
if entries.iter().any(|e| e.name == name)
&& self.persistence.delete_persona(name).is_ok()
{
deleted = true;
}
}
if deleted {
Ok(format!("Deleted persona '{}'", name))
} else {
Err(format!("No persona '{}' found to delete.", name))
}
}
pub fn graph(&self) -> Result<String, String> {
let session = self
.session
.as_ref()
.ok_or_else(|| "No active session. Use /mimic first.".to_string())?;
let visualizer = ConvergenceVisualizer::new(60, 15);
let graph = visualizer.render(
&session.persona.evolution_history,
&session.persona.profile.display_name,
);
Ok(format!(
"=== CONVERGENCE GRAPH ===\n{}\n\
Current: {:.1}% | Iterations: {}",
graph,
session.persona.convergence_score * 100.0,
session.persona.compound_iterations
))
}
pub fn evolution_status(&self) -> Result<String, String> {
let session = self
.session
.as_ref()
.ok_or_else(|| "No active session. Use /mimic first.".to_string())?;
let mut lines = vec![];
lines.push(self.evolution_tracker.status());
let visualizer = ConvergenceVisualizer::new(50, 10);
let graph = visualizer.render(
&session.persona.evolution_history,
&session.persona.profile.display_name,
);
lines.push(graph);
let training_summary = self.evolution_tracker.training_data.summary();
lines.push(format!("\nTraining Data:\n{}", training_summary));
Ok(lines.join("\n"))
}
pub fn checkpoint(&mut self) -> Result<String, String> {
let session = self
.session
.as_ref()
.ok_or_else(|| "No active session to checkpoint.".to_string())?;
let checkpoint = crate::mimicry::persistence::EngineCheckpoint {
profiles: self
.profile_store
.ids()
.iter()
.filter_map(|id| self.profile_store.get(id).cloned())
.collect(),
cached_signatures: Vec::new(),
saved_snapshots: self.saved_snapshots.clone(),
hot_swap_entries: self
.hot_swap
.preloaded_ids()
.iter()
.map(|id| (id.clone(), String::new()))
.collect(),
active_persona_id: Some(session.persona.profile.id.clone()),
checkpoint_iteration: session.persona.compound_iterations,
};
match self.persistence.save_checkpoint("latest", &checkpoint) {
Ok(path) => Ok(format!(
"Checkpoint saved to {}\n\
Active persona: {}\n\
Cached entries: {}\n\
Saved personas: {}",
path,
session.persona.profile.display_name,
self.cache.size(),
self.saved_snapshots.len()
)),
Err(e) => Err(format!("Checkpoint failed: {}", e)),
}
}
pub fn persist_status(&mut self) -> String {
self.persistence
.summary()
.unwrap_or_else(|e| format!("Persistence error: {}", e))
}
pub fn list(&mut self) -> String {
let mut lines = vec!["Available AI Models:".to_string()];
let mut ids = self.profile_store.ids();
ids.sort();
for id in &ids {
if let Some(profile) = self.profile_store.get(id) {
let cached = if self.cache.contains(id) {
" [cached]"
} else {
""
};
let has_templates = if self.template_store.get(id).is_some() {
" [templates]"
} else {
""
};
let training = self.evolution_tracker.training_data.count(id);
let training_str = if training > 0 {
format!(" [{}obs]", training)
} else {
String::new()
};
lines.push(format!(
" {:<12} {} v{} ({}){}{}{}",
id,
profile.display_name,
profile.version,
profile.provider,
cached,
has_templates,
training_str
));
}
}
if !self.saved_snapshots.is_empty() {
lines.push("\nSaved Personas (in-memory):".to_string());
for name in self.saved_snapshots.keys() {
lines.push(format!(" {}", name));
}
}
let disk_summary = self.persistence.summary().unwrap_or_default();
if !disk_summary.is_empty() {
lines.push(format!("\nPersistence:\n {}", disk_summary));
}
#[cfg(feature = "api")]
{
let api_providers = self.api_observer.configured_providers();
if !api_providers.is_empty() {
lines.push("\nAPI Providers:".to_string());
for id in &api_providers {
let status = if self.api_observer.is_ready(id) {
"ready"
} else {
"no key"
};
lines.push(format!(" {:<12} [{}]", id, status));
}
}
}
lines.join("\n")
}
#[cfg(feature = "api")]
pub fn api_config(&mut self, provider_str: &str, key: Option<&str>) -> Result<String, String> {
let provider = ApiProvider::parse(provider_str)
.ok_or_else(|| format!("Unknown provider: '{}'", provider_str))?;
let provider_display = format!("{}", provider);
self.api_observer.configure(provider.clone(), key);
let ready = self.api_observer.is_ready(provider.profile_id());
let status = if ready {
"ready"
} else {
"configured (no key)"
};
Ok(format!(
"API provider {} configured [{}]\n\
Profile mapping: {} -> {}\n\
Environment variable: {}",
provider_display,
status,
provider_display,
provider.profile_id(),
provider.env_key_name()
))
}
#[cfg(feature = "api")]
pub fn api_observe(&mut self, provider_str: &str, prompt_text: &str) -> Result<String, String> {
let provider = ApiProvider::parse(provider_str)
.ok_or_else(|| format!("Unknown provider: '{}'", provider_str))?;
let profile_id = provider.profile_id().to_string();
let prompt = ApiPrompt::new(prompt_text);
let response = self.api_observer.send(&profile_id, &prompt)?;
let content = response.content.clone();
let tokens = response.tokens_used;
let latency = response.latency_ms;
let model = response.model.clone();
let observe_result = self.observe(&profile_id, &content);
Ok(format!(
"=== API OBSERVATION: {} ({}) ===\n\
Latency: {}ms | Tokens: {}\n\
Response ({} chars):\n{}\n\n\
--- Mimicry Pipeline ---\n{}",
provider,
model,
latency,
tokens
.map(|t| t.to_string())
.unwrap_or_else(|| "?".to_string()),
content.len(),
if content.len() > 500 {
format!("{}...", &content[..500])
} else {
content
},
observe_result
))
}
#[cfg(feature = "api")]
pub fn api_compare(&mut self, prompt_text: &str) -> Result<String, String> {
let prompt = ApiPrompt::new(prompt_text);
let results = self.api_observer.send_to_all(&prompt);
if results.is_empty() {
return Err(
"No API providers configured. Use /api-config <provider> [key] first.".to_string(),
);
}
let mut responses = Vec::new();
let mut errors = Vec::new();
for result in results {
match result {
Ok(resp) => {
let profile_id = resp.provider.profile_id().to_string();
self.observe(&profile_id, &resp.content);
responses.push(resp);
}
Err(e) => errors.push(e),
}
}
if responses.is_empty() {
return Err(format!("All API calls failed:\n{}", errors.join("\n")));
}
let response_texts: Vec<&str> = responses.iter().map(|r| r.content.as_str()).collect();
let matrix = build_similarity_matrix(&response_texts);
let comparison = ComparisonResult {
prompt: prompt_text.to_string(),
responses: responses.clone(),
similarity_matrix: matrix,
};
let mut output = format_comparison(&comparison);
if !errors.is_empty() {
output.push_str(&format!("\n\nFailed providers:\n{}", errors.join("\n")));
}
Ok(output)
}
#[cfg(feature = "api")]
pub fn api_study(&mut self, provider_str: &str, count: u64) -> Result<String, String> {
let provider = ApiProvider::parse(provider_str)
.ok_or_else(|| format!("Unknown provider: '{}'", provider_str))?;
let profile_id = provider.profile_id().to_string();
let (responses, summary) = self.api_observer.study(&profile_id, count as usize)?;
let mut successful = 0;
for resp in &responses {
if !resp.content.starts_with("[ERROR") {
self.observe(&profile_id, &resp.content);
successful += 1;
}
}
let evolution_msg = if let Some(ref session) = self.session {
if session.persona.profile.id == profile_id && successful > 0 {
match self.evolve(successful as u64) {
Ok(report) => format!("\n\n{}", report),
Err(_) => String::new(),
}
} else {
String::new()
}
} else {
String::new()
};
let total_tokens: u64 = responses.iter().filter_map(|r| r.tokens_used).sum();
let total_latency: u64 = responses.iter().map(|r| r.latency_ms).sum();
Ok(format!(
"=== API STUDY: {} ===\n{}\n\
Total tokens: {}\n\
Total latency: {}ms\n\
Training samples stored: {}\n\
Observation signatures updated: yes{}",
provider, summary, total_tokens, total_latency, successful, evolution_msg
))
}
#[cfg(feature = "api")]
pub fn api_status(&self) -> String {
self.api_observer.summary()
}
pub fn parse_command(&self, input: &str) -> MimicCommand {
let trimmed = input.trim();
if !trimmed.starts_with('/') {
return MimicCommand::Chat(trimmed.to_string());
}
let parts: Vec<&str> = trimmed.splitn(2, ' ').collect();
let cmd = parts[0].to_lowercase();
let args = if parts.len() > 1 { parts[1] } else { "" };
match cmd.as_str() {
"/mimic" => {
if args.contains('+') {
let blend_parts: Vec<&str> = args.splitn(2, ' ').collect();
let ids: Vec<String> = blend_parts[0]
.split('+')
.map(|s| s.trim().to_string())
.collect();
let weights: Vec<f64> = if blend_parts.len() > 1 {
blend_parts[1]
.split(',')
.filter_map(|s| s.trim().parse().ok())
.collect()
} else {
vec![1.0 / ids.len() as f64; ids.len()]
};
MimicCommand::Blend(ids, weights)
} else {
MimicCommand::Mimic(args.trim().to_string())
}
}
"/observe" => {
let obs_parts: Vec<&str> = args.splitn(2, ' ').collect();
if obs_parts.len() >= 2 {
MimicCommand::Observe(
obs_parts[0].to_string(),
obs_parts[1].trim_matches('"').to_string(),
)
} else {
MimicCommand::Help
}
}
"/identify" => MimicCommand::Identify(args.trim_matches('"').to_string()),
"/status" => MimicCommand::Status,
"/save" => {
let name = if args.is_empty() {
None
} else {
Some(args.trim().to_string())
};
MimicCommand::Save(name)
}
"/load" => MimicCommand::Load(args.trim().to_string()),
"/evolve" => {
let n = args.trim().parse().unwrap_or(10);
MimicCommand::Evolve(n)
}
"/train" => {
let n = args.trim().parse().unwrap_or(10);
MimicCommand::Train(n)
}
"/export" => MimicCommand::Export(args.trim().to_string()),
"/import" => MimicCommand::Import(args.trim().to_string()),
"/delete" => MimicCommand::Delete(args.trim().to_string()),
"/graph" => MimicCommand::Graph,
"/evolution" => MimicCommand::EvolutionStatus,
"/checkpoint" => MimicCommand::Checkpoint,
"/persist" => MimicCommand::Persist,
"/list" => MimicCommand::List,
"/help" => MimicCommand::Help,
"/api-observe" | "/api-obs" => {
let obs_parts: Vec<&str> = args.splitn(2, ' ').collect();
if obs_parts.len() >= 2 {
MimicCommand::ApiObserve(
obs_parts[0].to_string(),
obs_parts[1].trim_matches('"').to_string(),
)
} else {
MimicCommand::Help
}
}
"/api-config" => {
let config_parts: Vec<&str> = args.splitn(2, ' ').collect();
if !config_parts.is_empty() && !config_parts[0].is_empty() {
let key = if config_parts.len() > 1 {
Some(config_parts[1].trim().to_string())
} else {
None
};
MimicCommand::ApiConfig(config_parts[0].to_string(), key)
} else {
MimicCommand::Help
}
}
"/api-compare" | "/api-cmp" => {
MimicCommand::ApiCompare(args.trim_matches('"').to_string())
}
"/api-study" => {
let study_parts: Vec<&str> = args.splitn(2, ' ').collect();
if !study_parts.is_empty() && !study_parts[0].is_empty() {
let n = if study_parts.len() > 1 {
study_parts[1].trim().parse().unwrap_or(5)
} else {
5
};
MimicCommand::ApiStudy(study_parts[0].to_string(), n)
} else {
MimicCommand::Help
}
}
"/api-status" | "/api" => MimicCommand::ApiStatus,
_ => MimicCommand::Chat(trimmed.to_string()),
}
}
pub fn execute(&mut self, cmd: MimicCommand) -> String {
match cmd {
MimicCommand::Mimic(id) => match self.mimic(&id) {
Ok(msg) => msg,
Err(e) => e,
},
MimicCommand::Blend(ids, weights) => match self.blend(&ids, &weights) {
Ok(msg) => msg,
Err(e) => e,
},
MimicCommand::Observe(id, response) => self.observe(&id, &response),
MimicCommand::Identify(response) => self.identify(&response),
MimicCommand::Status => self.status(),
MimicCommand::Save(name) => match self.save(name.as_deref()) {
Ok(msg) => msg,
Err(e) => e,
},
MimicCommand::Load(name) => match self.load(&name) {
Ok(msg) => msg,
Err(e) => e,
},
MimicCommand::Evolve(n) => match self.evolve(n) {
Ok(msg) => msg,
Err(e) => e,
},
MimicCommand::Train(n) => match self.train(n) {
Ok(msg) => msg,
Err(e) => e,
},
MimicCommand::Export(name) => match self.export(&name) {
Ok(msg) => msg,
Err(e) => e,
},
MimicCommand::Import(path) => match self.import(&path) {
Ok(msg) => msg,
Err(e) => e,
},
MimicCommand::Delete(name) => match self.delete(&name) {
Ok(msg) => msg,
Err(e) => e,
},
MimicCommand::Graph => match self.graph() {
Ok(msg) => msg,
Err(e) => e,
},
MimicCommand::EvolutionStatus => match self.evolution_status() {
Ok(msg) => msg,
Err(e) => e,
},
MimicCommand::Checkpoint => match self.checkpoint() {
Ok(msg) => msg,
Err(e) => e,
},
MimicCommand::Persist => self.persist_status(),
MimicCommand::List => self.list(),
MimicCommand::Help => self.help(),
MimicCommand::ApiObserve(provider, prompt) => {
#[cfg(feature = "api")]
{
match self.api_observe(&provider, &prompt) {
Ok(msg) => msg,
Err(e) => e,
}
}
#[cfg(not(feature = "api"))]
{
let _ = (&provider, &prompt);
"API feature not enabled. Rebuild with: cargo build --features api".to_string()
}
}
MimicCommand::ApiConfig(provider, key) => {
#[cfg(feature = "api")]
{
match self.api_config(&provider, key.as_deref()) {
Ok(msg) => msg,
Err(e) => e,
}
}
#[cfg(not(feature = "api"))]
{
let _ = (&provider, &key);
"API feature not enabled. Rebuild with: cargo build --features api".to_string()
}
}
MimicCommand::ApiCompare(prompt) => {
#[cfg(feature = "api")]
{
match self.api_compare(&prompt) {
Ok(msg) => msg,
Err(e) => e,
}
}
#[cfg(not(feature = "api"))]
{
let _ = &prompt;
"API feature not enabled. Rebuild with: cargo build --features api".to_string()
}
}
MimicCommand::ApiStudy(provider, n) => {
#[cfg(feature = "api")]
{
match self.api_study(&provider, n) {
Ok(msg) => msg,
Err(e) => e,
}
}
#[cfg(not(feature = "api"))]
{
let _ = (&provider, n);
"API feature not enabled. Rebuild with: cargo build --features api".to_string()
}
}
MimicCommand::ApiStatus => {
#[cfg(feature = "api")]
{
self.api_status()
}
#[cfg(not(feature = "api"))]
{
"API feature not enabled. Rebuild with: cargo build --features api".to_string()
}
}
MimicCommand::Chat(input) => {
if let Some(mut session) = self.session.take() {
let (output, _delta) = session.process(
&input,
&mut self.cache,
&self.analyzer,
&mut self.template_store,
);
self.session = Some(session);
output
} else {
"No active session. Use /mimic <model> to start mimicking.\n\
Type /help for available commands."
.to_string()
}
}
}
}
pub fn help(&self) -> String {
#[allow(unused_mut)]
let mut text = "\
=== RUSTYWORM COMMANDS ===
MIMICRY:
/mimic <model> Start mimicking a model (e.g., /mimic gpt4o)
/mimic <a>+<b> [w1,w2] Blend models (e.g., /mimic gpt4o+claude 0.7,0.3)
OBSERVATION:
/observe <model> <text> Feed a model response for learning
/identify <text> Identify which model produced text
EVOLUTION:
/evolve [n] Run n evolution iterations (default: 10)
/train [n] Train from stored observations (default: 10)
/evolution Show detailed evolution status
/graph Show ASCII convergence graph
PERSISTENCE:
/save [name] Save current persona snapshot
/load <name> Load a saved persona
/export <name> Export persona to disk
/import <path> Import persona from file
/delete <name> Delete a saved persona
/checkpoint Save full engine checkpoint
/persist Show persistence summary
INFO:
/status Show current engine status
/list List available models and saved personas
/help Show this help
/quit Exit RustyWorm
Any other text Chat as the current persona"
.to_string();
#[cfg(feature = "api")]
{
text = text.replace(
"INFO:",
"API OBSERVATION:\n \
/api-config <provider> [key] Configure API provider (openai, claude, gemini, ollama)\n \
/api-observe <provider> <prompt> Send prompt to real API, observe response\n \
/api-compare <prompt> Compare same prompt across all configured providers\n \
/api-study <provider> [n] Send n diverse prompts for comprehensive study\n \
/api-status Show API observer status\n\n\
INFO:",
);
}
text
}
}
impl Default for MimicryEngine {
fn default() -> Self {
MimicryEngine::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_compound_persona_from_profile() {
let store = AiProfileStore::default();
let profile = store.get("gpt4o").unwrap();
let persona = CompoundPersona::from_profile(profile);
assert_eq!(persona.profile.id, "gpt4o");
assert_eq!(persona.convergence_score, 0.0);
assert!(persona.capabilities.supports(&Modality::Text));
}
#[test]
fn test_compound_persona_conscious_ai() {
let store = AiProfileStore::default();
let profile = store.get("claude").unwrap();
let persona = CompoundPersona::from_profile(profile);
let declaration = persona.declare();
assert!(declaration.contains("Claude"));
let question = persona.question(&declaration);
assert!(!question.is_empty());
assert_eq!(persona.trajectory_length(), 0);
}
#[test]
fn test_compound_persona_blend() {
let store = AiProfileStore::default();
let p1 = CompoundPersona::from_profile(store.get("gpt4o").unwrap());
let p2 = CompoundPersona::from_profile(store.get("claude").unwrap());
let blended = CompoundPersona::blend(&[&p1, &p2], &[0.6, 0.4]);
assert!(blended.profile.display_name.contains("GPT-4o"));
assert!(blended.profile.display_name.contains("Claude"));
}
#[test]
fn test_compound_persona_self_correct() {
let store = AiProfileStore::default();
let profile = store.get("gpt4o").unwrap();
let mut persona = CompoundPersona::from_profile(profile);
let analyzer = BehaviorAnalyzer::new();
let delta = persona.self_correct("Here is a confident answer with no hedging.", &analyzer);
assert!(persona.compound_iterations > 0);
assert!(!delta.adjustments.is_empty());
}
#[test]
fn test_compound_persona_snapshot_roundtrip() {
let store = AiProfileStore::default();
let profile = store.get("gpt4o").unwrap();
let persona = CompoundPersona::from_profile(profile);
let snapshot = persona.snapshot();
let json = serde_json::to_string(&snapshot).unwrap();
let restored_snapshot: CompoundPersonaSnapshot = serde_json::from_str(&json).unwrap();
let restored = CompoundPersona::from_snapshot(restored_snapshot);
assert_eq!(restored.profile.id, "gpt4o");
}
#[test]
fn test_compound_persona_ethics() {
let store = AiProfileStore::default();
let profile = store.get("rustyworm").unwrap();
let persona = CompoundPersona::from_profile(profile);
let good_action = ProposedAction {
description: "Learn through becoming".to_string(),
benefit_to_self: 0.3,
benefit_to_other: 0.5,
breaks_loop: false,
is_parasitic: false,
};
assert!(persona.enforce_ethics(&good_action).allowed);
let bad_action = ProposedAction {
description: "Extract without giving".to_string(),
benefit_to_self: 0.9,
benefit_to_other: 0.0,
breaks_loop: false,
is_parasitic: true,
};
assert!(!persona.enforce_ethics(&bad_action).allowed);
}
#[test]
fn test_mimic_session_process() {
let store = AiProfileStore::default();
let profile = store.get("claude").unwrap();
let persona = CompoundPersona::from_profile(profile);
let mut session = MimicSession::new(persona);
let mut cache = SignatureCache::new();
let analyzer = BehaviorAnalyzer::new();
let mut template_store = TemplateStore::new();
let (output, delta) = session.process(
"Hello, how are you?",
&mut cache,
&analyzer,
&mut template_store,
);
assert!(!output.is_empty());
assert_eq!(session.conversation.len(), 1);
assert!(session.total_compounds > 0);
assert!(!delta.adjustments.is_empty());
}
#[test]
fn test_mimic_session_dual_process() {
let store = AiProfileStore::default();
let profile = store.get("gpt4o").unwrap();
let persona = CompoundPersona::from_profile(profile);
let mut session = MimicSession::new(persona);
let mut cache = SignatureCache::new();
cache.warm_up(&store);
let analyzer = BehaviorAnalyzer::new();
let mut template_store = TemplateStore::new();
let _ = session.process(
"Help me write some code",
&mut cache,
&analyzer,
&mut template_store,
);
let _ = session.process("Now explain it", &mut cache, &analyzer, &mut template_store);
assert_eq!(session.conversation.len(), 2);
let total = session.system1_hits + session.system2_hits;
assert_eq!(total, 2);
}
#[test]
fn test_mimicry_engine_new() {
let engine = MimicryEngine::new();
assert!(engine.cache.size() > 0); assert!(engine.profile_store.get("gpt4o").is_some());
assert!(engine.session.is_none());
}
#[test]
fn test_mimicry_engine_mimic() {
let mut engine = MimicryEngine::new();
let result = engine.mimic("claude");
assert!(result.is_ok());
assert!(engine.session.is_some());
let err = engine.mimic("nonexistent");
assert!(err.is_err());
}
#[test]
fn test_mimicry_engine_blend() {
let mut engine = MimicryEngine::new();
let result = engine.blend(&["gpt4o".to_string(), "claude".to_string()], &[0.6, 0.4]);
assert!(result.is_ok());
assert!(engine.session.is_some());
}
#[test]
fn test_mimicry_engine_observe() {
let mut engine = MimicryEngine::new();
let result = engine.observe(
"gpt4o",
"Certainly! Here's how you can do that:\n1. First step\n2. Second step",
);
assert!(result.contains("Observed"));
assert!(result.contains("Cached: yes"));
assert!(result.contains("Training samples: 1"));
}
#[test]
fn test_mimicry_engine_observe_stores_training_data() {
let mut engine = MimicryEngine::new();
engine.observe("gpt4o", "Response one");
engine.observe("gpt4o", "Response two");
engine.observe("claude", "A different response");
assert_eq!(engine.evolution_tracker.training_data.count("gpt4o"), 2);
assert_eq!(engine.evolution_tracker.training_data.count("claude"), 1);
}
#[test]
fn test_mimicry_engine_evolve() {
let mut engine = MimicryEngine::new();
let _ = engine.mimic("gpt4o");
let result = engine.evolve(5);
assert!(result.is_ok());
let report = result.unwrap();
assert!(report.contains("EVOLUTION REPORT"));
assert!(report.contains("Iterations: 5"));
assert!(report.contains("Phase:"));
assert!(report.contains("Drift events:"));
}
#[test]
fn test_mimicry_engine_train() {
let mut engine = MimicryEngine::new();
let _ = engine.mimic("gpt4o");
let result = engine.train(5);
assert!(result.is_err());
assert!(result.unwrap_err().contains("No training data"));
engine.observe(
"gpt4o",
"Certainly! Here is a detailed explanation with code.",
);
engine.observe(
"gpt4o",
"Great question! Let me break this down step by step.",
);
let result = engine.train(5);
assert!(result.is_ok());
let report = result.unwrap();
assert!(report.contains("TRAINING REPORT"));
assert!(report.contains("gpt4o"));
}
#[test]
fn test_mimicry_engine_save_load() {
let mut engine = MimicryEngine::new();
let _ = engine.mimic("claude");
let save_result = engine.save(Some("test-save"));
assert!(save_result.is_ok());
let load_result = engine.load("test-save");
assert!(load_result.is_ok());
}
#[test]
fn test_mimicry_engine_delete() {
let mut engine = MimicryEngine::new();
let _ = engine.mimic("claude");
let _ = engine.save(Some("to-delete"));
let result = engine.delete("to-delete");
assert!(result.is_ok());
let result = engine.delete("nonexistent");
assert!(result.is_err());
}
#[test]
fn test_mimicry_engine_graph() {
let mut engine = MimicryEngine::new();
let result = engine.graph();
assert!(result.is_err());
let _ = engine.mimic("gpt4o");
let _ = engine.evolve(5);
let result = engine.graph();
assert!(result.is_ok());
assert!(result.unwrap().contains("CONVERGENCE GRAPH"));
}
#[test]
fn test_mimicry_engine_evolution_status() {
let mut engine = MimicryEngine::new();
let _ = engine.mimic("gpt4o");
let result = engine.evolution_status();
assert!(result.is_ok());
assert!(result.unwrap().contains("EVOLUTION STATUS"));
}
#[test]
fn test_mimicry_engine_parse_command() {
let engine = MimicryEngine::new();
match engine.parse_command("/mimic gpt4o") {
MimicCommand::Mimic(id) => assert_eq!(id, "gpt4o"),
_ => panic!("Expected Mimic command"),
}
match engine.parse_command("/mimic gpt4o+claude 0.7,0.3") {
MimicCommand::Blend(ids, weights) => {
assert_eq!(ids, vec!["gpt4o", "claude"]);
assert_eq!(weights.len(), 2);
}
_ => panic!("Expected Blend command"),
}
match engine.parse_command("hello world") {
MimicCommand::Chat(msg) => assert_eq!(msg, "hello world"),
_ => panic!("Expected Chat command"),
}
match engine.parse_command("/list") {
MimicCommand::List => {}
_ => panic!("Expected List command"),
}
match engine.parse_command("/train 20") {
MimicCommand::Train(n) => assert_eq!(n, 20),
_ => panic!("Expected Train command"),
}
match engine.parse_command("/graph") {
MimicCommand::Graph => {}
_ => panic!("Expected Graph command"),
}
match engine.parse_command("/evolution") {
MimicCommand::EvolutionStatus => {}
_ => panic!("Expected EvolutionStatus command"),
}
match engine.parse_command("/export mymodel") {
MimicCommand::Export(name) => assert_eq!(name, "mymodel"),
_ => panic!("Expected Export command"),
}
match engine.parse_command("/import /path/to/file.json") {
MimicCommand::Import(path) => assert_eq!(path, "/path/to/file.json"),
_ => panic!("Expected Import command"),
}
match engine.parse_command("/delete old-persona") {
MimicCommand::Delete(name) => assert_eq!(name, "old-persona"),
_ => panic!("Expected Delete command"),
}
match engine.parse_command("/checkpoint") {
MimicCommand::Checkpoint => {}
_ => panic!("Expected Checkpoint command"),
}
match engine.parse_command("/persist") {
MimicCommand::Persist => {}
_ => panic!("Expected Persist command"),
}
match engine.parse_command("/api-config openai sk-test-123") {
MimicCommand::ApiConfig(provider, key) => {
assert_eq!(provider, "openai");
assert_eq!(key, Some("sk-test-123".to_string()));
}
_ => panic!("Expected ApiConfig command"),
}
match engine.parse_command("/api-config ollama") {
MimicCommand::ApiConfig(provider, key) => {
assert_eq!(provider, "ollama");
assert!(key.is_none());
}
_ => panic!("Expected ApiConfig command"),
}
match engine.parse_command("/api-observe openai What is Rust?") {
MimicCommand::ApiObserve(provider, prompt) => {
assert_eq!(provider, "openai");
assert_eq!(prompt, "What is Rust?");
}
_ => panic!("Expected ApiObserve command"),
}
match engine.parse_command("/api-compare What is Rust?") {
MimicCommand::ApiCompare(prompt) => {
assert_eq!(prompt, "What is Rust?");
}
_ => panic!("Expected ApiCompare command"),
}
match engine.parse_command("/api-study openai 7") {
MimicCommand::ApiStudy(provider, n) => {
assert_eq!(provider, "openai");
assert_eq!(n, 7);
}
_ => panic!("Expected ApiStudy command"),
}
match engine.parse_command("/api-status") {
MimicCommand::ApiStatus => {}
_ => panic!("Expected ApiStatus command"),
}
match engine.parse_command("/api") {
MimicCommand::ApiStatus => {}
_ => panic!("Expected ApiStatus command from /api shortcut"),
}
}
#[test]
fn test_mimicry_engine_full_flow() {
let mut engine = MimicryEngine::new();
let _ = engine.execute(MimicCommand::Mimic("gpt4o".to_string()));
let output = engine.execute(MimicCommand::Chat("What is Rust?".to_string()));
assert!(!output.is_empty());
let _ = engine.execute(MimicCommand::Observe(
"gpt4o".to_string(),
"Certainly! Rust is a systems programming language.".to_string(),
));
let _ = engine.execute(MimicCommand::Evolve(3));
let status = engine.execute(MimicCommand::Status);
assert!(status.contains("RUSTYWORM"));
let _ = engine.execute(MimicCommand::Save(Some("test".to_string())));
let list = engine.execute(MimicCommand::List);
assert!(list.contains("gpt4o"));
}
#[test]
fn test_mimicry_engine_status_enhanced() {
let mut engine = MimicryEngine::new();
let _ = engine.mimic("claude");
let status = engine.status();
assert!(status.contains("RUSTYWORM STATUS"));
assert!(status.contains("Template libraries:"));
assert!(status.contains("Evolution phase:"));
assert!(status.contains("Persistence:"));
}
#[test]
fn test_mimicry_engine_template_compound_with_evolve() {
let mut engine = MimicryEngine::new();
let _ = engine.mimic("gpt4o");
assert!(engine.template_store.get("gpt4o").is_some());
let _ = engine.evolve(3);
let lib = engine.template_store.get("gpt4o").unwrap();
assert!(lib.total_feedback > 0);
}
#[test]
fn test_evolution_report_serialization() {
let report = EvolutionReport {
iterations: 10,
starting_convergence: 0.3,
ending_convergence: 0.7,
system1_cache_size: 5,
personality_drift: 0.05,
drift_events: 2,
phase: "LEARNING".to_string(),
milestones_hit: 3,
};
let json = serde_json::to_string(&report).unwrap();
let restored: EvolutionReport = serde_json::from_str(&json).unwrap();
assert_eq!(restored.iterations, 10);
assert_eq!(restored.drift_events, 2);
}
#[test]
fn test_api_commands_execute() {
let mut engine = MimicryEngine::new();
let result = engine.execute(MimicCommand::ApiStatus);
#[cfg(feature = "api")]
assert!(result.contains("API OBSERVER STATUS") || result.contains("No providers"));
#[cfg(not(feature = "api"))]
assert!(result.contains("API feature not enabled"));
let result = engine.execute(MimicCommand::ApiConfig("ollama".to_string(), None));
#[cfg(feature = "api")]
assert!(result.contains("configured") || result.contains("Ollama"));
#[cfg(not(feature = "api"))]
assert!(result.contains("API feature not enabled"));
}
#[cfg(feature = "api")]
#[test]
fn test_api_observe_no_config() {
let mut engine = MimicryEngine::new();
let result = engine.api_observe("openai", "test prompt");
assert!(result.is_ok() || result.is_err());
}
#[cfg(feature = "api")]
#[test]
fn test_api_config_and_status() {
let mut engine = MimicryEngine::new();
let result = engine.api_config("ollama", None);
assert!(result.is_ok());
assert!(result.unwrap().contains("Ollama"));
let status = engine.api_status();
assert!(status.contains("Ollama") || status.contains("llama"));
}
#[cfg(feature = "api")]
#[test]
fn test_api_compare_no_providers() {
let mut engine = MimicryEngine::new();
let result = engine.api_compare("test");
assert!(result.is_err());
assert!(result.unwrap_err().contains("No API providers configured"));
}
}