Wip shift to core

This commit is contained in:
Daniel Edrisian
2025-08-26 07:31:08 -07:00
parent 6714afe2d7
commit a2985bab76
11 changed files with 165 additions and 61 deletions
+23
View File
@@ -108,6 +108,7 @@ use crate::user_notification::UserNotification;
use crate::util::backoff;
use codex_protocol::config_types::ReasoningEffort as ReasoningEffortConfig;
use codex_protocol::config_types::ReasoningSummary as ReasoningSummaryConfig;
use codex_protocol::custom_prompts::CustomPrompt;
use codex_protocol::models::ContentItem;
use codex_protocol::models::FunctionCallOutputPayload;
use codex_protocol::models::LocalShellAction;
@@ -1275,6 +1276,28 @@ async fn submission_loop(
warn!("failed to send McpListToolsResponse event: {e}");
}
}
Op::ListCustomPrompts => {
let tx_event = sess.tx_event.clone();
let sub_id = sub.id.clone();
// Discover prompts under the default prompts dir (includes content).
let custom_prompts: Vec<CustomPrompt> = tokio::task::spawn_blocking(|| {
let dir = crate::custom_prompts::default_prompts_dir();
crate::custom_prompts::discover_prompts_in(&dir)
})
.await
.unwrap_or_default();
let event = Event {
id: sub_id,
msg: EventMsg::ListCustomPromptsResponse(
crate::protocol::ListCustomPromptsResponseEvent { custom_prompts },
),
};
if let Err(e) = tx_event.send(event).await {
warn!("failed to send ListCustomPromptsResponse event: {e}");
}
}
Op::Compact => {
// Create a summarization request as user input
const SUMMARIZATION_PROMPT: &str = include_str!("prompt_for_compact_command.md");
+90
View File
@@ -0,0 +1,90 @@
use codex_protocol::custom_prompts::CustomPrompt;
use std::collections::HashSet;
use std::path::Path;
use std::path::PathBuf;
/// Return the default prompts directory: ~/.codex/prompts based on $HOME.
pub fn default_prompts_dir() -> PathBuf {
let home = std::env::var("HOME").unwrap_or_else(|_| ".".to_string());
PathBuf::from(format!("{home}/.codex/prompts"))
}
/// Discover prompt files in the given directory, returning entries sorted by name.
/// Non-files are ignored. If the directory does not exist or cannot be read, returns empty.
pub fn discover_prompts_in(dir: &Path) -> Vec<CustomPrompt> {
discover_prompts_in_excluding(dir, &HashSet::new())
}
/// Discover prompt files in the given directory, excluding any with names in `exclude`.
/// Returns entries sorted by name. Non-files are ignored. Missing/unreadable dir yields empty.
pub fn discover_prompts_in_excluding(dir: &Path, exclude: &HashSet<String>) -> Vec<CustomPrompt> {
let mut out: Vec<CustomPrompt> = Vec::new();
if let Ok(entries) = std::fs::read_dir(dir) {
for entry in entries.flatten() {
let path = entry.path();
if !path.is_file() {
continue;
}
let Some(name) = path
.file_stem()
.and_then(|s| s.to_str())
.map(|s| s.to_string())
else {
continue;
};
if exclude.contains(&name) {
continue;
}
let content = std::fs::read_to_string(&path).unwrap_or_default();
out.push(CustomPrompt { name, content });
}
out.sort_by(|a, b| a.name.cmp(&b.name));
}
out
}
/// Discover prompt files in the default prompts directory, excluding any with names in `exclude`.
pub fn discover_prompts_excluding(exclude: &HashSet<String>) -> Vec<CustomPrompt> {
let dir = default_prompts_dir();
discover_prompts_in_excluding(&dir, exclude)
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs;
use tempfile::TempDir;
#[test]
fn empty_when_dir_missing() {
let tmp = TempDir::new().unwrap();
let missing = tmp.path().join("nope");
let found = discover_prompts_in(&missing);
assert!(found.is_empty());
}
#[test]
fn discovers_and_sorts_files() {
let tmp = TempDir::new().unwrap();
let dir = tmp.path();
fs::write(dir.join("b"), b"b").unwrap();
fs::write(dir.join("a"), b"a").unwrap();
fs::create_dir(dir.join("subdir")).unwrap();
let found = discover_prompts_in(dir);
let names: Vec<String> = found.into_iter().map(|e| e.name).collect();
assert_eq!(names, vec!["a", "b"]);
}
#[test]
fn excludes_builtins() {
let tmp = TempDir::new().unwrap();
let dir = tmp.path();
fs::write(dir.join("init"), b"ignored").unwrap();
fs::write(dir.join("foo"), b"ok").unwrap();
let mut exclude = HashSet::new();
exclude.insert("init".to_string());
let found = discover_prompts_in_excluding(dir, &exclude);
let names: Vec<String> = found.into_iter().map(|e| e.name).collect();
assert_eq!(names, vec!["foo"]);
}
}
+1
View File
@@ -17,6 +17,7 @@ pub mod config;
pub mod config_profile;
pub mod config_types;
mod conversation_history;
pub mod custom_prompts;
mod environment_context;
pub mod error;
pub mod exec;