enable/disable remote control at runtime, not via features (#22578)

## Why
reapplies https://github.com/openai/codex/pull/22386 which was
previously reverted

Also, introduce `remoteControl/enable` and `remoteControl/disable`
app-server APIs to toggle on/off remote control at runtime for a given
running app-server instance.

## What Changed

- Adds experimental v2 RPCs:
  - `remoteControl/enable`
  - `remoteControl/disable`
- Adds `RemoteControlRequestProcessor` and routes the new RPCs through
it instead of `ConfigRequestProcessor`.
- Adds named `RemoteControlHandle::enable`, `disable`, and `status`
methods.
- Makes `remoteControl/enable` return an error when sqlite state DB is
unavailable, while keeping enrollment/websocket failures as async status
updates.
- Adds `AppServerRuntimeOptions.remote_control_enabled` and hidden
`--remote-control` flags for `codex app-server` and `codex-app-server`.
- Updates managed daemon startup to use `codex app-server
--remote-control --listen unix://`.
- Marks `Feature::RemoteControl` as removed and ignores
`[features].remote_control`.
- Updates app-server README entries for the new remote-control methods.
This commit is contained in:
Owen Lin
2026-05-13 18:07:46 -07:00
committed by GitHub
Unverified
parent 512f8f8012
commit 4e368aa2e9
22 changed files with 346 additions and 52 deletions
+4 -1
View File
@@ -421,6 +421,9 @@ impl Features {
"js_repl_tools_only" => {
continue;
}
"remote_control" => {
continue;
}
"image_detail_original" => {
continue;
}
@@ -1117,7 +1120,7 @@ pub const FEATURES: &[FeatureSpec] = &[
FeatureSpec {
id: Feature::RemoteControl,
key: "remote_control",
stage: Stage::UnderDevelopment,
stage: Stage::Removed,
default_enabled: false,
},
FeatureSpec {
+17 -2
View File
@@ -293,9 +293,24 @@ fn auth_elicitation_is_under_development() {
}
#[test]
fn remote_control_is_under_development() {
assert_eq!(Feature::RemoteControl.stage(), Stage::UnderDevelopment);
fn remote_control_is_removed_and_disabled_by_default() {
assert_eq!(Feature::RemoteControl.stage(), Stage::Removed);
assert_eq!(Feature::RemoteControl.default_enabled(), false);
assert_eq!(
feature_for_key("remote_control"),
Some(Feature::RemoteControl)
);
}
#[test]
fn remote_control_config_is_ignored() {
let mut entries = BTreeMap::new();
entries.insert("remote_control".to_string(), true);
let mut features = Features::with_defaults();
features.apply_map(&entries);
assert_eq!(features.enabled(Feature::RemoteControl), false);
}
#[test]