Add field to Thread object for the latest rename set for a given thread (#12301)

Exposes through the app server updated names set for a thread. This
enables other surfaces to use the core as the source of truth for thread
naming. `threadName` is gathered using the helper functions used to
interact with `session_index.jsonl`, and is hydrated in:
- `thread/list`
- `thread/read`
- `thread/resume`
- `thread/unarchive`
- `thread/rollback`

We don't do this for `thread/start` and `thread/fork`.
This commit is contained in:
natea-oai
2026-02-20 18:26:57 -08:00
committed by GitHub
parent 53bcfaf42d
commit 936e744c93
21 changed files with 386 additions and 7 deletions

View File

@@ -18,6 +18,7 @@ use codex_app_server_protocol::UserInput;
use codex_core::find_archived_thread_path_by_id_str;
use codex_core::find_thread_path_by_id_str;
use pretty_assertions::assert_eq;
use serde_json::Value;
use std::fs::FileTimes;
use std::fs::OpenOptions;
use std::path::Path;
@@ -120,6 +121,7 @@ async fn thread_unarchive_moves_rollout_back_into_sessions_directory() -> Result
mcp.read_stream_until_response_message(RequestId::Integer(unarchive_id)),
)
.await??;
let unarchive_result = unarchive_resp.result.clone();
let ThreadUnarchiveResponse {
thread: unarchived_thread,
} = to_response::<ThreadUnarchiveResponse>(unarchive_resp)?;
@@ -140,6 +142,18 @@ async fn thread_unarchive_moves_rollout_back_into_sessions_directory() -> Result
);
assert_eq!(unarchived_thread.status, ThreadStatus::NotLoaded);
// Wire contract: thread title field is `name`, serialized as null when unset.
let thread_json = unarchive_result
.get("thread")
.and_then(Value::as_object)
.expect("thread/unarchive result.thread must be an object");
assert_eq!(unarchived_thread.name, None);
assert_eq!(
thread_json.get("name"),
Some(&Value::Null),
"thread/unarchive must serialize `name: null` when unset"
);
let rollout_path_display = rollout_path.display();
assert!(
rollout_path.exists(),