Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
e4cb80f
feat(app-server): add background terminal process APIs
etraut-openai Jun 3, 2026
3a5856f
Simplify background terminal list API
etraut-openai Jun 3, 2026
353ed1b
Reduce background terminal test churn
etraut-openai Jun 3, 2026
0d37f06
Restore background terminal metadata fields
etraut-openai Jun 3, 2026
b90d036
Restore background terminal start time
etraut-openai Jun 4, 2026
4d1537d
codex: address PR review feedback (#26041)
etraut-openai Jun 4, 2026
e0f9c32
codex: address PR review feedback (#26041)
etraut-openai Jun 4, 2026
64dc0d2
codex: address PR review feedback (#26041)
etraut-openai Jun 4, 2026
cce9ca7
codex: address PR review feedback (#26041)
etraut-openai Jun 4, 2026
33a8e24
Merge branch 'main' into etraut/background-terminal-apis
etraut-openai Jun 4, 2026
61c5d9c
codex: stabilize background terminal termination tests
etraut-openai Jun 4, 2026
e78df1e
codex: make background terminal tests deterministic
etraut-openai Jun 4, 2026
ff2201a
Merge branch 'main' into etraut/background-terminal-apis
etraut-openai Jun 9, 2026
b592328
Simplify background terminal APIs
etraut-openai Jun 9, 2026
b949dc3
codex: address background terminal review feedback
etraut-openai Jun 10, 2026
7daf140
codex: simplify background terminal tests
etraut-openai Jun 10, 2026
dcd1b73
Address background terminal review comments
etraut-openai Jun 10, 2026
28b3f1e
Merge branch 'main' into etraut/background-terminal-apis
etraut-openai Jun 10, 2026
cac8884
codex: address PR review feedback (#26041)
etraut-openai Jun 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions codex-rs/app-server-protocol/schema/typescript/v2/index.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

56 changes: 56 additions & 0 deletions codex-rs/app-server-protocol/src/protocol/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,18 @@ client_request_definitions! {
serialization: thread_id(params.thread_id),
response: v2::ThreadBackgroundTerminalsCleanResponse,
},
#[experimental("thread/backgroundTerminals/list")]
ThreadBackgroundTerminalsList => "thread/backgroundTerminals/list" {
Comment thread
etraut-openai marked this conversation as resolved.
params: v2::ThreadBackgroundTerminalsListParams,
serialization: thread_id(params.thread_id),
response: v2::ThreadBackgroundTerminalsListResponse,
},
#[experimental("thread/backgroundTerminals/terminate")]
ThreadBackgroundTerminalsTerminate => "thread/backgroundTerminals/terminate" {
params: v2::ThreadBackgroundTerminalsTerminateParams,
serialization: thread_id(params.thread_id),
response: v2::ThreadBackgroundTerminalsTerminateResponse,
},
ThreadRollback => "thread/rollback" {
params: v2::ThreadRollbackParams,
serialization: thread_id(params.thread_id),
Expand Down Expand Up @@ -2876,6 +2888,50 @@ mod tests {
Ok(())
}

#[test]
fn serialize_thread_background_terminals_list() -> Result<()> {
let request = ClientRequest::ThreadBackgroundTerminalsList {
request_id: RequestId::Integer(8),
params: v2::ThreadBackgroundTerminalsListParams {
thread_id: "thr_123".to_string(),
},
};
assert_eq!(
json!({
"method": "thread/backgroundTerminals/list",
"id": 8,
"params": {
"threadId": "thr_123"
}
}),
serde_json::to_value(&request)?,
);
Ok(())
}

#[test]
fn serialize_thread_background_terminals_terminate() -> Result<()> {
let request = ClientRequest::ThreadBackgroundTerminalsTerminate {
request_id: RequestId::Integer(8),
params: v2::ThreadBackgroundTerminalsTerminateParams {
thread_id: "thr_123".to_string(),
process_id: "42".to_string(),
},
};
assert_eq!(
json!({
"method": "thread/backgroundTerminals/terminate",
"id": 8,
"params": {
"threadId": "thr_123",
"processId": "42"
}
}),
serde_json::to_value(&request)?,
);
Ok(())
}

#[test]
fn serialize_thread_realtime_start() -> Result<()> {
let request = ClientRequest::ThreadRealtimeStart {
Expand Down
44 changes: 44 additions & 0 deletions codex-rs/app-server-protocol/src/protocol/v2/thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -932,6 +932,50 @@ pub struct ThreadBackgroundTerminalsCleanParams {
#[ts(export_to = "v2/")]
pub struct ThreadBackgroundTerminalsCleanResponse {}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct ThreadBackgroundTerminalsListParams {
Comment thread
etraut-openai marked this conversation as resolved.
Comment thread
etraut-openai marked this conversation as resolved.
pub thread_id: String,
}
Comment thread
etraut-openai marked this conversation as resolved.

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct ThreadBackgroundTerminal {
pub item_id: String,
pub process_id: String,
pub command: String,
pub cwd: AbsolutePathBuf,
#[ts(type = "number")]
pub started_at_ms: i64,
Comment thread
etraut-openai marked this conversation as resolved.
Outdated
pub os_pid: Option<u32>,
pub cpu_percent: Option<f64>,
pub rss_kb: Option<u64>,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct ThreadBackgroundTerminalsListResponse {
pub data: Vec<ThreadBackgroundTerminal>,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct ThreadBackgroundTerminalsTerminateParams {
pub thread_id: String,
pub process_id: String,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct ThreadBackgroundTerminalsTerminateResponse {
pub terminated: bool,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
Expand Down
29 changes: 29 additions & 0 deletions codex-rs/app-server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ Example with notification opt-out:
- `thread/compact/start` — trigger conversation history compaction for a thread; returns `{}` immediately while progress streams through standard turn/item notifications.
- `thread/shellCommand` — run a user-initiated `!` shell command against a thread; this runs unsandboxed with full access rather than inheriting the thread sandbox policy. Returns `{}` immediately while progress streams through standard turn/item notifications and any active turn receives the formatted output in its message stream.
- `thread/backgroundTerminals/clean` — terminate all running background terminals for a thread (experimental; requires `capabilities.experimentalApi`); returns `{}` when the cleanup request is accepted.
- `thread/backgroundTerminals/list` — list running background terminals for a loaded thread (experimental; requires `capabilities.experimentalApi`); returns `data` with the running terminal ids.
- `thread/backgroundTerminals/terminate` — terminate one running background terminal by app-server `processId` (experimental; requires `capabilities.experimentalApi`); returns whether a process was terminated.
- `thread/rollback` — drop the last N turns from the agent’s in-memory context and persist a rollback marker in the rollout so future resumes see the pruned history; returns the updated `thread` (with `turns` populated) on success.
- `turn/start` — add user input to a thread and begin Codex generation; responds with the initial `turn` object and streams `turn/started`, `item/*`, and `turn/completed` notifications. `clientUserMessageId` is optional; when supplied, the corresponding `userMessage` item echoes it as `clientId`. Experimental `runtimeWorkspaceRoots` replaces the thread-scoped runtime workspace roots used to materialize `:workspace_roots`; relative paths resolve against the effective turn cwd. Prefer experimental `permissions` profile selection by id for permission overrides; the legacy `sandboxPolicy` field is still accepted but cannot be combined with `permissions`. For `collaborationMode`, `settings.developer_instructions: null` means "use built-in instructions for the selected mode".
- `thread/inject_items` — append raw Responses API items to a loaded thread’s model-visible history without starting a user turn; returns `{}` on success.
Expand Down Expand Up @@ -857,6 +859,33 @@ Use `thread/backgroundTerminals/clean` to terminate all running background termi
{ "id": 35, "result": {} }
```

### Example: List and terminate background terminals

Use `thread/backgroundTerminals/list` to inspect running background terminals associated with a loaded thread. The returned `processId` is the app-server process id; host OS metadata is nullable.

```json
{ "method": "thread/backgroundTerminals/list", "id": 36, "params": { "threadId": "thr_123" } }
{ "id": 36, "result": { "data": [
{
"itemId": "item_456",
"processId": "42",
"command": "python3 -m http.server",
"cwd": "/workspace",
"startedAtMs": 1730831111000,
"osPid": null,
"cpuPercent": null,
"rssKb": null
}
] } }
```

Use `thread/backgroundTerminals/terminate` to terminate one running background terminal by that `processId`.

```json
{ "method": "thread/backgroundTerminals/terminate", "id": 37, "params": { "threadId": "thr_123", "processId": "42" } }
{ "id": 37, "result": { "terminated": true } }
```

### Example: Steer an active turn

Use `turn/steer` to append additional user input to the currently active regular turn. This does
Expand Down
10 changes: 10 additions & 0 deletions codex-rs/app-server/src/message_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1086,6 +1086,16 @@ impl MessageProcessor {
.thread_background_terminals_clean(&request_id, params)
.await
}
ClientRequest::ThreadBackgroundTerminalsList { params, .. } => {
self.thread_processor
.thread_background_terminals_list(params)
.await
}
ClientRequest::ThreadBackgroundTerminalsTerminate { params, .. } => {
self.thread_processor
.thread_background_terminals_terminate(params)
.await
}
ClientRequest::ThreadRollback { params, .. } => {
self.thread_processor
.thread_rollback(&request_id, params)
Expand Down
5 changes: 5 additions & 0 deletions codex-rs/app-server/src/request_processors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,13 @@ use codex_app_server_protocol::ThreadApproveGuardianDeniedActionResponse;
use codex_app_server_protocol::ThreadArchiveParams;
use codex_app_server_protocol::ThreadArchiveResponse;
use codex_app_server_protocol::ThreadArchivedNotification;
use codex_app_server_protocol::ThreadBackgroundTerminal;
use codex_app_server_protocol::ThreadBackgroundTerminalsCleanParams;
use codex_app_server_protocol::ThreadBackgroundTerminalsCleanResponse;
use codex_app_server_protocol::ThreadBackgroundTerminalsListParams;
use codex_app_server_protocol::ThreadBackgroundTerminalsListResponse;
use codex_app_server_protocol::ThreadBackgroundTerminalsTerminateParams;
use codex_app_server_protocol::ThreadBackgroundTerminalsTerminateResponse;
use codex_app_server_protocol::ThreadClosedNotification;
use codex_app_server_protocol::ThreadCompactStartParams;
use codex_app_server_protocol::ThreadCompactStartResponse;
Expand Down
Loading
Loading