Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ members = [
"crates/mesh-llm-commands",
"crates/mesh-llm-config",
"crates/mesh-llm-events",
"crates/mesh-llm-build-info",
"crates/mesh-llm-gpu-bench",
"crates/mesh-llm-host-runtime",
"crates/mesh-llm-hardware-profile",
Expand Down Expand Up @@ -69,6 +70,7 @@ version = "0.68.0"
anyhow = "1"
blake3 = "1"
clap = { version = "4", features = ["derive"] }
mesh-llm-build-info = { path = "crates/mesh-llm-build-info", version = "0.68.0" }
mesh-llm-skills = { path = "crates/mesh-llm-skills", version = "0.68.0" }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
Expand Down
16 changes: 16 additions & 0 deletions crates/mesh-llm-build-info/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "mesh-llm-build-info"
edition.workspace = true
license.workspace = true
version.workspace = true
description = "Build and release version constants for mesh-llm"
repository = "https://github.com/Mesh-LLM/mesh-llm"
homepage = "https://github.com/Mesh-LLM/mesh-llm"
readme = "README.md"
keywords = ["llm", "mesh", "version"]
categories = ["development-tools"]

build = "build.rs"

[lints]
workspace = true
16 changes: 16 additions & 0 deletions crates/mesh-llm-build-info/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# mesh-llm-build-info

Shared build and release version constants for Mesh LLM.

This crate is intentionally dependency-free. It lets build scripts stamp a
source build with a SHA-bearing display version while preserving the package
release version for compatibility checks, cache identity, and release metadata.

## API Shape

- `BUILD_VERSION` is the stamped display version when
`MESH_LLM_BUILD_VERSION` is set at compile time, otherwise the package
version.
- `RELEASE_VERSION` is always the plain Cargo package version.
- `is_sha_build(version)` recognizes source-build metadata of the form
`+g<hex>` and `+g<hex>.dirty`.
3 changes: 3 additions & 0 deletions crates/mesh-llm-build-info/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
println!("cargo:rerun-if-env-changed=MESH_LLM_BUILD_VERSION");
}
75 changes: 75 additions & 0 deletions crates/mesh-llm-build-info/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
pub const BUILD_VERSION: &str = match option_env!("MESH_LLM_BUILD_VERSION") {
Some(version) => version,
None => env!("CARGO_PKG_VERSION"),
};

pub const RELEASE_VERSION: &str = env!("CARGO_PKG_VERSION");

