mirror of
https://github.com/openai/codex.git
synced 2026-05-23 20:44:50 +00:00
Move plugin and skill warmup into session startup (#23535)
## Why Plugin and skill loading is useful as warmup and early validation, but session startup does not need to wait for that work before it can continue building the session. Keeping it on the serial startup path adds avoidable latency to every fresh thread start. We still want invalid skill configurations to show up quickly, and we want the warmup to exercise the same plugin and skill manager caches that the normal turn path uses. ## What changed - moved plugin and skill warmup into the session startup async path instead of eagerly awaiting it on the serial setup path - kept the warmup using the session's resolved filesystem/environment context so skill loading still sees the right roots - preserved early skill-load error logging so broken skill configurations still surface during startup - left the per-turn plugin and skill loading path unchanged, so turns still use the normal cached managers ## Testing - Not run locally; relying on CI for validation.
This commit is contained in:
@@ -480,20 +480,6 @@ impl Codex {
|
||||
} = args;
|
||||
let (tx_sub, rx_sub) = async_channel::bounded(SUBMISSION_CHANNEL_CAPACITY);
|
||||
let (tx_event, rx_event) = async_channel::unbounded();
|
||||
let fs = environment_selections.primary_filesystem();
|
||||
let plugins_input = config.plugins_config_input();
|
||||
let plugin_outcome = plugins_manager.plugins_for_config(&plugins_input).await;
|
||||
let effective_skill_roots = plugin_outcome.effective_plugin_skill_roots();
|
||||
let skills_input = skills_load_input_from_config(&config, effective_skill_roots);
|
||||
let loaded_skills = skills_manager.skills_for_config(&skills_input, fs).await;
|
||||
|
||||
for err in &loaded_skills.errors {
|
||||
error!(
|
||||
"failed to load skill {}: {}",
|
||||
err.path.display(),
|
||||
err.message
|
||||
);
|
||||
}
|
||||
|
||||
if let SessionSource::SubAgent(SubAgentSource::ThreadSpawn { depth, .. }) = session_source
|
||||
&& depth >= config.agent_max_depth
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use super::input_queue::InputQueue;
|
||||
use super::*;
|
||||
use crate::goals::GoalRuntimeState;
|
||||
use crate::skills::SkillError;
|
||||
use crate::state::ActiveTurn;
|
||||
use codex_protocol::SessionId;
|
||||
use codex_protocol::config_types::ServiceTier;
|
||||
@@ -405,6 +406,29 @@ pub(crate) struct AppServerClientMetadata {
|
||||
pub(crate) client_version: Option<String>,
|
||||
}
|
||||
|
||||
async fn warm_plugins_and_skills_for_session_init(
|
||||
config: Arc<Config>,
|
||||
environment_manager: Arc<EnvironmentManager>,
|
||||
plugins_manager: Arc<PluginsManager>,
|
||||
skills_manager: Arc<SkillsManager>,
|
||||
environments: Vec<TurnEnvironmentSelection>,
|
||||
) -> Vec<SkillError> {
|
||||
let fs = crate::environment_selection::resolve_environment_selections(
|
||||
environment_manager.as_ref(),
|
||||
&environments,
|
||||
)
|
||||
.ok()
|
||||
.and_then(|resolved| resolved.primary_filesystem());
|
||||
let plugins_input = config.plugins_config_input();
|
||||
let plugin_outcome = plugins_manager.plugins_for_config(&plugins_input).await;
|
||||
let effective_skill_roots = plugin_outcome.effective_plugin_skill_roots();
|
||||
let skills_input = skills_load_input_from_config(config.as_ref(), effective_skill_roots);
|
||||
skills_manager
|
||||
.skills_for_config(&skills_input, fs)
|
||||
.await
|
||||
.errors
|
||||
}
|
||||
|
||||
impl Session {
|
||||
/// Returns the concrete identity for this thread.
|
||||
pub(crate) fn thread_id(&self) -> ThreadId {
|
||||
@@ -578,9 +602,38 @@ impl Session {
|
||||
otel.name = "session_init.auth_mcp",
|
||||
));
|
||||
|
||||
let plugin_and_skill_warmup_fut = warm_plugins_and_skills_for_session_init(
|
||||
Arc::clone(&config),
|
||||
Arc::clone(&environment_manager),
|
||||
Arc::clone(&plugins_manager),
|
||||
Arc::clone(&skills_manager),
|
||||
session_configuration.environments.clone(),
|
||||
)
|
||||
.instrument(info_span!(
|
||||
"session_init.plugin_skill_warmup",
|
||||
otel.name = "session_init.plugin_skill_warmup",
|
||||
));
|
||||
|
||||
// Join all independent futures.
|
||||
let (thread_persistence_result, state_db_ctx, (auth, mcp_servers, auth_statuses)) =
|
||||
tokio::join!(thread_persistence_fut, state_db_fut, auth_and_mcp_fut);
|
||||
let (
|
||||
thread_persistence_result,
|
||||
state_db_ctx,
|
||||
(auth, mcp_servers, auth_statuses),
|
||||
plugin_skill_errors,
|
||||
) = tokio::join!(
|
||||
thread_persistence_fut,
|
||||
state_db_fut,
|
||||
auth_and_mcp_fut,
|
||||
plugin_and_skill_warmup_fut
|
||||
);
|
||||
|
||||
for err in &plugin_skill_errors {
|
||||
error!(
|
||||
"failed to load skill {}: {}",
|
||||
err.path.display(),
|
||||
err.message
|
||||
);
|
||||
}
|
||||
|
||||
let mut live_thread_init =
|
||||
LiveThreadInitGuard::new(thread_persistence_result.map_err(|e| {
|
||||
|
||||
Reference in New Issue
Block a user