mirror of
https://github.com/openai/codex.git
synced 2026-10-22 17:58:46 +00:00
## Why The memories extension has several distinct responsibilities: registering its prompt and tool contributors, enforcing local-memory filesystem boundaries, implementing list/read/search behavior, and wrapping that backend as extension tools. Those responsibilities were concentrated in `lib.rs`, `local.rs`, and the tool modules, which made follow-up work harder to review and risked growing files through unrelated edits. This PR reorganizes the crate so each responsibility has a narrower owner while preserving the same extension entrypoint and memory tool behavior. ## What Changed - Moved extension lifecycle, prompt, and tool registration into `src/extension.rs`, leaving `src/lib.rs` as the small crate entrypoint. - Split `LocalMemoriesBackend` helpers into `local/list.rs`, `local/path.rs`, `local/read.rs`, and `local/search.rs`. - Centralized tool names and limits at the crate level, and kept the backend and extension implementation crate-private. - Made `memory_list`, `memory_read`, and `memory_search` tool executors generic over `MemoriesBackend`, so tests can exercise the full executor path without depending on tool internals. - Consolidated and expanded memory extension tests in `src/tests.rs`, including read/search tool output coverage, multi-query search, windowed `all_within_lines`, and legacy `query` rejection. ## Testing - Not run locally.
57 lines
1.5 KiB
Rust
57 lines
1.5 KiB
Rust
use std::path::Component;
|
|
use std::path::Path;
|
|
use std::path::PathBuf;
|
|
|
|
use crate::backend::MemoriesBackendError;
|
|
|
|
pub(super) async fn read_sorted_dir_paths(
|
|
dir_path: &Path,
|
|
) -> Result<Vec<PathBuf>, MemoriesBackendError> {
|
|
let mut dir = match tokio::fs::read_dir(dir_path).await {
|
|
Ok(dir) => dir,
|
|
Err(err) if err.kind() == std::io::ErrorKind::NotFound => return Ok(Vec::new()),
|
|
Err(err) => return Err(err.into()),
|
|
};
|
|
let mut paths = Vec::new();
|
|
while let Some(entry) = dir.next_entry().await? {
|
|
paths.push(entry.path());
|
|
}
|
|
paths.sort();
|
|
Ok(paths)
|
|
}
|
|
|
|
pub(super) fn reject_symlink(
|
|
path: &str,
|
|
metadata: &std::fs::Metadata,
|
|
) -> Result<(), MemoriesBackendError> {
|
|
if metadata.file_type().is_symlink() {
|
|
return Err(MemoriesBackendError::invalid_path(
|
|
path,
|
|
"must not be a symlink",
|
|
));
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
pub(super) fn is_hidden_component(component: Component<'_>) -> bool {
|
|
matches!(
|
|
component,
|
|
Component::Normal(name) if name.to_string_lossy().starts_with('.')
|
|
)
|
|
}
|
|
|
|
pub(super) fn is_hidden_path(path: &Path) -> bool {
|
|
path.file_name()
|
|
.is_some_and(|name| name.to_string_lossy().starts_with('.'))
|
|
}
|
|
|
|
pub(super) fn display_relative_path(root: &Path, path: &Path) -> String {
|
|
path.strip_prefix(root)
|
|
.unwrap_or(path)
|
|
.components()
|
|
.map(|component| component.as_os_str().to_string_lossy())
|
|
.filter(|component| !component.is_empty())
|
|
.collect::<Vec<_>>()
|
|
.join("/")
|
|
}
|