M5a task 15: the starter soul and device checks with memoryd, finished
The session did the task and stopped on make verify-device. The cause was not the server: run-plan.sh and the device tests both read BOXMAKER_MODEL, and the run's value (OpenCode's provider-prefixed id) reached llama-server as the model name. With it unset, verify-device passes 6 of 6. The copied files are identical to the plan's, and the gate prints gate: ok, 936 tests. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,9 @@
|
||||
//! They never touch the real `llama-server` process. The "server dies" test kills and restarts
|
||||
//! its own `inferproxy`.
|
||||
|
||||
#[path = "support/memoryd.rs"]
|
||||
mod memoryd_run;
|
||||
|
||||
use loopd::config::Config;
|
||||
use loopd::llama::info::{CacheOutcome, cache_outcome};
|
||||
use loopd::llama::{ChatEvent, ChatMessage, ChatRequest, Client};
|
||||
@@ -244,6 +247,7 @@ struct Served {
|
||||
child: Child,
|
||||
home: PathBuf,
|
||||
socket: PathBuf,
|
||||
memoryd: Child,
|
||||
}
|
||||
|
||||
fn config_text(infer: &Path, home: &Path) -> String {
|
||||
@@ -268,9 +272,12 @@ home = "{}"
|
||||
}
|
||||
|
||||
impl Served {
|
||||
/// Writes the config and the repository's `system.md` into `home`, and starts `loopd serve`.
|
||||
/// Writes the config and the repository's `system.md` into `home`, and starts `memoryd serve`
|
||||
/// (with the repository's starter `soul.md`), then `loopd serve`: `loopd` starts no session
|
||||
/// without the memory block.
|
||||
fn start(infer: &Path, home: &Path) -> Served {
|
||||
std::fs::create_dir_all(home).unwrap();
|
||||
let memoryd = memoryd_run::start(home);
|
||||
let config = home.join("config.toml");
|
||||
std::fs::write(&config, config_text(infer, home)).unwrap();
|
||||
let prompt = Path::new(env!("CARGO_MANIFEST_DIR")).join("../../config/system.md");
|
||||
@@ -288,6 +295,7 @@ impl Served {
|
||||
child,
|
||||
home: home.to_path_buf(),
|
||||
socket,
|
||||
memoryd,
|
||||
};
|
||||
for _ in 0..600 {
|
||||
if served.socket.exists() {
|
||||
@@ -302,6 +310,8 @@ impl Served {
|
||||
fn kill(&mut self) {
|
||||
let _ = self.child.kill();
|
||||
let _ = self.child.wait();
|
||||
let _ = self.memoryd.kill();
|
||||
let _ = self.memoryd.wait();
|
||||
}
|
||||
|
||||
/// One `bxctl chat --say` turn. Returns the answer.
|
||||
@@ -350,21 +360,40 @@ fn the_baseline_fits_the_token_budget() {
|
||||
let mut cfg = config(&socket);
|
||||
cfg.paths.home = home.clone();
|
||||
cfg.baseline.system = Path::new(env!("CARGO_MANIFEST_DIR")).join("../../config/system.md");
|
||||
let baseline =
|
||||
loopd::baseline::Baseline::assemble(&cfg, &loopd::tools::Registry::m3a()).unwrap();
|
||||
let client = Client::new(cfg);
|
||||
// The system text plus every tool schema as the request carries it.
|
||||
let mut text = baseline.system.clone();
|
||||
for tool in &baseline.tools {
|
||||
text.push('\n');
|
||||
text.push_str(&serde_json::to_string(&tool).unwrap());
|
||||
}
|
||||
let tokens = client.tokenize(&text).unwrap();
|
||||
eprintln!("baseline: {tokens} tokens");
|
||||
assert!(
|
||||
tokens <= 3000,
|
||||
"the baseline is {tokens} tokens; the brief allows 3000"
|
||||
let root = Path::new(env!("CARGO_MANIFEST_DIR")).join("../..");
|
||||
let soul = std::fs::read_to_string(root.join("config/soul.md")).unwrap();
|
||||
let prose = std::fs::read_to_string(root.join("docs/design.md")).unwrap();
|
||||
let prose: String = prose.split_whitespace().collect::<Vec<_>>().join(" ");
|
||||
let client = Client::new(cfg.clone());
|
||||
// The memory block as memoryd renders it (M5a spec, section 4): the starter soul with empty
|
||||
// files, as a new install sends it; then every file at its limit, the most it can be.
|
||||
let empty = format!(
|
||||
"# soul.md\n{}\n\n# memory.md (0 of 2,200 characters)\n(empty)\n\n# user.md (0 of 1,375 characters)\n(empty)",
|
||||
soul.trim()
|
||||
);
|
||||
let full = format!(
|
||||
"# soul.md\n{}\n\n# memory.md (2,200 of 2,200 characters)\n{}\n\n# user.md (1,375 of 1,375 characters)\n{}",
|
||||
prose.chars().take(4000).collect::<String>(),
|
||||
prose.chars().skip(4000).take(2200).collect::<String>(),
|
||||
prose.chars().skip(6200).take(1375).collect::<String>()
|
||||
);
|
||||
for (what, block) in [("starter", empty), ("full", full)] {
|
||||
let baseline =
|
||||
loopd::baseline::Baseline::assemble_with(&cfg, &loopd::tools::Registry::m5a(), &block)
|
||||
.unwrap();
|
||||
// The system text plus every tool schema as the request carries it.
|
||||
let mut text = baseline.system.clone();
|
||||
for tool in &baseline.tools {
|
||||
text.push('\n');
|
||||
text.push_str(&serde_json::to_string(&tool).unwrap());
|
||||
}
|
||||
let tokens = client.tokenize(&text).unwrap();
|
||||
eprintln!("baseline, {what} memory: {tokens} tokens");
|
||||
assert!(
|
||||
tokens <= 3000,
|
||||
"the baseline with {what} memory is {tokens} tokens; the brief allows 3000"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
//! Starting `memoryd` for the device tests, with the repository's starter `soul.md`: `loopd`
|
||||
//! starts no session without the memory block. Do not edit.
|
||||
|
||||
use std::path::Path;
|
||||
use std::process::{Child, Command};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
/// Write `memoryd.toml` into `home`, start `memoryd serve`, and wait for its `loopd` socket.
|
||||
pub fn start(home: &Path) -> Child {
|
||||
let root = Path::new(env!("CARGO_MANIFEST_DIR")).join("../..");
|
||||
let config = home.join("memoryd.toml");
|
||||
std::fs::write(
|
||||
&config,
|
||||
format!(
|
||||
"[paths]\nhome = \"{}\"\n[memory]\nsoul_starter = \"{}\"\n",
|
||||
home.display(),
|
||||
root.join("config/soul.md").display()
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
let socket = home.join("run").join("loop-memory").join("memory.sock");
|
||||
let _ = std::fs::remove_file(&socket);
|
||||
let bin = std::env::var("BOXMAKER_MEMORYD").expect("BOXMAKER_MEMORYD is not set");
|
||||
let mut child = Command::new(bin)
|
||||
.arg("serve")
|
||||
.arg("--config")
|
||||
.arg(&config)
|
||||
.spawn()
|
||||
.expect("cannot start memoryd");
|
||||
for _ in 0..600 {
|
||||
if socket.exists() {
|
||||
return child;
|
||||
}
|
||||
thread::sleep(Duration::from_millis(100));
|
||||
}
|
||||
let _ = child.kill();
|
||||
let _ = child.wait();
|
||||
panic!("memoryd did not come up within 60 s");
|
||||
}
|
||||
Reference in New Issue
Block a user