mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
feat(app-server): move v2 sessionId onto Thread (#21336)
## Why `session_id` and `thread_id` are separate identities after #20437, but app-server only surfaced `sessionId` on the `thread/start`, `thread/resume`, and `thread/fork` response envelopes. Other thread-bearing surfaces such as `thread/list`, `thread/read`, `thread/started`, `thread/rollback`, `thread/metadata/update`, and `thread/unarchive` either lacked the grouping key or forced clients to special-case those three responses. Making `sessionId` part of the reusable `Thread` payload gives every v2 API surface one place to expose session-tree identity. ## Mental model 1. thread.sessionId lives on `Thread` 2. It is a view/runtime identity for the current live session tree, not durable stored lineage metadata 3. When app-server has a live loaded thread, it copies the real value from core’s session_configured.session_id 4. When it only has stored/unloaded data, it falls back to thread.sessionId = thread.id ## What changed - Added `sessionId` to the v2 [`Thread`](https://github.com/openai/codex/blob/8fc9e9b4cf81b6f61d432e71f1eb266f6f104b63/codex-rs/app-server-protocol/src/protocol/v2/thread_data.rs#L105-L109). - Removed the duplicate top-level `sessionId` fields from `thread/start`, `thread/resume`, and `thread/fork`; clients should now read `response.thread.sessionId`. - Populated `thread.sessionId` when building live thread responses, replaying loaded threads, and returning stored-thread summaries so the field is present across start, resume, fork, list, read, rollback, metadata-update, unarchive, and `thread/started` paths. See [`load_thread_from_resume_source_or_send_internal`](https://github.com/openai/codex/blob/8fc9e9b4cf81b6f61d432e71f1eb266f6f104b63/codex-rs/app-server/src/request_processors/thread_processor.rs#L2824-L2918) and [`thread_from_stored_thread`](https://github.com/openai/codex/blob/8fc9e9b4cf81b6f61d432e71f1eb266f6f104b63/codex-rs/app-server/src/request_processors/thread_processor.rs#L3671-L3719). - Preserved the stored-thread fallback: if a thread has not been loaded into a live session tree yet, `thread.sessionId` falls back to `thread.id`; once the thread is live again, the field reports the active session tree root. - Regenerated the JSON/TypeScript schemas and updated the app-server README examples to show [`thread.sessionId`](https://github.com/openai/codex/blob/8fc9e9b4cf81b6f61d432e71f1eb266f6f104b63/codex-rs/app-server/README.md#L306-L310) on the thread object.
This commit is contained in:
@@ -2176,9 +2176,9 @@ mod tests {
|
||||
let response = ClientResponse::ThreadStart {
|
||||
request_id: RequestId::Integer(7),
|
||||
response: v2::ThreadStartResponse {
|
||||
session_id: "67e55044-10b1-426f-9247-bb680e5fe0c7".to_string(),
|
||||
thread: v2::Thread {
|
||||
id: "67e55044-10b1-426f-9247-bb680e5fe0c8".to_string(),
|
||||
session_id: "67e55044-10b1-426f-9247-bb680e5fe0c7".to_string(),
|
||||
forked_from_id: None,
|
||||
preview: "first prompt".to_string(),
|
||||
ephemeral: true,
|
||||
@@ -2218,9 +2218,9 @@ mod tests {
|
||||
"method": "thread/start",
|
||||
"id": 7,
|
||||
"response": {
|
||||
"sessionId": "67e55044-10b1-426f-9247-bb680e5fe0c7",
|
||||
"thread": {
|
||||
"id": "67e55044-10b1-426f-9247-bb680e5fe0c8",
|
||||
"sessionId": "67e55044-10b1-426f-9247-bb680e5fe0c7",
|
||||
"forkedFromId": null,
|
||||
"preview": "first prompt",
|
||||
"ephemeral": true,
|
||||
|
||||
@@ -3437,10 +3437,11 @@ fn thread_start_params_preserve_explicit_null_service_tier() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn thread_lifecycle_responses_default_missing_compat_fields() {
|
||||
fn thread_lifecycle_responses_default_missing_optional_fields() {
|
||||
let response = json!({
|
||||
"thread": {
|
||||
"id": "thread-id",
|
||||
"sessionId": "thread-id",
|
||||
"forkedFromId": null,
|
||||
"preview": "",
|
||||
"ephemeral": false,
|
||||
|
||||
@@ -189,9 +189,6 @@ pub struct MockExperimentalMethodResponse {
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ThreadStartResponse {
|
||||
/// Session id shared by threads that belong to the same session tree.
|
||||
#[serde(default)]
|
||||
pub session_id: String,
|
||||
pub thread: Thread,
|
||||
pub model: String,
|
||||
pub model_provider: String,
|
||||
@@ -307,9 +304,6 @@ pub struct ThreadResumeParams {
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ThreadResumeResponse {
|
||||
/// Session id shared by threads that belong to the same session tree.
|
||||
#[serde(default)]
|
||||
pub session_id: String,
|
||||
pub thread: Thread,
|
||||
pub model: String,
|
||||
pub model_provider: String,
|
||||
@@ -419,9 +413,6 @@ pub struct ThreadForkParams {
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ThreadForkResponse {
|
||||
/// Session id shared by threads that belong to the same session tree.
|
||||
#[serde(default)]
|
||||
pub session_id: String,
|
||||
pub thread: Thread,
|
||||
pub model: String,
|
||||
pub model_provider: String,
|
||||
|
||||
@@ -104,6 +104,8 @@ pub struct GitInfo {
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct Thread {
|
||||
pub id: String,
|
||||
/// Session id shared by threads that belong to the same session tree.
|
||||
pub session_id: String,
|
||||
/// Source thread id when this thread was created by forking another thread.
|
||||
pub forked_from_id: Option<String>,
|
||||
/// Usually the first user message in the thread, if available.
|
||||
|
||||
Reference in New Issue
Block a user