From 6b56ac102796ab0106b64b61937dfe8b89e0f55b Mon Sep 17 00:00:00 2001 From: starr-openai Date: Tue, 2 Jun 2026 22:23:38 -0700 Subject: [PATCH] refactor memories prompt source seam --- codex-rs/ext/memories/src/extension.rs | 74 +++++++++------ codex-rs/ext/memories/src/lib.rs | 1 + codex-rs/ext/memories/src/local.rs | 14 +++ codex-rs/ext/memories/src/prompt_source.rs | 13 +++ codex-rs/ext/memories/src/prompts.rs | 20 ++-- codex-rs/ext/memories/src/prompts_tests.rs | 4 +- codex-rs/ext/memories/src/tests.rs | 102 +++++++++++++-------- 7 files changed, 150 insertions(+), 78 deletions(-) create mode 100644 codex-rs/ext/memories/src/prompt_source.rs diff --git a/codex-rs/ext/memories/src/extension.rs b/codex-rs/ext/memories/src/extension.rs index 0be773b4c7..77a91aae26 100644 --- a/codex-rs/ext/memories/src/extension.rs +++ b/codex-rs/ext/memories/src/extension.rs @@ -1,3 +1,4 @@ +use std::marker::PhantomData; use std::sync::Arc; use codex_core::config::Config; @@ -11,56 +12,74 @@ use codex_extension_api::ThreadStartInput; use codex_extension_api::ToolContributor; use codex_features::Feature; use codex_otel::MetricsClient; -use codex_utils_absolute_path::AbsolutePathBuf; +use crate::backend::MemoriesBackend; use crate::local::LocalMemoriesBackend; +use crate::prompt_source::MemoryPromptSource; use crate::prompts::build_memory_tool_developer_instructions; use crate::tools; /// Contributes Codex memory read-path prompt context and memory read tools. -#[derive(Clone, Default)] -pub(crate) struct MemoriesExtension { +#[derive(Clone)] +pub(crate) struct MemoriesExtension { metrics_client: Option, + storage: PhantomData (B, S)>, } -impl MemoriesExtension { - fn new(metrics_client: Option) -> Self { - Self { metrics_client } +impl Default for MemoriesExtension { + fn default() -> Self { + Self::new(/*metrics_client*/ None) } } -#[derive(Clone, Debug)] -pub(crate) struct MemoriesExtensionConfig { - pub(crate) enabled: bool, - pub(crate) dedicated_tools: bool, - pub(crate) codex_home: AbsolutePathBuf, -} - -impl MemoriesExtensionConfig { - fn from_config(config: &Config) -> Self { +impl MemoriesExtension { + pub(crate) fn new(metrics_client: Option) -> Self { Self { - enabled: config.features.enabled(Feature::MemoryTool) && config.memories.use_memories, - dedicated_tools: config.memories.dedicated_tools, - codex_home: config.codex_home.clone(), + metrics_client, + storage: PhantomData, } } } -impl ContextContributor for MemoriesExtension { +#[derive(Clone)] +pub(crate) struct MemoriesExtensionConfig { + pub(crate) enabled: bool, + pub(crate) dedicated_tools: bool, + pub(crate) backend: B, + pub(crate) prompt_source: S, +} + +impl MemoriesExtensionConfig { + fn from_config(config: &Config) -> Self { + let backend = LocalMemoriesBackend::from_codex_home(&config.codex_home); + Self { + enabled: config.features.enabled(Feature::MemoryTool) && config.memories.use_memories, + dedicated_tools: config.memories.dedicated_tools, + prompt_source: backend.clone(), + backend, + } + } +} + +impl ContextContributor for MemoriesExtension +where + B: MemoriesBackend, + S: MemoryPromptSource, +{ fn contribute<'a>( &'a self, _session_store: &'a ExtensionData, thread_store: &'a ExtensionData, ) -> std::pin::Pin> + Send + 'a>> { Box::pin(async move { - let Some(config) = thread_store.get::() else { + let Some(config) = thread_store.get::>() else { return Vec::new(); }; if !config.enabled { return Vec::new(); } - build_memory_tool_developer_instructions(&config.codex_home) + build_memory_tool_developer_instructions(&config.prompt_source) .await .map(PromptFragment::developer_policy) .into_iter() @@ -90,23 +109,24 @@ impl ConfigContributor for MemoriesExtension { } } -impl ToolContributor for MemoriesExtension { +impl ToolContributor for MemoriesExtension +where + B: MemoriesBackend, + S: MemoryPromptSource, +{ fn tools( &self, _session_store: &ExtensionData, thread_store: &ExtensionData, ) -> Vec>> { - let Some(config) = thread_store.get::() else { + let Some(config) = thread_store.get::>() else { return Vec::new(); }; if !config.enabled || !config.dedicated_tools { return Vec::new(); } - tools::memory_tools( - LocalMemoriesBackend::from_codex_home(&config.codex_home), - self.metrics_client.clone(), - ) + tools::memory_tools(config.backend.clone(), self.metrics_client.clone()) } } diff --git a/codex-rs/ext/memories/src/lib.rs b/codex-rs/ext/memories/src/lib.rs index 25120c7a3a..43fe88f929 100644 --- a/codex-rs/ext/memories/src/lib.rs +++ b/codex-rs/ext/memories/src/lib.rs @@ -2,6 +2,7 @@ mod backend; mod extension; mod local; mod metrics; +mod prompt_source; mod prompts; mod schema; mod tools; diff --git a/codex-rs/ext/memories/src/local.rs b/codex-rs/ext/memories/src/local.rs index f4b6cbf1c4..e8cba3eaf6 100644 --- a/codex-rs/ext/memories/src/local.rs +++ b/codex-rs/ext/memories/src/local.rs @@ -14,6 +14,8 @@ use crate::backend::ReadMemoryRequest; use crate::backend::ReadMemoryResponse; use crate::backend::SearchMemoriesRequest; use crate::backend::SearchMemoriesResponse; +use crate::prompt_source::MemoryPromptSource; +use crate::prompt_source::MemoryPromptSummary; mod ad_hoc_note; mod list; @@ -127,3 +129,15 @@ impl MemoriesBackend for LocalMemoriesBackend { search::search(self, request).await } } + +impl MemoryPromptSource for LocalMemoriesBackend { + async fn read_summary(&self) -> Option { + let content = tokio::fs::read_to_string(self.root.join("memory_summary.md")) + .await + .ok()?; + Some(MemoryPromptSummary { + base_path: self.root.clone(), + content, + }) + } +} diff --git a/codex-rs/ext/memories/src/prompt_source.rs b/codex-rs/ext/memories/src/prompt_source.rs new file mode 100644 index 0000000000..a34ea86691 --- /dev/null +++ b/codex-rs/ext/memories/src/prompt_source.rs @@ -0,0 +1,13 @@ +use std::future::Future; +use std::path::PathBuf; + +/// Supplies the bounded memory summary used by prompt injection. +pub(crate) trait MemoryPromptSource: Clone + Send + Sync + 'static { + fn read_summary(&self) -> impl Future> + Send; +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub(crate) struct MemoryPromptSummary { + pub(crate) base_path: PathBuf, + pub(crate) content: String, +} diff --git a/codex-rs/ext/memories/src/prompts.rs b/codex-rs/ext/memories/src/prompts.rs index 6546206b1c..5bd47ea7b4 100644 --- a/codex-rs/ext/memories/src/prompts.rs +++ b/codex-rs/ext/memories/src/prompts.rs @@ -1,10 +1,10 @@ use crate::MEMORY_TOOL_DEVELOPER_INSTRUCTIONS_SUMMARY_TOKEN_LIMIT; -use codex_utils_absolute_path::AbsolutePathBuf; +use crate::prompt_source::MemoryPromptSource; +use crate::prompt_source::MemoryPromptSummary; 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