Move default realtime prompt into core (#17165)

- Adds a core-owned realtime backend prompt template and preparation
path.
- Makes omitted realtime start prompts use the core default, while null
or empty prompts intentionally send empty instructions.
- Covers the core realtime path and app-server v2 path with integration
coverage.

---------

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
Ahmed Ibrahim
2026-04-08 19:34:40 -07:00
committed by GitHub
Unverified
parent 36586eafed
commit 4c2a1ae31b
17 changed files with 491 additions and 59 deletions
+1
View File
@@ -13,6 +13,7 @@ mod client_common;
pub(crate) mod codex;
mod realtime_context;
mod realtime_conversation;
mod realtime_prompt;
pub use codex::SteerInputError;
mod codex_thread;
mod compact_remote;
+11 -9
View File
@@ -1,6 +1,7 @@
use crate::client::ModelClient;
use crate::codex::Session;
use crate::realtime_context::build_realtime_startup_context;
use crate::realtime_prompt::prepare_realtime_backend_prompt;
use async_channel::Receiver;
use async_channel::Sender;
use async_channel::TrySendError;
@@ -546,14 +547,14 @@ async fn prepare_realtime_start(
pub(crate) async fn build_realtime_session_config(
sess: &Arc<Session>,
prompt: String,
prompt: Option<Option<String>>,
session_id: Option<String>,
) -> CodexResult<RealtimeSessionConfig> {
let config = sess.get_config().await;
let prompt = config
.experimental_realtime_ws_backend_prompt
.clone()
.unwrap_or(prompt);
let prompt = prepare_realtime_backend_prompt(
prompt,
config.experimental_realtime_ws_backend_prompt.clone(),
);
let startup_context = match config.experimental_realtime_ws_startup_context.clone() {
Some(startup_context) => startup_context,
None => {
@@ -562,10 +563,11 @@ pub(crate) async fn build_realtime_session_config(
.unwrap_or_default()
}
};
let prompt = if startup_context.is_empty() {
prompt
} else {
format!("{prompt}\n\n{startup_context}")
let prompt = match (prompt.is_empty(), startup_context.is_empty()) {
(true, true) => String::new(),
(true, false) => startup_context,
(false, true) => prompt,
(false, false) => format!("{prompt}\n\n{startup_context}"),
};
let model = config.experimental_realtime_ws_model.clone();
let event_parser = match config.realtime.version {
+81
View File
@@ -0,0 +1,81 @@
const BACKEND_PROMPT: &str = include_str!("../templates/realtime/backend_prompt.md");
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("You are **Codex**"));
assert!(prompt.contains("The user's name is "));
assert!(!prompt.contains("{{ user_first_name }}"));
}
}