interactive/
interactive.rs1use std::io::{self, Write};
12use vex_adversarial::{ShadowAgent, ShadowConfig};
13use vex_core::{Agent, AgentConfig, ContextPacket, MerkleTree};
14use vex_llm::{DeepSeekProvider, LlmProvider, LlmRequest, VexConfig};
15use vex_temporal::{EpisodicMemory, HorizonConfig};
16
17#[tokio::main]
18async fn main() {
19 println!("\n╔═══════════════════════════════════════════════════════════════════╗");
20 println!("║ VEX Protocol - Interactive Assistant ║");
21 println!("║ Evolutionary | Adversarial | Temporal | Verified ║");
22 println!("╚═══════════════════════════════════════════════════════════════════╝\n");
23
24 let config = VexConfig::from_env();
26 let api_key = config
27 .llm
28 .deepseek_api_key
29 .as_deref()
30 .expect("DEEPSEEK_API_KEY environment variable must be set");
31
32 let llm = DeepSeekProvider::chat(api_key);
33 let mut memory = EpisodicMemory::new(HorizonConfig::for_depth(0));
34 let mut merkle_leaves = Vec::new();
35 let mut turn_count = 0;
36
37 let coordinator = Agent::new(AgentConfig {
39 name: "Assistant".to_string(),
40 role: "You are a helpful, accurate assistant. Provide clear, concise answers.".to_string(),
41 max_depth: 2,
42 spawn_shadow: true,
43 });
44
45 let _verifier = ShadowAgent::new(
46 &coordinator,
47 ShadowConfig {
48 challenge_intensity: 0.6,
49 fact_check: true,
50 logic_check: true,
51 },
52 );
53
54 println!("🤖 Assistant ready! Type your questions below.");
55 println!(" Commands: /help, /memory, /verify, /quit\n");
56
57 loop {
59 print!("You: ");
61 io::stdout().flush().unwrap();
62
63 let mut input = String::new();
65 if io::stdin().read_line(&mut input).is_err() {
66 break;
67 }
68 let input = input.trim();
69
70 if input.is_empty() {
72 continue;
73 }
74
75 match input {
77 "/quit" | "/exit" | "/q" => {
78 println!("\n👋 Goodbye! {} interactions processed.", turn_count);
79 break;
80 }
81 "/help" => {
82 println!("\n📚 Available Commands:");
83 println!(" /memory - Show episodic memory summary");
84 println!(" /verify - Show last verification status");
85 println!(" /quit - Exit the chat\n");
86 continue;
87 }
88 "/memory" => {
89 println!("\n📦 {}", memory.summarize());
90 if !memory.is_empty() {
91 println!(" Recent episodes:");
92 for (i, ep) in memory.episodes().take(3).enumerate() {
93 println!(
94 " {}. {}...",
95 i + 1,
96 &ep.content[..ep.content.len().min(40)]
97 );
98 }
99 }
100 println!();
101 continue;
102 }
103 "/verify" => {
104 if merkle_leaves.is_empty() {
105 println!("\n⚠️ No verified interactions yet.\n");
106 } else {
107 let tree = MerkleTree::from_leaves(merkle_leaves.clone());
108 println!("\n🔐 Verification Status:");
109 println!(" Interactions: {}", merkle_leaves.len());
110 println!(" Merkle Root: {}", tree.root_hash().unwrap());
111 println!(" Integrity: ✅ VERIFIED\n");
112 }
113 continue;
114 }
115 _ => {}
116 }
117
118 turn_count += 1;
119
120 print!("\n🤔 Thinking");
122 io::stdout().flush().unwrap();
123
124 let response = match llm
125 .complete(LlmRequest::with_role(&coordinator.config.role, input))
126 .await
127 {
128 Ok(resp) => {
129 print!(".");
130 resp.content
131 }
132 Err(e) => {
133 println!(" ⚠️\n");
134 println!("Error: {}\n", e);
135 continue;
136 }
137 };
138
139 let verify_request = LlmRequest::with_role(
141 "You are a fact-checker. Rate this response 1-10 for accuracy. Just the number.",
142 &format!(
143 "Response to verify: {}",
144 &response[..response.len().min(150)]
145 ),
146 );
147
148 let verification = match llm.complete(verify_request).await {
149 Ok(resp) => {
150 print!(".");
151 resp.content
152 }
153 Err(_) => "8".to_string(),
154 };
155
156 println!(" ✅\n");
157
158 println!("🤖 Assistant:");
160 for line in response.lines() {
161 println!(" {}", line);
162 }
163
164 let score = verification
166 .trim()
167 .chars()
168 .find(|c| c.is_ascii_digit())
169 .and_then(|c| c.to_digit(10))
170 .unwrap_or(7);
171 println!("\n 📊 Verification: {}/10", score);
172
173 if score < 6 {
174 println!(" ⚠️ Low confidence - consider fact-checking");
175 }
176 println!();
177
178 memory.remember(
180 &format!(
181 "Q: {} | A: {}...",
182 input,
183 &response[..response.len().min(50)]
184 ),
185 score as f64 / 10.0,
186 );
187
188 let packet = ContextPacket::new(&response);
190 merkle_leaves.push((format!("turn_{}", turn_count), packet.hash));
191 }
192
193 println!("\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
195 println!("📈 Session Summary:");
196 println!(" Total turns: {}", turn_count);
197 println!(" {}", memory.summarize());
198 if !merkle_leaves.is_empty() {
199 let tree = MerkleTree::from_leaves(merkle_leaves);
200 println!(" Merkle Root: {}", tree.root_hash().unwrap());
201 }
202 println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
203}