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 ec024d1f0988..256bdbd07130 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 @@ -11210,11 +11210,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": [ { @@ -11306,6 +11315,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": { @@ -14149,6 +14177,9 @@ ], "type": "string" }, + "ServiceTierId": { + "type": "string" + }, "SessionMigration": { "properties": { "cwd": { @@ -18230,4 +18261,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 3a18b7cd2180..55e7322fc08a 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 @@ -7864,11 +7864,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": [ { @@ -7960,6 +7969,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": { @@ -12035,6 +12063,9 @@ ], "type": "string" }, + "ServiceTierId": { + "type": "string" + }, "SessionMigration": { "properties": { "cwd": { @@ -16115,4 +16146,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 dc60c5b770bd..44b028c96ebe 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 f4cf5a946232..6a770d941b14 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 000000000000..5b7392e0f7c7 --- /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 000000000000..30b5d53c4a5d --- /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 28de6b108d81..059943d853d1 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 20dc1cb8a4fa..82e9cb2d1000 100644 --- a/codex-rs/app-server-protocol/src/protocol/v2.rs +++ b/codex-rs/app-server-protocol/src/protocol/v2.rs @@ -51,6 +51,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; @@ -153,6 +154,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 From for CoreServiceTier { + fn from(value: ServiceTierId) -> Self { + Self::from(value.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 { @@ -2541,6 +2565,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(), + name: value.name, + description: value.description, + } + } +} + #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] @@ -2559,8 +2612,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 3aae4ae610d6..e0a7ba7a61ac 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 4095893b208c..a805eee06a7f 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 26593e6f3237..3fc0819dea62 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 70c700928602..843acda95024 100644 --- a/sdk/python/src/codex_app_server/generated/v2_all.py +++ b/sdk/python/src/codex_app_server/generated/v2_all.py @@ -3348,6 +3348,13 @@ class ServiceTier(Enum): flex = "flex" +class ServiceTierId(RootModel[str]): + model_config = ConfigDict( + populate_by_name=True, + ) + root: str + + class SessionSourceValue(Enum): cli = "cli" vscode = "vscode" @@ -5854,13 +5861,19 @@ class MigrationDetails(BaseModel): plugins: list[PluginsMigration] +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 @@ -5876,6 +5889,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") ]