mirror of
https://github.com/openai/codex.git
synced 2026-10-28 18:58:46 +00:00
Configure memory consolidation service tiers independently (#57568)
## Why Memory consolidation inherits the session's service tier. Give background consolidation its own setting, defaulting to Standard. ## What changed Add `memories.consolidation_service_tier` with a default of `"default"` and apply it to the consolidation agent. Normalize recognized tier aliases, including `"fast"` to `"priority"`, and expose the setting in the configuration schema. ## Testing Add coverage for configuration parsing and alias normalization, Standard consolidation despite an Ultrafast session tier, and an explicit `"flex"` consolidation override. GitOrigin-RevId: 58031ad56196152d212531d56e7fe9813f83317e
This commit is contained in:
@@ -21,6 +21,7 @@ pub use codex_protocol::config_types::AltScreenMode;
|
||||
pub use codex_protocol::config_types::ApprovalsReviewer;
|
||||
pub use codex_protocol::config_types::ModeKind;
|
||||
pub use codex_protocol::config_types::Personality;
|
||||
use codex_protocol::config_types::SERVICE_TIER_DEFAULT_REQUEST_VALUE;
|
||||
pub use codex_protocol::config_types::ServiceTier;
|
||||
use codex_protocol::config_types::ToolExposureSurface;
|
||||
pub use codex_protocol::config_types::WebSearchMode;
|
||||
@@ -353,6 +354,8 @@ pub struct MemoriesToml {
|
||||
pub extract_model: Option<String>,
|
||||
/// Model used for memory consolidation.
|
||||
pub consolidation_model: Option<String>,
|
||||
/// Service tier for memory consolidation. Defaults to Standard (`"default"`).
|
||||
pub consolidation_service_tier: Option<String>,
|
||||
}
|
||||
|
||||
/// Effective memories settings after defaults are applied.
|
||||
@@ -372,6 +375,7 @@ pub struct MemoriesConfig {
|
||||
pub min_rate_limit_remaining_percent: i64,
|
||||
pub extract_model: Option<String>,
|
||||
pub consolidation_model: Option<String>,
|
||||
pub consolidation_service_tier: String,
|
||||
}
|
||||
|
||||
impl Default for MemoriesConfig {
|
||||
@@ -391,6 +395,7 @@ impl Default for MemoriesConfig {
|
||||
min_rate_limit_remaining_percent: DEFAULT_MEMORIES_MIN_RATE_LIMIT_REMAINING_PERCENT,
|
||||
extract_model: None,
|
||||
consolidation_model: None,
|
||||
consolidation_service_tier: SERVICE_TIER_DEFAULT_REQUEST_VALUE.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -439,6 +444,13 @@ impl From<MemoriesToml> for MemoriesConfig {
|
||||
.clamp(0, 100),
|
||||
extract_model: toml.extract_model,
|
||||
consolidation_model: toml.consolidation_model,
|
||||
consolidation_service_tier: toml
|
||||
.consolidation_service_tier
|
||||
.map(|tier| {
|
||||
ServiceTier::from_request_value(&tier)
|
||||
.map_or(tier, |tier| tier.request_value().to_string())
|
||||
})
|
||||
.unwrap_or(defaults.consolidation_service_tier),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2840,6 +2840,10 @@
|
||||
"description": "Model used for memory consolidation.",
|
||||
"type": "string"
|
||||
},
|
||||
"consolidation_service_tier": {
|
||||
"description": "Service tier for memory consolidation. Defaults to Standard (`\"default\"`).",
|
||||
"type": "string"
|
||||
},
|
||||
"dedicated_tools": {
|
||||
"description": "When `true`, expose dedicated memory tools through the extension tool surface.",
|
||||
"type": "boolean"
|
||||
|
||||
@@ -336,6 +336,7 @@ min_rollout_idle_hours = 24
|
||||
min_rate_limit_remaining_percent = 12
|
||||
extract_model = "gpt-5-mini"
|
||||
consolidation_model = "gpt-5.2"
|
||||
consolidation_service_tier = "fast"
|
||||
"#;
|
||||
let memories_cfg =
|
||||
toml::from_str::<ConfigToml>(memories).expect("TOML deserialization should succeed");
|
||||
@@ -355,6 +356,7 @@ consolidation_model = "gpt-5.2"
|
||||
min_rate_limit_remaining_percent: Some(12),
|
||||
extract_model: Some("gpt-5-mini".to_string()),
|
||||
consolidation_model: Some("gpt-5.2".to_string()),
|
||||
consolidation_service_tier: Some("fast".to_string()),
|
||||
}),
|
||||
memories_cfg.memories
|
||||
);
|
||||
@@ -383,6 +385,7 @@ consolidation_model = "gpt-5.2"
|
||||
min_rate_limit_remaining_percent: 12,
|
||||
extract_model: Some("gpt-5-mini".to_string()),
|
||||
consolidation_model: Some("gpt-5.2".to_string()),
|
||||
consolidation_service_tier: "priority".to_string(),
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -365,6 +365,7 @@ mod agent {
|
||||
.unwrap_or_else(|| provider.memory_consolidation_preferred_model().to_string()),
|
||||
);
|
||||
agent_config.model_reasoning_effort = Some(crate::stage_two::REASONING_EFFORT);
|
||||
agent_config.service_tier = Some(config.memories.consolidation_service_tier.clone());
|
||||
|
||||
Some(agent_config)
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ use codex_protocol::ThreadId;
|
||||
use codex_protocol::config_types::ServiceTier;
|
||||
use codex_protocol::models::ContentItem;
|
||||
use codex_protocol::models::ResponseItem;
|
||||
use codex_protocol::openai_models::ModelInfo;
|
||||
use codex_protocol::openai_models::ModelServiceTier;
|
||||
use codex_protocol::openai_models::ModelsResponse;
|
||||
use codex_protocol::openai_models::ReasoningEffort;
|
||||
use codex_protocol::protocol::EventMsg;
|
||||
@@ -48,6 +50,7 @@ use core_test_support::responses::sse;
|
||||
use core_test_support::responses::sse_failed;
|
||||
use core_test_support::responses::start_mock_server;
|
||||
use core_test_support::test_codex::TestCodex;
|
||||
use core_test_support::test_codex::TestCodexBuilder;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::wait_for_event;
|
||||
use pretty_assertions::assert_eq;
|
||||
@@ -86,7 +89,9 @@ async fn dual_write_prepares_both_roots_without_importing_old_notes() -> anyhow:
|
||||
tokio::fs::write(old_notes.join("old.md"), "old memory").await?;
|
||||
let mut memories = startup_test_memories_config();
|
||||
memories.dual_write = true;
|
||||
let test = build_test_codex_with_memories_config(&server, Arc::clone(&home), memories).await?;
|
||||
let test = memory_test_codex(Arc::clone(&home), memories)
|
||||
.build(&server)
|
||||
.await?;
|
||||
trigger_memories_startup(&test).await;
|
||||
wait_for_dir(&home.path().join("memories/extensions/ad_hoc")).await?;
|
||||
wait_for_dir(&home.path().join("memories_v2/extensions/ad_hoc")).await?;
|
||||
@@ -788,7 +793,7 @@ async fn memories_startup_phase1_provider_default_drives_request_model() -> anyh
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn memories_startup_phase2_provider_default_drives_request_model() -> anyhow::Result<()> {
|
||||
async fn memories_startup_phase2_uses_provider_model_and_standard_tier() -> anyhow::Result<()> {
|
||||
let server = start_mock_server().await;
|
||||
let home = Arc::new(TempDir::new()?);
|
||||
let request =
|
||||
@@ -799,6 +804,7 @@ async fn memories_startup_phase2_provider_default_drives_request_model() -> anyh
|
||||
request.body_json()["model"].as_str(),
|
||||
Some(MOCK_PROVIDER_PHASE_TWO_MODEL)
|
||||
);
|
||||
assert_eq!(request.body_json().get("service_tier"), None);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -843,7 +849,9 @@ async fn run_memory_phase_one_model_request_test(
|
||||
memories: MemoriesConfig,
|
||||
) -> anyhow::Result<ResponsesRequest> {
|
||||
let version = memories.version;
|
||||
let test = build_test_codex_with_memories_config(server, Arc::clone(&home), memories).await?;
|
||||
let test = memory_test_codex(Arc::clone(&home), memories)
|
||||
.build(server)
|
||||
.await?;
|
||||
let provider = Arc::new(MockMemoryModelProvider::new(
|
||||
test.config.model_provider.clone(),
|
||||
Some(test.thread_manager.auth_manager()),
|
||||
@@ -1055,7 +1063,27 @@ async fn run_memory_phase_two_model_request_test(
|
||||
memories: MemoriesConfig,
|
||||
) -> anyhow::Result<ResponsesRequest> {
|
||||
let version = memories.version;
|
||||
let test = build_test_codex_with_memories_config(server, home.clone(), memories).await?;
|
||||
// Both models support Ultrafast so an inherited tier would reach the wire.
|
||||
let advertise_ultrafast = |model: &mut ModelInfo| {
|
||||
model.service_tiers.push(ModelServiceTier {
|
||||
id: "ultrafast".to_string(),
|
||||
name: "Ultrafast".to_string(),
|
||||
description: String::new(),
|
||||
});
|
||||
model.default_service_tier = Some("ultrafast".to_string());
|
||||
};
|
||||
let test = memory_test_codex(Arc::clone(&home), memories)
|
||||
.with_model_info_override(MOCK_PROVIDER_PHASE_TWO_MODEL, advertise_ultrafast)
|
||||
.with_model_info_override("mock.interactive", advertise_ultrafast)
|
||||
.with_config(|config| {
|
||||
config
|
||||
.features
|
||||
.enable(Feature::UltrafastMode)
|
||||
.expect("enable Ultrafast");
|
||||
config.service_tier = Some("ultrafast".to_string());
|
||||
})
|
||||
.build_with_auto_env(server)
|
||||
.await?;
|
||||
let provider = Arc::new(MockMemoryModelProvider::new(
|
||||
test.config.model_provider.clone(),
|
||||
Some(test.thread_manager.auth_manager()),
|
||||
@@ -1165,27 +1193,21 @@ async fn build_test_codex(
|
||||
server: &wiremock::MockServer,
|
||||
home: Arc<TempDir>,
|
||||
) -> anyhow::Result<TestCodex> {
|
||||
build_test_codex_with_memories_config(server, home, startup_test_memories_config()).await
|
||||
}
|
||||
|
||||
async fn build_test_codex_with_memories_config(
|
||||
server: &wiremock::MockServer,
|
||||
home: Arc<TempDir>,
|
||||
memories: MemoriesConfig,
|
||||
) -> anyhow::Result<TestCodex> {
|
||||
test_codex()
|
||||
.with_home(home)
|
||||
.with_config(move |config| {
|
||||
config
|
||||
.features
|
||||
.enable(Feature::Sqlite)
|
||||
.expect("test config should allow feature update");
|
||||
config.memories = memories;
|
||||
})
|
||||
memory_test_codex(home, startup_test_memories_config())
|
||||
.build(server)
|
||||
.await
|
||||
}
|
||||
|
||||
fn memory_test_codex(home: Arc<TempDir>, memories: MemoriesConfig) -> TestCodexBuilder {
|
||||
test_codex().with_home(home).with_config(move |config| {
|
||||
config
|
||||
.features
|
||||
.enable(Feature::Sqlite)
|
||||
.expect("test config should allow feature update");
|
||||
config.memories = memories;
|
||||
})
|
||||
}
|
||||
|
||||
async fn init_state_db(home: &Arc<TempDir>) -> anyhow::Result<Arc<codex_state::StateRuntime>> {
|
||||
let db = codex_state::StateRuntime::init(
|
||||
codex_state::SqliteConfig::new_for_testing(home.path().abs()),
|
||||
@@ -1613,6 +1635,8 @@ async fn memories_startup_phase2_v2_consolidates_without_a_handbook() -> anyhow:
|
||||
let home = Arc::new(TempDir::new()?);
|
||||
let mut memories = startup_test_memories_config();
|
||||
memories.version = codex_protocol::MemoryVersion::V2;
|
||||
run_memory_phase_two_model_request_test(&server, home, memories).await?;
|
||||
memories.consolidation_service_tier = "flex".to_string();
|
||||
let request = run_memory_phase_two_model_request_test(&server, home, memories).await?;
|
||||
assert_eq!(request.body_json()["service_tier"], "flex");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user