Add opt-in gRPC over stdio for the code-mode host (#52723)

## What changed

- Add `grpc+stdio://` as a host transport and the disabled-by-default `code_mode_host_grpc` feature flag to select it.
- Share a lazy HTTP/2 channel and host process across code-mode sessions while keeping session state isolated.
- Use HTTP/2 keepalives to detect unresponsive hosts, kill and reap disconnected children, and spawn a fresh host on reconnect. Exit the host when its stdio connection closes.

## Testing

Add coverage for shared-host session isolation, host exit on stdin EOF, and recovery after an unresponsive host is reaped. Exercise nested tool calls with both legacy stdio and gRPC stdio, asserting that the feature flag selects the expected transport.

GitOrigin-RevId: 31389d8540de236b8e0571d3c24e29e117b75c4a
This commit is contained in:
Channing Conger
2026-10-09 23:26:34 +00:00
committed by copyberry
parent 07757f448f
commit 2dc0791c7d
17 changed files with 566 additions and 18 deletions
+25 -5
View File
@@ -61,6 +61,7 @@ use codex_history::HistoryInitialization;
use codex_history::InitialHistory;
use codex_history::ResumedHistory;
use codex_history::RolloutItem;
use codex_install_context::InstallContext;
use codex_login::AuthManager;
use codex_login::CodexAuth;
use codex_login::default_client::CODEX_INTERNAL_ORIGINATOR_OVERRIDE_ENV_VAR;
@@ -574,7 +575,10 @@ impl ThreadManager {
if config.features.enabled(Feature::CodeModeHost)
|| config.code_mode.disable_in_process_fallback
{
Arc::new(ProcessOwnedCodeModeSessionProvider::default())
Self::process_code_mode_session_provider(
config,
InstallContext::current().code_mode_host_program(),
)
} else {
Arc::new(DisabledCodeModeSessionProvider)
};
@@ -660,17 +664,33 @@ impl ThreadManager {
pub(crate) fn with_code_mode_host_program_for_tests(
mut self,
host_program: PathBuf,
_config: &Config,
config: &Config,
) -> Self {
let Some(state) = Arc::get_mut(&mut self.state) else {
unreachable!("new thread manager state should not be shared");
};
state.code_mode_session_provider = Arc::new(
ProcessOwnedCodeModeSessionProvider::with_host_program(host_program),
);
state.code_mode_session_provider =
Self::process_code_mode_session_provider(config, host_program);
self
}
fn process_code_mode_session_provider(
config: &Config,
host_program: PathBuf,
) -> Arc<dyn CodeModeSessionProvider> {
if config.features.enabled(Feature::CodeModeHostGrpc) {
Arc::new(
crate::code_mode_host::ProcessOwnedGrpcCodeModeSessionProvider::with_host_program(
host_program,
),
)
} else {
Arc::new(ProcessOwnedCodeModeSessionProvider::with_host_program(
host_program,
))
}
}
/// Construct with a dummy AuthManager containing the provided CodexAuth.
/// Used for integration tests: should not be used by ordinary business logic.
pub(crate) fn with_models_provider_for_tests(