mirror of
https://github.com/openai/codex.git
synced 2026-10-25 18:28:38 +00:00
## Summary - add a false-by-default `include_skills_usage_instructions` model metadata field - enable the field for the bundled `gpt-5.5` model metadata - consume the metadata in both core and extension skill rendering - remove hardcoded legacy-model matching and its marker plumbing
110 lines
3.6 KiB
Rust
110 lines
3.6 KiB
Rust
use std::borrow::Cow;
|
|
|
|
use codex_utils_string::take_bytes_at_char_boundary;
|
|
|
|
use crate::catalog::SkillCatalog;
|
|
use crate::catalog::SkillCatalogEntry;
|
|
use crate::catalog::SkillSourceKind;
|
|
use crate::fragments::AvailableSkillsInstructions;
|
|
|
|
const MAX_AVAILABLE_SKILLS_BYTES: usize = 8_000;
|
|
const MAX_MAIN_PROMPT_BYTES: usize = 8_000;
|
|
const MAX_CATALOG_SKILL_DESCRIPTION_CHARS: usize = 1_024;
|
|
const TRUNCATED_SKILL_DESCRIPTION_SUFFIX: &str = "...";
|
|
pub(crate) const MAX_SKILL_NAME_BYTES: usize = 256;
|
|
pub(crate) const MAX_SKILL_PATH_BYTES: usize = 1_024;
|
|
|
|
#[tracing::instrument(
|
|
level = "trace",
|
|
skip_all,
|
|
fields(catalog_entry_count = catalog.entries.len())
|
|
)]
|
|
pub(crate) fn available_skills_fragment(
|
|
catalog: &SkillCatalog,
|
|
include_skills_usage_instructions: bool,
|
|
) -> Option<AvailableSkillsInstructions> {
|
|
let mut total_bytes = 0usize;
|
|
let mut omitted = 0usize;
|
|
let mut skill_lines = Vec::new();
|
|
|
|
for entry in catalog
|
|
.entries
|
|
.iter()
|
|
.filter(|entry| entry.enabled && entry.prompt_visible)
|
|
{
|
|
let description = entry
|
|
.short_description
|
|
.as_deref()
|
|
.unwrap_or(entry.description.as_str());
|
|
let description = truncate_catalog_skill_description(description);
|
|
let line = render_skill_line(entry, description.as_ref());
|
|
let next_bytes = total_bytes.saturating_add(line.len());
|
|
if next_bytes > MAX_AVAILABLE_SKILLS_BYTES {
|
|
omitted = omitted.saturating_add(1);
|
|
continue;
|
|
}
|
|
total_bytes = next_bytes;
|
|
skill_lines.push(line);
|
|
}
|
|
|
|
if skill_lines.is_empty() {
|
|
return None;
|
|
}
|
|
if omitted > 0 {
|
|
let skill_word = if omitted == 1 { "skill" } else { "skills" };
|
|
skill_lines.push(format!(
|
|
"- {omitted} additional {skill_word} omitted from this bounded skills list."
|
|
));
|
|
}
|
|
|
|
Some(AvailableSkillsInstructions::from_skill_lines(
|
|
skill_lines,
|
|
include_skills_usage_instructions,
|
|
))
|
|
}
|
|
|
|
pub(crate) fn truncate_catalog_skill_description(description: &str) -> Cow<'_, str> {
|
|
if description
|
|
.char_indices()
|
|
.nth(MAX_CATALOG_SKILL_DESCRIPTION_CHARS)
|
|
.is_none()
|
|
{
|
|
return Cow::Borrowed(description);
|
|
}
|
|
|
|
let prefix_chars = MAX_CATALOG_SKILL_DESCRIPTION_CHARS
|
|
.saturating_sub(TRUNCATED_SKILL_DESCRIPTION_SUFFIX.chars().count());
|
|
let prefix_end = description
|
|
.char_indices()
|
|
.nth(prefix_chars)
|
|
.map_or(description.len(), |(index, _)| index);
|
|
let mut truncated = description[..prefix_end].to_string();
|
|
truncated.push_str(TRUNCATED_SKILL_DESCRIPTION_SUFFIX);
|
|
Cow::Owned(truncated)
|
|
}
|
|
|
|
fn render_skill_line(entry: &SkillCatalogEntry, description: &str) -> String {
|
|
let locator_kind = match &entry.authority.kind {
|
|
SkillSourceKind::Host => "file",
|
|
SkillSourceKind::Executor => "environment resource",
|
|
SkillSourceKind::Orchestrator => "orchestrator resource",
|
|
SkillSourceKind::Custom(_) => "custom resource",
|
|
};
|
|
let name = entry.name.as_str();
|
|
let path = entry.rendered_path();
|
|
if description.is_empty() {
|
|
format!("- {name}: ({locator_kind}: {path})")
|
|
} else {
|
|
format!("- {name}: {description} ({locator_kind}: {path})")
|
|
}
|
|
}
|
|
|
|
pub(crate) fn truncate_main_prompt_contents(contents: &str) -> (String, bool) {
|
|
truncate_utf8_to_bytes(contents, MAX_MAIN_PROMPT_BYTES)
|
|
}
|
|
|
|
pub(crate) fn truncate_utf8_to_bytes(contents: &str, max_bytes: usize) -> (String, bool) {
|
|
let truncated = take_bytes_at_char_boundary(contents, max_bytes);
|
|
(truncated.to_string(), truncated.len() < contents.len())
|
|
}
|