Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions codex-rs/Cargo.lock

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

9 changes: 7 additions & 2 deletions codex-rs/app-server-protocol/src/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,13 @@ use ts_rs::TS;
pub(crate) const GENERATED_TS_HEADER: &str = "// GENERATED CODE! DO NOT MODIFY BY HAND!\n\n";
const IGNORED_DEFINITIONS: &[&str] = &["Option<()>"];
const JSON_V1_ALLOWLIST: &[&str] = &["InitializeParams", "InitializeResponse"];
const EXPERIMENTAL_CLIENT_METHOD_DEPENDENCY_TYPES: &[&str] =
&["RemoteControlClient", "RemoteControlClientsListOrder"];
const EXPERIMENTAL_CLIENT_METHOD_DEPENDENCY_TYPES: &[&str] = &[
"CodeBridgeAvailability",
"CodeBridgeServiceStatus",
"CodeBridgeUnavailableReason",
"RemoteControlClient",
"RemoteControlClientsListOrder",
];
const SPECIAL_DEFINITIONS: &[&str] = &[
"ClientNotification",
"ClientRequest",
Expand Down
27 changes: 27 additions & 0 deletions codex-rs/app-server-protocol/src/protocol/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -873,6 +873,12 @@ client_request_definitions! {
serialization: global_shared_read("remote-control"),
response: v2::RemoteControlStatusReadResponse,
},
#[experimental("codeBridge/status/read")]
CodeBridgeStatusRead => "codeBridge/status/read" {
params: #[ts(type = "undefined")] #[serde(skip_serializing_if = "Option::is_none")] Option<()>,
serialization: global_shared_read("code-bridge-status"),
response: v2::CodeBridgeStatusReadResponse,
},
#[experimental("remoteControl/pairing/start")]
RemoteControlPairingStart => "remoteControl/pairing/start" {
params: v2::RemoteControlPairingStartParams,
Expand Down Expand Up @@ -2064,6 +2070,16 @@ mod tests {
"remote-control-pairing"
))
);
let code_bridge_status_read = ClientRequest::CodeBridgeStatusRead {
request_id: request_id(),
params: None,
};
assert_eq!(
code_bridge_status_read.serialization_scope(),
Some(ClientRequestSerializationScope::GlobalSharedRead(
"code-bridge-status"
))
);
let remote_control_clients_list = ClientRequest::RemoteControlClientsList {
request_id: request_id(),
params: v2::RemoteControlClientsListParams::default(),
Expand Down Expand Up @@ -2468,6 +2484,7 @@ mod tests {
cli_version: "0.0.0".to_string(),
source: v2::SessionSource::Exec,
thread_source: None,
session_provenance: None,
agent_nickname: None,
agent_role: None,
git_info: None,
Expand Down Expand Up @@ -3139,6 +3156,16 @@ mod tests {
assert_eq!(reason, Some("mock/experimentalMethod"));
}

#[test]
fn code_bridge_status_read_is_marked_experimental() {
let request = ClientRequest::CodeBridgeStatusRead {
request_id: RequestId::Integer(1),
params: None,
};
let reason = crate::experimental_api::ExperimentalApi::experimental_reason(&request);
assert_eq!(reason, Some("codeBridge/status/read"));
}

#[test]
fn environment_add_is_marked_experimental() {
let request = ClientRequest::EnvironmentAdd {
Expand Down
43 changes: 43 additions & 0 deletions codex-rs/app-server-protocol/src/protocol/v2/code_bridge.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use schemars::JsonSchema;
use serde::Deserialize;
use serde::Serialize;
use ts_rs::TS;

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct CodeBridgeStatusReadResponse {
pub status: CodeBridgeAvailability,
pub service: Option<CodeBridgeServiceStatus>,
pub unavailable_reason: Option<CodeBridgeUnavailableReason>,
}

#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(rename_all = "camelCase", export_to = "v2/")]
pub enum CodeBridgeAvailability {
Available,
Unavailable,
}

#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(rename_all = "camelCase", export_to = "v2/")]
pub enum CodeBridgeUnavailableReason {
DescriptorMissing,
DescriptorInvalid,
UnsupportedEndpoint,
ServiceUnreachable,
StatusInvalid,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct CodeBridgeServiceStatus {
pub protocol_version: String,
pub connected_producer_count: usize,
pub connected_subscriber_count: usize,
pub uptime_ms: u64,
pub last_event_time_unix_ms: Option<u64>,
}
2 changes: 2 additions & 0 deletions codex-rs/app-server-protocol/src/protocol/v2/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ mod shared;
mod account;
mod apps;
mod attestation;
mod code_bridge;
mod collaboration_mode;
mod command_exec;
mod config;
Expand All @@ -29,6 +30,7 @@ mod windows_sandbox;
pub use account::*;
pub use apps::*;
pub use attestation::*;
pub use code_bridge::*;
pub use collaboration_mode::*;
pub use command_exec::*;
pub use config::*;
Expand Down
1 change: 1 addition & 0 deletions codex-rs/app-server-protocol/src/protocol/v2/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ fn thread_resume_response_round_trips_initial_turns_page() {
cli_version: "0.0.0".to_string(),
source: SessionSource::Exec,
thread_source: None,
session_provenance: None,
agent_nickname: None,
agent_role: None,
git_info: None,
Expand Down
3 changes: 3 additions & 0 deletions codex-rs/app-server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ codex-analytics = { workspace = true }
codex-arg0 = { workspace = true }
codex-auto-review = { workspace = true }
codex-cloud-config = { workspace = true }
codex-code-bridge-client = { workspace = true }
codex-code-bridge-protocol = { workspace = true }
codex-config = { workspace = true }
codex-core = { workspace = true }
codex-core-plugins = { workspace = true }
Expand Down Expand Up @@ -109,6 +111,7 @@ axum = { workspace = true, default-features = false, features = [
] }
base64 = { workspace = true }
codex-model-provider-info = { workspace = true }
codex-code-bridge-service = { workspace = true }
codex-utils-cargo-bin = { workspace = true }
core_test_support = { workspace = true }
flate2 = { workspace = true }
Expand Down
1 change: 1 addition & 0 deletions codex-rs/app-server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ Example with notification opt-out:
- `remoteControl/enable` — experimental; enable remote control for the current app-server process and return the current remote-control status snapshot. The caller is responsible for persisting the desired setting outside app-server.
- `remoteControl/disable` — experimental; disable remote control for the current app-server process and return the current remote-control status snapshot. This does not revoke already enrolled controller devices.
- `remoteControl/status/read` — experimental; read the current remote-control status snapshot. `status` is one of `disabled`, `connecting`, `connected`, or `errored`; `serverName` is the local machine name used by this app-server process; `environmentId` is a string when the app-server has a current enrollment and `null` when that enrollment is cleared, invalidated, or remote control is disabled.
- `codeBridge/status/read` — experimental; read whether a local Code Bridge service is discoverable and responsive. This method reads the existing local bridge descriptor and calls the bridge `/status` endpoint only; it does not start Code Bridge, subscribe to events, proxy telemetry, request screenshots, or change `remoteControl/*` behavior. When the service is absent or unreachable, the request succeeds with `status: "unavailable"` and an `unavailableReason`.
- `remoteControl/pairing/start` — experimental; start a short-lived remote-control pairing artifact for the current app-server process. Pass `manualCode: true` to also request a manual pairing code. Returns `pairingCode`, `manualPairingCode`, `environmentId`, and Unix-seconds `expiresAt`; app-server intentionally does not expose the backend `serverId`.
- `remoteControl/pairing/status` — experimental; poll whether a remote-control `pairingCode` or `manualPairingCode` has been claimed. Pass exactly one of the two fields. Returns `claimed`.
- `remoteControl/client/list` — experimental; list controller devices granted access to an environment. Pass `environmentId` and optional `cursor`, `limit`, and `order`; returns picker-oriented client metadata plus `nextCursor`. This signed-in account-management operation works while the local relay is disabled or unenrolled.
Expand Down
9 changes: 9 additions & 0 deletions codex-rs/app-server/src/message_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use crate::outgoing_message::RequestContext;
use crate::request_processors::AccountRequestProcessor;
use crate::request_processors::AppsRequestProcessor;
use crate::request_processors::CatalogRequestProcessor;
use crate::request_processors::CodeBridgeRequestProcessor;
use crate::request_processors::CommandExecRequestProcessor;
use crate::request_processors::ConfigRequestProcessor;
use crate::request_processors::EnvironmentRequestProcessor;
Expand Down Expand Up @@ -166,6 +167,7 @@ pub(crate) struct MessageProcessor {
account_processor: AccountRequestProcessor,
apps_processor: AppsRequestProcessor,
catalog_processor: CatalogRequestProcessor,
code_bridge_processor: CodeBridgeRequestProcessor,
command_exec_processor: CommandExecRequestProcessor,
process_exec_processor: ProcessExecRequestProcessor,
config_processor: ConfigRequestProcessor,
Expand Down Expand Up @@ -414,6 +416,8 @@ impl MessageProcessor {
workspace_settings_cache,
);
let remote_control_processor = RemoteControlRequestProcessor::new(remote_control_handle);
let code_bridge_processor =
CodeBridgeRequestProcessor::new(config.codex_home.to_path_buf());
let search_processor = SearchRequestProcessor::new(outgoing.clone());
let thread_goal_processor = ThreadGoalRequestProcessor::new(
Arc::clone(&thread_manager),
Expand Down Expand Up @@ -497,6 +501,7 @@ impl MessageProcessor {
account_processor,
apps_processor,
catalog_processor,
code_bridge_processor,
command_exec_processor,
process_exec_processor,
config_processor,
Expand Down Expand Up @@ -922,6 +927,10 @@ impl MessageProcessor {
.remote_control_processor
.status_read()
.map(|response| Some(response.into())),
ClientRequest::CodeBridgeStatusRead { .. } => {
let response = self.code_bridge_processor.status_read().await;
Ok(Some(response.into()))
}
ClientRequest::RemoteControlPairingStart { params, .. } => self
.remote_control_processor
.pairing_start(params, app_server_client_name.as_deref())
Expand Down
2 changes: 2 additions & 0 deletions codex-rs/app-server/src/request_processors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,7 @@ use codex_app_server_protocol::ServerRequest;
mod account_processor;
mod apps_processor;
mod catalog_processor;
mod code_bridge_processor;
mod command_exec_processor;
mod config_processor;
mod environment_processor;
Expand All @@ -501,6 +502,7 @@ mod windows_sandbox_processor;
pub(crate) use account_processor::AccountRequestProcessor;
pub(crate) use apps_processor::AppsRequestProcessor;
pub(crate) use catalog_processor::CatalogRequestProcessor;
pub(crate) use code_bridge_processor::CodeBridgeRequestProcessor;
pub(crate) use command_exec_processor::CommandExecRequestProcessor;
pub(crate) use config_processor::ConfigRequestProcessor;
pub(crate) use environment_processor::EnvironmentRequestProcessor;
Expand Down
Loading
Loading