Skip to content

Commit 4d180ae

Browse files
authored
Add model availability NUX metadata (#12972)
- replace show_nux with structured availability_nux model metadata - expose availability NUX data through the app-server model API - update shared fixtures and tests for the new field
1 parent f53612d commit 4d180ae

File tree

20 files changed

+148
-46
lines changed

20 files changed

+148
-46
lines changed

codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10225,6 +10225,16 @@
1022510225
},
1022610226
"Model": {
1022710227
"properties": {
10228+
"availabilityNux": {
10229+
"anyOf": [
10230+
{
10231+
"$ref": "#/definitions/v2/ModelAvailabilityNux"
10232+
},
10233+
{
10234+
"type": "null"
10235+
}
10236+
]
10237+
},
1022810238
"defaultReasoningEffort": {
1022910239
"$ref": "#/definitions/v2/ReasoningEffort"
1023010240
},
@@ -10295,6 +10305,17 @@
1029510305
],
1029610306
"type": "object"
1029710307
},
10308+
"ModelAvailabilityNux": {
10309+
"properties": {
10310+
"message": {
10311+
"type": "string"
10312+
}
10313+
},
10314+
"required": [
10315+
"message"
10316+
],
10317+
"type": "object"
10318+
},
1029810319
"ModelListParams": {
1029910320
"$schema": "http://json-schema.org/draft-07/schema#",
1030010321
"properties": {

codex-rs/app-server-protocol/schema/json/v2/ModelListResponse.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,16 @@
2222
},
2323
"Model": {
2424
"properties": {
25+
"availabilityNux": {
26+
"anyOf": [
27+
{
28+
"$ref": "#/definitions/ModelAvailabilityNux"
29+
},
30+
{
31+
"type": "null"
32+
}
33+
]
34+
},
2535
"defaultReasoningEffort": {
2636
"$ref": "#/definitions/ReasoningEffort"
2737
},
@@ -92,6 +102,17 @@
92102
],
93103
"type": "object"
94104
},
105+
"ModelAvailabilityNux": {
106+
"properties": {
107+
"message": {
108+
"type": "string"
109+
}
110+
},
111+
"required": [
112+
"message"
113+
],
114+
"type": "object"
115+
},
95116
"ModelUpgradeInfo": {
96117
"properties": {
97118
"migrationMarkdown": {

codex-rs/app-server-protocol/schema/typescript/v2/Model.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
44
import type { InputModality } from "../InputModality";
55
import type { ReasoningEffort } from "../ReasoningEffort";
6+
import type { ModelAvailabilityNux } from "./ModelAvailabilityNux";
67
import type { ModelUpgradeInfo } from "./ModelUpgradeInfo";
78
import type { ReasoningEffortOption } from "./ReasoningEffortOption";
89

9-
export type Model = { id: string, model: string, upgrade: string | null, upgradeInfo: ModelUpgradeInfo | null, displayName: string, description: string, hidden: boolean, supportedReasoningEfforts: Array<ReasoningEffortOption>, defaultReasoningEffort: ReasoningEffort, inputModalities: Array<InputModality>, supportsPersonality: boolean, isDefault: boolean, };
10+
export type Model = { id: string, model: string, upgrade: string | null, upgradeInfo: ModelUpgradeInfo | null, availabilityNux: ModelAvailabilityNux | null, displayName: string, description: string, hidden: boolean, supportedReasoningEfforts: Array<ReasoningEffortOption>, defaultReasoningEffort: ReasoningEffort, inputModalities: Array<InputModality>, supportsPersonality: boolean, isDefault: boolean, };
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// GENERATED CODE! DO NOT MODIFY BY HAND!
2+
3+
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
4+
5+
export type ModelAvailabilityNux = { message: string, };

codex-rs/app-server-protocol/schema/typescript/v2/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ export type { McpToolCallResult } from "./McpToolCallResult";
107107
export type { McpToolCallStatus } from "./McpToolCallStatus";
108108
export type { MergeStrategy } from "./MergeStrategy";
109109
export type { Model } from "./Model";
110+
export type { ModelAvailabilityNux } from "./ModelAvailabilityNux";
110111
export type { ModelListParams } from "./ModelListParams";
111112
export type { ModelListResponse } from "./ModelListResponse";
112113
export type { ModelRerouteReason } from "./ModelRerouteReason";

codex-rs/app-server-protocol/src/protocol/v2.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ use codex_protocol::models::MessagePhase;
3131
use codex_protocol::models::PermissionProfile as CorePermissionProfile;
3232
use codex_protocol::models::ResponseItem;
3333
use codex_protocol::openai_models::InputModality;
34+
use codex_protocol::openai_models::ModelAvailabilityNux as CoreModelAvailabilityNux;
3435
use codex_protocol::openai_models::ReasoningEffort;
3536
use codex_protocol::openai_models::default_input_modalities;
3637
use codex_protocol::parse_command::ParsedCommand as CoreParsedCommand;
@@ -1389,6 +1390,21 @@ pub struct ModelListParams {
13891390
pub include_hidden: Option<bool>,
13901391
}
13911392

1393+
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
1394+
#[serde(rename_all = "camelCase")]
1395+
#[ts(export_to = "v2/")]
1396+
pub struct ModelAvailabilityNux {
1397+
pub message: String,
1398+
}
1399+
1400+
impl From<CoreModelAvailabilityNux> for ModelAvailabilityNux {
1401+
fn from(value: CoreModelAvailabilityNux) -> Self {
1402+
Self {
1403+
message: value.message,
1404+
}
1405+
}
1406+
}
1407+
13921408
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
13931409
#[serde(rename_all = "camelCase")]
13941410
#[ts(export_to = "v2/")]
@@ -1397,6 +1413,7 @@ pub struct Model {
13971413
pub model: String,
13981414
pub upgrade: Option<String>,
13991415
pub upgrade_info: Option<ModelUpgradeInfo>,
1416+
pub availability_nux: Option<ModelAvailabilityNux>,
14001417
pub display_name: String,
14011418
pub description: String,
14021419
pub hidden: bool,

codex-rs/app-server/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ Example with notification opt-out:
142142
- `thread/realtime/stop` — stop the active realtime session for the thread (experimental); returns `{}`.
143143
- `review/start` — kick off Codex’s automated reviewer for a thread; responds like `turn/start` and emits `item/started`/`item/completed` notifications with `enteredReviewMode` and `exitedReviewMode` items, plus a final assistant `agentMessage` containing the review.
144144
- `command/exec` — run a single command under the server sandbox without starting a thread/turn (handy for utilities and validation).
145-
- `model/list` — list available models (set `includeHidden: true` to include entries with `hidden: true`), with reasoning effort options, optional legacy `upgrade` model ids, and optional `upgradeInfo` metadata (`model`, `upgradeCopy`, `modelLink`, `migrationMarkdown`).
145+
- `model/list` — list available models (set `includeHidden: true` to include entries with `hidden: true`), with reasoning effort options, optional legacy `upgrade` model ids, optional `upgradeInfo` metadata (`model`, `upgradeCopy`, `modelLink`, `migrationMarkdown`), and optional `availabilityNux` metadata.
146146
- `experimentalFeature/list` — list feature flags with stage metadata (`beta`, `underDevelopment`, `stable`, etc.), enabled/default-enabled state, and cursor pagination. For non-beta flags, `displayName`/`description`/`announcement` are `null`.
147147
- `collaborationMode/list` — list available collaboration mode presets (experimental, no pagination). This response omits built-in developer instructions; clients should either pass `settings.developer_instructions: null` when setting a mode to use Codex's built-in instructions, or provide their own instructions explicitly.
148148
- `skills/list` — list skills for one or more `cwd` values (optional `forceReload`).

codex-rs/app-server/src/models.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ fn model_from_preset(preset: ModelPreset) -> Model {
3232
model_link: upgrade.model_link.clone(),
3333
migration_markdown: upgrade.migration_markdown.clone(),
3434
}),
35+
availability_nux: preset.availability_nux.map(Into::into),
3536
display_name: preset.display_name.to_string(),
3637
description: preset.description.to_string(),
3738
hidden: !preset.show_in_picker,

codex-rs/app-server/tests/common/models_cache.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ fn preset_to_info(preset: &ModelPreset, priority: i32) -> ModelInfo {
3434
default_reasoning_summary: ReasoningSummary::Auto,
3535
support_verbosity: false,
3636
default_verbosity: None,
37+
availability_nux: None,
3738
apply_patch_tool_type: None,
3839
truncation_policy: TruncationPolicyConfig::bytes(10_000),
3940
supports_parallel_tool_calls: false,

codex-rs/app-server/tests/suite/v2/model_list.rs

Lines changed: 1 addition & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ fn model_from_preset(preset: &ModelPreset) -> Model {
3131
model_link: upgrade.model_link.clone(),
3232
migration_markdown: upgrade.migration_markdown.clone(),
3333
}),
34+
availability_nux: preset.availability_nux.clone().map(Into::into),
3435
display_name: preset.display_name.clone(),
3536
description: preset.description.clone(),
3637
hidden: !preset.show_in_picker,
@@ -134,50 +135,6 @@ async fn list_models_includes_hidden_models() -> Result<()> {
134135
Ok(())
135136
}
136137

137-
#[tokio::test]
138-
async fn list_models_returns_upgrade_info_metadata() -> Result<()> {
139-
let codex_home = TempDir::new()?;
140-
write_models_cache(codex_home.path())?;
141-
let mut mcp = McpProcess::new(codex_home.path()).await?;
142-
143-
timeout(DEFAULT_TIMEOUT, mcp.initialize()).await??;
144-
145-
let request_id = mcp
146-
.send_list_models_request(ModelListParams {
147-
limit: Some(100),
148-
cursor: None,
149-
include_hidden: Some(true),
150-
})
151-
.await?;
152-
153-
let response: JSONRPCResponse = timeout(
154-
DEFAULT_TIMEOUT,
155-
mcp.read_stream_until_response_message(RequestId::Integer(request_id)),
156-
)
157-
.await??;
158-
159-
let ModelListResponse { data: items, .. } = to_response::<ModelListResponse>(response)?;
160-
161-
let item = items
162-
.iter()
163-
.find(|item| item.upgrade_info.is_some())
164-
.expect("expected at least one model with upgrade info");
165-
let upgrade_info = item
166-
.upgrade_info
167-
.as_ref()
168-
.expect("expected upgrade info to be populated");
169-
170-
assert_eq!(item.upgrade.as_ref(), Some(&upgrade_info.model));
171-
assert!(!upgrade_info.model.is_empty());
172-
assert!(
173-
upgrade_info.upgrade_copy.is_some()
174-
|| upgrade_info.model_link.is_some()
175-
|| upgrade_info.migration_markdown.is_some()
176-
);
177-
178-
Ok(())
179-
}
180-
181138
#[tokio::test]
182139
async fn list_models_pagination_works() -> Result<()> {
183140
let codex_home = TempDir::new()?;

0 commit comments

Comments
 (0)