feat: add MBE health check proxy endpoint

- Added /api/v1/mbe/health proxy in Studio proxy (port 8888)
- Frontend now uses proxy endpoint instead of direct mbeUrl
- Works for both localhost and external access (once proxy is deployed)
- MBE health response: {status: 'healthy', model: 'e4b', layers: 42}
This commit is contained in:
2026-10-22 23:52:23 +08:00
parent a429aca344
commit 951a2964f3
6 changed files with 23 additions and 4 deletions

Binary file not shown.

Binary file not shown.

1
src-tauri/Cargo.lock generated
View File

@@ -3766,6 +3766,7 @@ dependencies = [
"ctr 0.9.2", "ctr 0.9.2",
"dashmap", "dashmap",
"dav-server", "dav-server",
"dirs 5.0.1",
"ed25519-dalek 2.2.0", "ed25519-dalek 2.2.0",
"env_logger", "env_logger",
"filetime", "filetime",

View File

@@ -263,6 +263,24 @@ async fn fallback_handler(State(state): State<ProxyState>, req: axum::extract::R
return handle_local_api(req).await; return handle_local_api(req).await;
} }
// Handle MBE health check proxy
if path == "/api/v1/mbe/health" {
let client = reqwest::Client::new();
match client.get("http://localhost:8080/health").send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let body = resp.bytes().await.unwrap_or_default();
let status_code = axum::http::StatusCode::from_u16(status).unwrap_or(axum::http::StatusCode::INTERNAL_SERVER_ERROR);
let mut builder = axum::http::Response::builder().status(status_code);
builder = builder.header("content-type", "application/json");
return builder.body(axum::body::Body::from(body)).unwrap().into_response();
}
Err(_) => {
return (StatusCode::SERVICE_UNAVAILABLE, "{\"status\":\"unreachable\"}").into_response();
}
}
}
if path.starts_with("/api/v2/") { if path.starts_with("/api/v2/") {
return proxy_to(state, req, MARKBASE_API, false).await; return proxy_to(state, req, MARKBASE_API, false).await;
} else if path.starts_with("/api/") { } else if path.starts_with("/api/") {

View File

@@ -1 +1 @@
{"rustc_fingerprint":18311546023473579713,"outputs":{"17747080675513052775":{"success":true,"status":"","code":0,"stdout":"rustc 1.95.0 (59807616e 2026-04-14)\nbinary: rustc\ncommit-hash: 59807616e1fa2540724bfbac14d7976d7e4a3860\ncommit-date: 2026-04-14\nhost: aarch64-apple-darwin\nrelease: 1.95.0\nLLVM version: 22.1.2\n","stderr":""},"7971740275564407648":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.dylib\nlib___.dylib\nlib___.a\nlib___.dylib\n/Users/accusys/.rustup/toolchains/stable-aarch64-apple-darwin\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"aarch64\"\ntarget_endian=\"little\"\ntarget_env=\"\"\ntarget_family=\"unix\"\ntarget_feature=\"aes\"\ntarget_feature=\"crc\"\ntarget_feature=\"dit\"\ntarget_feature=\"dotprod\"\ntarget_feature=\"dpb\"\ntarget_feature=\"dpb2\"\ntarget_feature=\"fcma\"\ntarget_feature=\"fhm\"\ntarget_feature=\"flagm\"\ntarget_feature=\"fp16\"\ntarget_feature=\"frintts\"\ntarget_feature=\"jsconv\"\ntarget_feature=\"lor\"\ntarget_feature=\"lse\"\ntarget_feature=\"neon\"\ntarget_feature=\"paca\"\ntarget_feature=\"pacg\"\ntarget_feature=\"pan\"\ntarget_feature=\"pmuv3\"\ntarget_feature=\"ras\"\ntarget_feature=\"rcpc\"\ntarget_feature=\"rcpc2\"\ntarget_feature=\"rdm\"\ntarget_feature=\"sb\"\ntarget_feature=\"sha2\"\ntarget_feature=\"sha3\"\ntarget_feature=\"ssbs\"\ntarget_feature=\"vh\"\ntarget_has_atomic=\"128\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"macos\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"apple\"\nunix\n","stderr":""}},"successes":{}} {"rustc_fingerprint":12687021790548862218,"outputs":{"16541490229894744394":{"success":true,"status":"","code":0,"stdout":"rustc 1.99.0 (b940084d7 2026-09-28)\nbinary: rustc\ncommit-hash: b940084d7eb6a299eb4bfeb8e34901bc051e7ac4\ncommit-date: 2026-09-28\nhost: aarch64-apple-darwin\nrelease: 1.99.0\nLLVM version: 23.1.1\n","stderr":""},"7971740275564407648":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.dylib\nlib___.dylib\nlib___.a\nlib___.dylib\n/Users/accusys/.rustup/toolchains/stable-aarch64-apple-darwin\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"aarch64\"\ntarget_endian=\"little\"\ntarget_env=\"\"\ntarget_family=\"unix\"\ntarget_feature=\"aes\"\ntarget_feature=\"crc\"\ntarget_feature=\"dit\"\ntarget_feature=\"dotprod\"\ntarget_feature=\"dpb\"\ntarget_feature=\"dpb2\"\ntarget_feature=\"fcma\"\ntarget_feature=\"fhm\"\ntarget_feature=\"flagm\"\ntarget_feature=\"fp16\"\ntarget_feature=\"frintts\"\ntarget_feature=\"jsconv\"\ntarget_feature=\"lor\"\ntarget_feature=\"lse\"\ntarget_feature=\"neon\"\ntarget_feature=\"paca\"\ntarget_feature=\"pacg\"\ntarget_feature=\"pan\"\ntarget_feature=\"pmuv3\"\ntarget_feature=\"ras\"\ntarget_feature=\"rcpc\"\ntarget_feature=\"rcpc2\"\ntarget_feature=\"rdm\"\ntarget_feature=\"sb\"\ntarget_feature=\"sha2\"\ntarget_feature=\"sha3\"\ntarget_feature=\"ssbs\"\ntarget_feature=\"vh\"\ntarget_has_atomic=\"128\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_has_atomic_primitive_alignment=\"128\"\ntarget_has_atomic_primitive_alignment=\"16\"\ntarget_has_atomic_primitive_alignment=\"32\"\ntarget_has_atomic_primitive_alignment=\"64\"\ntarget_has_atomic_primitive_alignment=\"8\"\ntarget_has_atomic_primitive_alignment=\"ptr\"\ntarget_os=\"macos\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"apple\"\nunix\n","stderr":""}},"successes":{}}

View File

@@ -879,9 +879,9 @@ async function testMbe() {
testingMbe.value = true testingMbe.value = true
mbeInfo.value = null mbeInfo.value = null
try { try {
// MarkBaseServer only exposes /health (returns plain text "OK") // Use Studio proxy to reach MBE (works both locally and remotely)
// Always use /health regardless of hostname const base = getApiBase()
const healthUrl = `${mbeUrl.value.replace(/\/$/, '')}/health` const healthUrl = `${base.replace(/\/$/, '')}/api/v1/mbe/health`
const resp = await fetch(healthUrl, { signal: AbortSignal.timeout(5000) }) const resp = await fetch(healthUrl, { signal: AbortSignal.timeout(5000) })
if (!resp.ok) throw new Error(`HTTP ${resp.status}`) if (!resp.ok) throw new Error(`HTTP ${resp.status}`)