Move thread name edits to ThreadStore (#21264)

- Route live thread renames through `ThreadStore` metadata updates.
- Read resumed thread names from store metadata with legacy local
fallback preserved in the store.
This commit is contained in:
Tom
2026-05-07 11:12:22 -07:00
committed by GitHub
Unverified
parent 0dc1885a5c
commit 56823ec46b
4 changed files with 37 additions and 51 deletions
@@ -274,7 +274,6 @@ use codex_core::exec::ExecCapturePolicy;
use codex_core::exec::ExecExpiration;
use codex_core::exec::ExecParams;
use codex_core::exec_env::create_env;
use codex_core::find_thread_name_by_id;
use codex_core::find_thread_path_by_id_str;
use codex_core::path_utils;
#[cfg(test)]
@@ -2914,10 +2914,19 @@ impl ThreadRequestProcessor {
}
async fn attach_thread_name(&self, thread_id: ThreadId, thread: &mut Thread) {
if let Some(title) =
title_from_state_db(&self.config, self.state_db.as_ref(), thread_id).await
if let Ok(stored_thread) = self
.thread_store
.read_thread(StoreReadThreadParams {
thread_id,
include_archived: true,
include_history: false,
})
.await
&& let Some(title) = stored_thread.name.as_deref().map(str::trim)
&& !title.is_empty()
&& stored_thread.preview.trim() != title
{
set_thread_name_from_title(thread, title);
set_thread_name_from_title(thread, title.to_string());
}
}
@@ -3625,37 +3634,6 @@ fn thread_store_archive_error(operation: &str, err: ThreadStoreError) -> JSONRPC
}
}
async fn title_from_state_db(
config: &Config,
state_db_ctx: Option<&StateDbHandle>,
thread_id: ThreadId,
) -> Option<String> {
if let Some(state_db_ctx) = state_db_ctx
&& let Some(metadata) = state_db_ctx.get_thread(thread_id).await.ok().flatten()
&& let Some(title) = distinct_title(&metadata)
{
return Some(title);
}
find_thread_name_by_id(&config.codex_home, &thread_id)
.await
.ok()
.flatten()
}
fn non_empty_title(metadata: &ThreadMetadata) -> Option<String> {
let title = metadata.title.trim();
(!title.is_empty()).then(|| title.to_string())
}
fn distinct_title(metadata: &ThreadMetadata) -> Option<String> {
let title = non_empty_title(metadata)?;
if metadata.first_user_message.as_deref().map(str::trim) == Some(title.as_str()) {
None
} else {
Some(title)
}
}
fn set_thread_name_from_title(thread: &mut Thread, title: String) {
if title.trim().is_empty() || thread.preview.trim() == title.trim() {
return;
+24 -15
View File
@@ -35,7 +35,6 @@ use crate::exec_policy::ExecPolicyManager;
use crate::parse_turn_item;
use crate::path_utils::normalize_for_native_workdir;
use crate::realtime_conversation::RealtimeConversationManager;
use crate::rollout::find_thread_name_by_id;
use crate::session_prefix::format_subagent_notification_message;
use crate::skills::SkillRenderSideEffects;
use crate::skills_load_input_from_config;
@@ -133,6 +132,7 @@ use codex_thread_store::CreateThreadParams;
use codex_thread_store::LiveThread;
use codex_thread_store::LiveThreadInitGuard;
use codex_thread_store::LocalThreadStore;
use codex_thread_store::ReadThreadParams;
use codex_thread_store::ResumeThreadParams;
use codex_thread_store::ThreadEventPersistenceMode;
use codex_thread_store::ThreadPersistenceMetadata;
@@ -829,24 +829,33 @@ pub(crate) fn session_loop_termination_from_handle(
.shared()
}
async fn thread_title_from_state_db(
state_db: Option<&state_db::StateDbHandle>,
codex_home: &AbsolutePathBuf,
async fn thread_title_from_thread_store(
live_thread: Option<&LiveThread>,
thread_store: &Arc<dyn ThreadStore>,
conversation_id: ThreadId,
) -> Option<String> {
if let Some(metadata) = state_db
&& let Some(metadata) = metadata.get_thread(conversation_id).await.ok().flatten()
{
let title = metadata.title.trim();
if !title.is_empty() && metadata.first_user_message.as_deref().map(str::trim) != Some(title)
{
return Some(title.to_string());
let thread = match live_thread {
Some(live_thread) => {
live_thread
.read_thread(
/*include_archived*/ true, /*include_history*/ false,
)
.await
}
None => {
thread_store
.read_thread(ReadThreadParams {
thread_id: conversation_id,
include_archived: true,
include_history: false,
})
.await
}
}
find_thread_name_by_id(codex_home, &conversation_id)
.await
.ok()
.flatten()
.ok()?;
let title = thread.name.as_deref()?.trim();
(!title.is_empty() && thread.preview.trim() != title).then(|| title.to_string())
}
impl Session {
+1 -1
View File
@@ -717,7 +717,7 @@ impl Session {
tx
};
let thread_name =
thread_title_from_state_db(state_db_ctx.as_ref(), &config.codex_home, thread_id)
thread_title_from_thread_store(live_thread_init.as_ref(), &thread_store, thread_id)
.instrument(info_span!(
"session_init.thread_name_lookup",
otel.name = "session_init.thread_name_lookup",