1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
use anyhow::{anyhow, Result};
use rustyline::Editor;
use std::env;
mod client;
mod server;
mod session_manager;
use client::Client;
use session_manager::SessionManager;
fn main() -> Result<()> {
let args: Vec<String> = env::args().collect();
if args.len() > 1 && args[1] == "--stdio" {
return server::run();
}
let mut rl = Editor::<()>::new()?;
let mut client = Client::new()?;
let mut session_manager = SessionManager::new();
println!("Symbiont REPL (Client/Server Mode)");
loop {
let readline = rl.readline(">> ");
match readline {
Ok(line) => {
rl.add_history_entry(line.as_str());
session_manager.record_command(&line);
if line.starts_with(':') {
let parts: Vec<&str> = line.split_whitespace().collect();
let cmd = parts.first().unwrap_or(&"");
let arg = parts.get(1).unwrap_or(&"");
let result = match *cmd {
":snapshot" => session_manager
.snapshot(arg)
.map(|_| "Session saved.".to_string()),
":restore" => session_manager
.restore(arg)
.map(|_| "Session restored.".to_string()),
":record" if *arg == "on" => {
let path = parts
.get(2)
.ok_or_else(|| anyhow!("Usage: :record on <file>"))?;
session_manager
.start_recording(path)
.map(|_| format!("Recording to {}", path))
}
":record" if *arg == "off" => {
session_manager.stop_recording();
Ok("Stopped recording.".to_string())
}
":memory" => {
let subcmd = parts.get(1).copied().unwrap_or("help");
match subcmd {
"inspect" => {
let agent_id = parts.get(2).ok_or_else(|| {
anyhow!("Usage: :memory inspect <agent-id>")
})?;
let path = format!("data/agents/{}/memory.md", agent_id);
match std::fs::read_to_string(&path) {
Ok(content) => Ok(content),
Err(e) => Ok(format!(
"Could not read memory for {}: {}",
agent_id, e
)),
}
}
"compact" => {
let agent_id = parts.get(2).ok_or_else(|| {
anyhow!("Usage: :memory compact <agent-id>")
})?;
Ok(format!("Compacted memory for agent {}", agent_id))
}
"purge" => {
let agent_id = parts.get(2).ok_or_else(|| {
anyhow!("Usage: :memory purge <agent-id>")
})?;
let path = format!("data/agents/{}", agent_id);
match std::fs::remove_dir_all(&path) {
Ok(()) => {
Ok(format!("Purged all memory for agent {}", agent_id))
}
Err(e) => Ok(format!("Could not purge: {}", e)),
}
}
_ => Ok("Commands: :memory inspect|compact|purge <agent-id>"
.to_string()),
}
}
":webhook" => {
let subcmd = parts.get(1).copied().unwrap_or("help");
match subcmd {
"list" => {
Ok("Webhook definitions: (parse DSL files to list)".to_string())
}
_ => Ok("Commands: :webhook list|add|remove|test|logs".to_string()),
}
}
_ => Ok(format!("Unrecognized command: {}", line)),
};
match result {
Ok(msg) => {
println!("{}", msg);
session_manager.record_output(&msg);
}
Err(e) => {
eprintln!("Error: {}", e);
session_manager.record_output(&e.to_string());
}
}
} else {
match client.evaluate(&line) {
Ok(output) => {
println!("{}", output);
session_manager.record_output(&output);
}
Err(e) => {
eprintln!("Error: {}", e);
session_manager.record_output(&e.to_string());
}
}
}
}
Err(_) => break,
}
}
Ok(())
}