mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
support 'flex' tier in app-server in addition to 'fast' (#13391)
This commit is contained in:
committed by
GitHub
Unverified
parent
7134220f3c
commit
4f6c4bb143
@@ -1728,7 +1728,8 @@
|
||||
},
|
||||
"ServiceTier": {
|
||||
"enum": [
|
||||
"fast"
|
||||
"fast",
|
||||
"flex"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -5460,7 +5460,8 @@
|
||||
},
|
||||
"ServiceTier": {
|
||||
"enum": [
|
||||
"fast"
|
||||
"fast",
|
||||
"flex"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -12134,7 +12134,8 @@
|
||||
},
|
||||
"ServiceTier": {
|
||||
"enum": [
|
||||
"fast"
|
||||
"fast",
|
||||
"flex"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -10770,7 +10770,8 @@
|
||||
},
|
||||
"ServiceTier": {
|
||||
"enum": [
|
||||
"fast"
|
||||
"fast",
|
||||
"flex"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -707,7 +707,8 @@
|
||||
},
|
||||
"ServiceTier": {
|
||||
"enum": [
|
||||
"fast"
|
||||
"fast",
|
||||
"flex"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -53,7 +53,8 @@
|
||||
},
|
||||
"ServiceTier": {
|
||||
"enum": [
|
||||
"fast"
|
||||
"fast",
|
||||
"flex"
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
|
||||
@@ -744,7 +744,8 @@
|
||||
},
|
||||
"ServiceTier": {
|
||||
"enum": [
|
||||
"fast"
|
||||
"fast",
|
||||
"flex"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -759,7 +759,8 @@
|
||||
},
|
||||
"ServiceTier": {
|
||||
"enum": [
|
||||
"fast"
|
||||
"fast",
|
||||
"flex"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -744,7 +744,8 @@
|
||||
},
|
||||
"ServiceTier": {
|
||||
"enum": [
|
||||
"fast"
|
||||
"fast",
|
||||
"flex"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -78,7 +78,8 @@
|
||||
},
|
||||
"ServiceTier": {
|
||||
"enum": [
|
||||
"fast"
|
||||
"fast",
|
||||
"flex"
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
|
||||
@@ -744,7 +744,8 @@
|
||||
},
|
||||
"ServiceTier": {
|
||||
"enum": [
|
||||
"fast"
|
||||
"fast",
|
||||
"flex"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -305,7 +305,8 @@
|
||||
},
|
||||
"ServiceTier": {
|
||||
"enum": [
|
||||
"fast"
|
||||
"fast",
|
||||
"flex"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type ServiceTier = "fast";
|
||||
export type ServiceTier = "fast" | "flex";
|
||||
|
||||
@@ -180,6 +180,7 @@ Start a fresh thread when you need a new Codex conversation.
|
||||
"approvalPolicy": "never",
|
||||
"sandbox": "workspaceWrite",
|
||||
"personality": "friendly",
|
||||
"serviceTier": "flex",
|
||||
"serviceName": "my_app_server_client", // optional metrics tag (`service_name`)
|
||||
// Experimental: requires opt-in
|
||||
"dynamicTools": [
|
||||
@@ -208,6 +209,7 @@ Start a fresh thread when you need a new Codex conversation.
|
||||
```
|
||||
|
||||
Valid `personality` values are `"friendly"`, `"pragmatic"`, and `"none"`. When `"none"` is selected, the personality placeholder is replaced with an empty string.
|
||||
Valid `serviceTier` values are `"fast"` and `"flex"`.
|
||||
|
||||
To continue a stored session, call `thread/resume` with the `thread.id` you previously recorded. The response shape matches `thread/start`, and no additional notifications are emitted. You can also pass the same configuration overrides supported by `thread/start`, such as `personality`:
|
||||
|
||||
@@ -415,6 +417,7 @@ You can optionally specify config overrides on the new turn. If specified, these
|
||||
"networkAccess": true
|
||||
},
|
||||
"model": "gpt-5.1-codex",
|
||||
"serviceTier": "flex",
|
||||
"effort": "medium",
|
||||
"summary": "concise",
|
||||
"personality": "friendly",
|
||||
|
||||
@@ -12,6 +12,7 @@ use codex_app_server_protocol::ThreadStartedNotification;
|
||||
use codex_app_server_protocol::ThreadStatus;
|
||||
use codex_app_server_protocol::ThreadStatusChangedNotification;
|
||||
use codex_core::config::set_project_trust_level;
|
||||
use codex_protocol::config_types::ServiceTier;
|
||||
use codex_protocol::config_types::TrustLevel;
|
||||
use codex_protocol::openai_models::ReasoningEffort;
|
||||
use pretty_assertions::assert_eq;
|
||||
@@ -180,6 +181,34 @@ model_reasoning_effort = "high"
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn thread_start_accepts_flex_service_tier() -> Result<()> {
|
||||
let server = create_mock_responses_server_repeating_assistant("Done").await;
|
||||
|
||||
let codex_home = TempDir::new()?;
|
||||
create_config_toml(codex_home.path(), &server.uri())?;
|
||||
|
||||
let mut mcp = McpProcess::new(codex_home.path()).await?;
|
||||
timeout(DEFAULT_READ_TIMEOUT, mcp.initialize()).await??;
|
||||
|
||||
let req_id = mcp
|
||||
.send_thread_start_request(ThreadStartParams {
|
||||
service_tier: Some(Some(ServiceTier::Flex)),
|
||||
..Default::default()
|
||||
})
|
||||
.await?;
|
||||
|
||||
let resp: JSONRPCResponse = timeout(
|
||||
DEFAULT_READ_TIMEOUT,
|
||||
mcp.read_stream_until_response_message(RequestId::Integer(req_id)),
|
||||
)
|
||||
.await??;
|
||||
let ThreadStartResponse { service_tier, .. } = to_response::<ThreadStartResponse>(resp)?;
|
||||
|
||||
assert_eq!(service_tier, Some(ServiceTier::Flex));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn thread_start_accepts_metrics_service_name() -> Result<()> {
|
||||
let server = create_mock_responses_server_repeating_assistant("Done").await;
|
||||
|
||||
@@ -1336,7 +1336,8 @@
|
||||
},
|
||||
"ServiceTier": {
|
||||
"enum": [
|
||||
"fast"
|
||||
"fast",
|
||||
"flex"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
@@ -2146,7 +2147,7 @@
|
||||
"$ref": "#/definitions/ServiceTier"
|
||||
}
|
||||
],
|
||||
"description": "Optional explicit service tier preference for new turns."
|
||||
"description": "Optional explicit service tier preference for new turns (`fast` or `flex`)."
|
||||
},
|
||||
"shell_environment_policy": {
|
||||
"allOf": [
|
||||
|
||||
@@ -546,7 +546,8 @@ impl ModelClientSession {
|
||||
include,
|
||||
service_tier: match service_tier {
|
||||
Some(ServiceTier::Fast) => Some("priority".to_string()),
|
||||
_ => None,
|
||||
Some(service_tier) => Some(service_tier.to_string()),
|
||||
None => None,
|
||||
},
|
||||
prompt_cache_key,
|
||||
text,
|
||||
|
||||
@@ -234,6 +234,7 @@ mod tests {
|
||||
use codex_api::common::OpenAiVerbosity;
|
||||
use codex_api::common::TextControls;
|
||||
use codex_api::create_text_param_for_request;
|
||||
use codex_protocol::config_types::ServiceTier;
|
||||
use codex_protocol::models::FunctionCallOutputPayload;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
@@ -342,6 +343,31 @@ mod tests {
|
||||
assert!(v.get("text").is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serializes_flex_service_tier_when_set() {
|
||||
let req = ResponsesApiRequest {
|
||||
model: "gpt-5.1".to_string(),
|
||||
instructions: "i".to_string(),
|
||||
input: vec![],
|
||||
tools: vec![],
|
||||
tool_choice: "auto".to_string(),
|
||||
parallel_tool_calls: true,
|
||||
reasoning: None,
|
||||
store: false,
|
||||
stream: true,
|
||||
include: vec![],
|
||||
prompt_cache_key: None,
|
||||
service_tier: Some(ServiceTier::Flex.to_string()),
|
||||
text: None,
|
||||
};
|
||||
|
||||
let v = serde_json::to_value(&req).expect("json");
|
||||
assert_eq!(
|
||||
v.get("service_tier").and_then(|tier| tier.as_str()),
|
||||
Some("flex")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reserializes_shell_outputs_for_function_and_custom_tool_calls() {
|
||||
let raw_output = r#"{"output":"hello","metadata":{"exit_code":0,"duration_seconds":0.5}}"#;
|
||||
|
||||
@@ -189,7 +189,7 @@ pub struct Config {
|
||||
/// Optional override of model selection.
|
||||
pub model: Option<String>,
|
||||
|
||||
/// Effective service tier preference for new turns.
|
||||
/// Effective service tier preference for new turns (`fast` or `flex`).
|
||||
pub service_tier: Option<ServiceTier>,
|
||||
|
||||
/// Model used specifically for review sessions.
|
||||
@@ -1191,7 +1191,7 @@ pub struct ConfigToml {
|
||||
/// Optionally specify a personality for the model
|
||||
pub personality: Option<Personality>,
|
||||
|
||||
/// Optional explicit service tier preference for new turns.
|
||||
/// Optional explicit service tier preference for new turns (`fast` or `flex`).
|
||||
pub service_tier: Option<ServiceTier>,
|
||||
|
||||
/// Base URL for requests to ChatGPT (as opposed to the OpenAI API).
|
||||
@@ -1984,15 +1984,14 @@ impl Config {
|
||||
let forced_login_method = cfg.forced_login_method;
|
||||
|
||||
let model = model.or(config_profile.model).or(cfg.model);
|
||||
let service_tier = if features.enabled(Feature::FastMode) {
|
||||
service_tier_override.unwrap_or_else(|| {
|
||||
config_profile
|
||||
.service_tier
|
||||
.or(cfg.service_tier)
|
||||
.filter(|tier| matches!(tier, ServiceTier::Fast))
|
||||
})
|
||||
} else {
|
||||
None
|
||||
let service_tier = service_tier_override
|
||||
.unwrap_or_else(|| config_profile.service_tier.or(cfg.service_tier));
|
||||
let service_tier = match service_tier {
|
||||
Some(ServiceTier::Fast) if features.enabled(Feature::FastMode) => {
|
||||
Some(ServiceTier::Fast)
|
||||
}
|
||||
Some(ServiceTier::Flex) => Some(ServiceTier::Flex),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let compact_prompt = compact_prompt.or(cfg.compact_prompt).and_then(|value| {
|
||||
|
||||
@@ -22,6 +22,7 @@ use codex_protocol::user_input::UserInput;
|
||||
use core_test_support::responses::ev_completed_with_tokens;
|
||||
use core_test_support::responses::ev_response_created;
|
||||
use core_test_support::responses::mount_models_once;
|
||||
use core_test_support::responses::mount_sse_once;
|
||||
use core_test_support::responses::mount_sse_sequence;
|
||||
use core_test_support::responses::sse;
|
||||
use core_test_support::responses::sse_completed;
|
||||
@@ -247,6 +248,25 @@ async fn service_tier_change_is_applied_on_next_http_turn() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn flex_service_tier_is_applied_to_http_turn() -> Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
|
||||
let server = start_mock_server().await;
|
||||
let resp_mock = mount_sse_once(&server, sse_completed("resp-1")).await;
|
||||
|
||||
let test = test_codex().build(&server).await?;
|
||||
|
||||
test.submit_turn_with_service_tier("flex turn", Some(ServiceTier::Flex))
|
||||
.await?;
|
||||
|
||||
let request = resp_mock.single_request();
|
||||
let body = request.body_json();
|
||||
assert_eq!(body["service_tier"].as_str(), Some("flex"));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn model_change_from_image_to_text_strips_prior_image_content() -> Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
|
||||
@@ -118,6 +118,7 @@ pub enum WebSearchMode {
|
||||
#[strum(serialize_all = "lowercase")]
|
||||
pub enum ServiceTier {
|
||||
Fast,
|
||||
Flex,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Display, JsonSchema, TS)]
|
||||
|
||||
@@ -3681,7 +3681,7 @@ impl ChatWidget {
|
||||
self.open_model_popup();
|
||||
}
|
||||
SlashCommand::Fast => {
|
||||
let next_tier = if self.config.service_tier.is_some() {
|
||||
let next_tier = if matches!(self.config.service_tier, Some(ServiceTier::Fast)) {
|
||||
None
|
||||
} else {
|
||||
Some(ServiceTier::Fast)
|
||||
@@ -3976,7 +3976,8 @@ impl ChatWidget {
|
||||
"on" => self.set_service_tier_selection(Some(ServiceTier::Fast)),
|
||||
"off" => self.set_service_tier_selection(None),
|
||||
"status" => {
|
||||
let status = if self.config.service_tier.is_some() {
|
||||
let status = if matches!(self.config.service_tier, Some(ServiceTier::Fast))
|
||||
{
|
||||
"on"
|
||||
} else {
|
||||
"off"
|
||||
@@ -4342,7 +4343,7 @@ impl ChatWidget {
|
||||
.personality
|
||||
.filter(|_| self.config.features.enabled(Feature::Personality))
|
||||
.filter(|_| self.current_model_supports_personality());
|
||||
let service_tier = self.fast_mode_enabled().then_some(self.config.service_tier);
|
||||
let service_tier = self.config.service_tier.map(Some);
|
||||
let op = Op::UserTurn {
|
||||
items,
|
||||
cwd: self.config.cwd.clone(),
|
||||
|
||||
Reference in New Issue
Block a user