haematite-cli 0.21.1

The haematite command: serve a store, its door and Studio, answer MCP, query with jq, and host the store's assistant seat
Documentation
//! Start-timeout diagnostics after the stand-in has signalled that it is running.

use std::error::Error;
use std::io::Read;
use std::num::NonZeroU32;
use std::path::PathBuf;
use std::process::{Command, Stdio};
use std::time::Instant;

use haem_frames::embedding::read_message;
use haematite_query::worker_owner::{Control, OwnedChild};

use super::Handshake;
use crate::serve::embed::{Options, Settings};
use crate::serve::query::Setting;

type TestResult = Result<(), Box<dyn Error>>;

fn settings() -> Result<Settings, Box<dyn Error>> {
    Options {
        worker: Setting::Present(PathBuf::from("/bin/sh")),
        model_dir: Setting::Present(PathBuf::from("/")),
        model_sha256: Setting::Present("1".repeat(64)),
        memory_bytes: Setting::Present(1 << 30),
        threads: Setting::Present(1),
        batch_items: Setting::Present(4),
        input_bytes: Setting::Present(16_384),
        tokens: Setting::Present(512),
        frame_bytes: Setting::Present(1 << 20),
        ready_ms: Setting::Present(2_000),
        call_ms: Setting::Present(30_000),
        waiting: Setting::Present(4),
        request_items: Setting::Present(64),
        page_records: Setting::Present(64),
        writer_wait_ms: Setting::Absent,
        windows: Setting::Absent,
        max_windows: Setting::Absent,
        overlap_tokens: Setting::Absent,
    }
    .resolve()?
    .ok_or_else(|| "no embedding settings".into())
}

/// Keep both output pipes open while consuming input without answering Ready.
/// The started signal follows the diagnostic, so neither depends on a launch window.
fn started() -> Result<Handshake, Box<dyn Error>> {
    let mut child = OwnedChild(
        Command::new("/bin/sh")
            .args([
                "-c",
                "printf 'loading the model: out of memory\\n' >&2; printf 'started\\n'; \
                 while IFS= read -r request; do :; done",
            ])
            .env_clear()
            .current_dir("/")
            .stdin(Stdio::piped())
            .stdout(Stdio::piped())
            .stderr(Stdio::piped())
            .spawn()?,
    );
    let input = child.0.stdin.take().ok_or("no stand-in input")?;
    let mut output = child.0.stdout.take().ok_or("no stand-in output")?;
    let stderr = child.0.stderr.take().ok_or("no stand-in diagnostics")?;
    let mut signal = [0_u8; 8];
    output.read_exact(&mut signal)?;
    assert_eq!(
        &signal, b"started\n",
        "the stand-in must signal after writing its diagnostic and keep its output open"
    );
    // An expired deadline exercises the owner's timeout without a timer wait.
    let control = Control::start(child, stderr, Instant::now())?;
    Ok(Handshake {
        input,
        output,
        control,
        frame: NonZeroU32::new(1 << 20).ok_or("no frame bound")?,
    })
}

#[test]
fn a_start_timeout_says_the_status_and_what_the_worker_wrote() -> TestResult {
    let settings = settings()?;
    let mut handshake = started()?;
    let refused = handshake.before_ready(&settings, None);
    let answer = read_message(&mut handshake.output, handshake.frame)?;
    assert!(
        answer.is_none(),
        "the owner must close the stand-in's output without a Ready"
    );
    assert_eq!(
        refused.code, "embed_worker_start_timeout",
        "{}",
        refused.message
    );
    assert!(
        refused.message.contains("status signal: 9"),
        "the owner must kill and reap the held stand-in: {}",
        refused.message
    );
    assert!(
        refused
            .message
            .contains("stderr: loading the model: out of memory"),
        "the timeout must retain the diagnostic written before the started signal: {}",
        refused.message
    );
    assert!(
        handshake.control.finish(false).is_err(),
        "Ready refusal must have joined the owner already"
    );
    Ok(())
}