mirror of
https://github.com/openai/codex.git
synced 2026-11-12 21:20:34 +00:00
Add host-reserved V2 child creation APIs (#57586)
## What changed - Add `CodexThread::create_child` to create an idle child from a live tool invocation using a host-reserved thread ID and controller. - Add `prepare_child` and `ThreadManager::create_prepared_child` to capture inherited settings and fresh or forked history, then start the child on another manager even after the parent shuts down. Reject detached preparation when live bindings cannot be transferred. - Add opt-in `HostToolInvocationLookup` to track live calls and reject duplicate active call IDs within a turn. Revoke invocation access when dispatch ends and clean up provisional children when startup fails or is cancelled. ## Testing Add tests for invocation lifetime and call ID reservation, inherited policy and live bindings, detached startup with fresh and full history, and cancellation cleanup. GitOrigin-RevId: 71f17ecb4cd7636517e675df59289a8e8c7105b8
This commit is contained in:
@@ -8,11 +8,15 @@ use crate::elicitation::ElicitationRegistration;
|
||||
use crate::session::SessionIo;
|
||||
use crate::session::SessionSettingsUpdate;
|
||||
use crate::session::Submission;
|
||||
use crate::session::emit_subagent_session_started;
|
||||
use crate::session::new_submission_id;
|
||||
use crate::session::session::AppServerClientMetadata;
|
||||
use crate::session::session::Session;
|
||||
use crate::session::startup_prewarm::PrewarmInput;
|
||||
use crate::session::step_settings::StepSettingsUpdate;
|
||||
use crate::thread_startup_metadata::ThreadStartupMetadata;
|
||||
use chrono::DateTime;
|
||||
use chrono::Utc;
|
||||
use codex_diagnostics::Gauge;
|
||||
use codex_diagnostics::GaugeGuard;
|
||||
use codex_exec_server::SelectedCapabilityRootsStatus;
|
||||
@@ -45,6 +49,7 @@ use codex_protocol::protocol::MultiAgentVersion;
|
||||
use codex_protocol::protocol::Op;
|
||||
use codex_protocol::protocol::SandboxPolicy;
|
||||
use codex_protocol::protocol::SessionSource;
|
||||
use codex_protocol::protocol::SubAgentSource;
|
||||
use codex_protocol::protocol::ThreadHistoryMode;
|
||||
use codex_protocol::protocol::ThreadMemoryMode;
|
||||
use codex_protocol::protocol::ThreadSettingsOverrides;
|
||||
@@ -289,6 +294,39 @@ impl CodexThread {
|
||||
self.session.services.analytics_events_client.is_enabled()
|
||||
}
|
||||
|
||||
/// Looks up a live V2 tool invocation on a runtime with [`crate::HostToolInvocationLookup`].
|
||||
pub fn tool_invocation(
|
||||
&self,
|
||||
turn_id: &str,
|
||||
call_id: &str,
|
||||
) -> CodexResult<crate::ToolInvocationContext> {
|
||||
crate::agent::host::tool_invocation(self, turn_id, call_id)
|
||||
}
|
||||
|
||||
/// Creates an idle V2 child here with the invoking step's environments and live application
|
||||
/// bindings. Compatible children share the parent's exec policy.
|
||||
/// Ending the invocation or dropping this future aborts pending startup.
|
||||
/// [`crate::ThreadManager::create_prepared_child`] defines acceptance and cleanup.
|
||||
pub async fn create_child(
|
||||
&self,
|
||||
invocation: &crate::ToolInvocationContext,
|
||||
request: crate::ThreadCreateRequest,
|
||||
reservation: crate::HostThreadSpawnReservation,
|
||||
) -> Result<crate::ThreadSpawnResult, crate::ThreadSpawnError> {
|
||||
crate::agent::host::create(self, invocation, request, reservation).await
|
||||
}
|
||||
|
||||
/// Captures inputs from a live invocation for [`crate::ThreadManager::create_prepared_child`].
|
||||
/// The host owns cancellation and snapshot freshness after this returns. Detached preparation
|
||||
/// rejects managed application network, auth, and cloud config bindings.
|
||||
pub async fn prepare_child(
|
||||
&self,
|
||||
invocation: &crate::ToolInvocationContext,
|
||||
request: crate::ThreadCreateRequest,
|
||||
) -> Result<crate::PreparedThreadSpawn, crate::ThreadSpawnError> {
|
||||
crate::agent::host::prepare(self, invocation, request).await
|
||||
}
|
||||
|
||||
/// Returns extension-owned data attached to this thread runtime.
|
||||
pub fn thread_extension_data(&self) -> &codex_extension_api::ExtensionData {
|
||||
&self.session.services.thread_extension_data
|
||||
@@ -338,6 +376,29 @@ impl CodexThread {
|
||||
self.io.session_loop_termination.clone().await;
|
||||
}
|
||||
|
||||
pub(crate) async fn emit_subagent_session_started(
|
||||
&self,
|
||||
client_metadata: AppServerClientMetadata,
|
||||
resumed_created_at: Option<DateTime<Utc>>,
|
||||
) {
|
||||
let SessionSource::SubAgent(source @ SubAgentSource::ThreadSpawn { .. }) =
|
||||
&self.session_source
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let config = self.config_snapshot().await;
|
||||
emit_subagent_session_started(
|
||||
&self.session.services.analytics_events_client,
|
||||
client_metadata,
|
||||
self.session.session_id(),
|
||||
self.session.thread_id(),
|
||||
config.parent_thread_id,
|
||||
config,
|
||||
source.clone(),
|
||||
resumed_created_at,
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) async fn emit_thread_ready_lifecycle(&self) {
|
||||
let contributors = self
|
||||
.session
|
||||
|
||||
Reference in New Issue
Block a user