mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
core: load AGENTS.md from foreign environments (#28958)
## Why Make it possible to load AGENTS.md from remote exec-servers whose OS is different than app-server. ## What - keep `AGENTS.md` discovery and provenance as `PathUri`, with root-aware parent and ancestor traversal - expose lifecycle instruction sources as legacy app-server path strings in events while retaining `PathUri` internally - preserve and test mixed POSIX and Windows paths in model context and TUI status output - cover remote Windows loading end to end by seeding the Wine prefix through host filesystem APIs - fix bug in `PathUri`'s parent() implementation that would erase Windows drive letters
This commit is contained in:
@@ -53,16 +53,11 @@ pub(crate) async fn load_project_instructions(
|
||||
let mut loaded = LoadedAgentsMd::from_user_instructions(user_instructions);
|
||||
for turn_environment in &environments.turn_environments {
|
||||
let filesystem = turn_environment.environment.get_filesystem();
|
||||
// TODO(anp): Migrate AGENTS.md discovery to PathUri so instructions can be loaded from
|
||||
// environment-native foreign working directories.
|
||||
let Ok(cwd) = turn_environment.cwd().to_abs_path() else {
|
||||
continue;
|
||||
};
|
||||
match read_agents_md(
|
||||
config,
|
||||
filesystem.as_ref(),
|
||||
&turn_environment.environment_id,
|
||||
&cwd,
|
||||
turn_environment.cwd(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
@@ -97,7 +92,7 @@ async fn read_agents_md(
|
||||
config: &Config,
|
||||
fs: &dyn ExecutorFileSystem,
|
||||
environment_id: &str,
|
||||
cwd: &AbsolutePathBuf,
|
||||
cwd: &PathUri,
|
||||
) -> io::Result<Option<LoadedAgentsMd>> {
|
||||
let max_total = config.project_doc_max_bytes;
|
||||
|
||||
@@ -118,15 +113,14 @@ async fn read_agents_md(
|
||||
break;
|
||||
}
|
||||
|
||||
let path_uri = PathUri::from_abs_path(&p);
|
||||
match fs.get_metadata(&path_uri, /*sandbox*/ None).await {
|
||||
match fs.get_metadata(&p, /*sandbox*/ None).await {
|
||||
Ok(metadata) if !metadata.is_file => continue,
|
||||
Ok(_) => {}
|
||||
Err(err) if err.kind() == io::ErrorKind::NotFound => continue,
|
||||
Err(err) => return Err(err),
|
||||
}
|
||||
|
||||
let mut data = match fs.read_file(&path_uri, /*sandbox*/ None).await {
|
||||
let mut data = match fs.read_file(&p, /*sandbox*/ None).await {
|
||||
Ok(data) => data,
|
||||
Err(err) if err.kind() == io::ErrorKind::NotFound => continue,
|
||||
Err(err) => return Err(err),
|
||||
@@ -139,7 +133,7 @@ async fn read_agents_md(
|
||||
if size > remaining {
|
||||
tracing::warn!(
|
||||
"Project doc `{}` exceeds remaining budget ({} bytes) - truncating.",
|
||||
p.display(),
|
||||
p.inferred_native_path_string(),
|
||||
remaining,
|
||||
);
|
||||
}
|
||||
@@ -169,9 +163,9 @@ async fn read_agents_md(
|
||||
/// directory, inclusive. Symlinks are allowed.
|
||||
async fn agents_md_paths(
|
||||
config: &Config,
|
||||
cwd: &AbsolutePathBuf,
|
||||
cwd: &PathUri,
|
||||
fs: &dyn ExecutorFileSystem,
|
||||
) -> io::Result<Vec<AbsolutePathBuf>> {
|
||||
) -> io::Result<Vec<PathUri>> {
|
||||
let dir = cwd.clone();
|
||||
|
||||
let mut merged = TomlValue::Table(toml::map::Map::new());
|
||||
@@ -194,18 +188,18 @@ async fn agents_md_paths(
|
||||
};
|
||||
let mut project_root = None;
|
||||
if !project_root_markers.is_empty() {
|
||||
for ancestor in dir.ancestors() {
|
||||
for current in dir.ancestors() {
|
||||
for marker in &project_root_markers {
|
||||
let marker_path = ancestor.join(marker);
|
||||
let marker_path_uri = PathUri::from_abs_path(&marker_path);
|
||||
let marker_exists = match fs.get_metadata(&marker_path_uri, /*sandbox*/ None).await
|
||||
{
|
||||
let marker_path = current
|
||||
.join(marker)
|
||||
.map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err))?;
|
||||
let marker_exists = match fs.get_metadata(&marker_path, /*sandbox*/ None).await {
|
||||
Ok(_) => true,
|
||||
Err(err) if err.kind() == io::ErrorKind::NotFound => false,
|
||||
Err(err) => return Err(err),
|
||||
};
|
||||
if marker_exists {
|
||||
project_root = Some(ancestor.clone());
|
||||
project_root = Some(current.clone());
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -215,7 +209,7 @@ async fn agents_md_paths(
|
||||
}
|
||||
}
|
||||
|
||||
let search_dirs: Vec<AbsolutePathBuf> = if let Some(root) = project_root {
|
||||
let search_dirs: Vec<PathUri> = if let Some(root) = project_root {
|
||||
let mut dirs = Vec::new();
|
||||
let mut cursor = dir.clone();
|
||||
loop {
|
||||
@@ -234,13 +228,14 @@ async fn agents_md_paths(
|
||||
vec![dir]
|
||||
};
|
||||
|
||||
let mut found: Vec<AbsolutePathBuf> = Vec::new();
|
||||
let mut found: Vec<PathUri> = Vec::new();
|
||||
let candidate_filenames = candidate_filenames(config);
|
||||
for d in search_dirs {
|
||||
for name in &candidate_filenames {
|
||||
let candidate = d.join(name);
|
||||
let candidate_uri = PathUri::from_abs_path(&candidate);
|
||||
match fs.get_metadata(&candidate_uri, /*sandbox*/ None).await {
|
||||
let candidate = d
|
||||
.join(name)
|
||||
.map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err))?;
|
||||
match fs.get_metadata(&candidate, /*sandbox*/ None).await {
|
||||
Ok(md) if md.is_file => {
|
||||
found.push(candidate);
|
||||
break;
|
||||
@@ -371,7 +366,7 @@ impl LoadedAgentsMd {
|
||||
fn environment_labeled_text(&self) -> String {
|
||||
let mut output = String::new();
|
||||
let mut has_previous = false;
|
||||
let mut previous_environment: Option<(&str, &AbsolutePathBuf)> = None;
|
||||
let mut previous_environment: Option<(&str, &PathUri)> = None;
|
||||
if let Some(instructions) = &self.user_instructions {
|
||||
output.push_str(&instructions.text);
|
||||
has_previous = true;
|
||||
@@ -394,7 +389,7 @@ impl LoadedAgentsMd {
|
||||
output.push_str(&format!(
|
||||
"for `{}` with root {}\n\n",
|
||||
environment_id,
|
||||
cwd.display()
|
||||
cwd.inferred_native_path_string()
|
||||
));
|
||||
}
|
||||
output.push_str(&entry.contents);
|
||||
@@ -421,7 +416,7 @@ impl LoadedAgentsMd {
|
||||
None
|
||||
} else {
|
||||
self.single_project_cwd()
|
||||
.map(|cwd| cwd.to_string_lossy().into_owned())
|
||||
.map(PathUri::inferred_native_path_string)
|
||||
};
|
||||
ContextUserInstructions {
|
||||
directory,
|
||||
@@ -436,10 +431,10 @@ impl LoadedAgentsMd {
|
||||
}
|
||||
|
||||
/// Returns the AGENTS.md files that supplied instruction entries.
|
||||
pub fn sources(&self) -> impl Iterator<Item = &AbsolutePathBuf> {
|
||||
pub fn sources(&self) -> impl Iterator<Item = PathUri> + '_ {
|
||||
self.user_instructions
|
||||
.iter()
|
||||
.map(|instructions| &instructions.source)
|
||||
.map(|instructions| PathUri::from_abs_path(&instructions.source))
|
||||
.chain(
|
||||
self.entries
|
||||
.iter()
|
||||
@@ -463,7 +458,7 @@ impl LoadedAgentsMd {
|
||||
})
|
||||
}
|
||||
|
||||
fn single_project_cwd(&self) -> Option<&AbsolutePathBuf> {
|
||||
fn single_project_cwd(&self) -> Option<&PathUri> {
|
||||
self.entries
|
||||
.iter()
|
||||
.find_map(|entry| match &entry.provenance {
|
||||
@@ -488,9 +483,9 @@ enum InstructionProvenance {
|
||||
/// Workspace instructions discovered from project AGENTS.md files.
|
||||
Project {
|
||||
/// Exact AGENTS.md file, distinct from the environment's selected cwd.
|
||||
source_path: AbsolutePathBuf,
|
||||
source_path: PathUri,
|
||||
environment_id: String,
|
||||
cwd: AbsolutePathBuf,
|
||||
cwd: PathUri,
|
||||
},
|
||||
|
||||
/// Instructions without a file source, including internally defined guidance.
|
||||
@@ -498,9 +493,9 @@ enum InstructionProvenance {
|
||||
}
|
||||
|
||||
impl InstructionProvenance {
|
||||
fn path(&self) -> Option<&AbsolutePathBuf> {
|
||||
fn path(&self) -> Option<PathUri> {
|
||||
match self {
|
||||
Self::Project { source_path, .. } => Some(source_path),
|
||||
Self::Project { source_path, .. } => Some(source_path.clone()),
|
||||
Self::Internal => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,8 +250,13 @@ async fn load_agents_md(config: &TestConfig) -> Option<LoadedAgentsMd> {
|
||||
.await
|
||||
}
|
||||
|
||||
async fn agents_md_paths(config: &TestConfig) -> std::io::Result<Vec<AbsolutePathBuf>> {
|
||||
super::agents_md_paths(&config.config, &config.cwd, LOCAL_FS.as_ref()).await
|
||||
async fn agents_md_paths(config: &TestConfig) -> std::io::Result<Vec<PathUri>> {
|
||||
super::agents_md_paths(
|
||||
&config.config,
|
||||
&PathUri::from_abs_path(&config.cwd),
|
||||
LOCAL_FS.as_ref(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
fn resolved_local_environments<const N: usize>(
|
||||
@@ -277,12 +282,101 @@ fn resolved_local_environments<const N: usize>(
|
||||
|
||||
fn project_provenance(path: AbsolutePathBuf, cwd: AbsolutePathBuf) -> InstructionProvenance {
|
||||
InstructionProvenance::Project {
|
||||
source_path: path,
|
||||
source_path: PathUri::from_abs_path(&path),
|
||||
environment_id: "local".to_string(),
|
||||
cwd,
|
||||
cwd: PathUri::from_abs_path(&cwd),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn foreign_agents_md_uses_environment_native_paths() {
|
||||
let (cwd, rendered_cwd) = if cfg!(windows) {
|
||||
(
|
||||
PathUri::parse("file:///codex%20runtime").expect("POSIX cwd URI"),
|
||||
"/codex runtime",
|
||||
)
|
||||
} else {
|
||||
(
|
||||
PathUri::parse("file:///C:/codex%20runtime").expect("Windows cwd URI"),
|
||||
r"C:\codex runtime",
|
||||
)
|
||||
};
|
||||
let source_path = cwd.join("AGENTS.md").expect("AGENTS.md URI");
|
||||
let loaded = LoadedAgentsMd {
|
||||
user_instructions: None,
|
||||
entries: vec![InstructionEntry {
|
||||
contents: "remote instructions".to_string(),
|
||||
provenance: InstructionProvenance::Project {
|
||||
source_path: source_path.clone(),
|
||||
environment_id: "remote".to_string(),
|
||||
cwd,
|
||||
},
|
||||
}],
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
loaded.render(),
|
||||
format!(
|
||||
"# AGENTS.md instructions for {rendered_cwd}
|
||||
|
||||
<INSTRUCTIONS>
|
||||
remote instructions
|
||||
</INSTRUCTIONS>"
|
||||
)
|
||||
);
|
||||
assert_eq!(loaded.sources().collect::<Vec<_>>(), vec![source_path]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multi_environment_agents_md_renders_mixed_path_conventions() {
|
||||
let posix_cwd = PathUri::parse("file:///srv/project").expect("POSIX cwd URI");
|
||||
let windows_cwd = PathUri::parse("file:///C:/workspace").expect("Windows cwd URI");
|
||||
let posix_source = posix_cwd.join("AGENTS.md").expect("POSIX AGENTS.md URI");
|
||||
let windows_source = windows_cwd
|
||||
.join("AGENTS.md")
|
||||
.expect("Windows AGENTS.md URI");
|
||||
let loaded = LoadedAgentsMd {
|
||||
user_instructions: None,
|
||||
entries: vec![
|
||||
InstructionEntry {
|
||||
contents: "POSIX instructions".to_string(),
|
||||
provenance: InstructionProvenance::Project {
|
||||
source_path: posix_source.clone(),
|
||||
environment_id: "posix".to_string(),
|
||||
cwd: posix_cwd,
|
||||
},
|
||||
},
|
||||
InstructionEntry {
|
||||
contents: "Windows instructions".to_string(),
|
||||
provenance: InstructionProvenance::Project {
|
||||
source_path: windows_source.clone(),
|
||||
environment_id: "windows".to_string(),
|
||||
cwd: windows_cwd,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
loaded.render(),
|
||||
r#"# AGENTS.md instructions
|
||||
|
||||
<INSTRUCTIONS>
|
||||
for `posix` with root /srv/project
|
||||
|
||||
POSIX instructions
|
||||
|
||||
for `windows` with root C:\workspace
|
||||
|
||||
Windows instructions
|
||||
</INSTRUCTIONS>"#
|
||||
);
|
||||
assert_eq!(
|
||||
loaded.sources().collect::<Vec<_>>(),
|
||||
vec![posix_source, windows_source]
|
||||
);
|
||||
}
|
||||
|
||||
/// Helper that returns a `Config` pointing at `root` and using `limit` as
|
||||
/// the maximum number of bytes to embed from AGENTS.md. The caller can
|
||||
/// optionally specify a custom `instructions` string – when `None` the
|
||||
@@ -508,7 +602,7 @@ async fn read_agents_md_propagates_metadata_errors() {
|
||||
};
|
||||
|
||||
let cwd = config.cwd.clone();
|
||||
let err = read_agents_md(&config.config, &fs, "local", &cwd)
|
||||
let err = read_agents_md(&config.config, &fs, "local", &PathUri::from_abs_path(&cwd))
|
||||
.await
|
||||
.expect_err("metadata error");
|
||||
|
||||
@@ -526,7 +620,7 @@ async fn read_agents_md_propagates_read_errors() {
|
||||
};
|
||||
|
||||
let cwd = config.cwd.clone();
|
||||
let err = read_agents_md(&config.config, &fs, "local", &cwd)
|
||||
let err = read_agents_md(&config.config, &fs, "local", &PathUri::from_abs_path(&cwd))
|
||||
.await
|
||||
.expect_err("read error");
|
||||
|
||||
@@ -544,7 +638,7 @@ async fn read_agents_md_ignores_files_removed_after_discovery() {
|
||||
};
|
||||
|
||||
let cwd = config.cwd.clone();
|
||||
let loaded = read_agents_md(&config.config, &fs, "local", &cwd)
|
||||
let loaded = read_agents_md(&config.config, &fs, "local", &PathUri::from_abs_path(&cwd))
|
||||
.await
|
||||
.expect("removed file is recoverable");
|
||||
|
||||
@@ -659,17 +753,18 @@ secondary doc"#,
|
||||
);
|
||||
assert_eq!(loaded.render(), expected_fragment);
|
||||
assert_eq!(
|
||||
loaded.sources().cloned().collect::<Vec<_>>(),
|
||||
loaded.sources().collect::<Vec<_>>(),
|
||||
vec![
|
||||
config
|
||||
.user_instructions
|
||||
.as_ref()
|
||||
.expect("global instructions")
|
||||
.source
|
||||
.clone(),
|
||||
primary.path().join("AGENTS.md").abs(),
|
||||
primary_nested.join("AGENTS.md").abs(),
|
||||
secondary.path().join("AGENTS.md").abs(),
|
||||
PathUri::from_abs_path(
|
||||
&config
|
||||
.user_instructions
|
||||
.as_ref()
|
||||
.expect("global instructions")
|
||||
.source,
|
||||
),
|
||||
PathUri::from_abs_path(&primary.path().join("AGENTS.md").abs()),
|
||||
PathUri::from_abs_path(&primary_nested.join("AGENTS.md").abs()),
|
||||
PathUri::from_abs_path(&secondary.path().join("AGENTS.md").abs()),
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -898,7 +993,10 @@ async fn concatenates_root_and_cwd_docs() {
|
||||
assert_eq!(loaded.text(), "root doc\n\ncrate doc");
|
||||
assert_eq!(
|
||||
loaded.sources().collect::<Vec<_>>(),
|
||||
vec![&root_agents, &crate_agents]
|
||||
vec![
|
||||
PathUri::from_abs_path(&root_agents),
|
||||
PathUri::from_abs_path(&crate_agents),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -925,8 +1023,8 @@ async fn project_root_markers_are_honored_for_agents_discovery() {
|
||||
let expected_parent = root.path().join("AGENTS.md").abs();
|
||||
let expected_child = cfg.cwd.join("AGENTS.md");
|
||||
assert_eq!(discovery.len(), 2);
|
||||
assert_eq!(discovery[0], expected_parent);
|
||||
assert_eq!(discovery[1], expected_child);
|
||||
assert_eq!(discovery[0], PathUri::from_abs_path(&expected_parent));
|
||||
assert_eq!(discovery[1], PathUri::from_abs_path(&expected_child));
|
||||
|
||||
let res = get_user_instructions(&cfg).await.expect("doc expected");
|
||||
assert_eq!(res, "parent doc\n\nchild doc");
|
||||
@@ -971,8 +1069,8 @@ async fn project_layers_do_not_override_project_root_markers() {
|
||||
assert_eq!(
|
||||
discovery,
|
||||
vec![
|
||||
root.path().join("AGENTS.md").abs(),
|
||||
config.cwd.join("AGENTS.md"),
|
||||
PathUri::from_abs_path(&root.path().join("AGENTS.md").abs()),
|
||||
PathUri::from_abs_path(&config.cwd.join("AGENTS.md")),
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -991,7 +1089,10 @@ async fn agents_md_paths_preserve_symlinked_cwd() {
|
||||
cfg.cwd = linked_cwd.abs();
|
||||
|
||||
let discovery = agents_md_paths(&cfg).await.expect("discover paths");
|
||||
assert_eq!(discovery, vec![cfg.cwd.join("AGENTS.md")]);
|
||||
assert_eq!(
|
||||
discovery,
|
||||
vec![PathUri::from_abs_path(&cfg.cwd.join("AGENTS.md"))]
|
||||
);
|
||||
|
||||
let res = get_user_instructions(&cfg).await.expect("doc expected");
|
||||
assert_eq!(res, "project doc");
|
||||
@@ -1050,7 +1151,10 @@ async fn instruction_sources_include_global_before_agents_md_docs() {
|
||||
assert_eq!(loaded.user_instructions(), cfg.user_instructions.as_ref());
|
||||
assert_eq!(
|
||||
loaded.sources().collect::<Vec<_>>(),
|
||||
vec![&global_agents, &project_agents]
|
||||
vec![
|
||||
PathUri::from_abs_path(&global_agents),
|
||||
PathUri::from_abs_path(&project_agents),
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
loaded.text(),
|
||||
@@ -1091,7 +1195,10 @@ async fn child_agents_message_after_project_docs_is_not_an_instruction_source()
|
||||
assert_eq!(loaded, expected);
|
||||
assert_eq!(
|
||||
loaded.sources().collect::<Vec<_>>(),
|
||||
vec![&global_agents, &project_agents]
|
||||
vec![
|
||||
PathUri::from_abs_path(&global_agents),
|
||||
PathUri::from_abs_path(&project_agents),
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
loaded.text(),
|
||||
@@ -1117,8 +1224,8 @@ async fn agents_local_md_preferred() {
|
||||
let discovery = agents_md_paths(&cfg).await.expect("discover paths");
|
||||
assert_eq!(discovery.len(), 1);
|
||||
assert_eq!(
|
||||
discovery[0].file_name().unwrap().to_string_lossy(),
|
||||
LOCAL_AGENTS_MD_FILENAME
|
||||
discovery[0].basename().as_deref(),
|
||||
Some(LOCAL_AGENTS_MD_FILENAME)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1166,12 +1273,9 @@ async fn agents_md_preferred_over_fallbacks() {
|
||||
|
||||
let discovery = agents_md_paths(&cfg).await.expect("discover paths");
|
||||
assert_eq!(discovery.len(), 1);
|
||||
assert!(
|
||||
discovery[0]
|
||||
.file_name()
|
||||
.unwrap()
|
||||
.to_string_lossy()
|
||||
.eq(DEFAULT_AGENTS_MD_FILENAME)
|
||||
assert_eq!(
|
||||
discovery[0].basename().as_deref(),
|
||||
Some(DEFAULT_AGENTS_MD_FILENAME)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1186,7 +1290,7 @@ async fn agents_md_directory_is_ignored() {
|
||||
assert_eq!(res, None);
|
||||
|
||||
let discovery = agents_md_paths(&cfg).await.expect("discover paths");
|
||||
assert_eq!(discovery, Vec::<AbsolutePathBuf>::new());
|
||||
assert_eq!(discovery, Vec::<PathUri>::new());
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
@@ -1209,7 +1313,7 @@ async fn agents_md_special_file_is_ignored() {
|
||||
assert_eq!(res, None);
|
||||
|
||||
let discovery = agents_md_paths(&cfg).await.expect("discover paths");
|
||||
assert_eq!(discovery, Vec::<AbsolutePathBuf>::new());
|
||||
assert_eq!(discovery, Vec::<PathUri>::new());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -1228,11 +1332,8 @@ async fn override_directory_falls_back_to_agents_md_file() {
|
||||
let discovery = agents_md_paths(&cfg).await.expect("discover paths");
|
||||
assert_eq!(discovery.len(), 1);
|
||||
assert_eq!(
|
||||
discovery[0]
|
||||
.file_name()
|
||||
.expect("file name")
|
||||
.to_string_lossy(),
|
||||
DEFAULT_AGENTS_MD_FILENAME
|
||||
discovery[0].basename().as_deref(),
|
||||
Some(DEFAULT_AGENTS_MD_FILENAME)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ use codex_thread_store::ThreadMetadataPatch;
|
||||
use codex_thread_store::ThreadStoreError;
|
||||
use codex_thread_store::ThreadStoreResult;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use codex_utils_path_uri::LegacyAppPathString;
|
||||
use codex_utils_path_uri::PathUri;
|
||||
use rmcp::model::ReadResourceRequestParams;
|
||||
use std::collections::BTreeMap;
|
||||
@@ -564,10 +565,19 @@ impl CodexThread {
|
||||
}
|
||||
|
||||
/// Returns the files that supplied the thread's loaded model instructions.
|
||||
pub async fn instruction_sources(&self) -> Vec<AbsolutePathBuf> {
|
||||
pub async fn instruction_sources(&self) -> Vec<PathUri> {
|
||||
self.codex.instruction_sources().await
|
||||
}
|
||||
|
||||
/// Returns loaded instruction sources rendered as legacy app-server path strings.
|
||||
pub async fn legacy_instruction_sources(&self) -> Vec<LegacyAppPathString> {
|
||||
self.instruction_sources()
|
||||
.await
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub async fn config(&self) -> Arc<crate::config::Config> {
|
||||
self.codex.session.get_config().await
|
||||
}
|
||||
|
||||
@@ -830,15 +830,13 @@ impl Codex {
|
||||
state.session_configuration.thread_config_snapshot()
|
||||
}
|
||||
|
||||
pub(crate) async fn instruction_sources(&self) -> Vec<AbsolutePathBuf> {
|
||||
pub(crate) async fn instruction_sources(&self) -> Vec<PathUri> {
|
||||
let state = self.session.state.lock().await;
|
||||
state
|
||||
.session_configuration
|
||||
.loaded_agents_md
|
||||
.as_ref()
|
||||
.map_or_else(Vec::new, |instructions| {
|
||||
instructions.sources().cloned().collect()
|
||||
})
|
||||
.map_or_else(Vec::new, |instructions| instructions.sources().collect())
|
||||
}
|
||||
|
||||
pub(crate) async fn thread_environment_selections(&self) -> Vec<TurnEnvironmentSelection> {
|
||||
|
||||
Reference in New Issue
Block a user