mirror of
https://github.com/openai/codex.git
synced 2026-10-27 18:48:37 +00:00
codex: simplify environment path refs
This commit is contained in:
@@ -1718,6 +1718,7 @@ mod tests {
|
||||
request_id: request_id(),
|
||||
params: v2::SkillsListParams {
|
||||
cwds: Vec::new(),
|
||||
environment_id: None,
|
||||
force_reload: false,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -23,6 +23,10 @@ pub struct SkillsListParams {
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub cwds: Vec<PathBuf>,
|
||||
|
||||
/// Environment whose filesystem should be used for all requested cwd values.
|
||||
#[ts(optional = nullable)]
|
||||
pub environment_id: Option<String>,
|
||||
|
||||
/// When true, bypass the skills cache and re-scan skills from disk.
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
pub force_reload: bool,
|
||||
|
||||
@@ -2607,23 +2607,41 @@ fn skills_list_params_serialization_uses_force_reload() {
|
||||
assert_eq!(
|
||||
serde_json::to_value(SkillsListParams {
|
||||
cwds: Vec::new(),
|
||||
environment_id: None,
|
||||
force_reload: false,
|
||||
})
|
||||
.unwrap(),
|
||||
json!({}),
|
||||
json!({
|
||||
"environmentId": null,
|
||||
}),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
serde_json::to_value(SkillsListParams {
|
||||
cwds: vec![PathBuf::from("/repo")],
|
||||
environment_id: None,
|
||||
force_reload: true,
|
||||
})
|
||||
.unwrap(),
|
||||
json!({
|
||||
"cwds": ["/repo"],
|
||||
"environmentId": null,
|
||||
"forceReload": true,
|
||||
}),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
serde_json::to_value(SkillsListParams {
|
||||
cwds: vec![PathBuf::from("/repo")],
|
||||
environment_id: Some("devbox".to_string()),
|
||||
force_reload: false,
|
||||
})
|
||||
.unwrap(),
|
||||
json!({
|
||||
"cwds": ["/repo"],
|
||||
"environmentId": "devbox",
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -1504,13 +1504,14 @@ Example:
|
||||
$skill-creator Add a new skill for triaging flaky CI and include step-by-step usage.
|
||||
```
|
||||
|
||||
Use `skills/list` to fetch the available skills (optionally scoped by `cwds`, with `forceReload`).
|
||||
Use `skills/list` to fetch the available skills (optionally scoped by `cwds`, `environmentId`, and `forceReload`).
|
||||
`skills/list` might reuse a cached skills result per `cwd`; setting `forceReload` to `true` refreshes the result from disk.
|
||||
The server also emits `skills/changed` notifications when watched local skill files change. Treat this as an invalidation signal and re-run `skills/list` with your current params when needed.
|
||||
Use `skills/extraRoots/set` to replace additional standalone skill roots for the current app-server process. These roots use the same layout as other standalone skill roots: each root contains skill directories, and each skill directory contains `SKILL.md`. Missing roots are accepted and load no skills until they exist. This setting is lost when app-server exits.
|
||||
|
||||
```json
|
||||
{ "method": "skills/list", "id": 25, "params": {
|
||||
"environmentId": "local",
|
||||
"cwds": ["/Users/me/project", "/Users/me/other-project"],
|
||||
"forceReload": true
|
||||
} }
|
||||
|
||||
@@ -499,7 +499,11 @@ impl CatalogRequestProcessor {
|
||||
&self,
|
||||
params: SkillsListParams,
|
||||
) -> Result<SkillsListResponse, JSONRPCErrorError> {
|
||||
let SkillsListParams { cwds, force_reload } = params;
|
||||
let SkillsListParams {
|
||||
cwds,
|
||||
environment_id,
|
||||
force_reload,
|
||||
} = params;
|
||||
let cwds = if cwds.is_empty() {
|
||||
vec![self.config.cwd.to_path_buf()]
|
||||
} else {
|
||||
@@ -514,13 +518,23 @@ impl CatalogRequestProcessor {
|
||||
let skills_manager = self.thread_manager.skills_manager();
|
||||
let plugins_manager = self.thread_manager.plugins_manager();
|
||||
let environment_manager = self.thread_manager.environment_manager();
|
||||
let local_fs = environment_manager
|
||||
.try_local_environment()
|
||||
.map(|environment| environment.get_filesystem());
|
||||
let selected_environment = match environment_id {
|
||||
Some(environment_id) => {
|
||||
let environment = environment_manager
|
||||
.get_environment(&environment_id)
|
||||
.ok_or_else(|| {
|
||||
invalid_request(format!(
|
||||
"unknown skills/list environment id `{environment_id}`"
|
||||
))
|
||||
})?;
|
||||
Some(environment)
|
||||
}
|
||||
None => environment_manager.try_local_environment(),
|
||||
};
|
||||
let mut data = futures::stream::iter(cwds.into_iter().enumerate())
|
||||
.map(|(index, cwd)| {
|
||||
let config = &config;
|
||||
let local_fs = local_fs.clone();
|
||||
let selected_environment = selected_environment.clone();
|
||||
let plugins_manager = &plugins_manager;
|
||||
let skills_manager = &skills_manager;
|
||||
async move {
|
||||
@@ -541,14 +555,9 @@ impl CatalogRequestProcessor {
|
||||
);
|
||||
}
|
||||
};
|
||||
let local_path_ref = local_fs.clone().map(|file_system| {
|
||||
codex_core::skills::EnvironmentPathRef::new(
|
||||
codex_exec_server::LOCAL_ENVIRONMENT_ID.to_string(),
|
||||
file_system,
|
||||
cwd_abs.clone(),
|
||||
)
|
||||
});
|
||||
let Some(path_ref) = local_path_ref else {
|
||||
let Some(environment) = selected_environment.as_ref() else {
|
||||
// Legacy callers without `environmentId` remain local-only; if local is
|
||||
// unavailable, do not fabricate an unbound skill path.
|
||||
return (
|
||||
index,
|
||||
codex_app_server_protocol::SkillsListEntry {
|
||||
@@ -558,6 +567,10 @@ impl CatalogRequestProcessor {
|
||||
},
|
||||
);
|
||||
};
|
||||
let path_ref = codex_core::skills::EnvironmentPathRef::new(
|
||||
environment.get_filesystem(),
|
||||
cwd_abs.clone(),
|
||||
);
|
||||
let effective_skill_roots = if workspace_codex_plugins_enabled {
|
||||
let plugins_input = config.plugins_config_input();
|
||||
plugins_manager
|
||||
|
||||
@@ -101,11 +101,8 @@ impl SkillsWatcher {
|
||||
return WatchRegistration::default();
|
||||
}
|
||||
|
||||
let root_path_ref = EnvironmentPathRef::new(
|
||||
environment_selection.environment_id.clone(),
|
||||
environment.get_filesystem(),
|
||||
config.cwd.clone(),
|
||||
);
|
||||
let root_path_ref =
|
||||
EnvironmentPathRef::new(environment.get_filesystem(), config.cwd.clone());
|
||||
let plugins_input = config.plugins_config_input();
|
||||
let plugins_manager = thread_manager.plugins_manager();
|
||||
let plugin_outcome = plugins_manager.plugins_for_config(&plugins_input).await;
|
||||
|
||||
@@ -20,6 +20,7 @@ use codex_app_server_protocol::SkillsListResponse;
|
||||
use codex_app_server_protocol::ThreadStartParams;
|
||||
use codex_config::types::AuthCredentialsStoreMode;
|
||||
use codex_exec_server::CODEX_EXEC_SERVER_URL_ENV_VAR;
|
||||
use codex_exec_server::LOCAL_ENVIRONMENT_ID;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use pretty_assertions::assert_eq;
|
||||
use tempfile::TempDir;
|
||||
@@ -248,6 +249,7 @@ async fn skills_list_loads_remote_installed_plugin_skills_from_cache() -> Result
|
||||
let stale_skills_list_request_id = mcp
|
||||
.send_skills_list_request(SkillsListParams {
|
||||
cwds: vec![cwd.path().to_path_buf()],
|
||||
environment_id: None,
|
||||
force_reload: true,
|
||||
})
|
||||
.await?;
|
||||
@@ -298,6 +300,7 @@ async fn skills_list_loads_remote_installed_plugin_skills_from_cache() -> Result
|
||||
let skills_list_request_id = mcp
|
||||
.send_skills_list_request(SkillsListParams {
|
||||
cwds: vec![cwd.path().to_path_buf()],
|
||||
environment_id: None,
|
||||
force_reload: false,
|
||||
})
|
||||
.await?;
|
||||
@@ -372,6 +375,7 @@ async fn skills_list_excludes_plugin_skills_when_workspace_codex_plugins_disable
|
||||
let request_id = mcp
|
||||
.send_skills_list_request(SkillsListParams {
|
||||
cwds: vec![repo_root.path().to_path_buf()],
|
||||
environment_id: None,
|
||||
force_reload: true,
|
||||
})
|
||||
.await?;
|
||||
@@ -422,6 +426,7 @@ async fn skills_list_skips_cwd_roots_when_environment_disabled() -> Result<()> {
|
||||
let request_id = mcp
|
||||
.send_skills_list_request(SkillsListParams {
|
||||
cwds: vec![cwd.path().to_path_buf()],
|
||||
environment_id: None,
|
||||
force_reload: true,
|
||||
})
|
||||
.await?;
|
||||
@@ -462,6 +467,7 @@ async fn skills_list_accepts_relative_cwds() -> Result<()> {
|
||||
let request_id = mcp
|
||||
.send_skills_list_request(SkillsListParams {
|
||||
cwds: vec![relative_cwd.clone()],
|
||||
environment_id: Some(LOCAL_ENVIRONMENT_ID.to_string()),
|
||||
force_reload: true,
|
||||
})
|
||||
.await?;
|
||||
@@ -493,6 +499,7 @@ async fn skills_list_preserves_requested_cwd_order() -> Result<()> {
|
||||
first_cwd.path().to_path_buf(),
|
||||
second_cwd.path().to_path_buf(),
|
||||
],
|
||||
environment_id: None,
|
||||
force_reload: true,
|
||||
})
|
||||
.await?;
|
||||
@@ -527,6 +534,7 @@ async fn skills_list_uses_cached_result_until_force_reload() -> Result<()> {
|
||||
let first_request_id = mcp
|
||||
.send_skills_list_request(SkillsListParams {
|
||||
cwds: vec![cwd.path().to_path_buf()],
|
||||
environment_id: None,
|
||||
force_reload: false,
|
||||
})
|
||||
.await?;
|
||||
@@ -554,6 +562,7 @@ async fn skills_list_uses_cached_result_until_force_reload() -> Result<()> {
|
||||
let second_request_id = mcp
|
||||
.send_skills_list_request(SkillsListParams {
|
||||
cwds: vec![cwd.path().to_path_buf()],
|
||||
environment_id: None,
|
||||
force_reload: false,
|
||||
})
|
||||
.await?;
|
||||
@@ -574,6 +583,7 @@ async fn skills_list_uses_cached_result_until_force_reload() -> Result<()> {
|
||||
let third_request_id = mcp
|
||||
.send_skills_list_request(SkillsListParams {
|
||||
cwds: vec![cwd.path().to_path_buf()],
|
||||
environment_id: None,
|
||||
force_reload: true,
|
||||
})
|
||||
.await?;
|
||||
@@ -755,6 +765,7 @@ async fn skills_changed_notification_is_emitted_after_skill_change() -> Result<(
|
||||
let initial_skills_request_id = mcp
|
||||
.send_skills_list_request(SkillsListParams {
|
||||
cwds: vec![codex_home.path().to_path_buf()],
|
||||
environment_id: None,
|
||||
force_reload: true,
|
||||
})
|
||||
.await?;
|
||||
@@ -828,6 +839,7 @@ async fn skills_changed_notification_is_emitted_after_skill_change() -> Result<(
|
||||
let updated_skills_request_id = mcp
|
||||
.send_skills_list_request(SkillsListParams {
|
||||
cwds: vec![codex_home.path().to_path_buf()],
|
||||
environment_id: None,
|
||||
force_reload: false,
|
||||
})
|
||||
.await?;
|
||||
|
||||
@@ -1060,11 +1060,7 @@ pub(crate) async fn skill_roots_from_layer_stack(
|
||||
cwd: &AbsolutePathBuf,
|
||||
home_dir: Option<&AbsolutePathBuf>,
|
||||
) -> Vec<SkillRoot> {
|
||||
let path_ref = EnvironmentPathRef::new(
|
||||
codex_exec_server::LOCAL_ENVIRONMENT_ID.to_string(),
|
||||
fs,
|
||||
cwd.clone(),
|
||||
);
|
||||
let path_ref = EnvironmentPathRef::new(fs, cwd.clone());
|
||||
skill_roots_with_home_dir(&path_ref, config_layer_stack, home_dir, Vec::new(), Vec::new())
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ use codex_config::ConfigLayerEntry;
|
||||
use codex_config::ConfigLayerStack;
|
||||
use codex_config::ConfigRequirements;
|
||||
use codex_config::ConfigRequirementsToml;
|
||||
use codex_exec_server::LOCAL_ENVIRONMENT_ID;
|
||||
use codex_exec_server::LOCAL_FS;
|
||||
use codex_protocol::protocol::Product;
|
||||
use codex_protocol::protocol::SkillScope;
|
||||
@@ -145,17 +144,13 @@ fn normalized(path: &Path) -> AbsolutePathBuf {
|
||||
.abs()
|
||||
}
|
||||
|
||||
fn env_path(path: AbsolutePathBuf) -> EnvironmentPathRef {
|
||||
EnvironmentPathRef::new(
|
||||
LOCAL_ENVIRONMENT_ID.to_string(),
|
||||
Arc::clone(&LOCAL_FS),
|
||||
path,
|
||||
)
|
||||
fn local_env_path(path: AbsolutePathBuf) -> EnvironmentPathRef {
|
||||
EnvironmentPathRef::local(path)
|
||||
}
|
||||
|
||||
fn local_skill_root(path: AbsolutePathBuf, scope: SkillScope) -> SkillRoot {
|
||||
SkillRoot {
|
||||
path: env_path(path),
|
||||
path: local_env_path(path),
|
||||
scope,
|
||||
plugin_id: None,
|
||||
plugin_root: None,
|
||||
@@ -864,10 +859,10 @@ interface:
|
||||
|
||||
let plugin_root_abs = plugin_root.abs();
|
||||
let outcome = load_skills_from_roots([SkillRoot {
|
||||
path: env_path(plugin_root.join("skills").abs()),
|
||||
path: local_env_path(plugin_root.join("skills").abs()),
|
||||
scope: SkillScope::User,
|
||||
plugin_id: Some("twilio-developer-kit@test".to_string()),
|
||||
plugin_root: Some(env_path(plugin_root_abs.clone())),
|
||||
plugin_root: Some(local_env_path(plugin_root_abs.clone())),
|
||||
}])
|
||||
.await;
|
||||
|
||||
@@ -920,10 +915,10 @@ interface:
|
||||
);
|
||||
|
||||
let outcome = load_skills_from_roots([SkillRoot {
|
||||
path: env_path(plugin_root.join("skills").abs()),
|
||||
path: local_env_path(plugin_root.join("skills").abs()),
|
||||
scope: SkillScope::User,
|
||||
plugin_id: Some("twilio-developer-kit@test".to_string()),
|
||||
plugin_root: Some(env_path(plugin_root.abs())),
|
||||
plugin_root: Some(local_env_path(plugin_root.abs())),
|
||||
}])
|
||||
.await;
|
||||
|
||||
@@ -1271,10 +1266,10 @@ async fn namespaces_plugin_skills_using_plugin_name() {
|
||||
.unwrap();
|
||||
|
||||
let outcome = load_skills_from_roots([SkillRoot {
|
||||
path: env_path(plugin_root.join("skills").abs()),
|
||||
path: local_env_path(plugin_root.join("skills").abs()),
|
||||
scope: SkillScope::User,
|
||||
plugin_id: Some("sample@test".to_string()),
|
||||
plugin_root: Some(env_path(plugin_root.abs())),
|
||||
plugin_root: Some(local_env_path(plugin_root.abs())),
|
||||
}])
|
||||
.await;
|
||||
|
||||
@@ -1593,13 +1588,13 @@ async fn deduplicates_by_path_preferring_first_root() {
|
||||
|
||||
let outcome = load_skills_from_roots([
|
||||
SkillRoot {
|
||||
path: env_path(root.path().abs()),
|
||||
path: local_env_path(root.path().abs()),
|
||||
scope: SkillScope::Repo,
|
||||
plugin_id: None,
|
||||
plugin_root: None,
|
||||
},
|
||||
SkillRoot {
|
||||
path: env_path(root.path().abs()),
|
||||
path: local_env_path(root.path().abs()),
|
||||
scope: SkillScope::User,
|
||||
plugin_id: None,
|
||||
plugin_root: None,
|
||||
@@ -1891,7 +1886,7 @@ async fn skill_roots_include_admin_with_lowest_priority() {
|
||||
let codex_home = tempfile::tempdir().expect("tempdir");
|
||||
let cfg = make_config(&codex_home).await;
|
||||
|
||||
let cwd = env_path(cfg.cwd.clone());
|
||||
let cwd = local_env_path(cfg.cwd.clone());
|
||||
let scopes: Vec<SkillScope> =
|
||||
super::skill_roots(&cwd, &cfg.config_layer_stack, Vec::new(), Vec::new())
|
||||
.await
|
||||
|
||||
@@ -7,8 +7,6 @@ use codex_config::CONFIG_TOML_FILE;
|
||||
use codex_config::ConfigLayerEntry;
|
||||
use codex_config::ConfigLayerStack;
|
||||
use codex_config::ConfigRequirementsToml;
|
||||
use codex_exec_server::LOCAL_ENVIRONMENT_ID;
|
||||
use codex_exec_server::LOCAL_FS;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use codex_utils_absolute_path::test_support::PathBufExt;
|
||||
use codex_utils_absolute_path::test_support::PathExt;
|
||||
@@ -18,7 +16,6 @@ use std::collections::HashSet;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use tempfile::TempDir;
|
||||
|
||||
fn write_user_skill(codex_home: &TempDir, dir: &str, name: &str, description: &str) {
|
||||
@@ -89,11 +86,7 @@ fn test_skill(name: &str, path: PathBuf) -> SkillMetadata {
|
||||
}
|
||||
|
||||
fn skill_root_path_ref(path: AbsolutePathBuf) -> EnvironmentPathRef {
|
||||
EnvironmentPathRef::new(
|
||||
LOCAL_ENVIRONMENT_ID.to_string(),
|
||||
Arc::clone(&LOCAL_FS),
|
||||
path,
|
||||
)
|
||||
EnvironmentPathRef::local(path)
|
||||
}
|
||||
|
||||
fn local_skills_input(
|
||||
|
||||
@@ -421,8 +421,7 @@ enabled = false
|
||||
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 cwd = crate::environment_path(
|
||||
codex_exec_server::LOCAL_ENVIRONMENT_ID.to_string(),
|
||||
let cwd = crate::skills::EnvironmentPathRef::new(
|
||||
Arc::clone(&codex_exec_server::LOCAL_FS),
|
||||
config.cwd.clone(),
|
||||
);
|
||||
|
||||
@@ -92,7 +92,6 @@ pub(crate) use skills::build_skill_injections;
|
||||
pub(crate) use skills::build_skill_name_counts;
|
||||
pub(crate) use skills::collect_explicit_skill_mentions;
|
||||
pub(crate) use skills::default_skill_metadata_budget;
|
||||
pub(crate) use skills::environment_path_ref;
|
||||
pub(crate) use skills::injection;
|
||||
pub(crate) use skills::manager;
|
||||
pub(crate) use skills::maybe_emit_implicit_skill_invocation;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use super::input_queue::InputQueue;
|
||||
use super::*;
|
||||
use crate::config::ConstraintError;
|
||||
use crate::environment_path;
|
||||
use crate::goals::GoalRuntimeState;
|
||||
use crate::skills::SkillError;
|
||||
use crate::state::ActiveTurn;
|
||||
@@ -457,8 +456,7 @@ async fn warm_plugins_and_skills_for_session_init(
|
||||
.as_ref()
|
||||
.and_then(crate::environment_selection::ResolvedTurnEnvironments::primary)
|
||||
.map(|environment| {
|
||||
environment_path(
|
||||
environment.environment_id.clone(),
|
||||
crate::skills::EnvironmentPathRef::new(
|
||||
environment.environment.get_filesystem(),
|
||||
environment.cwd.clone(),
|
||||
)
|
||||
|
||||
@@ -4129,8 +4129,7 @@ async fn new_default_turn_uses_config_aware_skills_for_role_overrides() {
|
||||
.skills_for_cwd(
|
||||
&crate::skills_load_input_from_config(
|
||||
&parent_config,
|
||||
crate::environment_path(
|
||||
codex_exec_server::LOCAL_ENVIRONMENT_ID.to_string(),
|
||||
crate::skills::EnvironmentPathRef::new(
|
||||
Arc::clone(&skill_fs),
|
||||
parent_config.cwd.clone(),
|
||||
),
|
||||
@@ -4699,8 +4698,7 @@ pub(crate) async fn make_session_and_context() -> (Session, TurnContext) {
|
||||
.plugins_for_config(&per_turn_config.plugins_config_input())
|
||||
.await;
|
||||
let effective_skill_roots = plugin_outcome.effective_plugin_skill_roots();
|
||||
let cwd = crate::environment_path(
|
||||
codex_exec_server::LOCAL_ENVIRONMENT_ID.to_string(),
|
||||
let cwd = crate::skills::EnvironmentPathRef::new(
|
||||
environment.get_filesystem(),
|
||||
per_turn_config.cwd.clone(),
|
||||
);
|
||||
@@ -6546,8 +6544,7 @@ where
|
||||
.plugins_for_config(&per_turn_config.plugins_config_input())
|
||||
.await;
|
||||
let effective_skill_roots = plugin_outcome.effective_plugin_skill_roots();
|
||||
let cwd = crate::environment_path(
|
||||
codex_exec_server::LOCAL_ENVIRONMENT_ID.to_string(),
|
||||
let cwd = crate::skills::EnvironmentPathRef::new(
|
||||
environment.get_filesystem(),
|
||||
per_turn_config.cwd.clone(),
|
||||
);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use super::*;
|
||||
use crate::SkillLoadOutcome;
|
||||
use crate::config::GhostSnapshotConfig;
|
||||
use crate::environment_path;
|
||||
use crate::environment_selection::ResolvedTurnEnvironments;
|
||||
use codex_model_provider::SharedModelProvider;
|
||||
use codex_model_provider::create_model_provider;
|
||||
@@ -680,8 +679,7 @@ impl Session {
|
||||
)
|
||||
.await;
|
||||
let path_ref = primary_turn_environment.map(|turn_environment| {
|
||||
environment_path(
|
||||
turn_environment.environment_id.clone(),
|
||||
crate::skills::EnvironmentPathRef::new(
|
||||
turn_environment.environment.get_filesystem(),
|
||||
turn_environment.cwd.clone(),
|
||||
)
|
||||
|
||||
@@ -5,11 +5,9 @@ use codex_analytics::InvocationType;
|
||||
use codex_analytics::SkillInvocation;
|
||||
use codex_analytics::build_track_events_context;
|
||||
pub use codex_exec_server::EnvironmentPathRef;
|
||||
use codex_exec_server::ExecutorFileSystem;
|
||||
use codex_protocol::protocol::SkillScope;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use codex_utils_plugins::PluginSkillRoot;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub use codex_core_skills::SkillError;
|
||||
pub use codex_core_skills::SkillLoadOutcome;
|
||||
@@ -49,14 +47,6 @@ pub(crate) fn skills_load_input_from_config(
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn environment_path(
|
||||
environment_id: String,
|
||||
file_system: Arc<dyn ExecutorFileSystem>,
|
||||
path: AbsolutePathBuf,
|
||||
) -> EnvironmentPathRef {
|
||||
EnvironmentPathRef::new(environment_id, file_system, path)
|
||||
}
|
||||
|
||||
pub(crate) async fn maybe_emit_implicit_skill_invocation(
|
||||
sess: &Session,
|
||||
turn_context: &TurnContext,
|
||||
|
||||
@@ -10,47 +10,29 @@ use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use crate::ExecutorFileSystem;
|
||||
use crate::FileMetadata;
|
||||
use crate::FileSystemSandboxContext;
|
||||
use crate::LOCAL_ENVIRONMENT_ID;
|
||||
use crate::LOCAL_FS;
|
||||
use crate::ReadDirectoryEntry;
|
||||
|
||||
/// Binds an absolute path to the executor filesystem and environment that owns it.
|
||||
/// Binds an absolute path to the executor filesystem that owns it.
|
||||
#[derive(Clone)]
|
||||
pub struct EnvironmentPathRef {
|
||||
environment_id: String,
|
||||
file_system: Arc<dyn ExecutorFileSystem>,
|
||||
path: AbsolutePathBuf,
|
||||
}
|
||||
|
||||
impl EnvironmentPathRef {
|
||||
pub fn new(
|
||||
environment_id: String,
|
||||
file_system: Arc<dyn ExecutorFileSystem>,
|
||||
path: AbsolutePathBuf,
|
||||
) -> Self {
|
||||
Self {
|
||||
environment_id,
|
||||
file_system,
|
||||
path,
|
||||
}
|
||||
pub fn new(file_system: Arc<dyn ExecutorFileSystem>, path: AbsolutePathBuf) -> Self {
|
||||
Self { file_system, path }
|
||||
}
|
||||
|
||||
pub fn local(path: AbsolutePathBuf) -> Self {
|
||||
Self::new(
|
||||
LOCAL_ENVIRONMENT_ID.to_string(),
|
||||
Arc::clone(&LOCAL_FS),
|
||||
path,
|
||||
)
|
||||
Self::new(Arc::clone(&LOCAL_FS), path)
|
||||
}
|
||||
|
||||
pub fn path(&self) -> &AbsolutePathBuf {
|
||||
&self.path
|
||||
}
|
||||
|
||||
pub fn environment_id(&self) -> &str {
|
||||
&self.environment_id
|
||||
}
|
||||
|
||||
pub fn file_system(&self) -> Arc<dyn ExecutorFileSystem> {
|
||||
Arc::clone(&self.file_system)
|
||||
}
|
||||
@@ -87,19 +69,13 @@ impl EnvironmentPathRef {
|
||||
}
|
||||
|
||||
pub fn with_path(&self, path: AbsolutePathBuf) -> Self {
|
||||
Self::new(
|
||||
self.environment_id.clone(),
|
||||
Arc::clone(&self.file_system),
|
||||
path,
|
||||
)
|
||||
Self::new(Arc::clone(&self.file_system), path)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for EnvironmentPathRef {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.environment_id == other.environment_id
|
||||
&& Arc::ptr_eq(&self.file_system, &other.file_system)
|
||||
&& self.path == other.path
|
||||
Arc::ptr_eq(&self.file_system, &other.file_system) && self.path == other.path
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +83,6 @@ impl Eq for EnvironmentPathRef {}
|
||||
|
||||
impl Hash for EnvironmentPathRef {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.environment_id.hash(state);
|
||||
(Arc::as_ptr(&self.file_system) as *const () as usize).hash(state);
|
||||
self.path.hash(state);
|
||||
}
|
||||
@@ -116,7 +91,6 @@ impl Hash for EnvironmentPathRef {
|
||||
impl fmt::Debug for EnvironmentPathRef {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("EnvironmentPathRef")
|
||||
.field("environment_id", &self.environment_id)
|
||||
.field("path", &self.path)
|
||||
.finish()
|
||||
}
|
||||
@@ -272,8 +246,7 @@ mod tests {
|
||||
async fn environment_path_ref_forwards_sandbox_to_file_system_methods() {
|
||||
let path = std::env::temp_dir().join("skills/demo").abs();
|
||||
let file_system = Arc::new(RecordingFileSystem::default());
|
||||
let path_ref =
|
||||
EnvironmentPathRef::new("local".to_string(), file_system.clone(), path.clone());
|
||||
let path_ref = EnvironmentPathRef::new(file_system.clone(), path.clone());
|
||||
let sandbox = restricted_sandbox();
|
||||
|
||||
assert_eq!(
|
||||
@@ -330,26 +303,23 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn environment_path_ref_equality_and_hash_include_environment_id_and_file_system_identity() {
|
||||
fn environment_path_ref_equality_and_hash_include_file_system_identity() {
|
||||
let path = std::env::temp_dir().join("skills/demo").abs();
|
||||
let file_system = Arc::new(RecordingFileSystem::default());
|
||||
let same_file_system: Arc<dyn ExecutorFileSystem> = file_system.clone();
|
||||
let different_file_system: Arc<dyn ExecutorFileSystem> =
|
||||
Arc::new(RecordingFileSystem::default());
|
||||
|
||||
let left =
|
||||
EnvironmentPathRef::new("local".to_string(), same_file_system.clone(), path.clone());
|
||||
let same = EnvironmentPathRef::new("local".to_string(), same_file_system, path.clone());
|
||||
let different_env =
|
||||
EnvironmentPathRef::new("remote".to_string(), file_system.clone(), path.clone());
|
||||
let different_fs =
|
||||
EnvironmentPathRef::new("local".to_string(), different_file_system, path);
|
||||
let left = EnvironmentPathRef::new(same_file_system.clone(), path.clone());
|
||||
let same = EnvironmentPathRef::new(same_file_system, path.clone());
|
||||
let different_path = EnvironmentPathRef::new(file_system.clone(), path.parent().unwrap());
|
||||
let different_fs = EnvironmentPathRef::new(different_file_system, path);
|
||||
|
||||
assert_eq!(left, same);
|
||||
assert_ne!(left, different_env);
|
||||
assert_ne!(left, different_path);
|
||||
assert_ne!(left, different_fs);
|
||||
|
||||
let set = HashSet::from([left, same, different_env, different_fs]);
|
||||
let set = HashSet::from([left, same, different_path, different_fs]);
|
||||
assert_eq!(set.len(), 3);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -674,6 +674,7 @@ pub(super) async fn fetch_skills_list(
|
||||
request_id,
|
||||
params: SkillsListParams {
|
||||
cwds: vec![cwd],
|
||||
environment_id: None,
|
||||
force_reload: true,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -621,6 +621,7 @@ impl App {
|
||||
app_server
|
||||
.skills_list(codex_app_server_protocol::SkillsListParams {
|
||||
cwds: cwds.clone(),
|
||||
environment_id: None,
|
||||
force_reload: *force_reload,
|
||||
})
|
||||
.await,
|
||||
|
||||
Reference in New Issue
Block a user