A live-model e2e: any OpenAI-compatible brain must drive a shell turn (gated by env)
This commit is contained in:
parent
ef44db4645
commit
6f8568d16b
51
src/agent.rs
51
src/agent.rs
|
|
@ -2421,6 +2421,57 @@ mod tests {
|
||||||
/// a box: `ANYBOT_DATA_DIR=<scratch> cargo test --release -- --ignored
|
/// a box: `ANYBOT_DATA_DIR=<scratch> cargo test --release -- --ignored
|
||||||
/// a_brain_without_chrome_browses_on_its_box --nocapture`.
|
/// a_brain_without_chrome_browses_on_its_box --nocapture`.
|
||||||
#[test]
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn real_model_drives_a_shell_turn() {
|
||||||
|
// A real brain, end to end: point it at any OpenAI-compatible endpoint with
|
||||||
|
// ANYBOT_LIVE_BASE / ANYBOT_LIVE_KEY / ANYBOT_LIVE_MODEL and run
|
||||||
|
// `cargo test real_model_drives -- --ignored --nocapture`. It asks the model to write
|
||||||
|
// a file and read it back; the turn must survive real tool calls, not a script.
|
||||||
|
let Ok(base) = std::env::var("ANYBOT_LIVE_BASE") else { eprintln!("no ANYBOT_LIVE_BASE; skipped"); return };
|
||||||
|
let key = std::env::var("ANYBOT_LIVE_KEY").unwrap_or_default();
|
||||||
|
let model = std::env::var("ANYBOT_LIVE_MODEL").unwrap_or_else(|_| "husky".into());
|
||||||
|
let own = crate::model::BOT_COMPUTER_NAME.to_string();
|
||||||
|
let _ = std::fs::remove_dir_all("/tmp/anybot-live");
|
||||||
|
let job = Job {
|
||||||
|
req: ChatRequest {
|
||||||
|
kind: ProviderKind::Custom,
|
||||||
|
base_url: base,
|
||||||
|
api_key: key,
|
||||||
|
model,
|
||||||
|
system: "你是 AnyBot。用工具完成使用者的要求,最後用一句中文回答。".into(),
|
||||||
|
history: vec![Message::user("在 /tmp/anybot-live 建立 hello.txt,內容寫 anybot-was-here,然後用 shell 讀回來,告訴我市面檔裡寫了什麼。")],
|
||||||
|
tools: tools::specs(),
|
||||||
|
session: String::new(),
|
||||||
|
},
|
||||||
|
computers: vec![tools::Target { name: own.clone(), place: tools::Place::Local { workdir: "/tmp".into() } }],
|
||||||
|
default_computer: own.clone(),
|
||||||
|
roles: tools::Roles { own, person: None, server: true },
|
||||||
|
local_execution: false,
|
||||||
|
direct: Arc::new(AtomicBool::new(true)),
|
||||||
|
..test_job()
|
||||||
|
};
|
||||||
|
let (tx, rx) = channel();
|
||||||
|
spawn(job, 1, tx, Arc::new(AtomicBool::new(false)), eframe::egui::Context::default());
|
||||||
|
let mut tools_seen = vec![];
|
||||||
|
let mut answer = String::new();
|
||||||
|
loop {
|
||||||
|
match rx.recv_timeout(Duration::from_secs(180)).expect("loop stalled") {
|
||||||
|
(_, StreamEvent::ToolCall(m)) => tools_seen.push(m.name.clone()),
|
||||||
|
(_, StreamEvent::ToolResult(m)) => {
|
||||||
|
println!("[tool] {}: {}", m.tool_name, m.text.chars().take(120).collect::<String>());
|
||||||
|
tools_seen.push(format!("done:{}", m.tool_name));
|
||||||
|
}
|
||||||
|
(_, StreamEvent::Text(t)) => answer.push_str(&t),
|
||||||
|
(_, StreamEvent::Done) => break,
|
||||||
|
(_, StreamEvent::Error(e)) => panic!("model error: {e}"),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("tools: {tools_seen:?}\nanswer: {answer}");
|
||||||
|
assert!(tools_seen.iter().any(|t| t.contains("shell")), "the model never ran a shell tool: {tools_seen:?}");
|
||||||
|
assert!(answer.contains("anybot-was-here") || std::fs::read_to_string("/tmp/anybot-live/hello.txt").unwrap_or_default().contains("anybot-was-here"), "the file never appeared; answer was: {answer}");
|
||||||
|
}
|
||||||
|
|
||||||
#[ignore]
|
#[ignore]
|
||||||
fn a_brain_without_chrome_browses_on_its_box() {
|
fn a_brain_without_chrome_browses_on_its_box() {
|
||||||
let own = crate::model::BOT_COMPUTER_NAME;
|
let own = crate::model::BOT_COMPUTER_NAME;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue