chore: move memory prompt builder into extension (#24558)

## Why

The memories extension now owns the read-path developer instructions it
injects at thread start. Keeping that prompt builder and template in
`codex-memories-read` left the extension depending on a helper crate for
extension-specific prompt assembly, and kept async template/truncation
dependencies in the read crate after the remaining read surface no
longer needed them.

## What changed

- Moved `prompts.rs`, its tests, and `templates/memories/read_path.md`
from `memories/read` into `ext/memories`.
- Wired `MemoryExtension` to call the local prompt builder and added the
moved templates to `ext/memories/BUILD.bazel` compile data.
- Removed the now-unused prompt export and prompt-related dependencies
from `codex-memories-read`.

## Testing

- Not run locally.
This commit is contained in:
jif-oai authored and GitHub committed 2026-05-26 11:53:47 +02:00
1 parent d579dafb70
commit de513a83f3
11 files changed
+11 -24

No files matched your search

+1 -1
View File
@@ -10,10 +10,10 @@ use codex_extension_api::ThreadLifecycleContributor;
use codex_extension_api::ThreadStartInput;
use codex_extension_api::ToolContributor;
use codex_features::Feature;
use codex_memories_read::build_memory_tool_developer_instructions;
use codex_utils_absolute_path::AbsolutePathBuf;
use crate::local::LocalMemoriesBackend;
use crate::prompts::build_memory_tool_developer_instructions;
use crate::tools;
/// Contributes Codex memory read-path prompt context and memory read tools.
+2
View File
@@ -1,6 +1,7 @@
mod backend;
mod extension;
mod local;
mod prompts;
mod schema;
mod tools;
@@ -11,6 +12,7 @@ pub(crate) const MAX_LIST_RESULTS: usize = 2_000;
pub(crate) const DEFAULT_SEARCH_MAX_RESULTS: usize = 200;
pub(crate) const MAX_SEARCH_RESULTS: usize = 200;
pub(crate) const DEFAULT_READ_MAX_TOKENS: usize = 20_000;
pub(crate) const MEMORY_TOOL_DEVELOPER_INSTRUCTIONS_SUMMARY_TOKEN_LIMIT: usize = 2_500;
pub(crate) const MEMORY_TOOLS_NAMESPACE: &str = "memories/";
pub(crate) const LIST_TOOL_NAME: &str = "list";
+55
View File
@@ -0,0 +1,55 @@
use crate::MEMORY_TOOL_DEVELOPER_INSTRUCTIONS_SUMMARY_TOKEN_LIMIT;
use codex_utils_absolute_path::AbsolutePathBuf;
use codex_utils_output_truncation::TruncationPolicy;
use codex_utils_output_truncation::truncate_text;
use codex_utils_template::Template;
use std::sync::LazyLock;
use tokio::fs;
static MEMORY_TOOL_DEVELOPER_INSTRUCTIONS_TEMPLATE: LazyLock<Template> = LazyLock::new(|| {
parse_embedded_template(
include_str!("../templates/memories/read_path.md"),
"memories/read_path.md",
)
});
fn parse_embedded_template(source: &'static str, template_name: &str) -> Template {
match Template::parse(source) {
Ok(template) => template,
Err(err) => panic!("embedded template {template_name} is invalid: {err}"),
}
}
/// Build the memory read-path prompt that is added to developer instructions.
///
/// Large `memory_summary.md` files are truncated at
/// [MEMORY_TOOL_DEVELOPER_INSTRUCTIONS_SUMMARY_TOKEN_LIMIT].
pub(crate) async fn build_memory_tool_developer_instructions(
codex_home: &AbsolutePathBuf,
) -> Option<String> {
let base_path = codex_home.join("memories");
let memory_summary_path = base_path.join("memory_summary.md");
let memory_summary = fs::read_to_string(&memory_summary_path)
.await
.ok()?
.trim()
.to_string();
let memory_summary = truncate_text(
&memory_summary,
TruncationPolicy::Tokens(MEMORY_TOOL_DEVELOPER_INSTRUCTIONS_SUMMARY_TOKEN_LIMIT),
);
if memory_summary.is_empty() {
return None;
}
let base_path = base_path.display().to_string();
MEMORY_TOOL_DEVELOPER_INSTRUCTIONS_TEMPLATE
.render([
("base_path", base_path.as_str()),
("memory_summary", memory_summary.as_str()),
])
.ok()
}
#[cfg(test)]
#[path = "prompts_tests.rs"]
mod tests;
@@ -0,0 +1,35 @@
use super::*;
use codex_utils_absolute_path::AbsolutePathBuf;
use pretty_assertions::assert_eq;
use tempfile::tempdir;
use tokio::fs as tokio_fs;
#[tokio::test]
async fn build_memory_tool_developer_instructions_renders_embedded_template() {
let temp = tempdir().unwrap();
let codex_home = AbsolutePathBuf::from_absolute_path(temp.path()).unwrap();
let memories_dir = codex_home.join("memories");
tokio_fs::create_dir_all(&memories_dir).await.unwrap();
tokio_fs::write(
memories_dir.join("memory_summary.md"),
"Short memory summary for tests.",
)
.await
.unwrap();
let instructions = build_memory_tool_developer_instructions(&codex_home)
.await
.unwrap();
assert!(instructions.contains(&format!(
"- {}/memory_summary.md (already provided below; do NOT open again)",
memories_dir.display()
)));
assert!(instructions.contains("Short memory summary for tests."));
assert_eq!(
instructions
.matches("========= MEMORY_SUMMARY BEGINS =========")
.count(),
1
);
}