[codex] Move thread naming to app server (#21260)

## Why

Thread names are app-server metadata now, backed by the thread store and
sqlite state database. Keeping a core `SetThreadName` op plus a rollout
`thread_name_updated` event made rename persistence live in the wrong
layer and required historical replay support for an event that new
app-server flows should not write.

## What changed

- Removed `Op::SetThreadName` and `EventMsg::ThreadNameUpdated` from the
core protocol and deleted the core handler path that appended rename
events to rollouts.
- Updated app-server `thread/name/set` so both loaded and unloaded
threads write through thread-store metadata and app-server emits
`thread/name/updated` notifications.
- Updated local thread-store name metadata updates to write sqlite title
metadata and the legacy thread-name index without appending rollout
events.
- Removed state extraction and rollout handling for the deleted
thread-name event.

## Validation

- `cargo test -p codex-app-server thread_name_updated_broadcasts`
- `cargo test -p codex-app-server
thread_name_set_is_reflected_in_read_list_and_resume`
- `cargo test -p codex-thread-store
update_thread_metadata_sets_name_on_active_rollout_and_indexes_name`
- `cargo test -p codex-state`
- `cargo check -p codex-mcp-server -p codex-rollout-trace`
- `just fix -p codex-app-server -p codex-thread-store -p codex-state -p
codex-mcp-server -p codex-rollout-trace`

## Docs

No external documentation update is expected for this internal ownership
change.
This commit is contained in:
pakrym-oai
2026-05-05 17:16:06 -07:00
committed by Channing Conger
parent a69a70cb3b
commit b852d9627c
13 changed files with 32 additions and 215 deletions

View File

@@ -2,11 +2,9 @@ use std::path::Path;
use std::path::PathBuf;
use codex_protocol::ThreadId;
use codex_protocol::protocol::EventMsg;
use codex_protocol::protocol::GitInfo;
use codex_protocol::protocol::RolloutItem;
use codex_protocol::protocol::ThreadMemoryMode;
use codex_protocol::protocol::ThreadNameUpdatedEvent;
use codex_rollout::ARCHIVED_SESSIONS_SUBDIR;
use codex_rollout::append_rollout_item_to_path;
use codex_rollout::append_thread_name;
@@ -50,10 +48,8 @@ pub(super) async fn update_thread_metadata(
}
let resolved_rollout_path =
resolve_rollout_path(store, thread_id, params.include_archived).await?;
let name = params.patch.name;
let git_info = params.patch.git_info;
if let Some(name) = params.patch.name {
apply_thread_name(store, resolved_rollout_path.path.as_path(), thread_id, name).await?;
}
if let Some(memory_mode) = params.patch.memory_mode {
apply_thread_memory_mode(resolved_rollout_path.path.as_path(), thread_id, memory_mode)
.await?;
@@ -70,6 +66,10 @@ pub(super) async fn update_thread_metadata(
)
.await;
if let Some(name) = name {
apply_thread_name(store, thread_id, name).await?;
}
let resolved_git_info = match git_info {
Some(git_info) => {
let state_db = store.state_db();
@@ -229,20 +229,22 @@ async fn apply_thread_git_info_to_rollout(
async fn apply_thread_name(
store: &LocalThreadStore,
rollout_path: &Path,
thread_id: ThreadId,
name: String,
) -> ThreadStoreResult<()> {
let item = RolloutItem::EventMsg(EventMsg::ThreadNameUpdated(ThreadNameUpdatedEvent {
thread_id,
thread_name: Some(name.clone()),
}));
append_rollout_item_to_path(rollout_path, &item)
let updated = store
.state_db()
.update_thread_title(thread_id, &name)
.await
.map_err(|err| ThreadStoreError::Internal {
message: format!("failed to set thread name: {err}"),
})?;
if !updated {
return Err(ThreadStoreError::Internal {
message: format!("thread metadata unavailable before name update: {thread_id}"),
});
}
append_thread_name(store.config.codex_home.as_path(), thread_id, &name)
.await
.map_err(|err| ThreadStoreError::Internal {
@@ -369,8 +371,7 @@ mod tests {
let store = test_store(home.path()).await;
let uuid = Uuid::from_u128(301);
let thread_id = ThreadId::from_string(&uuid.to_string()).expect("valid thread id");
let path =
write_session_file(home.path(), "2025-01-03T14-00-00", uuid).expect("session file");
write_session_file(home.path(), "2025-01-03T14-00-00", uuid).expect("session file");
let thread = store
.update_thread_metadata(UpdateThreadMetadataParams {
@@ -390,11 +391,13 @@ mod tests {
.expect("find thread name");
assert_eq!(latest_name.as_deref(), Some("A sharper name"));
let appended = last_rollout_item(path.as_path());
assert_eq!(appended["type"], "event_msg");
assert_eq!(appended["payload"]["type"], "thread_name_updated");
assert_eq!(appended["payload"]["thread_id"], thread_id.to_string());
assert_eq!(appended["payload"]["thread_name"], "A sharper name");
let metadata = store
.state_db()
.get_thread(thread_id)
.await
.expect("get metadata")
.expect("metadata");
assert_eq!(metadata.title, "A sharper name");
}
#[tokio::test]