fn validate_unique_manifests(manifests: &[ToolManifest]) -> Result<(), ReconfigureError> {
let mut names = BTreeSet::new();
let mut ids = BTreeSet::new();
for manifest in manifests {
if manifest.id.as_str().trim().is_empty() {
return Err(ReconfigureError::Validation(
"tool id cannot be empty".to_string(),
));
}
if !ids.insert(manifest.id.clone()) {
return Err(ReconfigureError::Validation(format!(
"duplicate tool id `{}` in source",
manifest.id
)));
}
if manifest.name.trim().is_empty() {
return Err(ReconfigureError::Validation(
"tool name cannot be empty".to_string(),
));
}
if !names.insert(manifest.name.clone()) {
return Err(ReconfigureError::Validation(format!(
"duplicate tool name `{}` in source",
manifest.name
)));
}
}
Ok(())
}
fn manifest_with_restored_override(
mut live: ToolManifest,
stored: &ToolManifest,
) -> ToolManifest {
live.availability_override = stored.availability_override.or(live.availability_override);
live
}
fn manifest_with_compact_contract(
source: &dyn ToolSourceExecutor,
mut manifest: ToolManifest,
) -> ToolManifest {
if manifest.compact_contract.is_none()
&& let Some(contract) = source.resolve_contract_by_id(&manifest.id)
{
manifest.compact_contract = Some(contract.compact_contract(&manifest));
}
manifest
}
fn export_tool_state_entries(
entries: &BTreeMap<ToolId, ToolRegistryEntry>,
) -> BTreeMap<ToolId, ToolStateEntry> {
entries
.iter()
.map(|(id, entry)| (id.clone(), entry.export()))
.collect()
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum RebindMode {
OrphanUnresolved,
RejectUnresolved,
}
struct ReboundTools {
tools: BTreeMap<ToolId, ToolRegistryEntry>,
orphaned: Vec<ToolId>,
}
fn rebind_tool_state_entries(
entries: &BTreeMap<ToolId, ToolStateEntry>,
sources: &BTreeMap<String, Arc<dyn ToolSourceExecutor>>,
mode: RebindMode,
) -> Result<ReboundTools, ReconfigureError> {
let mut rebound = BTreeMap::new();
let mut orphaned = Vec::new();
for (id, entry) in entries {
if id != &entry.manifest.id {
return Err(ReconfigureError::Validation(format!(
"tool state key `{}` does not match manifest id `{}`",
id, entry.manifest.id
)));
}
let mut id_matches = Vec::new();
for (source_id, source) in sources {
let Some(manifest) = source.resolve_manifest_by_id(id) else {
continue;
};
id_matches.push((
source_id.clone(),
manifest_with_compact_contract(source.as_ref(), manifest),
));
}
if id_matches.is_empty() {
if mode == RebindMode::RejectUnresolved && !entry.orphaned {
return Err(ReconfigureError::Validation(format!(
"no registered tool source resolves tool id `{id}`"
)));
}
orphaned.push(id.clone());
rebound.insert(
id.clone(),
ToolRegistryEntry::orphaned(entry.manifest.clone()),
);
continue;
}
if id_matches.len() == 1 {
let (source_id, manifest) = id_matches
.into_iter()
.next()
.expect("len checked above");
rebound.insert(
id.clone(),
ToolRegistryEntry::new(
manifest_with_restored_override(manifest, &entry.manifest),
source_id,
),
);
} else {
return Err(ReconfigureError::Validation(format!(
"tool id `{id}` is resolved by multiple registered sources"
)));
}
}
Ok(ReboundTools {
tools: rebound,
orphaned,
})
}
fn validate_unique_manifest_entries<'a>(
entries: impl IntoIterator<Item = &'a ToolStateEntry>,
) -> Result<(), ReconfigureError> {
let manifests = entries
.into_iter()
.map(|entry| entry.stored_manifest().clone())
.collect::<Vec<_>>();
validate_unique_manifests(&manifests)
}