Codex Handbook
connectors/src/accessible.rs 76 lines
use std::collections::BTreeSet;use std::collections::HashMap;use crate::metadata::connector_install_url;use crate::normalize_connector_value;use codex_app_server_protocol::AppInfo;pub struct AccessibleConnectorTool {    pub connector_id: String,    pub connector_name: Option<String>,    pub connector_description: Option<String>,    pub plugin_display_names: Vec<String>,}pub fn collect_accessible_connectors<I>(tools: I) -> Vec<AppInfo>where    I: IntoIterator<Item = AccessibleConnectorTool>,{    let mut connectors: HashMap<String, (AppInfo, BTreeSet<String>)> = HashMap::new();    for tool in tools {        let connector_id = tool.connector_id;        let connector_name = normalize_connector_value(tool.connector_name.as_deref())            .unwrap_or_else(|| connector_id.clone());        let connector_description =            normalize_connector_value(tool.connector_description.as_deref());        if let Some((existing, existing_plugin_display_names)) = connectors.get_mut(&connector_id) {            if existing.name == connector_id && connector_name != connector_id {                existing.name = connector_name;            }            if existing.description.is_none() && connector_description.is_some() {                existing.description = connector_description;            }            existing_plugin_display_names.extend(tool.plugin_display_names);        } else {            connectors.insert(                connector_id.clone(),                (                    AppInfo {                        id: connector_id.clone(),                        name: connector_name,                        description: connector_description,                        logo_url: None,                        logo_url_dark: None,                        distribution_channel: None,                        branding: None,                        app_metadata: None,                        labels: None,                        install_url: None,                        is_accessible: true,                        is_enabled: true,                        plugin_display_names: Vec::new(),                    },                    tool.plugin_display_names                        .into_iter()                        .collect::<BTreeSet<String>>(),                ),            );        }    }    let mut accessible: Vec<AppInfo> = connectors        .into_values()        .map(|(mut connector, plugin_display_names)| {            connector.plugin_display_names = plugin_display_names.into_iter().collect();            connector.install_url = Some(connector_install_url(&connector.name, &connector.id));            connector        })        .collect();    accessible.sort_by(|left, right| {        right            .is_accessible            .cmp(&left.is_accessible)            .then_with(|| left.name.cmp(&right.name))            .then_with(|| left.id.cmp(&right.id))    });    accessible}