From e1ab174709b3e7d45fd4dc9ff847e0d4121b6cb2 Mon Sep 17 00:00:00 2001 From: "cyrus@tinyhumans.ai" Date: Thu, 28 May 2026 10:34:21 +0530 Subject: [PATCH] fix(inference): suppress Sentry noise when ollama model doesn't support tools Ollama models like gemma3:1b-it-qat and huihui_ai/deepseek-r1-abliterated:8b return HTTP 400 "does not support tools" when tool definitions are included in the request. The compatible provider already retries the request without tools (streaming path, compatible.rs), making the initial 400 expected capability discovery rather than a product bug. Before this fix the 400 bypassed all existing no-Sentry conditions and was reported to Sentry on every agent turn (TAURI-RUST-4K7, 14+ events). Adds the tool-unsupported phrase family to is_provider_config_rejection_message so is_provider_config_rejection_http catches and silences it in stream_native_chat before report_error is called. The retry logic in chat() runs unchanged. Closes #2787 Sentry: TAURI-RUST-4K7 --- .../inference/provider/config_rejection.rs | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/src/openhuman/inference/provider/config_rejection.rs b/src/openhuman/inference/provider/config_rejection.rs index 125edc4cc..e2a323b1d 100644 --- a/src/openhuman/inference/provider/config_rejection.rs +++ b/src/openhuman/inference/provider/config_rejection.rs @@ -30,6 +30,15 @@ //! from a user OAuth/scope gap) //! - `"not_found_error"` (J2 / J5 / J4 — litellm-compatible envelope //! `type` field carrying "model 'X' not found") +//! - `"does not support tools"` / `"function calling is not supported"` / +//! `"unknown parameter: tools"` / `"unrecognized field \`tools\`"` / +//! `"unsupported parameter: tools"` (TAURI-RUST-4K7 — Ollama models such +//! as `gemma3:1b-it-qat` and `huihui_ai/deepseek-r1-abliterated:8b` +//! reject tool-enabled requests with HTTP 400. The compatible provider +//! already retries without tools, so the initial 400 is not a +//! bug — it's expected discovery of the model's capability boundary. +//! Sentry noise suppressed here; the retry path in `compatible.rs` runs +//! unchanged.) //! //! These are **deterministic user-configuration state**, not bugs the //! maintainers can act on: the user pointed OpenHuman at a custom @@ -148,6 +157,18 @@ pub fn is_provider_config_rejection_message(body: &str) -> bool { // this is the `type` field used by litellm/Anthropic-style // envelopes for the same class of user-state error. "not_found_error", + // TAURI-RUST-4K7 — Ollama models that don't support tool calling + // (e.g. gemma3:1b-it-qat, huihui_ai/deepseek-r1-abliterated:8b) + // return HTTP 400 with one of these phrases. The compatible + // provider (`compatible.rs`) detects the error and retries + // without tools, so the 400 is expected capability-discovery + // rather than a product bug. Suppress Sentry to avoid noise from + // the first-attempt rejection that precedes the successful retry. + "does not support tools", + "function calling is not supported", + "unknown parameter: tools", + "unrecognized field `tools`", + "unsupported parameter: tools", ]; let lower = body.to_ascii_lowercase(); @@ -337,4 +358,64 @@ mod tests { ); } } + + /// TAURI-RUST-4K7 — Ollama models that don't support tool calling + /// (e.g. `gemma3:1b-it-qat`, `huihui_ai/deepseek-r1-abliterated:8b`) + /// return HTTP 400 with one of several tool-rejection phrases. + /// The compatible provider retries without tools, so the 400 is expected + /// capability-discovery rather than a product bug. These phrases must be + /// classified as config-rejections so Sentry is not flooded on every turn. + #[test] + fn detects_ollama_tool_unsupported_bodies() { + for (sentry_id, body) in [ + ( + "4K7-a", + r#"{"error":"gemma3:1b-it-qat does not support tools"}"#, + ), + ( + "4K7-b", + r#"{"error":"huihui_ai/deepseek-r1-abliterated:8b does not support tools"}"#, + ), + ( + "4K7-c", + r#"ollama streaming API error (400 Bad Request): {"error":"phi3:mini does not support tools"}"#, + ), + ( + "4K7-d", + r#"{"error":"function calling is not supported by this model"}"#, + ), + ( + "4K7-e", + r#"{"error":{"message":"unknown parameter: tools","type":"invalid_request_error"}}"#, + ), + ( + "4K7-f", + r#"{"error":"unrecognized field `tools` in request body"}"#, + ), + ( + "4K7-g", + r#"{"error":{"message":"unsupported parameter: tools","type":"invalid_request_error"}}"#, + ), + ] { + assert!( + is_provider_config_rejection_message(body), + "TAURI-RUST-{sentry_id} body must classify as provider config-rejection (tool-unsupported): {body:?}" + ); + } + } + + #[test] + fn detects_ollama_tool_unsupported_bodies_case_insensitive() { + // Ollama error messages should match regardless of casing. + for body in [ + "Model 'gemma3:1b-it-qat' DOES NOT SUPPORT TOOLS", + "Function Calling Is Not Supported By This Model", + "Unknown Parameter: Tools", + ] { + assert!( + is_provider_config_rejection_message(body), + "{body:?} must classify as config-rejection regardless of case" + ); + } + } }