[codex] Support model-defined reasoning efforts (#26444)

## Summary
- accept non-empty model-defined reasoning effort values while
preserving built-in effort behavior
- propagate the non-Copy effort type through core, app-server, TUI,
telemetry, and persistence call sites
- preserve string wire encoding and expose an open-string schema for
clients
- update model selection and shortcut behavior for model-advertised
effort values

## Root cause
`ReasoningEffort` gained a string-backed custom variant, so it could no
longer implement `Copy` or rely on derived closed-enum serialization.
Existing consumers still moved effort values from shared references and
assumed a fixed built-in value set.

## Validation
- `just fmt`
- Local tests and compilation were not run per request; relying on CI.
This commit is contained in:
Ahmed Ibrahim
2026-06-04 13:36:24 -07:00
committed by GitHub
parent 4a70e0ac1b
commit 8ac304c299
97 changed files with 685 additions and 581 deletions
+1 -1
View File
@@ -188,7 +188,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`, `serviceTiers`, optional `defaultServiceTier`, 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 model-advertised string reasoning effort options, `additionalSpeedTiers`, `serviceTiers`, optional `defaultServiceTier`, 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. Pass `threadId` when showing feature state for an existing loaded thread so `enabled` is computed from that thread's refreshed config, including project-local config for the thread's cwd; if omitted, the server uses its default config resolution context. For non-beta flags, `displayName`/`description`/`announcement` are `null`.
- `permissionProfile/list` — beta; list available permission profile ids with optional display `description` text, using cursor pagination. Pass `cwd` when the caller needs project-local `[permissions.<id>]` entries to be included in the current catalog view.
+2 -2
View File
@@ -62,10 +62,10 @@ fn reasoning_efforts_from_preset(
efforts: Vec<ReasoningEffortPreset>,
) -> Vec<ReasoningEffortOption> {
efforts
.iter()
.into_iter()
.map(|preset| ReasoningEffortOption {
reasoning_effort: preset.effort,
description: preset.description.to_string(),
description: preset.description,
})
.collect()
}
@@ -158,7 +158,7 @@ fn merge_persisted_resume_metadata(
typesafe_overrides.model = persisted_metadata.model.clone();
typesafe_overrides.model_provider = Some(persisted_metadata.model_provider.clone());
if let Some(reasoning_effort) = persisted_metadata.reasoning_effort {
if let Some(reasoning_effort) = persisted_metadata.reasoning_effort.as_ref() {
request_overrides.get_or_insert_with(HashMap::new).insert(
"model_reasoning_effort".to_string(),
serde_json::Value::String(reasoning_effort.to_string()),
@@ -203,7 +203,7 @@ pub(crate) fn thread_settings_from_config_snapshot(
model: config_snapshot.model.clone(),
model_provider: config_snapshot.model_provider_id.clone(),
service_tier: config_snapshot.service_tier.clone(),
effort: config_snapshot.reasoning_effort,
effort: config_snapshot.reasoning_effort.clone(),
summary: config_snapshot.reasoning_summary,
collaboration_mode: config_snapshot.collaboration_mode.clone(),
personality: config_snapshot.personality,
@@ -629,7 +629,7 @@ impl TurnRequestProcessor {
profile_workspace_roots: profile_workspace_roots.clone(),
windows_sandbox_level: None,
model: model.clone(),
effort,
effort: effort.clone(),
summary,
service_tier: service_tier.clone(),
collaboration_mode: collaboration_mode.clone(),
@@ -18,7 +18,7 @@ fn preset_to_info(preset: &ModelPreset, priority: i32) -> ModelInfo {
slug: preset.id.clone(),
display_name: preset.display_name.clone(),
description: Some(preset.description.clone()),
default_reasoning_level: Some(preset.default_reasoning_effort),
default_reasoning_level: Some(preset.default_reasoning_effort.clone()),
supported_reasoning_levels: preset.supported_reasoning_efforts.clone(),
shell_type: ConfigShellToolType::ShellCommand,
visibility: if preset.show_in_picker {
@@ -48,11 +48,11 @@ fn model_from_preset(preset: &ModelPreset) -> Model {
.supported_reasoning_efforts
.iter()
.map(|preset| ReasoningEffortOption {
reasoning_effort: preset.effort,
reasoning_effort: preset.effort.clone(),
description: preset.description.clone(),
})
.collect(),
default_reasoning_effort: preset.default_reasoning_effort,
default_reasoning_effort: preset.default_reasoning_effort.clone(),
input_modalities: preset.input_modalities.clone(),
// `write_models_cache()` round-trips through a simplified ModelInfo fixture that does not
// preserve personality placeholders in base instructions, so app-server list results from
@@ -164,10 +164,10 @@ async fn list_models_uses_chatgpt_remote_catalog_as_source_of_truth() -> Result<
"slug": "chatgpt-remote-only",
"display_name": "ChatGPT Remote Only",
"description": "Remote-only model for app-server model/list coverage",
"default_reasoning_level": "medium",
"default_reasoning_level": "max",
"supported_reasoning_levels": [
{"effort": "low", "description": "low"},
{"effort": "medium", "description": "medium"}
{"effort": "max", "description": "Maximum"}
],
"shell_type": "shell_command",
"visibility": "list",