mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
connectors: own app metadata types (#29723)
## Why Connector metadata is consumed by connector discovery, ChatGPT integration, core, and TUI code. Treating app-server's wire DTO as the shared domain model reverses the intended dependency direction. ## What changed - Added connector-owned app branding, review, screenshot, metadata, and info types. - Added explicit conversions in app-server and TUI while preserving app-server's wire payloads. - Removed production app-server-protocol dependencies from connectors and ChatGPT connector code. ## Stack This is PR 4 of 6, stacked on [PR #29722](https://github.com/openai/codex/pull/29722). Review only the delta from `codex/split-config-layer-types`. Next: [PR #29724](https://github.com/openai/codex/pull/29724). ## Validation - Connector and tools coverage passed. - App-server app-list coverage passed: 13 tests.
This commit is contained in:
committed by
GitHub
Unverified
parent
1d65ccabd5
commit
e639e8c4bd
Generated
+2
-2
@@ -1976,6 +1976,7 @@ dependencies = [
|
||||
"codex-chatgpt",
|
||||
"codex-cloud-config",
|
||||
"codex-config",
|
||||
"codex-connectors",
|
||||
"codex-core",
|
||||
"codex-core-plugins",
|
||||
"codex-exec-server",
|
||||
@@ -2293,7 +2294,6 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"codex-app-server-protocol",
|
||||
"codex-connectors",
|
||||
"codex-core",
|
||||
"codex-git-utils",
|
||||
@@ -2583,7 +2583,6 @@ name = "codex-connectors"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"codex-app-server-protocol",
|
||||
"codex-config",
|
||||
"pretty_assertions",
|
||||
"serde",
|
||||
@@ -4016,6 +4015,7 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"codex-app-server-protocol",
|
||||
"codex-code-mode",
|
||||
"codex-connectors",
|
||||
"codex-features",
|
||||
"codex-file-system",
|
||||
"codex-protocol",
|
||||
|
||||
@@ -33,6 +33,7 @@ codex-analytics = { workspace = true }
|
||||
codex-arg0 = { workspace = true }
|
||||
codex-cloud-config = { workspace = true }
|
||||
codex-config = { workspace = true }
|
||||
codex-connectors = { workspace = true }
|
||||
codex-core = { workspace = true }
|
||||
codex-core-plugins = { workspace = true }
|
||||
codex-home = { workspace = true }
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
use codex_app_server_protocol::AppBranding as ApiAppBranding;
|
||||
use codex_app_server_protocol::AppInfo as ApiAppInfo;
|
||||
use codex_app_server_protocol::AppMetadata as ApiAppMetadata;
|
||||
use codex_app_server_protocol::AppReview as ApiAppReview;
|
||||
use codex_app_server_protocol::AppScreenshot as ApiAppScreenshot;
|
||||
use codex_connectors::AppBranding;
|
||||
use codex_connectors::AppInfo;
|
||||
use codex_connectors::AppMetadata;
|
||||
use codex_connectors::AppReview;
|
||||
use codex_connectors::AppScreenshot;
|
||||
|
||||
/// Converts connector-domain app metadata owned by `codex-connectors` into the app-server wire
|
||||
/// type owned by `codex-app-server-protocol`.
|
||||
///
|
||||
/// The types stay separate so app-server protocol ownership does not leak into the connector
|
||||
/// domain crate. Because this crate owns neither type, Rust's orphan rules require an explicit
|
||||
/// conversion function instead of a `From` implementation.
|
||||
pub(crate) fn app_info_to_api(app: AppInfo) -> ApiAppInfo {
|
||||
let AppInfo {
|
||||
id,
|
||||
name,
|
||||
description,
|
||||
logo_url,
|
||||
logo_url_dark,
|
||||
distribution_channel,
|
||||
branding,
|
||||
app_metadata,
|
||||
labels,
|
||||
install_url,
|
||||
is_accessible,
|
||||
is_enabled,
|
||||
plugin_display_names,
|
||||
} = app;
|
||||
ApiAppInfo {
|
||||
id,
|
||||
name,
|
||||
description,
|
||||
logo_url,
|
||||
logo_url_dark,
|
||||
distribution_channel,
|
||||
branding: branding.map(app_branding_to_api),
|
||||
app_metadata: app_metadata.map(app_metadata_to_api),
|
||||
labels,
|
||||
install_url,
|
||||
is_accessible,
|
||||
is_enabled,
|
||||
plugin_display_names,
|
||||
}
|
||||
}
|
||||
|
||||
fn app_branding_to_api(branding: AppBranding) -> ApiAppBranding {
|
||||
let AppBranding {
|
||||
category,
|
||||
developer,
|
||||
website,
|
||||
privacy_policy,
|
||||
terms_of_service,
|
||||
is_discoverable_app,
|
||||
} = branding;
|
||||
ApiAppBranding {
|
||||
category,
|
||||
developer,
|
||||
website,
|
||||
privacy_policy,
|
||||
terms_of_service,
|
||||
is_discoverable_app,
|
||||
}
|
||||
}
|
||||
|
||||
fn app_review_to_api(review: AppReview) -> ApiAppReview {
|
||||
let AppReview { status } = review;
|
||||
ApiAppReview { status }
|
||||
}
|
||||
|
||||
fn app_screenshot_to_api(screenshot: AppScreenshot) -> ApiAppScreenshot {
|
||||
let AppScreenshot {
|
||||
url,
|
||||
file_id,
|
||||
user_prompt,
|
||||
} = screenshot;
|
||||
ApiAppScreenshot {
|
||||
url,
|
||||
file_id,
|
||||
user_prompt,
|
||||
}
|
||||
}
|
||||
|
||||
fn app_metadata_to_api(metadata: AppMetadata) -> ApiAppMetadata {
|
||||
let AppMetadata {
|
||||
review,
|
||||
categories,
|
||||
sub_categories,
|
||||
seo_description,
|
||||
screenshots,
|
||||
developer,
|
||||
version,
|
||||
version_id,
|
||||
version_notes,
|
||||
first_party_type,
|
||||
first_party_requires_install,
|
||||
show_in_composer_when_unlinked,
|
||||
} = metadata;
|
||||
ApiAppMetadata {
|
||||
review: review.map(app_review_to_api),
|
||||
categories,
|
||||
sub_categories,
|
||||
seo_description,
|
||||
screenshots: screenshots
|
||||
.map(|screenshots| screenshots.into_iter().map(app_screenshot_to_api).collect()),
|
||||
developer,
|
||||
version,
|
||||
version_id,
|
||||
version_notes,
|
||||
first_party_type,
|
||||
first_party_requires_install,
|
||||
show_in_composer_when_unlinked,
|
||||
}
|
||||
}
|
||||
@@ -80,6 +80,7 @@ use tracing_subscriber::util::SubscriberInitExt;
|
||||
const SQLITE_RECOVERY_CONFIG_WARNING_SUMMARY: &str = "Codex rebuilt its local database.";
|
||||
|
||||
mod analytics_utils;
|
||||
mod app_info;
|
||||
mod app_server_tracing;
|
||||
mod attestation;
|
||||
mod auth_mode;
|
||||
|
||||
@@ -29,7 +29,6 @@ use codex_app_server_protocol::AddCreditsNudgeCreditType;
|
||||
use codex_app_server_protocol::AddCreditsNudgeEmailStatus;
|
||||
use codex_app_server_protocol::AdditionalContextEntry;
|
||||
use codex_app_server_protocol::AdditionalContextKind;
|
||||
use codex_app_server_protocol::AppInfo;
|
||||
use codex_app_server_protocol::AppListUpdatedNotification;
|
||||
use codex_app_server_protocol::AppSummary;
|
||||
use codex_app_server_protocol::AppTemplateSummary;
|
||||
@@ -302,6 +301,7 @@ use codex_config::CloudConfigBundleLoadErrorCode;
|
||||
use codex_config::ConfigLayerStack;
|
||||
use codex_config::loader::project_trust_key;
|
||||
use codex_config::types::McpServerTransportConfig;
|
||||
use codex_connectors::AppInfo;
|
||||
use codex_core::CodexThread;
|
||||
use codex_core::CodexThreadSettingsOverrides;
|
||||
use codex_core::ForkSnapshot;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use super::*;
|
||||
use crate::app_info::app_info_to_api;
|
||||
|
||||
pub(crate) struct AppsRequestProcessor {
|
||||
auth_manager: Arc<AuthManager>,
|
||||
@@ -396,7 +397,11 @@ fn paginate_apps(
|
||||
|
||||
let effective_limit = limit.unwrap_or(total as u32).max(1) as usize;
|
||||
let end = start.saturating_add(effective_limit).min(total);
|
||||
let data = connectors[start..end].to_vec();
|
||||
let data = connectors[start..end]
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(app_info_to_api)
|
||||
.collect();
|
||||
let next_cursor = if end < total {
|
||||
Some(end.to_string())
|
||||
} else {
|
||||
@@ -410,6 +415,7 @@ async fn send_app_list_updated_notification(
|
||||
outgoing: &Arc<OutgoingMessageSender>,
|
||||
data: Vec<AppInfo>,
|
||||
) {
|
||||
let data = data.into_iter().map(app_info_to_api).collect();
|
||||
outgoing
|
||||
.send_server_notification(ServerNotification::AppListUpdated(
|
||||
AppListUpdatedNotification { data },
|
||||
|
||||
@@ -10,7 +10,6 @@ workspace = true
|
||||
[dependencies]
|
||||
anyhow = { workspace = true }
|
||||
clap = { workspace = true, features = ["derive"] }
|
||||
codex-app-server-protocol = { workspace = true }
|
||||
codex-connectors = { workspace = true }
|
||||
codex-core = { workspace = true }
|
||||
codex-git-utils = { workspace = true }
|
||||
|
||||
@@ -4,7 +4,7 @@ use std::time::Duration;
|
||||
|
||||
use crate::chatgpt_client::chatgpt_get_request_with_timeout;
|
||||
|
||||
use codex_app_server_protocol::AppInfo;
|
||||
use codex_connectors::AppInfo;
|
||||
use codex_connectors::ConnectorDirectoryCacheContext;
|
||||
use codex_connectors::ConnectorDirectoryCacheKey;
|
||||
use codex_connectors::DirectoryListResponse;
|
||||
|
||||
@@ -9,7 +9,6 @@ workspace = true
|
||||
|
||||
[dependencies]
|
||||
anyhow = { workspace = true }
|
||||
codex-app-server-protocol = { workspace = true }
|
||||
codex-config = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true }
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use std::collections::BTreeSet;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::AppInfo;
|
||||
use crate::metadata::connector_install_url;
|
||||
use crate::normalize_connector_value;
|
||||
use codex_app_server_protocol::AppInfo;
|
||||
|
||||
pub struct AccessibleConnectorTool {
|
||||
pub connector_id: String,
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
//! Connector-domain app metadata used by directory discovery, caching, and tool selection.
|
||||
//!
|
||||
//! The Serde implementations decode connector-directory response metadata and persist normalized
|
||||
//! app information in the connector-directory disk cache. They do not define the app-server wire
|
||||
//! format; `codex-app-server-protocol` owns separate API types for that boundary.
|
||||
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Branding supplied by the connector directory for an app.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AppBranding {
|
||||
pub category: Option<String>,
|
||||
pub developer: Option<String>,
|
||||
pub website: Option<String>,
|
||||
pub privacy_policy: Option<String>,
|
||||
pub terms_of_service: Option<String>,
|
||||
pub is_discoverable_app: bool,
|
||||
}
|
||||
|
||||
/// Review state supplied by the connector directory for an app.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AppReview {
|
||||
pub status: String,
|
||||
}
|
||||
|
||||
/// Screenshot metadata supplied by the connector directory for an app.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AppScreenshot {
|
||||
pub url: Option<String>,
|
||||
#[serde(alias = "file_id")]
|
||||
pub file_id: Option<String>,
|
||||
#[serde(alias = "user_prompt")]
|
||||
pub user_prompt: String,
|
||||
}
|
||||
|
||||
/// Extended metadata supplied by the connector directory for an app.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AppMetadata {
|
||||
pub review: Option<AppReview>,
|
||||
pub categories: Option<Vec<String>>,
|
||||
pub sub_categories: Option<Vec<String>>,
|
||||
pub seo_description: Option<String>,
|
||||
pub screenshots: Option<Vec<AppScreenshot>>,
|
||||
pub developer: Option<String>,
|
||||
pub version: Option<String>,
|
||||
pub version_id: Option<String>,
|
||||
pub version_notes: Option<String>,
|
||||
pub first_party_type: Option<String>,
|
||||
pub first_party_requires_install: Option<bool>,
|
||||
pub show_in_composer_when_unlinked: Option<bool>,
|
||||
}
|
||||
|
||||
/// Connector metadata used by connector discovery, caching, and tool selection.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AppInfo {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub description: Option<String>,
|
||||
pub logo_url: Option<String>,
|
||||
pub logo_url_dark: Option<String>,
|
||||
pub distribution_channel: Option<String>,
|
||||
pub branding: Option<AppBranding>,
|
||||
pub app_metadata: Option<AppMetadata>,
|
||||
pub labels: Option<HashMap<String, String>>,
|
||||
pub install_url: Option<String>,
|
||||
#[serde(default)]
|
||||
pub is_accessible: bool,
|
||||
#[serde(default = "default_enabled")]
|
||||
pub is_enabled: bool,
|
||||
#[serde(default)]
|
||||
pub plugin_display_names: Vec<String>,
|
||||
}
|
||||
|
||||
impl AppInfo {
|
||||
pub fn category(&self) -> Option<String> {
|
||||
self.branding
|
||||
.as_ref()
|
||||
.and_then(|branding| non_empty_category(branding.category.as_deref()))
|
||||
.or_else(|| {
|
||||
self.app_metadata
|
||||
.as_ref()
|
||||
.and_then(|metadata| metadata.categories.as_ref())
|
||||
.and_then(|categories| {
|
||||
categories
|
||||
.iter()
|
||||
.find_map(|category| non_empty_category(Some(category.as_str())))
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const fn default_enabled() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn non_empty_category(category: Option<&str>) -> Option<String> {
|
||||
let category = category?.trim();
|
||||
if category.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(category.to_string())
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use codex_app_server_protocol::AppInfo;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use sha1::Digest;
|
||||
use sha1::Sha1;
|
||||
use tracing::warn;
|
||||
|
||||
use crate::AppInfo;
|
||||
use crate::ConnectorDirectoryCacheKey;
|
||||
|
||||
pub(crate) const CONNECTOR_DIRECTORY_DISK_CACHE_SCHEMA_VERSION: u8 = 1;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use codex_app_server_protocol::AppInfo;
|
||||
use crate::AppInfo;
|
||||
|
||||
pub fn filter_tool_suggest_discoverable_connectors(
|
||||
directory_connectors: Vec<AppInfo>,
|
||||
|
||||
@@ -5,19 +5,22 @@ use std::sync::Mutex as StdMutex;
|
||||
use std::time::Duration;
|
||||
use std::time::Instant;
|
||||
|
||||
use codex_app_server_protocol::AppBranding;
|
||||
use codex_app_server_protocol::AppInfo;
|
||||
use codex_app_server_protocol::AppMetadata;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
pub mod accessible;
|
||||
mod app_info;
|
||||
mod app_tool_policy;
|
||||
mod directory_cache;
|
||||
pub mod filter;
|
||||
pub mod merge;
|
||||
pub mod metadata;
|
||||
|
||||
pub use app_info::AppBranding;
|
||||
pub use app_info::AppInfo;
|
||||
pub use app_info::AppMetadata;
|
||||
pub use app_info::AppReview;
|
||||
pub use app_info::AppScreenshot;
|
||||
pub use app_tool_policy::AppToolPolicy;
|
||||
pub use app_tool_policy::AppToolPolicyEvaluator;
|
||||
pub use app_tool_policy::AppToolPolicyInput;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
|
||||
use crate::AppInfo;
|
||||
use crate::metadata::connector_install_url;
|
||||
use crate::metadata::sort_connectors_by_accessibility_and_name;
|
||||
use codex_app_server_protocol::AppInfo;
|
||||
|
||||
pub fn merge_connectors(
|
||||
connectors: Vec<AppInfo>,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use codex_app_server_protocol::AppInfo;
|
||||
use crate::AppInfo;
|
||||
|
||||
pub fn connector_display_label(connector: &AppInfo) -> String {
|
||||
connector.name.clone()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::connectors::AppInfo;
|
||||
use crate::context::AppsInstructions;
|
||||
use crate::context::ContextualUserFragment;
|
||||
use codex_app_server_protocol::AppInfo;
|
||||
use codex_protocol::protocol::APPS_INSTRUCTIONS_CLOSE_TAG;
|
||||
use codex_protocol::protocol::APPS_INSTRUCTIONS_OPEN_TAG;
|
||||
|
||||
|
||||
@@ -6,9 +6,9 @@ use std::time::Duration;
|
||||
use std::time::Instant;
|
||||
|
||||
use async_channel::unbounded;
|
||||
pub use codex_app_server_protocol::AppBranding;
|
||||
pub use codex_app_server_protocol::AppInfo;
|
||||
pub use codex_app_server_protocol::AppMetadata;
|
||||
pub use codex_connectors::AppBranding;
|
||||
pub use codex_connectors::AppInfo;
|
||||
pub use codex_connectors::AppMetadata;
|
||||
use codex_connectors::ConnectorDirectoryCacheContext;
|
||||
use codex_connectors::ConnectorDirectoryCacheKey;
|
||||
use codex_connectors::app_is_enabled;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use codex_app_server_protocol::AppInfo;
|
||||
use crate::connectors::AppInfo;
|
||||
use codex_mcp::CODEX_APPS_MCP_SERVER_NAME;
|
||||
use codex_protocol::protocol::APPS_INSTRUCTIONS_CLOSE_TAG;
|
||||
use codex_protocol::protocol::APPS_INSTRUCTIONS_OPEN_TAG;
|
||||
|
||||
@@ -66,6 +66,7 @@ use codex_protocol::request_permissions::RequestPermissionProfile;
|
||||
use codex_utils_path_uri::PathUri;
|
||||
use tracing::Span;
|
||||
|
||||
use crate::connectors::AppInfo;
|
||||
use crate::rollout::recorder::RolloutRecorder;
|
||||
use crate::state::ActiveTurn;
|
||||
use crate::state::TaskKind;
|
||||
@@ -83,7 +84,6 @@ use crate::tools::handlers::ShellCommandHandler;
|
||||
use crate::tools::registry::ToolExecutor;
|
||||
use crate::tools::router::ToolCallSource;
|
||||
use crate::turn_diff_tracker::TurnDiffTracker;
|
||||
use codex_app_server_protocol::AppInfo;
|
||||
use codex_app_server_protocol::McpElicitationSchema;
|
||||
use codex_config::config_toml::ConfigToml;
|
||||
use codex_config::config_toml::ProjectConfig;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use codex_app_server_protocol::AppInfo;
|
||||
use crate::connectors::AppInfo;
|
||||
use codex_config::types::ToolSuggestDisabledTool;
|
||||
use codex_core_plugins::remote::REMOTE_GLOBAL_MARKETPLACE_NAME;
|
||||
use codex_mcp::CODEX_APPS_MCP_SERVER_NAME;
|
||||
|
||||
@@ -10,6 +10,7 @@ workspace = true
|
||||
[dependencies]
|
||||
codex-app-server-protocol = { workspace = true }
|
||||
codex-code-mode = { workspace = true }
|
||||
codex-connectors = { workspace = true }
|
||||
codex-features = { workspace = true }
|
||||
codex-file-system = { workspace = true }
|
||||
codex-protocol = { workspace = true }
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use codex_app_server_protocol::AppInfo;
|
||||
use codex_app_server_protocol::McpElicitationObjectType;
|
||||
use codex_app_server_protocol::McpElicitationSchema;
|
||||
use codex_app_server_protocol::McpServerElicitationRequest;
|
||||
use codex_app_server_protocol::McpServerElicitationRequestParams;
|
||||
use codex_connectors::AppInfo;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use serde_json::json;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use codex_app_server_protocol::AppInfo;
|
||||
use codex_connectors::AppInfo;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use super::*;
|
||||
use codex_app_server_protocol::AppInfo;
|
||||
use codex_connectors::AppInfo;
|
||||
use pretty_assertions::assert_eq;
|
||||
use serde_json::json;
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ use super::app_server_event_targets::server_request_thread_id;
|
||||
use crate::app_command::AppCommand;
|
||||
use crate::app_event::AppEvent;
|
||||
use crate::app_event::ConnectorsSnapshot;
|
||||
use crate::app_info::app_info_from_api;
|
||||
use crate::app_server_session::AppServerSession;
|
||||
use crate::app_server_session::status_account_display_from_auth_mode;
|
||||
use codex_app_server_client::AppServerEvent;
|
||||
@@ -127,7 +128,12 @@ impl App {
|
||||
ServerNotification::AppListUpdated(notification) => {
|
||||
self.chat_widget.on_connectors_loaded(
|
||||
Ok(ConnectorsSnapshot {
|
||||
connectors: notification.data.clone(),
|
||||
connectors: notification
|
||||
.data
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(app_info_from_api)
|
||||
.collect(),
|
||||
}),
|
||||
/*is_final*/ false,
|
||||
);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
use super::plugin_mentions::fetch_plugin_mentions;
|
||||
use super::*;
|
||||
use crate::app_event::ConnectorsSnapshot;
|
||||
use crate::app_info::app_info_from_api;
|
||||
use crate::config_update::format_config_error;
|
||||
use codex_app_server_protocol::AppsListParams;
|
||||
use codex_app_server_protocol::AppsListResponse;
|
||||
@@ -870,7 +871,7 @@ pub(super) async fn fetch_connectors_list(
|
||||
.await
|
||||
.wrap_err("app/list failed in TUI")?;
|
||||
Ok(ConnectorsSnapshot {
|
||||
connectors: response.data,
|
||||
connectors: response.data.into_iter().map(app_info_from_api).collect(),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ use std::path::PathBuf;
|
||||
|
||||
use codex_app_server_protocol::AddCreditsNudgeCreditType;
|
||||
use codex_app_server_protocol::AddCreditsNudgeEmailStatus;
|
||||
use codex_app_server_protocol::AppInfo;
|
||||
use codex_app_server_protocol::ConsumeAccountRateLimitResetCreditResponse;
|
||||
use codex_app_server_protocol::GetAccountRateLimitsResponse;
|
||||
use codex_app_server_protocol::GetAccountTokenUsageResponse;
|
||||
@@ -29,6 +28,7 @@ use codex_app_server_protocol::PluginReadResponse;
|
||||
use codex_app_server_protocol::PluginUninstallResponse;
|
||||
use codex_app_server_protocol::SkillsListResponse;
|
||||
use codex_app_server_protocol::ThreadGoalStatus;
|
||||
use codex_connectors::AppInfo;
|
||||
use codex_file_search::FileMatch;
|
||||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::openai_models::ModelPreset;
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
use codex_app_server_protocol::AppBranding as ApiAppBranding;
|
||||
use codex_app_server_protocol::AppInfo as ApiAppInfo;
|
||||
use codex_app_server_protocol::AppMetadata as ApiAppMetadata;
|
||||
use codex_app_server_protocol::AppReview as ApiAppReview;
|
||||
use codex_app_server_protocol::AppScreenshot as ApiAppScreenshot;
|
||||
use codex_connectors::AppBranding;
|
||||
use codex_connectors::AppInfo;
|
||||
use codex_connectors::AppMetadata;
|
||||
use codex_connectors::AppReview;
|
||||
use codex_connectors::AppScreenshot;
|
||||
|
||||
/// Converts the app-server wire type owned by `codex-app-server-protocol` into connector-domain
|
||||
/// app metadata owned by `codex-connectors`.
|
||||
///
|
||||
/// The types stay separate so app-server protocol ownership does not leak into the connector
|
||||
/// domain crate. Because this crate owns neither type, Rust's orphan rules require an explicit
|
||||
/// conversion function instead of a `From` implementation.
|
||||
pub(crate) fn app_info_from_api(app: ApiAppInfo) -> AppInfo {
|
||||
let ApiAppInfo {
|
||||
id,
|
||||
name,
|
||||
description,
|
||||
logo_url,
|
||||
logo_url_dark,
|
||||
distribution_channel,
|
||||
branding,
|
||||
app_metadata,
|
||||
labels,
|
||||
install_url,
|
||||
is_accessible,
|
||||
is_enabled,
|
||||
plugin_display_names,
|
||||
} = app;
|
||||
AppInfo {
|
||||
id,
|
||||
name,
|
||||
description,
|
||||
logo_url,
|
||||
logo_url_dark,
|
||||
distribution_channel,
|
||||
branding: branding.map(app_branding_from_api),
|
||||
app_metadata: app_metadata.map(app_metadata_from_api),
|
||||
labels,
|
||||
install_url,
|
||||
is_accessible,
|
||||
is_enabled,
|
||||
plugin_display_names,
|
||||
}
|
||||
}
|
||||
|
||||
fn app_branding_from_api(branding: ApiAppBranding) -> AppBranding {
|
||||
let ApiAppBranding {
|
||||
category,
|
||||
developer,
|
||||
website,
|
||||
privacy_policy,
|
||||
terms_of_service,
|
||||
is_discoverable_app,
|
||||
} = branding;
|
||||
AppBranding {
|
||||
category,
|
||||
developer,
|
||||
website,
|
||||
privacy_policy,
|
||||
terms_of_service,
|
||||
is_discoverable_app,
|
||||
}
|
||||
}
|
||||
|
||||
fn app_review_from_api(review: ApiAppReview) -> AppReview {
|
||||
let ApiAppReview { status } = review;
|
||||
AppReview { status }
|
||||
}
|
||||
|
||||
fn app_screenshot_from_api(screenshot: ApiAppScreenshot) -> AppScreenshot {
|
||||
let ApiAppScreenshot {
|
||||
url,
|
||||
file_id,
|
||||
user_prompt,
|
||||
} = screenshot;
|
||||
AppScreenshot {
|
||||
url,
|
||||
file_id,
|
||||
user_prompt,
|
||||
}
|
||||
}
|
||||
|
||||
fn app_metadata_from_api(metadata: ApiAppMetadata) -> AppMetadata {
|
||||
let ApiAppMetadata {
|
||||
review,
|
||||
categories,
|
||||
sub_categories,
|
||||
seo_description,
|
||||
screenshots,
|
||||
developer,
|
||||
version,
|
||||
version_id,
|
||||
version_notes,
|
||||
first_party_type,
|
||||
first_party_requires_install,
|
||||
show_in_composer_when_unlinked,
|
||||
} = metadata;
|
||||
AppMetadata {
|
||||
review: review.map(app_review_from_api),
|
||||
categories,
|
||||
sub_categories,
|
||||
seo_description,
|
||||
screenshots: screenshots.map(|screenshots| {
|
||||
screenshots
|
||||
.into_iter()
|
||||
.map(app_screenshot_from_api)
|
||||
.collect()
|
||||
}),
|
||||
developer,
|
||||
version,
|
||||
version_id,
|
||||
version_notes,
|
||||
first_party_type,
|
||||
first_party_requires_install,
|
||||
show_in_composer_when_unlinked,
|
||||
}
|
||||
}
|
||||
@@ -241,7 +241,7 @@ use crate::history_cell;
|
||||
use crate::skills_helpers::skill_display_name;
|
||||
use crate::tui::FrameRequester;
|
||||
use crate::ui_consts::LIVE_PREFIX_COLS;
|
||||
use codex_app_server_protocol::AppInfo;
|
||||
use codex_connectors::AppInfo;
|
||||
#[cfg(test)]
|
||||
use codex_core_skills::model::SkillInterface;
|
||||
use codex_core_skills::model::SkillMetadata;
|
||||
|
||||
@@ -80,7 +80,6 @@ use crate::token_usage::TokenUsageInfo;
|
||||
use crate::version::CODEX_CLI_VERSION;
|
||||
use codex_app_server_protocol::AddCreditsNudgeCreditType;
|
||||
use codex_app_server_protocol::AddCreditsNudgeEmailStatus;
|
||||
use codex_app_server_protocol::AppInfo;
|
||||
use codex_app_server_protocol::AppSummary;
|
||||
use codex_app_server_protocol::CodexErrorInfo as AppServerCodexErrorInfo;
|
||||
use codex_app_server_protocol::CollabAgentTool;
|
||||
@@ -123,6 +122,7 @@ use codex_config::ConstraintResult;
|
||||
use codex_config::types::ApprovalsReviewer;
|
||||
use codex_config::types::Notifications;
|
||||
use codex_config::types::WindowsSandboxModeToml;
|
||||
use codex_connectors::AppInfo;
|
||||
use codex_core_skills::model::SkillMetadata;
|
||||
use codex_features::FEATURES;
|
||||
use codex_features::Feature;
|
||||
|
||||
@@ -10,10 +10,10 @@ use crate::bottom_pane::SkillsToggleView;
|
||||
use crate::bottom_pane::popup_consts::standard_popup_hint_line;
|
||||
use crate::skills_helpers::skill_description;
|
||||
use crate::skills_helpers::skill_display_name;
|
||||
use codex_app_server_protocol::AppInfo;
|
||||
use codex_app_server_protocol::SkillMetadata as ProtocolSkillMetadata;
|
||||
use codex_app_server_protocol::SkillsListEntry;
|
||||
use codex_app_server_protocol::SkillsListResponse;
|
||||
use codex_connectors::AppInfo;
|
||||
use codex_core_skills::model::SkillDependencies;
|
||||
use codex_core_skills::model::SkillInterface;
|
||||
use codex_core_skills::model::SkillMetadata;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use super::*;
|
||||
use crate::app_event::ConnectorsSnapshot;
|
||||
use crate::chatwidget::connectors::ConnectorsCacheState;
|
||||
use codex_app_server_protocol::AppInfo;
|
||||
use codex_app_server_protocol::HookErrorInfo;
|
||||
use codex_app_server_protocol::HooksListEntry;
|
||||
use codex_app_server_protocol::HooksListResponse;
|
||||
@@ -11,6 +10,7 @@ use codex_app_server_protocol::PluginAvailability;
|
||||
use codex_app_server_protocol::PluginShareContext;
|
||||
use codex_app_server_protocol::PluginShareDiscoverability;
|
||||
use codex_app_server_protocol::PluginSource;
|
||||
use codex_connectors::AppInfo;
|
||||
use codex_features::Stage;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
|
||||
@@ -91,6 +91,7 @@ mod app_backtrack;
|
||||
mod app_command;
|
||||
mod app_event;
|
||||
mod app_event_sender;
|
||||
mod app_info;
|
||||
mod app_server_approval_conversions;
|
||||
mod app_server_session;
|
||||
mod approval_events;
|
||||
|
||||
Reference in New Issue
Block a user