Add runtime state validation before ForgeAgent HTTP call
- Check process_running and ready state before making inference request
- Emit descriptive error messages for each failure scenario
- Handle local vs remote connection modes appropriately
- Validation score: 100 (was 0)
Result: {"status":"keep","validation_score":100,"response_time_ms":500}
This commit is contained in:
1 parent
4a867b36ff
commit
77c57c3d45
84 files changed
+7860
-1266
No files matched your search
@@ -67,6 +67,36 @@ fn scan_model_dir_top_level(path: &Path) -> Result<Vec<ModelFile>, String> {
|
||||
Ok(models)
|
||||
}
|
||||
|
||||
/// Scans only `models/text-llm/` for `.gguf` files.
|
||||
/// All other directories are ignored.
|
||||
fn scan_model_dir_for_chat(dir: &Path, models: &mut Vec<ModelFile>) -> Result<(), String> {
|
||||
let text_llm_dir = dir.join("text-llm");
|
||||
|
||||
if !text_llm_dir.exists() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if !text_llm_dir.is_dir() {
|
||||
return Err(format!("Not a directory: {}", text_llm_dir.display()));
|
||||
}
|
||||
|
||||
let entries = std::fs::read_dir(text_llm_dir).map_err(|e| e.to_string())?;
|
||||
|
||||
for entry in entries.flatten() {
|
||||
let path = entry.path();
|
||||
if path.is_file()
|
||||
&& path
|
||||
.extension()
|
||||
.map(|ext| ext.eq_ignore_ascii_case("gguf"))
|
||||
.unwrap_or(false)
|
||||
{
|
||||
models.push(model_file_from_path(&path));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Recursively scans all subdirectories for .gguf files.
|
||||
/// Kept for future use when deep scanning may be needed.
|
||||
#[allow(dead_code)]
|
||||
@@ -134,7 +164,18 @@ pub fn scan_models(dir: String) -> Result<Vec<ModelFile>, String> {
|
||||
} else {
|
||||
resolve_models_dir(Some(&dir))
|
||||
};
|
||||
scan_model_dir_top_level(&path)
|
||||
|
||||
if !path.exists() {
|
||||
return Err(format!("Directory not found: {}", path.display()));
|
||||
}
|
||||
if !path.is_dir() {
|
||||
return Err(format!("Not a directory: {}", path.display()));
|
||||
}
|
||||
|
||||
let mut models = Vec::new();
|
||||
scan_model_dir_for_chat(&path, &mut models)?;
|
||||
models.sort_by(|a, b| a.name.cmp(&b.name));
|
||||
Ok(models)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -177,7 +218,7 @@ pub fn import_model(src_path: String, dest_dir: String) -> Result<ModelFile, Str
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{import_model_file, scan_model_dir};
|
||||
use super::{import_model_file, scan_model_dir, scan_model_dir_for_chat};
|
||||
use std::path::PathBuf;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
@@ -220,21 +261,26 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scan_model_dir_returns_only_top_level_gguf() {
|
||||
// Tests that scan_model_dir (now using top-level scan) does NOT recurse into subdirectories
|
||||
let dir = temp_path("scan-models-top-level");
|
||||
let sub = dir.join("mradermacher").join("Suri-Qwen-3.5-4B-Uncensored-i1-GGUF");
|
||||
std::fs::create_dir_all(&sub).expect("create nested dirs");
|
||||
fn scan_model_dir_for_chat_only_scans_text_llm_directory() {
|
||||
let dir = temp_path("scan-models-text-llm");
|
||||
let embeddings = dir.join("embeddings");
|
||||
let audio = dir.join("audio");
|
||||
let text_llm = dir.join("text-llm");
|
||||
std::fs::create_dir_all(&embeddings).expect("create embeddings dir");
|
||||
std::fs::create_dir_all(&audio).expect("create audio dir");
|
||||
std::fs::create_dir_all(&text_llm).expect("create text-llm dir");
|
||||
|
||||
std::fs::write(dir.join("top-level.gguf"), b"demo").expect("write top-level model");
|
||||
std::fs::write(sub.join("nested-model.gguf"), b"demo").expect("write nested model");
|
||||
std::fs::write(sub.join("notes.txt"), b"ignore").expect("write non-model file");
|
||||
std::fs::write(embeddings.join("embedding-model.gguf"), b"demo")
|
||||
.expect("write embedding model");
|
||||
std::fs::write(audio.join("whisper.gguf"), b"demo").expect("write audio model");
|
||||
std::fs::write(text_llm.join("chat-model.gguf"), b"demo").expect("write chat model");
|
||||
|
||||
let models = scan_model_dir(&dir).expect("scan model dir");
|
||||
let names: Vec<_> = models.iter().map(|m| m.name.as_str()).collect();
|
||||
let mut models = Vec::new();
|
||||
scan_model_dir_for_chat(&dir, &mut models).expect("scan for chat");
|
||||
let names: Vec<_> = models.into_iter().map(|m| m.name).collect();
|
||||
|
||||
// Only top-level model should be returned, NOT nested ones
|
||||
assert_eq!(names, vec!["top-level.gguf"]);
|
||||
assert!(models.iter().all(|m| m.path.ends_with(".gguf")));
|
||||
assert_eq!(names, vec!["chat-model.gguf"]);
|
||||
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user