loopd: the self-test checks the model's tags against the tokenizer
Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
This commit is contained in:
@@ -4,17 +4,26 @@ mod support;
|
||||
|
||||
use loopd::llama::Client;
|
||||
use loopd::selftest::{SelfTestError, run};
|
||||
use support::{FakeServer, Reply};
|
||||
use support::{FakeServer, Reply, tokenizer};
|
||||
|
||||
const CHAT: &str = "/v1/chat/completions";
|
||||
const TOKENIZE: &str = "/tokenize";
|
||||
|
||||
/// A change to the config before the self-test runs.
|
||||
type Edit = fn(&mut loopd::config::Config);
|
||||
|
||||
/// A server that passes: the recorded props, then the three recorded completions in order.
|
||||
fn healthy() -> FakeServer {
|
||||
/// The recorded props and the fake tokenizer, and no completion yet.
|
||||
fn props_and_tags() -> FakeServer {
|
||||
let server = FakeServer::start();
|
||||
server.route("/props", vec![Reply::fixture("props")]);
|
||||
server.respond(TOKENIZE, tokenizer);
|
||||
server
|
||||
}
|
||||
|
||||
/// A server that passes: the recorded props, the fake tokenizer, then the three recorded
|
||||
/// completions in order.
|
||||
fn healthy() -> FakeServer {
|
||||
let server = props_and_tags();
|
||||
server.route(
|
||||
CHAT,
|
||||
vec![
|
||||
@@ -38,7 +47,7 @@ fn run_with(
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_healthy_server_passes_all_three_checks_in_order() {
|
||||
fn a_healthy_server_passes_all_four_checks_in_order() {
|
||||
let server = healthy();
|
||||
let (result, steps) = run_with(&server, |_| {});
|
||||
assert!(result.is_ok(), "{result:?}");
|
||||
@@ -46,6 +55,7 @@ fn a_healthy_server_passes_all_three_checks_in_order() {
|
||||
steps,
|
||||
[
|
||||
"server matches config",
|
||||
"tags tokenize as recorded",
|
||||
"tool call round trip",
|
||||
"turn 2 cache hit"
|
||||
]
|
||||
@@ -115,27 +125,26 @@ fn each_expected_value_is_checked() {
|
||||
"a server that is not the expected one is not sent any prompt"
|
||||
);
|
||||
assert!(server.requests_to(CHAT).is_empty());
|
||||
assert!(server.requests_to(TOKENIZE).is_empty());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_completion_without_the_tool_call_fails_the_second_check() {
|
||||
let server = FakeServer::start();
|
||||
server.route("/props", vec![Reply::fixture("props")]);
|
||||
fn a_completion_without_the_tool_call_fails_the_tool_call_check() {
|
||||
let server = props_and_tags();
|
||||
server.route(CHAT, vec![Reply::fixture("plain")]);
|
||||
let (result, steps) = run_with(&server, |_| {});
|
||||
assert!(
|
||||
matches!(result, Err(SelfTestError::ToolCall(_))),
|
||||
"{result:?}"
|
||||
);
|
||||
assert_eq!(steps.len(), 2);
|
||||
assert_eq!(steps.len(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_cold_second_turn_fails_the_third_check() {
|
||||
fn a_cold_second_turn_fails_the_cache_check() {
|
||||
// turn1 twice: the "second turn" reuses 15 tokens where 46 were left.
|
||||
let server = FakeServer::start();
|
||||
server.route("/props", vec![Reply::fixture("props")]);
|
||||
let server = props_and_tags();
|
||||
server.route(
|
||||
CHAT,
|
||||
vec![
|
||||
@@ -149,13 +158,12 @@ fn a_cold_second_turn_fails_the_third_check() {
|
||||
Err(SelfTestError::CacheMiss { expected, got }) => assert_eq!((expected, got), (7052, 15)),
|
||||
other => panic!("{other:?}"),
|
||||
}
|
||||
assert_eq!(steps.len(), 3);
|
||||
assert_eq!(steps.len(), 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_server_that_is_down_is_an_inference_error_after_retries() {
|
||||
let server = FakeServer::start();
|
||||
server.route("/props", vec![Reply::fixture("props")]);
|
||||
let server = props_and_tags();
|
||||
server.route(CHAT, vec![Reply::fixture("tool_call").cut_after(500)]);
|
||||
let (result, _) = run_with(&server, |c| c.limits.retry_attempts = 2);
|
||||
assert!(matches!(result, Err(SelfTestError::Infer(_))), "{result:?}");
|
||||
|
||||
Reference in New Issue
Block a user