mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
feat: return session ID from thread/fork (#21332)
## Why `thread/start` and `thread/resume` already return `sessionId`, but `thread/fork` only returned the new thread. That left clients to infer the forked thread's session identity from `thread.id`, which kept the new `session_id` / `thread_id` split implicit at one lifecycle boundary. Follow-up to #20437. ## What changed - Add `sessionId` to `ThreadForkResponse`. - Populate it from the forked session configuration. - Regenerate the v2 JSON/TypeScript schema fixtures and update the app-server docs/example. - Extend the fork integration test to assert the returned `sessionId`. ## Verification - Added coverage in `thread_fork_creates_new_thread_and_emits_started` for the new response field.
This commit is contained in:
committed by
GitHub
Unverified
parent
fe24a180ab
commit
06e5dfa4dd
@@ -138,6 +138,7 @@ fn sample_thread_resume_response() -> ClientResponsePayload {
|
||||
|
||||
fn sample_thread_fork_response() -> ClientResponsePayload {
|
||||
ClientResponsePayload::ThreadFork(ThreadForkResponse {
|
||||
session_id: "session-3".to_string(),
|
||||
thread: sample_thread("thread-3"),
|
||||
model: "gpt-5".to_string(),
|
||||
model_provider: "openai".to_string(),
|
||||
|
||||
+5
@@ -15664,6 +15664,11 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessionId": {
|
||||
"default": "",
|
||||
"description": "Session id shared by threads that belong to the same session tree.",
|
||||
"type": "string"
|
||||
},
|
||||
"thread": {
|
||||
"$ref": "#/definitions/v2/Thread"
|
||||
}
|
||||
|
||||
+5
@@ -13550,6 +13550,11 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessionId": {
|
||||
"default": "",
|
||||
"description": "Session id shared by threads that belong to the same session tree.",
|
||||
"type": "string"
|
||||
},
|
||||
"thread": {
|
||||
"$ref": "#/definitions/Thread"
|
||||
}
|
||||
|
||||
@@ -2619,6 +2619,11 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessionId": {
|
||||
"default": "",
|
||||
"description": "Session id shared by threads that belong to the same session tree.",
|
||||
"type": "string"
|
||||
},
|
||||
"thread": {
|
||||
"$ref": "#/definitions/Thread"
|
||||
}
|
||||
|
||||
@@ -9,7 +9,10 @@ import type { AskForApproval } from "./AskForApproval";
|
||||
import type { SandboxPolicy } from "./SandboxPolicy";
|
||||
import type { Thread } from "./Thread";
|
||||
|
||||
export type ThreadForkResponse = {thread: Thread, model: string, modelProvider: string, serviceTier: ServiceTier | null, cwd: AbsolutePathBuf, /**
|
||||
export type ThreadForkResponse = {/**
|
||||
* Session id shared by threads that belong to the same session tree.
|
||||
*/
|
||||
sessionId: string, thread: Thread, model: string, modelProvider: string, serviceTier: ServiceTier | null, cwd: AbsolutePathBuf, /**
|
||||
* Instruction source files currently loaded for this thread.
|
||||
*/
|
||||
instructionSources: Array<AbsolutePathBuf>, approvalPolicy: AskForApproval, /**
|
||||
|
||||
@@ -419,6 +419,9 @@ 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,
|
||||
|
||||
@@ -303,11 +303,11 @@ Example:
|
||||
{ "id": 12, "result": { "thread": { "id": "thr_123", "turns": [], … } } }
|
||||
```
|
||||
|
||||
To branch from a stored session, call `thread/fork` with the `thread.id`. This creates a new thread id and emits a `thread/started` notification for it. When the source history includes persisted token usage, the server also emits `thread/tokenUsage/updated` for the new thread immediately after the response. If the source thread is actively running, the fork snapshots it as if the current turn had been interrupted first. Pass `ephemeral: true` when the fork should stay in-memory only:
|
||||
To branch from a stored session, call `thread/fork` with the `thread.id`. This creates a new thread id and emits a `thread/started` notification for it. The response includes the forked thread's `sessionId`, so clients do not need to infer it from the new thread id. When the source history includes persisted token usage, the server also emits `thread/tokenUsage/updated` for the new thread immediately after the response. If the source thread is actively running, the fork snapshots it as if the current turn had been interrupted first. Pass `ephemeral: true` when the fork should stay in-memory only:
|
||||
|
||||
```json
|
||||
{ "method": "thread/fork", "id": 12, "params": { "threadId": "thr_123", "ephemeral": true } }
|
||||
{ "id": 12, "result": { "thread": { "id": "thr_456", … } } }
|
||||
{ "id": 12, "result": { "sessionId": "thr_456", "thread": { "id": "thr_456", … } } }
|
||||
{ "method": "thread/started", "params": { "thread": { … } } }
|
||||
```
|
||||
|
||||
|
||||
@@ -3116,6 +3116,7 @@ impl ThreadRequestProcessor {
|
||||
thread_response_active_permission_profile(config_snapshot.active_permission_profile);
|
||||
|
||||
let response = ThreadForkResponse {
|
||||
session_id: session_configured.session_id.to_string(),
|
||||
thread: thread.clone(),
|
||||
model: session_configured.model,
|
||||
model_provider: session_configured.model_provider_id,
|
||||
|
||||
@@ -101,7 +101,9 @@ async fn thread_fork_creates_new_thread_and_emits_started() -> Result<()> {
|
||||
)
|
||||
.await??;
|
||||
let fork_result = fork_resp.result.clone();
|
||||
let ThreadForkResponse { thread, .. } = to_response::<ThreadForkResponse>(fork_resp)?;
|
||||
let ThreadForkResponse {
|
||||
session_id, thread, ..
|
||||
} = to_response::<ThreadForkResponse>(fork_resp)?;
|
||||
|
||||
// Wire contract: thread title field is `name`, serialized as null when unset.
|
||||
let thread_json = fork_result
|
||||
@@ -121,6 +123,7 @@ async fn thread_fork_creates_new_thread_and_emits_started() -> Result<()> {
|
||||
);
|
||||
|
||||
assert_ne!(thread.id, conversation_id);
|
||||
assert_eq!(session_id, thread.id);
|
||||
assert_eq!(thread.forked_from_id, Some(conversation_id.clone()));
|
||||
assert_eq!(thread.preview, preview);
|
||||
assert_eq!(thread.model_provider, "mock_provider");
|
||||
|
||||
Reference in New Issue
Block a user