diff --git a/codex-rs/tui/src/chatwidget/tests/app_server.rs b/codex-rs/tui/src/chatwidget/tests/app_server.rs index 2e6d7f8f7..3c7d9bbf5 100644 --- a/codex-rs/tui/src/chatwidget/tests/app_server.rs +++ b/codex-rs/tui/src/chatwidget/tests/app_server.rs @@ -1151,8 +1151,8 @@ async fn live_app_server_cyber_policy_error_renders_dedicated_notice() { let cells = drain_insert_history(&mut rx); assert_eq!(cells.len(), 1); let rendered = lines_to_single_string(&cells[0]); - assert!(rendered.contains("This chat was flagged for possible cybersecurity risk")); - assert!(rendered.contains("Trusted Access for Cyber")); + assert!(rendered.contains("This content can't be shown")); + assert!(rendered.contains("extra caution with cybersecurity requests")); assert!(!rendered.contains("server fallback message")); assert!(!chat.bottom_pane.is_task_running()); } @@ -1171,6 +1171,7 @@ async fn app_server_safety_access_errors_render_dedicated_notice() { assert_eq!(cells.len(), 1); let rendered = lines_to_single_string(&cells[0]); assert!(rendered.contains("This content can't be shown")); + assert!(rendered.contains("biological research")); assert!(!rendered.contains("Invalid prompt:")); } } diff --git a/codex-rs/tui/src/chatwidget/tests/status_and_layout.rs b/codex-rs/tui/src/chatwidget/tests/status_and_layout.rs index 329d24934..156348d42 100644 --- a/codex-rs/tui/src/chatwidget/tests/status_and_layout.rs +++ b/codex-rs/tui/src/chatwidget/tests/status_and_layout.rs @@ -54,8 +54,8 @@ async fn app_server_cyber_policy_error_renders_dedicated_notice() { let cells = drain_insert_history(&mut rx); assert_eq!(cells.len(), 1); let rendered = lines_to_single_string(&cells[0]); - assert!(rendered.contains("This chat was flagged for possible cybersecurity risk")); - assert!(rendered.contains("Trusted Access for Cyber")); + assert!(rendered.contains("This content can't be shown")); + assert!(rendered.contains("extra caution with cybersecurity requests")); assert!(!rendered.contains("server fallback message")); } diff --git a/codex-rs/tui/src/history_cell/notices.rs b/codex-rs/tui/src/history_cell/notices.rs index c4cc79cf7..c2fa6c921 100644 --- a/codex-rs/tui/src/history_cell/notices.rs +++ b/codex-rs/tui/src/history_cell/notices.rs @@ -86,91 +86,76 @@ pub(crate) fn new_warning_event(message: String) -> PrefixedWrappedHistoryCell { } #[derive(Debug)] -pub(crate) struct SafetyAccessBlockCell; +pub(crate) struct SafetyAccessBlockCell { + body: &'static str, + trusted_access_url: &'static str, +} const SAFETY_ACCESS_BLOCK_TITLE: &str = "This content can't be shown"; -const SAFETY_ACCESS_BLOCK_BODY: &str = "We've limited access to this content for safety reasons. This type of information may be used to benefit or to harm people."; +const SAFETY_ACCESS_BLOCK_LEARN_MORE_URL: &str = "https://help.openai.com/en/articles/20001326"; pub(crate) fn new_safety_access_block_event() -> SafetyAccessBlockCell { - SafetyAccessBlockCell + SafetyAccessBlockCell { + body: "We take extra caution with requests involving biological research and applications that could pose safety risks. If you’re 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", + } +} + +pub(crate) fn new_cyber_policy_error_event() -> SafetyAccessBlockCell { + SafetyAccessBlockCell { + body: "We take extra caution with cybersecurity requests. If you’re a security professional, you may be able to apply for Trusted Access.", + trusted_access_url: "https://openai.com/form/enterprise-trusted-access-for-cyber/", + } } impl HistoryCell for SafetyAccessBlockCell { fn display_lines(&self, width: u16) -> Vec> { - let mut lines = vec![vec!["ⓘ ".cyan(), SAFETY_ACCESS_BLOCK_TITLE.bold()].into()]; - let body = Line::from(vec![" ".into(), SAFETY_ACCESS_BLOCK_BODY.dim()]); - let wrap_width = width.saturating_sub(2).max(1) as usize; - let wrapped = adaptive_wrap_line( - &body, - RtOptions::new(wrap_width).subsequent_indent(" ".into()), - ); - push_owned_lines(&wrapped, &mut lines); - lines - } - - fn raw_lines(&self) -> Vec> { - vec![ - Line::from(SAFETY_ACCESS_BLOCK_TITLE), - Line::from(SAFETY_ACCESS_BLOCK_BODY), - ] - } -} - -const TRUSTED_ACCESS_FOR_CYBER_URL: &str = "https://chatgpt.com/cyber"; - -#[derive(Debug)] -pub(crate) struct CyberPolicyNoticeCell; - -pub(crate) fn new_cyber_policy_error_event() -> CyberPolicyNoticeCell { - CyberPolicyNoticeCell -} - -impl HistoryCell for CyberPolicyNoticeCell { - fn display_lines(&self, width: u16) -> Vec> { - let mut lines: Vec> = Vec::new(); - lines.push( - vec![ - "ⓘ ".cyan(), - "This chat was flagged for possible cybersecurity risk".bold(), - ] - .into(), - ); - - let wrap_width = width.saturating_sub(2).max(1) as usize; - let body = Line::from(vec![ - " If this seems wrong, try rephrasing your request. To get authorized for security work, join the " - .dim(), - "Trusted Access for Cyber".cyan().underlined(), - " program.".dim(), - ]); - let wrapped = adaptive_wrap_line( - &body, - RtOptions::new(wrap_width).subsequent_indent(" ".into()), - ); - push_owned_lines(&wrapped, &mut lines); - lines.push( - vec![ - " ".into(), - TRUSTED_ACCESS_FOR_CYBER_URL.cyan().underlined(), - ] - .into(), - ); - - lines - } - - fn raw_lines(&self) -> Vec> { - vec![ - Line::from("This chat was flagged for possible cybersecurity risk"), - Line::from( - "If this seems wrong, try rephrasing your request. To get authorized for security work, join the Trusted Access for Cyber program.", - ), - Line::from(TRUSTED_ACCESS_FOR_CYBER_URL), - ] + visible_lines(self.display_hyperlink_lines(width)) } fn display_hyperlink_lines(&self, width: u16) -> Vec { - crate::terminal_hyperlinks::annotate_web_urls(self.display_lines(width)) + let mut lines = vec![HyperlinkLine::new( + vec!["ⓘ ".cyan(), SAFETY_ACCESS_BLOCK_TITLE.bold()].into(), + )]; + let body = Line::from(vec![" ".into(), self.body.dim()]); + let wrap_width = width.saturating_sub(2).max(1) as usize; + let wrapped = adaptive_wrap_line( + &body, + RtOptions::new(wrap_width).subsequent_indent(" ".into()), + ); + let mut wrapped_body = Vec::new(); + push_owned_lines(&wrapped, &mut wrapped_body); + lines.extend(plain_hyperlink_lines(wrapped_body)); + + for (label, url) in [ + ("Trusted Access", self.trusted_access_url), + ("Learn more", SAFETY_ACCESS_BLOCK_LEARN_MORE_URL), + ] { + let source = crate::terminal_hyperlinks::annotate_web_urls_in_line( + vec![format!(" {label}: ").dim(), url.cyan().underlined()].into(), + ); + let wrapped = crate::wrapping::word_wrap_line( + &source.line, + RtOptions::new(wrap_width).subsequent_indent(" ".into()), + ); + let mut wrapped_links = Vec::new(); + push_owned_lines(&wrapped, &mut wrapped_links); + lines.extend(crate::terminal_hyperlinks::remap_wrapped_line( + &source, + wrapped_links, + )); + } + lines + } + + fn raw_lines(&self) -> Vec> { + let trusted_access_url = self.trusted_access_url; + vec![ + Line::from(SAFETY_ACCESS_BLOCK_TITLE), + Line::from(self.body), + Line::from(format!("Trusted Access: {trusted_access_url}")), + Line::from(format!("Learn more: {SAFETY_ACCESS_BLOCK_LEARN_MORE_URL}")), + ] } fn transcript_hyperlink_lines(&self, width: u16) -> Vec { diff --git a/codex-rs/tui/src/history_cell/snapshots/codex_tui__history_cell__tests__cyber_policy_error_event_narrow_snapshot.snap b/codex-rs/tui/src/history_cell/snapshots/codex_tui__history_cell__tests__cyber_policy_error_event_narrow_snapshot.snap index 9039b196e..17d6bf7ce 100644 --- a/codex-rs/tui/src/history_cell/snapshots/codex_tui__history_cell__tests__cyber_policy_error_event_narrow_snapshot.snap +++ b/codex-rs/tui/src/history_cell/snapshots/codex_tui__history_cell__tests__cyber_policy_error_event_narrow_snapshot.snap @@ -1,12 +1,16 @@ --- -source: tui/src/history_cell.rs -assertion_line: 3312 +source: tui/src/history_cell/tests.rs expression: rendered --- -ⓘ This chat was flagged for possible cybersecurity risk - If this seems wrong, try - rephrasing your request. To get - authorized for security work, - join the Trusted Access for - Cyber program. - https://chatgpt.com/cyber +ⓘ This content can't be shown + We take extra caution with + cybersecurity requests. If + you’re a security professional, + you may be able to apply for + Trusted Access. + Trusted Access: https:// + openai.com/form/enterprise- + trusted-access-for-cyber/ + Learn more: https:// + help.openai.com/en/ + articles/20001326 diff --git a/codex-rs/tui/src/history_cell/snapshots/codex_tui__history_cell__tests__cyber_policy_error_event_snapshot.snap b/codex-rs/tui/src/history_cell/snapshots/codex_tui__history_cell__tests__cyber_policy_error_event_snapshot.snap index 888a10c37..ca800e50d 100644 --- a/codex-rs/tui/src/history_cell/snapshots/codex_tui__history_cell__tests__cyber_policy_error_event_snapshot.snap +++ b/codex-rs/tui/src/history_cell/snapshots/codex_tui__history_cell__tests__cyber_policy_error_event_snapshot.snap @@ -3,7 +3,8 @@ source: tui/src/history_cell.rs assertion_line: 3305 expression: rendered --- -ⓘ This chat was flagged for possible cybersecurity risk - If this seems wrong, try rephrasing your request. To get authorized for - security work, join the Trusted Access for Cyber program. - https://chatgpt.com/cyber +ⓘ This content can't be shown + We take extra caution with cybersecurity requests. If you’re a security + professional, you may be able to apply for Trusted Access. + Trusted Access: https://openai.com/form/enterprise-trusted-access-for-cyber/ + Learn more: https://help.openai.com/en/articles/20001326 diff --git a/codex-rs/tui/src/history_cell/snapshots/codex_tui__history_cell__tests__safety_access_block_event_snapshot.snap b/codex-rs/tui/src/history_cell/snapshots/codex_tui__history_cell__tests__safety_access_block_event_snapshot.snap index f51269788..fe027f0d9 100644 --- a/codex-rs/tui/src/history_cell/snapshots/codex_tui__history_cell__tests__safety_access_block_event_snapshot.snap +++ b/codex-rs/tui/src/history_cell/snapshots/codex_tui__history_cell__tests__safety_access_block_event_snapshot.snap @@ -3,5 +3,8 @@ source: tui/src/history_cell/tests.rs expression: rendered --- ⓘ This content can't be shown - We've limited access to this content for safety reasons. This type of - information may be used to benefit or to harm people. + We take extra caution with requests involving biological research and + applications that could pose safety risks. If you’re 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 + Learn more: https://help.openai.com/en/articles/20001326