Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
15 changes: 15 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 @@ -26,6 +26,8 @@ members = [
"crates/mesh-llm-plugin",
"crates/mesh-llm-skills",
"crates/mesh-llm-plugin-manager",
"crates/mesh-native-serving-plugin-api",
"crates/mesh-native-serving-plugin-host",
"crates/mesh-client",
"crates/mesh-llm-api-client",
"crates/mesh-llm-api-server",
Expand Down
48 changes: 48 additions & 0 deletions crates/mesh-llm-cli/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,4 +138,52 @@ mod tests {
Some(std::path::PathBuf::from("topology.json"))
);
}

#[test]
fn native_serving_plugin_requires_the_complete_local_model_contract() {
let error = Cli::try_parse_from([
"mesh-llm",
"--local-model-only",
"--native-serving-plugin",
"/plugins/cacheline.dylib",
])
.expect_err("partial native serving plugin configuration should fail");
assert!(error.to_string().contains("native-serving-plugin-config"));

let cli = Cli::try_parse_from([
"mesh-llm",
"--local-model-only",
"--native-serving-plugin",
"/plugins/cacheline.dylib",
"--native-serving-plugin-config",
"/config/cacheline.toml",
"--native-serving-plugin-state",
"/state/cacheline",
"--native-serving-plugin-deadline-ms",
"4",
])
.expect("complete native serving plugin configuration should parse");
assert_eq!(
cli.native_serving_plugin,
Some(std::path::PathBuf::from("/plugins/cacheline.dylib"))
);
assert_eq!(cli.native_serving_plugin_deadline_ms, Some(4));
}

#[test]
fn native_serving_plugin_is_rejected_outside_local_model_serving() {
let error = Cli::try_parse_from([
"mesh-llm",
"--native-serving-plugin",
"/plugins/cacheline.dylib",
"--native-serving-plugin-config",
"/config/cacheline.toml",
"--native-serving-plugin-state",
"/state/cacheline",
"--native-serving-plugin-deadline-ms",
"4",
])
.expect_err("native serving plugins should require local-model serving");
assert!(error.to_string().contains("local-model-only"));
}
}
25 changes: 25 additions & 0 deletions crates/mesh-llm-cli/src/parser/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,31 @@ pub struct Cli {
#[arg(long)]
pub local_model_only: bool,

/// Load a native serving plugin into the dedicated local-model path.
#[arg(
long,
hide = true,
requires = "local_model_only",
requires_all = [
"native_serving_plugin_config",
"native_serving_plugin_state",
"native_serving_plugin_deadline_ms"
]
)]
pub native_serving_plugin: Option<PathBuf>,

/// Absolute path to the native serving plugin configuration.
#[arg(long, hide = true, requires = "native_serving_plugin")]
pub native_serving_plugin_config: Option<PathBuf>,

/// Absolute path to the native serving plugin state directory.
#[arg(long, hide = true, requires = "native_serving_plugin")]
pub native_serving_plugin_state: Option<PathBuf>,

/// Mesh-enforced hard proposal deadline in milliseconds.
#[arg(long, hide = true, requires = "native_serving_plugin")]
pub native_serving_plugin_deadline_ms: Option<u64>,

/// Run as a client — no GPU, no model needed.
#[arg(long)]
pub client: bool,
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 @@ -33,6 +33,7 @@ mesh-llm-plugin = { path = "../mesh-llm-plugin", version = "0.72.1" }
mesh-llm-plugin-manager = { path = "../mesh-llm-plugin-manager", version = "0.72.1" }
mesh-llm-identity = { path = "../mesh-llm-identity", version = "0.72.1", features = ["host-io"] }
mesh-llm-native-runtime = { path = "../mesh-llm-native-runtime", version = "0.72.1" }
mesh-native-serving-plugin-host = { path = "../mesh-native-serving-plugin-host", version = "0.72.1" }
mesh-llm-runtime-install = { path = "../mesh-llm-runtime-install", version = "0.72.1" }
mesh-llm-guardrails = { path = "../mesh-llm-guardrails", version = "0.72.1" }
mesh-llm-protocol = { path = "../mesh-llm-protocol", version = "0.72.1" }
Expand Down
3 changes: 1 addition & 2 deletions crates/mesh-llm-host-runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub mod proto {
pub use mesh_llm_protocol::proto::*;
}

use anyhow::Result;
pub use crypto::{
ReleaseAttestationClaims, ReleaseAttestationStatus, ReleaseAttestationSummary,
ReleaseBuildAttestation, ReleaseSignerTrustStore, TrustedReleaseSigner,
Expand All @@ -38,8 +39,6 @@ pub use mesh::requirements::{
ReleaseAttestationRequirement, SignedBootstrapToken, SignedMeshGenesisPolicy,
};
pub use skippy_server::{ModelServingHooks, ModelServingHooksFactory};

use anyhow::Result;
use std::path::Path;

pub const BUILD_VERSION: &str = mesh_llm_build_info::BUILD_VERSION;
Expand Down
52 changes: 51 additions & 1 deletion crates/mesh-llm-host-runtime/src/runtime/local_model_only.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use crate::system::hardware;
use anyhow::{Context, Result};
use mesh_llm_events::{OutputEvent, emit_event};
use skippy_server::EmbeddedState;
use skippy_server::SharedModelServingHooksFactory;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::time::Duration;

Expand Down Expand Up @@ -84,11 +85,30 @@ pub(super) fn validate_local_model_only_options(options: &RuntimeOptions) -> Res
"--max-vram must be a finite positive number"
);
}
match options.native_serving_plugin.as_ref() {
Some(_) => {
anyhow::ensure!(
options.native_serving_plugin_config.is_some()
&& options.native_serving_plugin_state.is_some()
&& options.native_serving_plugin_deadline_ms.is_some(),
"--native-serving-plugin requires config, state, and deadline options"
);
}
None => {
anyhow::ensure!(
options.native_serving_plugin_config.is_none()
&& options.native_serving_plugin_state.is_none()
&& options.native_serving_plugin_deadline_ms.is_none(),
"native serving plugin config, state, and deadline require --native-serving-plugin"
);
}
}
Ok(())
}

