[apps] Thread structured icon assets through app list (#29889)

## Summary

- Add `iconAssets` and `iconDarkAssets` to the app-list protocol.
- Preserve structured icons through directory merging and the connector,
app-
  server, and TUI boundaries.
- Keep legacy logo URLs unchanged as compatibility fallbacks.
- Update generated protocol schemas and TypeScript types.
This commit is contained in:
Drew
2026-06-24 13:25:44 -07:00
committed by GitHub
Unverified
parent ece1dfece0
commit a33ad93996
30 changed files with 381 additions and 2 deletions
@@ -241,6 +241,24 @@
"null"
]
},
"iconAssets": {
"additionalProperties": {
"type": "string"
},
"type": [
"object",
"null"
]
},
"iconDarkAssets": {
"additionalProperties": {
"type": "string"
},
"type": [
"object",
"null"
]
},
"id": {
"type": "string"
},
@@ -6406,6 +6406,24 @@
"null"
]
},
"iconAssets": {
"additionalProperties": {
"type": "string"
},
"type": [
"object",
"null"
]
},
"iconDarkAssets": {
"additionalProperties": {
"type": "string"
},
"type": [
"object",
"null"
]
},
"id": {
"type": "string"
},
@@ -532,6 +532,24 @@
"null"
]
},
"iconAssets": {
"additionalProperties": {
"type": "string"
},
"type": [
"object",
"null"
]
},
"iconDarkAssets": {
"additionalProperties": {
"type": "string"
},
"type": [
"object",
"null"
]
},
"id": {
"type": "string"
},
@@ -78,6 +78,24 @@
"null"
]
},
"iconAssets": {
"additionalProperties": {
"type": "string"
},
"type": [
"object",
"null"
]
},
"iconDarkAssets": {
"additionalProperties": {
"type": "string"
},
"type": [
"object",
"null"
]
},
"id": {
"type": "string"
},
@@ -78,6 +78,24 @@
"null"
]
},
"iconAssets": {
"additionalProperties": {
"type": "string"
},
"type": [
"object",
"null"
]
},
"iconDarkAssets": {
"additionalProperties": {
"type": "string"
},
"type": [
"object",
"null"
]
},
"id": {
"type": "string"
},
@@ -7,7 +7,7 @@ import type { AppMetadata } from "./AppMetadata";
/**
* EXPERIMENTAL - app metadata returned by app-list APIs.
*/
export type AppInfo = { id: string, name: string, description: string | null, logoUrl: string | null, logoUrlDark: string | null, distributionChannel: string | null, branding: AppBranding | null, appMetadata: AppMetadata | null, labels: { [key in string]?: string } | null, installUrl: string | null, isAccessible: boolean,
export type AppInfo = { id: string, name: string, description: string | null, logoUrl: string | null, logoUrlDark: string | null, iconAssets: { [key in string]?: string } | null, iconDarkAssets: { [key in string]?: string } | null, distributionChannel: string | null, branding: AppBranding | null, appMetadata: AppMetadata | null, labels: { [key in string]?: string } | null, installUrl: string | null, isAccessible: boolean,
/**
* Whether this app is enabled in config.toml.
* Example:
@@ -83,6 +83,8 @@ pub struct AppInfo {
pub description: Option<String>,
pub logo_url: Option<String>,
pub logo_url_dark: Option<String>,
pub icon_assets: Option<HashMap<String, String>>,
pub icon_dark_assets: Option<HashMap<String, String>>,
pub distribution_channel: Option<String>,
pub branding: Option<AppBranding>,
pub app_metadata: Option<AppMetadata>,
+9 -1
View File
@@ -1787,7 +1787,7 @@ To disable a non-managed hook, upsert a state entry at `hooks.state` with `confi
To re-enable it, upsert the same hook key with `"enabled": true`.
## Apps
Use `app/list` to fetch available apps (connectors). Each entry includes metadata like the app `id`, display `name`, `installUrl`, `branding`, `appMetadata`, `labels`, whether it is currently accessible, and whether it is enabled in config.
Use `app/list` to fetch available apps (connectors). Each entry includes metadata like the app `id`, display `name`, `installUrl`, legacy logo URLs, structured light and dark icon assets, `branding`, `appMetadata`, `labels`, whether it is currently accessible, and whether it is enabled in config.
```json
{ "method": "app/list", "id": 50, "params": {
@@ -1804,6 +1804,10 @@ Use `app/list` to fetch available apps (connectors). Each entry includes metadat
"description": "Example connector for documentation.",
"logoUrl": "https://example.com/demo-app.png",
"logoUrlDark": null,
"iconAssets": {
"256_square": "https://example.com/demo-app-square.png"
},
"iconDarkAssets": null,
"distributionChannel": null,
"branding": null,
"appMetadata": null,
@@ -1834,6 +1838,10 @@ The server also emits `app/list/updated` notifications whenever either source (a
"description": "Example connector for documentation.",
"logoUrl": "https://example.com/demo-app.png",
"logoUrlDark": null,
"iconAssets": {
"256_square": "https://example.com/demo-app-square.png"
},
"iconDarkAssets": null,
"distributionChannel": null,
"branding": null,
"appMetadata": null,
+4
View File
@@ -22,6 +22,8 @@ pub(crate) fn app_info_to_api(app: AppInfo) -> ApiAppInfo {
description,
logo_url,
logo_url_dark,
icon_assets,
icon_dark_assets,
distribution_channel,
branding,
app_metadata,
@@ -37,6 +39,8 @@ pub(crate) fn app_info_to_api(app: AppInfo) -> ApiAppInfo {
description,
logo_url,
logo_url_dark,
icon_assets,
icon_dark_assets,
distribution_channel,
branding: branding.map(app_branding_to_api),
app_metadata: app_metadata.map(app_metadata_to_api),
@@ -97,6 +97,8 @@ async fn list_apps_returns_empty_with_api_key_auth() -> Result<()> {
description: Some("Beta connector".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -162,6 +164,8 @@ async fn list_apps_returns_empty_when_workspace_codex_plugins_disabled() -> Resu
description: Some("Beta connector".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -268,6 +272,8 @@ async fn list_apps_uses_thread_feature_flag_when_thread_id_is_provided() -> Resu
description: Some("Beta connector".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -372,6 +378,8 @@ async fn list_apps_keeps_apps_with_app_only_tools_accessible() -> Result<()> {
description: Some("Formerly blocked connector".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -439,6 +447,8 @@ async fn list_apps_reports_is_enabled_from_config() -> Result<()> {
description: Some("Beta connector".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -549,6 +559,8 @@ async fn list_apps_emits_updates_and_returns_after_both_lists_load() -> Result<(
description: Some("Alpha connector".to_string()),
logo_url: Some("https://example.com/alpha.png".to_string()),
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: alpha_branding.clone(),
app_metadata: alpha_app_metadata.clone(),
@@ -564,6 +576,8 @@ async fn list_apps_emits_updates_and_returns_after_both_lists_load() -> Result<(
description: None,
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -613,6 +627,8 @@ async fn list_apps_emits_updates_and_returns_after_both_lists_load() -> Result<(
description: None,
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -633,6 +649,8 @@ async fn list_apps_emits_updates_and_returns_after_both_lists_load() -> Result<(
description: None,
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -648,6 +666,8 @@ async fn list_apps_emits_updates_and_returns_after_both_lists_load() -> Result<(
description: Some("Alpha connector".to_string()),
logo_url: Some("https://example.com/alpha.png".to_string()),
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: alpha_branding,
app_metadata: alpha_app_metadata,
@@ -689,6 +709,8 @@ async fn list_apps_waits_for_accessible_data_before_emitting_directory_updates()
description: Some("Alpha connector".to_string()),
logo_url: Some("https://example.com/alpha.png".to_string()),
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -704,6 +726,8 @@ async fn list_apps_waits_for_accessible_data_before_emitting_directory_updates()
description: None,
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -754,6 +778,8 @@ async fn list_apps_waits_for_accessible_data_before_emitting_directory_updates()
description: None,
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -769,6 +795,8 @@ async fn list_apps_waits_for_accessible_data_before_emitting_directory_updates()
description: Some("Alpha connector".to_string()),
logo_url: Some("https://example.com/alpha.png".to_string()),
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -813,6 +841,8 @@ async fn list_apps_does_not_emit_empty_interim_updates() -> Result<()> {
description: Some("Alpha connector".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -869,6 +899,8 @@ async fn list_apps_does_not_emit_empty_interim_updates() -> Result<()> {
description: Some("Alpha connector".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -904,6 +936,8 @@ async fn list_apps_paginates_results() -> Result<()> {
description: Some("Alpha connector".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -919,6 +953,8 @@ async fn list_apps_paginates_results() -> Result<()> {
description: None,
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -977,6 +1013,8 @@ async fn list_apps_paginates_results() -> Result<()> {
description: None,
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -1021,6 +1059,8 @@ async fn list_apps_paginates_results() -> Result<()> {
description: Some("Alpha connector".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -1046,6 +1086,8 @@ async fn list_apps_force_refetch_preserves_previous_cache_on_failure() -> Result
description: Some("Beta connector".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -1151,6 +1193,8 @@ async fn list_apps_force_refetch_patches_updates_from_cached_snapshots() -> Resu
description: Some("Alpha v1".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -1166,6 +1210,8 @@ async fn list_apps_force_refetch_patches_updates_from_cached_snapshots() -> Resu
description: Some("Beta v1".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -1216,6 +1262,8 @@ async fn list_apps_force_refetch_patches_updates_from_cached_snapshots() -> Resu
description: None,
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -1237,6 +1285,8 @@ async fn list_apps_force_refetch_patches_updates_from_cached_snapshots() -> Resu
description: Some("Beta v1".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -1252,6 +1302,8 @@ async fn list_apps_force_refetch_patches_updates_from_cached_snapshots() -> Resu
description: Some("Alpha v1".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -1282,6 +1334,8 @@ async fn list_apps_force_refetch_patches_updates_from_cached_snapshots() -> Resu
description: Some("Alpha v2".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -1312,6 +1366,8 @@ async fn list_apps_force_refetch_patches_updates_from_cached_snapshots() -> Resu
description: Some("Beta v1".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -1327,6 +1383,8 @@ async fn list_apps_force_refetch_patches_updates_from_cached_snapshots() -> Resu
description: Some("Alpha v1".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -1355,6 +1413,8 @@ async fn list_apps_force_refetch_patches_updates_from_cached_snapshots() -> Resu
description: Some("Alpha v2".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -1095,6 +1095,8 @@ async fn plugin_install_returns_apps_needing_auth() -> Result<()> {
description: Some("Alpha connector".to_string()),
logo_url: Some("https://example.com/alpha.png".to_string()),
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: Some("featured".to_string()),
branding: None,
app_metadata: None,
@@ -1110,6 +1112,8 @@ async fn plugin_install_returns_apps_needing_auth() -> Result<()> {
description: Some("Beta connector".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -1194,6 +1198,8 @@ async fn plugin_install_skips_mcp_oauth_for_chatgpt_dual_surface_plugin() -> Res
description: Some("Sample MCP connector".to_string()),
logo_url: Some("https://example.com/alpha.png".to_string()),
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: Some("featured".to_string()),
branding: None,
app_metadata: None,
@@ -1586,6 +1592,8 @@ async fn plugin_install_includes_formerly_disallowed_apps_needing_auth() -> Resu
description: Some("Alpha connector".to_string()),
logo_url: Some("https://example.com/alpha.png".to_string()),
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: Some("featured".to_string()),
branding: None,
app_metadata: None,
@@ -220,6 +220,8 @@ apps = true
description: Some("Example app connector".to_string()),
logo_url: Some("https://example.com/example.png".to_string()),
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: Some("featured".to_string()),
branding: None,
app_metadata: None,
@@ -1587,6 +1589,8 @@ async fn plugin_read_returns_app_metadata_category() -> Result<()> {
description: Some("Alpha connector".to_string()),
logo_url: Some("https://example.com/alpha.png".to_string()),
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: Some("featured".to_string()),
branding: None,
app_metadata: Some(AppMetadata {
@@ -1615,6 +1619,8 @@ async fn plugin_read_returns_app_metadata_category() -> Result<()> {
description: Some("Beta connector".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -1690,6 +1696,8 @@ async fn plugin_read_hides_apps_for_api_key_auth() -> Result<()> {
description: Some("Alpha connector".to_string()),
logo_url: Some("https://example.com/alpha.png".to_string()),
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: Some("featured".to_string()),
branding: None,
app_metadata: Some(AppMetadata {
+4
View File
@@ -198,6 +198,8 @@ mod tests {
description: None,
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -216,6 +218,8 @@ mod tests {
description: None,
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
+2
View File
@@ -41,6 +41,8 @@ where
description: connector_description,
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
+2
View File
@@ -65,6 +65,8 @@ pub struct AppInfo {
pub description: Option<String>,
pub logo_url: Option<String>,
pub logo_url_dark: Option<String>,
pub icon_assets: Option<HashMap<String, String>>,
pub icon_dark_assets: Option<HashMap<String, String>>,
pub distribution_channel: Option<String>,
pub branding: Option<AppBranding>,
pub app_metadata: Option<AppMetadata>,
+2
View File
@@ -39,6 +39,8 @@ mod tests {
description: None,
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
install_url: None,
branding: None,
+77
View File
@@ -84,6 +84,10 @@ pub struct DirectoryApp {
logo_url: Option<String>,
#[serde(alias = "logoUrlDark")]
logo_url_dark: Option<String>,
#[serde(alias = "iconAssets")]
icon_assets: Option<HashMap<String, String>>,
#[serde(alias = "iconDarkAssets")]
icon_dark_assets: Option<HashMap<String, String>>,
#[serde(alias = "distributionChannel")]
distribution_channel: Option<String>,
visibility: Option<String>,
@@ -279,6 +283,8 @@ fn merge_directory_app(existing: &mut DirectoryApp, incoming: DirectoryApp) {
labels,
logo_url,
logo_url_dark,
icon_assets,
icon_dark_assets,
distribution_channel,
visibility: _,
} = incoming;
@@ -302,6 +308,23 @@ fn merge_directory_app(existing: &mut DirectoryApp, incoming: DirectoryApp) {
if existing.logo_url_dark.is_none() && logo_url_dark.is_some() {
existing.logo_url_dark = logo_url_dark;
}
if existing.icon_assets.as_ref().is_none_or(HashMap::is_empty)
&& icon_assets
.as_ref()
.is_some_and(|assets| !assets.is_empty())
{
existing.icon_assets = icon_assets;
}
if existing
.icon_dark_assets
.as_ref()
.is_none_or(HashMap::is_empty)
&& icon_dark_assets
.as_ref()
.is_some_and(|assets| !assets.is_empty())
{
existing.icon_dark_assets = icon_dark_assets;
}
if existing.distribution_channel.is_none() && distribution_channel.is_some() {
existing.distribution_channel = distribution_channel;
}
@@ -420,6 +443,8 @@ fn directory_app_to_app_info(app: DirectoryApp) -> AppInfo {
description: app.description,
logo_url: app.logo_url,
logo_url_dark: app.logo_url_dark,
icon_assets: app.icon_assets,
icon_dark_assets: app.icon_dark_assets,
distribution_channel: app.distribution_channel,
branding: app.branding,
app_metadata: app.app_metadata,
@@ -512,11 +537,63 @@ mod tests {
labels: None,
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
visibility: None,
}
}
#[test]
fn directory_app_icon_assets_reach_app_info() -> anyhow::Result<()> {
let response: DirectoryListResponse = serde_json::from_value(serde_json::json!({
"apps": [{
"id": "alpha",
"name": "Alpha",
"icon_assets": {},
"icon_dark_assets": {}
}, {
"id": "alpha",
"name": "",
"icon_assets": {
"256_square": "https://example.com/alpha-square.png"
},
"icon_dark_assets": {
"256_square": "https://example.com/alpha-square-dark.png"
}
}],
"next_token": null
}))?;
let app_info = directory_app_to_app_info(merge_directory_apps(response.apps).remove(0));
assert_eq!(
serde_json::to_value(app_info)?,
serde_json::json!({
"id": "alpha",
"name": "Alpha",
"description": null,
"logoUrl": null,
"logoUrlDark": null,
"iconAssets": {
"256_square": "https://example.com/alpha-square.png"
},
"iconDarkAssets": {
"256_square": "https://example.com/alpha-square-dark.png"
},
"distributionChannel": null,
"branding": null,
"appMetadata": null,
"labels": null,
"installUrl": null,
"isAccessible": false,
"isEnabled": true,
"pluginDisplayNames": []
})
);
Ok(())
}
#[tokio::test]
#[expect(
clippy::await_holding_invalid_type,
+14
View File
@@ -34,6 +34,12 @@ pub fn merge_connectors(
if existing.logo_url_dark.is_none() && connector.logo_url_dark.is_some() {
existing.logo_url_dark = connector.logo_url_dark;
}
if existing.icon_assets.is_none() && connector.icon_assets.is_some() {
existing.icon_assets = connector.icon_assets;
}
if existing.icon_dark_assets.is_none() && connector.icon_dark_assets.is_some() {
existing.icon_dark_assets = connector.icon_dark_assets;
}
if existing.distribution_channel.is_none() && connector.distribution_channel.is_some() {
existing.distribution_channel = connector.distribution_channel;
}
@@ -107,6 +113,8 @@ pub fn plugin_connector_to_app_info(connector_id: String) -> AppInfo {
description: None,
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -136,6 +144,8 @@ mod tests {
description: Some("Plan events".to_string()),
logo_url: Some("https://example.com/logo.png".to_string()),
logo_url_dark: Some("https://example.com/logo-dark.png".to_string()),
icon_assets: None,
icon_dark_assets: None,
distribution_channel: Some("workspace".to_string()),
branding: None,
app_metadata: None,
@@ -162,6 +172,8 @@ mod tests {
description: Some("Plan events".to_string()),
logo_url: Some("https://example.com/logo.png".to_string()),
logo_url_dark: Some("https://example.com/logo-dark.png".to_string()),
icon_assets: None,
icon_dark_assets: None,
distribution_channel: Some("workspace".to_string()),
branding: None,
app_metadata: None,
@@ -192,6 +204,8 @@ mod tests {
description: Some("Plan events".to_string()),
logo_url: Some("https://example.com/logo.png".to_string()),
logo_url_dark: Some("https://example.com/logo-dark.png".to_string()),
icon_assets: None,
icon_dark_assets: None,
distribution_channel: Some("workspace".to_string()),
branding: None,
app_metadata: None,
+2
View File
@@ -19,6 +19,8 @@ mod tests {
description: None,
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
+14
View File
@@ -31,6 +31,8 @@ fn app(id: &str) -> AppInfo {
description: None,
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
install_url: None,
branding: None,
@@ -129,6 +131,8 @@ fn accessible_connectors_from_mcp_tools_carries_plugin_display_names() {
description: None,
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
install_url: Some(connector_install_url("Google Calendar", "calendar")),
branding: None,
@@ -168,6 +172,8 @@ fn synthetic_links_are_exposed_to_the_agent_but_not_accessible_in_app_list() {
description: None,
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
install_url: Some(connector_install_url("Calendar", "calendar")),
branding: None,
@@ -191,6 +197,8 @@ fn synthetic_links_are_exposed_to_the_agent_but_not_accessible_in_app_list() {
description: None,
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
install_url: Some(connector_install_url("Gmail", "gmail")),
branding: None,
@@ -243,6 +251,8 @@ async fn refresh_accessible_connectors_cache_from_mcp_tools_writes_latest_instal
description: None,
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
install_url: Some(connector_install_url("Google Calendar", "calendar")),
branding: None,
@@ -258,6 +268,8 @@ async fn refresh_accessible_connectors_cache_from_mcp_tools_writes_latest_instal
description: None,
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
install_url: Some(connector_install_url("Hidden", "connector_openai_hidden")),
branding: None,
@@ -298,6 +310,8 @@ fn accessible_connectors_from_mcp_tools_preserves_description() {
description: Some("Plan events".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -23,6 +23,8 @@ fn make_connector(id: &str, name: &str) -> AppInfo {
description: None,
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
+2
View File
@@ -640,6 +640,8 @@ fn make_connector(id: &str, name: &str) -> AppInfo {
description: None,
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -235,6 +235,8 @@ fn connector_tool(id: &str, name: &str) -> DiscoverableTool {
description: None,
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -11,6 +11,8 @@ fn build_request_plugin_install_elicitation_request_uses_expected_shape() {
description: Some("Plan events and schedules.".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -124,6 +126,8 @@ fn build_request_plugin_install_meta_uses_expected_shape() {
description: None,
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -165,6 +169,8 @@ fn verified_connector_install_completed_requires_accessible_connector() {
description: None,
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -193,6 +199,8 @@ fn all_requested_connectors_picked_up_requires_every_expected_connector() {
description: None,
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -26,6 +26,8 @@ fn filter_request_plugin_install_discoverable_tools_for_codex_tui_omits_plugins(
description: Some("Plan events and schedules.".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -57,6 +59,8 @@ fn filter_request_plugin_install_discoverable_tools_for_codex_tui_omits_plugins(
description: Some("Plan events and schedules.".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
+4
View File
@@ -22,6 +22,8 @@ pub(crate) fn app_info_from_api(app: ApiAppInfo) -> AppInfo {
description,
logo_url,
logo_url_dark,
icon_assets,
icon_dark_assets,
distribution_channel,
branding,
app_metadata,
@@ -37,6 +39,8 @@ pub(crate) fn app_info_from_api(app: ApiAppInfo) -> AppInfo {
description,
logo_url,
logo_url_dark,
icon_assets,
icon_dark_assets,
distribution_channel,
branding: branding.map(app_branding_from_api),
app_metadata: app_metadata.map(app_metadata_from_api),
@@ -6135,6 +6135,8 @@ mod tests {
description: Some("Workspace docs".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -6177,6 +6179,8 @@ mod tests {
description: Some("Workspace docs".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -6314,6 +6318,8 @@ mod tests {
description: Some("Look up events and availability".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -6428,6 +6434,8 @@ mod tests {
description: Some("Look up events and availability".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -6462,6 +6470,8 @@ mod tests {
description: Some("Workspace docs".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
+2
View File
@@ -521,6 +521,8 @@ mod tests {
description: None,
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -1284,6 +1284,8 @@ async fn submit_user_message_ignores_inaccessible_app_mentions_from_bindings() {
description: Some("Directory-only app".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -1926,6 +1926,8 @@ async fn apps_popup_stays_loading_until_final_snapshot_updates() {
description: Some("Workspace docs".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -1960,6 +1962,8 @@ async fn apps_popup_stays_loading_until_final_snapshot_updates() {
description: Some("Workspace docs".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -1975,6 +1979,8 @@ async fn apps_popup_stays_loading_until_final_snapshot_updates() {
description: Some("Project tracking".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -2021,6 +2027,8 @@ async fn apps_notification_update_excludes_inaccessible_apps_from_mentions() {
description: Some("Connected files".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -2036,6 +2044,8 @@ async fn apps_notification_update_excludes_inaccessible_apps_from_mentions() {
description: Some("Directory-only app".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -2090,6 +2100,8 @@ async fn apps_refresh_failure_keeps_existing_full_snapshot() {
description: Some("Workspace docs".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -2105,6 +2117,8 @@ async fn apps_refresh_failure_keeps_existing_full_snapshot() {
description: Some("Project tracking".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -2130,6 +2144,8 @@ async fn apps_refresh_failure_keeps_existing_full_snapshot() {
description: Some("Workspace docs".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -2179,6 +2195,8 @@ async fn apps_popup_preserves_selected_app_across_refresh() {
description: Some("Workspace docs".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -2194,6 +2212,8 @@ async fn apps_popup_preserves_selected_app_across_refresh() {
description: Some("Team chat".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -2225,6 +2245,8 @@ async fn apps_popup_preserves_selected_app_across_refresh() {
description: Some("Spreadsheets".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -2240,6 +2262,8 @@ async fn apps_popup_preserves_selected_app_across_refresh() {
description: Some("Workspace docs".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -2255,6 +2279,8 @@ async fn apps_popup_preserves_selected_app_across_refresh() {
description: Some("Team chat".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -2298,6 +2324,8 @@ async fn apps_refresh_failure_with_cached_snapshot_triggers_pending_force_refetc
description: Some("Workspace docs".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -2341,6 +2369,8 @@ async fn apps_popup_keeps_existing_full_snapshot_while_partial_refresh_loads() {
description: Some("Workspace docs".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -2356,6 +2386,8 @@ async fn apps_popup_keeps_existing_full_snapshot_while_partial_refresh_loads() {
description: Some("Project tracking".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -2383,6 +2415,8 @@ async fn apps_popup_keeps_existing_full_snapshot_while_partial_refresh_loads() {
description: Some("Workspace docs".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -2398,6 +2432,8 @@ async fn apps_popup_keeps_existing_full_snapshot_while_partial_refresh_loads() {
description: Some("Should be filtered".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -2446,6 +2482,8 @@ async fn apps_refresh_failure_without_full_snapshot_falls_back_to_installed_apps
description: Some("Workspace docs".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -2505,6 +2543,8 @@ async fn apps_popup_shows_disabled_status_for_installed_but_disabled_apps() {
description: Some("Workspace docs".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -2548,6 +2588,8 @@ async fn apps_refresh_preserves_toggled_enabled_state() {
description: Some("Workspace docs".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -2570,6 +2612,8 @@ async fn apps_refresh_preserves_toggled_enabled_state() {
description: Some("Workspace docs".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,
@@ -2619,6 +2663,8 @@ async fn apps_popup_for_not_installed_app_uses_install_only_selected_description
description: Some("Project tracking".to_string()),
logo_url: None,
logo_url_dark: None,
icon_assets: None,
icon_dark_assets: None,
distribution_channel: None,
branding: None,
app_metadata: None,