Expose structured service tiers in app-server

This commit is contained in:
Ahmed Ibrahim
2026-05-03 07:24:42 +03:00
parent 93f7d42258
commit 7c33858266
12 changed files with 209 additions and 8 deletions
@@ -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"
}
}
@@ -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"
}
}
@@ -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"
}
}
+7 -1
View File
@@ -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<ReasoningEffortOption>, defaultReasoningEffort: ReasoningEffort, inputModalities: Array<InputModality>, supportsPersonality: boolean, additionalSpeedTiers: Array<string>, 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<ReasoningEffortOption>, defaultReasoningEffort: ReasoningEffort, inputModalities: Array<InputModality>, supportsPersonality: boolean, /**
* Deprecated: use `serviceTiers` for structured service-tier metadata.
*
* @deprecated use `serviceTiers` instead.
*/
additionalSpeedTiers: Array<string>, serviceTiers: Array<ModelServiceTier>, isDefault: boolean, };
@@ -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, };
@@ -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;
@@ -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";
@@ -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<CoreServiceTier> 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<CoreModelAvailabilityNux> 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<CoreModelServiceTier> for ModelServiceTier {
fn from(value: CoreModelServiceTier) -> Self {
Self {
id: value.id.into(),
name: value.name,
description: value.description,
}
}
}
impl From<ModelServiceTier> 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<InputModality>,
#[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<String>,
#[serde(default)]
pub service_tiers: Vec<ModelServiceTier>,
// Only one model should be marked as default.
pub is_default: bool,
}
+1 -1
View File
@@ -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 <feature_name> > config.toml > experimentalFeature/enablement/set (new) > code default.
+1
View File
@@ -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,
}
}
@@ -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,
}
}
@@ -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")
]