Host: - test first: a new version is tested where it lies; only an installed version goes to versions/, and instances run from there - data/ and public/ are shared by all versions; no snapshots; rollback restores code only - no re-delivery, status.json, list, remove/archive, smoke test, data/ hiding, or stdin timeout; rollback needs a version - supervisor.rs split out; one place for installing a version - init only writes the agent folder; run installs it like any actor - console: @actor, text to the agent, /help, /quit Agent: - every text goes out as a broadcast; 5-line prompt; 5 tools that describe themselves; turn.json only marks an active turn Docs: PROTOCOL.md, README.md, DECISIONS.md, AGENTS.md rewritten. Examples: only notes and notes-v2.
68 lines
2.3 KiB
Rust
68 lines
2.3 KiB
Rust
//! The native `console` actor: your terminal.
|
|
//!
|
|
//! - `@<actor> <json>` sends a JSON body. `@<actor> <text>` sends
|
|
//! `{"type": "text", "text": ...}`.
|
|
//! - A line without `@` goes to `agent` as text.
|
|
//! - `/help`, `/quit`. EOF on stdin also quits.
|
|
|
|
use std::sync::Arc;
|
|
|
|
use serde_json::{Value, json};
|
|
use tokio::io::{AsyncBufReadExt, BufReader};
|
|
use tokio::sync::mpsc;
|
|
|
|
use crate::broker::{Broker, Envelope};
|
|
|
|
pub const ID: &str = "console";
|
|
|
|
const HELP: &str = "\
|
|
@<actor> <json> send a JSON body to an actor
|
|
@<actor> <text> send {\"type\":\"text\",\"text\":...}
|
|
<text> send text to the agent
|
|
/quit stop all actors and exit";
|
|
|
|
/// Print a message: text bodies as text, everything else as JSON.
|
|
fn show(env: &Envelope) {
|
|
let reply = if env.reply_to.is_some() { " ↩" } else { "" };
|
|
match env.body["text"].as_str() {
|
|
Some(text) if env.body["type"] == "text" => println!("[{}{reply}] {text}", env.from),
|
|
_ => println!("[{}{reply}] {}", env.from, env.body),
|
|
}
|
|
}
|
|
|
|
/// Print every message that arrives for the console.
|
|
pub async fn run_mailbox(mut mailbox: mpsc::Receiver<Envelope>) {
|
|
while let Some(env) = mailbox.recv().await {
|
|
show(&env);
|
|
}
|
|
}
|
|
|
|
/// Read lines until EOF or `/quit`, and send them as messages.
|
|
pub async fn run_input(broker: Arc<Broker>) {
|
|
println!("Sausage console. Type /help for commands.");
|
|
let mut lines = BufReader::new(tokio::io::stdin()).lines();
|
|
while let Ok(Some(line)) = lines.next_line().await {
|
|
let line = line.trim();
|
|
let (to, body) = match line {
|
|
"" => continue,
|
|
"/quit" => break,
|
|
"/help" => {
|
|
println!("{HELP}");
|
|
continue;
|
|
}
|
|
_ => match line.strip_prefix('@') {
|
|
Some(rest) => {
|
|
let (to, text) = rest.split_once(char::is_whitespace).unwrap_or((rest, ""));
|
|
let body = match serde_json::from_str::<Value>(text.trim()) {
|
|
Ok(v @ Value::Object(_)) => v,
|
|
_ => json!({"type": "text", "text": text.trim()}),
|
|
};
|
|
(to, body)
|
|
}
|
|
None => ("agent", json!({"type": "text", "text": line})),
|
|
},
|
|
};
|
|
broker.send(ID, Some(to), None, None, body);
|
|
}
|
|
}
|