use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum GroqTool {
Function {
function: GroqFunctionDefinition,
},
#[serde(rename = "web_search_preview")]
WebSearch {
#[serde(skip_serializing_if = "Option::is_none")]
max_results: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
search_context_size: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
user_location: Option<GroqUserLocation>,
},
#[serde(rename = "visit_website_preview")]
VisitWebsite {},
#[serde(rename = "mcp")]
Mcp {
server_label: String,
server_url: String,
#[serde(skip_serializing_if = "Option::is_none")]
headers: Option<HashMap<String, String>>,
#[serde(skip_serializing_if = "Option::is_none")]
server_description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
require_approval: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
allowed_tools: Option<Vec<GroqMcpAllowedTool>>,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GroqFunctionDefinition {
pub name: String,
pub description: String,
pub parameters: serde_json::Value,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GroqUserLocation {
#[serde(rename = "type")]
pub location_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub city: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub region: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub country: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GroqMcpAllowedTool {
pub name: String,
}
impl GroqTool {
#[must_use]
pub fn builtin_web_search(max_results: Option<u32>) -> Self {
GroqTool::WebSearch {
max_results,
search_context_size: None,
user_location: None,
}
}
#[must_use]
pub fn builtin_web_search_with_config(
max_results: Option<u32>,
search_context_size: Option<String>,
user_location: Option<GroqUserLocation>,
) -> Self {
GroqTool::WebSearch {
max_results,
search_context_size,
user_location,
}
}
#[must_use]
pub fn builtin_visit_website() -> Self {
GroqTool::VisitWebsite {}
}
#[must_use]
pub fn mcp(label: impl Into<String>, url: impl Into<String>) -> Self {
GroqTool::Mcp {
server_label: label.into(),
server_url: url.into(),
headers: None,
server_description: None,
require_approval: None,
allowed_tools: None,
}
}
#[must_use]
pub fn mcp_with_auth(
label: impl Into<String>,
url: impl Into<String>,
headers: HashMap<String, String>,
) -> Self {
GroqTool::Mcp {
server_label: label.into(),
server_url: url.into(),
headers: Some(headers),
server_description: None,
require_approval: None,
allowed_tools: None,
}
}
#[must_use]
pub fn function(def: crate::core::types::ToolDefinition) -> Self {
GroqTool::Function {
function: GroqFunctionDefinition {
name: def.name,
description: def.description,
parameters: def.parameters,
},
}
}
}
impl GroqUserLocation {
#[must_use]
pub fn new(country: impl Into<String>) -> Self {
Self {
location_type: "approximate".to_string(),
city: None,
region: None,
country: Some(country.into()),
}
}
#[must_use]
pub fn full(
city: impl Into<String>,
region: impl Into<String>,
country: impl Into<String>,
) -> Self {
Self {
location_type: "approximate".to_string(),
city: Some(city.into()),
region: Some(region.into()),
country: Some(country.into()),
}
}
}
pub const COMPOUND_MODELS: &[&str] = &["groq/compound", "groq/compound-mini"];
pub const TOOL_CALLING_MODELS: &[&str] = &[
"llama-3.3-70b-versatile",
"llama-3.1-8b-instant",
"meta-llama/llama-4-scout-17b-16e-instruct",
"qwen/qwen3-32b",
"mistral-saba-24b",
];