Update safety check links (#30491)

## Summary

Bio/Cyber safety surfaces in the TUI could send users to stale Trusted
Access pages, and safety buffering did not always expose the Help
Center.

This follow-up to #30317 adds the missing Learn more action, refreshes
the Bio access URL and block copy, and updates the affected snapshots
while preserving the existing retry and wait behavior.
This commit is contained in:
Eric Traut
2026-06-29 11:10:11 -07:00
committed by GitHub
Unverified
parent 80f54d1266
commit 9d13291955
6 changed files with 76 additions and 49 deletions
+44 -38
View File
@@ -4,6 +4,7 @@ use super::*;
use codex_app_server_protocol::ModelSafetyBufferingUpdatedNotification;
const SAFETY_BUFFERING_PROMPT_VIEW_ID: &str = "safety-buffering-prompt";
const SAFETY_BUFFERING_LEARN_MORE_URL: &str = "https://help.openai.com/en/articles/20001326";
const SAFETY_BUFFERING_MESSAGE_WITH_RETRY: &str = "This request requires additional safety checks, which can take extra time. Hang tight or retry with a faster model for a quicker response, though it may be less capable of handling complex requests.";
const SAFETY_BUFFERING_MESSAGE_WITHOUT_RETRY: &str =
@@ -12,7 +13,7 @@ const SAFETY_BUFFERING_MESSAGE_WITHOUT_RETRY: &str =
#[derive(Debug)]
struct ActiveSafetyBuffering {
turn_id: String,
retry_prompt_shown: bool,
last_prompt_had_retry: bool,
agent_message_started: bool,
}
@@ -119,22 +120,18 @@ impl ChatWidget {
.map(|(_, turn)| turn.clone());
let thread_id = self.thread_id;
let can_offer_retry = faster_model.is_some() && retry_turn.is_some() && thread_id.is_some();
if !can_offer_retry {
self.bottom_pane
.dismiss_view_by_id(SAFETY_BUFFERING_PROMPT_VIEW_ID);
}
let previous_active = self
.safety_buffering
.active
.as_ref()
.filter(|active| active.turn_id == turn_id);
let retry_prompt_shown = previous_active.is_some_and(|active| active.retry_prompt_shown);
let should_show_retry_prompt = can_offer_retry && !retry_prompt_shown;
let should_show_prompt =
previous_active.is_none_or(|active| active.last_prompt_had_retry != can_offer_retry);
let agent_message_started =
previous_active.is_some_and(|active| active.agent_message_started);
self.safety_buffering.active = Some(ActiveSafetyBuffering {
turn_id: turn_id.clone(),
retry_prompt_shown: retry_prompt_shown || should_show_retry_prompt,
last_prompt_had_retry: can_offer_retry,
agent_message_started,
});
@@ -151,45 +148,54 @@ impl ChatWidget {
/*details_max_lines*/ 6,
);
let (Some(faster_model), Some(turn), Some(thread_id)) =
(faster_model, retry_turn, thread_id)
else {
return;
};
if !should_show_retry_prompt {
if !should_show_prompt {
return;
}
self.bottom_pane
.dismiss_view_by_id(SAFETY_BUFFERING_PROMPT_VIEW_ID);
let header = ColumnRenderable::with(vec![
Box::new(Line::from("Additional safety checks").bold()) as Box<dyn Renderable>,
Box::new(
Paragraph::new(Line::from(SAFETY_BUFFERING_MESSAGE_WITH_RETRY).dim())
.wrap(Wrap { trim: false }),
),
Box::new(Paragraph::new(Line::from(message).dim()).wrap(Wrap { trim: false })),
]);
let mut items = Vec::new();
if let (Some(faster_model), Some(turn), Some(thread_id)) =
(faster_model, retry_turn, thread_id)
{
items.push(SelectionItem {
name: "Retry with a faster model".to_string(),
actions: vec![Box::new(move |tx| {
tx.send(AppEvent::RetrySafetyBufferedTurn {
thread_id,
turn_id: turn_id.clone(),
model: faster_model.clone(),
turn: turn.clone(),
});
})],
dismiss_on_select: true,
..Default::default()
});
}
items.extend([
SelectionItem {
name: "Keep waiting".to_string(),
dismiss_on_select: true,
..Default::default()
},
SelectionItem {
name: "Learn more".to_string(),
actions: vec![Box::new(|tx| {
tx.send(AppEvent::OpenUrlInBrowser {
url: SAFETY_BUFFERING_LEARN_MORE_URL.to_string(),
});
})],
..Default::default()
},
]);
self.bottom_pane.show_selection_view(SelectionViewParams {
view_id: Some(SAFETY_BUFFERING_PROMPT_VIEW_ID),
header: Box::new(header),
items: vec![
SelectionItem {
name: "Retry with a faster model".to_string(),
actions: vec![Box::new(move |tx| {
tx.send(AppEvent::RetrySafetyBufferedTurn {
thread_id,
turn_id: turn_id.clone(),
model: faster_model.clone(),
turn: turn.clone(),
});
})],
dismiss_on_select: true,
..Default::default()
},
SelectionItem {
name: "Keep waiting".to_string(),
dismiss_on_select: true,
..Default::default()
},
],
items,
..Default::default()
});
}
@@ -9,5 +9,6 @@ expression: popup
1. Retry with a faster model
2. Keep waiting
3. Learn more
Press enter to confirm or esc to go back
@@ -1,11 +1,11 @@
---
source: tui/src/chatwidget/tests/app_server.rs
expression: "render_bottom_popup(&chat, 80)"
expression: popup
---
• Working (0s • esc to interrupt)
This request requires additional safety checks, which can take extra time.
Additional safety checks
This request requires additional safety checks, which can take extra time.
1. Keep waiting
2. Learn more
Ask Codex to do anything
gpt-5.5 default · /tmp/project
Press enter to confirm or esc to go back
@@ -125,6 +125,21 @@ async fn safety_buffering_offers_one_retry_with_app_wording() {
let popup = render_bottom_popup(&chat, /*width*/ 80);
assert_chatwidget_snapshot!("safety_buffering_retry_prompt", popup);
chat.handle_key_event(KeyEvent::new(KeyCode::Down, KeyModifiers::NONE));
chat.handle_key_event(KeyEvent::new(KeyCode::Down, KeyModifiers::NONE));
chat.handle_key_event(KeyEvent::new(KeyCode::Enter, KeyModifiers::NONE));
let opened_url = loop {
match rx.try_recv() {
Ok(AppEvent::OpenUrlInBrowser { url }) => break url,
Ok(_) => continue,
Err(err) => panic!("expected learn-more URL event: {err}"),
}
};
assert_eq!(opened_url, "https://help.openai.com/en/articles/20001326");
assert!(render_bottom_popup(&chat, /*width*/ 80).contains("Additional safety checks"));
chat.handle_key_event(KeyEvent::new(KeyCode::Up, KeyModifiers::NONE));
chat.handle_key_event(KeyEvent::new(KeyCode::Up, KeyModifiers::NONE));
chat.handle_key_event(KeyEvent::new(KeyCode::Enter, KeyModifiers::NONE));
let (event_thread_id, event_turn_id, model, turn) = loop {
match rx.try_recv() {
@@ -201,6 +216,9 @@ async fn safety_buffering_without_retry_shows_short_app_message() {
Some(ReplayKind::ThreadSnapshot),
);
assert_eq!(render_popup(&chat), popup);
chat.handle_key_event(KeyEvent::new(KeyCode::Enter, KeyModifiers::NONE));
assert!(!render_bottom_popup(&chat, /*width*/ 80).contains("Additional safety checks"));
}
#[tokio::test]
+2 -2
View File
@@ -96,8 +96,8 @@ const SAFETY_ACCESS_BLOCK_LEARN_MORE_URL: &str = "https://help.openai.com/en/art
pub(crate) fn new_safety_access_block_event() -> SafetyAccessBlockCell {
SafetyAccessBlockCell {
body: "We take extra caution with requests involving biological research and applications that could pose safety risks. If youre a researcher at an approved organization, you may be able to apply for Trusted Access.",
trusted_access_url: "https://openai.com/form/trusted-access-for-life-sciences",
body: "We take extra caution with requests involving biological research and applications that could pose safety risks. Eligible researchers can apply for Trusted Access. If youre a researcher at an approved organization, you may be able to apply for Trusted Access.",
trusted_access_url: "https://www.openai.com/form/trusted-access-for-biology-research/",
}
}
@@ -4,7 +4,9 @@ expression: rendered
---
ⓘ This content can't be shown
We take extra caution with requests involving biological research and
applications that could pose safety risks. If youre a researcher at an
approved organization, you may be able to apply for Trusted Access.
Trusted Access: https://openai.com/form/trusted-access-for-life-sciences
applications that could pose safety risks. Eligible researchers can apply
for Trusted Access. If youre a researcher at an approved organization, you
may be able to apply for Trusted Access.
Trusted Access: https://www.openai.com/form/trusted-access-for-biology-
research/
Learn more: https://help.openai.com/en/articles/20001326