use codex_protocol::parse_command::ParsedCommand; use codex_shell_command::is_safe_command::is_known_safe_command; use codex_shell_command::parse_command::parse_command; pub use crate::metrics::MEMORIES_USAGE_METRIC; #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum MemoriesUsageKind { MemoryMd, MemorySummary, RawMemories, RolloutSummaries, Skills, } impl MemoriesUsageKind { pub fn as_tag(self) -> &'static str { match self { Self::MemoryMd => "memory_md", Self::MemorySummary => "memory_summary", Self::RawMemories => "raw_memories", Self::RolloutSummaries => "rollout_summaries", Self::Skills => "skills", } } } pub fn memories_usage_kinds_from_command(command: &[String]) -> Vec { if !is_known_safe_command(command) { return Vec::new(); } parse_command(command) .into_iter() .filter_map(|command| match command { ParsedCommand::Read { path, .. } => get_memory_kind(path.display().to_string()), ParsedCommand::Search { path, .. } => path.and_then(get_memory_kind), ParsedCommand::ListFiles { .. } | ParsedCommand::Unknown { .. } => None, }) .collect() } fn get_memory_kind(path: String) -> Option { if path.contains("memories/MEMORY.md") { Some(MemoriesUsageKind::MemoryMd) } else if path.contains("memories/memory_summary.md") { Some(MemoriesUsageKind::MemorySummary) } else if path.contains("memories/raw_memories.md") { Some(MemoriesUsageKind::RawMemories) } else if path.contains("memories/rollout_summaries/") { Some(MemoriesUsageKind::RolloutSummaries) } else if path.contains("memories/skills/") { Some(MemoriesUsageKind::Skills) } else { None } }