Repository navigation
Conversation
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.
|
Looking for one thing? Review this PR in Change Stack to search files, summaries, diffs, and code without losing your place. 📝 WalkthroughWalkthroughComposio memory sources are now filtered based on active connection scans. ChangesComposio Memory Sources Active Connection Filtering
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested labels
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
…hide-inactive-connections # Conflicts: # tests/json_rpc_e2e.rs
…hide-inactive-connections # Conflicts: # tests/json_rpc_e2e.rs
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.
…hide-inactive-connections
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.
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.
…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
Summary
connection_id, reusing the Composio scanlist_rpcalready runs every 5s poll.Problem
Composio memory sources are keyed by
connection_id. Two independent mechanisms produced duplicate rows: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.list_rpcreconciles on every poll andupsert_composio_sourceis a non-atomic read-check-write, so two overlapping polls can double-insert the sameconnection_id.Solution
reconcile::ensure_composio_sourcesnow returns the activeconnection_idset it scans (Some(set)on success,Nonewhen the scan couldn't run — config / network / auth failure).list_rpcfeeds that set to a new pure helperfilter_to_active_composio_sources:connection_idis in the active set (hides RC-A stragglers), first occurrence per id (collapses RC-B duplicates).None⇒ pass-through — never hide everything on a transient scan failure.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
/connected_accountsendpoint.reconcile.rsreturn Noneon a config-load failure, impractical to unit-test); ~16/17 measured changed lines ≈ 94%.N/A: bug fix to existing memory-sources list behaviour; no feature row added/removed/renamed.## Related—N/A: behaviour-only fix.N/A: does not touch a release-cut surface.Impact
MemorySourcesRegistry.tsx, driven solely bymemory_sources_list; thestatus_listpoll only supplies per-row stats and never adds rows. Other Composio surfaces (integration grids, Add Source picker) readcomposio_list_connectionsand are intentionally out of scope.Related
upsert_composio_sourcewrite 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
Commit & Branch
fix/memory-sources-hide-inactive-connections32f640de6bd09f5dfefacd9d0c78b4a7bc891c69Validation Run
pnpm --filter openhuman-app format:checknot run — noapp/changes.pnpm typechecknot run — no TS changes.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).cargo fmt --checkclean;cargo checkclean.Behavior Changes
Parity Contract
None) falls back to showing all sources — verified bynone_active_set_shows_all(unit) andjson_rpc_memory_sources_list_shows_all_when_scan_unavailable(E2E).Duplicate / Superseded PR Handling
Summary by CodeRabbit
Bug Fixes
Tests