Skip to content

fix(observability): classify 'does not support tools' provider 400 as user-state (Sentry TAURI-RUST-35 + 10 siblings)#2796

Merged
M3gA-Mind merged 2 commits into
tinyhumansai:mainfrom
CodeGhost21:fix/sentry-tauri-rust-35-does-not-support-tools
May 28, 2026
Merged

fix(observability): classify 'does not support tools' provider 400 as user-state (Sentry TAURI-RUST-35 + 10 siblings)#2796
M3gA-Mind merged 2 commits into
tinyhumansai:mainfrom
CodeGhost21:fix/sentry-tauri-rust-35-does-not-support-tools

Conversation

@CodeGhost21
Copy link
Copy Markdown
Contributor

@CodeGhost21 CodeGhost21 commented May 27, 2026

Summary

Add "does not support tools" to is_provider_config_rejection_message's PHRASES array (src/openhuman/inference/provider/config_rejection.rs). The user picks a model that doesn't implement tool calling, the agent harness sends a tool spec anyway, and the upstream rejects with {"error":{"message":"<model id> does not support tools",...}}. Pure user-config — Sentry has no actionable path.

Why this drops 11 Sentry issues, not 1

Because the rejection message includes the literal model id, each (provider prefix × model id) combination produced a distinct Sentry fingerprint. The same root cause is currently split across 11 unresolved Sentry issues totalling ~459 events (snapshot 2026-05-28):

shortId events provider prefix
TAURI-RUST-35 307 cloud (gemma3:1b-it-qat)
TAURI-RUST-DF 83 cloud
TAURI-RUST-123 25 cloud
TAURI-RUST-4K7 19 ollama
TAURI-RUST-4FS 10 cloud
TAURI-RUST-4F6 5 cloud
TAURI-RUST-2YA 4 cloud
TAURI-RUST-4KR 3 ollama
TAURI-RUST-4KH 1 cloud
TAURI-RUST-4KY 1 ollama
TAURI-RUST-4Z0 1 ollama (deepseek-r1:8b, type=api_error)

Anchor token: the exact substring "does not support tools". It's stable across every observed wrapper shape (cloud / ollama / custom_openai × streaming API error / API error), every observed model id, and both observed type tokens (invalid_request_error and api_error — TAURI-RUST-4Z0). A single phrase covers the whole long tail and any future model that hits the same upstream rejection class.

The matcher upstream is already case-insensitive (body.to_ascii_lowercase() before substring search), so capitalisation variants are covered for free.

Tests added (provider::config_rejection::tests)

  • detects_does_not_support_tools_family — 5 verbatim wire shapes: TAURI-RUST-35 (cloud, gemma3), TAURI-RUST-4K7 (ollama prefix), the non-streaming API error sibling, a bare body without the wrapper, and TAURI-RUST-4Z0 (ollama / deepseek-r1:8b with the distinct type:"api_error" envelope — pins that the matcher never requires a specific type token).
  • does_not_classify_unrelated_tools_phrases_as_config_rejection — polarity guard pinning near-miss phrases that must STILL escalate to Sentry (real tool execution failures, generic "tools" mentions, reversed phrasing).

Test plan

  • cargo test detects_does_not_support_tools_family — passes (5 wire shapes)
  • cargo test does_not_classify_unrelated_tools_phrases — passes (polarity)
  • cargo test config_rejection — 8 tests pass, 0 regressions
  • cargo check --manifest-path Cargo.toml --bin openhuman-core — passes
  • cargo fmt --check — clean

Post-merge observation: all 11 listed Sentry issues should drop to ~0 events on releases ≥ this fix. Any new "does not support tools" event on a newer release means the matcher missed a wrapper variant — investigate the wire shape, not the model id.

Summary by CodeRabbit

  • New Features

    • Improved detection of provider configuration rejections, including recognition of common tool-capability phrasing across different provider/wrapper formats and streaming vs non-streaming flows.
  • Tests

    • Expanded positive and negative test coverage to validate correct classification and prevent false positives from unrelated or malformed "tools" mentions.

Review Change Stack

@CodeGhost21 CodeGhost21 requested a review from a team May 27, 2026 21:54
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 27, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5ecd00a6-c923-4f2c-bebc-796717bd9131

📥 Commits

Reviewing files that changed from the base of the PR and between 85cc3e6 and deb82ab.

📒 Files selected for processing (1)
  • src/openhuman/inference/provider/config_rejection.rs

📝 Walkthrough

Walkthrough

Extended is_provider_config_rejection_message to classify upstream responses containing the exact substring "does not support tools" as provider config-rejections, and added unit tests covering positive and negative tool-related message variants across wrapper shapes and providers.

Changes

Provider Config Rejection Classifier Enhancement

Layer / File(s) Summary
Tool-calling capability rejection detection
src/openhuman/inference/provider/config_rejection.rs
Added exact "does not support tools" substring match to is_provider_config_rejection_message to detect tool-calling model capability-mismatch responses.
Positive tests for TAURI-RUST-35 family
src/openhuman/inference/provider/config_rejection.rs
New unit test detects_does_not_support_tools_family validates matches across streaming, non-streaming wrappers and bare extracted bodies containing the substring.
Negative tests for unrelated/near-miss tools phrases
src/openhuman/inference/provider/config_rejection.rs
New unit test does_not_classify_unrelated_tools_phrases_as_config_rejection verifies generic mentions, near-miss phrasing, dispatch failures, malformed payload contexts, and empty body do not match.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • tinyhumansai/openhuman#2830: Updates to is_provider_config_rejection_message and test fixtures for TAURI-RUST / thinking-mode / Ollama-related message shapes.
  • tinyhumansai/openhuman#2813: Earlier change extending deterministic phrase-matching for "tools not supported" 400-body shapes with tests.
  • tinyhumansai/openhuman#2239: Related work wiring the config-rejection classifier into observability/ops handling.

Suggested labels

Sentry-traced-bug, sentry-traced-bug

Suggested reviewers

  • oxoxDev
  • M3gA-Mind

Poem

🐰 I sniffed the logs and found the clues,
"does not support tools" — no more confused news,
Tests hop in for wrappers and bare,
Near-miss phrases get left in the air,
Hooray — mismatch messages handled with care!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding classification for 'does not support tools' provider errors as user-state signals for observability/Sentry issue tracking.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot added working A PR that is being worked on by the team. bug labels May 28, 2026
@CodeGhost21 CodeGhost21 changed the title fix(observability): classify 'does not support tools' provider 400 as user-state (Sentry TAURI-RUST-35 + 9 siblings) fix(observability): classify 'does not support tools' provider 400 as user-state (Sentry TAURI-RUST-35 + 10 siblings) May 28, 2026
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 28, 2026
graycyrus
graycyrus previously approved these changes May 28, 2026
Copy link
Copy Markdown
Contributor

@graycyrus graycyrus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean fix. Single additive change to the PHRASES array in is_provider_config_rejection_message — the anchor phrase "does not support tools" is stable across every observed provider prefix (cloud / ollama / custom_openai), wrapper shape (streaming / non-streaming), and type token (invalid_request_error / api_error). The existing body.to_ascii_lowercase() call means capitalisation variants are free.

Test coverage is thorough: 5 verbatim wire shapes pin each meaningful variant, and the polarity guard correctly rejects near-miss phrases that must still reach Sentry. The diff-cover gate passed, all Rust core tests green, fmt + clippy clean.

Breaking risk is zero — purely additive. No API, type, or schema changes. The 11 Sentry issues (~459 events) should drain to zero on the next release.

@graycyrus graycyrus dismissed their stale review May 28, 2026 05:19

Auto-corrected: reviewer policy requires COMMENT state, not APPROVE. Clean PR moved to manual approval queue.

Copy link
Copy Markdown
Contributor

@graycyrus graycyrus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean fix. Single additive change to the PHRASES array in is_provider_config_rejection_message — the anchor phrase "does not support tools" is stable across every observed provider prefix (cloud / ollama / custom_openai), wrapper shape (streaming / non-streaming), and type token (invalid_request_error / api_error). The existing body.to_ascii_lowercase() call means capitalisation variants are free.

Test coverage is thorough: 5 verbatim wire shapes pin each meaningful variant, and the polarity guard correctly rejects near-miss phrases that must still reach Sentry. The diff-cover gate passed, all Rust core tests green, fmt + clippy clean.

Breaking risk is zero — purely additive. No API, type, or schema changes. The 11 Sentry issues (~459 events) should drain to zero on the next release.

✅ Ready for approval.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 28, 2026

Actionable comments posted: 0

coderabbitai[bot]
coderabbitai Bot previously approved these changes May 28, 2026
@oxoxDev oxoxDev self-requested a review May 28, 2026 18:08
… user-state (Sentry TAURI-RUST-35 + 9 siblings)

Add `"does not support tools"` to the `is_provider_config_rejection_message`
PHRASES array. The user picks a model that doesn't implement tool calling
(e.g. `gemma3:1b-it-qat`, `qwen2.5:0.5b`, `phi3.5:mini`), the agent
harness sends a tool spec anyway, and the upstream rejects with
`{"error":{"message":"<model id> does not support tools",
"type":"invalid_request_error",…}}`. Pure user-config error — the
remediation is "pick a tool-capable model in Settings → AI → LLM";
Sentry has no actionable path.

