Request summarized thinking for Claude Opus 4.7 (#54217)

Starting with Claude Opus 4.7, Anthropic omits thinking content from
responses by default; callers must pass `display: "summarized"` to keep
seeing thinking summaries. Without opting in, the agent UI shows a long
pause with no visible thinking, and users get no progress indication
during extended reasoning.

This extends the adaptive-thinking wire type with an optional `display`
field and requests `Summarized` from every call site that builds an
adaptive thinking request (direct Anthropic, Copilot Chat proxy, Zed
Cloud, and Bedrock).

## Notes

- Applied at the adaptive-thinking layer rather than special-casing Opus
4.7. The `display` parameter is accepted by every
adaptive-thinking-capable model, and the previous behavior (visible
summaries) is what users already see on Opus 4.6 / Sonnet 4.6, so there
is no behavior change for those models.

Release Notes:

- Restored thinking summaries for Claude Opus 4.7.
This commit is contained in:
Eric Holk 2026-04-23 08:43:02 -07:00 committed by GitHub
parent ad2939f2e0
commit 4a5fbf6a3f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 33 additions and 10 deletions

View file

@ -764,8 +764,20 @@ pub enum ToolChoice {
#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "lowercase")]
pub enum Thinking {
Enabled { budget_tokens: Option<u32> },
Adaptive,
Enabled {
budget_tokens: Option<u32>,
},
Adaptive {
#[serde(default, skip_serializing_if = "Option::is_none")]
display: Option<AdaptiveThinkingDisplay>,
},
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum AdaptiveThinkingDisplay {
Omitted,
Summarized,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, EnumString)]

View file

@ -11,9 +11,9 @@ use std::pin::Pin;
use std::str::FromStr;
use crate::{
AnthropicError, AnthropicModelMode, CacheControl, CacheControlType, ContentDelta, Event,
ImageSource, Message, RequestContent, ResponseContent, StringOrContents, Thinking, Tool,
ToolChoice, ToolResultContent, ToolResultPart, Usage,
AdaptiveThinkingDisplay, AnthropicError, AnthropicModelMode, CacheControl, CacheControlType,
ContentDelta, Event, ImageSource, Message, RequestContent, ResponseContent, StringOrContents,
Thinking, Tool, ToolChoice, ToolResultContent, ToolResultPart, Usage,
};
fn to_anthropic_content(content: MessageContent) -> Option<RequestContent> {
@ -180,7 +180,9 @@ pub fn into_anthropic(
AnthropicModelMode::Thinking { budget_tokens } => {
Some(Thinking::Enabled { budget_tokens })
}
AnthropicModelMode::AdaptiveThinking => Some(Thinking::Adaptive),
AnthropicModelMode::AdaptiveThinking => Some(Thinking::Adaptive {
display: Some(AdaptiveThinkingDisplay::Summarized),
}),
AnthropicModelMode::Default => None,
}
} else {

View file

@ -58,8 +58,13 @@ pub async fn stream_completion(
additional_fields.insert("thinking".to_string(), Document::from(thinking_config));
}
Some(Thinking::Adaptive { effort: _ }) => {
let thinking_config =
HashMap::from([("type".to_string(), Document::String("adaptive".to_string()))]);
let thinking_config = HashMap::from([
("type".to_string(), Document::String("adaptive".to_string())),
(
"display".to_string(),
Document::String("summarized".to_string()),
),
]);
additional_fields.insert("thinking".to_string(), Document::from(thinking_config));
}
_ => {}

View file

@ -365,7 +365,9 @@ impl LanguageModel for CopilotChatLanguageModel {
if model.supports_adaptive_thinking() {
if anthropic_request.thinking.is_some() {
anthropic_request.thinking = Some(anthropic::Thinking::Adaptive);
anthropic_request.thinking = Some(anthropic::Thinking::Adaptive {
display: Some(anthropic::AdaptiveThinkingDisplay::Summarized),
});
anthropic_request.output_config =
effort.map(|effort| anthropic::OutputConfig {
effort: Some(effort),

View file

@ -408,7 +408,9 @@ impl<TP: CloudLlmTokenProvider + 'static> LanguageModel for CloudLanguageModel<T
);
if enable_thinking && effort.is_some() {
request.thinking = Some(anthropic::Thinking::Adaptive);
request.thinking = Some(anthropic::Thinking::Adaptive {
display: Some(anthropic::AdaptiveThinkingDisplay::Summarized),
});
request.output_config = Some(anthropic::OutputConfig { effort });
}