mirror of
https://github.com/openai/codex.git
synced 2026-10-28 18:58:46 +00:00
Acquire and cache opt-in executor capability inventories via V2 (#53736)
## What changed - Add the disabled-by-default `executor_capability_discovery_v2` feature to acquire `capabilities/discoverV2` inventories from supporting remote executors using each selected environment's working directory and sandbox. - Share snapshots with MCP and world-state contributors and skill providers without activating discovered plugins or publishing discovered skills to the model. - Cache inventories by environment instance, executor session, working directory, and sandbox. Coalesce concurrent requests, refresh the cache at turn start, retry transient failures, and refresh MCP projections after recovery. - Resolve the system skills root in the executor and pass it explicitly to capability location discovery. ## Testing Add coverage for feature gating, unsupported executors, inert inventories, cache reuse and eviction, turn refreshes, failure recovery, executor replacement, and system skill locations. GitOrigin-RevId: 1bdca28fa7f17622b27e2713ab3dcc0c13426889
This commit is contained in:
committed by
copyberry
parent
4d82d36ccf
commit
cf0ed4c600
@@ -8,7 +8,6 @@ use std::io;
|
||||
|
||||
use crate::LocalFileSystem;
|
||||
use crate::protocol::FsOpenMode;
|
||||
use codex_config::loader::system_config_toml_file;
|
||||
use codex_file_system::ExecutorFileSystem;
|
||||
use codex_file_system::WalkEntryKind;
|
||||
use codex_file_system::WalkOptions;
|
||||
@@ -24,11 +23,12 @@ use codex_core_plugin_common::installed::parse_remote_plugin_id;
|
||||
use codex_core_plugin_common::plugin_id::PluginId;
|
||||
use tokio::io::AsyncReadExt;
|
||||
|
||||
/// Home paths are supplied by the executor, not read from the sandbox helper's sanitized env.
|
||||
/// Fixed paths are supplied by the executor, not read from the sandbox helper's sanitized env.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub(crate) struct CapabilityLocationRequest {
|
||||
pub codex_home: PathUri,
|
||||
pub user_home: Option<PathUri>,
|
||||
pub system_skills_root: Option<PathUri>,
|
||||
}
|
||||
|
||||
const MAX_LOCATIONS: usize = 512;
|
||||
@@ -73,8 +73,8 @@ pub(crate) async fn prewarm_locations(
|
||||
if let Some(home) = user_home {
|
||||
skill_roots.push(home.join(AGENTS_SKILLS_SUFFIX));
|
||||
}
|
||||
if let Some(system_root) = system_config_toml_file()?.parent() {
|
||||
skill_roots.push(system_root.join("skills"));
|
||||
if let Some(system_root) = &request.system_skills_root {
|
||||
skill_roots.push(system_root.to_abs_path()?);
|
||||
}
|
||||
CandidateCapabilityLocations::resolve(
|
||||
fs,
|
||||
@@ -211,4 +211,4 @@ async fn read_remote_plugin_id(path: &std::path::Path) -> io::Result<Option<Stri
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "tests/capability_locations_tests.rs"]
|
||||
pub(super) mod tests;
|
||||
pub(crate) mod tests;
|
||||
|
||||
@@ -9,6 +9,7 @@ use crate::discover_v2::capability_discoveries::load_capability_discoveries;
|
||||
use crate::discover_v2::capability_locations::CapabilityLocationRequest;
|
||||
use crate::discover_v2::capability_locations::CapabilityLocations;
|
||||
use crate::discover_v2::capability_locations::prewarm_locations;
|
||||
use codex_config::loader::system_config_toml_file;
|
||||
use codex_file_watcher::WatchRegistration;
|
||||
use codex_utils_path_uri::PathUri;
|
||||
use std::io;
|
||||
@@ -55,7 +56,7 @@ impl CapabilityManager {
|
||||
})
|
||||
}
|
||||
|
||||
/// Resolves home paths on first initialization and reuses the prewarmed locations.
|
||||
/// Resolves fixed paths on first initialization and reuses the prewarmed locations.
|
||||
pub(crate) async fn prewarm_locations(
|
||||
self: &Arc<Self>,
|
||||
) -> io::Result<&(CapabilityLocationRequest, CapabilityLocations)> {
|
||||
@@ -66,6 +67,9 @@ impl CapabilityManager {
|
||||
codex_home: PathUri::from_abs_path(&codex_utils_home_dir::find_codex_home()?),
|
||||
user_home: dirs::home_dir()
|
||||
.and_then(|home| PathUri::from_host_native_path(home).ok()),
|
||||
system_skills_root: system_config_toml_file()?
|
||||
.parent()
|
||||
.map(|root| PathUri::from_abs_path(&root.join("skills"))),
|
||||
};
|
||||
let locations = prewarm_locations(&self.file_system, &request).await?;
|
||||
Ok::<_, io::Error>((request, locations))
|
||||
|
||||
@@ -14,12 +14,15 @@ use crate::LocalFileSystem;
|
||||
pub(crate) const MANIFEST: &str = r#"{"name":"demo","version":"1.10.0"}"#;
|
||||
|
||||
pub(crate) fn request(root: &Path) -> anyhow::Result<CapabilityLocationRequest> {
|
||||
for path in ["codex", "home", "project"] {
|
||||
for path in ["codex", "home", "project", "etc/codex"] {
|
||||
std::fs::create_dir_all(root.join(path))?;
|
||||
}
|
||||
Ok(CapabilityLocationRequest {
|
||||
codex_home: PathUri::from_host_native_path(root.join("codex"))?,
|
||||
user_home: Some(PathUri::from_host_native_path(root.join("home"))?),
|
||||
system_skills_root: Some(PathUri::from_host_native_path(
|
||||
root.join("etc/codex/skills"),
|
||||
)?),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -42,6 +45,7 @@ async fn prewarming_resolves_global_locations_without_cwd_or_config() -> anyhow:
|
||||
for root in [
|
||||
"codex/skills",
|
||||
"home/.agents/skills",
|
||||
"etc/codex/skills",
|
||||
"project/.agents/skills",
|
||||
] {
|
||||
write(temp.path(), &format!("{root}/demo/SKILL.md"), "unparsed")?;
|
||||
@@ -69,7 +73,7 @@ async fn prewarming_resolves_global_locations_without_cwd_or_config() -> anyhow:
|
||||
remote_plugin_id: Some("plugins~demo".to_string()),
|
||||
}),
|
||||
}];
|
||||
for root in ["codex/skills", "home/.agents/skills"] {
|
||||
for root in ["codex/skills", "home/.agents/skills", "etc/codex/skills"] {
|
||||
expected.push(CapabilityLocation {
|
||||
root: PathUri::from_host_native_path(temp.path().join(root))?,
|
||||
plugin: None,
|
||||
|
||||
Reference in New Issue
Block a user