mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
feat: Compress skill paths with root aliases (#19098)
Add skill root tracking so model-visible skill lists can use short path aliases when absolute paths would exceed the metadata budget.
This commit is contained in:
committed by
GitHub
Unverified
parent
588f7a9fc4
commit
1e560f33e1
@@ -1,4 +1,5 @@
|
||||
use codex_core_skills::AvailableSkills;
|
||||
use codex_core_skills::render_available_skills_body;
|
||||
use codex_protocol::protocol::SKILLS_INSTRUCTIONS_CLOSE_TAG;
|
||||
use codex_protocol::protocol::SKILLS_INSTRUCTIONS_OPEN_TAG;
|
||||
|
||||
@@ -6,12 +7,14 @@ use super::ContextualUserFragment;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub(crate) struct AvailableSkillsInstructions {
|
||||
skill_root_lines: Vec<String>,
|
||||
skill_lines: Vec<String>,
|
||||
}
|
||||
|
||||
impl From<AvailableSkills> for AvailableSkillsInstructions {
|
||||
fn from(available_skills: AvailableSkills) -> Self {
|
||||
Self {
|
||||
skill_root_lines: available_skills.skill_root_lines,
|
||||
skill_lines: available_skills.skill_lines,
|
||||
}
|
||||
}
|
||||
@@ -23,34 +26,6 @@ impl ContextualUserFragment for AvailableSkillsInstructions {
|
||||
const END_MARKER: &'static str = SKILLS_INSTRUCTIONS_CLOSE_TAG;
|
||||
|
||||
fn body(&self) -> String {
|
||||
let mut lines: Vec<String> = Vec::new();
|
||||
lines.push("## Skills".to_string());
|
||||
lines.push("A skill is a set of local instructions to follow that is stored in a `SKILL.md` file. Below is the list of skills that can be used. Each entry includes a name, description, and file path so you can open the source for full instructions when using a specific skill.".to_string());
|
||||
lines.push("### Available skills".to_string());
|
||||
lines.extend(self.skill_lines.iter().cloned());
|
||||
|
||||
lines.push("### How to use skills".to_string());
|
||||
lines.push(
|
||||
r###"- Discovery: The list above is the skills available in this session (name + description + file path). Skill bodies live on disk at the listed paths.
|
||||
- Trigger rules: If the user names a skill (with `$SkillName` or plain text) OR the task clearly matches a skill's description shown above, you must use that skill for that turn. Multiple mentions mean use them all. Do not carry skills across turns unless re-mentioned.
|
||||
- Missing/blocked: If a named skill isn't in the list or the path can't be read, say so briefly and continue with the best fallback.
|
||||
- How to use a skill (progressive disclosure):
|
||||
1) After deciding to use a skill, open its `SKILL.md`. Read only enough to follow the workflow.
|
||||
2) When `SKILL.md` references relative paths (e.g., `scripts/foo.py`), resolve them relative to the skill directory listed above first, and only consider other paths if needed.
|
||||
3) If `SKILL.md` points to extra folders such as `references/`, load only the specific files needed for the request; don't bulk-load everything.
|
||||
4) If `scripts/` exist, prefer running or patching them instead of retyping large code blocks.
|
||||
5) If `assets/` or templates exist, reuse them instead of recreating from scratch.
|
||||
- Coordination and sequencing:
|
||||
- If multiple skills apply, choose the minimal set that covers the request and state the order you'll use them.
|
||||
- Announce which skill(s) you're using and why (one short line). If you skip an obvious skill, say why.
|
||||
- Context hygiene:
|
||||
- Keep context small: summarize long sections instead of pasting them; only load extra files when needed.
|
||||
- Avoid deep reference-chasing: prefer opening only files directly linked from `SKILL.md` unless you're blocked.
|
||||
- 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."###
|
||||
.to_string(),
|
||||
);
|
||||
|
||||
format!("\n{}\n", lines.join("\n"))
|
||||
render_available_skills_body(&self.skill_root_lines, &self.skill_lines)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2627,12 +2627,8 @@ impl Session {
|
||||
}
|
||||
}
|
||||
if turn_context.config.include_skill_instructions {
|
||||
let implicit_skills = turn_context
|
||||
.turn_skills
|
||||
.outcome
|
||||
.allowed_skills_for_implicit_invocation();
|
||||
let available_skills = build_available_skills(
|
||||
&implicit_skills,
|
||||
&turn_context.turn_skills.outcome,
|
||||
default_skill_metadata_budget(turn_context.model_info.context_window),
|
||||
SkillRenderSideEffects::ThreadStart {
|
||||
session_telemetry: &self.services.session_telemetry,
|
||||
|
||||
@@ -5185,17 +5185,19 @@ async fn build_initial_context_trims_skill_metadata_from_context_window_budget()
|
||||
#[test]
|
||||
fn emit_thread_start_skill_metrics_records_enabled_kept_and_truncated_values() {
|
||||
let session_telemetry = test_session_telemetry_without_metadata();
|
||||
let mut outcome = SkillLoadOutcome::default();
|
||||
outcome.skills = vec![SkillMetadata {
|
||||
name: "repo-skill".to_string(),
|
||||
description: "desc".to_string(),
|
||||
short_description: None,
|
||||
interface: None,
|
||||
dependencies: None,
|
||||
policy: None,
|
||||
path_to_skills_md: test_path_buf("/tmp/repo-skill/SKILL.md").abs(),
|
||||
scope: SkillScope::Repo,
|
||||
}];
|
||||
let rendered = build_available_skills(
|
||||
&[SkillMetadata {
|
||||
name: "repo-skill".to_string(),
|
||||
description: "desc".to_string(),
|
||||
short_description: None,
|
||||
interface: None,
|
||||
dependencies: None,
|
||||
policy: None,
|
||||
path_to_skills_md: test_path_buf("/tmp/repo-skill/SKILL.md").abs(),
|
||||
scope: SkillScope::Repo,
|
||||
}],
|
||||
&outcome,
|
||||
SkillMetadataBudget::Characters(1),
|
||||
SkillRenderSideEffects::ThreadStart {
|
||||
session_telemetry: &session_telemetry,
|
||||
@@ -5255,9 +5257,11 @@ fn emit_thread_start_skill_metrics_records_description_truncated_chars_without_o
|
||||
.count()
|
||||
};
|
||||
let minimum_budget = minimum_skill_line_cost(&alpha) + minimum_skill_line_cost(&beta);
|
||||
let mut outcome = SkillLoadOutcome::default();
|
||||
outcome.skills = vec![alpha, beta];
|
||||
|
||||
let rendered = build_available_skills(
|
||||
&[alpha, beta],
|
||||
&outcome,
|
||||
SkillMetadataBudget::Characters(minimum_budget + 6),
|
||||
SkillRenderSideEffects::ThreadStart {
|
||||
session_telemetry: &session_telemetry,
|
||||
|
||||
Reference in New Issue
Block a user