Run code mode exclusively through the standalone host (#36217)

## What changed

- Move the V8 implementation into a dedicated `codex-code-mode-runtime` crate used by `codex-code-mode-host`, removing the embedded runtime fallback from the Codex process.
- Resolve the host executable from the active installation layout and check its availability before selecting tools.
- Fall back to direct tools with a one-time warning when optional code mode is unavailable. Keep `code_mode_only` and `disable_in_process_fallback` configurations fail-closed.

## Testing

- Cover host discovery for standalone and package layouts, including missing hosts and symlinks.
- Verify direct-tool fallback, one-time warnings, and fail-closed code-mode-only behavior.

GitOrigin-RevId: 5aa3c6f1db148b2231fc24089a2ee0e2b00dbddb
This commit is contained in:
Channing Conger
2026-07-30 20:24:29 +00:00
committed by copyberry
parent acd540f158
commit 97576b1794
51 changed files with 627 additions and 424 deletions
+25 -44
View File
@@ -76,9 +76,11 @@ pub(crate) struct ExecContext {
pub(crate) struct CodeModeService {
session: OnceCell<Arc<dyn CodeModeSession>>,
session_provider: Arc<dyn CodeModeSessionProvider>,
availability: Result<(), String>,
dispatch_broker: Arc<CodeModeDispatchBroker>,
default_exec_yield_time_override_ms: Option<u64>,
shutting_down: AtomicBool,
unavailable_warning_emitted: AtomicBool,
}
impl CodeModeService {
@@ -87,15 +89,38 @@ impl CodeModeService {
features: &Features,
) -> Self {
let dispatch_broker = Arc::new(CodeModeDispatchBroker::new());
let availability = session_provider.availability();
Self {
session: OnceCell::new(),
session_provider,
availability,
dispatch_broker,
default_exec_yield_time_override_ms: default_exec_yield_time_override_ms(features),
shutting_down: AtomicBool::new(false),
unavailable_warning_emitted: AtomicBool::new(false),
}
}
pub(crate) fn is_available(&self) -> bool {
self.availability.is_ok()
}
pub(crate) fn take_unavailable_warning(&self, tool_mode: ToolMode) -> Option<String> {
let error = self.availability.as_ref().err()?;
let behavior = match tool_mode {
ToolMode::Direct => "Falling back to direct tools",
ToolMode::CodeMode | ToolMode::CodeModeOnly => "Code mode will fail closed",
};
(!self
.unavailable_warning_emitted
.swap(true, Ordering::Relaxed))
.then(|| {
format!(
"Code Mode is unavailable because {error}. {behavior}; enable `features.code_mode_host` and install `codex-code-mode-host`."
)
})
}
pub(crate) fn session_provider(&self) -> Arc<dyn CodeModeSessionProvider> {
Arc::clone(&self.session_provider)
}
@@ -378,18 +403,10 @@ fn build_freeform_tool_payload(
#[cfg(test)]
mod tests {
use std::sync::Arc;
use super::CodeModeService;
use super::build_nested_tool_payload;
use super::truncate_code_mode_result;
use crate::tools::context::ToolPayload;
use codex_code_mode::CodeModeToolKind;
use codex_code_mode::ExecuteRequest;
use codex_code_mode::FunctionCallOutputContentItem as CodeModeOutputContentItem;
use codex_code_mode::ProcessOwnedCodeModeSessionProvider;
use codex_code_mode::RuntimeResponse;
use codex_features::Features;
use codex_protocol::models::FunctionCallOutputContentItem;
use codex_tools::ToolName;
use serde_json::json;
@@ -460,40 +477,4 @@ mod tests {
}]
);
}
#[tokio::test]
async fn missing_process_host_falls_back_to_in_process_session() {
let service = CodeModeService::new(
Arc::new(ProcessOwnedCodeModeSessionProvider::with_host_program(
"codex-code-mode-host-does-not-exist".into(),
)),
&Features::with_defaults(),
);
let response = service
.execute(ExecuteRequest {
tool_call_id: "call-1".to_string(),
enabled_tools: Vec::new(),
source: "text('fallback')".to_string(),
yield_time_ms: None,
max_output_tokens: None,
})
.await
.expect("missing host should fall back to an in-process session")
.initial_response()
.await
.expect("read fallback response");
assert_eq!(
response,
RuntimeResponse::Result {
cell_id: codex_code_mode::CellId::new("1".to_string()),
content_items: vec![CodeModeOutputContentItem::InputText {
text: "fallback".to_string(),
}],
error_text: None,
}
);
service.shutdown().await.expect("shutdown service");
}
}