pub(super) async fn run_local_model_only(mut options: RuntimeOptions) -> Result<()> {
validate_local_model_only_options(&options)?;
let serving_hooks_factory = native_serving_plugin_factory(&options)?;
let mut config = plugin::load_config(options.config.as_deref())?;
apply_runtime_cli_speculative_overrides(&mut config, options.speculative_overrides.as_ref());
apply_runtime_config_options(&mut options, &config);
Expand Down Expand Up @@ -159,7 +179,7 @@ pub(super) async fn run_local_model_only(mut options: RuntimeOptions) -> Result<
skippy_telemetry: skippy_telemetry_options(&options),
survey_telemetry: survey::SurveyTelemetry::disabled(),
hook_policy: None,
serving_hooks_factory: None,
serving_hooks_factory,
http_bind_addr: bind_addr,
};

Expand All @@ -168,6 +188,36 @@ pub(super) async fn run_local_model_only(mut options: RuntimeOptions) -> Result<
result
}

fn native_serving_plugin_factory(
options: &RuntimeOptions,
) -> Result<Option<SharedModelServingHooksFactory>> {
let Some(library_path) = options.native_serving_plugin.as_deref() else {
return Ok(None);
};
let config_path = options
.native_serving_plugin_config
.clone()
.context("--native-serving-plugin-config is required")?;
let state_directory = options
.native_serving_plugin_state
.clone()
.context("--native-serving-plugin-state is required")?;
let deadline_ms = options
.native_serving_plugin_deadline_ms
.context("--native-serving-plugin-deadline-ms is required")?;
anyhow::ensure!(
deadline_ms > 0,
"--native-serving-plugin-deadline-ms must be greater than zero"
);
let factory = mesh_native_serving_plugin_host::NativeServingPluginFactory::load(
library_path,
config_path,
state_directory,
Duration::from_millis(deadline_ms),
)?;
Ok(Some(std::sync::Arc::new(factory)))
}

fn local_capacity_bytes(
options: &RuntimeOptions,
pinned_gpu: Option<&super::StartupPinnedGpuTarget>,
Expand Down
8 changes: 8 additions & 0 deletions crates/mesh-llm-host-runtime/src/runtime/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ pub struct RuntimeOptions {
pub mmproj: Option<PathBuf>,
pub port: u16,
pub local_model_only: bool,
pub native_serving_plugin: Option<PathBuf>,
pub native_serving_plugin_config: Option<PathBuf>,
pub native_serving_plugin_state: Option<PathBuf>,
pub native_serving_plugin_deadline_ms: Option<u64>,
pub client: bool,
pub console: u16,
pub headless: bool,
Expand Down Expand Up @@ -105,6 +109,10 @@ impl Default for RuntimeOptions {
mmproj: None,
port: 9337,
local_model_only: false,
native_serving_plugin: None,
native_serving_plugin_config: None,
native_serving_plugin_state: None,
native_serving_plugin_deadline_ms: None,
client: false,
console: 3131,
headless: false,
Expand Down
4 changes: 4 additions & 0 deletions crates/mesh-llm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@ fn runtime_options_from_cli(cli: mesh_llm_cli::Cli) -> mesh_llm_host_runtime::Ru
mmproj: cli.mmproj,
port: cli.port,
local_model_only: cli.local_model_only,
native_serving_plugin: cli.native_serving_plugin,
native_serving_plugin_config: cli.native_serving_plugin_config,
native_serving_plugin_state: cli.native_serving_plugin_state,
native_serving_plugin_deadline_ms: cli.native_serving_plugin_deadline_ms,
client: cli.client,
console: cli.console,
headless: cli.headless,
Expand Down
12 changes: 12 additions & 0 deletions crates/mesh-native-serving-plugin-api/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "mesh-native-serving-plugin-api"
version.workspace = true
edition.workspace = true
license.workspace = true
description = "Stable native serving-plugin ABI for Mesh Skippy lifecycle and proposals"
repository = "https://github.com/Mesh-LLM/mesh-llm"
homepage = "https://github.com/Mesh-LLM/mesh-llm"
readme = "README.md"

[lints]
workspace = true
11 changes: 11 additions & 0 deletions crates/mesh-native-serving-plugin-api/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Mesh native serving plugin API

This crate defines Mesh's versioned C-compatible ABI for native plugins that
observe Skippy generation lifecycle events and supply speculative proposals.
Mesh owns model execution, tokenization, verification, and the absolute
proposal deadline. Plugins exchange only fixed-layout values, borrowed slices,
opaque handles, and host-owned output buffers across the dynamic-library
boundary.

The ABI deliberately has no fixed proposal-token limit. Each query carries the
capacity Skippy can verify at that exact decode position.
Loading
Loading