1use crate::{ExpertDomain, MicroExpert, ProcessingConfig, NetworkStats};
8use serde::{Deserialize, Serialize};
9use std::collections::HashMap;
10use wasm_bindgen::prelude::*;
11
12#[wasm_bindgen]
14pub struct EnhancedRouter {
15 experts: HashMap<ExpertDomain, Vec<MicroExpert>>,
16 market_integration: Option<MarketIntegration>,
17 #[allow(dead_code)]
18 config: ProcessingConfig,
19 stats: NetworkStats,
20}
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct MarketIntegration {
25 pub market_routing_enabled: bool,
27 pub compute_budget: u64,
29 pub min_reputation: f64,
31 pub max_price_per_unit: u64,
33 pub preferred_domains: Vec<ExpertDomain>,
35}
36
37#[derive(Debug, Clone, Serialize, Deserialize)]
39pub struct ExpertMetrics {
40 pub domain: ExpertDomain,
42 pub queries_processed: u64,
44 pub avg_response_time: f64,
46 pub success_rate: f64,
48 pub quality_score: f64,
50 pub current_load: f64,
52}
53
54#[derive(Debug, Clone, Serialize, Deserialize)]
56pub struct RouteRecommendation {
57 pub domain: ExpertDomain,
59 pub confidence: f64,
61 pub estimated_cost: u64,
63 pub estimated_time: u32,
65 pub use_market: bool,
67 pub reasoning: String,
69}
70
71#[derive(Debug, Clone, Serialize, Deserialize)]
73pub struct QueryClassification {
74 pub primary_domain: ExpertDomain,
76 pub secondary_domains: Vec<ExpertDomain>,
78 pub complexity: f64,
80 pub urgency: f64,
82}
83
84#[wasm_bindgen]
85impl EnhancedRouter {
86 #[wasm_bindgen(constructor)]
88 pub fn new(config: ProcessingConfig) -> EnhancedRouter {
89 let mut experts = HashMap::new();
90
91 for domain in [
93 ExpertDomain::Reasoning,
94 ExpertDomain::Coding,
95 ExpertDomain::Language,
96 ExpertDomain::Mathematics,
97 ExpertDomain::ToolUse,
98 ExpertDomain::Context,
99 ] {
100 experts.insert(domain, vec![MicroExpert::new(domain)]);
101 }
102
103 let stats = NetworkStats {
104 active_peers: 1,
105 total_queries: 0,
106 average_latency_ms: 0.0,
107 expert_utilization: HashMap::new(),
108 neural_accuracy: 0.85,
109 };
110
111 EnhancedRouter {
112 experts,
113 market_integration: None,
114 config,
115 stats,
116 }
117 }
118
119 pub fn enable_market_integration(&mut self, integration_config: &str) -> Result<(), JsValue> {
121 let config: MarketIntegration = serde_json::from_str(integration_config)
122 .map_err(|e| JsValue::from_str(&format!("Invalid config: {}", e)))?;
123
124 self.market_integration = Some(config);
125 Ok(())
126 }
127
128 pub fn classify_query(&self, query: &str) -> String {
130 let classification = self.internal_classify_query(query);
131 serde_json::to_string(&classification).unwrap_or_default()
132 }
133
134 pub fn get_route_recommendation(&self, query: &str) -> String {
136 let recommendation = self.internal_get_route_recommendation(query);
137 serde_json::to_string(&recommendation).unwrap_or_default()
138 }
139
140 pub fn enhanced_route(&mut self, query: &str) -> String {
142 let classification = self.internal_classify_query(query);
144
145 let recommendation = self.internal_get_route_recommendation(query);
147
148 self.update_stats(&classification, &recommendation);
150
151 self.process_with_recommendation(query, &recommendation)
153 }
154
155 pub fn get_expert_metrics(&self) -> String {
157 let metrics: Vec<ExpertMetrics> = self.experts.keys().map(|&domain| {
158 let utilization = self.stats.expert_utilization.get(&domain).copied().unwrap_or(0.0);
159
160 ExpertMetrics {
161 domain,
162 queries_processed: self.stats.total_queries / self.experts.len() as u64,
163 avg_response_time: self.stats.average_latency_ms,
164 success_rate: 0.95, quality_score: 0.85, current_load: utilization,
167 }
168 }).collect();
169
170 serde_json::to_string(&metrics).unwrap_or_default()
171 }
172
173 pub fn get_network_stats(&self) -> String {
175 serde_json::to_string(&self.stats).unwrap_or_default()
176 }
177
178 pub fn update_capacity(&mut self, domain_str: &str, capacity: usize) -> Result<(), JsValue> {
180 let domain: ExpertDomain = serde_json::from_str(&format!("\"{}\"", domain_str))
181 .map_err(|e| JsValue::from_str(&format!("Invalid domain: {}", e)))?;
182
183 if let Some(expert_pool) = self.experts.get_mut(&domain) {
184 if capacity > expert_pool.len() {
186 for _ in expert_pool.len()..capacity {
188 expert_pool.push(MicroExpert::new(domain));
189 }
190 } else if capacity < expert_pool.len() {
191 expert_pool.truncate(capacity);
193 }
194 }
195
196 Ok(())
197 }
198}
199
200impl EnhancedRouter {
201 fn internal_classify_query(&self, query: &str) -> QueryClassification {
203 let query_lower = query.to_lowercase();
204
205 let has_arithmetic = self.detect_arithmetic_expression(query);
207
208 let (primary_domain, complexity) = if has_arithmetic {
210 (ExpertDomain::Mathematics, 0.9) } else if query_lower.contains("machine learning") || query_lower.contains("deep learning") || query_lower.contains("neural network") || query_lower.contains("ai") || query_lower.contains("artificial intelligence") {
212 (ExpertDomain::Reasoning, 0.9) } else if query_lower.contains("code") || query_lower.contains("function") || query_lower.contains("algorithm") || query_lower.contains("program") || query_lower.contains("implement") || query_lower.contains("array") || query_lower.contains("loop") || query_lower.contains("data structure") || query_lower.contains("recursion") || query_lower.contains("linked list") || query_lower.contains("binary search") || query_lower.contains("sorting") || (query_lower.contains("explain") && (query_lower.contains("programming") || query_lower.contains("code"))) || (query_lower.contains("write") && (query_lower.contains("function") || query_lower.contains("code") || query_lower.contains("algorithm"))) {
214 (ExpertDomain::Coding, 0.85)
215 } else if query_lower.contains("math") || query_lower.contains("calculate") || query_lower.contains("equation") || query_lower.contains("solve") || query_lower.contains("integral") || query_lower.contains("derivative") || query_lower.contains("algebra") || query_lower.contains("geometry") || query_lower.contains("number") || query_lower.contains("sum") || query_lower.contains("subtract") || query_lower.contains("multiply") || query_lower.contains("divide") || query_lower.contains("calculus") || query_lower.contains("statistics") || query_lower.contains("probability") || query_lower.contains("pythagorean") || query_lower.contains("theorem") {
216 (ExpertDomain::Mathematics, 0.7)
217 } else if query_lower.contains("tool") || query_lower.contains("api") || query_lower.contains("execute") || query_lower.contains("command") {
218 (ExpertDomain::ToolUse, 0.6)
219 } else if query_lower.contains("meaning of life") || query_lower.contains("consciousness") || query_lower.contains("free will") || query_lower.contains("reality") || query_lower.contains("existence") || query_lower.contains("philosophy") || query_lower.contains("purpose of") {
220 (ExpertDomain::Reasoning, 0.95) } else if query_lower.contains("reason") || query_lower.contains("logic") || query_lower.contains("analyze") || query_lower.contains("think") || query_lower.contains("explain") {
222 (ExpertDomain::Reasoning, 0.9)
223 } else if query_lower.contains("context") || query_lower.contains("remember") || query_lower.contains("previous") || query_lower.contains("earlier") {
224 (ExpertDomain::Context, 0.5)
225 } else if query_lower.contains("translate") || query_lower.contains("language") || query_lower.contains("grammar") || query_lower.contains("text") || query_lower.contains("nlp") || query_lower.contains("natural language") || (query_lower.contains("write") && !query_lower.contains("function") && !query_lower.contains("code")) {
226 (ExpertDomain::Language, 0.6)
227 } else if query_lower.contains("hello") || query_lower.contains("hi ") || query_lower.starts_with("hi") || query_lower.contains("greet") {
228 (ExpertDomain::Language, 0.8) } else if query_lower.contains("what is") {
230 (ExpertDomain::Reasoning, 0.7)
232 } else {
233 (ExpertDomain::Reasoning, 0.4) };
235
236 let mut secondary_domains = Vec::new();
238 if complexity > 0.7 {
239 secondary_domains.push(ExpertDomain::Reasoning);
240 }
241 if query_lower.len() > 100 {
242 secondary_domains.push(ExpertDomain::Context);
243 }
244
245 let urgency = if query_lower.contains("urgent") || query_lower.contains("asap") || query_lower.contains("quickly") {
247 0.9
248 } else if query_lower.contains("when possible") || query_lower.contains("sometime") {
249 0.2
250 } else {
251 0.5
252 };
253
254 QueryClassification {
255 primary_domain,
256 secondary_domains,
257 complexity,
258 urgency,
259 }
260 }
261
262 fn internal_get_route_recommendation(&self, query: &str) -> RouteRecommendation {
264 let classification = self.internal_classify_query(query);
265
266 let local_available = self.experts.get(&classification.primary_domain)
268 .map(|experts| !experts.is_empty())
269 .unwrap_or(false);
270
271 let use_market = if let Some(ref market_config) = self.market_integration {
273 market_config.market_routing_enabled &&
274 (classification.complexity > 0.8 || classification.urgency > 0.7 || !local_available)
275 } else {
276 false
277 };
278
279 let base_cost = (classification.complexity * 100.0) as u64;
281 let estimated_cost = if use_market {
282 base_cost * 2 } else {
284 base_cost / 10 };
286
287 let estimated_time = if use_market {
288 (classification.complexity * 5000.0) as u32 } else {
290 (classification.complexity * 1000.0) as u32 };
292
293 let confidence = if local_available && !use_market {
295 0.9
296 } else if use_market {
297 0.7
298 } else {
299 0.5
300 };
301
302 let reasoning = if use_market {
304 format!("Using market experts for {} domain due to high complexity/urgency",
305 format!("{:?}", classification.primary_domain))
306 } else {
307 format!("Using local {} expert - sufficient capacity available",
308 format!("{:?}", classification.primary_domain))
309 };
310
311 RouteRecommendation {
312 domain: classification.primary_domain,
313 confidence,
314 estimated_cost,
315 estimated_time,
316 use_market,
317 reasoning,
318 }
319 }
320
321 fn update_stats(&mut self, classification: &QueryClassification, recommendation: &RouteRecommendation) {
323 self.stats.total_queries += 1;
324
325 let current_util = self.stats.expert_utilization
327 .get(&classification.primary_domain)
328 .copied()
329 .unwrap_or(0.0);
330
331 let new_util = (current_util * 0.9) + (0.1 * if recommendation.use_market { 0.5 } else { 1.0 });
332 self.stats.expert_utilization.insert(classification.primary_domain, new_util);
333
334 let new_latency = recommendation.estimated_time as f64;
336 if self.stats.average_latency_ms == 0.0 {
337 self.stats.average_latency_ms = new_latency;
338 } else {
339 self.stats.average_latency_ms = (self.stats.average_latency_ms * 0.9) + (new_latency * 0.1);
340 }
341 }
342
343 fn detect_arithmetic_expression(&self, query: &str) -> bool {
345 let has_operators = query.contains('+') || query.contains('-') ||
347 query.contains('*') || query.contains('/') ||
348 query.contains('^') || query.contains('=');
349 let has_numbers = query.chars().any(|c| c.is_numeric());
350
351 if has_operators && has_numbers {
353 let chars: Vec<char> = query.chars().collect();
355 for i in 0..chars.len() {
356 if chars[i].is_numeric() {
357 for j in i+1..chars.len() {
359 if matches!(chars[j], '+' | '-' | '*' | '/' | '^') {
360 for k in j+1..chars.len() {
362 if chars[k].is_numeric() {
363 return true;
364 }
365 }
366 }
367 }
368 }
369 }
370 }
371
372 let query_lower = query.to_lowercase();
374 let has_arithmetic_words = query_lower.contains("plus") ||
375 query_lower.contains("minus") ||
376 query_lower.contains("times") ||
377 query_lower.contains("divided") ||
378 query_lower.contains("add") ||
379 query_lower.contains("subtract") ||
380 query_lower.contains("multiply") ||
381 query_lower.contains("divide") ||
382 query_lower.contains("equals") ||
383 query_lower.contains("sum of") ||
384 query_lower.contains("difference");
385
386 has_numbers && has_arithmetic_words
387 }
388
389 fn process_with_recommendation(&self, query: &str, recommendation: &RouteRecommendation) -> String {
391 if recommendation.use_market {
392 format!(
394 "Market processing: {} (domain: {:?}, cost: {} tokens, time: {}ms)",
395 query,
396 recommendation.domain,
397 recommendation.estimated_cost,
398 recommendation.estimated_time
399 )
400 } else {
401 if let Some(experts) = self.experts.get(&recommendation.domain) {
403 if let Some(expert) = experts.first() {
404 expert.process(query)
405 } else {
406 "No local expert available".to_string()
407 }
408 } else {
409 "Domain not supported".to_string()
410 }
411 }
412 }
413}
414
415pub struct MarketUtils;
417
418impl MarketUtils {
419 pub fn calculate_market_strategy(
421 local_capacity: &HashMap<ExpertDomain, usize>,
422 market_prices: &HashMap<ExpertDomain, u64>,
423 budget: u64,
424 ) -> MarketStrategy {
425 let mut recommendations = HashMap::new();
426
427 for (&domain, &local_count) in local_capacity {
428 let market_price = market_prices.get(&domain).copied().unwrap_or(100);
429
430 let action = if local_count == 0 && market_price <= budget / 10 {
431 StrategyAction::BuyFromMarket
432 } else if local_count > 3 && market_price > 50 {
433 StrategyAction::SellToMarket
434 } else {
435 StrategyAction::UseLocal
436 };
437
438 recommendations.insert(domain, action);
439 }
440
441 MarketStrategy {
442 recommendations,
443 total_budget: budget,
444 expected_cost: market_prices.values().sum::<u64>() / market_prices.len() as u64,
445 }
446 }
447}
448
449#[derive(Debug, Clone, Serialize, Deserialize)]
451pub struct MarketStrategy {
452 pub recommendations: HashMap<ExpertDomain, StrategyAction>,
454 pub total_budget: u64,
456 pub expected_cost: u64,
458}
459
460#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
462pub enum StrategyAction {
463 UseLocal,
465 BuyFromMarket,
467 SellToMarket,
469}
470
471#[cfg(test)]
472mod tests {
473 use super::*;
474
475 #[test]
476 fn test_enhanced_router_creation() {
477 let config = ProcessingConfig::new();
478 let router = EnhancedRouter::new(config);
479
480 assert_eq!(router.experts.len(), 6);
481 assert!(router.market_integration.is_none());
482 }
483
484 #[test]
485 fn test_query_classification() {
486 let config = ProcessingConfig::new();
487 let router = EnhancedRouter::new(config);
488
489 let classification = router.internal_classify_query("Write a function to calculate fibonacci numbers");
490 assert_eq!(classification.primary_domain, ExpertDomain::Coding);
491 assert!(classification.complexity > 0.5);
492 }
493
494 #[test]
495 fn test_route_recommendation() {
496 let config = ProcessingConfig::new();
497 let router = EnhancedRouter::new(config);
498
499 let recommendation = router.internal_get_route_recommendation("Simple greeting");
500 assert_eq!(recommendation.domain, ExpertDomain::Language);
501 assert!(!recommendation.use_market); }
503
504 #[test]
505 fn test_market_strategy_calculation() {
506 let mut local_capacity = HashMap::new();
507 local_capacity.insert(ExpertDomain::Coding, 0);
508 local_capacity.insert(ExpertDomain::Mathematics, 5);
509
510 let mut market_prices = HashMap::new();
511 market_prices.insert(ExpertDomain::Coding, 50);
512 market_prices.insert(ExpertDomain::Mathematics, 100);
513
514 let strategy = MarketUtils::calculate_market_strategy(&local_capacity, &market_prices, 1000);
515
516 assert!(matches!(
517 strategy.recommendations.get(&ExpertDomain::Coding),
518 Some(StrategyAction::BuyFromMarket)
519 ));
520 assert!(matches!(
521 strategy.recommendations.get(&ExpertDomain::Mathematics),
522 Some(StrategyAction::SellToMarket)
523 ));
524 }
525
526 #[test]
527 fn test_arithmetic_detection() {
528 let config = ProcessingConfig::new();
529 let router = EnhancedRouter::new(config);
530
531 assert!(router.detect_arithmetic_expression("What is 2+2?"));
533 assert!(router.detect_arithmetic_expression("Calculate 5 * 3"));
534 assert!(router.detect_arithmetic_expression("10 - 7 equals what?"));
535 assert!(router.detect_arithmetic_expression("What is 100 / 4"));
536
537 assert!(router.detect_arithmetic_expression("What is 5 plus 3?"));
539 assert!(router.detect_arithmetic_expression("Calculate 10 minus 2"));
540 assert!(router.detect_arithmetic_expression("What is 4 times 6?"));
541
542 assert!(!router.detect_arithmetic_expression("What is machine learning?"));
544 assert!(!router.detect_arithmetic_expression("How does AI work?"));
545 assert!(!router.detect_arithmetic_expression("Tell me about programming"));
546 }
547
548 #[test]
549 fn test_mathematics_routing() {
550 let config = ProcessingConfig::new();
551 let router = EnhancedRouter::new(config);
552
553 let classification = router.internal_classify_query("What is 2+2?");
555 assert_eq!(classification.primary_domain, ExpertDomain::Mathematics);
556 assert!(classification.complexity >= 0.9); let classification2 = router.internal_classify_query("Calculate 10 * 5");
559 assert_eq!(classification2.primary_domain, ExpertDomain::Mathematics);
560
561 let classification3 = router.internal_classify_query("What is machine learning?");
563 assert_eq!(classification3.primary_domain, ExpertDomain::Reasoning);
564 }
565}