feat(app-server) install runtime

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
Dylan Hurd
2026-05-22 07:28:37 -04:00
committed by acrognale-oai
co-authored by Codex
parent 932f72c225
commit bd820e2cd2
26 changed files with 2101 additions and 9 deletions
+2
View File
@@ -2770,6 +2770,7 @@ dependencies = [
"serde",
"serde_json",
"serial_test",
"sha2",
"tempfile",
"test-case",
"thiserror 2.0.18",
@@ -2780,6 +2781,7 @@ dependencies = [
"tracing",
"uuid",
"wiremock",
"zip 2.4.2",
]
[[package]]
@@ -2765,6 +2765,82 @@
}
]
},
"RuntimeInstallManifest": {
"properties": {
"archiveName": {
"type": [
"string",
"null"
]
},
"archiveSha256": {
"type": "string"
},
"archiveSizeBytes": {
"format": "uint64",
"minimum": 0.0,
"type": [
"integer",
"null"
]
},
"archiveUrl": {
"type": "string"
},
"bundleFormatVersion": {
"format": "uint32",
"minimum": 0.0,
"type": [
"integer",
"null"
]
},
"bundleVersion": {
"type": [
"string",
"null"
]
},
"format": {
"type": [
"string",
"null"
]
},
"runtimeRootDirectoryName": {
"type": [
"string",
"null"
]
}
},
"required": [
"archiveSha256",
"archiveUrl"
],
"type": "object"
},
"RuntimeInstallParams": {
"properties": {
"environmentId": {
"type": [
"string",
"null"
]
},
"manifest": {
"$ref": "#/definitions/RuntimeInstallManifest"
},
"release": {
"type": "string"
}
},
"required": [
"manifest",
"release"
],
"type": "object"
},
"SandboxMode": {
"enum": [
"read-only",
@@ -5309,6 +5385,30 @@
"title": "Plugin/installRequest",
"type": "object"
},
{
"properties": {
"id": {
"$ref": "#/definitions/RequestId"
},
"method": {
"enum": [
"runtime/install"
],
"title": "Runtime/installRequestMethod",
"type": "string"
},
"params": {
"$ref": "#/definitions/RuntimeInstallParams"
}
},
"required": [
"id",
"method",
"params"
],
"title": "Runtime/installRequest",
"type": "object"
},
{
"properties": {
"id": {
@@ -1309,6 +1309,30 @@
"title": "Plugin/installRequest",
"type": "object"
},
{
"properties": {
"id": {
"$ref": "#/definitions/v2/RequestId"
},
"method": {
"enum": [
"runtime/install"
],
"title": "Runtime/installRequestMethod",
"type": "string"
},
"params": {
"$ref": "#/definitions/v2/RuntimeInstallParams"
}
},
"required": [
"id",
"method",
"params"
],
"title": "Runtime/installRequest",
"type": "object"
},
{
"properties": {
"id": {
@@ -14613,6 +14637,154 @@
}
]
},
"RuntimeInstallManifest": {
"properties": {
"archiveName": {
"type": [
"string",
"null"
]
},
"archiveSha256": {
"type": "string"
},
"archiveSizeBytes": {
"format": "uint64",
"minimum": 0.0,
"type": [
"integer",
"null"
]
},
"archiveUrl": {
"type": "string"
},
"bundleFormatVersion": {
"format": "uint32",
"minimum": 0.0,
"type": [
"integer",
"null"
]
},
"bundleVersion": {
"type": [
"string",
"null"
]
},
"format": {
"type": [
"string",
"null"
]
},
"runtimeRootDirectoryName": {
"type": [
"string",
"null"
]
}
},
"required": [
"archiveSha256",
"archiveUrl"
],
"type": "object"
},
"RuntimeInstallParams": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"environmentId": {
"type": [
"string",
"null"
]
},
"manifest": {
"$ref": "#/definitions/v2/RuntimeInstallManifest"
},
"release": {
"type": "string"
}
},
"required": [
"manifest",
"release"
],
"title": "RuntimeInstallParams",
"type": "object"
},
"RuntimeInstallPaths": {
"properties": {
"bundledPluginMarketplacePaths": {
"items": {
"$ref": "#/definitions/v2/AbsolutePathBuf"
},
"type": "array"
},
"bundledSkillPaths": {
"items": {
"$ref": "#/definitions/v2/AbsolutePathBuf"
},
"type": "array"
},
"nodeModulesPath": {
"$ref": "#/definitions/v2/AbsolutePathBuf"
},
"nodePath": {
"$ref": "#/definitions/v2/AbsolutePathBuf"
},
"pythonPath": {
"$ref": "#/definitions/v2/AbsolutePathBuf"
},
"skillsToRemove": {
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"bundledPluginMarketplacePaths",
"bundledSkillPaths",
"nodeModulesPath",
"nodePath",
"pythonPath",
"skillsToRemove"
],
"type": "object"
},
"RuntimeInstallResponse": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"bundleVersion": {
"type": [
"string",
"null"
]
},
"paths": {
"$ref": "#/definitions/v2/RuntimeInstallPaths"
},
"status": {
"$ref": "#/definitions/v2/RuntimeInstallStatus"
}
},
"required": [
"paths",
"status"
],
"title": "RuntimeInstallResponse",
"type": "object"
},
"RuntimeInstallStatus": {
"enum": [
"already-current",
"installed"
],
"type": "string"
},
"SandboxMode": {
"enum": [
"read-only",
@@ -2035,6 +2035,30 @@
"title": "Plugin/installRequest",
"type": "object"
},
{
"properties": {
"id": {
"$ref": "#/definitions/RequestId"
},
"method": {
"enum": [
"runtime/install"
],
"title": "Runtime/installRequestMethod",
"type": "string"
},
"params": {
"$ref": "#/definitions/RuntimeInstallParams"
}
},
"required": [
"id",
"method",
"params"
],
"title": "Runtime/installRequest",
"type": "object"
},
{
"properties": {
"id": {
@@ -11142,6 +11166,154 @@
}
]
},
"RuntimeInstallManifest": {
"properties": {
"archiveName": {
"type": [
"string",
"null"
]
},
"archiveSha256": {
"type": "string"
},
"archiveSizeBytes": {
"format": "uint64",
"minimum": 0.0,
"type": [
"integer",
"null"
]
},
"archiveUrl": {
"type": "string"
},
"bundleFormatVersion": {
"format": "uint32",
"minimum": 0.0,
"type": [
"integer",
"null"
]
},
"bundleVersion": {
"type": [
"string",
"null"
]
},
"format": {
"type": [
"string",
"null"
]
},
"runtimeRootDirectoryName": {
"type": [
"string",
"null"
]
}
},
"required": [
"archiveSha256",
"archiveUrl"
],
"type": "object"
},
"RuntimeInstallParams": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"environmentId": {
"type": [
"string",
"null"
]
},
"manifest": {
"$ref": "#/definitions/RuntimeInstallManifest"
},
"release": {
"type": "string"
}
},
"required": [
"manifest",
"release"
],
"title": "RuntimeInstallParams",
"type": "object"
},
"RuntimeInstallPaths": {
"properties": {
"bundledPluginMarketplacePaths": {
"items": {
"$ref": "#/definitions/AbsolutePathBuf"
},
"type": "array"
},
"bundledSkillPaths": {
"items": {
"$ref": "#/definitions/AbsolutePathBuf"
},
"type": "array"
},
"nodeModulesPath": {
"$ref": "#/definitions/AbsolutePathBuf"
},
"nodePath": {
"$ref": "#/definitions/AbsolutePathBuf"
},
"pythonPath": {
"$ref": "#/definitions/AbsolutePathBuf"
},
"skillsToRemove": {
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"bundledPluginMarketplacePaths",
"bundledSkillPaths",
"nodeModulesPath",
"nodePath",
"pythonPath",
"skillsToRemove"
],
"type": "object"
},
"RuntimeInstallResponse": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"bundleVersion": {
"type": [
"string",
"null"
]
},
"paths": {
"$ref": "#/definitions/RuntimeInstallPaths"
},
"status": {
"$ref": "#/definitions/RuntimeInstallStatus"
}
},
"required": [
"paths",
"status"
],
"title": "RuntimeInstallResponse",
"type": "object"
},
"RuntimeInstallStatus": {
"enum": [
"already-current",
"installed"
],
"type": "string"
},
"SandboxMode": {
"enum": [
"read-only",
@@ -0,0 +1,80 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"RuntimeInstallManifest": {
"properties": {
"archiveName": {
"type": [
"string",
"null"
]
},
"archiveSha256": {
"type": "string"
},
"archiveSizeBytes": {
"format": "uint64",
"minimum": 0.0,
"type": [
"integer",
"null"
]
},
"archiveUrl": {
"type": "string"
},
"bundleFormatVersion": {
"format": "uint32",
"minimum": 0.0,
"type": [
"integer",
"null"
]
},
"bundleVersion": {
"type": [
"string",
"null"
]
},
"format": {
"type": [
"string",
"null"
]
},
"runtimeRootDirectoryName": {
"type": [
"string",
"null"
]
}
},
"required": [
"archiveSha256",
"archiveUrl"
],
"type": "object"
}
},
"properties": {
"environmentId": {
"type": [
"string",
"null"
]
},
"manifest": {
"$ref": "#/definitions/RuntimeInstallManifest"
},
"release": {
"type": "string"
}
},
"required": [
"manifest",
"release"
],
"title": "RuntimeInstallParams",
"type": "object"
}
@@ -0,0 +1,76 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"AbsolutePathBuf": {
"description": "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.",
"type": "string"
},
"RuntimeInstallPaths": {
"properties": {
"bundledPluginMarketplacePaths": {
"items": {
"$ref": "#/definitions/AbsolutePathBuf"
},
"type": "array"
},
"bundledSkillPaths": {
"items": {
"$ref": "#/definitions/AbsolutePathBuf"
},
"type": "array"
},
"nodeModulesPath": {
"$ref": "#/definitions/AbsolutePathBuf"
},
"nodePath": {
"$ref": "#/definitions/AbsolutePathBuf"
},
"pythonPath": {
"$ref": "#/definitions/AbsolutePathBuf"
},
"skillsToRemove": {
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"bundledPluginMarketplacePaths",
"bundledSkillPaths",
"nodeModulesPath",
"nodePath",
"pythonPath",
"skillsToRemove"
],
"type": "object"
},
"RuntimeInstallStatus": {
"enum": [
"already-current",
"installed"
],
"type": "string"
}
},
"properties": {
"bundleVersion": {
"type": [
"string",
"null"
]
},
"paths": {
"$ref": "#/definitions/RuntimeInstallPaths"
},
"status": {
"$ref": "#/definitions/RuntimeInstallStatus"
}
},
"required": [
"paths",
"status"
],
"title": "RuntimeInstallResponse",
"type": "object"
}
File diff suppressed because one or more lines are too long
@@ -0,0 +1,5 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type RuntimeInstallManifest = { archiveName: string | null, archiveSha256: string, archiveSizeBytes: bigint | null, archiveUrl: string, bundleFormatVersion: number | null, bundleVersion: string | null, format: string | null, runtimeRootDirectoryName: string | null, };
@@ -0,0 +1,6 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { RuntimeInstallManifest } from "./RuntimeInstallManifest";
export type RuntimeInstallParams = { environmentId?: string | null, manifest: RuntimeInstallManifest, release: string, };
@@ -0,0 +1,6 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { AbsolutePathBuf } from "../AbsolutePathBuf";
export type RuntimeInstallPaths = { bundledPluginMarketplacePaths: Array<AbsolutePathBuf>, bundledSkillPaths: Array<AbsolutePathBuf>, nodeModulesPath: AbsolutePathBuf, nodePath: AbsolutePathBuf, pythonPath: AbsolutePathBuf, skillsToRemove: Array<string>, };
@@ -0,0 +1,7 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { RuntimeInstallPaths } from "./RuntimeInstallPaths";
import type { RuntimeInstallStatus } from "./RuntimeInstallStatus";
export type RuntimeInstallResponse = { bundleVersion: string | null, paths: RuntimeInstallPaths, status: RuntimeInstallStatus, };
@@ -0,0 +1,5 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type RuntimeInstallStatus = "already-current" | "installed";
@@ -325,6 +325,11 @@ export type { ReviewDelivery } from "./ReviewDelivery";
export type { ReviewStartParams } from "./ReviewStartParams";
export type { ReviewStartResponse } from "./ReviewStartResponse";
export type { ReviewTarget } from "./ReviewTarget";
export type { RuntimeInstallManifest } from "./RuntimeInstallManifest";
export type { RuntimeInstallParams } from "./RuntimeInstallParams";
export type { RuntimeInstallPaths } from "./RuntimeInstallPaths";
export type { RuntimeInstallResponse } from "./RuntimeInstallResponse";
export type { RuntimeInstallStatus } from "./RuntimeInstallStatus";
export type { SandboxMode } from "./SandboxMode";
export type { SandboxPolicy } from "./SandboxPolicy";
export type { SandboxWorkspaceWrite } from "./SandboxWorkspaceWrite";
@@ -737,6 +737,11 @@ client_request_definitions! {
serialization: global("config"),
response: v2::PluginInstallResponse,
},
RuntimeInstall => "runtime/install" {
params: v2::RuntimeInstallParams,
serialization: global("runtime-install"),
response: v2::RuntimeInstallResponse,
},
PluginUninstall => "plugin/uninstall" {
params: v2::PluginUninstallParams,
serialization: global("config"),
@@ -21,6 +21,7 @@ mod process;
mod realtime;
mod remote_control;
mod review;
mod runtime;
mod thread;
mod thread_data;
mod turn;
@@ -47,6 +48,7 @@ pub use process::*;
pub use realtime::*;
pub use remote_control::*;
pub use review::*;
pub use runtime::*;
pub use shared::*;
pub use thread::*;
pub use thread_data::*;
@@ -0,0 +1,58 @@
use codex_utils_absolute_path::AbsolutePathBuf;
use schemars::JsonSchema;
use serde::Deserialize;
use serde::Serialize;
use ts_rs::TS;
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct RuntimeInstallManifest {
pub archive_name: Option<String>,
pub archive_sha256: String,
pub archive_size_bytes: Option<u64>,
pub archive_url: String,
pub bundle_format_version: Option<u32>,
pub bundle_version: Option<String>,
pub format: Option<String>,
pub runtime_root_directory_name: Option<String>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct RuntimeInstallParams {
#[ts(optional = nullable)]
pub environment_id: Option<String>,
pub manifest: Box<RuntimeInstallManifest>,
pub release: String,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "kebab-case")]
#[ts(export_to = "v2/")]
pub enum RuntimeInstallStatus {
AlreadyCurrent,
Installed,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct RuntimeInstallPaths {
pub bundled_plugin_marketplace_paths: Vec<AbsolutePathBuf>,
pub bundled_skill_paths: Vec<AbsolutePathBuf>,
pub node_modules_path: AbsolutePathBuf,
pub node_path: AbsolutePathBuf,
pub python_path: AbsolutePathBuf,
pub skills_to_remove: Vec<String>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct RuntimeInstallResponse {
pub bundle_version: Option<String>,
pub paths: RuntimeInstallPaths,
pub status: RuntimeInstallStatus,
}
@@ -167,6 +167,7 @@ pub(crate) struct MessageProcessor {
command_exec_processor: CommandExecRequestProcessor,
process_exec_processor: ProcessExecRequestProcessor,
config_processor: ConfigRequestProcessor,
environment_manager: Arc<EnvironmentManager>,
environment_processor: EnvironmentRequestProcessor,
external_agent_config_processor: ExternalAgentConfigRequestProcessor,
feedback_processor: FeedbackRequestProcessor,
@@ -488,6 +489,7 @@ impl MessageProcessor {
command_exec_processor,
process_exec_processor,
config_processor,
environment_manager: thread_manager.environment_manager(),
environment_processor,
external_agent_config_processor,
feedback_processor,
@@ -968,6 +970,26 @@ impl MessageProcessor {
.model_provider_capabilities_read()
.await
.map(|response| Some(response.into())),
ClientRequest::RuntimeInstall { params, .. } => {
let mut params = params;
let environment = if let Some(environment_id) = params.environment_id.take() {
self.environment_manager
.get_environment(&environment_id)
.ok_or_else(|| {
invalid_request(format!(
"unknown runtime install environment id `{environment_id}`"
))
})?
} else {
self.environment_manager
.default_environment()
.unwrap_or_else(|| self.environment_manager.local_environment())
};
environment
.install_runtime(params)
.await
.map(|response| Some(response.into()))
}
ClientRequest::ThreadStart { params, .. } => {
self.thread_processor
.thread_start(
+3 -1
View File
@@ -30,6 +30,8 @@ reqwest = { workspace = true, features = ["json", "rustls-tls", "stream"] }
prost = "0.14.3"
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
sha2 = { workspace = true }
tempfile = { workspace = true }
thiserror = { workspace = true }
toml = { workspace = true }
tokio = { workspace = true, features = [
@@ -47,6 +49,7 @@ tokio-util = { workspace = true, features = ["rt"] }
tokio-tungstenite = { workspace = true }
tracing = { workspace = true }
uuid = { workspace = true, features = ["v4"] }
zip = { workspace = true }
[dev-dependencies]
anyhow = { workspace = true }
@@ -55,6 +58,5 @@ ctor = { workspace = true }
http = { workspace = true }
pretty_assertions = { workspace = true }
serial_test = { workspace = true }
tempfile = { workspace = true }
test-case = "3.3.1"
wiremock = { workspace = true }
+10
View File
@@ -8,6 +8,8 @@ use std::time::Duration;
use arc_swap::ArcSwap;
use codex_app_server_protocol::JSONRPCNotification;
use codex_app_server_protocol::RuntimeInstallParams;
use codex_app_server_protocol::RuntimeInstallResponse;
use futures::FutureExt;
use futures::future::BoxFuture;
use serde_json::Value;
@@ -69,6 +71,7 @@ use crate::protocol::INITIALIZED_METHOD;
use crate::protocol::InitializeParams;
use crate::protocol::InitializeResponse;
use crate::protocol::ProcessOutputChunk;
use crate::protocol::RUNTIME_INSTALL_METHOD;
use crate::protocol::ReadParams;
use crate::protocol::ReadResponse;
use crate::protocol::TerminateParams;
@@ -432,6 +435,13 @@ impl ExecServerClient {
self.call(FS_COPY_METHOD, &params).await
}
pub async fn runtime_install(
&self,
params: RuntimeInstallParams,
) -> Result<RuntimeInstallResponse, ExecServerError> {
self.call(RUNTIME_INSTALL_METHOD, &params).await
}
pub(crate) async fn register_session(
&self,
process_id: &ProcessId,
+53 -1
View File
@@ -2,6 +2,10 @@ use std::collections::HashMap;
use std::sync::Arc;
use std::sync::RwLock;
use codex_app_server_protocol::JSONRPCErrorError;
use codex_app_server_protocol::RuntimeInstallParams;
use codex_app_server_protocol::RuntimeInstallResponse;
use crate::ExecServerError;
use crate::ExecServerRuntimePaths;
use crate::ExecutorFileSystem;
@@ -20,6 +24,7 @@ use crate::local_process::LocalProcess;
use crate::process::ExecBackend;
use crate::remote_file_system::RemoteFileSystem;
use crate::remote_process::RemoteProcess;
use crate::rpc::internal_error;
pub const CODEX_EXEC_SERVER_URL_ENV_VAR: &str = "CODEX_EXEC_SERVER_URL";
@@ -289,9 +294,45 @@ pub struct Environment {
exec_backend: Arc<dyn ExecBackend>,
filesystem: Arc<dyn ExecutorFileSystem>,
http_client: Arc<dyn HttpClient>,
runtime_installer: RuntimeInstaller,
local_runtime_paths: Option<ExecServerRuntimePaths>,
}
#[derive(Clone)]
enum RuntimeInstaller {
Local,
Remote(LazyRemoteExecServerClient),
}
impl RuntimeInstaller {
async fn install_runtime(
&self,
params: RuntimeInstallParams,
) -> Result<RuntimeInstallResponse, JSONRPCErrorError> {
match self {
RuntimeInstaller::Local => crate::runtime_install::install_runtime(params).await,
RuntimeInstaller::Remote(client) => {
let client = client.get().await.map_err(exec_server_error_to_jsonrpc)?;
client
.runtime_install(params)
.await
.map_err(exec_server_error_to_jsonrpc)
}
}
}
}
fn exec_server_error_to_jsonrpc(err: ExecServerError) -> JSONRPCErrorError {
match err {
ExecServerError::Server { code, message } => JSONRPCErrorError {
code,
data: None,
message,
},
_ => internal_error(err.to_string()),
}
}
impl Environment {
/// Builds a test-only local environment without configured sandbox helper paths.
pub fn default_for_tests() -> Self {
@@ -301,6 +342,7 @@ impl Environment {
exec_backend: Arc::new(LocalProcess::default()),
filesystem: Arc::new(LocalFileSystem::unsandboxed()),
http_client: Arc::new(ReqwestHttpClient),
runtime_installer: RuntimeInstaller::Local,
local_runtime_paths: None,
}
}
@@ -359,6 +401,7 @@ impl Environment {
local_runtime_paths.clone(),
)),
http_client: Arc::new(ReqwestHttpClient),
runtime_installer: RuntimeInstaller::Local,
local_runtime_paths: Some(local_runtime_paths),
}
}
@@ -388,13 +431,15 @@ impl Environment {
let exec_backend: Arc<dyn ExecBackend> = Arc::new(RemoteProcess::new(client.clone()));
let filesystem: Arc<dyn ExecutorFileSystem> =
Arc::new(RemoteFileSystem::new(client.clone()));
let http_client = client.clone();
Self {
exec_server_url,
remote_transport: Some(remote_transport),
exec_backend,
filesystem,
http_client: Arc::new(client),
http_client: Arc::new(http_client),
runtime_installer: RuntimeInstaller::Remote(client),
local_runtime_paths,
}
}
@@ -423,6 +468,13 @@ impl Environment {
pub fn get_filesystem(&self) -> Arc<dyn ExecutorFileSystem> {
Arc::clone(&self.filesystem)
}
pub async fn install_runtime(
&self,
params: RuntimeInstallParams,
) -> Result<RuntimeInstallResponse, JSONRPCErrorError> {
self.runtime_installer.install_runtime(params).await
}
}
#[cfg(test)]
+2
View File
@@ -19,6 +19,7 @@ mod remote;
mod remote_file_system;
mod remote_process;
mod rpc;
mod runtime_install;
mod runtime_paths;
mod sandboxed_file_system;
mod server;
@@ -84,6 +85,7 @@ pub use protocol::HttpRequestResponse;
pub use protocol::InitializeParams;
pub use protocol::InitializeResponse;
pub use protocol::ProcessOutputChunk;
pub use protocol::RUNTIME_INSTALL_METHOD;
pub use protocol::ReadParams;
pub use protocol::ReadResponse;
pub use protocol::TerminateParams;
+1
View File
@@ -30,6 +30,7 @@ pub const FS_COPY_METHOD: &str = "fs/copy";
pub const HTTP_REQUEST_METHOD: &str = "http/request";
/// JSON-RPC notification method for streamed executor HTTP response bodies.
pub const HTTP_REQUEST_BODY_DELTA_METHOD: &str = "http/request/bodyDelta";
pub const RUNTIME_INSTALL_METHOD: &str = "runtime/install";
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(transparent)]
+6 -6
View File
@@ -80,7 +80,7 @@ impl RpcNotificationSender {
self.outgoing_tx
.send(RpcServerOutboundMessage::Response { request_id, result })
.await
.map_err(|_| internal_error("RPC connection closed while sending response".into()))
.map_err(|_| internal_error("RPC connection closed while sending response"))
}
pub(crate) async fn notify<P: Serialize>(
@@ -97,7 +97,7 @@ impl RpcNotificationSender {
},
))
.await
.map_err(|_| internal_error("RPC connection closed while sending notification".into()))
.map_err(|_| internal_error("RPC connection closed while sending notification"))
}
}
@@ -425,11 +425,11 @@ pub(crate) fn method_not_found(message: String) -> JSONRPCErrorError {
}
}
pub(crate) fn invalid_params(message: String) -> JSONRPCErrorError {
pub(crate) fn invalid_params(message: impl Into<String>) -> JSONRPCErrorError {
JSONRPCErrorError {
code: -32602,
data: None,
message,
message: message.into(),
}
}
@@ -441,11 +441,11 @@ pub(crate) fn not_found(message: String) -> JSONRPCErrorError {
}
}
pub(crate) fn internal_error(message: String) -> JSONRPCErrorError {
pub(crate) fn internal_error(message: impl Into<String>) -> JSONRPCErrorError {
JSONRPCErrorError {
code: -32603,
data: None,
message,
message: message.into(),
}
}
File diff suppressed because it is too large Load Diff
@@ -5,6 +5,8 @@ use std::sync::atomic::Ordering;
use codex_app_server_protocol::JSONRPCErrorError;
use codex_app_server_protocol::RequestId;
use codex_app_server_protocol::RuntimeInstallParams;
use codex_app_server_protocol::RuntimeInstallResponse;
use serde_json::to_value;
use std::collections::HashSet;
use tokio::sync::Mutex;
@@ -264,6 +266,14 @@ impl ExecServerHandler {
self.file_system.copy(params).await
}
pub(crate) async fn runtime_install(
&self,
params: RuntimeInstallParams,
) -> Result<RuntimeInstallResponse, JSONRPCErrorError> {
self.require_initialized_for("runtime")?;
crate::runtime_install::install_runtime(params).await
}
fn require_initialized_for(
&self,
method_family: &str,
@@ -24,11 +24,13 @@ use crate::protocol::HttpRequestParams;
use crate::protocol::INITIALIZE_METHOD;
use crate::protocol::INITIALIZED_METHOD;
use crate::protocol::InitializeParams;
use crate::protocol::RUNTIME_INSTALL_METHOD;
use crate::protocol::ReadParams;
use crate::protocol::TerminateParams;
use crate::protocol::WriteParams;
use crate::rpc::RpcRouter;
use crate::server::ExecServerHandler;
use codex_app_server_protocol::RuntimeInstallParams;
pub(crate) fn build_router() -> RpcRouter<ExecServerHandler> {
let mut router = RpcRouter::new();
@@ -114,5 +116,11 @@ pub(crate) fn build_router() -> RpcRouter<ExecServerHandler> {
handler.fs_copy(params).await
},
);
router.request(
RUNTIME_INSTALL_METHOD,
|handler: Arc<ExecServerHandler>, params: RuntimeInstallParams| async move {
handler.runtime_install(params).await
},
);
router
}