fix(channels): managed-DM credentials surface as connected to chat#1209
fix(channels): managed-DM credentials surface as connected to chat#1209senamakel merged 4 commits intotinyhumansai:mainfrom
Conversation
The exact-match filter on list_provider_credentials cannot enumerate provider keys grouped under a common stem (e.g. channel:<slug>:<mode>). Add a prefix variant so callers like channel_status can list every channel-namespaced credential in one call. Refs tinyhumansai#1149.
…channels channel_status passed "channel:" to the exact-match list_provider_credentials filter, so it never matched the real keys (channel:telegram:managed_dm, channel:slack:bot_token, …) and always reported connected:false. Switch it to the new prefix helper. Add connected_channel_slugs which merges the legacy channels_config.<slug> TOML store with the channel:<slug>:<mode> credential store so every consumer agrees on what's connected. Used by the welcome-agent onboarding snapshot in the next commit. Refs tinyhumansai#1149.
OnboardingState now carries the merged channel list produced by channels::controllers::connected_channel_slugs, so the welcome agent sees Telegram/Slack/etc. as soon as their managed-DM credential lands — no app restart required and no "telegram not connected" reply right after a successful link. Closes tinyhumansai#1149.
…atus Wire-level regression guard for issue tinyhumansai#1149: store channel:telegram:managed_dm via openhuman.auth_store_provider_credentials, then assert openhuman.channels_status reports the managed_dm entry as connected:true. Catches regressions in either the prefix-match credential helper or the channels controller at the transport layer. Refs tinyhumansai#1149.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (8)
📝 WalkthroughWalkthroughThis PR enables channel connection state to be tracked via credentials stored with ChangesCredential-Backed Channel Detection
Sequence DiagramsequenceDiagram
participant Tool as Tool
participant Creds as Credentials<br/>Service
participant Config as Config
participant ChanCtrl as Channel<br/>Controller
participant Tools as Onboarding<br/>Tools
Tool->>+ChanCtrl: connected_channel_slugs(config)
ChanCtrl->>+Config: read channels_config
Config-->>-ChanCtrl: legacy channels
ChanCtrl->>+Creds: list_provider_credentials_by_prefix("channel:")
Creds-->>-ChanCtrl: channel:*:* credentials
ChanCtrl->>ChanCtrl: merge slugs + deduplicate
ChanCtrl-->>-Tool: Vec<String> (all connected)
Tool->>+Tools: format_status_markdown(connected_channels)
Tools-->>-Tool: markdown with all channels
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary
list_provider_credentials's exact-match filter never matched the namespaced channel keys, and the welcome-agent onboarding surface only consulted the legacy TOML store.connected_channel_slugshelper that mergeschannels_config.<slug>with the credential store so every consumer sees the same picture.Problem
After a Telegram managed-DM link succeeds, the credential is stored under
channel:telegram:managed_dmbutchannels_config.telegramstays unset (managed DM doesn't materialise a TOML block — the bot lives on the OpenHuman backend, not the local runtime). Two layers then go stale:openhuman.channels_statusreturnedconnected:falsefor every channel becauselist_provider_credentialsfiltered byprovider == "channel:"(exact equality on a value that's never the literal stringchannel:). Frontend reload reverted the badge to "disconnected" and chat-side callers saw nothing.check_onboarding_statussnapshot only walkedconfig.channels_config, so the agent answered "Telegram is not connected" verbatim even when the credential was already in place.Solution
Three backend fixes, each in its own commit:
feat(credentials): add list_provider_credentials_by_prefix— a pure prefix variant for namespaces grouped under a common stem.fix(channels): channel_status + slug merge surface credential-stored channels—channel_statusswitches to the prefix helper, andconnected_channel_slugsmerges both stores in deterministic order with dedupe.fix(agent): onboarding status surface honors credential-stored channels—OnboardingStatecarries the merged slug list;build_status_snapshotandformat_status_markdownconsume it instead of re-reading config directly.The fourth commit is a JSON-RPC E2E test that exercises the full transport path (
auth_store_provider_credentials→channels_status) so a regression in either layer is caught at the wire level.Frontend already dispatches
upsertChannelConnection({status:'connected'})after a successful link, so no app changes are needed — the UI was correct in the moment, only the post-reload / chat-side reads were stale.Submission Checklist
docs/TESTING-STRATEGY.mddiff-cover) meet the gate enforced by.github/workflows/coverage.yml. Runpnpm test:coverageandpnpm test:rustlocally; PRs below 80% on changed lines will not merge.docs/TEST-COVERAGE-MATRIX.mdreflect this change (no new feature row; bug fix on existing channel-status surface)## Relateddocs/TESTING-STRATEGY.md)docs/RELEASE-MANUAL-SMOKE.md)Closes #NNNin the## RelatedsectionImpact
channels_statusnow returns truthful entries (was previously alwaysconnected:false).connected_channel_slugsis additive;channels_config.<slug>continues to work forbot_token/webhook/oauthflows that need a local listener.compute_statecall (same as the existing Composio integrations fetch). No hot path.AuthService::load_profilespath; never exports tokens.Related
Summary by CodeRabbit
New Features
Tests