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] <windmill-internal-app[bot]@users.noreply.github.com>

* fix

---------

Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
This commit is contained in:
centdix
2025-10-28 18:14:18 +01:00
committed by GitHub
parent 2dc042fe06
commit bfbeb468f1
2 changed files with 7 additions and 11 deletions

View File

@@ -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

View File

@@ -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<String> = 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());