Skip to main content

headless_lms_chatbot/azure_chatbot/azure/
tools.rs

1//! The `tools` array of an Azure request: how a tool is advertised to the model.
2//!
3//! Only the wire shapes live here. What tools exist, who may use them and how a call is carried
4//! out is [`crate::chatbot_tools`]; building the search definition from the deployment's search
5//! configuration is [`crate::chatbot_tools::provider_tools::azure_ai_search`].
6
7use serde::{Deserialize, Serialize};
8
9use headless_lms_utils::json_schema_types::Schema;
10
11/// The name Azure gives its own search tool. Unlike every other tool it has no
12/// `ChatbotToolDeclaration` to carry its name.
13pub const AZURE_AI_SEARCH_TOOL_NAME: &str = "azure_ai_search";
14
15#[derive(Clone, Debug, Deserialize, Serialize)]
16#[serde(untagged)]
17pub enum AzureLLMToolDefinition {
18    Function(AzureLLMFunctionToolDefinition),
19    Search(AzureAISearchToolDefinition),
20}
21
22/// A function tool definition, formatted for Azure.
23#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
24pub struct AzureLLMFunctionToolDefinition {
25    #[serde(rename = "type")]
26    pub tool_type: LLMToolType,
27    pub name: String,
28    pub description: String,
29    /// Azure requires `additional_properties: false` here.
30    pub parameters: Schema,
31    /// Always `true`: makes Azure validate calls against `parameters` instead of just passing them through.
32    pub strict: bool,
33}
34
35#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
36#[serde(rename_all = "snake_case")]
37pub enum LLMToolType {
38    Function,
39}
40
41#[derive(Serialize, Deserialize, Debug, Clone)]
42pub struct AzureAISearchToolDefinition {
43    #[serde(rename = "type")]
44    pub data_type: String,
45    pub azure_ai_search: AzureAISearch,
46}
47
48#[derive(Serialize, Deserialize, Debug, Clone)]
49pub struct AzureAISearch {
50    pub indexes: Vec<SearchIndex>,
51}
52
53#[derive(Serialize, Deserialize, Debug, Clone)]
54pub struct SearchIndex {
55    pub project_connection_id: String,
56    pub index_name: String,
57    pub query_type: String,
58    pub top_k: i32,
59    pub embedding_dependency: EmbeddingDependency,
60    pub in_scope: bool,
61    pub strictness: i32,
62    #[serde(skip_serializing_if = "Option::is_none")]
63    pub filter: Option<String>,
64    pub fields_mapping: FieldsMapping,
65    pub semantic_configuration: String,
66}
67
68#[derive(Serialize, Deserialize, Debug, Clone)]
69pub struct FieldsMapping {
70    pub content_fields_separator: String,
71    pub content_fields: Vec<String>,
72    pub filepath_field: String,
73    pub title_field: String,
74    pub url_field: String,
75    pub vector_fields: Vec<String>,
76}
77
78#[derive(Serialize, Deserialize, Debug, Clone)]
79pub struct EmbeddingDependency {
80    #[serde(rename = "type")]
81    pub dep_type: String,
82    pub deployment_name: String,
83}