Files
codex/codex-rs/ext/skills/src/fragments.rs
T
felixxia-oai 5e8b22488f Use the host skill provider catalog in world state (#36309)
## What changed

- Load and cache the host skill provider catalog during world-state contribution.
- Render host skill listings from that catalog with Core-compatible budgeting, while preserving Core's full prompt injection for selected host skills.
- Reuse the cached host catalog for shadow selection, including when skill listings are disabled.
- Preserve an empty Core-compatible skills fragment when every entry exceeds the metadata budget, and make budget warnings independent of the configured percentage.

## Testing

- Cover provider-backed host listings, selected-skill prompt injection, shadow selection, disabled listings, oversized prompts, empty fragments, metrics, and warnings.

GitOrigin-RevId: b6b2d8ea14386356094cff5783d121d74657e9e3
2026-07-31 11:01:47 +00:00

104 lines
3.1 KiB
Rust

use codex_core_skills::SKILLS_HOW_TO_USE_WITH_ABSOLUTE_PATHS;
use codex_core_skills::SKILLS_HOW_TO_USE_WITH_ALIASES;
use codex_core_skills::render_available_skills_body;
use codex_extension_api::ContextualUserFragment;
use codex_protocol::protocol::SKILLS_INSTRUCTIONS_CLOSE_TAG;
use codex_protocol::protocol::SKILLS_INSTRUCTIONS_OPEN_TAG;
#[derive(Clone, Debug, Eq, PartialEq)]
pub(crate) struct AvailableSkillsInstructions {
skill_root_lines: Vec<String>,
skill_lines: Vec<String>,
}
impl AvailableSkillsInstructions {
pub(crate) fn from_skill_lines(
skill_root_lines: Vec<String>,
mut skill_lines: Vec<String>,
include_skills_usage_instructions: bool,
) -> Self {
if include_skills_usage_instructions {
skill_lines.push("### How to use skills".to_string());
let instructions = if skill_root_lines.is_empty() {
SKILLS_HOW_TO_USE_WITH_ABSOLUTE_PATHS
} else {
SKILLS_HOW_TO_USE_WITH_ALIASES
};
skill_lines.push(instructions.to_string());
}
Self {
skill_root_lines,
skill_lines,
}
}
}
impl ContextualUserFragment for AvailableSkillsInstructions {
fn role(&self) -> &'static str {
"developer"
}
fn markers(&self) -> (&'static str, &'static str) {
Self::type_markers()
}
fn type_markers() -> (&'static str, &'static str) {
(SKILLS_INSTRUCTIONS_OPEN_TAG, SKILLS_INSTRUCTIONS_CLOSE_TAG)
}
fn body(&self) -> String {
render_available_skills_body(&self.skill_root_lines, &self.skill_lines)
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub(crate) struct SkillInstructions {
pub(crate) name: String,
pub(crate) path: String,
pub(crate) contents: String,
pub(crate) executor_resource_access: Option<ExecutorSkillResourceAccess>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub(crate) struct ExecutorSkillResourceAccess {
pub(crate) authority_id: String,
pub(crate) package: String,
pub(crate) main_resource: String,
}
impl ContextualUserFragment for SkillInstructions {
fn role(&self) -> &'static str {
"user"
}
fn markers(&self) -> (&'static str, &'static str) {
Self::type_markers()
}
fn type_markers() -> (&'static str, &'static str) {
("<skill>", "</skill>")
}
fn body(&self) -> String {
let name = &self.name;
let path = &self.path;
let contents = &self.contents;
let resource_access = self
.executor_resource_access
.as_ref()
.map(|access| {
let metadata = serde_json::json!({
"authority": {
"kind": "executor",
"id": access.authority_id,
},
"package": access.package,
"main_resource": access.main_resource,
});
format!("\n<resource_access>{metadata}</resource_access>")
})
.unwrap_or_default();
format!("\n<name>{name}</name>\n<path>{path}</path>{resource_access}\n{contents}\n")
}
}