mirror of
https://github.com/openai/codex.git
synced 2026-11-10 16:44:38 +00:00
Add a configurable skill catalog token budget (#38978)
## What changed - Add `[skills].max_context_tokens` to override the token budget used to render the available-skills catalog. - Require a positive value and cap configured budgets at 10,000 tokens. - Preserve the existing default of 2% of the model context window when the option is unset. ## Testing - Cover configuration parsing, override behavior, the 10,000-token cap, and catalog rendering within the configured budget. GitOrigin-RevId: f29ddcb57fc2d800c0006d03e1c33cbe3ab6272d
This commit is contained in:
1 parent
c6058ccaa9
commit
632e35ce8d
19 files changed
+126
-7
No files matched your search
@@ -1,8 +1,12 @@
|
||||
use std::num::NonZeroUsize;
|
||||
|
||||
/// Host-supplied configuration used by the skills extension.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct SkillsExtensionConfig {
|
||||
/// Whether the available-skills catalog is included in model context.
|
||||
pub include_instructions: bool,
|
||||
/// Optional token budget override for the available-skills catalog.
|
||||
pub max_context_tokens: Option<NonZeroUsize>,
|
||||
/// Whether bundled skills are eligible for discovery.
|
||||
pub bundled_skills_enabled: bool,
|
||||
/// Whether orchestrator-owned skills are eligible for discovery.
|
||||
|
||||
@@ -228,7 +228,7 @@ where
|
||||
&catalog,
|
||||
include_usage,
|
||||
SkillCatalogRenderPolicy::ExtensionCompatible,
|
||||
skill_metadata_budget(/*context_window*/ None),
|
||||
skill_metadata_budget(/*context_window*/ None, config.max_context_tokens),
|
||||
);
|
||||
if let Some(message) = rendered.warning_message {
|
||||
self.emit_warning(thread_store.level_id(), /*turn_id*/ None, message);
|
||||
@@ -420,7 +420,8 @@ where
|
||||
let context_window = model_info
|
||||
.as_deref()
|
||||
.and_then(ModelInfo::resolved_context_window);
|
||||
let metadata_budget = skill_metadata_budget(context_window);
|
||||
let metadata_budget =
|
||||
skill_metadata_budget(context_window, config.max_context_tokens);
|
||||
let rendered = render_catalog(
|
||||
extension_metrics.as_deref(),
|
||||
CatalogSurface::TurnInput,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use std::borrow::Cow;
|
||||
use std::num::NonZeroUsize;
|
||||
|
||||
use codex_protocol::protocol::SkillScope;
|
||||
use codex_utils_string::approx_token_count;
|
||||
@@ -14,6 +15,7 @@ use crate::fragments::AvailableSkillsInstructions;
|
||||
use crate::host_aliases::shared_host_alias_roots;
|
||||
|
||||
const DEFAULT_SKILL_METADATA_CHAR_BUDGET: usize = 8_000;
|
||||
const MAX_CONFIGURED_SKILL_METADATA_TOKEN_BUDGET: usize = 10_000;
|
||||
const MAX_SKILL_PROMPT_BYTES: usize = 8_000;
|
||||
const SKILL_METADATA_CONTEXT_WINDOW_PERCENT: usize = 2;
|
||||
const MAX_CATALOG_SKILL_DESCRIPTION_CHARS: usize = 1_024;
|
||||
@@ -122,7 +124,18 @@ impl SkillRenderReport {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn skill_metadata_budget(context_window: Option<i64>) -> SkillMetadataBudget {
|
||||
pub(crate) fn skill_metadata_budget(
|
||||
context_window: Option<i64>,
|
||||
max_context_tokens: Option<NonZeroUsize>,
|
||||
) -> SkillMetadataBudget {
|
||||
if let Some(max_context_tokens) = max_context_tokens {
|
||||
return SkillMetadataBudget::Tokens(
|
||||
max_context_tokens
|
||||
.get()
|
||||
.min(MAX_CONFIGURED_SKILL_METADATA_TOKEN_BUDGET),
|
||||
);
|
||||
}
|
||||
|
||||
context_window
|
||||
.and_then(|window| usize::try_from(window).ok())
|
||||
.filter(|window| *window > 0)
|
||||
|
||||
@@ -194,17 +194,27 @@ fn description_selection_follows_render_policy() {
|
||||
#[test]
|
||||
fn catalog_budget_uses_context_percentage_or_character_fallback() {
|
||||
assert_eq!(
|
||||
skill_metadata_budget(Some(100_000)),
|
||||
skill_metadata_budget(Some(100_000), /*max_context_tokens*/ None),
|
||||
SkillMetadataBudget::Tokens(2_000)
|
||||
);
|
||||
assert_eq!(
|
||||
skill_metadata_budget(Some(400_000)),
|
||||
skill_metadata_budget(Some(400_000), /*max_context_tokens*/ None),
|
||||
SkillMetadataBudget::Tokens(8_000)
|
||||
);
|
||||
assert_eq!(
|
||||
skill_metadata_budget(/*context_window*/ None),
|
||||
skill_metadata_budget(
|
||||
/*context_window*/ None, /*max_context_tokens*/ None
|
||||
),
|
||||
SkillMetadataBudget::Characters(8_000)
|
||||
);
|
||||
assert_eq!(
|
||||
skill_metadata_budget(Some(100_000), NonZeroUsize::new(5_000)),
|
||||
SkillMetadataBudget::Tokens(5_000)
|
||||
);
|
||||
assert_eq!(
|
||||
skill_metadata_budget(/*context_window*/ None, NonZeroUsize::new(50_000)),
|
||||
SkillMetadataBudget::Tokens(10_000)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -107,6 +107,7 @@ impl<'a> CatalogContext<'a> {
|
||||
let context_window = model_info
|
||||
.as_deref()
|
||||
.and_then(ModelInfo::resolved_context_window);
|
||||
let metadata_budget = skill_metadata_budget(context_window, config.max_context_tokens);
|
||||
let emitted_warnings = input
|
||||
.turn_store
|
||||
.get_or_init(EmittedCatalogBudgetWarnings::default);
|
||||
@@ -127,7 +128,7 @@ impl<'a> CatalogContext<'a> {
|
||||
input,
|
||||
thread_state,
|
||||
config,
|
||||
metadata_budget: skill_metadata_budget(context_window),
|
||||
metadata_budget,
|
||||
include_usage,
|
||||
warning_emitter,
|
||||
})
|
||||
|
||||
@@ -2393,6 +2393,7 @@ fn default_config() -> TestConfig {
|
||||
fn skills_extension_config(config: &TestConfig) -> SkillsExtensionConfig {
|
||||
SkillsExtensionConfig {
|
||||
include_instructions: config.include_instructions,
|
||||
max_context_tokens: None,
|
||||
bundled_skills_enabled: config.bundled_skills_enabled,
|
||||
orchestrator_skills_enabled: config.orchestrator_skills_enabled,
|
||||
shadow_selection_enabled: config.shadow_selection_enabled,
|
||||
|
||||
Reference in new issue
Block a user