mirror of
https://github.com/openai/codex.git
synced 2026-10-23 18:08:45 +00:00
Add plugin list force refetch
This commit is contained in:
@@ -1905,6 +1905,10 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"forceRefetch": {
|
||||
"description": "When true, bypass app/tool caches that can stay stale after external app re-auth.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"marketplaceKinds": {
|
||||
"description": "Optional marketplace kind filter. When omitted, only local marketplaces are queried, plus the default remote catalog when enabled by feature flag.",
|
||||
"items": {
|
||||
|
||||
+4
@@ -13525,6 +13525,10 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"forceRefetch": {
|
||||
"description": "When true, bypass app/tool caches that can stay stale after external app re-auth.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"marketplaceKinds": {
|
||||
"description": "Optional marketplace kind filter. When omitted, only local marketplaces are queried, plus the default remote catalog when enabled by feature flag.",
|
||||
"items": {
|
||||
|
||||
+4
@@ -9929,6 +9929,10 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"forceRefetch": {
|
||||
"description": "When true, bypass app/tool caches that can stay stale after external app re-auth.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"marketplaceKinds": {
|
||||
"description": "Optional marketplace kind filter. When omitted, only local marketplaces are queried, plus the default remote catalog when enabled by feature flag.",
|
||||
"items": {
|
||||
|
||||
@@ -27,6 +27,10 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"forceRefetch": {
|
||||
"description": "When true, bypass app/tool caches that can stay stale after external app re-auth.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"marketplaceKinds": {
|
||||
"description": "Optional marketplace kind filter. When omitted, only local marketplaces are queried, plus the default remote catalog when enabled by feature flag.",
|
||||
"items": {
|
||||
|
||||
@@ -14,4 +14,8 @@ cwds?: Array<AbsolutePathBuf> | null,
|
||||
* Optional marketplace kind filter. When omitted, only local marketplaces are queried, plus
|
||||
* the default remote catalog when enabled by feature flag.
|
||||
*/
|
||||
marketplaceKinds?: Array<PluginListMarketplaceKind> | null, };
|
||||
marketplaceKinds?: Array<PluginListMarketplaceKind> | null,
|
||||
/**
|
||||
* When true, bypass app/tool caches that can stay stale after external app re-auth.
|
||||
*/
|
||||
forceRefetch?: boolean, };
|
||||
|
||||
@@ -1875,6 +1875,7 @@ mod tests {
|
||||
params: v2::PluginListParams {
|
||||
cwds: None,
|
||||
marketplace_kinds: None,
|
||||
force_refetch: false,
|
||||
},
|
||||
};
|
||||
assert_eq!(plugin_list.serialization_scope(), None);
|
||||
|
||||
@@ -135,6 +135,9 @@ pub struct PluginListParams {
|
||||
/// the default remote catalog when enabled by feature flag.
|
||||
#[ts(optional = nullable)]
|
||||
pub marketplace_kinds: Option<Vec<PluginListMarketplaceKind>>,
|
||||
/// When true, bypass app/tool caches that can stay stale after external app re-auth.
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
pub force_refetch: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
|
||||
@@ -3032,6 +3032,7 @@ fn plugin_list_params_ignore_removed_force_remote_sync_field() {
|
||||
PluginListParams {
|
||||
cwds: None,
|
||||
marketplace_kinds: None,
|
||||
force_refetch: false,
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -3048,6 +3049,7 @@ fn plugin_list_params_serializes_marketplace_kind_filter() {
|
||||
PluginListMarketplaceKind::SharedWithMe,
|
||||
PluginListMarketplaceKind::CreatedByMeRemote,
|
||||
]),
|
||||
force_refetch: false,
|
||||
})
|
||||
.unwrap(),
|
||||
json!({
|
||||
@@ -3063,6 +3065,23 @@ fn plugin_list_params_serializes_marketplace_kind_filter() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn plugin_list_params_serializes_force_refetch_when_enabled() {
|
||||
assert_eq!(
|
||||
serde_json::to_value(PluginListParams {
|
||||
cwds: None,
|
||||
marketplace_kinds: None,
|
||||
force_refetch: true,
|
||||
})
|
||||
.unwrap(),
|
||||
json!({
|
||||
"cwds": null,
|
||||
"marketplaceKinds": null,
|
||||
"forceRefetch": true,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn plugin_installed_params_serializes_install_suggestion_names() {
|
||||
assert_eq!(
|
||||
|
||||
@@ -533,6 +533,7 @@ impl PluginRequestProcessor {
|
||||
let PluginListParams {
|
||||
cwds,
|
||||
marketplace_kinds,
|
||||
force_refetch,
|
||||
} = params;
|
||||
let roots = cwds.unwrap_or_default();
|
||||
let explicit_marketplace_kinds = marketplace_kinds.is_some();
|
||||
@@ -560,6 +561,10 @@ impl PluginRequestProcessor {
|
||||
let auth_mode = auth.as_ref().map(CodexAuth::api_auth_mode);
|
||||
plugins_manager.set_auth_mode(auth_mode);
|
||||
let plugins_input = config.plugins_config_input();
|
||||
if force_refetch {
|
||||
self.force_refresh_app_caches_for_plugin_list(&config, auth.as_ref())
|
||||
.await;
|
||||
}
|
||||
let include_shared_with_me =
|
||||
marketplace_kinds.contains(&PluginListMarketplaceKind::SharedWithMe);
|
||||
let include_created_by_me_remote = marketplace_kinds
|
||||
@@ -738,6 +743,7 @@ impl PluginRequestProcessor {
|
||||
|| include_shared_with_me
|
||||
|| include_global_remote
|
||||
{
|
||||
let on_effective_plugins_changed = Some(self.effective_plugins_changed_callback());
|
||||
plugins_manager.maybe_start_plugin_list_background_tasks_for_config(
|
||||
&plugins_input,
|
||||
auth.clone(),
|
||||
@@ -745,8 +751,15 @@ impl PluginRequestProcessor {
|
||||
PluginListBackgroundTaskOptions {
|
||||
refresh_global_remote_catalog_cache,
|
||||
},
|
||||
Some(self.effective_plugins_changed_callback()),
|
||||
on_effective_plugins_changed.clone(),
|
||||
);
|
||||
if force_refetch {
|
||||
plugins_manager.maybe_start_remote_installed_plugins_cache_refresh_after_mutation(
|
||||
&plugins_input,
|
||||
auth.clone(),
|
||||
on_effective_plugins_changed,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let featured_plugin_ids = if data.iter().any(|marketplace| {
|
||||
@@ -777,6 +790,64 @@ impl PluginRequestProcessor {
|
||||
})
|
||||
}
|
||||
|
||||
async fn force_refresh_app_caches_for_plugin_list(
|
||||
&self,
|
||||
config: &Config,
|
||||
auth: Option<&CodexAuth>,
|
||||
) {
|
||||
if !config
|
||||
.features
|
||||
.apps_enabled_for_auth(auth.is_some_and(CodexAuth::uses_codex_backend))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
let plugins_manager = self.thread_manager.plugins_manager();
|
||||
let plugin_apps = plugins_manager
|
||||
.plugins_for_config(&config.plugins_config_input())
|
||||
.await
|
||||
.effective_apps();
|
||||
let environment_manager = self.thread_manager.environment_manager();
|
||||
let (all_connectors_result, accessible_connectors_result) = tokio::join!(
|
||||
connectors::list_all_connectors_with_options(
|
||||
config,
|
||||
/*force_refetch*/ true,
|
||||
&plugin_apps,
|
||||
),
|
||||
connectors::list_accessible_connectors_from_mcp_tools_with_mcp_manager(
|
||||
config,
|
||||
/*force_refetch*/ true,
|
||||
Arc::clone(&environment_manager),
|
||||
self.thread_manager.mcp_manager(),
|
||||
),
|
||||
);
|
||||
|
||||
match all_connectors_result {
|
||||
Ok(_) => {}
|
||||
Err(err) => {
|
||||
warn!("plugin/list forceRefetch failed to refresh app directory cache: {err:#}");
|
||||
}
|
||||
}
|
||||
let mut refreshed_codex_apps_tools_cache = false;
|
||||
match accessible_connectors_result {
|
||||
Ok(status) => {
|
||||
refreshed_codex_apps_tools_cache = true;
|
||||
if !status.codex_apps_ready {
|
||||
warn!(
|
||||
"plugin/list forceRefetch refreshed Codex Apps cache before codex-apps was ready"
|
||||
);
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
warn!("plugin/list forceRefetch failed to refresh Codex Apps tools cache: {err:#}");
|
||||
}
|
||||
}
|
||||
|
||||
if refreshed_codex_apps_tools_cache {
|
||||
self.on_effective_plugins_changed();
|
||||
}
|
||||
}
|
||||
|
||||
async fn plugin_installed_response(
|
||||
&self,
|
||||
params: PluginInstalledParams,
|
||||
|
||||
@@ -504,6 +504,7 @@ async fn external_agent_config_import_sends_completion_notification_for_local_pl
|
||||
.send_plugin_list_request(PluginListParams {
|
||||
cwds: None,
|
||||
marketplace_kinds: None,
|
||||
force_refetch: false,
|
||||
})
|
||||
.await?;
|
||||
let response: JSONRPCResponse = timeout(
|
||||
|
||||
@@ -97,6 +97,7 @@ async fn plugin_list_skips_invalid_marketplace_file_and_reports_error() -> Resul
|
||||
.send_plugin_list_request(PluginListParams {
|
||||
cwds: Some(vec![AbsolutePathBuf::try_from(repo_root.path())?]),
|
||||
marketplace_kinds: None,
|
||||
force_refetch: false,
|
||||
})
|
||||
.await?;
|
||||
|
||||
@@ -417,6 +418,7 @@ async fn plugin_list_keeps_valid_marketplaces_when_another_marketplace_fails_to_
|
||||
AbsolutePathBuf::try_from(invalid_repo_root.path())?,
|
||||
]),
|
||||
marketplace_kinds: None,
|
||||
force_refetch: false,
|
||||
})
|
||||
.await?;
|
||||
|
||||
@@ -531,6 +533,7 @@ async fn plugin_list_returns_empty_when_workspace_codex_plugins_disabled() -> Re
|
||||
.send_plugin_list_request(PluginListParams {
|
||||
cwds: Some(vec![AbsolutePathBuf::try_from(repo_root.path())?]),
|
||||
marketplace_kinds: None,
|
||||
force_refetch: false,
|
||||
})
|
||||
.await?;
|
||||
|
||||
@@ -623,6 +626,7 @@ async fn plugin_list_reuses_cached_workspace_codex_plugins_setting() -> Result<(
|
||||
.send_plugin_list_request(PluginListParams {
|
||||
cwds: Some(vec![AbsolutePathBuf::try_from(repo_root.path())?]),
|
||||
marketplace_kinds: None,
|
||||
force_refetch: false,
|
||||
})
|
||||
.await?;
|
||||
|
||||
@@ -707,6 +711,7 @@ async fn plugin_list_uses_alternate_discoverable_manifest_and_keeps_undiscoverab
|
||||
.send_plugin_list_request(PluginListParams {
|
||||
cwds: Some(vec![AbsolutePathBuf::try_from(repo_root.path())?]),
|
||||
marketplace_kinds: None,
|
||||
force_refetch: false,
|
||||
})
|
||||
.await?;
|
||||
|
||||
@@ -822,6 +827,7 @@ async fn plugin_list_accepts_omitted_cwds() -> Result<()> {
|
||||
.send_plugin_list_request(PluginListParams {
|
||||
cwds: None,
|
||||
marketplace_kinds: None,
|
||||
force_refetch: false,
|
||||
})
|
||||
.await?;
|
||||
|
||||
@@ -875,6 +881,7 @@ async fn plugin_list_returns_share_context_for_shared_local_plugin() -> Result<(
|
||||
.send_plugin_list_request(PluginListParams {
|
||||
cwds: Some(vec![AbsolutePathBuf::try_from(repo_root.path())?]),
|
||||
marketplace_kinds: None,
|
||||
force_refetch: false,
|
||||
})
|
||||
.await?;
|
||||
|
||||
@@ -967,6 +974,7 @@ enabled = false
|
||||
.send_plugin_list_request(PluginListParams {
|
||||
cwds: Some(vec![AbsolutePathBuf::try_from(repo_root.path())?]),
|
||||
marketplace_kinds: None,
|
||||
force_refetch: false,
|
||||
})
|
||||
.await?;
|
||||
|
||||
@@ -1124,6 +1132,7 @@ enabled = false
|
||||
AbsolutePathBuf::try_from(workspace_default.path())?,
|
||||
]),
|
||||
marketplace_kinds: None,
|
||||
force_refetch: false,
|
||||
})
|
||||
.await?;
|
||||
|
||||
@@ -1208,6 +1217,7 @@ async fn plugin_list_returns_plugin_interface_with_absolute_asset_paths() -> Res
|
||||
.send_plugin_list_request(PluginListParams {
|
||||
cwds: Some(vec![AbsolutePathBuf::try_from(repo_root.path())?]),
|
||||
marketplace_kinds: None,
|
||||
force_refetch: false,
|
||||
})
|
||||
.await?;
|
||||
|
||||
@@ -1321,6 +1331,7 @@ async fn plugin_list_accepts_legacy_string_default_prompt() -> Result<()> {
|
||||
.send_plugin_list_request(PluginListParams {
|
||||
cwds: Some(vec![AbsolutePathBuf::try_from(repo_root.path())?]),
|
||||
marketplace_kinds: None,
|
||||
force_refetch: false,
|
||||
})
|
||||
.await?;
|
||||
|
||||
@@ -1409,6 +1420,7 @@ enabled = true
|
||||
.send_plugin_list_request(PluginListParams {
|
||||
cwds: Some(vec![AbsolutePathBuf::try_from(repo_root.path())?]),
|
||||
marketplace_kinds: None,
|
||||
force_refetch: false,
|
||||
})
|
||||
.await?;
|
||||
|
||||
@@ -1599,6 +1611,7 @@ async fn plugin_list_sync_upgrades_and_removes_remote_installed_plugin_bundles()
|
||||
.send_plugin_list_request(PluginListParams {
|
||||
cwds: None,
|
||||
marketplace_kinds: None,
|
||||
force_refetch: false,
|
||||
})
|
||||
.await?;
|
||||
let response: JSONRPCResponse = timeout(
|
||||
@@ -1779,6 +1792,7 @@ async fn plugin_list_includes_remote_marketplaces_when_remote_plugin_enabled() -
|
||||
.send_plugin_list_request(PluginListParams {
|
||||
cwds: None,
|
||||
marketplace_kinds: None,
|
||||
force_refetch: false,
|
||||
})
|
||||
.await?;
|
||||
|
||||
@@ -1922,6 +1936,7 @@ async fn plugin_list_uses_cached_global_remote_catalog_and_refreshes_it() -> Res
|
||||
.send_plugin_list_request(PluginListParams {
|
||||
cwds: None,
|
||||
marketplace_kinds: None,
|
||||
force_refetch: false,
|
||||
})
|
||||
.await?;
|
||||
let response: PluginListResponse = to_response(
|
||||
@@ -1955,6 +1970,7 @@ async fn plugin_list_uses_cached_global_remote_catalog_and_refreshes_it() -> Res
|
||||
.send_plugin_list_request(PluginListParams {
|
||||
cwds: None,
|
||||
marketplace_kinds: None,
|
||||
force_refetch: false,
|
||||
})
|
||||
.await?;
|
||||
let response: PluginListResponse = to_response(
|
||||
@@ -2036,6 +2052,7 @@ async fn plugin_list_includes_openai_curated_remote_collection_when_requested()
|
||||
.send_plugin_list_request(PluginListParams {
|
||||
cwds: None,
|
||||
marketplace_kinds: Some(vec![PluginListMarketplaceKind::Vertical]),
|
||||
force_refetch: false,
|
||||
})
|
||||
.await?;
|
||||
let response: JSONRPCResponse = timeout(
|
||||
@@ -2124,6 +2141,7 @@ async fn plugin_list_propagates_explicit_openai_curated_remote_collection_errors
|
||||
.send_plugin_list_request(PluginListParams {
|
||||
cwds: None,
|
||||
marketplace_kinds: Some(vec![PluginListMarketplaceKind::Vertical]),
|
||||
force_refetch: false,
|
||||
})
|
||||
.await?;
|
||||
let err = timeout(
|
||||
@@ -2163,6 +2181,7 @@ async fn plugin_list_skips_explicit_openai_curated_remote_collection_for_api_aut
|
||||
.send_plugin_list_request(PluginListParams {
|
||||
cwds: None,
|
||||
marketplace_kinds: Some(vec![PluginListMarketplaceKind::Vertical]),
|
||||
force_refetch: false,
|
||||
})
|
||||
.await?;
|
||||
let response: JSONRPCResponse = timeout(
|
||||
@@ -2202,6 +2221,7 @@ async fn plugin_list_includes_api_curated_marketplace_for_api_auth_when_remote_p
|
||||
.send_plugin_list_request(PluginListParams {
|
||||
cwds: None,
|
||||
marketplace_kinds: None,
|
||||
force_refetch: false,
|
||||
})
|
||||
.await?;
|
||||
let response: JSONRPCResponse = timeout(
|
||||
@@ -2257,6 +2277,7 @@ async fn plugin_list_does_not_query_openai_curated_remote_collection_by_default(
|
||||
.send_plugin_list_request(PluginListParams {
|
||||
cwds: None,
|
||||
marketplace_kinds: None,
|
||||
force_refetch: false,
|
||||
})
|
||||
.await?;
|
||||
let response: JSONRPCResponse = timeout(
|
||||
@@ -2310,6 +2331,7 @@ async fn plugin_list_vertical_kind_noops_when_remote_plugin_enabled() -> Result<
|
||||
.send_plugin_list_request(PluginListParams {
|
||||
cwds: None,
|
||||
marketplace_kinds: Some(vec![PluginListMarketplaceKind::Vertical]),
|
||||
force_refetch: false,
|
||||
})
|
||||
.await?;
|
||||
let response: JSONRPCResponse = timeout(
|
||||
@@ -2364,6 +2386,7 @@ async fn plugin_list_does_not_append_global_remote_when_marketplace_kinds_are_ex
|
||||
.send_plugin_list_request(PluginListParams {
|
||||
cwds: None,
|
||||
marketplace_kinds: Some(vec![PluginListMarketplaceKind::Local]),
|
||||
force_refetch: false,
|
||||
})
|
||||
.await?;
|
||||
|
||||
@@ -2785,6 +2808,7 @@ async fn plugin_list_fetches_workspace_directory_kind_without_remote_plugin_flag
|
||||
.send_plugin_list_request(PluginListParams {
|
||||
cwds: None,
|
||||
marketplace_kinds: Some(vec![PluginListMarketplaceKind::WorkspaceDirectory]),
|
||||
force_refetch: false,
|
||||
})
|
||||
.await?;
|
||||
|
||||
@@ -2912,6 +2936,7 @@ plugin_sharing = false
|
||||
.send_plugin_list_request(PluginListParams {
|
||||
cwds: None,
|
||||
marketplace_kinds: Some(vec![PluginListMarketplaceKind::CreatedByMeRemote]),
|
||||
force_refetch: false,
|
||||
})
|
||||
.await?;
|
||||
|
||||
@@ -3039,6 +3064,7 @@ async fn plugin_list_fetches_shared_with_me_kind() -> Result<()> {
|
||||
.send_plugin_list_request(PluginListParams {
|
||||
cwds: None,
|
||||
marketplace_kinds: Some(vec![PluginListMarketplaceKind::SharedWithMe]),
|
||||
force_refetch: false,
|
||||
})
|
||||
.await?;
|
||||
|
||||
@@ -3196,6 +3222,7 @@ plugin_sharing = false
|
||||
.send_plugin_list_request(PluginListParams {
|
||||
cwds: None,
|
||||
marketplace_kinds: Some(vec![PluginListMarketplaceKind::SharedWithMe]),
|
||||
force_refetch: false,
|
||||
})
|
||||
.await?;
|
||||
|
||||
@@ -3256,6 +3283,7 @@ plugin_sharing = true
|
||||
.send_plugin_list_request(PluginListParams {
|
||||
cwds: None,
|
||||
marketplace_kinds: Some(vec![PluginListMarketplaceKind::CreatedByMeRemote]),
|
||||
force_refetch: false,
|
||||
})
|
||||
.await?;
|
||||
|
||||
@@ -3386,6 +3414,7 @@ async fn plugin_list_marks_remote_plugin_disabled_by_admin() -> Result<()> {
|
||||
.send_plugin_list_request(PluginListParams {
|
||||
cwds: None,
|
||||
marketplace_kinds: None,
|
||||
force_refetch: false,
|
||||
})
|
||||
.await?;
|
||||
|
||||
@@ -3446,6 +3475,7 @@ remote_plugin = true
|
||||
.send_plugin_list_request(PluginListParams {
|
||||
cwds: None,
|
||||
marketplace_kinds: None,
|
||||
force_refetch: false,
|
||||
})
|
||||
.await?;
|
||||
|
||||
@@ -3482,6 +3512,7 @@ async fn plugin_list_fetches_featured_plugin_ids_without_chatgpt_auth() -> Resul
|
||||
.send_plugin_list_request(PluginListParams {
|
||||
cwds: None,
|
||||
marketplace_kinds: None,
|
||||
force_refetch: false,
|
||||
})
|
||||
.await?;
|
||||
|
||||
@@ -3522,6 +3553,7 @@ async fn plugin_list_uses_warmed_featured_plugin_ids_cache_on_first_request() ->
|
||||
.send_plugin_list_request(PluginListParams {
|
||||
cwds: None,
|
||||
marketplace_kinds: None,
|
||||
force_refetch: false,
|
||||
})
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -719,6 +719,7 @@ async fn plugin_share_checkout_adds_personal_marketplace_entry() -> Result<()> {
|
||||
marketplace_kinds: Some(vec![
|
||||
codex_app_server_protocol::PluginListMarketplaceKind::Local,
|
||||
]),
|
||||
force_refetch: false,
|
||||
})
|
||||
.await?;
|
||||
let response: JSONRPCResponse = timeout(
|
||||
|
||||
@@ -390,6 +390,7 @@ async fn skills_list_loads_remote_installed_plugin_skills_from_cache() -> Result
|
||||
.send_plugin_list_request(PluginListParams {
|
||||
cwds: None,
|
||||
marketplace_kinds: None,
|
||||
force_refetch: false,
|
||||
})
|
||||
.await?;
|
||||
let plugin_list_response: JSONRPCResponse = timeout(
|
||||
|
||||
Reference in New Issue
Block a user