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 authored and copyberry committed 2026-07-30 20:24:29 +00:00
1 parent acd540f158
commit 97576b1794
51 files changed
+627 -424

No files matched your search

+19
View File
@@ -115,6 +115,7 @@ pub struct TurnContext {
pub(crate) sub_id: String,
pub(crate) trace_id: Option<String>,
pub(crate) realtime_active: bool,
pub(crate) code_mode_available: bool,
pub config: Arc<Config>,
pub(crate) auth_manager: Option<Arc<AuthManager>>,
pub(crate) model_info: ModelInfo,
@@ -280,6 +281,7 @@ impl TurnContext {
sub_id: self.sub_id.clone(),
trace_id: self.trace_id.clone(),
realtime_active: self.realtime_active,
code_mode_available: self.code_mode_available,
config: Arc::new(config),
auth_manager: self.auth_manager.clone(),
model_info: model_info.clone(),
@@ -551,6 +553,7 @@ impl Session {
sub_id,
trace_id: current_span_trace_id(),
realtime_active: false,
code_mode_available: true,
config: per_turn_config,
auth_manager: auth_manager_for_context,
model_info,
@@ -798,6 +801,7 @@ impl Session {
sub_id,
skills_snapshot,
);
turn_context.code_mode_available = self.services.code_mode_service.is_available();
turn_context.extension_data.insert(trusted_plugin_roots);
turn_context.realtime_active = self.conversation.running_state().await.is_some();
@@ -830,6 +834,21 @@ impl Session {
.await;
}
if !tc.code_mode_available
&& matches!(
crate::tools::requested_tool_mode(tc),
codex_protocol::openai_models::ToolMode::CodeMode
| codex_protocol::openai_models::ToolMode::CodeModeOnly
)
&& let Some(message) = self
.services
.code_mode_service
.take_unavailable_warning(crate::tools::effective_tool_mode(tc))
{
self.send_event(tc, EventMsg::Warning(WarningEvent { message }))
.await;
}
if let Some(message) =
unsupported_code_mode_warning(&tc.model_info, tc.config.features.get())
{