Route Guardian reviewers through ThreadManager for inline parents (#45518)

## Why

Inline delegates have no entry in the thread registry, so reviewer creation cannot depend on looking up the parent or waiting for its thread-ready notification.

## What changed

- Capture parent identity, authentication, shared agent control, originator, and inherited instructions in `StartThreadOptions` so `ThreadManager` can start a child without a registered parent.
- Route Guardian reviewer creation through this path, remove the standalone fallback and readiness gate, and require a Guardian extension host.
- Install explicit reviewer hosts in unit tests and the Guardian reviewer extension in the integration test harness, using `ExtensionRegistry::to_builder()` to preserve existing contributors.

## Testing

Extend the thread-manager regression test to remove the parent from the registry before starting a child, then verify inherited lineage, originator, session identity, and authentication, and exclusion from the public thread list.

GitOrigin-RevId: 468ded6fdce7520cb39d55c1a884dcfa5aaea2d9
This commit is contained in:
jif authored and copyberry committed 2026-09-14 21:23:06 +00:00
1 parent 280c7e1e56
commit 7c73903be2
18 files changed
+318 -199

No files matched your search

+34 -28
View File
@@ -719,39 +719,45 @@ impl TestCodexBuilder {
.models_manager
.clone()
.unwrap_or_else(|| codex_core::build_models_manager(&config, auth_manager.clone()));
let thread_manager = ThreadManager::new(
&config,
auth_manager.clone(),
models_manager,
codex_core::CodexAppsToolsCache::default(),
SessionSource::Exec,
Arc::clone(&environment_manager),
Arc::clone(&self.extensions),
user_instructions_provider,
/*analytics_events_client*/ None,
codex_core::passthrough_image_store(),
Arc::clone(&thread_store),
codex_core::local_agent_graph_store_from_state_db(state_db.as_ref()),
installation_id,
/*attestation_provider*/ None,
/*external_time_provider*/ self.external_time_provider.clone(),
);
let code_mode_host_program = self
.code_mode_host_program
.take()
.or_else(|| codex_utils_cargo_bin::cargo_bin("codex-code-mode-host").ok());
let thread_manager = if config.features.enabled(Feature::CodeModeHost)
&& let Some(code_mode_host_program) = code_mode_host_program
{
codex_core::test_support::with_code_mode_host_program(
thread_manager,
code_mode_host_program,
let thread_manager = Arc::new_cyclic(|manager| {
let mut extensions = self.extensions.to_builder();
let guardian = Arc::new(codex_guardian_v2::GuardianReviewerExtension::new(
manager.clone(),
));
extensions.thread_lifecycle_contributor(guardian);
let thread_manager = ThreadManager::new(
&config,
)
} else {
thread_manager
};
let thread_manager = Arc::new(thread_manager);
auth_manager.clone(),
models_manager,
codex_core::CodexAppsToolsCache::default(),
SessionSource::Exec,
Arc::clone(&environment_manager),
Arc::new(extensions.build()),
user_instructions_provider,
/*analytics_events_client*/ None,
codex_core::passthrough_image_store(),
Arc::clone(&thread_store),
codex_core::local_agent_graph_store_from_state_db(state_db.as_ref()),
installation_id,
/*attestation_provider*/ None,
/*external_time_provider*/ self.external_time_provider.clone(),
);
if config.features.enabled(Feature::CodeModeHost)
&& let Some(code_mode_host_program) = code_mode_host_program
{
codex_core::test_support::with_code_mode_host_program(
thread_manager,
code_mode_host_program,
&config,
)
} else {
thread_manager
}
});
let user_shell_override = self.user_shell_override.clone();
let client_mcp_extensions = || {
ClientMcpExtensions::new(