diff --git a/MODULE.bazel b/MODULE.bazel index f55bd1f26d..c4bcd33e22 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -88,6 +88,14 @@ crate.annotation( ], ) +crate.annotation( + crate = "v8", + patch_args = ["-p1"], + patches = [ + "//patches:v8_relative_prebuilt_binding_path.patch", + ], +) + inject_repo(crate, "zstd") bazel_dep(name = "bzip2", version = "1.0.8.bcr.3") diff --git a/codex-rs/Cargo.toml b/codex-rs/Cargo.toml index a140dd028d..f816275613 100644 --- a/codex-rs/Cargo.toml +++ b/codex-rs/Cargo.toml @@ -236,7 +236,7 @@ regex-lite = "0.1.8" reqwest = "0.12" rmcp = { version = "0.15.0", default-features = false } runfiles = { git = "https://github.com/dzbarsky/rules_rust", rev = "b56cbaa8465e74127f1ea216f813cd377295ad81" } -rusty_v8 = { package = "v8", version = "146.4.0" } +v8 = "146.4.0" rustls = { version = "0.23", default-features = false, features = [ "ring", "std", diff --git a/codex-rs/code-mode/BUILD.bazel b/codex-rs/code-mode/BUILD.bazel index bf39d9d5a5..0119c6e7cd 100644 --- a/codex-rs/code-mode/BUILD.bazel +++ b/codex-rs/code-mode/BUILD.bazel @@ -3,4 +3,5 @@ load("//:defs.bzl", "codex_rust_crate") codex_rust_crate( name = "code-mode", crate_name = "codex_code_mode", + compile_data = ["src/code_mode_bridge.js"], ) diff --git a/codex-rs/code-mode/Cargo.toml b/codex-rs/code-mode/Cargo.toml index 014c20c0a9..d98fb6f8c9 100644 --- a/codex-rs/code-mode/Cargo.toml +++ b/codex-rs/code-mode/Cargo.toml @@ -16,4 +16,4 @@ serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } [target.'cfg(not(all(target_os = "linux", target_env = "musl")))'.dependencies] -rusty_v8 = { workspace = true } +v8 = { workspace = true } diff --git a/codex-rs/code-mode/src/imp.rs b/codex-rs/code-mode/src/imp.rs index 74dae12134..581dfac738 100644 --- a/codex-rs/code-mode/src/imp.rs +++ b/codex-rs/code-mode/src/imp.rs @@ -3,7 +3,6 @@ use std::sync::Once; use crate::EnabledTool; use crate::ToolCallHandler; -use rusty_v8 as v8; use serde_json::Value as JsonValue; const CODE_MODE_BOOTSTRAP_SOURCE: &str = include_str!("code_mode_bridge.js"); @@ -101,7 +100,11 @@ fn install_tool_call_binding(scope: &mut v8::PinScope<'_, '_>) -> Result<(), Str } } -fn run_script(scope: &mut v8::PinScope<'_, '_>, filename: &str, source: &str) -> Result<(), String> { +fn run_script( + scope: &mut v8::PinScope<'_, '_>, + filename: &str, + source: &str, +) -> Result<(), String> { let scope = pin!(v8::TryCatch::new(scope)); let scope = &mut scope.init(); let source = v8_string(scope, source)?; @@ -386,7 +389,10 @@ fn wait_for_module_promise( } fn read_content_items(scope: &mut v8::PinScope<'_, '_>) -> Result, String> { - let source = v8_string(scope, "JSON.stringify(globalThis.__codexContentItems ?? [])")?; + let source = v8_string( + scope, + "JSON.stringify(globalThis.__codexContentItems ?? [])", + )?; let script = v8::Script::compile(scope, source, None) .ok_or_else(|| "failed to read code_mode content items".to_string())?; let value = script @@ -396,7 +402,8 @@ fn read_content_items(scope: &mut v8::PinScope<'_, '_>) -> Result .to_string(scope) .ok_or_else(|| "failed to serialize code_mode content items".to_string())? .to_rust_string_lossy(scope); - serde_json::from_str(&serialized).map_err(|err| format!("invalid code_mode content items: {err}")) + serde_json::from_str(&serialized) + .map_err(|err| format!("invalid code_mode content items: {err}")) } fn build_bootstrap_source(enabled_tools: &[EnabledTool]) -> Result { @@ -453,9 +460,7 @@ fn throw_v8_exception<'s, T>( None } -fn format_v8_exception( - try_catch: &mut v8::PinnedRef<'_, v8::TryCatch>, -) -> String { +fn format_v8_exception(try_catch: &mut v8::PinnedRef<'_, v8::TryCatch>) -> String { let Some(exception) = try_catch.exception() else { return "JavaScript execution failed".to_string(); }; diff --git a/codex-rs/core/src/codex.rs b/codex-rs/core/src/codex.rs index 47e6d9646d..8669f4023a 100644 --- a/codex-rs/core/src/codex.rs +++ b/codex-rs/core/src/codex.rs @@ -392,8 +392,9 @@ impl Codex { && let Some(reason) = codex_code_mode::unsupported_reason() { let _ = config.features.disable(Feature::CodeMode); - let message = - format!("Disabled `code_mode` for this session because it is unavailable: {reason}"); + let message = format!( + "Disabled `code_mode` for this session because it is unavailable: {reason}" + ); warn!("{message}"); config.startup_warnings.push(message); } diff --git a/codex-rs/core/src/tools/code_mode.rs b/codex-rs/core/src/tools/code_mode.rs index 4668abf147..ed7971089d 100644 --- a/codex-rs/core/src/tools/code_mode.rs +++ b/codex-rs/core/src/tools/code_mode.rs @@ -11,16 +11,16 @@ use crate::tools::context::SharedTurnDiffTracker; use crate::tools::context::ToolPayload; use crate::tools::router::ToolCall; use crate::tools::router::ToolCallSource; -use codex_code_mode::execute as execute_code_mode; use codex_code_mode::EnabledTool; use codex_code_mode::ToolKind as CodeModeToolKind; +use codex_code_mode::execute as execute_code_mode; use codex_protocol::models::ContentItem; use codex_protocol::models::FunctionCallOutputBody; use codex_protocol::models::FunctionCallOutputContentItem; use codex_protocol::models::FunctionCallOutputPayload; use codex_protocol::models::ResponseInputItem; -use serde_json::json; use serde_json::Value as JsonValue; +use serde_json::json; use tokio::runtime::Handle; use tokio::runtime::RuntimeFlavor; diff --git a/codex-rs/core/src/tools/spec.rs b/codex-rs/core/src/tools/spec.rs index 010166dca5..ca3d76f1ca 100644 --- a/codex-rs/core/src/tools/spec.rs +++ b/codex-rs/core/src/tools/spec.rs @@ -95,7 +95,8 @@ impl ToolsConfig { session_source, } = params; let include_apply_patch_tool = features.enabled(Feature::ApplyPatchFreeform); - let include_code_mode = features.enabled(Feature::CodeMode) && codex_code_mode::is_supported(); + let include_code_mode = + features.enabled(Feature::CodeMode) && codex_code_mode::is_supported(); let include_js_repl = features.enabled(Feature::JsRepl); let include_js_repl_tools_only = include_js_repl && features.enabled(Feature::JsReplToolsOnly); diff --git a/patches/v8_relative_prebuilt_binding_path.patch b/patches/v8_relative_prebuilt_binding_path.patch new file mode 100644 index 0000000000..f621dff4e8 --- /dev/null +++ b/patches/v8_relative_prebuilt_binding_path.patch @@ -0,0 +1,49 @@ +diff --git a/build.rs b/build.rs +--- a/build.rs ++++ b/build.rs +@@ -578,6 +578,16 @@ + } + + fn static_lib_dir() -> PathBuf { ++ if let Some(out_dir) = env::var_os("OUT_DIR") { ++ let out_dir = PathBuf::from(out_dir); ++ if out_dir ++ .components() ++ .any(|component| component.as_os_str() == "bazel-out") ++ { ++ return out_dir; ++ } ++ } ++ + build_dir().join("gn_out").join("obj") + } + +@@ -591,6 +601,13 @@ + ); + let out_dir_abs = cwd.join(out_dir); + ++ if out_dir_abs ++ .components() ++ .any(|component| component.as_os_str() == "bazel-out") ++ { ++ return out_dir_abs.parent().unwrap().to_path_buf(); ++ } ++ + // This would be `target/debug` or `target/release` + out_dir_abs + .parent() +@@ -861,9 +878,13 @@ + download_file(&url, &src_binding_path); + } + ++ // `src/binding.rs` includes this path directly, so keep it relative to that ++ // source file instead of the build script's synthetic runfiles directory. ++ let include_path = Path::new("..").join("gen").join(name); ++ + println!( + "cargo:rustc-env=RUSTY_V8_SRC_BINDING_PATH={}", +- src_binding_path.display() ++ include_path.display() + ); + } +