mirror of
https://github.com/openai/codex.git
synced 2026-11-06 00:30:29 +00:00
feat: arcticfox in the wild (#6906)
<img width="485" height="600" alt="image" src="https://github.com/user-attachments/assets/4341740d-dd58-4a3e-b69a-33a3be0606c5" /> --------- Co-authored-by: jif-oai <jif@openai.com>
This commit is contained in:
1 parent
1924500250
commit
d5dfba2509
31 files changed
+375
-211
No files matched your search
+29
-13
@@ -19,7 +19,7 @@ use crate::tui::TuiEvent;
|
||||
use crate::update_action::UpdateAction;
|
||||
use codex_ansi_escape::ansi_escape_line;
|
||||
use codex_app_server_protocol::AuthMode;
|
||||
use codex_common::model_presets::HIDE_ARCTICFOX_MIGRATION_PROMPT_CONFIG;
|
||||
use codex_common::model_presets::HIDE_GPT_5_1_CODEX_MAX_MIGRATION_PROMPT_CONFIG;
|
||||
use codex_common::model_presets::HIDE_GPT5_1_MIGRATION_PROMPT_CONFIG;
|
||||
use codex_common::model_presets::ModelUpgrade;
|
||||
use codex_common::model_presets::all_model_presets;
|
||||
@@ -57,7 +57,7 @@ use tokio::sync::mpsc::unbounded_channel;
|
||||
use crate::history_cell::UpdateAvailableHistoryCell;
|
||||
|
||||
const GPT_5_1_MIGRATION_AUTH_MODES: [AuthMode; 2] = [AuthMode::ChatGPT, AuthMode::ApiKey];
|
||||
const ARCTICFOX_MIGRATION_AUTH_MODES: [AuthMode; 1] = [AuthMode::ChatGPT];
|
||||
const GPT_5_1_CODEX_MIGRATION_AUTH_MODES: [AuthMode; 1] = [AuthMode::ChatGPT];
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AppExitInfo {
|
||||
@@ -106,7 +106,9 @@ fn should_show_model_migration_prompt(
|
||||
|
||||
fn migration_prompt_hidden(config: &Config, migration_config_key: &str) -> Option<bool> {
|
||||
match migration_config_key {
|
||||
HIDE_ARCTICFOX_MIGRATION_PROMPT_CONFIG => config.notices.hide_arcticfox_migration_prompt,
|
||||
HIDE_GPT_5_1_CODEX_MAX_MIGRATION_PROMPT_CONFIG => {
|
||||
config.notices.hide_gpt_5_1_codex_max_migration_prompt
|
||||
}
|
||||
HIDE_GPT5_1_MIGRATION_PROMPT_CONFIG => config.notices.hide_gpt5_1_migration_prompt,
|
||||
_ => None,
|
||||
}
|
||||
@@ -170,6 +172,11 @@ async fn handle_model_migration_prompt_if_needed(
|
||||
effort: mapped_effort,
|
||||
});
|
||||
}
|
||||
ModelMigrationOutcome::Rejected => {
|
||||
app_event_tx.send(AppEvent::PersistModelMigrationPromptAcknowledged {
|
||||
migration_config: migration_config_key.to_string(),
|
||||
});
|
||||
}
|
||||
ModelMigrationOutcome::Exit => {
|
||||
return Some(AppExitInfo {
|
||||
token_usage: TokenUsage::default(),
|
||||
@@ -641,19 +648,17 @@ impl App {
|
||||
.await
|
||||
{
|
||||
Ok(()) => {
|
||||
let effort_label = effort
|
||||
.map(|eff| format!(" with {eff} reasoning"))
|
||||
.unwrap_or_else(|| " with default reasoning".to_string());
|
||||
let reasoning_label = Self::reasoning_label(effort);
|
||||
if let Some(profile) = profile {
|
||||
self.chat_widget.add_info_message(
|
||||
format!(
|
||||
"Model changed to {model}{effort_label} for {profile} profile"
|
||||
"Model changed to {model} {reasoning_label} for {profile} profile"
|
||||
),
|
||||
None,
|
||||
);
|
||||
} else {
|
||||
self.chat_widget.add_info_message(
|
||||
format!("Model changed to {model}{effort_label}"),
|
||||
format!("Model changed to {model} {reasoning_label}"),
|
||||
None,
|
||||
);
|
||||
}
|
||||
@@ -821,6 +826,17 @@ impl App {
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn reasoning_label(reasoning_effort: Option<ReasoningEffortConfig>) -> &'static str {
|
||||
match reasoning_effort {
|
||||
Some(ReasoningEffortConfig::Minimal) => "minimal",
|
||||
Some(ReasoningEffortConfig::Low) => "low",
|
||||
Some(ReasoningEffortConfig::Medium) => "medium",
|
||||
Some(ReasoningEffortConfig::High) => "high",
|
||||
Some(ReasoningEffortConfig::XHigh) => "xhigh",
|
||||
None | Some(ReasoningEffortConfig::None) => "default",
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn token_usage(&self) -> codex_core::protocol::TokenUsage {
|
||||
self.chat_widget.token_usage()
|
||||
}
|
||||
@@ -946,7 +962,7 @@ impl App {
|
||||
fn migration_prompt_allowed_auth_modes(migration_config_key: &str) -> Option<&'static [AuthMode]> {
|
||||
match migration_config_key {
|
||||
HIDE_GPT5_1_MIGRATION_PROMPT_CONFIG => Some(&GPT_5_1_MIGRATION_AUTH_MODES),
|
||||
HIDE_ARCTICFOX_MIGRATION_PROMPT_CONFIG => Some(&ARCTICFOX_MIGRATION_AUTH_MODES),
|
||||
HIDE_GPT_5_1_CODEX_MAX_MIGRATION_PROMPT_CONFIG => Some(&GPT_5_1_CODEX_MIGRATION_AUTH_MODES),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -1034,7 +1050,7 @@ mod tests {
|
||||
));
|
||||
assert!(should_show_model_migration_prompt(
|
||||
"gpt-5.1-codex",
|
||||
"arcticfox",
|
||||
"gpt-5.1-codex-max",
|
||||
None
|
||||
));
|
||||
assert!(!should_show_model_migration_prompt(
|
||||
@@ -1181,14 +1197,14 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn arcticfox_migration_limits_to_chatgpt() {
|
||||
fn gpt_5_1_codex_max_migration_limits_to_chatgpt() {
|
||||
assert!(migration_prompt_allows_auth_mode(
|
||||
Some(AuthMode::ChatGPT),
|
||||
HIDE_ARCTICFOX_MIGRATION_PROMPT_CONFIG,
|
||||
HIDE_GPT_5_1_CODEX_MAX_MIGRATION_PROMPT_CONFIG,
|
||||
));
|
||||
assert!(!migration_prompt_allows_auth_mode(
|
||||
Some(AuthMode::ApiKey),
|
||||
HIDE_ARCTICFOX_MIGRATION_PROMPT_CONFIG,
|
||||
HIDE_GPT_5_1_CODEX_MAX_MIGRATION_PROMPT_CONFIG,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -2030,8 +2030,8 @@ impl ChatWidget {
|
||||
let effort_label = Self::reasoning_effort_label(effort);
|
||||
format!("⚠ {effort_label} reasoning effort can quickly consume Plus plan rate limits.")
|
||||
});
|
||||
let warn_for_model =
|
||||
preset.model.starts_with("gpt-5.1-codex") || preset.model.starts_with("arcticfox");
|
||||
let warn_for_model = preset.model.starts_with("gpt-5.1-codex")
|
||||
|| preset.model.starts_with("gpt-5.1-codex-max");
|
||||
|
||||
struct EffortChoice {
|
||||
stored: Option<ReasoningEffortConfig>,
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
source: tui/src/chatwidget/tests.rs
|
||||
expression: popup
|
||||
---
|
||||
Select Reasoning Level for arcticfox
|
||||
Select Reasoning Level for gpt-5.1-codex-max
|
||||
|
||||
1. Low Fast responses with lighter reasoning
|
||||
2. Medium (default) Balances speed and reasoning depth for everyday tasks
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ source: tui/src/chatwidget/tests.rs
|
||||
assertion_line: 1548
|
||||
expression: popup
|
||||
---
|
||||
Select Reasoning Level for arcticfox
|
||||
Select Reasoning Level for gpt-5.1-codex-max
|
||||
|
||||
1. Low Fast responses with lighter reasoning
|
||||
2. Medium (default) Balances speed and reasoning depth for everyday
|
||||
|
||||
@@ -1526,13 +1526,13 @@ fn startup_prompts_for_windows_sandbox_when_agent_requested() {
|
||||
fn model_reasoning_selection_popup_snapshot() {
|
||||
let (mut chat, _rx, _op_rx) = make_chatwidget_manual();
|
||||
|
||||
chat.config.model = "arcticfox".to_string();
|
||||
chat.config.model = "gpt-5.1-codex-max".to_string();
|
||||
chat.config.model_reasoning_effort = Some(ReasoningEffortConfig::High);
|
||||
|
||||
let preset = builtin_model_presets(None)
|
||||
.into_iter()
|
||||
.find(|preset| preset.model == "arcticfox")
|
||||
.expect("arcticfox preset");
|
||||
.find(|preset| preset.model == "gpt-5.1-codex-max")
|
||||
.expect("gpt-5.1-codex-max preset");
|
||||
chat.open_reasoning_popup(preset);
|
||||
|
||||
let popup = render_bottom_popup(&chat, 80);
|
||||
@@ -1543,13 +1543,13 @@ fn model_reasoning_selection_popup_snapshot() {
|
||||
fn model_reasoning_selection_popup_extra_high_warning_snapshot() {
|
||||
let (mut chat, _rx, _op_rx) = make_chatwidget_manual();
|
||||
|
||||
chat.config.model = "arcticfox".to_string();
|
||||
chat.config.model = "gpt-5.1-codex-max".to_string();
|
||||
chat.config.model_reasoning_effort = Some(ReasoningEffortConfig::XHigh);
|
||||
|
||||
let preset = builtin_model_presets(None)
|
||||
.into_iter()
|
||||
.find(|preset| preset.model == "arcticfox")
|
||||
.expect("arcticfox preset");
|
||||
.find(|preset| preset.model == "gpt-5.1-codex-max")
|
||||
.expect("gpt-5.1-codex-max preset");
|
||||
chat.open_reasoning_popup(preset);
|
||||
|
||||
let popup = render_bottom_popup(&chat, 80);
|
||||
@@ -1560,12 +1560,12 @@ fn model_reasoning_selection_popup_extra_high_warning_snapshot() {
|
||||
fn reasoning_popup_shows_extra_high_with_space() {
|
||||
let (mut chat, _rx, _op_rx) = make_chatwidget_manual();
|
||||
|
||||
chat.config.model = "arcticfox".to_string();
|
||||
chat.config.model = "gpt-5.1-codex-max".to_string();
|
||||
|
||||
let preset = builtin_model_presets(None)
|
||||
.into_iter()
|
||||
.find(|preset| preset.model == "arcticfox")
|
||||
.expect("arcticfox preset");
|
||||
.find(|preset| preset.model == "gpt-5.1-codex-max")
|
||||
.expect("gpt-5.1-codex-max preset");
|
||||
chat.open_reasoning_popup(preset);
|
||||
|
||||
let popup = render_bottom_popup(&chat, 120);
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
use crate::key_hint;
|
||||
use crate::render::Insets;
|
||||
use crate::render::renderable::ColumnRenderable;
|
||||
use crate::render::renderable::Renderable;
|
||||
use crate::render::renderable::RenderableExt as _;
|
||||
use crate::selection_list::selection_option_row;
|
||||
use crate::tui::FrameRequester;
|
||||
use crate::tui::Tui;
|
||||
use crate::tui::TuiEvent;
|
||||
use codex_common::model_presets::HIDE_ARCTICFOX_MIGRATION_PROMPT_CONFIG;
|
||||
use codex_common::model_presets::HIDE_GPT_5_1_CODEX_MAX_MIGRATION_PROMPT_CONFIG;
|
||||
use codex_common::model_presets::HIDE_GPT5_1_MIGRATION_PROMPT_CONFIG;
|
||||
use crossterm::event::KeyCode;
|
||||
use crossterm::event::KeyEvent;
|
||||
@@ -22,8 +24,10 @@ use ratatui::widgets::Wrap;
|
||||
use tokio_stream::StreamExt;
|
||||
|
||||
/// Outcome of the migration prompt.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub(crate) enum ModelMigrationOutcome {
|
||||
Accepted,
|
||||
Rejected,
|
||||
Exit,
|
||||
}
|
||||
|
||||
@@ -31,13 +35,33 @@ pub(crate) enum ModelMigrationOutcome {
|
||||
pub(crate) struct ModelMigrationCopy {
|
||||
pub heading: Vec<Span<'static>>,
|
||||
pub content: Vec<Line<'static>>,
|
||||
pub can_opt_out: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
enum MigrationMenuOption {
|
||||
TryNewModel,
|
||||
UseExistingModel,
|
||||
}
|
||||
|
||||
impl MigrationMenuOption {
|
||||
fn all() -> [Self; 2] {
|
||||
[Self::TryNewModel, Self::UseExistingModel]
|
||||
}
|
||||
|
||||
fn label(self) -> &'static str {
|
||||
match self {
|
||||
Self::TryNewModel => "Try new model",
|
||||
Self::UseExistingModel => "Use existing model",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn migration_copy_for_config(migration_config_key: &str) -> ModelMigrationCopy {
|
||||
match migration_config_key {
|
||||
HIDE_GPT5_1_MIGRATION_PROMPT_CONFIG => gpt5_migration_copy(),
|
||||
HIDE_ARCTICFOX_MIGRATION_PROMPT_CONFIG => arcticfox_migration_copy(),
|
||||
_ => arcticfox_migration_copy(),
|
||||
HIDE_GPT_5_1_CODEX_MAX_MIGRATION_PROMPT_CONFIG => gpt_5_1_codex_max_migration_copy(),
|
||||
_ => gpt_5_1_codex_max_migration_copy(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +122,8 @@ struct ModelMigrationScreen {
|
||||
request_frame: FrameRequester,
|
||||
copy: ModelMigrationCopy,
|
||||
done: bool,
|
||||
should_exit: bool,
|
||||
outcome: ModelMigrationOutcome,
|
||||
highlighted_option: MigrationMenuOption,
|
||||
}
|
||||
|
||||
impl ModelMigrationScreen {
|
||||
@@ -107,15 +132,47 @@ impl ModelMigrationScreen {
|
||||
request_frame,
|
||||
copy,
|
||||
done: false,
|
||||
should_exit: false,
|
||||
outcome: ModelMigrationOutcome::Accepted,
|
||||
highlighted_option: MigrationMenuOption::TryNewModel,
|
||||
}
|
||||
}
|
||||
|
||||
fn accept(&mut self) {
|
||||
fn finish_with(&mut self, outcome: ModelMigrationOutcome) {
|
||||
self.outcome = outcome;
|
||||
self.done = true;
|
||||
self.request_frame.schedule_frame();
|
||||
}
|
||||
|
||||
fn accept(&mut self) {
|
||||
self.finish_with(ModelMigrationOutcome::Accepted);
|
||||
}
|
||||
|
||||
fn reject(&mut self) {
|
||||
self.finish_with(ModelMigrationOutcome::Rejected);
|
||||
}
|
||||
|
||||
fn exit(&mut self) {
|
||||
self.finish_with(ModelMigrationOutcome::Exit);
|
||||
}
|
||||
|
||||
fn confirm_selection(&mut self) {
|
||||
if self.copy.can_opt_out {
|
||||
match self.highlighted_option {
|
||||
MigrationMenuOption::TryNewModel => self.accept(),
|
||||
MigrationMenuOption::UseExistingModel => self.reject(),
|
||||
}
|
||||
} else {
|
||||
self.accept();
|
||||
}
|
||||
}
|
||||
|
||||
fn highlight_option(&mut self, option: MigrationMenuOption) {
|
||||
if self.highlighted_option != option {
|
||||
self.highlighted_option = option;
|
||||
self.request_frame.schedule_frame();
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_key(&mut self, key_event: KeyEvent) {
|
||||
if key_event.kind == KeyEventKind::Release {
|
||||
return;
|
||||
@@ -124,14 +181,36 @@ impl ModelMigrationScreen {
|
||||
if key_event.modifiers.contains(KeyModifiers::CONTROL)
|
||||
&& matches!(key_event.code, KeyCode::Char('c') | KeyCode::Char('d'))
|
||||
{
|
||||
self.should_exit = true;
|
||||
self.done = true;
|
||||
self.request_frame.schedule_frame();
|
||||
self.exit();
|
||||
return;
|
||||
}
|
||||
|
||||
if matches!(key_event.code, KeyCode::Esc | KeyCode::Enter) {
|
||||
self.accept();
|
||||
if !self.copy.can_opt_out {
|
||||
if matches!(key_event.code, KeyCode::Esc | KeyCode::Enter) {
|
||||
self.accept();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
match key_event.code {
|
||||
KeyCode::Up | KeyCode::Char('k') => {
|
||||
self.highlight_option(MigrationMenuOption::TryNewModel);
|
||||
}
|
||||
KeyCode::Down | KeyCode::Char('j') => {
|
||||
self.highlight_option(MigrationMenuOption::UseExistingModel);
|
||||
}
|
||||
KeyCode::Char('1') => {
|
||||
self.highlight_option(MigrationMenuOption::TryNewModel);
|
||||
self.accept();
|
||||
}
|
||||
KeyCode::Char('2') => {
|
||||
self.highlight_option(MigrationMenuOption::UseExistingModel);
|
||||
self.reject();
|
||||
}
|
||||
KeyCode::Enter | KeyCode::Esc => {
|
||||
self.confirm_selection();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,11 +219,7 @@ impl ModelMigrationScreen {
|
||||
}
|
||||
|
||||
fn outcome(&self) -> ModelMigrationOutcome {
|
||||
if self.should_exit {
|
||||
ModelMigrationOutcome::Exit
|
||||
} else {
|
||||
ModelMigrationOutcome::Accepted
|
||||
}
|
||||
self.outcome
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,25 +247,56 @@ impl WidgetRef for &ModelMigrationScreen {
|
||||
);
|
||||
}
|
||||
|
||||
if self.copy.can_opt_out {
|
||||
column.push(Line::from(""));
|
||||
column.push(
|
||||
Paragraph::new("Choose how you'd like Codex to proceed.")
|
||||
.wrap(Wrap { trim: false })
|
||||
.inset(Insets::tlbr(0, 2, 0, 0)),
|
||||
);
|
||||
column.push(Line::from(""));
|
||||
|
||||
for (idx, option) in MigrationMenuOption::all().into_iter().enumerate() {
|
||||
column.push(selection_option_row(
|
||||
idx,
|
||||
option.label().to_string(),
|
||||
self.highlighted_option == option,
|
||||
));
|
||||
}
|
||||
|
||||
column.push(Line::from(""));
|
||||
column.push(
|
||||
Line::from(vec![
|
||||
"Use ".dim(),
|
||||
key_hint::plain(KeyCode::Up).into(),
|
||||
"/".dim(),
|
||||
key_hint::plain(KeyCode::Down).into(),
|
||||
" to move, press ".dim(),
|
||||
key_hint::plain(KeyCode::Enter).into(),
|
||||
" to confirm".dim(),
|
||||
])
|
||||
.inset(Insets::tlbr(0, 2, 0, 0)),
|
||||
);
|
||||
}
|
||||
|
||||
column.render(area, buf);
|
||||
}
|
||||
}
|
||||
|
||||
fn arcticfox_migration_copy() -> ModelMigrationCopy {
|
||||
fn gpt_5_1_codex_max_migration_copy() -> ModelMigrationCopy {
|
||||
ModelMigrationCopy {
|
||||
heading: vec!["Introducing arcticfox".bold()],
|
||||
heading: vec!["Codex just got an upgrade. Introducing gpt-5.1-codex-max".bold()],
|
||||
content: vec![
|
||||
Line::from("We've upgraded our family of models supported in Codex to arcticfox."),
|
||||
Line::from(
|
||||
"You can continue using legacy models by specifying them directly with the -m option or in your config.toml.",
|
||||
"Codex is now powered by gpt-5.1-codex-max, our latest frontier agentic coding model. It is smarter and faster than its predecessors and capable of long-running project-scale work.",
|
||||
),
|
||||
Line::from(vec![
|
||||
"Learn more at ".into(),
|
||||
"www.openai.com/index/arcticfox".cyan().underlined(),
|
||||
"www.openai.com/index/gpt-5-1-codex-max".cyan().underlined(),
|
||||
".".into(),
|
||||
]),
|
||||
Line::from(vec!["Press enter to continue".dim()]),
|
||||
],
|
||||
can_opt_out: true,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,13 +317,14 @@ fn gpt5_migration_copy() -> ModelMigrationCopy {
|
||||
]),
|
||||
Line::from(vec!["Press enter to continue".dim()]),
|
||||
],
|
||||
can_opt_out: false,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::ModelMigrationScreen;
|
||||
use super::arcticfox_migration_copy;
|
||||
use super::gpt_5_1_codex_max_migration_copy;
|
||||
use super::migration_copy_for_config;
|
||||
use crate::custom_terminal::Terminal;
|
||||
use crate::test_backend::VT100Backend;
|
||||
@@ -231,13 +338,15 @@ mod tests {
|
||||
#[test]
|
||||
fn prompt_snapshot() {
|
||||
let width: u16 = 60;
|
||||
let height: u16 = 12;
|
||||
let height: u16 = 20;
|
||||
let backend = VT100Backend::new(width, height);
|
||||
let mut terminal = Terminal::with_options(backend).expect("terminal");
|
||||
terminal.set_viewport_area(Rect::new(0, 0, width, height));
|
||||
|
||||
let screen =
|
||||
ModelMigrationScreen::new(FrameRequester::test_dummy(), arcticfox_migration_copy());
|
||||
let screen = ModelMigrationScreen::new(
|
||||
FrameRequester::test_dummy(),
|
||||
gpt_5_1_codex_max_migration_copy(),
|
||||
);
|
||||
|
||||
{
|
||||
let mut frame = terminal.get_frame();
|
||||
@@ -304,8 +413,10 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn escape_key_accepts_prompt() {
|
||||
let mut screen =
|
||||
ModelMigrationScreen::new(FrameRequester::test_dummy(), arcticfox_migration_copy());
|
||||
let mut screen = ModelMigrationScreen::new(
|
||||
FrameRequester::test_dummy(),
|
||||
gpt_5_1_codex_max_migration_copy(),
|
||||
);
|
||||
|
||||
// Simulate pressing Escape
|
||||
screen.handle_key(KeyEvent::new(
|
||||
@@ -319,4 +430,27 @@ mod tests {
|
||||
super::ModelMigrationOutcome::Accepted
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn selecting_use_existing_model_rejects_upgrade() {
|
||||
let mut screen = ModelMigrationScreen::new(
|
||||
FrameRequester::test_dummy(),
|
||||
gpt_5_1_codex_max_migration_copy(),
|
||||
);
|
||||
|
||||
screen.handle_key(KeyEvent::new(
|
||||
KeyCode::Down,
|
||||
crossterm::event::KeyModifiers::NONE,
|
||||
));
|
||||
screen.handle_key(KeyEvent::new(
|
||||
KeyCode::Enter,
|
||||
crossterm::event::KeyModifiers::NONE,
|
||||
));
|
||||
|
||||
assert!(screen.is_done());
|
||||
assert!(matches!(
|
||||
screen.outcome(),
|
||||
super::ModelMigrationOutcome::Rejected
|
||||
));
|
||||
}
|
||||
}
|
||||
+11
-7
@@ -2,14 +2,18 @@
|
||||
source: tui/src/model_migration.rs
|
||||
expression: terminal.backend()
|
||||
---
|
||||
> Introducing arcticfox
|
||||
> Codex just got an upgrade. Introducing gpt-5.1-codex-max
|
||||
|
||||
We've upgraded our family of models supported in Codex to
|
||||
arcticfox.
|
||||
Codex is now powered by gpt-5.1-codex-max, our latest
|
||||
frontier agentic coding model. It is smarter and faster
|
||||
than its predecessors and capable of long-running
|
||||
project-scale work.
|
||||
|
||||
You can continue using legacy models by specifying them
|
||||
directly with the -m option or in your config.toml.
|
||||
Learn more at www.openai.com/index/gpt-5-1-codex-max.
|
||||
|
||||
Learn more at www.openai.com/index/arcticfox.
|
||||
Choose how you'd like Codex to proceed.
|
||||
|
||||
Press enter to continue
|
||||
› 1. Try new model
|
||||
2. Use existing model
|
||||
|
||||
Use ↑/↓ to move, press enter to confirm
|
||||
+1
-1
@@ -10,7 +10,7 @@ expression: sanitized
|
||||
│ Visit https://chatgpt.com/codex/settings/usage for up-to-date │
|
||||
│ information on rate limits and credits │
|
||||
│ │
|
||||
│ Model: arcticfox (reasoning none, summaries auto) │
|
||||
│ Model: gpt-5.1-codex-max (reasoning none, summaries auto) │
|
||||
│ Directory: [[workspace]] │
|
||||
│ Approval: on-request │
|
||||
│ Sandbox: read-only │
|
||||
|
||||
+17
-17
@@ -4,20 +4,20 @@ expression: sanitized
|
||||
---
|
||||
/status
|
||||
|
||||
╭───────────────────────────────────────────────────────────────────╮
|
||||
│ >_ OpenAI Codex (v0.0.0) │
|
||||
│ │
|
||||
│ Visit https://chatgpt.com/codex/settings/usage for up-to-date │
|
||||
│ information on rate limits and credits │
|
||||
│ │
|
||||
│ Model: arcticfox (reasoning high, summaries detailed) │
|
||||
│ Directory: [[workspace]] │
|
||||
│ Approval: on-request │
|
||||
│ Sandbox: workspace-write │
|
||||
│ Agents.md: <none> │
|
||||
│ │
|
||||
│ Token usage: 1.9K total (1K input + 900 output) │
|
||||
│ Context window: 100% left (2.25K used / 272K) │
|
||||
│ 5h limit: [██████░░░░░░░░░░░░░░] 28% left (resets 03:14) │
|
||||
│ Weekly limit: [███████████░░░░░░░░░] 55% left (resets 03:24) │
|
||||
╰───────────────────────────────────────────────────────────────────╯
|
||||
╭───────────────────────────────────────────────────────────────────────────╮
|
||||
│ >_ OpenAI Codex (v0.0.0) │
|
||||
│ │
|
||||
│ Visit https://chatgpt.com/codex/settings/usage for up-to-date │
|
||||
│ information on rate limits and credits │
|
||||
│ │
|
||||
│ Model: gpt-5.1-codex-max (reasoning high, summaries detailed) │
|
||||
│ Directory: [[workspace]] │
|
||||
│ Approval: on-request │
|
||||
│ Sandbox: workspace-write │
|
||||
│ Agents.md: <none> │
|
||||
│ │
|
||||
│ Token usage: 1.9K total (1K input + 900 output) │
|
||||
│ Context window: 100% left (2.25K used / 272K) │
|
||||
│ 5h limit: [██████░░░░░░░░░░░░░░] 28% left (resets 03:14) │
|
||||
│ Weekly limit: [███████████░░░░░░░░░] 55% left (resets 03:24) │
|
||||
╰───────────────────────────────────────────────────────────────────────────╯
|
||||
+16
-16
@@ -4,19 +4,19 @@ expression: sanitized
|
||||
---
|
||||
/status
|
||||
|
||||
╭───────────────────────────────────────────────────────────────╮
|
||||
│ >_ OpenAI Codex (v0.0.0) │
|
||||
│ │
|
||||
│ Visit https://chatgpt.com/codex/settings/usage for up-to-date │
|
||||
│ information on rate limits and credits │
|
||||
│ │
|
||||
│ Model: arcticfox (reasoning none, summaries auto) │
|
||||
│ Directory: [[workspace]] │
|
||||
│ Approval: on-request │
|
||||
│ Sandbox: read-only │
|
||||
│ Agents.md: <none> │
|
||||
│ │
|
||||
│ Token usage: 750 total (500 input + 250 output) │
|
||||
│ Context window: 100% left (750 used / 272K) │
|
||||
│ Limits: data not available yet │
|
||||
╰───────────────────────────────────────────────────────────────╯
|
||||
╭───────────────────────────────────────────────────────────────────────╮
|
||||
│ >_ OpenAI Codex (v0.0.0) │
|
||||
│ │
|
||||
│ Visit https://chatgpt.com/codex/settings/usage for up-to-date │
|
||||
│ information on rate limits and credits │
|
||||
│ │
|
||||
│ Model: gpt-5.1-codex-max (reasoning none, summaries auto) │
|
||||
│ Directory: [[workspace]] │
|
||||
│ Approval: on-request │
|
||||
│ Sandbox: read-only │
|
||||
│ Agents.md: <none> │
|
||||
│ │
|
||||
│ Token usage: 750 total (500 input + 250 output) │
|
||||
│ Context window: 100% left (750 used / 272K) │
|
||||
│ Limits: data not available yet │
|
||||
╰───────────────────────────────────────────────────────────────────────╯
|
||||
+16
-16
@@ -4,19 +4,19 @@ expression: sanitized
|
||||
---
|
||||
/status
|
||||
|
||||
╭───────────────────────────────────────────────────────────────╮
|
||||
│ >_ OpenAI Codex (v0.0.0) │
|
||||
│ │
|
||||
│ Visit https://chatgpt.com/codex/settings/usage for up-to-date │
|
||||
│ information on rate limits and credits │
|
||||
│ │
|
||||
│ Model: arcticfox (reasoning none, summaries auto) │
|
||||
│ Directory: [[workspace]] │
|
||||
│ Approval: on-request │
|
||||
│ Sandbox: read-only │
|
||||
│ Agents.md: <none> │
|
||||
│ │
|
||||
│ Token usage: 750 total (500 input + 250 output) │
|
||||
│ Context window: 100% left (750 used / 272K) │
|
||||
│ Limits: data not available yet │
|
||||
╰───────────────────────────────────────────────────────────────╯
|
||||
╭───────────────────────────────────────────────────────────────────────╮
|
||||
│ >_ OpenAI Codex (v0.0.0) │
|
||||
│ │
|
||||
│ Visit https://chatgpt.com/codex/settings/usage for up-to-date │
|
||||
│ information on rate limits and credits │
|
||||
│ │
|
||||
│ Model: gpt-5.1-codex-max (reasoning none, summaries auto) │
|
||||
│ Directory: [[workspace]] │
|
||||
│ Approval: on-request │
|
||||
│ Sandbox: read-only │
|
||||
│ Agents.md: <none> │
|
||||
│ │
|
||||
│ Token usage: 750 total (500 input + 250 output) │
|
||||
│ Context window: 100% left (750 used / 272K) │
|
||||
│ Limits: data not available yet │
|
||||
╰───────────────────────────────────────────────────────────────────────╯
|
||||
+18
-18
@@ -4,21 +4,21 @@ expression: sanitized
|
||||
---
|
||||
/status
|
||||
|
||||
╭─────────────────────────────────────────────────────────────────────╮
|
||||
│ >_ OpenAI Codex (v0.0.0) │
|
||||
│ │
|
||||
│ Visit https://chatgpt.com/codex/settings/usage for up-to-date │
|
||||
│ information on rate limits and credits │
|
||||
│ │
|
||||
│ Model: arcticfox (reasoning none, summaries auto) │
|
||||
│ Directory: [[workspace]] │
|
||||
│ Approval: on-request │
|
||||
│ Sandbox: read-only │
|
||||
│ Agents.md: <none> │
|
||||
│ │
|
||||
│ Token usage: 1.9K total (1K input + 900 output) │
|
||||
│ Context window: 100% left (2.25K used / 272K) │
|
||||
│ 5h limit: [██████░░░░░░░░░░░░░░] 28% left (resets 03:14) │
|
||||
│ Weekly limit: [████████████░░░░░░░░] 60% left (resets 03:34) │
|
||||
│ Warning: limits may be stale - start new turn to refresh. │
|
||||
╰─────────────────────────────────────────────────────────────────────╯
|
||||
╭───────────────────────────────────────────────────────────────────────╮
|
||||
│ >_ OpenAI Codex (v0.0.0) │
|
||||
│ │
|
||||
│ Visit https://chatgpt.com/codex/settings/usage for up-to-date │
|
||||
│ information on rate limits and credits │
|
||||
│ │
|
||||
│ Model: gpt-5.1-codex-max (reasoning none, summaries auto) │
|
||||
│ Directory: [[workspace]] │
|
||||
│ Approval: on-request │
|
||||
│ Sandbox: read-only │
|
||||
│ Agents.md: <none> │
|
||||
│ │
|
||||
│ Token usage: 1.9K total (1K input + 900 output) │
|
||||
│ Context window: 100% left (2.25K used / 272K) │
|
||||
│ 5h limit: [██████░░░░░░░░░░░░░░] 28% left (resets 03:14) │
|
||||
│ Weekly limit: [████████████░░░░░░░░] 60% left (resets 03:34) │
|
||||
│ Warning: limits may be stale - start new turn to refresh. │
|
||||
╰───────────────────────────────────────────────────────────────────────╯
|
||||
+16
-16
@@ -4,19 +4,19 @@ expression: sanitized
|
||||
---
|
||||
/status
|
||||
|
||||
╭───────────────────────────────────────────────────────────────────╮
|
||||
│ >_ OpenAI Codex (v0.0.0) │
|
||||
│ │
|
||||
│ Visit https://chatgpt.com/codex/settings/usage for up-to-date │
|
||||
│ information on rate limits and credits │
|
||||
│ │
|
||||
│ Model: arcticfox (reasoning high, summaries detailed) │
|
||||
│ Directory: [[workspace]] │
|
||||
│ Approval: on-request │
|
||||
│ Sandbox: read-only │
|
||||
│ Agents.md: <none> │
|
||||
│ │
|
||||
│ Token usage: 1.9K total (1K input + 900 output) │
|
||||
│ Context window: 100% left (2.25K used / 272K) │
|
||||
│ 5h limit: [██████░░░░░░░░░░░░░░] 28% left (resets 03:14) │
|
||||
╰───────────────────────────────────────────────────────────────────╯
|
||||
╭────────────────────────────────────────────────────────────────────╮
|
||||
│ >_ OpenAI Codex (v0.0.0) │
|
||||
│ │
|
||||
│ Visit https://chatgpt.com/codex/settings/usage for up-to-date │
|
||||
│ information on rate limits and credits │
|
||||
│ │
|
||||
│ Model: gpt-5.1-codex-max (reasoning high, summaries de │
|
||||
│ Directory: [[workspace]] │
|
||||
│ Approval: on-request │
|
||||
│ Sandbox: read-only │
|
||||
│ Agents.md: <none> │
|
||||
│ │
|
||||
│ Token usage: 1.9K total (1K input + 900 output) │
|
||||
│ Context window: 100% left (2.25K used / 272K) │
|
||||
│ 5h limit: [██████░░░░░░░░░░░░░░] 28% left (resets 03:14) │
|
||||
╰────────────────────────────────────────────────────────────────────╯
|
||||
@@ -81,7 +81,7 @@ fn reset_at_from(captured_at: &chrono::DateTime<chrono::Local>, seconds: i64) ->
|
||||
fn status_snapshot_includes_reasoning_details() {
|
||||
let temp_home = TempDir::new().expect("temp home");
|
||||
let mut config = test_config(&temp_home);
|
||||
config.model = "arcticfox".to_string();
|
||||
config.model = "gpt-5.1-codex-max".to_string();
|
||||
config.model_provider_id = "openai".to_string();
|
||||
config.model_reasoning_effort = Some(ReasoningEffort::High);
|
||||
config.model_reasoning_summary = ReasoningSummary::Detailed;
|
||||
@@ -144,7 +144,7 @@ fn status_snapshot_includes_reasoning_details() {
|
||||
fn status_snapshot_includes_monthly_limit() {
|
||||
let temp_home = TempDir::new().expect("temp home");
|
||||
let mut config = test_config(&temp_home);
|
||||
config.model = "arcticfox".to_string();
|
||||
config.model = "gpt-5.1-codex-max".to_string();
|
||||
config.model_provider_id = "openai".to_string();
|
||||
config.cwd = PathBuf::from("/workspace/tests");
|
||||
|
||||
@@ -194,7 +194,7 @@ fn status_snapshot_includes_monthly_limit() {
|
||||
fn status_card_token_usage_excludes_cached_tokens() {
|
||||
let temp_home = TempDir::new().expect("temp home");
|
||||
let mut config = test_config(&temp_home);
|
||||
config.model = "arcticfox".to_string();
|
||||
config.model = "gpt-5.1-codex-max".to_string();
|
||||
config.cwd = PathBuf::from("/workspace/tests");
|
||||
|
||||
let auth_manager = test_auth_manager(&config);
|
||||
@@ -232,7 +232,7 @@ fn status_card_token_usage_excludes_cached_tokens() {
|
||||
fn status_snapshot_truncates_in_narrow_terminal() {
|
||||
let temp_home = TempDir::new().expect("temp home");
|
||||
let mut config = test_config(&temp_home);
|
||||
config.model = "arcticfox".to_string();
|
||||
config.model = "gpt-5.1-codex-max".to_string();
|
||||
config.model_provider_id = "openai".to_string();
|
||||
config.model_reasoning_effort = Some(ReasoningEffort::High);
|
||||
config.model_reasoning_summary = ReasoningSummary::Detailed;
|
||||
@@ -285,7 +285,7 @@ fn status_snapshot_truncates_in_narrow_terminal() {
|
||||
fn status_snapshot_shows_missing_limits_message() {
|
||||
let temp_home = TempDir::new().expect("temp home");
|
||||
let mut config = test_config(&temp_home);
|
||||
config.model = "arcticfox".to_string();
|
||||
config.model = "gpt-5.1-codex-max".to_string();
|
||||
config.cwd = PathBuf::from("/workspace/tests");
|
||||
|
||||
let auth_manager = test_auth_manager(&config);
|
||||
@@ -325,7 +325,7 @@ fn status_snapshot_shows_missing_limits_message() {
|
||||
fn status_snapshot_shows_empty_limits_message() {
|
||||
let temp_home = TempDir::new().expect("temp home");
|
||||
let mut config = test_config(&temp_home);
|
||||
config.model = "arcticfox".to_string();
|
||||
config.model = "gpt-5.1-codex-max".to_string();
|
||||
config.cwd = PathBuf::from("/workspace/tests");
|
||||
|
||||
let auth_manager = test_auth_manager(&config);
|
||||
@@ -370,7 +370,7 @@ fn status_snapshot_shows_empty_limits_message() {
|
||||
fn status_snapshot_shows_stale_limits_message() {
|
||||
let temp_home = TempDir::new().expect("temp home");
|
||||
let mut config = test_config(&temp_home);
|
||||
config.model = "arcticfox".to_string();
|
||||
config.model = "gpt-5.1-codex-max".to_string();
|
||||
config.cwd = PathBuf::from("/workspace/tests");
|
||||
|
||||
let auth_manager = test_auth_manager(&config);
|
||||
|
||||
Reference in new issue
Block a user