From e835b60f0de208c92256df60d5ea9af391dfa9f6 Mon Sep 17 00:00:00 2001 From: ani-oai Date: Tue, 30 Jun 2026 13:46:19 +0900 Subject: [PATCH] Move skills intro out of the harness --- codex-rs/core-skills/src/render.rs | 16 +++++++++++----- .../src/context/available_skills_instructions.rs | 9 ++++++++- codex-rs/ext/skills/src/fragments.rs | 12 ++++++++++-- codex-rs/ext/skills/tests/skills_extension.rs | 3 +-- 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/codex-rs/core-skills/src/render.rs b/codex-rs/core-skills/src/render.rs index 3f26e8caf1..25d4fbcc5d 100644 --- a/codex-rs/core-skills/src/render.rs +++ b/codex-rs/core-skills/src/render.rs @@ -62,13 +62,19 @@ pub const SKILLS_HOW_TO_USE_WITH_ALIASES: &str = r###"- Discovery: The list abov - When variants exist (frameworks, providers, domains), pick only the relevant reference file(s) and note that choice. - Safety and fallback: If a skill can't be applied cleanly (missing files, unclear instructions), state the issue, pick the next-best approach, and continue."###; -pub fn render_available_skills_body(skill_root_lines: &[String], skill_lines: &[String]) -> String { +pub fn render_available_skills_body( + skill_root_lines: &[String], + skill_lines: &[String], + include_intro: bool, +) -> String { let mut lines: Vec = Vec::new(); lines.push("## Skills".to_string()); - if skill_root_lines.is_empty() { + if include_intro && skill_root_lines.is_empty() { lines.push(SKILLS_INTRO_WITH_ABSOLUTE_PATHS.to_string()); - } else { + } else if include_intro { lines.push(SKILLS_INTRO_WITH_ALIASES.to_string()); + } + if !skill_root_lines.is_empty() { lines.push("### Skill roots".to_string()); lines.extend(skill_root_lines.iter().cloned()); } @@ -802,8 +808,8 @@ fn aliased_metadata_overhead_cost( skill_root_lines: &[String], ) -> usize { let empty_skill_lines: &[String] = &[]; - let absolute_body = render_available_skills_body(&[], empty_skill_lines); - let aliased_body = render_available_skills_body(skill_root_lines, empty_skill_lines); + let absolute_body = render_available_skills_body(&[], empty_skill_lines, true); + let aliased_body = render_available_skills_body(skill_root_lines, empty_skill_lines, true); budget .cost(&aliased_body) .saturating_sub(budget.cost(&absolute_body)) diff --git a/codex-rs/core/src/context/available_skills_instructions.rs b/codex-rs/core/src/context/available_skills_instructions.rs index a96f2195cc..8a10463142 100644 --- a/codex-rs/core/src/context/available_skills_instructions.rs +++ b/codex-rs/core/src/context/available_skills_instructions.rs @@ -12,6 +12,7 @@ use super::ContextualUserFragment; pub struct AvailableSkillsInstructions { skill_root_lines: Vec, skill_lines: Vec, + include_skills_usage_instructions: bool, } impl AvailableSkillsInstructions { @@ -20,6 +21,7 @@ impl AvailableSkillsInstructions { Self { skill_root_lines: Vec::new(), skill_lines, + include_skills_usage_instructions: false, } } @@ -40,6 +42,7 @@ impl AvailableSkillsInstructions { Self { skill_root_lines: available_skills.skill_root_lines.clone(), skill_lines, + include_skills_usage_instructions, } } } @@ -58,6 +61,10 @@ impl ContextualUserFragment for AvailableSkillsInstructions { } fn body(&self) -> String { - render_available_skills_body(&self.skill_root_lines, &self.skill_lines) + render_available_skills_body( + &self.skill_root_lines, + &self.skill_lines, + self.include_skills_usage_instructions, + ) } } diff --git a/codex-rs/ext/skills/src/fragments.rs b/codex-rs/ext/skills/src/fragments.rs index 6769ffbcb1..230f555e00 100644 --- a/codex-rs/ext/skills/src/fragments.rs +++ b/codex-rs/ext/skills/src/fragments.rs @@ -7,6 +7,7 @@ use codex_protocol::protocol::SKILLS_INSTRUCTIONS_OPEN_TAG; #[derive(Clone, Debug, Eq, PartialEq)] pub(crate) struct AvailableSkillsInstructions { skill_lines: Vec, + include_skills_usage_instructions: bool, } impl AvailableSkillsInstructions { @@ -18,7 +19,10 @@ impl AvailableSkillsInstructions { skill_lines.push("### How to use skills".to_string()); skill_lines.push(SKILLS_HOW_TO_USE_WITH_ABSOLUTE_PATHS.to_string()); } - Self { skill_lines } + Self { + skill_lines, + include_skills_usage_instructions, + } } } @@ -36,7 +40,11 @@ impl ContextualUserFragment for AvailableSkillsInstructions { } fn body(&self) -> String { - render_available_skills_body(&[], &self.skill_lines) + render_available_skills_body( + &[], + &self.skill_lines, + self.include_skills_usage_instructions, + ) } } diff --git a/codex-rs/ext/skills/tests/skills_extension.rs b/codex-rs/ext/skills/tests/skills_extension.rs index 76d0df7954..dbcd212719 100644 --- a/codex-rs/ext/skills/tests/skills_extension.rs +++ b/codex-rs/ext/skills/tests/skills_extension.rs @@ -5,7 +5,6 @@ use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; use codex_core_skills::HostSkillsSnapshot; -use codex_core_skills::SKILLS_INTRO_WITH_ABSOLUTE_PATHS; use codex_core_skills::SkillLoadOutcome; use codex_core_skills::SkillMetadata; use codex_core_skills::injection::InjectedHostSkillPrompts; @@ -124,7 +123,7 @@ async fn installed_extension_uses_host_service_snapshot() -> TestResult { .await; let expected_catalog = format!( - "{SKILLS_INSTRUCTIONS_OPEN_TAG}\n## Skills\n{SKILLS_INTRO_WITH_ABSOLUTE_PATHS}\n### Available skills\n- demo: Demo skill. (file: {skill_prompt_path})\n{SKILLS_INSTRUCTIONS_CLOSE_TAG}" + "{SKILLS_INSTRUCTIONS_OPEN_TAG}\n## Skills\n### Available skills\n- demo: Demo skill. (file: {skill_prompt_path})\n{SKILLS_INSTRUCTIONS_CLOSE_TAG}" ); let expected_skill = format!( "\ndemo\n{skill_prompt_path}\n{DEMO_SKILL_CONTENTS}\n"