mirror of
https://github.com/openai/codex.git
synced 2026-10-27 18:48:37 +00:00
Support metadata staging for reserved thread IDs (#38819)
## Why Callers need to associate host-owned state with a thread before Core starts it. ## What changed - Add `ThreadManager::reserve_thread_id` and allow new threads to start with the reserved ID. Reject reserved IDs when resuming an existing thread. - Let thread stores stage metadata for a reserved ID. The local store merges staged values into the first successful metadata update and then removes them. - Clear staged metadata when an unmaterialized thread shuts down or is discarded, and require the state database for staging. ## Testing - Cover reserved ID generation and resume validation. - Cover metadata persistence, merging, rollout-compatible updates, cleanup, and invalid staging requests. GitOrigin-RevId: 3f9bc48f0f7764011cc90ea01349e497dda0a9e3
This commit is contained in:
committed by
copyberry
parent
5ba12929f8
commit
fcdae21073
@@ -231,6 +231,8 @@ pub struct StartThreadOptions {
|
||||
pub environments: Option<Vec<TurnEnvironmentSelection>>,
|
||||
pub thread_extension_init: ExtensionDataInit,
|
||||
pub client_mcp_extensions: ClientMcpExtensions,
|
||||
/// Thread ID reserved before startup so the caller can associate host-owned state with it.
|
||||
pub reserved_thread_id: Option<ThreadId>,
|
||||
}
|
||||
|
||||
impl StartThreadOptions {
|
||||
@@ -248,6 +250,7 @@ impl StartThreadOptions {
|
||||
environments: None,
|
||||
thread_extension_init: ExtensionDataInit::default(),
|
||||
client_mcp_extensions: ClientMcpExtensions::default(),
|
||||
reserved_thread_id: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -891,6 +894,11 @@ impl ThreadManager {
|
||||
Box::pin(self.start_thread_inner(options, /*forked_from_thread_id*/ None)).await
|
||||
}
|
||||
|
||||
/// Allocates a thread ID before startup so a caller can associate host-owned state with it.
|
||||
pub fn reserve_thread_id(&self) -> ThreadId {
|
||||
self.state.thread_id_generator.as_ref()()
|
||||
}
|
||||
|
||||
async fn start_thread_inner(
|
||||
&self,
|
||||
mut options: StartThreadOptions,
|
||||
@@ -1755,6 +1763,7 @@ impl ThreadManagerState {
|
||||
environments,
|
||||
thread_extension_init,
|
||||
client_mcp_extensions,
|
||||
reserved_thread_id,
|
||||
} = options;
|
||||
let session_source = session_source.unwrap_or_else(|| self.session_source.clone());
|
||||
let environments = environments.unwrap_or_else(|| {
|
||||
@@ -1765,6 +1774,11 @@ impl ThreadManagerState {
|
||||
)
|
||||
});
|
||||
let is_resumed_thread = matches!(&initial_history, InitialHistory::Resumed(_));
|
||||
if reserved_thread_id.is_some() && matches!(&initial_history, InitialHistory::Resumed(_)) {
|
||||
return Err(CodexErr::InvalidRequest(
|
||||
"reserved thread ID cannot be used when resuming a thread".to_string(),
|
||||
));
|
||||
}
|
||||
if let InitialHistory::Resumed(resumed) = &initial_history {
|
||||
let mut threads = self.threads.write().await;
|
||||
if let Some(thread) = threads.get(&resumed.conversation_id).cloned() {
|
||||
@@ -1851,6 +1865,7 @@ impl ThreadManagerState {
|
||||
environment_selections: environments,
|
||||
thread_extension_init,
|
||||
client_mcp_extensions,
|
||||
reserved_thread_id,
|
||||
analytics_events_client: self.analytics_events_client.clone(),
|
||||
thread_store: Arc::clone(&self.thread_store),
|
||||
attestation_provider: self.attestation_provider.clone(),
|
||||
|
||||
Reference in New Issue
Block a user