Skip to content

Commit b5f566f

Browse files
committed
Release codex infinity 1.3.40
1 parent c0caa48 commit b5f566f

21 files changed

Lines changed: 119 additions & 20 deletions

codex-cli/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@codex-infinity/codex-infinity",
3-
"version": "1.3.39",
3+
"version": "1.3.40",
44
"license": "Apache-2.0",
55
"description": "Codex Infinity - a smarter coding agent that can run forever",
66
"bin": {

codex-rs/core/src/config/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,12 @@ use codex_git_utils::resolve_root_git_project_for_trust;
6666
use codex_login::AuthManagerConfig;
6767
use codex_mcp::McpConfig;
6868
use codex_memories_read::memory_root;
69+
use codex_model_provider_info::GEMINI_PROVIDER_ID;
6970
use codex_model_provider_info::LEGACY_OLLAMA_CHAT_PROVIDER_ID;
7071
use codex_model_provider_info::ModelProviderInfo;
7172
use codex_model_provider_info::OLLAMA_CHAT_PROVIDER_REMOVED_ERROR;
7273
use codex_model_provider_info::OPENAI_PROVIDER_ID;
74+
use codex_model_provider_info::OPENROUTER_PROVIDER_ID;
7375
use codex_model_provider_info::built_in_model_providers;
7476
use codex_model_provider_info::infer_builtin_provider_id_for_model;
7577
use codex_model_provider_info::merge_configured_model_providers;

codex-rs/models-manager/src/manager.rs

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,10 +143,17 @@ pub trait ModelsManager: fmt::Debug + Send + Sync {
143143
refresh_strategy: RefreshStrategy,
144144
) -> String {
145145
async move {
146-
if let Some(model) = model.as_ref() {
146+
if let Some(model) = model.as_ref()
147+
&& model != "latest"
148+
{
147149
return model.to_string();
148150
}
149-
default_model_from_available(self.list_models(refresh_strategy).await)
151+
let available = self.list_models(refresh_strategy).await;
152+
if model.as_deref() == Some("latest") {
153+
return latest_model_from_available(&available)
154+
.unwrap_or_else(|| default_model_from_available(available));
155+
}
156+
default_model_from_available(available)
150157
}
151158
.instrument(tracing::info_span!(
152159
"get_default_model",
@@ -410,6 +417,44 @@ fn default_model_from_available(available: Vec<ModelPreset>) -> String {
410417
.unwrap_or_default()
411418
}
412419

420+
fn latest_model_from_available(available: &[ModelPreset]) -> Option<String> {
421+
available
422+
.iter()
423+
.filter(|model| model.show_in_picker)
424+
.filter(|model| !numeric_parts(&model.model).is_empty())
425+
.max_by(|a, b| compare_model_latest_rank(&a.model, &b.model))
426+
.map(|model| model.model.clone())
427+
}
428+
429+
fn compare_model_latest_rank(a: &str, b: &str) -> std::cmp::Ordering {
430+
numeric_parts(a)
431+
.cmp(&numeric_parts(b))
432+
.then_with(|| a.len().cmp(&b.len()))
433+
.then_with(|| a.cmp(b))
434+
}
435+
436+
fn numeric_parts(model: &str) -> Vec<u64> {
437+
let mut parts = Vec::new();
438+
let mut current: Option<u64> = None;
439+
for c in model.chars() {
440+
if let Some(digit) = c.to_digit(10) {
441+
let digit = u64::from(digit);
442+
current = Some(
443+
current
444+
.unwrap_or_default()
445+
.saturating_mul(10)
446+
.saturating_add(digit),
447+
);
448+
} else if let Some(value) = current.take() {
449+
parts.push(value);
450+
}
451+
}
452+
if let Some(value) = current {
453+
parts.push(value);
454+
}
455+
parts
456+
}
457+
413458
fn find_model_by_longest_prefix(model: &str, candidates: &[ModelInfo]) -> Option<ModelInfo> {
414459
let mut best: Option<ModelInfo> = None;
415460
for candidate in candidates {

codex-rs/models-manager/src/manager_tests.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,57 @@ fn static_manager_for_tests(model_catalog: ModelsResponse) -> StaticModelsManage
203203
)
204204
}
205205

206+
#[tokio::test]
207+
async fn get_default_model_resolves_latest_to_highest_available_model() {
208+
let manager = static_manager_for_tests(ModelsResponse {
209+
models: vec![
210+
remote_model("gpt-5.5", "GPT-5.5", /*priority*/ 2),
211+
remote_model("gpt-5.5-max", "GPT-5.5 Max", /*priority*/ 1),
212+
remote_model("gpt-5.6", "GPT-5.6", /*priority*/ 3),
213+
remote_model("gpt-5.10", "GPT-5.10", /*priority*/ 4),
214+
remote_model("gpt-5.9", "GPT-5.9", /*priority*/ 0),
215+
],
216+
});
217+
218+
let model = manager
219+
.get_default_model(&Some("latest".to_string()), RefreshStrategy::Offline)
220+
.await;
221+
222+
assert_eq!(model, "gpt-5.10");
223+
}
224+
225+
#[tokio::test]
226+
async fn get_default_model_resolves_latest_to_longest_model_when_numbers_tie() {
227+
let manager = static_manager_for_tests(ModelsResponse {
228+
models: vec![
229+
remote_model("gpt-5.5", "GPT-5.5", /*priority*/ 0),
230+
remote_model("gpt-5.5-max", "GPT-5.5 Max", /*priority*/ 1),
231+
],
232+
});
233+
234+
let model = manager
235+
.get_default_model(&Some("latest".to_string()), RefreshStrategy::Offline)
236+
.await;
237+
238+
assert_eq!(model, "gpt-5.5-max");
239+
}
240+
241+
#[tokio::test]
242+
async fn get_default_model_keeps_explicit_model_without_fetching_catalog() {
243+
let codex_home = tempdir().expect("temp dir");
244+
let endpoint = TestModelsEndpoint::new(vec![vec![remote_model(
245+
"gpt-5.6", "GPT-5.6", /*priority*/ 0,
246+
)]]);
247+
let manager = openai_manager_for_tests(codex_home.path().to_path_buf(), endpoint.clone());
248+
249+
let model = manager
250+
.get_default_model(&Some("gpt-custom".to_string()), RefreshStrategy::Online)
251+
.await;
252+
253+
assert_eq!(model, "gpt-custom");
254+
assert_eq!(endpoint.fetch_count(), 0);
255+
}
256+
206257
async fn chatgpt_auth_tokens_for_tests(codex_home: &Path) -> CodexAuth {
207258
let auth_dot_json = codex_login::AuthDotJson {
208259
auth_mode: Some(AuthMode::ChatgptAuthTokens),

codex-rs/tui/src/chatwidget.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,8 @@ use unicode_segmentation::UnicodeSegmentation;
437437
const USER_SHELL_COMMAND_HELP_TITLE: &str = "Prefix a command with ! to run it locally";
438438
const USER_SHELL_COMMAND_HELP_HINT: &str = "Example: !ls";
439439
const DEFAULT_OPENAI_BASE_URL: &str = "https://api.openai.com/v1";
440-
const DEFAULT_STATUS_LINE_ITEMS: [&str; 2] = ["model-with-reasoning", "current-dir"];
440+
const DEFAULT_STATUS_LINE_ITEMS: [&str; 3] =
441+
["model-with-reasoning", "current-dir", "context-remaining"];
441442
// Track information about an in-flight exec command.
442443
struct RunningCommand {
443444
command: Vec<String>,

codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__app_server_guardian_review_denied_renders_denied_request.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,4 @@ expression: normalize_snapshot_paths(term.backend().vt100().screen().contents())
1717

1818
Ask Codex to do anything
1919

20-
gpt-5.5 default · /tmp/project
20+
gpt-5.5 default · /tmp/project · Context 100% left

codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__app_server_guardian_review_timed_out_renders_timed_out_request.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,4 @@ expression: normalize_snapshot_paths(term.backend().vt100().screen().contents())
1717

1818
Ask Codex to do anything
1919

20-
gpt-5.5 default · /tmp/project
20+
gpt-5.5 default · /tmp/project · Context 100% left

codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__app_server_mcp_startup_failure_renders_warning_history.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ expression: normalize_snapshot_paths(term.backend().vt100().screen().contents())
1111

1212
Ask Codex to do anything
1313

14-
gpt-5.5 default · /tmp/project
14+
gpt-5.5 default · /tmp/project · Context 100% left

codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__chatwidget_tall.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,4 @@ expression: normalize_snapshot_paths(term.backend().vt100().screen().contents())
2626

2727
Ask Codex to do anything
2828

29-
gpt-5.5 default · /tmp/project
29+
gpt-5.5 default · /tmp/project · Context 100% left

codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__compact_queues_user_messages_snapshot.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@ expression: normalize_snapshot_paths(term.backend().vt100().screen().contents())
1919

2020
Ask Codex to do anything
2121

22-
gpt-5.5 default · /tmp/project
22+
gpt-5.5 default · /tmp/project · Context 100% left

0 commit comments

Comments
 (0)