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
2 changes: 1 addition & 1 deletion .codespellrc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[codespell]
# Ref: https://github.com/codespell-project/codespell#using-a-config-file
skip = .git*,vendor,*-lock.yaml,*.lock,.codespellrc,*test.ts,*.jsonl,frame*.txt,*.snap,*.snap.new
skip = .git*,vendor,*-lock.yaml,*.lock,.codespellrc,*test.ts,*.jsonl,frame*.txt,*.snap,*.snap.new,*meriyah.umd.min.js
check-hidden = true
ignore-regex = ^\s*"image/\S+": ".*|\b(afterAll)\b
ignore-words-list = ratatui,ser,iTerm,iterm2,iterm
3 changes: 3 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ Copyright 2025 OpenAI
This project includes code derived from [Ratatui](https://github.com/ratatui/ratatui), licensed under the MIT license.
Copyright (c) 2016-2022 Florian Dehau
Copyright (c) 2023-2025 The Ratatui Developers

This project includes Meriyah parser assets from [meriyah](https://github.com/meriyah/meriyah), licensed under the ISC license.
Copyright (c) 2019 and later, KFlash and others.
4 changes: 3 additions & 1 deletion codex-rs/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@

exports_files([
"node-version.txt",
])
4 changes: 3 additions & 1 deletion codex-rs/core/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ codex_rust_crate(
"Cargo.toml",
],
allow_empty = True,
),
) + [
"//codex-rs:node-version.txt",
],
integration_compile_data_extra = [
"//codex-rs/apply-patch:apply_patch_tool_instructions.md",
"models.json",
Expand Down
17 changes: 17 additions & 0 deletions codex-rs/core/config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,9 @@
"include_apply_patch_tool": {
"type": "boolean"
},
"js_repl": {
"type": "boolean"
},
"memory_tool": {
"type": "boolean"
},
Expand Down Expand Up @@ -290,6 +293,9 @@
"include_apply_patch_tool": {
"type": "boolean"
},
"js_repl_node_path": {
"$ref": "#/definitions/AbsolutePathBuf"
},
"model": {
"type": "string"
},
Expand Down Expand Up @@ -1275,6 +1281,9 @@
"include_apply_patch_tool": {
"type": "boolean"
},
"js_repl": {
"type": "boolean"
},
"memory_tool": {
"type": "boolean"
},
Expand Down Expand Up @@ -1397,6 +1406,14 @@
"description": "System instructions.",
"type": "string"
},
"js_repl_node_path": {
"allOf": [
{
"$ref": "#/definitions/AbsolutePathBuf"
}
],
"description": "Optional absolute path to the Node runtime used by `js_repl`."
},
"log_dir": {
"allOf": [
{
Expand Down
30 changes: 28 additions & 2 deletions codex-rs/core/src/codex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ use crate::tasks::SessionTask;
use crate::tasks::SessionTaskContext;
use crate::tools::ToolRouter;
use crate::tools::context::SharedTurnDiffTracker;
use crate::tools::js_repl::JsReplHandle;
use crate::tools::parallel::ToolCallRuntime;
use crate::tools::sandboxing::ApprovalStore;
use crate::tools::spec::ToolsConfig;
Expand Down Expand Up @@ -510,6 +511,7 @@ pub(crate) struct Session {
pending_mcp_server_refresh_config: Mutex<Option<McpServerRefreshConfig>>,
pub(crate) active_turn: Mutex<Option<ActiveTurn>>,
pub(crate) services: SessionServices,
js_repl: Arc<JsReplHandle>,
next_internal_sub_id: AtomicU64,
}

Expand Down Expand Up @@ -549,6 +551,7 @@ pub(crate) struct TurnContext {
pub(crate) codex_linux_sandbox_exe: Option<PathBuf>,
pub(crate) tool_call_gate: Arc<ReadinessFlag>,
pub(crate) truncation_policy: TruncationPolicy,
pub(crate) js_repl: Arc<JsReplHandle>,
pub(crate) dynamic_tools: Vec<DynamicToolSpec>,
turn_metadata_header: OnceCell<Option<String>>,
}
Expand Down Expand Up @@ -809,6 +812,7 @@ impl Session {
model_info: ModelInfo,
network: Option<NetworkProxy>,
sub_id: String,
js_repl: Arc<JsReplHandle>,
) -> TurnContext {
let reasoning_effort = session_configuration.collaboration_mode.reasoning_effort();
let reasoning_summary = session_configuration.model_reasoning_summary;
Expand Down Expand Up @@ -857,6 +861,7 @@ impl Session {
codex_linux_sandbox_exe: per_turn_config.codex_linux_sandbox_exe.clone(),
tool_call_gate: Arc::new(ReadinessFlag::new()),
truncation_policy: model_info.truncation_policy.into(),
js_repl,
dynamic_tools: session_configuration.dynamic_tools.clone(),
turn_metadata_header: OnceCell::new(),
}
Expand Down Expand Up @@ -1123,6 +1128,10 @@ impl Session {
Self::build_model_client_beta_features_header(config.as_ref()),
),
};
let js_repl = Arc::new(JsReplHandle::with_node_path(
config.js_repl_node_path.clone(),
config.codex_home.clone(),
));

let prewarm_model_info = models_manager
.get_model_info(session_configuration.collaboration_mode.model(), &config)
Expand Down Expand Up @@ -1150,6 +1159,7 @@ impl Session {
pending_mcp_server_refresh_config: Mutex::new(None),
active_turn: Mutex::new(None),
services,
js_repl,
next_internal_sub_id: AtomicU64::new(0),
});

Expand Down Expand Up @@ -1598,6 +1608,7 @@ impl Session {
.as_ref()
.map(StartedNetworkProxy::proxy),
sub_id,
Arc::clone(&self.js_repl),
);

if let Some(final_schema) = final_output_json_schema {
Expand Down Expand Up @@ -3766,6 +3777,7 @@ async fn spawn_review_thread(
final_output_json_schema: None,
codex_linux_sandbox_exe: parent_turn_context.codex_linux_sandbox_exe.clone(),
tool_call_gate: Arc::new(ReadinessFlag::new()),
js_repl: Arc::clone(&sess.js_repl),
dynamic_tools: parent_turn_context.dynamic_tools.clone(),
truncation_policy: model_info.truncation_policy.into(),
turn_metadata_header: parent_turn_context.turn_metadata_header.clone(),
Expand Down Expand Up @@ -4253,11 +4265,13 @@ async fn run_sampling_request(

let model_supports_parallel = turn_context.model_info.supports_parallel_tool_calls;

let tools =
crate::tools::spec::filter_tools_for_model(router.specs(), &turn_context.tools_config);
let base_instructions = sess.get_base_instructions().await;

let prompt = Prompt {
input,
tools: router.specs(),
tools,
parallel_tool_calls: model_supports_parallel,
base_instructions,
personality: turn_context.personality,
Expand Down Expand Up @@ -5280,9 +5294,9 @@ mod tests {
];

let (session, _turn_context) = make_session_and_context().await;
let config = test_config();

for test_case in test_cases {
let config = test_config();
let model_info = model_info_for_slug(test_case.slug, &config);
if test_case.expects_apply_patch_instructions {
assert_eq!(
Expand Down Expand Up @@ -6298,6 +6312,10 @@ mod tests {
Session::build_model_client_beta_features_header(config.as_ref()),
),
};
let js_repl = Arc::new(JsReplHandle::with_node_path(
config.js_repl_node_path.clone(),
config.codex_home.clone(),
));

let turn_context = Session::make_turn_context(
Some(Arc::clone(&auth_manager)),
Expand All @@ -6308,6 +6326,7 @@ mod tests {
model_info,
None,
"turn_id".to_string(),
Arc::clone(&js_repl),
);

let session = Session {
Expand All @@ -6319,6 +6338,7 @@ mod tests {
pending_mcp_server_refresh_config: Mutex::new(None),
active_turn: Mutex::new(None),
services,
js_repl,
next_internal_sub_id: AtomicU64::new(0),
};

Expand Down Expand Up @@ -6435,6 +6455,10 @@ mod tests {
Session::build_model_client_beta_features_header(config.as_ref()),
),
};
let js_repl = Arc::new(JsReplHandle::with_node_path(
config.js_repl_node_path.clone(),
config.codex_home.clone(),
));

let turn_context = Arc::new(Session::make_turn_context(
Some(Arc::clone(&auth_manager)),
Expand All @@ -6445,6 +6469,7 @@ mod tests {
model_info,
None,
"turn_id".to_string(),
Arc::clone(&js_repl),
));

let session = Arc::new(Session {
Expand All @@ -6456,6 +6481,7 @@ mod tests {
pending_mcp_server_refresh_config: Mutex::new(None),
active_turn: Mutex::new(None),
services,
js_repl,
next_internal_sub_id: AtomicU64::new(0),
});

Expand Down
16 changes: 16 additions & 0 deletions codex-rs/core/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,9 @@ pub struct Config {
/// When this program is invoked, arg0 will be set to `codex-linux-sandbox`.
pub codex_linux_sandbox_exe: Option<PathBuf>,

/// Optional absolute path to the Node runtime used by `js_repl`.
pub js_repl_node_path: Option<PathBuf>,

/// Value to use for `reasoning.effort` when making a request using the
/// Responses API.
pub model_reasoning_effort: Option<ReasoningEffort>,
Expand Down Expand Up @@ -936,6 +939,9 @@ pub struct ConfigToml {
/// Token budget applied when storing tool/function outputs in the context manager.
pub tool_output_token_limit: Option<usize>,

/// Optional absolute path to the Node runtime used by `js_repl`.
pub js_repl_node_path: Option<AbsolutePathBuf>,

/// Profile to use from the `profiles` map.
pub profile: Option<String>,

Expand Down Expand Up @@ -1277,6 +1283,7 @@ pub struct ConfigOverrides {
pub model_provider: Option<String>,
pub config_profile: Option<String>,
pub codex_linux_sandbox_exe: Option<PathBuf>,
pub js_repl_node_path: Option<PathBuf>,
pub base_instructions: Option<String>,
pub developer_instructions: Option<String>,
pub personality: Option<Personality>,
Expand Down Expand Up @@ -1403,6 +1410,7 @@ impl Config {
model_provider,
config_profile: config_profile_key,
codex_linux_sandbox_exe,
js_repl_node_path: js_repl_node_path_override,
base_instructions,
developer_instructions,
personality,
Expand Down Expand Up @@ -1634,6 +1642,9 @@ impl Config {
"experimental compact prompt file",
)?;
let compact_prompt = compact_prompt.or(file_compact_prompt);
let js_repl_node_path = js_repl_node_path_override
.or(config_profile.js_repl_node_path.map(Into::into))
.or(cfg.js_repl_node_path.map(Into::into));

let review_model = override_review_model.or(cfg.review_model);

Expand Down Expand Up @@ -1751,6 +1762,7 @@ impl Config {
ephemeral: ephemeral.unwrap_or_default(),
file_opener: cfg.file_opener.unwrap_or(UriBasedFileOpener::VsCode),
codex_linux_sandbox_exe,
js_repl_node_path,

hide_agent_reasoning: cfg.hide_agent_reasoning.unwrap_or(false),
show_raw_agent_reasoning: cfg
Expand Down Expand Up @@ -4048,6 +4060,7 @@ model_verbosity = "high"
ephemeral: false,
file_opener: UriBasedFileOpener::VsCode,
codex_linux_sandbox_exe: None,
js_repl_node_path: None,
hide_agent_reasoning: false,
show_raw_agent_reasoning: false,
model_reasoning_effort: Some(ReasoningEffort::High),
Expand Down Expand Up @@ -4154,6 +4167,7 @@ model_verbosity = "high"
ephemeral: false,
file_opener: UriBasedFileOpener::VsCode,
codex_linux_sandbox_exe: None,
js_repl_node_path: None,
hide_agent_reasoning: false,
show_raw_agent_reasoning: false,
model_reasoning_effort: None,
Expand Down Expand Up @@ -4258,6 +4272,7 @@ model_verbosity = "high"
ephemeral: false,
file_opener: UriBasedFileOpener::VsCode,
codex_linux_sandbox_exe: None,
js_repl_node_path: None,
hide_agent_reasoning: false,
show_raw_agent_reasoning: false,
model_reasoning_effort: None,
Expand Down Expand Up @@ -4348,6 +4363,7 @@ model_verbosity = "high"
ephemeral: false,
file_opener: UriBasedFileOpener::VsCode,
codex_linux_sandbox_exe: None,
js_repl_node_path: None,
hide_agent_reasoning: false,
show_raw_agent_reasoning: false,
model_reasoning_effort: Some(ReasoningEffort::High),
Expand Down
1 change: 1 addition & 0 deletions codex-rs/core/src/config/profile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ pub struct ConfigProfile {
pub chatgpt_base_url: Option<String>,
/// Optional path to a file containing model instructions.
pub model_instructions_file: Option<AbsolutePathBuf>,
pub js_repl_node_path: Option<AbsolutePathBuf>,
/// Deprecated: ignored. Use `model_instructions_file`.
#[schemars(skip)]
pub experimental_instructions_file: Option<AbsolutePathBuf>,
Expand Down
8 changes: 8 additions & 0 deletions codex-rs/core/src/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ pub enum Feature {
ShellTool,

// Experimental
/// Enable JavaScript REPL tools backed by a persistent Node kernel.
JsRepl,
/// Use the single unified PTY-backed exec tool.
UnifiedExec,
/// Include the freeform apply_patch tool.
Expand Down Expand Up @@ -422,6 +424,12 @@ pub const FEATURES: &[FeatureSpec] = &[
stage: Stage::Stable,
default_enabled: true,
},
FeatureSpec {
id: Feature::JsRepl,
key: "js_repl",
stage: Stage::UnderDevelopment,
default_enabled: false,
},
FeatureSpec {
id: Feature::WebSearchRequest,
key: "web_search_request",
Expand Down
Loading
Loading