mirror of
https://github.com/openai/codex.git
synced 2026-11-08 20:40:33 +00:00
## What changed - Add an extension API for spawning host-owned internal sessions and a `ThreadReadyInput` lifecycle callback that runs after thread registration. - Add Guardian reviewer session scaffolding that records the parent thread and effective model, plus the under-development `guardian_ext` feature flag. - Start internal sessions with fresh history while preserving parent lineage, shared session controls, and internal-thread visibility rules. - Scope internal-session prompt cache keys to their source and parent thread, and expose `guardian` as an internal session source. ## Testing - Cover internal-session spawning, parent metadata, history isolation, prompt cache keys, and extension spawner argument forwarding. GitOrigin-RevId: 682dae80397d62bb36247796b447042e760ca364
96 lines
2.9 KiB
Rust
96 lines
2.9 KiB
Rust
use std::sync::Arc;
|
|
use std::sync::Weak;
|
|
|
|
use codex_core::ThreadManager;
|
|
use codex_core::config::Config;
|
|
use codex_extension_api::AgentSpawnFuture;
|
|
use codex_extension_api::AgentSpawner;
|
|
use codex_extension_api::ExtensionFuture;
|
|
use codex_extension_api::ExtensionRegistryBuilder;
|
|
use codex_extension_api::ThreadLifecycleContributor;
|
|
use codex_extension_api::ThreadStartInput;
|
|
use codex_login::AuthManager;
|
|
use codex_protocol::ThreadId;
|
|
|
|
mod async_scorer;
|
|
mod sync_reviewer;
|
|
|
|
pub use async_scorer::StrictReviewReason;
|
|
pub use sync_reviewer::GuardianExtension as GuardianReviewerExtension;
|
|
pub use sync_reviewer::GuardianThreadContext as GuardianReviewerThreadContext;
|
|
|
|
/// Guardian extension dependencies supplied by the host at construction time.
|
|
#[derive(Clone, Debug)]
|
|
pub struct GuardianExtension<S> {
|
|
agent_spawner: S,
|
|
}
|
|
|
|
impl<S> GuardianExtension<S> {
|
|
/// Creates a guardian extension with its host-provided agent spawn helper.
|
|
pub fn new(agent_spawner: S) -> Self {
|
|
Self { agent_spawner }
|
|
}
|
|
|
|
/// Delegates one guardian-owned subagent spawn request to the host helper.
|
|
pub fn spawn_subagent<'a, R>(
|
|
&'a self,
|
|
forked_from_thread_id: ThreadId,
|
|
request: R,
|
|
) -> AgentSpawnFuture<'a, <S as AgentSpawner<R>>::Spawned, <S as AgentSpawner<R>>::Error>
|
|
where
|
|
S: AgentSpawner<R>,
|
|
{
|
|
self.agent_spawner
|
|
.spawn_subagent(forked_from_thread_id, request)
|
|
}
|
|
}
|
|
|
|
/// Thread-local guardian state captured when the host starts a thread.
|
|
#[derive(Clone, Copy, Debug)]
|
|
pub struct GuardianThreadContext {
|
|
forked_from_thread_id: ThreadId,
|
|
}
|
|
|
|
impl GuardianThreadContext {
|
|
/// Returns the thread that future guardian subagents should fork from by default.
|
|
pub fn forked_from_thread_id(&self) -> ThreadId {
|
|
self.forked_from_thread_id
|
|
}
|
|
}
|
|
|
|
impl<S> ThreadLifecycleContributor<Config> for GuardianExtension<S>
|
|
where
|
|
S: Send + Sync,
|
|
{
|
|
fn on_thread_start<'a>(
|
|
&'a self,
|
|
input: ThreadStartInput<'a, Config>,
|
|
) -> ExtensionFuture<'a, ()> {
|
|
Box::pin(async move {
|
|
let Ok(forked_from_thread_id) = ThreadId::from_string(input.thread_store.level_id())
|
|
else {
|
|
return;
|
|
};
|
|
input.thread_store.insert(GuardianThreadContext {
|
|
forked_from_thread_id,
|
|
});
|
|
})
|
|
}
|
|
}
|
|
|
|
/// Installs the guardian contributors into the extension registry.
|
|
pub fn install<S, I>(
|
|
registry: &mut ExtensionRegistryBuilder<Config>,
|
|
agent_spawner: S,
|
|
internal_session_spawner: I,
|
|
auth_manager: Arc<AuthManager>,
|
|
thread_manager: Weak<ThreadManager>,
|
|
) where
|
|
S: Send + Sync + 'static,
|
|
I: Send + Sync + 'static,
|
|
{
|
|
registry.thread_lifecycle_contributor(Arc::new(GuardianExtension::new(agent_spawner)));
|
|
async_scorer::install(registry, auth_manager, thread_manager.clone());
|
|
sync_reviewer::install(registry, thread_manager, internal_session_spawner);
|
|
}
|