test: add llamacpp model-slot consistency and content-null tests
Cover the properties that prevent mid-turn model swaps in llama-swap exclusive mode: vision_model defaults to primary, cloned local client mirrors the user-selected model, embeddings stay on their own slot. Also test the content:null serialization for tool-calling messages. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -985,4 +985,91 @@ mod tests {
|
|||||||
assert!(vision.has_vision);
|
assert!(vision.has_vision);
|
||||||
assert!(other.has_vision);
|
assert!(other.has_vision);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn vision_model_defaults_to_primary() {
|
||||||
|
let c = LlamaCppClient::new(None, Some("qwen3:32b".into()));
|
||||||
|
assert_eq!(c.primary_model, "qwen3:32b");
|
||||||
|
assert_eq!(c.vision_model, "qwen3:32b");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn vision_model_explicit_override_diverges_from_primary() {
|
||||||
|
let mut c = LlamaCppClient::new(None, Some("qwen3:32b".into()));
|
||||||
|
c.set_vision_model("minicpm-v".into());
|
||||||
|
assert_eq!(c.primary_model, "qwen3:32b");
|
||||||
|
assert_eq!(c.vision_model, "minicpm-v");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cloned_local_with_model_override_keeps_all_slots_consistent() {
|
||||||
|
// Simulates what resolve_backend does for the `local` client:
|
||||||
|
// clone the configured client, then override primary + vision
|
||||||
|
// to match the user-selected chat model. This prevents mid-turn
|
||||||
|
// model swaps in llama-swap exclusive mode.
|
||||||
|
let mut base = LlamaCppClient::new(None, Some("chat".into()));
|
||||||
|
base.set_vision_model("vision".into());
|
||||||
|
base.set_embedding_model("embed".into());
|
||||||
|
|
||||||
|
let mut local = base.clone();
|
||||||
|
let user_selected = "qwen3:32b";
|
||||||
|
local.primary_model = user_selected.to_string();
|
||||||
|
local.set_vision_model(user_selected.to_string());
|
||||||
|
|
||||||
|
// Chat generation (rerank) routes through primary_model.
|
||||||
|
assert_eq!(local.primary_model, user_selected);
|
||||||
|
// describe_image routes through vision_model.
|
||||||
|
assert_eq!(local.vision_model, user_selected);
|
||||||
|
// Embeddings stay on the dedicated slot — separate endpoint,
|
||||||
|
// no model swap conflict.
|
||||||
|
assert_eq!(local.embedding_model, "embed");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assistant_tool_calls_emit_null_content() {
|
||||||
|
let msg = ChatMessage {
|
||||||
|
role: "assistant".into(),
|
||||||
|
content: String::new(),
|
||||||
|
tool_calls: Some(vec![ToolCall {
|
||||||
|
id: Some("call_1".into()),
|
||||||
|
function: ToolCallFunction {
|
||||||
|
name: "search".into(),
|
||||||
|
arguments: json!({}),
|
||||||
|
},
|
||||||
|
}]),
|
||||||
|
images: None,
|
||||||
|
};
|
||||||
|
let wire = LlamaCppClient::messages_to_openai(&[msg]);
|
||||||
|
assert!(wire[0]["content"].is_null(), "empty content + tool_calls should emit null");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assistant_with_content_and_tool_calls_preserves_content() {
|
||||||
|
let msg = ChatMessage {
|
||||||
|
role: "assistant".into(),
|
||||||
|
content: "Let me search for that.".into(),
|
||||||
|
tool_calls: Some(vec![ToolCall {
|
||||||
|
id: Some("call_1".into()),
|
||||||
|
function: ToolCallFunction {
|
||||||
|
name: "search".into(),
|
||||||
|
arguments: json!({}),
|
||||||
|
},
|
||||||
|
}]),
|
||||||
|
images: None,
|
||||||
|
};
|
||||||
|
let wire = LlamaCppClient::messages_to_openai(&[msg]);
|
||||||
|
assert_eq!(wire[0]["content"], "Let me search for that.");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assistant_without_tool_calls_keeps_empty_string_content() {
|
||||||
|
let msg = ChatMessage {
|
||||||
|
role: "assistant".into(),
|
||||||
|
content: String::new(),
|
||||||
|
tool_calls: None,
|
||||||
|
images: None,
|
||||||
|
};
|
||||||
|
let wire = LlamaCppClient::messages_to_openai(&[msg]);
|
||||||
|
assert_eq!(wire[0]["content"], "");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user