//! Run the Mesh OpenAI-compatible reference server — a real //! `/v1/chat/completions` endpoint any OpenAI client (curl, the SDKs, vLLM-style //! tooling) can drive, returning energy-metered serving + a sealed receipt. //! //! ```text //! cargo run --example serve --features server -- 127.0.0.1:8088 & //! curl -s localhost:8088/v1/chat/completions \ //! -d '{"model":"gpt-mini","messages":[{"role":"user","content":"hi"}],"max_tokens":8}' //! ``` //! //! **What a receipt's figure is.** Each request's `usage.energy` carries the //! energy of the served span — the deterministic reference engine's work, in //! this process (the HTTP handling around it is outside the span) — at the //! grade of whatever read it, in `usage.energy.provenance` and in the sealed //! `mesh/1` receipt. The meter is the one this build can read: //! //! - `--features server,metal` (macOS): `mesh_meter::ProcessMeter`, this //! process's own CPU and GPU energy over the span. The engine runs in this //! process and uses no GPU, so where the GPU counter is proved live its GPU //! energy is exactly zero and the span covers the whole request: `HwShunt`, //! the kernel's count of this process's CPU energy. That count is every //! thread of this process, so a request served while another of its //! threads works reads that work too. Where the GPU counter is not proved //! live (a GPU busy with other work fails its probe) the span covers part //! of the request and is sealed as an estimate of all of it, `Estimator`. //! A serve too short for the CPU count to advance over it (this engine's //! are microseconds) has no reading either, and is the estimator's figure //! for the serve, `Estimator`. //! - `--features server,hw-meter` (or `hw-meter-rapl`, `-nvml`, `-apple`): //! `mesh_meter::HwMeter::detect`, the machine's counter, a reading only //! where a live one covers the whole request (a RAPL package on Linux) and //! `mesh_meter::EstimatorMeter` otherwise. With `-apple` on a Mac whose //! IOReport CPU rail is frozen it is the SMC's whole-machine power: a modeled //! figure (`ModelBased`) for a serve at least its 2 s floor long, an estimate //! for a shorter one, as this engine's are. A machine counter reads //! everything the host does over the span, not this request alone. //! - `--features server` alone: `mesh_meter::EstimatorMeter`, wall time × an //! assumed draw, `Estimator`. //! //! No build seals a figure nothing read: a `mesh/1` receipt has no coverage //! field, so `HwShunt` there claims a hardware reading of the whole request //! (SPEC §3.3), and only a meter that read one may say so. use std::net::TcpListener; use ed25519_dalek::SigningKey; use mesh_core::Mesh; use mesh_engine::ReferenceEngine; use mesh_meter::Meter; use mesh_openai::{server, ChatBackend}; use mesh_router::BackendSpec; use mesh_schema::Fidelity; /// A trivial tokenizer bridge: bytes in, a deterministic note out. A real /// deployment pairs the model's own tokenizer with the engine that serves it. pub struct ByteBackend; impl ChatBackend for ByteBackend { fn encode(&self, text: &str) -> Vec { text.bytes().map(u32::from).collect() } fn decode(&self, ids: &[u32]) -> String { format!("[mesh reference engine served {} tokens]", ids.len()) } } /// The meter this build serves with: see the module docs for each feature's /// meter and what its figures cover. pub fn meter() -> Box { #[cfg(feature = "metal")] let meter: Box = Box::new(mesh_meter::ProcessMeter::new( jouleclaw_backend_apple::gpu_liveness_load, mesh_meter::SpanUses::CpuGpu, )); #[cfg(all(feature = "hw-meter", not(feature = "metal")))] let meter: Box = Box::new(mesh_meter::HwMeter::detect()); #[cfg(not(feature = "hw-meter"))] let meter: Box = Box::new(mesh_meter::EstimatorMeter::default()); meter } /// The deterministic reference engine behind one steward-signed receipt /// chain, metered by `meter`. pub fn mesh(meter: &dyn Meter) -> Mesh<'_> { let sk = SigningKey::from_bytes(&[8u8; 32]); let mut mesh = Mesh::new(meter, sk, "did:example:mesh-demo"); mesh.register( BackendSpec::new("tiny", "ssm-1b", Fidelity::F2, 50_000), Box::new(ReferenceEngine::new("tiny", "ssm-1b", Fidelity::F2, 50_000, 32)), ); mesh } fn main() -> std::io::Result<()> { let addr = std::env::args().nth(1).unwrap_or_else(|| "127.0.0.1:8088".to_string()); let listener = TcpListener::bind(&addr)?; let meter = meter(); eprintln!("mesh OpenAI server: http://{addr}/v1/chat/completions (meter: {})", meter.name()); let mut mesh = journalled(mesh(meter.as_ref()))?; server::run(&listener, &mut mesh, &ByteBackend, 100_000_000) } /// With `MESH_JOURNAL` set, record grant decisions and seals in that file and /// replay what it already holds before serving, so a restart gives no budget /// back and the receipt chain continues (Mesh SPEC §2.2). Without it the /// journal is in memory, which a steward that restarts must not rely on. pub fn journalled(mesh: mesh_core::Mesh<'_>) -> std::io::Result> { let Some(path) = std::env::var_os("MESH_JOURNAL") else { return Ok(mesh); }; let (journal, recorded) = mesh_core::FileJournal::open(&path)?; let mesh = mesh .with_journal(journal, &recorded) .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e.to_string()))?; for u in mesh.unresolved() { eprintln!("unresolved: request {} on backend {}, debited {} µJ", u.request_id.to_hex(), u.backend, u.debited_uj); } Ok(mesh) }