mirror of
https://github.com/openai/codex.git
synced 2026-10-23 18:08:45 +00:00
## What changed - Add optional `websocketRequestId` to `environment/add` and send it as `X-Request-ID` on direct WebSocket upgrades, including reconnects. It requires a secure transport or a loopback destination. - Echo a supplied `X-Request-ID` in the exec-server WebSocket upgrade response. ## Testing Add coverage for `websocketRequestId` serialization and for handshake header forwarding and echoing, both with and without a request ID. GitOrigin-RevId: 235303ff7e1150405b7e1158d6024223144e0cc3
102 lines
3.6 KiB
Rust
102 lines
3.6 KiB
Rust
use super::*;
|
|
use codex_config::ScopedSkillsConfig;
|
|
use codex_exec_server::RemoteEnvironmentOptions;
|
|
use std::time::Duration;
|
|
|
|
#[derive(Clone)]
|
|
pub(crate) struct EnvironmentRequestProcessor {
|
|
environment_manager: Arc<EnvironmentManager>,
|
|
}
|
|
|
|
impl EnvironmentRequestProcessor {
|
|
pub(crate) fn new(environment_manager: Arc<EnvironmentManager>) -> Self {
|
|
Self {
|
|
environment_manager,
|
|
}
|
|
}
|
|
|
|
pub(crate) async fn environment_add(
|
|
&self,
|
|
params: EnvironmentAddParams,
|
|
) -> Result<Option<ClientResponsePayload>, JSONRPCErrorError> {
|
|
let skills = ScopedSkillsConfig {
|
|
required: params
|
|
.skills
|
|
.and_then(|skills| skills.required)
|
|
.unwrap_or_default(),
|
|
};
|
|
let options = RemoteEnvironmentOptions {
|
|
exec_server_url: params.exec_server_url,
|
|
connect_timeout: params.connect_timeout_ms.map(Duration::from_millis),
|
|
http_headers: params
|
|
.auth_bearer_token
|
|
.into_iter()
|
|
.map(|token| {
|
|
(
|
|
"Authorization".to_string(),
|
|
format!("Bearer {}", token.into_inner()),
|
|
)
|
|
})
|
|
.chain(
|
|
params
|
|
.websocket_request_id
|
|
.map(|request_id| ("X-Request-ID".to_string(), request_id)),
|
|
)
|
|
.collect(),
|
|
};
|
|
self.environment_manager
|
|
.upsert_environment_with_options(params.environment_id, options, skills)
|
|
.map_err(|err| invalid_request(err.to_string()))?;
|
|
Ok(Some(EnvironmentAddResponse {}.into()))
|
|
}
|
|
|
|
pub(crate) async fn environment_info(
|
|
&self,
|
|
params: EnvironmentInfoParams,
|
|
) -> Result<Option<ClientResponsePayload>, JSONRPCErrorError> {
|
|
let environment_id = params.environment_id;
|
|
let environment = self
|
|
.environment_manager
|
|
.get_environment(&environment_id)
|
|
.ok_or_else(|| invalid_request(format!("unknown environment id `{environment_id}`")))?;
|
|
let info = environment.force_info().await.map_err(|err| {
|
|
internal_error(format!(
|
|
"failed to get info for environment `{environment_id}`: {err}"
|
|
))
|
|
})?;
|
|
Ok(Some(
|
|
EnvironmentInfoResponse {
|
|
shell: EnvironmentShellInfo {
|
|
name: info.shell.name,
|
|
path: info.shell.path,
|
|
},
|
|
cwd: info.cwd,
|
|
}
|
|
.into(),
|
|
))
|
|
}
|
|
|
|
pub(crate) async fn environment_status(
|
|
&self,
|
|
params: EnvironmentStatusParams,
|
|
) -> Result<Option<ClientResponsePayload>, JSONRPCErrorError> {
|
|
let environment_id = params.environment_id;
|
|
let (status, error) = match self
|
|
.environment_manager
|
|
.get_environment_status(&environment_id)
|
|
.await
|
|
{
|
|
Some(EnvironmentObservedStatus::Ready) => (EnvironmentStatusKind::Ready, None),
|
|
Some(EnvironmentObservedStatus::Pending) => (EnvironmentStatusKind::Pending, None),
|
|
Some(EnvironmentObservedStatus::Disconnected { error }) => {
|
|
(EnvironmentStatusKind::Disconnected, Some(error))
|
|
}
|
|
None => (
|
|
EnvironmentStatusKind::Unknown,
|
|
Some(format!("unknown environment id `{environment_id}`")),
|
|
),
|
|
};
|
|
Ok(Some(EnvironmentStatusResponse { status, error }.into()))
|
|
}
|
|
}
|