Skip to main content

codex_memories_write/
lib.rs

1//! Write-path implementation for Codex memories.
2//!
3//! This crate owns the startup memory pipeline, file-backed memory artifact
4//! helpers, Phase 1 and Phase 2 prompt rendering, extension pruning, and
5//! workspace diffing.
6
7mod control;
8mod extensions;
9mod guard;
10mod metrics;
11mod phase1;
12mod phase2;
13mod prompts;
14mod runtime;
15mod start;
16mod storage;
17pub mod workspace;
18
19use codex_utils_absolute_path::AbsolutePathBuf;
20use std::path::Path;
21use std::path::PathBuf;
22
23pub use control::clear_memory_roots_contents;
24pub use extensions::prune_old_extension_resources;
25pub use prompts::build_consolidation_prompt;
26pub use prompts::build_stage_one_input_message;
27pub use start::start_memories_startup_task;
28pub use storage::rebuild_raw_memories_file_from_memories;
29pub use storage::rollout_summary_file_stem;
30pub use storage::sync_rollout_summaries_from_memories;
31
32#[cfg(test)]
33mod startup_tests;
34
35mod artifacts {
36    pub(super) const EXTENSIONS_SUBDIR: &str = "extensions";
37    pub(super) const ROLLOUT_SUMMARIES_SUBDIR: &str = "rollout_summaries";
38    pub(super) const RAW_MEMORIES_FILENAME: &str = "raw_memories.md";
39}
40
41mod extension_resources {
42    pub(super) const FILENAME_TS_FORMAT: &str = "%Y-%m-%dT%H-%M-%S";
43    pub(super) const RETENTION_DAYS: i64 = 7;
44}
45
46mod guard_limits {
47    pub(super) const CODEX_LIMIT_ID: &str = "codex";
48}
49
50mod prompt_blocks {
51    pub(super) const EXTENSIONS_FOLDER_STRUCTURE: &str = r#"
52Memory extensions (under {{ memory_extensions_root }}/):
53
54- <extension_name>/instructions.md
55  - Source-specific guidance for interpreting additional memory signals. If an
56    extension folder exists, you must read its instructions.md to determine how to use this memory
57    source.
58
59If the user has any memory extensions, you MUST read the instructions for each extension to
60determine how to use the memory source. If the workspace diff shows deleted extension resource files,
61remove stale memories derived only from those resources. If it has no extension folders, continue
62with the standard memory inputs only.
63"#;
64
65    pub(super) const EXTENSIONS_PRIMARY_INPUTS: &str = r#"
66Optional source-specific inputs:
67Under `{{ memory_extensions_root }}/`:
68
69- `<extension_name>/instructions.md`
70  - If extension folders exist, read each instructions.md first and follow it when interpreting
71    that extension's memory source.
72
73If the workspace diff shows deleted memory extension resources, use that extension-specific deletion
74signal to remove stale memories derived only from those resources.
75"#;
76}
77
78mod stage_one {
79    pub(super) const REASONING_EFFORT: codex_protocol::openai_models::ReasoningEffort =
80        codex_protocol::openai_models::ReasoningEffort::Low;
81    pub(super) const CONCURRENCY_LIMIT: usize = 8;
82    pub(super) const JOB_LEASE_SECONDS: i64 = 3_600;
83    pub(super) const JOB_RETRY_DELAY_SECONDS: i64 = 3_600;
84    pub(super) const THREAD_SCAN_LIMIT: usize = 5_000;
85    pub(super) const PRUNE_BATCH_SIZE: usize = 200;
86
87    /// Prompt used for phase 1 extraction.
88    pub(super) const PROMPT: &str = include_str!("../templates/memories/stage_one_system.md");
89
90    /// Fallback stage-1 rollout truncation limit (tokens) when model metadata
91    /// does not include a valid context window.
92    pub(super) const DEFAULT_ROLLOUT_TOKEN_LIMIT: usize = 150_000;
93
94    /// Portion of the model effective input window reserved for the stage-1
95    /// rollout input.
96    ///
97    /// Keeping this below 100% leaves room for system instructions, prompt framing,
98    /// and model output.
99    pub(super) const CONTEXT_WINDOW_PERCENT: i64 = 70;
100}
101
102mod stage_two {
103    pub(super) const REASONING_EFFORT: codex_protocol::openai_models::ReasoningEffort =
104        codex_protocol::openai_models::ReasoningEffort::Medium;
105    pub(super) const JOB_LEASE_SECONDS: i64 = 3_600;
106    pub(super) const JOB_RETRY_DELAY_SECONDS: i64 = 3_600;
107    pub(super) const JOB_HEARTBEAT_SECONDS: u64 = 90;
108}
109
110mod workspace_diff {
111    /// Generated diff file the Phase 2 consolidation agent reads before editing memories.
112    pub(super) const FILENAME: &str = "phase2_workspace_diff.md";
113    pub(super) const MAX_BYTES: usize = 4 * 1024 * 1024;
114}
115
116pub fn memory_root(codex_home: &AbsolutePathBuf) -> AbsolutePathBuf {
117    codex_home.join("memories")
118}
119
120pub fn rollout_summaries_dir(root: &Path) -> PathBuf {
121    root.join(artifacts::ROLLOUT_SUMMARIES_SUBDIR)
122}
123
124pub fn memory_extensions_root(root: &Path) -> PathBuf {
125    root.join(artifacts::EXTENSIONS_SUBDIR)
126}
127
128pub fn raw_memories_file(root: &Path) -> PathBuf {
129    root.join(artifacts::RAW_MEMORIES_FILENAME)
130}
131
132pub async fn ensure_layout(root: &Path) -> std::io::Result<()> {
133    tokio::fs::create_dir_all(rollout_summaries_dir(root)).await
134}