1use crate::dsl::{evaluator::DslEvaluator, lexer::Lexer, parser::Parser, DslValue};
6use crate::error::{ReplError, Result};
7use crate::runtime_bridge::RuntimeBridge;
8use std::sync::Arc;
9use uuid::Uuid;
10
11pub struct ReplEngine {
13 evaluator: DslEvaluator,
15}
16
17impl ReplEngine {
18 pub fn new(runtime_bridge: Arc<RuntimeBridge>) -> Self {
20 let evaluator = DslEvaluator::new(runtime_bridge);
21
22 Self { evaluator }
23 }
24
25 pub async fn evaluate(&self, input: &str) -> Result<String> {
27 let trimmed = input.trim();
28
29 if trimmed.is_empty() {
30 return Err(ReplError::Evaluation("Empty expression".to_string()));
31 }
32
33 if let Some(result) = self.handle_repl_command(trimmed).await? {
35 return Ok(result);
36 }
37
38 match self.evaluate_dsl(trimmed).await {
40 Ok(value) => Ok(self.format_value(value)),
41 Err(e) => {
42 if trimmed.contains('=') || trimmed.contains('+') || trimmed.contains('-') {
44 self.evaluate_simple_expression(trimmed)
45 } else {
46 Err(e)
47 }
48 }
49 }
50 }
51
52 async fn handle_repl_command(&self, input: &str) -> Result<Option<String>> {
54 let parts: Vec<&str> = input.split_whitespace().collect();
55 if parts.is_empty() {
56 return Ok(None);
57 }
58
59 match parts[0] {
60 ":help" | ":h" => Ok(Some(self.show_help())),
61 ":agents" => Ok(Some(self.list_agents().await)),
62 ":agent" => {
63 if parts.len() > 1 {
64 match parts[1] {
65 "list" => Ok(Some(self.list_agents().await)),
66 "start" => {
67 if parts.len() > 2 {
68 let agent_id = parts[2].parse::<Uuid>().map_err(|_| {
69 ReplError::Evaluation("Invalid agent ID".to_string())
70 })?;
71 self.start_agent(agent_id).await
72 } else {
73 Err(ReplError::Evaluation(
74 "Usage: :agent start <agent_id>".to_string(),
75 ))
76 }
77 }
78 "stop" => {
79 if parts.len() > 2 {
80 let agent_id = parts[2].parse::<Uuid>().map_err(|_| {
81 ReplError::Evaluation("Invalid agent ID".to_string())
82 })?;
83 self.stop_agent(agent_id).await
84 } else {
85 Err(ReplError::Evaluation(
86 "Usage: :agent stop <agent_id>".to_string(),
87 ))
88 }
89 }
90 "pause" => {
91 if parts.len() > 2 {
92 let agent_id = parts[2].parse::<Uuid>().map_err(|_| {
93 ReplError::Evaluation("Invalid agent ID".to_string())
94 })?;
95 self.pause_agent(agent_id).await
96 } else {
97 Err(ReplError::Evaluation(
98 "Usage: :agent pause <agent_id>".to_string(),
99 ))
100 }
101 }
102 "resume" => {
103 if parts.len() > 2 {
104 let agent_id = parts[2].parse::<Uuid>().map_err(|_| {
105 ReplError::Evaluation("Invalid agent ID".to_string())
106 })?;
107 self.resume_agent(agent_id).await
108 } else {
109 Err(ReplError::Evaluation(
110 "Usage: :agent resume <agent_id>".to_string(),
111 ))
112 }
113 }
114 "destroy" => {
115 if parts.len() > 2 {
116 let agent_id = parts[2].parse::<Uuid>().map_err(|_| {
117 ReplError::Evaluation("Invalid agent ID".to_string())
118 })?;
119 self.destroy_agent(agent_id).await
120 } else {
121 Err(ReplError::Evaluation(
122 "Usage: :agent destroy <agent_id>".to_string(),
123 ))
124 }
125 }
126 "execute" => {
127 if parts.len() > 3 {
128 let agent_id = parts[2].parse::<Uuid>().map_err(|_| {
129 ReplError::Evaluation("Invalid agent ID".to_string())
130 })?;
131 let behavior_name = parts[3];
132 let args = parts[4..].join(" ");
134 self.execute_agent_behavior(agent_id, behavior_name, &args)
135 .await
136 } else {
137 Err(ReplError::Evaluation(
138 "Usage: :agent execute <agent_id> <behavior> [args...]"
139 .to_string(),
140 ))
141 }
142 }
143 "debug" => {
144 if parts.len() > 2 {
145 let agent_id = parts[2].parse::<Uuid>().map_err(|_| {
146 ReplError::Evaluation("Invalid agent ID".to_string())
147 })?;
148 self.debug_agent(agent_id).await
149 } else {
150 Err(ReplError::Evaluation(
151 "Usage: :agent debug <agent_id>".to_string(),
152 ))
153 }
154 }
155 _ => Err(ReplError::Evaluation(
156 "Unknown agent command. Use :help for available commands".to_string(),
157 )),
158 }
159 } else {
160 Ok(Some(self.list_agents().await))
161 }
162 }
163 ":snapshot" => {
164 let snapshot = self.evaluator.create_snapshot().await;
165 Ok(Some(format!("Created snapshot: {}", snapshot.id)))
166 }
167 ":monitor" => {
168 if parts.len() > 1 {
169 match parts[1] {
170 "stats" => self.show_monitor_stats().await,
171 "traces" => {
172 let limit = if parts.len() > 2 {
173 parts[2].parse().unwrap_or(20)
174 } else {
175 20
176 };
177 self.show_traces(limit).await
178 }
179 "report" => self.show_monitor_report().await,
180 "clear" => self.clear_monitor().await,
181 _ => Err(ReplError::Evaluation(
182 "Unknown monitor command. Use :help for available commands".to_string(),
183 )),
184 }
185 } else {
186 self.show_monitor_stats().await
187 }
188 }
189 ":clear" => Ok(Some("Session cleared".to_string())),
190 ":version" => Ok(Some("Symbiont REPL v0.3.0".to_string())),
191 _ => Ok(None), }
193 }
194
195 async fn evaluate_dsl(&self, input: &str) -> Result<DslValue> {
197 let mut lexer = Lexer::new(input);
198 let tokens = lexer.tokenize()?;
199
200 let mut parser = Parser::new(tokens);
201 let program = parser.parse()?;
202
203 self.evaluator.execute_program(program).await
204 }
205
206 fn evaluate_simple_expression(&self, input: &str) -> Result<String> {
208 if let Some(result) = self.try_basic_arithmetic(input) {
210 Ok(result.to_string())
211 } else {
212 Err(ReplError::Evaluation(format!(
213 "Unable to evaluate: {}",
214 input
215 )))
216 }
217 }
218
219 fn try_basic_arithmetic(&self, input: &str) -> Option<f64> {
221 if let Ok(num) = input.parse::<f64>() {
223 return Some(num);
224 }
225
226 if let Some(pos) = input.find('+') {
228 let left = input[..pos].trim().parse::<f64>().ok()?;
229 let right = input[pos + 1..].trim().parse::<f64>().ok()?;
230 return Some(left + right);
231 }
232
233 if let Some(pos) = input.rfind('-') {
235 if pos > 0 {
236 let left = input[..pos].trim().parse::<f64>().ok()?;
238 let right = input[pos + 1..].trim().parse::<f64>().ok()?;
239 return Some(left - right);
240 }
241 }
242
243 if let Some(pos) = input.find('*') {
245 let left = input[..pos].trim().parse::<f64>().ok()?;
246 let right = input[pos + 1..].trim().parse::<f64>().ok()?;
247 return Some(left * right);
248 }
249
250 if let Some(pos) = input.find('/') {
252 let left = input[..pos].trim().parse::<f64>().ok()?;
253 let right = input[pos + 1..].trim().parse::<f64>().ok()?;
254 if right != 0.0 {
255 return Some(left / right);
256 }
257 }
258
259 None
260 }
261
262 fn format_value(&self, value: DslValue) -> String {
264 Self::format_value_impl(value)
265 }
266
267 fn format_value_impl(value: DslValue) -> String {
269 match value {
270 DslValue::String(s) => format!("\"{}\"", s),
271 DslValue::Number(n) => n.to_string(),
272 DslValue::Integer(i) => i.to_string(),
273 DslValue::Boolean(b) => b.to_string(),
274 DslValue::Duration { value, unit } => {
275 let unit_str = match unit {
276 crate::dsl::ast::DurationUnit::Milliseconds => "ms",
277 crate::dsl::ast::DurationUnit::Seconds => "s",
278 crate::dsl::ast::DurationUnit::Minutes => "m",
279 crate::dsl::ast::DurationUnit::Hours => "h",
280 crate::dsl::ast::DurationUnit::Days => "d",
281 };
282 format!("{}{}", value, unit_str)
283 }
284 DslValue::Size { value, unit } => {
285 let unit_str = match unit {
286 crate::dsl::ast::SizeUnit::Bytes => "B",
287 crate::dsl::ast::SizeUnit::KB => "KB",
288 crate::dsl::ast::SizeUnit::MB => "MB",
289 crate::dsl::ast::SizeUnit::GB => "GB",
290 crate::dsl::ast::SizeUnit::TB => "TB",
291 };
292 format!("{}{}", value, unit_str)
293 }
294 DslValue::List(items) => {
295 let formatted_items: Vec<String> =
296 items.into_iter().map(Self::format_value_impl).collect();
297 format!("[{}]", formatted_items.join(", "))
298 }
299 DslValue::Map(entries) => {
300 let formatted_entries: Vec<String> = entries
301 .into_iter()
302 .map(|(k, v)| format!("{}: {}", k, Self::format_value_impl(v)))
303 .collect();
304 format!("{{{}}}", formatted_entries.join(", "))
305 }
306 DslValue::Null => "null".to_string(),
307 DslValue::Agent(agent) => {
308 format!("Agent(id: {}, state: {:?})", agent.id, agent.state)
309 }
310 DslValue::Function(name) => format!("Function({})", name),
311 DslValue::Lambda(lambda) => format!("Lambda({} params)", lambda.parameters.len()),
312 }
313 }
314
315 fn show_help(&self) -> String {
317 r#"Symbiont REPL Commands:
318
319DSL Expressions:
320 agent MyAgent { ... } - Define an agent
321 behavior MyBehavior { ... } - Define a behavior
322 function myFunc(...) { ... } - Define a function
323 let x = 42 - Variable assignment
324 x + y - Arithmetic expressions
325
326REPL Commands:
327 :help, :h - Show this help
328 :agents - List all agents
329 :agent list - List all agents
330 :agent start <id> - Start an agent
331 :agent stop <id> - Stop an agent
332 :agent pause <id> - Pause an agent
333 :agent resume <id> - Resume a paused agent
334 :agent destroy <id> - Destroy an agent
335 :agent execute <id> <behavior> [args] - Execute agent behavior
336 :agent debug <id> - Show debug info for an agent
337 :snapshot - Create a session snapshot
338 :monitor stats - Show execution statistics
339 :monitor traces [limit] - Show execution traces
340 :monitor report - Show detailed execution report
341 :monitor clear - Clear monitoring data
342 :clear - Clear the session
343 :version - Show version information
344
345Examples:
346 agent TestAgent {
347 name: "My Test Agent"
348 version: "1.0.0"
349 }
350
351 behavior Greet {
352 input { name: string }
353 output { greeting: string }
354 steps {
355 let greeting = format("Hello, {}!", name)
356 return greeting
357 }
358 }"#
359 .to_string()
360 }
361
362 async fn list_agents(&self) -> String {
364 let agents = self.evaluator.list_agents().await;
365
366 if agents.is_empty() {
367 "No agents created.".to_string()
368 } else {
369 let mut output = String::from("Agents:\n");
370 for agent in agents {
371 let state_str = format!("{:?}", agent.state);
372 output.push_str(&format!(
373 " {} - {} ({})\n",
374 agent.id, agent.definition.name, state_str
375 ));
376 }
377 output
378 }
379 }
380
381 async fn start_agent(&self, agent_id: Uuid) -> Result<Option<String>> {
383 match self.evaluator.start_agent(agent_id).await {
384 Ok(()) => Ok(Some(format!("Started agent {}", agent_id))),
385 Err(e) => Err(e),
386 }
387 }
388
389 async fn stop_agent(&self, agent_id: Uuid) -> Result<Option<String>> {
391 match self.evaluator.stop_agent(agent_id).await {
392 Ok(()) => Ok(Some(format!("Stopped agent {}", agent_id))),
393 Err(e) => Err(e),
394 }
395 }
396
397 async fn pause_agent(&self, agent_id: Uuid) -> Result<Option<String>> {
399 match self.evaluator.pause_agent(agent_id).await {
400 Ok(()) => Ok(Some(format!("Paused agent {}", agent_id))),
401 Err(e) => Err(e),
402 }
403 }
404
405 async fn resume_agent(&self, agent_id: Uuid) -> Result<Option<String>> {
407 match self.evaluator.resume_agent(agent_id).await {
408 Ok(()) => Ok(Some(format!("Resumed agent {}", agent_id))),
409 Err(e) => Err(e),
410 }
411 }
412
413 async fn destroy_agent(&self, agent_id: Uuid) -> Result<Option<String>> {
415 match self.evaluator.destroy_agent(agent_id).await {
416 Ok(()) => Ok(Some(format!("Destroyed agent {}", agent_id))),
417 Err(e) => Err(e),
418 }
419 }
420
421 async fn execute_agent_behavior(
423 &self,
424 agent_id: Uuid,
425 behavior_name: &str,
426 args: &str,
427 ) -> Result<Option<String>> {
428 match self
429 .evaluator
430 .execute_agent_behavior(agent_id, behavior_name, args)
431 .await
432 {
433 Ok(result) => Ok(Some(format!(
434 "Executed behavior '{}' on agent {}: {}",
435 behavior_name,
436 agent_id,
437 self.format_value(result)
438 ))),
439 Err(e) => Err(e),
440 }
441 }
442
443 async fn debug_agent(&self, agent_id: Uuid) -> Result<Option<String>> {
445 match self.evaluator.debug_agent(agent_id).await {
446 Ok(debug_info) => Ok(Some(debug_info)),
447 Err(e) => Err(e),
448 }
449 }
450
451 pub fn evaluator(&self) -> &DslEvaluator {
453 &self.evaluator
454 }
455
456 async fn show_monitor_stats(&self) -> Result<Option<String>> {
458 let stats = self.evaluator.monitor().get_stats();
459 let mut output = String::from("Execution Monitor Statistics:\n");
460 output.push_str(&format!(" Total Executions: {}\n", stats.total_executions));
461 output.push_str(&format!(" Successful: {}\n", stats.successful_executions));
462 output.push_str(&format!(" Failed: {}\n", stats.failed_executions));
463
464 if stats.total_executions > 0 {
465 let success_rate =
466 (stats.successful_executions as f64 / stats.total_executions as f64) * 100.0;
467 output.push_str(&format!(" Success Rate: {:.1}%\n", success_rate));
468 output.push_str(&format!(
469 " Average Duration: {:?}\n",
470 stats.average_duration
471 ));
472 output.push_str(&format!(" Total Duration: {:?}\n", stats.total_duration));
473 }
474
475 let active = self.evaluator.monitor().get_active_executions();
476 output.push_str(&format!(" Active Executions: {}\n", active.len()));
477
478 Ok(Some(output))
479 }
480
481 async fn show_traces(&self, limit: usize) -> Result<Option<String>> {
483 let traces = self.evaluator.monitor().get_traces(Some(limit));
484
485 if traces.is_empty() {
486 return Ok(Some("No execution traces available.".to_string()));
487 }
488
489 let mut output = String::from("Recent Execution Traces:\n");
490 for trace in traces.iter().rev() {
491 let agent_info = if let Some(agent_id) = trace.agent_id {
492 format!(" [Agent: {}]", agent_id)
493 } else {
494 String::new()
495 };
496
497 let duration_info = if let Some(duration) = trace.duration {
498 format!(" ({:?})", duration)
499 } else {
500 String::new()
501 };
502
503 output.push_str(&format!(
504 " {} - {:?}{}{}\n",
505 trace.timestamp.format("%H:%M:%S%.3f"),
506 trace.event_type,
507 agent_info,
508 duration_info
509 ));
510 }
511
512 Ok(Some(output))
513 }
514
515 async fn show_monitor_report(&self) -> Result<Option<String>> {
517 let report = self.evaluator.monitor().generate_report();
518 Ok(Some(report))
519 }
520
521 async fn clear_monitor(&self) -> Result<Option<String>> {
523 self.evaluator.monitor().clear_traces();
524 Ok(Some("Monitoring data cleared.".to_string()))
525 }
526}
527
528pub fn evaluate(expression: &str) -> Result<String> {
530 if expression.is_empty() {
532 return Err(ReplError::Evaluation("Empty expression".to_string()));
533 }
534
535 if let Ok(num) = expression.parse::<f64>() {
537 return Ok(num.to_string());
538 }
539
540 if let Some(pos) = expression.find('+') {
542 let left = expression[..pos]
543 .trim()
544 .parse::<f64>()
545 .map_err(|_| ReplError::Evaluation("Invalid number".to_string()))?;
546 let right = expression[pos + 1..]
547 .trim()
548 .parse::<f64>()
549 .map_err(|_| ReplError::Evaluation("Invalid number".to_string()))?;
550 return Ok((left + right).to_string());
551 }
552
553 Ok(format!("ECHO: {}", expression))
555}
556
557#[cfg(test)]
558mod tests {
559 use super::*;
560 use crate::runtime_bridge::RuntimeBridge;
561
562 async fn create_test_engine() -> ReplEngine {
563 let runtime_bridge = Arc::new(RuntimeBridge::new());
564 ReplEngine::new(runtime_bridge)
565 }
566
567 #[tokio::test]
568 async fn test_basic_arithmetic() {
569 let engine = create_test_engine().await;
570
571 let result = engine.evaluate("2 + 3").await.unwrap();
572 assert_eq!(result, "5");
573
574 let result = engine.evaluate("10 - 4").await.unwrap();
575 assert_eq!(result, "6");
576 }
577
578 #[tokio::test]
579 async fn test_help_command() {
580 let engine = create_test_engine().await;
581
582 let result = engine.evaluate(":help").await.unwrap();
583 assert!(result.contains("Symbiont REPL Commands"));
584 }
585
586 #[tokio::test]
587 async fn test_version_command() {
588 let engine = create_test_engine().await;
589
590 let result = engine.evaluate(":version").await.unwrap();
591 assert!(result.contains("Symbiont REPL"));
592 }
593
594 #[tokio::test]
595 async fn test_agents_command() {
596 let engine = create_test_engine().await;
597
598 let result = engine.evaluate(":agents").await.unwrap();
599 assert_eq!(result, "No agents created.");
600 }
601
602 #[test]
603 fn test_legacy_evaluate() {
604 let result = evaluate("42").unwrap();
605 assert_eq!(result, "42");
606
607 let result = evaluate("5 + 3").unwrap();
608 assert_eq!(result, "8");
609 }
610}