diff --git a/codex-rs/app-server/src/codex_message_processor.rs b/codex-rs/app-server/src/codex_message_processor.rs index 74510de7e3..e9a11d0059 100644 --- a/codex-rs/app-server/src/codex_message_processor.rs +++ b/codex-rs/app-server/src/codex_message_processor.rs @@ -5504,7 +5504,7 @@ impl CodexMessageProcessor { } }; let config_layer_stack = match load_config_layers_state( - &self.codex_home, + &self.config.codex_home, Some(cwd_abs), cli_overrides, LoaderOverrides::default(), @@ -5529,14 +5529,14 @@ impl CodexMessageProcessor { &config_layer_stack, config.features.enabled(Feature::Plugins), ); + let skills_input = codex_core::skills::SkillsLoadInput::new( + cwd.clone(), + effective_skill_roots, + config_layer_stack, + config.bundled_skills_enabled(), + ); let outcome = skills_manager - .skills_for_cwd_with_extra_user_roots( - &cwd, - &effective_skill_roots, - force_reload, - extra_roots, - &config_layer_stack, - ) + .skills_for_cwd_with_extra_user_roots(&skills_input, force_reload, extra_roots) .await; let errors = errors_to_info(&outcome.errors); let skills = skills_to_info(&outcome.skills, &outcome.disabled_paths); diff --git a/codex-rs/app-server/src/config_api.rs b/codex-rs/app-server/src/config_api.rs index 09cc55341f..2f23ec7570 100644 --- a/codex-rs/app-server/src/config_api.rs +++ b/codex-rs/app-server/src/config_api.rs @@ -264,6 +264,8 @@ fn config_write_error(code: ConfigWriteErrorCode, message: impl Into) -> mod tests { use super::*; use codex_core::AnalyticsEventsClient; + use codex_core::AuthManager; + use codex_core::CodexAuth; use codex_core::config_loader::NetworkRequirementsToml as CoreNetworkRequirementsToml; use codex_protocol::protocol::AskForApproval as CoreAskForApproval; use pretty_assertions::assert_eq; @@ -404,6 +406,9 @@ mod tests { .await .expect("load analytics config"), ); + let auth_manager = Arc::new(AuthManager::from_auth_for_testing(CodexAuth::from_api_key( + "test", + ))); let config_api = ConfigApi::new( codex_home.path().to_path_buf(), Vec::new(), @@ -411,7 +416,7 @@ mod tests { Arc::new(RwLock::new(CloudRequirementsLoader::default())), reloader.clone(), AnalyticsEventsClient::new( - Arc::clone(&analytics_config.auth_manager), + auth_manager, analytics_config .chatgpt_base_url .trim_end_matches('/') diff --git a/codex-rs/core/src/contextual_user_message_tests.rs b/codex-rs/core/src/contextual_user_message_tests.rs index f71ca35f6e..93db860ea9 100644 --- a/codex-rs/core/src/contextual_user_message_tests.rs +++ b/codex-rs/core/src/contextual_user_message_tests.rs @@ -1,6 +1,7 @@ use super::*; use codex_protocol::items::HookPromptFragment; use codex_protocol::items::build_hook_prompt_message; +use codex_protocol::models::ResponseItem; #[test] fn detects_environment_context_fragment() { diff --git a/codex-rs/core/src/plugins/manager_tests.rs b/codex-rs/core/src/plugins/manager_tests.rs index 7c7ef57c50..61afc40f35 100644 --- a/codex-rs/core/src/plugins/manager_tests.rs +++ b/codex-rs/core/src/plugins/manager_tests.rs @@ -15,6 +15,7 @@ use crate::plugins::test_support::write_curated_plugin_sha_with as write_curated use crate::plugins::test_support::write_file; use crate::plugins::test_support::write_openai_curated_marketplace; use codex_app_server_protocol::ConfigLayerSource; +use codex_plugin::prompt_safe_plugin_description; use codex_protocol::protocol::Product; use pretty_assertions::assert_eq; use std::fs; @@ -28,6 +29,8 @@ use wiremock::matchers::method; use wiremock::matchers::path; use wiremock::matchers::query_param; +const MAX_CAPABILITY_SUMMARY_DESCRIPTION_LEN: usize = 1024; + fn write_plugin(root: &Path, dir_name: &str, manifest_name: &str) { let plugin_root = root.join(dir_name); fs::create_dir_all(plugin_root.join(".codex-plugin")).unwrap(); @@ -132,7 +135,7 @@ fn load_plugins_loads_default_skills_and_mcp_servers() { let outcome = load_plugins_from_config(&plugin_config_toml(true, true), codex_home.path()); assert_eq!( - outcome.plugins, + outcome.plugins(), vec![LoadedPlugin { config_name: "sample@test".to_string(), manifest_name: Some("sample".to_string()), @@ -222,10 +225,10 @@ enabled = true let skill_path = dunce::canonicalize(skill_path).expect("skill path should canonicalize"); assert_eq!( - outcome.plugins[0].disabled_skill_paths, + outcome.plugins()[0].disabled_skill_paths, HashSet::from([skill_path]) ); - assert!(!outcome.plugins[0].has_enabled_skills); + assert!(!outcome.plugins()[0].has_enabled_skills); assert!(outcome.capability_summaries().is_empty()); } @@ -258,8 +261,8 @@ enabled = true "#; let outcome = load_plugins_from_config(config_toml, codex_home.path()); - assert!(outcome.plugins[0].disabled_skill_paths.is_empty()); - assert!(outcome.plugins[0].has_enabled_skills); + assert!(outcome.plugins()[0].disabled_skill_paths.is_empty()); + assert!(outcome.plugins()[0].has_enabled_skills); assert_eq!( outcome.capability_summaries(), &[PluginCapabilitySummary { @@ -340,7 +343,7 @@ fn capability_summary_sanitizes_plugin_descriptions_to_one_line() { let outcome = load_plugins_from_config(&plugin_config_toml(true, true), codex_home.path()); assert_eq!( - outcome.plugins[0].manifest_description.as_deref(), + outcome.plugins()[0].manifest_description.as_deref(), Some("Plugin that\n includes the sample\tserver") ); assert_eq!( @@ -375,7 +378,7 @@ fn capability_summary_truncates_overlong_plugin_descriptions() { let outcome = load_plugins_from_config(&plugin_config_toml(true, true), codex_home.path()); assert_eq!( - outcome.plugins[0].manifest_description.as_deref(), + outcome.plugins()[0].manifest_description.as_deref(), Some(too_long.as_str()) ); assert_eq!( @@ -455,14 +458,14 @@ fn load_plugins_uses_manifest_configured_component_paths() { let outcome = load_plugins_from_config(&plugin_config_toml(true, true), codex_home.path()); assert_eq!( - outcome.plugins[0].skill_roots, + outcome.plugins()[0].skill_roots, vec![ plugin_root.join("custom-skills"), plugin_root.join("skills") ] ); assert_eq!( - outcome.plugins[0].mcp_servers, + outcome.plugins()[0].mcp_servers, HashMap::from([( "custom".to_string(), McpServerConfig { @@ -485,7 +488,7 @@ fn load_plugins_uses_manifest_configured_component_paths() { )]) ); assert_eq!( - outcome.plugins[0].apps, + outcome.plugins()[0].apps, vec![AppConnectorId("connector_custom".to_string())] ); } @@ -561,11 +564,11 @@ fn load_plugins_ignores_manifest_component_paths_without_dot_slash() { let outcome = load_plugins_from_config(&plugin_config_toml(true, true), codex_home.path()); assert_eq!( - outcome.plugins[0].skill_roots, + outcome.plugins()[0].skill_roots, vec![plugin_root.join("skills")] ); assert_eq!( - outcome.plugins[0].mcp_servers, + outcome.plugins()[0].mcp_servers, HashMap::from([( "default".to_string(), McpServerConfig { @@ -588,7 +591,7 @@ fn load_plugins_ignores_manifest_component_paths_without_dot_slash() { )]) ); assert_eq!( - outcome.plugins[0].apps, + outcome.plugins()[0].apps, vec![AppConnectorId("connector_default".to_string())] ); } @@ -620,7 +623,7 @@ fn load_plugins_preserves_disabled_plugins_without_effective_contributions() { let outcome = load_plugins_from_config(&plugin_config_toml(false, true), codex_home.path()); assert_eq!( - outcome.plugins, + outcome.plugins(), vec![LoadedPlugin { config_name: "sample@test".to_string(), manifest_name: None, @@ -864,9 +867,9 @@ fn load_plugins_rejects_invalid_plugin_keys() { codex_home.path(), ); - assert_eq!(outcome.plugins.len(), 1); + assert_eq!(outcome.plugins().len(), 1); assert_eq!( - outcome.plugins[0].error.as_deref(), + outcome.plugins()[0].error.as_deref(), Some("invalid plugin key `sample`; expected @") ); assert!(outcome.effective_skill_roots().is_empty());