mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-22 00:01:34 +00:00
fix(aiagent): fix usage for gemini 3 models (#7682)
* fix for gemini3 models * cleaning * cleaning * small opti
This commit is contained in:
@@ -21,9 +21,11 @@ use serde::Deserialize;
|
||||
use windmill_common::ai_bedrock::{
|
||||
bedrock_stream_event_is_block_stop, bedrock_stream_event_to_text,
|
||||
bedrock_stream_event_to_tool_delta, bedrock_stream_event_to_tool_start, format_bedrock_error,
|
||||
BedrockClient, OpenAIMessage, OpenAIToolCall,
|
||||
BedrockClient
|
||||
};
|
||||
use windmill_common::error::{Error, Result};
|
||||
use windmill_common::ai_types::{OpenAIFunction, OpenAIMessage, OpenAIToolCall, ToolDef, ToolDefFunction};
|
||||
use windmill_common::ai_bedrock::build_tool_config;
|
||||
|
||||
// ============================================================================
|
||||
// Shared Request Types for SDK-Based Handlers
|
||||
@@ -122,11 +124,11 @@ fn build_tool_config_from_request(
|
||||
tool_choice: Option<&serde_json::Value>,
|
||||
) -> Result<Option<aws_sdk_bedrockruntime::types::ToolConfiguration>> {
|
||||
if let Some(tools) = tools {
|
||||
let tool_defs: Vec<windmill_common::ai_bedrock::ToolDef> = tools
|
||||
let tool_defs: Vec<ToolDef> = tools
|
||||
.iter()
|
||||
.map(|t| windmill_common::ai_bedrock::ToolDef {
|
||||
.map(|t| ToolDef {
|
||||
r#type: "function".to_string(),
|
||||
function: windmill_common::ai_bedrock::ToolDefFunction {
|
||||
function: ToolDefFunction {
|
||||
name: t.function.name.clone(),
|
||||
description: t.function.description.clone(),
|
||||
parameters: Box::from(
|
||||
@@ -152,7 +154,7 @@ fn build_tool_config_from_request(
|
||||
.map(|tc| tc == "required" || tc.as_str() == Some("required"))
|
||||
.unwrap_or(false);
|
||||
|
||||
windmill_common::ai_bedrock::build_tool_config(Some(&tool_defs), force_tool_use)
|
||||
build_tool_config(Some(&tool_defs), force_tool_use)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
@@ -668,7 +670,7 @@ pub async fn handle_bedrock_sdk_non_streaming(
|
||||
let input_json = document_to_json(tool_use.input());
|
||||
tool_calls.push(OpenAIToolCall {
|
||||
id: tool_use.tool_use_id().to_string(),
|
||||
function: windmill_common::ai_bedrock::OpenAIFunction {
|
||||
function: OpenAIFunction {
|
||||
name: tool_use.name().to_string(),
|
||||
arguments: serde_json::to_string(&input_json).unwrap_or_default(),
|
||||
},
|
||||
|
||||
@@ -19,10 +19,9 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::error::Error;
|
||||
|
||||
// Re-export types from ai_types
|
||||
pub use crate::ai_types::{
|
||||
ContentPart, ExtraContent, ImageUrlData, OpenAIContent, OpenAIFunction, OpenAIMessage,
|
||||
OpenAIToolCall, ToolDef, ToolDefFunction, UrlCitation,
|
||||
use crate::ai_types::{
|
||||
ContentPart, OpenAIContent, OpenAIFunction, OpenAIMessage,
|
||||
OpenAIToolCall, ToolDef,
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
|
||||
@@ -37,6 +37,9 @@ pub enum GeminiPart {
|
||||
FunctionCall {
|
||||
#[serde(rename = "functionCall")]
|
||||
function_call: GeminiFunctionCall,
|
||||
/// Thought signature for Gemini 3+ models - required for function calling
|
||||
#[serde(rename = "thoughtSignature", skip_serializing_if = "Option::is_none")]
|
||||
thought_signature: Option<String>,
|
||||
},
|
||||
FunctionResponse {
|
||||
#[serde(rename = "functionResponse")]
|
||||
@@ -369,11 +372,18 @@ impl GoogleAIQueryBuilder {
|
||||
for tc in tool_calls {
|
||||
let args: serde_json::Value =
|
||||
serde_json::from_str(&tc.function.arguments).unwrap_or_default();
|
||||
// Extract thought_signature from extra_content if present
|
||||
let thought_signature = tc
|
||||
.extra_content
|
||||
.as_ref()
|
||||
.and_then(|ec| ec.google.as_ref())
|
||||
.and_then(|g| g.thought_signature.clone());
|
||||
parts.push(GeminiPart::FunctionCall {
|
||||
function_call: GeminiFunctionCall {
|
||||
name: tc.function.name.clone(),
|
||||
args,
|
||||
},
|
||||
thought_signature,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,9 +11,7 @@ use crate::ai::{
|
||||
utils::extract_text_content,
|
||||
};
|
||||
|
||||
pub use windmill_common::ai_types::{
|
||||
ExtraContent, OpenAIFunction, OpenAIToolCall,
|
||||
};
|
||||
use windmill_common::ai_types::OpenAIToolCall;
|
||||
|
||||
// Responses API structures
|
||||
#[derive(Deserialize)]
|
||||
|
||||
@@ -9,7 +9,7 @@ use crate::{
|
||||
providers::{
|
||||
anthropic::AnthropicQueryBuilder,
|
||||
google_ai::GoogleAIQueryBuilder,
|
||||
openai::{OpenAIQueryBuilder, OpenAIToolCall},
|
||||
openai::{OpenAIQueryBuilder},
|
||||
openrouter::OpenRouterQueryBuilder,
|
||||
other::OtherQueryBuilder,
|
||||
},
|
||||
@@ -18,6 +18,8 @@ use crate::{
|
||||
job_logger::append_result_stream,
|
||||
};
|
||||
|
||||
use windmill_common::ai_types::OpenAIToolCall;
|
||||
|
||||
/// Arguments for building an AI request
|
||||
pub struct BuildRequestArgs<'a> {
|
||||
pub messages: &'a [OpenAIMessage],
|
||||
|
||||
@@ -8,11 +8,12 @@ use tokio_stream::StreamExt;
|
||||
use windmill_common::{error::Error, utils::rd_string};
|
||||
|
||||
use crate::ai::{
|
||||
providers::openai::{ExtraContent, OpenAIFunction, OpenAIToolCall},
|
||||
query_builder::StreamEventProcessor,
|
||||
types::{StreamingEvent, UrlCitation},
|
||||
};
|
||||
|
||||
use windmill_common::ai_types::{ExtraContent, GoogleExtraContent, OpenAIFunction, OpenAIToolCall};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct OpenAIChoiceDeltaToolCallFunction {
|
||||
pub name: Option<String>,
|
||||
@@ -24,8 +25,6 @@ pub struct OpenAIChoiceDeltaToolCall {
|
||||
pub index: Option<i64>,
|
||||
pub id: Option<String>,
|
||||
pub function: Option<OpenAIChoiceDeltaToolCallFunction>,
|
||||
/// Extra content for provider-specific metadata (e.g., Google Gemini thought signatures)
|
||||
pub extra_content: Option<ExtraContent>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
@@ -140,10 +139,6 @@ impl SSEParser for OpenAISSEParser {
|
||||
if let Some(arguments) = function.arguments {
|
||||
existing_tool_call.function.arguments += &arguments;
|
||||
}
|
||||
// Update extra_content if provided in this delta (for thought signatures)
|
||||
if let Some(extra) = tool_call.extra_content {
|
||||
existing_tool_call.extra_content = Some(extra);
|
||||
}
|
||||
} else {
|
||||
let fun_name = function.name.unwrap_or_default();
|
||||
let call_id = tool_call.id.unwrap_or_else(|| rd_string(24));
|
||||
@@ -163,7 +158,7 @@ impl SSEParser for OpenAISSEParser {
|
||||
arguments: function.arguments.unwrap_or_default(),
|
||||
},
|
||||
r#type: "function".to_string(),
|
||||
extra_content: tool_call.extra_content,
|
||||
extra_content: None,
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -425,6 +420,9 @@ pub struct GeminiSSEPart {
|
||||
pub text: Option<String>,
|
||||
#[serde(rename = "functionCall")]
|
||||
pub function_call: Option<GeminiSSEFunctionCall>,
|
||||
/// Thought signature for Gemini 3+ models - required for function calling
|
||||
#[serde(rename = "thoughtSignature")]
|
||||
pub thought_signature: Option<String>,
|
||||
}
|
||||
|
||||
/// Function call in Gemini streaming response
|
||||
@@ -547,6 +545,14 @@ impl SSEParser for GeminiSSEParser {
|
||||
.send(event, &mut self.events_str)
|
||||
.await?;
|
||||
|
||||
// Build extra_content with thought_signature if present
|
||||
let extra_content =
|
||||
part.thought_signature.map(|sig| ExtraContent {
|
||||
google: Some(GoogleExtraContent {
|
||||
thought_signature: Some(sig),
|
||||
}),
|
||||
});
|
||||
|
||||
// Store accumulated tool call
|
||||
self.accumulated_tool_calls.insert(
|
||||
idx,
|
||||
@@ -560,7 +566,7 @@ impl SSEParser for GeminiSSEParser {
|
||||
.unwrap_or_else(|_| "{}".to_string()),
|
||||
},
|
||||
r#type: "function".to_string(),
|
||||
extra_content: None,
|
||||
extra_content,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::ai::providers::openai::OpenAIToolCall;
|
||||
use windmill_common::ai_types::OpenAIToolCall;
|
||||
use crate::ai::query_builder::StreamEventProcessor;
|
||||
use crate::ai::types::*;
|
||||
use crate::ai::utils::{
|
||||
|
||||
Reference in New Issue
Block a user