Share the skills budget across host and executor catalogs (#35769)

## Why

Rendering host and executor skill catalogs independently allows their combined
metadata to exceed the skills context budget.

## What changed

- Allocate one budget across both catalogs when both contain model-visible
  skills.
- Prefer retaining executor skills when budget pressure requires omissions,
  while preserving an executor omission marker and reporting when all host
  skills were omitted.
- Evaluate absolute and aliased host paths under the shared budget and select
  the rendering that best preserves executor entries, total entries, and
  descriptions, in that order.

## Testing

Added renderer and production-turn coverage for shared-budget description
shortening, host-first omission, executor omission markers, and alias selection.

GitOrigin-RevId: 30041736a76aa173cb641aa98a876a306cb437d2
This commit is contained in:
felixxia-oai authored and copyberry committed 2026-07-28 13:16:04 +00:00
1 parent a68d0a74bd
commit f6160ca5b3
6 files changed
+688 -110

No files matched your search

+129
View File
@@ -323,6 +323,135 @@ fn mixed_catalogs_keep_absolute_authority_aware_rendering_under_budget_pressure(
assert!(!body.contains("additional skills omitted"));
}
#[test]
fn mixed_catalog_reserves_executor_omission_marker_by_omitting_host_first() {
let host_catalog = SkillCatalog {
entries: vec![entry_with_path(
"h", "", /*short_description*/ None, "/h",
)],
warnings: Vec::new(),
};
let executor_entry = |name: &str, resource: &str| {
SkillCatalogEntry::new(
SkillPackageId(name.to_string()),
SkillAuthority::new(SkillSourceKind::Executor, "env-1"),
name,
"",
SkillResourceId::new(resource),
)
.with_display_path(resource)
};
let executor_catalog = SkillCatalog {
entries: vec![
executor_entry("e1", "skill://executor/one"),
executor_entry(
"e2",
"skill://executor/this-resource-is-intentionally-too-long",
),
],
warnings: Vec::new(),
};
let (host, executor) = render_combined_available_skills(
&host_catalog,
&executor_catalog,
SkillMetadataBudget::Tokens(28),
);
let host = host.expect("host catalog should render");
let executor = executor.expect("executor catalog should render");
assert_eq!(
host.report,
SkillRenderReport {
total_count: 1,
included_count: 0,
omitted_count: 1,
truncated_description_chars: 0,
truncated_description_count: 0,
}
);
assert_eq!(
executor.report,
SkillRenderReport {
total_count: 2,
included_count: 1,
omitted_count: 1,
truncated_description_chars: 0,
truncated_description_count: 0,
}
);
assert_eq!(
executor.skill_lines,
vec![
"- e1: (environment resource: skill://executor/one)".to_string(),
"- 1 additional skill omitted from this bounded skills list.".to_string(),
]
);
}
#[test]
fn mixed_catalog_prefers_executor_inclusion_over_total_aliased_inclusion() {
let root = format!("/{}", "r".repeat(219));
let host_catalog = SkillCatalog {
entries: ["h1", "h2"]
.into_iter()
.map(|name| {
entry(name, "", /*short_description*/ None)
.with_display_path(format!("{root}/{name}/SKILL.md"))
.with_display_path_root(root.as_str())
})
.collect(),
warnings: Vec::new(),
};
let executor_entry = |name: &str, resource: &str| {
SkillCatalogEntry::new(
SkillPackageId(name.to_string()),
SkillAuthority::new(SkillSourceKind::Executor, "env-1"),
name,
"",
SkillResourceId::new(resource),
)
.with_display_path(resource)
};
let executor_catalog = SkillCatalog {
entries: vec![
executor_entry("e1", "skill://executor/one"),
executor_entry("e2", &format!("skill://{}", "e".repeat(132))),
],
warnings: Vec::new(),
};
let (host, executor) = render_combined_available_skills(
&host_catalog,
&executor_catalog,
SkillMetadataBudget::Tokens(74),
);
let host = host.expect("host catalog should render");
let executor = executor.expect("executor catalog should render");
assert_eq!(
executor.report,
SkillRenderReport {
total_count: 2,
included_count: 2,
omitted_count: 0,
truncated_description_chars: 0,
truncated_description_count: 0,
}
);
assert_eq!(
host.report,
SkillRenderReport {
total_count: 2,
included_count: 0,
omitted_count: 2,
truncated_description_chars: 0,
truncated_description_count: 0,
}
);
assert_eq!(host.skill_root_lines, Vec::<String>::new());
}
#[test]
fn singleton_plugin_versions_share_the_marketplace_alias_root() {
let github_root = "/Users/test/.codex/plugins/cache/openai-curated/github/hash123/skills";