Files
codex/codex-rs/core/src/realtime_prompt.rs
T
Adam Perry @ OpenAIandGitHub ba2b67f9cd [codex] Consolidate shared prompts in codex-prompts (#25151)
## Why

`codex_core` is consistently a bottleneck for incremental builds during
iteration. The simplest fix is to make the crate smaller.

## Summary

`codex-core` owns several reusable prompt renderers and static prompt
assets, which makes the crate harder to split apart.

Rename `codex-review-prompts` to `codex-prompts` and move shared review,
goal, permissions, compaction, realtime, hierarchical AGENTS.md, and
`apply_patch` prompts into it. Move prompt-only tests and update
consumers and `CODEOWNERS`.

## Validation

- `just test -p codex-prompts -p codex-apply-patch`
- `just test -p codex-core prompt_caching`
- Bazel builds for the affected crates
2026-06-01 18:45:07 +00:00

83 lines
2.4 KiB
Rust

use codex_prompts::BACKEND_PROMPT;
const DEFAULT_USER_FIRST_NAME: &str = "there";
const USER_FIRST_NAME_PLACEHOLDER: &str = "{{ user_first_name }}";
pub(crate) fn prepare_realtime_backend_prompt(
prompt: Option<Option<String>>,
config_prompt: Option<String>,
) -> String {
if let Some(config_prompt) = config_prompt
&& !config_prompt.trim().is_empty()
{
return config_prompt;
}
match prompt {
Some(Some(prompt)) => return prompt,
Some(None) => return String::new(),
None => {}
}
BACKEND_PROMPT
.trim_end()
.replace(USER_FIRST_NAME_PLACEHOLDER, &current_user_first_name())
}
fn current_user_first_name() -> String {
[whoami::realname(), whoami::username()]
.into_iter()
.filter_map(|name| name.split_whitespace().next().map(str::to_string))
.find(|name| !name.is_empty())
.unwrap_or_else(|| DEFAULT_USER_FIRST_NAME.to_string())
}
#[cfg(test)]
mod tests {
use super::prepare_realtime_backend_prompt;
#[test]
fn prepare_realtime_backend_prompt_prefers_config_override() {
assert_eq!(
prepare_realtime_backend_prompt(
Some(Some("prompt from request".to_string())),
Some("prompt from config".to_string()),
),
"prompt from config"
);
}
#[test]
fn prepare_realtime_backend_prompt_uses_request_prompt() {
assert_eq!(
prepare_realtime_backend_prompt(
Some(Some("prompt from request".to_string())),
/*config_prompt*/ None,
),
"prompt from request"
);
}
#[test]
fn prepare_realtime_backend_prompt_preserves_empty_request_prompt() {
assert_eq!(
prepare_realtime_backend_prompt(Some(Some(String::new())), /*config_prompt*/ None),
""
);
assert_eq!(
prepare_realtime_backend_prompt(Some(None), /*config_prompt*/ None),
""
);
}
#[test]
fn prepare_realtime_backend_prompt_renders_default() {
let prompt =
prepare_realtime_backend_prompt(/*prompt*/ None, /*config_prompt*/ None);
assert!(prompt.starts_with("## Identity, tone, and role"));
assert!(prompt.contains("You are Codex, an OpenAI general-purpose agentic assistant"));
assert!(prompt.contains("The user's name is "));
assert!(!prompt.contains("{{ user_first_name }}"));
}
}