121 lines
4.9 KiB
Rust
121 lines
4.9 KiB
Rust
use super::*;
|
|
|
|
pub(crate) fn apply_configured_context_limits(
|
|
runtime_models: &mut [CodexRuntimeModel],
|
|
content: &str,
|
|
) -> Result<(), String> {
|
|
let document: serde_norway::Value = serde_norway::from_str(content)
|
|
.map_err(|error| format!("Failed to parse kernel model context configuration: {error}"))?;
|
|
let root = document
|
|
.as_mapping()
|
|
.ok_or("Kernel configuration root must be a YAML mapping")?;
|
|
let mut limits: HashMap<String, u64> = HashMap::new();
|
|
for section in crate::MODEL_ALIAS_CONFIG_SECTIONS {
|
|
let Some(providers) =
|
|
crate::yaml_mapping_value(root, section).and_then(serde_norway::Value::as_sequence)
|
|
else {
|
|
continue;
|
|
};
|
|
for provider in providers {
|
|
let Some(models) = provider
|
|
.as_mapping()
|
|
.and_then(|provider| crate::yaml_mapping_value(provider, "models"))
|
|
.and_then(serde_norway::Value::as_sequence)
|
|
else {
|
|
continue;
|
|
};
|
|
for model in models {
|
|
let Some((_, public_name, _)) = crate::configured_model_identity(model) else {
|
|
continue;
|
|
};
|
|
let Some(limit) = model
|
|
.as_mapping()
|
|
.and_then(|model| crate::yaml_mapping_value(model, "max-context-length"))
|
|
.and_then(serde_norway::Value::as_u64)
|
|
.filter(|value| *value > 0)
|
|
else {
|
|
continue;
|
|
};
|
|
limits
|
|
.entry(normalize_id(&public_name))
|
|
.and_modify(|existing| *existing = (*existing).min(limit))
|
|
.or_insert(limit);
|
|
}
|
|
}
|
|
}
|
|
for runtime in runtime_models {
|
|
if let Some(&limit) = limits.get(&normalize_id(&runtime.slug)) {
|
|
runtime.context_window = Some(limit);
|
|
runtime.max_context_window = Some(limit);
|
|
runtime.context_source = "configuration";
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn codex_client_context_defaults_are_preserved_in_editor_and_generated_catalog() {
|
|
let runtime = parse_runtime_models(&serde_json::json!({"models":[
|
|
{"slug":"gpt-5.6-sol","context_window":272000,"max_context_window":872000},
|
|
{"slug":"fast-alias","context_window":128000,"max_context_window":256000},
|
|
{"slug":"missing-context"}
|
|
]}))
|
|
.unwrap();
|
|
let sources = parse_sources(MODEL_CATALOG_JSON).unwrap();
|
|
let state = CatalogState {
|
|
sources,
|
|
json: MODEL_CATALOG_JSON.to_string(),
|
|
customizations: Default::default(),
|
|
};
|
|
let snapshot = customizations::snapshot_for_state(&runtime, &state).unwrap();
|
|
let snapshot = serde_json::to_value(snapshot).unwrap();
|
|
let prepared =
|
|
prepare_catalog_with_customizations(&runtime, &state.sources, &state.customizations)
|
|
.unwrap();
|
|
let catalog: Value = serde_json::from_str(&prepared.json).unwrap();
|
|
for (slug, context, maximum, source) in [
|
|
("gpt-5.6-sol", 272_000, 872_000, "client"),
|
|
("fast-alias", 128_000, 256_000, "client"),
|
|
("missing-context", 272_000, 272_000, "template"),
|
|
] {
|
|
let model = snapshot["models"]
|
|
.as_array()
|
|
.unwrap()
|
|
.iter()
|
|
.find(|model| model["slug"] == slug)
|
|
.unwrap();
|
|
for field in ["configuration", "defaults"] {
|
|
assert_eq!(model[field]["context_window"], context);
|
|
assert_eq!(model[field]["max_context_window"], maximum);
|
|
}
|
|
assert_eq!(model["contextSource"], source);
|
|
let generated = catalog["models"]
|
|
.as_array()
|
|
.unwrap()
|
|
.iter()
|
|
.find(|model| model["slug"] == slug)
|
|
.unwrap();
|
|
assert_eq!(generated["context_window"], context);
|
|
assert_eq!(generated["max_context_window"], maximum);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn core_configured_context_limit_takes_precedence_over_client_defaults() {
|
|
let mut runtime = parse_runtime_models(&serde_json::json!({"models":[
|
|
{"slug":"custom-alias","context_window":921000,"max_context_window":921000},
|
|
{"slug":"unmodified","context_window":128000,"max_context_window":128000}
|
|
]}))
|
|
.unwrap();
|
|
apply_configured_context_limits(&mut runtime, "codex-api-key:\n - models:\n - name: upstream-model\n alias: custom-alias\n max-context-length: 64000\n").unwrap();
|
|
assert_eq!(runtime[0].context_window, Some(64_000));
|
|
assert_eq!(runtime[0].max_context_window, Some(64_000));
|
|
assert_eq!(runtime[0].context_source, "configuration");
|
|
assert_eq!(runtime[1].context_window, Some(128_000));
|
|
}
|
|
}
|