Skip to content

fix(observability,composio): demote direct-mode Composio 401/Invalid API key noise (Sentry TAURI-RUST-X9)#2481

Merged
senamakel merged 6 commits into
tinyhumansai:mainfrom
oxoxDev:fix/sentry-1166-composio-direct-auth-symmetry
May 23, 2026
Merged

fix(observability,composio): demote direct-mode Composio 401/Invalid API key noise (Sentry TAURI-RUST-X9)#2481
senamakel merged 6 commits into
tinyhumansai:mainfrom
oxoxDev:fix/sentry-1166-composio-direct-auth-symmetry

Conversation

@oxoxDev
Copy link
Copy Markdown
Contributor

@oxoxDev oxoxDev commented May 22, 2026

Summary

  • Restore symmetric error routing on Composio direct-mode call sites that were silently bypassing the classifier ladder.
  • Add an expected_error_kind arm for the canonical [composio-direct] … HTTP 401 / Invalid API key shape so user-supplied bad API keys land at debug instead of Sentry.
  • Closes the leak behind Sentry TAURI-RUST-X9 (15,732 events in ~22h from a single user on openhuman@0.54.0).
  • Adds 9 unit tests pinning the new classifier + the failure-tag / status-extraction contract on the canonical body.

Problem

Composio direct mode (shipped via #1825, 2026-05-15) added per-tenant list_connections / authorize / list_tools call sites on the agent-integrations path, but the direct branches did not wire their error closures through report_composio_op_error() the way the backend branches do. The classifier ladder in src/core/observability.rs::expected_error_kind was therefore never consulted for direct-mode errors, so an invalid user API key (ak_…) returned a raw 401 to the JSON-RPC layer where it captured to Sentry on every 5 s UI poll and every server-side composio::periodic tick.

Result: Sentry TAURI-RUST-X9 accumulated 15,732 events in ~22 hours from a single affected user (release openhuman@0.54.0+c25fc8e5fd3e). Bug-shape was user-config (their own key was bad), not a runtime fault — it is exactly the kind of shape the existing classifier ladder is designed to demote.

Two compounding gaps:

  1. Asymmetric reporting — direct-mode .map_err closures never called report_composio_op_error even though the backend branch in the same handler did. The classifier never had a chance to see the message.
  2. Missing matcher — even after fixing the asymmetry, expected_error_kind had no arm for the [composio-direct] … HTTP 401 / Invalid API key shape, so the message would still have classified as a real error → Sentry capture.

Solution

Three micro-commits, each independently revertible.

Commit 1 — fix(composio): restore symmetric reporting

Add report_composio_op_error(op, &e) to every direct-mode .map_err closure that was missing it, mirroring the backend branch pattern exactly:

  • src/openhuman/composio/ops.rscomposio_list_connections (direct branch), composio_authorize (direct branch), composio_list_tools prefetch + main call (direct branches). Widened report_composio_op_error from private to pub(super) so siblings (tools, periodic) can call it.
  • src/openhuman/composio/tools.rsComposioListConnectionsTool::execute direct branch (the only tool-side direct branch that issues a network call against the user's tenant).
  • src/openhuman/composio/periodic.rsrun_one_tick direct branch.

composio_delete_connection already routes through the unified resolve_client path, so the single .map_err at ops.rs:362 covers both modes; no change needed.

Commit 2 — fix(observability): new classifier arm

Add a matcher in is_provider_user_state_message (src/core/observability.rs) that recognizes the [composio-direct] caller prefix combined with one of HTTP 401 / Invalid API key. Routes to the existing ExpectedErrorKind::ProviderUserState variant (no new enum variants), which downgrades to debug log and skips Sentry.

The combined prefix anchor ([composio-direct] is unique to our own callers in src/openhuman/composio/*) keeps the matcher discriminating — unrelated 401s elsewhere in the codebase are unaffected.

Commit 3 — test: pin the contract

  • 5 new tests in src/core/observability.rs covering: canonical Sentry-body match, sibling op-name match, Invalid API key without HTTP 401, negative case (unrelated 401 stays unclassified), negative case (composio-direct 500 stays unclassified).
  • 4 new tests in src/openhuman/composio/ops_test.rs pinning the classifier + failure-tag (non_2xx) + status-extraction contract on the canonical body, plus a 500-doesn't-demote regression test.

Rejected alternatives

  • Stateful auth-state machinery that pauses the 5 s UI poll on direct-mode 401. Triples PR size and the classifier alone fully solves the Sentry-noise leak. Defer to a follow-up if poll-volume becomes the next concern.
  • Dropping the [composio-direct] log line entirely. Hurts debuggability when users report "integrations missing". Demoting to debug via the expected-kind branch is the right trade.

Submission Checklist

If a section does not apply to this change, mark the item as N/A with a one-line reason. Do not delete items.

  • Tests added or updated (happy path + at least one failure / edge case) per Testing Strategy
  • Diff coverage ≥ 80% — changed lines (Vitest + cargo-llvm-cov merged via diff-cover) meet the gate enforced by .github/workflows/coverage.yml. Run pnpm test:coverage and pnpm test:rust locally; PRs below 80% on changed lines will not merge.
  • N/A: behaviour-only change to observability classifier + symmetric error routing. No new product features in the coverage matrix.
  • N/A: no feature IDs map to this fix — observability/classifier hygiene + symmetric error routing only.
  • No new external network dependencies introduced (mock backend used per Testing Strategy)
  • N/A: this does not touch release-cut surfaces — server-side error routing + classifier ladder only.
  • N/A: Sentry-only triage (self-hosted sentry.tinyhumans.ai issue TAURI-RUST-X9); no GitHub issue to close. Sentry-Issue: header in ## Related so the post-merge resolver hook can flip it.

Impact

  • Runtime/platform: Rust core (src/openhuman/composio/*, src/core/observability.rs). No frontend / Tauri shell changes. Desktop only.
  • Performance: nil (one extra closure call per error path; never on the happy path).
  • Security: nil (no new logging surface for credentials; the log line already exists, only its level changes).
  • Migration / compat: nil (no schema, no API change, no user-visible UX change).
  • Sentry impact: eliminates the dominant tauri-rust project leak (15.7 k events / 22 h from a single user) and pre-empts the same shape from every other direct-mode call site that was bypassing the classifier.

Related

  • Closes:
  • Follow-up PR(s)/TODOs: backend branch of composio::periodic::run_one_tick also lacks the report_composio_op_error hook on its list_connections (backend) arm. Out of scope here (plan was direct-only) but worth a follow-up issue.

Sentry-Issue: TAURI-RUST-X9


AI Authored PR Metadata (required for Codex/Linear PRs)

Keep this section for AI-authored PRs. For human-only PRs, mark each field N/A.

Linear Issue

  • Key: N/A: triage driven from self-hosted Sentry (sentry.tinyhumans.ai) not Linear.
  • URL: N/A: see Sentry-Issue header above.

Commit & Branch

  • Branch: fix/sentry-1166-composio-direct-auth-symmetry
  • Commit SHA: b21d43be (tip — 3 micro-commits ahead of upstream/main@c204a53d)

Validation Run

  • N/A: no app/ changes in this PR (Rust core + observability only).
  • N/A: no TypeScript changes in this PR.
  • Focused tests: cargo test -p openhuman --lib openhuman::composio::ops (61 passed), cargo test -p openhuman --lib core::observability (84 passed), cargo test -p openhuman --lib openhuman::composio::periodic (6 passed), cargo test -p openhuman --lib openhuman::composio::tools (31 passed).
  • Rust fmt/check (if changed): cargo fmt --check clean; cargo check --manifest-path Cargo.toml clean.
  • Tauri fmt/check (if changed): cargo check --manifest-path app/src-tauri/Cargo.toml clean (no Tauri-shell changes in this PR; checked for parity).

Validation Blocked

  • command: N/A
  • error: N/A
  • impact: N/A

Behavior Changes

  • Intended behavior change: direct-mode Composio HTTP 401 / Invalid API key errors no longer reach Sentry. They surface in debug logs and the existing user-visible "not connected" UI state remains the actionable surface for the user.
  • User-visible effect: zero functional change. Settings UI continues to show direct-mode connections as not-connected when the user's API key is invalid (same as before this PR). Only Sentry stops capturing the noise.

Parity Contract

  • Legacy behavior preserved: backend-mode error routing untouched. The same report_composio_op_errorreport_error_or_expectedexpected_error_kind pipeline that the backend branch already used is now applied uniformly to the direct branch.
  • Guard/fallback/dispatch parity checks: pre-existing report_composio_op_error pinning tests at ops_test.rs:1376+ still pass. The new arm in is_provider_user_state_message reuses the existing ExpectedErrorKind::ProviderUserState variant — no enum surface change, no dispatcher branches changed.

Summary by CodeRabbit

  • Bug Fixes

    • More accurate classification of Composio direct-mode authentication failures: only messages containing the direct-mode anchor plus 401 / "Invalid API key" patterns are treated as provider-user errors, preventing unrelated 401s from being demoted.
    • Direct-mode error paths now also flow through the unified reporting/observability funnel so direct-mode failures are consistently reported.
  • Tests

    • Added tests covering direct-mode auth-rejection wire shapes, op-name and status-text variants, and negative cases to prevent regressions.

Review Change Stack

@oxoxDev oxoxDev requested a review from a team May 22, 2026 06:26
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 22, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1fba41a3-7b60-469d-839a-bd6cb2ece295

📥 Commits

Reviewing files that changed from the base of the PR and between 1936fd9 and 1060eaa.

📒 Files selected for processing (1)
  • src/openhuman/composio/tools.rs

📝 Walkthrough

Walkthrough

Composio direct-mode authentication failures marked with [composio-direct] and containing HTTP 401 or Invalid API key are classified as ProviderUserState; the composio op error reporter is exposed and invoked from direct-mode ops, periodic, and tool paths. Tests validate positive and negative message shapes.

Changes

Composio Direct-Mode Auth Observability

Layer / File(s) Summary
Direct-mode auth failure detection
src/core/observability.rs, src/openhuman/composio/ops_test.rs
is_provider_user_state_message matches [composio-direct] plus HTTP 401 or Invalid API key, returning ProviderUserState; unit tests added for canonical, variant, and negative cases.
Error reporting helper visibility
src/openhuman/composio/ops.rs
report_composio_op_error visibility changed to pub(super) so direct-mode branches can call the shared reporting path.
Direct-mode error reporting across operations
src/openhuman/composio/ops.rs, src/openhuman/composio/periodic.rs, src/openhuman/composio/tools.rs
Direct-mode error paths for list_connections, authorize, and list_tools (including prefetch), periodic tick, and the ComposioListConnections tool now render [composio-direct]-anchored messages and call report_composio_op_error before returning formatted errors.
sequenceDiagram
  participant Client as Client (direct mode)
  participant ComposioOp as composio op (list/authorize/tools)
  participant Reporter as report_composio_op_error
  participant Classifier as is_provider_user_state_message
  participant Sentry as Sentry/Observability

  Client->>ComposioOp: invoke direct operation
  ComposioOp->>Reporter: report_composio_op_error(operation, &error)
  Reporter->>Classifier: pass rendered error message for classification
  Classifier->>Sentry: classification result (e.g., ProviderUserState) forwarded
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • graycyrus

Poem

🐰 I hopped through logs with a careful glance,
Found [composio-direct] in the error dance,
Routed reports to the watcher near,
So invalid keys are clearly clear,
A little rabbit cheers—observability is here!

🚥 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 accurately summarizes the main objective: fixing observability for direct-mode Composio 401/Invalid API key errors by demoting them to avoid Sentry noise.
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 22, 2026
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 22, 2026
@oxoxDev
Copy link
Copy Markdown
Contributor Author

oxoxDev commented May 22, 2026

Heads-up to reviewers: the 3 frontend failures on this PR (Frontend Coverage, test / Frontend Unit Tests, test / i18n Coverage) are pre-existing breakage on main, not introduced by this PR.

Root cause: PR #2378 (Add German locale support, merged 2026-05-21) shipped without 20 keys that PR #2280 (feat(settings): add MCP server configuration panel, 4e5eaa71) added to English. The strict-equality assertion in src/lib/i18n/__tests__/coverage.test.ts:77 and I18nContext.test.tsx:86 fails as a result.

Verification:

This PR's own quality gates are clean:

  • cargo fmt --check, cargo check, all Rust core + tauri checks green
  • Focused tests: cargo test -p openhuman --lib openhuman::composio::ops (61 passed), core::observability (84 passed), openhuman::composio::periodic (6 passed), openhuman::composio::tools (31 passed)
  • PR Submission Checklist parser: 12/12 satisfied
  • All Rust Quality, Type Check, e2e/Linux integration, Smoke install.sh green

Happy to rebase once a German-backfill PR lands on main. Flagging in case anyone wants to pick up that fix in parallel — out of scope for this Sentry triage PR.

Sentry-Issue: TAURI-RUST-X9 (15,732 events / 22h, single user, openhuman@0.54.0)

@M3gA-Mind
Copy link
Copy Markdown
Contributor

@oxoxDev this PR has merge conflicts with main — please rebase/resolve before review.

@oxoxDev oxoxDev force-pushed the fix/sentry-1166-composio-direct-auth-symmetry branch from b21d43b to d1d8f1d Compare May 22, 2026 14:04
oxoxDev added 3 commits May 22, 2026 19:36
…ites (Sentry TAURI-RUST-X9)

Direct mode shipped via PR tinyhumansai#1825 (2026-05-15) but the mode-aware error
paths in `src/openhuman/composio/{ops,tools,periodic}.rs` only routed
the backend branch through `report_composio_op_error`. The
`ComposioClientKind::Direct` branches wrapped the inner error with
`format!("[composio-direct] … failed: {e:#}")` and skipped the
classifier hook entirely, so the dominant failure shape

    `Composio v3 connected_accounts failed: HTTP 401: Invalid API key: ak_…`

bypassed `report_error_or_expected` and leaked to Sentry on every UI
5 s poll plus every server-side `periodic.rs` tick. Sentry TAURI-RUST-X9
captured 15,732 events in ~22 h from a single user.

This commit restores symmetric error routing — each direct-mode
`.map_err` closure now calls `report_composio_op_error("<op>", &e)`
with the same op-name string the backend branch uses. The
`report_composio_op_error` helper visibility is widened from private
to `pub(super)` so `tools.rs` and `periodic.rs` can reuse it without
inlining the classifier logic.

Patch 2 (next commit) adds the matching arm to
`expected_error_kind` so the wire shape demotes to
`ProviderUserState` (info breadcrumb, no Sentry event) instead of
escaping as an unclassified error.

Files touched:
- src/openhuman/composio/ops.rs — direct branches in
  `composio_list_connections`, `composio_authorize`, and both
  `composio_list_tools` call sites (prefetch + `list_tools` itself).
  `report_composio_op_error` visibility widened to `pub(super)`.
- src/openhuman/composio/tools.rs — `ComposioListConnectionsTool::execute`
  direct branch. (The other tool `execute` direct branches either refuse
  the verb or return an empty response with no network call, so no hook
  to add.)
- src/openhuman/composio/periodic.rs — `run_one_tick` direct branch
  on the server-side scheduler.

Sentry-Issue: TAURI-RUST-X9
…as expected user-state (Sentry TAURI-RUST-X9)

Adds a new arm to `is_provider_user_state_message` that recognizes the
direct-mode composio v3 auth-rejection wire shape:

  `[composio-direct] <op> failed: Composio v3 … failed:
   HTTP 401: Invalid API key: ak_…`

The matcher is gated on a combined anchor — the `[composio-direct]`
prefix (added by ops.rs / tools.rs / periodic.rs direct branches in
the previous commit) AND one of (`HTTP 401`, `Invalid API key`). This
discriminates against backend-mode 401s (which carry the `Backend
returned 401` shape and route through the failure-tag flow with
`status="401"`) while still catching every direct-mode call site that
emits the new prefix.

The arm routes to the existing `ProviderUserState` variant — the same
bucket used for the composio toolkit-not-enabled / OAuth-scope cases
— so the wire shape demotes to an info breadcrumb via
`report_expected_message` with `kind="provider_user_state"` instead of
firing a Sentry event.

Together with the symmetric `report_composio_op_error` hooks added in
the previous commit, this closes the leak for Sentry TAURI-RUST-X9
(~15.7 k events / ~22 h on a single user with a bad direct-mode key).

Sentry-Issue: TAURI-RUST-X9
…er + ops routing

Adds five tests in `src/core/observability.rs` and four tests in
`src/openhuman/composio/ops_test.rs` that lock the
TAURI-RUST-X9 (tinyhumansai#1166) leak-fix in place.

## Observability classifier tests

- `classifies_composio_direct_invalid_api_key_as_provider_user_state`
  pins the verbatim Sentry title body
  (`[composio-direct] list_connections failed: Composio v3
  connected_accounts failed: HTTP 401: Invalid API key: ak_VsUvq*****`)
  to `Some(ProviderUserState)` so the dominant wire shape demotes to an
  info breadcrumb.
- `classifies_composio_direct_invalid_api_key_for_other_ops` covers
  the parallel direct-mode op-name prefixes (`list_tools` prefetch,
  `authorize`, `list_tools`) so a future op added to the family doesn't
  silently bypass the matcher.
- `classifies_composio_direct_with_invalid_api_key_only_no_http_401`
  pins the OR semantics of the combined anchor — body matches either
  `HTTP 401` or `Invalid API key`.
- `does_not_classify_unrelated_http_401_as_composio_direct_user_state`
  is the discrimination test: backend-mode 401 (`Backend returned 401
  …`) and unrelated provider 401s (`GitHub API error: HTTP 401`) MUST
  NOT match the new arm.
- `does_not_classify_composio_direct_500_as_user_state` pins that a
  real bug shape (500 with no auth body) still falls through to
  `None`, preserving Sentry signal for genuine backend faults.

## Composio ops tests

- `composio_direct_invalid_api_key_classifies_as_provider_user_state`
  re-asserts the classifier contract from the composio side so a future
  classifier regression surfaces in both crates.
- `composio_direct_invalid_api_key_failure_tag_is_non_2xx` pins the
  failure-tag side of the path: even if the classifier ever stops
  matching, the tag stays `non_2xx` so the `before_send` filter has a
  consistent input.
- `composio_direct_invalid_api_key_extract_status_returns_none` pins
  the contract that `extract_backend_returned_status` only parses the
  integrations-layer `Backend returned <status>` rendering, NOT the
  direct-mode `HTTP 401` shape. Documents the boundary so a future
  extension to cover both shapes comes with its own test.
- `composio_direct_500_does_not_demote` re-asserts the discrimination
  contract from the composio side.

## Spy infrastructure (deviation from plan)

The plan suggested extending an `report_composio_op_error` spy in
ops_test.rs to assert the hook was invoked on the direct branch. No
such spy infrastructure exists in the current codebase — the existing
ops_test pinning tests only exercise `classify_composio_failure_tag`
and `extract_backend_returned_status` directly. Rather than introduce
a Sentry test client + mock plumbing for this single commit, the tests
above pin the **observable contract** (`expected_error_kind` for the
canonical Sentry body + `classify_composio_failure_tag` + status
extraction) which is what the leak-fix actually changes from the
caller's perspective. The direct-branch call sites were verified by
inspection in patch 1 of tinyhumansai#1166 (every `.map_err` on the direct path
now calls `report_composio_op_error(<op>, &e)`).

Sentry-Issue: TAURI-RUST-X9
@oxoxDev oxoxDev force-pushed the fix/sentry-1166-composio-direct-auth-symmetry branch from d1d8f1d to 549a4ad Compare May 22, 2026 14:08
@oxoxDev
Copy link
Copy Markdown
Contributor Author

oxoxDev commented May 22, 2026

Rebased onto upstream/main ed3e453b (was c204a53d). Resolved one conflict in composio_authorize direct branch — upstream PR #2469 swapped direct_authorize for direct_authorize_with_meta_guard + rate-limit wrap; merged my report_composio_op_error hook onto the wrapped error so rate-limit classifications also flow through the expected-kind ladder.

New tip: 549a4add (3 GPG-signed commits). Focused tests still green post-rebase:

  • cargo test -p openhuman --lib core::observability → 86 passed
  • cargo test -p openhuman --lib openhuman::composio::ops → 62 passed

PR now MERGEABLE. The 3 frontend failures persist — confirmed pre-existing main breakage per earlier comment; main Test workflow still red on ed3e453b.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/openhuman/composio/ops.rs`:
- Around line 246-255: The report_composio_op_error calls in the direct-mode
branches are logging the original error before adding the “[composio-direct]”
anchor, so the classifier misses demotion; update each direct-mode error mapping
(the ones wrapping direct_list_connections, authorize, the direct list_tools
prefetch and the direct list_tools call) to first prepend or format the error
with the “[composio-direct]” anchor and then pass that prefixed error into
report_composio_op_error, e.g. create a prefixed_error =
format!("[composio-direct] {e:#}") (or otherwise attach the anchor) and call
report_composio_op_error("list_connections", &prefixed_error) before returning
the formatted error string; apply the same pattern to the authorize and
list_tools direct branches referenced in the comment.

In `@src/openhuman/composio/periodic.rs`:
- Around line 178-190: The periodic Direct branch (ComposioClientKind::Direct)
currently calls super::ops::report_composio_op_error with the raw error `e`,
which bypasses the composio-direct classifier; instead, build a rendered message
containing the `[composio-direct]` anchor (e.g. let msg =
format!("[composio-direct] list_connections (direct): {e:#}")), call
super::ops::report_composio_op_error("list_connections", &msg) with that string,
and then return Err(msg) (i.e. propagate the same rendered message via the
map_err return) so the periodic 401s are classified the same as UI failures;
update the direct_list_connections(direct).await.map_err closure to construct
and use that anchored message rather than passing `e` directly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: eea3e84a-6e18-472c-9876-5c17f589b4a2

📥 Commits

Reviewing files that changed from the base of the PR and between d1d8f1d and 549a4ad.

📒 Files selected for processing (5)
  • src/core/observability.rs
  • src/openhuman/composio/ops.rs
  • src/openhuman/composio/ops_test.rs
  • src/openhuman/composio/periodic.rs
  • src/openhuman/composio/tools.rs

Comment thread src/openhuman/composio/ops.rs
Comment thread src/openhuman/composio/periodic.rs
senamakel added 2 commits May 22, 2026 17:46
…e reporting

The `report_composio_op_error` hook in tinyhumansai#1166 was called with the unprefixed
inner error, so the classifier arm in `is_provider_user_state_message` that
gates on `[composio-direct]` never matched — the demotion fix only worked in
the assert-side tests, not in the live error path.

Render the full `[composio-direct] …` message FIRST, pass that to the reporter,
then return the same string. Applies to all 5 direct-mode call sites:

- ops.rs: list_connections, authorize, list_tools prefetch, list_tools
- periodic.rs: run_one_tick list_connections (direct)
- tools.rs: ComposioListConnectionsTool::execute direct branch

Addresses CodeRabbit comments r3288995437 and r3288995447 on PR tinyhumansai#2481.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/openhuman/composio/tools.rs`:
- Around line 512-519: The formatted direct-mode error string loses inner error
details because it uses "{e}" when building `rendered` in the
`composio_list_connections` failure path; change the interpolation to use the
alternate/debug display "{e:#}" so the full error chain (e.g. "HTTP 401: Invalid
API key ...") is preserved before calling
`super::ops::report_composio_op_error("list_connections", &rendered)` and
returning `anyhow::anyhow!("{rendered}")`, ensuring the reported message
includes the inner anchors expected by the observability tests.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 30b69478-d0a7-4273-8350-39f83965192b

📥 Commits

Reviewing files that changed from the base of the PR and between 549a4ad and 1936fd9.

📒 Files selected for processing (4)
  • src/openhuman/composio/ops.rs
  • src/openhuman/composio/ops_test.rs
  • src/openhuman/composio/periodic.rs
  • src/openhuman/composio/tools.rs

Comment thread src/openhuman/composio/tools.rs
…ering

Use `{e:#}` instead of `{e}` so the inner anyhow chain (carrying
`HTTP 401: Invalid API key …`) survives into the rendered message that
`report_composio_op_error` passes to the classifier. Matches the other
4 direct-mode call sites in ops.rs and periodic.rs.

Addresses CodeRabbit comment r3291771563 on PR tinyhumansai#2481.
@senamakel senamakel merged commit b087d70 into tinyhumansai:main May 23, 2026
27 of 29 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug working A PR that is being worked on by the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants