From bfbeb468f13bbdc5b78c08fa1f276d4d84acbace Mon Sep 17 00:00:00 2001 From: centdix <40307056+centdix@users.noreply.github.com> Date: Tue, 28 Oct 2025 18:14:18 +0100 Subject: [PATCH] fix(aiagent): use tool-based structured output for all claude models (#6979) * fix(aiagent): use tool-based structured output for all claude models Extended is_anthropic_provider to check if model starts with 'claude' regardless of provider. This ensures the tool-based structured output logic is used for all Claude models, not just when using Anthropic or OpenRouter providers. Closes #6977 Co-authored-by: windmill-internal-app[bot] * fix --------- Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: windmill-internal-app[bot] --- backend/windmill-worker/src/ai/utils.rs | 10 +++------- backend/windmill-worker/src/ai_executor.rs | 8 ++++---- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/backend/windmill-worker/src/ai/utils.rs b/backend/windmill-worker/src/ai/utils.rs index 6f70c02c84..fb27c419ba 100644 --- a/backend/windmill-worker/src/ai/utils.rs +++ b/backend/windmill-worker/src/ai/utils.rs @@ -8,7 +8,6 @@ use std::{ }; use uuid::Uuid; use windmill_common::{ - ai_providers::AIProvider, db::DB, error::Error, flow_conversations::{add_message_to_conversation_tx, MessageType}, @@ -311,12 +310,9 @@ pub fn get_step_name_from_flow( ) } -/// Check if the provider is Anthropic (either direct or through OpenRouter) -pub fn is_anthropic_provider(provider: &ProviderWithResource) -> bool { - let provider_is_anthropic = provider.kind.is_anthropic(); - let is_openrouter_anthropic = - provider.kind == AIProvider::OpenRouter && provider.model.starts_with("anthropic/"); - provider_is_anthropic || is_openrouter_anthropic +/// Claude models starts with claude if provider is anthropic, or anthropic for openrouter and other providers +pub fn is_claude_model(model: &str) -> bool { + model.starts_with("claude") || model.starts_with("anthropic") } /// Cleanup MCP clients by gracefully shutting down connections diff --git a/backend/windmill-worker/src/ai_executor.rs b/backend/windmill-worker/src/ai_executor.rs index cb696d8a6c..a7c3bf12a7 100644 --- a/backend/windmill-worker/src/ai_executor.rs +++ b/backend/windmill-worker/src/ai_executor.rs @@ -2,8 +2,8 @@ use crate::ai::tools::{execute_tool_calls, ToolExecutionContext}; use crate::ai::utils::{ add_message_to_conversation, any_tool_needs_previous_result, cleanup_mcp_clients, filter_schema_by_input_transforms, find_unique_tool_name, get_flow_context, - get_flow_job_runnable_and_raw_flow, get_step_name_from_flow, is_anthropic_provider, - load_mcp_tools, parse_raw_script_schema, update_flow_status_module_with_actions, + get_flow_job_runnable_and_raw_flow, get_step_name_from_flow, is_claude_model, load_mcp_tools, + parse_raw_script_schema, update_flow_status_module_with_actions, update_flow_status_module_with_actions_success, }; use crate::memory_oss::{read_from_memory, write_to_memory}; @@ -471,14 +471,14 @@ pub async fn run_agent( .map(|props| !props.is_empty()) .unwrap_or(false); - let is_anthropic = is_anthropic_provider(&args.provider); + let is_claude_model = is_claude_model(&args.provider.model); let mut used_structured_output_tool = false; let mut structured_output_tool_name: Option = None; // For text output with schema, handle structured output if has_output_properties && output_type == &OutputType::Text { let schema = args.output_schema.as_ref().unwrap(); - if is_anthropic { + if is_claude_model { // Anthropic uses a tool for structured output let unique_tool_name = find_unique_tool_name("structured_output", tool_defs.as_deref()); structured_output_tool_name = Some(unique_tool_name.clone());