Add plugin ID to skill analytics (#20923)

## Summary
- thread plugin skill roots through the skills loader with their plugin
ID
- store plugin ID on loaded skill metadata for plugin-provided skills
- include plugin ID on skill invocation analytics events

## Test plan
- cargo check -p codex-core-skills
- cargo check -p codex-core -p codex-core-plugins -p codex-analytics
- cargo check -p codex-tui
- cargo check -p codex-plugin -p codex-core -p codex-core-plugins -p
codex-analytics
- cargo check -p codex-app-server
- cargo test -p codex-analytics
- HOME=/private/tmp/codex-empty-home cargo test -p codex-core-skills
- just fix -p codex-core-skills
- just fix -p codex-analytics
- just fix -p codex-core-plugins
- just fix -p codex-core
- just fmt
- git diff --check
This commit is contained in:
alexsong-oai
2026-05-04 20:36:29 -07:00
committed by GitHub
parent 707e51bd8b
commit 3ad7cf0993
27 changed files with 228 additions and 20 deletions
+1 -1
View File
@@ -657,7 +657,7 @@ enabled = false
SkillsManager::new(home.path().abs(), /*bundled_skills_enabled*/ true);
let plugins_input = config.plugins_config_input();
let plugin_outcome = plugins_manager.plugins_for_config(&plugins_input).await;
let effective_skill_roots = plugin_outcome.effective_skill_roots();
let effective_skill_roots = plugin_outcome.effective_plugin_skill_roots();
let skills_input = skills_load_input_from_config(&config, effective_skill_roots);
let outcome = skills_manager
.skills_for_config(
+1 -1
View File
@@ -476,7 +476,7 @@ impl Codex {
let fs = environment_selections.primary_filesystem();
let plugins_input = config.plugins_config_input();
let plugin_outcome = plugins_manager.plugins_for_config(&plugins_input).await;
let effective_skill_roots = plugin_outcome.effective_skill_roots();
let effective_skill_roots = plugin_outcome.effective_plugin_skill_roots();
let skills_input = skills_load_input_from_config(&config, effective_skill_roots);
let loaded_skills = skills_manager.skills_for_config(&skills_input, fs).await;
+9 -2
View File
@@ -3661,7 +3661,7 @@ pub(crate) async fn make_session_and_context() -> (Session, TurnContext) {
.plugins_manager
.plugins_for_config(&per_turn_config.plugins_config_input())
.await;
let effective_skill_roots = plugin_outcome.effective_skill_roots();
let effective_skill_roots = plugin_outcome.effective_plugin_skill_roots();
let skills_input =
crate::skills_load_input_from_config(&per_turn_config, effective_skill_roots);
let skill_fs = environment.get_filesystem();
@@ -5189,7 +5189,7 @@ where
.plugins_manager
.plugins_for_config(&per_turn_config.plugins_config_input())
.await;
let effective_skill_roots = plugin_outcome.effective_skill_roots();
let effective_skill_roots = plugin_outcome.effective_plugin_skill_roots();
let skills_input =
crate::skills_load_input_from_config(&per_turn_config, effective_skill_roots);
let skill_fs = environment.get_filesystem();
@@ -5829,6 +5829,7 @@ async fn build_initial_context_trims_skill_metadata_from_context_window_budget()
policy: None,
path_to_skills_md: test_path_buf("/tmp/admin-skill/SKILL.md").abs(),
scope: SkillScope::Admin,
plugin_id: None,
},
SkillMetadata {
name: "repo-skill".to_string(),
@@ -5839,6 +5840,7 @@ async fn build_initial_context_trims_skill_metadata_from_context_window_budget()
policy: None,
path_to_skills_md: test_path_buf("/tmp/repo-skill/SKILL.md").abs(),
scope: SkillScope::Repo,
plugin_id: None,
},
];
turn_context.model_info.context_window = Some(100);
@@ -5874,6 +5876,7 @@ fn emit_thread_start_skill_metrics_records_enabled_kept_and_truncated_values() {
policy: None,
path_to_skills_md: test_path_buf("/tmp/repo-skill/SKILL.md").abs(),
scope: SkillScope::Repo,
plugin_id: None,
}];
let rendered = build_available_skills(
&outcome,
@@ -5918,6 +5921,7 @@ fn emit_thread_start_skill_metrics_records_description_truncated_chars_without_o
policy: None,
path_to_skills_md: test_path_buf("/tmp/alpha-skill/SKILL.md").abs(),
scope: SkillScope::Repo,
plugin_id: None,
};
let beta = SkillMetadata {
name: "beta-skill".to_string(),
@@ -5928,6 +5932,7 @@ fn emit_thread_start_skill_metrics_records_description_truncated_chars_without_o
policy: None,
path_to_skills_md: test_path_buf("/tmp/beta-skill/SKILL.md").abs(),
scope: SkillScope::Repo,
plugin_id: None,
};
let minimum_skill_line_cost = |skill: &SkillMetadata| {
let path = skill.path_to_skills_md.to_string_lossy().replace('\\', "/");
@@ -5975,6 +5980,7 @@ async fn build_initial_context_emits_thread_start_skill_warning_on_repeated_buil
policy: None,
path_to_skills_md: test_path_buf("/tmp/admin-skill/SKILL.md").abs(),
scope: SkillScope::Admin,
plugin_id: None,
},
SkillMetadata {
name: "repo-skill".to_string(),
@@ -5985,6 +5991,7 @@ async fn build_initial_context_emits_thread_start_skill_warning_on_repeated_buil
policy: None,
path_to_skills_md: test_path_buf("/tmp/repo-skill/SKILL.md").abs(),
scope: SkillScope::Repo,
plugin_id: None,
},
];
turn_context.model_info.context_window = Some(100);
+1 -1
View File
@@ -699,7 +699,7 @@ impl Session {
.plugins_manager
.plugins_for_config(&per_turn_config.plugins_config_input())
.await;
let effective_skill_roots = plugin_outcome.effective_skill_roots();
let effective_skill_roots = plugin_outcome.effective_plugin_skill_roots();
let skills_input = skills_load_input_from_config(&per_turn_config, effective_skill_roots);
let fs = primary_turn_environment
.map(|turn_environment| turn_environment.environment.get_filesystem());
+3 -1
View File
@@ -14,6 +14,7 @@ use codex_protocol::request_user_input::RequestUserInputArgs;
use codex_protocol::request_user_input::RequestUserInputQuestion;
use codex_protocol::request_user_input::RequestUserInputResponse;
use codex_utils_absolute_path::AbsolutePathBuf;
use codex_utils_plugins::PluginSkillRoot;
use tracing::warn;
pub use codex_core_skills::SkillDependencyInfo;
@@ -45,7 +46,7 @@ pub use codex_core_skills::system;
pub(crate) fn skills_load_input_from_config(
config: &Config,
effective_skill_roots: Vec<AbsolutePathBuf>,
effective_skill_roots: Vec<PluginSkillRoot>,
) -> SkillsLoadInput {
SkillsLoadInput::new(
config.cwd.clone(),
@@ -187,6 +188,7 @@ pub(crate) async fn maybe_emit_implicit_skill_invocation(
skill_name: candidate.name,
skill_scope: candidate.scope,
skill_path: candidate.path_to_skills_md.to_path_buf(),
plugin_id: candidate.plugin_id,
invocation_type: InvocationType::Implicit,
};
let skill_scope = match invocation.skill_scope {
+1 -1
View File
@@ -63,7 +63,7 @@ impl SkillsWatcher {
) -> WatchRegistration {
let plugins_input = config.plugins_config_input();
let plugin_outcome = plugins_manager.plugins_for_config(&plugins_input).await;
let effective_skill_roots = plugin_outcome.effective_skill_roots();
let effective_skill_roots = plugin_outcome.effective_plugin_skill_roots();
let skills_input = skills_load_input_from_config(config, effective_skill_roots);
let roots = skills_manager
.skill_roots_for_config(&skills_input, fs)