fix: prevent hybrid mode from leaking OpenRouter model to local llamacpp client
When backend=hybrid with LLM_BACKEND=llamacpp, the user-selected model (an OpenRouter id like "google/gemini-3-flash-preview") was being applied to the local LlamaCppClient's primary_model and vision_model. This caused describe_image to send the OpenRouter model name to llama-swap, which returned 400 because it has no such slot. Guard the local-client model override with !is_hybrid so it only applies in local-only mode (where the user is selecting a different local model). Bump to v1.2.0. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
0a627f4880
commit
b03ee60342
7 files changed
+172
-79
No files matched your search
+27
-5
@@ -409,10 +409,7 @@ impl LlmClient for LlamaCppClient {
|
||||
tools.len()
|
||||
);
|
||||
let mut body = serde_json::Map::new();
|
||||
body.insert(
|
||||
"model".into(),
|
||||
Value::String(self.primary_model.clone()),
|
||||
);
|
||||
body.insert("model".into(), Value::String(self.primary_model.clone()));
|
||||
body.insert(
|
||||
"messages".into(),
|
||||
Value::Array(Self::messages_to_openai(&messages)),
|
||||
@@ -1071,6 +1068,28 @@ mod tests {
|
||||
assert_eq!(local.embedding_model, "embed");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hybrid_mode_local_client_preserves_vision_model() {
|
||||
// In hybrid mode, overrides.model is an OpenRouter model id
|
||||
// (e.g. "google/gemini-3-flash-preview"). The local llamacpp
|
||||
// client must NOT adopt that as its vision_model — it should
|
||||
// keep the configured LLAMA_SWAP_VISION_MODEL so describe_image
|
||||
// hits the correct local slot instead of sending an unknown
|
||||
// model name to llama-swap.
|
||||
let mut base = LlamaCppClient::new(None, Some("chat".into()));
|
||||
base.set_vision_model("vision".into());
|
||||
base.set_embedding_model("embed".into());
|
||||
|
||||
// Simulate what resolve_backend SHOULD do for hybrid mode:
|
||||
// clone but do NOT override primary_model / vision_model.
|
||||
let local = base.clone();
|
||||
|
||||
// The local client keeps its configured slots.
|
||||
assert_eq!(local.primary_model, "chat");
|
||||
assert_eq!(local.vision_model, "vision");
|
||||
assert_eq!(local.embedding_model, "embed");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn assistant_tool_calls_emit_null_content() {
|
||||
let msg = ChatMessage {
|
||||
@@ -1086,7 +1105,10 @@ mod tests {
|
||||
images: None,
|
||||
};
|
||||
let wire = LlamaCppClient::messages_to_openai(&[msg]);
|
||||
assert!(wire[0]["content"].is_null(), "empty content + tool_calls should emit null");
|
||||
assert!(
|
||||
wire[0]["content"].is_null(),
|
||||
"empty content + tool_calls should emit null"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in new issue
Block a user