pub fn is_sha_build(version: &str) -> bool {
let Some((_, metadata)) = version.split_once('+') else {
return false;
};

let sha = if let Some(sha) = metadata.strip_suffix(".dirty") {
sha
} else {
metadata
};

let Some(hex) = sha.strip_prefix('g') else {
return false;
};

hex.len() >= 6 && hex.bytes().all(|byte| byte.is_ascii_hexdigit())
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn build_version_uses_override_when_present() {
let expected = option_env!("MESH_LLM_BUILD_VERSION").unwrap_or(env!("CARGO_PKG_VERSION"));
assert_eq!(BUILD_VERSION, expected);
}

#[test]
fn release_version_is_plain_package_version() {
assert_eq!(RELEASE_VERSION, env!("CARGO_PKG_VERSION"));
}

#[test]
fn recognizes_clean_sha_build() {
assert!(is_sha_build("0.68.0+gABCDEF"));
}

#[test]
fn recognizes_dirty_sha_build() {
assert!(is_sha_build("0.68.0+gABCDEF.dirty"));
}

#[test]
fn recognizes_lowercase_sha_build() {
assert!(is_sha_build("0.68.0+gabcdef"));
}

#[test]
fn rejects_malformed_metadata() {
assert!(!is_sha_build("0.68.0+gABCDEF.dirty.extra"));
}

#[test]
fn rejects_missing_plus() {
assert!(!is_sha_build("0.68.0gABCDEF"));
}

#[test]
fn rejects_short_sha() {
assert!(!is_sha_build("0.68.0+gABCD"));
}

#[test]
fn rejects_non_hex_sha() {
assert!(!is_sha_build("0.68.0+gABCDEX"));
}
}
1 change: 1 addition & 0 deletions crates/mesh-llm-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ workspace = true
[dependencies]
anyhow.workspace = true
clap.workspace = true
mesh-llm-build-info.workspace = true
mesh-llm-events = { path = "../mesh-llm-events", version = "0.68.0" }
serde.workspace = true
2 changes: 1 addition & 1 deletion crates/mesh-llm-cli/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ impl MeshGuardrailCliMode {
#[derive(Parser, Debug)]
#[command(
name = "mesh-llm",
version = env!("CARGO_PKG_VERSION"),
version = mesh_llm_build_info::BUILD_VERSION,
about = "Pool GPUs over the internet for LLM inference",
after_help = "Preferred runtime entrypoints:\n mesh-llm serve\n mesh-llm serve --model Qwen3-8B-Q4_K_M\n mesh-llm client --auto\n mesh-llm gpus\n\n`mesh-llm serve` loads startup models from ~/.mesh-llm/config.toml.\nRun with --help-advanced for all options.\n\nExternal backends (vLLM, TGI, Ollama):\n Install the plugin:\n mesh-llm plugins install openai-endpoint\n Add to ~/.mesh-llm/config.toml:\n [[plugin]]\n name = \"openai-endpoint\"\n url = \"http://gpu-box:8000/v1\"\n Then: mesh-llm serve (or: mesh-llm client for client-only mode)\n\nFlash-MoE SSD backend:\n Install the plugin:\n mesh-llm plugins install flash-moe\n Add [[plugin]] name = \"flash-moe\" with url or plugin-owned args.\n Then: mesh-llm serve (or: mesh-llm client for client-only mode)"
)]
Expand Down
1 change: 1 addition & 0 deletions crates/mesh-llm-commands/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ hf_hub = { package = "hf-hub", version = "1.0.0-rc.1", default-features = false,
hex = "0.4.3"
iroh = "1.0.0-rc.0"
json5 = "1.3.1"
mesh-llm-build-info.workspace = true
mesh-llm-cli = { path = "../mesh-llm-cli", version = "0.68.0" }
mesh-llm-native-runtime = { path = "../mesh-llm-native-runtime", version = "0.68.0" }
mesh-llm-plugin-manager = { path = "../mesh-llm-plugin-manager", version = "0.68.0" }
Expand Down
2 changes: 1 addition & 1 deletion crates/mesh-llm-commands/src/benchmark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub async fn dispatch_benchmark_command(command: &BenchmarkCommand) -> Result<()
limit: *limit,
max_tokens: *max_tokens,
output: output.clone(),
user_agent_version: env!("CARGO_PKG_VERSION"),
user_agent_version: mesh_llm_build_info::BUILD_VERSION,
};
benchmark_prompts::import_prompt_corpus(args).await
}
Expand Down
2 changes: 1 addition & 1 deletion crates/mesh-llm-commands/src/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub async fn run_update(cli: &Cli) -> Result<()> {
flavor,
detect_flavor,
requested_version,
current_version: env!("CARGO_PKG_VERSION"),
current_version: mesh_llm_build_info::BUILD_VERSION,
})
.await
}
Expand Down
1 change: 1 addition & 0 deletions crates/mesh-llm-host-runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ workspace = true

[dependencies]
bytes = "1"
mesh-llm-build-info.workspace = true
mesh-mixture-of-agents = { path = "../mesh-mixture-of-agents", version = "0.68.0" }
mesh-llm-config = { path = "../mesh-llm-config", version = "0.68.0" }
mesh-llm-events = { path = "../mesh-llm-events", version = "0.68.0" }
Expand Down
4 changes: 2 additions & 2 deletions crates/mesh-llm-host-runtime/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ use crate::network::proxy;
#[cfg(test)]
use crate::runtime::wakeable::{WakeableInventoryEntry, WakeableState};

const MESH_LLM_VERSION: &str = crate::VERSION;
const MESH_LLM_BUILD_VERSION: &str = crate::BUILD_VERSION;

