Skip to content

fix(memory-sources): hide inactive Composio connections in sources list - #3413

Merged
senamakel merged 5 commits into
tinyhumansai:mainfrom
sanil-23:fix/memory-sources-hide-inactive-connections
Jun 7, 2026
Merged

senamakel merged 5 commits into
tinyhumansai:mainfrom
sanil-23:fix/memory-sources-hide-inactive-connections

Conversation

@sanil-23

@sanil-23 sanil-23 commented Jun 5, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • The Memory sources list showed multiple rows per provider (e.g. several "Gmail") even when only one connection was active.
  • Filters the sources listing to the live active-connection set and dedupes by connection_id, reusing the Composio scan list_rpc already runs every 5s poll.
  • Display-layer only, non-destructive: no row, setting, or ingested memory is removed; an inactive connection's row reappears on its own once it re-activates. Explicit Disconnect remains the only removal path.
  • On a failed/unavailable scan the list passes through untouched — a transient outage never hides every source.

Problem

Composio memory sources are keyed by connection_id. Two independent mechanisms produced duplicate rows:

  • RC-A (primary): the registry keeps one row per connection and the list returned every row status-blind. Re-auth / token expiry / reconnect mints a new connection_id, so the old (now-inactive) connection's row lingers — "multiple Gmail rows, only one active." The reconciler only ever upserts; nothing prunes a connection that dropped out of the active set.
  • RC-B (secondary): list_rpc reconciles on every poll and upsert_composio_source is a non-atomic read-check-write, so two overlapping polls can double-insert the same connection_id.

