Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions codex-rs/core/src/codex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2940,6 +2940,12 @@ async fn submission_loop(sess: Arc<Session>, config: Arc<Config>, rx_sub: Receiv
Op::Compact => {
handlers::compact(&sess, sub.id.clone()).await;
}
Op::DropMemories => {
handlers::drop_memories(&sess, &config, sub.id.clone()).await;
}
Op::UpdateMemories => {
handlers::update_memories(&sess, &config, sub.id.clone()).await;
}
Op::ThreadRollback { num_turns } => {
handlers::thread_rollback(&sess, sub.id.clone(), num_turns).await;
}
Expand Down Expand Up @@ -3489,6 +3495,68 @@ mod handlers {
.await;
}

pub async fn drop_memories(sess: &Arc<Session>, config: &Arc<Config>, sub_id: String) {
let mut errors = Vec::new();

if let Some(state_db) = sess.services.state_db.as_deref() {
if let Err(err) = state_db.clear_memory_data().await {
errors.push(format!("failed clearing memory rows from state db: {err}"));
}
} else {
errors.push("state db unavailable; memory rows were not cleared".to_string());
}

let memory_root = crate::memories::memory_root(&config.codex_home);
if let Err(err) = tokio::fs::remove_dir_all(&memory_root).await
&& err.kind() != std::io::ErrorKind::NotFound
{
errors.push(format!(
"failed removing memory directory {}: {err}",
memory_root.display()
));
}

if errors.is_empty() {
sess.send_event_raw(Event {
id: sub_id,
msg: EventMsg::Warning(WarningEvent {
message: format!(
"Dropped memories at {} and cleared memory rows from state db.",
memory_root.display()
),
}),
})
.await;
return;
}

sess.send_event_raw(Event {
id: sub_id,
msg: EventMsg::Error(ErrorEvent {
message: format!("Memory drop completed with errors: {}", errors.join("; ")),
codex_error_info: Some(CodexErrorInfo::Other),
}),
})
.await;
}

pub async fn update_memories(sess: &Arc<Session>, config: &Arc<Config>, sub_id: String) {
let session_source = {
let state = sess.state.lock().await;
state.session_configuration.session_source.clone()
};

crate::memories::start_memories_startup_task(sess, Arc::clone(config), &session_source);

sess.send_event_raw(Event {
id: sub_id.clone(),
msg: EventMsg::Warning(WarningEvent {
message: "Memory update triggered.".to_string(),
}),
})
.await;
}

pub async fn thread_rollback(sess: &Arc<Session>, sub_id: String, num_turns: u32) {
if num_turns == 0 {
sess.send_event_raw(Event {
Expand Down
6 changes: 6 additions & 0 deletions codex-rs/protocol/src/protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,12 @@ pub enum Op {
/// to generate a summary which will be returned as an AgentMessage event.
Compact,

/// Drop all persisted memory artifacts and memory-tracking DB rows.
DropMemories,

/// Trigger a single pass of the startup memory pipeline.
UpdateMemories,

/// Set a user-facing thread name in the persisted rollout metadata.
/// This is a local-only operation handled by codex-core; it does not
/// involve the model.
Expand Down
26 changes: 26 additions & 0 deletions codex-rs/state/src/runtime/memories.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,32 @@ const MEMORY_CONSOLIDATION_JOB_KEY: &str = "global";
const DEFAULT_RETRY_REMAINING: i64 = 3;

impl StateRuntime {
pub async fn clear_memory_data(&self) -> anyhow::Result<()> {
let mut tx = self.pool.begin().await?;

sqlx::query(
r#"
DELETE FROM stage1_outputs
"#,
)
.execute(&mut *tx)
.await?;

sqlx::query(
r#"
DELETE FROM jobs
WHERE kind = ? OR kind = ?
"#,
)
.bind(JOB_KIND_MEMORY_STAGE1)
.bind(JOB_KIND_MEMORY_CONSOLIDATE_GLOBAL)
.execute(&mut *tx)
.await?;

tx.commit().await?;
Ok(())
}

pub async fn claim_stage1_jobs_for_startup(
&self,
current_thread_id: ThreadId,
Expand Down
6 changes: 6 additions & 0 deletions codex-rs/tui/src/chatwidget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3410,6 +3410,12 @@ impl ChatWidget {
SlashCommand::Clean => {
self.clean_background_terminals();
}
SlashCommand::MemoryDrop => {
self.submit_op(Op::DropMemories);
}
SlashCommand::MemoryUpdate => {
self.submit_op(Op::UpdateMemories);
}
SlashCommand::Mcp => {
self.add_mcp_output();
}
Expand Down
18 changes: 18 additions & 0 deletions codex-rs/tui/src/chatwidget/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3380,6 +3380,24 @@ async fn slash_clean_submits_background_terminal_cleanup() {
);
}

#[tokio::test]
async fn slash_memory_drop_submits_drop_memories_op() {
let (mut chat, _rx, mut op_rx) = make_chatwidget_manual(None).await;

chat.dispatch_command(SlashCommand::MemoryDrop);

assert_matches!(op_rx.try_recv(), Ok(Op::DropMemories));
}

#[tokio::test]
async fn slash_memory_update_submits_update_memories_op() {
let (mut chat, _rx, mut op_rx) = make_chatwidget_manual(None).await;

chat.dispatch_command(SlashCommand::MemoryUpdate);

assert_matches!(op_rx.try_recv(), Ok(Op::UpdateMemories));
}

#[tokio::test]
async fn slash_resume_opens_picker() {
let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(None).await;
Expand Down
11 changes: 10 additions & 1 deletion codex-rs/tui/src/slash_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ pub enum SlashCommand {
Clean,
Personality,
TestApproval,
// Debugging commands.
#[strum(serialize = "debug-m-drop")]
MemoryDrop,
#[strum(serialize = "debug-m-update")]
MemoryUpdate,
}

impl SlashCommand {
Expand All @@ -70,6 +75,8 @@ impl SlashCommand {
SlashCommand::Statusline => "configure which items appear in the status line",
SlashCommand::Ps => "list background terminals",
SlashCommand::Clean => "stop all background terminals",
SlashCommand::MemoryDrop => "DO NOT USE",
SlashCommand::MemoryUpdate => "DO NOT USE",
SlashCommand::Model => "choose what model and reasoning effort to use",
SlashCommand::Personality => "choose a communication style for Codex",
SlashCommand::Plan => "switch to Plan mode",
Expand Down Expand Up @@ -118,7 +125,9 @@ impl SlashCommand {
| SlashCommand::Experimental
| SlashCommand::Review
| SlashCommand::Plan
| SlashCommand::Logout => false,
| SlashCommand::Logout
| SlashCommand::MemoryDrop
| SlashCommand::MemoryUpdate => false,
SlashCommand::Diff
| SlashCommand::Rename
| SlashCommand::Mention
Expand Down
Loading