Skip to content

Commit f24a91e

Browse files
authored
Merge branch 'main' into migration-markdown
2 parents b6b58b6 + 81caee3 commit f24a91e

File tree

96 files changed

+3295
-1136
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

96 files changed

+3295
-1136
lines changed

codex-rs/app-server-protocol/src/protocol/common.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ client_request_definitions! {
109109
params: v2::ThreadResumeParams,
110110
response: v2::ThreadResumeResponse,
111111
},
112+
ThreadFork => "thread/fork" {
113+
params: v2::ThreadForkParams,
114+
response: v2::ThreadForkResponse,
115+
},
112116
ThreadArchive => "thread/archive" {
113117
params: v2::ThreadArchiveParams,
114118
response: v2::ThreadArchiveResponse,
@@ -230,6 +234,11 @@ client_request_definitions! {
230234
params: v1::ResumeConversationParams,
231235
response: v1::ResumeConversationResponse,
232236
},
237+
/// Fork a recorded Codex conversation into a new session.
238+
ForkConversation {
239+
params: v1::ForkConversationParams,
240+
response: v1::ForkConversationResponse,
241+
},
233242
ArchiveConversation {
234243
params: v1::ArchiveConversationParams,
235244
response: v1::ArchiveConversationResponse,

codex-rs/app-server-protocol/src/protocol/v1.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,15 @@ pub struct ResumeConversationResponse {
8383
pub rollout_path: PathBuf,
8484
}
8585

86+
#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema, TS)]
87+
#[serde(rename_all = "camelCase")]
88+
pub struct ForkConversationResponse {
89+
pub conversation_id: ThreadId,
90+
pub model: String,
91+
pub initial_messages: Option<Vec<EventMsg>>,
92+
pub rollout_path: PathBuf,
93+
}
94+
8695
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
8796
#[serde(untagged)]
8897
pub enum GetConversationSummaryParams {
@@ -148,6 +157,14 @@ pub struct ResumeConversationParams {
148157
pub overrides: Option<NewConversationParams>,
149158
}
150159

160+
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
161+
#[serde(rename_all = "camelCase")]
162+
pub struct ForkConversationParams {
163+
pub path: Option<PathBuf>,
164+
pub conversation_id: Option<ThreadId>,
165+
pub overrides: Option<NewConversationParams>,
166+
}
167+
151168
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
152169
#[serde(rename_all = "camelCase")]
153170
pub struct AddConversationSubscriptionResponse {

codex-rs/app-server-protocol/src/protocol/v2.rs

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,6 +1080,47 @@ pub struct ThreadResumeResponse {
10801080
pub reasoning_effort: Option<ReasoningEffort>,
10811081
}
10821082

1083+
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, JsonSchema, TS)]
1084+
#[serde(rename_all = "camelCase")]
1085+
#[ts(export_to = "v2/")]
1086+
/// There are two ways to fork a thread:
1087+
/// 1. By thread_id: load the thread from disk by thread_id and fork it into a new thread.
1088+
/// 2. By path: load the thread from disk by path and fork it into a new thread.
1089+
///
1090+
/// If using path, the thread_id param will be ignored.
1091+
///
1092+
/// Prefer using thread_id whenever possible.
1093+
pub struct ThreadForkParams {
1094+
pub thread_id: String,
1095+
1096+
/// [UNSTABLE] Specify the rollout path to fork from.
1097+
/// If specified, the thread_id param will be ignored.
1098+
pub path: Option<PathBuf>,
1099+
1100+
/// Configuration overrides for the forked thread, if any.
1101+
pub model: Option<String>,
1102+
pub model_provider: Option<String>,
1103+
pub cwd: Option<String>,
1104+
pub approval_policy: Option<AskForApproval>,
1105+
pub sandbox: Option<SandboxMode>,
1106+
pub config: Option<HashMap<String, serde_json::Value>>,
1107+
pub base_instructions: Option<String>,
1108+
pub developer_instructions: Option<String>,
1109+
}
1110+
1111+
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
1112+
#[serde(rename_all = "camelCase")]
1113+
#[ts(export_to = "v2/")]
1114+
pub struct ThreadForkResponse {
1115+
pub thread: Thread,
1116+
pub model: String,
1117+
pub model_provider: String,
1118+
pub cwd: PathBuf,
1119+
pub approval_policy: AskForApproval,
1120+
pub sandbox: SandboxPolicy,
1121+
pub reasoning_effort: Option<ReasoningEffort>,
1122+
}
1123+
10831124
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
10841125
#[serde(rename_all = "camelCase")]
10851126
#[ts(export_to = "v2/")]
@@ -1275,7 +1316,7 @@ pub struct Thread {
12751316
pub source: SessionSource,
12761317
/// Optional Git metadata captured when the thread was created.
12771318
pub git_info: Option<GitInfo>,
1278-
/// Only populated on `thread/resume` and `thread/rollback` responses.
1319+
/// Only populated on `thread/resume`, `thread/rollback`, `thread/fork` responses.
12791320
/// For all other responses and notifications returning a Thread,
12801321
/// the turns field will be an empty list.
12811322
pub turns: Vec<Turn>,
@@ -1351,7 +1392,7 @@ impl From<CoreTokenUsage> for TokenUsageBreakdown {
13511392
#[ts(export_to = "v2/")]
13521393
pub struct Turn {
13531394
pub id: String,
1354-
/// Only populated on a `thread/resume` response.
1395+
/// Only populated on a `thread/resume` or `thread/fork` response.
13551396
/// For all other responses and notifications returning a Turn,
13561397
/// the items field will be an empty list.
13571398
pub items: Vec<ThreadItem>,

codex-rs/app-server/README.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ Use the thread APIs to create, list, or archive conversations. Drive a conversat
4141
## Lifecycle Overview
4242

4343
- Initialize once: Immediately after launching the codex app-server process, send an `initialize` request with your client metadata, then emit an `initialized` notification. Any other request before this handshake gets rejected.
44-
- Start (or resume) a thread: Call `thread/start` to open a fresh conversation. The response returns the thread object and you’ll also get a `thread/started` notification. If you’re continuing an existing conversation, call `thread/resume` with its ID instead.
44+
- Start (or resume) a thread: Call `thread/start` to open a fresh conversation. The response returns the thread object and you’ll also get a `thread/started` notification. If you’re continuing an existing conversation, call `thread/resume` with its ID instead. If you want to branch from an existing conversation, call `thread/fork` to create a new thread id with copied history.
4545
- Begin a turn: To send user input, call `turn/start` with the target `threadId` and the user's input. Optional fields let you override model, cwd, sandbox policy, etc. This immediately returns the new turn object and triggers a `turn/started` notification.
4646
- Stream events: After `turn/start`, keep reading JSON-RPC notifications on stdout. You’ll see `item/started`, `item/completed`, deltas like `item/agentMessage/delta`, tool progress, etc. These represent streaming model output plus any side effects (commands, tool calls, reasoning notes).
4747
- Finish the turn: When the model is done (or the turn is interrupted via making the `turn/interrupt` call), the server sends `turn/completed` with the final turn state and token usage.
@@ -72,6 +72,7 @@ Example (from OpenAI's official VSCode extension):
7272

7373
- `thread/start` — create a new thread; emits `thread/started` and auto-subscribes you to turn/item events for that thread.
7474
- `thread/resume` — reopen an existing thread by id so subsequent `turn/start` calls append to it.
75+
- `thread/fork` — fork an existing thread into a new thread id by copying the stored history; emits `thread/started` and auto-subscribes you to turn/item events for the new thread.
7576
- `thread/list` — page through stored rollouts; supports cursor-based pagination and optional `modelProviders` filtering.
7677
- `thread/loaded/list` — list the thread ids currently loaded in memory.
7778
- `thread/archive` — move a thread’s rollout file into the archived directory; returns `{}` on success.
@@ -122,6 +123,14 @@ To continue a stored session, call `thread/resume` with the `thread.id` you prev
122123
{ "id": 11, "result": { "thread": { "id": "thr_123", } } }
123124
```
124125

126+
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:
127+
128+
```json
129+
{ "method": "thread/fork", "id": 12, "params": { "threadId": "thr_123" } }
130+
{ "id": 12, "result": { "thread": { "id": "thr_456", } } }
131+
{ "method": "thread/started", "params": { "thread": { } } }
132+
```
133+
125134
### Example: List threads (with pagination & filters)
126135

127136
`thread/list` lets you render a history UI. Pass any combination of:

0 commit comments

Comments
 (0)