Remove auto model routing; default to Claude Opus 4.6 on Bedrock; strip Oz tips

This commit is contained in:
Ryan Ward
2026-05-13 09:33:45 -05:00
parent e1c33317d3
commit 029e90be2b
6 changed files with 90 additions and 109 deletions
+9 -1
View File
@@ -175,7 +175,7 @@ pub async fn generate_multi_agent_output(
.unwrap_or_default();
if model_id.is_empty() || model_id == "auto" {
model_id = "us.anthropic.claude-sonnet-4-20250514-v1:0".to_string();
model_id = "us.anthropic.claude-opus-4-6".to_string();
}
log::info!("[bedrock] Model: {model_id}");
@@ -203,6 +203,14 @@ pub async fn generate_multi_agent_output(
messages.extend(new_input_messages);
}
// Sanitize: ensure every tool_use has a matching tool_result
// immediately after, and that the conversation starts with a
// user message. Without this, interrupted tool calls cause
// Bedrock ValidationException errors.
crate::ai::bedrock::convert_request::sanitize_messages_for_bedrock(
&mut messages,
);
let system_prompt =
crate::ai::bedrock::convert_request::extract_system_prompt(&request);
let tools = crate::ai::bedrock::convert_request::extract_tools(&request);
-7
View File
@@ -261,13 +261,6 @@ static DEFAULT_TIPS: LazyLock<Vec<AgentTip>> = LazyLock::new(|| {
action: None,
kind: AgentTipKind::General,
},
AgentTip {
description: "Use the `oz` command to run an Oz agent in headless mode, useful for remote machines.".to_string(),
link: Some("https://docs.warp.dev/reference/cli".to_string()),
binding_name: None,
action: None,
kind: AgentTipKind::General,
},
AgentTip {
description: "Right-click selected text to attach it as agent context.".to_string(),
link: Some("https://docs.warp.dev/agent-platform/local-agents/agent-context/blocks-as-context#attaching-blocks-as-context".to_string()),
+18 -1
View File
@@ -18,6 +18,7 @@ pub fn extract_new_input_messages(request: &api::Request) -> Vec<ConversationMes
match input_type {
api::request::input::Type::UserInputs(user_inputs) => {
let mut tool_results: Vec<ConversationMessage> = Vec::new();
let mut user_queries: Vec<ConversationMessage> = Vec::new();
for user_input in &user_inputs.inputs {
match &user_input.input {
Some(api::request::input::user_inputs::user_input::Input::ToolCallResult(
@@ -39,7 +40,7 @@ pub fn extract_new_input_messages(request: &api::Request) -> Vec<ConversationMes
query,
)) => {
if !query.query.is_empty() {
results.push(ConversationMessage {
user_queries.push(ConversationMessage {
role: MessageRole::User,
content: MessageContent::Text(query.query.clone()),
});
@@ -48,6 +49,9 @@ pub fn extract_new_input_messages(request: &api::Request) -> Vec<ConversationMes
_ => {}
}
}
// Tool results MUST come before user queries so they pair with
// the preceding assistant tool_use messages (Bedrock requires
// tool_result immediately after the corresponding tool_use).
if !tool_results.is_empty() {
if tool_results.len() == 1 {
results.extend(tool_results);
@@ -67,6 +71,7 @@ pub fn extract_new_input_messages(request: &api::Request) -> Vec<ConversationMes
});
}
}
results.extend(user_queries);
}
#[allow(deprecated)]
api::request::input::Type::UserQuery(query) => {
@@ -458,6 +463,18 @@ pub fn extract_messages_from_request(request: &api::Request) -> Vec<Conversation
messages
}
/// Sanitizes a message list to satisfy Bedrock Converse API invariants:
/// 1. Messages must start with a user message.
/// 2. Every assistant tool_use must be immediately followed by a user
/// message containing the matching tool_result.
///
/// Call this on the combined (history + new input) messages before
/// sending to `build_converse_request`.
pub fn sanitize_messages_for_bedrock(messages: &mut Vec<ConversationMessage>) {
ensure_starts_with_user_message(messages);
ensure_tool_results_paired(messages);
}
fn ensure_starts_with_user_message(messages: &mut Vec<ConversationMessage>) {
if messages.is_empty() {
messages.push(ConversationMessage {
+5
View File
@@ -7,6 +7,11 @@ pub struct DefaultModel {
}
pub const DEFAULT_BEDROCK_MODELS: &[DefaultModel] = &[
DefaultModel {
model_id: "anthropic.claude-opus-4-6",
display_name: "Claude Opus 4.6",
vision_supported: true,
},
DefaultModel {
model_id: "anthropic.claude-opus-4-7",
display_name: "Claude Opus 4.7",
+58 -12
View File
@@ -424,11 +424,11 @@ impl Default for ModelsByFeature {
fn default() -> Self {
Self {
agent_mode: AvailableLLMs {
default_id: "auto".to_owned().into(),
default_id: "anthropic.claude-opus-4-6".to_owned().into(),
choices: vec![LLMInfo {
display_name: "auto (cost-efficient)".to_owned(),
base_model_name: "auto (cost-efficient)".to_owned(),
id: "auto".to_owned().into(),
display_name: "Claude Opus 4.6".to_owned(),
base_model_name: "Claude Opus 4.6".to_owned(),
id: "anthropic.claude-opus-4-6".to_owned().into(),
reasoning_level: None,
usage_metadata: LLMUsageMetadata {
request_multiplier: 1,
@@ -445,11 +445,11 @@ impl Default for ModelsByFeature {
preferred_codex_model_id: None,
},
coding: AvailableLLMs {
default_id: "auto".to_owned().into(),
default_id: "anthropic.claude-sonnet-4-6".to_owned().into(),
choices: vec![LLMInfo {
display_name: "auto (responsive)".to_owned(),
base_model_name: "auto (responsive)".to_owned(),
id: "auto".to_owned().into(),
display_name: "Claude Sonnet 4.6".to_owned(),
base_model_name: "Claude Sonnet 4.6".to_owned(),
id: "anthropic.claude-sonnet-4-6".to_owned().into(),
reasoning_level: None,
usage_metadata: LLMUsageMetadata {
request_multiplier: 1,
@@ -466,11 +466,11 @@ impl Default for ModelsByFeature {
preferred_codex_model_id: None,
},
cli_agent: Some(AvailableLLMs {
default_id: "cli-agent-auto".to_owned().into(),
default_id: "anthropic.claude-haiku-4-5-20251001-v1:0".to_owned().into(),
choices: vec![LLMInfo {
display_name: "auto".to_owned(),
base_model_name: "auto".to_owned(),
id: "cli-agent-auto".to_owned().into(),
display_name: "Claude Haiku 4.5".to_owned(),
base_model_name: "Claude Haiku 4.5".to_owned(),
id: "anthropic.claude-haiku-4-5-20251001-v1:0".to_owned().into(),
reasoning_level: None,
usage_metadata: LLMUsageMetadata {
request_multiplier: 1,
@@ -687,6 +687,52 @@ impl LLMPreferences {
cli.choices.push(llm_info);
}
}
// Remove any placeholder/auto-routing entries now that real Bedrock models are available.
self.models_by_feature
.agent_mode
.choices
.retain(|m| m.provider != LLMProvider::Unknown);
self.models_by_feature
.coding
.choices
.retain(|m| m.provider != LLMProvider::Unknown);
if let Some(ref mut cli) = self.models_by_feature.cli_agent {
cli.choices.retain(|m| m.provider != LLMProvider::Unknown);
}
// Default agent mode to Claude Opus 4.6, falling back to the first available model.
if let Some(id) = self
.models_by_feature
.agent_mode
.choices
.iter()
.find(|m| m.display_name.contains("Opus 4.6"))
.or_else(|| self.models_by_feature.agent_mode.choices.first())
.map(|m| m.id.clone())
{
self.models_by_feature.agent_mode.default_id = id;
}
// Default coding to Claude Sonnet 4.6, falling back to the first available model.
if let Some(id) = self
.models_by_feature
.coding
.choices
.iter()
.find(|m| m.display_name.contains("Sonnet 4.6"))
.or_else(|| self.models_by_feature.coding.choices.first())
.map(|m| m.id.clone())
{
self.models_by_feature.coding.default_id = id;
}
// Default CLI agent to the first available model.
if let Some(ref mut cli) = self.models_by_feature.cli_agent {
if let Some(id) = cli.choices.first().map(|m| m.id.clone()) {
cli.default_id = id;
}
}
}
/// Returns the `LLMInfo` for the base LLM to be used for an Agent Mode request.