diff --git a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json index f856b43d66..40658e2ec0 100644 --- a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json +++ b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json @@ -11212,11 +11212,20 @@ "properties": { "additionalSpeedTiers": { "default": [], + "deprecated": true, + "description": "Deprecated: use `serviceTiers` for structured service-tier metadata.\n\n@deprecated use `serviceTiers` instead.", "items": { "type": "string" }, "type": "array" }, + "serviceTiers": { + "default": [], + "items": { + "$ref": "#/definitions/v2/ModelServiceTier" + }, + "type": "array" + }, "availabilityNux": { "anyOf": [ { @@ -11308,6 +11317,25 @@ ], "type": "object" }, + "ModelServiceTier": { + "properties": { + "description": { + "type": "string" + }, + "id": { + "$ref": "#/definitions/v2/ServiceTierId" + }, + "name": { + "type": "string" + } + }, + "required": [ + "description", + "id", + "name" + ], + "type": "object" + }, "ModelListParams": { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { @@ -14236,6 +14264,9 @@ ], "type": "string" }, + "ServiceTierId": { + "type": "string" + }, "SessionMigration": { "properties": { "cwd": { @@ -18239,4 +18270,4 @@ }, "title": "CodexAppServerProtocol", "type": "object" -} \ No newline at end of file +} diff --git a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json index c17efe7a45..a4aabd6ded 100644 --- a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json +++ b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json @@ -7865,11 +7865,20 @@ "properties": { "additionalSpeedTiers": { "default": [], + "deprecated": true, + "description": "Deprecated: use `serviceTiers` for structured service-tier metadata.\n\n@deprecated use `serviceTiers` instead.", "items": { "type": "string" }, "type": "array" }, + "serviceTiers": { + "default": [], + "items": { + "$ref": "#/definitions/ModelServiceTier" + }, + "type": "array" + }, "availabilityNux": { "anyOf": [ { @@ -7961,6 +7970,25 @@ ], "type": "object" }, + "ModelServiceTier": { + "properties": { + "description": { + "type": "string" + }, + "id": { + "$ref": "#/definitions/ServiceTierId" + }, + "name": { + "type": "string" + } + }, + "required": [ + "description", + "id", + "name" + ], + "type": "object" + }, "ModelListParams": { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { @@ -12122,6 +12150,9 @@ ], "type": "string" }, + "ServiceTierId": { + "type": "string" + }, "SessionMigration": { "properties": { "cwd": { @@ -16124,4 +16155,4 @@ }, "title": "CodexAppServerProtocolV2", "type": "object" -} \ No newline at end of file +} diff --git a/codex-rs/app-server-protocol/schema/json/v2/ModelListResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ModelListResponse.json index dc60c5b770..44b028c96e 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ModelListResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ModelListResponse.json @@ -24,11 +24,20 @@ "properties": { "additionalSpeedTiers": { "default": [], + "deprecated": true, + "description": "Deprecated: use `serviceTiers` for structured service-tier metadata.\n\n@deprecated use `serviceTiers` instead.", "items": { "type": "string" }, "type": "array" }, + "serviceTiers": { + "default": [], + "items": { + "$ref": "#/definitions/ModelServiceTier" + }, + "type": "array" + }, "availabilityNux": { "anyOf": [ { @@ -120,6 +129,25 @@ ], "type": "object" }, + "ModelServiceTier": { + "properties": { + "description": { + "type": "string" + }, + "id": { + "$ref": "#/definitions/ServiceTierId" + }, + "name": { + "type": "string" + } + }, + "required": [ + "description", + "id", + "name" + ], + "type": "object" + }, "ModelUpgradeInfo": { "properties": { "migrationMarkdown": { @@ -175,6 +203,9 @@ "reasoningEffort" ], "type": "object" + }, + "ServiceTierId": { + "type": "string" } }, "properties": { @@ -197,4 +228,4 @@ ], "title": "ModelListResponse", "type": "object" -} \ No newline at end of file +} diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/Model.ts b/codex-rs/app-server-protocol/schema/typescript/v2/Model.ts index f4cf5a9462..6a770d941b 100644 --- a/codex-rs/app-server-protocol/schema/typescript/v2/Model.ts +++ b/codex-rs/app-server-protocol/schema/typescript/v2/Model.ts @@ -4,7 +4,13 @@ import type { InputModality } from "../InputModality"; import type { ReasoningEffort } from "../ReasoningEffort"; import type { ModelAvailabilityNux } from "./ModelAvailabilityNux"; +import type { ModelServiceTier } from "./ModelServiceTier"; import type { ModelUpgradeInfo } from "./ModelUpgradeInfo"; import type { ReasoningEffortOption } from "./ReasoningEffortOption"; -export type Model = { id: string, model: string, upgrade: string | null, upgradeInfo: ModelUpgradeInfo | null, availabilityNux: ModelAvailabilityNux | null, displayName: string, description: string, hidden: boolean, supportedReasoningEfforts: Array, defaultReasoningEffort: ReasoningEffort, inputModalities: Array, supportsPersonality: boolean, additionalSpeedTiers: Array, isDefault: boolean, }; +export type Model = { id: string, model: string, upgrade: string | null, upgradeInfo: ModelUpgradeInfo | null, availabilityNux: ModelAvailabilityNux | null, displayName: string, description: string, hidden: boolean, supportedReasoningEfforts: Array, defaultReasoningEffort: ReasoningEffort, inputModalities: Array, supportsPersonality: boolean, /** + * Deprecated: use `serviceTiers` for structured service-tier metadata. + * + * @deprecated use `serviceTiers` instead. + */ +additionalSpeedTiers: Array, serviceTiers: Array, isDefault: boolean, }; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/ModelServiceTier.ts b/codex-rs/app-server-protocol/schema/typescript/v2/ModelServiceTier.ts new file mode 100644 index 0000000000..5b7392e0f7 --- /dev/null +++ b/codex-rs/app-server-protocol/schema/typescript/v2/ModelServiceTier.ts @@ -0,0 +1,6 @@ +// GENERATED CODE! DO NOT MODIFY BY HAND! + +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { ServiceTierId } from "./ServiceTierId"; + +export type ModelServiceTier = { id: ServiceTierId, name: string, description: string, }; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/ServiceTierId.ts b/codex-rs/app-server-protocol/schema/typescript/v2/ServiceTierId.ts new file mode 100644 index 0000000000..30b5d53c4a --- /dev/null +++ b/codex-rs/app-server-protocol/schema/typescript/v2/ServiceTierId.ts @@ -0,0 +1,5 @@ +// GENERATED CODE! DO NOT MODIFY BY HAND! + +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type ServiceTierId = string; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/index.ts b/codex-rs/app-server-protocol/schema/typescript/v2/index.ts index d369ba3423..445d91883b 100644 --- a/codex-rs/app-server-protocol/schema/typescript/v2/index.ts +++ b/codex-rs/app-server-protocol/schema/typescript/v2/index.ts @@ -241,6 +241,8 @@ export type { Model } from "./Model"; export type { ModelAvailabilityNux } from "./ModelAvailabilityNux"; export type { ModelListParams } from "./ModelListParams"; export type { ModelListResponse } from "./ModelListResponse"; +export type { ModelServiceTier } from "./ModelServiceTier"; +export type { ServiceTierId } from "./ServiceTierId"; export type { ModelProviderCapabilitiesReadParams } from "./ModelProviderCapabilitiesReadParams"; export type { ModelProviderCapabilitiesReadResponse } from "./ModelProviderCapabilitiesReadResponse"; export type { ModelRerouteReason } from "./ModelRerouteReason"; diff --git a/codex-rs/app-server-protocol/src/protocol/v2.rs b/codex-rs/app-server-protocol/src/protocol/v2.rs index d10d80a50a..9cdf56a185 100644 --- a/codex-rs/app-server-protocol/src/protocol/v2.rs +++ b/codex-rs/app-server-protocol/src/protocol/v2.rs @@ -52,6 +52,7 @@ use codex_protocol::models::PermissionProfile as CorePermissionProfile; use codex_protocol::models::ResponseItem; use codex_protocol::openai_models::InputModality; use codex_protocol::openai_models::ModelAvailabilityNux as CoreModelAvailabilityNux; +use codex_protocol::openai_models::ModelServiceTier as CoreModelServiceTier; use codex_protocol::openai_models::ReasoningEffort; use codex_protocol::openai_models::default_input_modalities; use codex_protocol::parse_command::ParsedCommand as CoreParsedCommand; @@ -154,6 +155,29 @@ impl TryFrom<&CoreServiceTier> for ServiceTier { } } +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] +#[serde(transparent)] +#[ts(type = "string", export_to = "v2/")] +pub struct ServiceTierId(pub String); + +impl ServiceTierId { + pub fn into_core(self) -> CoreServiceTier { + CoreServiceTier::new(self.0) + } +} + +impl From for ServiceTierId { + fn from(value: CoreServiceTier) -> Self { + Self(value.to_string()) + } +} + +impl From<&CoreServiceTier> for ServiceTierId { + fn from(value: &CoreServiceTier) -> Self { + Self(value.to_string()) + } +} + // Macro to declare a camelCased API v2 enum mirroring a core enum which // tends to use either snake_case or kebab-case. macro_rules! v2_enum_from_core { @@ -2542,6 +2566,35 @@ impl From for ModelAvailabilityNux { } } +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] +#[serde(rename_all = "camelCase")] +#[ts(export_to = "v2/")] +pub struct ModelServiceTier { + pub id: ServiceTierId, + pub name: String, + pub description: String, +} + +impl From for ModelServiceTier { + fn from(value: CoreModelServiceTier) -> Self { + Self { + id: value.id.into(), + name: value.name, + description: value.description, + } + } +} + +impl From for CoreModelServiceTier { + fn from(value: ModelServiceTier) -> Self { + Self { + id: value.id.into_core(), + name: value.name, + description: value.description, + } + } +} + #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] @@ -2560,8 +2613,13 @@ pub struct Model { pub input_modalities: Vec, #[serde(default)] pub supports_personality: bool, + /// Deprecated: use `serviceTiers` for structured service-tier metadata. + /// + /// @deprecated use `serviceTiers` instead. #[serde(default)] pub additional_speed_tiers: Vec, + #[serde(default)] + pub service_tiers: Vec, // Only one model should be marked as default. pub is_default: bool, } diff --git a/codex-rs/app-server/README.md b/codex-rs/app-server/README.md index dab47ec3a2..a910647fa7 100644 --- a/codex-rs/app-server/README.md +++ b/codex-rs/app-server/README.md @@ -191,7 +191,7 @@ Example with notification opt-out: - `fs/watch` — subscribe this connection to filesystem change notifications for an absolute file or directory path and caller-provided `watchId`; returns the canonicalized `path`. - `fs/unwatch` — stop sending notifications for a prior `fs/watch`; returns `{}`. - `fs/changed` — notification emitted when watched paths change, including the `watchId` and `changedPaths`. -- `model/list` — list available models (set `includeHidden: true` to include entries with `hidden: true`), with reasoning effort options, `additionalSpeedTiers`, optional legacy `upgrade` model ids, optional `upgradeInfo` metadata (`model`, `upgradeCopy`, `modelLink`, `migrationMarkdown`), and optional `availabilityNux` metadata. +- `model/list` — list available models (set `includeHidden: true` to include entries with `hidden: true`), with reasoning effort options, `serviceTiers` (`id`, `name`, `description`), deprecated `additionalSpeedTiers`, optional legacy `upgrade` model ids, optional `upgradeInfo` metadata (`model`, `upgradeCopy`, `modelLink`, `migrationMarkdown`), and optional `availabilityNux` metadata. - `modelProvider/capabilities/read` — read provider-level capabilities for the currently configured model provider. - `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`. - `experimentalFeature/enablement/set` — patch the in-memory process-wide runtime feature enablement for the currently supported feature keys (`apps`, `memories`, `plugins`, `remote_control`, `tool_search`, `tool_suggest`, `tool_call_mcp_elicitation`). For each feature, precedence is: cloud requirements > --enable > config.toml > experimentalFeature/enablement/set (new) > code default. diff --git a/codex-rs/app-server/src/models.rs b/codex-rs/app-server/src/models.rs index 4095893b20..a805eee06a 100644 --- a/codex-rs/app-server/src/models.rs +++ b/codex-rs/app-server/src/models.rs @@ -46,6 +46,7 @@ fn model_from_preset(preset: ModelPreset) -> Model { input_modalities: preset.input_modalities, supports_personality: preset.supports_personality, additional_speed_tiers, + service_tiers: preset.service_tiers.into_iter().map(Into::into).collect(), is_default: preset.is_default, } } diff --git a/codex-rs/app-server/tests/suite/v2/model_list.rs b/codex-rs/app-server/tests/suite/v2/model_list.rs index 26593e6f32..3fc0819dea 100644 --- a/codex-rs/app-server/tests/suite/v2/model_list.rs +++ b/codex-rs/app-server/tests/suite/v2/model_list.rs @@ -53,6 +53,12 @@ fn model_from_preset(preset: &ModelPreset) -> Model { // todo(sayan): fix, maybe make roundtrip use ModelInfo only supports_personality: false, additional_speed_tiers: legacy_additional_speed_tiers(&preset.service_tiers), + service_tiers: preset + .service_tiers + .clone() + .into_iter() + .map(Into::into) + .collect(), is_default: preset.is_default, } } diff --git a/sdk/python/src/codex_app_server/generated/v2_all.py b/sdk/python/src/codex_app_server/generated/v2_all.py index ae85d122cc..5448da3de9 100644 --- a/sdk/python/src/codex_app_server/generated/v2_all.py +++ b/sdk/python/src/codex_app_server/generated/v2_all.py @@ -3524,6 +3524,13 @@ class ServiceTier(Enum): flex = "flex" +class ServiceTierId(RootModel[str]): + model_config = ConfigDict( + populate_by_name=True, + ) + root: str + + class SessionMigration(BaseModel): model_config = ConfigDict( populate_by_name=True, @@ -6314,13 +6321,19 @@ class MigrationDetails(BaseModel): subagents: list[SubagentMigration] | None = [] +class ModelServiceTier(BaseModel): + model_config = ConfigDict( + populate_by_name=True, + ) + description: str + id: ServiceTierId + name: str + + class Model(BaseModel): model_config = ConfigDict( populate_by_name=True, ) - additional_speed_tiers: Annotated[ - list[str] | None, Field(alias="additionalSpeedTiers") - ] = [] availability_nux: Annotated[ ModelAvailabilityNux | None, Field(alias="availabilityNux") ] = None @@ -6336,6 +6349,17 @@ class Model(BaseModel): ] = ["text", "image"] is_default: Annotated[bool, Field(alias="isDefault")] model: str + additional_speed_tiers: Annotated[ + list[str] | None, + Field( + alias="additionalSpeedTiers", + description="Deprecated: use `serviceTiers` for structured service-tier metadata.\n\n@deprecated use `serviceTiers` instead.", + json_schema_extra={"deprecated": True}, + ), + ] = [] + service_tiers: Annotated[ + list[ModelServiceTier] | None, Field(alias="serviceTiers") + ] = [] supported_reasoning_efforts: Annotated[ list[ReasoningEffortOption], Field(alias="supportedReasoningEfforts") ]