Solution

  • reconcile::ensure_composio_sources now returns the active connection_id set it scans (Some(set) on success, None when the scan couldn't run — config / network / auth failure).
  • list_rpc feeds that set to a new pure helper filter_to_active_composio_sources:
    • Composio sources kept only if their connection_id is in the active set (hides RC-A stragglers), first occurrence per id (collapses RC-B duplicates).
    • Non-Composio sources (folder / git / …) always shown.
    • None ⇒ pass-through — never hide everything on a transient scan failure.
  • No change to removal semantics or to time-to-appear for new connections: the live scan still runs inline in list_rpc, so a just-connected integration still shows within one poll. The filter only subtracts inactive/duplicate rows — no added network cost.

Submission Checklist

  • Tests added or updated (happy path + failure / edge case) — 6 unit tests over the pure filter + 2 JSON-RPC E2E tests (active-filter path and scan-unavailable fallback) driving a mock Composio /connected_accounts endpoint.
  • Diff coverage ≥ 80% — every changed production line is exercised except one (reconcile.rs return None on a config-load failure, impractical to unit-test); ~16/17 measured changed lines ≈ 94%.
  • Coverage matrix updated — N/A: bug fix to existing memory-sources list behaviour; no feature row added/removed/renamed.
  • All affected feature IDs listed under ## Related — N/A: behaviour-only fix.
  • No new external network dependencies — mock Composio endpoint used in-test per mock policy.
  • Manual smoke checklist — N/A: does not touch a release-cut surface.
  • N/A: Linked issue closed — no tracking issue filed for this report.

Impact

  • Desktop (Memory → Sources registry). The only UI affected is MemorySourcesRegistry.tsx, driven solely by memory_sources_list; the status_list poll only supplies per-row stats and never adds rows. Other Composio surfaces (integration grids, Add Source picker) read composio_list_connections and are intentionally out of scope.
  • No migration, no schema change, no security impact. Reversible: worst case a stale row shows briefly until the next good scan.

Related

  • Closes: N/A (no tracking issue filed)
  • Follow-up PR(s)/TODOs: eliminating the non-atomic upsert_composio_source write race at the source (RC-B residue) is deliberately out of scope — the dedupe hides it; growth is slow.

AI Authored PR Metadata

Linear Issue

  • Key: N/A
  • URL: N/A

Commit & Branch

  • Branch: fix/memory-sources-hide-inactive-connections
  • Commit SHA: 32f640de6bd09f5dfefacd9d0c78b4a7bc891c69

Validation Run

  • N/A: pnpm --filter openhuman-app format:check not run — no app/ changes.
  • N/A: pnpm typecheck not run — no TS changes.
  • Focused tests: cargo test -p openhuman --lib memory_sources::rpc::filter_tests (6 passed); cargo test --test json_rpc_e2e json_rpc_memory_sources_list (2 passed).
  • Rust fmt/check: cargo fmt --check clean; cargo check clean.
  • N/A: Tauri fmt/check not run — no shell changes.

Behavior Changes

  • Intended behavior change: inactive/duplicate Composio rows no longer appear in the sources list.
  • User-visible effect: one row per active connection; stale rows vanish (and reappear if the connection re-activates).

Parity Contract

  • Legacy behavior preserved: explicit Disconnect removal unchanged; new-connection time-to-appear unchanged (live scan stays inline).
  • Guard/fallback/dispatch parity checks: scan-failure (None) falls back to showing all sources — verified by none_active_set_shows_all (unit) and json_rpc_memory_sources_list_shows_all_when_scan_unavailable (E2E).

Duplicate / Superseded PR Handling

  • Duplicate PR(s): N/A
  • Canonical PR: this
  • Resolution: N/A

Summary by CodeRabbit

  • Bug Fixes

    • Listings now show only active Composio connections and consolidate duplicates when live scan is available.
    • Inactive/stale Composio rows are hidden when scan succeeds; when the live scan is unavailable, all sources are preserved (no hiding).
    • Composio rows lacking connection IDs are retained instead of dropped.
  • Tests

    • Added E2E and unit tests covering filtering, deduplication, reactivation, fallback, and orphan-row behavior.

The Memory page listed one row per connection regardless of liveness, so
re-auth / token-expiry / reconnect (which mints a fresh connection_id) left
the old connection's row stranded — surfacing as several "Gmail" rows with
only one active. A non-atomic upsert on the 5s poll could also double-insert
the same connection_id.

Reuse the live active-connection scan that list_rpc already runs every poll:
ensure_composio_sources now returns the active connection_id set (or None on
scan failure), and list_rpc filters Composio sources to that set and dedupes
by connection_id. Display-layer only — no row, setting, or ingested memory is
removed; an inactive connection reappears once it re-activates. On scan
failure the list passes through untouched, so a transient outage never hides
every source.

Tests: 6 unit tests over the pure filter (hide-inactive, dedupe, reactivation,
non-composio always shown, failed-scan-shows-all, missing connection_id) plus
2 JSON-RPC E2E tests driving a mock Composio /connected_accounts endpoint.
@sanil-23
sanil-23 requested a review from a team June 5, 2026 15:28
@coderabbitai

coderabbitai Bot commented Jun 5, 2026 •

Copy link
Copy Markdown
Contributor

Looking for one thing? Review this PR in Change Stack to search files, summaries, diffs, and code without losing your place.

Review Change Stack

📝 Walkthrough

Walkthrough

Composio memory sources are now filtered based on active connection scans. ensure_composio_sources returns an Option<HashSet<String>> containing live connection IDs or None when the scan is unavailable. list_rpc uses this set to filter listings: hiding inactive Composio sources, deduplicating by active connection ID, and preserving all sources when unavailable. E2E tests verify both filtering behavior and graceful handling when the Composio endpoint is unreachable.

Changes

Composio Memory Sources Active Connection Filtering

Layer / File(s) Summary
Active connection set return contract
src/openhuman/memory_sources/reconcile.rs
ensure_composio_sources signature changes to return Option<HashSet<String>>: on successful scan it returns Some(...) containing live connection IDs; on config-load or scan failure it returns None instead of exiting, explicitly signaling the active set is unavailable to callers.
Listing-layer filtering and deduplication
src/openhuman/memory_sources/rpc.rs
list_rpc calls ensure_composio_sources and filters registry results using a new pure helper: hides inactive Composio rows, collapses duplicates by active connection_id, keeps non-Composio sources, retains Composio rows missing connection_id, and preserves all rows when the active-connection set is None. Debug logging reports scan availability and filtered counts. Unit tests cover filtering semantics, deduplication, reactivation, non-Composio pass-through, unavailable-scan behavior, and orphan connection handling.
End-to-end integration tests
tests/json_rpc_e2e.rs
Adds mock Composio v3 router returning ACTIVE Gmail connection, helpers to write Composio direct-mode config and add memory sources over JSON-RPC, and response normalization. Two E2E tests: (1) verifies filtering collapses active Composio duplicates into one row while hiding inactive ones and preserving folder sources; (2) verifies all sources are shown when the Composio endpoint is unreachable (scan unavailable).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

rust-core, memory

Poem

🐰 I hopped through code to clear the stew,
Active links kept, stale ones withdrew.
Duplicate tails fold into one,
And when the scan sleeps, the full list runs.
A rabbit’s tidy hop—now the sources are true. 🌱

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: hiding inactive Composio connections in the sources list display layer, which matches the primary objective of the PR.
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ 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 rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. memory Memory store, memory tree, recall, summarization, and embeddings in src/openhuman/memory/. labels Jun 5, 2026
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 5, 2026
@sanil-23
sanil-23 requested a review from senamakel June 5, 2026 19:21
…hide-inactive-connections

# Conflicts:
#	tests/json_rpc_e2e.rs
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 5, 2026
…hide-inactive-connections

# Conflicts:
#	tests/json_rpc_e2e.rs
sanil-23 added 2 commits June 7, 2026 11:07
Regression for tinyhumansai#3443 (multiple account connections per toolkit): a JSON-RPC
E2E test where the active scan reports two distinct Gmail connections plus a
third stale one. Asserts both active connection_ids are listed (the filter
keys on connection_id, never toolkit, so it must not collapse them) while the
stale connection stays hidden.
@senamakel
senamakel merged commit d7c4f35 into tinyhumansai:main Jun 7, 2026
19 checks passed
YellowSnnowmann added a commit to YellowSnnowmann/openhuman that referenced this pull request Sep 1, 2026
The two memory_sources_list filtering tests (tinyhumansai#3413/tinyhumansai#3443) mocked Composio's
v3 /connected_accounts directly and steered the scan there with the
OPENHUMAN_COMPOSIO_DIRECT_BASE_* env knobs -- the pre-extraction path. The
connector extraction (tinyhumansai#5854) moved composio_list_connections into the
tinyconnectors module, which fetches the backend's
/agent-integrations/composio/connections route from BACKEND_URL instead;
with BACKEND_URL deliberately unset, the scan failed, ensure_composio_
sources answered None, and the filter took its documented fail-open arm --
every row listed, both assertions red. Main has carried that since the
extraction merged; this branch's full-suite coverage fallback is what
first ran them.

Both tests now serve the backend route per-test (one shared helper taking
the active set; response shape mirrored from the composio ops lib
fixtures, is_active = status ACTIVE/CONNECTED) and point BACKEND_URL at
it. The dead direct-endpoint routers are removed; the fail-open contract
itself is already pinned by the reconcile doc and unit coverage.
YellowSnnowmann added a commit to YellowSnnowmann/openhuman that referenced this pull request Sep 1, 2026
The two memory_sources_list filtering tests (tinyhumansai#3413/tinyhumansai#3443) mocked Composio's
v3 /connected_accounts directly and steered the scan there with the
OPENHUMAN_COMPOSIO_DIRECT_BASE_* env knobs -- the pre-extraction path. The
connector extraction (tinyhumansai#5854) moved composio_list_connections into the
tinyconnectors module, which fetches the backend's
/agent-integrations/composio/connections route from BACKEND_URL instead;
with BACKEND_URL deliberately unset, the scan failed, ensure_composio_
sources answered None, and the filter took its documented fail-open arm --
every row listed, both assertions red. Main has carried that since the
extraction merged; this branch's full-suite coverage fallback is what
first ran them.

Both tests now serve the backend route per-test (one shared helper taking
the active set; response shape mirrored from the composio ops lib
fixtures, is_active = status ACTIVE/CONNECTED) and point BACKEND_URL at
it. The dead direct-endpoint routers are removed; the fail-open contract
itself is already pinned by the reconcile doc and unit coverage.
senamakel pushed a commit to HDZTony/openhuman that referenced this pull request Sep 11, 2026
…eam\n\nThe two memory_sources_list filtering tests (tinyhumansai#3413/tinyhumansai#3443) mocked Composio's\nv3 /connected_accounts directly and steered the scan there with the\nOPENHUMAN_COMPOSIO_DIRECT_BASE_* env knobs -- the pre-extraction path. The\nconnector extraction (tinyhumansai#5854) moved composio_list_connections into the\ntinyconnectors module, which fetches the backend's\n/agent-integrations/composio/connections route from BACKEND_URL instead;\nwith BACKEND_URL deliberately unset, the scan failed, ensure_composio_\nsources answered None, and the filter took its documented fail-open arm --\nevery row listed, both assertions red. Main has carried that since the\nextraction merged; this branch's full-suite coverage fallback is what\nfirst ran them.\n\nBoth tests now serve the backend route per-test (one shared helper taking\nthe active set; response shape mirrored from the composio ops lib\nfixtures, is_active = status ACTIVE/CONNECTED) and point BACKEND_URL at\nit. The dead direct-endpoint routers are removed; the fail-open contract\nitself is already pinned by the reconcile doc and unit coverage.\n
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

memory Memory store, memory tree, recall, summarization, and embeddings in src/openhuman/memory/. rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants