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

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

Conversation

@CodeGhost21

@CodeGhost21 CodeGhost21 commented May 27, 2026 •

Copy link
Copy Markdown
Member

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

coderabbitai Bot commented May 27, 2026 •

Copy link
Copy Markdown
Contributor

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

@graycyrus graycyrus left a comment

Copy link
Copy Markdown
Contributor

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.

@graycyrus graycyrus left a comment

Copy link
Copy Markdown
Contributor

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

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown
Contributor

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

@M3gA-Mind M3gA-Mind left a comment

Copy link
Copy Markdown
Collaborator

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
senamakel pushed a commit to nocstah/openhuman that referenced this pull request Sep 11, 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