From 029e90be2b79cab20aefa9d5a9e8135f2cdb522c Mon Sep 17 00:00:00 2001 From: Ryan Ward Date: Wed, 13 May 2026 09:33:45 -0500 Subject: [PATCH] Remove auto model routing; default to Claude Opus 4.6 on Bedrock; strip Oz tips --- app/src/ai/agent/api/impl.rs | 10 ++- app/src/ai/agent_tips.rs | 7 -- app/src/ai/bedrock/convert_request.rs | 19 ++++- app/src/ai/bedrock/models.rs | 5 ++ app/src/ai/llms.rs | 70 +++++++++++++--- app/src/terminal/view/ambient_agent/tips.rs | 88 --------------------- 6 files changed, 90 insertions(+), 109 deletions(-) diff --git a/app/src/ai/agent/api/impl.rs b/app/src/ai/agent/api/impl.rs index 043146b6..1d244e2b 100644 --- a/app/src/ai/agent/api/impl.rs +++ b/app/src/ai/agent/api/impl.rs @@ -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); diff --git a/app/src/ai/agent_tips.rs b/app/src/ai/agent_tips.rs index 0908a948..87d2472d 100644 --- a/app/src/ai/agent_tips.rs +++ b/app/src/ai/agent_tips.rs @@ -261,13 +261,6 @@ static DEFAULT_TIPS: LazyLock> = 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()), diff --git a/app/src/ai/bedrock/convert_request.rs b/app/src/ai/bedrock/convert_request.rs index 1291f44f..e6d65c13 100644 --- a/app/src/ai/bedrock/convert_request.rs +++ b/app/src/ai/bedrock/convert_request.rs @@ -18,6 +18,7 @@ pub fn extract_new_input_messages(request: &api::Request) -> Vec { let mut tool_results: Vec = Vec::new(); + let mut user_queries: Vec = 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 { 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 {} } } + // 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 { @@ -458,6 +463,18 @@ pub fn extract_messages_from_request(request: &api::Request) -> Vec) { + ensure_starts_with_user_message(messages); + ensure_tool_results_paired(messages); +} + fn ensure_starts_with_user_message(messages: &mut Vec) { if messages.is_empty() { messages.push(ConversationMessage { diff --git a/app/src/ai/bedrock/models.rs b/app/src/ai/bedrock/models.rs index 364a1a2f..6fa2e0b3 100644 --- a/app/src/ai/bedrock/models.rs +++ b/app/src/ai/bedrock/models.rs @@ -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", diff --git a/app/src/ai/llms.rs b/app/src/ai/llms.rs index 8d40283a..4d007a9d 100644 --- a/app/src/ai/llms.rs +++ b/app/src/ai/llms.rs @@ -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. diff --git a/app/src/terminal/view/ambient_agent/tips.rs b/app/src/terminal/view/ambient_agent/tips.rs index 70f4e065..a9d67632 100644 --- a/app/src/terminal/view/ambient_agent/tips.rs +++ b/app/src/terminal/view/ambient_agent/tips.rs @@ -39,26 +39,6 @@ impl AITip for CloudModeTip { /// Returns a collection of tips for the cloud mode loading screen. pub fn get_cloud_mode_tips() -> Vec { vec![ - CloudModeTip::new( - "Install the Oz Slack integration to trigger agents from any channel or DM.", - Some("https://docs.warp.dev/agent-platform/cloud-agents/integrations/slack"), - ), - CloudModeTip::new( - "Build programmatic agents using Oz's TypeScript and Python SDKs.", - Some("https://docs.warp.dev/reference/api-and-sdk"), - ), - CloudModeTip::new( - "Set team or personal secrets for agents using the `oz secret` command.", - Some("https://docs.warp.dev/agent-platform/cloud-agents/secrets"), - ), - CloudModeTip::new( - "View all your agent runs and their status in the Oz web app.", - Some("https://oz.warp.dev"), - ), - CloudModeTip::new( - "Join any Oz cloud agent run in real-time using Agent Session Sharing.", - Some("https://docs.warp.dev/agent-platform/cloud-agents/viewing-cloud-agent-runs"), - ), CloudModeTip::new( "Set up recurring agents that run on cron schedules for automated maintenance.", Some("https://docs.warp.dev/agent-platform/cloud-agents/triggers/scheduled-agents"), @@ -71,14 +51,6 @@ pub fn get_cloud_mode_tips() -> Vec { "Build agents that respond to CI failures and attempt automatic fixes.", Some("https://docs.warp.dev/agent-platform/cloud-agents/integrations/github-actions"), ), - CloudModeTip::new( - "Run agents from GitHub Actions using the `oz-agent-action`.", - Some("https://github.com/warpdotdev/oz-agent-action"), - ), - CloudModeTip::new( - "Call the Oz REST API to trigger agents from any backend service or internal tool.", - Some("https://docs.warp.dev/reference/api-and-sdk"), - ), CloudModeTip::new( "Create reusable environments with Docker images for consistent agent execution.", Some("https://docs.warp.dev/agent-platform/cloud-agents/environments"), @@ -87,14 +59,6 @@ pub fn get_cloud_mode_tips() -> Vec { "Share agent session links with your team for collaborative debugging.", Some("https://docs.warp.dev/agent-platform/cloud-agents/viewing-cloud-agent-runs"), ), - CloudModeTip::new( - "Use the `--share` flag with the Oz CLI to enable session sharing from anywhere.", - Some("https://docs.warp.dev/agent-platform/cloud-agents/platform"), - ), - CloudModeTip::new( - "Fork a completed Oz cloud agent session into Warp to continue the work locally.", - Some("https://docs.warp.dev/agent-platform/cloud-agents/viewing-cloud-agent-runs"), - ), CloudModeTip::new( "Build internal tools that use agents to answer questions from your databases.", Some("https://docs.warp.dev/agent-platform/cloud-agents/integrations"), @@ -103,26 +67,6 @@ pub fn get_cloud_mode_tips() -> Vec { "Create a scheduled agent to clean up stale feature flags every week.", Some("https://docs.warp.dev/agent-platform/cloud-agents/triggers/scheduled-agents"), ), - CloudModeTip::new( - "Tag @Oz in Linear issues to automatically investigate and propose fixes.", - Some("https://docs.warp.dev/agent-platform/cloud-agents/integrations/linear"), - ), - CloudModeTip::new( - "Run agents on remote dev boxes or CI runners using the Oz CLI.", - Some("https://docs.warp.dev/agent-platform/cloud-agents/platform"), - ), - CloudModeTip::new( - "Configure MCP servers to give Oz cloud agents access to GitHub, Linear, and Sentry.", - Some("https://docs.warp.dev/agent-platform/capabilities/mcp"), - ), - CloudModeTip::new( - "Use `oz agent run` to kick off tasks without opening the Warp terminal.", - Some("https://docs.warp.dev/agent-platform/cloud-agents/platform"), - ), - CloudModeTip::new( - "View your teammates' agent runs in the Oz web app for shared visibility.", - Some("https://oz.warp.dev"), - ), CloudModeTip::new( "Build agents that automatically triage and label incoming GitHub issues.", Some("https://docs.warp.dev/agent-platform/cloud-agents/integrations/github-actions"), @@ -135,10 +79,6 @@ pub fn get_cloud_mode_tips() -> Vec { "Create an agent that automatically reviews PRs and suggests improvements.", Some("https://docs.warp.dev/agent-platform/cloud-agents/integrations/github-actions"), ), - CloudModeTip::new( - "Use `oz environment create` to define reproducible execution contexts.", - Some("https://docs.warp.dev/agent-platform/cloud-agents/environments"), - ), CloudModeTip::new( "Trigger agents from webhooks to respond to production incidents.", Some("https://docs.warp.dev/reference/api-and-sdk"), @@ -163,38 +103,10 @@ pub fn get_cloud_mode_tips() -> Vec { "Build an agent that automatically formats and lints code on a schedule.", Some("https://docs.warp.dev/agent-platform/cloud-agents/triggers/scheduled-agents"), ), - CloudModeTip::new( - "Use `oz schedule create` to set up cron-triggered agents.", - Some("https://docs.warp.dev/agent-platform/cloud-agents/triggers/scheduled-agents"), - ), - CloudModeTip::new( - "Pause and resume scheduled agents without deleting them using `oz schedule pause`.", - Some("https://docs.warp.dev/agent-platform/cloud-agents/triggers/scheduled-agents"), - ), - CloudModeTip::new( - "Use `oz mcp list` to see which MCP servers are available to your agents.", - Some("https://docs.warp.dev/agent-platform/capabilities/mcp"), - ), - CloudModeTip::new( - "Build an internal Slack bot that delegates coding tasks to Oz agents.", - Some("https://docs.warp.dev/agent-platform/cloud-agents/integrations/slack"), - ), CloudModeTip::new( "Create an agent that responds to @mentions in Slack threads with full context.", Some("https://docs.warp.dev/agent-platform/cloud-agents/integrations/slack"), ), - CloudModeTip::new( - "Use the Oz TypeScript SDK to build custom automation pipelines.", - Some("https://docs.warp.dev/reference/api-and-sdk"), - ), - CloudModeTip::new( - "Use the Oz Python SDK to integrate agents into your data pipelines.", - Some("https://docs.warp.dev/reference/api-and-sdk"), - ), - CloudModeTip::new( - "Monitor agent success rates and runtimes using the Oz API.", - Some("https://docs.warp.dev/reference/api-and-sdk"), - ), CloudModeTip::new( "Build a dashboard that tracks all agent activity across your team.", Some("https://docs.warp.dev/reference/api-and-sdk"),