mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
feat: trigger memories from user turns with cooldown (#19970)
## Why Memory startup was tied to thread lifecycle events such as create, load, and fork. That can run memory work before a thread receives real user input, and it makes startup cost scale with thread management instead of actual turns. Moving the trigger to `thread/sendInput` keeps memory startup aligned with the first real user turn and lets it use the current thread config at turn time. The idea is to prevent ghost cost due to pre-warm triggered by the app Turn-based startup can also make global phase-2 consolidation easier to request repeatedly, so this adds a success cooldown and tightens the default startup scan window. ## What Changed - Start `codex_memories_write::start_memories_startup_task` after a non-empty `thread/sendInput` turn is submitted, instead of from thread create/load/fork paths: https://github.com/openai/codex/blob/d4a6885b7829e2fd2ec7a09355e4f75ebe1d1fe3/codex-rs/app-server/src/codex_message_processor.rs#L6477-L6487 - Expose `CodexThread::config()` so app-server can pass the live config into memory startup at turn time. - Add a six-hour successful-run cooldown for global phase-2 consolidation via `SkippedCooldown`: https://github.com/openai/codex/blob/d4a6885b7829e2fd2ec7a09355e4f75ebe1d1fe3/codex-rs/state/src/runtime/memories.rs#L963-L966 - Reduce memory startup defaults to at most 2 rollouts over 10 days: https://github.com/openai/codex/blob/d4a6885b7829e2fd2ec7a09355e4f75ebe1d1fe3/codex-rs/config/src/types.rs#L31-L34 ## Verification Updated the memory runtime coverage around phase-2 reclaim behavior, including `phase2_global_lock_respects_success_cooldown`. --------- Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
committed by
GitHub
Unverified
parent
fa127be25f
commit
a9e5c34083
@@ -542,7 +542,6 @@ pub(crate) enum ApiVersion {
|
||||
|
||||
#[derive(Clone)]
|
||||
struct ListenerTaskContext {
|
||||
auth_manager: Arc<AuthManager>,
|
||||
thread_manager: Arc<ThreadManager>,
|
||||
thread_state_manager: ThreadStateManager,
|
||||
outgoing: Arc<OutgoingMessageSender>,
|
||||
@@ -2415,7 +2414,6 @@ impl CodexMessageProcessor {
|
||||
);
|
||||
typesafe_overrides.ephemeral = ephemeral;
|
||||
let listener_task_context = ListenerTaskContext {
|
||||
auth_manager: Arc::clone(&self.auth_manager),
|
||||
thread_manager: Arc::clone(&self.thread_manager),
|
||||
thread_state_manager: self.thread_state_manager.clone(),
|
||||
outgoing: Arc::clone(&self.outgoing),
|
||||
@@ -2615,7 +2613,6 @@ impl CodexMessageProcessor {
|
||||
.collect()
|
||||
};
|
||||
let core_dynamic_tool_count = core_dynamic_tools.len();
|
||||
let memory_config = Arc::new(config.clone());
|
||||
|
||||
let NewThread {
|
||||
thread_id,
|
||||
@@ -2669,14 +2666,6 @@ impl CodexMessageProcessor {
|
||||
otel.name = "app_server.thread_start.config_snapshot",
|
||||
))
|
||||
.await;
|
||||
codex_memories_write::start_memories_startup_task(
|
||||
Arc::clone(&listener_task_context.thread_manager),
|
||||
Arc::clone(&listener_task_context.auth_manager),
|
||||
thread_id,
|
||||
Arc::clone(&thread),
|
||||
Arc::clone(&memory_config),
|
||||
&config_snapshot.session_source,
|
||||
);
|
||||
let mut thread = build_thread_from_snapshot(
|
||||
thread_id,
|
||||
&config_snapshot,
|
||||
@@ -4178,7 +4167,6 @@ impl CodexMessageProcessor {
|
||||
|
||||
let instruction_sources = Self::instruction_sources_from_config(&config).await;
|
||||
let response_history = thread_history.clone();
|
||||
let memory_config = Arc::new(config.clone());
|
||||
|
||||
match self
|
||||
.thread_manager
|
||||
@@ -4253,14 +4241,6 @@ impl CodexMessageProcessor {
|
||||
/*has_live_in_progress_turn*/ false,
|
||||
);
|
||||
let config_snapshot = codex_thread.config_snapshot().await;
|
||||
codex_memories_write::start_memories_startup_task(
|
||||
Arc::clone(&self.thread_manager),
|
||||
Arc::clone(&self.auth_manager),
|
||||
thread_id,
|
||||
Arc::clone(&codex_thread),
|
||||
Arc::clone(&memory_config),
|
||||
&config_snapshot.session_source,
|
||||
);
|
||||
let sandbox = thread_response_sandbox_policy(
|
||||
&config_snapshot.permission_profile,
|
||||
config_snapshot.cwd.as_path(),
|
||||
@@ -4766,7 +4746,6 @@ impl CodexMessageProcessor {
|
||||
let fallback_model_provider = config.model_provider_id.clone();
|
||||
let instruction_sources = Self::instruction_sources_from_config(&config).await;
|
||||
let fork_thread_store = configured_thread_store(&config);
|
||||
let memory_config = Arc::new(config.clone());
|
||||
|
||||
let NewThread {
|
||||
thread_id,
|
||||
@@ -4862,14 +4841,6 @@ impl CodexMessageProcessor {
|
||||
/*has_in_progress_turn*/ false,
|
||||
);
|
||||
let config_snapshot = forked_thread.config_snapshot().await;
|
||||
codex_memories_write::start_memories_startup_task(
|
||||
Arc::clone(&self.thread_manager),
|
||||
Arc::clone(&self.auth_manager),
|
||||
thread_id,
|
||||
Arc::clone(&forked_thread),
|
||||
Arc::clone(&memory_config),
|
||||
&config_snapshot.session_source,
|
||||
);
|
||||
let sandbox = thread_response_sandbox_policy(
|
||||
&config_snapshot.permission_profile,
|
||||
config_snapshot.cwd.as_path(),
|
||||
@@ -6363,12 +6334,12 @@ impl CodexMessageProcessor {
|
||||
);
|
||||
return Err(error);
|
||||
}
|
||||
let (_, thread) = self
|
||||
.load_thread(¶ms.thread_id)
|
||||
.await
|
||||
.inspect_err(|error| {
|
||||
self.track_error_response(&request_id, error, /*error_type*/ None);
|
||||
})?;
|
||||
let (thread_id, thread) =
|
||||
self.load_thread(¶ms.thread_id)
|
||||
.await
|
||||
.inspect_err(|error| {
|
||||
self.track_error_response(&request_id, error, /*error_type*/ None);
|
||||
})?;
|
||||
Self::set_app_server_client_info(
|
||||
thread.as_ref(),
|
||||
app_server_client_name,
|
||||
@@ -6408,6 +6379,7 @@ impl CodexMessageProcessor {
|
||||
.into_iter()
|
||||
.map(V2UserInput::into_core)
|
||||
.collect();
|
||||
let turn_has_input = !mapped_items.is_empty();
|
||||
|
||||
let has_any_overrides = params.cwd.is_some()
|
||||
|| params.approval_policy.is_some()
|
||||
@@ -6502,6 +6474,18 @@ impl CodexMessageProcessor {
|
||||
error
|
||||
})?;
|
||||
|
||||
if turn_has_input {
|
||||
let config_snapshot = thread.config_snapshot().await;
|
||||
codex_memories_write::start_memories_startup_task(
|
||||
Arc::clone(&self.thread_manager),
|
||||
Arc::clone(&self.auth_manager),
|
||||
thread_id,
|
||||
Arc::clone(&thread),
|
||||
thread.config().await,
|
||||
&config_snapshot.session_source,
|
||||
);
|
||||
}
|
||||
|
||||
self.outgoing
|
||||
.record_request_turn_id(&request_id, &turn_id)
|
||||
.await;
|
||||
@@ -7188,7 +7172,6 @@ impl CodexMessageProcessor {
|
||||
) -> Result<EnsureConversationListenerResult, JSONRPCErrorError> {
|
||||
Self::ensure_conversation_listener_task(
|
||||
ListenerTaskContext {
|
||||
auth_manager: Arc::clone(&self.auth_manager),
|
||||
thread_manager: Arc::clone(&self.thread_manager),
|
||||
thread_state_manager: self.thread_state_manager.clone(),
|
||||
outgoing: Arc::clone(&self.outgoing),
|
||||
@@ -7306,7 +7289,6 @@ impl CodexMessageProcessor {
|
||||
) -> Result<(), JSONRPCErrorError> {
|
||||
Self::ensure_listener_task_running_task(
|
||||
ListenerTaskContext {
|
||||
auth_manager: Arc::clone(&self.auth_manager),
|
||||
thread_manager: Arc::clone(&self.thread_manager),
|
||||
thread_state_manager: self.thread_state_manager.clone(),
|
||||
outgoing: Arc::clone(&self.outgoing),
|
||||
@@ -7355,7 +7337,6 @@ impl CodexMessageProcessor {
|
||||
thread_state.set_listener(cancel_tx, &conversation)
|
||||
};
|
||||
let ListenerTaskContext {
|
||||
auth_manager: _,
|
||||
outgoing,
|
||||
thread_manager,
|
||||
thread_state_manager,
|
||||
|
||||
Reference in New Issue
Block a user