async fn external_inference_models(plugin_manager: &plugin::PluginManager) -> Vec<String> {
plugin_manager
Expand Down Expand Up @@ -908,7 +908,7 @@ impl MeshApi {

let mut payload = runtime_data::status_payload(runtime_data_collector.build_status_view(
runtime_data::StatusViewInput {
version: MESH_LLM_VERSION.to_string(),
version: MESH_LLM_BUILD_VERSION.to_string(),
latest_version,
node_id,
owner: node.owner_summary().await,
Expand Down
22 changes: 20 additions & 2 deletions crates/mesh-llm-host-runtime/src/api/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2620,6 +2620,21 @@ async fn status_includes_external_inference_endpoint_models() {
}
}

#[tokio::test]
async fn status_reports_local_build_version_and_independent_latest_release() {
let state = build_test_mesh_api().await;
let latest_release = "9.9.9".to_string();
{
let mut inner = state.inner.lock().await;
inner.latest_version = Some(latest_release.clone());
}

let status_body = request_management_json(state, "/api/status").await;

assert_eq!(status_body["version"], json!(crate::BUILD_VERSION));
assert_eq!(status_body["latest_version"], json!(latest_release));
}

#[tokio::test]
async fn management_mcp_endpoint_initializes_streamable_http_session() {
let state = build_test_mesh_api().await;
Expand Down Expand Up @@ -4087,7 +4102,7 @@ async fn status_payload_safety_net_adds_self_when_empty() {
instances.push(LocalInstance {
pid: std::process::id(),
api_port: Some(3131),
version: Some(MESH_LLM_VERSION.to_string()),
version: Some(MESH_LLM_BUILD_VERSION.to_string()),
started_at_unix: 0,
runtime_dir: String::new(),
is_self: true,
Expand All @@ -4098,7 +4113,10 @@ async fn status_payload_safety_net_adds_self_when_empty() {
assert!(instances[0].is_self);
assert_eq!(instances[0].pid, std::process::id());
assert_eq!(instances[0].api_port, Some(3131));
assert_eq!(instances[0].version, Some(MESH_LLM_VERSION.to_string()));
assert_eq!(
instances[0].version,
Some(MESH_LLM_BUILD_VERSION.to_string())
);
}

#[test]
Expand Down
4 changes: 3 additions & 1 deletion crates/mesh-llm-host-runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ pub use mesh::requirements::{

use anyhow::Result;

pub const VERSION: &str = env!("CARGO_PKG_VERSION");
pub const BUILD_VERSION: &str = mesh_llm_build_info::BUILD_VERSION;
pub const RELEASE_VERSION: &str = mesh_llm_build_info::RELEASE_VERSION;
pub const VERSION: &str = RELEASE_VERSION;

pub use runtime::{
MeshGuardrailMode, RuntimeOptions, RuntimeSurface, console_session_mode_for_runtime_surface,
Expand Down
2 changes: 1 addition & 1 deletion crates/mesh-llm-host-runtime/src/plugin/mcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1346,7 +1346,7 @@ impl ServerHandler for PluginMcpServer {
.build(),
)
.with_server_info(
Implementation::new("mesh-plugins", env!("CARGO_PKG_VERSION"))
Implementation::new("mesh-plugins", crate::BUILD_VERSION)
.with_title("Mesh Plugin MCP")
.with_description(
"Re-exposes mesh-llm plugins as a single MCP server with the standard MCP surface.",
Expand Down
6 changes: 3 additions & 3 deletions crates/mesh-llm-host-runtime/src/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3180,7 +3180,7 @@ fn write_runtime_owner_metadata(
let owner_meta = serde_json::json!({
"pid": std::process::id(),
"api_port": console_port,
"version": crate::VERSION,
"version": crate::BUILD_VERSION,
"started_at_unix": started_at,
"mesh_llm_binary": std::env::current_exe()
.map(|p| p.to_string_lossy().to_string())
Expand Down Expand Up @@ -3569,13 +3569,13 @@ async fn run_runtime_cli(
plugin_requested: options.plugin.is_some(),
command_is_update: options.command_is_update,
llama_flavor: options.llama_flavor,
current_version: crate::VERSION,
current_version: crate::BUILD_VERSION,
})
.await?;

// Finish the release check before startup continues.
if !checked_updates && !options.command_is_update && !options.command_uses_machine_output {
autoupdate::check_for_update(crate::VERSION).await;
autoupdate::check_for_update(crate::BUILD_VERSION).await;
}

let config = plugin::load_config(options.config.as_deref())?;
Expand Down
Loading
Loading