mirror of
https://github.com/openai/codex.git
synced 2026-05-19 10:43:38 +00:00
## Why The model list needs to carry display-ready service tier metadata so clients can render tier choices with stable IDs, names, and descriptions. A raw speed-tier string list is not enough for richer UI copy or future tier labels. ## What changed - Added `ModelServiceTier` to shared model metadata with string `id`, `name`, and `description` fields. - Added `service_tiers` to `ModelInfo` and `ModelPreset`, preserving empty defaults for older cached model payloads. - Exposed `serviceTiers` on app-server v2 `Model` responses and threaded it through TUI app-server model conversion. - Marked legacy `additional_speed_tiers` / `additionalSpeedTiers` metadata as deprecated in source and generated schema output. - Regenerated app-server protocol JSON schema and TypeScript fixtures, including `ModelServiceTier.ts`. ## Verification - Ran `just write-app-server-schema`. - Did not run local tests per repo instruction; relying on PR CI. --------- Co-authored-by: Codex <noreply@openai.com>
123 lines
5.1 KiB
Rust
123 lines
5.1 KiB
Rust
use codex_protocol::config_types::ReasoningSummary;
|
|
use codex_protocol::openai_models::ConfigShellToolType;
|
|
use codex_protocol::openai_models::ModelInfo;
|
|
use codex_protocol::openai_models::ModelInstructionsVariables;
|
|
use codex_protocol::openai_models::ModelMessages;
|
|
use codex_protocol::openai_models::ModelVisibility;
|
|
use codex_protocol::openai_models::TruncationMode;
|
|
use codex_protocol::openai_models::TruncationPolicyConfig;
|
|
use codex_protocol::openai_models::WebSearchToolType;
|
|
use codex_protocol::openai_models::default_input_modalities;
|
|
|
|
use crate::config::ModelsManagerConfig;
|
|
use codex_utils_output_truncation::approx_bytes_for_tokens;
|
|
use tracing::warn;
|
|
|
|
pub const BASE_INSTRUCTIONS: &str = include_str!("../prompt.md");
|
|
const DEFAULT_PERSONALITY_HEADER: &str = "You are Codex, a coding agent based on GPT-5. You and the user share the same workspace and collaborate to achieve the user's goals.";
|
|
const LOCAL_FRIENDLY_TEMPLATE: &str =
|
|
"You optimize for team morale and being a supportive teammate as much as code quality.";
|
|
const LOCAL_PRAGMATIC_TEMPLATE: &str = "You are a deeply pragmatic, effective software engineer.";
|
|
const PERSONALITY_PLACEHOLDER: &str = "{{ personality }}";
|
|
|
|
pub fn with_config_overrides(mut model: ModelInfo, config: &ModelsManagerConfig) -> ModelInfo {
|
|
if let Some(supports_reasoning_summaries) = config.model_supports_reasoning_summaries
|
|
&& supports_reasoning_summaries
|
|
{
|
|
model.supports_reasoning_summaries = true;
|
|
}
|
|
if let Some(context_window) = config.model_context_window {
|
|
model.context_window = Some(
|
|
model
|
|
.max_context_window
|
|
.map_or(context_window, |max_context_window| {
|
|
context_window.min(max_context_window)
|
|
}),
|
|
);
|
|
}
|
|
if let Some(auto_compact_token_limit) = config.model_auto_compact_token_limit {
|
|
model.auto_compact_token_limit = Some(auto_compact_token_limit);
|
|
}
|
|
if let Some(token_limit) = config.tool_output_token_limit {
|
|
model.truncation_policy = match model.truncation_policy.mode {
|
|
TruncationMode::Bytes => {
|
|
let byte_limit =
|
|
i64::try_from(approx_bytes_for_tokens(token_limit)).unwrap_or(i64::MAX);
|
|
TruncationPolicyConfig::bytes(byte_limit)
|
|
}
|
|
TruncationMode::Tokens => {
|
|
let limit = i64::try_from(token_limit).unwrap_or(i64::MAX);
|
|
TruncationPolicyConfig::tokens(limit)
|
|
}
|
|
};
|
|
}
|
|
|
|
if let Some(base_instructions) = &config.base_instructions {
|
|
model.base_instructions = base_instructions.clone();
|
|
model.model_messages = None;
|
|
} else if !config.personality_enabled {
|
|
model.model_messages = None;
|
|
}
|
|
|
|
model
|
|
}
|
|
|
|
/// Build a minimal fallback model descriptor for missing/unknown slugs.
|
|
pub fn model_info_from_slug(slug: &str) -> ModelInfo {
|
|
warn!("Unknown model {slug} is used. This will use fallback model metadata.");
|
|
ModelInfo {
|
|
slug: slug.to_string(),
|
|
display_name: slug.to_string(),
|
|
description: None,
|
|
default_reasoning_level: None,
|
|
supported_reasoning_levels: Vec::new(),
|
|
shell_type: ConfigShellToolType::Default,
|
|
visibility: ModelVisibility::None,
|
|
supported_in_api: true,
|
|
priority: 99,
|
|
additional_speed_tiers: Vec::new(),
|
|
service_tiers: Vec::new(),
|
|
availability_nux: None,
|
|
upgrade: None,
|
|
base_instructions: BASE_INSTRUCTIONS.to_string(),
|
|
model_messages: local_personality_messages_for_slug(slug),
|
|
supports_reasoning_summaries: false,
|
|
default_reasoning_summary: ReasoningSummary::Auto,
|
|
support_verbosity: false,
|
|
default_verbosity: None,
|
|
apply_patch_tool_type: None,
|
|
web_search_tool_type: WebSearchToolType::Text,
|
|
truncation_policy: TruncationPolicyConfig::bytes(/*limit*/ 10_000),
|
|
supports_parallel_tool_calls: false,
|
|
supports_image_detail_original: false,
|
|
context_window: Some(272_000),
|
|
max_context_window: Some(272_000),
|
|
auto_compact_token_limit: None,
|
|
effective_context_window_percent: 95,
|
|
experimental_supported_tools: Vec::new(),
|
|
input_modalities: default_input_modalities(),
|
|
used_fallback_model_metadata: true, // this is the fallback model metadata
|
|
supports_search_tool: false,
|
|
}
|
|
}
|
|
|
|
fn local_personality_messages_for_slug(slug: &str) -> Option<ModelMessages> {
|
|
match slug {
|
|
"gpt-5.2-codex" | "exp-codex-personality" => Some(ModelMessages {
|
|
instructions_template: Some(format!(
|
|
"{DEFAULT_PERSONALITY_HEADER}\n\n{PERSONALITY_PLACEHOLDER}\n\n{BASE_INSTRUCTIONS}"
|
|
)),
|
|
instructions_variables: Some(ModelInstructionsVariables {
|
|
personality_default: Some(String::new()),
|
|
personality_friendly: Some(LOCAL_FRIENDLY_TEMPLATE.to_string()),
|
|
personality_pragmatic: Some(LOCAL_PRAGMATIC_TEMPLATE.to_string()),
|
|
}),
|
|
}),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
#[path = "model_info_tests.rs"]
|
|
mod tests;
|