From ba9e4e8435c4f0aec30096bc719a697031dd68bf Mon Sep 17 00:00:00 2001 From: Burke Holland Date: Wed, 21 Oct 2026 09:25:03 -0700 Subject: [PATCH] Add supported reasoning efforts to provider models Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- nodejs/src/generated/rpc.ts | 4 ++++ nodejs/src/types.ts | 5 ++++ rust/src/generated/api_types.rs | 3 +++ rust/src/types.rs | 12 ++++++++++ rust/src/types/tests.rs | 42 ++++++++++++++++++++++++++++++++- 5 files changed, 65 insertions(+), 1 deletion(-) diff --git a/nodejs/src/generated/rpc.ts b/nodejs/src/generated/rpc.ts index c6fda03575..a72ec39627 100644 --- a/nodejs/src/generated/rpc.ts +++ b/nodejs/src/generated/rpc.ts @@ -22277,6 +22277,10 @@ export interface ProviderModelConfig { * Maximum output tokens for the model. */ maxOutputTokens?: number; + /** + * Reasoning effort levels supported by the model. + */ + supportedReasoningEfforts?: string[]; capabilities?: ModelCapabilitiesOverride; systemMessage?: ProtocolSystemMessageConfig; /** diff --git a/nodejs/src/types.ts b/nodejs/src/types.ts index 6c3d83286d..cd12d1d60a 100644 --- a/nodejs/src/types.ts +++ b/nodejs/src/types.ts @@ -3766,6 +3766,11 @@ export interface ProviderModelConfig { */ maxOutputTokens?: number; + /** + * Reasoning effort levels supported by the model. + */ + supportedReasoningEfforts?: ReasoningEffort[]; + /** * Optional capability overrides (vision, tool_calls, reasoning, etc.) for * the synthesized model. diff --git a/rust/src/generated/api_types.rs b/rust/src/generated/api_types.rs index 98794f5672..f7225ceadb 100644 --- a/rust/src/generated/api_types.rs +++ b/rust/src/generated/api_types.rs @@ -19320,6 +19320,9 @@ pub struct ProviderModelConfig { pub name: Option, /// Name of the configured provider that serves this model. pub provider: String, + /// Reasoning effort levels supported by the model. + #[serde(skip_serializing_if = "Option::is_none")] + pub supported_reasoning_efforts: Option>, /// System-message configuration used when the runtime builds the standard prompt for this provider-qualified model, including general-purpose subagents. It uses the same object hierarchy as session-level systemMessage configuration, except transform actions are rejected because the current callback protocol is not model-scoped. When present, it overrides the session-wide configuration on those prompt paths. Selected custom-agent and specialized-subagent prompts remain authoritative. #[serde(skip_serializing_if = "Option::is_none")] pub system_message: Option, diff --git a/rust/src/types.rs b/rust/src/types.rs index 319c7970db..55d42192c4 100644 --- a/rust/src/types.rs +++ b/rust/src/types.rs @@ -1879,6 +1879,9 @@ pub struct ProviderModelConfig { /// Overrides the resolved model's default max output tokens. #[serde(default, skip_serializing_if = "Option::is_none")] pub max_output_tokens: Option, + /// Reasoning effort levels supported by the model. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub supported_reasoning_efforts: Option>, /// Per-property overrides for model capabilities, deep-merged over /// runtime defaults. #[serde(default, skip_serializing_if = "Option::is_none")] @@ -1933,6 +1936,15 @@ impl ProviderModelConfig { self } + /// Set the reasoning effort levels supported by this model. + pub fn with_supported_reasoning_efforts( + mut self, + efforts: impl IntoIterator>, + ) -> Self { + self.supported_reasoning_efforts = Some(efforts.into_iter().map(Into::into).collect()); + self + } + /// Set per-property model capability overrides. pub fn with_capabilities( mut self, diff --git a/rust/src/types/tests.rs b/rust/src/types/tests.rs index 18bbab77cd..35ab25f490 100644 --- a/rust/src/types/tests.rs +++ b/rust/src/types/tests.rs @@ -907,7 +907,8 @@ fn session_config_into_wire_serializes_named_providers_and_models() { .with_models(vec![ ProviderModelConfig::new("gpt-x", "my-openai") .with_wire_model("gpt-x-2025") - .with_max_output_tokens(2048), + .with_max_output_tokens(2048) + .with_supported_reasoning_efforts(["low", "high"]), ]); let (wire, _) = cfg @@ -927,6 +928,10 @@ fn session_config_into_wire_serializes_named_providers_and_models() { assert_eq!(wire_json["models"][0]["provider"], "my-openai"); assert_eq!(wire_json["models"][0]["wireModel"], "gpt-x-2025"); assert_eq!(wire_json["models"][0]["maxOutputTokens"], 2048); + assert_eq!( + wire_json["models"][0]["supportedReasoningEfforts"], + serde_json::json!(["low", "high"]) + ); let (empty_wire, _) = SessionConfig::default() .into_wire(Some(SessionId::from("empty"))) @@ -936,6 +941,41 @@ fn session_config_into_wire_serializes_named_providers_and_models() { assert!(empty_json.get("models").is_none()); } +#[test] +fn provider_model_config_preserves_omission_compatibility() { + let model_json = serde_json::to_value(ProviderModelConfig::new("gpt-x", "my-openai")).unwrap(); + assert!(model_json.get("supportedReasoningEfforts").is_none()); + + let legacy_model: ProviderModelConfig = serde_json::from_value(serde_json::json!({ + "id": "gpt-x", + "provider": "my-openai" + })) + .unwrap(); + assert!(legacy_model.supported_reasoning_efforts.is_none()); +} + +#[test] +fn generated_provider_model_config_serializes_supported_reasoning_efforts() { + let model = crate::rpc::ProviderModelConfig { + id: "gpt-x".to_string(), + provider: "my-openai".to_string(), + supported_reasoning_efforts: Some(vec!["low".to_string(), "high".to_string()]), + ..Default::default() + }; + let model_json = serde_json::to_value(model).unwrap(); + assert_eq!( + model_json["supportedReasoningEfforts"], + serde_json::json!(["low", "high"]) + ); + + let legacy_model: crate::rpc::ProviderModelConfig = serde_json::from_value(serde_json::json!({ + "id": "gpt-x", + "provider": "my-openai" + })) + .unwrap(); + assert!(legacy_model.supported_reasoning_efforts.is_none()); +} + #[test] fn resume_config_into_wire_serializes_named_providers_and_models() { let cfg = ResumeSessionConfig::new(SessionId::from("sess-resume"))