mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
[2/4] Implement executor HTTP request runner (#18582)
### Why Remote streamable HTTP MCP needs the executor to perform ordinary HTTP requests on the executor side. This keeps network placement aligned with `experimental_environment = "remote"` without adding MCP-specific executor APIs. ### What - Add an executor-side `http/request` runner backed by `reqwest`. - Validate request method and URL scheme, preserving the transport boundary at plain HTTP. - Return buffered responses for ordinary calls and emit ordered `http/request/bodyDelta` notifications for streaming responses. - Register the request handler in the exec-server router. - Document the runner entrypoint, conversion helpers, body-stream bridge, notification sender, timeout behavior, and new integration-test helpers. - Add exec-server integration tests with the existing websocket harness and a local TCP HTTP peer for buffered and streamed responses, with comments spelling out what each test proves and its setup/exercise/assert phases. ### Stack 1. #18581 protocol 2. #18582 runner 3. #18583 RMCP client 4. #18584 manager wiring and local/remote coverage ### Verification - `just fmt` - `cargo check -p codex-exec-server -p codex-rmcp-client --tests` - `cargo check -p codex-core --test all` compile-only - `git diff --check` - Online full CI is running from the `full-ci` branch, including the remote Rust test job. Co-authored-by: Codex <noreply@openai.com> --------- Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
@@ -36,8 +36,9 @@ pub(crate) enum RpcCallError {
|
||||
|
||||
type PendingRequest = oneshot::Sender<Result<Value, RpcCallError>>;
|
||||
type BoxFuture<T> = Pin<Box<dyn Future<Output = T> + Send + 'static>>;
|
||||
type RequestRoute<S> =
|
||||
Box<dyn Fn(Arc<S>, JSONRPCRequest) -> BoxFuture<RpcServerOutboundMessage> + Send + Sync>;
|
||||
type RequestRoute<S> = Box<
|
||||
dyn Fn(Arc<S>, JSONRPCRequest) -> BoxFuture<Option<RpcServerOutboundMessage>> + Send + Sync,
|
||||
>;
|
||||
type NotificationRoute<S> =
|
||||
Box<dyn Fn(Arc<S>, JSONRPCNotification) -> BoxFuture<Result<(), String>> + Send + Sync>;
|
||||
|
||||
@@ -72,6 +73,17 @@ impl RpcNotificationSender {
|
||||
Self { outgoing_tx }
|
||||
}
|
||||
|
||||
pub(crate) async fn response(
|
||||
&self,
|
||||
request_id: RequestId,
|
||||
result: Value,
|
||||
) -> Result<(), JSONRPCErrorError> {
|
||||
self.outgoing_tx
|
||||
.send(RpcServerOutboundMessage::Response { request_id, result })
|
||||
.await
|
||||
.map_err(|_| internal_error("RPC connection closed while sending response".into()))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) async fn notify<P: Serialize>(
|
||||
&self,
|
||||
@@ -131,10 +143,10 @@ where
|
||||
let response = match response {
|
||||
Ok(response) => response.await,
|
||||
Err(error) => {
|
||||
return RpcServerOutboundMessage::Error { request_id, error };
|
||||
return Some(RpcServerOutboundMessage::Error { request_id, error });
|
||||
}
|
||||
};
|
||||
match response {
|
||||
Some(match response {
|
||||
Ok(result) => match serde_json::to_value(result) {
|
||||
Ok(result) => RpcServerOutboundMessage::Response { request_id, result },
|
||||
Err(err) => RpcServerOutboundMessage::Error {
|
||||
@@ -143,6 +155,34 @@ where
|
||||
},
|
||||
},
|
||||
Err(error) => RpcServerOutboundMessage::Error { request_id, error },
|
||||
})
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) fn request_with_id<P, F, Fut>(&mut self, method: &'static str, handler: F)
|
||||
where
|
||||
P: DeserializeOwned + Send + 'static,
|
||||
F: Fn(Arc<S>, RequestId, P) -> Fut + Send + Sync + 'static,
|
||||
Fut: Future<Output = Result<(), JSONRPCErrorError>> + Send + 'static,
|
||||
{
|
||||
self.request_routes.insert(
|
||||
method,
|
||||
Box::new(move |state, request| {
|
||||
let request_id = request.id;
|
||||
let params = decode_request_params::<P>(request.params)
|
||||
.map(|params| handler(state, request_id.clone(), params));
|
||||
Box::pin(async move {
|
||||
let response = match params {
|
||||
Ok(response) => response.await,
|
||||
Err(error) => {
|
||||
return Some(RpcServerOutboundMessage::Error { request_id, error });
|
||||
}
|
||||
};
|
||||
match response {
|
||||
Ok(()) => None,
|
||||
Err(error) => Some(RpcServerOutboundMessage::Error { request_id, error }),
|
||||
}
|
||||
})
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user