mirror of
https://github.com/openai/codex.git
synced 2026-11-13 14:46:14 +00:00
Add batched executor capability discovery (#33852)
## Why Selected capability roots can contribute plugins, MCP servers, connectors, and skills. Discovering each contribution separately requires repeated access to the executor filesystem. ## What changed - Add the `capabilityRoots/discoverV1` exec-server RPC to scan selected roots and materialize recognized plugin manifests, configuration files, skill instructions, and skill metadata in one bounded request. - Add the opt-in `executor_capability_discovery` feature, with a thread-scoped cache and per-step snapshot shared by MCP and skill discovery. - Parse MCP, connector, and skill contributions from the materialized snapshot, including serving cached skill instructions without another filesystem read. ## Testing - Cover discovery limits, manifest precedence, root-local failures, cache reuse, plugin contributions, and parity with the existing environment skill loader. GitOrigin-RevId: f98fd2321cafb58c596db02da1f83c09d8eb375d
This commit is contained in:
1 parent
caa6e554d6
commit
08e30a2e4e
47 files changed
+1957
-47
No files matched your search
@@ -30,6 +30,7 @@ pub(crate) struct SkillsThreadState {
|
||||
config: Mutex<SkillsExtensionConfig>,
|
||||
orchestrator_skills_available: bool,
|
||||
executor_cache: Mutex<Vec<CachedExecutorCatalog>>,
|
||||
executor_discovery_cache: Mutex<Option<CachedExecutorDiscoveryCatalog>>,
|
||||
orchestrator_cache: Mutex<Option<Arc<OrchestratorGenerationCache>>>,
|
||||
shadow_selection_turn: Mutex<Option<ShadowSelectionTurn>>,
|
||||
}
|
||||
@@ -40,6 +41,7 @@ impl SkillsThreadState {
|
||||
config: Mutex::new(config),
|
||||
orchestrator_skills_available,
|
||||
executor_cache: Mutex::new(Vec::new()),
|
||||
executor_discovery_cache: Mutex::new(None),
|
||||
orchestrator_cache: Mutex::new(None),
|
||||
shadow_selection_turn: Mutex::new(None),
|
||||
}
|
||||
@@ -107,6 +109,11 @@ impl SkillsThreadState {
|
||||
providers: &SkillProviders,
|
||||
mut query: SkillListQuery,
|
||||
) -> SkillCatalog {
|
||||
if query.executor_capability_discovery.is_some() {
|
||||
return self
|
||||
.executor_discovery_catalog_snapshot(providers, query)
|
||||
.await;
|
||||
}
|
||||
let roots = std::mem::take(&mut query.executor_roots);
|
||||
let mut catalog = SkillCatalog::default();
|
||||
for root in roots {
|
||||
@@ -119,6 +126,36 @@ impl SkillsThreadState {
|
||||
catalog
|
||||
}
|
||||
|
||||
async fn executor_discovery_catalog_snapshot(
|
||||
&self,
|
||||
providers: &SkillProviders,
|
||||
query: SkillListQuery,
|
||||
) -> SkillCatalog {
|
||||
if let Some(cached) = self
|
||||
.executor_discovery_cache
|
||||
.lock()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner)
|
||||
.as_ref()
|
||||
.filter(|cached| cached.roots == query.executor_roots)
|
||||
{
|
||||
return cached.catalog.clone();
|
||||
}
|
||||
let roots = query.executor_roots.clone();
|
||||
let discovered = providers.list_executor_for_turn(query).await;
|
||||
let mut cache = self
|
||||
.executor_discovery_cache
|
||||
.lock()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner);
|
||||
if let Some(cached) = cache.as_ref().filter(|cached| cached.roots == roots) {
|
||||
return cached.catalog.clone();
|
||||
}
|
||||
*cache = Some(CachedExecutorDiscoveryCatalog {
|
||||
roots,
|
||||
catalog: discovered.clone(),
|
||||
});
|
||||
discovered
|
||||
}
|
||||
|
||||
pub(crate) async fn orchestrator_catalog_snapshot(
|
||||
&self,
|
||||
mcp_resources: Option<&McpResourceClient>,
|
||||
@@ -236,6 +273,11 @@ struct CachedExecutorCatalog {
|
||||
catalog: SkillCatalog,
|
||||
}
|
||||
|
||||
struct CachedExecutorDiscoveryCatalog {
|
||||
roots: Vec<SelectedCapabilityRoot>,
|
||||
catalog: SkillCatalog,
|
||||
}
|
||||
|
||||
struct OrchestratorGenerationCache {
|
||||
mcp_cache_key: Option<McpResourceClientCacheKey>,
|
||||
catalog: OnceCell<SkillCatalog>,
|
||||
|
||||
Reference in new issue
Block a user