[router][grpc] Add error handling to generate_tool_constraints (#11562)
This commit is contained in:
@@ -106,9 +106,13 @@ impl PreparationStage {
|
|||||||
let token_ids = encoding.token_ids().to_vec();
|
let token_ids = encoding.token_ids().to_vec();
|
||||||
|
|
||||||
// Step 4: Build tool constraints if needed
|
// Step 4: Build tool constraints if needed
|
||||||
let tool_call_constraint = body_ref.tools.as_ref().and_then(|tools| {
|
let tool_call_constraint = if let Some(tools) = body_ref.tools.as_ref() {
|
||||||
utils::generate_tool_constraints(tools, &request.tool_choice, &request.model)
|
utils::generate_tool_constraints(tools, &request.tool_choice, &request.model).map_err(
|
||||||
});
|
|e| utils::bad_request_error(format!("Invalid tool configuration: {}", e)),
|
||||||
|
)?
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
// Step 5: Create stop sequence decoder (build once, reuse in non-stream)
|
// Step 5: Create stop sequence decoder (build once, reuse in non-stream)
|
||||||
let stop_decoder = utils::create_stop_decoder(
|
let stop_decoder = utils::create_stop_decoder(
|
||||||
|
|||||||
@@ -158,51 +158,54 @@ pub fn generate_tool_constraints(
|
|||||||
tools: &[Tool],
|
tools: &[Tool],
|
||||||
tool_choice: &Option<ToolChoice>,
|
tool_choice: &Option<ToolChoice>,
|
||||||
_model: &str,
|
_model: &str,
|
||||||
) -> Option<(String, String)> {
|
) -> Result<Option<(String, String)>, String> {
|
||||||
let choice = tool_choice.as_ref()?;
|
let Some(choice) = tool_choice.as_ref() else {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
|
||||||
match choice {
|
match choice {
|
||||||
// Specific function: Return parameters schema directly
|
// Specific function: Return parameters schema directly
|
||||||
// tools should already be filtered to contain only the specific function
|
// tools should already be filtered to contain only the specific function
|
||||||
ToolChoice::Function { .. } => {
|
ToolChoice::Function { .. } => {
|
||||||
if tools.is_empty() {
|
if tools.is_empty() {
|
||||||
return None;
|
return Ok(None);
|
||||||
}
|
}
|
||||||
let tool = &tools[0];
|
let tool = &tools[0];
|
||||||
|
|
||||||
// Return the tool's parameters schema directly (not wrapped in array)
|
// Return the tool's parameters schema directly (not wrapped in array)
|
||||||
let params_schema = serde_json::to_string(&tool.function.parameters).ok()?;
|
let params_schema = serde_json::to_string(&tool.function.parameters)
|
||||||
Some(("json_schema".to_string(), params_schema))
|
.map_err(|e| format!("Failed to serialize tool parameters: {}", e))?;
|
||||||
|
Ok(Some(("json_schema".to_string(), params_schema)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Required: Array of tool calls with minItems: 1
|
// Required: Array of tool calls with minItems: 1
|
||||||
ToolChoice::Value(ToolChoiceValue::Required) => {
|
ToolChoice::Value(ToolChoiceValue::Required) => {
|
||||||
let schema = build_required_array_schema(tools)?;
|
let schema = build_required_array_schema(tools)?;
|
||||||
Some(("json_schema".to_string(), schema))
|
Ok(Some(("json_schema".to_string(), schema)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// AllowedTools with required mode: tools are already filtered
|
// AllowedTools with required mode: tools are already filtered
|
||||||
ToolChoice::AllowedTools { mode, .. } => {
|
ToolChoice::AllowedTools { mode, .. } => {
|
||||||
if mode == "required" {
|
if mode == "required" {
|
||||||
if tools.is_empty() {
|
if tools.is_empty() {
|
||||||
return None;
|
return Ok(None);
|
||||||
}
|
}
|
||||||
let schema = build_required_array_schema(tools)?;
|
let schema = build_required_array_schema(tools)?;
|
||||||
Some(("json_schema".to_string(), schema))
|
Ok(Some(("json_schema".to_string(), schema)))
|
||||||
} else {
|
} else {
|
||||||
// "auto" mode - no constraint needed
|
// "auto" mode - no constraint needed
|
||||||
None
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// "auto" or "none" - no constraint
|
// "auto" or "none" - no constraint
|
||||||
_ => None,
|
_ => Ok(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build JSON schema for required tool calls (array with minItems: 1)
|
/// Build JSON schema for required tool calls (array with minItems: 1)
|
||||||
/// Includes $defs consolidation from all tools (matching Python's behavior)
|
/// Includes $defs consolidation from all tools (matching Python's behavior)
|
||||||
pub fn build_required_array_schema(tools: &[Tool]) -> Option<String> {
|
pub fn build_required_array_schema(tools: &[Tool]) -> Result<String, String> {
|
||||||
// Build anyOf schemas for each tool
|
// Build anyOf schemas for each tool
|
||||||
let mut any_of_schemas = Vec::new();
|
let mut any_of_schemas = Vec::new();
|
||||||
for tool in tools {
|
for tool in tools {
|
||||||
@@ -228,11 +231,12 @@ pub fn build_required_array_schema(tools: &[Tool]) -> Option<String> {
|
|||||||
if let Some(existing) = all_defs.get(def_name) {
|
if let Some(existing) = all_defs.get(def_name) {
|
||||||
// Check for conflicts
|
// Check for conflicts
|
||||||
if existing != def_schema {
|
if existing != def_schema {
|
||||||
error!(
|
let error_msg = format!(
|
||||||
"Tool definition '{}' has multiple schemas, which is not supported",
|
"Tool definition '{}' has multiple conflicting schemas, which is not supported",
|
||||||
def_name
|
def_name
|
||||||
);
|
);
|
||||||
return None;
|
error!("{}", error_msg);
|
||||||
|
return Err(error_msg);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
all_defs.insert(def_name.clone(), def_schema.clone());
|
all_defs.insert(def_name.clone(), def_schema.clone());
|
||||||
@@ -260,7 +264,8 @@ pub fn build_required_array_schema(tools: &[Tool]) -> Option<String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
serde_json::to_string(&array_schema).ok()
|
serde_json::to_string(&array_schema)
|
||||||
|
.map_err(|e| format!("Failed to serialize tool schema: {}", e))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Filter tools based on tool_choice (shared by both routers)
|
/// Filter tools based on tool_choice (shared by both routers)
|
||||||
|
|||||||
Reference in New Issue
Block a user