Add trusted external capability provider registry#2548
Conversation
📝 WalkthroughWalkthroughAdds configurable external capability providers: new config and runtime types, provider ID normalization/validation, a config-backed registry exposing list/get/can_register_tools/errors, unit tests, and integration into the top-level Config and schema re-exports. ChangesExternal Capability Provider Registry System
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 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 |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/openhuman/external_capabilities/mod.rs (1)
93-111: ⚡ Quick winAdd structured debug/trace logs on registry load error branches
from_confighas duplicate/error/state-transition branches but no instrumentation. Add structureddebug/tracelogs (stable prefix + provider id) for invalid records and duplicates so config diagnosis is grep-friendly.As per coding guidelines: “Use
log/tracingatdebugortracelevel on RPC entry and exit, error paths, state transitions, and any branch that is hard to infer from tests alone.”🤖 Prompt for 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. In `@src/openhuman/external_capabilities/mod.rs` around lines 93 - 111, The from_config function currently swallows error and duplicate branches without instrumentation; update ExternalCapabilityProviders::from_config to emit structured debug/trace logs: on the Err(err) branch of ExternalCapabilityProvider::from_config log a trace/debug with a stable prefix (e.g. "external_capability:invalid") plus the provider config id and the error string, and on the duplicate branch where providers.contains_key(&provider.id) is true log a trace/debug with a stable prefix (e.g. "external_capability:duplicate") plus the conflicting provider.id; use the project logging crate (log or tracing) consistently and keep messages machine-grep-friendly and concise to aid config diagnosis.
🤖 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/external_capabilities/mod.rs`:
- Around line 13-254: The file mixes domain exports, operational logic and tests
— split into focused modules: move the plain data types
(ExternalCapabilityProviderConfig, ExternalCapabilityProvidersConfig,
ExternalCapabilityProvider) into a new types.rs, move the operational code and
registry (ExternalCapabilityProvider::from_config,
ExternalCapabilityProvider::can_register_tools,
ExternalCapabilityProviderRegistry and its impls, normalize_provider_id,
is_separator, trim_optional) into an ops.rs (or registry.rs), and move the
#[cfg(test)] tests into the corresponding sibling (or keep them in
types.rs/ops.rs guarded by cfg(test)); then update mod.rs to only pub mod types;
pub mod ops; and re-export the key symbols (pub use
types::{ExternalCapabilityProviderConfig, ExternalCapabilityProvidersConfig,
ExternalCapabilityProvider}; pub use ops::{ExternalCapabilityProviderRegistry,
normalize_provider_id};) so external callers and tests continue to work.
---
Nitpick comments:
In `@src/openhuman/external_capabilities/mod.rs`:
- Around line 93-111: The from_config function currently swallows error and
duplicate branches without instrumentation; update
ExternalCapabilityProviders::from_config to emit structured debug/trace logs: on
the Err(err) branch of ExternalCapabilityProvider::from_config log a trace/debug
with a stable prefix (e.g. "external_capability:invalid") plus the provider
config id and the error string, and on the duplicate branch where
providers.contains_key(&provider.id) is true log a trace/debug with a stable
prefix (e.g. "external_capability:duplicate") plus the conflicting provider.id;
use the project logging crate (log or tracing) consistently and keep messages
machine-grep-friendly and concise to aid config diagnosis.
🪄 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: 1b8c244e-2125-4803-add9-d54f121ccb9e
📒 Files selected for processing (5)
src/openhuman/config/schema/mod.rssrc/openhuman/config/schema/tools.rssrc/openhuman/config/schema/types.rssrc/openhuman/external_capabilities/mod.rssrc/openhuman/mod.rs
There was a problem hiding this comment.
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/external_capabilities/registry.rs`:
- Around line 38-70: Update ExternalCapabilityRegistry::from_config to emit
flow-level debug diagnostics: add an entry log at start and an exit log before
returning, and log branch outcomes each time
ExternalCapabilityProvider::from_config succeeds or fails and when a duplicate
is detected; include stable prefixes like "[external_capability][registry]" and
correlation fields such as total_providers (config.providers.len()),
accepted_count, rejected_count, duplicate_count, and a normalized provider id
list or the provider.id for each processed item. Ensure the existing debug calls
are augmented (or replaced) to follow this pattern and increment the
accepted/rejected/duplicate counters as you process providers so the exit log
reports the final counts and any aggregated errors in Self { providers, errors
}.
🪄 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: 7c109b51-9f04-412f-babb-6d7afcbcb5d2
📒 Files selected for processing (3)
src/openhuman/external_capabilities/mod.rssrc/openhuman/external_capabilities/registry.rssrc/openhuman/external_capabilities/types.rs
✅ Files skipped from review due to trivial changes (1)
- src/openhuman/external_capabilities/mod.rs
| pub fn from_config(config: &ExternalCapabilityProvidersConfig) -> Self { | ||
| let mut providers = BTreeMap::new(); | ||
| let mut errors = Vec::new(); | ||
|
|
||
| for provider in &config.providers { | ||
| match ExternalCapabilityProvider::from_config(provider) { | ||
| Ok(provider) => { | ||
| if providers.contains_key(&provider.id) { | ||
| log::debug!( | ||
| "[external_capability] duplicate provider_id={}", | ||
| provider.id | ||
| ); | ||
| errors.push(format!( | ||
| "duplicate external capability provider id `{}`", | ||
| provider.id | ||
| )); | ||
| } else { | ||
| providers.insert(provider.id.clone(), provider); | ||
| } | ||
| } | ||
| Err(err) => { | ||
| log::debug!( | ||
| "[external_capability] invalid provider_config_id={} error={}", | ||
| provider.id, | ||
| err | ||
| ); | ||
| errors.push(err); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| Self { providers, errors } | ||
| } |
There was a problem hiding this comment.
Add full flow-level diagnostics in registry construction.
from_config currently logs only some error paths. Per guideline, new flow diagnostics should include entry/exit and branch outcomes with stable prefixes and correlation fields (e.g., total provider count, accepted/rejected/duplicate counts, normalized provider IDs).
Suggested logging expansion
pub fn from_config(config: &ExternalCapabilityProvidersConfig) -> Self {
+ log::debug!(
+ "[domain] [external_capability] registry_build_start providers_count={}",
+ config.providers.len()
+ );
let mut providers = BTreeMap::new();
let mut errors = Vec::new();
+ let mut accepted = 0usize;
+ let mut rejected = 0usize;
+ let mut duplicates = 0usize;
for provider in &config.providers {
match ExternalCapabilityProvider::from_config(provider) {
Ok(provider) => {
if providers.contains_key(&provider.id) {
+ duplicates += 1;
log::debug!(
- "[external_capability] duplicate provider_id={}",
+ "[domain] [external_capability] duplicate provider_id={}",
provider.id
);
errors.push(format!(
"duplicate external capability provider id `{}`",
provider.id
));
} else {
+ accepted += 1;
+ log::debug!(
+ "[domain] [external_capability] accepted provider_id={} trusted={} enabled={}",
+ provider.id,
+ provider.trusted,
+ provider.enabled
+ );
providers.insert(provider.id.clone(), provider);
}
}
Err(err) => {
+ rejected += 1;
log::debug!(
- "[external_capability] invalid provider_config_id={} error={}",
+ "[domain] [external_capability] invalid provider_config_id={} error={}",
provider.id,
err
);
errors.push(err);
}
}
}
+ log::debug!(
+ "[domain] [external_capability] registry_build_end accepted={} duplicates={} rejected={} errors={}",
+ accepted,
+ duplicates,
+ rejected,
+ errors.len()
+ );
Self { providers, errors }
}As per coding guidelines, “Debug logging must follow these rules: default to verbose diagnostics on new/changed flows; log entry/exit, branches… and errors… All changes lacking diagnosis logging are incomplete.”
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| pub fn from_config(config: &ExternalCapabilityProvidersConfig) -> Self { | |
| let mut providers = BTreeMap::new(); | |
| let mut errors = Vec::new(); | |
| for provider in &config.providers { | |
| match ExternalCapabilityProvider::from_config(provider) { | |
| Ok(provider) => { | |
| if providers.contains_key(&provider.id) { | |
| log::debug!( | |
| "[external_capability] duplicate provider_id={}", | |
| provider.id | |
| ); | |
| errors.push(format!( | |
| "duplicate external capability provider id `{}`", | |
| provider.id | |
| )); | |
| } else { | |
| providers.insert(provider.id.clone(), provider); | |
| } | |
| } | |
| Err(err) => { | |
| log::debug!( | |
| "[external_capability] invalid provider_config_id={} error={}", | |
| provider.id, | |
| err | |
| ); | |
| errors.push(err); | |
| } | |
| } | |
| } | |
| Self { providers, errors } | |
| } | |
| pub fn from_config(config: &ExternalCapabilityProvidersConfig) -> Self { | |
| log::debug!( | |
| "[domain] [external_capability] registry_build_start providers_count={}", | |
| config.providers.len() | |
| ); | |
| let mut providers = BTreeMap::new(); | |
| let mut errors = Vec::new(); | |
| let mut accepted = 0usize; | |
| let mut rejected = 0usize; | |
| let mut duplicates = 0usize; | |
| for provider in &config.providers { | |
| match ExternalCapabilityProvider::from_config(provider) { | |
| Ok(provider) => { | |
| if providers.contains_key(&provider.id) { | |
| duplicates += 1; | |
| log::debug!( | |
| "[domain] [external_capability] duplicate provider_id={}", | |
| provider.id | |
| ); | |
| errors.push(format!( | |
| "duplicate external capability provider id `{}`", | |
| provider.id | |
| )); | |
| } else { | |
| accepted += 1; | |
| log::debug!( | |
| "[domain] [external_capability] accepted provider_id={} trusted={} enabled={}", | |
| provider.id, | |
| provider.trusted, | |
| provider.enabled | |
| ); | |
| providers.insert(provider.id.clone(), provider); | |
| } | |
| } | |
| Err(err) => { | |
| rejected += 1; | |
| log::debug!( | |
| "[domain] [external_capability] invalid provider_config_id={} error={}", | |
| provider.id, | |
| err | |
| ); | |
| errors.push(err); | |
| } | |
| } | |
| } | |
| log::debug!( | |
| "[domain] [external_capability] registry_build_end accepted={} duplicates={} rejected={} errors={}", | |
| accepted, | |
| duplicates, | |
| rejected, | |
| errors.len() | |
| ); | |
| Self { providers, errors } | |
| } |
🤖 Prompt for 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.
In `@src/openhuman/external_capabilities/registry.rs` around lines 38 - 70, Update
ExternalCapabilityRegistry::from_config to emit flow-level debug diagnostics:
add an entry log at start and an exit log before returning, and log branch
outcomes each time ExternalCapabilityProvider::from_config succeeds or fails and
when a duplicate is detected; include stable prefixes like
"[external_capability][registry]" and correlation fields such as total_providers
(config.providers.len()), accepted_count, rejected_count, duplicate_count, and a
normalized provider id list or the provider.id for each processed item. Ensure
the existing debug calls are augmented (or replaced) to follow this pattern and
increment the accepted/rejected/duplicate counters as you process providers so
the exit log reports the final counts and any aggregated errors in Self {
providers, errors }.
Summary
Problem
Solution
openhuman::external_capabilitieswith provider config, normalization, registry construction, and error reporting.external_capability_providersinto the top-level config schema with a default-empty configuration.Submission Checklist
## Related: N/A, no coverage-matrix feature ID applies.docs/RELEASE-MANUAL-SMOKE.md): N/A, no release-cut UI/runtime smoke surface changed.Closes #NNNin the## Relatedsection.Impact
Related
AI Authored PR Metadata (required for Codex/Linear PRs)
Linear Issue
Commit & Branch
codex/oh-2541-external-capability-providersd91b5ef1371e65e81b77ea701e4a6b03e121d6d9Validation Run
pnpm --filter openhuman-app format:check: N/A, Rust-only backend schema/module change.pnpm typecheck: N/A, Rust-only backend schema/module change.cargo test --manifest-path Cargo.toml external_capabilities --libcargo fmt --manifest-path Cargo.toml --all --check;git diff --checknode scripts/check-pr-checklist.mjs /tmp/openhuman-pr-body-2541.mdValidation Blocked
command:N/Aerror:N/Aimpact:N/ABehavior Changes
Parity Contract
Duplicate / Superseded PR Handling
vaddisrinivas:codex/oh-2541-external-capability-providers.Summary by CodeRabbit
New Features
Tests
Documentation