Aligned feature stage names with public feature maturity stages (#9929)

We've recently standardized a [feature maturity
model](https://developers.openai.com/codex/feature-maturity) that we're
using in our docs and support forums to communicate expectations to
users. This PR updates the internal stage names and descriptions to
match.

This change involves a simple internal rename and updates to a few
user-visible strings. No functional change.
This commit is contained in:
Eric Traut
2026-01-26 11:43:36 -08:00
committed by GitHub
parent 62266b13f8
commit b77bf4d36d
10 changed files with 48 additions and 43 deletions

View File

@@ -453,8 +453,8 @@ enum FeaturesSubcommand {
fn stage_str(stage: codex_core::features::Stage) -> &'static str {
use codex_core::features::Stage;
match stage {
Stage::Beta => "experimental",
Stage::Experimental { .. } => "beta",
Stage::UnderDevelopment => "under development",
Stage::Experimental { .. } => "experimental",
Stage::Stable => "stable",
Stage::Deprecated => "deprecated",
Stage::Removed => "removed",

View File

@@ -625,11 +625,13 @@ fn build_api_prompt(prompt: &Prompt, instructions: String, tools_json: Vec<Value
}
}
fn beta_feature_headers(config: &Config) -> ApiHeaderMap {
fn experimental_feature_headers(config: &Config) -> ApiHeaderMap {
let enabled = FEATURES
.iter()
.filter_map(|spec| {
if spec.stage.beta_menu_description().is_some() && config.features.enabled(spec.id) {
if spec.stage.experimental_menu_description().is_some()
&& config.features.enabled(spec.id)
{
Some(spec.key)
} else {
None
@@ -650,7 +652,7 @@ fn build_responses_headers(
config: &Config,
turn_state: Option<&Arc<OnceLock<String>>>,
) -> ApiHeaderMap {
let mut headers = beta_feature_headers(config);
let mut headers = experimental_feature_headers(config);
headers.insert(
WEB_SEARCH_ELIGIBLE_HEADER,
HeaderValue::from_static(

View File

@@ -21,8 +21,8 @@ pub(crate) use legacy::legacy_feature_keys;
/// High-level lifecycle stage for a feature.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Stage {
/// Closed beta features to be used while developing or within the company.
Beta,
/// Features that are still under development, not ready for external use
UnderDevelopment,
/// Experimental features made available to users through the `/experimental` menu
Experimental {
name: &'static str,
@@ -38,14 +38,14 @@ pub enum Stage {
}
impl Stage {
pub fn beta_menu_name(self) -> Option<&'static str> {
pub fn experimental_menu_name(self) -> Option<&'static str> {
match self {
Stage::Experimental { name, .. } => Some(name),
_ => None,
}
}
pub fn beta_menu_description(self) -> Option<&'static str> {
pub fn experimental_menu_description(self) -> Option<&'static str> {
match self {
Stage::Experimental {
menu_description, ..
@@ -54,7 +54,7 @@ impl Stage {
}
}
pub fn beta_announcement(self) -> Option<&'static str> {
pub fn experimental_announcement(self) -> Option<&'static str> {
match self {
Stage::Experimental { announcement, .. } => Some(announcement),
_ => None,
@@ -343,10 +343,10 @@ pub const FEATURES: &[FeatureSpec] = &[
FeatureSpec {
id: Feature::WebSearchCached,
key: "web_search_cached",
stage: Stage::Beta,
stage: Stage::UnderDevelopment,
default_enabled: false,
},
// Beta program. Rendered in the `/experimental` menu for users.
// Experimental program. Rendered in the `/experimental` menu for users.
FeatureSpec {
id: Feature::UnifiedExec,
key: "unified_exec",
@@ -370,43 +370,43 @@ pub const FEATURES: &[FeatureSpec] = &[
FeatureSpec {
id: Feature::ChildAgentsMd,
key: "child_agents_md",
stage: Stage::Beta,
stage: Stage::UnderDevelopment,
default_enabled: false,
},
FeatureSpec {
id: Feature::ApplyPatchFreeform,
key: "apply_patch_freeform",
stage: Stage::Beta,
stage: Stage::UnderDevelopment,
default_enabled: false,
},
FeatureSpec {
id: Feature::ExecPolicy,
key: "exec_policy",
stage: Stage::Beta,
stage: Stage::UnderDevelopment,
default_enabled: true,
},
FeatureSpec {
id: Feature::WindowsSandbox,
key: "experimental_windows_sandbox",
stage: Stage::Beta,
stage: Stage::UnderDevelopment,
default_enabled: false,
},
FeatureSpec {
id: Feature::WindowsSandboxElevated,
key: "elevated_windows_sandbox",
stage: Stage::Beta,
stage: Stage::UnderDevelopment,
default_enabled: false,
},
FeatureSpec {
id: Feature::RemoteCompaction,
key: "remote_compaction",
stage: Stage::Beta,
stage: Stage::UnderDevelopment,
default_enabled: true,
},
FeatureSpec {
id: Feature::RemoteModels,
key: "remote_models",
stage: Stage::Beta,
stage: Stage::UnderDevelopment,
default_enabled: true,
},
FeatureSpec {
@@ -421,26 +421,26 @@ pub const FEATURES: &[FeatureSpec] = &[
#[cfg(windows)]
default_enabled: true,
#[cfg(not(windows))]
stage: Stage::Beta,
stage: Stage::UnderDevelopment,
#[cfg(not(windows))]
default_enabled: false,
},
FeatureSpec {
id: Feature::EnableRequestCompression,
key: "enable_request_compression",
stage: Stage::Beta,
stage: Stage::UnderDevelopment,
default_enabled: false,
},
FeatureSpec {
id: Feature::Collab,
key: "collab",
stage: Stage::Beta,
stage: Stage::UnderDevelopment,
default_enabled: false,
},
FeatureSpec {
id: Feature::Connectors,
key: "connectors",
stage: Stage::Beta,
stage: Stage::UnderDevelopment,
default_enabled: false,
},
FeatureSpec {
@@ -456,13 +456,13 @@ pub const FEATURES: &[FeatureSpec] = &[
FeatureSpec {
id: Feature::CollaborationModes,
key: "collaboration_modes",
stage: Stage::Beta,
stage: Stage::UnderDevelopment,
default_enabled: false,
},
FeatureSpec {
id: Feature::ResponsesWebsockets,
key: "responses_websockets",
stage: Stage::Beta,
stage: Stage::UnderDevelopment,
default_enabled: false,
},
];

View File

@@ -29,7 +29,7 @@ use super::selection_popup_common::GenericDisplayRow;
use super::selection_popup_common::measure_rows_height;
use super::selection_popup_common::render_rows;
pub(crate) struct BetaFeatureItem {
pub(crate) struct ExperimentalFeatureItem {
pub feature: Feature,
pub name: String,
pub description: String,
@@ -37,7 +37,7 @@ pub(crate) struct BetaFeatureItem {
}
pub(crate) struct ExperimentalFeaturesView {
features: Vec<BetaFeatureItem>,
features: Vec<ExperimentalFeatureItem>,
state: ScrollState,
complete: bool,
app_event_tx: AppEventSender,
@@ -46,11 +46,14 @@ pub(crate) struct ExperimentalFeaturesView {
}
impl ExperimentalFeaturesView {
pub(crate) fn new(features: Vec<BetaFeatureItem>, app_event_tx: AppEventSender) -> Self {
pub(crate) fn new(
features: Vec<ExperimentalFeatureItem>,
app_event_tx: AppEventSender,
) -> Self {
let mut header = ColumnRenderable::new();
header.push(Line::from("Experimental features".bold()));
header.push(Line::from(
"Toggle beta features. Changes are saved to config.toml.".dim(),
"Toggle experimental features. Changes are saved to config.toml.".dim(),
));
let mut view = Self {

View File

@@ -108,7 +108,7 @@ pub(crate) use chat_composer::InputResult;
use codex_protocol::custom_prompts::CustomPrompt;
use crate::status_indicator_widget::StatusIndicatorWidget;
pub(crate) use experimental_features_view::BetaFeatureItem;
pub(crate) use experimental_features_view::ExperimentalFeatureItem;
pub(crate) use experimental_features_view::ExperimentalFeaturesView;
pub(crate) use list_selection_view::SelectionAction;
pub(crate) use list_selection_view::SelectionItem;

View File

@@ -133,12 +133,12 @@ use crate::app_event::WindowsSandboxEnableMode;
use crate::app_event::WindowsSandboxFallbackReason;
use crate::app_event_sender::AppEventSender;
use crate::bottom_pane::ApprovalRequest;
use crate::bottom_pane::BetaFeatureItem;
use crate::bottom_pane::BottomPane;
use crate::bottom_pane::BottomPaneParams;
use crate::bottom_pane::CancellationEvent;
use crate::bottom_pane::CollaborationModeIndicator;
use crate::bottom_pane::DOUBLE_PRESS_QUIT_SHORTCUT_ENABLED;
use crate::bottom_pane::ExperimentalFeatureItem;
use crate::bottom_pane::ExperimentalFeaturesView;
use crate::bottom_pane::InputResult;
use crate::bottom_pane::LocalImageAttachment;
@@ -4029,12 +4029,12 @@ impl ChatWidget {
}
pub(crate) fn open_experimental_popup(&mut self) {
let features: Vec<BetaFeatureItem> = FEATURES
let features: Vec<ExperimentalFeatureItem> = FEATURES
.iter()
.filter_map(|spec| {
let name = spec.stage.beta_menu_name()?;
let description = spec.stage.beta_menu_description()?;
Some(BetaFeatureItem {
let name = spec.stage.experimental_menu_name()?;
let description = spec.stage.experimental_menu_description()?;
Some(ExperimentalFeatureItem {
feature: spec.id,
name: name.to_string(),
description: description.to_string(),

View File

@@ -3,7 +3,7 @@ source: tui/src/chatwidget/tests.rs
expression: popup
---
Experimental features
Toggle beta features. Changes are saved to config.toml.
Toggle experimental features. Changes are saved to config.toml.
[ ] Ghost snapshots Capture undo snapshots each turn.
[x] Shell tool Allow the model to run shell commands.

View File

@@ -2911,13 +2911,13 @@ async fn experimental_features_popup_snapshot() {
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(None).await;
let features = vec![
BetaFeatureItem {
ExperimentalFeatureItem {
feature: Feature::GhostCommit,
name: "Ghost snapshots".to_string(),
description: "Capture undo snapshots each turn.".to_string(),
enabled: false,
},
BetaFeatureItem {
ExperimentalFeatureItem {
feature: Feature::ShellTool,
name: "Shell tool".to_string(),
description: "Allow the model to run shell commands.".to_string(),
@@ -2937,7 +2937,7 @@ async fn experimental_features_toggle_saves_on_exit() {
let expected_feature = Feature::GhostCommit;
let view = ExperimentalFeaturesView::new(
vec![BetaFeatureItem {
vec![ExperimentalFeatureItem {
feature: expected_feature,
name: "Ghost snapshots".to_string(),
description: "Capture undo snapshots each turn.".to_string(),

View File

@@ -67,7 +67,7 @@ impl SlashCommand {
SlashCommand::Approvals => "choose what Codex can do without approval",
SlashCommand::Permissions => "choose what Codex is allowed to do",
SlashCommand::ElevateSandbox => "set up elevated agent sandbox",
SlashCommand::Experimental => "toggle beta features",
SlashCommand::Experimental => "toggle experimental features",
SlashCommand::Mcp => "list configured MCP tools",
SlashCommand::Logout => "log out of Codex",
SlashCommand::Rollout => "print the rollout file path",

View File

@@ -15,15 +15,15 @@ lazy_static! {
static ref ALL_TOOLTIPS: Vec<&'static str> = {
let mut tips = Vec::new();
tips.extend(TOOLTIPS.iter().copied());
tips.extend(beta_tooltips());
tips.extend(experimental_tooltips());
tips
};
}
fn beta_tooltips() -> Vec<&'static str> {
fn experimental_tooltips() -> Vec<&'static str> {
FEATURES
.iter()
.filter_map(|spec| spec.stage.beta_announcement())
.filter_map(|spec| spec.stage.experimental_announcement())
.collect()
}