mirror of
https://github.com/openai/codex.git
synced 2026-11-13 14:46:14 +00:00
Inject SKILL.md when it's explicitly mentioned. (#7763)
1. Skills load once in core at session start; the cached outcome is reused across core and surfaced to TUI via SessionConfigured. 2. TUI detects explicit skill selections, and core injects the matching SKILL.md content into the turn when a selected skill is present.
This commit is contained in:
1 parent
eb2e5458cc
commit
b36ecb6c32
21 files changed
+584
-88
No files matched your search
@@ -0,0 +1,78 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use crate::skills::SkillLoadOutcome;
|
||||
use crate::skills::SkillMetadata;
|
||||
use crate::user_instructions::SkillInstructions;
|
||||
use codex_protocol::models::ResponseItem;
|
||||
use codex_protocol::user_input::UserInput;
|
||||
use tokio::fs;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub(crate) struct SkillInjections {
|
||||
pub(crate) items: Vec<ResponseItem>,
|
||||
pub(crate) warnings: Vec<String>,
|
||||
}
|
||||
|
||||
pub(crate) async fn build_skill_injections(
|
||||
inputs: &[UserInput],
|
||||
skills: Option<&SkillLoadOutcome>,
|
||||
) -> SkillInjections {
|
||||
if inputs.is_empty() {
|
||||
return SkillInjections::default();
|
||||
}
|
||||
|
||||
let Some(outcome) = skills else {
|
||||
return SkillInjections::default();
|
||||
};
|
||||
|
||||
let mentioned_skills = collect_explicit_skill_mentions(inputs, &outcome.skills);
|
||||
if mentioned_skills.is_empty() {
|
||||
return SkillInjections::default();
|
||||
}
|
||||
|
||||
let mut result = SkillInjections {
|
||||
items: Vec::with_capacity(mentioned_skills.len()),
|
||||
warnings: Vec::new(),
|
||||
};
|
||||
|
||||
for skill in mentioned_skills {
|
||||
match fs::read_to_string(&skill.path).await {
|
||||
Ok(contents) => {
|
||||
result.items.push(ResponseItem::from(SkillInstructions {
|
||||
name: skill.name,
|
||||
path: skill.path.to_string_lossy().into_owned(),
|
||||
contents,
|
||||
}));
|
||||
}
|
||||
Err(err) => {
|
||||
let message = format!(
|
||||
"Failed to load skill {} at {}: {err:#}",
|
||||
skill.name,
|
||||
skill.path.display()
|
||||
);
|
||||
result.warnings.push(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn collect_explicit_skill_mentions(
|
||||
inputs: &[UserInput],
|
||||
skills: &[SkillMetadata],
|
||||
) -> Vec<SkillMetadata> {
|
||||
let mut selected: Vec<SkillMetadata> = Vec::new();
|
||||
let mut seen: HashSet<String> = HashSet::new();
|
||||
|
||||
for input in inputs {
|
||||
if let UserInput::Skill { name, path } = input
|
||||
&& seen.insert(name.clone())
|
||||
&& let Some(skill) = skills.iter().find(|s| s.name == *name && s.path == *path)
|
||||
{
|
||||
selected.push(skill.clone());
|
||||
}
|
||||
}
|
||||
|
||||
selected
|
||||
}
|
||||
Reference in new issue
Block a user