One body substring drops the entire long-tail family. Because the error
includes the model id, each distinct (provider prefix × model id) combo
produced its own Sentry fingerprint — currently 10 unresolved sibling
issues totaling ~458 events on the latest production release as of
2026-05-28:

| shortId         | events | provider |
|-----------------|--------|----------|
| TAURI-RUST-35   | 307    | cloud    |
| TAURI-RUST-DF   | 83     | cloud    |
| TAURI-RUST-123  | 25     | cloud    |
| TAURI-RUST-4K7  | 19     | ollama   |
| TAURI-RUST-4FS  | 10     | cloud    |
| TAURI-RUST-4F6  | 5      | cloud    |
| TAURI-RUST-2YA  | 4      | cloud    |
| TAURI-RUST-4KR  | 3      | ollama   |
| TAURI-RUST-4KH  | 1      | cloud    |
| TAURI-RUST-4KY  | 1      | ollama   |

The anchor is the exact `"does not support tools"` substring — stable
across all observed wrapper shapes (`cloud` / `ollama` / `custom_openai`
× `streaming API error` / `API error`) and across all observed model
ids. The matcher is already case-insensitive (`body.to_ascii_lowercase()`
upstream), so capitalisation variants are covered for free.

Tests added in `provider::config_rejection::tests`:
- `detects_does_not_support_tools_family` — verbatim TAURI-RUST-35 wire
  shape (cloud + ollama prefix + non-streaming sibling + bare body
  variants).
- `does_not_classify_unrelated_tools_phrases_as_config_rejection` —
  polarity guard pinning near-miss phrases that must STILL escalate
  (real tool execution failures, generic "tools" mentions, reversed
  phrasing).

- [x] `cargo test detects_does_not_support_tools_family` — passes (4 wire shapes)
- [x] `cargo test does_not_classify_unrelated_tools_phrases` — passes (polarity)
- [x] `cargo test config_rejection` — 8 tests pass, 0 regressions
- [x] `cargo check --bin openhuman-core` — passes
- [x] `cargo fmt --check` — clean
…or does-not-support-tools

Sentry issue 5664 (TAURI-RUST-4Z0, ollama/deepseek-r1:8b) is the 11th
fingerprint of the same "does not support tools" root cause this PR
classifies. Its envelope carries `"type":"api_error"` rather than the
`"invalid_request_error"` seen in the other siblings — add it as a test
case so the matcher can never be narrowed to require a specific `type`
token. The `"does not support tools"` body substring stays the only
anchor.

No production code change — the existing PHRASES entry already matches
this body (verified). Test-only strengthening.
@M3gA-Mind M3gA-Mind force-pushed the fix/sentry-tauri-rust-35-does-not-support-tools branch from 85cc3e6 to deb82ab Compare May 28, 2026 19:25
Copy link
Copy Markdown
Contributor

@M3gA-Mind M3gA-Mind left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR #2796 — fix(observability): classify 'does not support tools' provider 400 as user-state

Walkthrough

Clean, single-phrase addition to is_provider_config_rejection_message. The anchor "does not support tools" covers all 11 Sentry issues in the family (cloud / ollama / custom_openai prefixes, streaming / non-streaming, invalid_request_error / api_error type tokens) with one string. Case-insensitive match already in place.

Changes

File Summary
src/openhuman/inference/provider/config_rejection.rs Add "does not support tools" phrase; 2 new tests

Verified / looks good

  • Phrase placed at end of PHRASES array with clear comment linking the 10 sibling Sentry issues.
  • detects_does_not_support_tools_family: 5 verbatim wire shapes — cloud/ollama prefixes, streaming/non-streaming, bare body, and TAURI-RUST-4Z0's distinct type:"api_error" envelope (pinning that the matcher doesn't require a specific type token).
  • does_not_classify_unrelated_tools_phrases_as_config_rejection: polarity contract covers tool-execution failure, generic "tools" mention, reversed phrasing, and empty body.
  • Merge conflict resolved (PR #2809's detects_insufficient_balance_402_family test was added to the same area concurrently — both tests preserved).
  • All CI checks passed (30/30).

@M3gA-Mind M3gA-Mind merged commit 7704836 into tinyhumansai:main May 28, 2026
30 of 57 checks passed
@coderabbitai coderabbitai Bot added the sentry-traced-bug Bug identified via Sentry triage label May 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug sentry-traced-bug Bug identified via Sentry triage working A PR that is being worked on by the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants